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