Merge "OPP: Fix leaked IntentReceiver issue" into q-keystone-qcom-dev
diff --git a/src/com/android/bluetooth/a2dp/A2dpService.java b/src/com/android/bluetooth/a2dp/A2dpService.java
index 81ba906..3c8435b 100755
--- a/src/com/android/bluetooth/a2dp/A2dpService.java
+++ b/src/com/android/bluetooth/a2dp/A2dpService.java
@@ -84,6 +84,7 @@
     private final Object mActiveDeviceLock = new Object();
     private final Object mVariableLock = new Object();
     private final ReentrantReadWriteLock mA2dpNativeInterfaceLock = new ReentrantReadWriteLock();
+    private final Object mAudioManagerLock = new Object();
 
     @VisibleForTesting
     A2dpNativeInterface mA2dpNativeInterface;
@@ -138,7 +139,7 @@
            switch (msg.what) {
                case SET_EBMONO_CFG:
                    Log.d(TAG, "setparameters to Mono");
-                   synchronized (mVariableLock) {
+                   synchronized (mAudioManagerLock) {
                         if(mAudioManager != null)
                            mAudioManager.setParameters("TwsChannelConfig=mono");
                    }
@@ -146,7 +147,7 @@
                    break;
                case SET_EBDUALMONO_CFG:
                    Log.d(TAG, "setparameters to Dual-Mono");
-                   synchronized (mVariableLock) {
+                   synchronized (mAudioManagerLock) {
                        if(mAudioManager != null)
                            mAudioManager.setParameters("TwsChannelConfig=dual-mono");
                    }
@@ -191,11 +192,14 @@
             mA2dpNativeInterfaceLock.writeLock().unlock();
         }
         BluetoothCodecConfig[] OffloadCodecConfig;
-        synchronized (mVariableLock) {
+
+        synchronized (mAudioManagerLock) {
             mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
             Objects.requireNonNull(mAudioManager,
                                "AudioManager cannot be null when A2dpService starts");
+        }
 
+        synchronized (mVariableLock) {
             // Step 2: Get maximum number of connected audio devices
             mMaxConnectedAudioDevices = mAdapterService.getMaxConnectedAudioDevices();
             mSetMaxConnectedAudioDevices = mMaxConnectedAudioDevices;
@@ -240,7 +244,9 @@
 
             // Step 5: Setup codec config
             mA2dpCodecConfig = new A2dpCodecConfig(this, mA2dpNativeInterface);
+        }
 
+        synchronized (mAudioManagerLock) {
             // Step 6: Initialize native interface
             List<BluetoothCodecConfig> mCodecConfigOffload;
             mCodecConfigOffload = mAudioManager.getHwOffloadEncodingFormatsSupportedForA2DP();
@@ -258,13 +264,13 @@
         }
 
         synchronized (mVariableLock) {
-
             // Step 7: Check if A2DP is in offload mode
             mA2dpOffloadEnabled = mAdapterService.isA2dpOffloadEnabled();
             if (DBG) {
                 Log.d(TAG, "A2DP offload flag set to " + mA2dpOffloadEnabled);
             }
          }
+
         // Step 8: Setup broadcast receivers
         IntentFilter filter = new IntentFilter();
         filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
@@ -358,13 +364,16 @@
                 }
             } else {
                 mMaxConnectedAudioDevices = 1;
-            } 
+            }
             mSetMaxConnectedAudioDevices = 1;
             // Step 1: Clear AdapterService, A2dpNativeInterface, AudioManager
-            mAudioManager = null;
             mAdapterService = null;
         }
 
+        synchronized (mAudioManagerLock) {
+            mAudioManager = null;
+        }
+
         try {
             mA2dpNativeInterfaceLock.writeLock().lock();
             mA2dpNativeInterface = null;
@@ -673,9 +682,11 @@
                     }
                 }
                 int connectionState = BluetoothProfile.STATE_DISCONNECTED;
-                A2dpStateMachine sm = mStateMachines.get(device);
-                if (sm != null) {
-                    connectionState = sm.getConnectionState();
+                synchronized (mBtA2dpLock) {
+                    A2dpStateMachine sm = mStateMachines.get(device);
+                    if (sm != null) {
+                        connectionState = sm.getConnectionState();
+                    }
                 }
                 for (int state : states) {
                     if (connectionState == state) {
@@ -760,7 +771,7 @@
             isBAActive = (mBatService != null) && (mBatService.isBATActive());
             Log.d(TAG," removeActiveDevice: BA active " + isBAActive);
             // If BA streaming is ongoing, we don't want to pause music player
-            synchronized (mVariableLock ) {
+            synchronized (mAudioManagerLock) {
                 if(!isBAActive && mAudioManager != null) {
                     mAudioManager.handleBluetoothA2dpActiveDeviceChange(
                            previousActiveDevice, BluetoothProfile.STATE_DISCONNECTED,
@@ -916,10 +927,12 @@
             storeActiveDeviceVolume();
 
             if(previousActiveDevice != null && !tws_switch && isA2dpPlaying(previousActiveDevice)) {
-                if (mAudioManager != null && !mAudioManager.isStreamMute(AudioManager.STREAM_MUSIC)) {
-                    mAudioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC,
-                            AudioManager.ADJUST_MUTE,
-                            mAudioManager.FLAG_BLUETOOTH_ABS_VOLUME);
+                synchronized (mAudioManagerLock) {
+                    if (mAudioManager != null && !mAudioManager.isStreamMute(AudioManager.STREAM_MUSIC)) {
+                        mAudioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC,
+                                AudioManager.ADJUST_MUTE,
+                                mAudioManager.FLAG_BLUETOOTH_ABS_VOLUME);
+                    }
                 }
             }
 
@@ -943,8 +956,10 @@
         updateAndBroadcastActiveDevice(device);
         Log.d(TAG, "setActiveDevice(" + device + "): completed");
 
-        if(mAvrcp_ext != null)
-            mAvrcp_ext.setActiveDevice(device);
+        synchronized (mBtAvrcpLock) {
+            if (mAvrcp_ext != null)
+                mAvrcp_ext.setActiveDevice(device);
+        }
         // Send an intent with the active device codec config
         if (codecStatus != null) {
             broadcastCodecConfig(mActiveDevice, codecStatus);
@@ -958,9 +973,11 @@
                 rememberedVolume = mAvrcp_ext.getVolume(device);
                 Log.d(TAG,"volume = " + rememberedVolume);
             }
+        }
+
             // Make sure the Audio Manager knows the previous Active device is disconnected,
             // and the new Active device is connected.
-
+        synchronized (mAudioManagerLock) {
             if (!isBAActive && mAudioManager != null) {
             // Make sure the Audio Manager knows the previous
             // Active device is disconnected, and the new Active
@@ -973,6 +990,7 @@
                         mActiveDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP,
                           true, rememberedVolume);
             }
+        }
 
         // Inform the Audio Service about the codec configuration
         // change, so the Audio Service can reset accordingly the audio
@@ -980,6 +998,7 @@
 
         // Split A2dp will be enabled by default
             boolean isSplitA2dpEnabled = true;
+        synchronized (mVariableLock) {
             AdapterService adapterService = AdapterService.getAdapterService();
 
             if (adapterService != null){
@@ -990,9 +1009,11 @@
             }
         }
         // Don't update the absVolume flags when disconnect one device in multicast mode
-        if (!a2dpMulticast || previousActiveDevice == null) {
-            if (mAvrcp_ext != null && !tws_switch) {
-                mAvrcp_ext.setAbsVolumeFlag(device);
+        synchronized (mBtAvrcpLock) {
+            if (!a2dpMulticast || previousActiveDevice == null) {
+                if (mAvrcp_ext != null && !tws_switch) {
+                    mAvrcp_ext.setAbsVolumeFlag(device);
+                }
             }
         }
         tws_switch = false;
@@ -1089,11 +1110,13 @@
     public void storeDeviceAudioVolume(BluetoothDevice device) {
         if (device != null)
         {
-            if (AvrcpTargetService.get() != null) {
-                AvrcpTargetService.get().storeVolumeForDevice(device);
-            } else if (mAvrcp_ext != null) {
-                //store volume in multi-a2dp for the device doesn't set as active
-                mAvrcp_ext.storeVolumeForDevice(device);
+            synchronized (mBtAvrcpLock) {
+                if (AvrcpTargetService.get() != null) {
+                    AvrcpTargetService.get().storeVolumeForDevice(device);
+                } else if (mAvrcp_ext != null) {
+                    //store volume in multi-a2dp for the device doesn't set as active
+                    mAvrcp_ext.storeVolumeForDevice(device);
+                }
             }
         }
     }
@@ -1377,6 +1400,7 @@
             BluetoothDevice device = stackEvent.device;
             A2dpStateMachine sm = mStateMachines.get(device);
             if (sm == null) {
+                Log.d(TAG, "messageFromNative: stackEvent.type: " + stackEvent.type);
                 if (stackEvent.type == A2dpStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED) {
                     switch (stackEvent.valueInt) {
                         case A2dpStackEvent.CONNECTION_STATE_CONNECTED:
@@ -1421,7 +1445,9 @@
                     }
                 }
             } else {
+                Log.d(TAG, "messageFromNative: Going to acquire mVariableLock.");
                 synchronized (mVariableLock) {
+                    Log.d(TAG, "messageFromNative: Acquired mVariableLock");
                     if (mAdapterService != null && mAdapterService.isVendorIntfEnabled()) {
                         switch (sm.getConnectionState()) {
                             case BluetoothProfile.STATE_DISCONNECTED:
@@ -1433,6 +1459,7 @@
                         }
                     }
                 }
+                Log.d(TAG, "messageFromNative: Released mVariableLock");
             }
             if (sm == null) {
                 Log.e(TAG, "Cannot process stack event: no state machine: " + stackEvent);
@@ -1448,6 +1475,7 @@
                     sA2dpSinkService.disconnect(src);
                 }
             }
+            Log.d(TAG, "messageFromNative: Sending STACK_EVENT: " + stackEvent + " to sm.");
             sm.sendMessage(A2dpStateMachine.STACK_EVENT, stackEvent);
         }
     }
@@ -1495,9 +1523,11 @@
         // parameters in the Audio HAL to the Bluetooth stack.
         int rememberedVolume = -1;
         if (isActiveDevice(device) && !sameAudioFeedingParameters) {
-            if (mAvrcp_ext != null)
-                rememberedVolume = mAvrcp_ext.getVolume(device);
-            synchronized (mVariableLock) {
+            synchronized (mBtAvrcpLock) {
+                if (mAvrcp_ext != null)
+                    rememberedVolume = mAvrcp_ext.getVolume(device);
+            }
+            synchronized (mAudioManagerLock) {
                 if (mAudioManager != null) {
                     mAudioManager.handleBluetoothA2dpActiveDeviceChange(device,
                             BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP,
@@ -1508,13 +1538,14 @@
     }
 
     void updateTwsChannelMode(int state, BluetoothDevice device) {
+        Log.d(TAG, "updateTwsChannelMode: mIsTwsPlusMonoSupported: " + mIsTwsPlusMonoSupported);
         if (mIsTwsPlusMonoSupported) {
             BluetoothDevice peerTwsDevice = null;
             synchronized (mVariableLock) {
                 if (mAdapterService != null)
                     peerTwsDevice = mAdapterService.getTwsPlusPeerDevice(device);
             }
-            Log.d(TAG, "TwsChannelMode: " + mTwsPlusChannelMode);
+            Log.d(TAG, "TwsChannelMode: " + mTwsPlusChannelMode + " state: " + state);
             synchronized(mBtTwsLock) {
                 if ("mono".equals(mTwsPlusChannelMode)) {
                     if ((state == BluetoothA2dp.STATE_PLAYING) && (peerTwsDevice!= null)
@@ -1523,11 +1554,14 @@
                         Message msg = mHandler.obtainMessage(SET_EBDUALMONO_CFG);
                         mHandler.sendMessageDelayed(msg, DualMonoCfg_Timeout);
                     } else if (state == BluetoothA2dp.STATE_PLAYING) {
-                        Log.d(TAG, "setparameters to Mono");
-                        synchronized (mVariableLock) {
-                            if (mAudioManager != null)
+                        Log.d(TAG, "updateTwsChannelMode: setparameters to Mono");
+                        synchronized (mAudioManagerLock) {
+                            if (mAudioManager != null) {
+                                Log.d(TAG, "updateTwsChannelMode: Acquired mAudioManagerLock");
                                 mAudioManager.setParameters("TwsChannelConfig=mono");
+                            }
                         }
+                        Log.d(TAG, "updateTwsChannelMode: Released mAudioManagerLock");
                     }
                     if ((state == BluetoothA2dp.STATE_NOT_PLAYING) &&
                            isA2dpPlaying(peerTwsDevice)) {
@@ -1553,7 +1587,7 @@
                     if ((state == BluetoothA2dp.STATE_NOT_PLAYING)
                           && isA2dpPlaying(peerTwsDevice)) {
                         Log.d(TAG, "setparameters to Mono");
-                        synchronized (mVariableLock) {
+                        synchronized (mAudioManagerLock) {
                             if (mAudioManager != null)
                                 mAudioManager.setParameters("TwsChannelConfig=mono");
                         }
@@ -1576,7 +1610,7 @@
         if(isBAActive) {
             return;
         }
-        synchronized (mVariableLock) {
+        synchronized (mAudioManagerLock) {
             if (mAudioManager != null)
                 mAudioManager.setParameters("reconfigA2dp=true");
         }
@@ -1689,15 +1723,16 @@
             if (sm.getConnectionState() != BluetoothProfile.STATE_DISCONNECTED) {
                 return;
             }
+        }
+        synchronized (mBtAvrcpLock) {
             if (mFactory.getAvrcpTargetService() != null) {
                 mFactory.getAvrcpTargetService().removeStoredVolumeForDevice(device);
             }
             if (mAvrcp_ext != null) {
                 mAvrcp_ext.removeVolumeForDevice(device);
             }
-
-            removeStateMachine(device);
         }
+        removeStateMachine(device);
     }
 
     private void removeStateMachine(BluetoothDevice device) {
diff --git a/src/com/android/bluetooth/a2dp/A2dpStateMachine.java b/src/com/android/bluetooth/a2dp/A2dpStateMachine.java
index 01018d0..94ad8da 100644
--- a/src/com/android/bluetooth/a2dp/A2dpStateMachine.java
+++ b/src/com/android/bluetooth/a2dp/A2dpStateMachine.java
@@ -572,6 +572,7 @@
 
         // in Connected state
         private void processAudioStateEvent(int state) {
+            Log.i(TAG, "Connected: processAudioStateEvent: state: " + state + " mIsPlaying: " + mIsPlaying);
             switch (state) {
                 case A2dpStackEvent.AUDIO_STATE_STARTED:
                     synchronized (this) {