Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4647abef authored by Jackson Michael's avatar Jackson Michael
Browse files

Adding startUser tests without removing user at the end

When we create a user, the default is that we ask to initialize it whenever we change from one user to another, without removing that user from Android.
These tests will serve to demonstrate the execution time in the common case of using the start user.

Results:
startUser_uninitializedUser Mean (ms): 2026.75
startUser_startOnceBefore Mean (ms): 924.75

startUser_startTwiceBefore Mean (ms): 438.0

startAndUnlockUser Mean (ms): 2032.75
startAndUnlockUser_startTwiceBefore Mean (ms): 1134.25

switchUser_stopped Mean (ms): 3095.75
switchUser_stopped_realistic Mean (ms): 2403.25

Bug: 266192048
Bug: 266555909
Test: atest UserLifecycleTests#startUser_uninitializedUser
Test: atest UserLifecycleTests#startUser_startOnceBefore
Test: atest UserLifecycleTests#startUser_startTwiceBefore
Test: atest UserLifecycleTests#startAndUnlockUser
Test: atest UserLifecycleTests#startAndUnlockUser_startTwiceBefore
Test: atest UserLifecycleTests#switchUser_stopped
Test: atest UserLifecycleTests#switchUser_stopped_realistic
Change-Id: I1157431eb7f13b21ba2fd230e1148cd5eb09724e
parent 0b9b6f13
Loading
Loading
Loading
Loading
+160 −18
Original line number Diff line number Diff line
@@ -271,33 +271,109 @@ public class UserLifecycleTests {

    /**
     * Tests starting an uninitialized user, with wait times in between iterations.
     * Measures the time until the ProgressListener callback.
     *
     * The first iteration will take longer due to the process of setting policy permissions for
     * a new user.
     */
    @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
    public void startUser_realistic() throws RemoteException {
    public void startUser_uninitializedUser() throws RemoteException {
        startUser_measuresAfterFirstIterations(/* numberOfIterationsToSkip */0);
    }

    /**
     * Tests the second iteration of start user that has a problem that it takes too long to run, a
     * bug has been created (b/266574680) and after investigating or fix this problem,
     * this test can be removed.
     */
    @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
    public void startUser_startOnceBefore() throws RemoteException {
        startUser_measuresAfterFirstIterations(/* numberOfIterationsToSkip */1);
    }

    /**
     * Tests a specific iteration of the start user process.
     * Measures the time until ACTION_USER_STARTED is received.
     * @param numberOfIterationsToSkip number of iterations that must be skipped in the preStartUser
     *                                 method.
     */
    private void startUser_measuresAfterFirstIterations(int numberOfIterationsToSkip)
            throws RemoteException {
        /**
         * Run start user and stop for the next iteration, measures time while mRunner.keepRunning()
         * return true.
         */
        while (mRunner.keepRunning()) {
            mRunner.pauseTiming();

            final int userId = createUserNoFlags();
            final ProgressWaiter waiter = new ProgressWaiter();

            preStartUser(userId, numberOfIterationsToSkip);

            waitForBroadcastIdle();
            waitCoolDownPeriod();

            runThenWaitForBroadcasts(userId, () -> {
                mRunner.resumeTiming();
                Log.i(TAG, "Starting timer");

            final boolean success = mIam.startUserInBackgroundWithListener(userId, waiter)
                    && waiter.waitForFinish(TIMEOUT_IN_SECOND * 1000);
                mIam.startUserInBackground(userId);
            }, Intent.ACTION_USER_STARTED);

            mRunner.pauseTiming();
            Log.i(TAG, "Stopping timer");

            assertTrue("Error: could not start user " + userId, success);

            removeUser(userId);
            mRunner.resumeTimingForNextIteration();
        }
    }

    /**
     * Tests starting an initialized user, with wait times in between iterations stopping between
     * iterations,this test will skip the first two iterations and only measure the next ones.
     *
     * The first iteration will take longer due to the process of setting policy permissions for
     * a new user.
     *
     * The second iteration takes longer than expected and has a bug (b/266574680) to investigate
     * it.
     *
     * The next iterations take the expected time to start a user.
     */
    @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
    public void startUser_startTwiceBefore() throws RemoteException {
        final int userId = createUserNoFlags();

        //TODO(b/266681181) Reduce iteration number by 1 after investigation and possible fix.
        preStartUser(userId, /* numberOfIterations */2);

        /**
         * Run start user and stop for the next iteration, measures time while mRunner.keepRunning()
         * return true.
         */
        while (mRunner.keepRunning()) {
            mRunner.pauseTiming();

            waitForBroadcastIdle();
            waitCoolDownPeriod();

            runThenWaitForBroadcasts(userId, () -> {
                mRunner.resumeTiming();
                Log.i(TAG, "Starting timer");

                mIam.startUserInBackground(userId);
            }, Intent.ACTION_USER_STARTED);

            mRunner.pauseTiming();
            Log.i(TAG, "Stopping timer");

            stopUser(userId, /* force */true);
            mRunner.resumeTimingForNextIteration();
        }

        removeUser(userId);
    }


    /**
     * Tests starting & unlocking an uninitialized user.
     * Measures the time until unlock listener is triggered and user is unlocked.
@@ -320,6 +396,46 @@ public class UserLifecycleTests {
        }
    }

    /**
     * Tests starting & unlocking an initialized user, stopping the user at the end simulating real
     * usage where the user is not removed after created and initialized.
     * Measures the time until unlock listener is triggered and user is unlocked.
     * This test will skip the first two iterations and only measure the next ones.
     *
     * The first iteration will take longer due to the process of setting policy permissions for a
     * new user.
     *
     * The second iteration takes longer than expected and has a bug (b/266574680) to investigate
     * it.
     *
     * The next iterations take the expected time to start a user.
     */
    @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
    public void startAndUnlockUser_startTwiceBefore() throws RemoteException {
        final int userId = createUserNoFlags();

        //TODO(b/266681181) Reduce iteration number by 1 after investigation and possible fix.
        preStartUser(userId, /* numberOfIterations */2);

        while (mRunner.keepRunning()) {
            mRunner.pauseTiming();

            waitCoolDownPeriod();
            mRunner.resumeTiming();
            Log.i(TAG, "Starting timer");

            // Waits for UserState.mUnlockProgress.finish().
            startUserInBackgroundAndWaitForUnlock(userId);

            mRunner.pauseTiming();
            Log.i(TAG, "Stopping timer");
            stopUser(userId, /* force */true);
            mRunner.resumeTimingForNextIteration();
        }

        removeUser(userId);
    }

    /**
     * Tests starting & unlocking an uninitialized user.
     * Measures the time until unlock listener is triggered and user is unlocked.
@@ -404,28 +520,36 @@ public class UserLifecycleTests {
        }
    }

    /** Tests switching to a previously-started, but no-longer-running, user with wait
     * times between iterations */
    /**
     * Tests switching to a previously-started, but no-longer-running, user with wait
     * times between iterations
     **/
    @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
    public void switchUser_stopped_realistic() throws RemoteException {
        final int startUser = ActivityManager.getCurrentUser();
        final int testUser = initializeNewUserAndSwitchBack(/* stopNewUser */ true);
        final int currentUserId = ActivityManager.getCurrentUser();
        final int userId = initializeNewUserAndSwitchBack(/* stopNewUser */ true);

        /**
         * Skip the second iteration of start user process that is taking a long time to finish.
         */
        preStartUser(userId, /* numberOfIterations */1);

        while (mRunner.keepRunning()) {
            mRunner.pauseTiming();
            waitCoolDownPeriod();
            Log.d(TAG, "Starting timer");
            mRunner.resumeTiming();

            switchUser(testUser);
            switchUser(userId);

            mRunner.pauseTiming();
            Log.d(TAG, "Stopping timer");
            switchUserNoCheck(startUser);
            stopUserAfterWaitingForBroadcastIdle(testUser, true);
            attestFalse("Failed to stop user " + testUser, mAm.isUserRunning(testUser));
            switchUserNoCheck(currentUserId);
            stopUserAfterWaitingForBroadcastIdle(userId, /* force */true);
            attestFalse("Failed to stop user " + userId, mAm.isUserRunning(userId));
            mRunner.resumeTimingForNextIteration();
        }
        removeUser(testUser);
        removeUser(userId);
    }

    /** Tests switching to a previously-started, but no-longer-running, user with wait
@@ -1378,6 +1502,24 @@ public class UserLifecycleTests {
        }
    }

    /**
     * Start the user and stop after that, will repeat numberOfIterations times.
     * Make sure the user is started before proceeding with the test.
     * @param userId identifier of the user that will be started.
     * @param numberOfIterations number of iterations that must be skipped.
     */
    private void preStartUser(int userId, int numberOfIterations) throws RemoteException {
        for (int i = 0; i < numberOfIterations; i++) {
            final ProgressWaiter preWaiter = new ProgressWaiter();

            final boolean preStartComplete = mIam.startUserInBackgroundWithListener(userId,
                    preWaiter) && preWaiter.waitForFinish(TIMEOUT_IN_SECOND * 1000);
            stopUserAfterWaitingForBroadcastIdle(userId, /* force */true);

            assertTrue("Pre start was not performed for user" + userId, preStartComplete);
        }
    }

    private void fail(@NonNull String message) {
        Log.e(TAG, "Test failed on iteration #" + mRunner.getIteration() + ": " + message);
        mRunner.markAsFailed(new AssertionError(message));