diff options
author | Jakub Tyszkowski <jakub.tyszkowski@codecoup.pl> | 2021-11-04 13:06:20 +0100 |
---|---|---|
committer | Jakub Tyszkowski <jakub.tyszkowski@codecoup.pl> | 2021-11-05 14:56:19 +0100 |
commit | fbcf2004e8ead688b538b9375c3f4840e47aabb5 (patch) | |
tree | 1fe6f0a22e99fac3854f4b0a4d5f54bf4ddfc0c4 | |
parent | e514f0dd9437df7e2b13921961ff71202a53f797 (diff) | |
download | Bluetooth-fbcf2004e8ead688b538b9375c3f4840e47aabb5.tar.gz |
mcp: Synchronize mPendingStateRequest list access
Since this can be accessed either by MediaControlGattService
or by the MediaPlayerList as a result of media player state change
callback, it should be protected against concurrent access.
Bug: 204845801
Tag: #feature
Sponsor: jpawlowski@
Test: atest BluetoothInstrumentationTests
Change-Id: Ica3d6cd731d6e8946fb6ddfcc5a744f88d1c6044
-rw-r--r-- | src/com/android/bluetooth/mcp/MediaControlProfile.java | 146 |
1 files changed, 78 insertions, 68 deletions
diff --git a/src/com/android/bluetooth/mcp/MediaControlProfile.java b/src/com/android/bluetooth/mcp/MediaControlProfile.java index 724b969b9..fb72a36c6 100644 --- a/src/com/android/bluetooth/mcp/MediaControlProfile.java +++ b/src/com/android/bluetooth/mcp/MediaControlProfile.java @@ -192,7 +192,7 @@ public class MediaControlProfile implements MediaControlServiceCallbacks { } } - private void removePendingStateRequests(Set<PlayerStateField> fields) { + private synchronized void removePendingStateRequests(Set<PlayerStateField> fields) { if (mPendingStateRequest == null) return; for (PlayerStateField field : fields) { @@ -263,7 +263,9 @@ public class MediaControlProfile implements MediaControlServiceCallbacks { @Override public void onPlayerStateRequest(PlayerStateField[] stateFields) { - mPendingStateRequest = Stream.of(stateFields).collect(Collectors.toList()); + synchronized (this) { + mPendingStateRequest = Stream.of(stateFields).collect(Collectors.toList()); + } processPendingPlayerStateRequest(); } @@ -513,70 +515,76 @@ public class MediaControlProfile implements MediaControlServiceCallbacks { Map<PlayerStateField, Object> handled_request_map = new HashMap<>(); - if (mPendingStateRequest == null) return; - - // Notice: If we are unable to provide the requested field it will stay queued until we are - // able to provide it. - for (PlayerStateField settings_field : mPendingStateRequest) { - switch (settings_field) { - case PLAYBACK_STATE: - if (mCurrentData.state != null) { - handled_request_map.put(settings_field, - playerState2McsState(mCurrentData.state.getState())); - } - break; - case TRACK_DURATION: - handled_request_map.put(settings_field, getCurrentTrackDuration()); - break; - case PLAYBACK_SPEED: - if (mCurrentData.state != null) { - handled_request_map.put( - settings_field, mCurrentData.state.getPlaybackSpeed()); - } - break; - case SEEKING_SPEED: - float seeking_speed = 1.0f; - if (mCurrentData.state != null) { - if ((mCurrentData.state.getState() == PlaybackState.STATE_FAST_FORWARDING) - || (mCurrentData.state.getState() - == PlaybackState.STATE_REWINDING)) { - seeking_speed = mCurrentData.state.getPlaybackSpeed(); + synchronized (this) { + if (mPendingStateRequest == null) return; + // Notice: If we are unable to provide the requested field it will stay queued until we + // are able to provide it. + for (PlayerStateField settings_field : mPendingStateRequest) { + switch (settings_field) { + case PLAYBACK_STATE: + if (mCurrentData.state != null) { + handled_request_map.put(settings_field, + playerState2McsState(mCurrentData.state.getState())); + } + break; + case TRACK_DURATION: + handled_request_map.put(settings_field, getCurrentTrackDuration()); + break; + case PLAYBACK_SPEED: + if (mCurrentData.state != null) { + handled_request_map.put( + settings_field, mCurrentData.state.getPlaybackSpeed()); + } + break; + case SEEKING_SPEED: + float seeking_speed = 1.0f; + if (mCurrentData.state != null) { + if ((mCurrentData.state.getState() + == PlaybackState.STATE_FAST_FORWARDING) + || (mCurrentData.state.getState() + == PlaybackState.STATE_REWINDING)) { + seeking_speed = mCurrentData.state.getPlaybackSpeed(); + } } - } - handled_request_map.put(settings_field, seeking_speed); - break; - case PLAYING_ORDER: - handled_request_map.put(settings_field, getCurrentPlayerPlayingOrder()); - break; - case TRACK_POSITION: - if (mCurrentData.state != null) { - handled_request_map.put( - settings_field, getDriftCorrectedTrackPosition(mCurrentData.state)); - } - break; - case PLAYER_NAME: - String player_name = getCurrentPlayerName(); - if (player_name != null) handled_request_map.put(settings_field, player_name); - break; - case ICON_URL: - // Not implemented - break; - case ICON_OBJ_ID: - // TODO: Implement once we have Object Transfer Service - break; - case PLAYING_ORDER_SUPPORTED: - Integer playing_order = getSupportedPlayingOrder(); - if (playing_order != null) { - handled_request_map.put(settings_field, playing_order.intValue()); - } - break; - case OPCODES_SUPPORTED: - if (mCurrentData.state != null) { - handled_request_map.put(settings_field, - playerActions2McsSupportedOpcodes(mCurrentData.state.getActions())); - } - break; + handled_request_map.put(settings_field, seeking_speed); + break; + case PLAYING_ORDER: + handled_request_map.put(settings_field, getCurrentPlayerPlayingOrder()); + break; + case TRACK_POSITION: + if (mCurrentData.state != null) { + handled_request_map.put( + settings_field, getDriftCorrectedTrackPosition( + mCurrentData.state)); + } + break; + case PLAYER_NAME: + String player_name = getCurrentPlayerName(); + if (player_name != null) { + handled_request_map.put(settings_field, player_name); + } + break; + case ICON_URL: + // Not implemented + break; + case ICON_OBJ_ID: + // TODO: Implement once we have Object Transfer Service + break; + case PLAYING_ORDER_SUPPORTED: + Integer playing_order = getSupportedPlayingOrder(); + if (playing_order != null) { + handled_request_map.put(settings_field, playing_order.intValue()); + } + break; + case OPCODES_SUPPORTED: + if (mCurrentData.state != null) { + handled_request_map.put(settings_field, + playerActions2McsSupportedOpcodes( + mCurrentData.state.getActions())); + } + break; + } } } @@ -588,10 +596,12 @@ public class MediaControlProfile implements MediaControlServiceCallbacks { } if (DBG) { - if (mPendingStateRequest != null && !mPendingStateRequest.isEmpty()) { - Log.w(TAG, "MCS service state fields left unhandled: "); - for (PlayerStateField item : mPendingStateRequest) { - Log.w(TAG, " > " + item); + synchronized (this) { + if (mPendingStateRequest != null && !mPendingStateRequest.isEmpty()) { + Log.w(TAG, "MCS service state fields left unhandled: "); + for (PlayerStateField item : mPendingStateRequest) { + Log.w(TAG, " > " + item); + } } } } |