1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.cts.crossprofileappstest; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import static org.junit.Assert.fail; 22 23 import android.app.AppOpsManager; 24 import android.app.admin.DevicePolicyManager; 25 import android.content.ComponentName; 26 import android.content.Context; 27 import android.content.Intent; 28 import android.content.pm.CrossProfileApps; 29 import android.content.pm.PackageManager; 30 import android.os.Binder; 31 import android.os.Bundle; 32 import android.os.UserHandle; 33 import android.os.UserManager; 34 35 import androidx.test.InstrumentationRegistry; 36 import androidx.test.runner.AndroidJUnit4; 37 38 import com.android.bedstead.nene.TestApis; 39 import com.android.bedstead.nene.permissions.PermissionContext; 40 41 import org.junit.After; 42 import org.junit.Test; 43 import org.junit.runner.RunWith; 44 45 import java.util.Collections; 46 47 @RunWith(AndroidJUnit4.class) 48 public class CrossProfileAppsPermissionToInteractTest { 49 public static final String MANAGE_APP_OPS_MODES_PERMISSION = 50 "android.permission.MANAGE_APP_OPS_MODES"; 51 public static final String INTERACT_ACROSS_PROFILES_PERMISSION = 52 "android.permission.INTERACT_ACROSS_PROFILES"; 53 public static final String INTERACT_ACROSS_USERS_PERMISSION = 54 "android.permission.INTERACT_ACROSS_USERS"; 55 public static final String INTERACT_ACROSS_USERS_FULL_PERMISSION = 56 "android.permission.INTERACT_ACROSS_USERS_FULL"; 57 public static final String ACTION_MANAGE_CROSS_PROFILE_ACCESS = 58 "android.settings.MANAGE_CROSS_PROFILE_ACCESS"; 59 60 private static final ComponentName ADMIN_RECEIVER_COMPONENT = 61 new ComponentName( 62 AdminReceiver.class.getPackage().getName(), AdminReceiver.class.getName()); 63 private static final String PARAM_CROSS_PROFILE_PACKAGE = "crossProfilePackage"; 64 private static final TestApis sTestApis = new TestApis(); 65 66 private final Context mContext = InstrumentationRegistry.getContext(); 67 private final CrossProfileApps mCrossProfileApps = 68 mContext.getSystemService(CrossProfileApps.class); 69 private final AppOpsManager mAppOpsManager = mContext.getSystemService(AppOpsManager.class); 70 71 @After tearDown()72 public void tearDown() { 73 InstrumentationRegistry.getInstrumentation().getUiAutomation() 74 .dropShellPermissionIdentity(); 75 } 76 77 @Test testCanRequestInteractAcrossProfiles_returnsFalse()78 public void testCanRequestInteractAcrossProfiles_returnsFalse() { 79 assertThat(mCrossProfileApps.canRequestInteractAcrossProfiles()).isFalse(); 80 } 81 82 @Test testCanRequestInteractAcrossProfiles_returnsTrue()83 public void testCanRequestInteractAcrossProfiles_returnsTrue() { 84 assertThat(mCrossProfileApps.canRequestInteractAcrossProfiles()).isTrue(); 85 } 86 87 @Test testCanInteractAcrossProfiles_withAppOpEnabled_returnsTrue()88 public void testCanInteractAcrossProfiles_withAppOpEnabled_returnsTrue() { 89 setAppOpOnAllProfiles(AppOpsManager.MODE_ALLOWED); 90 91 assertThat(mCrossProfileApps.canInteractAcrossProfiles()).isTrue(); 92 } 93 94 @Test testCanInteractAcrossProfiles_withCrossProfilesPermission_returnsTrue()95 public void testCanInteractAcrossProfiles_withCrossProfilesPermission_returnsTrue() { 96 // Ideally we want to grant the permission in the other profile instead of allowing the 97 // appop, however UiAutomation#adoptShellPermission can't be used for multiple UIDs. 98 setAppOpOnAllProfiles(AppOpsManager.MODE_ALLOWED, /* includeCallingProfile= */ false); 99 setAppOpOnCurrentProfile(AppOpsManager.MODE_IGNORED); 100 101 try (PermissionContext p = sTestApis.permissions().withPermission( 102 INTERACT_ACROSS_PROFILES_PERMISSION)) { 103 assertThat(mCrossProfileApps.canInteractAcrossProfiles()).isTrue(); 104 } 105 } 106 107 @Test testCanInteractAcrossProfiles_withCrossUsersPermission_returnsTrue()108 public void testCanInteractAcrossProfiles_withCrossUsersPermission_returnsTrue() { 109 // Ideally we want to grant the permission in the other profile instead of allowing the 110 // appop, however UiAutomation#adoptShellPermission can't be used for multiple UIDs. 111 setAppOpOnAllProfiles(AppOpsManager.MODE_ALLOWED, /* includeCallingProfile= */ false); 112 setAppOpOnCurrentProfile(AppOpsManager.MODE_IGNORED); 113 114 try (PermissionContext p = sTestApis.permissions().withPermission( 115 INTERACT_ACROSS_USERS_PERMISSION)) { 116 assertThat(mCrossProfileApps.canInteractAcrossProfiles()).isTrue(); 117 } 118 } 119 120 @Test testCanInteractAcrossProfiles_withCrossUsersFullPermission_returnsTrue()121 public void testCanInteractAcrossProfiles_withCrossUsersFullPermission_returnsTrue() { 122 // Ideally we want to grant the permission in the other profile instead of allowing the 123 // appop, however UiAutomation#adoptShellPermission can't be used for multiple UIDs. 124 setAppOpOnAllProfiles(AppOpsManager.MODE_ALLOWED, /* includeCallingProfile= */ false); 125 setAppOpOnCurrentProfile(AppOpsManager.MODE_IGNORED); 126 127 try (PermissionContext p = sTestApis.permissions().withPermission( 128 INTERACT_ACROSS_USERS_FULL_PERMISSION)) { 129 assertThat(mCrossProfileApps.canInteractAcrossProfiles()).isTrue(); 130 } 131 } 132 133 @Test testCanInteractAcrossProfiles_withAppOpDisabledOnCallingProfile_returnsFalse()134 public void testCanInteractAcrossProfiles_withAppOpDisabledOnCallingProfile_returnsFalse() { 135 setAppOpOnAllProfiles(AppOpsManager.MODE_ALLOWED, /* includeCallingProfile= */ false); 136 setAppOpOnCurrentProfile(AppOpsManager.MODE_IGNORED); 137 138 assertThat(mCrossProfileApps.canInteractAcrossProfiles()).isFalse(); 139 } 140 141 @Test testCanInteractAcrossProfiles_withAppOpDisabledOnOtherProfiles_returnsFalse()142 public void testCanInteractAcrossProfiles_withAppOpDisabledOnOtherProfiles_returnsFalse() { 143 setAppOpOnAllProfiles(AppOpsManager.MODE_IGNORED, /* includeCallingProfile= */ false); 144 setAppOpOnCurrentProfile(AppOpsManager.MODE_ALLOWED); 145 146 assertThat(mCrossProfileApps.canInteractAcrossProfiles()).isFalse(); 147 } 148 149 @Test testCanInteractAcrossProfiles_withNoOtherProfile_returnsFalse()150 public void testCanInteractAcrossProfiles_withNoOtherProfile_returnsFalse() { 151 setAppOpOnCurrentProfile(AppOpsManager.MODE_ALLOWED); 152 153 assertThat(mCrossProfileApps.canInteractAcrossProfiles()).isFalse(); 154 } 155 156 @Test testCreateRequestInteractAcrossProfilesIntent_canRequestInteraction_returnsIntent()157 public void testCreateRequestInteractAcrossProfilesIntent_canRequestInteraction_returnsIntent() { 158 Intent intent = mCrossProfileApps.createRequestInteractAcrossProfilesIntent(); 159 160 assertThat(intent).isNotNull(); 161 assertThat(intent.getAction()).isEqualTo(ACTION_MANAGE_CROSS_PROFILE_ACCESS); 162 assertThat(intent.getData()).isNotNull(); 163 assertThat(intent.getData().getSchemeSpecificPart()).isEqualTo(mContext.getPackageName()); 164 } 165 166 @Test testCreateRequestInteractAcrossProfilesIntent_canNotRequestInteraction_throwsSecurityException()167 public void testCreateRequestInteractAcrossProfilesIntent_canNotRequestInteraction_throwsSecurityException() { 168 try { 169 mCrossProfileApps.createRequestInteractAcrossProfilesIntent(); 170 } catch (SecurityException e) { 171 return; 172 } 173 fail("Should throw a Security Exception"); 174 } 175 176 /** 177 * Calls {@link CrossProfileApps#createRequestInteractAcrossProfilesIntent()}. This can then be 178 * used by host-side tests. 179 */ 180 @Test testCreateRequestInteractAcrossProfilesIntent_noAsserts()181 public void testCreateRequestInteractAcrossProfilesIntent_noAsserts() { 182 mCrossProfileApps.createRequestInteractAcrossProfilesIntent(); 183 } 184 185 @Test testSetCrossProfilePackages_noAsserts()186 public void testSetCrossProfilePackages_noAsserts() { 187 final DevicePolicyManager devicePolicyManager = 188 (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); 189 devicePolicyManager.setCrossProfilePackages( 190 ADMIN_RECEIVER_COMPONENT, Collections.singleton(getCrossProfilePackage())); 191 } 192 getCrossProfilePackage()193 private String getCrossProfilePackage() { 194 final Bundle testArguments = InstrumentationRegistry.getArguments(); 195 if (testArguments.containsKey(PARAM_CROSS_PROFILE_PACKAGE)) { 196 try { 197 return testArguments.getString(PARAM_CROSS_PROFILE_PACKAGE); 198 } catch (NumberFormatException ignore) { 199 } 200 } 201 fail("cross profile package param not found."); 202 return null; 203 } 204 setAppOpOnCurrentProfile(int mode)205 private void setAppOpOnCurrentProfile(int mode) { 206 try (PermissionContext p = sTestApis.permissions().withPermission( 207 MANAGE_APP_OPS_MODES_PERMISSION)) { 208 mAppOpsManager.setMode(AppOpsManager.OPSTR_INTERACT_ACROSS_PROFILES, 209 Binder.getCallingUid(), mContext.getPackageName(), mode); 210 } 211 } 212 setAppOpOnAllProfiles(int mode)213 private void setAppOpOnAllProfiles(int mode) { 214 setAppOpOnAllProfiles(mode, /* includeCallingProfile= */ true); 215 } 216 setAppOpOnAllProfiles(int mode, boolean includeCallingProfile)217 private void setAppOpOnAllProfiles(int mode, boolean includeCallingProfile) { 218 try (PermissionContext p = sTestApis.permissions().withPermission( 219 MANAGE_APP_OPS_MODES_PERMISSION, INTERACT_ACROSS_USERS_PERMISSION)) { 220 for (UserHandle profile : mContext.getSystemService( 221 UserManager.class).getAllProfiles()) { 222 if (!includeCallingProfile && profile.getIdentifier() == mContext.getUserId()) { 223 continue; 224 } 225 try { 226 final int uid = mContext.createContextAsUser(profile, /* flags= */ 0) 227 .getPackageManager().getPackageUid( 228 mContext.getPackageName(), /* flags= */ 0); 229 mAppOpsManager.setMode(AppOpsManager.OPSTR_INTERACT_ACROSS_PROFILES, 230 uid, mContext.getPackageName(), mode); 231 } catch (PackageManager.NameNotFoundException e) { 232 // Do nothing 233 } 234 } 235 } 236 } 237 } 238