[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
This commit is contained in:
committed by
John Firebaugh
parent
204c7fee03
commit
40e590b681
@@ -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)>&&) {
|
||||
|
||||
Reference in New Issue
Block a user