diff options
| author | 2011-06-06 11:02:30 +0900 | |
|---|---|---|
| committer | 2011-06-23 17:37:07 -0700 | |
| commit | 5312af0c95d781a00298c6f919f95f6f6f442099 (patch) | |
| tree | 410821d783038a46f807af81936d7678ccc7e6d6 | |
| parent | 7656b21e6313671437c9fbc9bb16096072b1ead5 (diff) | |
Fix excessive locking synchronization leading to deadlocks.
We should never have to look on the entire instance. There
are many places in the code where it there and we need to fix it.
This is a start. In this particular case what we are protecting
is the properties map of the remote device and thus we just need to lock
on it. Ofcourse, it would be better to have a state machine but this
is good for now.
Deadlock: When a new device was found it will call addProperties which will hold
a lock. addProperties calls into BluetoothService. Now Settings app makes a call
into BluetoothService which will call into this file and we have a deadlock.
Change-Id: Ieb69d5ace222bf5d1e6677af151241153303099f
| -rw-r--r-- | core/java/android/server/BluetoothDeviceProperties.java | 112 |
1 files changed, 62 insertions, 50 deletions
diff --git a/core/java/android/server/BluetoothDeviceProperties.java b/core/java/android/server/BluetoothDeviceProperties.java index 3dc53d7c0fc8..fe3ef793e8cd 100644 --- a/core/java/android/server/BluetoothDeviceProperties.java +++ b/core/java/android/server/BluetoothDeviceProperties.java @@ -35,43 +35,45 @@ class BluetoothDeviceProperties { mService = service; } - synchronized Map<String, String> addProperties(String address, - String[] properties) { + Map<String, String> addProperties(String address, String[] properties) { /* * We get a DeviceFound signal every time RSSI changes or name changes. * Don't create a new Map object every time. */ - Map<String, String> propertyValues = mPropertiesMap.get(address); - if (propertyValues == null) { - propertyValues = new HashMap<String, String>(); - } + Map<String, String> propertyValues; + synchronized(mPropertiesMap) { + propertyValues = mPropertiesMap.get(address); + if (propertyValues == null) { + propertyValues = new HashMap<String, String>(); + } - for (int i = 0; i < properties.length; i++) { - String name = properties[i]; - String newValue = null; - int len; - if (name == null) { - Log.e(TAG, "Error: Remote Device Property at index " + for (int i = 0; i < properties.length; i++) { + String name = properties[i]; + String newValue = null; + int len; + if (name == null) { + Log.e(TAG, "Error: Remote Device Property at index " + i + " is null"); - continue; - } - if (name.equals("UUIDs") || name.equals("Nodes")) { - StringBuilder str = new StringBuilder(); - len = Integer.valueOf(properties[++i]); - for (int j = 0; j < len; j++) { - str.append(properties[++i]); - str.append(","); + continue; } - if (len > 0) { - newValue = str.toString(); + if (name.equals("UUIDs") || name.equals("Nodes")) { + StringBuilder str = new StringBuilder(); + len = Integer.valueOf(properties[++i]); + for (int j = 0; j < len; j++) { + str.append(properties[++i]); + str.append(","); + } + if (len > 0) { + newValue = str.toString(); + } + } else { + newValue = properties[++i]; } - } else { - newValue = properties[++i]; - } - propertyValues.put(name, newValue); + propertyValues.put(name, newValue); + } + mPropertiesMap.put(address, propertyValues); } - mPropertiesMap.put(address, propertyValues); // We have added a new remote device or updated its properties. // Also update the serviceChannel cache. @@ -79,46 +81,56 @@ class BluetoothDeviceProperties { return propertyValues; } - synchronized void setProperty(String address, String name, String value) { - Map <String, String> propVal = mPropertiesMap.get(address); - if (propVal != null) { - propVal.put(name, value); - mPropertiesMap.put(address, propVal); - } else { - Log.e(TAG, "setRemoteDeviceProperty for a device not in cache:" + address); + void setProperty(String address, String name, String value) { + synchronized(mPropertiesMap) { + Map <String, String> propVal = mPropertiesMap.get(address); + if (propVal != null) { + propVal.put(name, value); + mPropertiesMap.put(address, propVal); + } else { + Log.e(TAG, "setRemoteDeviceProperty for a device not in cache:" + address); + } } } - synchronized boolean isInCache(String address) { - return (mPropertiesMap.get(address) != null); + boolean isInCache(String address) { + synchronized (mPropertiesMap) { + return (mPropertiesMap.get(address) != null); + } } - synchronized boolean isEmpty() { - return mPropertiesMap.isEmpty(); + boolean isEmpty() { + synchronized (mPropertiesMap) { + return mPropertiesMap.isEmpty(); + } } - synchronized Set<String> keySet() { - return mPropertiesMap.keySet(); + Set<String> keySet() { + synchronized (mPropertiesMap) { + return mPropertiesMap.keySet(); + } } - synchronized String getProperty(String address, String property) { - Map<String, String> properties = mPropertiesMap.get(address); - if (properties != null) { - return properties.get(property); - } else { - // Query for remote device properties, again. - // We will need to reload the cache when we switch Bluetooth on / off - // or if we crash. - properties = updateCache(address); + String getProperty(String address, String property) { + synchronized(mPropertiesMap) { + Map<String, String> properties = mPropertiesMap.get(address); if (properties != null) { return properties.get(property); + } else { + // Query for remote device properties, again. + // We will need to reload the cache when we switch Bluetooth on / off + // or if we crash. + properties = updateCache(address); + if (properties != null) { + return properties.get(property); + } } } Log.e(TAG, "getRemoteDeviceProperty: " + property + " not present: " + address); return null; } - synchronized Map<String, String> updateCache(String address) { + Map<String, String> updateCache(String address) { String[] propValues = mService.getRemoteDeviceProperties(address); if (propValues != null) { return addProperties(address, propValues); |