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

Commit 9b871e4f authored by Aritra Sen's avatar Aritra Sen
Browse files

Handle ACL disconnect events across multiple Bluetooth profiles via AdapterService.

Tag: #refactor
Bug: 296932947
Test: atest BluetoothInstrumentationTests
Change-Id: I53d07f54acb8ddbceb113c6fddc59d6ea312f1ea
parent 016e262f
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -6930,6 +6930,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}.
+6 −0
Original line number Diff line number Diff line
@@ -197,6 +197,11 @@ public class RemoteDevices {
                            + 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 +1149,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
+22 −17
Original line number Diff line number Diff line
@@ -694,7 +694,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);

@@ -1195,10 +1194,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,8 +1221,6 @@ public class BluetoothMapService extends ProfileService {
            mSessionStatusHandler.obtainMessage(USER_TIMEOUT).sendToTarget();
        }
    }
        }
    }

    //Binder object: Must be static class or memory leak may occur

+34 −21
Original line number Diff line number Diff line
@@ -31,6 +31,8 @@ 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.sysprop.BluetoothProperties;
import android.util.Log;
@@ -66,6 +68,7 @@ public class MapClientService extends ProfileService {
    private static MapClientService sMapClientService;
    @VisibleForTesting
    MapBroadcastReceiver mMapReceiver;
    private Handler mHandler;

    public static boolean isEnabled() {
        return BluetoothProperties.isProfileMapClientEnabled().orElse(false);
@@ -312,6 +315,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) {
@@ -325,7 +330,6 @@ public class MapClientService extends ProfileService {
        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);
@@ -353,6 +357,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;
    }

@@ -728,11 +738,6 @@ public class MapClientService extends ProfileService {
            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!");
@@ -745,21 +750,6 @@ public class MapClientService extends ProfileService {
                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);

                if (transport != BluetoothDevice.TRANSPORT_BREDR) {
                    return;
                }

                if (stateMachine.getState() == BluetoothProfile.STATE_CONNECTED) {
                    stateMachine.disconnect();
                }
            }

            if (action.equals(BluetoothDevice.ACTION_SDP_RECORD)) {
                ParcelUuid uuid = intent.getParcelableExtra(BluetoothDevice.EXTRA_UUID);
                if (DBG) {
@@ -780,4 +770,27 @@ public class MapClientService extends ProfileService {
            }
        }
    }

    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;
        }

        Log.i(TAG, "Received ACL disconnection event, device=" + device.toString()
                + ", transport=" + transport);

        if (transport != BluetoothDevice.TRANSPORT_BREDR) {
            return;
        }

        if (stateMachine.getState() == BluetoothProfile.STATE_CONNECTED) {
            stateMachine.disconnect();
        }
    }
}
+32 −17
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Handler;
import android.os.Looper;
import android.provider.CallLog;
import android.sysprop.BluetoothProperties;
import android.util.Log;
@@ -92,6 +93,7 @@ public class PbapClientService extends ProfileService {
    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() {
@@ -134,9 +136,9 @@ public class PbapClientService extends ProfileService {

        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 +166,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;
@@ -293,13 +302,25 @@ public class PbapClientService extends ProfileService {
        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();
                }
            }
        }
    }

                Log.i(TAG, "Received ACL disconnection event, device=" + device.toString()
                        + ", transport=" + transport);
    public void aclDisconnected(BluetoothDevice device, int transport) {
        mHandler.post(() -> handleAclDisconnected(device, 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 +329,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();
                }
            }
        }
    }

    /**
Loading