I have an android service that uses a native library via NDK/JNI. The native library is statically loaded/initialized as suggested...
static {
System.loadLibrary("mylibrary");
if (!nativeClassInit())
throw new RuntimeException("native init failed");
}
Everything works fine until the service is stopped (e.g., from a UI activity where the service may be started/stopped). The problem is when the service is stopped the task has not yet been killed by android and if the user restarts the service the native libraries are not reloaded and a call to a native function causes a crash in the native code?
I tried calling the nativeClassInit() method again after a restart but this doesn't help?
Also, I seen in other posts that unloading the native library is not allowed in Android.
I found by making the service run in its own private process and having the service kill itself in its onDestroy() method via android.os.Process.killProcess() solved my problem. Not sure if this is the most correct way but I would be happy to hear any suggestions.
Concerning the above comments...
What is the native code trying to do when it crashes, and what is the error?
The native code crashed as soon as an internal native library function was called just before the crash an __android_log_print was done displaying the correct parameter values passed in. Its hard to say what exactly happened from the dump.
Do you preserve some JNI pointers (JniENV, jobject-s, etc.) on native side between Service restarts?
Yes, I preserve the JVM in the Onload method and also JNI class IDs & method IDs in my static initialization method. I tried recalling the static initialization method but the same crash occurred.
Related
For the purpose of profiling, I instrumented my android application so that it collects some log at the beginnings and ends of all functions. I do so by calling a public static method called keepLog(String log) at method boundaries. I also wrote another public static method called writeCollectedLogs() which is supposed to write all collected logs into disk. It is important that all logs are written at once because I do not want to use write system-call every time (instead I prefer to keep logs in memory and write everything on disk only once at the end)
My problem is I do not know where to call writeCollectedLogs(). I am looking for some onTerminate() method for the whole android app. However, non of android default onDestroy and onTerminate() seems to work in my case. It is important to note that I have 2 methods of running my application. Sometimes I run my app using android instrumentation test runner and sometimes I use adb to start activities and send touch events manually.
Instrumentation test runner opens my app, runs the tests and then closes the app. In the second scenario however, I have control over my app life cycle. I am looking for a universal way of calling for writeCollectedLogs just before the app closes.
Any suggestions?
This is a bit complicated because there is no universal answer for this problem. If you are using only Activities, onPause() is the only method that is always called (except application crash). Unfortunately, onStop() and onDestroy() are not called with 100% probability. However the android documentation advises to avoid CPU-intensive work in onPause().
I am using JNI in my application... When application launches it works fine and JNI logs are getting printed .. But once application went background and comes foreground after using some other application JNI Logs are not printing and methods are not getting called..
Can anyone suggest me a solution?
Thanks in advance..
Would you give more specific info about your JNI design?
First thing need to check...
Are you building JNIcode as shared library.So Check in logs JNI_Unload is getting called when Application is going in background.
Second thing need to check...
Check in Application going in backgroud ..Shared Library getting unloaded by Application.
Third Thing need to check...
Your JNI code is caching properly jvm and JNIEnv variable.
I have implemented a service which is invoked by system server during the boot-up.
My service has JNI implementation which creates another thread.
The reason for having another thread is to have the capability of canceling operation while monitoring the call back.
This mechanism worked well in Android Kitkat release but it crashes in Android L.
Between two threads, I stored the JavaVM* that I get from GetJavaVM(env) to a static global variable. Of course, this shared data is protected by pthread mutex.
I have tried the following so far, but all of them below still crashed :
1) Used JavaVM* I get from JNI onLoad() function by store it to global
2) In the new thread, as there is only one JavaVM running on Android, get the vm from calling android::AndroidRuntime::getJavaVM();
3) Stored the vm information in the main thread after calling NewGlobalRef(). And saved that reference to the shared data. The new thread used the reference from NewGlobalRef().
Does anyone know what is significantly changed in JNI environment on Android L release?
UPDATE :
Debugged further and the solution I mentioned 1) or 2) should have worked.
The actual issue was due to the garbage collection running more frequently. So the HAL pointer I kept was not valid any more...
These links were helpful!!!
https://developer.android.com/guide/practices/verifying-apps-art.html
http://developer.android.com/training/articles/perf-jni.html
Thanks for all the comments!
What has changed with L release is the move to ART that is less flexible than Dalvik regarding errors.
It's perfectly fine to share JavaVM* across threads, you should keep it this way.
However, what are you doing later with this JavaVM* ?
JNIEnv* has to be retrieved and used from the same thread and must not be used across threads. To use JNIEnv*, a thread must have been attached to the VM (using AttachCurrentThread).
Threads also have to be detached using DetachCurrentThread before they exit.
I have developed an Android app for video conference using WebRTC. I used the available Java Library for the same.
I can successfully make a P2P call. However, when i make the same P2P call again one-after-another, I get the following error:
SetRemoteDescription failed: Called with type in wrong state, type: answer state:
STATE_INPROGRESS
However when I restart the app, I can make the call again, it works flawlessly.
Summary: In order to make a second call, I have to restart the application. It might be because of some possible caching of some objects like PC, SDPObserver or PCObserver. I make all of them null and also kill the activity after the first call. Even then second call doesn't work unless I restart my app.
What can be the possible cause?
It sounds like the local resources are not properly disposed even though you are killing the activity.
Make sure you are calling when the video call ends:
peerConnection.dispose();
videoSource.dispose();
peerConnectionFactory.dispose();
You can test that this works on the AppRTCDemo reference app. Here is the reference code.
I'm working an Android AudioRecord app. If I do not call the release() method on the AudioRecord object at the end of the script, it will not run correctly until I restart the phone.
This becomes a major hassle when working on this project because if the app should ever crash (which happens sometimes while testing and there's an unexpected buffer overflow, etc.) then I have to restart the phone every time.
I have the method to release the buffers inside the finalize() method of my AudioListener class, and I also call them onStop() of the main Activity.
Neither of these seem to work when the app freezes or crashes. Is there a way to attach the release action to an error handler or some general way of ensuring that an app will execute some code to release resources properly even after a crash.
Thanks for any help.
Create your own Application class (need to be declared in AndroidManifest.xml) and then overwrite methods:
Application.onLowMemory();
Application.onTerminate();
More about it can be read in Android manuals for Application