1 /* 2 * Copyright (C) 2017 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 package com.android.server.devicepolicy; 17 18 import static org.mockito.ArgumentMatchers.any; 19 import static org.mockito.ArgumentMatchers.anyInt; 20 import static org.mockito.ArgumentMatchers.eq; 21 import static org.mockito.Mockito.RETURNS_DEEP_STUBS; 22 import static org.mockito.Mockito.mock; 23 import static org.mockito.Mockito.spy; 24 import static org.mockito.Mockito.when; 25 26 import android.accounts.Account; 27 import android.accounts.AccountManager; 28 import android.annotation.NonNull; 29 import android.app.ActivityManagerInternal; 30 import android.app.AlarmManager; 31 import android.app.AppOpsManager; 32 import android.app.IActivityManager; 33 import android.app.IActivityTaskManager; 34 import android.app.NotificationManager; 35 import android.app.admin.DevicePolicyManager; 36 import android.app.backup.IBackupManager; 37 import android.app.role.RoleManager; 38 import android.app.supervision.SupervisionManagerInternal; 39 import android.app.usage.UsageStatsManagerInternal; 40 import android.content.BroadcastReceiver; 41 import android.content.ComponentName; 42 import android.content.ContentValues; 43 import android.content.Context; 44 import android.content.Intent; 45 import android.content.IntentFilter; 46 import android.content.pm.CrossProfileApps; 47 import android.content.pm.IPackageManager; 48 import android.content.pm.PackageManager; 49 import android.content.pm.PackageManagerInternal; 50 import android.content.pm.UserInfo; 51 import android.database.Cursor; 52 import android.hardware.usb.UsbManager; 53 import android.location.LocationManager; 54 import android.media.IAudioService; 55 import android.net.ConnectivityManager; 56 import android.net.IIpConnectivityMetrics; 57 import android.net.Uri; 58 import android.net.VpnManager; 59 import android.net.wifi.WifiManager; 60 import android.os.Binder; 61 import android.os.Handler; 62 import android.os.PowerManager; 63 import android.os.PowerManagerInternal; 64 import android.os.UserHandle; 65 import android.os.UserManager; 66 import android.permission.IPermissionManager; 67 import android.provider.Settings; 68 import android.security.KeyChain; 69 import android.telephony.SubscriptionManager; 70 import android.telephony.TelephonyManager; 71 import android.telephony.euicc.EuiccManager; 72 import android.test.mock.MockContentProvider; 73 import android.test.mock.MockContentResolver; 74 import android.util.ArrayMap; 75 import android.util.Pair; 76 import android.view.IWindowManager; 77 78 import com.android.internal.util.test.FakeSettingsProvider; 79 import com.android.internal.widget.LockPatternUtils; 80 import com.android.internal.widget.LockSettingsInternal; 81 import com.android.server.AlarmManagerInternal; 82 import com.android.server.net.NetworkPolicyManagerInternal; 83 import com.android.server.pdb.PersistentDataBlockManagerInternal; 84 import com.android.server.pm.PackageManagerLocal; 85 import com.android.server.pm.UserManagerInternal; 86 import com.android.server.pm.pkg.PackageState; 87 import com.android.server.pm.pkg.PackageUserState; 88 import com.android.server.wm.ActivityTaskManagerInternal; 89 90 import java.io.File; 91 import java.io.IOException; 92 import java.util.ArrayList; 93 import java.util.List; 94 import java.util.Map; 95 import java.util.concurrent.Executor; 96 import java.util.concurrent.atomic.AtomicReference; 97 98 /** 99 * System services mocks and some other data that are shared by all contexts during the test. 100 */ 101 public class MockSystemServices { 102 public final File systemUserDataDir; 103 public final EnvironmentForMock environment; 104 public final SystemPropertiesForMock systemProperties; 105 public final Executor executor; 106 public final UserManager userManager; 107 public final UserManagerInternal userManagerInternal; 108 public final UsageStatsManagerInternal usageStatsManagerInternal; 109 public final NetworkPolicyManagerInternal networkPolicyManagerInternal; 110 public final PackageManagerInternal packageManagerInternal; 111 public final PackageManagerLocal packageManagerLocal; 112 public final UserManagerForMock userManagerForMock; 113 public final PowerManagerForMock powerManager; 114 public final PowerManagerInternal powerManagerInternal; 115 public final RecoverySystemForMock recoverySystem; 116 public final NotificationManager notificationManager; 117 public final IIpConnectivityMetrics iipConnectivityMetrics; 118 public final IWindowManager iwindowManager; 119 public final IActivityManager iactivityManager; 120 public final IActivityTaskManager iactivityTaskManager; 121 public ActivityManagerInternal activityManagerInternal; 122 public ActivityTaskManagerInternal activityTaskManagerInternal; 123 public final IPackageManager ipackageManager; 124 public final IPermissionManager ipermissionManager; 125 public final IBackupManager ibackupManager; 126 public final IAudioService iaudioService; 127 public final LockPatternUtils lockPatternUtils; 128 public final LockSettingsInternal lockSettingsInternal; 129 public final StorageManagerForMock storageManager; 130 public final WifiManager wifiManager; 131 public final SettingsForMock settings; 132 public final MockContentResolver contentResolver; 133 public final TelephonyManager telephonyManager; 134 public final ConnectivityManager connectivityManager; 135 public final AccountManager accountManager; 136 public final AlarmManager alarmManager; 137 public final AlarmManagerInternal alarmManagerInternal; 138 public final KeyChain.KeyChainConnection keyChainConnection; 139 public final CrossProfileApps crossProfileApps; 140 public final PersistentDataBlockManagerInternal persistentDataBlockManagerInternal; 141 public final AppOpsManager appOpsManager; 142 public final UsbManager usbManager; 143 public final VpnManager vpnManager; 144 public final DevicePolicyManager devicePolicyManager; 145 public final LocationManager locationManager; 146 public final RoleManager roleManager; 147 public final RoleManagerForMock roleManagerForMock; 148 public final SubscriptionManager subscriptionManager; 149 /** Note this is a partial mock, not a real mock. */ 150 public final PackageManager packageManager; 151 public final BuildMock buildMock = new BuildMock(); 152 public final File dataDir; 153 public final PolicyPathProvider pathProvider; 154 public final SupervisionManagerInternal supervisionManagerInternal; 155 public final EuiccManager euiccManager; 156 157 private final Map<String, PackageState> mTestPackageStates = new ArrayMap<>(); 158 MockSystemServices(Context realContext, String name, @NonNull DpmMockContext.MockBinder mockBinder)159 public MockSystemServices(Context realContext, String name, 160 @NonNull DpmMockContext.MockBinder mockBinder) { 161 dataDir = new File(realContext.getCacheDir(), name); 162 DpmTestUtils.clearDir(dataDir); 163 164 environment = mock(EnvironmentForMock.class); 165 systemProperties = mock(SystemPropertiesForMock.class); 166 executor = mock(Executor.class); 167 userManager = mock(UserManager.class); 168 userManagerInternal = mock(UserManagerInternal.class); 169 usageStatsManagerInternal = mock(UsageStatsManagerInternal.class); 170 networkPolicyManagerInternal = mock(NetworkPolicyManagerInternal.class); 171 172 userManagerForMock = mock(UserManagerForMock.class); 173 packageManagerInternal = mock(PackageManagerInternal.class); 174 packageManagerLocal = mock(PackageManagerLocal.class); 175 powerManager = mock(PowerManagerForMock.class); 176 powerManagerInternal = mock(PowerManagerInternal.class); 177 recoverySystem = mock(RecoverySystemForMock.class); 178 notificationManager = mock(NotificationManager.class); 179 iipConnectivityMetrics = mock(IIpConnectivityMetrics.class); 180 iwindowManager = mock(IWindowManager.class); 181 iactivityManager = mock(IActivityManager.class); 182 iactivityTaskManager = mock(IActivityTaskManager.class); 183 activityManagerInternal = mock(ActivityManagerInternal.class); 184 activityTaskManagerInternal = mock(ActivityTaskManagerInternal.class); 185 ipackageManager = mock(IPackageManager.class); 186 ipermissionManager = mock(IPermissionManager.class); 187 ibackupManager = mock(IBackupManager.class); 188 iaudioService = mock(IAudioService.class); 189 lockPatternUtils = mock(LockPatternUtils.class); 190 lockSettingsInternal = mock(LockSettingsInternal.class); 191 storageManager = mock(StorageManagerForMock.class); 192 wifiManager = mock(WifiManager.class); 193 settings = mock(SettingsForMock.class); 194 telephonyManager = mock(TelephonyManager.class); 195 connectivityManager = mock(ConnectivityManager.class); 196 accountManager = mock(AccountManager.class); 197 alarmManager = mock(AlarmManager.class); 198 alarmManagerInternal = mock(AlarmManagerInternal.class); 199 keyChainConnection = mock(KeyChain.KeyChainConnection.class, RETURNS_DEEP_STUBS); 200 crossProfileApps = mock(CrossProfileApps.class); 201 persistentDataBlockManagerInternal = mock(PersistentDataBlockManagerInternal.class); 202 appOpsManager = mock(AppOpsManager.class); 203 usbManager = mock(UsbManager.class); 204 vpnManager = mock(VpnManager.class); 205 devicePolicyManager = mock(DevicePolicyManager.class); 206 locationManager = mock(LocationManager.class); 207 roleManager = realContext.getSystemService(RoleManager.class); 208 roleManagerForMock = mock(RoleManagerForMock.class); 209 subscriptionManager = mock(SubscriptionManager.class); 210 supervisionManagerInternal = mock(SupervisionManagerInternal.class); 211 euiccManager = mock(EuiccManager.class); 212 213 // Package manager is huge, so we use a partial mock instead. 214 packageManager = spy(realContext.getPackageManager()); 215 when(packageManagerInternal.getSystemUiServiceComponent()).thenReturn( 216 new ComponentName("com.android.systemui", ".Service")); 217 218 addTestPackageUid("android", DpmMockContext.SYSTEM_UID); 219 addTestPackageUid(realContext.getPackageName(), Binder.getCallingUid()); 220 when(packageManagerLocal.withUnfilteredSnapshot()).thenAnswer(unused -> { 221 var snapshot = mock(PackageManagerLocal.UnfilteredSnapshot.class); 222 when(snapshot.getPackageStates()).thenAnswer(unused1 -> mTestPackageStates); 223 return snapshot; 224 }); 225 226 contentResolver = new MockContentResolver(); 227 contentResolver.addProvider("telephony", new MockContentProvider(realContext) { 228 @Override 229 public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 230 return 0; 231 } 232 233 @Override 234 public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 235 String sortOrder) { 236 return null; 237 } 238 239 @Override 240 public int delete(Uri uri, String selection, String[] selectionArgs) { 241 return 0; 242 } 243 }); 244 contentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); 245 246 // Add the system user with a fake profile group already set up (this can happen in the real 247 // world if a managed profile is added and then removed). 248 systemUserDataDir = addUser(UserHandle.USER_SYSTEM, 249 UserInfo.FLAG_PRIMARY | UserInfo.FLAG_MAIN, 250 UserManager.USER_TYPE_FULL_SYSTEM, UserHandle.USER_SYSTEM); 251 when(userManager.getMainUser()).thenReturn(UserHandle.SYSTEM); 252 253 // System user is always running. 254 setUserRunning(UserHandle.USER_SYSTEM, true); 255 pathProvider = new PolicyPathProvider() { 256 @Override 257 public File getDataSystemDirectory() { 258 return new File(systemUserDataDir.getAbsolutePath()); 259 } 260 261 @Override 262 public File getUserSystemDirectory(int userId) { 263 return environment.getUserSystemDirectory(userId); 264 } 265 }; 266 } 267 268 /** Optional mapping of other user contexts for {@link #createPackageContextAsUser} to return */ 269 private final Map<Pair<UserHandle, String>, Context> userPackageContexts = new ArrayMap<>(); 270 271 private final ArrayList<UserInfo> mUserInfos = new ArrayList<>(); 272 273 private final List<BroadcastReceiverRegistration> mBroadcastReceivers = new ArrayList<>(); 274 registerReceiver( BroadcastReceiver receiver, IntentFilter filter, Handler scheduler)275 public void registerReceiver( 276 BroadcastReceiver receiver, IntentFilter filter, Handler scheduler) { 277 mBroadcastReceivers.add(new BroadcastReceiverRegistration(receiver, filter, scheduler)); 278 } 279 unregisterReceiver(BroadcastReceiver receiver)280 public void unregisterReceiver(BroadcastReceiver receiver) { 281 mBroadcastReceivers.removeIf(r -> r.receiver == receiver); 282 } 283 addUser(int userId, int flags, String type)284 public File addUser(int userId, int flags, String type) { 285 return addUser(userId, flags, type, UserInfo.NO_PROFILE_GROUP_ID); 286 } 287 addUser(int userId, int flags, String type, int profileGroupId)288 public File addUser(int userId, int flags, String type, int profileGroupId) { 289 // Set up (default) UserInfo for CALLER_USER_HANDLE. 290 final UserInfo uh = new UserInfo(userId, "user" + userId, flags); 291 292 uh.userType = type; 293 uh.profileGroupId = profileGroupId; 294 when(userManager.getUserInfo(eq(userId))).thenReturn(uh); 295 // Ensure there are no duplicate UserInfo records. 296 // TODO: fix tests so that this is not needed. 297 for (int i = 0; i < mUserInfos.size(); i++) { 298 if (mUserInfos.get(i).id == userId) { 299 mUserInfos.remove(i); 300 break; 301 } 302 } 303 mUserInfos.add(uh); 304 when(userManager.getUsers()).thenReturn(mUserInfos); 305 when(userManager.getAliveUsers()).thenReturn(mUserInfos); 306 when(userManager.isUserRunning(eq(new UserHandle(userId)))).thenReturn(true); 307 when(userManager.getProfileParent(anyInt())).thenAnswer( 308 invocation -> { 309 final int userId1 = (int) invocation.getArguments()[0]; 310 final UserInfo ui = getUserInfo(userId1); 311 return ui == null ? null : getUserInfo(ui.profileGroupId); 312 } 313 ); 314 when(userManager.getProfileParent(any(UserHandle.class))).thenAnswer( 315 invocation -> { 316 final UserHandle userHandle = (UserHandle) invocation.getArguments()[0]; 317 final UserInfo ui = getUserInfo(userHandle.getIdentifier()); 318 return ui == null ? UserHandle.USER_NULL : UserHandle.of(ui.profileGroupId); 319 } 320 ); 321 when(userManager.getProfiles(anyInt())).thenAnswer( 322 invocation -> { 323 final int userId12 = (int) invocation.getArguments()[0]; 324 return getProfiles(userId12); 325 } 326 ); 327 when(userManager.getProfileIdsWithDisabled(anyInt())).thenAnswer( 328 invocation -> { 329 final int userId13 = (int) invocation.getArguments()[0]; 330 List<UserInfo> profiles = getProfiles(userId13); 331 return profiles.stream() 332 .mapToInt(profile -> profile.id) 333 .toArray(); 334 } 335 ); 336 when(userManagerInternal.getUserInfos()).thenReturn( 337 mUserInfos.toArray(new UserInfo[mUserInfos.size()])); 338 339 when(accountManager.getAccountsAsUser(anyInt())).thenReturn(new Account[0]); 340 341 // Create a data directory. 342 final File dir = new File(dataDir, "users/" + userId); 343 DpmTestUtils.clearDir(dir); 344 345 when(environment.getUserSystemDirectory(eq(userId))).thenReturn(dir); 346 return dir; 347 } 348 removeUser(int userId)349 public void removeUser(int userId) { 350 for (int i = 0; i < mUserInfos.size(); i++) { 351 if (mUserInfos.get(i).id == userId) { 352 mUserInfos.remove(i); 353 break; 354 } 355 } 356 when(userManager.getUserInfo(eq(userId))).thenReturn(null); 357 358 when(userManager.isUserRunning(eq(new UserHandle(userId)))).thenReturn(false); 359 } 360 getUserInfo(int userId)361 private UserInfo getUserInfo(int userId) { 362 for (final UserInfo ui : mUserInfos) { 363 if (ui.id == userId) { 364 return ui; 365 } 366 } 367 return null; 368 } 369 getProfiles(int userId)370 private List<UserInfo> getProfiles(int userId) { 371 final ArrayList<UserInfo> ret = new ArrayList<>(); 372 UserInfo parent = null; 373 for (final UserInfo ui : mUserInfos) { 374 if (ui.id == userId) { 375 parent = ui; 376 break; 377 } 378 } 379 if (parent == null) { 380 return ret; 381 } 382 for (final UserInfo ui : mUserInfos) { 383 if (ui == parent 384 || ui.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID 385 && ui.profileGroupId == parent.profileGroupId) { 386 ret.add(ui); 387 } 388 } 389 return ret; 390 } 391 392 /** 393 * Add multiple users at once. They'll all have flag 0. 394 */ addUsers(int... userIds)395 public void addUsers(int... userIds) { 396 for (final int userId : userIds) { 397 addUser(userId, 0, ""); 398 } 399 } 400 setUserRunning(int userId, boolean isRunning)401 public void setUserRunning(int userId, boolean isRunning) { 402 when(userManager.isUserRunning(MockUtils.checkUserHandle(userId))) 403 .thenReturn(isRunning); 404 } 405 injectBroadcast(Context context, final Intent intent, int userId)406 public void injectBroadcast(Context context, final Intent intent, int userId) { 407 //final int userId = UserHandle.getUserId(binder.getCallingUid()); 408 for (final BroadcastReceiverRegistration receiver : mBroadcastReceivers) { 409 receiver.sendBroadcastIfApplicable(context, userId, intent); 410 } 411 } 412 rethrowBackgroundBroadcastExceptions()413 public void rethrowBackgroundBroadcastExceptions() throws Exception { 414 for (final BroadcastReceiverRegistration receiver : mBroadcastReceivers) { 415 final Exception e = receiver.backgroundException.getAndSet(null); 416 if (e != null) { 417 throw e; 418 } 419 } 420 } 421 addPackageContext(UserHandle user, Context context)422 public void addPackageContext(UserHandle user, Context context) { 423 if (context.getPackageName() == null) { 424 throw new NullPointerException("getPackageName() == null"); 425 } 426 userPackageContexts.put(new Pair<>(user, context.getPackageName()), context); 427 } 428 createPackageContextAsUser(String packageName, int flags, UserHandle user)429 public Context createPackageContextAsUser(String packageName, int flags, UserHandle user) 430 throws PackageManager.NameNotFoundException { 431 final Pair<UserHandle, String> key = new Pair<>(user, packageName); 432 if (userPackageContexts.containsKey(key)) { 433 return userPackageContexts.get(key); 434 } 435 throw new UnsupportedOperationException("No package " + packageName + " for user " + user); 436 } 437 addTestPackageUid(@onNull String packageName, int uid)438 public void addTestPackageUid(@NonNull String packageName, int uid) { 439 var packageState = mock(PackageState.class); 440 when(packageState.getAppId()).thenReturn(UserHandle.getAppId(uid)); 441 when(packageState.getUserStateOrDefault(anyInt())).thenAnswer(invocation -> { 442 var userState = mock(PackageUserState.class); 443 when(userState.isInstalled()).thenReturn(true); 444 return userState; 445 }); 446 mTestPackageStates.put(packageName, packageState); 447 } 448 449 public static class EnvironmentForMock { getUserSystemDirectory(int userId)450 public File getUserSystemDirectory(int userId) { 451 return null; 452 } 453 } 454 455 public static class BuildMock { 456 public boolean isDebuggable = true; 457 } 458 459 public static class PowerManagerForMock { newWakeLock(int levelAndFlags, String tag)460 public PowerManager.WakeLock newWakeLock(int levelAndFlags, String tag) { 461 return null; 462 } 463 goToSleep(long time, int reason, int flags)464 public void goToSleep(long time, int reason, int flags) { 465 } 466 reboot(String reason)467 public void reboot(String reason) { 468 } 469 } 470 471 public static class RecoverySystemForMock { rebootWipeUserData(boolean shutdown, String reason, boolean force, boolean wipeEuicc, boolean wipeExtRequested, boolean wipeResetProtectionData)472 public boolean rebootWipeUserData(boolean shutdown, String reason, boolean force, 473 boolean wipeEuicc, boolean wipeExtRequested, boolean wipeResetProtectionData) 474 throws IOException { 475 return false; 476 } 477 } 478 479 public static class SystemPropertiesForMock { getBoolean(String key, boolean def)480 public boolean getBoolean(String key, boolean def) { 481 return false; 482 } 483 getLong(String key, long def)484 public long getLong(String key, long def) { 485 return 0; 486 } 487 get(String key, String def)488 public String get(String key, String def) { 489 return null; 490 } 491 get(String key)492 public String get(String key) { 493 return null; 494 } 495 set(String key, String value)496 public void set(String key, String value) { 497 } 498 } 499 500 public static class UserManagerForMock { isHeadlessSystemUserMode()501 public boolean isHeadlessSystemUserMode() { 502 return false; 503 } 504 } 505 506 public static class RoleManagerForMock { getRoleHoldersAsUser(String role, UserHandle userHandle)507 public List<String> getRoleHoldersAsUser(String role, UserHandle userHandle) { 508 return new ArrayList<>(); 509 } 510 } 511 512 public static class SettingsForMock { settingsSecureGetIntForUser(String name, int def, int userHandle)513 public int settingsSecureGetIntForUser(String name, int def, int userHandle) { 514 return 0; 515 } 516 settingsSecureGetStringForUser(String name, int userHandle)517 public String settingsSecureGetStringForUser(String name, int userHandle) { 518 return null; 519 } 520 settingsSecurePutIntForUser(String name, int value, int userHandle)521 public void settingsSecurePutIntForUser(String name, int value, int userHandle) { 522 } 523 settingsSecurePutStringForUser(String name, String value, int userHandle)524 public void settingsSecurePutStringForUser(String name, String value, int userHandle) { 525 } 526 settingsGlobalPutStringForUser(String name, String value, int userHandle)527 public void settingsGlobalPutStringForUser(String name, String value, int userHandle) { 528 } 529 settingsSecurePutInt(String name, int value)530 public void settingsSecurePutInt(String name, int value) { 531 } 532 settingsGlobalPutInt(String name, int value)533 public void settingsGlobalPutInt(String name, int value) { 534 } 535 settingsSecurePutString(String name, String value)536 public void settingsSecurePutString(String name, String value) { 537 } 538 settingsGlobalPutString(String name, String value)539 public void settingsGlobalPutString(String name, String value) { 540 } 541 settingsSystemPutStringForUser(String name, String value, int callingUserId)542 public void settingsSystemPutStringForUser(String name, String value, int callingUserId) { 543 } 544 settingsGlobalGetInt(String name, int value)545 public int settingsGlobalGetInt(String name, int value) { 546 return 0; 547 } 548 settingsGlobalGetString(String name)549 public String settingsGlobalGetString(String name) { 550 return ""; 551 } 552 securityLogSetLoggingEnabledProperty(boolean enabled)553 public void securityLogSetLoggingEnabledProperty(boolean enabled) { 554 } 555 securityLogGetLoggingEnabledProperty()556 public boolean securityLogGetLoggingEnabledProperty() { 557 return false; 558 } 559 securityLogIsLoggingEnabled()560 public boolean securityLogIsLoggingEnabled() { 561 return false; 562 } 563 } 564 565 public static class StorageManagerForMock { isFileBasedEncryptionEnabled()566 public boolean isFileBasedEncryptionEnabled() { 567 return false; 568 } 569 } 570 571 // We have to keep track of broadcast receivers registered for a given intent ourselves as the 572 // DPM unit tests mock out the package manager and PackageManager.queryBroadcastReceivers() does 573 // not work. 574 private static class BroadcastReceiverRegistration { 575 public final BroadcastReceiver receiver; 576 public final IntentFilter filter; 577 public final Handler scheduler; 578 579 // Exceptions thrown in a background thread kill the whole test. Save them instead. 580 public final AtomicReference<Exception> backgroundException = new AtomicReference<>(); 581 BroadcastReceiverRegistration(BroadcastReceiver receiver, IntentFilter filter, Handler scheduler)582 public BroadcastReceiverRegistration(BroadcastReceiver receiver, IntentFilter filter, 583 Handler scheduler) { 584 this.receiver = receiver; 585 this.filter = filter; 586 this.scheduler = scheduler; 587 } 588 sendBroadcastIfApplicable(Context context, int userId, Intent intent)589 public void sendBroadcastIfApplicable(Context context, int userId, Intent intent) { 590 final BroadcastReceiver.PendingResult result = new BroadcastReceiver.PendingResult( 591 0 /* resultCode */, null /* resultData */, null /* resultExtras */, 592 0 /* type */, false /* ordered */, false /* sticky */, null /* token */, userId, 593 0 /* flags */); 594 if (filter.match(null, intent, false, "DpmMockContext") > 0) { 595 final Runnable send = () -> { 596 receiver.setPendingResult(result); 597 receiver.onReceive(context, intent); 598 }; 599 if (scheduler != null) { 600 scheduler.post(() -> { 601 try { 602 send.run(); 603 } catch (Exception e) { 604 backgroundException.compareAndSet(null, e); 605 } 606 }); 607 } else { 608 send.run(); 609 } 610 } 611 } 612 } 613 } 614