/** * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "NativeCallbackThread" //#define LOG_NDEBUG 0 #include "NativeCallbackThread.h" #include namespace android { NativeCallbackThread::NativeCallbackThread(JavaVM *vm) : mExitting(false), mvm(vm) { auto res = pthread_create(&mThread, nullptr, main, this); if (res != 0) { ALOGE("Couldn't start NativeCallbackThread"); mThread = 0; return; } ALOGD("Started native callback thread %p", this); } NativeCallbackThread::~NativeCallbackThread() { ALOGV("~NativeCallbackThread %p", this); stop(); } void* NativeCallbackThread::main(void *args) { auto self = reinterpret_cast(args); self->main(); return nullptr; } void NativeCallbackThread::main() { ALOGV("NativeCallbackThread::main()"); JNIEnv *env = nullptr; JavaVMAttachArgs aargs = {JNI_VERSION_1_4, "NativeCallbackThread", nullptr}; if (mvm->AttachCurrentThread(&env, &aargs) != JNI_OK || env == nullptr) { ALOGE("Couldn't attach thread"); return; } while (!mExitting) { ALOGV("Waiting for task..."); Task task; { AutoMutex _l(mQueueMutex); auto res = mQueueCond.wait(mQueueMutex); ALOGE_IF(res != 0, "Wait failed: %d", res); if (mExitting || res != 0) break; if (mQueue.empty()) continue; task = mQueue.front(); mQueue.pop(); } ALOGV("Executing task..."); task(env); if (env->ExceptionCheck()) { ALOGE("Unexpected exception:"); env->ExceptionDescribe(); env->ExceptionClear(); } } auto res = mvm->DetachCurrentThread(); ALOGE_IF(res != JNI_OK, "Couldn't detach thread"); ALOGV("Native callback thread %p finished", this); } void NativeCallbackThread::enqueue(const Task &task) { AutoMutex _l(mQueueMutex); if (mThread == 0 || mExitting) { ALOGW("Callback thread %p is not serving calls", this); return; } mQueue.push(task); mQueueCond.signal(); } void NativeCallbackThread::stop() { ALOGV("stop() %p", this); { AutoMutex _l(mQueueMutex); if (mThread == 0 || mExitting) return; mExitting = true; mQueueCond.signal(); } auto ret = pthread_join(mThread, nullptr); ALOGE_IF(ret != 0, "Couldn't join thread: %d", ret); ALOGD("Stopped native callback thread %p", this); } } // namespace android