Added information on running valgrind on Android
authorSam Lantinga <slouken@libsdl.org>
Sun, 04 Nov 2012 13:49:32 -0800
changeset 6650 d36232135316
parent 6646 dd32cce44d3c
child 6651 17ef8a7cab55
Added information on running valgrind on Android
README.android
src/core/android/SDL_android.cpp
--- a/README.android	Sun Nov 04 09:45:18 2012 -0800
+++ b/README.android	Sun Nov 04 13:49:32 2012 -0800
@@ -48,7 +48,7 @@
 5. Edit <project>/local.properties to point to the Android SDK directory
 6. Run 'ant debug' in android/project. This compiles the .java and eventually 
 creates a .apk with the native code embedded
-7. 'ant install' will push the apk to the device or emulator (if connected)
+7. 'ant debug install' will push the apk to the device or emulator (if connected)
 
 Here's an explanation of the files in the Android project, so you can customize them:
 
@@ -276,6 +276,50 @@
 
 
 ================================================================================
+ Memory debugging
+================================================================================
+
+The best (and slowest) way to debug memory issues on Android is valgrind.
+Valgrind has support for Android out of the box, just grab code using:
+	svn co svn://svn.valgrind.org/valgrind/trunk valgrind
+... and follow the instructions in the file README.android to build it.
+
+One thing I needed to do on Mac OS X was change the path to the toolchain,
+and add ranlib to the environment variables:
+export RANLIB=$NDKROOT/toolchains/arm-linux-androideabi-4.4.3/prebuilt/darwin-x86/bin/arm-linux-androideabi-ranlib
+
+Once valgrind is built, you can create a wrapper script to launch your
+application with it, changing org.libsdl.app to your package identifier:
+--- start_valgrind_app -------------------
+#!/system/bin/sh
+export TMPDIR=/data/data/org.libsdl.app
+exec /data/local/Inst/bin/valgrind --log-file=/sdcard/valgrind.log --error-limit=no $*
+------------------------------------------
+
+Then push it to the device:
+	adb push start_valgrind_app /data/local
+
+and make it executable:
+	adb shell chmod 755 /data/local/start_valgrind_app
+
+and tell Android to use the script to launch your application:
+	adb shell setprop wrap.org.libsdl.app "logwrapper /data/local/start_valgrind_app"
+
+If the setprop command says "could not set property", it's likely that
+your package name is too long and you should make it shorter by changing
+AndroidManifest.xml and the path to your class file in android-project/src
+
+You can then launch your application normally and waaaaaaaiiittt for it.
+You can monitor the startup process with the logcat command above, and
+when it's done (or even while it's running) you can grab the valgrind
+output file:
+	adb pull /sdcard/valgrind.log
+
+When you're done instrumenting with valgrind, you can disable the wrapper:
+	adb shell setprop wrap.org.libsdl.app ""
+
+
+================================================================================
  Known issues
 ================================================================================
 
--- a/src/core/android/SDL_android.cpp	Sun Nov 04 09:45:18 2012 -0800
+++ b/src/core/android/SDL_android.cpp	Sun Nov 04 13:49:32 2012 -0800
@@ -21,6 +21,7 @@
 #include "SDL_config.h"
 #include "SDL_stdinc.h"
 #include "SDL_assert.h"
+#include "SDL_log.h"
 
 #ifdef __ANDROID__
 
@@ -41,6 +42,8 @@
 #define LOGI(...) do {} while (false)
 #define LOGE(...) do {} while (false)
 
+/* Uncomment this to log messages entering and exiting methods in this file */
+//#define DEBUG_JNI
 
 /* Implemented in audio/android/SDL_androidaudio.c */
 extern void Android_RunAudioThread();
@@ -259,8 +262,15 @@
     }
 
 public:
-    LocalReferenceHolder() : m_env(NULL) { }
+    LocalReferenceHolder(const char *func) : m_env(NULL), m_func(func) {
+#ifdef DEBUG_JNI
+        SDL_Log("Entering function %s", m_func);
+#endif
+    }
     ~LocalReferenceHolder() {
+#ifdef DEBUG_JNI
+        SDL_Log("Leaving function %s", m_func);
+#endif
         if (m_env) {
             m_env->PopLocalFrame(NULL);
             --s_active;
@@ -279,6 +289,7 @@
 
 protected:
     JNIEnv *m_env;
+    const char *m_func;
 };
 int LocalReferenceHolder::s_active;
 
@@ -497,7 +508,7 @@
 
 static int Android_JNI_FileOpen(SDL_RWops* ctx)
 {
-    LocalReferenceHolder refs;
+    LocalReferenceHolder refs(__FUNCTION__);
     int result = 0;
 
     jmethodID mid;
@@ -592,7 +603,7 @@
 extern "C" int Android_JNI_FileOpen(SDL_RWops* ctx,
         const char* fileName, const char*)
 {
-    LocalReferenceHolder refs;
+    LocalReferenceHolder refs(__FUNCTION__);
     JNIEnv *mEnv = Android_JNI_GetEnv();
 
     if (!refs.init(mEnv)) {
@@ -615,7 +626,7 @@
 extern "C" size_t Android_JNI_FileRead(SDL_RWops* ctx, void* buffer,
         size_t size, size_t maxnum)
 {
-    LocalReferenceHolder refs;
+    LocalReferenceHolder refs(__FUNCTION__);
     jlong bytesRemaining = (jlong) (size * maxnum);
     jlong bytesMax = (jlong) (ctx->hidden.androidio.size -  ctx->hidden.androidio.position);
     int bytesRead = 0;
@@ -661,7 +672,7 @@
 
 static int Android_JNI_FileClose(SDL_RWops* ctx, bool release)
 {
-    LocalReferenceHolder refs;
+    LocalReferenceHolder refs(__FUNCTION__);
     int result = 0;
     JNIEnv *mEnv = Android_JNI_GetEnv();
 
@@ -731,7 +742,7 @@
 
     Sint64 movement = newPosition - ctx->hidden.androidio.position;
     if (movement > 0) {
-        unsigned char buffer[1024];
+        unsigned char buffer[4096];
 
         // The easy case where we're seeking forwards
         while (movement > 0) {
@@ -767,7 +778,7 @@
 // returns a new global reference which needs to be released later
 static jobject Android_JNI_GetSystemServiceObject(const char* name)
 {
-    LocalReferenceHolder refs;
+    LocalReferenceHolder refs(__FUNCTION__);
     JNIEnv* env = Android_JNI_GetEnv();
     if (!refs.init(env)) {
         return NULL;
@@ -789,7 +800,7 @@
 }
 
 #define SETUP_CLIPBOARD(error) \
-    LocalReferenceHolder refs; \
+    LocalReferenceHolder refs(__FUNCTION__); \
     JNIEnv* env = Android_JNI_GetEnv(); \
     if (!refs.init(env)) { \
         return error; \
@@ -847,7 +858,7 @@
 // returns the value in seconds and percent or -1 if not available
 extern "C" int Android_JNI_GetPowerInfo(int* plugged, int* charged, int* battery, int* seconds, int* percent)
 {
-    LocalReferenceHolder refs;
+    LocalReferenceHolder refs(__FUNCTION__);
     JNIEnv* env = Android_JNI_GetEnv();
     if (!refs.init(env)) {
         return -1;
@@ -993,7 +1004,7 @@
 
 extern "C" void *SDL_AndroidGetActivity()
 {
-    LocalReferenceHolder refs;
+    LocalReferenceHolder refs(__FUNCTION__);
     jmethodID mid;
 
     JNIEnv *env = Android_JNI_GetEnv();
@@ -1012,7 +1023,7 @@
     static char *s_AndroidInternalFilesPath = NULL;
 
     if (!s_AndroidInternalFilesPath) {
-        LocalReferenceHolder refs;
+        LocalReferenceHolder refs(__FUNCTION__);
         jmethodID mid;
         jobject context;
         jobject fileObject;
@@ -1052,7 +1063,7 @@
 
 extern "C" int SDL_AndroidGetExternalStorageState()
 {
-    LocalReferenceHolder refs;
+    LocalReferenceHolder refs(__FUNCTION__);
     jmethodID mid;
     jclass cls;
     jstring stateString;
@@ -1092,7 +1103,7 @@
     static char *s_AndroidExternalFilesPath = NULL;
 
     if (!s_AndroidExternalFilesPath) {
-        LocalReferenceHolder refs;
+        LocalReferenceHolder refs(__FUNCTION__);
         jmethodID mid;
         jobject context;
         jobject fileObject;