Home | History | Annotate | Download | only in multiuser
      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 android.app.ActivityManager;
     19 import android.app.IActivityManager;
     20 import android.app.IStopUserCallback;
     21 import android.app.UserSwitchObserver;
     22 import android.content.BroadcastReceiver;
     23 import android.content.Context;
     24 import android.content.Intent;
     25 import android.content.IntentFilter;
     26 import android.content.pm.UserInfo;
     27 import android.os.RemoteException;
     28 import android.os.UserHandle;
     29 import android.os.UserManager;
     30 import android.util.Log;
     31 
     32 import androidx.test.InstrumentationRegistry;
     33 import androidx.test.filters.LargeTest;
     34 import androidx.test.runner.AndroidJUnit4;
     35 
     36 import org.junit.After;
     37 import org.junit.Before;
     38 import org.junit.Rule;
     39 import org.junit.Test;
     40 import org.junit.runner.RunWith;
     41 
     42 import java.util.ArrayList;
     43 import java.util.concurrent.CountDownLatch;
     44 import java.util.concurrent.TimeUnit;
     45 
     46 /**
     47  * Perf tests for user life cycle events.
     48  *
     49  * Running the tests:
     50  *
     51  * make MultiUserPerfTests &&
     52  * adb install -r \
     53  *     ${ANDROID_PRODUCT_OUT}/data/app/MultiUserPerfTests/MultiUserPerfTests.apk &&
     54  * adb shell am instrument -e class android.multiuser.UserLifecycleTests \
     55  *     -w com.android.perftests.multiuser/androidx.test.runner.AndroidJUnitRunner
     56  *
     57  * or
     58  *
     59  * bit MultiUserPerfTests:android.multiuser.UserLifecycleTests
     60  *
     61  * Note: If you use bit for running the tests, benchmark results won't be printed on the host side.
     62  * But in either case, results can be checked on the device side 'adb logcat -s UserLifecycleTests'
     63  */
     64 @LargeTest
     65 @RunWith(AndroidJUnit4.class)
     66 public class UserLifecycleTests {
     67     private static final String TAG = UserLifecycleTests.class.getSimpleName();
     68 
     69     private final int TIMEOUT_IN_SECOND = 30;
     70     private final int CHECK_USER_REMOVED_INTERVAL_MS = 200;
     71 
     72     private UserManager mUm;
     73     private ActivityManager mAm;
     74     private IActivityManager mIam;
     75     private ArrayList<Integer> mUsersToRemove;
     76 
     77     private final BenchmarkRunner mRunner = new BenchmarkRunner();
     78     @Rule
     79     public BenchmarkResultsReporter mReporter = new BenchmarkResultsReporter(mRunner);
     80 
     81     @Before
     82     public void setUp() {
     83         final Context context = InstrumentationRegistry.getContext();
     84         mUm = UserManager.get(context);
     85         mAm = context.getSystemService(ActivityManager.class);
     86         mIam = ActivityManager.getService();
     87         mUsersToRemove = new ArrayList<>();
     88     }
     89 
     90     @After
     91     public void tearDown() {
     92         for (int userId : mUsersToRemove) {
     93             try {
     94                 mUm.removeUser(userId);
     95             } catch (Exception e) {
     96                 // Ignore
     97             }
     98         }
     99     }
    100 
    101     @Test
    102     public void createAndStartUser() throws Exception {
    103         while (mRunner.keepRunning()) {
    104             final UserInfo userInfo = mUm.createUser("TestUser", 0);
    105 
    106             final CountDownLatch latch = new CountDownLatch(1);
    107             registerBroadcastReceiver(Intent.ACTION_USER_STARTED, latch, userInfo.id);
    108             mIam.startUserInBackground(userInfo.id);
    109             latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
    110 
    111             mRunner.pauseTiming();
    112             removeUser(userInfo.id);
    113             mRunner.resumeTiming();
    114         }
    115     }
    116 
    117     @Test
    118     public void switchUser() throws Exception {
    119         while (mRunner.keepRunning()) {
    120             mRunner.pauseTiming();
    121             final int startUser = mAm.getCurrentUser();
    122             final UserInfo userInfo = mUm.createUser("TestUser", 0);
    123             mRunner.resumeTiming();
    124 
    125             switchUser(userInfo.id);
    126 
    127             mRunner.pauseTiming();
    128             switchUser(startUser);
    129             removeUser(userInfo.id);
    130             mRunner.resumeTiming();
    131         }
    132     }
    133 
    134     /** Tests switching to an already-created, but no-longer-running, user. */
    135     @Test
    136     public void switchUser_stopped() throws Exception {
    137         while (mRunner.keepRunning()) {
    138             mRunner.pauseTiming();
    139             final int startUser = mAm.getCurrentUser();
    140             final int testUser = initializeNewUserAndSwitchBack(/* stopNewUser */ true);
    141             final CountDownLatch latch = new CountDownLatch(1);
    142             registerBroadcastReceiver(Intent.ACTION_USER_UNLOCKED, latch, testUser);
    143             mRunner.resumeTiming();
    144 
    145             mAm.switchUser(testUser);
    146             boolean success = latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
    147 
    148             mRunner.pauseTiming();
    149             attestTrue("Failed to achieve 2nd ACTION_USER_UNLOCKED for user " + testUser, success);
    150             switchUser(startUser);
    151             removeUser(testUser);
    152             mRunner.resumeTiming();
    153         }
    154     }
    155 
    156     /** Tests switching to an already-created already-running non-owner user. */
    157     @Test
    158     public void switchUser_running() throws Exception {
    159         while (mRunner.keepRunning()) {
    160             mRunner.pauseTiming();
    161             final int startUser = mAm.getCurrentUser();
    162             final int testUser = initializeNewUserAndSwitchBack(/* stopNewUser */ false);
    163             mRunner.resumeTiming();
    164 
    165             switchUser(testUser);
    166 
    167             mRunner.pauseTiming();
    168             attestTrue("Failed to switch to user " + testUser, mAm.isUserRunning(testUser));
    169             switchUser(startUser);
    170             removeUser(testUser);
    171             mRunner.resumeTiming();
    172         }
    173     }
    174 
    175     @Test
    176     public void stopUser() throws Exception {
    177         while (mRunner.keepRunning()) {
    178             mRunner.pauseTiming();
    179             final UserInfo userInfo = mUm.createUser("TestUser", 0);
    180             final CountDownLatch latch = new CountDownLatch(1);
    181             registerBroadcastReceiver(Intent.ACTION_USER_STARTED, latch, userInfo.id);
    182             mIam.startUserInBackground(userInfo.id);
    183             latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
    184             mRunner.resumeTiming();
    185 
    186             stopUser(userInfo.id, false);
    187 
    188             mRunner.pauseTiming();
    189             removeUser(userInfo.id);
    190             mRunner.resumeTiming();
    191         }
    192     }
    193 
    194     @Test
    195     public void lockedBootCompleted() throws Exception {
    196         while (mRunner.keepRunning()) {
    197             mRunner.pauseTiming();
    198             final int startUser = mAm.getCurrentUser();
    199             final UserInfo userInfo = mUm.createUser("TestUser", 0);
    200             final CountDownLatch latch = new CountDownLatch(1);
    201             registerUserSwitchObserver(null, latch, userInfo.id);
    202             mRunner.resumeTiming();
    203 
    204             mAm.switchUser(userInfo.id);
    205             latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
    206 
    207             mRunner.pauseTiming();
    208             switchUser(startUser);
    209             removeUser(userInfo.id);
    210             mRunner.resumeTiming();
    211         }
    212     }
    213 
    214     @Test
    215     public void managedProfileUnlock() throws Exception {
    216         while (mRunner.keepRunning()) {
    217             mRunner.pauseTiming();
    218             final UserInfo userInfo = mUm.createProfileForUser("TestUser",
    219                     UserInfo.FLAG_MANAGED_PROFILE, mAm.getCurrentUser());
    220             final CountDownLatch latch = new CountDownLatch(1);
    221             registerBroadcastReceiver(Intent.ACTION_USER_UNLOCKED, latch, userInfo.id);
    222             mRunner.resumeTiming();
    223 
    224             mIam.startUserInBackground(userInfo.id);
    225             latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
    226 
    227             mRunner.pauseTiming();
    228             removeUser(userInfo.id);
    229             mRunner.resumeTiming();
    230         }
    231     }
    232 
    233     /** Tests starting an already-created, but no-longer-running, profile. */
    234     @Test
    235     public void managedProfileUnlock_stopped() throws Exception {
    236         while (mRunner.keepRunning()) {
    237             mRunner.pauseTiming();
    238             final UserInfo userInfo = mUm.createProfileForUser("TestUser",
    239                     UserInfo.FLAG_MANAGED_PROFILE, mAm.getCurrentUser());
    240             // Start the profile initially, then stop it. Similar to setQuietModeEnabled.
    241             final CountDownLatch latch1 = new CountDownLatch(1);
    242             registerBroadcastReceiver(Intent.ACTION_USER_UNLOCKED, latch1, userInfo.id);
    243             mIam.startUserInBackground(userInfo.id);
    244             latch1.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
    245             stopUser(userInfo.id, true);
    246 
    247             // Now we restart the profile.
    248             final CountDownLatch latch2 = new CountDownLatch(1);
    249             registerBroadcastReceiver(Intent.ACTION_USER_UNLOCKED, latch2, userInfo.id);
    250             mRunner.resumeTiming();
    251 
    252             mIam.startUserInBackground(userInfo.id);
    253             latch2.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
    254 
    255             mRunner.pauseTiming();
    256             removeUser(userInfo.id);
    257             mRunner.resumeTiming();
    258         }
    259     }
    260 
    261     @Test
    262     public void ephemeralUserStopped() throws Exception {
    263         while (mRunner.keepRunning()) {
    264             mRunner.pauseTiming();
    265             final int startUser = mAm.getCurrentUser();
    266             final UserInfo userInfo = mUm.createUser("TestUser",
    267                     UserInfo.FLAG_EPHEMERAL | UserInfo.FLAG_DEMO);
    268             switchUser(userInfo.id);
    269             final CountDownLatch latch = new CountDownLatch(1);
    270             InstrumentationRegistry.getContext().registerReceiver(new BroadcastReceiver() {
    271                 @Override
    272                 public void onReceive(Context context, Intent intent) {
    273                     if (Intent.ACTION_USER_STOPPED.equals(intent.getAction()) && intent.getIntExtra(
    274                             Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL) == userInfo.id) {
    275                         latch.countDown();
    276                     }
    277                 }
    278             }, new IntentFilter(Intent.ACTION_USER_STOPPED));
    279             final CountDownLatch switchLatch = new CountDownLatch(1);
    280             registerUserSwitchObserver(switchLatch, null, startUser);
    281             mRunner.resumeTiming();
    282 
    283             mAm.switchUser(startUser);
    284             latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
    285 
    286             mRunner.pauseTiming();
    287             switchLatch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
    288             removeUser(userInfo.id);
    289             mRunner.resumeTiming();
    290         }
    291     }
    292 
    293     @Test
    294     public void managedProfileStopped() throws Exception {
    295         while (mRunner.keepRunning()) {
    296             mRunner.pauseTiming();
    297             final UserInfo userInfo = mUm.createProfileForUser("TestUser",
    298                     UserInfo.FLAG_MANAGED_PROFILE, mAm.getCurrentUser());
    299             final CountDownLatch latch = new CountDownLatch(1);
    300             registerBroadcastReceiver(Intent.ACTION_USER_UNLOCKED, latch, userInfo.id);
    301             mIam.startUserInBackground(userInfo.id);
    302             latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
    303             mRunner.resumeTiming();
    304 
    305             stopUser(userInfo.id, true);
    306 
    307             mRunner.pauseTiming();
    308             removeUser(userInfo.id);
    309             mRunner.resumeTiming();
    310         }
    311     }
    312 
    313     private void switchUser(int userId) throws Exception {
    314         final CountDownLatch latch = new CountDownLatch(1);
    315         registerUserSwitchObserver(latch, null, userId);
    316         mAm.switchUser(userId);
    317         latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
    318     }
    319 
    320     private void stopUser(int userId, boolean force) throws Exception {
    321         final CountDownLatch latch = new CountDownLatch(1);
    322         mIam.stopUser(userId, force /* force */, new IStopUserCallback.Stub() {
    323             @Override
    324             public void userStopped(int userId) throws RemoteException {
    325                 latch.countDown();
    326             }
    327 
    328             @Override
    329             public void userStopAborted(int userId) throws RemoteException {
    330             }
    331         });
    332         latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
    333     }
    334 
    335     /**
    336      * Creates a user and waits for its ACTION_USER_UNLOCKED.
    337      * Then switches to back to the original user and waits for its switchUser() to finish.
    338      *
    339      * @param stopNewUser whether to stop the new user after switching to otherUser.
    340      * @return userId of the newly created user.
    341      */
    342     private int initializeNewUserAndSwitchBack(boolean stopNewUser) throws Exception {
    343         final int origUser = mAm.getCurrentUser();
    344         // First, create and switch to testUser, waiting for its ACTION_USER_UNLOCKED
    345         final int testUser = mUm.createUser("TestUser", 0).id;
    346         final CountDownLatch latch1 = new CountDownLatch(1);
    347         registerBroadcastReceiver(Intent.ACTION_USER_UNLOCKED, latch1, testUser);
    348         mAm.switchUser(testUser);
    349         attestTrue("Failed to achieve initial ACTION_USER_UNLOCKED for user " + testUser,
    350                 latch1.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS));
    351 
    352         // Second, switch back to origUser, waiting merely for switchUser() to finish
    353         switchUser(origUser);
    354         attestTrue("Didn't switch back to user, " + origUser, origUser == mAm.getCurrentUser());
    355 
    356         if (stopNewUser) {
    357             stopUser(testUser, true);
    358             attestFalse("Failed to stop user " + testUser, mAm.isUserRunning(testUser));
    359         }
    360 
    361         return testUser;
    362     }
    363 
    364     private void registerUserSwitchObserver(final CountDownLatch switchLatch,
    365             final CountDownLatch bootCompleteLatch, final int userId) throws Exception {
    366         ActivityManager.getService().registerUserSwitchObserver(
    367                 new UserSwitchObserver() {
    368                     @Override
    369                     public void onUserSwitchComplete(int newUserId) throws RemoteException {
    370                         if (switchLatch != null && userId == newUserId) {
    371                             switchLatch.countDown();
    372                         }
    373                     }
    374 
    375                     @Override
    376                     public void onLockedBootComplete(int newUserId) {
    377                         if (bootCompleteLatch != null && userId == newUserId) {
    378                             bootCompleteLatch.countDown();
    379                         }
    380                     }
    381                 }, TAG);
    382     }
    383 
    384     private void registerBroadcastReceiver(final String action, final CountDownLatch latch,
    385             final int userId) {
    386         InstrumentationRegistry.getContext().registerReceiverAsUser(new BroadcastReceiver() {
    387             @Override
    388             public void onReceive(Context context, Intent intent) {
    389                 if (action.equals(intent.getAction()) && intent.getIntExtra(
    390                         Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL) == userId) {
    391                     latch.countDown();
    392                 }
    393             }
    394         }, UserHandle.of(userId), new IntentFilter(action), null, null);
    395     }
    396 
    397     private void removeUser(int userId) {
    398         try {
    399             mUm.removeUser(userId);
    400             final long startTime = System.currentTimeMillis();
    401             final long timeoutInMs = TIMEOUT_IN_SECOND * 1000;
    402             while (mUm.getUserInfo(userId) != null &&
    403                     System.currentTimeMillis() - startTime < timeoutInMs) {
    404                 TimeUnit.MILLISECONDS.sleep(CHECK_USER_REMOVED_INTERVAL_MS);
    405             }
    406         } catch (InterruptedException e) {
    407             Thread.currentThread().interrupt();
    408         } catch (Exception e) {
    409             // Ignore
    410         }
    411         if (mUm.getUserInfo(userId) != null) {
    412             mUsersToRemove.add(userId);
    413         }
    414     }
    415 
    416     private void attestTrue(String message, boolean attestion) {
    417         if (!attestion) {
    418             Log.w(TAG, message);
    419         }
    420     }
    421 
    422     private void attestFalse(String message, boolean attestion) {
    423         attestTrue(message, !attestion);
    424     }
    425 }
    426