diff --git a/services/core/jni/NativeCallbackThread.cpp b/services/core/jni/NativeCallbackThread.cpp index 7d668e3183a7f..0c84e6dbf03b6 100644 --- a/services/core/jni/NativeCallbackThread.cpp +++ b/services/core/jni/NativeCallbackThread.cpp @@ -107,10 +107,15 @@ void NativeCallbackThread::stop() { mQueueCond.signal(); } - auto ret = pthread_join(mThread, nullptr); - ALOGE_IF(ret != 0, "Couldn't join thread: %d", ret); + if (pthread_self() == mThread) { + // you can't self-join a thread, but it's ok when calling from our sub-task + ALOGD("About to stop native callback thread %p", this); + } else { + auto ret = pthread_join(mThread, nullptr); + ALOGE_IF(ret != 0, "Couldn't join thread: %d", ret); - ALOGD("Stopped native callback thread %p", this); + ALOGD("Stopped native callback thread %p", this); + } } } // namespace android diff --git a/services/core/jni/com_android_server_radio_Tuner.cpp b/services/core/jni/com_android_server_radio_Tuner.cpp index 2a712387e3934..f9418e4c108e8 100644 --- a/services/core/jni/com_android_server_radio_Tuner.cpp +++ b/services/core/jni/com_android_server_radio_Tuner.cpp @@ -35,6 +35,7 @@ namespace radio { namespace Tuner { using hardware::Return; +using hardware::hidl_death_recipient; using hardware::hidl_vec; namespace V1_0 = hardware::broadcastradio::V1_0; @@ -63,6 +64,15 @@ static struct { static const char* const kAudioDeviceName = "Radio tuner source"; +class HalDeathRecipient : public hidl_death_recipient { + wp mTunerCallback; + +public: + HalDeathRecipient(wp tunerCallback):mTunerCallback(tunerCallback) {} + + virtual void serviceDied(uint64_t cookie, const wp& who); +}; + struct TunerContext { TunerContext() {} @@ -71,6 +81,7 @@ struct TunerContext { bool mWithAudio; sp mHalTuner; sp mHalTuner11; + sp mHalDeathRecipient; private: DISALLOW_COPY_AND_ASSIGN(TunerContext); @@ -109,6 +120,16 @@ static void nativeFinalize(JNIEnv *env, jobject obj, jlong nativeContext) { delete ctx; } +void HalDeathRecipient::serviceDied(uint64_t cookie __unused, + const wp& who __unused) { + ALOGW("HAL Tuner died unexpectedly"); + + auto tunerCallback = mTunerCallback.promote(); + if (tunerCallback == nullptr) return; + + tunerCallback->hardwareFailure(); +} + // TODO(b/62713378): implement support for multiple tuners open at the same time static void notifyAudioService(TunerContext& ctx, bool connected) { if (!ctx.mWithAudio) return; @@ -133,12 +154,19 @@ void setHalTuner(JNIEnv *env, JavaRef const &jTuner, sp h // dropping the last reference will close HAL tuner return; } + if (ctx.mHalTuner != nullptr) { + ALOGE("HAL tuner is already set."); + return; + } ctx.mHalTuner = halTuner; ctx.mHalTuner11 = V1_1::ITuner::castFrom(halTuner).withDefault(nullptr); ALOGW_IF(ctx.mHalRev >= HalRevision::V1_1 && ctx.mHalTuner11 == nullptr, "Provided tuner does not implement 1.1 HAL"); + ctx.mHalDeathRecipient = new HalDeathRecipient(getNativeCallback(env, jTuner)); + halTuner->linkToDeath(ctx.mHalDeathRecipient, 0); + notifyAudioService(ctx, true); } @@ -175,7 +203,12 @@ static void nativeClose(JNIEnv *env, jobject obj, jlong nativeContext) { } ALOGI("Closing tuner %p", ctx.mHalTuner.get()); + notifyAudioService(ctx, false); + + ctx.mHalTuner->unlinkToDeath(ctx.mHalDeathRecipient); + ctx.mHalDeathRecipient = nullptr; + ctx.mHalTuner11 = nullptr; ctx.mHalTuner = nullptr; }