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

Commit aa58f747 authored by William Escande's avatar William Escande
Browse files

No longer bind to gatt from BluetoothManagerService

Having or not a gatt service is now consider as a implementation detail.

----

Previous Behavior:
1. Bind to AdapterService(mBluetooth)
2. adapter.enable -> bringUpBle() -> StartService(Gatt)
3. After start is done, trigger state_change callback with BLE_ON
4. BMS bind to Gatt and then start brEdr if needed

Between 3 and 4, listener of BLE_STATE_CHANGED intent may expect
getBluetoothGatt to return a non-null token

Current Behavior:
1. Bind to AdapterService(mBluetooth)
2. adapter.enable -> bringUpBle() -> BindService(Gatt)
3. After bind is done, trigger state_change callback with BLE_ON
4. BMS start brEdr if needed

Bug: 262605980
Bug: 285959170
Test: atest ServiceBluetoothTests
Test: manual start & stop of Bluetooth
Change-Id: I1aef0faa84d9f465239a05731e740c34df38e753
parent 1d5da504
Loading
Loading
Loading
Loading
+123 −2
Original line number Diff line number Diff line
@@ -64,6 +64,7 @@ import android.bluetooth.IBluetooth;
import android.bluetooth.IBluetoothActivityEnergyInfoListener;
import android.bluetooth.IBluetoothCallback;
import android.bluetooth.IBluetoothConnectionCallback;
import android.bluetooth.IBluetoothGatt;
import android.bluetooth.IBluetoothMetadataListener;
import android.bluetooth.IBluetoothOobDataCallback;
import android.bluetooth.IBluetoothPreferredAudioProfilesCallback;
@@ -75,9 +76,11 @@ import android.bluetooth.UidTraffic;
import android.companion.CompanionDeviceManager;
import android.content.AttributionSource;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.os.AsyncTask;
@@ -358,6 +361,7 @@ public class AdapterService extends Service {
    private BassClientService mBassClientService;
    private BatteryService mBatteryService;
    private BluetoothQualityReportNativeInterface mBluetoothQualityReportNativeInterface;
    private IBluetoothGatt mBluetoothGatt;

    private volatile boolean mTestModeEnabled = false;

@@ -411,6 +415,8 @@ public class AdapterService extends Service {
    private static final int MESSAGE_PROFILE_SERVICE_REGISTERED = 2;
    private static final int MESSAGE_PROFILE_SERVICE_UNREGISTERED = 3;
    private static final int MESSAGE_PREFERRED_AUDIO_PROFILES_AUDIO_FRAMEWORK_TIMEOUT = 4;
    private static final int MESSAGE_ON_PROFILE_SERVICE_BIND = 5;
    private static final int MESSAGE_ON_PROFILE_SERVICE_UNBIND = 6;

    class AdapterServiceHandler extends Handler {
        @Override
@@ -430,6 +436,14 @@ public class AdapterService extends Service {
                    verboseLog("handleMessage() - MESSAGE_PROFILE_SERVICE_UNREGISTERED");
                    unregisterProfileService((ProfileService) msg.obj);
                    break;
                case MESSAGE_ON_PROFILE_SERVICE_BIND:
                    verboseLog("handleMessage() - MESSAGE_ON_PROFILE_SERVICE_BIND");
                    onGattBind((IBinder) msg.obj);
                    break;
                case MESSAGE_ON_PROFILE_SERVICE_UNBIND:
                    verboseLog("handleMessage() - MESSAGE_ON_PROFILE_SERVICE_UNBIND");
                    onGattUnbind();
                    break;
                case MESSAGE_PREFERRED_AUDIO_PROFILES_AUDIO_FRAMEWORK_TIMEOUT:
                    errorLog("handleMessage() - "
                            + "MESSAGE_PREFERRED_PROFILE_CHANGE_AUDIO_FRAMEWORK_TIMEOUT");
@@ -464,6 +478,22 @@ public class AdapterService extends Service {
            mRegisteredProfiles.remove(profile);
        }

        private void onGattBind(IBinder service) {
            mBluetoothGatt = IBluetoothGatt.Stub.asInterface(service);
            try {
                mBluetoothGatt.startService();
            } catch (RemoteException e) {
                Log.e(TAG, "onGattBind: RemoteException", e);
            }
        }

        private void onGattUnbind() {
            mBluetoothGatt = null;
            Log.e(
                    TAG,
                    "onGattUnbind: Gatt service has disconnected from AdapterService unexpectedly");
        }

        private void processProfileServiceStateChanged(ProfileService profile, int state) {
            switch (state) {
                case BluetoothAdapter.STATE_ON:
@@ -841,7 +871,7 @@ public class AdapterService extends Service {
            Log.w(TAG,
                    "GATT is configured off but the stack assumes it to be enabled. Start anyway.");
        }
        setProfileServiceState(GattService.class, BluetoothAdapter.STATE_ON);
        startGattProfileService();
    }

    void bringDownBle() {
@@ -892,13 +922,66 @@ public class AdapterService extends Service {
        }
    }

    class GattServiceConnection implements ServiceConnection {
        public void onServiceConnected(ComponentName componentName, IBinder service) {
            String name = componentName.getClassName();
            if (DBG) {
                Log.d(TAG, "GattServiceConnection.onServiceConnected: " + name);
            }
            if (!name.equals(GattService.class.getName())) {
                Log.e(TAG, "Unknown service connected: " + name);
                return;
            }
            mHandler.obtainMessage(MESSAGE_ON_PROFILE_SERVICE_BIND, service).sendToTarget();
        }

        public void onServiceDisconnected(ComponentName componentName) {
            // Called if we unexpectedly disconnect. This should never happen.
            String name = componentName.getClassName();
            Log.e(TAG, "GattServiceConnection.onServiceDisconnected: " + name);
            if (!name.equals(GattService.class.getName())) {
                Log.e(TAG, "Unknown service disconnected: " + name);
                return;
            }
            mHandler.sendEmptyMessage(MESSAGE_ON_PROFILE_SERVICE_UNBIND);
        }
    }

    private GattServiceConnection mGattConnection = new GattServiceConnection();

    private void startGattProfileService() {
        mStartedProfiles.add(GattService.class.getSimpleName());

        Intent intent = new Intent(this, GattService.class);
        if (!bindServiceAsUser(
                intent,
                mGattConnection,
                Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
                UserHandle.CURRENT)) {
            // This should never happen
            // unbindService will be called during stopGattProfileService triggered by AdapterState
            Log.e(TAG, "Error while binding to gatt. This Bluetooth session will timeout");
            unbindService(mGattConnection);
        }
    }

    private void stopGattProfileService() {
        mAdapterProperties.onBleDisable();
        if (mRunningProfiles.size() == 0) {
            debugLog("stopGattProfileService() - No profiles services to stop.");
            mAdapterStateMachine.sendMessage(AdapterState.BLE_STOPPED);
        }
        setProfileServiceState(GattService.class, BluetoothAdapter.STATE_OFF);

        mStartedProfiles.remove(GattService.class.getSimpleName());

        try {
            if (mBluetoothGatt != null) {
                mBluetoothGatt.stopService();
            }
        } catch (RemoteException e) {
            Log.e(TAG, "stopGattProfileService: RemoteException", e);
        }
        unbindService(mGattConnection);
    }

    private void invalidateBluetoothGetStateCache() {
@@ -4714,6 +4797,30 @@ public class AdapterService extends Service {

            return service.getOffloadedTransportDiscoveryDataScanSupported();
        }

        @Override
        public IBluetoothGatt getBluetoothGatt() {
            AdapterService service = getService();
            if (service == null) {
                return null;
            }
            return service.getBluetoothGatt();
        }

        @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
        @Override
        public void unregAllGattClient(
                AttributionSource source, SynchronousResultReceiver receiver) {
            try {
                AdapterService service = getService();
                if (service != null) {
                    service.unregAllGattClient(source);
                }
                receiver.send(null);
            } catch (RuntimeException e) {
                receiver.propagateException(e);
            }
        }
    }

    /**
@@ -6236,6 +6343,20 @@ public class AdapterService extends Service {
        return BluetoothStatusCodes.FEATURE_NOT_SUPPORTED;
    }

    IBluetoothGatt getBluetoothGatt() {
        return mBluetoothGatt;
    }

    void unregAllGattClient(AttributionSource source) {
        if (mBluetoothGatt != null) {
            try {
                mBluetoothGatt.unregAll(source);
            } catch (RemoteException e) {
                Log.e(TAG, "Unable to disconnect all apps.", e);
            }
        }
    }

    /**
     * Notify the UID and package name of the app, and the address of associated active device
     *
+10 −6
Original line number Diff line number Diff line
@@ -280,6 +280,7 @@ public abstract class ProfileService extends Service {
    // Suppressed since this is called from framework
    @SuppressLint("AndroidFrameworkRequiresPermission")
    public void onDestroy() {
        Log.v(mName, "onDestroy");
        cleanup();
        if (mBinder != null) {
            mBinder.cleanup();
@@ -289,11 +290,13 @@ public abstract class ProfileService extends Service {
        super.onDestroy();
    }

    @RequiresPermission(anyOf = {
    @RequiresPermission(
            anyOf = {
                android.Manifest.permission.MANAGE_USERS,
                android.Manifest.permission.INTERACT_ACROSS_USERS
            })
    private void doStart() {
    protected void doStart() {
        Log.v(mName, "doStart");
        if (mAdapter == null) {
            Log.w(mName, "Can't start profile service: device does not have BT");
            return;
@@ -318,7 +321,8 @@ public abstract class ProfileService extends Service {
        mAdapterService.onProfileServiceStateChanged(this, BluetoothAdapter.STATE_ON);
    }

    private void doStop() {
    protected void doStop() {
        Log.v(mName, "doStop");
        if (mAdapterService == null || mAdapterService.isStartedProfile(mName)) {
            Log.w(mName, "Unexpectedly do Stop, don't stop.");
            return;
+30 −10
Original line number Diff line number Diff line
@@ -84,8 +84,8 @@ import com.android.bluetooth.Utils;
import com.android.bluetooth.btservice.AbstractionLayer;
import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.BluetoothAdapterProxy;
import com.android.bluetooth.btservice.MetricsLogger;
import com.android.bluetooth.btservice.CompanionManager;
import com.android.bluetooth.btservice.MetricsLogger;
import com.android.bluetooth.btservice.ProfileService;
import com.android.bluetooth.util.NumberUtils;
import com.android.internal.annotations.VisibleForTesting;
@@ -608,6 +608,34 @@ public class GattService extends ProfileService {
            return null;
        }

        @Override
        public void startService() {
            GattService service = mService;
            if (service == null) {
                Log.e(TAG, "startService: Service is null");
                return;
            }
            if (!Utils.checkConnectPermissionForDataDelivery(
                    service, null, "GattService startService")) {
                return;
            }
            service.doStart();
        }

        @Override
        public void stopService() {
            GattService service = mService;
            if (service == null) {
                Log.e(TAG, "stopService: Service is null");
                return;
            }
            if (!Utils.checkConnectPermissionForDataDelivery(
                    service, null, "GattService stopService")) {
                return;
            }
            service.doStop();
        }

        @Override
        public void getDevicesMatchingConnectionStates(int[] states,
                AttributionSource attributionSource, SynchronousResultReceiver receiver) {
@@ -1747,15 +1775,7 @@ public class GattService extends ProfileService {
        }

        @Override
        public void unregAll(AttributionSource source, SynchronousResultReceiver receiver) {
            try {
                unregAll(source);
                receiver.send(null);
            } catch (RuntimeException e) {
                receiver.propagateException(e);
            }
        }
        private void unregAll(AttributionSource attributionSource) {
        public void unregAll(AttributionSource attributionSource) {
            GattService service = getService();
            if (service == null) {
                return;
+35 −30
Original line number Diff line number Diff line
@@ -330,7 +330,7 @@ public class AdapterServiceFactoryResetTest {
        Log.e(TAG, "tearDown()");

        // Enable the stack to re-create the config. Next tests rely on it.
        doEnable(0, false);
        doEnable();

        // Restores the foregroundUserId to the ID prior to the test setup
        Utils.setForegroundUserId(mForegroundUserId);
@@ -353,55 +353,60 @@ public class AdapterServiceFactoryResetTest {
        }
    }

    private void doEnable(int invocationNumber, boolean onlyGatt) {
        Log.e(TAG, "doEnable() start");
    private void doEnable() {
        Log.e("AdapterServiceTest", "doEnable() start");
        Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON);

        int startServiceCalls;
        startServiceCalls = 2 * (onlyGatt ? 1 : 3); // Start and stop GATT + 2

        mAdapterService.enable(false);

        verifyStateChange(BluetoothAdapter.STATE_OFF, BluetoothAdapter.STATE_BLE_TURNING_ON,
                invocationNumber + 1, CONTEXT_SWITCH_MS);
        verifyStateChange(
                BluetoothAdapter.STATE_OFF,
                BluetoothAdapter.STATE_BLE_TURNING_ON,
                1,
                CONTEXT_SWITCH_MS);

        // Start GATT
        verify(mMockContext, timeout(GATT_START_TIME_MS).times(
                startServiceCalls * invocationNumber + 1)).startService(any());
        verify(mMockContext, timeout(GATT_START_TIME_MS).times(1))
                .bindServiceAsUser(any(), any(), anyInt(), any());
        mAdapterService.addProfile(mMockGattService);
        mAdapterService.onProfileServiceStateChanged(mMockGattService, BluetoothAdapter.STATE_ON);

        verifyStateChange(BluetoothAdapter.STATE_BLE_TURNING_ON, BluetoothAdapter.STATE_BLE_ON,
                invocationNumber + 1, NATIVE_INIT_MS);
        verifyStateChange(
                BluetoothAdapter.STATE_BLE_TURNING_ON,
                BluetoothAdapter.STATE_BLE_ON,
                1,
                NATIVE_INIT_MS);

        mServiceBinder.startBrEdr(mAttributionSource);

        verifyStateChange(BluetoothAdapter.STATE_BLE_ON, BluetoothAdapter.STATE_TURNING_ON,
                invocationNumber + 1, CONTEXT_SWITCH_MS);
        verifyStateChange(
                BluetoothAdapter.STATE_BLE_ON,
                BluetoothAdapter.STATE_TURNING_ON,
                1,
                CONTEXT_SWITCH_MS);

        if (!onlyGatt) {
        // Start Mock PBAP and PAN services
            verify(mMockContext, timeout(ONE_SECOND_MS).times(
                    startServiceCalls * invocationNumber + 3)).startService(any());
        verify(mMockContext, timeout(ONE_SECOND_MS).times(2)).startService(any());

        mAdapterService.addProfile(mMockService);
        mAdapterService.addProfile(mMockService2);
        mAdapterService.onProfileServiceStateChanged(mMockService, BluetoothAdapter.STATE_ON);
        mAdapterService.onProfileServiceStateChanged(mMockService2, BluetoothAdapter.STATE_ON);
        }

        verifyStateChange(BluetoothAdapter.STATE_TURNING_ON, BluetoothAdapter.STATE_ON,
                invocationNumber + 1, PROFILE_SERVICE_TOGGLE_TIME_MS);
        verifyStateChange(
                BluetoothAdapter.STATE_TURNING_ON,
                BluetoothAdapter.STATE_ON,
                1,
                PROFILE_SERVICE_TOGGLE_TIME_MS);

        verify(mMockContext, timeout(CONTEXT_SWITCH_MS).times(2 * invocationNumber + 2))
                .sendBroadcast(any(), eq(BLUETOOTH_SCAN),
                        any(Bundle.class));
        verify(mMockContext, timeout(CONTEXT_SWITCH_MS).times(2))
                .sendBroadcast(any(), eq(BLUETOOTH_SCAN), any(Bundle.class));
        final int scanMode = mServiceBinder.getScanMode(mAttributionSource);
        Assert.assertTrue(scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE
                || scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);
        Assert.assertTrue(mAdapterService.getState() == BluetoothAdapter.STATE_ON);

        Log.e(TAG, "doEnable() complete success");
        Log.e("AdapterServiceTest", "doEnable() complete success");
    }

    /**
@@ -434,7 +439,7 @@ public class AdapterServiceFactoryResetTest {
        Assert.assertFalse(AdapterServiceTest.isByteArrayAllZero(obfuscatedAddress2));
        Assert.assertFalse(Arrays.equals(obfuscatedAddress2,
                obfuscatedAddress1));
        doEnable(0, false);
        doEnable();
        byte[] obfuscatedAddress3 = mAdapterService.obfuscateAddress(device);
        Assert.assertTrue(obfuscatedAddress3.length > 0);
        Assert.assertFalse(AdapterServiceTest.isByteArrayAllZero(obfuscatedAddress3));
+74 −43

File changed.

Preview size limit exceeded, changes collapsed.

Loading