Fix AAE dev guide sycnhronized pattern issues + receiver leak
Bug: b/143696191
Bug: b/143695396
Test: Build, Flash automotive hardware, force reconnects, test projected
applications, run atest unit tests, run automated tests using dumpsys
activity broadcasts com.android.car to watch for leaked receivers
Change-Id: I344e4b67b2ad5e25747f6f4c74bd55d1554893fe
diff --git a/service/src/com/android/car/BluetoothDeviceConnectionPolicy.java b/service/src/com/android/car/BluetoothDeviceConnectionPolicy.java
index 4bb2790..c0f393a 100644
--- a/service/src/com/android/car/BluetoothDeviceConnectionPolicy.java
+++ b/service/src/com/android/car/BluetoothDeviceConnectionPolicy.java
@@ -117,7 +117,7 @@
}
}
}
- private BluetoothBroadcastReceiver mBluetoothBroadcastReceiver;
+ private final BluetoothBroadcastReceiver mBluetoothBroadcastReceiver;
/**
* Create a new BluetoothDeviceConnectionPolicy object, responsible for encapsulating the
@@ -153,6 +153,7 @@
mUserId = userId;
mContext = Objects.requireNonNull(context);
mCarBluetoothService = bluetoothService;
+ mBluetoothBroadcastReceiver = new BluetoothBroadcastReceiver();
mBluetoothAdapter = Objects.requireNonNull(BluetoothAdapter.getDefaultAdapter());
}
@@ -160,9 +161,8 @@
* Setup the Bluetooth profile service connections and Vehicle Event listeners.
* and start the state machine -{@link BluetoothAutoConnectStateMachine}
*/
- public synchronized void init() {
+ public void init() {
logd("init()");
- mBluetoothBroadcastReceiver = new BluetoothBroadcastReceiver();
IntentFilter profileFilter = new IntentFilter();
profileFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
mContext.registerReceiverAsUser(mBluetoothBroadcastReceiver, UserHandle.CURRENT,
@@ -190,7 +190,7 @@
* Clean up slate. Close the Bluetooth profile service connections and quit the state machine -
* {@link BluetoothAutoConnectStateMachine}
*/
- public synchronized void release() {
+ public void release() {
logd("release()");
if (mCarPowerManager != null) {
mCarPowerManager.clearListener();
@@ -198,7 +198,6 @@
}
if (mBluetoothBroadcastReceiver != null) {
mContext.unregisterReceiver(mBluetoothBroadcastReceiver);
- mBluetoothBroadcastReceiver = null;
}
}
@@ -250,7 +249,7 @@
/**
* Print the verbose status of the object
*/
- public synchronized void dump(PrintWriter writer, String indent) {
+ public void dump(PrintWriter writer, String indent) {
writer.println(indent + TAG + ":");
writer.println(indent + "\tUserId: " + mUserId);
}
diff --git a/service/src/com/android/car/BluetoothProfileDeviceManager.java b/service/src/com/android/car/BluetoothProfileDeviceManager.java
index 505a05b..e73d9ea 100644
--- a/service/src/com/android/car/BluetoothProfileDeviceManager.java
+++ b/service/src/com/android/car/BluetoothProfileDeviceManager.java
@@ -46,6 +46,8 @@
import android.util.Log;
import android.util.SparseArray;
+import com.android.internal.annotations.GuardedBy;
+
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
@@ -114,23 +116,30 @@
}, new int[] {}));
}
+ // Fixed per-profile information for the profile this object manages
private final int mProfileId;
private final String mSettingsKey;
private final String mProfileConnectionAction;
private final ParcelUuid[] mProfileUuids;
private final int[] mProfileTriggers;
+
+ // Central priority list of devices
+ private final Object mPrioritizedDevicesLock = new Object();
+ @GuardedBy("mPrioritizedDevicesLock")
private ArrayList<BluetoothDevice> mPrioritizedDevices;
- private BluetoothAdapter mBluetoothAdapter;
- private BluetoothBroadcastReceiver mBluetoothBroadcastReceiver;
-
- private ICarBluetoothUserService mBluetoothUserProxies;
-
+ // Auto connection process state
private final Object mAutoConnectLock = new Object();
+ @GuardedBy("mAutoConnectLock")
private boolean mConnecting = false;
+ @GuardedBy("mAutoConnectLock")
private int mAutoConnectPriority;
+ @GuardedBy("mAutoConnectLock")
private ArrayList<BluetoothDevice> mAutoConnectingDevices;
+ private final BluetoothAdapter mBluetoothAdapter;
+ private final BluetoothBroadcastReceiver mBluetoothBroadcastReceiver;
+ private final ICarBluetoothUserService mBluetoothUserProxies;
private final Handler mHandler = new Handler(Looper.getMainLooper());
/**
@@ -313,6 +322,7 @@
mProfileUuids = bpi.mUuids;
mProfileTriggers = bpi.mProfileTriggers;
+ mBluetoothBroadcastReceiver = new BluetoothBroadcastReceiver();
mBluetoothAdapter = Objects.requireNonNull(BluetoothAdapter.getDefaultAdapter());
}
@@ -327,7 +337,7 @@
mAutoConnectPriority = -1;
mAutoConnectingDevices = null;
}
- mBluetoothBroadcastReceiver = new BluetoothBroadcastReceiver();
+
IntentFilter profileFilter = new IntentFilter();
profileFilter.addAction(mProfileConnectionAction);
profileFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
@@ -347,7 +357,6 @@
if (mContext != null) {
mContext.unregisterReceiver(mBluetoothBroadcastReceiver);
}
- mBluetoothBroadcastReceiver = null;
}
cancelAutoConnecting();
commit();
@@ -392,7 +401,7 @@
}
}
- synchronized (this) {
+ synchronized (mPrioritizedDevicesLock) {
mPrioritizedDevices = devices;
}
@@ -408,7 +417,7 @@
private boolean commit() {
StringBuilder sb = new StringBuilder();
String delimiter = "";
- synchronized (this) {
+ synchronized (mPrioritizedDevicesLock) {
for (BluetoothDevice device : mPrioritizedDevices) {
sb.append(delimiter);
sb.append(device.getAddress());
@@ -434,7 +443,7 @@
addDevice(device); // No-op if device is already in the priority list
}
- synchronized (this) {
+ synchronized (mPrioritizedDevicesLock) {
ArrayList<BluetoothDevice> devices = getDeviceListSnapshot();
for (BluetoothDevice device : devices) {
if (!bondedDevices.contains(device)) {
@@ -451,7 +460,7 @@
*/
public ArrayList<BluetoothDevice> getDeviceListSnapshot() {
ArrayList<BluetoothDevice> devices = new ArrayList<>();
- synchronized (this) {
+ synchronized (mPrioritizedDevicesLock) {
devices = (ArrayList) mPrioritizedDevices.clone();
}
return devices;
@@ -462,12 +471,14 @@
*
* @param device - The device you wish to add
*/
- public synchronized void addDevice(BluetoothDevice device) {
+ public void addDevice(BluetoothDevice device) {
if (device == null) return;
- if (mPrioritizedDevices.contains(device)) return;
- logd("Add device " + device);
- mPrioritizedDevices.add(device);
- commit();
+ synchronized (mPrioritizedDevicesLock) {
+ if (mPrioritizedDevices.contains(device)) return;
+ logd("Add device " + device);
+ mPrioritizedDevices.add(device);
+ commit();
+ }
}
/**
@@ -475,12 +486,14 @@
*
* @param device - The device you wish to remove
*/
- public synchronized void removeDevice(BluetoothDevice device) {
+ public void removeDevice(BluetoothDevice device) {
if (device == null) return;
- if (!mPrioritizedDevices.contains(device)) return;
- logd("Remove device " + device);
- mPrioritizedDevices.remove(device);
- commit();
+ synchronized (mPrioritizedDevicesLock) {
+ if (!mPrioritizedDevices.contains(device)) return;
+ logd("Remove device " + device);
+ mPrioritizedDevices.remove(device);
+ commit();
+ }
}
/**
@@ -489,10 +502,12 @@
* @param device - The device you want the priority of
* @return The priority of the device, or -1 if the device is not in the list
*/
- public synchronized int getDeviceConnectionPriority(BluetoothDevice device) {
+ public int getDeviceConnectionPriority(BluetoothDevice device) {
if (device == null) return -1;
logd("Get connection priority of " + device);
- return mPrioritizedDevices.indexOf(device);
+ synchronized (mPrioritizedDevicesLock) {
+ return mPrioritizedDevices.indexOf(device);
+ }
}
/**
@@ -505,16 +520,18 @@
* @param device - The device you want to set the priority of
* @param priority - The priority you want to the device to have
*/
- public synchronized void setDeviceConnectionPriority(BluetoothDevice device, int priority) {
- if (device == null || priority < 0 || priority > mPrioritizedDevices.size()
- || getDeviceConnectionPriority(device) == priority) return;
- if (mPrioritizedDevices.contains(device)) {
- mPrioritizedDevices.remove(device);
- if (priority > mPrioritizedDevices.size()) priority = mPrioritizedDevices.size();
+ public void setDeviceConnectionPriority(BluetoothDevice device, int priority) {
+ synchronized (mPrioritizedDevicesLock) {
+ if (device == null || priority < 0 || priority > mPrioritizedDevices.size()
+ || getDeviceConnectionPriority(device) == priority) return;
+ if (mPrioritizedDevices.contains(device)) {
+ mPrioritizedDevices.remove(device);
+ if (priority > mPrioritizedDevices.size()) priority = mPrioritizedDevices.size();
+ }
+ logd("Set connection priority of " + device + " to " + priority);
+ mPrioritizedDevices.add(priority, device);
+ commit();
}
- logd("Set connection priority of " + device + " to " + priority);
- mPrioritizedDevices.add(priority, device);
- commit();
}
/**
diff --git a/service/src/com/android/car/BluetoothProfileInhibitManager.java b/service/src/com/android/car/BluetoothProfileInhibitManager.java
index 4dcc6b7..691592f 100644
--- a/service/src/com/android/car/BluetoothProfileInhibitManager.java
+++ b/service/src/com/android/car/BluetoothProfileInhibitManager.java
@@ -56,14 +56,16 @@
private final int mUserId;
private final ICarBluetoothUserService mBluetoothUserProxies;
- @GuardedBy("this")
+ private final Object mProfileInhibitsLock = new Object();
+
+ @GuardedBy("mProfileInhibitsLock")
private final SetMultimap<BluetoothConnection, InhibitRecord> mProfileInhibits =
new SetMultimap<>();
- @GuardedBy("this")
+ @GuardedBy("mProfileInhibitsLock")
private final HashSet<InhibitRecord> mRestoredInhibits = new HashSet<>();
- @GuardedBy("this")
+ @GuardedBy("mProfileInhibitsLock")
private final HashSet<BluetoothConnection> mAlreadyDisabledProfiles = new HashSet<>();
private final Handler mHandler = new Handler(Looper.getMainLooper());
@@ -190,7 +192,7 @@
}
public boolean removeSelf() {
- synchronized (BluetoothProfileInhibitManager.this) {
+ synchronized (mProfileInhibitsLock) {
if (mRemoved) {
return true;
}
@@ -328,9 +330,7 @@
BluetoothConnection params = new BluetoothConnection(profile, device);
InhibitRecord record;
- synchronized (this) {
- record = findInhibitRecord(params, token);
- }
+ record = findInhibitRecord(params, token);
if (record == null) {
Log.e(TAG, "Record not found");
@@ -343,64 +343,66 @@
/**
* Add a profile inhibit record, disabling the profile if necessary.
*/
- private synchronized boolean addInhibitRecord(InhibitRecord record) {
- BluetoothConnection params = record.getParams();
- if (!isProxyAvailable(params.getProfile())) {
- return false;
- }
-
- Set<InhibitRecord> previousRecords = mProfileInhibits.get(params);
- if (findInhibitRecord(params, record.getToken()) != null) {
- Log.e(TAG, "Inhibit request already registered - skipping duplicate");
- return false;
- }
-
- try {
- record.getToken().linkToDeath(record, 0);
- } catch (RemoteException e) {
- Log.e(TAG, "Could not link to death on inhibit token (already dead?)", e);
- return false;
- }
-
- boolean isNewlyAdded = previousRecords.isEmpty();
- mProfileInhibits.put(params, record);
-
- if (isNewlyAdded) {
- try {
- int priority =
- mBluetoothUserProxies.getProfilePriority(
- params.getProfile(),
- params.getDevice());
- if (priority == BluetoothProfile.PRIORITY_OFF) {
- // This profile was already disabled (and not as the result of an inhibit).
- // Add it to the already-disabled list, and do nothing else.
- mAlreadyDisabledProfiles.add(params);
-
- logd("Profile " + Utils.getProfileName(params.getProfile())
- + " already disabled for device " + params.getDevice()
- + " - suppressing re-enable");
- } else {
- mBluetoothUserProxies.setProfilePriority(
- params.getProfile(),
- params.getDevice(),
- BluetoothProfile.PRIORITY_OFF);
- mBluetoothUserProxies.bluetoothDisconnectFromProfile(
- params.getProfile(),
- params.getDevice());
- logd("Disabled profile "
- + Utils.getProfileName(params.getProfile())
- + " for device " + params.getDevice());
- }
- } catch (RemoteException e) {
- Log.e(TAG, "Could not disable profile", e);
- record.getToken().unlinkToDeath(record, 0);
- mProfileInhibits.remove(params, record);
+ private boolean addInhibitRecord(InhibitRecord record) {
+ synchronized (mProfileInhibitsLock) {
+ BluetoothConnection params = record.getParams();
+ if (!isProxyAvailable(params.getProfile())) {
return false;
}
- }
- commit();
- return true;
+ Set<InhibitRecord> previousRecords = mProfileInhibits.get(params);
+ if (findInhibitRecord(params, record.getToken()) != null) {
+ Log.e(TAG, "Inhibit request already registered - skipping duplicate");
+ return false;
+ }
+
+ try {
+ record.getToken().linkToDeath(record, 0);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Could not link to death on inhibit token (already dead?)", e);
+ return false;
+ }
+
+ boolean isNewlyAdded = previousRecords.isEmpty();
+ mProfileInhibits.put(params, record);
+
+ if (isNewlyAdded) {
+ try {
+ int priority =
+ mBluetoothUserProxies.getProfilePriority(
+ params.getProfile(),
+ params.getDevice());
+ if (priority == BluetoothProfile.PRIORITY_OFF) {
+ // This profile was already disabled (and not as the result of an inhibit).
+ // Add it to the already-disabled list, and do nothing else.
+ mAlreadyDisabledProfiles.add(params);
+
+ logd("Profile " + Utils.getProfileName(params.getProfile())
+ + " already disabled for device " + params.getDevice()
+ + " - suppressing re-enable");
+ } else {
+ mBluetoothUserProxies.setProfilePriority(
+ params.getProfile(),
+ params.getDevice(),
+ BluetoothProfile.PRIORITY_OFF);
+ mBluetoothUserProxies.bluetoothDisconnectFromProfile(
+ params.getProfile(),
+ params.getDevice());
+ logd("Disabled profile "
+ + Utils.getProfileName(params.getProfile())
+ + " for device " + params.getDevice());
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Could not disable profile", e);
+ record.getToken().unlinkToDeath(record, 0);
+ mProfileInhibits.remove(params, record);
+ return false;
+ }
+ }
+
+ commit();
+ return true;
+ }
}
/**
@@ -411,41 +413,45 @@
* @return InhibitRecord for the connection parameters and token if exists, null otherwise.
*/
private InhibitRecord findInhibitRecord(BluetoothConnection params, IBinder token) {
- return mProfileInhibits.get(params)
- .stream()
- .filter(r -> r.getToken() == token)
- .findAny()
- .orElse(null);
+ synchronized (mProfileInhibitsLock) {
+ return mProfileInhibits.get(params)
+ .stream()
+ .filter(r -> r.getToken() == token)
+ .findAny()
+ .orElse(null);
+ }
}
/**
* Remove a given profile inhibit record, reconnecting if necessary.
*/
- private synchronized boolean removeInhibitRecord(InhibitRecord record) {
- BluetoothConnection params = record.getParams();
- if (!isProxyAvailable(params.getProfile())) {
- return false;
- }
- if (!mProfileInhibits.containsEntry(params, record)) {
- Log.e(TAG, "Record already removed");
- // Removing something a second time vacuously succeeds.
- return true;
- }
-
- // Re-enable profile before unlinking and removing the record, in case of error.
- // The profile should be re-enabled if this record is the only one left for that
- // device and profile combination.
- if (mProfileInhibits.get(params).size() == 1) {
- if (!restoreProfilePriority(params)) {
+ private boolean removeInhibitRecord(InhibitRecord record) {
+ synchronized (mProfileInhibitsLock) {
+ BluetoothConnection params = record.getParams();
+ if (!isProxyAvailable(params.getProfile())) {
return false;
}
+ if (!mProfileInhibits.containsEntry(params, record)) {
+ Log.e(TAG, "Record already removed");
+ // Removing something a second time vacuously succeeds.
+ return true;
+ }
+
+ // Re-enable profile before unlinking and removing the record, in case of error.
+ // The profile should be re-enabled if this record is the only one left for that
+ // device and profile combination.
+ if (mProfileInhibits.get(params).size() == 1) {
+ if (!restoreProfilePriority(params)) {
+ return false;
+ }
+ }
+
+ record.getToken().unlinkToDeath(record, 0);
+ mProfileInhibits.remove(params, record);
+
+ commit();
+ return true;
}
-
- record.getToken().unlinkToDeath(record, 0);
- mProfileInhibits.remove(params, record);
-
- commit();
- return true;
}
/**
@@ -504,46 +510,51 @@
* Keep trying to remove all profile inhibits that were restored from settings
* until all such inhibits have been removed.
*/
- private synchronized void removeRestoredProfileInhibits() {
- tryRemoveRestoredProfileInhibits();
+ private void removeRestoredProfileInhibits() {
+ synchronized (mProfileInhibitsLock) {
+ tryRemoveRestoredProfileInhibits();
- if (!mRestoredInhibits.isEmpty()) {
- logd("Could not remove all restored profile inhibits - "
- + "trying again in " + RESTORE_BACKOFF_MILLIS + "ms");
- mHandler.postDelayed(
- this::removeRestoredProfileInhibits,
- RESTORED_PROFILE_INHIBIT_TOKEN,
- RESTORE_BACKOFF_MILLIS);
+ if (!mRestoredInhibits.isEmpty()) {
+ logd("Could not remove all restored profile inhibits - "
+ + "trying again in " + RESTORE_BACKOFF_MILLIS + "ms");
+ mHandler.postDelayed(
+ this::removeRestoredProfileInhibits,
+ RESTORED_PROFILE_INHIBIT_TOKEN,
+ RESTORE_BACKOFF_MILLIS);
+ }
}
}
/**
* Release all active inhibit records prior to user switch or shutdown
*/
- private synchronized void releaseAllInhibitsBeforeUnbind() {
+ private void releaseAllInhibitsBeforeUnbind() {
logd("Unbinding CarBluetoothUserService - releasing all profile inhibits");
- for (BluetoothConnection params : mProfileInhibits.keySet()) {
- for (InhibitRecord record : mProfileInhibits.get(params)) {
- record.removeSelf();
+
+ synchronized (mProfileInhibitsLock) {
+ for (BluetoothConnection params : mProfileInhibits.keySet()) {
+ for (InhibitRecord record : mProfileInhibits.get(params)) {
+ record.removeSelf();
+ }
}
+
+ // Some inhibits might be hanging around because they couldn't be cleaned up.
+ // Make sure they get persisted...
+ commit();
+
+ // ...then clear them from the map.
+ mProfileInhibits.clear();
+
+ // We don't need to maintain previously-disabled profiles any more - they were already
+ // skipped in saveProfileInhibitsToSettings() above, and they don't need any
+ // further handling when the user resumes.
+ mAlreadyDisabledProfiles.clear();
+
+ // Clean up bookkeeping for restored inhibits. (If any are still around, they'll be
+ // restored again when this user restarts.)
+ mHandler.removeCallbacksAndMessages(RESTORED_PROFILE_INHIBIT_TOKEN);
+ mRestoredInhibits.clear();
}
-
- // Some inhibits might be hanging around because they couldn't be cleaned up.
- // Make sure they get persisted...
- commit();
-
- // ...then clear them from the map.
- mProfileInhibits.clear();
-
- // We don't need to maintain previously-disabled profiles any more - they were already
- // skipped in saveProfileInhibitsToSettings() above, and they don't need any
- // further handling when the user resumes.
- mAlreadyDisabledProfiles.clear();
-
- // Clean up bookkeeping for restored inhibits. (If any are still around, they'll be
- // restored again when this user restarts.)
- mHandler.removeCallbacksAndMessages(RESTORED_PROFILE_INHIBIT_TOKEN);
- mRestoredInhibits.clear();
}
/**
@@ -564,7 +575,7 @@
/**
* Print the verbose status of the object
*/
- public synchronized void dump(PrintWriter writer, String indent) {
+ public void dump(PrintWriter writer, String indent) {
writer.println(indent + TAG + ":");
// User metadata
@@ -572,7 +583,7 @@
// Current inhibits
String inhibits;
- synchronized (this) {
+ synchronized (mProfileInhibitsLock) {
inhibits = mProfileInhibits.keySet().toString();
}
writer.println(indent + "\tInhibited profiles: " + inhibits);
diff --git a/service/src/com/android/car/CarBluetoothService.java b/service/src/com/android/car/CarBluetoothService.java
index 0dffce9..bf996e4 100644
--- a/service/src/com/android/car/CarBluetoothService.java
+++ b/service/src/com/android/car/CarBluetoothService.java
@@ -28,6 +28,8 @@
import android.util.Log;
import android.util.SparseArray;
+import com.android.internal.annotations.GuardedBy;
+
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
@@ -63,20 +65,31 @@
BluetoothProfile.PAN
);
+ // Each time PerUserCarService connects we need to get new Bluetooth profile proxies and refresh
+ // all our internal objects to use them. When it disconnects we're to assume our proxies are
+ // invalid. This lock protects all our internal objects.
+ private final Object mPerUserLock = new Object();
+
// Set of Bluetooth Profile Device Managers, own the priority connection lists, updated on user
// switch
- private SparseArray<BluetoothProfileDeviceManager> mProfileDeviceManagers = new SparseArray<>();
+ private final SparseArray<BluetoothProfileDeviceManager> mProfileDeviceManagers =
+ new SparseArray<>();
// Profile-Inhibit Manager that will temporarily inhibit connections on profiles, per user
+ @GuardedBy("mPerUserLock")
private BluetoothProfileInhibitManager mInhibitManager = null;
// Default Bluetooth device connection policy, per user, enabled with an overlay
private final boolean mUseDefaultPolicy;
+ @GuardedBy("mPerUserLock")
private BluetoothDeviceConnectionPolicy mBluetoothDeviceConnectionPolicy = null;
// Listen for user switch events from the PerUserCarService
+ @GuardedBy("mPerUserLock")
private int mUserId;
+ @GuardedBy("mPerUserLock")
private IPerUserCarService mPerUserCarService;
+ @GuardedBy("mPerUserLock")
private ICarBluetoothUserService mCarBluetoothUserService;
private final PerUserCarServiceHelper mUserServiceHelper;
private final PerUserCarServiceHelper.ServiceCallback mUserServiceCallback =
@@ -84,7 +97,7 @@
@Override
public void onServiceConnected(IPerUserCarService perUserCarService) {
logd("Connected to PerUserCarService");
- synchronized (this) {
+ synchronized (mPerUserLock) {
mPerUserCarService = perUserCarService;
initializeUser();
}
@@ -99,7 +112,7 @@
@Override
public void onServiceDisconnected() {
logd("Disconnected from PerUserCarService");
- synchronized (this) {
+ synchronized (mPerUserLock) {
mPerUserCarService = null;
}
}
@@ -126,7 +139,7 @@
* Wait for the user service helper to report a user before initializing a user.
*/
@Override
- public synchronized void init() {
+ public void init() {
logd("init()");
mUserServiceHelper.registerServiceCallback(mUserServiceCallback);
}
@@ -137,11 +150,10 @@
* Clean up the user context once we've detached from the user service helper, if any.
*/
@Override
- public synchronized void release() {
+ public void release() {
logd("release()");
mUserServiceHelper.unregisterServiceCallback(mUserServiceCallback);
destroyUser();
- mPerUserCarService = null;
}
/**
@@ -158,32 +170,37 @@
*
* Only call this following a known user switch once we've connected to the user service helper.
*/
- private synchronized void initializeUser() {
+ private void initializeUser() {
logd("Initializing new user");
- mUserId = ActivityManager.getCurrentUser();
- createBluetoothUserService();
- createBluetoothProfileDeviceManagers();
- createBluetoothProfileInhibitManager();
+ synchronized (mPerUserLock) {
+ mUserId = ActivityManager.getCurrentUser();
+ createBluetoothUserService();
+ createBluetoothProfileDeviceManagers();
+ createBluetoothProfileInhibitManager();
- // Determine if we need to begin the default policy
- mBluetoothDeviceConnectionPolicy = null;
- if (mUseDefaultPolicy) {
- createBluetoothDeviceConnectionPolicy();
+ // Determine if we need to begin the default policy
+ mBluetoothDeviceConnectionPolicy = null;
+ if (mUseDefaultPolicy) {
+ createBluetoothDeviceConnectionPolicy();
+ }
+ logd("Switched to user " + mUserId);
}
- logd("Switched to user " + mUserId);
}
/**
* Destroy the current user context, defined by the set of profile proxies, profile device
* managers, inhibit manager and the policy.
*/
- private synchronized void destroyUser() {
+ private void destroyUser() {
logd("Destroying user " + mUserId);
- destroyBluetoothDeviceConnectionPolicy();
- destroyBluetoothProfileInhibitManager();
- destroyBluetoothProfileDeviceManagers();
- destroyBluetoothUserService();
- mUserId = -1;
+ synchronized (mPerUserLock) {
+ destroyBluetoothDeviceConnectionPolicy();
+ destroyBluetoothProfileInhibitManager();
+ destroyBluetoothProfileDeviceManagers();
+ destroyBluetoothUserService();
+ mPerUserCarService = null;
+ mUserId = -1;
+ }
}
/**
@@ -192,17 +209,19 @@
* Also sets up the connection proxy objects required to communicate with the Bluetooth
* Profile Services.
*/
- private synchronized void createBluetoothUserService() {
- if (mPerUserCarService != null) {
- try {
- mCarBluetoothUserService = mPerUserCarService.getBluetoothUserService();
- mCarBluetoothUserService.setupBluetoothConnectionProxies();
- } catch (RemoteException e) {
- Log.e(TAG, "Remote Service Exception on ServiceConnection Callback: "
- + e.getMessage());
+ private void createBluetoothUserService() {
+ synchronized (mPerUserLock) {
+ if (mPerUserCarService != null) {
+ try {
+ mCarBluetoothUserService = mPerUserCarService.getBluetoothUserService();
+ mCarBluetoothUserService.setupBluetoothConnectionProxies();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Remote Service Exception on ServiceConnection Callback: "
+ + e.getMessage());
+ }
+ } else {
+ logd("PerUserCarService not connected. Cannot get bluetooth user proxy objects");
}
- } else {
- logd("PerUserCarService not connected. Cannot get bluetooth user proxy objects");
}
}
@@ -210,109 +229,122 @@
* Close out the Per User Car Bluetooth profile proxy connections and destroys the Car Bluetooth
* User Service object.
*/
- private synchronized void destroyBluetoothUserService() {
- if (mCarBluetoothUserService == null) return;
- try {
- mCarBluetoothUserService.closeBluetoothConnectionProxies();
- } catch (RemoteException e) {
- Log.e(TAG, "Remote Service Exception on ServiceConnection Callback: "
- + e.getMessage());
+ private void destroyBluetoothUserService() {
+ synchronized (mPerUserLock) {
+ if (mCarBluetoothUserService == null) return;
+ try {
+ mCarBluetoothUserService.closeBluetoothConnectionProxies();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Remote Service Exception on ServiceConnection Callback: "
+ + e.getMessage());
+ }
+ mCarBluetoothUserService = null;
}
- mCarBluetoothUserService = null;
}
/**
* Clears out Profile Device Managers and re-creates them for the current user.
*/
- private synchronized void createBluetoothProfileDeviceManagers() {
- mProfileDeviceManagers.clear();
- if (mUserId == -1) {
- logd("No foreground user, cannot create profile device managers");
- return;
- }
- for (int profileId : sManagedProfiles) {
- BluetoothProfileDeviceManager deviceManager = BluetoothProfileDeviceManager.create(
- mContext, mUserId, mCarBluetoothUserService, profileId);
- if (deviceManager == null) {
- logd("Failed to create profile device manager for "
- + Utils.getProfileName(profileId));
- continue;
+ private void createBluetoothProfileDeviceManagers() {
+ synchronized (mPerUserLock) {
+ if (mUserId == -1) {
+ logd("No foreground user, cannot create profile device managers");
+ return;
}
- mProfileDeviceManagers.put(profileId, deviceManager);
- logd("Created profile device manager for " + Utils.getProfileName(profileId));
- }
+ for (int profileId : sManagedProfiles) {
+ BluetoothProfileDeviceManager deviceManager = BluetoothProfileDeviceManager.create(
+ mContext, mUserId, mCarBluetoothUserService, profileId);
+ if (deviceManager == null) {
+ logd("Failed to create profile device manager for "
+ + Utils.getProfileName(profileId));
+ continue;
+ }
+ mProfileDeviceManagers.put(profileId, deviceManager);
+ logd("Created profile device manager for " + Utils.getProfileName(profileId));
+ }
- for (int i = 0; i < mProfileDeviceManagers.size(); i++) {
- int key = mProfileDeviceManagers.keyAt(i);
- BluetoothProfileDeviceManager deviceManager =
- (BluetoothProfileDeviceManager) mProfileDeviceManagers.get(key);
- deviceManager.start();
+ for (int i = 0; i < mProfileDeviceManagers.size(); i++) {
+ int key = mProfileDeviceManagers.keyAt(i);
+ BluetoothProfileDeviceManager deviceManager =
+ (BluetoothProfileDeviceManager) mProfileDeviceManagers.get(key);
+ deviceManager.start();
+ }
}
}
/**
* Stops and clears the entire set of Profile Device Managers.
*/
- private synchronized void destroyBluetoothProfileDeviceManagers() {
- for (int i = 0; i < mProfileDeviceManagers.size(); i++) {
- int key = mProfileDeviceManagers.keyAt(i);
- BluetoothProfileDeviceManager deviceManager =
- (BluetoothProfileDeviceManager) mProfileDeviceManagers.get(key);
- deviceManager.stop();
+ private void destroyBluetoothProfileDeviceManagers() {
+ synchronized (mPerUserLock) {
+ for (int i = 0; i < mProfileDeviceManagers.size(); i++) {
+ int key = mProfileDeviceManagers.keyAt(i);
+ BluetoothProfileDeviceManager deviceManager =
+ (BluetoothProfileDeviceManager) mProfileDeviceManagers.get(key);
+ deviceManager.stop();
+ }
+ mProfileDeviceManagers.clear();
}
- mProfileDeviceManagers.clear();
}
/**
* Creates an instance of a BluetoothProfileInhibitManager under the current user
*/
- private synchronized void createBluetoothProfileInhibitManager() {
+ private void createBluetoothProfileInhibitManager() {
logd("Creating inhibit manager");
- if (mUserId == -1) {
- logd("No foreground user, cannot create profile inhibit manager");
- return;
+ synchronized (mPerUserLock) {
+ if (mUserId == -1) {
+ logd("No foreground user, cannot create profile inhibit manager");
+ return;
+ }
+ mInhibitManager = new BluetoothProfileInhibitManager(mContext, mUserId,
+ mCarBluetoothUserService);
+ mInhibitManager.start();
}
- mInhibitManager = new BluetoothProfileInhibitManager(mContext, mUserId,
- mCarBluetoothUserService);
- mInhibitManager.start();
}
/**
* Destroys the current instance of a BluetoothProfileInhibitManager, if one exists
*/
- private synchronized void destroyBluetoothProfileInhibitManager() {
+ private void destroyBluetoothProfileInhibitManager() {
logd("Destroying inhibit manager");
- if (mInhibitManager == null) return;
- mInhibitManager.stop();
- mInhibitManager = null;
+ synchronized (mPerUserLock) {
+ if (mInhibitManager == null) return;
+ mInhibitManager.stop();
+ mInhibitManager = null;
+ }
}
/**
* Creates an instance of a BluetoothDeviceConnectionPolicy under the current user
*/
- private synchronized void createBluetoothDeviceConnectionPolicy() {
+ private void createBluetoothDeviceConnectionPolicy() {
logd("Creating device connection policy");
- if (mUserId == -1) {
- logd("No foreground user, cannot create device connection policy");
- return;
+ synchronized (mPerUserLock) {
+ if (mUserId == -1) {
+ logd("No foreground user, cannot create device connection policy");
+ return;
+ }
+ mBluetoothDeviceConnectionPolicy = BluetoothDeviceConnectionPolicy.create(mContext,
+ mUserId, this);
+ if (mBluetoothDeviceConnectionPolicy == null) {
+ logd("Failed to create default Bluetooth device connection policy.");
+ return;
+ }
+ mBluetoothDeviceConnectionPolicy.init();
}
- mBluetoothDeviceConnectionPolicy = BluetoothDeviceConnectionPolicy.create(mContext, mUserId,
- this);
- if (mBluetoothDeviceConnectionPolicy == null) {
- logd("Failed to create default Bluetooth device connection policy.");
- return;
- }
- mBluetoothDeviceConnectionPolicy.init();
}
/**
* Destroys the current instance of a BluetoothDeviceConnectionPolicy, if one exists
*/
- private synchronized void destroyBluetoothDeviceConnectionPolicy() {
+ private void destroyBluetoothDeviceConnectionPolicy() {
logd("Destroying device connection policy");
- if (mBluetoothDeviceConnectionPolicy != null) {
- mBluetoothDeviceConnectionPolicy.release();
- mBluetoothDeviceConnectionPolicy = null;
+ synchronized (mPerUserLock) {
+ if (mBluetoothDeviceConnectionPolicy != null) {
+ mBluetoothDeviceConnectionPolicy.release();
+ mBluetoothDeviceConnectionPolicy = null;
+ }
}
}
@@ -322,7 +354,9 @@
* @return true if the default policy is active, false otherwise
*/
public boolean isUsingDefaultConnectionPolicy() {
- return mBluetoothDeviceConnectionPolicy != null;
+ synchronized (mPerUserLock) {
+ return mBluetoothDeviceConnectionPolicy != null;
+ }
}
/**
@@ -332,7 +366,7 @@
public void connectDevices() {
enforceBluetoothAdminPermission();
logd("Connect devices for each profile");
- synchronized (this) {
+ synchronized (mPerUserLock) {
for (int i = 0; i < mProfileDeviceManagers.size(); i++) {
int key = mProfileDeviceManagers.keyAt(i);
BluetoothProfileDeviceManager deviceManager =
@@ -350,7 +384,7 @@
*/
public List<BluetoothDevice> getProfileDevicePriorityList(int profile) {
enforceBluetoothAdminPermission();
- synchronized (this) {
+ synchronized (mPerUserLock) {
BluetoothProfileDeviceManager deviceManager =
(BluetoothProfileDeviceManager) mProfileDeviceManagers.get(profile);
if (deviceManager != null) {
@@ -369,7 +403,7 @@
*/
public int getDeviceConnectionPriority(int profile, BluetoothDevice device) {
enforceBluetoothAdminPermission();
- synchronized (this) {
+ synchronized (mPerUserLock) {
BluetoothProfileDeviceManager deviceManager =
(BluetoothProfileDeviceManager) mProfileDeviceManagers.get(profile);
if (deviceManager != null) {
@@ -388,7 +422,7 @@
*/
public void setDeviceConnectionPriority(int profile, BluetoothDevice device, int priority) {
enforceBluetoothAdminPermission();
- synchronized (this) {
+ synchronized (mPerUserLock) {
BluetoothProfileDeviceManager deviceManager =
(BluetoothProfileDeviceManager) mProfileDeviceManagers.get(profile);
if (deviceManager != null) {
@@ -408,11 +442,13 @@
* owning the token dies, the request will automatically be released
* @return True if the profile was successfully inhibited, false if an error occurred.
*/
- synchronized boolean requestProfileInhibit(BluetoothDevice device, int profile, IBinder token) {
+ boolean requestProfileInhibit(BluetoothDevice device, int profile, IBinder token) {
logd("Request profile inhibit: profile " + Utils.getProfileName(profile)
+ ", device " + device.getAddress());
- if (mInhibitManager == null) return false;
- return mInhibitManager.requestProfileInhibit(device, profile, token);
+ synchronized (mPerUserLock) {
+ if (mInhibitManager == null) return false;
+ return mInhibitManager.requestProfileInhibit(device, profile, token);
+ }
}
/**
@@ -425,11 +461,13 @@
* {@link #requestBluetoothProfileInhibit}.
* @return True if the request was released, false if an error occurred.
*/
- synchronized boolean releaseProfileInhibit(BluetoothDevice device, int profile, IBinder token) {
+ boolean releaseProfileInhibit(BluetoothDevice device, int profile, IBinder token) {
logd("Release profile inhibit: profile " + Utils.getProfileName(profile)
+ ", device " + device.getAddress());
- if (mInhibitManager == null) return false;
- return mInhibitManager.releaseProfileInhibit(device, profile, token);
+ synchronized (mPerUserLock) {
+ if (mInhibitManager == null) return false;
+ return mInhibitManager.releaseProfileInhibit(device, profile, token);
+ }
}
/**
@@ -452,29 +490,31 @@
* Print out the verbose debug status of this object
*/
@Override
- public synchronized void dump(PrintWriter writer) {
+ public void dump(PrintWriter writer) {
writer.println("*" + TAG + "*");
- writer.println("\tUser ID: " + mUserId);
- writer.println("\tUser Proxies: " + (mCarBluetoothUserService != null ? "Yes" : "No"));
+ synchronized (mPerUserLock) {
+ writer.println("\tUser ID: " + mUserId);
+ writer.println("\tUser Proxies: " + (mCarBluetoothUserService != null ? "Yes" : "No"));
- // Profile Device Manager statuses
- for (int i = 0; i < mProfileDeviceManagers.size(); i++) {
- int key = mProfileDeviceManagers.keyAt(i);
- BluetoothProfileDeviceManager deviceManager =
- (BluetoothProfileDeviceManager) mProfileDeviceManagers.get(key);
- deviceManager.dump(writer, "\t");
- }
+ // Profile Device Manager statuses
+ for (int i = 0; i < mProfileDeviceManagers.size(); i++) {
+ int key = mProfileDeviceManagers.keyAt(i);
+ BluetoothProfileDeviceManager deviceManager =
+ (BluetoothProfileDeviceManager) mProfileDeviceManagers.get(key);
+ deviceManager.dump(writer, "\t");
+ }
- // Profile Inhibits
- if (mInhibitManager != null) mInhibitManager.dump(writer, "\t");
- else writer.println("\tBluetoothProfileInhibitManager: null");
+ // Profile Inhibits
+ if (mInhibitManager != null) mInhibitManager.dump(writer, "\t");
+ else writer.println("\tBluetoothProfileInhibitManager: null");
- // Device Connection Policy
- writer.println("\tUsing default policy? " + (mUseDefaultPolicy ? "Yes" : "No"));
- if (mBluetoothDeviceConnectionPolicy == null) {
- writer.println("\tBluetoothDeviceConnectionPolicy: null");
- } else {
- mBluetoothDeviceConnectionPolicy.dump(writer, "\t");
+ // Device Connection Policy
+ writer.println("\tUsing default policy? " + (mUseDefaultPolicy ? "Yes" : "No"));
+ if (mBluetoothDeviceConnectionPolicy == null) {
+ writer.println("\tBluetoothDeviceConnectionPolicy: null");
+ } else {
+ mBluetoothDeviceConnectionPolicy.dump(writer, "\t");
+ }
}
}