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

Commit c8e76bb2 authored by Hieu Dang's avatar Hieu Dang Committed by Automerger Merge Worker
Browse files

Merge "Disallow Bt Sharing on secondary users correctly" am: 0fb6bdac

parents 7f5ce23b 0fb6bdac
Loading
Loading
Loading
Loading
+26 −19
Original line number Diff line number Diff line
@@ -155,7 +155,8 @@ public class BluetoothManagerService extends IBluetoothManager.Stub {
    private static final int DELAY_FOR_RETRY_INIT_FLAG_CHECK_MS = 86400000;

    private static final int MESSAGE_ENABLE = 1;
    private static final int MESSAGE_DISABLE = 2;
    @VisibleForTesting
    static final int MESSAGE_DISABLE = 2;
    private static final int MESSAGE_HANDLE_ENABLE_DELAYED = 3;
    private static final int MESSAGE_HANDLE_DISABLE_DELAYED = 4;
    private static final int MESSAGE_REGISTER_STATE_CHANGE_CALLBACK = 30;
@@ -324,19 +325,19 @@ public class BluetoothManagerService extends IBluetoothManager.Stub {
    public void onUserRestrictionsChanged(UserHandle userHandle) {
        final boolean newBluetoothDisallowed = mUserManager.hasUserRestrictionForUser(
                UserManager.DISALLOW_BLUETOOTH, userHandle);
        boolean newBluetoothSharingDisallowed = mUserManager.hasUserRestrictionForUser(
                UserManager.DISALLOW_BLUETOOTH_SHARING, userHandle);
        // Disallow Bluetooth sharing when either Bluetooth is disallowed or Bluetooth sharing
        // is disallowed
        final boolean newBluetoothSharingDisallowed = mUserManager.hasUserRestrictionForUser(
                UserManager.DISALLOW_BLUETOOTH_SHARING, userHandle) || newBluetoothDisallowed;

        // Disable OPP activities for this userHandle
        updateOppLauncherComponentState(userHandle, newBluetoothSharingDisallowed);

        // DISALLOW_BLUETOOTH can only be set by DO or PO on the system user.
        if (userHandle == UserHandle.SYSTEM) {
            if (newBluetoothDisallowed) {
                updateOppLauncherComponentState(userHandle, true); // Sharing disallowed
        // Only trigger once instead of for all users
        if (userHandle == UserHandle.SYSTEM && newBluetoothDisallowed) {
            sendDisableMsg(BluetoothProtoEnums.ENABLE_DISABLE_REASON_DISALLOWED,
                    mContext.getPackageName());
            } else {
                updateOppLauncherComponentState(userHandle, newBluetoothSharingDisallowed);
            }
        } else {
            updateOppLauncherComponentState(userHandle, newBluetoothSharingDisallowed);
        }
    }

@@ -568,10 +569,12 @@ public class BluetoothManagerService extends IBluetoothManager.Stub {
    };

    BluetoothManagerService(Context context) {
        mBluetoothHandlerThread = new HandlerThread("BluetoothManagerService");
        mBluetoothHandlerThread = BluetoothServerProxy.getInstance()
                .createHandlerThread("BluetoothManagerService");
        mBluetoothHandlerThread.start();

        mHandler = new BluetoothHandler(mBluetoothHandlerThread.getLooper());
        mHandler = BluetoothServerProxy.getInstance().newBluetoothHandler(
                new BluetoothHandler(mBluetoothHandlerThread.getLooper()));

        mContext = context;

@@ -819,8 +822,11 @@ public class BluetoothManagerService extends IBluetoothManager.Stub {
            }
            return;
        }
        mName = Settings.Secure.getString(mContentResolver, Settings.Secure.BLUETOOTH_NAME);
        mAddress = Settings.Secure.getString(mContentResolver, Settings.Secure.BLUETOOTH_ADDRESS);
        mName = BluetoothServerProxy.getInstance()
                .settingsSecureGetString(mContentResolver, Settings.Secure.BLUETOOTH_NAME);
        mAddress = BluetoothServerProxy.getInstance()
                .settingsSecureGetString(mContentResolver, Settings.Secure.BLUETOOTH_ADDRESS);

        if (DBG) {
            Log.d(TAG, "Stored bluetooth Name=" + mName + ",Address=" + mAddress);
        }
@@ -2062,7 +2068,8 @@ public class BluetoothManagerService extends IBluetoothManager.Stub {

    private BluetoothServiceConnection mConnection = new BluetoothServiceConnection();

    private class BluetoothHandler extends Handler {
    @VisibleForTesting
    class BluetoothHandler extends Handler {
        boolean mGetNameAddressOnly = false;
        private int mWaitForEnableRetry;
        private int mWaitForDisableRetry;
@@ -2968,7 +2975,7 @@ public class BluetoothManagerService extends IBluetoothManager.Stub {
    }

    private void sendDisableMsg(int reason, String packageName) {
        mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISABLE));
        BluetoothServerProxy.getInstance().handlerSendWhatMessage(mHandler, MESSAGE_DISABLE);
        addActiveLog(reason, packageName, false);
    }

+103 −0
Original line number Diff line number Diff line
/*
 * Copyright 2023 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.content.ContentResolver;
import android.os.HandlerThread;
import android.provider.Settings;
import android.util.Log;

import com.android.internal.annotations.VisibleForTesting;

/**
 * Proxy class for method calls to help with unit testing
 */
public class BluetoothServerProxy {
    private static final String TAG = BluetoothServerProxy.class.getSimpleName();
    private static final Object INSTANCE_LOCK = new Object();
    private static BluetoothServerProxy sInstance;

    private BluetoothServerProxy() {
    }

    /**
     * Get the singleton instance of proxy
     *
     * @return the singleton instance, guaranteed not null
     */
    public static BluetoothServerProxy getInstance() {
        synchronized (INSTANCE_LOCK) {
            if (sInstance == null) {
                sInstance = new BluetoothServerProxy();
            }
        }
        return sInstance;
    }

    /**
     * Allow unit tests to substitute BluetoothPbapMethodCallProxy with a test instance
     *
     * @param proxy a test instance of the BluetoothPbapMethodCallProxy
     */
    @VisibleForTesting
    public static void setInstanceForTesting(BluetoothServerProxy proxy) {
        synchronized (INSTANCE_LOCK) {
            Log.d(TAG, "setInstanceForTesting(), set to " + proxy);
            sInstance = proxy;
        }
    }

    /**
     * Proxies {@link com.android.server.bluetooth.BluetoothManagerService.BluetoothHandler}.
     */
    public BluetoothManagerService.BluetoothHandler createBluetoothHandler(
            BluetoothManagerService.BluetoothHandler bluetoothHandler) {
        return bluetoothHandler;
    }

    /**
     * Proxies {@link com.android.server.bluetooth.BluetoothManagerService.BluetoothHandler}.
     */
    public BluetoothManagerService.BluetoothHandler newBluetoothHandler(
            BluetoothManagerService.BluetoothHandler bluetoothHandler) {
        return bluetoothHandler;
    }

    /**
     * Proxies {@link HandlerThread(String)}.
     */
    public HandlerThread createHandlerThread(String name) {
        return new HandlerThread(name);
    }

    /**
     * Proxies {@link android.provider.Settings.Secure.getString}.
     */
    public String settingsSecureGetString(ContentResolver contentResolver, String name) {
        return Settings.Secure.getString(contentResolver, name);
    }

    /**
     * Proxies
     * {@link com.android.server.bluetooth.BluetoothManagerService.BluetoothHandler.sendMessage}.
     */
    public boolean handlerSendWhatMessage(
            com.android.server.bluetooth.BluetoothManagerService.BluetoothHandler handler,
            int what) {
        return handler.sendMessage(handler.obtainMessage(what));
    }
}
+108 −0
Original line number Diff line number Diff line
/*
 * Copyright 2023 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 org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;

import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.os.HandlerThread;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;

import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

@RunWith(AndroidJUnit4.class)
public class BluetoothManagerServiceTest {
    static int sTimeout = 3000;
    BluetoothManagerService mManagerService;
    Context mContext;
    @Mock
    BluetoothServerProxy mBluetoothServerProxy;
    @Mock
    BluetoothManagerService.BluetoothHandler mHandler;
    HandlerThread mHandlerThread;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        mContext = spy(new ContextWrapper(
                InstrumentationRegistry.getInstrumentation().getTargetContext()));
        mHandlerThread = new HandlerThread("BluetoothManagerServiceTest");
    }

    @After
    public void tearDown() {
        mHandlerThread.quitSafely();
    }

    @Test
    public void onUserRestrictionsChanged_disallowBluetooth_onlySendDisableMessageOnSystemUser()
            throws InterruptedException {
        doReturn(mock(Intent.class)).when(mContext).registerReceiverForAllUsers(any(), any(),
                eq(null), eq(null));
        BluetoothServerProxy.setInstanceForTesting(mBluetoothServerProxy);
        // Mock the handler to avoid handle message & to terminate the thread after
        // test
        doReturn(mHandlerThread).when(mBluetoothServerProxy).createHandlerThread(any());
        doReturn(mHandler).when(mBluetoothServerProxy).newBluetoothHandler(any());

        // Mock these functions so security errors won't throw
        doReturn("name").when(mBluetoothServerProxy).settingsSecureGetString(any(),
                eq(Settings.Secure.BLUETOOTH_NAME));
        doReturn("00:11:22:33:44:55").when(mBluetoothServerProxy).settingsSecureGetString(any(),
                eq(Settings.Secure.BLUETOOTH_ADDRESS));

        // Spy UserManager so we can mimic the case when restriction settings changed
        UserManager userManager = mock(UserManager.class);
        doReturn(userManager).when(mContext).getSystemService(UserManager.class);
        doReturn(true).when(userManager).hasUserRestrictionForUser(
                eq(UserManager.DISALLOW_BLUETOOTH), any());
        doReturn(false).when(userManager).hasUserRestrictionForUser(
                eq(UserManager.DISALLOW_BLUETOOTH_SHARING), any());
        mManagerService = new BluetoothManagerService(mContext);

        // Check if disable message sent once for system user only
        // Since Message object is recycled after processed, use proxy function to get what value

        // test run on user -1, should not turning Bluetooth off
        mManagerService.onUserRestrictionsChanged(UserHandle.CURRENT);
        verify(mBluetoothServerProxy, timeout(sTimeout).times(0)).handlerSendWhatMessage(mHandler,
                BluetoothManagerService.MESSAGE_DISABLE);

        // called from SYSTEM user, should try to toggle Bluetooth off
        mManagerService.onUserRestrictionsChanged(UserHandle.SYSTEM);
        verify(mBluetoothServerProxy, timeout(sTimeout)).handlerSendWhatMessage(mHandler,
                BluetoothManagerService.MESSAGE_DISABLE);
    }
}