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 setUp()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 tearDown()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 createAndStartUser()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 switchUser()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 switchUser_stopped()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 switchUser_running()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 stopUser()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 lockedBootCompleted()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 managedProfileUnlock()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 managedProfileUnlock_stopped()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 ephemeralUserStopped()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 managedProfileStopped()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 switchUser(int userId)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 stopUser(int userId, boolean force)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 */ initializeNewUserAndSwitchBack(boolean stopNewUser)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 registerUserSwitchObserver(final CountDownLatch switchLatch, final CountDownLatch bootCompleteLatch, final int userId)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 registerBroadcastReceiver(final String action, final CountDownLatch latch, final int userId)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 removeUser(int userId)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 attestTrue(String message, boolean attestion)416 private void attestTrue(String message, boolean attestion) { 417 if (!attestion) { 418 Log.w(TAG, message); 419 } 420 } 421 attestFalse(String message, boolean attestion)422 private void attestFalse(String message, boolean attestion) { 423 attestTrue(message, !attestion); 424 } 425 } 426