• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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