Implement client death monitoring.
Bug: b/36863239
Test: one-off integration test (not committed)
Change-Id: I0eef3522b62a3ab5d13071c5118026548b3d052c
diff --git a/services/core/java/com/android/server/radio/RadioService.java b/services/core/java/com/android/server/radio/RadioService.java
index 227ea6b..87a6fc1 100644
--- a/services/core/java/com/android/server/radio/RadioService.java
+++ b/services/core/java/com/android/server/radio/RadioService.java
@@ -98,7 +98,6 @@
throw new IllegalArgumentException("Callback must not be empty");
}
synchronized (mLock) {
- // TODO(b/36863239): add death monitoring for binder
return nativeOpenTuner(mNativeContext, moduleId, bandConfig, withAudio, callback);
}
}
diff --git a/services/core/java/com/android/server/radio/Tuner.java b/services/core/java/com/android/server/radio/Tuner.java
index 3c7babd..5bd7c81 100644
--- a/services/core/java/com/android/server/radio/Tuner.java
+++ b/services/core/java/com/android/server/radio/Tuner.java
@@ -20,6 +20,8 @@
import android.hardware.radio.ITuner;
import android.hardware.radio.ITunerCallback;
import android.hardware.radio.RadioManager;
+import android.os.IBinder;
+import android.os.RemoteException;
import android.util.Slog;
import java.util.List;
@@ -33,18 +35,28 @@
*/
private final long mNativeContext;
- @NonNull private final TunerCallback mTunerCallback;
private final Object mLock = new Object();
+ @NonNull private final TunerCallback mTunerCallback;
+ @NonNull private final ITunerCallback mClientCallback;
+ @NonNull private final IBinder.DeathRecipient mDeathRecipient;
+
private boolean mIsClosed = false;
private boolean mIsMuted = false;
private int mRegion; // TODO(b/62710330): find better solution to handle regions
private final boolean mWithAudio;
Tuner(@NonNull ITunerCallback clientCallback, int halRev, int region, boolean withAudio) {
+ mClientCallback = clientCallback;
mTunerCallback = new TunerCallback(this, clientCallback, halRev);
mRegion = region;
mWithAudio = withAudio;
mNativeContext = nativeInit(halRev, withAudio);
+ mDeathRecipient = this::close;
+ try {
+ mClientCallback.asBinder().linkToDeath(mDeathRecipient, 0);
+ } catch (RemoteException ex) {
+ close();
+ }
}
@Override
@@ -81,6 +93,7 @@
synchronized (mLock) {
if (mIsClosed) return;
mTunerCallback.detach();
+ mClientCallback.asBinder().unlinkToDeath(mDeathRecipient, 0);
nativeClose(mNativeContext);
mIsClosed = true;
}
diff --git a/services/core/jni/com_android_server_radio_Tuner.cpp b/services/core/jni/com_android_server_radio_Tuner.cpp
index e6dbfec..2a71238 100644
--- a/services/core/jni/com_android_server_radio_Tuner.cpp
+++ b/services/core/jni/com_android_server_radio_Tuner.cpp
@@ -66,6 +66,7 @@
struct TunerContext {
TunerContext() {}
+ bool mIsClosed = false;
HalRevision mHalRev;
bool mWithAudio;
sp<V1_0::ITuner> mHalTuner;
@@ -127,6 +128,12 @@
AutoMutex _l(gContextMutex);
auto& ctx = getNativeContext(env, jTuner);
+ if (ctx.mIsClosed) {
+ ALOGI("Tuner was closed during initialization");
+ // dropping the last reference will close HAL tuner
+ return;
+ }
+
ctx.mHalTuner = halTuner;
ctx.mHalTuner11 = V1_1::ITuner::castFrom(halTuner).withDefault(nullptr);
ALOGW_IF(ctx.mHalRev >= HalRevision::V1_1 && ctx.mHalTuner11 == nullptr,
@@ -159,7 +166,13 @@
static void nativeClose(JNIEnv *env, jobject obj, jlong nativeContext) {
AutoMutex _l(gContextMutex);
auto& ctx = getNativeContext(nativeContext);
- if (ctx.mHalTuner == nullptr) return;
+ if (ctx.mIsClosed) return;
+ ctx.mIsClosed = true;
+
+ if (ctx.mHalTuner == nullptr) {
+ ALOGI("Tuner closed during initialization");
+ return;
+ }
ALOGI("Closing tuner %p", ctx.mHalTuner.get());
notifyAudioService(ctx, false);