DO NOT MERGE: Fix system_server watchdog timeout
AudioPlayerStateMonitor can't implement IPlaybackConfigDispatcher.Stub
directly, instead it needs to go through AudioManager to prevent
potential deadlock.
Bug: 124415216
Test: build
Change-Id: Id2ef99ed6271ceb63a27f895a6c08f79d60ba7eb
diff --git a/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java b/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java
index 648c782..603d7cf 100644
--- a/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java
+++ b/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java
@@ -18,14 +18,11 @@
import android.annotation.NonNull;
import android.content.Context;
+import android.media.AudioManager;
import android.media.AudioPlaybackConfiguration;
-import android.media.IAudioService;
-import android.media.IPlaybackConfigDispatcher;
-import android.os.Binder;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
-import android.os.RemoteException;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -42,11 +39,11 @@
/**
* Monitors the state changes of audio players.
*/
-class AudioPlayerStateMonitor extends IPlaybackConfigDispatcher.Stub {
+class AudioPlayerStateMonitor {
private static boolean DEBUG = MediaSessionService.DEBUG;
private static String TAG = "AudioPlayerStateMonitor";
- private static AudioPlayerStateMonitor sInstance = new AudioPlayerStateMonitor();
+ private static AudioPlayerStateMonitor sInstance;
/**
* Listener for handling the active state changes of audio players.
@@ -96,96 +93,33 @@
private final Map<OnAudioPlayerActiveStateChangedListener, MessageHandler> mListenerMap =
new ArrayMap<>();
@GuardedBy("mLock")
- private final Set<Integer> mActiveAudioUids = new ArraySet<>();
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ final Set<Integer> mActiveAudioUids = new ArraySet<>();
@GuardedBy("mLock")
- private ArrayMap<Integer, AudioPlaybackConfiguration> mPrevActiveAudioPlaybackConfigs =
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ ArrayMap<Integer, AudioPlaybackConfiguration> mPrevActiveAudioPlaybackConfigs =
new ArrayMap<>();
// Sorted array of UIDs that had active audio playback. (i.e. playing an audio/video)
// The UID whose audio playback becomes active at the last comes first.
// TODO(b/35278867): Find and use unique identifier for apps because apps may share the UID.
@GuardedBy("mLock")
- private final IntArray mSortedAudioPlaybackClientUids = new IntArray();
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ final IntArray mSortedAudioPlaybackClientUids = new IntArray();
- @GuardedBy("mLock")
- private boolean mRegisteredToAudioService;
-
- static AudioPlayerStateMonitor getInstance() {
- return sInstance;
- }
-
- private AudioPlayerStateMonitor() {
- }
-
- /**
- * Called when the {@link AudioPlaybackConfiguration} is updated.
- * <p>If an app starts audio playback, the app's local media session will be the media button
- * session. If the app has multiple media sessions, the playback active local session will be
- * picked.
- *
- * @param configs List of the current audio playback configuration
- */
- @Override
- public void dispatchPlaybackConfigChange(List<AudioPlaybackConfiguration> configs,
- boolean flush) {
- if (flush) {
- Binder.flushPendingCommands();
- }
- final long token = Binder.clearCallingIdentity();
- try {
- synchronized (mLock) {
- // Update mActiveAudioUids
- mActiveAudioUids.clear();
- ArrayMap<Integer, AudioPlaybackConfiguration> activeAudioPlaybackConfigs =
- new ArrayMap<>();
- for (AudioPlaybackConfiguration config : configs) {
- if (config.isActive()) {
- mActiveAudioUids.add(config.getClientUid());
- activeAudioPlaybackConfigs.put(config.getPlayerInterfaceId(), config);
- }
- }
-
- // Update mSortedAuioPlaybackClientUids.
- for (int i = 0; i < activeAudioPlaybackConfigs.size(); ++i) {
- AudioPlaybackConfiguration config = activeAudioPlaybackConfigs.valueAt(i);
- final int uid = config.getClientUid();
- if (!mPrevActiveAudioPlaybackConfigs.containsKey(
- config.getPlayerInterfaceId())) {
- if (DEBUG) {
- Log.d(TAG, "Found a new active media playback. " +
- AudioPlaybackConfiguration.toLogFriendlyString(config));
- }
- // New active audio playback.
- int index = mSortedAudioPlaybackClientUids.indexOf(uid);
- if (index == 0) {
- // It's the lastly played music app already. Skip updating.
- continue;
- } else if (index > 0) {
- mSortedAudioPlaybackClientUids.remove(index);
- }
- mSortedAudioPlaybackClientUids.add(0, uid);
- }
- }
- // Notify the active state change of audio players.
- for (AudioPlaybackConfiguration config : configs) {
- final int pii = config.getPlayerInterfaceId();
- boolean wasActive = mPrevActiveAudioPlaybackConfigs.remove(pii) != null;
- if (wasActive != config.isActive()) {
- sendAudioPlayerActiveStateChangedMessageLocked(
- config, /* isRemoved */ false);
- }
- }
- for (AudioPlaybackConfiguration config : mPrevActiveAudioPlaybackConfigs.values()) {
- sendAudioPlayerActiveStateChangedMessageLocked(config, /* isRemoved */ true);
- }
-
- // Update mPrevActiveAudioPlaybackConfigs
- mPrevActiveAudioPlaybackConfigs = activeAudioPlaybackConfigs;
+ static AudioPlayerStateMonitor getInstance(Context context) {
+ synchronized (AudioPlayerStateMonitor.class) {
+ if (sInstance == null) {
+ sInstance = new AudioPlayerStateMonitor(context);
}
- } finally {
- Binder.restoreCallingIdentity(token);
+ return sInstance;
}
}
+ private AudioPlayerStateMonitor(Context context) {
+ AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ am.registerAudioPlaybackCallback(new AudioManagerPlaybackListener(), null);
+ }
+
/**
* Registers OnAudioPlayerActiveStateChangedListener.
*/
@@ -275,20 +209,6 @@
}
}
- public void registerSelfIntoAudioServiceIfNeeded(IAudioService audioService) {
- synchronized (mLock) {
- try {
- if (!mRegisteredToAudioService) {
- audioService.registerPlaybackCallback(this);
- mRegisteredToAudioService = true;
- }
- } catch (RemoteException e) {
- Log.wtf(TAG, "Failed to register playback callback", e);
- mRegisteredToAudioService = false;
- }
- }
- }
-
@GuardedBy("mLock")
private void sendAudioPlayerActiveStateChangedMessageLocked(
final AudioPlaybackConfiguration config, final boolean isRemoved) {
@@ -296,4 +216,59 @@
messageHandler.sendAudioPlayerActiveStateChangedMessage(config, isRemoved);
}
}
+
+ private class AudioManagerPlaybackListener extends AudioManager.AudioPlaybackCallback {
+ @Override
+ public void onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs) {
+ synchronized (mLock) {
+ // Update mActiveAudioUids
+ mActiveAudioUids.clear();
+ ArrayMap<Integer, AudioPlaybackConfiguration> activeAudioPlaybackConfigs =
+ new ArrayMap<>();
+ for (AudioPlaybackConfiguration config : configs) {
+ if (config.isActive()) {
+ mActiveAudioUids.add(config.getClientUid());
+ activeAudioPlaybackConfigs.put(config.getPlayerInterfaceId(), config);
+ }
+ }
+
+ // Update mSortedAuioPlaybackClientUids.
+ for (int i = 0; i < activeAudioPlaybackConfigs.size(); ++i) {
+ AudioPlaybackConfiguration config = activeAudioPlaybackConfigs.valueAt(i);
+ final int uid = config.getClientUid();
+ if (!mPrevActiveAudioPlaybackConfigs.containsKey(
+ config.getPlayerInterfaceId())) {
+ if (DEBUG) {
+ Log.d(TAG, "Found a new active media playback. "
+ + AudioPlaybackConfiguration.toLogFriendlyString(config));
+ }
+ // New active audio playback.
+ int index = mSortedAudioPlaybackClientUids.indexOf(uid);
+ if (index == 0) {
+ // It's the lastly played music app already. Skip updating.
+ continue;
+ } else if (index > 0) {
+ mSortedAudioPlaybackClientUids.remove(index);
+ }
+ mSortedAudioPlaybackClientUids.add(0, uid);
+ }
+ }
+ // Notify the active state change of audio players.
+ for (AudioPlaybackConfiguration config : configs) {
+ final int pii = config.getPlayerInterfaceId();
+ boolean wasActive = mPrevActiveAudioPlaybackConfigs.remove(pii) != null;
+ if (wasActive != config.isActive()) {
+ sendAudioPlayerActiveStateChangedMessageLocked(
+ config, /* isRemoved */ false);
+ }
+ }
+ for (AudioPlaybackConfiguration config : mPrevActiveAudioPlaybackConfigs.values()) {
+ sendAudioPlayerActiveStateChangedMessageLocked(config, /* isRemoved */ true);
+ }
+
+ // Update mPrevActiveAudioPlaybackConfigs
+ mPrevActiveAudioPlaybackConfigs = activeAudioPlaybackConfigs;
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
index a7df0e2..47f2270 100644
--- a/services/core/java/com/android/server/media/MediaRouterService.java
+++ b/services/core/java/com/android/server/media/MediaRouterService.java
@@ -16,14 +16,10 @@
package com.android.server.media;
-import com.android.internal.util.DumpUtils;
-import com.android.server.Watchdog;
-
import android.annotation.NonNull;
import android.app.ActivityManager;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothProfile;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -57,6 +53,9 @@
import android.util.SparseArray;
import android.util.TimeUtils;
+import com.android.internal.util.DumpUtils;
+import com.android.server.Watchdog;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -115,7 +114,7 @@
mAudioService = IAudioService.Stub.asInterface(
ServiceManager.getService(Context.AUDIO_SERVICE));
- mAudioPlayerStateMonitor = AudioPlayerStateMonitor.getInstance();
+ mAudioPlayerStateMonitor = AudioPlayerStateMonitor.getInstance(context);
mAudioPlayerStateMonitor.registerListener(
new AudioPlayerStateMonitor.OnAudioPlayerActiveStateChangedListener() {
static final long WAIT_MS = 500;
@@ -166,7 +165,6 @@
}
}
}, mHandler);
- mAudioPlayerStateMonitor.registerSelfIntoAudioServiceIfNeeded(mAudioService);
AudioRoutesInfo audioRoutes = null;
try {
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 68b2a58..67f605c 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -93,8 +93,8 @@
import java.util.HashSet;
import java.util.List;
import java.util.Map;
-import java.util.Set;
import java.util.NoSuchElementException;
+import java.util.Set;
/**
* System implementation of MediaSessionManager
@@ -164,7 +164,7 @@
mKeyguardManager =
(KeyguardManager) getContext().getSystemService(Context.KEYGUARD_SERVICE);
mAudioService = getAudioService();
- mAudioPlayerStateMonitor = AudioPlayerStateMonitor.getInstance();
+ mAudioPlayerStateMonitor = AudioPlayerStateMonitor.getInstance(getContext());
mAudioPlayerStateMonitor.registerListener(
(config, isRemoved) -> {
if (isRemoved || !config.isActive() || config.getPlayerType()
@@ -179,7 +179,6 @@
}
}
}, null /* handler */);
- mAudioPlayerStateMonitor.registerSelfIntoAudioServiceIfNeeded(mAudioService);
mContentResolver = getContext().getContentResolver();
mSettingsObserver = new SettingsObserver();
mSettingsObserver.observe();