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

Commit 0c86889d authored by William Escande's avatar William Escande
Browse files

Pbap use profileConnector, resolveSystemService api fix

* All profiles use the BluetoothProfileConnector but not Pbap.
I reproduced the changes that were made in aosp/932813 for all other
profiles. This allow pbap to no longer call resolveSystemService.
* `Intent.resolveSystemService` is an hidden API and can no longer be
called from Bluetooth as we aim to become mainline. It's code is simple
enough to be copied.

Tag: #refactor
Bug: 200200870
Test: atest BluetoothInstrumentationTests

Change-Id: I838b910c633b3ca943fec01f3ccca466ff65f892
parent 780e4386
Loading
Loading
Loading
Loading
+20 −115
Original line number Diff line number Diff line
@@ -26,15 +26,10 @@ import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Attributable;
import android.content.AttributionSource;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Log;

import java.util.ArrayList;
@@ -97,10 +92,6 @@ public class BluetoothPbap implements BluetoothProfile {
    public static final String ACTION_CONNECTION_STATE_CHANGED =
            "android.bluetooth.pbap.profile.action.CONNECTION_STATE_CHANGED";

    private volatile IBluetoothPbap mService;
    private final Context mContext;
    private ServiceListener mServiceListener;
    private final BluetoothAdapter mAdapter;
    private final AttributionSource mAttributionSource;

    /** @hide */
@@ -114,16 +105,13 @@ public class BluetoothPbap implements BluetoothProfile {
     */
    public static final int RESULT_CANCELED = 2;

    @SuppressLint("AndroidFrameworkBluetoothPermission")
    private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
            new IBluetoothStateChangeCallback.Stub() {
                public void onBluetoothStateChange(boolean up) {
                    log("onBluetoothStateChange: up=" + up);
                    if (!up) {
                        doUnbind();
                    } else {
                        doBind();
                    }
    private BluetoothAdapter mAdapter;
    private final BluetoothProfileConnector<IBluetoothPbap> mProfileConnector =
            new BluetoothProfileConnector(this, BluetoothProfile.PBAP, "BluetoothPbap",
                    IBluetoothPbap.class.getName()) {
                @Override
                public IBluetoothPbap getServiceInterface(IBinder service) {
                    return IBluetoothPbap.Stub.asInterface(service);
                }
    };

@@ -132,69 +120,10 @@ public class BluetoothPbap implements BluetoothProfile {
     *
     * @hide
     */
    public BluetoothPbap(Context context, ServiceListener l, BluetoothAdapter adapter) {
        mContext = context;
        mServiceListener = l;
    public BluetoothPbap(Context context, ServiceListener listener, BluetoothAdapter adapter) {
        mAdapter = adapter;
        mAttributionSource = adapter.getAttributionSource();

        // Preserve legacy compatibility where apps were depending on
        // registerStateChangeCallback() performing a permissions check which
        // has been relaxed in modern platform versions
        if (context.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.R
                && context.checkSelfPermission(android.Manifest.permission.BLUETOOTH)
                        != PackageManager.PERMISSION_GRANTED) {
            throw new SecurityException("Need BLUETOOTH permission");
        }

        IBluetoothManager mgr = mAdapter.getBluetoothManager();
        if (mgr != null) {
            try {
                mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
            } catch (RemoteException re) {
                Log.e(TAG, "", re);
            }
        }
        doBind();
    }

    @SuppressLint("AndroidFrameworkRequiresPermission")
    boolean doBind() {
        synchronized (mConnection) {
            try {
                if (mService == null) {
                    log("Binding service...");
                    Intent intent = new Intent(IBluetoothPbap.class.getName());
                    ComponentName comp = intent.resolveSystemService(
                            mContext.getPackageManager(), 0);
                    intent.setComponent(comp);
                    if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
                            UserHandle.CURRENT)) {
                        Log.e(TAG, "Could not bind to Bluetooth Pbap Service with " + intent);
                        return false;
                    }
                }
            } catch (SecurityException se) {
                Log.e(TAG, "", se);
                return false;
            }
        }
        return true;
    }

    private void doUnbind() {
        synchronized (mConnection) {
            if (mService != null) {
                log("Unbinding service...");
                try {
                    mContext.unbindService(mConnection);
                } catch (IllegalArgumentException ie) {
                    Log.e(TAG, "", ie);
                } finally {
                    mService = null;
                }
            }
        }
        mProfileConnector.connect(context, listener);
    }

    /** @hide */
@@ -215,16 +144,11 @@ public class BluetoothPbap implements BluetoothProfile {
     * @hide
     */
    public synchronized void close() {
        IBluetoothManager mgr = mAdapter.getBluetoothManager();
        if (mgr != null) {
            try {
                mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
            } catch (RemoteException re) {
                Log.e(TAG, "", re);
            }
        mProfileConnector.disconnect();
    }
        doUnbind();
        mServiceListener = null;

    private IBluetoothPbap getService() {
        return (IBluetoothPbap) mProfileConnector.getService();
    }

    /**
@@ -237,7 +161,7 @@ public class BluetoothPbap implements BluetoothProfile {
    @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
    public List<BluetoothDevice> getConnectedDevices() {
        log("getConnectedDevices()");
        final IBluetoothPbap service = mService;
        final IBluetoothPbap service = getService();
        if (service == null) {
            Log.w(TAG, "Proxy not attached to service");
            return new ArrayList<BluetoothDevice>();
@@ -266,7 +190,7 @@ public class BluetoothPbap implements BluetoothProfile {
    public @BtProfileState int getConnectionState(@NonNull BluetoothDevice device) {
        log("getConnectionState: device=" + device);
        try {
            final IBluetoothPbap service = mService;
            final IBluetoothPbap service = getService();
            if (service != null && isEnabled() && isValidDevice(device)) {
                return service.getConnectionState(device, mAttributionSource);
            }
@@ -290,7 +214,7 @@ public class BluetoothPbap implements BluetoothProfile {
    @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
    public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
        log("getDevicesMatchingConnectionStates: states=" + Arrays.toString(states));
        final IBluetoothPbap service = mService;
        final IBluetoothPbap service = getService();
        if (service == null) {
            Log.w(TAG, "Proxy not attached to service");
            return new ArrayList<BluetoothDevice>();
@@ -331,7 +255,7 @@ public class BluetoothPbap implements BluetoothProfile {
            @ConnectionPolicy int connectionPolicy) {
        if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
        try {
            final IBluetoothPbap service = mService;
            final IBluetoothPbap service = getService();
            if (service != null && isEnabled()
                    && isValidDevice(device)) {
                if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN
@@ -360,7 +284,7 @@ public class BluetoothPbap implements BluetoothProfile {
    @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
    public boolean disconnect(BluetoothDevice device) {
        log("disconnect()");
        final IBluetoothPbap service = mService;
        final IBluetoothPbap service = getService();
        if (service == null) {
            Log.w(TAG, "Proxy not attached to service");
            return false;
@@ -374,25 +298,6 @@ public class BluetoothPbap implements BluetoothProfile {
        return false;
    }

    @SuppressLint("AndroidFrameworkBluetoothPermission")
    private final ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            log("Proxy object connected");
            mService = IBluetoothPbap.Stub.asInterface(service);
            if (mServiceListener != null) {
                mServiceListener.onServiceConnected(BluetoothProfile.PBAP, BluetoothPbap.this);
            }
        }

        public void onServiceDisconnected(ComponentName className) {
            log("Proxy object disconnected");
            doUnbind();
            if (mServiceListener != null) {
                mServiceListener.onServiceDisconnected(BluetoothProfile.PBAP);
            }
        }
    };

    private boolean isEnabled() {
        if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
        return false;
+30 −2
Original line number Diff line number Diff line
@@ -16,12 +16,16 @@

package android.bluetooth;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Build;
import android.os.IBinder;
import android.os.RemoteException;
@@ -29,6 +33,7 @@ import android.os.UserHandle;
import android.util.CloseGuard;
import android.util.Log;

import java.util.List;
/**
 * Connector for Bluetooth profile proxies to bind manager service and
 * profile services
@@ -57,6 +62,30 @@ public abstract class BluetoothProfileConnector<T> {
        }
    };

    private @Nullable ComponentName resolveSystemService(@NonNull Intent intent,
            @NonNull PackageManager pm) {
        List<ResolveInfo> results = pm.queryIntentServices(intent,
                PackageManager.ResolveInfoFlags.of(0));
        if (results == null) {
            return null;
        }
        ComponentName comp = null;
        for (int i = 0; i < results.size(); i++) {
            ResolveInfo ri = results.get(i);
            if ((ri.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
                continue;
            }
            ComponentName foundComp = new ComponentName(ri.serviceInfo.applicationInfo.packageName,
                    ri.serviceInfo.name);
            if (comp != null) {
                throw new IllegalStateException("Multiple system services handle " + intent
                        + ": " + comp + ", " + foundComp);
            }
            comp = foundComp;
        }
        return comp;
    }

    private final ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            logDebug("Proxy object connected");
@@ -99,8 +128,7 @@ public abstract class BluetoothProfileConnector<T> {
                mCloseGuard.open("doUnbind");
                try {
                    Intent intent = new Intent(mServiceName);
                    ComponentName comp = intent.resolveSystemService(
                            mContext.getPackageManager(), 0);
                    ComponentName comp = resolveSystemService(intent, mContext.getPackageManager());
                    intent.setComponent(comp);
                    if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
                            UserHandle.CURRENT)) {