| /* |
| * Copyright (C) 2019 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.cts.context; |
| |
| import static com.google.common.truth.Truth.assertThat; |
| |
| import static org.junit.Assert.fail; |
| |
| import android.app.AppOpsManager; |
| import android.app.UiAutomation; |
| import android.content.ComponentName; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.os.Binder; |
| import android.os.Bundle; |
| import android.os.UserHandle; |
| |
| import androidx.test.InstrumentationRegistry; |
| |
| import org.junit.After; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.JUnit4; |
| |
| /** |
| * This suite of test ensures that certain APIs in {@link Context} behaves correctly across users. |
| */ |
| @RunWith(JUnit4.class) |
| public class ContextCrossProfileDeviceTest { |
| private static final String INTERACT_ACROSS_USERS_FULL_PERMISSION = |
| "android.permission.INTERACT_ACROSS_USERS_FULL"; |
| private static final String INTERACT_ACROSS_USERS_PERMISSION = |
| "android.permission.INTERACT_ACROSS_USERS"; |
| private static final String INTERACT_ACROSS_PROFILES_PERMISSION = |
| "android.permission.INTERACT_ACROSS_PROFILES"; |
| private static final String MANAGE_APP_OPS_MODE = "android.permission.MANAGE_APP_OPS_MODES"; |
| |
| private static final String TEST_SERVICE_PKG = |
| "com.android.cts.testService"; |
| private static final String TEST_SERVICE_IN_DIFFERENT_PKG_CLASS = |
| TEST_SERVICE_PKG + ".ContextCrossProfileTestService"; |
| public static final ComponentName TEST_SERVICE_IN_DIFFERENT_PKG_COMPONENT_NAME = |
| new ComponentName(TEST_SERVICE_PKG, TEST_SERVICE_IN_DIFFERENT_PKG_CLASS); |
| |
| private static final String TEST_SERVICE_IN_SAME_PKG_CLASS = |
| InstrumentationRegistry.getContext().getPackageName() |
| + ".ContextCrossProfileSamePackageTestService"; |
| public static final ComponentName TEST_SERVICE_IN_SAME_PKG_COMPONENT_NAME = |
| new ComponentName(InstrumentationRegistry.getContext().getPackageName(), |
| TEST_SERVICE_IN_SAME_PKG_CLASS); |
| @After |
| public void tearDown() throws Exception { |
| InstrumentationRegistry.getInstrumentation().getUiAutomation() |
| .dropShellPermissionIdentity(); |
| } |
| |
| private int getTestUser() { |
| final Bundle testArguments = InstrumentationRegistry.getArguments(); |
| if (testArguments.containsKey("testUser")) { |
| try { |
| return Integer.parseInt(testArguments.getString("testUser")); |
| } catch (NumberFormatException ignore) { |
| } |
| } |
| fail("testUser not found."); |
| return -1; |
| } |
| |
| @Test |
| public void testBindServiceAsUser_differentUser_bindsServiceToCorrectUser() { |
| final Context context = InstrumentationRegistry.getContext(); |
| final UiAutomation uiAutomation = |
| InstrumentationRegistry.getInstrumentation().getUiAutomation(); |
| int otherProfileId = getTestUser(); |
| UserHandle otherProfileHandle = UserHandle.of(otherProfileId); |
| uiAutomation.adoptShellPermissionIdentity(INTERACT_ACROSS_USERS_PERMISSION); |
| Intent bindIntent = new Intent(); |
| bindIntent.setComponent(TEST_SERVICE_IN_DIFFERENT_PKG_COMPONENT_NAME); |
| |
| assertThat(context.bindServiceAsUser( |
| bindIntent, new ContextCrossProfileTestConnection(), |
| Context.BIND_AUTO_CREATE, otherProfileHandle)) |
| .isTrue(); |
| assertThat(context.bindService( |
| bindIntent, new ContextCrossProfileTestConnection(), Context.BIND_AUTO_CREATE)) |
| .isFalse(); |
| } |
| |
| @Test |
| public void testBindServiceAsUser_sameProfileGroup_samePackage_withAcrossUsersPermission_bindsService() { |
| final Context context = InstrumentationRegistry.getContext(); |
| final UiAutomation uiAutomation = |
| InstrumentationRegistry.getInstrumentation().getUiAutomation(); |
| int otherProfileId = getTestUser(); |
| UserHandle otherProfileHandle = UserHandle.of(otherProfileId); |
| uiAutomation.adoptShellPermissionIdentity(INTERACT_ACROSS_USERS_PERMISSION); |
| Intent bindIntent = new Intent(); |
| bindIntent.setComponent(TEST_SERVICE_IN_SAME_PKG_COMPONENT_NAME); |
| |
| assertThat(context.bindServiceAsUser( |
| bindIntent, new ContextCrossProfileTestConnection(), |
| Context.BIND_AUTO_CREATE, otherProfileHandle)).isTrue(); |
| } |
| |
| @Test |
| public void testBindServiceAsUser_sameProfileGroup_differentPackage_withAcrossUsersPermission_bindsService() { |
| final Context context = InstrumentationRegistry.getContext(); |
| final UiAutomation uiAutomation = |
| InstrumentationRegistry.getInstrumentation().getUiAutomation(); |
| int otherProfileId = getTestUser(); |
| UserHandle otherProfileHandle = UserHandle.of(otherProfileId); |
| uiAutomation.adoptShellPermissionIdentity(INTERACT_ACROSS_USERS_PERMISSION); |
| Intent bindIntent = new Intent(); |
| bindIntent.setComponent(TEST_SERVICE_IN_DIFFERENT_PKG_COMPONENT_NAME); |
| |
| assertThat(context.bindServiceAsUser( |
| bindIntent, new ContextCrossProfileTestConnection(), |
| Context.BIND_AUTO_CREATE, otherProfileHandle)).isTrue(); |
| } |
| |
| @Test |
| public void testBindServiceAsUser_sameProfileGroup_samePackage_withAcrossProfilesPermission_bindsService() { |
| final Context context = InstrumentationRegistry.getContext(); |
| final UiAutomation uiAutomation = |
| InstrumentationRegistry.getInstrumentation().getUiAutomation(); |
| final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class); |
| uiAutomation.adoptShellPermissionIdentity(MANAGE_APP_OPS_MODE); |
| appOpsManager.setMode(AppOpsManager.permissionToOp(INTERACT_ACROSS_PROFILES_PERMISSION), |
| Binder.getCallingUid(), context.getPackageName(), AppOpsManager.MODE_DEFAULT); |
| uiAutomation.dropShellPermissionIdentity(); |
| int otherProfileId = getTestUser(); |
| UserHandle otherProfileHandle = UserHandle.of(otherProfileId); |
| uiAutomation.adoptShellPermissionIdentity(INTERACT_ACROSS_PROFILES_PERMISSION); |
| Intent bindIntent = new Intent(); |
| bindIntent.setComponent(TEST_SERVICE_IN_SAME_PKG_COMPONENT_NAME); |
| |
| assertThat(context.bindServiceAsUser( |
| bindIntent, new ContextCrossProfileTestConnection(), |
| Context.BIND_AUTO_CREATE, otherProfileHandle)).isTrue(); |
| } |
| |
| @Test |
| public void testBindServiceAsUser_sameProfileGroup_differentPackage_withAcrossProfilesPermission_throwsException() { |
| final Context context = InstrumentationRegistry.getContext(); |
| final UiAutomation uiAutomation = |
| InstrumentationRegistry.getInstrumentation().getUiAutomation(); |
| int otherProfileId = getTestUser(); |
| UserHandle otherProfileHandle = UserHandle.of(otherProfileId); |
| uiAutomation.adoptShellPermissionIdentity(INTERACT_ACROSS_PROFILES_PERMISSION); |
| Intent bindIntent = new Intent(); |
| bindIntent.setComponent(TEST_SERVICE_IN_DIFFERENT_PKG_COMPONENT_NAME); |
| |
| try { |
| context.bindServiceAsUser( |
| bindIntent, new ContextCrossProfileTestConnection(), Context.BIND_AUTO_CREATE, |
| otherProfileHandle); |
| |
| fail("Should throw a Security Exception"); |
| } catch (SecurityException ignored) { |
| } |
| } |
| |
| @Test |
| public void testBindServiceAsUser_sameProfileGroup_samePackage_withAcrossProfilesAppOp_bindsService(){ |
| final Context context = InstrumentationRegistry.getContext(); |
| final UiAutomation uiAutomation = |
| InstrumentationRegistry.getInstrumentation().getUiAutomation(); |
| final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class); |
| uiAutomation.adoptShellPermissionIdentity(MANAGE_APP_OPS_MODE); |
| appOpsManager.setMode(AppOpsManager.permissionToOp(INTERACT_ACROSS_PROFILES_PERMISSION), |
| Binder.getCallingUid(), context.getPackageName(), AppOpsManager.MODE_ALLOWED); |
| uiAutomation.dropShellPermissionIdentity(); |
| int otherProfileId = getTestUser(); |
| UserHandle otherProfileHandle = UserHandle.of(otherProfileId); |
| Intent bindIntent = new Intent(); |
| bindIntent.setComponent(TEST_SERVICE_IN_SAME_PKG_COMPONENT_NAME); |
| |
| assertThat(context.bindServiceAsUser( |
| bindIntent, new ContextCrossProfileTestConnection(), |
| Context.BIND_AUTO_CREATE, otherProfileHandle)).isTrue(); |
| } |
| |
| @Test |
| public void testBindServiceAsUser_sameProfileGroup_differentPackage_withAcrossProfilesAppOp_throwsException(){ |
| final Context context = InstrumentationRegistry.getContext(); |
| final UiAutomation uiAutomation = |
| InstrumentationRegistry.getInstrumentation().getUiAutomation(); |
| final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class); |
| uiAutomation.adoptShellPermissionIdentity(MANAGE_APP_OPS_MODE); |
| appOpsManager.setMode(AppOpsManager.permissionToOp(INTERACT_ACROSS_PROFILES_PERMISSION), |
| Binder.getCallingUid(), context.getPackageName(), AppOpsManager.MODE_ALLOWED); |
| uiAutomation.dropShellPermissionIdentity(); |
| int otherProfileId = getTestUser(); |
| UserHandle otherProfileHandle = UserHandle.of(otherProfileId); |
| Intent bindIntent = new Intent(); |
| bindIntent.setComponent(TEST_SERVICE_IN_DIFFERENT_PKG_COMPONENT_NAME); |
| |
| try { |
| context.bindServiceAsUser( |
| bindIntent, new ContextCrossProfileTestConnection(), Context.BIND_AUTO_CREATE, |
| otherProfileHandle); |
| |
| fail("Should throw a Security Exception"); |
| } catch (SecurityException ignored) { |
| } |
| } |
| |
| @Test |
| public void testBindServiceAsUser_differentProfileGroup_samePackage_withAcrossUsersPermission_bindsService() { |
| final Context context = InstrumentationRegistry.getContext(); |
| final UiAutomation uiAutomation = |
| InstrumentationRegistry.getInstrumentation().getUiAutomation(); |
| int otherUserId = getTestUser(); |
| UserHandle otherUserHandle = UserHandle.of(otherUserId); |
| uiAutomation.adoptShellPermissionIdentity(INTERACT_ACROSS_USERS_PERMISSION); |
| Intent bindIntent = new Intent(); |
| bindIntent.setComponent(TEST_SERVICE_IN_SAME_PKG_COMPONENT_NAME); |
| |
| assertThat(context.bindServiceAsUser( |
| bindIntent, new ContextCrossProfileTestConnection(), Context.BIND_AUTO_CREATE, |
| otherUserHandle)).isTrue(); |
| } |
| |
| @Test |
| public void testBindServiceAsUser_differentProfileGroup_differentPackage_withAcrossUsersPermission_throwsException() { |
| final Context context = InstrumentationRegistry.getContext(); |
| final UiAutomation uiAutomation = |
| InstrumentationRegistry.getInstrumentation().getUiAutomation(); |
| int otherUserId = getTestUser(); |
| UserHandle otherUserHandle = UserHandle.of(otherUserId); |
| uiAutomation.adoptShellPermissionIdentity(INTERACT_ACROSS_USERS_PERMISSION); |
| try { |
| Intent bindIntent = new Intent(); |
| bindIntent.setComponent(TEST_SERVICE_IN_DIFFERENT_PKG_COMPONENT_NAME); |
| |
| context.bindServiceAsUser( |
| bindIntent, new ContextCrossProfileTestConnection(), Context.BIND_AUTO_CREATE, |
| otherUserHandle); |
| |
| fail("Should throw a Security Exception"); |
| } catch (SecurityException ignored) { |
| } |
| } |
| |
| @Test |
| public void testBindServiceAsUser_differentProfileGroup_withInteractAcrossProfilesPermission_throwsException() { |
| final Context context = InstrumentationRegistry.getContext(); |
| final UiAutomation uiAutomation = |
| InstrumentationRegistry.getInstrumentation().getUiAutomation(); |
| int otherUserId = getTestUser(); |
| UserHandle otherUserHandle = UserHandle.of(otherUserId); |
| uiAutomation.adoptShellPermissionIdentity(INTERACT_ACROSS_PROFILES_PERMISSION); |
| try { |
| Intent bindIntent = new Intent(); |
| bindIntent.setComponent(TEST_SERVICE_IN_SAME_PKG_COMPONENT_NAME); |
| |
| context.bindServiceAsUser( |
| bindIntent, new ContextCrossProfileTestConnection(), Context.BIND_AUTO_CREATE, |
| otherUserHandle); |
| |
| fail("Should throw a Security Exception"); |
| } catch (SecurityException ignored) { |
| } |
| } |
| |
| @Test |
| public void testBindServiceAsUser_differentProfileGroup_withInteractAcrossProfilesAppOp_throwsException(){ |
| final Context context = InstrumentationRegistry.getContext(); |
| final UiAutomation uiAutomation = |
| InstrumentationRegistry.getInstrumentation().getUiAutomation(); |
| final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class); |
| uiAutomation.adoptShellPermissionIdentity(MANAGE_APP_OPS_MODE); |
| appOpsManager.setMode(AppOpsManager.permissionToOp(INTERACT_ACROSS_PROFILES_PERMISSION), |
| Binder.getCallingUid(), context.getPackageName(), AppOpsManager.MODE_ALLOWED); |
| uiAutomation.dropShellPermissionIdentity(); |
| int otherUserId = getTestUser(); |
| UserHandle otherUserHandle = UserHandle.of(otherUserId); |
| try { |
| Intent bindIntent = new Intent(); |
| bindIntent.setComponent(TEST_SERVICE_IN_SAME_PKG_COMPONENT_NAME); |
| |
| context.bindServiceAsUser( |
| bindIntent, new ContextCrossProfileTestConnection(), |
| Context.BIND_AUTO_CREATE, otherUserHandle); |
| |
| fail("Should throw a Security Exception"); |
| } catch (SecurityException ignored) { |
| } |
| } |
| |
| @Test |
| public void testBindServiceAsUser_sameProfileGroup_withNoPermissions_throwsException() { |
| final Context context = InstrumentationRegistry.getContext(); |
| int otherProfileId = getTestUser(); |
| UserHandle otherProfileHandle = UserHandle.of(otherProfileId); |
| try { |
| Intent bindIntent = new Intent(); |
| bindIntent.setComponent(TEST_SERVICE_IN_SAME_PKG_COMPONENT_NAME); |
| |
| context.bindServiceAsUser( |
| bindIntent, new ContextCrossProfileTestConnection(), Context.BIND_AUTO_CREATE, |
| otherProfileHandle); |
| |
| fail("Should throw a Security Exception"); |
| } catch (SecurityException ignored) { |
| } |
| } |
| |
| @Test |
| public void testBindServiceAsUser_withInteractAcrossProfilePermission_noAsserts() { |
| final Context context = InstrumentationRegistry.getContext(); |
| final UiAutomation uiAutomation = |
| InstrumentationRegistry.getInstrumentation().getUiAutomation(); |
| final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class); |
| uiAutomation.adoptShellPermissionIdentity(MANAGE_APP_OPS_MODE); |
| appOpsManager.setMode(AppOpsManager.permissionToOp(INTERACT_ACROSS_PROFILES_PERMISSION), |
| Binder.getCallingUid(), context.getPackageName(), AppOpsManager.MODE_DEFAULT); |
| uiAutomation.dropShellPermissionIdentity(); |
| int otherProfileId = getTestUser(); |
| UserHandle otherProfileHandle = UserHandle.of(otherProfileId); |
| uiAutomation.adoptShellPermissionIdentity(INTERACT_ACROSS_PROFILES_PERMISSION); |
| Intent bindIntent = new Intent(); |
| bindIntent.setComponent(TEST_SERVICE_IN_SAME_PKG_COMPONENT_NAME); |
| |
| context.bindServiceAsUser( |
| bindIntent, new ContextCrossProfileTestConnection(), |
| Context.BIND_AUTO_CREATE, otherProfileHandle); |
| } |
| |
| @Test |
| public void testBindServiceAsUser_withInteractAcrossUsersFullPermission_noAsserts() { |
| final Context context = InstrumentationRegistry.getContext(); |
| final UiAutomation uiAutomation = |
| InstrumentationRegistry.getInstrumentation().getUiAutomation(); |
| int otherProfileId = getTestUser(); |
| UserHandle otherProfileHandle = UserHandle.of(otherProfileId); |
| uiAutomation.adoptShellPermissionIdentity( |
| INTERACT_ACROSS_USERS_FULL_PERMISSION, INTERACT_ACROSS_USERS_PERMISSION); |
| Intent bindIntent = new Intent(); |
| bindIntent.setComponent(TEST_SERVICE_IN_SAME_PKG_COMPONENT_NAME); |
| |
| context.bindServiceAsUser( |
| bindIntent, new ContextCrossProfileTestConnection(), |
| Context.BIND_AUTO_CREATE, otherProfileHandle); |
| } |
| |
| @Test |
| public void testCreateContextAsUser_sameProfileGroup_withInteractAcrossProfilesPermission_throwsException() { |
| final Context context = InstrumentationRegistry.getContext(); |
| final UiAutomation uiAutomation = |
| InstrumentationRegistry.getInstrumentation().getUiAutomation(); |
| int otherProfileId = getTestUser(); |
| UserHandle otherProfileHandle = UserHandle.of(otherProfileId); |
| uiAutomation.adoptShellPermissionIdentity(INTERACT_ACROSS_PROFILES_PERMISSION); |
| |
| try { |
| context.createContextAsUser(otherProfileHandle, /*flags= */0); |
| |
| fail("Should throw a Security Exception"); |
| } catch (SecurityException ignored) { |
| } |
| } |
| |
| @Test |
| public void testCreateContextAsUser_sameProfileGroup_withInteractAcrossUsersPermission_createsContext() { |
| final Context context = InstrumentationRegistry.getContext(); |
| final UiAutomation uiAutomation = |
| InstrumentationRegistry.getInstrumentation().getUiAutomation(); |
| int otherProfileId = getTestUser(); |
| UserHandle otherProfileHandle = UserHandle.of(otherProfileId); |
| uiAutomation.adoptShellPermissionIdentity(INTERACT_ACROSS_USERS_PERMISSION); |
| |
| Context otherProfileContext = context.createContextAsUser( |
| otherProfileHandle, /*flags= */0); |
| |
| assertThat(otherProfileContext.getUserId()).isEqualTo(otherProfileId); |
| } |
| } |