Merge "Reduced the impact of "synchronized" statements"
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index ceb7e91..15b16f7 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -53,6 +53,8 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.UUID;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 /**
  * Represents the local device Bluetooth adapter. The {@link BluetoothAdapter}
@@ -487,6 +489,8 @@
 
     private final IBluetoothManager mManagerService;
     private IBluetooth mService;
+    private final ReentrantReadWriteLock mServiceLock =
+        new ReentrantReadWriteLock();
 
     private final Object mLock = new Object();
     private final Map<LeScanCallback, ScanCallback> mLeScanClients;
@@ -521,8 +525,13 @@
             throw new IllegalArgumentException("bluetooth manager service is null");
         }
         try {
+            mServiceLock.writeLock().lock();
             mService = managerService.registerAdapter(mManagerCallback);
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        } finally {
+            mServiceLock.writeLock().unlock();
+        }
         mManagerService = managerService;
         mLeScanClients = new HashMap<LeScanCallback, ScanCallback>();
         mToken = new Binder();
@@ -609,10 +618,14 @@
     @RequiresPermission(Manifest.permission.BLUETOOTH)
     public boolean isEnabled() {
         try {
-            synchronized(mManagerCallback) {
-                if (mService != null) return mService.isEnabled();
-            }
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
+            mServiceLock.readLock().lock();
+            if (mService != null) return mService.isEnabled();
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
+
         return false;
     }
 
@@ -643,12 +656,12 @@
      * or OFF if BT is in BLE_ON state
      */
     private void notifyUserAction(boolean enable) {
-        if (mService == null) {
-            Log.e(TAG, "mService is null");
-            return;
-        }
-
         try {
+            mServiceLock.readLock().lock();
+            if (mService == null) {
+                Log.e(TAG, "mService is null");
+                return;
+            }
             if (enable) {
                 mService.onLeServiceUp(); //NA:TODO implementation pending
             } else {
@@ -656,6 +669,8 @@
             }
         } catch (RemoteException e) {
             Log.e(TAG, "", e);
+        } finally {
+            mServiceLock.readLock().unlock();
         }
     }
 
@@ -787,26 +802,28 @@
     @RequiresPermission(Manifest.permission.BLUETOOTH)
     @AdapterState
     public int getState() {
+        int state = BluetoothAdapter.STATE_OFF;
+
         try {
-            synchronized(mManagerCallback) {
-                if (mService != null)
-                {
-                    int state=  mService.getState();
-                    if (VDBG) Log.d(TAG, "" + hashCode() + ": getState(). Returning " + state);
-                    //consider all internal states as OFF
-                    if (state == BluetoothAdapter.STATE_BLE_ON
-                        || state == BluetoothAdapter.STATE_BLE_TURNING_ON
-                        || state == BluetoothAdapter.STATE_BLE_TURNING_OFF) {
-                        if (VDBG) Log.d(TAG, "Consider internal state as OFF");
-                        state = BluetoothAdapter.STATE_OFF;
-                    }
-                    return state;
-                }
-                // TODO(BT) there might be a small gap during STATE_TURNING_ON that
-                //          mService is null, handle that case
+            mServiceLock.readLock().lock();
+            if (mService != null) {
+                state = mService.getState();
             }
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
-        return STATE_OFF;
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
+
+        // Consider all internal states as OFF
+        if (state == BluetoothAdapter.STATE_BLE_ON
+            || state == BluetoothAdapter.STATE_BLE_TURNING_ON
+            || state == BluetoothAdapter.STATE_BLE_TURNING_OFF) {
+            if (VDBG) Log.d(TAG, "Consider internal state as OFF");
+            state = BluetoothAdapter.STATE_OFF;
+        }
+        if (VDBG) Log.d(TAG, "" + hashCode() + ": getState(). Returning " + state);
+        return state;
     }
 
     /**
@@ -829,19 +846,21 @@
     @RequiresPermission(Manifest.permission.BLUETOOTH)
     @AdapterState
     public int getLeState() {
+        int state = BluetoothAdapter.STATE_OFF;
+
         try {
-            synchronized(mManagerCallback) {
-                if (mService != null)
-                {
-                    int state=  mService.getState();
-                    if (VDBG) Log.d(TAG,"getLeState() returning " + state);
-                    return state;
-                }
+            mServiceLock.readLock().lock();
+            if (mService != null) {
+                state = mService.getState();
             }
         } catch (RemoteException e) {
             Log.e(TAG, "", e);
+        } finally {
+            mServiceLock.readLock().unlock();
         }
-        return BluetoothAdapter.STATE_OFF;
+
+        if (VDBG) Log.d(TAG,"getLeState() returning " + state);
+        return state;
     }
 
     boolean getLeAccess() {
@@ -883,16 +902,21 @@
      */
     @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
     public boolean enable() {
-        int state = STATE_OFF;
-        if (isEnabled() == true){
+        int state = BluetoothAdapter.STATE_OFF;
+        if (isEnabled() == true) {
             if (DBG) Log.d(TAG, "enable(): BT is already enabled..!");
             return true;
         }
-        //Use service interface to get the exact state
-        if (mService != null) {
-            try {
-               state = mService.getState();
-            } catch (RemoteException e) {Log.e(TAG, "", e);}
+        // Use service interface to get the exact state
+        try {
+            mServiceLock.readLock().lock();
+            if (mService != null) {
+                state = mService.getState();
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        } finally {
+            mServiceLock.readLock().unlock();
         }
 
         if (state == BluetoothAdapter.STATE_BLE_ON) {
@@ -997,10 +1021,13 @@
      */
     public boolean configHciSnoopLog(boolean enable) {
         try {
-            synchronized(mManagerCallback) {
-                if (mService != null) return mService.configHciSnoopLog(enable);
-            }
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
+            mServiceLock.readLock().lock();
+            if (mService != null) return mService.configHciSnoopLog(enable);
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
         return false;
     }
 
@@ -1016,12 +1043,16 @@
      */
     public boolean factoryReset() {
         try {
+            mServiceLock.readLock().lock();
             if (mService != null) {
                 return mService.factoryReset();
-            } else {
-                SystemProperties.set("persist.bluetooth.factoryreset", "true");
             }
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
+            SystemProperties.set("persist.bluetooth.factoryreset", "true");
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
         return false;
     }
 
@@ -1036,10 +1067,13 @@
     public ParcelUuid[] getUuids() {
         if (getState() != STATE_ON) return null;
         try {
-            synchronized(mManagerCallback) {
-                if (mService != null) return mService.getUuids();
-            }
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
+            mServiceLock.readLock().lock();
+            if (mService != null) return mService.getUuids();
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
         return null;
     }
 
@@ -1062,10 +1096,13 @@
     public boolean setName(String name) {
         if (getState() != STATE_ON) return false;
         try {
-            synchronized(mManagerCallback) {
-                if (mService != null) return mService.setName(name);
-            }
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
+            mServiceLock.readLock().lock();
+            if (mService != null) return mService.setName(name);
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
         return false;
     }
 
@@ -1090,10 +1127,13 @@
     public int getScanMode() {
         if (getState() != STATE_ON) return SCAN_MODE_NONE;
         try {
-            synchronized(mManagerCallback) {
-                if (mService != null) return mService.getScanMode();
-            }
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
+            mServiceLock.readLock().lock();
+            if (mService != null) return mService.getScanMode();
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
         return SCAN_MODE_NONE;
     }
 
@@ -1128,10 +1168,13 @@
     public boolean setScanMode(@ScanMode int mode, int duration) {
         if (getState() != STATE_ON) return false;
         try {
-            synchronized(mManagerCallback) {
-                if (mService != null) return mService.setScanMode(mode, duration);
-            }
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
+            mServiceLock.readLock().lock();
+            if (mService != null) return mService.setScanMode(mode, duration);
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
         return false;
     }
 
@@ -1146,10 +1189,13 @@
     public int getDiscoverableTimeout() {
         if (getState() != STATE_ON) return -1;
         try {
-            synchronized(mManagerCallback) {
-                if (mService != null) return mService.getDiscoverableTimeout();
-            }
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
+            mServiceLock.readLock().lock();
+            if (mService != null) return mService.getDiscoverableTimeout();
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
         return -1;
     }
 
@@ -1157,10 +1203,13 @@
     public void setDiscoverableTimeout(int timeout) {
         if (getState() != STATE_ON) return;
         try {
-            synchronized(mManagerCallback) {
-                if (mService != null) mService.setDiscoverableTimeout(timeout);
-            }
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
+            mServiceLock.readLock().lock();
+            if (mService != null) mService.setDiscoverableTimeout(timeout);
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
     }
 
     /**
@@ -1197,10 +1246,13 @@
     public boolean startDiscovery() {
         if (getState() != STATE_ON) return false;
         try {
-            synchronized(mManagerCallback) {
-                if (mService != null) return mService.startDiscovery();
-            }
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
+            mServiceLock.readLock().lock();
+            if (mService != null) return mService.startDiscovery();
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
         return false;
     }
 
@@ -1225,10 +1277,13 @@
     public boolean cancelDiscovery() {
         if (getState() != STATE_ON) return false;
         try {
-            synchronized(mManagerCallback) {
-                if (mService != null) return mService.cancelDiscovery();
-            }
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
+            mServiceLock.readLock().lock();
+            if (mService != null) return mService.cancelDiscovery();
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
         return false;
     }
 
@@ -1255,10 +1310,13 @@
     public boolean isDiscovering() {
         if (getState() != STATE_ON) return false;
         try {
-            synchronized(mManagerCallback) {
-                if (mService != null ) return mService.isDiscovering();
-            }
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
+            mServiceLock.readLock().lock();
+            if (mService != null) return mService.isDiscovering();
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
         return false;
     }
 
@@ -1270,9 +1328,12 @@
     public boolean isMultipleAdvertisementSupported() {
         if (getState() != STATE_ON) return false;
         try {
-            return mService.isMultiAdvertisementSupported();
+            mServiceLock.readLock().lock();
+            if (mService != null) return mService.isMultiAdvertisementSupported();
         } catch (RemoteException e) {
             Log.e(TAG, "failed to get isMultipleAdvertisementSupported, error: ", e);
+        } finally {
+            mServiceLock.readLock().unlock();
         }
         return false;
     }
@@ -1305,9 +1366,12 @@
     public boolean isPeripheralModeSupported() {
         if (getState() != STATE_ON) return false;
         try {
-            return mService.isPeripheralModeSupported();
+            mServiceLock.readLock().lock();
+            if (mService != null) return mService.isPeripheralModeSupported();
         } catch (RemoteException e) {
             Log.e(TAG, "failed to get peripheral mode capability: ", e);
+        } finally {
+            mServiceLock.readLock().unlock();
         }
         return false;
     }
@@ -1320,9 +1384,12 @@
     public boolean isOffloadedFilteringSupported() {
         if (!getLeAccess()) return false;
         try {
-            return mService.isOffloadedFilteringSupported();
+            mServiceLock.readLock().lock();
+            if (mService != null) return mService.isOffloadedFilteringSupported();
         } catch (RemoteException e) {
             Log.e(TAG, "failed to get isOffloadedFilteringSupported, error: ", e);
+        } finally {
+            mServiceLock.readLock().unlock();
         }
         return false;
     }
@@ -1335,9 +1402,12 @@
     public boolean isOffloadedScanBatchingSupported() {
         if (!getLeAccess()) return false;
         try {
-            return mService.isOffloadedScanBatchingSupported();
+            mServiceLock.readLock().lock();
+            if (mService != null) return mService.isOffloadedScanBatchingSupported();
         } catch (RemoteException e) {
             Log.e(TAG, "failed to get isOffloadedScanBatchingSupported, error: ", e);
+        } finally {
+            mServiceLock.readLock().unlock();
         }
         return false;
     }
@@ -1376,9 +1446,12 @@
     public BluetoothActivityEnergyInfo getControllerActivityEnergyInfo(int updateType) {
         if (getState() != STATE_ON) return null;
         try {
+            mServiceLock.readLock().lock();
             BluetoothActivityEnergyInfo record;
-            if (!mService.isActivityAndEnergyReportingSupported()) {
-                return null;
+            if (mService != null) {
+                if (!mService.isActivityAndEnergyReportingSupported()) {
+                    return null;
+                }
             }
             synchronized(this) {
                 if (updateType == ACTIVITY_ENERGY_INFO_REFRESHED) {
@@ -1396,6 +1469,8 @@
             Log.e(TAG, "getControllerActivityEnergyInfoCallback wait interrupted: " + e);
         } catch (RemoteException e) {
             Log.e(TAG, "getControllerActivityEnergyInfoCallback: " + e);
+        } finally {
+            mServiceLock.readLock().unlock();
         }
         return null;
     }
@@ -1417,11 +1492,14 @@
             return toDeviceSet(new BluetoothDevice[0]);
         }
         try {
-            synchronized(mManagerCallback) {
-                if (mService != null) return toDeviceSet(mService.getBondedDevices());
-            }
+            mServiceLock.readLock().lock();
+            if (mService != null) return toDeviceSet(mService.getBondedDevices());
             return toDeviceSet(new BluetoothDevice[0]);
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
         return null;
     }
 
@@ -1441,10 +1519,13 @@
     public int getConnectionState() {
         if (getState() != STATE_ON) return BluetoothAdapter.STATE_DISCONNECTED;
         try {
-            synchronized(mManagerCallback) {
-                if (mService != null) return mService.getAdapterConnectionState();
-            }
-        } catch (RemoteException e) {Log.e(TAG, "getConnectionState:", e);}
+            mServiceLock.readLock().lock();
+            if (mService != null) return mService.getAdapterConnectionState();
+        } catch (RemoteException e) {
+            Log.e(TAG, "getConnectionState:", e);
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
         return BluetoothAdapter.STATE_DISCONNECTED;
     }
 
@@ -1467,11 +1548,12 @@
     public int getProfileConnectionState(int profile) {
         if (getState() != STATE_ON) return BluetoothProfile.STATE_DISCONNECTED;
         try {
-            synchronized(mManagerCallback) {
-                if (mService != null) return mService.getProfileConnectionState(profile);
-            }
+            mServiceLock.readLock().lock();
+            if (mService != null) return mService.getProfileConnectionState(profile);
         } catch (RemoteException e) {
             Log.e(TAG, "getProfileConnectionState:", e);
+        } finally {
+            mServiceLock.readLock().unlock();
         }
         return BluetoothProfile.STATE_DISCONNECTED;
     }
@@ -1775,7 +1857,9 @@
             byte[] hash;
             byte[] randomizer;
 
-            byte[] ret = mService.readOutOfBandData();
+            byte[] ret = null;
+            mServiceLock.readLock().lock();
+            if (mService != null) mService.readOutOfBandData();
 
             if (ret  == null || ret.length != 32) return null;
 
@@ -1788,7 +1872,12 @@
             }
             return new Pair<byte[], byte[]>(hash, randomizer);
 
-        } catch (RemoteException e) {Log.e(TAG, "", e);}*/
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
+        */
         return null;
     }
 
@@ -1917,17 +2006,21 @@
         new IBluetoothManagerCallback.Stub() {
             public void onBluetoothServiceUp(IBluetooth bluetoothService) {
                 if (VDBG) Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService);
-                synchronized (mManagerCallback) {
-                    mService = bluetoothService;
-                    synchronized (mProxyServiceStateCallbacks) {
-                        for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){
-                            try {
-                                if (cb != null) {
-                                    cb.onBluetoothServiceUp(bluetoothService);
-                                } else {
-                                    Log.d(TAG, "onBluetoothServiceUp: cb is null!!!");
-                                }
-                            } catch (Exception e)  { Log.e(TAG,"",e);}
+
+                mServiceLock.writeLock().lock();
+                mService = bluetoothService;
+                mServiceLock.writeLock().unlock();
+
+                synchronized (mProxyServiceStateCallbacks) {
+                    for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ) {
+                        try {
+                            if (cb != null) {
+                                cb.onBluetoothServiceUp(bluetoothService);
+                            } else {
+                                Log.d(TAG, "onBluetoothServiceUp: cb is null!!!");
+                            }
+                        } catch (Exception e) {
+                            Log.e(TAG,"",e);
                         }
                     }
                 }
@@ -1935,20 +2028,24 @@
 
             public void onBluetoothServiceDown() {
                 if (VDBG) Log.d(TAG, "onBluetoothServiceDown: " + mService);
-                synchronized (mManagerCallback) {
-                    mService = null;
-                    if (mLeScanClients != null) mLeScanClients.clear();
-                    if (sBluetoothLeAdvertiser != null) sBluetoothLeAdvertiser.cleanup();
-                    if (sBluetoothLeScanner != null) sBluetoothLeScanner.cleanup();
-                    synchronized (mProxyServiceStateCallbacks) {
-                        for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){
-                            try {
-                                if (cb != null) {
-                                    cb.onBluetoothServiceDown();
-                                } else {
-                                    Log.d(TAG, "onBluetoothServiceDown: cb is null!!!");
-                                }
-                            } catch (Exception e)  { Log.e(TAG,"",e);}
+
+                mServiceLock.writeLock().lock();
+                mService = null;
+                if (mLeScanClients != null) mLeScanClients.clear();
+                if (sBluetoothLeAdvertiser != null) sBluetoothLeAdvertiser.cleanup();
+                if (sBluetoothLeScanner != null) sBluetoothLeScanner.cleanup();
+                mServiceLock.writeLock().unlock();
+
+                synchronized (mProxyServiceStateCallbacks) {
+                    for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){
+                        try {
+                            if (cb != null) {
+                                cb.onBluetoothServiceDown();
+                            } else {
+                                Log.d(TAG, "onBluetoothServiceDown: cb is null!!!");
+                            }
+                        } catch (Exception e) {
+                            Log.e(TAG,"",e);
                         }
                     }
                 }
@@ -2011,11 +2108,17 @@
         //TODO(BT)
         /*
         try {
-            return mService.changeApplicationBluetoothState(on, new
+            mServiceLock.readLock().lock();
+            if (mService != null) {
+                return mService.changeApplicationBluetoothState(on, new
                     StateChangeCallbackWrapper(callback), new Binder());
+            }
         } catch (RemoteException e) {
             Log.e(TAG, "changeBluetoothState", e);
-        }*/
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
+        */
         return false;
     }
 
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 1e91a2c..e97f6a3 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -54,6 +54,7 @@
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
 import android.util.Log;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 import java.io.FileDescriptor;
 import java.io.IOException;
@@ -129,6 +130,8 @@
     private IBinder mBluetoothBinder;
     private IBluetooth mBluetooth;
     private IBluetoothGatt mBluetoothGatt;
+    private final ReentrantReadWriteLock mBluetoothLock =
+        new ReentrantReadWriteLock();
     private boolean mBinding;
     private boolean mUnbinding;
     // used inside handler thread
@@ -193,12 +196,15 @@
                     }
 
                     int st = BluetoothAdapter.STATE_OFF;
-                    if (mBluetooth != null) {
-                        try {
+                    try {
+                        mBluetoothLock.readLock().lock();
+                        if (mBluetooth != null) {
                             st = mBluetooth.getState();
-                        } catch (RemoteException e) {
-                            Log.e(TAG,"Unable to call getState", e);
                         }
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Unable to call getState", e);
+                    } finally {
+                        mBluetoothLock.readLock().unlock();
                     }
                     Log.d(TAG, "state" + st);
 
@@ -211,12 +217,15 @@
                         if (st == BluetoothAdapter.STATE_BLE_ON) {
                             //if state is BLE_ON make sure you trigger disableBLE part
                             try {
+                                mBluetoothLock.readLock().lock();
                                 if (mBluetooth != null) {
                                     mBluetooth.onBrEdrDown();
                                     mEnableExternal = false;
                                 }
                             } catch(RemoteException e) {
                                 Log.e(TAG,"Unable to call onBrEdrDown", e);
+                            } finally {
+                                mBluetoothLock.readLock().lock();
                             }
                         } else if (st == BluetoothAdapter.STATE_ON){
                             // disable without persisting the setting
@@ -369,9 +378,8 @@
         Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER);
         msg.obj = callback;
         mHandler.sendMessage(msg);
-        synchronized(mConnection) {
-            return mBluetooth;
-        }
+
+        return mBluetooth;
     }
 
     public void unregisterAdapter(IBluetoothManagerCallback callback) {
@@ -409,12 +417,13 @@
             return false;
         }
 
-        synchronized(mConnection) {
-            try {
-                return (mBluetooth != null && mBluetooth.isEnabled());
-            } catch (RemoteException e) {
-                Log.e(TAG, "isEnabled()", e);
-            }
+        try {
+            mBluetoothLock.readLock().lock();
+            if (mBluetooth != null) return mBluetooth.isEnabled();
+        } catch (RemoteException e) {
+            Log.e(TAG, "isEnabled()", e);
+        } finally {
+            mBluetoothLock.readLock().unlock();
         }
         return false;
     }
@@ -427,11 +436,14 @@
             if (mBleAppCount == 0) {
                 if (DBG) Log.d(TAG, "Disabling LE only mode after application crash");
                 try {
+                    mBluetoothLock.readLock().lock();
                     if (mBluetooth != null) {
                         mBluetooth.onBrEdrDown();
                     }
                 } catch(RemoteException e) {
                      Log.e(TAG,"Unable to call onBrEdrDown", e);
+                } finally {
+                    mBluetoothLock.readLock().unlock();
                 }
             }
         }
@@ -459,9 +471,12 @@
                     disableBleScanMode();
                     clearBleApps();
                     try {
+                        mBluetoothLock.readLock().lock();
                         if (mBluetooth != null) mBluetooth.onBrEdrDown();
                     } catch (RemoteException e) {
                         Log.e(TAG, "error when disabling bluetooth", e);
+                    } finally {
+                        mBluetoothLock.readLock().unlock();
                     }
                 }
             }
@@ -475,12 +490,15 @@
     // Disable ble scan only mode.
     private void disableBleScanMode() {
         try {
+            mBluetoothLock.writeLock().lock();
             if (mBluetooth != null && (mBluetooth.getState() != BluetoothAdapter.STATE_ON)) {
                 if (DBG) Log.d(TAG, "Reseting the mEnable flag for clean disable");
                 mEnable = false;
             }
         } catch (RemoteException e) {
             Log.e(TAG, "getState()", e);
+        } finally {
+            mBluetoothLock.writeLock().unlock();
         }
     }
 
@@ -539,7 +557,8 @@
      */
     private void onBluetoothGattServiceUp() {
         if (DBG) Log.d(TAG,"BluetoothGatt Service is Up");
-        try{
+        try {
+            mBluetoothLock.readLock().lock();
             if (isBleAppPresent() == false && mBluetooth != null
                   && mBluetooth.getState() == BluetoothAdapter.STATE_BLE_ON) {
                 mBluetooth.onLeServiceUp();
@@ -549,8 +568,10 @@
                 persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
                 Binder.restoreCallingIdentity(callingIdentity);
             }
-        } catch(RemoteException e) {
-                Log.e(TAG,"Unable to call onServiceUp", e);
+        } catch (RemoteException e) {
+            Log.e(TAG,"Unable to call onServiceUp", e);
+        } finally {
+            mBluetoothLock.readLock().unlock();
         }
     }
 
@@ -561,22 +582,25 @@
     private void sendBrEdrDownCallback() {
         if (DBG) Log.d(TAG,"Calling sendBrEdrDownCallback callbacks");
 
-        if(mBluetooth == null) {
+        if (mBluetooth == null) {
             Log.w(TAG, "Bluetooth handle is null");
             return;
         }
 
         if (isBleAppPresent() == false) {
             try {
-                mBluetooth.onBrEdrDown();
-            } catch(RemoteException e) {
+                mBluetoothLock.readLock().lock();
+                if (mBluetooth != null) mBluetooth.onBrEdrDown();
+            } catch (RemoteException e) {
                 Log.e(TAG, "Call to onBrEdrDown() failed.", e);
+            } finally {
+                mBluetoothLock.readLock().unlock();
             }
         } else {
             // Need to stay at BLE ON. Disconnect all Gatt connections
-            try{
+            try {
                 mBluetoothGatt.unregAll();
-            } catch(RemoteException e) {
+            } catch (RemoteException e) {
                 Log.e(TAG, "Unable to disconnect all apps.", e);
             }
         }
@@ -672,7 +696,8 @@
                 " mBinding = " + mBinding);
         }
 
-        synchronized (mConnection) {
+        try {
+            mBluetoothLock.writeLock().lock();
             if (mUnbinding) return;
             mUnbinding = true;
             if (mBluetooth != null) {
@@ -695,6 +720,8 @@
                 mUnbinding=false;
             }
             mBluetoothGatt = null;
+        } finally {
+            mBluetoothLock.writeLock().unlock();
         }
     }
 
@@ -1007,15 +1034,15 @@
             return BluetoothAdapter.DEFAULT_MAC_ADDRESS;
         }
 
-        synchronized(mConnection) {
-            if (mBluetooth != null) {
-                try {
-                    return mBluetooth.getAddress();
-                } catch (RemoteException e) {
-                    Log.e(TAG, "getAddress(): Unable to retrieve address remotely..Returning cached address",e);
-                }
-            }
+        try {
+            mBluetoothLock.readLock().lock();
+            if (mBluetooth != null) return mBluetooth.getAddress();
+        } catch (RemoteException e) {
+            Log.e(TAG, "getAddress(): Unable to retrieve address remotely. Returning cached address", e);
+        } finally {
+            mBluetoothLock.readLock().unlock();
         }
+
         // mAddress is accessed from outside.
         // It is alright without a lock. Here, bluetooth is off, no other thread is
         // changing mAddress
@@ -1032,15 +1059,15 @@
             return null;
         }
 
-        synchronized(mConnection) {
-            if (mBluetooth != null) {
-                try {
-                    return mBluetooth.getName();
-                } catch (RemoteException e) {
-                    Log.e(TAG, "getName(): Unable to retrieve name remotely..Returning cached name",e);
-                }
-            }
+        try {
+            mBluetoothLock.readLock().lock();
+            if (mBluetooth != null) return mBluetooth.getName();
+        } catch (RemoteException e) {
+            Log.e(TAG, "getName(): Unable to retrieve name remotely. Returning cached name", e);
+        } finally {
+            mBluetoothLock.readLock().unlock();
         }
+
         // mName is accessed from outside.
         // It alright without a lock. Here, bluetooth is off, no other thread is
         // changing mName
@@ -1104,10 +1131,10 @@
         public void handleMessage(Message msg) {
             if (DBG) Log.d (TAG, "Message: " + msg.what);
             switch (msg.what) {
-                case MESSAGE_GET_NAME_AND_ADDRESS: {
-                    if (DBG) Log.d(TAG,"MESSAGE_GET_NAME_AND_ADDRESS");
-                    synchronized(mConnection) {
-                        //Start bind request
+                case MESSAGE_GET_NAME_AND_ADDRESS:
+                    if (DBG) Log.d(TAG, "MESSAGE_GET_NAME_AND_ADDRESS");
+                    try {
+                        mBluetoothLock.writeLock().lock();
                         if ((mBluetooth == null) && (!mBinding)) {
                             if (DBG) Log.d(TAG, "Binding to service to get name and address");
                             mConnection.setGetNameAddressOnly(true);
@@ -1134,23 +1161,28 @@
                                 mHandler.sendMessageDelayed(saveMsg, TIMEOUT_SAVE_MS);
                             }
                         }
+                    } finally {
+                        mBluetoothLock.writeLock().unlock();
                     }
                     break;
-                }
+
                 case MESSAGE_SAVE_NAME_AND_ADDRESS: {
                     boolean unbind = false;
                     if (DBG) Log.d(TAG,"MESSAGE_SAVE_NAME_AND_ADDRESS");
-                    synchronized(mConnection) {
+                    try {
+                        mBluetoothLock.readLock().lock();
                         if (!mEnable && mBluetooth != null && !mConnection.isGetNameAddressOnly()) {
-                            try {
-                                mBluetooth.enable();
-                            } catch (RemoteException e) {
-                                Log.e(TAG,"Unable to call enable()",e);
-                            }
+                            mBluetooth.enable();
                         }
+                    } catch (RemoteException e) {
+                        Log.e(TAG,"Unable to call enable()",e);
+                    } finally {
+                        mBluetoothLock.readLock().unlock();
                     }
+
                     if (mBluetooth != null && !mConnection.isGetNameAddressOnly()) waitForOnOff(true, false);
-                    synchronized(mConnection) {
+                    try {
+                        mBluetoothLock.writeLock().lock();
                         if (mBluetooth != null) {
                             String name =  null;
                             String address = null;
@@ -1193,6 +1225,8 @@
                             Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
                             mHandler.sendMessage(getMsg);
                         }
+                    } finally {
+                        mBluetoothLock.writeLock().unlock();
                     }
                     if (!mEnable && mBluetooth != null && !mConnection.isGetNameAddressOnly()) {
                         waitForOnOff(false, true);
@@ -1281,7 +1315,8 @@
                     if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1);
 
                     IBinder service = (IBinder) msg.obj;
-                    synchronized(mConnection) {
+                    try {
+                        mBluetoothLock.writeLock().lock();
                         if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
                             mBluetoothGatt = IBluetoothGatt.Stub.asInterface(service);
                             onBluetoothGattServiceUp();
@@ -1338,6 +1373,8 @@
                         } catch (RemoteException e) {
                             Log.e(TAG,"Unable to call enable()",e);
                         }
+                    } finally {
+                        mBluetoothLock.writeLock().unlock();
                     }
 
                     if (!mEnable) {
@@ -1349,9 +1386,9 @@
                 }
                 case MESSAGE_TIMEOUT_BIND: {
                     Log.e(TAG, "MESSAGE_TIMEOUT_BIND");
-                    synchronized(mConnection) {
-                        mBinding = false;
-                    }
+                    mBluetoothLock.writeLock().lock();
+                    mBinding = false;
+                    mBluetoothLock.writeLock().unlock();
                     break;
                 }
                 case MESSAGE_BLUETOOTH_STATE_CHANGE:
@@ -1386,7 +1423,8 @@
                 case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:
                 {
                     Log.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: " + msg.arg1);
-                    synchronized(mConnection) {
+                    try {
+                        mBluetoothLock.writeLock().lock();
                         if (msg.arg1 == SERVICE_IBLUETOOTH) {
                             // if service is unbinded already, do nothing and return
                             if (mBluetooth == null) break;
@@ -1398,6 +1436,8 @@
                             Log.e(TAG, "Bad msg.arg1: " + msg.arg1);
                             break;
                         }
+                    } finally {
+                        mBluetoothLock.writeLock().unlock();
                     }
 
                     if (mEnable) {
@@ -1445,9 +1485,9 @@
                 case MESSAGE_TIMEOUT_UNBIND:
                 {
                     Log.e(TAG, "MESSAGE_TIMEOUT_UNBIND");
-                    synchronized(mConnection) {
-                        mUnbinding = false;
-                    }
+                    mBluetoothLock.writeLock().lock();
+                    mUnbinding = false;
+                    mBluetoothLock.writeLock().unlock();
                     break;
                 }
 
@@ -1459,15 +1499,15 @@
                     mHandler.removeMessages(MESSAGE_USER_SWITCHED);
                     /* disable and enable BT when detect a user switch */
                     if (mEnable && mBluetooth != null) {
-                        synchronized (mConnection) {
+                        try {
+                            mBluetoothLock.readLock().lock();
                             if (mBluetooth != null) {
-                                //Unregister callback object
-                                try {
-                                    mBluetooth.unregisterCallback(mBluetoothCallback);
-                                } catch (RemoteException re) {
-                                    Log.e(TAG, "Unable to unregister",re);
-                                }
+                                mBluetooth.unregisterCallback(mBluetoothCallback);
                             }
+                        } catch (RemoteException re) {
+                            Log.e(TAG, "Unable to unregister", re);
+                        } finally {
+                            mBluetoothLock.readLock().unlock();
                         }
 
                         if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
@@ -1498,14 +1538,16 @@
                         bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
                                                     BluetoothAdapter.STATE_OFF);
                         sendBluetoothServiceDownCallback();
-                        synchronized (mConnection) {
-                            if (mBluetooth != null) {
-                                mBluetooth = null;
-                                //Unbind
-                                mContext.unbindService(mConnection);
-                            }
-                            mBluetoothGatt = null;
+
+                        mBluetoothLock.writeLock().lock();
+                        if (mBluetooth != null) {
+                            mBluetooth = null;
+                            // Unbind
+                            mContext.unbindService(mConnection);
                         }
+                        mBluetoothGatt = null;
+                        mBluetoothLock.writeLock().unlock();
+
                         SystemClock.sleep(100);
 
                         mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
@@ -1531,7 +1573,8 @@
     private void handleEnable(boolean quietMode) {
         mQuietEnable = quietMode;
 
-        synchronized(mConnection) {
+        try {
+            mBluetoothLock.writeLock().lock();
             if ((mBluetooth == null) && (!mBinding)) {
                 //Start bind timeout and bind
                 Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
@@ -1576,6 +1619,8 @@
                     Log.e(TAG,"Unable to call enable()",e);
                 }
             }
+        } finally {
+            mBluetoothLock.writeLock().unlock();
         }
     }
 
@@ -1590,20 +1635,18 @@
     }
 
     private void handleDisable() {
-        synchronized(mConnection) {
-            // don't need to disable if GetNameAddressOnly is set,
-            // service will be unbinded after Name and Address are saved
-            if ((mBluetooth != null) && (!mConnection.isGetNameAddressOnly())) {
+        try {
+            mBluetoothLock.readLock().lock();
+            if (mBluetooth != null) {
                 if (DBG) Log.d(TAG,"Sending off request.");
-
-                try {
-                    if(!mBluetooth.disable()) {
-                        Log.e(TAG,"IBluetooth.disable() returned false");
-                    }
-                } catch (RemoteException e) {
-                    Log.e(TAG,"Unable to call disable()",e);
+                if (!mBluetooth.disable()) {
+                    Log.e(TAG,"IBluetooth.disable() returned false");
                 }
             }
+        } catch (RemoteException e) {
+            Log.e(TAG,"Unable to call disable()",e);
+        } finally {
+            mBluetoothLock.readLock().unlock();
         }
     }
 
@@ -1730,20 +1773,21 @@
     private boolean waitForOnOff(boolean on, boolean off) {
         int i = 0;
         while (i < 10) {
-            synchronized(mConnection) {
-                try {
-                    if (mBluetooth == null) break;
-                    if (on) {
-                        if (mBluetooth.getState() == BluetoothAdapter.STATE_ON) return true;
-                    } else if (off) {
-                        if (mBluetooth.getState() == BluetoothAdapter.STATE_OFF) return true;
-                    } else {
-                        if (mBluetooth.getState() != BluetoothAdapter.STATE_ON) return true;
-                    }
-                } catch (RemoteException e) {
-                    Log.e(TAG, "getState()", e);
-                    break;
+            try {
+                mBluetoothLock.readLock().lock();
+                if (mBluetooth == null) break;
+                if (on) {
+                    if (mBluetooth.getState() == BluetoothAdapter.STATE_ON) return true;
+                } else if (off) {
+                    if (mBluetooth.getState() == BluetoothAdapter.STATE_OFF) return true;
+                } else {
+                    if (mBluetooth.getState() != BluetoothAdapter.STATE_ON) return true;
                 }
+            } catch (RemoteException e) {
+                Log.e(TAG, "getState()", e);
+                break;
+            } finally {
+                mBluetoothLock.readLock().unlock();
             }
             if (on || off) {
                 SystemClock.sleep(300);
@@ -1766,34 +1810,36 @@
     }
 
     private boolean canUnbindBluetoothService() {
-        synchronized(mConnection) {
+        try {
             //Only unbind with mEnable flag not set
             //For race condition: disable and enable back-to-back
             //Avoid unbind right after enable due to callback from disable
             //Only unbind with Bluetooth at OFF state
             //Only unbind without any MESSAGE_BLUETOOTH_STATE_CHANGE message
-            try {
-                if (mEnable || (mBluetooth == null)) return false;
-                if (mHandler.hasMessages(MESSAGE_BLUETOOTH_STATE_CHANGE)) return false;
-                return (mBluetooth.getState() == BluetoothAdapter.STATE_OFF);
-            } catch (RemoteException e) {
-                Log.e(TAG, "getState()", e);
-            }
+            mBluetoothLock.readLock().lock();
+            if (mEnable || (mBluetooth == null)) return false;
+            if (mHandler.hasMessages(MESSAGE_BLUETOOTH_STATE_CHANGE)) return false;
+            return (mBluetooth.getState() == BluetoothAdapter.STATE_OFF);
+        } catch (RemoteException e) {
+            Log.e(TAG, "getState()", e);
+        } finally {
+            mBluetoothLock.readLock().unlock();
         }
         return false;
     }
 
     private void recoverBluetoothServiceFromError() {
         Log.e(TAG,"recoverBluetoothServiceFromError");
-        synchronized (mConnection) {
+        try {
+            mBluetoothLock.readLock().lock();
             if (mBluetooth != null) {
                 //Unregister callback object
-                try {
-                    mBluetooth.unregisterCallback(mBluetoothCallback);
-                } catch (RemoteException re) {
-                    Log.e(TAG, "Unable to unregister",re);
-                }
+                mBluetooth.unregisterCallback(mBluetoothCallback);
             }
+        } catch (RemoteException re) {
+            Log.e(TAG, "Unable to unregister", re);
+        } finally {
+            mBluetoothLock.readLock().unlock();
         }
 
         SystemClock.sleep(500);
@@ -1804,14 +1850,15 @@
         waitForOnOff(false, true);
 
         sendBluetoothServiceDownCallback();
-        synchronized (mConnection) {
-            if (mBluetooth != null) {
-                mBluetooth = null;
-                //Unbind
-                mContext.unbindService(mConnection);
-            }
-            mBluetoothGatt = null;
+
+        mBluetoothLock.writeLock().lock();
+        if (mBluetooth != null) {
+            mBluetooth = null;
+            // Unbind
+            mContext.unbindService(mConnection);
         }
+        mBluetoothGatt = null;
+        mBluetoothLock.writeLock().unlock();
 
         mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
         mState = BluetoothAdapter.STATE_OFF;