Merge "AudioService: internal API for disabling audio playback for a UID" into oc-dr1-dev
diff --git a/media/java/android/media/AudioManagerInternal.java b/media/java/android/media/AudioManagerInternal.java
index 0a1de33..2b5ac5e 100644
--- a/media/java/android/media/AudioManagerInternal.java
+++ b/media/java/android/media/AudioManagerInternal.java
@@ -59,4 +59,15 @@
int getRingerModeAffectedStreams(int streams);
}
+
+ /**
+ * Disable or restore the ability to play audio for a given UID.
+ * When a UID isn't meant to be tracked anymore (e.g. client died), re-enable audio for this UID
+ * to prevent disabling audio for future UIDs that would reuse the same value.
+ * This operation is asynchronous.
+ * @param disable when true, prevents playback of audio streams from the given uid. If false,
+ * restores the ability to play, or no-op if playback hadn't been disabled before.
+ * @param uid the client UID whose ability to play will be affected.
+ */
+ public abstract void disableAudioForUid(boolean disable, int uid);
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index e5ab784..2199bba 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -239,6 +239,7 @@
private static final int MSG_SET_A2DP_SRC_CONNECTION_STATE = 101;
private static final int MSG_SET_A2DP_SINK_CONNECTION_STATE = 102;
private static final int MSG_A2DP_DEVICE_CONFIG_CHANGE = 103;
+ private static final int MSG_DISABLE_AUDIO_FOR_UID = 104;
// end of messages handled under wakelock
private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
@@ -4871,6 +4872,12 @@
mAudioEventWakeLock.release();
break;
+ case MSG_DISABLE_AUDIO_FOR_UID:
+ mPlaybackMonitor.disableAudioForUid( msg.arg1 == 1 /* disable */,
+ msg.arg2 /* uid */);
+ mAudioEventWakeLock.release();
+ break;
+
case MSG_REPORT_NEW_ROUTES: {
int N = mRoutesObservers.beginBroadcast();
if (N > 0) {
@@ -6591,6 +6598,13 @@
}
}
}
+
+ @Override
+ public void disableAudioForUid(boolean disable, int uid) {
+ queueMsgUnderWakeLock(mAudioHandler, MSG_DISABLE_AUDIO_FOR_UID,
+ disable ? 1 : 0 /* arg1 */, uid /* arg2 */,
+ null /* obj */, 0 /* delay */);
+ }
}
//==========================================================================================
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index f9e4d94..663559f 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -95,6 +95,43 @@
}
//=================================================================
+ private final ArrayList<Integer> mBannedUids = new ArrayList<Integer>();
+
+ // see AudioManagerInternal.disableAudioForUid(boolean disable, int uid)
+ public void disableAudioForUid(boolean disable, int uid) {
+ synchronized(mPlayerLock) {
+ final int index = mBannedUids.indexOf(new Integer(uid));
+ if (index >= 0) {
+ if (!disable) {
+ mBannedUids.remove(index);
+ // nothing else to do, future playback requests from this uid are ok
+ } // no else to handle, uid already present, so disabling again is no-op
+ } else {
+ if (disable) {
+ for (AudioPlaybackConfiguration apc : mPlayers.values()) {
+ checkBanPlayer(apc, uid);
+ }
+ mBannedUids.add(new Integer(uid));
+ } // no else to handle, uid already not in list, so enabling again is no-op
+ }
+ }
+ }
+
+ private boolean checkBanPlayer(@NonNull AudioPlaybackConfiguration apc, int uid) {
+ final boolean toBan = (apc.getClientUid() == uid);
+ if (toBan) {
+ final int piid = apc.getPlayerInterfaceId();
+ try {
+ Log.v(TAG, "banning player " + piid + " uid:" + uid);
+ apc.getPlayerProxy().pause();
+ } catch (Exception e) {
+ Log.e(TAG, "error banning player " + piid + " uid:" + uid, e);
+ }
+ }
+ return toBan;
+ }
+
+ //=================================================================
// Track players and their states
// methods playerAttributes, playerEvent, releasePlayer are all oneway calls
// into AudioService. They trigger synchronous dispatchPlaybackChange() which updates
@@ -137,6 +174,14 @@
if (apc == null) {
return;
}
+ if (event == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
+ for (Integer uidInteger: mBannedUids) {
+ if (checkBanPlayer(apc, uidInteger.intValue())) {
+ // player was banned, do not update its state
+ return;
+ }
+ }
+ }
if (apc.getPlayerType() == AudioPlaybackConfiguration.PLAYER_TYPE_JAM_SOUNDPOOL) {
// FIXME SoundPool not ready for state reporting
return;
@@ -186,10 +231,17 @@
pw.println("\n ducked players:");
mDuckingManager.dump(pw);
// players muted due to the device ringing or being in a call
- pw.println("\n muted player piids:");
+ pw.print("\n muted player piids:");
for (int piid : mMutedPlayers) {
- pw.println(" " + piid);
+ pw.print(" " + piid);
}
+ pw.println();
+ // banned players:
+ pw.print("\n banned uids:");
+ for (int uid : mBannedUids) {
+ pw.print(" " + uid);
+ }
+ pw.println();
}
}