engine.animating = 1;
so that the plasma anim starts right away. Now, when the screen is touched I want
the app to shut down. So I modified the code so that a quit flag is set when the appropriate
input event comes in. The main loop listens to this quit flag and if it is set, the main loop
in the android_main() function calls ANativeActivity_Finish() on the app and returns
control to the native app glue. This works so far but there is one big problem: My
app is shut down correctly but it can't be started again!! When trying to start the app
again after it has been shut down using ANativeActivity_Finish(), it doesn't start and
logcat prints the error message: "Launch timeout has expired, giving up wake lock!"
Any ideas what I'm doing wrong there? (modified version of the plasma sample is
attached to this mail)
Tks,
Andreas
>The NDK examples are notorious for having static variables without re-
>initializing routines. Those static variables will retain their state
>even after the app "exits" because android apps are not booted from
>memory until that memory is needed. This can cause the app to work
>differently whether it was compiled and launched again, or simply ran,
>exited, and launched again. To verify this, try this: Compile the app,
>run it, exit. Now make a small change, recompile and run again. Does
>the app work OK? That means there is a static variable somewhere not
>being initialized to a good value, it just has whatever value it had
>when the app exited (because the library is still in memory). Go
>through the native code and check for any static variables, and make
>sure you add code to initialize them to a valid value when the app
>starts.
Thanks, that would be an explanation for the weird behaviour. In fact,
it really *does* work if I just recompile it again so it really seems to be
caused by static variables that still contain the values from the last
run.
The problem is that I can't change this so easily because my app is
quite huge and has tons of global static variables which I'd have to
initialize to their correct values. This would be a huge effort so I'm
wondering if their is a way to "purge" the library from memory when
the app exits? Or is there some option that can be set in the app's
Android manifest that tells Android to always flush the library from
memory and reload it again so that all static variables are initialized
correctly? Such an option would be very helpful for my case because
initializing all these static variables would be a huge effort...
Tks,
Andreas
If there's a way to do that, I never found it; it certainly would be a
useful feature, given how applications EXPECT to use a process. It
wouldn't even have to purge everything; just running the ".so exit"
destructors and then rerunning the static variable init routines should
be sufficient.
Instead I took a different approach: I EXPECT the JNI data to persist.
Then the only thing I need to purge are the various OpenGL texture IDs
(and other buffer IDs) when an OpenGL context is lost, but for me that
was a lot less work than trying to purge all the statics of an existing
game and all of its libraries. (I'm talking about NinJump on Android,
btw, which I ported from the iPhone version.)
Tim
In my app it still would be a hell of work because my app consists of
like a hundred *.c sources and most of these sources use maybe two
or three global static variables. Because these statics are only accessible
from inside the respective *.c source, I'd need to add a resetvars() function
to each of these *.c sources. And whenever I add a new global static
variable, I'd have to add it to the respective resetvars() function as well
so there is suddenly some kind of redundancy in my app which is always
bad IMHO.
It's all pretty suboptimal to say the least so it'd really be helpful if the
whole *.so library could be purged from memory upon startup of my app.
This would really make things much much easier...
Greets,
Andreas
Yes, but that doesn't help me in my case, does it? I mean, I've lots of
global static variables like linked list pointers etc. When my app starts,
all of these list pointers are initialized to NULL. However, with the current
Android behaviour, they're only set to NULL upon the very first start of
my app. After that, they'll contain the (now invalid) pointers from the
previous cycle of my app. Of course, I could fix all this by setting all
global pointers to NULL upon app start (or exit) but as I said, it's a
huuuuuuge work! It would be so much easier to simply purge the *.so
and reload it.
Does anybody know how to get in touch with the Android NDK team?
I think this issue should really be taken into account by the NDK devs
because it is totally inconvenient that there is no option that purges
the old *.so on app startup. It will make Android ports much harder
because programmers suddenly have to deal with the fact that global
statics in their C code "remember" their last values instead of initializing
it correctly. I'd really like to hear a comment from one of the NDK devs
about this behaviour.
Greets,
Andreas
>Why doesn't it help you? Why is the data invalid? Is it pointing to Java
>data? Or OpenGL IDs?
No, it is pointing to memory that has been freed.
>
>If not, then the data is invalid only because you're calling something
>that MAKES it invalid. Otherwise everything is still valid because the
>process IS STILL IN ITS FIRST CYCLE; it's only the Java "Application"
>object that's new. Your JNI data is all still the way you left it. The
>problem then becomes connecting a new instance of the Application object
>and its children to your persistent C/C++ process. The whole Application
>life cycle is an illusion that your C++ code can mostly ignore (though
>it should certainly pause any serious activity when in the background).
>Ideally it would release lots of data when it's shut down to be a "nice"
>application, but the OS will kill it if it needs the RAM.
>
>If you understand what I'm saying and have some other reason that you
>need to REALLY shut down and restart your app, then you haven't made
>that clear. I have tons of static data all over the place; the only
>thing I need to touch on restart is OpenGL and the list of links to Java
>classes that change with a new application instance. The other static
>data stays initialized across multiple runs with whatever state it's
>accumulated.
Ok, but that's not the case for my app. Maybe we were really talking about
different things so let me give you an example. My app looks like this:
static struct LinkedList *sound_list = NULL; // list of sounds
static struct LinkedList *gfx_list = NULL; // list of gfx
Now, during the startup of my app these lists are filled with nodes. When
my app receives a shut down event, it frees everything like this:
for(node = sound_list; node; node = succ) {
succ = node->succ; // backup successor pointer because freelistnode() will free memory of 'node'
freelistnode(node);
}
What I'm NOT doing is setting "sound_list" to NULL after all nodes have
been removed because I'm expecting my app to go away, so I don't need
to reset all global pointers because my app is going away anyway. So
after all list nodes have been removed, "sound_list" will contain a pointer
to memory that has been freed. When I restart my app, nodes are again
added to "sound_list" and this is done like this:
if(!sound_list) {
// chain first node into the list
} else {
// iterate thru list append node to the end of the list
}
NOW of course I have the problem that "sound_list" still contains the invalid
memory pointer from the previous run of my app. Thus, the code tries to
iterate through the list using an invalid pointer as a starting pointer which
of course leads to an immediate crash.
Of course you might say now: "Hey, why don't you simply reset all pointers
correctly once you have freed their memory?" ... this would of course solve the
problem but there are *tons* of similar cases more (lots of global flags that
my app expects to be ZERO on startup and not to contain any previous
values...)
You really need to look at my problem from a C programmer's point of view.
I know nothing about Java. I'm using plain old school C and my android_main()
function simply expects that all global static values contain the values I assigned
to them in my sources, just as it is the case on all other systems (Win32, Linux,
Mac..) ---> when the main() function of a C program is called, I can be sure that
all my globals will have the values I assigned to them and not some random values
from previous cycles. That is what is confusing me here and that is why I'm trying
to work around. I just need to find a way that all my globals have the values I
assigned to them when android_main() is called.
An idea would be if I could call dlopen() from my Android app. If this would
be possible, I could simply create a dummy startup code, that calls dlopen()
on my real application's *.so and then dlclose() after my real application has
quit. This would ensure that the *.so constructor and destructor is always
run and so my globals get the correct values. But I'm not sure if dlopen() is
possible on Android.
>
>> Does anybody know how to get in touch with the Android NDK team? I
>> think this issue should really be taken into account by the NDK devs
>> because it is totally inconvenient that there is no option that
>> purges the old *.so on app startup. It will make Android ports much
>> harder because programmers suddenly have to deal with the fact that
>> global statics in their C code "remember" their last values instead
>> of initializing it correctly. I'd really like to hear a comment from
>> one of the NDK devs about this behaviour.
>
>Several awesome developers from the Android team read this list. If they
>care that the clean answer is to not release all of your data (which is
>what I'm suggesting), then they haven't said so, and they certainly
>haven't acted to add an API to do what you're requesting (at least not
>that I know of).
I'm just a little bit confused that nobody seems to have had trouble with
this serious limitation yet. I mean, every C programmer expects all his
globals to contain the correct values when his main() function is called.
But on Android this is currently not the case because global values retain
their values because the *.so is not purged. I think this is a serious
problem and needs a solution that is different from: "Hey, just reset all
your globals manually when you shut down your app!"
Greets,
Andreas
Hi, you could try to call clib exit() function from your native code on exit. That would kill your app, but it is real hack!
>Hi, you could try to call clib exit() function from your native code on
>exit. That would kill your app, but it is real hack!
Great idea, that solves the problem. Thanks for the trick :)
Greets,
Andreas