summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThiago Marcos P. Santos <thiago@mapbox.com>2016-04-13 17:07:35 +0300
committerJohn Firebaugh <john.firebaugh@gmail.com>2016-04-14 13:44:08 -0700
commit40e590b681444a3726543689ee5f478f358357f6 (patch)
treed7dc2e72e530fb27e32445253529939b6d075b7c
parent204c7fee032bf8509747046b43a788366a189ae7 (diff)
downloadqtlocation-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
-rw-r--r--platform/android/src/run_loop.cpp110
-rw-r--r--platform/android/src/run_loop_impl.hpp7
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;