diff options
| author | 2011-08-24 18:41:55 -0700 | |
|---|---|---|
| committer | 2011-08-24 19:08:48 -0700 | |
| commit | 3094d955b8321f01e50cb0c448ae1c4c461f41c9 (patch) | |
| tree | 347b624f7b46cb4425a1c810cb78cdcdedce6ef1 | |
| parent | 4b6df6a3dcbd9990e36438c529fa8c16b2580df9 (diff) | |
Fix deadlock in AudioService
Locks related to audio focus and remote control should always be
taken in the following order:
1/ audio focus lock
2/ remote control stack
3/ current remote control client generation
Change-Id: If8be11bfef92849957e692b2bd52adbd67a2ef0b
| -rw-r--r-- | media/java/android/media/AudioService.java | 80 |
1 files changed, 41 insertions, 39 deletions
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index a87629188108..fe57e8acb751 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -3072,7 +3072,7 @@ public class AudioService extends IAudioService.Stub { /** * Update the remote control displays with the new "focused" client generation */ - private void setNewRcClientOnDisplays_syncRcStack(int newClientGeneration, + private void setNewRcClientOnDisplays_syncAfRcsCurrc(int newClientGeneration, ComponentName newClientEventReceiver, boolean clearing) { // NOTE: Only one IRemoteControlDisplay supported in this implementation if (mRcDisplay != null) { @@ -3091,7 +3091,7 @@ public class AudioService extends IAudioService.Stub { /** * Update the remote control clients with the new "focused" client generation */ - private void setNewRcClientGenerationOnClients_syncRcStack(int newClientGeneration) { + private void setNewRcClientGenerationOnClients_syncAfRcsCurrc(int newClientGeneration) { Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); while(stackIterator.hasNext()) { RemoteControlStackEntry se = stackIterator.next(); @@ -3115,15 +3115,13 @@ public class AudioService extends IAudioService.Stub { * @param clearing true if the new client generation value maps to a remote control update * where the display should be cleared. */ - private void setNewRcClient(int newClientGeneration, ComponentName newClientEventReceiver, - boolean clearing) { - synchronized(mRCStack) { - // send the new valid client generation ID to all displays - setNewRcClientOnDisplays_syncRcStack(newClientGeneration, newClientEventReceiver, - clearing); - // send the new valid client generation ID to all clients - setNewRcClientGenerationOnClients_syncRcStack(newClientGeneration); - } + private void setNewRcClient_syncAfRcsCurrc(int newClientGeneration, + ComponentName newClientEventReceiver, boolean clearing) { + // send the new valid client generation ID to all displays + setNewRcClientOnDisplays_syncAfRcsCurrc(newClientGeneration, newClientEventReceiver, + clearing); + // send the new valid client generation ID to all clients + setNewRcClientGenerationOnClients_syncAfRcsCurrc(newClientGeneration); } /** @@ -3133,11 +3131,13 @@ public class AudioService extends IAudioService.Stub { // TODO remove log before release Log.i(TAG, "Clear remote control display"); - synchronized(mCurrentRcLock) { - mCurrentRcClientGen++; - - // synchronously update the displays and clients with the new client generation - setNewRcClient(mCurrentRcClientGen, null /*event receiver*/, true /*clearing*/); + synchronized(mRCStack) { + synchronized(mCurrentRcLock) { + mCurrentRcClientGen++; + // synchronously update the displays and clients with the new client generation + setNewRcClient_syncAfRcsCurrc(mCurrentRcClientGen, + null /*event receiver*/, true /*clearing*/); + } } } @@ -3145,30 +3145,32 @@ public class AudioService extends IAudioService.Stub { * Called when processing MSG_RCDISPLAY_UPDATE event */ private void onRcDisplayUpdate(RemoteControlStackEntry rcse, int flags /* USED ?*/) { - synchronized(mCurrentRcLock) { - if ((mCurrentRcClient != null) && (mCurrentRcClient.equals(rcse.mRcClient))) { - // TODO remove log before release - Log.i(TAG, "Display/update remote control "); - - mCurrentRcClientGen++; - - // synchronously update the displays and clients with the new client generation - setNewRcClient(mCurrentRcClientGen, - rcse.mReceiverComponent /*event receiver*/, - false /*clearing*/); - - // ask the current client that it needs to send info - try { - mCurrentRcClient.onInformationRequested(mCurrentRcClientGen, - flags, mArtworkExpectedWidth, mArtworkExpectedHeight); - } catch (RemoteException e) { - Log.e(TAG, "Current valid remote client is dead: "+e); - mCurrentRcClient = null; + synchronized(mRCStack) { + synchronized(mCurrentRcLock) { + if ((mCurrentRcClient != null) && (mCurrentRcClient.equals(rcse.mRcClient))) { + // TODO remove log before release + Log.i(TAG, "Display/update remote control "); + + mCurrentRcClientGen++; + // synchronously update the displays and clients with + // the new client generation + setNewRcClient_syncAfRcsCurrc(mCurrentRcClientGen, + rcse.mReceiverComponent /*event receiver*/, + false /*clearing*/); + + // ask the current client that it needs to send info + try { + mCurrentRcClient.onInformationRequested(mCurrentRcClientGen, + flags, mArtworkExpectedWidth, mArtworkExpectedHeight); + } catch (RemoteException e) { + Log.e(TAG, "Current valid remote client is dead: "+e); + mCurrentRcClient = null; + } + } else { + // the remote control display owner has changed between the + // the message to update the display was sent, and the time it + // gets to be processed (now) } - } else { - // the remote control display owner has changed between the - // the message to update the display was sent, and the time it - // gets to be processed (now) } } } |