From d497edd97936fefc2ad472c05dc920947c588ec4 Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Tue, 22 Oct 2019 08:59:36 -0700 Subject: [PATCH] AudioService: handle errors when reconnecting mixes after server crash Log errors when reconnecting dynamic policy mixes after an audio server crash. Add IntDef for AudioSystem errors, and conversion to String. Add support for notifying an AudioPolicy user that it was unregistered. Bug: 133279309 Test: connect DAP, kill audio server, verify no errors reported Change-Id: I1dbfdac1873ed9c44c20ca9d25bbe01ce9904ee5 Merged-In: I1dbfdac1873ed9c44c20ca9d25bbe01ce9904ee5 --- media/java/android/media/AudioSystem.java | 47 +++++++++++++++++++ .../media/audiopolicy/AudioPolicy.java | 4 ++ .../audiopolicy/IAudioPolicyCallback.aidl | 4 ++ .../android/server/audio/AudioService.java | 34 +++++++++----- 4 files changed, 77 insertions(+), 12 deletions(-) diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index 53bc65d711b0d..bb731a8189f96 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -16,6 +16,7 @@ package android.media; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; @@ -26,6 +27,8 @@ import android.media.audiofx.AudioEffect; import android.media.audiopolicy.AudioMix; import android.util.Log; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Map; @@ -431,6 +434,50 @@ public class AudioSystem public static final int DEAD_OBJECT = -6; public static final int WOULD_BLOCK = -7; + /** @hide */ + @IntDef({ + SUCCESS, + ERROR, + BAD_VALUE, + INVALID_OPERATION, + PERMISSION_DENIED, + NO_INIT, + DEAD_OBJECT, + WOULD_BLOCK + }) + @Retention(RetentionPolicy.SOURCE) + public @interface AudioSystemError {} + + /** + * Convert an int error value to its String value for readability. + * Accepted error values are the java AudioSystem errors, matching android_media_AudioErrors.h, + * which map onto the native status_t type. + * @param error one of the java AudioSystem errors + * @return a human-readable string + */ + public static String audioSystemErrorToString(@AudioSystemError int error) { + switch(error) { + case SUCCESS: + return "SUCCESS"; + case ERROR: + return "ERROR"; + case BAD_VALUE: + return "BAD_VALUE"; + case INVALID_OPERATION: + return "INVALID_OPERATION"; + case PERMISSION_DENIED: + return "PERMISSION_DENIED"; + case NO_INIT: + return "NO_INIT"; + case DEAD_OBJECT: + return "DEAD_OBJECT"; + case WOULD_BLOCK: + return "WOULD_BLOCK"; + default: + return ("unknown error:" + error); + } + } + /* * AudioPolicyService methods */ diff --git a/media/java/android/media/audiopolicy/AudioPolicy.java b/media/java/android/media/audiopolicy/AudioPolicy.java index 39474e13a2d00..01f12500b77be 100644 --- a/media/java/android/media/audiopolicy/AudioPolicy.java +++ b/media/java/android/media/audiopolicy/AudioPolicy.java @@ -853,6 +853,10 @@ public class AudioPolicy { Log.v(TAG, "notifyVolumeAdjust: " + adjustment); } } + + public void notifyUnregistration() { + setRegistration(null); + } }; //================================================== diff --git a/media/java/android/media/audiopolicy/IAudioPolicyCallback.aidl b/media/java/android/media/audiopolicy/IAudioPolicyCallback.aidl index 107e7cd59ca25..1d581516e7b11 100644 --- a/media/java/android/media/audiopolicy/IAudioPolicyCallback.aidl +++ b/media/java/android/media/audiopolicy/IAudioPolicyCallback.aidl @@ -34,4 +34,8 @@ oneway interface IAudioPolicyCallback { // callback for volume events void notifyVolumeAdjust(int adjustment); + + // callback for unregistration (e.g. if policy couldn't automatically be re-registered after + // an audioserver crash) + void notifyUnregistration(); } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index e26cbc4487f90..055a4bde8a784 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -1018,7 +1018,14 @@ public class AudioService extends IAudioService.Stub synchronized (mAudioPolicies) { for (AudioPolicyProxy policy : mAudioPolicies.values()) { - policy.connectMixes(); + final int status = policy.connectMixes(); + if (status != AudioSystem.SUCCESS) { + // note that PERMISSION_DENIED may also indicate trouble getting to APService + Log.e(TAG, "onAudioServerDied: error " + + AudioSystem.audioSystemErrorToString(status) + + " when connecting mixes for policy " + policy.toLogFriendlyString()); + policy.release(); + } } } @@ -7007,16 +7014,8 @@ public class AudioService extends IAudioService.Stub } public void binderDied() { - synchronized (mAudioPolicies) { - Log.i(TAG, "audio policy " + mPolicyCallback + " died"); - release(); - mAudioPolicies.remove(mPolicyCallback.asBinder()); - } - if (mIsVolumeController) { - synchronized (mExtVolumeControllerLock) { - mExtVolumeController = null; - } - } + Log.i(TAG, "audio policy " + mPolicyCallback + " died"); + release(); } String getRegistrationId() { @@ -7040,9 +7039,20 @@ public class AudioService extends IAudioService.Stub Log.e(TAG, "Fail to unregister Audiopolicy callback from MediaProjection"); } } + if (mIsVolumeController) { + synchronized (mExtVolumeControllerLock) { + mExtVolumeController = null; + } + } final long identity = Binder.clearCallingIdentity(); AudioSystem.registerPolicyMixes(mMixes, false); Binder.restoreCallingIdentity(identity); + synchronized (mAudioPolicies) { + mAudioPolicies.remove(mPolicyCallback.asBinder()); + } + try { + mPolicyCallback.notifyUnregistration(); + } catch (RemoteException e) { } } boolean hasMixAffectingUsage(int usage, int excludedFlags) { @@ -7093,7 +7103,7 @@ public class AudioService extends IAudioService.Stub } } - int connectMixes() { + @AudioSystem.AudioSystemError int connectMixes() { final long identity = Binder.clearCallingIdentity(); int status = AudioSystem.registerPolicyMixes(mMixes, true); Binder.restoreCallingIdentity(identity);