Added information on running valgrind on Android
This commit is contained in:
parent
b6409c551c
commit
dcc4ab558c
2 changed files with 69 additions and 14 deletions
|
@ -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
|
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
|
6. Run 'ant debug' in android/project. This compiles the .java and eventually
|
||||||
creates a .apk with the native code embedded
|
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:
|
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
|
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
|
Known issues
|
||||||
================================================================================
|
================================================================================
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "SDL_config.h"
|
#include "SDL_config.h"
|
||||||
#include "SDL_stdinc.h"
|
#include "SDL_stdinc.h"
|
||||||
#include "SDL_assert.h"
|
#include "SDL_assert.h"
|
||||||
|
#include "SDL_log.h"
|
||||||
|
|
||||||
#ifdef __ANDROID__
|
#ifdef __ANDROID__
|
||||||
|
|
||||||
|
@ -41,6 +42,8 @@ extern "C" {
|
||||||
#define LOGI(...) do {} while (false)
|
#define LOGI(...) do {} while (false)
|
||||||
#define LOGE(...) 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 */
|
/* Implemented in audio/android/SDL_androidaudio.c */
|
||||||
extern void Android_RunAudioThread();
|
extern void Android_RunAudioThread();
|
||||||
|
@ -259,8 +262,15 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
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() {
|
~LocalReferenceHolder() {
|
||||||
|
#ifdef DEBUG_JNI
|
||||||
|
SDL_Log("Leaving function %s", m_func);
|
||||||
|
#endif
|
||||||
if (m_env) {
|
if (m_env) {
|
||||||
m_env->PopLocalFrame(NULL);
|
m_env->PopLocalFrame(NULL);
|
||||||
--s_active;
|
--s_active;
|
||||||
|
@ -279,6 +289,7 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
JNIEnv *m_env;
|
JNIEnv *m_env;
|
||||||
|
const char *m_func;
|
||||||
};
|
};
|
||||||
int LocalReferenceHolder::s_active;
|
int LocalReferenceHolder::s_active;
|
||||||
|
|
||||||
|
@ -497,7 +508,7 @@ static bool Android_JNI_ExceptionOccurred()
|
||||||
|
|
||||||
static int Android_JNI_FileOpen(SDL_RWops* ctx)
|
static int Android_JNI_FileOpen(SDL_RWops* ctx)
|
||||||
{
|
{
|
||||||
LocalReferenceHolder refs;
|
LocalReferenceHolder refs(__FUNCTION__);
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
|
||||||
jmethodID mid;
|
jmethodID mid;
|
||||||
|
@ -592,7 +603,7 @@ failure:
|
||||||
extern "C" int Android_JNI_FileOpen(SDL_RWops* ctx,
|
extern "C" int Android_JNI_FileOpen(SDL_RWops* ctx,
|
||||||
const char* fileName, const char*)
|
const char* fileName, const char*)
|
||||||
{
|
{
|
||||||
LocalReferenceHolder refs;
|
LocalReferenceHolder refs(__FUNCTION__);
|
||||||
JNIEnv *mEnv = Android_JNI_GetEnv();
|
JNIEnv *mEnv = Android_JNI_GetEnv();
|
||||||
|
|
||||||
if (!refs.init(mEnv)) {
|
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,
|
extern "C" size_t Android_JNI_FileRead(SDL_RWops* ctx, void* buffer,
|
||||||
size_t size, size_t maxnum)
|
size_t size, size_t maxnum)
|
||||||
{
|
{
|
||||||
LocalReferenceHolder refs;
|
LocalReferenceHolder refs(__FUNCTION__);
|
||||||
jlong bytesRemaining = (jlong) (size * maxnum);
|
jlong bytesRemaining = (jlong) (size * maxnum);
|
||||||
jlong bytesMax = (jlong) (ctx->hidden.androidio.size - ctx->hidden.androidio.position);
|
jlong bytesMax = (jlong) (ctx->hidden.androidio.size - ctx->hidden.androidio.position);
|
||||||
int bytesRead = 0;
|
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)
|
static int Android_JNI_FileClose(SDL_RWops* ctx, bool release)
|
||||||
{
|
{
|
||||||
LocalReferenceHolder refs;
|
LocalReferenceHolder refs(__FUNCTION__);
|
||||||
int result = 0;
|
int result = 0;
|
||||||
JNIEnv *mEnv = Android_JNI_GetEnv();
|
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;
|
Sint64 movement = newPosition - ctx->hidden.androidio.position;
|
||||||
if (movement > 0) {
|
if (movement > 0) {
|
||||||
unsigned char buffer[1024];
|
unsigned char buffer[4096];
|
||||||
|
|
||||||
// The easy case where we're seeking forwards
|
// The easy case where we're seeking forwards
|
||||||
while (movement > 0) {
|
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
|
// returns a new global reference which needs to be released later
|
||||||
static jobject Android_JNI_GetSystemServiceObject(const char* name)
|
static jobject Android_JNI_GetSystemServiceObject(const char* name)
|
||||||
{
|
{
|
||||||
LocalReferenceHolder refs;
|
LocalReferenceHolder refs(__FUNCTION__);
|
||||||
JNIEnv* env = Android_JNI_GetEnv();
|
JNIEnv* env = Android_JNI_GetEnv();
|
||||||
if (!refs.init(env)) {
|
if (!refs.init(env)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -789,7 +800,7 @@ static jobject Android_JNI_GetSystemServiceObject(const char* name)
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SETUP_CLIPBOARD(error) \
|
#define SETUP_CLIPBOARD(error) \
|
||||||
LocalReferenceHolder refs; \
|
LocalReferenceHolder refs(__FUNCTION__); \
|
||||||
JNIEnv* env = Android_JNI_GetEnv(); \
|
JNIEnv* env = Android_JNI_GetEnv(); \
|
||||||
if (!refs.init(env)) { \
|
if (!refs.init(env)) { \
|
||||||
return error; \
|
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
|
// 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)
|
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();
|
JNIEnv* env = Android_JNI_GetEnv();
|
||||||
if (!refs.init(env)) {
|
if (!refs.init(env)) {
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -993,7 +1004,7 @@ extern "C" void *SDL_AndroidGetJNIEnv()
|
||||||
|
|
||||||
extern "C" void *SDL_AndroidGetActivity()
|
extern "C" void *SDL_AndroidGetActivity()
|
||||||
{
|
{
|
||||||
LocalReferenceHolder refs;
|
LocalReferenceHolder refs(__FUNCTION__);
|
||||||
jmethodID mid;
|
jmethodID mid;
|
||||||
|
|
||||||
JNIEnv *env = Android_JNI_GetEnv();
|
JNIEnv *env = Android_JNI_GetEnv();
|
||||||
|
@ -1012,7 +1023,7 @@ extern "C" const char * SDL_AndroidGetInternalStoragePath()
|
||||||
static char *s_AndroidInternalFilesPath = NULL;
|
static char *s_AndroidInternalFilesPath = NULL;
|
||||||
|
|
||||||
if (!s_AndroidInternalFilesPath) {
|
if (!s_AndroidInternalFilesPath) {
|
||||||
LocalReferenceHolder refs;
|
LocalReferenceHolder refs(__FUNCTION__);
|
||||||
jmethodID mid;
|
jmethodID mid;
|
||||||
jobject context;
|
jobject context;
|
||||||
jobject fileObject;
|
jobject fileObject;
|
||||||
|
@ -1052,7 +1063,7 @@ extern "C" const char * SDL_AndroidGetInternalStoragePath()
|
||||||
|
|
||||||
extern "C" int SDL_AndroidGetExternalStorageState()
|
extern "C" int SDL_AndroidGetExternalStorageState()
|
||||||
{
|
{
|
||||||
LocalReferenceHolder refs;
|
LocalReferenceHolder refs(__FUNCTION__);
|
||||||
jmethodID mid;
|
jmethodID mid;
|
||||||
jclass cls;
|
jclass cls;
|
||||||
jstring stateString;
|
jstring stateString;
|
||||||
|
@ -1092,7 +1103,7 @@ extern "C" const char * SDL_AndroidGetExternalStoragePath()
|
||||||
static char *s_AndroidExternalFilesPath = NULL;
|
static char *s_AndroidExternalFilesPath = NULL;
|
||||||
|
|
||||||
if (!s_AndroidExternalFilesPath) {
|
if (!s_AndroidExternalFilesPath) {
|
||||||
LocalReferenceHolder refs;
|
LocalReferenceHolder refs(__FUNCTION__);
|
||||||
jmethodID mid;
|
jmethodID mid;
|
||||||
jobject context;
|
jobject context;
|
||||||
jobject fileObject;
|
jobject fileObject;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue