I have a separate thread running in C++ in the background and I want it to be able to post code to be run on another thread that\'s already running an android.os.Looper (e.g
You need a function already executed in the main thread. If you call ALooper_forThread()
or ALooper_prepare()
there, you will get a pointer to looper associated with main thread. Remember to call ALooper_acquire()
so it can be shared among different threads.
If you want to make some stuffs in the main thread from another thread, I suggest you to use the runOnUiThread function. The main thread in Android is the User Interface thread. I'm not sure if you can use this function in the ndk code.
An example of code could be this:
private void runOnMainThread() {
runOnUiThread(new Runnable(){ public void run() { try { // do some stuffs } catch (final Exception ex) { // handle the possible exception } } }); }
Anyway I suggest you to read the follow links: link1, link2, link3.
I hope it helps.
You will have to go through Java, as android.os.Looper
is not implemented in native code (at least in the currently most recent commit).
I have not enough experience with the NDK to quickly type the required boilerplate, but the obvious option seems to be creating a java Runnable
based on native code and sending it to the looper.
The not-so-obvious solution is directly operating on the MessageQueue
of the thread. Once you have a reference of that, you can register one end of a native pipe there, and write messages to the other end; the pipe basically takes the function of a Handler
, but on native code. Technically, your code is still called from Java, but you won't need the overhead. I haven't found much documentation on the whole thing, but this thread might be a good starting point.¹
However, it is perfectly possible that your code does not actually have to be called from the main thread, or that there is another option to solve your problem without going through Java. That would, however, depend on the problem you're trying to solve.
Note: I assume the main thread scenario. If you can use a native-code-based looper in the thread you want to deploy, you have more options.
¹ It is possible that the ALooper
could be used in some sort of client-mode to do that, as well. Very unsure about that.
A thread can only have one Looper associated with it, a Looper has only one message queue, so mixing Java and native callbacks will maintain ordering.
With that, I don't think there is any contractual obligation in Android today that post()
is guaranteed to execute in particular order, i.e.
getHandler().post(new Runnable() {
@Override
public void run() {
mTextView.setText("first");
}
});
getHandler().post(new Runnable() {
@Override
public void run() {
mTextView.setText("second");
}
});
is not formally guaranteed to leave mTextView displaying second. Definitely nothing is set in stone when two posts are issued from different threads, or delayed.
You can find an Android messaging and concurrency framework for native code development desctibed in a great blog post.
Here is the required proof. The stacktrace below was received while working on an unrelated problem:
A/art: art/runtime/check_jni.cc:65] native: #00 pc 0000484c /system/lib/libbacktrace_libc++.so (UnwindCurrent::Unwind(unsigned int, ucontext*)+23)
A/art: art/runtime/check_jni.cc:65] native: #01 pc 00003031 /system/lib/libbacktrace_libc++.so (Backtrace::Unwind(unsigned int, ucontext*)+8)
A/art: art/runtime/check_jni.cc:65] native: #02 pc 002441f9 /system/lib/libart.so (art::DumpNativeStack(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, int, char const*, art::mirror::ArtMethod*)+68)
A/art: art/runtime/check_jni.cc:65] native: #03 pc 002285a1 /system/lib/libart.so (art::Thread::Dump(std::__1::basic_ostream<char, std::__1::char_traits<char> >&) const+144)
A/art: art/runtime/check_jni.cc:65] native: #04 pc 000afe9b /system/lib/libart.so (art::JniAbort(char const*, char const*)+582)
A/art: art/runtime/check_jni.cc:65] native: #05 pc 000b05d1 /system/lib/libart.so (art::JniAbortF(char const*, char const*, ...)+60)
A/art: art/runtime/check_jni.cc:65] native: #06 pc 000b299d /system/lib/libart.so (art::ScopedCheck::Check(bool, char const*, ...) (.constprop.129)+672)
A/art: art/runtime/check_jni.cc:65] native: #07 pc 000bab87 /system/lib/libart.so (art::CheckJNI::CallVoidMethodV(_JNIEnv*, _jobject*, _jmethodID*, std::__va_list)+50)
A/art: art/runtime/check_jni.cc:65] native: #08 pc 00060817 /system/lib/libandroid_runtime.so (???)
A/art: art/runtime/check_jni.cc:65] native: #09 pc 000a5b29 /system/lib/libandroid_runtime.so (???)
A/art: art/runtime/check_jni.cc:65] native: #10 pc 00010fd7 /system/lib/libutils.so (android::Looper::pollInner(int)+482)
A/art: art/runtime/check_jni.cc:65] native: #11 pc 00011081 /system/lib/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+92)
A/art: art/runtime/check_jni.cc:65] native: #12 pc 0007fbe5 /system/lib/libandroid_runtime.so (android::NativeMessageQueue::pollOnce(_JNIEnv*, int)+22)
A/art: art/runtime/check_jni.cc:65] native: #13 pc 00051b8b /system/framework/arm/boot.oat (Java_android_os_MessageQueue_nativePollOnce__JI+102)
A/art: art/runtime/check_jni.cc:65] at android.os.MessageQueue.nativePollOnce(Native method)
A/art: art/runtime/check_jni.cc:65] at android.os.MessageQueue.next(MessageQueue.java:143)
A/art: art/runtime/check_jni.cc:65] at android.os.Looper.loop(Looper.java:122)
A/art: art/runtime/check_jni.cc:65] at android.app.ActivityThread.main(ActivityThread.java:5411)
A/art: art/runtime/check_jni.cc:65] at java.lang.reflect.Method.invoke!(Native method)
A/art: art/runtime/check_jni.cc:65] at java.lang.reflect.Method.invoke(Method.java:372)
A/art: art/runtime/check_jni.cc:65] at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:916)
A/art: art/runtime/check_jni.cc:65] at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:709)
This could help you https://groups.google.com/forum/#!topic/android-ndk/v2OITtaZTes
But it is easy to achieve through a handler on the java side, sending and processing messages doing back and forth between native and java with jni calls.