| 53 | const static char CMD_EXIT = 2; |
| 54 | |
| 55 | class AndroidThread { |
| 56 | std::thread thread; |
| 57 | std::mutex mutex; |
| 58 | std::condition_variable started; |
| 59 | std::queue<std::function<void()>> tasks; |
| 60 | ALooper *looper = nullptr; |
| 61 | int function_queue_fd = -1; |
| 62 | bool quit = false; |
| 63 | |
| 64 | public: |
| 65 | AndroidThread() : |
| 66 | thread(&AndroidThread::run, this) { |
| 67 | std::unique_lock<std::mutex> lock(mutex); |
| 68 | started.wait(lock, [this]() { |
| 69 | return function_queue_fd >= 0; |
| 70 | }); |
| 71 | } |
| 72 | |
| 73 | static int looper_callback(int fd, int events, void *data) { |
| 74 | char cmd; |
| 75 | AndroidThread *self = (AndroidThread *)data; |
| 76 | ssize_t res = read(fd, &cmd, sizeof(cmd)); |
| 77 | if (res < 0) { |
| 78 | LOGE("Unable to read looper event from pipe: %d", errno); |
| 79 | return 1; |
| 80 | } |
| 81 | if (res == 0) { |
| 82 | LOGE("End of file event should not happen."); |
| 83 | return 1; |
| 84 | } |
| 85 | if (res != sizeof(cmd)) { |
| 86 | LOGE("Unable to read command fully from pipe"); |
| 87 | return 1; |
| 88 | } |
| 89 | |
| 90 | switch (cmd) { |
| 91 | case CMD_FUNCTION: { |
| 92 | std::function<void()> task; |
| 93 | { |
| 94 | std::lock_guard<std::mutex> lock(self->mutex); |
| 95 | if (self->tasks.empty()) { |
| 96 | LOGW("Empty queue when processing CMD_FUNCTION"); |
| 97 | break; |
| 98 | } |
| 99 | task = std::move(self->tasks.front()); |
| 100 | self->tasks.pop(); |
| 101 | } |
| 102 | task(); |
| 103 | } break; |
| 104 | case CMD_EXIT: { |
| 105 | self->quit = true; |
| 106 | } break; |
| 107 | default: { |
| 108 | LOGE("Unknown command: %d", cmd); |
| 109 | } |
| 110 | } |
| 111 | |
| 112 | return 1; |
nothing calls this directly
no outgoing calls
no test coverage detected