Home | History | Annotate | Download | only in BroadcastRadio
      1 /**
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #define LOG_TAG "NativeCallbackThread"
     18 //#define LOG_NDEBUG 0
     19 
     20 #include "NativeCallbackThread.h"
     21 
     22 #include <utils/Log.h>
     23 
     24 namespace android {
     25 
     26 using std::lock_guard;
     27 using std::mutex;
     28 using std::unique_lock;
     29 
     30 NativeCallbackThread::NativeCallbackThread(JavaVM *vm) : mvm(vm), mExiting(false),
     31         mThread(&NativeCallbackThread::threadLoop, this) {
     32     ALOGD("Started native callback thread %p", this);
     33 }
     34 
     35 NativeCallbackThread::~NativeCallbackThread() {
     36     ALOGV("%s %p", __func__, this);
     37     stop();
     38 }
     39 
     40 void NativeCallbackThread::threadLoop() {
     41     ALOGV("%s", __func__);
     42 
     43     JNIEnv *env = nullptr;
     44     JavaVMAttachArgs aargs = {JNI_VERSION_1_4, "NativeCallbackThread", nullptr};
     45     if (mvm->AttachCurrentThread(&env, &aargs) != JNI_OK || env == nullptr) {
     46         ALOGE("Couldn't attach thread");
     47         mExiting = true;
     48         return;
     49     }
     50 
     51     while (true) {
     52         Task task;
     53         {
     54             unique_lock<mutex> lk(mQueueMutex);
     55 
     56             if (mExiting) break;
     57             if (mQueue.empty()) {
     58                 ALOGV("Waiting for task...");
     59                 mQueueCond.wait(lk);
     60                 if (mExiting) break;
     61                 if (mQueue.empty()) continue;
     62             }
     63 
     64             task = mQueue.front();
     65             mQueue.pop();
     66         }
     67 
     68         ALOGV("Executing task...");
     69         task(env);
     70         if (env->ExceptionCheck()) {
     71             ALOGE("Unexpected exception:");
     72             env->ExceptionDescribe();
     73             env->ExceptionClear();
     74         }
     75     }
     76 
     77     auto res = mvm->DetachCurrentThread();
     78     ALOGE_IF(res != JNI_OK, "Couldn't detach thread");
     79 
     80     ALOGV("Native callback thread %p finished", this);
     81     ALOGD_IF(!mQueue.empty(), "Skipped execution of %zu tasks", mQueue.size());
     82 }
     83 
     84 void NativeCallbackThread::enqueue(const Task &task) {
     85     lock_guard<mutex> lk(mQueueMutex);
     86 
     87     if (mExiting) {
     88         ALOGW("Callback thread %p is not serving calls", this);
     89         return;
     90     }
     91 
     92     ALOGV("Adding task to the queue...");
     93     mQueue.push(task);
     94     mQueueCond.notify_one();
     95 }
     96 
     97 void NativeCallbackThread::stop() {
     98     ALOGV("%s %p", __func__, this);
     99 
    100     {
    101         lock_guard<mutex> lk(mQueueMutex);
    102 
    103         if (mExiting) return;
    104 
    105         mExiting = true;
    106         mQueueCond.notify_one();
    107     }
    108 
    109     if (mThread.get_id() == std::thread::id()) {
    110         // you can't self-join a thread, but it's ok when calling from our sub-task
    111         ALOGD("About to stop native callback thread %p", this);
    112         mThread.detach();
    113     } else {
    114         mThread.join();
    115         ALOGD("Stopped native callback thread %p", this);
    116     }
    117 }
    118 
    119 } // namespace android
    120