Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a03ab269 authored by Ugo Yu's avatar Ugo Yu Committed by Hansong Zhang
Browse files

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)
parent bf251153
Loading
Loading
Loading
Loading
+10 −16
Original line number Original line Diff line number Diff line
@@ -355,24 +355,18 @@ public class A2dpService extends ProfileService {
            return false;
            return false;
        }
        }
        // Check priority and accept or reject the connection.
        // 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 priority = getPriority(device);
        int bondState = mAdapterService.getBondState(device);
        int bondState = mAdapterService.getBondState(device);
        // If priority is undefined, it is likely that service discovery has not completed and peer
        // Allow this connection only if the device is bonded. Any attempt to connect while
        // initiated the connection. Allow this connection only if the device is bonded or bonding
        // bonding would potentially lead to an unauthorized connection.
        boolean serviceDiscoveryPending = (priority == BluetoothProfile.PRIORITY_UNDEFINED)
        if (bondState != BluetoothDevice.BOND_BONDED) {
                && (bondState == BluetoothDevice.BOND_BONDING
            Log.w(TAG, "okToConnect: return false, bondState=" + bondState);
                || bondState == BluetoothDevice.BOND_BONDED);
            return false;
        // Also allow connection when device is bonded/bonding and priority is ON/AUTO_CONNECT.
        } else if (priority != BluetoothProfile.PRIORITY_UNDEFINED
        boolean isEnabled = (priority == BluetoothProfile.PRIORITY_ON
                && priority != BluetoothProfile.PRIORITY_ON
                || priority == BluetoothProfile.PRIORITY_AUTO_CONNECT)
                && priority != BluetoothProfile.PRIORITY_AUTO_CONNECT) {
                && (bondState == BluetoothDevice.BOND_BONDED
            // Otherwise, reject the connection if priority is not valid.
                || bondState == BluetoothDevice.BOND_BONDING);
            Log.w(TAG, "okToConnect: return false, priority=" + priority);
        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);
            return false;
            return false;
        }
        }
        return true;
        return true;
+2 −0
Original line number Original line Diff line number Diff line
@@ -41,6 +41,7 @@ import android.os.ParcelUuid;
import android.os.SystemProperties;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserHandle;
import android.provider.Settings.Secure;
import android.provider.Settings.Secure;
import android.support.annotation.VisibleForTesting;
import android.util.Log;
import android.util.Log;
import android.util.Pair;
import android.util.Pair;
import android.util.StatsLog;
import android.util.StatsLog;
@@ -462,6 +463,7 @@ class AdapterProperties {


    // This function shall be invoked from BondStateMachine whenever the bond
    // This function shall be invoked from BondStateMachine whenever the bond
    // state changes.
    // state changes.
    @VisibleForTesting
    void onBondStateChanged(BluetoothDevice device, int state) {
    void onBondStateChanged(BluetoothDevice device, int state) {
        if (device == null) {
        if (device == null) {
            Log.w(TAG, "onBondStateChanged, device is null");
            Log.w(TAG, "onBondStateChanged, device is null");
+12 −0
Original line number Original line Diff line number Diff line
@@ -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) {
    boolean cancelBondProcess(BluetoothDevice device) {
        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission");
        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission");
        byte[] addr = Utils.getBytesFromAddress(device.getAddress());
        byte[] addr = Utils.getBytesFromAddress(device.getAddress());
+47 −2
Original line number Original line Diff line number Diff line
@@ -34,10 +34,13 @@ import com.android.bluetooth.hfp.HeadsetService;
import com.android.bluetooth.hfpclient.HeadsetClientService;
import com.android.bluetooth.hfpclient.HeadsetClientService;
import com.android.bluetooth.hid.HidHostService;
import com.android.bluetooth.hid.HidHostService;
import com.android.bluetooth.pbapclient.PbapClientService;
import com.android.bluetooth.pbapclient.PbapClientService;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.State;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
import com.android.internal.util.StateMachine;


import java.util.ArrayList;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;


/**
/**
 * This state machine handles Bluetooth Adapter State.
 * 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 BONDING_STATE_CHANGE = 4;
    static final int SSP_REQUEST = 5;
    static final int SSP_REQUEST = 5;
    static final int PIN_REQUEST = 6;
    static final int PIN_REQUEST = 6;
    static final int UUID_UPDATE = 10;
    static final int BOND_STATE_NONE = 0;
    static final int BOND_STATE_NONE = 0;
    static final int BOND_STATE_BONDING = 1;
    static final int BOND_STATE_BONDING = 1;
    static final int BOND_STATE_BONDED = 2;
    static final int BOND_STATE_BONDED = 2;
@@ -71,6 +75,8 @@ final class BondStateMachine extends StateMachine {


    public static final String OOBDATA = "oobdata";
    public static final String OOBDATA = "oobdata";


    @VisibleForTesting Set<BluetoothDevice> mPendingBondedDevices = new HashSet<>();

    private BondStateMachine(AdapterService service, AdapterProperties prop,
    private BondStateMachine(AdapterService service, AdapterProperties prop,
            RemoteDevices remoteDevices) {
            RemoteDevices remoteDevices) {
        super("BondStateMachine:");
        super("BondStateMachine:");
@@ -144,7 +150,11 @@ final class BondStateMachine extends StateMachine {
                                + state2str(newState));
                                + state2str(newState));
                    }
                    }
                    break;
                    break;

                case UUID_UPDATE:
                    if (mPendingBondedDevices.contains(dev)) {
                        sendIntent(dev, BluetoothDevice.BOND_BONDED, 0);
                    }
                    break;
                case CANCEL_BOND:
                case CANCEL_BOND:
                default:
                default:
                    Log.e(TAG, "Received unhandled state: " + msg.what);
                    Log.e(TAG, "Received unhandled state: " + msg.what);
@@ -330,17 +340,52 @@ final class BondStateMachine extends StateMachine {
        mAdapterService.sendOrderedBroadcast(intent, mAdapterService.BLUETOOTH_ADMIN_PERM);
        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);
        DeviceProperties devProp = mRemoteDevices.getDeviceProperties(device);
        int oldState = BluetoothDevice.BOND_NONE;
        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) {
        if (devProp != null) {
            oldState = devProp.getBondState();
            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) {
        if (oldState == newState) {
            return;
            return;
        }
        }

        mAdapterProperties.onBondStateChanged(device, newState);
        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 intent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
        intent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, newState);
        intent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, newState);
+5 −4
Original line number Original line Diff line number Diff line
@@ -177,6 +177,7 @@ final class RemoteDevices {
        return prop.getDevice();
        return prop.getDevice();
    }
    }


    @VisibleForTesting
    DeviceProperties addDeviceProperties(byte[] address) {
    DeviceProperties addDeviceProperties(byte[] address) {
        synchronized (mDevices) {
        synchronized (mDevices) {
            DeviceProperties prop = new DeviceProperties();
            DeviceProperties prop = new DeviceProperties();
@@ -207,13 +208,13 @@ final class RemoteDevices {
        private byte[] mAddress;
        private byte[] mAddress;
        private int mBluetoothClass = BluetoothClass.Device.Major.UNCATEGORIZED;
        private int mBluetoothClass = BluetoothClass.Device.Major.UNCATEGORIZED;
        private short mRssi;
        private short mRssi;
        private ParcelUuid[] mUuids;
        private int mDeviceType;
        private String mAlias;
        private String mAlias;
        private int mBondState;
        private BluetoothDevice mDevice;
        private BluetoothDevice mDevice;
        private boolean mIsBondingInitiatedLocally;
        private boolean mIsBondingInitiatedLocally;
        private int mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
        private int mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
        @VisibleForTesting int mBondState;
        @VisibleForTesting int mDeviceType;
        @VisibleForTesting ParcelUuid[] mUuids;


        DeviceProperties() {
        DeviceProperties() {
            mBondState = BluetoothDevice.BOND_NONE;
            mBondState = BluetoothDevice.BOND_NONE;
@@ -272,7 +273,6 @@ final class RemoteDevices {
                return mRssi;
                return mRssi;
            }
            }
        }
        }

        /**
        /**
         * @return mDeviceType
         * @return mDeviceType
         */
         */
@@ -545,6 +545,7 @@ final class RemoteDevices {
                            }
                            }
                            device.mUuids = newUuids;
                            device.mUuids = newUuids;
                            if (sAdapterService.getState() == BluetoothAdapter.STATE_ON) {
                            if (sAdapterService.getState() == BluetoothAdapter.STATE_ON) {
                                sAdapterService.deviceUuidUpdated(bdDevice);
                                sendUuidIntent(bdDevice);
                                sendUuidIntent(bdDevice);
                            }
                            }
                            break;
                            break;
Loading