OSDN Git Service

Fix system_server watchdog timeout
authorSungsoo Lim <sungsoo@google.com>
Wed, 3 Apr 2019 17:19:52 +0000 (02:19 +0900)
committerSungsoo Lim <sungsoo@google.com>
Thu, 4 Apr 2019 15:21:37 +0000 (15:21 +0000)
AudioPlayerStateMonitor can't implement IPlaybackConfigDispatcher.Stub
directly, instead it needs to go through AudioManager to prevent
potential deadlock.

Bug: 124415216
Test: build
Change-Id: I8b0c8aba9705fa83d6c2dbd005b9e464f661f862

services/core/java/com/android/server/media/AudioPlayerStateMonitor.java
services/core/java/com/android/server/media/MediaRouterService.java
services/core/java/com/android/server/media/MediaSessionServiceImpl.java

index 648c782..603d7cf 100644 (file)
@@ -18,14 +18,11 @@ package com.android.server.media;
 
 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 @@ import java.util.Set;
 /**
  * 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 @@ class AudioPlayerStateMonitor extends IPlaybackConfigDispatcher.Stub {
     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 @@ class AudioPlayerStateMonitor extends IPlaybackConfigDispatcher.Stub {
         }
     }
 
-    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 @@ class AudioPlayerStateMonitor extends IPlaybackConfigDispatcher.Stub {
             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;
+            }
+        }
+    }
 }
index f822e82..a43533f 100644 (file)
@@ -117,7 +117,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub
 
         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;
@@ -168,7 +168,6 @@ public final class MediaRouterService extends IMediaRouterService.Stub
                 }
             }
         }, mHandler);
-        mAudioPlayerStateMonitor.registerSelfIntoAudioServiceIfNeeded(mAudioService);
 
         AudioRoutesInfo audioRoutes = null;
         try {
index 3acad7a..0cabf1d 100644 (file)
@@ -168,7 +168,7 @@ public class MediaSessionServiceImpl extends MediaSessionService.ServiceImpl {
         mAudioManagerInternal = LocalServices.getService(AudioManagerInternal.class);
         mActivityManager =
                 (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
-        mAudioPlayerStateMonitor = AudioPlayerStateMonitor.getInstance();
+        mAudioPlayerStateMonitor = AudioPlayerStateMonitor.getInstance(mContext);
         mAudioPlayerStateMonitor.registerListener(
                 (config, isRemoved) -> {
                     if (isRemoved || !config.isActive() || config.getPlayerType()
@@ -183,7 +183,6 @@ public class MediaSessionServiceImpl extends MediaSessionService.ServiceImpl {
                         }
                     }
                 }, null /* handler */);
-        mAudioPlayerStateMonitor.registerSelfIntoAudioServiceIfNeeded(mAudioService);
         mContentResolver = mContext.getContentResolver();
         mSettingsObserver = new SettingsObserver();
         mSettingsObserver.observe();