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