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

Commit 0fb6bdac authored by Hieu Dang's avatar Hieu Dang Committed by Gerrit Code Review
Browse files

Merge "Disallow Bt Sharing on secondary users correctly"

parents 32f6d2bb 9d1cfc79
Loading
Loading
Loading
Loading
+26 −19
Original line number Original line 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 DELAY_FOR_RETRY_INIT_FLAG_CHECK_MS = 86400000;


    private static final int MESSAGE_ENABLE = 1;
    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_ENABLE_DELAYED = 3;
    private static final int MESSAGE_HANDLE_DISABLE_DELAYED = 4;
    private static final int MESSAGE_HANDLE_DISABLE_DELAYED = 4;
    private static final int MESSAGE_REGISTER_STATE_CHANGE_CALLBACK = 30;
    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) {
    public void onUserRestrictionsChanged(UserHandle userHandle) {
        final boolean newBluetoothDisallowed = mUserManager.hasUserRestrictionForUser(
        final boolean newBluetoothDisallowed = mUserManager.hasUserRestrictionForUser(
                UserManager.DISALLOW_BLUETOOTH, userHandle);
                UserManager.DISALLOW_BLUETOOTH, userHandle);
        boolean newBluetoothSharingDisallowed = mUserManager.hasUserRestrictionForUser(
        // Disallow Bluetooth sharing when either Bluetooth is disallowed or Bluetooth sharing
                UserManager.DISALLOW_BLUETOOTH_SHARING, userHandle);
        // 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.
        // DISALLOW_BLUETOOTH can only be set by DO or PO on the system user.
        if (userHandle == UserHandle.SYSTEM) {
        // Only trigger once instead of for all users
            if (newBluetoothDisallowed) {
        if (userHandle == UserHandle.SYSTEM && newBluetoothDisallowed) {
                updateOppLauncherComponentState(userHandle, true); // Sharing disallowed
            sendDisableMsg(BluetoothProtoEnums.ENABLE_DISABLE_REASON_DISALLOWED,
            sendDisableMsg(BluetoothProtoEnums.ENABLE_DISABLE_REASON_DISALLOWED,
                    mContext.getPackageName());
                    mContext.getPackageName());
            } else {
                updateOppLauncherComponentState(userHandle, newBluetoothSharingDisallowed);
            }
        } else {
            updateOppLauncherComponentState(userHandle, newBluetoothSharingDisallowed);
        }
        }
    }
    }


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


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


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


        mContext = context;
        mContext = context;


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

        if (DBG) {
        if (DBG) {
            Log.d(TAG, "Stored bluetooth Name=" + mName + ",Address=" + mAddress);
            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 BluetoothServiceConnection mConnection = new BluetoothServiceConnection();


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


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


+103 −0
Original line number Original line 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 Original line 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);
    }
}