• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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.server.devicepolicy;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import static org.mockito.ArgumentMatchers.anyBoolean;
22 import static org.mockito.ArgumentMatchers.anyLong;
23 import static org.mockito.ArgumentMatchers.anyString;
24 import static org.mockito.Matchers.anyInt;
25 import static org.mockito.Matchers.eq;
26 import static org.mockito.Mockito.doReturn;
27 import static org.mockito.Mockito.when;
28 
29 import android.annotation.RawRes;
30 import android.app.admin.DevicePolicyManager;
31 import android.content.ComponentName;
32 import android.content.Context;
33 import android.content.Intent;
34 import android.content.pm.ActivityInfo;
35 import android.content.pm.ApplicationInfo;
36 import android.content.pm.PackageInfo;
37 import android.content.pm.PackageManager;
38 import android.content.pm.ResolveInfo;
39 import android.os.UserHandle;
40 
41 import androidx.test.InstrumentationRegistry;
42 
43 import org.junit.Before;
44 
45 import java.io.InputStream;
46 import java.util.List;
47 
48 /**
49  * Temporary copy of DpmTestBase using JUnit 4 - once all tests extend it, it should be renamed
50  * back to DpmTestBase (with the temporary methods removed.
51  *
52  */
53 public abstract class DpmTestBase {
54 
55     public static final String TAG = "DpmTest";
56 
57     protected final Context mRealTestContext = InstrumentationRegistry.getTargetContext();
58     protected DpmMockContext mMockContext;
59     private MockSystemServices mServices;
60 
61     // Attributes below are public so they don't need to be prefixed with m
62     public ComponentName admin1;
63     public ComponentName admin2;
64     public ComponentName admin3;
65     public ComponentName adminAnotherPackage;
66     public ComponentName adminNoPerm;
67     public ComponentName delegateCertInstaller;
68 
69     @Before
setFixtures()70     public void setFixtures() throws Exception {
71         mServices = new MockSystemServices(mRealTestContext, "test-data");
72         mMockContext = new DpmMockContext(mServices, mRealTestContext);
73 
74         admin1 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin1.class);
75         admin2 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin2.class);
76         admin3 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin3.class);
77         adminAnotherPackage = new ComponentName(DpmMockContext.ANOTHER_PACKAGE_NAME,
78                 "whatever.random.class");
79         adminNoPerm = new ComponentName(mRealTestContext, DummyDeviceAdmins.AdminNoPerm.class);
80         delegateCertInstaller = new ComponentName(DpmMockContext.DELEGATE_PACKAGE_NAME,
81                 "some.random.class");
82         mockSystemPropertiesToReturnDefault();
83     }
84 
getContext()85     protected DpmMockContext getContext() {
86         return mMockContext;
87     }
88 
getServices()89     public MockSystemServices getServices() {
90         return mServices;
91     }
92 
sendBroadcastWithUser(DevicePolicyManagerServiceTestable dpms, String action, int userHandle)93     protected void sendBroadcastWithUser(DevicePolicyManagerServiceTestable dpms, String action,
94             int userHandle) throws Exception {
95         final Intent intent = new Intent(action);
96         intent.putExtra(Intent.EXTRA_USER_HANDLE, userHandle);
97         getServices().injectBroadcast(getContext(), intent, userHandle);
98         flushTasks(dpms);
99     }
100 
flushTasks(DevicePolicyManagerServiceTestable dpms)101     protected void flushTasks(DevicePolicyManagerServiceTestable dpms) throws Exception {
102         dpms.mHandler.runWithScissors(() -> { }, 0 /*now*/);
103         dpms.mBackgroundHandler.runWithScissors(() -> { }, 0 /*now*/);
104 
105         // We can't let exceptions happen on the background thread. Throw them here if they happen
106         // so they still cause the test to fail despite being suppressed.
107         getServices().rethrowBackgroundBroadcastExceptions();
108     }
109 
110     protected interface DpmRunnable {
run(DevicePolicyManager dpm)111         void run(DevicePolicyManager dpm) throws Exception;
112     }
113 
114     /**
115      * Simulate an RPC from {@param caller} to the service context ({@link #mMockContext}).
116      *
117      * The caller sees its own context. The server also sees its own separate context, with the
118      * appropriate calling UID and calling permissions fields already set up.
119      */
runAsCaller(DpmMockContext caller, DevicePolicyManagerServiceTestable dpms, DpmRunnable action)120     protected void runAsCaller(DpmMockContext caller, DevicePolicyManagerServiceTestable dpms,
121             DpmRunnable action) {
122         final DpmMockContext serviceContext = mMockContext;
123 
124         // Save calling UID and PID before clearing identity so we don't run into aliasing issues.
125         final int callingUid = caller.binder.callingUid;
126         final int callingPid = caller.binder.callingPid;
127 
128         final long origId = serviceContext.binder.clearCallingIdentity();
129         try {
130             serviceContext.binder.callingUid = callingUid;
131             serviceContext.binder.callingPid = callingPid;
132             serviceContext.binder.callingPermissions.put(callingUid, caller.permissions);
133             action.run(new DevicePolicyManagerTestable(caller, dpms));
134         } catch (Exception e) {
135             throw new AssertionError(e);
136         } finally {
137             serviceContext.binder.restoreCallingIdentity(origId);
138         }
139     }
140 
markPackageAsInstalled(String packageName, ApplicationInfo ai, int userId)141     private void markPackageAsInstalled(String packageName, ApplicationInfo ai, int userId)
142             throws Exception {
143         final PackageInfo pi = DpmTestUtils.cloneParcelable(
144                 mRealTestContext.getPackageManager().getPackageInfo(
145                         mRealTestContext.getPackageName(), 0));
146         assertThat(pi.applicationInfo.flags).isNotEqualTo(0);
147 
148         if (ai != null) {
149             pi.applicationInfo = ai;
150         }
151 
152         doReturn(pi).when(mServices.ipackageManager).getPackageInfo(packageName, 0, userId);
153 
154         doReturn(ai.uid).when(mServices.packageManager).getPackageUidAsUser(packageName, userId);
155     }
156 
markDelegatedCertInstallerAsInstalled()157     protected void markDelegatedCertInstallerAsInstalled() throws Exception {
158         final ApplicationInfo ai = new ApplicationInfo();
159         ai.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
160         ai.flags = ApplicationInfo.FLAG_HAS_CODE;
161         // Mark the package as installed on the work profile.
162         ai.uid = UserHandle.getUid(DpmMockContext.CALLER_USER_HANDLE,
163                 DpmMockContext.DELEGATE_CERT_INSTALLER_UID);
164         ai.packageName = delegateCertInstaller.getPackageName();
165         ai.name = delegateCertInstaller.getClassName();
166 
167         markPackageAsInstalled(delegateCertInstaller.getPackageName(), ai,
168                 DpmMockContext.CALLER_USER_HANDLE);
169     }
170 
setUpPackageManagerForAdmin(ComponentName admin, int packageUid)171     protected void setUpPackageManagerForAdmin(ComponentName admin, int packageUid)
172             throws Exception {
173         setUpPackageManagerForAdmin(admin, packageUid,
174                 /* enabledSetting =*/ null, /* appTargetSdk = */ null);
175     }
176 
setUpPackageManagerForAdmin(ComponentName admin, int packageUid, int enabledSetting)177     protected void setUpPackageManagerForAdmin(ComponentName admin, int packageUid,
178             int enabledSetting) throws Exception {
179         setUpPackageManagerForAdmin(admin, packageUid, enabledSetting, /* appTargetSdk = */ null);
180     }
181 
setUpPackageManagerForAdmin(ComponentName admin, int packageUid, Integer enabledSetting, Integer appTargetSdk)182     protected void setUpPackageManagerForAdmin(ComponentName admin, int packageUid,
183             Integer enabledSetting, Integer appTargetSdk) throws Exception {
184         setUpPackageManagerForFakeAdmin(admin, packageUid, enabledSetting, appTargetSdk,
185                 admin);
186     }
187 
setUpPackageManagerForFakeAdmin(ComponentName admin, int packageUid, ComponentName copyFromAdmin)188     protected void setUpPackageManagerForFakeAdmin(ComponentName admin, int packageUid,
189             ComponentName copyFromAdmin)
190             throws Exception {
191         setUpPackageManagerForFakeAdmin(admin, packageUid,
192                 /* enabledSetting =*/ null, /* appTargetSdk = */ null, copyFromAdmin);
193     }
194 
195     /**
196      * Set up a component in the mock package manager to be an active admin.
197      *
198      * @param admin ComponentName that's visible to the test code, which doesn't have to exist.
199      * @param copyFromAdmin package information for {@code admin} will be built based on this
200      *    component's information.
201      */
setUpPackageManagerForFakeAdmin(ComponentName admin, int packageUid, Integer enabledSetting, Integer appTargetSdk, ComponentName copyFromAdmin)202     protected void setUpPackageManagerForFakeAdmin(ComponentName admin, int packageUid,
203             Integer enabledSetting, Integer appTargetSdk, ComponentName copyFromAdmin)
204             throws Exception {
205 
206         // Set up getApplicationInfo().
207 
208         final ApplicationInfo ai = DpmTestUtils.cloneParcelable(
209                 mRealTestContext.getPackageManager().getApplicationInfo(
210                         copyFromAdmin.getPackageName(),
211                         PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS));
212         ai.enabledSetting = enabledSetting == null
213                 ? PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED
214                 : enabledSetting;
215         if (appTargetSdk != null) {
216             ai.targetSdkVersion = appTargetSdk;
217         }
218         ai.uid = packageUid;
219         ai.packageName = admin.getPackageName();
220         ai.name = admin.getClassName();
221 
222         doReturn(ai).when(mServices.ipackageManager).getApplicationInfo(
223                 eq(admin.getPackageName()),
224                 anyInt(),
225                 eq(UserHandle.getUserId(packageUid)));
226 
227         // Set up queryBroadcastReceivers().
228 
229         final Intent resolveIntent = new Intent();
230         resolveIntent.setComponent(copyFromAdmin);
231         final List<ResolveInfo> realResolveInfo =
232                 mRealTestContext.getPackageManager().queryBroadcastReceivers(
233                         resolveIntent,
234                         PackageManager.GET_META_DATA);
235         assertThat(realResolveInfo).isNotNull();
236         assertThat(realResolveInfo).hasSize(1);
237 
238         // We need to change AI, so set a clone.
239         realResolveInfo.set(0, DpmTestUtils.cloneParcelable(realResolveInfo.get(0)));
240 
241         // We need to rewrite the UID in the activity info.
242         final ActivityInfo aci = realResolveInfo.get(0).activityInfo;
243         aci.applicationInfo = ai;
244         aci.packageName = admin.getPackageName();
245         aci.name = admin.getClassName();
246 
247         // Note we don't set up queryBroadcastReceivers.  We don't use it in DPMS.
248 
249         doReturn(aci).when(mServices.ipackageManager).getReceiverInfo(
250                 eq(admin),
251                 anyInt(),
252                 eq(UserHandle.getUserId(packageUid)));
253 
254         doReturn(new String[] {admin.getPackageName()}).when(mServices.ipackageManager)
255             .getPackagesForUid(eq(packageUid));
256         doReturn(new String[] {admin.getPackageName()}).when(mServices.packageManager)
257                 .getPackagesForUid(eq(packageUid));
258         // Set up getPackageInfo().
259         markPackageAsInstalled(admin.getPackageName(), ai, UserHandle.getUserId(packageUid));
260     }
261 
262     /**
263      * By default, system properties are mocked to return default value. Override the mock if you
264      * want a specific value.
265      */
mockSystemPropertiesToReturnDefault()266     private void mockSystemPropertiesToReturnDefault() {
267         when(getServices().systemProperties.get(
268                 anyString(), anyString())).thenAnswer(
269                 invocation -> invocation.getArguments()[1]
270         );
271 
272         when(getServices().systemProperties.getBoolean(
273                 anyString(), anyBoolean())).thenAnswer(
274                 invocation -> invocation.getArguments()[1]
275         );
276 
277         when(getServices().systemProperties.getLong(
278                 anyString(), anyLong())).thenAnswer(
279                 invocation -> invocation.getArguments()[1]
280         );
281     }
282 
getRawStream(@awRes int id)283     protected InputStream getRawStream(@RawRes int id) {
284         return mRealTestContext.getResources().openRawResource(id);
285     }
286 }
287