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

Commit 4fbc1a04 authored by Ömer Faruk Yılmaz's avatar Ömer Faruk Yılmaz
Browse files

Scan from ScanController instead of GattService

See go/scan-manager-refactor for more details.

Test: m com.android.btservices
Test: Manual. Start a BluetoothLeScanner and scan for nearby devices. With the flag enabled, the new ScanController will be used
Bug: 313335632
Bug: 267361243
Bug: 327503826
Change-Id: I10bad9a78620c1ccb621b96961d217baf3d4e440
parent 3505ccf1
Loading
Loading
Loading
Loading
+100 −37
Original line number Diff line number Diff line
@@ -531,7 +531,8 @@ public class AdapterService extends Service {
                    mRunningProfiles.add(profile);
                    // TODO(b/228875190): GATT is assumed supported. GATT starting triggers hardware
                    // initialization. Configuring a device without GATT causes start up failures.
                    if (GattService.class.getSimpleName().equals(profile.getName())) {
                    if (GattService.class.getSimpleName().equals(profile.getName())
                            && !Flags.scanManagerRefactor()) {
                        mNativeInterface.enable();
                    } else if (mRegisteredProfiles.size() == Config.getSupportedProfiles().length
                            && mRegisteredProfiles.size() == mRunningProfiles.size()) {
@@ -556,8 +557,14 @@ public class AdapterService extends Service {
                        return;
                    }
                    mRunningProfiles.remove(profile);
                    // TODO(b/228875190): GATT is assumed supported. GATT is expected to be the only
                    // profile available in the "BLE ON" state. If only GATT is left, send

                    if (Flags.scanManagerRefactor()) {
                        if (mRunningProfiles.size() == 0) {
                            mAdapterStateMachine.sendMessage(AdapterState.BREDR_STOPPED);
                        }
                    } else {
                        // TODO(b/228875190): GATT is assumed supported. GATT is expected to be the
                        // only profile available in the "BLE ON" state. If only GATT is left, send
                        // BREDR_STOPPED. If GATT is stopped, deinitialize the hardware.
                        if ((mRunningProfiles.size() == 1
                                && (GattService.class
@@ -567,6 +574,7 @@ public class AdapterService extends Service {
                        } else if (mRunningProfiles.size() == 0) {
                            mNativeInterface.disable();
                        }
                    }
                    break;
                default:
                    Log.e(TAG, "Unhandled profile state: " + state);
@@ -1027,12 +1035,20 @@ public class AdapterService extends Service {
                    TAG,
                    "GATT is configured off but the stack assumes it to be enabled. Start anyway.");
        }
        if (Flags.scanManagerRefactor()) {
            startScanController();
        } else {
            startGattProfileService();
        }
    }

    void bringDownBle() {
        if (Flags.scanManagerRefactor()) {
            stopScanController();
        } else {
            stopGattProfileService();
        }
    }

    void stateChangeCallback(int status) {
        if (status == AbstractionLayer.BT_STATE_OFF) {
@@ -1048,9 +1064,20 @@ public class AdapterService extends Service {
    void startProfileServices() {
        Log.d(TAG, "startCoreServices()");
        int[] supportedProfileServices = Config.getSupportedProfiles();
        // TODO(b/228875190): GATT is assumed supported. If we support no other profiles then just
        // move on to BREDR_STARTED. Note that configuring GATT to NOT supported will cause adapter
        // initialization failures
        if (Flags.scanManagerRefactor()) {
            // Scanning is always supported, started separately, and is not a profile service.
            // This will check other profile services.
            if (supportedProfileServices.length == 0) {
                mAdapterProperties.onBluetoothReady();
                updateUuids();
                mAdapterStateMachine.sendMessage(AdapterState.BREDR_STARTED);
            } else {
                setAllProfileServiceStates(supportedProfileServices, BluetoothAdapter.STATE_ON);
            }
        } else {
            // TODO(b/228875190): GATT is assumed supported. If we support no other profiles then
            // just move on to BREDR_STARTED. Note that configuring GATT to NOT supported will cause
            // adapter initialization failures
            if (supportedProfileServices.length == 1
                    && supportedProfileServices[0] == BluetoothProfile.GATT) {
                mAdapterProperties.onBluetoothReady();
@@ -1060,6 +1087,7 @@ public class AdapterService extends Service {
                setAllProfileServiceStates(supportedProfileServices, BluetoothAdapter.STATE_ON);
            }
        }
    }

    void stopProfileServices() {
        // Make sure to stop classic background tasks now
@@ -1067,19 +1095,31 @@ public class AdapterService extends Service {
        mAdapterProperties.setScanMode(BluetoothAdapter.SCAN_MODE_NONE);

        int[] supportedProfileServices = Config.getSupportedProfiles();
        // TODO(b/228875190): GATT is assumed supported. If we support no profiles then just move on
        // to BREDR_STOPPED
        if (Flags.scanManagerRefactor()) {
            // Scanning is always supported, started separately, and is not a profile service.
            // This will check other profile services.
            if (supportedProfileServices.length == 0) {
                mAdapterStateMachine.sendMessage(AdapterState.BREDR_STOPPED);
            } else {
                setAllProfileServiceStates(supportedProfileServices, BluetoothAdapter.STATE_OFF);
            }
        } else {
            // TODO(b/228875190): GATT is assumed supported. If we support no profiles then just
            // move on to BREDR_STOPPED
            if (supportedProfileServices.length == 1
                    && (mRunningProfiles.size() == 1
                            && GattService.class
                                    .getSimpleName()
                                    .equals(mRunningProfiles.get(0).getName()))) {
            Log.d(TAG, "stopProfileServices() - No profiles services to stop or already stopped.");
                Log.d(
                        TAG,
                        "stopProfileServices() - No profiles services to stop or already stopped.");
                mAdapterStateMachine.sendMessage(AdapterState.BREDR_STOPPED);
            } else {
                setAllProfileServiceStates(supportedProfileServices, BluetoothAdapter.STATE_OFF);
            }
        }
    }

    private void startGattProfileService() {
        mGattService = new GattService(this);
@@ -1091,6 +1131,11 @@ public class AdapterService extends Service {
        onProfileServiceStateChanged(mGattService, BluetoothAdapter.STATE_ON);
    }

    private void startScanController() {
        mScanController = new ScanController(this);
        mNativeInterface.enable();
    }

    private void stopGattProfileService() {
        mAdapterProperties.onBleDisable();
        if (mRunningProfiles.size() == 0) {
@@ -1110,6 +1155,18 @@ public class AdapterService extends Service {
        }
    }

    private void stopScanController() {
        mAdapterProperties.onBleDisable();

        if (mScanController == null) {
            mAdapterStateMachine.sendMessage(AdapterState.BLE_STOPPED);
        } else {
            mScanController.stop();
            mScanController = null;
            mNativeInterface.disable();
        }
    }

    private void invalidateBluetoothGetStateCache() {
        BluetoothAdapter.invalidateBluetoothGetStateCache();
    }
@@ -1529,11 +1586,13 @@ public class AdapterService extends Service {

    private void setAllProfileServiceStates(int[] profileIds, int state) {
        for (int profileId : profileIds) {
            // TODO(b/228875190): GATT is assumed supported and treated differently as part of the
            // "BLE ON" state, despite GATT not being BLE specific.
            if (!Flags.scanManagerRefactor()) {
                // TODO(b/228875190): GATT is assumed supported and treated differently as part of
                //  the "BLE ON" state, despite GATT not being BLE specific.
                if (profileId == BluetoothProfile.GATT) {
                    continue;
                }
            }
            setProfileServiceState(profileId, state);
        }
    }
@@ -5951,8 +6010,12 @@ public class AdapterService extends Service {
            Log.w(TAG, "GATT Service is not running!");
            return;
        }
        if (Flags.scanManagerRefactor()) {
            mScanController.notifyProfileConnectionStateChange(profile, fromState, toState);
        } else {
            mGattService.notifyProfileConnectionStateChange(profile, fromState, toState);
        }
    }

    /**
     * Handle Bluetooth app state when connection state changes for a given {@code profile}.
+23 −16
Original line number Diff line number Diff line
@@ -40,16 +40,12 @@ public class ScanController {

    private final BluetoothScanBinder mBinder;

    private boolean isAvailable = false;
    private boolean mIsAvailable;

    public ScanController(Context ctx) {
        mTransitionalScanHelper = new TransitionalScanHelper(ctx, () -> false);
        mBinder = new BluetoothScanBinder(this);
    }

    public void start() {
        Log.d(TAG, "start()");
        isAvailable = true;
        mIsAvailable = true;
        HandlerThread thread = new HandlerThread("BluetoothScanManager");
        thread.start();
        mTransitionalScanHelper.start(thread.getLooper());
@@ -57,11 +53,17 @@ public class ScanController {

    public void stop() {
        Log.d(TAG, "stop()");
        isAvailable = false;
        mIsAvailable = false;
        mBinder.clearScanController();
        mTransitionalScanHelper.stop();
        mTransitionalScanHelper.cleanup();
    }

    /** Notify Scan manager of bluetooth profile connection state changes */
    public void notifyProfileConnectionStateChange(int profile, int fromState, int toState) {
        mTransitionalScanHelper.notifyProfileConnectionStateChange(profile, fromState, toState);
    }

    TransitionalScanHelper getTransitionalScanHelper() {
        return mTransitionalScanHelper;
    }
@@ -71,20 +73,12 @@ public class ScanController {
    }

    static class BluetoothScanBinder extends IBluetoothScan.Stub {
        private final ScanController mScanController;
        private ScanController mScanController;

        BluetoothScanBinder(ScanController scanController) {
            mScanController = scanController;
        }

        private ScanController getScanController() {
            if (mScanController.isAvailable) {
                return mScanController;
            }
            Log.e(TAG, "getScanController() - ScanController requested, but not available!");
            return null;
        }

        @Override
        public void registerScanner(
                IScannerCallback callback,
@@ -236,5 +230,18 @@ public class ScanController {
                    .getTransitionalScanHelper()
                    .numHwTrackFiltersAvailable(attributionSource);
        }

        private void clearScanController() {
            mScanController = null;
        }

        private ScanController getScanController() {
            ScanController controller = mScanController;
            if (controller != null && controller.mIsAvailable) {
                return controller;
            }
            Log.e(TAG, "getScanController() - ScanController requested, but not available!");
            return null;
        }
    }
}
+134 −2
Original line number Diff line number Diff line
@@ -409,9 +409,11 @@ public class AdapterServiceTest {
        TestUtils.syncHandler(looper, AdapterState.BLE_TURN_ON);
        verifyStateChange(callback, STATE_OFF, STATE_BLE_TURNING_ON);

        if (!Flags.scanManagerRefactor()) {
            TestUtils.syncHandler(looper, MESSAGE_PROFILE_SERVICE_REGISTERED);

            TestUtils.syncHandler(looper, MESSAGE_PROFILE_SERVICE_STATE_CHANGED);
        }

        verify(nativeInterface).enable();
        adapter.stateChangeCallback(AbstractionLayer.BT_STATE_ON);
@@ -675,6 +677,136 @@ public class AdapterServiceTest {
        assertThat(mAdapterService.getState()).isEqualTo(STATE_OFF);
    }

    @Test
    public void startBleOnly_whenScanManagerRefactorFlagIsOff_onlyStartGattProfile() {
        mSetFlagsRule.disableFlags(Flags.FLAG_SCAN_MANAGER_REFACTOR);

        mAdapterService.bringUpBle();

        assertThat(mAdapterService.getBluetoothGatt()).isNotNull();
        assertThat(mAdapterService.getBluetoothScan()).isNull();

        dropNextMessage(MESSAGE_PROFILE_SERVICE_REGISTERED);
        dropNextMessage(MESSAGE_PROFILE_SERVICE_STATE_CHANGED);
    }

    @Test
    public void startBleOnly_whenScanManagerRefactorFlagIsOn_onlyStartScanController() {
        mSetFlagsRule.enableFlags(Flags.FLAG_SCAN_MANAGER_REFACTOR);

        mAdapterService.bringUpBle();

        assertThat(mAdapterService.getBluetoothGatt()).isNull();
        assertThat(mAdapterService.getBluetoothScan()).isNotNull();
    }

    @Test
    public void startBleOnly_whenScanManagerRefactorFlagIsOn_startAndStopScanController() {
        mSetFlagsRule.enableFlags(Flags.FLAG_SCAN_MANAGER_REFACTOR);

        assertThat(mAdapterService.getBluetoothScan()).isNull();
        assertThat(mAdapterService.getBluetoothGatt()).isNull();

        IBluetoothCallback callback = mock(IBluetoothCallback.class);
        Binder binder = mock(Binder.class);
        doReturn(binder).when(callback).asBinder();
        mAdapterService.registerRemoteCallback(callback);

        offToBleOn(
                mLooper,
                mMockGattService,
                mAdapterService,
                mMockContext,
                mIBluetoothCallback,
                mNativeInterface);

        assertThat(mAdapterService.getBluetoothScan()).isNotNull();
        assertThat(mAdapterService.getBluetoothGatt()).isNull();

        mAdapterService.stopBle();
        TestUtils.syncHandler(mLooper, AdapterState.BLE_TURN_OFF);
        verifyStateChange(callback, STATE_BLE_ON, STATE_BLE_TURNING_OFF);

        verify(mNativeInterface).disable();
        mAdapterService.stateChangeCallback(AbstractionLayer.BT_STATE_OFF);
        TestUtils.syncHandler(mLooper, AdapterState.BLE_STOPPED);
        verifyStateChange(callback, STATE_BLE_TURNING_OFF, STATE_OFF);

        assertThat(mAdapterService.getState()).isEqualTo(STATE_OFF);
        mAdapterService.unregisterRemoteCallback(callback);

        assertThat(mAdapterService.getBluetoothScan()).isNull();
        assertThat(mAdapterService.getBluetoothGatt()).isNull();
    }

    @Test
    public void startBrDr_whenScanManagerRefactorFlagIsOn_startAndStopScanController() {
        mSetFlagsRule.enableFlags(Flags.FLAG_SCAN_MANAGER_REFACTOR);

        assertThat(mAdapterService.getBluetoothScan()).isNull();
        assertThat(mAdapterService.getBluetoothGatt()).isNull();

        IBluetoothCallback callback = mock(IBluetoothCallback.class);
        Binder binder = mock(Binder.class);
        doReturn(binder).when(callback).asBinder();
        mAdapterService.registerRemoteCallback(callback);

        assertThat(mAdapterService.getState()).isEqualTo(STATE_OFF);

        offToBleOn(
                mLooper,
                mMockGattService,
                mAdapterService,
                mMockContext,
                mIBluetoothCallback,
                mNativeInterface);

        assertThat(mAdapterService.getBluetoothScan()).isNotNull();
        assertThat(mAdapterService.getBluetoothGatt()).isNull();

        mAdapterService.startBrEdr();
        TestUtils.syncHandler(mLooper, AdapterState.USER_TURN_ON);
        verifyStateChange(callback, STATE_BLE_ON, STATE_TURNING_ON);

        // Start Mock PBAP, PAN, and GATT services
        assertThat(mAdapterService.mSetProfileServiceStateCounter).isEqualTo(3);
        List<ProfileService> services = List.of(mMockService, mMockService2, mMockGattService);

        for (ProfileService service : services) {
            mAdapterService.addProfile(service);
            TestUtils.syncHandler(mLooper, MESSAGE_PROFILE_SERVICE_REGISTERED);
        }

        for (ProfileService service : services) {
            mAdapterService.onProfileServiceStateChanged(service, STATE_ON);
            TestUtils.syncHandler(mLooper, MESSAGE_PROFILE_SERVICE_STATE_CHANGED);
        }

        TestUtils.syncHandler(mLooper, AdapterState.BREDR_STARTED);
        verifyStateChange(callback, STATE_TURNING_ON, STATE_ON);

        assertThat(mAdapterService.getState()).isEqualTo(STATE_ON);

        mAdapterService.disable();
        TestUtils.syncHandler(mLooper, AdapterState.USER_TURN_OFF);
        verifyStateChange(callback, STATE_ON, STATE_TURNING_OFF);

        // Stop PBAP, PAN, and GATT services
        assertThat(mAdapterService.mSetProfileServiceStateCounter).isEqualTo(6);

        for (ProfileService service : services) {
            mAdapterService.onProfileServiceStateChanged(service, STATE_OFF);
            TestUtils.syncHandler(mLooper, MESSAGE_PROFILE_SERVICE_STATE_CHANGED);
        }

        TestUtils.syncHandler(mLooper, AdapterState.BREDR_STOPPED);
        verifyStateChange(callback, STATE_TURNING_OFF, STATE_BLE_ON);

        assertThat(mAdapterService.getState()).isEqualTo(STATE_BLE_ON);

        mAdapterService.unregisterRemoteCallback(callback);
    }

    /**
     * Test: Don't start a classic profile
     * Check whether the AdapterService quits gracefully