From 2ff302a185c0d7e2b3d003bae70703b1d7c0449d Mon Sep 17 00:00:00 2001 From: Vlad Popa Date: Fri, 10 Jun 2022 00:22:41 +0200 Subject: [PATCH] Associate port id to piid in audio service The implementation reuses the playerEvent callback in the PlaybackActivityMonitor to track events when the portId changes. This can be used to track changes that happen on the lower levels to a track with a given port id and reflect them through the playback notification API. Test: make Bug: 235521198 Change-Id: I5cdf4f47cacc31b2aecffa3029081b01a9e367fd --- .../media/AudioPlaybackConfiguration.java | 12 +- media/java/android/media/IAudioService.aidl | 2 +- .../android/server/audio/AudioService.java | 10 +- .../server/audio/PlaybackActivityMonitor.java | 117 +++++++++++++++--- 4 files changed, 117 insertions(+), 24 deletions(-) diff --git a/media/java/android/media/AudioPlaybackConfiguration.java b/media/java/android/media/AudioPlaybackConfiguration.java index d18d7e4238e2e..457fccf0a24ed 100644 --- a/media/java/android/media/AudioPlaybackConfiguration.java +++ b/media/java/android/media/AudioPlaybackConfiguration.java @@ -167,6 +167,11 @@ public final class AudioPlaybackConfiguration implements Parcelable { * The state used to update device id, does not actually change the state of the player */ public static final int PLAYER_UPDATE_DEVICE_ID = 5; + /** + * @hide + * The state used to update port id, does not actually change the state of the player + */ + public static final int PLAYER_UPDATE_PORT_ID = 6; /** @hide */ @IntDef({ @@ -176,7 +181,8 @@ public final class AudioPlaybackConfiguration implements Parcelable { PLAYER_STATE_STARTED, PLAYER_STATE_PAUSED, PLAYER_STATE_STOPPED, - PLAYER_UPDATE_DEVICE_ID + PLAYER_UPDATE_DEVICE_ID, + PLAYER_UPDATE_PORT_ID, }) @Retention(RetentionPolicy.SOURCE) public @interface PlayerState {} @@ -191,6 +197,7 @@ public final class AudioPlaybackConfiguration implements Parcelable { case PLAYER_STATE_PAUSED: return "PLAYER_STATE_PAUSED"; case PLAYER_STATE_STOPPED: return "PLAYER_STATE_STOPPED"; case PLAYER_UPDATE_DEVICE_ID: return "PLAYER_UPDATE_DEVICE_ID"; + case PLAYER_UPDATE_PORT_ID: return "PLAYER_UPDATE_PORT_ID"; default: return "invalid state " + state; } @@ -669,7 +676,8 @@ public final class AudioPlaybackConfiguration implements Parcelable { case PLAYER_STATE_STARTED: return "started"; case PLAYER_STATE_PAUSED: return "paused"; case PLAYER_STATE_STOPPED: return "stopped"; - case PLAYER_UPDATE_DEVICE_ID: return "device"; + case PLAYER_UPDATE_DEVICE_ID: return "device updated"; + case PLAYER_UPDATE_PORT_ID: return "port updated"; default: return "unknown player state - FIXME"; } diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index f9b043f2525ca..92d81c61ee5a4 100755 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -74,7 +74,7 @@ interface IAudioService { oneway void playerAttributes(in int piid, in AudioAttributes attr); - oneway void playerEvent(in int piid, in int event, in int deviceId); + oneway void playerEvent(in int piid, in int event, in int eventId); oneway void releasePlayer(in int piid); diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 7c02531d54079..46b0dedbab20a 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -550,6 +550,10 @@ public class AudioService extends IAudioService.Stub if (mRecordMonitor != null) { mRecordMonitor.onAudioServerDied(); } + // Notify the playback monitor that the audio server has died + if (mPlaybackMonitor != null) { + mPlaybackMonitor.onAudioServerDied(); + } sendMsg(mAudioHandler, MSG_AUDIO_SERVER_DIED, SENDMSG_NOOP, 0, 0, null, 0); sendMsg(mAudioHandler, MSG_DISPATCH_AUDIO_SERVER_STATE, @@ -11023,10 +11027,10 @@ public class AudioService extends IAudioService.Stub * Update player event * @param piid Player id to update * @param event The new player event - * @param deviceId The new player device id + * @param eventValue The value associated with this event */ - public void playerEvent(int piid, int event, int deviceId) { - mPlaybackMonitor.playerEvent(piid, event, deviceId, Binder.getCallingUid()); + public void playerEvent(int piid, int event, int eventValue) { + mPlaybackMonitor.playerEvent(piid, event, eventValue, Binder.getCallingUid()); } public void playerHasOpPlayAudio(int piid, boolean hasOpPlayAudio) { diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java index b3e7e31d37fc8..02036db4551ec 100644 --- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java +++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java @@ -34,7 +34,9 @@ import android.os.HandlerThread; import android.os.IBinder; import android.os.Message; import android.os.RemoteException; +import android.text.TextUtils; import android.util.Log; +import android.util.SparseIntArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.ArrayUtils; @@ -115,6 +117,9 @@ public final class PlaybackActivityMonitor private final HashMap mPlayers = new HashMap(); + @GuardedBy("mPlayerLock") + private final SparseIntArray mPortIdToPiid = new SparseIntArray(); + private final Context mContext; private int mSavedAlarmVolume = -1; private final int mMaxAlarmVolume; @@ -290,22 +295,29 @@ public final class PlaybackActivityMonitor * Update player event * @param piid Player id to update * @param event The new player event - * @param deviceId The new player device id + * @param eventValue The value associated with this event * @param binderUid Calling binder uid */ - public void playerEvent(int piid, int event, int deviceId, int binderUid) { + public void playerEvent(int piid, int event, int eventValue, int binderUid) { if (DEBUG) { - Log.v(TAG, String.format("playerEvent(piid=%d, deviceId=%d, event=%s)", - piid, deviceId, AudioPlaybackConfiguration.playerStateToString(event))); + Log.v(TAG, TextUtils.formatSimple("playerEvent(piid=%d, event=%s, eventValue=%d)", + piid, AudioPlaybackConfiguration.playerStateToString(event), eventValue)); } + final boolean change; synchronized(mPlayerLock) { final AudioPlaybackConfiguration apc = mPlayers.get(new Integer(piid)); if (apc == null) { return; } - sEventLogger.log(new PlayerEvent(piid, event, deviceId)); - if (event == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) { + + sEventLogger.log(new PlayerEvent(piid, event, eventValue)); + + if (event == AudioPlaybackConfiguration.PLAYER_UPDATE_PORT_ID) { + mEventHandler.sendMessage( + mEventHandler.obtainMessage(MSG_L_UPDATE_PORT_EVENT, eventValue, piid)); + return; + } else if (event == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) { for (Integer uidInteger: mBannedUids) { if (checkBanPlayer(apc, uidInteger.intValue())) { // player was banned, do not update its state @@ -322,7 +334,7 @@ public final class PlaybackActivityMonitor if (checkConfigurationCaller(piid, apc, binderUid)) { //TODO add generation counter to only update to the latest state checkVolumeForPrivilegedAlarm(apc, event); - change = apc.handleStateEvent(event, deviceId); + change = apc.handleStateEvent(event, eventValue); } else { Log.e(TAG, "Error handling event " + event); change = false; @@ -357,6 +369,11 @@ public final class PlaybackActivityMonitor checkVolumeForPrivilegedAlarm(apc, AudioPlaybackConfiguration.PLAYER_STATE_RELEASED); change = apc.handleStateEvent(AudioPlaybackConfiguration.PLAYER_STATE_RELEASED, AudioPlaybackConfiguration.PLAYER_DEVICEID_INVALID); + + // remove all port ids mapped to the released player + mEventHandler.sendMessage( + mEventHandler.obtainMessage(MSG_L_CLEAR_PORTS_FOR_PIID, piid, /*arg2=*/0)); + } } if (change) { @@ -364,6 +381,18 @@ public final class PlaybackActivityMonitor } } + /*package*/ void onAudioServerDied() { + sEventLogger.log( + new AudioEventLogger.StringEvent( + "clear port id to piid map")); + synchronized (mPlayerLock) { + if (DEBUG) { + Log.v(TAG, "clear port id to piid map:\n" + mPortIdToPiid); + } + mPortIdToPiid.clear(); + } + } + /** * A map of uid to capture policy. */ @@ -499,9 +528,18 @@ public final class PlaybackActivityMonitor pw.print(" " + piid); } pw.println("\n"); + // portId to piid mappings: + pw.println("\n current portId to piid map:"); + for (int i = 0; i < mPortIdToPiid.size(); ++i) { + pw.println( + " portId: " + mPortIdToPiid.keyAt(i) + " piid: " + mPortIdToPiid.valueAt( + i)); + } + pw.println("\n"); // log sEventLogger.dump(pw); } + synchronized (mAllowedCapturePolicies) { pw.println("\n allowed capture policies:"); for (HashMap.Entry entry : mAllowedCapturePolicies.entrySet()) { @@ -1010,27 +1048,36 @@ public final class PlaybackActivityMonitor //================================================================= // For logging - private final static class PlayerEvent extends AudioEventLogger.Event { + private static final class PlayerEvent extends AudioEventLogger.Event { // only keeping the player interface ID as it uniquely identifies the player in the event final int mPlayerIId; - final int mState; - final int mDeviceId; + final int mEvent; + final int mEventValue; - PlayerEvent(int piid, int state, int deviceId) { + PlayerEvent(int piid, int event, int eventValue) { mPlayerIId = piid; - mState = state; - mDeviceId = deviceId; + mEvent = event; + mEventValue = eventValue; } @Override public String eventToString() { - return new StringBuilder("player piid:").append(mPlayerIId).append(" state:") - .append(AudioPlaybackConfiguration.toLogFriendlyPlayerState(mState)) - .append(" DeviceId:").append(mDeviceId).toString(); + if (mEvent == AudioPlaybackConfiguration.PLAYER_UPDATE_PORT_ID) { + return AudioPlaybackConfiguration.toLogFriendlyPlayerState(mEvent) + " portId:" + + mEventValue + " mapped to player piid:" + mPlayerIId; + } + + StringBuilder builder = new StringBuilder("player piid:").append(mPlayerIId).append( + " state:") + .append(AudioPlaybackConfiguration.toLogFriendlyPlayerState(mEvent)); + if (mEventValue != 0) { + builder.append(" DeviceId:").append(mEventValue); + } + return builder.toString(); } } - private final static class PlayerOpPlayAudioEvent extends AudioEventLogger.Event { + private static final class PlayerOpPlayAudioEvent extends AudioEventLogger.Event { // only keeping the player interface ID as it uniquely identifies the player in the event final int mPlayerIId; final boolean mHasOp; @@ -1050,7 +1097,7 @@ public final class PlaybackActivityMonitor } } - private final static class NewPlayerEvent extends AudioEventLogger.Event { + private static final class NewPlayerEvent extends AudioEventLogger.Event { private final int mPlayerIId; private final int mPlayerType; private final int mClientUid; @@ -1267,6 +1314,21 @@ public final class PlaybackActivityMonitor */ private static final int MSG_L_TIMEOUT_MUTE_AWAIT_CONNECTION = 1; + /** + * assign new port id to piid + * args: + * msg.arg1: port id + * msg.arg2: piid + */ + private static final int MSG_L_UPDATE_PORT_EVENT = 2; + + /** + * clear all ports assigned to a given piid + * args: + * msg.arg1: the piid + */ + private static final int MSG_L_CLEAR_PORTS_FOR_PIID = 3; + private void initEventHandler() { mEventThread = new HandlerThread(TAG); mEventThread.start(); @@ -1282,6 +1344,25 @@ public final class PlaybackActivityMonitor } mMuteAwaitConnectionTimeoutCb.accept((AudioDeviceAttributes) msg.obj); break; + case MSG_L_UPDATE_PORT_EVENT: + synchronized (mPlayerLock) { + mPortIdToPiid.put(/*portId*/msg.arg1, /*piid*/msg.arg2); + } + break; + case MSG_L_CLEAR_PORTS_FOR_PIID: + int piid = msg.arg1; + if (piid == AudioPlaybackConfiguration.PLAYER_PIID_INVALID) { + Log.w(TAG, "Received clear ports with invalid piid"); + break; + } + + synchronized (mPlayerLock) { + int portIdx; + while ((portIdx = mPortIdToPiid.indexOfValue(piid)) >= 0) { + mPortIdToPiid.removeAt(portIdx); + } + } + break; default: break; }