Added information on running valgrind on Android

This commit is contained in:
Sam Lantinga 2012-11-04 13:49:32 -08:00
parent b6409c551c
commit dcc4ab558c
2 changed files with 69 additions and 14 deletions

View file

@ -48,7 +48,7 @@ If you want to use the Eclipse IDE, skip to the Eclipse section below.
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:
@ -275,6 +275,50 @@ If you need to build without optimization turned on, you can create a file calle
APP_OPTIM := debug
================================================================================
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
================================================================================

View file

@ -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 @@ extern "C" {
#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:
}
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 @@ public:
protected:
JNIEnv *m_env;
const char *m_func;
};
int LocalReferenceHolder::s_active;
@ -497,7 +508,7 @@ static bool Android_JNI_ExceptionOccurred()
static int Android_JNI_FileOpen(SDL_RWops* ctx)
{
LocalReferenceHolder refs;
LocalReferenceHolder refs(__FUNCTION__);
int result = 0;
jmethodID mid;
@ -592,7 +603,7 @@ failure:
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" int Android_JNI_FileOpen(SDL_RWops* ctx,
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 @@ extern "C" size_t Android_JNI_FileWrite(SDL_RWops* ctx, const void* buffer,
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 @@ extern "C" Sint64 Android_JNI_FileSeek(SDL_RWops* ctx, Sint64 offset, int whence
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 @@ extern "C" int Android_JNI_FileClose(SDL_RWops* ctx)
// 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 @@ static jobject Android_JNI_GetSystemServiceObject(const char* name)
}
#define SETUP_CLIPBOARD(error) \
LocalReferenceHolder refs; \
LocalReferenceHolder refs(__FUNCTION__); \
JNIEnv* env = Android_JNI_GetEnv(); \
if (!refs.init(env)) { \
return error; \
@ -847,7 +858,7 @@ extern "C" SDL_bool Android_JNI_HasClipboardText()
// 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_AndroidGetJNIEnv()
extern "C" void *SDL_AndroidGetActivity()
{
LocalReferenceHolder refs;
LocalReferenceHolder refs(__FUNCTION__);
jmethodID mid;
JNIEnv *env = Android_JNI_GetEnv();
@ -1012,7 +1023,7 @@ extern "C" const char * SDL_AndroidGetInternalStoragePath()
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" const char * SDL_AndroidGetInternalStoragePath()
extern "C" int SDL_AndroidGetExternalStorageState()
{
LocalReferenceHolder refs;
LocalReferenceHolder refs(__FUNCTION__);
jmethodID mid;
jclass cls;
jstring stateString;
@ -1092,7 +1103,7 @@ extern "C" const char * SDL_AndroidGetExternalStoragePath()
static char *s_AndroidExternalFilesPath = NULL;
if (!s_AndroidExternalFilesPath) {
LocalReferenceHolder refs;
LocalReferenceHolder refs(__FUNCTION__);
jmethodID mid;
jobject context;
jobject fileObject;