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

Commit ac31258e authored by Aritra Sen's avatar Aritra Sen Committed by Gerrit Code Review
Browse files

Merge changes I456d5f0a,I53d07f54 into main

* changes:
  Remove receiving ACTION_SDP_RECORD via broadcasts intents inside Bluetooth App.
  Handle ACL disconnect events across multiple Bluetooth profiles via AdapterService.
parents f18f5be4 9b43ee54
Loading
Loading
Loading
Loading
+34 −0
Original line number Diff line number Diff line
@@ -92,6 +92,7 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.ParcelUuid;
import android.os.Parcelable;
import android.os.PowerManager;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
@@ -6930,6 +6931,25 @@ public class AdapterService extends Service {
        }
    }

    /**
     * Notify {@link BluetoothProfile} when ACL connection disconnects from {@link BluetoothDevice}
     * for a given {@code transport}.
     */
    public void notifyAclDisconnected(BluetoothDevice device, int transport) {
        if (mMapService != null && mMapService.isAvailable()) {
            mMapService.aclDisconnected(device);
        }
        if (mMapClientService != null && mMapClientService.isAvailable()) {
            mMapClientService.aclDisconnected(device, transport);
        }
        if (mSapService != null && mSapService.isAvailable()) {
            mSapService.aclDisconnected(device);
        }
        if (mPbapClientService != null && mPbapClientService.isAvailable()) {
            mPbapClientService.aclDisconnected(device, transport);
        }
    }

    /**
     * Notify GATT of a Bluetooth profile's connection state change for a given {@link
     * BluetoothProfile}.
@@ -6964,6 +6984,20 @@ public class AdapterService extends Service {
        }
    }

    /** Notify MAP and Pbap when a new sdp search record is found. */
    public void sendSdpSearchRecord(
            BluetoothDevice device, int status, Parcelable record, ParcelUuid uuid) {
        if (mMapService != null && mMapService.isAvailable()) {
            mMapService.receiveSdpSearchRecord(status, record, uuid);
        }
        if (mMapClientService != null && mMapClientService.isAvailable()) {
            mMapClientService.receiveSdpSearchRecord(device, status, record, uuid);
        }
        if (mPbapClientService != null && mPbapClientService.isAvailable()) {
            mPbapClientService.receiveSdpSearchRecord(device, status, record, uuid);
        }
    }

    /** Handle Bluetooth profiles when bond state changes with a {@link BluetoothDevice} */
    public void handleBondStateChanged(BluetoothDevice device, int fromState, int toState) {
        if (mA2dpService != null && mA2dpService.isAvailable()) {
+14 −4
Original line number Diff line number Diff line
@@ -190,13 +190,22 @@ public class RemoteDevices {
            if (mDevices != null) {
                debugLog("reset(): Broadcasting ACL_DISCONNECTED");

                mDevices.forEach((address, deviceProperties) -> {
                mDevices.forEach(
                        (address, deviceProperties) -> {
                            BluetoothDevice bluetoothDevice = deviceProperties.getDevice();

                    debugLog("reset(): address=" + address + ", connected="
                            debugLog(
                                    "reset(): address="
                                            + address
                                            + ", connected="
                                            + bluetoothDevice.isConnected());

                    if (bluetoothDevice.isConnected()) {
                        int transport = deviceProperties.getConnectionHandle(
                                BluetoothDevice.TRANSPORT_BREDR) != BluetoothDevice.ERROR
                                        ? BluetoothDevice.TRANSPORT_BREDR
                                        : BluetoothDevice.TRANSPORT_LE;
                        mAdapterService.notifyAclDisconnected(bluetoothDevice, transport);
                        Intent intent = new Intent(BluetoothDevice.ACTION_ACL_DISCONNECTED);
                        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, bluetoothDevice);
                        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
@@ -1144,6 +1153,7 @@ public class RemoteDevices {
                mDevices.remove(key);
            }
            if (state == BluetoothAdapter.STATE_ON || state == BluetoothAdapter.STATE_TURNING_OFF) {
                mAdapterService.notifyAclDisconnected(device, transportLinkType);
                intent = new Intent(BluetoothDevice.ACTION_ACL_DISCONNECTED);
                intent.putExtra(BluetoothDevice.EXTRA_TRANSPORT, transportLinkType);
            } else if (state == BluetoothAdapter.STATE_BLE_ON
+58 −47
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.os.ParcelUuid;
import android.os.Parcelable;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.SystemProperties;
@@ -694,8 +695,6 @@ public class BluetoothMapService extends ProfileService {
        IntentFilter filter = new IntentFilter();
        filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
        filter.addAction(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY);
        filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
        filter.addAction(BluetoothDevice.ACTION_SDP_RECORD);
        filter.addAction(USER_CONFIRM_TIMEOUT_ACTION);

        // We need two filters, since Type only applies to the ACTION_MESSAGE_SENT
@@ -1148,37 +1147,6 @@ public class BluetoothMapService extends ProfileService {
                    }
                    sendConnectCancelMessage();
                }
            } else if (action.equals(BluetoothDevice.ACTION_SDP_RECORD)) {
                if (DEBUG) {
                    Log.d(TAG, "Received ACTION_SDP_RECORD.");
                }
                ParcelUuid uuid = intent.getParcelableExtra(BluetoothDevice.EXTRA_UUID);
                if (VERBOSE) {
                    Log.v(TAG, "Received UUID: " + uuid.toString());
                    Log.v(TAG, "expected UUID: "
                            + BluetoothMnsObexClient.BLUETOOTH_UUID_OBEX_MNS.toString());
                }
                if (uuid.equals(BluetoothMnsObexClient.BLUETOOTH_UUID_OBEX_MNS)) {
                    mMnsRecord = intent.getParcelableExtra(BluetoothDevice.EXTRA_SDP_RECORD);
                    int status = intent.getIntExtra(BluetoothDevice.EXTRA_SDP_SEARCH_STATUS, -1);
                    if (VERBOSE) {
                        Log.v(TAG, " -> MNS Record:" + mMnsRecord);
                        Log.v(TAG, " -> status: " + status);
                    }
                    if (mBluetoothMnsObexClient != null && !mSdpSearchInitiated) {
                        mBluetoothMnsObexClient.setMnsRecord(mMnsRecord);
                    }
                    if (status != -1 && mMnsRecord != null) {
                        for (int i = 0, c = mMasInstances.size(); i < c; i++) {
                            mMasInstances.valueAt(i)
                                    .setRemoteFeatureMask(mMnsRecord.getSupportedFeatures());
                        }
                    }
                    if (mSdpSearchInitiated) {
                        mSdpSearchInitiated = false; // done searching
                        sendConnectMessage(-1); // -1 indicates all MAS instances
                    }
                }
            } else if (action.equals(BluetoothMapContentObserver.ACTION_MESSAGE_SENT)) {
                int result = getResultCode();
                boolean handled = false;
@@ -1195,10 +1163,18 @@ public class BluetoothMapService extends ProfileService {
                    BluetoothMapContentObserver.actionMessageSentDisconnected(context, intent,
                            result);
                }
            } else if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)
                    && mIsWaitingAuthorization) {
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            }
        }
    }

    public void aclDisconnected(BluetoothDevice device) {
        mSessionStatusHandler.post(() -> handleAclDisconnected(device));
    }

    private void handleAclDisconnected(BluetoothDevice device) {
        if (!mIsWaitingAuthorization) {
            return;
        }
        if (sRemoteDevice == null || device == null) {
            Log.e(TAG, "Unexpected error!");
            return;
@@ -1214,6 +1190,41 @@ public class BluetoothMapService extends ProfileService {
            mSessionStatusHandler.obtainMessage(USER_TIMEOUT).sendToTarget();
        }
    }

    public void receiveSdpSearchRecord(int status, Parcelable record, ParcelUuid uuid) {
        mSessionStatusHandler.post(() -> handleSdpSearchRecordReceived(status, record, uuid));
    }

    private void handleSdpSearchRecordReceived(int status, Parcelable record, ParcelUuid uuid) {
        if (DEBUG) {
            Log.d(TAG, "Received ACTION_SDP_RECORD.");
        }
        if (VERBOSE) {
            Log.v(TAG, "Received UUID: " + uuid.toString());
            Log.v(
                    TAG,
                    "expected UUID: " + BluetoothMnsObexClient.BLUETOOTH_UUID_OBEX_MNS.toString());
        }
        if (uuid.equals(BluetoothMnsObexClient.BLUETOOTH_UUID_OBEX_MNS)) {
            mMnsRecord = (SdpMnsRecord) record;
            if (VERBOSE) {
                Log.v(TAG, " -> MNS Record:" + mMnsRecord);
                Log.v(TAG, " -> status: " + status);
            }
            if (mBluetoothMnsObexClient != null && !mSdpSearchInitiated) {
                mBluetoothMnsObexClient.setMnsRecord(mMnsRecord);
            }
            if (status != -1 && mMnsRecord != null) {
                for (int i = 0, c = mMasInstances.size(); i < c; i++) {
                    mMasInstances
                            .valueAt(i)
                            .setRemoteFeatureMask(mMnsRecord.getSupportedFeatures());
                }
            }
            if (mSdpSearchInitiated) {
                mSdpSearchInitiated = false; // done searching
                sendConnectMessage(-1); // -1 indicates all MAS instances
            }
        }
    }

+50 −66
Original line number Diff line number Diff line
@@ -26,12 +26,11 @@ import android.bluetooth.BluetoothUuid;
import android.bluetooth.IBluetoothMapClient;
import android.bluetooth.SdpMasRecord;
import android.content.AttributionSource;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.os.ParcelUuid;
import android.os.Parcelable;
import android.sysprop.BluetoothProperties;
import android.util.Log;

@@ -65,7 +64,7 @@ public class MapClientService extends ProfileService {
    private DatabaseManager mDatabaseManager;
    private static MapClientService sMapClientService;
    @VisibleForTesting
    MapBroadcastReceiver mMapReceiver;
    private Handler mHandler;

    public static boolean isEnabled() {
        return BluetoothProperties.isProfileMapClientEnabled().orElse(false);
@@ -312,6 +311,8 @@ public class MapClientService extends ProfileService {
        mDatabaseManager = Objects.requireNonNull(AdapterService.getAdapterService().getDatabase(),
                "DatabaseManager cannot be null when MapClientService starts");

        mHandler = new Handler(Looper.getMainLooper());

        if (mMnsServer == null) {
            mMnsServer = MapUtils.newMnsServiceInstance(this);
            if (mMnsServer == null) {
@@ -321,12 +322,6 @@ public class MapClientService extends ProfileService {
            }
        }

        mMapReceiver = new MapBroadcastReceiver();
        IntentFilter filter = new IntentFilter();
        filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
        filter.addAction(BluetoothDevice.ACTION_SDP_RECORD);
        filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
        registerReceiver(mMapReceiver, filter);
        removeUncleanAccounts();
        MapClientContent.clearAllContent(this);
        setMapClientService(this);
@@ -339,10 +334,6 @@ public class MapClientService extends ProfileService {
            Log.d(TAG, "stop()");
        }

        if (mMapReceiver != null) {
            unregisterReceiver(mMapReceiver);
            mMapReceiver = null;
        }
        if (mMnsServer != null) {
            mMnsServer.stop();
        }
@@ -353,6 +344,12 @@ public class MapClientService extends ProfileService {
            stateMachine.doQuit();
        }
        mMapInstanceMap.clear();

        // Unregister Handler and stop all queued messages.
        if (mHandler != null) {
            mHandler.removeCallbacksAndMessages(null);
            mHandler = null;
        }
        return true;
    }

@@ -720,34 +717,17 @@ public class MapClientService extends ProfileService {
        }
    }

    @VisibleForTesting
    class MapBroadcastReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (DBG) {
                Log.d(TAG, "onReceive: " + action);
            }
            if (!action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)
                    && !action.equals(BluetoothDevice.ACTION_SDP_RECORD)) {
                // we don't care about this intent
                return;
            }
            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            if (device == null) {
                Log.e(TAG, "broadcast has NO device param!");
                return;
    public void aclDisconnected(BluetoothDevice device, int transport) {
        mHandler.post(() -> handleAclDisconnected(device, transport));
    }

    private void handleAclDisconnected(BluetoothDevice device, int transport) {
        MceStateMachine stateMachine = mMapInstanceMap.get(device);
        if (stateMachine == null) {
            Log.e(TAG, "No Statemachine found for the device=" + device.toString());
            return;
        }

            if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) {
                int transport =
                        intent.getIntExtra(BluetoothDevice.EXTRA_TRANSPORT, BluetoothDevice.ERROR);
        Log.i(TAG, "Received ACL disconnection event, device=" + device.toString()
                + ", transport=" + transport);

@@ -760,18 +740,24 @@ public class MapClientService extends ProfileService {
        }
    }

            if (action.equals(BluetoothDevice.ACTION_SDP_RECORD)) {
                ParcelUuid uuid = intent.getParcelableExtra(BluetoothDevice.EXTRA_UUID);
                if (DBG) {
                    Log.d(TAG, "Received SDP Record event, device=" + device.toString() + ", uuid="
                            + uuid);
    public void receiveSdpSearchRecord(
            BluetoothDevice device, int status, Parcelable record, ParcelUuid uuid) {
        mHandler.post(() -> handleSdpSearchRecordReceived(device, status, record, uuid));
    }

    private void handleSdpSearchRecordReceived(
            BluetoothDevice device, int status, Parcelable record, ParcelUuid uuid) {
        MceStateMachine stateMachine = mMapInstanceMap.get(device);
        if (DBG) {
            Log.d(TAG, "Received SDP Record, device=" + device.toString() + ", uuid=" + uuid);
        }
        if (stateMachine == null) {
            Log.e(TAG, "No Statemachine found for the device=" + device.toString());
            return;
        }
        if (uuid.equals(BluetoothUuid.MAS)) {
                    // Check if we have a successful status with a valid SDP record.
                    int status = intent.getIntExtra(BluetoothDevice.EXTRA_SDP_SEARCH_STATUS, -1);
                    SdpMasRecord masRecord =
                            intent.getParcelableExtra(BluetoothDevice.EXTRA_SDP_RECORD);
            // Check if we have a valid SDP record.
            SdpMasRecord masRecord = (SdpMasRecord) record;
            if (DBG) {
                Log.d(TAG, "SDP complete, status: " + status + ", record:" + masRecord);
            }
@@ -779,5 +765,3 @@ public class MapClientService extends ProfileService {
        }
    }
}
    }
}
+58 −20
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.accounts.AccountManager;
import android.annotation.RequiresPermission;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothUuid;
import android.bluetooth.IBluetoothPbapClient;
import android.content.AttributionSource;
import android.content.BroadcastReceiver;
@@ -29,6 +30,9 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Handler;
import android.os.Looper;
import android.os.ParcelUuid;
import android.os.Parcelable;
import android.provider.CallLog;
import android.sysprop.BluetoothProperties;
import android.util.Log;
@@ -89,9 +93,11 @@ public class PbapClientService extends ProfileService {
     */
    // TODO(233361365): Remove this pattern when the framework solves their race condition
    private static final int ACCOUNT_VISIBILITY_CHECK_MS = 500;

    private static final int ACCOUNT_VISIBILITY_CHECK_TRIES_MAX = 6;
    private int mAccountVisibilityCheckTries = 0;
    private final Handler mAuthServiceHandler = new Handler();
    private Handler mHandler;
    private final Runnable mCheckAuthService = new Runnable() {
        @Override
        public void run() {
@@ -129,14 +135,16 @@ public class PbapClientService extends ProfileService {
            Log.v(TAG, "onStart");
        }

        mDatabaseManager = Objects.requireNonNull(AdapterService.getAdapterService().getDatabase(),
        mDatabaseManager =
                Objects.requireNonNull(
                        AdapterService.getAdapterService().getDatabase(),
                        "DatabaseManager cannot be null when PbapClientService starts");

        setComponentAvailable(AUTHENTICATOR_SERVICE, true);

        mHandler = new Handler(Looper.getMainLooper());
        IntentFilter filter = new IntentFilter();
        filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
        filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
        // delay initial download until after the user is unlocked to add an account.
        filter.addAction(Intent.ACTION_USER_UNLOCKED);
        try {
@@ -164,6 +172,13 @@ public class PbapClientService extends ProfileService {
            pbapClientStateMachine.doQuit();
        }
        mPbapClientStateMachineMap.clear();

        // Unregister Handler and stop all queued messages.
        if (mHandler != null) {
            mHandler.removeCallbacksAndMessages(null);
            mHandler = null;
        }

        cleanupAuthenicationService();
        setComponentAvailable(AUTHENTICATOR_SERVICE, false);
        return true;
@@ -286,20 +301,31 @@ public class PbapClientService extends ProfileService {
        }
    }


    @VisibleForTesting
    class PbapBroadcastReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (DBG) Log.v(TAG, "onReceive" + action);
            if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) {
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                int transport =
                        intent.getIntExtra(BluetoothDevice.EXTRA_TRANSPORT, BluetoothDevice.ERROR);
            if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
                for (PbapClientStateMachine stateMachine : mPbapClientStateMachineMap.values()) {
                    stateMachine.tryDownloadIfConnected();
                }
            }
        }
    }

    public void aclDisconnected(BluetoothDevice device, int transport) {
        mHandler.post(() -> handleAclDisconnected(device, transport));
    }

                Log.i(TAG, "Received ACL disconnection event, device=" + device.toString()
                        + ", transport=" + transport);
    private void handleAclDisconnected(BluetoothDevice device, int transport) {
        Log.i(
                TAG,
                "Received ACL disconnection event, device="
                        + device.toString()
                        + ", transport="
                        + transport);

        if (transport != BluetoothDevice.TRANSPORT_BREDR) {
            return;
@@ -308,12 +334,6 @@ public class PbapClientService extends ProfileService {
        if (getConnectionState(device) == BluetoothProfile.STATE_CONNECTED) {
            disconnect(device);
        }
            } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
                for (PbapClientStateMachine stateMachine : mPbapClientStateMachineMap.values()) {
                    stateMachine.tryDownloadIfConnected();
                }
            }
        }
    }

    /**
@@ -566,6 +586,24 @@ public class PbapClientService extends ProfileService {
        return deviceList;
    }

    public void receiveSdpSearchRecord(
            BluetoothDevice device, int status, Parcelable record, ParcelUuid uuid) {
        PbapClientStateMachine stateMachine = mPbapClientStateMachineMap.get(device);
        if (stateMachine == null) {
            Log.e(TAG, "No Statemachine found for the device=" + device.toString());
            return;
        }
        if (DBG) {
            Log.v(TAG, "Received UUID: " + uuid.toString());
            Log.v(TAG, "expected UUID: " + BluetoothUuid.PBAP_PSE.toString());
        }
        if (uuid.equals(BluetoothUuid.PBAP_PSE)) {
            stateMachine
                    .obtainMessage(PbapClientStateMachine.MSG_SDP_COMPLETE, record)
                    .sendToTarget();
        }
    }

    /**
     * Get the current connection state of the profile
     *
Loading