Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I post code to be run on the Android main thread from a separate thread in C++?

Tags:

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. the main thread). By 'post', I mean something akin to View#post where a Runnable is enqueued to be run on the event loop. The code that would be executed is also written in C++.

I found the ALooper API (http://developer.android.com/ndk/reference/group___looper.html), but the docs aren't great and it's unclear to me whether getting the ALooper associated with the destination thread, adding another FD, and signaling it will make my code maintain correct ordering in the event queue with respect to the other enqueued Runnables.

I'd prefer not to have to go through Java and get a Handler, etc. -- it just seems unnecessary since both the code I'm trying to run and the code that's posting it are in c++.

like image 322
Foxichu Avatar asked Dec 10 '15 21:12

Foxichu


People also ask

How do I run something on the main thread?

A condensed code block is as follows: new Handler(Looper. getMainLooper()). post(new Runnable() { @Override public void run() { // things to do on the main thread } });

Does android service run on main thread?

Caution: A service runs in the main thread of its hosting process; the service does not create its own thread and does not run in a separate process unless you specify otherwise. You should run any blocking operations on a separate thread within the service to avoid Application Not Responding (ANR) errors.

Which methods are run on the main UI thread within android applications?

Main Thread: The default, primary thread created anytime an Android application is launched. Also known as a UI thread, it is in charge of handling all user interface and activities, unless otherwise specified. Runnable is an interface meant to handle sharing code between threads. It contains only one method: run() .


1 Answers

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.

Update

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) 
like image 197
Alex Cohn Avatar answered Sep 17 '22 14:09

Alex Cohn