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

Commit 5bd5ff65 authored by William Escande's avatar William Escande
Browse files

GattService: No longer start a remote service

Since the Bluetooth app is self binding its own service, it does not
need to be started as a remote service.

Bug: 285959170
Bug: 294040500
Test: atest BluetoothInstrumentationTests
Test: atest ProfileServiceTest
Test: atest AdapterServiceTest
Test: atest AdapterServiceRestartTest
Test: atest AdapterServiceFactoryResetTest
Test: atest GattServiceTest
Test: boot bluetooth | having a working gattService is a unskippable
      step of startup. Simply booting the bluetooth validate this CL
Change-Id: I9474b0fc5d85b811b148698b143b4b3b03ba2756
parent 46fb236e
Loading
Loading
Loading
Loading
+0 −11
Original line number Original line Diff line number Diff line
@@ -221,17 +221,6 @@
            </intent-filter>
            </intent-filter>
        </service>
        </service>


        <!--  Generic Attribute (GATT) Profile Service  -->
        <service android:process="@string/process"
             android:name="com.android.bluetooth.gatt.GattService"
             android:enabled="true"
             android:exported="true"
             android:permission="android.permission.ACCESS_BLUETOOTH_SHARE">
            <intent-filter>
                <action android:name="android.bluetooth.IBluetoothGatt"/>
            </intent-filter>
        </service>

        <!--  Hearing Aid Profile (HAP) client Profile Service  -->
        <!--  Hearing Aid Profile (HAP) client Profile Service  -->
        <service android:process="@string/process"
        <service android:process="@string/process"
             android:name="com.android.bluetooth.hap.HapClientService"
             android:name="com.android.bluetooth.hap.HapClientService"
+13 −82
Original line number Original line Diff line number Diff line
@@ -79,11 +79,9 @@ import android.bluetooth.UidTraffic;
import android.companion.CompanionDeviceManager;
import android.companion.CompanionDeviceManager;
import android.content.AttributionSource;
import android.content.AttributionSource;
import android.content.BroadcastReceiver;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Context;
import android.content.Intent;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager;
import android.os.AsyncTask;
import android.os.AsyncTask;
@@ -370,7 +368,7 @@ public class AdapterService extends Service {
    private BassClientService mBassClientService;
    private BassClientService mBassClientService;
    private BatteryService mBatteryService;
    private BatteryService mBatteryService;
    private BluetoothQualityReportNativeInterface mBluetoothQualityReportNativeInterface;
    private BluetoothQualityReportNativeInterface mBluetoothQualityReportNativeInterface;
    private IBluetoothGatt mBluetoothGatt;
    private GattService mGattService;


    private volatile boolean mTestModeEnabled = false;
    private volatile boolean mTestModeEnabled = false;


@@ -424,8 +422,6 @@ public class AdapterService extends Service {
    private static final int MESSAGE_PROFILE_SERVICE_REGISTERED = 2;
    private static final int MESSAGE_PROFILE_SERVICE_REGISTERED = 2;
    private static final int MESSAGE_PROFILE_SERVICE_UNREGISTERED = 3;
    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_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 {
    class AdapterServiceHandler extends Handler {
        AdapterServiceHandler(Looper looper) {
        AdapterServiceHandler(Looper looper) {
@@ -449,14 +445,6 @@ public class AdapterService extends Service {
                    verboseLog("handleMessage() - MESSAGE_PROFILE_SERVICE_UNREGISTERED");
                    verboseLog("handleMessage() - MESSAGE_PROFILE_SERVICE_UNREGISTERED");
                    unregisterProfileService((ProfileService) msg.obj);
                    unregisterProfileService((ProfileService) msg.obj);
                    break;
                    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:
                case MESSAGE_PREFERRED_AUDIO_PROFILES_AUDIO_FRAMEWORK_TIMEOUT:
                    errorLog(
                    errorLog(
                            "handleMessage() - "
                            "handleMessage() - "
@@ -496,22 +484,6 @@ public class AdapterService extends Service {
            mRegisteredProfiles.remove(profile);
            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) {
        private void processProfileServiceStateChanged(ProfileService profile, int state) {
            switch (state) {
            switch (state) {
                case BluetoothAdapter.STATE_ON:
                case BluetoothAdapter.STATE_ON:
@@ -1002,47 +974,11 @@ 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() {
    private void startGattProfileService() {
        mStartedProfiles.add(GattService.class.getSimpleName());
        mStartedProfiles.add(GattService.class.getSimpleName());


        Intent intent = new Intent(this, GattService.class);
        mGattService = new GattService(this);
        if (!bindServiceAsUser(
        ((ProfileService) mGattService).doStart();
                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() {
    private void stopGattProfileService() {
@@ -1053,15 +989,10 @@ public class AdapterService extends Service {
        }
        }


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

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


    private void invalidateBluetoothGetStateCache() {
    private void invalidateBluetoothGetStateCache() {
@@ -5241,6 +5172,7 @@ public class AdapterService extends Service {
            try {
            try {
                AdapterService service = getService();
                AdapterService service = getService();
                if (service != null) {
                if (service != null) {
                    enforceBluetoothPrivilegedPermission(service);
                    service.unregAllGattClient(source);
                    service.unregAllGattClient(source);
                }
                }
                receiver.send(null);
                receiver.send(null);
@@ -6880,16 +6812,15 @@ public class AdapterService extends Service {
    }
    }


    IBluetoothGatt getBluetoothGatt() {
    IBluetoothGatt getBluetoothGatt() {
        return mBluetoothGatt;
        if (mGattService == null) {
            return null;
        }
        return IBluetoothGatt.Stub.asInterface(((ProfileService) mGattService).getBinder());
    }
    }


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


+9 −2
Original line number Original line Diff line number Diff line
@@ -18,6 +18,8 @@ package com.android.bluetooth.btservice;


import static android.Manifest.permission.BLUETOOTH_CONNECT;
import static android.Manifest.permission.BLUETOOTH_CONNECT;


import static java.util.Objects.requireNonNull;

import android.annotation.RequiresPermission;
import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.annotation.SuppressLint;
import android.app.Service;
import android.app.Service;
@@ -180,6 +182,11 @@ public abstract class ProfileService extends Service {
        return mBinder;
        return mBinder;
    }
    }


    IBinder getBinder() {
        requireNonNull(mBinder, "Binder is null. onCreate need to be called first");
        return mBinder;
    }

    @Override
    @Override
    // Suppressed since this is called from framework
    // Suppressed since this is called from framework
    @SuppressLint("AndroidFrameworkRequiresPermission")
    @SuppressLint("AndroidFrameworkRequiresPermission")
@@ -295,7 +302,7 @@ public abstract class ProfileService extends Service {
                android.Manifest.permission.MANAGE_USERS,
                android.Manifest.permission.MANAGE_USERS,
                android.Manifest.permission.INTERACT_ACROSS_USERS
                android.Manifest.permission.INTERACT_ACROSS_USERS
            })
            })
    protected void doStart() {
    void doStart() {
        Log.v(mName, "doStart");
        Log.v(mName, "doStart");
        if (mAdapter == null) {
        if (mAdapter == null) {
            Log.w(mName, "Can't start profile service: device does not have BT");
            Log.w(mName, "Can't start profile service: device does not have BT");
@@ -321,7 +328,7 @@ public abstract class ProfileService extends Service {
        mAdapterService.onProfileServiceStateChanged(this, BluetoothAdapter.STATE_ON);
        mAdapterService.onProfileServiceStateChanged(this, BluetoothAdapter.STATE_ON);
    }
    }


    protected void doStop() {
    void doStop() {
        Log.v(mName, "doStop");
        Log.v(mName, "doStop");
        if (mAdapterService == null || mAdapterService.isStartedProfile(mName)) {
        if (mAdapterService == null || mAdapterService.isStartedProfile(mName)) {
            Log.w(mName, "Unexpectedly do Stop, don't stop.");
            Log.w(mName, "Unexpectedly do Stop, don't stop.");
+7 −38
Original line number Original line Diff line number Diff line
@@ -56,6 +56,7 @@ import android.bluetooth.le.ScanSettings;
import android.companion.AssociationInfo;
import android.companion.AssociationInfo;
import android.companion.CompanionDeviceManager;
import android.companion.CompanionDeviceManager;
import android.content.AttributionSource;
import android.content.AttributionSource;
import android.content.Context;
import android.content.Intent;
import android.content.Intent;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManager.PackageInfoFlags;
import android.content.pm.PackageManager.PackageInfoFlags;
@@ -290,6 +291,11 @@ public class GattService extends ProfileService {
    private Handler mTestModeHandler;
    private Handler mTestModeHandler;
    private final Object mTestModeLock = new Object();
    private final Object mTestModeLock = new Object();


    public GattService(Context ctx) {
        attachBaseContext(ctx);
        onCreate();
    }

    public static boolean isEnabled() {
    public static boolean isEnabled() {
        return BluetoothProperties.isProfileGattEnabled().orElse(true);
        return BluetoothProperties.isProfileGattEnabled().orElse(true);
    }
    }
@@ -611,34 +617,6 @@ public class GattService extends ProfileService {
            return null;
            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
        @Override
        public void getDevicesMatchingConnectionStates(int[] states,
        public void getDevicesMatchingConnectionStates(int[] states,
                AttributionSource attributionSource, SynchronousResultReceiver receiver) {
                AttributionSource attributionSource, SynchronousResultReceiver receiver) {
@@ -1777,15 +1755,6 @@ public class GattService extends ProfileService {
            service.disconnectAll(attributionSource);
            service.disconnectAll(attributionSource);
        }
        }


        @Override
        public void unregAll(AttributionSource attributionSource) {
            GattService service = getService();
            if (service == null) {
                return;
            }
            service.unregAll(attributionSource);
        }

        @Override
        @Override
        public void numHwTrackFiltersAvailable(AttributionSource attributionSource,
        public void numHwTrackFiltersAvailable(AttributionSource attributionSource,
                SynchronousResultReceiver receiver) {
                SynchronousResultReceiver receiver) {
@@ -3435,7 +3404,7 @@ public class GattService extends ProfileService {
    }
    }


    @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
    @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
    void unregAll(AttributionSource attributionSource) {
    public void unregAll(AttributionSource attributionSource) {
        for (Integer appId : mClientMap.getAllAppsIds()) {
        for (Integer appId : mClientMap.getAllAppsIds()) {
            if (DBG) {
            if (DBG) {
                Log.d(TAG, "unreg:" + appId);
                Log.d(TAG, "unreg:" + appId);
+19 −0
Original line number Original line Diff line number Diff line
@@ -39,6 +39,7 @@ import androidx.test.uiautomator.UiDevice;
import com.android.bluetooth.avrcpcontroller.BluetoothMediaBrowserService;
import com.android.bluetooth.avrcpcontroller.BluetoothMediaBrowserService;
import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.ProfileService;
import com.android.bluetooth.btservice.ProfileService;
import com.android.bluetooth.gatt.GattService;


import org.junit.Assert;
import org.junit.Assert;
import org.junit.rules.TestRule;
import org.junit.rules.TestRule;
@@ -138,6 +139,21 @@ public class TestUtils {
        method.invoke(null, adapterService);
        method.invoke(null, adapterService);
    }
    }


    /** Helper function to mock getSystemService calls */
    public static <T> void mockGetSystemService(
            Context ctx, String serviceName, Class<T> serviceClass, T mockService) {
        when(ctx.getSystemService(eq(serviceName))).thenReturn(mockService);
        when(ctx.getSystemServiceName(eq(serviceClass))).thenReturn(serviceName);
    }

    /** Helper function to mock getSystemService calls */
    public static <T> T mockGetSystemService(
            Context ctx, String serviceName, Class<T> serviceClass) {
        T mockedService = mock(serviceClass);
        mockGetSystemService(ctx, serviceName, serviceClass, mockedService);
        return mockedService;
    }

    /**
    /**
     * Start a profile service using the given {@link ServiceTestRule} and verify through
     * Start a profile service using the given {@link ServiceTestRule} and verify through
     * {@link AdapterService#getAdapterService()} that the service is actually started within
     * {@link AdapterService#getAdapterService()} that the service is actually started within
@@ -156,6 +172,9 @@ public class TestUtils {
     */
     */
    public static <T extends ProfileService> void startService(ServiceTestRule serviceTestRule,
    public static <T extends ProfileService> void startService(ServiceTestRule serviceTestRule,
            Class<T> profileServiceClass) throws TimeoutException {
            Class<T> profileServiceClass) throws TimeoutException {
        if (profileServiceClass == GattService.class) {
            Assert.assertFalse("GattService cannot be started as a service", true);
        }
        AdapterService adapterService = AdapterService.getAdapterService();
        AdapterService adapterService = AdapterService.getAdapterService();
        Assert.assertNotNull("Adapter service should not be null", adapterService);
        Assert.assertNotNull("Adapter service should not be null", adapterService);
        Assert.assertTrue("AdapterService.getAdapterService() must return a mocked or spied object"
        Assert.assertTrue("AdapterService.getAdapterService() must return a mocked or spied object"
Loading