Merge "Get AdapterService while setting priority" into q-keystone-qcom-dev
diff --git a/src/com/android/bluetooth/a2dp/A2dpService.java b/src/com/android/bluetooth/a2dp/A2dpService.java
index 1cc276f..63d4181 100644
--- a/src/com/android/bluetooth/a2dp/A2dpService.java
+++ b/src/com/android/bluetooth/a2dp/A2dpService.java
@@ -56,6 +56,7 @@
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* Provides Bluetooth A2DP profile, as a service in the Bluetooth application.
@@ -76,6 +77,7 @@
private final Object mBtAvrcpLock = new Object();
private final Object mActiveDeviceLock = new Object();
private final Object mVariableLock = new Object();
+ private final ReentrantReadWriteLock mA2dpNativeInterfaceLock = new ReentrantReadWriteLock();
@VisibleForTesting
A2dpNativeInterface mA2dpNativeInterface;
@@ -174,8 +176,16 @@
synchronized (mVariableLock) {
mAdapterService = Objects.requireNonNull(AdapterService.getAdapterService(),
"AdapterService cannot be null when A2dpService starts");
+ }
+ try {
+ mA2dpNativeInterfaceLock.writeLock().lock();
mA2dpNativeInterface = Objects.requireNonNull(A2dpNativeInterface.getInstance(),
"A2dpNativeInterface cannot be null when A2dpService starts");
+ } finally {
+ mA2dpNativeInterfaceLock.writeLock().unlock();
+ }
+ BluetoothCodecConfig[] OffloadCodecConfig;
+ synchronized (mVariableLock) {
mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
Objects.requireNonNull(mAudioManager,
"AudioManager cannot be null when A2dpService starts");
@@ -228,10 +238,20 @@
// Step 6: Initialize native interface
List<BluetoothCodecConfig> mCodecConfigOffload;
mCodecConfigOffload = mAudioManager.getHwOffloadEncodingFormatsSupportedForA2DP();
- BluetoothCodecConfig[] OffloadCodecConfig = new BluetoothCodecConfig[mCodecConfigOffload.size()];
+ OffloadCodecConfig = new BluetoothCodecConfig[mCodecConfigOffload.size()];
OffloadCodecConfig = mCodecConfigOffload.toArray(OffloadCodecConfig);
- mA2dpNativeInterface.init(mMaxConnectedAudioDevices,
- mA2dpCodecConfig.codecConfigPriorities(),OffloadCodecConfig);
+ }
+
+ try {
+ mA2dpNativeInterfaceLock.writeLock().lock();
+ if (mA2dpNativeInterface != null)
+ mA2dpNativeInterface.init(mMaxConnectedAudioDevices,
+ mA2dpCodecConfig.codecConfigPriorities(),OffloadCodecConfig);
+ } finally {
+ mA2dpNativeInterfaceLock.writeLock().unlock();
+ }
+
+ synchronized (mVariableLock) {
// Step 7: Check if A2DP is in offload mode
mA2dpOffloadEnabled = mAdapterService.isA2dpOffloadEnabled();
@@ -277,10 +297,14 @@
unregisterReceiver(mBondStateChangedReceiver);
mBondStateChangedReceiver = null;
// Step 6: Cleanup native interface
- synchronized (mVariableLock) {
+ try {
+ mA2dpNativeInterfaceLock.writeLock().lock();
if (mA2dpNativeInterface != null)
mA2dpNativeInterface.cleanup();
+ } finally {
+ mA2dpNativeInterfaceLock.writeLock().unlock();
}
+
// Step 5: Clear codec config
mA2dpCodecConfig = null;
@@ -323,10 +347,16 @@
mSetMaxConnectedAudioDevices = 1;
// Step 1: Clear AdapterService, A2dpNativeInterface, AudioManager
mAudioManager = null;
- mA2dpNativeInterface = null;
mAdapterService = null;
}
+ try {
+ mA2dpNativeInterfaceLock.writeLock().lock();
+ mA2dpNativeInterface = null;
+ } finally {
+ mA2dpNativeInterfaceLock.writeLock().unlock();
+ }
+
return true;
}
@@ -720,11 +750,14 @@
}
}
// Make sure the Active device in native layer is set to null and audio is off
- synchronized (mVariableLock ) {
+ try {
+ mA2dpNativeInterfaceLock.readLock().lock();
if (mA2dpNativeInterface != null && !mA2dpNativeInterface.setActiveDevice(null)) {
Log.w(TAG, "setActiveDevice(null): Cannot remove active device in native "
+ "layer");
}
+ } finally {
+ mA2dpNativeInterfaceLock.readLock().unlock();
}
}
@@ -746,13 +779,18 @@
// Set the device as the active device if currently no active device.
setActiveDevice(device);
}
- synchronized (mVariableLock) {
+
+ try {
+ mA2dpNativeInterfaceLock.readLock().lock();
if (mA2dpNativeInterface != null &&
!mA2dpNativeInterface.setSilenceDevice(device, silence)) {
Log.e(TAG, "Cannot set " + device + " silence mode " + silence + " in native layer");
return false;
}
+ } finally {
+ mA2dpNativeInterfaceLock.readLock().unlock();
}
+
return true;
}
@@ -802,19 +840,21 @@
boolean tws_switch = false;
Log.w(TAG, "setActiveDevice(" + device + "): previous is " + previousActiveDevice);
+ if (device == null) {
+ // Remove active device and continue playing audio only if necessary.
+ removeActiveDevice(false);
+ synchronized(mBtAvrcpLock) {
+ if(mAvrcp_ext != null)
+ mAvrcp_ext.setActiveDevice(device);
+ }
+ return true;
+ }
+
synchronized (mBtA2dpLock) {
BATService mBatService = BATService.getBATService();
isBAActive = (mBatService != null) && (mBatService.isBATActive());
Log.d(TAG," setActiveDevice: BA active " + isBAActive);
- if (device == null) {
- // Remove active device and continue playing audio only if necessary.
- removeActiveDevice(false);
- if(mAvrcp_ext != null)
- mAvrcp_ext.setActiveDevice(device);
- return true;
- }
-
A2dpStateMachine sm = mStateMachines.get(device);
deviceChanged = !Objects.equals(device, mActiveDevice);
if (!deviceChanged) {
@@ -856,13 +896,18 @@
Log.w(TAG, "setActiveDevice coming out of mutex lock");
}
- synchronized (mVariableLock) {
+ try {
+ mA2dpNativeInterfaceLock.readLock().lock();
if (mA2dpNativeInterface != null && !mA2dpNativeInterface.setActiveDevice(device)) {
Log.e(TAG, "setActiveDevice(" + device + "): Cannot set as active in native layer");
return false;
}
+
+ } finally {
+ mA2dpNativeInterfaceLock.readLock().unlock();
}
+
updateAndBroadcastActiveDevice(device);
Log.d(TAG, "setActiveDevice(" + device + "): completed");
@@ -1299,7 +1344,8 @@
if (stackEvent.type == A2dpStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED) {
switch (stackEvent.valueInt) {
case A2dpStackEvent.CONNECTION_STATE_CONNECTED:
- case A2dpStackEvent.CONNECTION_STATE_CONNECTING:
+ case A2dpStackEvent.CONNECTION_STATE_CONNECTING: {
+ boolean connectionAllowed;
synchronized (mVariableLock) {
// Create a new state machine only when connecting to a device
if (mAdapterService != null && mAdapterService.isVendorIntfEnabled())
@@ -1308,15 +1354,24 @@
sm = getOrCreateStateMachine(device);
break;
}
- if (!connectionAllowedCheckMaxDevices(device) && mA2dpNativeInterface != null) {
- Log.e(TAG, "Cannot connect to " + device
- + " : too many connected devices");
- mA2dpNativeInterface.disconnectA2dp(device);
- return;
+ connectionAllowed = connectionAllowedCheckMaxDevices(device);
+ }
+ if (!connectionAllowed) {
+ Log.e(TAG, "Cannot connect to " + device
+ + " : too many connected devices");
+ try {
+ mA2dpNativeInterfaceLock.readLock().lock();
+ if (mA2dpNativeInterface != null) {
+ mA2dpNativeInterface.disconnectA2dp(device);
+ return;
+ }
+ } finally {
+ mA2dpNativeInterfaceLock.readLock().unlock();
}
}
sm = getOrCreateStateMachine(device);
break;
+ }
default:
synchronized (mVariableLock) {
if (mAdapterService!= null && mAdapterService.isVendorIntfEnabled() &&
diff --git a/src/com/android/bluetooth/btservice/AdapterProperties.java b/src/com/android/bluetooth/btservice/AdapterProperties.java
index c7eb53c..beff7c8 100644
--- a/src/com/android/bluetooth/btservice/AdapterProperties.java
+++ b/src/com/android/bluetooth/btservice/AdapterProperties.java
@@ -86,18 +86,7 @@
private CopyOnWriteArrayList<BluetoothDevice> mBondedDevices =
new CopyOnWriteArrayList<BluetoothDevice>();
- private final class ProfilesConnectionState {
- public int mProfilesConnecting, mProfilesConnected, mProfilesDisconnecting;
-
- ProfilesConnectionState(int connecting, int connected, int disconnecting) {
- mProfilesConnecting = connecting;
- mProfilesConnected = connected;
- mProfilesDisconnecting = disconnecting;
- }
- }
- private final HashMap<BluetoothDevice, ProfilesConnectionState> mDevicesConnectionState =
- new HashMap<>();
-
+ private int mProfilesConnecting, mProfilesConnected, mProfilesDisconnecting;
private final HashMap<Integer, Pair<Integer, Integer>> mProfileConnectionState =
new HashMap<>();
@@ -229,7 +218,6 @@
public void init(RemoteDevices remoteDevices) {
mProfileConnectionState.clear();
- mDevicesConnectionState.clear();
mRemoteDevices = remoteDevices;
// Get default max connected audio devices from config.xml in frameworks/base/core
@@ -286,7 +274,6 @@
}
mService = null;
mBondedDevices.clear();
- mDevicesConnectionState.clear();
}
@Override
@@ -800,10 +787,6 @@
debugLog("Adding bonded device:" + device);
mBondedDevices.add(device);
}
- if (!mDevicesConnectionState.containsKey(device)) {
- debugLog("Adding connection state:" + device);
- mDevicesConnectionState.put(device, new ProfilesConnectionState(0, 0, 0));
- }
} else if (state == BluetoothDevice.BOND_NONE) {
// remove device from list
if (mBondedDevices.remove(device)) {
@@ -811,10 +794,6 @@
} else {
debugLog("Failed to remove device: " + device);
}
- if (mDevicesConnectionState.containsKey(device)) {
- debugLog("Removing connection state:" + device);
- mDevicesConnectionState.remove(device);
- }
}
} catch (Exception ee) {
Log.w(TAG, "onBondStateChanged: Exception ", ee);
@@ -889,7 +868,7 @@
try {
validateConnectionState =
- updateCountersAndCheckForConnectionStateChange(device, state, prevState);
+ updateCountersAndCheckForConnectionStateChange(state, prevState);
} catch (IllegalStateException ee) {
Log.w(TAG, "ADAPTER_CONNECTION_STATE_CHANGE: unexpected transition for profile="
+ profile + ", " + prevState + " -> " + state);
@@ -953,45 +932,33 @@
}
}
- private boolean updateCountersAndCheckForConnectionStateChange(BluetoothDevice device,
- int state, int prevState) {
- if(!mDevicesConnectionState.containsKey(device)) {
- Log.e(TAG, "Can't find device connection record, adding new one: " + device);
- mDevicesConnectionState.put(device, new ProfilesConnectionState(0, 0, 0));
- }
- ProfilesConnectionState connstate = mDevicesConnectionState.get(device);
-
- Log.e(TAG, "prevState=" + prevState + " -> State=" + state +
- " mProfilesConnecting=" + connstate.mProfilesConnecting +
- " mProfilesConnected=" + connstate.mProfilesConnected +
- " mProfilesDisconnecting=" + connstate.mProfilesDisconnecting);
-
+ private boolean updateCountersAndCheckForConnectionStateChange(int state, int prevState) {
switch (prevState) {
case BluetoothProfile.STATE_CONNECTING:
- if (connstate.mProfilesConnecting > 0) {
- connstate.mProfilesConnecting--;
+ if (mProfilesConnecting > 0) {
+ mProfilesConnecting--;
} else {
- Log.e(TAG, "mProfilesConnecting " + connstate.mProfilesConnecting);
+ Log.e(TAG, "mProfilesConnecting " + mProfilesConnecting);
throw new IllegalStateException(
"Invalid state transition, " + prevState + " -> " + state);
}
break;
case BluetoothProfile.STATE_CONNECTED:
- if (connstate.mProfilesConnected > 0) {
- connstate.mProfilesConnected--;
+ if (mProfilesConnected > 0) {
+ mProfilesConnected--;
} else {
- Log.e(TAG, "mProfilesConnected " + connstate.mProfilesConnected);
+ Log.e(TAG, "mProfilesConnected " + mProfilesConnected);
throw new IllegalStateException(
"Invalid state transition, " + prevState + " -> " + state);
}
break;
case BluetoothProfile.STATE_DISCONNECTING:
- if (connstate.mProfilesDisconnecting > 0) {
- connstate.mProfilesDisconnecting--;
+ if (mProfilesDisconnecting > 0) {
+ mProfilesDisconnecting--;
} else {
- Log.e(TAG, "mProfilesDisconnecting " + connstate.mProfilesDisconnecting);
+ Log.e(TAG, "mProfilesDisconnecting " + mProfilesDisconnecting);
throw new IllegalStateException(
"Invalid state transition, " + prevState + " -> " + state);
}
@@ -1000,19 +967,19 @@
switch (state) {
case BluetoothProfile.STATE_CONNECTING:
- connstate.mProfilesConnecting++;
- return (connstate.mProfilesConnected == 0 && connstate.mProfilesConnecting == 1);
+ mProfilesConnecting++;
+ return (mProfilesConnected == 0 && mProfilesConnecting == 1);
case BluetoothProfile.STATE_CONNECTED:
- connstate.mProfilesConnected++;
- return (connstate.mProfilesConnected == 1);
+ mProfilesConnected++;
+ return (mProfilesConnected == 1);
case BluetoothProfile.STATE_DISCONNECTING:
- connstate.mProfilesDisconnecting++;
- return (connstate.mProfilesConnected == 0 && connstate.mProfilesDisconnecting == 1);
+ mProfilesDisconnecting++;
+ return (mProfilesConnected == 0 && mProfilesDisconnecting == 1);
case BluetoothProfile.STATE_DISCONNECTED:
- return (connstate.mProfilesConnected == 0 && connstate.mProfilesConnecting == 0);
+ return (mProfilesConnected == 0 && mProfilesConnecting == 0);
default:
return true;
@@ -1273,8 +1240,9 @@
// Reset adapter and profile connection states
setConnectionState(BluetoothAdapter.STATE_DISCONNECTED);
mProfileConnectionState.clear();
- mDevicesConnectionState.clear();
-
+ mProfilesConnected = 0;
+ mProfilesConnecting = 0;
+ mProfilesDisconnecting = 0;
// adapterPropertyChangedCallback has already been received. Set the scan mode.
setScanMode(AbstractionLayer.BT_SCAN_MODE_CONNECTABLE);
// This keeps NV up-to date on first-boot after flash.
diff --git a/src/com/android/bluetooth/hfp/HeadsetService.java b/src/com/android/bluetooth/hfp/HeadsetService.java
index 7bb15f0..d9cadd9 100644
--- a/src/com/android/bluetooth/hfp/HeadsetService.java
+++ b/src/com/android/bluetooth/hfp/HeadsetService.java
@@ -988,13 +988,13 @@
Log.w(TAG, "connect: PRIORITY_OFF, device=" + device + ", " + Utils.getUidPidString());
return false;
}
- ParcelUuid[] featureUuids = mAdapterService.getRemoteUuids(device);
- if (!BluetoothUuid.containsAnyUuid(featureUuids, HEADSET_UUIDS)) {
- Log.e(TAG, "connect: Cannot connect to " + device + ": no headset UUID, "
- + Utils.getUidPidString());
- return false;
- }
synchronized (mStateMachines) {
+ ParcelUuid[] featureUuids = mAdapterService.getRemoteUuids(device);
+ if (!BluetoothUuid.containsAnyUuid(featureUuids, HEADSET_UUIDS)) {
+ Log.e(TAG, "connect: Cannot connect to " + device + ": no headset UUID, "
+ + Utils.getUidPidString());
+ return false;
+ }
Log.i(TAG, "connect: device=" + device + ", " + Utils.getUidPidString());
HeadsetStateMachine stateMachine = mStateMachines.get(device);
if (stateMachine == null) {
@@ -1106,12 +1106,12 @@
Log.e(TAG, "->States is null");
return devices;
}
- final BluetoothDevice[] bondedDevices = mAdapterService.getBondedDevices();
- if (bondedDevices == null) {
- Log.e(TAG, "->Bonded device is null");
- return devices;
- }
synchronized (mStateMachines) {
+ final BluetoothDevice[] bondedDevices = mAdapterService.getBondedDevices();
+ if (bondedDevices == null) {
+ Log.e(TAG, "->Bonded device is null");
+ return devices;
+ }
for (BluetoothDevice device : bondedDevices) {
int connectionState = getConnectionState(device);
@@ -2253,7 +2253,7 @@
synchronized (mStateMachines) {
if (toState == BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
//Transfer SCO is not needed for TWS+ devices
- if (mAdapterService.isTwsPlusDevice(device) &&
+ if (mAdapterService != null && mAdapterService.isTwsPlusDevice(device) &&
mActiveDevice != null &&
mAdapterService.isTwsPlusDevice(mActiveDevice) &&
isAudioOn()) {
@@ -2264,7 +2264,7 @@
Log.w(TAG, "onAudioStateChangedFromStateMachine:"
+ "shouldPersistAudio() returns"
+ shouldPersistAudio());
- if (mAdapterService.isTwsPlusDevice(device) &&
+ if (mAdapterService != null && mAdapterService.isTwsPlusDevice(device) &&
isAudioOn()) {
Log.w(TAG, "TWS: Don't stop VR or VOIP");
} else {
@@ -2297,11 +2297,11 @@
if (mActiveDevice != null &&
!mActiveDevice.equals(device) &&
shouldPersistAudio()) {
- if (mAdapterService.isTwsPlusDevice(device)
+ if (mAdapterService != null && mAdapterService.isTwsPlusDevice(device)
&& isAudioOn()) {
Log.d(TAG, "TWS: Wait for both eSCO closed");
} else {
- if (mAdapterService.isTwsPlusDevice(device) &&
+ if (mAdapterService != null && mAdapterService.isTwsPlusDevice(device) &&
isTwsPlusActive(mActiveDevice)) {
/* If the device for which SCO got disconnected
is a TwsPlus device and TWS+ set is active
diff --git a/src/com/android/bluetooth/opp/BluetoothOppObexClientSession.java b/src/com/android/bluetooth/opp/BluetoothOppObexClientSession.java
index 349951c..ada8ab4 100644
--- a/src/com/android/bluetooth/opp/BluetoothOppObexClientSession.java
+++ b/src/com/android/bluetooth/opp/BluetoothOppObexClientSession.java
@@ -32,6 +32,7 @@
package com.android.bluetooth.opp;
+import android.bluetooth.BluetoothAdapter;
import android.content.ContentValues;
import android.content.Context;
import android.net.Uri;
@@ -80,12 +81,15 @@
private int mNumFilesAttemptedToSend;
+ private BluetoothAdapter mAdapter;
+
public BluetoothOppObexClientSession(Context context, ObexTransport transport) {
if (transport == null) {
throw new NullPointerException("transport is null");
}
mContext = context;
mTransport = transport;
+ mAdapter = BluetoothAdapter.getDefaultAdapter();
}
@Override
@@ -99,7 +103,7 @@
}
@Override
- public void stop() {
+ public synchronized void stop() {
if (D) {
Log.d(TAG, "Stop!");
}
@@ -110,7 +114,23 @@
if (V) {
Log.v(TAG, "waiting for thread to terminate");
}
- mThread.join();
+ if (mAdapter.getState() == BluetoothAdapter.STATE_TURNING_OFF) {
+ Log.d(TAG, "stop, bt is turning off");
+ mThread.join(1500);
+ if (mThread.isAlive()) {
+ Log.d(TAG, "stop, close the transport");
+ mThread.interrupt();
+ try {
+ mTransport.close();
+ } catch (IOException e) {
+ Log.e(TAG, "mTransport.close error");
+ }
+ Log.d(TAG, "stop, close the transport, done");
+ mThread.join();
+ }
+ } else {
+ mThread.join();
+ }
mThread = null;
} catch (InterruptedException e) {
if (V) {