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

Commit 20ef0c56 authored by William Escande's avatar William Escande Committed by Gerrit Code Review
Browse files

Merge "Remove init_flag related code"

parents a5b737e2 e52c5b4e
Loading
Loading
Loading
Loading
+0 −85
Original line number Diff line number Diff line
/*
 * Copyright 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.bluetooth;

import android.provider.DeviceConfig;
import android.provider.DeviceConfig.Properties;
import android.util.Log;

import java.util.ArrayList;
import java.util.HashMap;

/**
 * The BluetoothDeviceConfigChangeTracker receives changes to the DeviceConfig for
 * NAMESPACE_BLUETOOTH, and determines whether we should queue a restart, if any Bluetooth-related
 * INIT_ flags have been changed.
 *
 * <p>The initialProperties should be fetched from the BLUETOOTH namespace in DeviceConfig
 */
public final class BluetoothDeviceConfigChangeTracker {
    private static final String TAG = "BluetoothDeviceConfigChangeTracker";

    private final HashMap<String, String> mCurrFlags;

    public BluetoothDeviceConfigChangeTracker(Properties initialProperties) {
        mCurrFlags = getFlags(initialProperties);
    }

    /**
     * Updates the instance state tracking the latest init flag values, and determines whether an
     * init flag has changed (requiring a restart at some point)
     */
    public boolean shouldRestartWhenPropertiesUpdated(Properties newProperties) {
        if (!newProperties.getNamespace().equals(DeviceConfig.NAMESPACE_BLUETOOTH)) {
            return false;
        }
        ArrayList<String> flags = new ArrayList<>();
        for (String name : newProperties.getKeyset()) {
            flags.add(name + "='" + newProperties.getString(name, "") + "'");
        }
        Log.d(TAG, "shouldRestartWhenPropertiesUpdated: " + String.join(",", flags));
        boolean shouldRestart = false;
        for (String name : newProperties.getKeyset()) {
            if (!isInitFlag(name)) {
                continue;
            }
            var oldValue = mCurrFlags.get(name);
            var newValue = newProperties.getString(name, "");
            if (newValue.equals(oldValue)) {
                continue;
            }
            Log.d(TAG, "Property " + name + " changed from " + oldValue + " -> " + newValue);
            mCurrFlags.put(name, newValue);
            shouldRestart = true;
        }
        return shouldRestart;
    }

    private HashMap<String, String> getFlags(Properties initialProperties) {
        var out = new HashMap();
        for (var name : initialProperties.getKeyset()) {
            if (isInitFlag(name)) {
                out.put(name, initialProperties.getString(name, ""));
            }
        }
        return out;
    }

    private Boolean isInitFlag(String flagName) {
        return flagName.startsWith("INIT_");
    }
}
+0 −62
Original line number Diff line number Diff line
/*
 * Copyright 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.bluetooth;

import android.provider.DeviceConfig;
import android.util.Log;

/**
 * The BluetoothDeviceConfigListener handles system device config change callback and checks
 * whether we need to inform BluetoothManagerService on this change.
 *
 * The information of device config change would not be passed to the BluetoothManagerService
 * when Bluetooth is on and Bluetooth is in one of the following situations:
 *   1. Bluetooth A2DP is connected.
 *   2. Bluetooth Hearing Aid profile is connected.
 */
public class BluetoothDeviceConfigListener {
    private static final String TAG = "BluetoothDeviceConfigListener";

    private final BluetoothManagerService mService;
    private final boolean mLogDebug;
    private final BluetoothDeviceConfigChangeTracker mConfigChangeTracker;

    BluetoothDeviceConfigListener(BluetoothManagerService service, boolean logDebug) {
        mService = service;
        mLogDebug = logDebug;
        mConfigChangeTracker =
                new BluetoothDeviceConfigChangeTracker(
                        DeviceConfig.getProperties(DeviceConfig.NAMESPACE_BLUETOOTH));
        DeviceConfig.addOnPropertiesChangedListener(
                DeviceConfig.NAMESPACE_BLUETOOTH,
                (Runnable r) -> r.run(),
                mDeviceConfigChangedListener);
    }

    private final DeviceConfig.OnPropertiesChangedListener mDeviceConfigChangedListener =
            new DeviceConfig.OnPropertiesChangedListener() {
                @Override
                public void onPropertiesChanged(DeviceConfig.Properties newProperties) {
                    if (mConfigChangeTracker.shouldRestartWhenPropertiesUpdated(newProperties)) {
                        Log.d(TAG, "Properties changed, enqueuing restart");
                        mService.onInitFlagsChanged();
                    } else {
                        Log.d(TAG, "All properties unchanged, skipping restart");
                    }
                }
            };
}
+13 −101
Original line number Diff line number Diff line
@@ -32,10 +32,7 @@ import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.BroadcastOptions;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothHearingAid;
import android.bluetooth.BluetoothLeAudio;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothProtoEnums;
import android.bluetooth.BluetoothStatusCodes;
@@ -142,8 +139,6 @@ class BluetoothManagerService {
    private static final int ADD_PROXY_DELAY_MS = 100;
    // Delay for retrying enable and disable in msec
    private static final int ENABLE_DISABLE_DELAY_MS = 300;
    private static final int DELAY_BEFORE_RESTART_DUE_TO_INIT_FLAGS_CHANGED_MS = 300;
    private static final int DELAY_FOR_RETRY_INIT_FLAG_CHECK_MS = 86400000;

    private static final int MESSAGE_ENABLE = 1;
    @VisibleForTesting
@@ -163,7 +158,6 @@ class BluetoothManagerService {
    private static final int MESSAGE_ADD_PROXY_DELAYED = 400;
    private static final int MESSAGE_BIND_PROFILE_SERVICE = 401;
    private static final int MESSAGE_RESTORE_USER_SETTING = 500;
    private static final int MESSAGE_INIT_FLAGS_CHANGED = 600;

    private static final int RESTORE_SETTING_TO_ON = 1;
    private static final int RESTORE_SETTING_TO_OFF = 0;
@@ -223,8 +217,6 @@ class BluetoothManagerService {

    private BluetoothAirplaneModeListener mBluetoothAirplaneModeListener;

    private BluetoothDeviceConfigListener mBluetoothDeviceConfigListener;

    private BluetoothNotificationManager mBluetoothNotificationManager;

    private BluetoothSatelliteModeListener mBluetoothSatelliteModeListener;
@@ -322,11 +314,6 @@ class BluetoothManagerService {
        }
    }

    @VisibleForTesting
    public void onInitFlagsChanged() {
        // TODO(b/265386284)
    }

    boolean onFactoryReset(AttributionSource source) {
        // Wait for stable state if bluetooth is temporary state.
        int state = getState();
@@ -601,17 +588,6 @@ class BluetoothManagerService {
                        mHandler.sendMessage(msg);
                    }
                }
            } else if (BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED.equals(action)
                    || BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED.equals(action)
                    || BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED.equals(action)) {
                final int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
                        BluetoothProfile.STATE_CONNECTED);
                if (mHandler.hasMessages(MESSAGE_INIT_FLAGS_CHANGED)
                        && state == BluetoothProfile.STATE_DISCONNECTED
                        && !mBluetoothModeChangeHelper.isMediaProfileConnected()) {
                    Log.i(TAG, "Device disconnected, reactivating pending flag changes");
                    onInitFlagsChanged();
                }
            } else if (action.equals(Intent.ACTION_SHUTDOWN)) {
                Log.i(TAG, "Device is shutting down.");
                mShutdownInProgress = true;
@@ -701,8 +677,6 @@ class BluetoothManagerService {
        filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
        filter.addAction(BluetoothAdapter.ACTION_BLUETOOTH_ADDRESS_CHANGED);
        filter.addAction(Intent.ACTION_SETTING_RESTORED);
        filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
        filter.addAction(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
        filter.addAction(Intent.ACTION_SHUTDOWN);
        filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
        mContext.registerReceiver(mReceiver, filter);
@@ -1158,35 +1132,6 @@ class BluetoothManagerService {
        return mIsHearingAidProfileSupported;
    }

    private boolean isDeviceProvisioned() {
        return Settings.Global.getInt(mContentResolver, Settings.Global.DEVICE_PROVISIONED,
                0) != 0;
    }

    // Monitor change of BLE scan only mode settings.
    private void registerForProvisioningStateChange() {
        ContentObserver contentObserver = new ContentObserver(null) {
            @Override
            public void onChange(boolean selfChange) {
                if (!isDeviceProvisioned()) {
                    if (DBG) {
                        Log.d(TAG, "DEVICE_PROVISIONED setting changed, but device is not "
                                + "provisioned");
                    }
                    return;
                }
                if (mHandler.hasMessages(MESSAGE_INIT_FLAGS_CHANGED)) {
                    Log.i(TAG, "Device provisioned, reactivating pending flag changes");
                    onInitFlagsChanged();
                }
            }
        };

        mContentResolver.registerContentObserver(
                Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), false,
                contentObserver);
    }

    // Monitor change of BLE scan only mode settings.
    private void registerForBleScanModeChange() {
        ContentObserver contentObserver = new ContentObserver(null) {
@@ -1658,8 +1603,6 @@ class BluetoothManagerService {
        if (mBluetoothAirplaneModeListener != null) {
            mBluetoothAirplaneModeListener.start(mBluetoothModeChangeHelper);
        }
        registerForProvisioningStateChange();
        mBluetoothDeviceConfigListener = new BluetoothDeviceConfigListener(this, DBG);
        loadApmEnhancementStateFromResource();
    }

@@ -1671,9 +1614,7 @@ class BluetoothManagerService {
        mBluetoothModeChangeHelper = bluetoothModeChangeHelper;
    }

    /**
     * Load whether APM Enhancement feature should be enabled from overlay
     */
    /** Load whether APM Enhancement feature should be enabled from overlay */
    @VisibleForTesting
    void loadApmEnhancementStateFromResource() {
        String btPackageName = mBluetoothModeChangeHelper.getBluetoothPackageName();
@@ -1682,20 +1623,21 @@ class BluetoothManagerService {
            return;
        }
        try {
            Resources resources = mContext.getPackageManager()
                    .getResourcesForApplication(btPackageName);
            int apmEnhancement = resources.getIdentifier("config_bluetooth_apm_enhancement_enabled",
                    "bool", btPackageName);
            Settings.Global.putInt(mContext.getContentResolver(),
                    APM_ENHANCEMENT, resources.getBoolean(apmEnhancement) ? 1 : 0);
            Resources resources =
                    mContext.getPackageManager().getResourcesForApplication(btPackageName);
            int apmEnhancement =
                    resources.getIdentifier(
                            "config_bluetooth_apm_enhancement_enabled", "bool", btPackageName);
            Settings.Global.putInt(
                    mContext.getContentResolver(),
                    APM_ENHANCEMENT,
                    resources.getBoolean(apmEnhancement) ? 1 : 0);
        } catch (Exception e) {
            Log.e(TAG, "Unable to set whether APM enhancement should be enabled");
        }
    }

    /**
     * Called when switching to a different foreground user.
     */
    /** Called when switching to a different foreground user. */
    void handleSwitchUser(UserHandle userHandle) {
        if (DBG) {
            Log.d(TAG, "User " + userHandle + " switched");
@@ -1712,8 +1654,8 @@ class BluetoothManagerService {
    }

    /**
     * This class manages the clients connected to a given ProfileService
     * and maintains the connection with that service.
     * This class manages the clients connected to a given ProfileService and maintains the
     * connection with that service.
     */
    private final class ProfileServiceConnections
            implements ServiceConnection, IBinder.DeathRecipient {
@@ -2545,36 +2487,6 @@ class BluetoothManagerService {
                    }
                    break;
                }
                case MESSAGE_INIT_FLAGS_CHANGED: {
                    if (DBG) {
                        Log.d(TAG, "MESSAGE_INIT_FLAGS_CHANGED");
                    }
                    mHandler.removeMessages(MESSAGE_INIT_FLAGS_CHANGED);
                    if (mBluetoothModeChangeHelper.isMediaProfileConnected()) {
                        Log.i(TAG, "Delaying MESSAGE_INIT_FLAGS_CHANGED by "
                                + DELAY_FOR_RETRY_INIT_FLAG_CHECK_MS
                                + " ms due to existing connections");
                        mHandler.sendEmptyMessageDelayed(
                                MESSAGE_INIT_FLAGS_CHANGED,
                                DELAY_FOR_RETRY_INIT_FLAG_CHECK_MS);
                        break;
                    }
                    if (!isDeviceProvisioned()) {
                        Log.i(TAG, "Delaying MESSAGE_INIT_FLAGS_CHANGED by "
                                + DELAY_FOR_RETRY_INIT_FLAG_CHECK_MS
                                +  "ms because device is not provisioned");
                        mHandler.sendEmptyMessageDelayed(
                                MESSAGE_INIT_FLAGS_CHANGED,
                                DELAY_FOR_RETRY_INIT_FLAG_CHECK_MS);
                        break;
                    }
                    if (mBluetooth != null && isEnabled()) {
                        Log.i(TAG, "Restarting Bluetooth due to init flag change");
                        restartForReason(
                                BluetoothProtoEnums.ENABLE_DISABLE_REASON_INIT_FLAGS_CHANGED);
                    }
                    break;
                }
            }
        }

+0 −167
Original line number Diff line number Diff line
/*
 * Copyright 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.bluetooth;

import static com.google.common.truth.Truth.assertThat;

import android.provider.DeviceConfig;
import android.provider.DeviceConfig.Properties;

import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;

import org.junit.Test;
import org.junit.runner.RunWith;

@SmallTest
@RunWith(AndroidJUnit4.class)
public class BluetoothDeviceConfigChangeTrackerTest {
    @Test
    public void testNoProperties() {
        BluetoothDeviceConfigChangeTracker changeTracker =
                new BluetoothDeviceConfigChangeTracker(
                        new Properties.Builder(DeviceConfig.NAMESPACE_BLUETOOTH).build());

        boolean shouldRestart =
                changeTracker.shouldRestartWhenPropertiesUpdated(
                        new Properties.Builder(DeviceConfig.NAMESPACE_BLUETOOTH).build());

        assertThat(shouldRestart).isFalse();
    }

    @Test
    public void testNewFlag() {
        BluetoothDeviceConfigChangeTracker changeTracker =
                new BluetoothDeviceConfigChangeTracker(
                        new Properties.Builder(DeviceConfig.NAMESPACE_BLUETOOTH)
                                .setString("INIT_a", "true")
                                .build());

        boolean shouldRestart =
                changeTracker.shouldRestartWhenPropertiesUpdated(
                        new Properties.Builder(DeviceConfig.NAMESPACE_BLUETOOTH)
                                .setString("INIT_a", "true")
                                .setString("INIT_b", "true")
                                .build());

        assertThat(shouldRestart).isTrue();
    }

    @Test
    public void testChangedFlag() {
        BluetoothDeviceConfigChangeTracker changeTracker =
                new BluetoothDeviceConfigChangeTracker(
                        new Properties.Builder(DeviceConfig.NAMESPACE_BLUETOOTH)
                                .setString("INIT_a", "true")
                                .build());

        boolean shouldRestart =
                changeTracker.shouldRestartWhenPropertiesUpdated(
                        new Properties.Builder(DeviceConfig.NAMESPACE_BLUETOOTH)
                                .setString("INIT_a", "false")
                                .build());

        assertThat(shouldRestart).isTrue();
    }

    @Test
    public void testUnchangedInitFlag() {
        BluetoothDeviceConfigChangeTracker changeTracker =
                new BluetoothDeviceConfigChangeTracker(
                        new Properties.Builder(DeviceConfig.NAMESPACE_BLUETOOTH)
                                .setString("INIT_a", "true")
                                .build());

        boolean shouldRestart =
                changeTracker.shouldRestartWhenPropertiesUpdated(
                        new Properties.Builder(DeviceConfig.NAMESPACE_BLUETOOTH)
                                .setString("INIT_a", "true")
                                .build());

        assertThat(shouldRestart).isFalse();
    }

    @Test
    public void testRepeatedChangeInitFlag() {
        BluetoothDeviceConfigChangeTracker changeTracker =
                new BluetoothDeviceConfigChangeTracker(
                        new Properties.Builder(DeviceConfig.NAMESPACE_BLUETOOTH).build());

        changeTracker.shouldRestartWhenPropertiesUpdated(
                new Properties.Builder(DeviceConfig.NAMESPACE_BLUETOOTH)
                        .setString("INIT_a", "true")
                        .build());

        boolean shouldRestart =
                changeTracker.shouldRestartWhenPropertiesUpdated(
                        new Properties.Builder(DeviceConfig.NAMESPACE_BLUETOOTH)
                                .setString("INIT_a", "true")
                                .build());

        assertThat(shouldRestart).isFalse();
    }

    @Test
    public void testWrongNamespace() {
        BluetoothDeviceConfigChangeTracker changeTracker =
                new BluetoothDeviceConfigChangeTracker(
                        new Properties.Builder(DeviceConfig.NAMESPACE_BLUETOOTH).build());

        boolean shouldRestart =
                changeTracker.shouldRestartWhenPropertiesUpdated(
                        new Properties.Builder("another_namespace")
                                .setString("INIT_a", "true")
                                .build());

        assertThat(shouldRestart).isFalse();
    }

    @Test
    public void testSkipProperty() {
        BluetoothDeviceConfigChangeTracker changeTracker =
                new BluetoothDeviceConfigChangeTracker(
                        new Properties.Builder(DeviceConfig.NAMESPACE_BLUETOOTH)
                                .setString("INIT_a", "true")
                                .setString("INIT_b", "false")
                                .build());

        boolean shouldRestart =
                changeTracker.shouldRestartWhenPropertiesUpdated(
                        new Properties.Builder(DeviceConfig.NAMESPACE_BLUETOOTH)
                                .setString("INIT_b", "false")
                                .build());

        assertThat(shouldRestart).isFalse();
    }

    @Test
    public void testNonInitFlag() {
        BluetoothDeviceConfigChangeTracker changeTracker =
                new BluetoothDeviceConfigChangeTracker(
                        new Properties.Builder(DeviceConfig.NAMESPACE_BLUETOOTH)
                                .setString("a", "true")
                                .build());

        boolean shouldRestart =
                changeTracker.shouldRestartWhenPropertiesUpdated(
                        new Properties.Builder(DeviceConfig.NAMESPACE_BLUETOOTH)
                                .setString("a", "false")
                                .build());

        assertThat(shouldRestart).isFalse();
    }
}