diff options
-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; |