forked from organicmaps/organicmaps
(1) Writing log to a file on Android and iOS was implemented; (2) Memory tracking was implemented;
This commit is contained in:
parent
aa6d49feb3
commit
db109e51a0
16 changed files with 163 additions and 89 deletions
|
@ -3,15 +3,11 @@
|
|||
#include <android/log.h>
|
||||
#include <cassert>
|
||||
|
||||
#include "../../../../../base/assert.hpp"
|
||||
#include "../../../../../base/logging.hpp"
|
||||
#include "../../../../../base/exception.hpp"
|
||||
#include "../../../../../coding/file_writer.hpp"
|
||||
#include "../../../../../platform/platform.hpp"
|
||||
|
||||
#include "../../../../../std/unique_ptr.hpp"
|
||||
|
||||
//#define MWM_LOG_TO_FILE
|
||||
#include "../../../../../platform/file_logging.hpp"
|
||||
|
||||
|
||||
namespace jni
|
||||
|
@ -36,28 +32,10 @@ void AndroidLogMessage(LogLevel l, SrcPoint const & src, string const & s)
|
|||
__android_log_write(pr, "MapsWithMe_JNI", out.c_str());
|
||||
}
|
||||
|
||||
void AndroidLogToFile(LogLevel l, SrcPoint const & src, string const & s)
|
||||
{
|
||||
static unique_ptr<FileWriter> file;
|
||||
|
||||
if (file == NULL)
|
||||
{
|
||||
if (GetPlatform().WritableDir().empty())
|
||||
return;
|
||||
|
||||
file.reset(new FileWriter(GetPlatform().WritablePathForFile("logging.txt")));
|
||||
}
|
||||
|
||||
string srcString = DebugPrint(src) + " " + s + "\n";
|
||||
|
||||
file->Write(srcString.c_str(), srcString.size());
|
||||
file->Flush();
|
||||
}
|
||||
|
||||
void AndroidAssertMessage(SrcPoint const & src, string const & s)
|
||||
{
|
||||
#if defined(MWM_LOG_TO_FILE)
|
||||
AndroidLogToFile(LERROR, src, s);
|
||||
LogMessageFile(LERROR, src, s);
|
||||
#else
|
||||
AndroidLogMessage(LERROR, src, s);
|
||||
#endif
|
||||
|
@ -72,7 +50,7 @@ void AndroidAssertMessage(SrcPoint const & src, string const & s)
|
|||
void InitSystemLog()
|
||||
{
|
||||
#if defined(MWM_LOG_TO_FILE)
|
||||
SetLogMessageFn(&AndroidLogToFile);
|
||||
SetLogMessageFn(&LogMessageFile);
|
||||
#else
|
||||
SetLogMessageFn(&AndroidLogMessage);
|
||||
#endif
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
|
||||
#include "../../../../../base/logging.hpp"
|
||||
|
||||
#include "../../../../../platform/file_logging.hpp"
|
||||
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
@ -52,6 +54,7 @@ extern "C"
|
|||
if (speed > 0.0)
|
||||
info.m_speed = speed;
|
||||
|
||||
LogMemoryInfo();
|
||||
g_framework->OnLocationUpdated(info);
|
||||
}
|
||||
|
||||
|
|
|
@ -55,6 +55,29 @@ string Platform::UniqueClientId() const
|
|||
return res;
|
||||
}
|
||||
|
||||
string Platform::GetMemoryInfo() const
|
||||
{
|
||||
JNIEnv * env = jni::GetEnv();
|
||||
if (!env)
|
||||
{
|
||||
LOG(LWARNING, ("Can't get JNIEnv"));
|
||||
return string("");
|
||||
}
|
||||
|
||||
jclass memLoggingClass = env->FindClass("com/mapswithme/util/log/MemLogging");
|
||||
ASSERT(memLoggingClass, ());
|
||||
|
||||
jmethodID getMemoryInfoId = env->GetStaticMethodID(memLoggingClass, "GetMemoryInfo", "()Ljava/lang/String;");
|
||||
ASSERT(getMemoryInfoId, ());
|
||||
|
||||
jstring memInfoString = (jstring)env->CallStaticObjectMethod(memLoggingClass, getMemoryInfoId);
|
||||
ASSERT(memInfoString, ());
|
||||
|
||||
string res = jni::ToNativeString(env, memInfoString);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void Platform::RunOnGuiThread(TFunctor const & fn)
|
||||
{
|
||||
android::Platform::RunOnGuiThreadImpl(fn);
|
||||
|
|
|
@ -75,7 +75,6 @@ import com.mapswithme.util.ShareAction;
|
|||
import com.mapswithme.util.UiUtils;
|
||||
import com.mapswithme.util.Utils;
|
||||
import com.mapswithme.util.Yota;
|
||||
import com.mapswithme.util.log.MemLogging;
|
||||
import com.mapswithme.util.statistics.Statistics;
|
||||
import com.nineoldandroids.animation.Animator;
|
||||
import com.nineoldandroids.animation.ObjectAnimator;
|
||||
|
@ -153,7 +152,6 @@ public class MWMActivity extends BaseMwmFragmentActivity
|
|||
private LocationPredictor mLocationPredictor;
|
||||
private LikesManager mLikesManager;
|
||||
|
||||
private MemLogging mMemLogging;
|
||||
|
||||
public static Intent createShowMapIntent(Context context, Index index, boolean doAutoDownload)
|
||||
{
|
||||
|
@ -582,7 +580,6 @@ public class MWMActivity extends BaseMwmFragmentActivity
|
|||
|
||||
mLocationPredictor = new LocationPredictor(new Handler(), this);
|
||||
mLikesManager = new LikesManager(this);
|
||||
mMemLogging = new MemLogging(this);
|
||||
restoreRoutingState(savedInstanceState);
|
||||
}
|
||||
|
||||
|
@ -1029,14 +1026,11 @@ public class MWMActivity extends BaseMwmFragmentActivity
|
|||
mPlacePage.onResume();
|
||||
mLocationPredictor.resume();
|
||||
mLikesManager.showLikeDialogs();
|
||||
mMemLogging.startLogging();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause()
|
||||
{
|
||||
mMemLogging.stopLogging();
|
||||
|
||||
pauseLocation();
|
||||
stopWatchingExternalStorage();
|
||||
stopWatchingCompassStatusUpdate();
|
||||
|
|
|
@ -3,63 +3,36 @@ package com.mapswithme.util.log;
|
|||
import android.app.ActivityManager;
|
||||
import android.content.Context;
|
||||
import android.os.Debug;
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
import com.mapswithme.maps.BuildConfig;
|
||||
import android.os.Build;
|
||||
import com.mapswithme.maps.MWMApplication;
|
||||
import java.text.DateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
public class MemLogging
|
||||
{
|
||||
private final static String TAG = "MemLogging";
|
||||
private Context mContext;
|
||||
private Handler mHandler;
|
||||
|
||||
private Runnable logging = new Runnable()
|
||||
public static String GetMemoryInfo()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
final Debug.MemoryInfo debugMI = new Debug.MemoryInfo();
|
||||
Debug.getMemoryInfo(debugMI);
|
||||
final ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo();
|
||||
final Context content = MWMApplication.get().getApplicationContext();
|
||||
final ActivityManager activityManager =
|
||||
(ActivityManager) content.getSystemService(content.ACTIVITY_SERVICE);
|
||||
activityManager.getMemoryInfo(mi);
|
||||
StringBuilder log = new StringBuilder("Memory info: " +
|
||||
" Debug.getNativeHeapSize() = " + Debug.getNativeHeapSize() / 1024 +
|
||||
"KB; Debug.getNativeHeapAllocatedSize() = " + Debug.getNativeHeapAllocatedSize() / 1024 +
|
||||
"KB; Debug.getNativeHeapFreeSize() = " + Debug.getNativeHeapFreeSize() / 1024 +
|
||||
"KB; debugMI.getTotalPrivateDirty() = " + debugMI.getTotalPrivateDirty() +
|
||||
"KB; debugMI.getTotalPss() = " + debugMI.getTotalPss() +
|
||||
"KB; mi.availMem = " + mi.availMem / 1024 +
|
||||
"KB; mi.threshold = " + mi.threshold / 1024 +
|
||||
"KB; mi.lowMemory = " + mi.lowMemory);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
|
||||
{
|
||||
final Debug.MemoryInfo debugMI = new Debug.MemoryInfo();
|
||||
Debug.getMemoryInfo(debugMI);
|
||||
final ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo();
|
||||
final ActivityManager activityManager =
|
||||
(ActivityManager) mContext.getSystemService(mContext.ACTIVITY_SERVICE);
|
||||
activityManager.getMemoryInfo(mi);
|
||||
StringBuilder log = new StringBuilder("Memory info: Debug.getNativeHeapSize() = " + Debug.getNativeHeapSize() / 1024 +
|
||||
"KB; Debug.getNativeHeapAllocatedSize() = " + Debug.getNativeHeapAllocatedSize() / 1024 +
|
||||
"KB, Debug.getNativeHeapFreeSize() = " + Debug.getNativeHeapFreeSize() / 1024 +
|
||||
"KB. debugMI.getTotalPrivateDirty() = " + debugMI.getTotalPrivateDirty() +
|
||||
"KB. debugMI.getTotalPss() = " + debugMI.getTotalPss() +
|
||||
"KB. mi.availMem = " + mi.availMem / 1024 +
|
||||
"KB. mi.threshold = " + mi.threshold / 1024 +
|
||||
"KB. mi.lowMemory = " + mi.lowMemory + " ");
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
|
||||
{
|
||||
log.append("mi.totalMem = " + mi.totalMem / 1024 + "KB.");
|
||||
}
|
||||
Log.d(TAG, log.toString());
|
||||
|
||||
final long memLogPeriod = 3000;
|
||||
mHandler.postDelayed(logging, memLogPeriod);
|
||||
log.append(" mi.totalMem = " + mi.totalMem / 1024 + "KB.");
|
||||
}
|
||||
};
|
||||
|
||||
public MemLogging(Context context)
|
||||
{
|
||||
mContext = context;
|
||||
mHandler = new Handler();
|
||||
}
|
||||
|
||||
public void startLogging()
|
||||
{
|
||||
if (BuildConfig.DEBUG)
|
||||
mHandler.post(logging);
|
||||
}
|
||||
|
||||
public void stopLogging()
|
||||
{
|
||||
if (BuildConfig.DEBUG)
|
||||
mHandler.removeCallbacks(logging);
|
||||
return log.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,7 +73,6 @@ namespace graphics
|
|||
res.m_indices->lock();
|
||||
res.m_vertices->lock();
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
#include "data_formats.hpp"
|
||||
#include "defines.hpp"
|
||||
|
||||
//#include "../base/mutex.hpp"
|
||||
#include "../base/resource_pool.hpp"
|
||||
|
||||
#include "../std/shared_ptr.hpp"
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "../../../map/user_mark.hpp"
|
||||
#include "../../../map/country_status_display.hpp"
|
||||
#include "../../../platform/settings.hpp"
|
||||
#include "../../../platform/file_logging.hpp"
|
||||
|
||||
#define ALERT_VIEW_FACEBOOK 1
|
||||
#define ALERT_VIEW_APPSTORE 2
|
||||
|
@ -133,6 +134,7 @@
|
|||
[m_predictor reset:info];
|
||||
Framework & frm = GetFramework();
|
||||
frm.OnLocationUpdate(info);
|
||||
LogMemoryInfo();
|
||||
|
||||
[self showPopover];
|
||||
[self updateRoutingInfo];
|
||||
|
|
|
@ -4,8 +4,7 @@
|
|||
|
||||
#include "../../platform/settings.hpp"
|
||||
#include "../../platform/platform.hpp"
|
||||
|
||||
#include "../../base/logging.hpp"
|
||||
#include "../../platform/file_logging.hpp"
|
||||
|
||||
|
||||
/// Used to trick iOs and enable multithreading support with non-native pthreads.
|
||||
|
@ -19,6 +18,9 @@
|
|||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
#ifdef MWM_LOG_TO_FILE
|
||||
my::SetLogMessageFn(LogMessageFile);
|
||||
#endif
|
||||
LOG(LINFO, ("maps.me started, detected CPU cores:", GetPlatform().CpuCores()));
|
||||
|
||||
int retVal;
|
||||
|
|
|
@ -951,9 +951,8 @@ void Framework::ClearAllCaches()
|
|||
|
||||
void Framework::MemoryWarning()
|
||||
{
|
||||
ClearAllCaches();
|
||||
|
||||
LOG(LINFO, ("MemoryWarning"));
|
||||
ClearAllCaches();
|
||||
}
|
||||
|
||||
void Framework::EnterBackground()
|
||||
|
|
59
platform/file_logging.cpp
Normal file
59
platform/file_logging.cpp
Normal file
|
@ -0,0 +1,59 @@
|
|||
#include "file_logging.hpp"
|
||||
|
||||
#include "../base/mutex.hpp"
|
||||
|
||||
#include "../std/chrono.hpp"
|
||||
|
||||
#include "../coding/file_writer.hpp"
|
||||
|
||||
#include "../platform/platform.hpp"
|
||||
|
||||
|
||||
void LogMessageFile(my::LogLevel level, my::SrcPoint const & srcPoint, string const & msg)
|
||||
{
|
||||
static threads::Mutex mutex;
|
||||
|
||||
threads::MutexGuard guard(mutex);
|
||||
UNUSED_VALUE(guard);
|
||||
|
||||
static unique_ptr<FileWriter> file;
|
||||
|
||||
if (file == nullptr)
|
||||
{
|
||||
if (GetPlatform().WritableDir().empty())
|
||||
return;
|
||||
auto const curTime = system_clock::now();
|
||||
time_t const curCTime = system_clock::to_time_t(curTime);
|
||||
tm * curTimeTM = localtime(&curCTime);
|
||||
assert(curTimeTM != nullptr);
|
||||
stringstream fileName;
|
||||
fileName << "logging_" << curTimeTM->tm_year + 1900 << "_" << curTimeTM->tm_mon + 1 << "_" << curTimeTM->tm_mday << "_"
|
||||
<< curTimeTM->tm_hour << "_" << curTimeTM->tm_min << "_" << curTimeTM->tm_sec << ".txt";
|
||||
file.reset(new FileWriter(GetPlatform().WritablePathForFile(fileName.str())));
|
||||
}
|
||||
|
||||
string srcString = DebugPrint(srcPoint) + " " + msg + "\n";
|
||||
|
||||
file->Write(srcString.c_str(), srcString.size());
|
||||
file->Flush();
|
||||
}
|
||||
|
||||
void LogMemoryInfo()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
static unsigned long counter = 0;
|
||||
const unsigned short writeLogEveryNthLocationUpdate = 3;
|
||||
if (counter % writeLogEveryNthLocationUpdate == 0)
|
||||
{
|
||||
auto const curTime = system_clock::now();
|
||||
time_t const curCTime = system_clock::to_time_t(curTime);
|
||||
tm * curTimeTM = localtime(&curCTime);
|
||||
ASSERT(curTimeTM != nullptr, ());
|
||||
stringstream fileName;
|
||||
fileName << " " << curTimeTM->tm_year + 1900 << "." << curTimeTM->tm_mon + 1 << "." << curTimeTM->tm_mday << " "
|
||||
<< curTimeTM->tm_hour << ":" << curTimeTM->tm_min << ":" << curTimeTM->tm_sec << " ";
|
||||
LOG(LDEBUG, (fileName.str(), GetPlatform().GetMemoryInfo()));
|
||||
}
|
||||
++counter;
|
||||
#endif
|
||||
}
|
10
platform/file_logging.hpp
Normal file
10
platform/file_logging.hpp
Normal file
|
@ -0,0 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include "../base/logging.hpp"
|
||||
|
||||
// If you uncomment the line bellow the application log will be written to a file.
|
||||
// You'll fild the file in MapsWithMe directory on Android platform and in Documents on iOS.
|
||||
// #define MWM_LOG_TO_FILE
|
||||
|
||||
void LogMessageFile(my::LogLevel level, my::SrcPoint const & srcPoint, string const & msg);
|
||||
void LogMemoryInfo();
|
|
@ -164,6 +164,10 @@ public:
|
|||
|
||||
bool IsTablet() const { return m_isTablet; }
|
||||
|
||||
/// @return information about kinds of memory which are relevant for a platform
|
||||
/// This methid is implemented for iOS and Android only
|
||||
string GetMemoryInfo() const;
|
||||
|
||||
private:
|
||||
void GetSystemFontNames(FilesList & res) const;
|
||||
};
|
||||
|
|
|
@ -71,7 +71,8 @@ HEADERS += \
|
|||
http_thread_callback.hpp \
|
||||
chunks_download_strategy.hpp \
|
||||
servers_list.hpp \
|
||||
constants.hpp
|
||||
constants.hpp \
|
||||
file_logging.hpp \
|
||||
|
||||
SOURCES += \
|
||||
preferred_languages.cpp \
|
||||
|
@ -80,4 +81,5 @@ SOURCES += \
|
|||
http_request.cpp \
|
||||
chunks_download_strategy.cpp \
|
||||
platform.cpp \
|
||||
servers_list.cpp
|
||||
servers_list.cpp \
|
||||
file_logging.cpp \
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
#define IFT_ETHER 0x6 /* Ethernet CSMACD */
|
||||
#endif
|
||||
|
||||
#import <mach/mach.h>
|
||||
|
||||
#import <Foundation/NSAutoreleasePool.h>
|
||||
#import <Foundation/NSBundle.h>
|
||||
#import <Foundation/NSPathUtilities.h>
|
||||
|
@ -145,6 +147,29 @@ static void PerformImpl(void * obj)
|
|||
delete f;
|
||||
}
|
||||
|
||||
string Platform::GetMemoryInfo() const
|
||||
{
|
||||
struct task_basic_info info;
|
||||
mach_msg_type_number_t size = sizeof(info);
|
||||
kern_return_t const kerr = task_info(mach_task_self(),
|
||||
TASK_BASIC_INFO,
|
||||
(task_info_t)&info,
|
||||
&size);
|
||||
stringstream ss;
|
||||
if (kerr == KERN_SUCCESS)
|
||||
{
|
||||
ss << "Memory info: Resident_size = " << info.resident_size / 1024
|
||||
<< "KB; virtual_size = " << info.resident_size / 1024 << "KB; suspend_count = " << info.suspend_count
|
||||
<< " policy = " << info.policy;
|
||||
return ss.str();
|
||||
}
|
||||
else
|
||||
{
|
||||
ss << "Error with task_info(): " << mach_error_string(kerr);
|
||||
return ss.str();
|
||||
}
|
||||
}
|
||||
|
||||
void Platform::RunOnGuiThread(TFunctor const & fn)
|
||||
{
|
||||
dispatch_async_f(dispatch_get_main_queue(), new TFunctor(fn), &PerformImpl);
|
||||
|
|
|
@ -11,6 +11,8 @@ using std::chrono::duration_cast;
|
|||
using std::chrono::high_resolution_clock;
|
||||
using std::chrono::milliseconds;
|
||||
using std::chrono::nanoseconds;
|
||||
using std::chrono::duration_cast;
|
||||
using std::chrono::system_clock;
|
||||
|
||||
#ifdef DEBUG_NEW
|
||||
#define new DEBUG_NEW
|
||||
|
|
Loading…
Add table
Reference in a new issue