[Applimulator ;)] apkenv + apkenv.ui


i've only included the android libraries that are needed for the currently supported libraries (this was a request by thp).

if you need any other lib that isn't inside the libs/pandora/system/lib/ folder then they can either be found at github (see history) or extracted from the gingerbread.pnd
 
Last edited by a moderator:
@notaz @crow_riot thanks. I could see the next error I needed to fix, but wanted to check that warning first.

The crash is in CShaders::GetShaderProgram(CStringId const&), initially I was creating a GLES2 context, but that died earlier, so I switched to GLES1, but something obviously isn't right if it is trying to use shaders. More investigation required..!
 
if you want to get GLES2 working you need to build with APKENV_GLES2. then it should work with shaders, too. apkenv doesnt support GLES1 and GLES2 in one binary at the moment.
 
Any suggestions here? I have set a break point in the JNIEnv_ExceptionOccurred for my module, clearly the native code is attempting to create an instance of the FileSystem class (in the com.king.core package), a JNIEnv_NewObjectV and then JNIEnv_NewGlobalRef call are made, but then the native code makes an internal call to CJava::CheckForErrors which triggers JNIEnv_ExceptionOccurred. At the moment, I am wondering if the native code is inspecting the JNIEnv to ensure no errors/exceptions have occurred, and deciding that there are errors (by whatever means). Ultimately I don't know for sure how bad this is (check error, find one and continue, or check error, find one and abort function):


JNIEnv_FindClass('com/king/core/FileSystem')
JNIEnv_GetMethodID(88aa0, 'getHomeDirectory', '()Ljava/lang/String;')
JNIEnv_GetMethodID(88aa0, 'getCacheDirectory', '()Ljava/lang/String;')
JNIEnv_GetMethodID(88aa0, '<init>', '(Landroid/content/Context;)V')
JNIEnv_NewObjectV(88aa0, <init>)
JNIEnv_NewGlobalRef(4f718)

Breakpoint 1, candycrashsaga_JNIEnv_ExceptionOccurred (p0=0x3177c) at modules/candycrushsaga.c:88
88 modules/candycrushsaga.c: No such file or directory.
in modules/candycrushsaga.c
(gdb) bt
#0 candycrashsaga_JNIEnv_ExceptionOccurred (p0=0x3177c) at modules/candycrushsaga.c:88
#1 0x4057ad4c in CJava::CheckForErrors(_JNIEnv*) () from ./lib/armeabi-v7a/libcandycrushsaga.so
#2 0x40588348 in CFileSystemAndroid::CFileSystemAndroid(_JavaVM*, _jobject*) ()
from ./lib/armeabi-v7a/libcandycrushsaga.so
#3 0x405871e8 in CAndroidApp::Create(IPlatformProxy*, _JavaVM*, _jobject*, _jobject*) ()
from ./lib/armeabi-v7a/libcandycrushsaga.so
#4 0x40d19bd8 in candycrushsaga_init (self=0x53378, width=800, height=480,
home=0xbeffeb7c "./data/Candy Crush Saga_1.0.10.apk/") at modules/candycrushsaga.c:149
#5 0x0000fef4 in main (argc=2, argv=0xbefffd14) at apkenv.c:544
(gdb)



I thought anyone who has already tackled a module may have some ideas? For what it is worth, here is the disassembly of CheckForErrors:


00169d38 <_ZN5CJava14CheckForErrorsEP7_JNIEnv>:
169d38: e5903000 ldr r3, [r0]
169d3c: e92d4010 push {r4, lr}
169d40: e1a04000 mov r4, r0
169d44: e593303c ldr r3, [r3, #60] ; 0x3c
169d48: e12fff33 blx r3
169d4c: e3500000 cmp r0, #0
169d50: 08bd8010 popeq {r4, pc}
169d54: e5943000 ldr r3, [r4]
169d58: e1a00004 mov r0, r4
169d5c: e5933040 ldr r3, [r3, #64] ; 0x40
169d60: e12fff33 blx r3
169d64: e5943000 ldr r3, [r4]
169d68: e1a00004 mov r0, r4
169d6c: e5933044 ldr r3, [r3, #68] ; 0x44
169d70: e12fff33 blx r3
169d74: e8bd8010 pop {r4, pc}


I haven't tried NOPing the function out yet to see what happens.
 
Any idea what would lead to strtod/atof being broken inside apkenv? For instance, inside GDB, attached to apkenv:


(gdb) p printf( "Value : %3.2f\n", atof( "5.9" ) )
Value : 2.12
$12 = 13

Code:
(gdb) p printf( "%f\n", strtod( "5.5", 0 ) )
2.116463
$14 = 9

Could it be using linking (at runtime) against some libraries that don't work as the prototypes I am compiling against expect?
 
strtod is replaced/wrapped to my_strtod when you look inside libc_wrappers. i cant tell for sure, but maybe it finds androids libc strtod instead of the native one? whats the problem you're experiencing?
 
I get a crash inside /lib/libc.so.6 (coming from my_strtod). If I put a break point on the call to strtod (inside my_strtod), and then manually execute the strtod call in the debugger, I get the same crash:

Code:
Breakpoint 1, my_strtod (__nptr=0xbeffdd20 "5.5", __endptr=0x0) at compat/libc_wrappers.c:634
634     compat/libc_wrappers.c: No such file or directory.
        in compat/libc_wrappers.c
(gdb) p strtod( "5.5", 0 )

Program received signal SIGSEGV, Segmentation fault.
0x402a1a80 in ?? () from /lib/libc.so.6
The program being debugged was signaled while in a function called from GDB.
GDB remains in the frame where the signal was received.
To change this behavior use "set unwindonsignal on".
Evaluation of the expression containing the function
(strtod) will be abandoned.
When the function is done executing, GDB will silently stop.
 
hm difficult to say whats happening there. does your game crash if you just return 0 and dont call strtod at all?


first google result: http://www.opensource.apple.com/source/tcl/tcl-14/tcl/compat/strtod.c


maybe replace the direct call with this implementation? might help tracking down the problem.


but you're at the point now i guess where i somewhen just gave up cause at least i wasnt able to fond the reasons for crashes of functions that usually just work or should work.
 
Uh, okay, tried that, gets through that function, but attempting to print the value crashes. Now I have removed that function and am just attempting to printf a float and it crashes (is fine with printf'ing an int). So it feels like stack corruption is a likely culprit, unfortunately I am doing a printf float test in the previous function that is called in JNI (as in apkenv/my module) and that works fine, then a bunch of code in the game itself runs, and then the stack seems to be corrupt. Bound to be something I am screwing up somewhere, but a bit hard to work out where exactly!
 
@crow_riot thanks, I will look further at this either tonight or tomorrow. I have actually been going through and tidying up/fixing a bunch of issues with arguments to printf style functions not being set up properly, but that is throughout the application. I will double check over my module to see if I am failing to pop off any variable arguments for any of the functions I intercept.
 
Float functions printing garbage is a sign of EABI stack alignment rules being violated, which say that stack pointer must be aligned by 8 on function calls.

Crashing strtod means that glibc's thread local storage was corrupted, which was most likely done by some bionic (libc.so) function call (glibc and bionic uses TLS in incompatible ways), so you have to track down function after calling which strtod starts to crash.
 
Last edited by a moderator:
@notaz Interestingly, there is a message about a thread failing to be created just before, essentially pthread_create ends up returning EAGAIN, which I believe means low resources/maximum thread count reached, plus there was a couple of missing pthread functions which I had to map/implement, so perhaps I have screwed something up, I will review.

I have littered the program with printf's (with float arguments) to try and track it down, essentially it works inside some apkenv code, then the game code runs, when the game code comes back and calls an apkenv function (FindClass I believe) the first thing I do is printf which causes the problem. Based on that I wanted to set some break points inside the game code, however I was struggling (I am not so knowledgeable with gdb). I am able to set break points in any of the apkenv or my module code with b function_name however I couldn't get this to work with the game code (where the function was a c++ class method if that makes any difference), I tried b GameClass::GameMethod but it told me to try again with a leading quote and then hit tab, so I tried that, b 'GameClass::GameMethod<tab> however it didn't bring up a list of functions to choose from or anything. Do you have any advise? Perhaps I need to manually mangle the function and attempt to set a break point there, or do something to get GDB to allow me to set symbols in the game codes shared lib?
 
gdb has trouble setting breakpoints on android libraries for some reason, maybe because they have been loaded by android linker code in apkenv. Sometimes it works but sometimes it doesn't..

Failing pthread_create is most likely also a sign of TLS being corrupted by some bionic (libc.so) call.. Did you wrap all pthread_* functions that the game uses?
 
Regarding break points, I found that using rbreak (instead of break) helped out for c++ methods. I have found what I would describe as a bug in GDB, that sometimes after setting a break point, when the break point is hit, the code will not continue, you can remove the break point but it gets trapped. When you examine the assembly for the given instruction under the PC it is actually an ASM break instructions, so it seems GDB isn't doing something quite right.
 
Regarding threads, I have done the following:
 
pthread_create used to be directly mapped to pthread_create, however I have instead made a my_pthread_create, which looks like:
 


int
my_pthread_create(pthread_t *thread, const pthread_attr_t *__attr, void *(*start_routine)(void*), void *arg)
{
assert(__attr != NULL);
pthread_attr_t *realattr = (pthread_attr_t *) *(int *) __attr;
assert(realattr != NULL);

int result = pthread_create( thread, realattr, start_routine, arg );

if ( result != 0 )
{
printf( "my_pthread_create failed to create thread (return : %d)\n", result );
}

return result;
}

 
That fixed one error message I was seeing (I was getting an error from androidCreateRawThreadEtc which turned out to be from pthread_create). On top of that, I tried directly mapping the following functions:


pthread_key_create
pthread_getspecific
pthread_setspecific
pthread_key_delete

pthread_condattr_init
pthread_condattr_setpshared
pthread_condattr_destroy
pthread_mutexattr_setpshared


I am currently trying to find out whether it is safe to map these functions, i.e. is it safe to pass pthread_key_t and pthread_condattr_t around, or do they need mapping?

Finally, I have also implemented the following function/mapping pthread_cond_timedwait_relative_np -> my_pthread_cond_timedwait_relative_np which looks like:


// Android specific, passes relative time, we need to convert to absolute time then call the non *_np version.
int
my_pthread_cond_timedwait_relative_np(pthread_cond_t *__cond,
pthread_mutex_t *__mutex,
const struct timespec *relative_time)
{
pthread_cond_t *realcond = late_init_pthread_cond(__cond);
pthread_mutex_t *realmutex = late_init_pthread_mutex(__mutex);

struct timespec now;
struct timeval tv;
gettimeofday(&tv, NULL);
TIMEVAL_TO_TIMESPEC(&tv, &now);

now.tv_sec += relative_time->tv_sec;
now.tv_nsec += relative_time->tv_nsec;


return (pthread_cond_timedwait(realcond, realmutex, &now));
}


I am thinking I may want to try and download the source code for the glibc and bionic libc so I can compare the pthread primitives on each platform.

Thanks for your insights so far, it is an interesting learning process.

EDIT: Checked pthread_key_t and pthread_condattr_t they are both int/long's in Bionic and sizeof == 4 on Pandora, so they seem compatible. Not sure what to debug next on this now, hmmm..
 
Last edited by a moderator:
Ah! Knocking out the sound finally makes some progress:

11rvtdg.jpg

 

Got another crash to look at, but nice to see something on screen!
 
Back
Top