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

Commit d395be0f authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "LE Audio Allowlist refactor for default connection" into main

parents 9d4f3e7a 0dfefc84
Loading
Loading
Loading
Loading
+13 −51
Original line number Diff line number Diff line
@@ -96,7 +96,6 @@ import android.os.PowerManager;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.DeviceConfig;
@@ -208,7 +207,6 @@ public class AdapterService extends Service {
    private final ArrayList<ProfileService> mRegisteredProfiles = new ArrayList<>();
    private final ArrayList<ProfileService> mRunningProfiles = new ArrayList<>();
    private HashSet<String> mLeAudioAllowDevices = new HashSet<>();
    private boolean mLeAudioAllowListEnabled = false;

    public static final String ACTION_LOAD_ADAPTER_PROPERTIES =
            "com.android.bluetooth.btservice.action.LOAD_ADAPTER_PROPERTIES";
@@ -236,8 +234,7 @@ public class AdapterService extends Service {
    static final String LOCAL_MAC_ADDRESS_PERM = android.Manifest.permission.LOCAL_MAC_ADDRESS;
    static final String RECEIVE_MAP_PERM = android.Manifest.permission.RECEIVE_BLUETOOTH_MAP;
    static final String BLUETOOTH_LE_AUDIO_ALLOW_LIST = "persist.bluetooth.leaudio.allow_list";
    static final String BLUETOOTH_ENABLE_LE_AUDIO_ALLOW_LIST =
            "persist.bluetooth.leaudio.enable_allow_list";


    static final String PHONEBOOK_ACCESS_PERMISSION_PREFERENCE_FILE = "phonebook_access_permission";
    static final String MESSAGE_ACCESS_PERMISSION_PREFERENCE_FILE = "message_access_permission";
@@ -673,7 +670,6 @@ public class AdapterService extends Service {
        mBluetoothQualityReportNativeInterface.init();

        mSdpManager = SdpManager.init(this);
        loadLeAudioAllowDevices();

        mDatabaseManager = new DatabaseManager(this);
        mDatabaseManager.start(MetadataDatabase.createDatabase(this));
@@ -1554,8 +1550,7 @@ public class AdapterService extends Service {
            return Utils.arrayContains(remoteDeviceUuids, BluetoothUuid.COORDINATED_SET);
        }
        if (profile == BluetoothProfile.LE_AUDIO) {
            return Utils.arrayContains(remoteDeviceUuids, BluetoothUuid.LE_AUDIO)
                    && isLeAudioAllowed(device);
            return Utils.arrayContains(remoteDeviceUuids, BluetoothUuid.LE_AUDIO);
        }
        if (profile == BluetoothProfile.HAP_CLIENT) {
            return Utils.arrayContains(remoteDeviceUuids, BluetoothUuid.HAS);
@@ -7503,15 +7498,16 @@ public class AdapterService extends Service {
                                ScanManager.SCAN_MODE_SCREEN_OFF_BALANCED_INTERVAL_MS);
                mLeAudioAllowList = properties.getString(LE_AUDIO_ALLOW_LIST, "");

                if (mLeAudioAllowList.isEmpty()) {
                    List<String> leAudioAllowDevices = BluetoothProperties.le_audio_allow_list();
                    if (leAudioAllowDevices != null && !leAudioAllowDevices.isEmpty()) {
                        mLeAudioAllowDevices = new HashSet<String>(leAudioAllowDevices);
                if (!mLeAudioAllowList.isEmpty()) {
                    List<String> leAudioAllowlistFromDeviceConfig =
                            Arrays.asList(mLeAudioAllowList.split(","));
                    BluetoothProperties.le_audio_allow_list(leAudioAllowlistFromDeviceConfig);
                }
                } else {
                    List<String> leAudioAllowDevices = Arrays.asList(mLeAudioAllowList.split(","));
                    BluetoothProperties.le_audio_allow_list(leAudioAllowDevices);
                    mLeAudioAllowDevices = new HashSet<String>(leAudioAllowDevices);

                List<String> leAudioAllowlistProp = BluetoothProperties.le_audio_allow_list();
                if (leAudioAllowlistProp != null && !leAudioAllowlistProp.isEmpty()) {
                    mLeAudioAllowDevices.clear();
                    mLeAudioAllowDevices.addAll(leAudioAllowlistProp);
                }
            }
        }
@@ -7735,56 +7731,22 @@ public class AdapterService extends Service {
        mNativeInterface.interopDatabaseAddRemoveName(false, feature.name(), name);
    }

    private void loadLeAudioAllowDevices() {
        Log.i(TAG, "loadLeAudioAllowDevices");
        mLeAudioAllowListEnabled =
                SystemProperties.getBoolean(BLUETOOTH_ENABLE_LE_AUDIO_ALLOW_LIST, false);

        if (!mLeAudioAllowListEnabled) {
            Log.i(TAG, "LE Audio allow list is disabled.");
            return;
        }

        synchronized (mDeviceConfigLock) {
            mLeAudioAllowDevices = new HashSet<String>(Arrays.asList(mLeAudioAllowList.split(",")));
        }
        return;
    }

    /**
     * Checks the remote device is in the LE Audio allow list or not.
     *
     * @param device the device to check
     * @return boolean true if le audio allow list is not enabled or the device is in the allow
     *     list, false otherwise.
     * @return boolean true if the device is in the allow list, false otherwise.
     */
    public boolean isLeAudioAllowed(BluetoothDevice device) {
        if (!mLeAudioAllowListEnabled) {
            return true;
        }

        DeviceProperties deviceProp = mRemoteDevices.getDeviceProperties(device);

        if (deviceProp == null
                || deviceProp.getModelName() == null
                || !mLeAudioAllowDevices.contains(deviceProp.getModelName())) {

            if (mLeAudioService != null) {
                mLeAudioService.setConnectionPolicy(
                        device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
            }

            Log.e(
                    TAG,
                    String.format("Device %s not in the LE Audio allow list, ", device)
                            + "force LE Audio policy to forbidden");
            return false;
        }

        if (mLeAudioService != null) {
            mLeAudioService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
        }

        return true;
    }

+31 −18
Original line number Diff line number Diff line
@@ -73,10 +73,13 @@ public class PhonePolicy implements AdapterService.BluetoothStateCallback {

    @VisibleForTesting static final String AUTO_CONNECT_PROFILES_PROPERTY =
            "bluetooth.auto_connect_profiles.enabled";
    private static final String CONFIG_LE_AUDIO_ENABLED_BY_DEFAULT = "le_audio_enabled_by_default";

    private static boolean sLeAudioEnabledByDefault = DeviceConfig.getBoolean(
            DeviceConfig.NAMESPACE_BLUETOOTH, CONFIG_LE_AUDIO_ENABLED_BY_DEFAULT, false);
    private static final String LE_AUDIO_CONNECTION_BY_DEFAULT_PROPERTY =
            "ro.bluetooth.leaudio.le_audio_connection_by_default";

    @VisibleForTesting
    static final String BYPASS_LE_AUDIO_ALLOWLIST_PROPERTY =
            "persist.bluetooth.leaudio.bypass_allow_list";

    /** flag for multi auto connect */
    public static boolean sIsHfpMultiAutoConnectEnabled =
@@ -97,6 +100,7 @@ public class PhonePolicy implements AdapterService.BluetoothStateCallback {
    private final HashSet<BluetoothDevice> mA2dpRetrySet = new HashSet<>();
    private final HashSet<BluetoothDevice> mConnectOtherProfilesDeviceSet = new HashSet<>();
    @VisibleForTesting boolean mAutoConnectProfilesSupported;
    @VisibleForTesting boolean mLeAudioEnabledByDefault;

    @Override
    public void onBluetoothStateChange(int prevState, int newState) {
@@ -184,6 +188,8 @@ public class PhonePolicy implements AdapterService.BluetoothStateCallback {
        mHandler = new PhonePolicyHandler(service.getMainLooper());
        mAutoConnectProfilesSupported =
                SystemProperties.getBoolean(AUTO_CONNECT_PROFILES_PROPERTY, false);
        mLeAudioEnabledByDefault =
                SystemProperties.getBoolean(LE_AUDIO_CONNECTION_BY_DEFAULT_PROPERTY, true);
    }

    // Policy implementation, all functions MUST be private
@@ -204,12 +210,24 @@ public class PhonePolicy implements AdapterService.BluetoothStateCallback {
        BassClientService bcService = mFactory.getBassClientService();
        BatteryService batteryService = mFactory.getBatteryService();

        boolean isLeAudioProfileAllowed = (leAudioService != null)
        final boolean isBypassLeAudioAllowlist =
                SystemProperties.getBoolean(BYPASS_LE_AUDIO_ALLOWLIST_PROPERTY, false);

        boolean isLeAudioProfileAllowed =
                (leAudioService != null)
                        && Utils.arrayContains(uuids, BluetoothUuid.LE_AUDIO)
                        && (leAudioService.getConnectionPolicy(device)
                                != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN)
                && mAdapterService.isLeAudioAllowed(device)
                && (sLeAudioEnabledByDefault || isDualModeAudioEnabled());
                        && (mLeAudioEnabledByDefault || isDualModeAudioEnabled())
                        && (isBypassLeAudioAllowlist || mAdapterService.isLeAudioAllowed(device));

        debugLog(
                "mLeAudioEnabledByDefault: "
                        + mLeAudioEnabledByDefault
                        + ", isBypassLeAudioAllowlist: "
                        + isBypassLeAudioAllowlist
                        + ", isLeAudioAllowDevice: "
                        + mAdapterService.isLeAudioAllowed(device));

        // Set profile priorities only for the profiles discovered on the remote device.
        // This avoids needless auto-connect attempts to profiles non-existent on the remote device
@@ -790,11 +808,11 @@ public class PhonePolicy implements AdapterService.BluetoothStateCallback {
        }
        if (leAudioService != null) {
            List<BluetoothDevice> leAudioConnDevList = leAudioService.getConnectedDevices();
            if (!leAudioConnDevList.contains(device) && (leAudioService.getConnectionPolicy(device)
            if (!leAudioConnDevList.contains(device)
                    && (leAudioService.getConnectionPolicy(device)
                            == BluetoothProfile.CONNECTION_POLICY_ALLOWED)
                    && (leAudioService.getConnectionState(device)
                    == BluetoothProfile.STATE_DISCONNECTED)
                    && mAdapterService.isLeAudioAllowed(device)) {
                            == BluetoothProfile.STATE_DISCONNECTED)) {
                debugLog("Retrying connection to LEAudio with device " + device);
                leAudioService.connect(device);
            }
@@ -866,11 +884,6 @@ public class PhonePolicy implements AdapterService.BluetoothStateCallback {
        }
    }

    @VisibleForTesting
    void setLeAudioEnabledByDefaultForTesting(boolean enabled) {
        sLeAudioEnabledByDefault = enabled;
    }

    private static void debugLog(String msg) {
        if (DBG) {
            Log.i(TAG, msg);
+19 −12
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothUuid;
import android.os.HandlerThread;
import android.os.ParcelUuid;
import android.os.SystemProperties;

import androidx.room.Room;
import androidx.test.filters.MediumTest;
@@ -189,7 +190,7 @@ public class PhonePolicyTest {
        when(mAdapterService.isLeAudioAllowed(device)).thenReturn(true);

        // Auto connect to LE audio, HFP, A2DP
        processInitProfilePriorities_LeAudioHelper(true, true, false);
        processInitProfilePriorities_LeAudioHelper(true, true, false, false);
        verify(mLeAudioService, timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(1))
                .setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
        verify(mA2dpService, timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(1))
@@ -198,7 +199,7 @@ public class PhonePolicyTest {
                .setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);

        // Does not auto connect and allow HFP and A2DP to be connected
        processInitProfilePriorities_LeAudioHelper(true, false, false);
        processInitProfilePriorities_LeAudioHelper(true, false, false, false);
        verify(mDatabaseManager, timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(1))
                .setProfileConnectionPolicy(device, BluetoothProfile.LE_AUDIO,
                        BluetoothProfile.CONNECTION_POLICY_ALLOWED);
@@ -209,8 +210,8 @@ public class PhonePolicyTest {
                .setProfileConnectionPolicy(device, BluetoothProfile.HEADSET,
                        BluetoothProfile.CONNECTION_POLICY_ALLOWED);

        // Auto connect to LE audio but disallow HFP and A2DP
        processInitProfilePriorities_LeAudioHelper(false, true, false);
        // Auto connect to HFP and A2DP but disallow LE Audio
        processInitProfilePriorities_LeAudioHelper(false, true, false, false);
        verify(mDatabaseManager, timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(1))
                .setProfileConnectionPolicy(device, BluetoothProfile.LE_AUDIO,
                        BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
@@ -219,8 +220,8 @@ public class PhonePolicyTest {
        verify(mHeadsetService, timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(2))
                .setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);

        // Does not auto connect and disallow HFP and A2DP to be connected
        processInitProfilePriorities_LeAudioHelper(false, false, false);
        // Does not auto connect and disallow LE Audio to be connected
        processInitProfilePriorities_LeAudioHelper(false, false, false, false);
        verify(mDatabaseManager, timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(2))
                .setProfileConnectionPolicy(device, BluetoothProfile.LE_AUDIO,
                        BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
@@ -238,7 +239,7 @@ public class PhonePolicyTest {
        when(mAdapterService.isLeAudioAllowed(device)).thenReturn(true);

        // Auto connect to LE audio, HFP, A2DP
        processInitProfilePriorities_LeAudioHelper(true, true, true);
        processInitProfilePriorities_LeAudioHelper(true, true, true, false);
        verify(mLeAudioService, timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(1))
                .setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
        verify(mA2dpService, timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(1))
@@ -247,7 +248,7 @@ public class PhonePolicyTest {
                .setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);

        // Does not auto connect and allow HFP and A2DP to be connected
        processInitProfilePriorities_LeAudioHelper(true, false, true);
        processInitProfilePriorities_LeAudioHelper(true, false, true, false);
        verify(mDatabaseManager, timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(1))
                .setProfileConnectionPolicy(device, BluetoothProfile.LE_AUDIO,
                        BluetoothProfile.CONNECTION_POLICY_ALLOWED);
@@ -259,7 +260,7 @@ public class PhonePolicyTest {
                        BluetoothProfile.CONNECTION_POLICY_ALLOWED);

        // Auto connect to LE audio but disallow HFP and A2DP
        processInitProfilePriorities_LeAudioHelper(false, true, true);
        processInitProfilePriorities_LeAudioHelper(false, true, true, false);
        verify(mLeAudioService, timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(2))
                .setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
        verify(mDatabaseManager, timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(1))
@@ -270,7 +271,7 @@ public class PhonePolicyTest {
                        BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);

        // Does not auto connect and disallow HFP and A2DP to be connected
        processInitProfilePriorities_LeAudioHelper(false, false, true);
        processInitProfilePriorities_LeAudioHelper(false, false, true, false);
        verify(mDatabaseManager, timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(2))
                .setProfileConnectionPolicy(device, BluetoothProfile.LE_AUDIO,
                        BluetoothProfile.CONNECTION_POLICY_ALLOWED);
@@ -283,10 +284,16 @@ public class PhonePolicyTest {
    }

    private void processInitProfilePriorities_LeAudioHelper(
            boolean dualModeEnabled, boolean autoConnect, boolean leAudioEnabledByDefault) {
            boolean dualModeEnabled,
            boolean autoConnect,
            boolean leAudioEnabledByDefault,
            boolean bypassLeAudioAllowlist) {
        Utils.setDualModeAudioStateForTesting(dualModeEnabled);
        mPhonePolicy.setLeAudioEnabledByDefaultForTesting(leAudioEnabledByDefault);
        mPhonePolicy.mLeAudioEnabledByDefault = leAudioEnabledByDefault;
        mPhonePolicy.mAutoConnectProfilesSupported = autoConnect;
        SystemProperties.set(
                PhonePolicy.BYPASS_LE_AUDIO_ALLOWLIST_PROPERTY,
                Boolean.toString(bypassLeAudioAllowlist));

        BluetoothDevice device = getTestDevice(mAdapter, 0);
        // Mock the HFP, A2DP and LE audio services to return unknown connection policy