diff options
author | Ugo Yu <ugoyu@google.com> | 2018-10-11 17:49:46 +0800 |
---|---|---|
committer | JP Sugarbroad <jpsugar@google.com> | 2019-02-12 13:37:18 -0800 |
commit | a0ac9860e494124a007318d1621a55bacd74a154 (patch) | |
tree | fb33e03c915b2565f7c166de75eea95264587152 /src | |
parent | 3e191ef459a9f81bf6cfcfee1e36dec72c2831f2 (diff) | |
download | android_packages_apps_Bluetooth-a0ac9860e494124a007318d1621a55bacd74a154.tar.gz android_packages_apps_Bluetooth-a0ac9860e494124a007318d1621a55bacd74a154.tar.bz2 android_packages_apps_Bluetooth-a0ac9860e494124a007318d1621a55bacd74a154.zip |
DO NOT MERGE Separate SDP procedure from bonding state (2/2)
- Do not stay in bonding state if the device is paried but still
discovering service.
- Report BOND_BONDED to Java after authentication is completed.
- Change bond state to bond none if a classic Bluetooth device
SDP failed while pairing.
- Hold BOND_BONDED intent util SDP is findished.
- Only accept profile connection for the device is at bonded
state. Any attempt to connect while bonding would potentially
lead to an unauthorized connection.
Bug: 79703832
Test: runtest bluetooth
Change-Id: I141f7daf84e74f9d4e472206b7fe94319f544227
(cherry picked from commit c9c30ef6f8b4f54f66fbfa2c1c0a9826f89b05e2)
(cherry picked from commit a29d558076e5247954217f092494a23e91da5cbc)
Diffstat (limited to 'src')
8 files changed, 129 insertions, 61 deletions
diff --git a/src/com/android/bluetooth/a2dp/A2dpService.java b/src/com/android/bluetooth/a2dp/A2dpService.java index 10a2f8b5d..16188899d 100644 --- a/src/com/android/bluetooth/a2dp/A2dpService.java +++ b/src/com/android/bluetooth/a2dp/A2dpService.java @@ -355,24 +355,18 @@ public class A2dpService extends ProfileService { return false; } // Check priority and accept or reject the connection. - // Note: Logic can be simplified, but keeping it this way for readability int priority = getPriority(device); int bondState = mAdapterService.getBondState(device); - // If priority is undefined, it is likely that service discovery has not completed and peer - // initiated the connection. Allow this connection only if the device is bonded or bonding - boolean serviceDiscoveryPending = (priority == BluetoothProfile.PRIORITY_UNDEFINED) - && (bondState == BluetoothDevice.BOND_BONDING - || bondState == BluetoothDevice.BOND_BONDED); - // Also allow connection when device is bonded/bonding and priority is ON/AUTO_CONNECT. - boolean isEnabled = (priority == BluetoothProfile.PRIORITY_ON - || priority == BluetoothProfile.PRIORITY_AUTO_CONNECT) - && (bondState == BluetoothDevice.BOND_BONDED - || bondState == BluetoothDevice.BOND_BONDING); - if (!serviceDiscoveryPending && !isEnabled) { - // Otherwise, reject the connection if no service discovery is pending and priority is - // neither PRIORITY_ON nor PRIORITY_AUTO_CONNECT - Log.w(TAG, "okToConnect: return false, priority=" + priority + ", bondState=" - + bondState); + // Allow this connection only if the device is bonded. Any attempt to connect while + // bonding would potentially lead to an unauthorized connection. + if (bondState != BluetoothDevice.BOND_BONDED) { + Log.w(TAG, "okToConnect: return false, bondState=" + bondState); + return false; + } else if (priority != BluetoothProfile.PRIORITY_UNDEFINED + && priority != BluetoothProfile.PRIORITY_ON + && priority != BluetoothProfile.PRIORITY_AUTO_CONNECT) { + // Otherwise, reject the connection if priority is not valid. + Log.w(TAG, "okToConnect: return false, priority=" + priority); return false; } return true; diff --git a/src/com/android/bluetooth/btservice/AdapterProperties.java b/src/com/android/bluetooth/btservice/AdapterProperties.java index d594850c2..981a45acb 100644 --- a/src/com/android/bluetooth/btservice/AdapterProperties.java +++ b/src/com/android/bluetooth/btservice/AdapterProperties.java @@ -41,6 +41,7 @@ import android.os.ParcelUuid; import android.os.SystemProperties; import android.os.UserHandle; import android.provider.Settings.Secure; +import android.support.annotation.VisibleForTesting; import android.util.Log; import android.util.Pair; import android.util.StatsLog; @@ -462,6 +463,7 @@ class AdapterProperties { // This function shall be invoked from BondStateMachine whenever the bond // state changes. + @VisibleForTesting void onBondStateChanged(BluetoothDevice device, int state) { if (device == null) { Log.w(TAG, "onBondStateChanged, device is null"); diff --git a/src/com/android/bluetooth/btservice/AdapterService.java b/src/com/android/bluetooth/btservice/AdapterService.java index ad7895519..9d8cde986 100644 --- a/src/com/android/bluetooth/btservice/AdapterService.java +++ b/src/com/android/bluetooth/btservice/AdapterService.java @@ -1817,6 +1817,18 @@ public class AdapterService extends Service { } } + /** + * Update device UUID changed to {@link BondStateMachine} + * + * @param device remote device of interest + */ + public void deviceUuidUpdated(BluetoothDevice device) { + // Notify BondStateMachine for SDP complete / UUID changed. + Message msg = mBondStateMachine.obtainMessage(BondStateMachine.UUID_UPDATE); + msg.obj = device; + mBondStateMachine.sendMessage(msg); + } + boolean cancelBondProcess(BluetoothDevice device) { enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); byte[] addr = Utils.getBytesFromAddress(device.getAddress()); diff --git a/src/com/android/bluetooth/btservice/BondStateMachine.java b/src/com/android/bluetooth/btservice/BondStateMachine.java index 13ef2ad4b..e89f5e7e1 100644 --- a/src/com/android/bluetooth/btservice/BondStateMachine.java +++ b/src/com/android/bluetooth/btservice/BondStateMachine.java @@ -34,10 +34,13 @@ import com.android.bluetooth.hfp.HeadsetService; import com.android.bluetooth.hfpclient.HeadsetClientService; import com.android.bluetooth.hid.HidHostService; import com.android.bluetooth.pbapclient.PbapClientService; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.State; import com.android.internal.util.StateMachine; import java.util.ArrayList; +import java.util.HashSet; +import java.util.Set; /** * This state machine handles Bluetooth Adapter State. @@ -57,6 +60,7 @@ final class BondStateMachine extends StateMachine { static final int BONDING_STATE_CHANGE = 4; static final int SSP_REQUEST = 5; static final int PIN_REQUEST = 6; + static final int UUID_UPDATE = 10; static final int BOND_STATE_NONE = 0; static final int BOND_STATE_BONDING = 1; static final int BOND_STATE_BONDED = 2; @@ -71,6 +75,8 @@ final class BondStateMachine extends StateMachine { public static final String OOBDATA = "oobdata"; + @VisibleForTesting Set<BluetoothDevice> mPendingBondedDevices = new HashSet<>(); + private BondStateMachine(AdapterService service, AdapterProperties prop, RemoteDevices remoteDevices) { super("BondStateMachine:"); @@ -144,7 +150,11 @@ final class BondStateMachine extends StateMachine { + state2str(newState)); } break; - + case UUID_UPDATE: + if (mPendingBondedDevices.contains(dev)) { + sendIntent(dev, BluetoothDevice.BOND_BONDED, 0); + } + break; case CANCEL_BOND: default: Log.e(TAG, "Received unhandled state: " + msg.what); @@ -330,17 +340,52 @@ final class BondStateMachine extends StateMachine { mAdapterService.sendOrderedBroadcast(intent, mAdapterService.BLUETOOTH_ADMIN_PERM); } - private void sendIntent(BluetoothDevice device, int newState, int reason) { + @VisibleForTesting + void sendIntent(BluetoothDevice device, int newState, int reason) { DeviceProperties devProp = mRemoteDevices.getDeviceProperties(device); int oldState = BluetoothDevice.BOND_NONE; + if (newState != BluetoothDevice.BOND_NONE + && newState != BluetoothDevice.BOND_BONDING + && newState != BluetoothDevice.BOND_BONDED) { + infoLog("Invalid bond state " + newState); + return; + } if (devProp != null) { oldState = devProp.getBondState(); } + if (mPendingBondedDevices.contains(device)) { + mPendingBondedDevices.remove(device); + if (oldState == BluetoothDevice.BOND_BONDED) { + if (newState == BluetoothDevice.BOND_BONDING) { + mAdapterProperties.onBondStateChanged(device, newState); + } + oldState = BluetoothDevice.BOND_BONDING; + } else { + // Should not enter here. + throw new IllegalArgumentException("Invalid old state " + oldState); + } + } if (oldState == newState) { return; } + mAdapterProperties.onBondStateChanged(device, newState); + if ((devProp.getDeviceType() == BluetoothDevice.DEVICE_TYPE_CLASSIC + || devProp.getDeviceType() == BluetoothDevice.DEVICE_TYPE_DUAL) + && newState == BluetoothDevice.BOND_BONDED && devProp.getUuids() == null) { + infoLog(device + " is bonded, wait for SDP complete to broadcast bonded intent"); + if (!mPendingBondedDevices.contains(device)) { + mPendingBondedDevices.add(device); + } + if (oldState == BluetoothDevice.BOND_NONE) { + // Broadcast NONE->BONDING for NONE->BONDED case. + newState = BluetoothDevice.BOND_BONDING; + } else { + return; + } + } + Intent intent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED); intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); intent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, newState); diff --git a/src/com/android/bluetooth/btservice/RemoteDevices.java b/src/com/android/bluetooth/btservice/RemoteDevices.java index 12897fea5..7525a78f9 100644 --- a/src/com/android/bluetooth/btservice/RemoteDevices.java +++ b/src/com/android/bluetooth/btservice/RemoteDevices.java @@ -177,6 +177,7 @@ final class RemoteDevices { return prop.getDevice(); } + @VisibleForTesting DeviceProperties addDeviceProperties(byte[] address) { synchronized (mDevices) { DeviceProperties prop = new DeviceProperties(); @@ -207,13 +208,13 @@ final class RemoteDevices { private byte[] mAddress; private int mBluetoothClass = BluetoothClass.Device.Major.UNCATEGORIZED; private short mRssi; - private ParcelUuid[] mUuids; - private int mDeviceType; private String mAlias; - private int mBondState; private BluetoothDevice mDevice; private boolean mIsBondingInitiatedLocally; private int mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN; + @VisibleForTesting int mBondState; + @VisibleForTesting int mDeviceType; + @VisibleForTesting ParcelUuid[] mUuids; DeviceProperties() { mBondState = BluetoothDevice.BOND_NONE; @@ -272,7 +273,6 @@ final class RemoteDevices { return mRssi; } } - /** * @return mDeviceType */ @@ -545,6 +545,7 @@ final class RemoteDevices { } device.mUuids = newUuids; if (sAdapterService.getState() == BluetoothAdapter.STATE_ON) { + sAdapterService.deviceUuidUpdated(bdDevice); sendUuidIntent(bdDevice); } break; diff --git a/src/com/android/bluetooth/hearingaid/HearingAidService.java b/src/com/android/bluetooth/hearingaid/HearingAidService.java index bbc61baf6..7f2ed89b5 100644 --- a/src/com/android/bluetooth/hearingaid/HearingAidService.java +++ b/src/com/android/bluetooth/hearingaid/HearingAidService.java @@ -334,24 +334,18 @@ public class HearingAidService extends ProfileService { return false; } // Check priority and accept or reject the connection. - // Note: Logic can be simplified, but keeping it this way for readability int priority = getPriority(device); int bondState = mAdapterService.getBondState(device); - // If priority is undefined, it is likely that service discovery has not completed and peer - // initiated the connection. Allow this connection only if the device is bonded or bonding - boolean serviceDiscoveryPending = (priority == BluetoothProfile.PRIORITY_UNDEFINED) - && (bondState == BluetoothDevice.BOND_BONDING - || bondState == BluetoothDevice.BOND_BONDED); - // Also allow connection when device is bonded/bonding and priority is ON/AUTO_CONNECT. - boolean isEnabled = (priority == BluetoothProfile.PRIORITY_ON - || priority == BluetoothProfile.PRIORITY_AUTO_CONNECT) - && (bondState == BluetoothDevice.BOND_BONDED - || bondState == BluetoothDevice.BOND_BONDING); - if (!serviceDiscoveryPending && !isEnabled) { - // Otherwise, reject the connection if no service discovery is pending and priority is - // neither PRIORITY_ON nor PRIORITY_AUTO_CONNECT - Log.w(TAG, "okToConnect: return false, priority=" + priority + ", bondState=" - + bondState); + // Allow this connection only if the device is bonded. Any attempt to connect while + // bonding would potentially lead to an unauthorized connection. + if (bondState != BluetoothDevice.BOND_BONDED) { + Log.w(TAG, "okToConnect: return false, bondState=" + bondState); + return false; + } else if (priority != BluetoothProfile.PRIORITY_UNDEFINED + && priority != BluetoothProfile.PRIORITY_ON + && priority != BluetoothProfile.PRIORITY_AUTO_CONNECT) { + // Otherwise, reject the connection if priority is not valid. + Log.w(TAG, "okToConnect: return false, priority=" + priority); return false; } return true; diff --git a/src/com/android/bluetooth/hfp/HeadsetService.java b/src/com/android/bluetooth/hfp/HeadsetService.java index db115ca2a..e7a7d6392 100644 --- a/src/com/android/bluetooth/hfp/HeadsetService.java +++ b/src/com/android/bluetooth/hfp/HeadsetService.java @@ -1688,24 +1688,18 @@ public class HeadsetService extends ProfileService { return false; } // Check priority and accept or reject the connection. - // Note: Logic can be simplified, but keeping it this way for readability int priority = getPriority(device); int bondState = mAdapterService.getBondState(device); - // If priority is undefined, it is likely that service discovery has not completed and peer - // initiated the connection. Allow this connection only if the device is bonded or bonding - boolean serviceDiscoveryPending = (priority == BluetoothProfile.PRIORITY_UNDEFINED) && ( - bondState == BluetoothDevice.BOND_BONDING - || bondState == BluetoothDevice.BOND_BONDED); - // Also allow connection when device is bonded/bonding and priority is ON/AUTO_CONNECT. - boolean isEnabled = (priority == BluetoothProfile.PRIORITY_ON - || priority == BluetoothProfile.PRIORITY_AUTO_CONNECT) && ( - bondState == BluetoothDevice.BOND_BONDED - || bondState == BluetoothDevice.BOND_BONDING); - if (!serviceDiscoveryPending && !isEnabled) { - // Otherwise, reject the connection if no service discovery is pending and priority is - // neither PRIORITY_ON nor PRIORITY_AUTO_CONNECT - Log.w(TAG, - "okToConnect: return false, priority=" + priority + ", bondState=" + bondState); + // Allow this connection only if the device is bonded. Any attempt to connect while + // bonding would potentially lead to an unauthorized connection. + if (bondState != BluetoothDevice.BOND_BONDED) { + Log.w(TAG, "okToAcceptConnection: return false, bondState=" + bondState); + return false; + } else if (priority != BluetoothProfile.PRIORITY_UNDEFINED + && priority != BluetoothProfile.PRIORITY_ON + && priority != BluetoothProfile.PRIORITY_AUTO_CONNECT) { + // Otherwise, reject the connection if priority is not valid. + Log.w(TAG, "okToAcceptConnection: return false, priority=" + priority); return false; } List<BluetoothDevice> connectingConnectedDevices = diff --git a/src/com/android/bluetooth/hid/HidHostService.java b/src/com/android/bluetooth/hid/HidHostService.java index ff1a608da..63f52060b 100644 --- a/src/com/android/bluetooth/hid/HidHostService.java +++ b/src/com/android/bluetooth/hid/HidHostService.java @@ -26,6 +26,7 @@ import android.os.Handler; import android.os.Message; import android.os.UserHandle; import android.provider.Settings; +import android.support.annotation.VisibleForTesting; import android.util.Log; import com.android.bluetooth.BluetoothMetricsProto; @@ -793,16 +794,41 @@ public class HidHostService extends ProfileService { } } - private boolean okToConnect(BluetoothDevice device) { + /** + * Check whether can connect to a peer device. + * The check considers a number of factors during the evaluation. + * + * @param device the peer device to connect to + * @return true if connection is allowed, otherwise false + */ + @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) + public boolean okToConnect(BluetoothDevice device) { AdapterService adapterService = AdapterService.getAdapterService(); - //check if it is inbound connection in Quiet mode, priority and Bond status - //to decide if its ok to allow this connection - if ((adapterService == null) || ((adapterService.isQuietModeEnabled()) && (mTargetDevice - == null)) || (BluetoothProfile.PRIORITY_OFF == getPriority(device)) || ( - device.getBondState() == BluetoothDevice.BOND_NONE)) { + // Check if adapter service is null. + if (adapterService == null) { + Log.w(TAG, "okToConnect: adapter service is null"); + return false; + } + // Check if this is an incoming connection in Quiet mode. + if (adapterService.isQuietModeEnabled() && mTargetDevice == null) { + Log.w(TAG, "okToConnect: return false as quiet mode enabled"); + return false; + } + // Check priority and accept or reject the connection. + int priority = getPriority(device); + int bondState = adapterService.getBondState(device); + // Allow this connection only if the device is bonded. Any attempt to connect while + // bonding would potentially lead to an unauthorized connection. + if (bondState != BluetoothDevice.BOND_BONDED) { + Log.w(TAG, "okToConnect: return false, bondState=" + bondState); + return false; + } else if (priority != BluetoothProfile.PRIORITY_UNDEFINED + && priority != BluetoothProfile.PRIORITY_ON + && priority != BluetoothProfile.PRIORITY_AUTO_CONNECT) { + // Otherwise, reject the connection if priority is not valid. + Log.w(TAG, "okToConnect: return false, priority=" + priority); return false; } - return true; } |