From 40e590b681444a3726543689ee5f478f358357f6 Mon Sep 17 00:00:00 2001 From: "Thiago Marcos P. Santos" Date: Wed, 13 Apr 2016 17:07:35 +0300 Subject: [PATCH] [android] Use ALooper_addFd() and callbacks to wake up This is needed for plugging into an existing Looper because we won't call ::run() on the main thread (this is called on the Java side of the application automatically by Android). But we still need to wake up and process the events. For that we create a pipe and write to the pipe to wake up the main loop and we process events on the callback of the fd handler. Fixes #4682 --- platform/android/src/run_loop.cpp | 110 ++++++++++++++++++++----- platform/android/src/run_loop_impl.hpp | 7 ++ 2 files changed, 95 insertions(+), 22 deletions(-) diff --git a/platform/android/src/run_loop.cpp b/platform/android/src/run_loop.cpp index e05d27a08..4bd048021 100644 --- a/platform/android/src/run_loop.cpp +++ b/platform/android/src/run_loop.cpp @@ -8,18 +8,101 @@ #include #include #include +#include #include +#include +#include + +#define PIPE_OUT 0 +#define PIPE_IN 1 + namespace { using namespace mbgl::util; static ThreadLocal& current = *new ThreadLocal; +int looperCallbackNew(int fd, int, void* data) { + int buffer[1]; + while (read(fd, buffer, sizeof(buffer)) > 0) {} + + auto loop = reinterpret_cast(data); + ALooper_wake(loop); + + return 1; +} + +int looperCallbackDefault(int fd, int, void* data) { + int buffer[1]; + while (read(fd, buffer, sizeof(buffer)) > 0) {} + + auto runLoop = reinterpret_cast(data); + runLoop->runOnce(); + + return 1; +} + } // namespace namespace mbgl { namespace util { +RunLoop::Impl::Impl(RunLoop* runLoop, RunLoop::Type type) { + using namespace mbgl::android; + detach = attach_jni_thread(theJVM, &env, ThreadContext::getName()); + + loop = ALooper_prepare(0); + assert(loop); + + ALooper_acquire(loop); + + if (pipe(fds)) { + throw std::runtime_error("Failed to create pipe."); + } + + if (fcntl(fds[PIPE_OUT], F_SETFL, O_NONBLOCK)) { + throw std::runtime_error("Failed to set pipe read end non-blocking."); + } + + int ret = 0; + + switch (type) { + case Type::New: + ret = ALooper_addFd(loop, fds[PIPE_OUT], ALOOPER_POLL_CALLBACK, + ALOOPER_EVENT_INPUT, looperCallbackNew, loop); + break; + case Type::Default: + ret = ALooper_addFd(loop, fds[PIPE_OUT], ALOOPER_POLL_CALLBACK, + ALOOPER_EVENT_INPUT, looperCallbackDefault, runLoop); + break; + } + + if (ret != 1) { + throw std::runtime_error("Failed to add file descriptor to Looper."); + } +} + +RunLoop::Impl::~Impl() { + if (ALooper_removeFd(loop, fds[PIPE_OUT]) != 1) { + throw std::runtime_error("Failed to remove file descriptor from Looper."); + } + + if (close(fds[PIPE_IN]) || close(fds[PIPE_OUT])) { + throw std::runtime_error("Failed to close file descriptor."); + } + + ALooper_release(loop); + + using namespace mbgl::android; + detach_jni_thread(theJVM, &env, detach); +} + +void RunLoop::Impl::wake() { + if (write(fds[PIPE_IN], "\n", 1) == -1) { + throw std::runtime_error("Failed to write to file descriptor."); + } +} + void RunLoop::Impl::addRunnable(Runnable* runnable) { std::lock_guard lock(mtx); @@ -28,7 +111,7 @@ void RunLoop::Impl::addRunnable(Runnable* runnable) { runnable->iter = std::move(iter); } - ALooper_wake(loop); + wake(); } void RunLoop::Impl::removeRunnable(Runnable* runnable) { @@ -74,25 +157,12 @@ RunLoop* RunLoop::Get() { return current.get(); } -RunLoop::RunLoop(Type) : impl(std::make_unique()) { - using namespace mbgl::android; - impl->detach = attach_jni_thread(theJVM, &impl->env, ThreadContext::getName()); - - impl->loop = ALooper_prepare(0); - assert(impl->loop); - - ALooper_acquire(impl->loop); - +RunLoop::RunLoop(Type type) : impl(std::make_unique(this, type)) { current.set(this); } RunLoop::~RunLoop() { current.set(nullptr); - - ALooper_release(impl->loop); - - using namespace mbgl::android; - detach_jni_thread(theJVM, &impl->env, impl->detach); } LOOP_HANDLE RunLoop::getLoopHandle() { @@ -101,7 +171,7 @@ LOOP_HANDLE RunLoop::getLoopHandle() { void RunLoop::push(std::shared_ptr task) { withMutex([&] { queue.push(std::move(task)); }); - ALooper_wake(impl->loop); + impl->wake(); } void RunLoop::run() { @@ -122,17 +192,13 @@ void RunLoop::run() { void RunLoop::runOnce() { MBGL_VERIFY_THREAD(tid); - int outFd, outEvents; - char *outData = nullptr; - process(); - impl->processRunnables().count(); - ALooper_pollOnce(0, &outFd, &outEvents, reinterpret_cast(&outData)); + impl->processRunnables(); } void RunLoop::stop() { impl->running = false; - ALooper_wake(impl->loop); + impl->wake(); } void RunLoop::addWatch(int, Event, std::function&&) { diff --git a/platform/android/src/run_loop_impl.hpp b/platform/android/src/run_loop_impl.hpp index 2dd912994..5cf723117 100644 --- a/platform/android/src/run_loop_impl.hpp +++ b/platform/android/src/run_loop_impl.hpp @@ -27,6 +27,11 @@ public: std::list::iterator iter; }; + Impl(RunLoop*, RunLoop::Type); + ~Impl(); + + void wake(); + void addRunnable(Runnable*); void removeRunnable(Runnable*); void initRunnable(Runnable*); @@ -36,6 +41,8 @@ public: private: friend RunLoop; + int fds[2]; + JNIEnv *env = nullptr; bool detach = false;