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.
Related
I am trying to get firebase working with my Android app but it is mainly C++ code.
A lot of chances are that if there is any crash it will be some kind of bad access in the C++ part.
Firebase works well with uncaught java exceptions however I cannot get it to work with JNI signals/exceptions.
As far as I know it is not yet compatible with JNI but I thought a workaround would be something similar to this:
Somewehre in the C++ add a signal handler for signals we would like to handle that will send it back to the Java side and try to send a report ( with part of the stacktrace if possible ).
#include <cisgnal>
namespace
{
void SignalHandler( int sig )
{
// Code to call a static method in my Activity
}
}
CrashReporter::CrashReporter()
{
::signal( SIGABRT, & ::SignalHandler )
}
// In java
public static void SendReportOnCrash()
{
FirebaseCrash.report( new Exception( "OOPS" ) );
}
Unfortunately, fake reports are never sent, however I do get callback in Java.
I tried to launch a process separated activity in which I would call FirebaseCrash.report() but there is no non-static way to it therefore it always crash since FirebaseApp/Crash are not instantiated in secondary activity.
I come here to ask if someone would have a hint on how to do that.
My last try but least wanted test would be to write the stack trace to a file, and upon a new start, test if this file exists, if so use FirebaseCrash.log then send a fake report...
You are not guaranteed to be able to do any Java processing after the JVM calls abort() for a fatal error. Per the Java documentation:
SIGABRT
The HotSpot VM does not handle this signal. Instead it calls the abort
function after fatal error handling. If an application uses this
signal then it should terminate the process to preserve the expected
semantics.
Yes, that is for the Oracle implementation. It quite likely applies to all other implementations also.
Because at the point it calls abort(), the JVM expects to be killed.
I have an Android application which consists of some native threads (not attached to JVM) which need to be able to call methods of a Java object.
The way in which I was intending to do this was to create a JNI function which I call from the relevant Java object which allows me to obtain and cache the required java object method ID's, JNIEnv and object references in a static native data structure so that my native threads can (thread safely) access the required methods (e.g. using (*env)->CallVoidMethod(env, this, JavaMethodID, ...), etc;
I'm not convinced this approach is going to work, since I read that the JNIEnv pointer can't be shared between threads, and that only threads which are attached to the JVM can do this kind of thing...
Is this a viable approach?
in JNI_OnLoad, cache JavaVM*. That's the only thing persistent and valid across threads.
as soon as you set up some native thread, call AttachCurrentThread and obtain JNIEnv*, which is valid only for that single thread.
with JavaVM* and JNIEnv*, look up your jclasses, jobjects and jmethodIDs. These are still valid only for the single thread you have attached to.
convert jclasses and jobjects to global references, so that it persists across threads. jmethodIDs do not need to be globalized, they are not jobjects.
On any further native threads, you again need to call AttachCurrentThread to obtain a valid JNIEnv* for that thread.
Don't forget to delete the created global references when you don't need them anymore (in JNI_OnUnload at the latest)
I'm trying to build an Android application that uses an existing C library for some background operation (i.e. does some radio scans, tunes to stations etc). As a stand-alone C executable, the main-loop can deal with message handling from lower levels (hardware components). My understanding is that using JNI, no main function is required because
1) a shared library is created and
2) the shared library is "alive" for as long as the java thread that loaded it is alive.
So assuming that the C library uses multiple threads: where should then the message handling that normally is done in the initial main-loop be done? Is it as simple as by calling C functions that are declared together with the JNI functions?
Re 2) library is "alive" in the meaning of persisting in the memory. But it does not do anything on its own. If you need the library to "do something" even if no functions are being called through JNI, then you need a separate native thread of course. You can create the thread and start a message loop within a regular JNI function call (init method or use JNI_OnLoad for that purpose). It will keep on running when the JNI function call returns. You then also need a teardown method which stops the thread and tears it down (JNI_OnUnload can be used for that)
I have a pretty basic question regarding JNI calls to Java in Android NDK. I have no problems with making the actual calls, but I am not sure whether the Java call is blocked or not when it is called from C.
My question is specifically whether the c call blocks while the Java method is executed, or if it returns immediately. The reason I am asking is that I pass a byteArray to Java and I wonder if Java has access to it after the call is initiated.
JNI calls are like nornal function call. Your native code continues running when JNI call (and Java function) returns.
You should be careful about your selection of JNI calls, some can become blocking. For example getting a Critical pointer to a byte array and not releasing it can block the jvm from continuing to operate.
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.