Adding recovery logic for IAudioControl
When HAL dies
- AudioControlWrapper grabs a new HAL Handle
- AudioControlWrapper calls CarAudioService#resetHalAudioFocus
- resetHalAudioFocus resets HalAudioFocus and re-registers the listener
Bug: 153475563
Test: atest com.android.car.audio, also manually killed audiocontrol and
verified it recovered
Change-Id: If689af0dc7cc1c628ae750a46a2452079a093762
diff --git a/service/src/com/android/car/audio/CarAudioService.java b/service/src/com/android/car/audio/CarAudioService.java
index 96ddc27..6d244d1 100644
--- a/service/src/com/android/car/audio/CarAudioService.java
+++ b/service/src/com/android/car/audio/CarAudioService.java
@@ -270,7 +270,11 @@
if (mHalAudioFocus != null) {
mHalAudioFocus.unregisterFocusListener();
}
- mAudioControlWrapper = null;
+
+ if (mAudioControlWrapper != null) {
+ mAudioControlWrapper.unlinkToDeath();
+ mAudioControlWrapper = null;
+ }
}
}
@@ -1201,10 +1205,18 @@
private AudioControlWrapper getAudioControlWrapperLocked() {
if (mAudioControlWrapper == null) {
mAudioControlWrapper = AudioControlFactory.newAudioControl();
+ mAudioControlWrapper.linkToDeath(this::resetHalAudioFocus);
}
return mAudioControlWrapper;
}
+ private void resetHalAudioFocus() {
+ if (mHalAudioFocus != null) {
+ mHalAudioFocus.reset();
+ mHalAudioFocus.registerFocusListener();
+ }
+ }
+
boolean isAudioZoneIdValid(int zoneId) {
for (CarAudioZone zone : mCarAudioZones) {
if (zone.getId() == zoneId) {
diff --git a/service/src/com/android/car/audio/hal/AudioControlWrapper.java b/service/src/com/android/car/audio/hal/AudioControlWrapper.java
index af1c02e..c491056 100644
--- a/service/src/com/android/car/audio/hal/AudioControlWrapper.java
+++ b/service/src/com/android/car/audio/hal/AudioControlWrapper.java
@@ -19,6 +19,8 @@
import android.hardware.automotive.audiocontrol.V2_0.IFocusListener;
import android.media.AudioAttributes.AttributeUsage;
+import androidx.annotation.Nullable;
+
import java.io.PrintWriter;
/**
@@ -75,4 +77,25 @@
* @param value to set for the balance. Positive is towards the right.
*/
void setBalanceTowardRight(float value);
+
+ /**
+ * Registers recipient to be notified if AudioControl HAL service dies.
+ * @param deathRecipient to be notified upon HAL service death.
+ */
+ void linkToDeath(@Nullable AudioControlDeathRecipient deathRecipient);
+
+ /**
+ * Unregisters recipient for AudioControl HAL service death.
+ */
+ void unlinkToDeath();
+
+ /**
+ * Recipient to be notified upon death of AudioControl HAL.
+ */
+ interface AudioControlDeathRecipient {
+ /**
+ * Called if AudioControl HAL dies.
+ */
+ void serviceDied();
+ }
}
diff --git a/service/src/com/android/car/audio/hal/AudioControlWrapperV1.java b/service/src/com/android/car/audio/hal/AudioControlWrapperV1.java
index 02b11d3..433b5d5 100644
--- a/service/src/com/android/car/audio/hal/AudioControlWrapperV1.java
+++ b/service/src/com/android/car/audio/hal/AudioControlWrapperV1.java
@@ -35,7 +35,9 @@
*/
public final class AudioControlWrapperV1 implements AudioControlWrapper {
private static final String TAG = AudioControlWrapperV1.class.getSimpleName();
+
private IAudioControl mAudioControlV1;
+ private AudioControlDeathRecipient mDeathRecipient;
/**
* Gets IAudioControl@1.0 service if registered.
@@ -122,4 +124,35 @@
throw new IllegalStateException("Failed to query IAudioControl#getBusForContext", e);
}
}
+
+ @Override
+ public void linkToDeath(@Nullable AudioControlDeathRecipient deathRecipient) {
+ try {
+ mAudioControlV1.linkToDeath(this::serviceDied, 0);
+ mDeathRecipient = deathRecipient;
+ } catch (RemoteException e) {
+ throw new IllegalStateException("Call to IAudioControl@1.0#linkToDeath failed", e);
+ }
+ }
+
+ @Override
+ public void unlinkToDeath() {
+ try {
+ mAudioControlV1.unlinkToDeath(this::serviceDied);
+ mDeathRecipient = null;
+ } catch (RemoteException e) {
+ throw new IllegalStateException("Call to IAudioControl@1.0#unlinkToDeath failed", e);
+ }
+ }
+
+ private void serviceDied(long cookie) {
+ Log.w(TAG, "IAudioControl@1.0 died. Fetching new handle");
+ mAudioControlV1 = AudioControlWrapperV1.getService();
+ linkToDeath(mDeathRecipient);
+ if (mDeathRecipient != null) {
+ mDeathRecipient.serviceDied();
+ }
+ }
+
+
}
diff --git a/service/src/com/android/car/audio/hal/AudioControlWrapperV2.java b/service/src/com/android/car/audio/hal/AudioControlWrapperV2.java
index 6bf9a00..c623c15 100644
--- a/service/src/com/android/car/audio/hal/AudioControlWrapperV2.java
+++ b/service/src/com/android/car/audio/hal/AudioControlWrapperV2.java
@@ -35,6 +35,7 @@
private IAudioControl mAudioControlV2;
+ private AudioControlDeathRecipient mDeathRecipient;
private ICloseHandle mCloseHandle;
public static @Nullable IAudioControl getService() {
@@ -122,4 +123,33 @@
Log.e(TAG, "setBalanceTowardRight failed", e);
}
}
+
+ @Override
+ public void linkToDeath(@Nullable AudioControlDeathRecipient deathRecipient) {
+ try {
+ mAudioControlV2.linkToDeath(this::serviceDied, 0);
+ mDeathRecipient = deathRecipient;
+ } catch (RemoteException e) {
+ throw new IllegalStateException("Call to IAudioControl@2.0#linkToDeath failed", e);
+ }
+ }
+
+ @Override
+ public void unlinkToDeath() {
+ try {
+ mAudioControlV2.unlinkToDeath(this::serviceDied);
+ mDeathRecipient = null;
+ } catch (RemoteException e) {
+ throw new IllegalStateException("Call to IAudioControl@2.0#unlinkToDeath failed", e);
+ }
+ }
+
+ private void serviceDied(long cookie) {
+ Log.w(TAG, "IAudioControl@2.0 died. Fetching new handle");
+ mAudioControlV2 = AudioControlWrapperV2.getService();
+ linkToDeath(mDeathRecipient);
+ if (mDeathRecipient != null) {
+ mDeathRecipient.serviceDied();
+ }
+ }
}