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.managedprovisioning.ota; 18 19 import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE; 20 21 import static org.mockito.ArgumentMatchers.any; 22 import static org.mockito.ArgumentMatchers.anyInt; 23 import static org.mockito.ArgumentMatchers.anyString; 24 import static org.mockito.ArgumentMatchers.eq; 25 import static org.mockito.Mockito.mock; 26 import static org.mockito.Mockito.when; 27 import static org.robolectric.Shadows.shadowOf; 28 29 import static com.google.common.truth.Truth.assertThat; 30 import android.app.AppOpsManager; 31 import android.app.admin.DevicePolicyManager; 32 import android.content.Context; 33 import android.content.pm.CrossProfileApps; 34 import android.content.pm.PackageManager; 35 import android.os.UserHandle; 36 import android.os.UserManager; 37 38 import androidx.test.core.app.ApplicationProvider; 39 40 import com.android.managedprovisioning.task.interactacrossprofiles.CrossProfileAppsSnapshot; 41 42 import org.junit.Before; 43 import org.junit.Test; 44 import org.junit.runner.RunWith; 45 import org.robolectric.RobolectricTestRunner; 46 import org.robolectric.annotation.Config; 47 import org.robolectric.shadow.api.Shadow; 48 import org.robolectric.shadows.ShadowProcess; 49 50 import java.util.Collections; 51 import java.util.Set; 52 53 @RunWith(RobolectricTestRunner.class) 54 @Config(shadows={ExtendsShadowCrossProfileApps.class, ExtendsShadowDevicePolicyManager.class}) 55 public class CrossProfileAppsPregrantControllerTest { 56 57 private static final int MY_USER_ID = 0; 58 private static final int OTHER_USER_ID = 5; 59 private static final int OTHER_USER_UID = UserHandle.PER_USER_RANGE * OTHER_USER_ID; 60 61 private final Context mContext = ApplicationProvider.getApplicationContext(); 62 private final UserManager mUserManager = mContext.getSystemService(UserManager.class); 63 private final CrossProfileApps mCrossProfileApps = 64 mContext.getSystemService(CrossProfileApps.class); 65 private final DevicePolicyManager mDevicePolicyManager = 66 mContext.getSystemService(DevicePolicyManager.class); 67 private final CrossProfileAppsSnapshot mCrossProfileAppsSnapshot = 68 new CrossProfileAppsSnapshot(mContext); 69 70 // TODO(158280372): Remove mocks once suitable shadows are added 71 private final PackageManager mPackageManager = mock(PackageManager.class); 72 private final AppOpsManager mAppOpsManager = mock(AppOpsManager.class); 73 74 private final CrossProfileAppsPregrantController mPregrantController = 75 new CrossProfileAppsPregrantController( 76 mContext, 77 mUserManager, 78 mPackageManager, 79 mDevicePolicyManager, 80 mCrossProfileApps, 81 mAppOpsManager); 82 83 private static final String TEST_PACKAGE = "test.package"; 84 myShadowOf(CrossProfileApps mCrossProfileApps)85 private static ExtendsShadowCrossProfileApps myShadowOf(CrossProfileApps mCrossProfileApps) { 86 return (ExtendsShadowCrossProfileApps) Shadow.extract(mCrossProfileApps); 87 } 88 89 @Before setup()90 public void setup() { 91 // This is needed because the cross profile apps shadow doesn't actually set the appop 92 // so we copy the value of the app op into the mock AppOpsManager 93 when(mAppOpsManager.unsafeCheckOpNoThrow(anyString(), anyInt(), anyString())) 94 .thenAnswer( 95 invocation -> 96 myShadowOf(mCrossProfileApps).getInteractAcrossProfilesAppOp( 97 invocation.getArgument(2))); 98 } 99 100 @Test onPrimaryProfile_noManagedProfile_doesNotPregrant()101 public void onPrimaryProfile_noManagedProfile_doesNotPregrant() { 102 // We default to no managed profile 103 setWhitelistedPackages(Collections.singleton(TEST_PACKAGE)); 104 setConfigurablePackages(Collections.singleton(TEST_PACKAGE)); 105 mCrossProfileAppsSnapshot.takeNewSnapshot(mContext.getUserId()); 106 mCrossProfileApps.setInteractAcrossProfilesAppOp(TEST_PACKAGE, AppOpsManager.MODE_DEFAULT); 107 108 mPregrantController.checkCrossProfileAppsPermissions(); 109 110 assertThat(myShadowOf(mCrossProfileApps) 111 .getInteractAcrossProfilesAppOp(TEST_PACKAGE)) 112 .isEqualTo(AppOpsManager.MODE_DEFAULT); 113 } 114 115 @Test onManagedProfile_doesNotPregrant()116 public void onManagedProfile_doesNotPregrant() { 117 setRunningOnManagedProfile(); 118 setWhitelistedPackages(Collections.singleton(TEST_PACKAGE)); 119 setConfigurablePackages(Collections.singleton(TEST_PACKAGE)); 120 mCrossProfileAppsSnapshot.takeNewSnapshot(mContext.getUserId()); 121 mCrossProfileApps.setInteractAcrossProfilesAppOp(TEST_PACKAGE, AppOpsManager.MODE_DEFAULT); 122 123 mPregrantController.checkCrossProfileAppsPermissions(); 124 125 assertThat(myShadowOf(mCrossProfileApps) 126 .getInteractAcrossProfilesAppOp(TEST_PACKAGE)) 127 .isEqualTo(AppOpsManager.MODE_DEFAULT); 128 } 129 130 @Test defaultConfigurablePackage_doesPregrant()131 public void defaultConfigurablePackage_doesPregrant() { 132 setRunningOnParentProfile(); 133 setWhitelistedPackages(Collections.singleton(TEST_PACKAGE)); 134 setConfigurablePackages(Collections.singleton(TEST_PACKAGE)); 135 mCrossProfileAppsSnapshot.takeNewSnapshot(mContext.getUserId()); 136 mCrossProfileApps.setInteractAcrossProfilesAppOp(TEST_PACKAGE, AppOpsManager.MODE_DEFAULT); 137 138 mPregrantController.checkCrossProfileAppsPermissions(); 139 140 assertThat(myShadowOf(mCrossProfileApps) 141 .getInteractAcrossProfilesAppOp(TEST_PACKAGE)) 142 .isEqualTo(AppOpsManager.MODE_ALLOWED); 143 } 144 145 @Test nonDefaultConfigurablePackage_doesNotPregrant()146 public void nonDefaultConfigurablePackage_doesNotPregrant() { 147 setRunningOnParentProfile(); 148 setWhitelistedPackages(Collections.singleton(TEST_PACKAGE)); 149 setConfigurablePackages(Collections.singleton(TEST_PACKAGE)); 150 mCrossProfileAppsSnapshot.takeNewSnapshot(mContext.getUserId()); 151 mCrossProfileApps.setInteractAcrossProfilesAppOp(TEST_PACKAGE, AppOpsManager.MODE_IGNORED); 152 153 mPregrantController.checkCrossProfileAppsPermissions(); 154 155 assertThat(myShadowOf(mCrossProfileApps) 156 .getInteractAcrossProfilesAppOp(TEST_PACKAGE)) 157 .isEqualTo(AppOpsManager.MODE_IGNORED); 158 } 159 setRunningOnParentProfile()160 private void setRunningOnParentProfile() { 161 shadowOf(mUserManager).addProfile( 162 MY_USER_ID, OTHER_USER_ID, /* profileName= */"otherUser", FLAG_MANAGED_PROFILE); 163 } 164 setRunningOnManagedProfile()165 private void setRunningOnManagedProfile() { 166 shadowOf(mUserManager).addProfile( 167 MY_USER_ID, OTHER_USER_ID, /* profileName= */"otherUser", FLAG_MANAGED_PROFILE); 168 ShadowProcess.setUid(OTHER_USER_UID); 169 } 170 setWhitelistedPackages(Set<String> packages)171 private void setWhitelistedPackages(Set<String> packages) { 172 ((ExtendsShadowDevicePolicyManager) Shadow.extract(mDevicePolicyManager)).setDefaultCrossProfilePackages(packages); 173 } 174 setConfigurablePackages(Set<String> packages)175 private void setConfigurablePackages(Set<String> packages) { 176 packages.forEach(p -> myShadowOf(mCrossProfileApps).addCrossProfilePackage(p)); 177 } 178 } 179