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.shadows.ShadowProcess;
47 
48 import java.util.Collections;
49 import java.util.Set;
50 
51 @RunWith(RobolectricTestRunner.class)
52 public class CrossProfileAppsPregrantControllerTest {
53 
54     private static final int MY_USER_ID = 0;
55     private static final int OTHER_USER_ID = 5;
56     private static final int OTHER_USER_UID = UserHandle.PER_USER_RANGE * OTHER_USER_ID;
57 
58     private final Context mContext = ApplicationProvider.getApplicationContext();
59     private final UserManager mUserManager = mContext.getSystemService(UserManager.class);
60     private final CrossProfileApps mCrossProfileApps =
61             mContext.getSystemService(CrossProfileApps.class);
62     private final DevicePolicyManager mDevicePolicyManager =
63             mContext.getSystemService(DevicePolicyManager.class);
64     private final CrossProfileAppsSnapshot mCrossProfileAppsSnapshot =
65             new CrossProfileAppsSnapshot(mContext);
66 
67     // TODO(158280372): Remove mocks once suitable shadows are added
68     private final PackageManager mPackageManager = mock(PackageManager.class);
69     private final AppOpsManager mAppOpsManager = mock(AppOpsManager.class);
70 
71     private final CrossProfileAppsPregrantController mPregrantController =
72             new CrossProfileAppsPregrantController(
73                     mContext,
74                     mUserManager,
75                     mPackageManager,
76                     mDevicePolicyManager,
77                     mCrossProfileApps,
78                     mAppOpsManager);
79 
80     private static final String TEST_PACKAGE = "test.package";
81 
82     @Before
setup()83     public void setup() {
84         // This is needed because the cross profile apps shadow doesn't actually set the appop
85         // so we copy the value of the app op into the mock AppOpsManager
86         when(mAppOpsManager.unsafeCheckOpNoThrow(anyString(), anyInt(), anyString()))
87                 .thenAnswer(
88                         invocation ->
89                                 shadowOf(mCrossProfileApps).getInteractAcrossProfilesAppOp(
90                                         invocation.getArgument(2)));
91     }
92 
93     @Test
onPrimaryProfile_noManagedProfile_doesNotPregrant()94     public void onPrimaryProfile_noManagedProfile_doesNotPregrant() {
95         // We default to no managed profile
96         setWhitelistedPackages(Collections.singleton(TEST_PACKAGE));
97         setConfigurablePackages(Collections.singleton(TEST_PACKAGE));
98         mCrossProfileAppsSnapshot.takeNewSnapshot(mContext.getUserId());
99         mCrossProfileApps.setInteractAcrossProfilesAppOp(TEST_PACKAGE, AppOpsManager.MODE_DEFAULT);
100 
101         mPregrantController.checkCrossProfileAppsPermissions();
102 
103         assertThat(shadowOf(mCrossProfileApps)
104                 .getInteractAcrossProfilesAppOp(TEST_PACKAGE))
105                 .isEqualTo(AppOpsManager.MODE_DEFAULT);
106     }
107 
108     @Test
onManagedProfile_doesNotPregrant()109     public void onManagedProfile_doesNotPregrant() {
110         setRunningOnManagedProfile();
111         setWhitelistedPackages(Collections.singleton(TEST_PACKAGE));
112         setConfigurablePackages(Collections.singleton(TEST_PACKAGE));
113         mCrossProfileAppsSnapshot.takeNewSnapshot(mContext.getUserId());
114         mCrossProfileApps.setInteractAcrossProfilesAppOp(TEST_PACKAGE, AppOpsManager.MODE_DEFAULT);
115 
116         mPregrantController.checkCrossProfileAppsPermissions();
117 
118         assertThat(shadowOf(mCrossProfileApps)
119                 .getInteractAcrossProfilesAppOp(TEST_PACKAGE))
120                 .isEqualTo(AppOpsManager.MODE_DEFAULT);
121     }
122 
123     @Test
defaultConfigurablePackage_doesPregrant()124     public void defaultConfigurablePackage_doesPregrant() {
125         setRunningOnParentProfile();
126         setWhitelistedPackages(Collections.singleton(TEST_PACKAGE));
127         setConfigurablePackages(Collections.singleton(TEST_PACKAGE));
128         mCrossProfileAppsSnapshot.takeNewSnapshot(mContext.getUserId());
129         mCrossProfileApps.setInteractAcrossProfilesAppOp(TEST_PACKAGE, AppOpsManager.MODE_DEFAULT);
130 
131         mPregrantController.checkCrossProfileAppsPermissions();
132 
133         assertThat(shadowOf(mCrossProfileApps)
134                 .getInteractAcrossProfilesAppOp(TEST_PACKAGE))
135                 .isEqualTo(AppOpsManager.MODE_ALLOWED);
136     }
137 
138     @Test
nonDefaultConfigurablePackage_doesNotPregrant()139     public void nonDefaultConfigurablePackage_doesNotPregrant() {
140         setRunningOnParentProfile();
141         setWhitelistedPackages(Collections.singleton(TEST_PACKAGE));
142         setConfigurablePackages(Collections.singleton(TEST_PACKAGE));
143         mCrossProfileAppsSnapshot.takeNewSnapshot(mContext.getUserId());
144         mCrossProfileApps.setInteractAcrossProfilesAppOp(TEST_PACKAGE, AppOpsManager.MODE_IGNORED);
145 
146         mPregrantController.checkCrossProfileAppsPermissions();
147 
148         assertThat(shadowOf(mCrossProfileApps)
149                 .getInteractAcrossProfilesAppOp(TEST_PACKAGE))
150                 .isEqualTo(AppOpsManager.MODE_IGNORED);
151     }
152 
setRunningOnParentProfile()153     private void setRunningOnParentProfile() {
154         shadowOf(mUserManager).addProfile(
155                 MY_USER_ID, OTHER_USER_ID, /* profileName= */"otherUser", FLAG_MANAGED_PROFILE);
156     }
157 
setRunningOnManagedProfile()158     private void setRunningOnManagedProfile() {
159         shadowOf(mUserManager).addProfile(
160                 MY_USER_ID, OTHER_USER_ID, /* profileName= */"otherUser", FLAG_MANAGED_PROFILE);
161         ShadowProcess.setUid(OTHER_USER_UID);
162     }
163 
setWhitelistedPackages(Set<String> packages)164     private void setWhitelistedPackages(Set<String> packages) {
165         shadowOf(mDevicePolicyManager).setDefaultCrossProfilePackages(packages);
166     }
167 
setConfigurablePackages(Set<String> packages)168     private void setConfigurablePackages(Set<String> packages) {
169         packages.forEach(p -> shadowOf(mCrossProfileApps).addCrossProfilePackage(p));
170     }
171 }
172