1 /*
2  * Copyright (C) 2016 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 android.multiuser;
17 
18 import static org.junit.Assume.assumeTrue;
19 
20 import android.annotation.NonNull;
21 import android.app.ActivityManager;
22 import android.app.ActivityTaskManager;
23 import android.app.AppGlobals;
24 import android.app.IActivityManager;
25 import android.app.IStopUserCallback;
26 import android.app.UserSwitchObserver;
27 import android.app.WaitResult;
28 import android.content.BroadcastReceiver;
29 import android.content.Context;
30 import android.content.IIntentReceiver;
31 import android.content.IIntentSender;
32 import android.content.Intent;
33 import android.content.IntentFilter;
34 import android.content.IntentSender;
35 import android.content.pm.IPackageInstaller;
36 import android.content.pm.PackageManager;
37 import android.content.pm.UserInfo;
38 import android.os.Bundle;
39 import android.os.IBinder;
40 import android.os.IProgressListener;
41 import android.os.RemoteException;
42 import android.os.SystemClock;
43 import android.os.SystemProperties;
44 import android.os.UserHandle;
45 import android.os.UserManager;
46 import android.perftests.utils.ShellHelper;
47 import android.util.Log;
48 import android.view.WindowManagerGlobal;
49 
50 import androidx.test.InstrumentationRegistry;
51 import androidx.test.filters.LargeTest;
52 import androidx.test.runner.AndroidJUnit4;
53 
54 import org.junit.After;
55 import org.junit.Before;
56 import org.junit.Rule;
57 import org.junit.Test;
58 import org.junit.runner.RunWith;
59 
60 import java.util.ArrayList;
61 import java.util.concurrent.CountDownLatch;
62 import java.util.concurrent.TimeUnit;
63 
64 /**
65  * Perf tests for user life cycle events.
66  *
67  * To run the tests: atest UserLifecycleTests
68  *
69  *
70  * Old methods for running the tests:
71  *
72  * make MultiUserPerfTests &&
73  * adb install -r \
74  *     ${ANDROID_PRODUCT_OUT}/data/app/MultiUserPerfTests/MultiUserPerfTests.apk &&
75  * adb shell am instrument -e class android.multiuser.UserLifecycleTests \
76  *     -w com.android.perftests.multiuser/androidx.test.runner.AndroidJUnitRunner
77  *
78  * or
79  *
80  * bit MultiUserPerfTests:android.multiuser.UserLifecycleTests
81  *
82  * Note: If you use bit for running the tests, benchmark results won't be printed on the host side.
83  * But in either case, results can be checked on the device side 'adb logcat -s UserLifecycleTests'
84  */
85 @LargeTest
86 @RunWith(AndroidJUnit4.class)
87 public class UserLifecycleTests {
88     private static final String TAG = UserLifecycleTests.class.getSimpleName();
89 
90     private static final int TIMEOUT_IN_SECOND = 30;
91     private static final int CHECK_USER_REMOVED_INTERVAL_MS = 200;
92 
93     /** Name of users/profiles in the test. Users with this name may be freely removed. */
94     private static final String TEST_USER_NAME = "UserLifecycleTests_test_user";
95 
96     /** Name of dummy package used when timing how long app launches take. */
97     private static final String DUMMY_PACKAGE_NAME = "perftests.multiuser.apps.dummyapp";
98 
99     // Copy of UserSystemPackageInstaller whitelist mode constants.
100     private static final String PACKAGE_WHITELIST_MODE_PROP =
101             "persist.debug.user.package_whitelist_mode";
102     private static final int USER_TYPE_PACKAGE_WHITELIST_MODE_DISABLE = 0;
103     private static final int USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE = 0b001;
104     private static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST = 0b100;
105     private static final int USER_TYPE_PACKAGE_WHITELIST_MODE_DEVICE_DEFAULT = -1;
106 
107     private UserManager mUm;
108     private ActivityManager mAm;
109     private IActivityManager mIam;
110     private PackageManager mPm;
111     private ArrayList<Integer> mUsersToRemove;
112     private boolean mHasManagedUserFeature;
113 
114     private final BenchmarkRunner mRunner = new BenchmarkRunner();
115     @Rule
116     public BenchmarkResultsReporter mReporter = new BenchmarkResultsReporter(mRunner);
117 
118     @Before
setUp()119     public void setUp() {
120         final Context context = InstrumentationRegistry.getContext();
121         mUm = UserManager.get(context);
122         mAm = context.getSystemService(ActivityManager.class);
123         mIam = ActivityManager.getService();
124         mUsersToRemove = new ArrayList<>();
125         mPm = context.getPackageManager();
126         mHasManagedUserFeature = mPm.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS);
127         removeAnyPreviousTestUsers();
128         if (mAm.getCurrentUser() != UserHandle.USER_SYSTEM) {
129             Log.w(TAG, "WARNING: Tests are being run from user " + mAm.getCurrentUser()
130                     + " rather than the system user");
131         }
132     }
133 
134     @After
tearDown()135     public void tearDown() {
136         for (int userId : mUsersToRemove) {
137             try {
138                 mUm.removeUser(userId);
139             } catch (Exception e) {
140                 // Ignore
141             }
142         }
143     }
144 
145     @Test
createUser()146     public void createUser() {
147         while (mRunner.keepRunning()) {
148             final int userId = createUserNoFlags();
149 
150             mRunner.pauseTiming();
151             removeUser(userId);
152             mRunner.resumeTiming();
153         }
154     }
155 
156     @Test
createAndStartUser()157     public void createAndStartUser() throws RemoteException {
158         while (mRunner.keepRunning()) {
159             final int userId = createUserNoFlags();
160 
161             final CountDownLatch latch = new CountDownLatch(1);
162             registerBroadcastReceiver(Intent.ACTION_USER_STARTED, latch, userId);
163             // Don't use this.startUserInBackgroundAndWaitForUnlock() since only waiting until
164             // ACTION_USER_STARTED.
165             mIam.startUserInBackground(userId);
166             waitForLatch("Failed to achieve ACTION_USER_STARTED for user " + userId, latch);
167 
168             mRunner.pauseTiming();
169             removeUser(userId);
170             mRunner.resumeTiming();
171         }
172     }
173 
174     /**
175      * Measures the time until ACTION_USER_STARTED is received.
176      */
177     @Test
startUser()178     public void startUser() throws RemoteException {
179         while (mRunner.keepRunning()) {
180             mRunner.pauseTiming();
181             final int userId = createUserNoFlags();
182             final CountDownLatch latch = new CountDownLatch(1);
183             registerBroadcastReceiver(Intent.ACTION_USER_STARTED, latch, userId);
184             mRunner.resumeTiming();
185 
186             mIam.startUserInBackground(userId);
187             waitForLatch("Failed to achieve ACTION_USER_STARTED for user " + userId, latch);
188 
189             mRunner.pauseTiming();
190             removeUser(userId);
191             mRunner.resumeTiming();
192         }
193     }
194 
195     /**
196      * Measures the time until unlock listener is triggered and user is unlocked.
197      */
198     @Test
startAndUnlockUser()199     public void startAndUnlockUser() {
200         while (mRunner.keepRunning()) {
201             mRunner.pauseTiming();
202             final int userId = createUserNoFlags();
203             mRunner.resumeTiming();
204 
205             // Waits for UserState.mUnlockProgress.finish().
206             startUserInBackgroundAndWaitForUnlock(userId);
207 
208             mRunner.pauseTiming();
209             removeUser(userId);
210             mRunner.resumeTiming();
211         }
212     }
213 
214     @Test
switchUser()215     public void switchUser() throws RemoteException {
216         while (mRunner.keepRunning()) {
217             mRunner.pauseTiming();
218             final int startUser = mAm.getCurrentUser();
219             final int userId = createUserNoFlags();
220             mRunner.resumeTiming();
221 
222             switchUser(userId);
223 
224             mRunner.pauseTiming();
225             switchUserNoCheck(startUser);
226             removeUser(userId);
227             mRunner.resumeTiming();
228         }
229     }
230 
231     /** Tests switching to an already-created, but no-longer-running, user. */
232     @Test
switchUser_stopped()233     public void switchUser_stopped() throws RemoteException {
234         while (mRunner.keepRunning()) {
235             mRunner.pauseTiming();
236             final int startUser = mAm.getCurrentUser();
237             final int testUser = initializeNewUserAndSwitchBack(/* stopNewUser */ true);
238             final CountDownLatch latch = new CountDownLatch(1);
239             registerBroadcastReceiver(Intent.ACTION_USER_UNLOCKED, latch, testUser);
240             mRunner.resumeTiming();
241 
242             mAm.switchUser(testUser);
243             waitForLatch("Failed to achieve 2nd ACTION_USER_UNLOCKED for user " + testUser, latch);
244 
245 
246             mRunner.pauseTiming();
247             switchUserNoCheck(startUser);
248             removeUser(testUser);
249             mRunner.resumeTiming();
250         }
251     }
252 
253     /** Tests switching to an already-created already-running non-owner user. */
254     @Test
switchUser_running()255     public void switchUser_running() throws RemoteException {
256         while (mRunner.keepRunning()) {
257             mRunner.pauseTiming();
258             final int startUser = mAm.getCurrentUser();
259             final int testUser = initializeNewUserAndSwitchBack(/* stopNewUser */ false);
260             mRunner.resumeTiming();
261 
262             switchUser(testUser);
263 
264             mRunner.pauseTiming();
265             switchUserNoCheck(startUser);
266             removeUser(testUser);
267             mRunner.resumeTiming();
268         }
269     }
270 
271     @Test
stopUser()272     public void stopUser() throws RemoteException {
273         while (mRunner.keepRunning()) {
274             mRunner.pauseTiming();
275             final int userId = createUserNoFlags();
276             final CountDownLatch latch = new CountDownLatch(1);
277             registerBroadcastReceiver(Intent.ACTION_USER_STARTED, latch, userId);
278             mIam.startUserInBackground(userId);
279             waitForLatch("Failed to achieve ACTION_USER_STARTED for user " + userId, latch);
280             mRunner.resumeTiming();
281 
282             stopUser(userId, false);
283 
284             mRunner.pauseTiming();
285             removeUser(userId);
286             mRunner.resumeTiming();
287         }
288     }
289 
290     @Test
lockedBootCompleted()291     public void lockedBootCompleted() throws RemoteException {
292         while (mRunner.keepRunning()) {
293             mRunner.pauseTiming();
294             final int startUser = mAm.getCurrentUser();
295             final int userId = createUserNoFlags();
296             final CountDownLatch latch = new CountDownLatch(1);
297             registerUserSwitchObserver(null, latch, userId);
298             mRunner.resumeTiming();
299 
300             mAm.switchUser(userId);
301             waitForLatch("Failed to achieve onLockedBootComplete for user " + userId, latch);
302 
303             mRunner.pauseTiming();
304             switchUserNoCheck(startUser);
305             removeUser(userId);
306             mRunner.resumeTiming();
307         }
308     }
309 
310     @Test
ephemeralUserStopped()311     public void ephemeralUserStopped() throws RemoteException {
312         while (mRunner.keepRunning()) {
313             mRunner.pauseTiming();
314             final int startUser = mAm.getCurrentUser();
315             final int userId = createUserWithFlags(UserInfo.FLAG_EPHEMERAL | UserInfo.FLAG_DEMO);
316             switchUser(userId);
317             final CountDownLatch latch = new CountDownLatch(1);
318             InstrumentationRegistry.getContext().registerReceiver(new BroadcastReceiver() {
319                 @Override
320                 public void onReceive(Context context, Intent intent) {
321                     if (Intent.ACTION_USER_STOPPED.equals(intent.getAction()) && intent.getIntExtra(
322                             Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL) == userId) {
323                         latch.countDown();
324                     }
325                 }
326             }, new IntentFilter(Intent.ACTION_USER_STOPPED));
327             final CountDownLatch switchLatch = new CountDownLatch(1);
328             registerUserSwitchObserver(switchLatch, null, startUser);
329             mRunner.resumeTiming();
330 
331             mAm.switchUser(startUser);
332             waitForLatch("Failed to achieve ACTION_USER_STOPPED for user " + userId, latch);
333 
334             mRunner.pauseTiming();
335             try {
336                 switchLatch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
337             } catch (InterruptedException e) {
338                 Log.e(TAG, "Thread interrupted unexpectedly while waiting for switch.", e);
339             }
340             removeUser(userId);
341             mRunner.resumeTiming();
342         }
343     }
344 
345     /** Tests creating a new profile. */
346     @Test
managedProfileCreate()347     public void managedProfileCreate() {
348         assumeTrue(mHasManagedUserFeature);
349 
350         while (mRunner.keepRunning()) {
351             final int userId = createManagedProfile();
352 
353             mRunner.pauseTiming();
354             attestTrue("Failed creating profile " + userId, mUm.isManagedProfile(userId));
355             removeUser(userId);
356             mRunner.resumeTiming();
357         }
358     }
359 
360     /** Tests starting (unlocking) a newly-created profile. */
361     @Test
managedProfileUnlock()362     public void managedProfileUnlock() {
363         assumeTrue(mHasManagedUserFeature);
364 
365         while (mRunner.keepRunning()) {
366             mRunner.pauseTiming();
367             final int userId = createManagedProfile();
368             mRunner.resumeTiming();
369 
370             startUserInBackgroundAndWaitForUnlock(userId);
371 
372             mRunner.pauseTiming();
373             removeUser(userId);
374             mRunner.resumeTiming();
375         }
376     }
377 
378     /** Tests starting (unlocking) an already-created, but no-longer-running, profile. */
379     @Test
managedProfileUnlock_stopped()380     public void managedProfileUnlock_stopped() throws RemoteException {
381         assumeTrue(mHasManagedUserFeature);
382 
383         while (mRunner.keepRunning()) {
384             mRunner.pauseTiming();
385             final int userId = createManagedProfile();
386             // Start the profile initially, then stop it. Similar to setQuietModeEnabled.
387             startUserInBackgroundAndWaitForUnlock(userId);
388             stopUser(userId, true);
389             mRunner.resumeTiming();
390 
391             startUserInBackgroundAndWaitForUnlock(userId);
392 
393             mRunner.pauseTiming();
394             removeUser(userId);
395             mRunner.resumeTiming();
396         }
397     }
398 
399     /**
400      * Tests starting (unlocking) and launching an already-installed app in a newly-created profile.
401      */
402     @Test
managedProfileUnlockAndLaunchApp()403     public void managedProfileUnlockAndLaunchApp() throws RemoteException {
404         assumeTrue(mHasManagedUserFeature);
405 
406         while (mRunner.keepRunning()) {
407             mRunner.pauseTiming();
408             final int userId = createManagedProfile();
409             WindowManagerGlobal.getWindowManagerService().dismissKeyguard(null, null);
410             installPreexistingApp(userId, DUMMY_PACKAGE_NAME);
411             mRunner.resumeTiming();
412 
413             startUserInBackgroundAndWaitForUnlock(userId);
414             startApp(userId, DUMMY_PACKAGE_NAME);
415 
416             mRunner.pauseTiming();
417             removeUser(userId);
418             mRunner.resumeTiming();
419         }
420     }
421 
422     /**
423      * Tests starting (unlocking) and launching a previously-launched app
424      * in an already-created, but no-longer-running, profile.
425      * A sort of combination of {@link #managedProfileUnlockAndLaunchApp} and
426      * {@link #managedProfileUnlock_stopped}}.
427      */
428     @Test
managedProfileUnlockAndLaunchApp_stopped()429     public void managedProfileUnlockAndLaunchApp_stopped() throws RemoteException {
430         assumeTrue(mHasManagedUserFeature);
431 
432         while (mRunner.keepRunning()) {
433             mRunner.pauseTiming();
434             final int userId = createManagedProfile();
435             WindowManagerGlobal.getWindowManagerService().dismissKeyguard(null, null);
436             installPreexistingApp(userId, DUMMY_PACKAGE_NAME);
437             startUserInBackgroundAndWaitForUnlock(userId);
438             startApp(userId, DUMMY_PACKAGE_NAME);
439             stopUser(userId, true);
440             SystemClock.sleep(1_000); // 1 second cool-down before re-starting profile.
441             mRunner.resumeTiming();
442 
443             startUserInBackgroundAndWaitForUnlock(userId);
444             startApp(userId, DUMMY_PACKAGE_NAME);
445 
446             mRunner.pauseTiming();
447             removeUser(userId);
448             mRunner.resumeTiming();
449         }
450     }
451 
452     /** Tests installing a pre-existing app in a newly-created profile. */
453     @Test
managedProfileInstall()454     public void managedProfileInstall() throws RemoteException {
455         assumeTrue(mHasManagedUserFeature);
456 
457         while (mRunner.keepRunning()) {
458             mRunner.pauseTiming();
459             final int userId = createManagedProfile();
460             mRunner.resumeTiming();
461 
462             installPreexistingApp(userId, DUMMY_PACKAGE_NAME);
463 
464             mRunner.pauseTiming();
465             removeUser(userId);
466             mRunner.resumeTiming();
467         }
468     }
469 
470     /**
471      * Tests creating a new profile, starting (unlocking) it, installing an app,
472      * and launching that app in it.
473      */
474     @Test
managedProfileCreateUnlockInstallAndLaunchApp()475     public void managedProfileCreateUnlockInstallAndLaunchApp() throws RemoteException {
476         assumeTrue(mHasManagedUserFeature);
477 
478         while (mRunner.keepRunning()) {
479             mRunner.pauseTiming();
480             WindowManagerGlobal.getWindowManagerService().dismissKeyguard(null, null);
481             mRunner.resumeTiming();
482 
483             final int userId = createManagedProfile();
484             startUserInBackgroundAndWaitForUnlock(userId);
485             installPreexistingApp(userId, DUMMY_PACKAGE_NAME);
486             startApp(userId, DUMMY_PACKAGE_NAME);
487 
488             mRunner.pauseTiming();
489             removeUser(userId);
490             mRunner.resumeTiming();
491         }
492     }
493 
494     /** Tests stopping a profile. */
495     @Test
managedProfileStopped()496     public void managedProfileStopped() throws RemoteException {
497         assumeTrue(mHasManagedUserFeature);
498 
499         while (mRunner.keepRunning()) {
500             mRunner.pauseTiming();
501             final int userId = createManagedProfile();
502             startUserInBackgroundAndWaitForUnlock(userId);
503             mRunner.resumeTiming();
504 
505             stopUser(userId, true);
506 
507             mRunner.pauseTiming();
508             removeUser(userId);
509             mRunner.resumeTiming();
510         }
511     }
512 
513     // TODO: This is just a POC. Do this properly and add more.
514     /** Tests starting (unlocking) a newly-created profile using the user-type-pkg-whitelist. */
515     @Test
managedProfileUnlock_usingWhitelist()516     public void managedProfileUnlock_usingWhitelist() {
517         assumeTrue(mHasManagedUserFeature);
518         final int origMode = getUserTypePackageWhitelistMode();
519         setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE
520                 | USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST);
521 
522         try {
523             while (mRunner.keepRunning()) {
524                 mRunner.pauseTiming();
525                 final int userId = createManagedProfile();
526                 mRunner.resumeTiming();
527 
528                 startUserInBackgroundAndWaitForUnlock(userId);
529 
530                 mRunner.pauseTiming();
531                 removeUser(userId);
532                 mRunner.resumeTiming();
533             }
534         } finally {
535             setUserTypePackageWhitelistMode(origMode);
536         }
537     }
538     /** Tests starting (unlocking) a newly-created profile NOT using the user-type-pkg-whitelist. */
539     @Test
managedProfileUnlock_notUsingWhitelist()540     public void managedProfileUnlock_notUsingWhitelist() {
541         assumeTrue(mHasManagedUserFeature);
542         final int origMode = getUserTypePackageWhitelistMode();
543         setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_DISABLE);
544 
545         try {
546             while (mRunner.keepRunning()) {
547                 mRunner.pauseTiming();
548                 final int userId = createManagedProfile();
549                 mRunner.resumeTiming();
550 
551                 startUserInBackgroundAndWaitForUnlock(userId);
552 
553                 mRunner.pauseTiming();
554                 removeUser(userId);
555                 mRunner.resumeTiming();
556             }
557         } finally {
558             setUserTypePackageWhitelistMode(origMode);
559         }
560     }
561 
562     /** Creates a new user, returning its userId. */
createUserNoFlags()563     private int createUserNoFlags() {
564         return createUserWithFlags(/* flags= */ 0);
565     }
566 
567     /** Creates a new user with the given flags, returning its userId. */
createUserWithFlags(int flags)568     private int createUserWithFlags(int flags) {
569         int userId = mUm.createUser(TEST_USER_NAME, flags).id;
570         mUsersToRemove.add(userId);
571         return userId;
572     }
573 
574     /** Creates a managed (work) profile under the current user, returning its userId. */
createManagedProfile()575     private int createManagedProfile() {
576         final UserInfo userInfo = mUm.createProfileForUser(TEST_USER_NAME,
577                 UserManager.USER_TYPE_PROFILE_MANAGED, /* flags */ 0, mAm.getCurrentUser());
578         attestFalse("Creating managed profile failed. Most likely there is "
579                 + "already a pre-existing profile on the device.", userInfo == null);
580         mUsersToRemove.add(userInfo.id);
581         return userInfo.id;
582     }
583 
584     /**
585      * Start user in background and wait for it to unlock by waiting for
586      * UserState.mUnlockProgress.finish().
587      * <p> To start in foreground instead, see {@link #switchUser(int)}.
588      * <p> This should always be used for profiles since profiles cannot be started in foreground.
589      */
startUserInBackgroundAndWaitForUnlock(int userId)590     private void startUserInBackgroundAndWaitForUnlock(int userId) {
591         final ProgressWaiter waiter = new ProgressWaiter();
592         boolean success = false;
593         try {
594             mIam.startUserInBackgroundWithListener(userId, waiter);
595             success = waiter.waitForFinish(TIMEOUT_IN_SECOND);
596         } catch (RemoteException e) {
597             Log.e(TAG, "startUserInBackgroundAndWaitForUnlock failed", e);
598         }
599         attestTrue("Failed to start user " + userId + " in background.", success);
600     }
601 
602     /** Starts the given user in the foreground. */
switchUser(int userId)603     private void switchUser(int userId) throws RemoteException {
604         boolean success = switchUserNoCheck(userId);
605         attestTrue("Failed to properly switch to user " + userId, success);
606     }
607 
608     /**
609      * Starts the given user in the foreground.
610      * Returns true if successful. Does not fail the test if unsuccessful.
611      * If lack of success should fail the test, use {@link #switchUser(int)} instead.
612      */
switchUserNoCheck(int userId)613     private boolean switchUserNoCheck(int userId) throws RemoteException {
614         final CountDownLatch latch = new CountDownLatch(1);
615         registerUserSwitchObserver(latch, null, userId);
616         mAm.switchUser(userId);
617         try {
618             return latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
619         } catch (InterruptedException e) {
620             Log.e(TAG, "Thread interrupted unexpectedly.", e);
621             return false;
622         }
623     }
624 
stopUser(int userId, boolean force)625     private void stopUser(int userId, boolean force) throws RemoteException {
626         final CountDownLatch latch = new CountDownLatch(1);
627         mIam.stopUser(userId, force /* force */, new IStopUserCallback.Stub() {
628             @Override
629             public void userStopped(int userId) throws RemoteException {
630                 latch.countDown();
631             }
632 
633             @Override
634             public void userStopAborted(int userId) throws RemoteException {
635             }
636         });
637         waitForLatch("Failed to properly stop user " + userId, latch);
638     }
639 
640     /**
641      * Creates a user and waits for its ACTION_USER_UNLOCKED.
642      * Then switches to back to the original user and waits for its switchUser() to finish.
643      *
644      * @param stopNewUser whether to stop the new user after switching to otherUser.
645      * @return userId of the newly created user.
646      */
initializeNewUserAndSwitchBack(boolean stopNewUser)647     private int initializeNewUserAndSwitchBack(boolean stopNewUser) throws RemoteException {
648         final int origUser = mAm.getCurrentUser();
649         // First, create and switch to testUser, waiting for its ACTION_USER_UNLOCKED
650         final int testUser = createUserNoFlags();
651         final CountDownLatch latch1 = new CountDownLatch(1);
652         registerBroadcastReceiver(Intent.ACTION_USER_UNLOCKED, latch1, testUser);
653         mAm.switchUser(testUser);
654         waitForLatch("Failed to achieve initial ACTION_USER_UNLOCKED for user " + testUser, latch1);
655 
656         // Second, switch back to origUser, waiting merely for switchUser() to finish
657         switchUser(origUser);
658         attestTrue("Didn't switch back to user, " + origUser, origUser == mAm.getCurrentUser());
659 
660         if (stopNewUser) {
661             stopUser(testUser, true);
662             attestFalse("Failed to stop user " + testUser, mAm.isUserRunning(testUser));
663         }
664 
665         return testUser;
666     }
667 
668     /**
669      * Installs the given package in the given user.
670      */
installPreexistingApp(int userId, String packageName)671     private void installPreexistingApp(int userId, String packageName) throws RemoteException {
672         final CountDownLatch latch = new CountDownLatch(1);
673 
674         final IntentSender sender = new IntentSender((IIntentSender) new IIntentSender.Stub() {
675             @Override
676             public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
677                     IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
678                 latch.countDown();
679             }
680         });
681 
682         final IPackageInstaller installer = AppGlobals.getPackageManager().getPackageInstaller();
683         installer.installExistingPackage(packageName,
684                 PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS,
685                 PackageManager.INSTALL_REASON_UNKNOWN, sender, userId, null);
686 
687         waitForLatch("Failed to install app " + packageName + " on user " + userId, latch);
688     }
689 
690     /**
691      * Launches the given package in the given user.
692      * Make sure the keyguard has been dismissed prior to calling.
693      */
startApp(int userId, String packageName)694     private void startApp(int userId, String packageName) throws RemoteException {
695         final Context context = InstrumentationRegistry.getContext();
696         final WaitResult result = ActivityTaskManager.getService().startActivityAndWait(null,
697                 context.getPackageName(), context.getAttributionTag(),
698                 context.getPackageManager().getLaunchIntentForPackage(packageName), null, null,
699                 null, 0, 0, null, null, userId);
700         attestTrue("User " + userId + " failed to start " + packageName,
701                 result.result == ActivityManager.START_SUCCESS);
702     }
703 
registerUserSwitchObserver(final CountDownLatch switchLatch, final CountDownLatch bootCompleteLatch, final int userId)704     private void registerUserSwitchObserver(final CountDownLatch switchLatch,
705             final CountDownLatch bootCompleteLatch, final int userId) throws RemoteException {
706         ActivityManager.getService().registerUserSwitchObserver(
707                 new UserSwitchObserver() {
708                     @Override
709                     public void onUserSwitchComplete(int newUserId) throws RemoteException {
710                         if (switchLatch != null && userId == newUserId) {
711                             switchLatch.countDown();
712                         }
713                     }
714 
715                     @Override
716                     public void onLockedBootComplete(int newUserId) {
717                         if (bootCompleteLatch != null && userId == newUserId) {
718                             bootCompleteLatch.countDown();
719                         }
720                     }
721                 }, TAG);
722     }
723 
registerBroadcastReceiver(final String action, final CountDownLatch latch, final int userId)724     private void registerBroadcastReceiver(final String action, final CountDownLatch latch,
725             final int userId) {
726         InstrumentationRegistry.getContext().registerReceiverAsUser(new BroadcastReceiver() {
727             @Override
728             public void onReceive(Context context, Intent intent) {
729                 if (action.equals(intent.getAction()) && intent.getIntExtra(
730                         Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL) == userId) {
731                     latch.countDown();
732                 }
733             }
734         }, UserHandle.of(userId), new IntentFilter(action), null, null);
735     }
736 
737     private class ProgressWaiter extends IProgressListener.Stub {
738         private final CountDownLatch mFinishedLatch = new CountDownLatch(1);
739 
740         @Override
onStarted(int id, Bundle extras)741         public void onStarted(int id, Bundle extras) {}
742 
743         @Override
onProgress(int id, int progress, Bundle extras)744         public void onProgress(int id, int progress, Bundle extras) {}
745 
746         @Override
onFinished(int id, Bundle extras)747         public void onFinished(int id, Bundle extras) {
748             mFinishedLatch.countDown();
749         }
750 
waitForFinish(long timeoutSecs)751         public boolean waitForFinish(long timeoutSecs) {
752             try {
753                 return mFinishedLatch.await(timeoutSecs, TimeUnit.SECONDS);
754             } catch (InterruptedException e) {
755                 Log.e(TAG, "Thread interrupted unexpectedly.", e);
756                 return false;
757             }
758         }
759     }
760 
761     /** Waits TIMEOUT_IN_SECOND for the latch to complete, otherwise declares the given error. */
waitForLatch(String errMsg, CountDownLatch latch)762     private void waitForLatch(String errMsg, CountDownLatch latch) {
763         boolean success = false;
764         try {
765             success = latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
766         } catch (InterruptedException e) {
767             Log.e(TAG, "Thread interrupted unexpectedly.", e);
768         }
769         attestTrue(errMsg, success);
770     }
771 
772     /** Gets the PACKAGE_WHITELIST_MODE_PROP System Property. */
getUserTypePackageWhitelistMode()773     private int getUserTypePackageWhitelistMode() {
774         return SystemProperties.getInt(PACKAGE_WHITELIST_MODE_PROP,
775                 USER_TYPE_PACKAGE_WHITELIST_MODE_DEVICE_DEFAULT);
776     }
777 
778     /** Sets the PACKAGE_WHITELIST_MODE_PROP System Property to the given value. */
setUserTypePackageWhitelistMode(int mode)779     private void setUserTypePackageWhitelistMode(int mode) {
780         String result = ShellHelper.runShellCommand(
781                 String.format("setprop %s %d", PACKAGE_WHITELIST_MODE_PROP, mode));
782         attestFalse("Failed to set sysprop " + PACKAGE_WHITELIST_MODE_PROP + ": " + result,
783                 result != null && result.contains("Failed"));
784     }
785 
removeUser(int userId)786     private void removeUser(int userId) {
787         try {
788             mUm.removeUser(userId);
789             final long startTime = System.currentTimeMillis();
790             final long timeoutInMs = TIMEOUT_IN_SECOND * 1000;
791             while (mUm.getUserInfo(userId) != null &&
792                     System.currentTimeMillis() - startTime < timeoutInMs) {
793                 TimeUnit.MILLISECONDS.sleep(CHECK_USER_REMOVED_INTERVAL_MS);
794             }
795         } catch (InterruptedException e) {
796             Thread.currentThread().interrupt();
797         } catch (Exception e) {
798             // Ignore
799         }
800         if (mUm.getUserInfo(userId) != null) {
801             mUsersToRemove.add(userId);
802         }
803     }
804 
removeAnyPreviousTestUsers()805     private void removeAnyPreviousTestUsers() {
806         for (UserInfo user : mUm.getUsers()) {
807             if (TEST_USER_NAME.equals(user.name)) {
808                 Log.i(TAG, "Found previous test user " + user.id + ". Removing it.");
809                 if (mAm.getCurrentUser() == user.id) {
810                     try {
811                         switchUserNoCheck(UserHandle.USER_SYSTEM);
812                     } catch (RemoteException e) {
813                         Log.e(TAG, "Failed to correctly switch to system user", e);
814                     }
815                 }
816                 mUm.removeUser(user.id);
817             }
818         }
819     }
820 
attestTrue(@onNull String message, boolean assertion)821     private void attestTrue(@NonNull String message, boolean assertion) {
822         if (!assertion) {
823             Log.e(TAG, "Test failed on iteration #" + mRunner.getIteration() + ": " + message);
824             mRunner.markAsFailed(new AssertionError(message));
825         }
826     }
827 
attestFalse(@onNull String message, boolean assertion)828     private void attestFalse(@NonNull String message, boolean assertion) {
829         attestTrue(message, !assertion);
830     }
831 }
832