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
This commit is contained in:
@@ -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
|
||||
*/
|
||||
|
||||
@@ -853,6 +853,10 @@ public class AudioPolicy {
|
||||
Log.v(TAG, "notifyVolumeAdjust: " + adjustment);
|
||||
}
|
||||
}
|
||||
|
||||
public void notifyUnregistration() {
|
||||
setRegistration(null);
|
||||
}
|
||||
};
|
||||
|
||||
//==================================================
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user