diff options
author | Thiago Marcos P. Santos <thiago@mapbox.com> | 2016-04-13 17:07:35 +0300 |
---|---|---|
committer | John Firebaugh <john.firebaugh@gmail.com> | 2016-04-14 13:44:08 -0700 |
commit | 40e590b681444a3726543689ee5f478f358357f6 (patch) | |
tree | d7dc2e72e530fb27e32445253529939b6d075b7c /platform | |
parent | 204c7fee032bf8509747046b43a788366a189ae7 (diff) | |
download | qtlocation-mapboxgl-40e590b681444a3726543689ee5f478f358357f6.tar.gz |
[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
Diffstat (limited to 'platform')
-rw-r--r-- | platform/android/src/run_loop.cpp | 110 | ||||
-rw-r--r-- | 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 e05d27a088..4bd0480219 100644 --- a/platform/android/src/run_loop.cpp +++ b/platform/android/src/run_loop.cpp @@ -8,18 +8,101 @@ #include <algorithm> #include <cassert> #include <functional> +#include <stdexcept> #include <vector> +#include <fcntl.h> +#include <unistd.h> + +#define PIPE_OUT 0 +#define PIPE_IN 1 + namespace { using namespace mbgl::util; static ThreadLocal<RunLoop>& current = *new ThreadLocal<RunLoop>; +int looperCallbackNew(int fd, int, void* data) { + int buffer[1]; + while (read(fd, buffer, sizeof(buffer)) > 0) {} + + auto loop = reinterpret_cast<ALooper*>(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<RunLoop*>(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<std::recursive_mutex> 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<Impl>()) { - 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<Impl>(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<WorkTask> 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<void**>(&outData)); + impl->processRunnables(); } void RunLoop::stop() { impl->running = false; - ALooper_wake(impl->loop); + impl->wake(); } void RunLoop::addWatch(int, Event, std::function<void(int, Event)>&&) { diff --git a/platform/android/src/run_loop_impl.hpp b/platform/android/src/run_loop_impl.hpp index 2dd912994f..5cf7231175 100644 --- a/platform/android/src/run_loop_impl.hpp +++ b/platform/android/src/run_loop_impl.hpp @@ -27,6 +27,11 @@ public: std::list<Runnable*>::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; |