Skip to content

Commit b716f0b

Browse files
committed
Fix 5243349 RemoteControlDisplay incorrectly updated
This fixes a case where the RCD would display transport control for a RemoteControlClient that didn't have audio focus. This was happening because registering an RCD was directly calling the updateRemoteControlDisplay method, without first calling the checkUpdateRemoteControlDisplay method which verifies the conditions before updating the display. One of those conditions is that the audio focus stack shouldn't be empty. To verify this fix, several functions were also rename to clearly indicate the lock order and verify we properly synchronize on the right objects. In doing so, a missing synchronization on audio focus was found. Change-Id: If1baaac224ea676aeb83ac0aefcc53f87461c32e
1 parent 528e382 commit b716f0b

File tree

1 file changed

+47
-43
lines changed

1 file changed

+47
-43
lines changed

media/java/android/media/AudioService.java

Lines changed: 47 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -2637,7 +2637,7 @@ private void removeFocusStackEntry(String clientToRemove, boolean signal) {
26372637
notifyTopOfAudioFocusStack();
26382638
// there's a new top of the stack, let the remote control know
26392639
synchronized(mRCStack) {
2640-
checkUpdateRemoteControlDisplay_syncRcs(RC_INFO_ALL);
2640+
checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
26412641
}
26422642
}
26432643
} else {
@@ -2680,7 +2680,7 @@ private void removeFocusStackEntryForClient(IBinder cb) {
26802680
notifyTopOfAudioFocusStack();
26812681
// there's a new top of the stack, let the remote control know
26822682
synchronized(mRCStack) {
2683-
checkUpdateRemoteControlDisplay_syncRcs(RC_INFO_ALL);
2683+
checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
26842684
}
26852685
}
26862686
}
@@ -2784,7 +2784,7 @@ public int requestAudioFocus(int mainStreamType, int focusChangeHint, IBinder cb
27842784

27852785
// there's a new top of the stack, let the remote control know
27862786
synchronized(mRCStack) {
2787-
checkUpdateRemoteControlDisplay_syncRcs(RC_INFO_ALL);
2787+
checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
27882788
}
27892789
}//synchronized(mAudioFocusLock)
27902790

@@ -3182,7 +3182,7 @@ private void onRcDisplayUpdate(RemoteControlStackEntry rcse, int flags /* USED ?
31823182
* Helper function:
31833183
* Called synchronized on mRCStack
31843184
*/
3185-
private void clearRemoteControlDisplay_syncRcs() {
3185+
private void clearRemoteControlDisplay_syncAfRcs() {
31863186
synchronized(mCurrentRcLock) {
31873187
mCurrentRcClient = null;
31883188
}
@@ -3191,18 +3191,21 @@ private void clearRemoteControlDisplay_syncRcs() {
31913191
}
31923192

31933193
/**
3194-
* Helper function:
3195-
* Called synchronized on mRCStack
3196-
* mRCStack.isEmpty() is false
3194+
* Helper function for code readability: only to be called from
3195+
* checkUpdateRemoteControlDisplay_syncAfRcs() which checks the preconditions for
3196+
* this method.
3197+
* Preconditions:
3198+
* - called synchronized mAudioFocusLock then on mRCStack
3199+
* - mRCStack.isEmpty() is false
31973200
*/
3198-
private void updateRemoteControlDisplay_syncRcs(int infoChangedFlags) {
3201+
private void updateRemoteControlDisplay_syncAfRcs(int infoChangedFlags) {
31993202
RemoteControlStackEntry rcse = mRCStack.peek();
32003203
int infoFlagsAboutToBeUsed = infoChangedFlags;
32013204
// this is where we enforce opt-in for information display on the remote controls
32023205
// with the new AudioManager.registerRemoteControlClient() API
32033206
if (rcse.mRcClient == null) {
32043207
//Log.w(TAG, "Can't update remote control display with null remote control client");
3205-
clearRemoteControlDisplay_syncRcs();
3208+
clearRemoteControlDisplay_syncAfRcs();
32063209
return;
32073210
}
32083211
synchronized(mCurrentRcLock) {
@@ -3219,36 +3222,36 @@ private void updateRemoteControlDisplay_syncRcs(int infoChangedFlags) {
32193222

32203223
/**
32213224
* Helper function:
3222-
* Called synchronized on mFocusLock, then mRCStack
3225+
* Called synchronized on mAudioFocusLock, then mRCStack
32233226
* Check whether the remote control display should be updated, triggers the update if required
32243227
* @param infoChangedFlags the flags corresponding to the remote control client information
32253228
* that has changed, if applicable (checking for the update conditions might trigger a
32263229
* clear, rather than an update event).
32273230
*/
3228-
private void checkUpdateRemoteControlDisplay_syncRcs(int infoChangedFlags) {
3231+
private void checkUpdateRemoteControlDisplay_syncAfRcs(int infoChangedFlags) {
32293232
// determine whether the remote control display should be refreshed
32303233
// if either stack is empty, there is a mismatch, so clear the RC display
32313234
if (mRCStack.isEmpty() || mFocusStack.isEmpty()) {
3232-
clearRemoteControlDisplay_syncRcs();
3235+
clearRemoteControlDisplay_syncAfRcs();
32333236
return;
32343237
}
32353238
// if the top of the two stacks belong to different packages, there is a mismatch, clear
32363239
if ((mRCStack.peek().mCallingPackageName != null)
32373240
&& (mFocusStack.peek().mPackageName != null)
32383241
&& !(mRCStack.peek().mCallingPackageName.compareTo(
32393242
mFocusStack.peek().mPackageName) == 0)) {
3240-
clearRemoteControlDisplay_syncRcs();
3243+
clearRemoteControlDisplay_syncAfRcs();
32413244
return;
32423245
}
32433246
// if the audio focus didn't originate from the same Uid as the one in which the remote
32443247
// control information will be retrieved, clear
32453248
if (mRCStack.peek().mCallingUid != mFocusStack.peek().mCallingUid) {
3246-
clearRemoteControlDisplay_syncRcs();
3249+
clearRemoteControlDisplay_syncAfRcs();
32473250
return;
32483251
}
32493252
// refresh conditions were verified: update the remote controls
3250-
// ok to call, mRCStack is not empty
3251-
updateRemoteControlDisplay_syncRcs(infoChangedFlags);
3253+
// ok to call: synchronized mAudioFocusLock then on mRCStack, mRCStack is not empty
3254+
updateRemoteControlDisplay_syncAfRcs(infoChangedFlags);
32523255
}
32533256

32543257
/** see AudioManager.registerMediaButtonEventReceiver(ComponentName eventReceiver) */
@@ -3259,7 +3262,7 @@ public void registerMediaButtonEventReceiver(ComponentName eventReceiver) {
32593262
synchronized(mRCStack) {
32603263
pushMediaButtonReceiver(eventReceiver);
32613264
// new RC client, assume every type of information shall be queried
3262-
checkUpdateRemoteControlDisplay_syncRcs(RC_INFO_ALL);
3265+
checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
32633266
}
32643267
}
32653268
}
@@ -3274,7 +3277,7 @@ public void unregisterMediaButtonEventReceiver(ComponentName eventReceiver) {
32743277
removeMediaButtonReceiver(eventReceiver);
32753278
if (topOfStackWillChange) {
32763279
// current RC client will change, assume every type of info needs to be queried
3277-
checkUpdateRemoteControlDisplay_syncRcs(RC_INFO_ALL);
3280+
checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
32783281
}
32793282
}
32803283
}
@@ -3283,6 +3286,7 @@ public void unregisterMediaButtonEventReceiver(ComponentName eventReceiver) {
32833286
/** see AudioManager.registerRemoteControlClient(ComponentName eventReceiver, ...) */
32843287
public void registerRemoteControlClient(ComponentName eventReceiver,
32853288
IRemoteControlClient rcClient, String clientName, String callingPackageName) {
3289+
if (DEBUG_RC) Log.i(TAG, "Register remote control client rcClient="+rcClient);
32863290
synchronized(mAudioFocusLock) {
32873291
synchronized(mRCStack) {
32883292
// store the new display information
@@ -3330,7 +3334,7 @@ public void registerRemoteControlClient(ComponentName eventReceiver,
33303334
// if the eventReceiver is at the top of the stack
33313335
// then check for potential refresh of the remote controls
33323336
if (isCurrentRcController(eventReceiver)) {
3333-
checkUpdateRemoteControlDisplay_syncRcs(RC_INFO_ALL);
3337+
checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
33343338
}
33353339
}
33363340
}
@@ -3435,35 +3439,35 @@ private void rcDisplay_startDeathMonitor_syncRcStack() {
34353439
*/
34363440
public void registerRemoteControlDisplay(IRemoteControlDisplay rcd) {
34373441
if (DEBUG_RC) Log.d(TAG, ">>> registerRemoteControlDisplay("+rcd+")");
3438-
synchronized(mRCStack) {
3439-
if ((mRcDisplay == rcd) || (rcd == null)) {
3440-
return;
3441-
}
3442-
// if we had a display before, stop monitoring its death
3443-
rcDisplay_stopDeathMonitor_syncRcStack();
3444-
mRcDisplay = rcd;
3445-
// new display, start monitoring its death
3446-
rcDisplay_startDeathMonitor_syncRcStack();
3442+
synchronized(mAudioFocusLock) {
3443+
synchronized(mRCStack) {
3444+
if ((mRcDisplay == rcd) || (rcd == null)) {
3445+
return;
3446+
}
3447+
// if we had a display before, stop monitoring its death
3448+
rcDisplay_stopDeathMonitor_syncRcStack();
3449+
mRcDisplay = rcd;
3450+
// new display, start monitoring its death
3451+
rcDisplay_startDeathMonitor_syncRcStack();
34473452

3448-
// let all the remote control clients there is a new display
3449-
// no need to unplug the previous because we only support one display
3450-
// and the clients don't track the death of the display
3451-
Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
3452-
while(stackIterator.hasNext()) {
3453-
RemoteControlStackEntry rcse = stackIterator.next();
3454-
if(rcse.mRcClient != null) {
3455-
try {
3456-
rcse.mRcClient.plugRemoteControlDisplay(mRcDisplay);
3457-
} catch (RemoteException e) {
3458-
Log.e(TAG, "Error connecting remote control display to client: " + e);
3459-
e.printStackTrace();
3453+
// let all the remote control clients there is a new display
3454+
// no need to unplug the previous because we only support one display
3455+
// and the clients don't track the death of the display
3456+
Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
3457+
while(stackIterator.hasNext()) {
3458+
RemoteControlStackEntry rcse = stackIterator.next();
3459+
if(rcse.mRcClient != null) {
3460+
try {
3461+
rcse.mRcClient.plugRemoteControlDisplay(mRcDisplay);
3462+
} catch (RemoteException e) {
3463+
Log.e(TAG, "Error connecting remote control display to client: " + e);
3464+
e.printStackTrace();
3465+
}
34603466
}
34613467
}
3462-
}
34633468

3464-
if (!mRCStack.isEmpty()) {
34653469
// we have a new display, of which all the clients are now aware: have it be updated
3466-
updateRemoteControlDisplay_syncRcs(RC_INFO_ALL);
3470+
checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
34673471
}
34683472
}
34693473
}

0 commit comments

Comments
 (0)