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