Add unlinking from binder death
- When a binder dies or when CarWatchdogService unregisters itself from
car watchdog daemon, binder death is no longer of interest.
Bug: 150728793
Test: atest CarWatchdogServiceTest
Change-Id: I4fd2fd744664342e911775b9fb177cac014e3095
diff --git a/service/src/com/android/car/watchdog/CarWatchdogService.java b/service/src/com/android/car/watchdog/CarWatchdogService.java
index 348522d..b15ede5 100644
--- a/service/src/com/android/car/watchdog/CarWatchdogService.java
+++ b/service/src/com/android/car/watchdog/CarWatchdogService.java
@@ -59,6 +59,20 @@
@GuardedBy("mLock")
private @Nullable ICarWatchdog mCarWatchdogDaemon;
+ private final DeathRecipient mDeathRecipient = new DeathRecipient() {
+ @Override
+ public void binderDied() {
+ Log.w(TAG_WATCHDOG, "Car watchdog daemon died: reconnecting");
+ unlinkToDeath();
+ synchronized (mLock) {
+ mCarWatchdogDaemon = null;
+ }
+ mMainHandler.postDelayed(() -> {
+ connectToDaemon(CAR_WATCHDOG_DAEMON_BIND_MAX_RETRY);
+ }, CAR_WATCHDOG_DAEMON_BIND_RETRY_INTERVAL_MS);
+ }
+ };
+
public CarWatchdogService(Context context) {
// Car watchdog daemon is found at init().
this(context, /* daemon= */ null);
@@ -81,12 +95,14 @@
if (daemon == null) {
connectToDaemon(CAR_WATCHDOG_DAEMON_BIND_MAX_RETRY);
} else {
+ linkToDeath();
registerToDaemon(daemon);
}
}
@Override
public void release() {
+ unlinkToDeath();
ICarWatchdog daemon;
synchronized (mLock) {
daemon = mCarWatchdogDaemon;
@@ -149,23 +165,6 @@
Log.wtf(TAG_WATCHDOG,
"Finding car watchdog daemon took too long(" + elapsedTimeMs + "ms)");
}
- try {
- binder.linkToDeath(new DeathRecipient() {
- @Override
- public void binderDied() {
- Log.w(TAG_WATCHDOG, "Car watchdog daemon died: reconnecting");
- synchronized (mLock) {
- mCarWatchdogDaemon = null;
- }
- mMainHandler.postDelayed(() -> {
- connectToDaemon(CAR_WATCHDOG_DAEMON_BIND_MAX_RETRY);
- }, CAR_WATCHDOG_DAEMON_BIND_RETRY_INTERVAL_MS);
- }
- }, 0);
- } catch (RemoteException e) {
- Log.w(TAG_WATCHDOG, "Linking to binder death recipient failed: " + e);
- return false;
- }
ICarWatchdog daemon = ICarWatchdog.Stub.asInterface(binder);
if (daemon == null) {
@@ -175,6 +174,7 @@
synchronized (mLock) {
mCarWatchdogDaemon = daemon;
}
+ linkToDeath();
registerToDaemon(daemon);
return true;
}
@@ -211,6 +211,32 @@
});
}
+ private void linkToDeath() {
+ IBinder binder;
+ synchronized (mLock) {
+ if (mCarWatchdogDaemon == null) {
+ return;
+ }
+ binder = mCarWatchdogDaemon.asBinder();
+ }
+ try {
+ binder.linkToDeath(mDeathRecipient, 0);
+ } catch (RemoteException e) {
+ Log.w(TAG_WATCHDOG, "Linking to binder death recipient failed: " + e);
+ }
+ }
+
+ private void unlinkToDeath() {
+ IBinder binder;
+ synchronized (mLock) {
+ if (mCarWatchdogDaemon == null) {
+ return;
+ }
+ binder = mCarWatchdogDaemon.asBinder();
+ }
+ binder.unlinkToDeath(mDeathRecipient, 0);
+ }
+
private static final class ICarWatchdogClientImpl extends ICarWatchdogClient.Stub {
private final WeakReference<CarWatchdogService> mService;
diff --git a/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogServiceTest.java b/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogServiceTest.java
index dcc6f81..3ab03e5 100644
--- a/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogServiceTest.java
@@ -18,11 +18,16 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.verify;
+
import android.automotive.watchdog.ICarWatchdog;
import android.automotive.watchdog.ICarWatchdogClient;
import android.automotive.watchdog.TimeoutLength;
import android.content.Context;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;
@@ -47,6 +52,7 @@
private static final String TAG = CarWatchdogServiceTest.class.getSimpleName();
@Mock private Context mMockContext;
+ @Mock private IBinder mBinder;
private CarWatchdogService mCarWatchdogService;
private FakeCarWatchdog mFakeCarWatchdog;
@@ -71,6 +77,18 @@
assertThat(mFakeCarWatchdog.gotResponse()).isTrue();
}
+ @Test
+ public void testLinkUnlinkDeathRecipient() {
+ mCarWatchdogService.init();
+ try {
+ verify(mBinder).linkToDeath(any(), anyInt());
+ } catch (RemoteException e) {
+ // Do nothing
+ }
+ mCarWatchdogService.release();
+ verify(mBinder).unlinkToDeath(any(), anyInt());
+ }
+
// FakeCarWatchdog mimics ICarWatchdog daemon in local process.
final class FakeCarWatchdog extends ICarWatchdog.Default {
@@ -98,6 +116,11 @@
}
@Override
+ public IBinder asBinder() {
+ return mBinder;
+ }
+
+ @Override
public void registerMediator(ICarWatchdogClient mediator) throws RemoteException {
mClients.add(mediator);
mMainHandler.post(() -> {