blob: e2ef7a11b3a0b6e68c2ef195d14be88409cf2c3a [file] [log] [blame]
Sudheer Shanka53c23fd2016-08-17 19:34:58 -07001/*
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 */
16package android.multiuser;
17
18import android.app.ActivityManager;
Bookatz312da052019-04-11 09:24:54 -070019import android.app.ActivityTaskManager;
20import android.app.AppGlobals;
Sudheer Shanka53c23fd2016-08-17 19:34:58 -070021import android.app.IActivityManager;
Sudheer Shanka2c4522c2016-08-27 20:53:28 -070022import android.app.IStopUserCallback;
23import android.app.UserSwitchObserver;
Bookatz312da052019-04-11 09:24:54 -070024import android.app.WaitResult;
Sudheer Shanka53c23fd2016-08-17 19:34:58 -070025import android.content.BroadcastReceiver;
26import android.content.Context;
Bookatz312da052019-04-11 09:24:54 -070027import android.content.IIntentReceiver;
28import android.content.IIntentSender;
Sudheer Shanka53c23fd2016-08-17 19:34:58 -070029import android.content.Intent;
30import android.content.IntentFilter;
Bookatz312da052019-04-11 09:24:54 -070031import android.content.IntentSender;
32import android.content.pm.IPackageInstaller;
33import android.content.pm.PackageManager;
Sudheer Shanka53c23fd2016-08-17 19:34:58 -070034import android.content.pm.UserInfo;
Bookatz312da052019-04-11 09:24:54 -070035import android.os.Bundle;
36import android.os.IBinder;
37import android.os.IProgressListener;
Sudheer Shanka53c23fd2016-08-17 19:34:58 -070038import android.os.RemoteException;
39import android.os.UserHandle;
40import android.os.UserManager;
Bookatz52b12ac2019-02-28 17:29:26 -080041import android.util.Log;
Bookatz312da052019-04-11 09:24:54 -070042import android.view.WindowManagerGlobal;
KOUSHIK PANUGANTI130f0a52018-12-17 14:41:06 -080043
44import androidx.test.InstrumentationRegistry;
45import androidx.test.filters.LargeTest;
46import androidx.test.runner.AndroidJUnit4;
Sudheer Shanka53c23fd2016-08-17 19:34:58 -070047
48import org.junit.After;
49import org.junit.Before;
50import org.junit.Rule;
51import org.junit.Test;
52import org.junit.runner.RunWith;
53
54import java.util.ArrayList;
55import java.util.concurrent.CountDownLatch;
56import java.util.concurrent.TimeUnit;
57
Sudheer Shanka2c4522c2016-08-27 20:53:28 -070058/**
59 * Perf tests for user life cycle events.
60 *
61 * Running the tests:
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -070062 *
Sudheer Shanka2c4522c2016-08-27 20:53:28 -070063 * make MultiUserPerfTests &&
64 * adb install -r \
65 * ${ANDROID_PRODUCT_OUT}/data/app/MultiUserPerfTests/MultiUserPerfTests.apk &&
Sudheer Shanka2d0278b2017-07-12 18:12:31 -070066 * adb shell am instrument -e class android.multiuser.UserLifecycleTests \
KOUSHIK PANUGANTI130f0a52018-12-17 14:41:06 -080067 * -w com.android.perftests.multiuser/androidx.test.runner.AndroidJUnitRunner
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -070068 *
69 * or
70 *
Sudheer Shanka2d0278b2017-07-12 18:12:31 -070071 * bit MultiUserPerfTests:android.multiuser.UserLifecycleTests
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -070072 *
73 * Note: If you use bit for running the tests, benchmark results won't be printed on the host side.
Sudheer Shanka2d0278b2017-07-12 18:12:31 -070074 * But in either case, results can be checked on the device side 'adb logcat -s UserLifecycleTests'
Sudheer Shanka2c4522c2016-08-27 20:53:28 -070075 */
Sudheer Shanka53c23fd2016-08-17 19:34:58 -070076@LargeTest
77@RunWith(AndroidJUnit4.class)
Sudheer Shanka2d0278b2017-07-12 18:12:31 -070078public class UserLifecycleTests {
79 private static final String TAG = UserLifecycleTests.class.getSimpleName();
80
Bookatz312da052019-04-11 09:24:54 -070081 private static final int TIMEOUT_IN_SECOND = 30;
82 private static final int CHECK_USER_REMOVED_INTERVAL_MS = 200;
83
84 private static final String DUMMY_PACKAGE_NAME = "perftests.multiuser.apps.dummyapp";
Sudheer Shanka2c4522c2016-08-27 20:53:28 -070085
Sudheer Shanka53c23fd2016-08-17 19:34:58 -070086 private UserManager mUm;
87 private ActivityManager mAm;
88 private IActivityManager mIam;
Sudheer Shanka53c23fd2016-08-17 19:34:58 -070089 private ArrayList<Integer> mUsersToRemove;
90
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -070091 private final BenchmarkRunner mRunner = new BenchmarkRunner();
Sudheer Shanka53c23fd2016-08-17 19:34:58 -070092 @Rule
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -070093 public BenchmarkResultsReporter mReporter = new BenchmarkResultsReporter(mRunner);
Sudheer Shanka53c23fd2016-08-17 19:34:58 -070094
95 @Before
96 public void setUp() {
97 final Context context = InstrumentationRegistry.getContext();
98 mUm = UserManager.get(context);
99 mAm = context.getSystemService(ActivityManager.class);
Sudheer Shankadc589ac2016-11-10 15:30:17 -0800100 mIam = ActivityManager.getService();
Sudheer Shanka53c23fd2016-08-17 19:34:58 -0700101 mUsersToRemove = new ArrayList<>();
102 }
103
104 @After
105 public void tearDown() {
106 for (int userId : mUsersToRemove) {
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700107 try {
108 mUm.removeUser(userId);
109 } catch (Exception e) {
110 // Ignore
111 }
Sudheer Shanka53c23fd2016-08-17 19:34:58 -0700112 }
113 }
114
115 @Test
Sudheer Shankaa319f8b2017-07-11 15:28:48 -0700116 public void createAndStartUser() throws Exception {
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700117 while (mRunner.keepRunning()) {
Bookatz312da052019-04-11 09:24:54 -0700118 final int userId = createUser();
Sudheer Shanka53c23fd2016-08-17 19:34:58 -0700119
120 final CountDownLatch latch = new CountDownLatch(1);
Bookatz312da052019-04-11 09:24:54 -0700121 registerBroadcastReceiver(Intent.ACTION_USER_STARTED, latch, userId);
122 // Don't use this.startUserInBackground() since only waiting until ACTION_USER_STARTED.
123 mIam.startUserInBackground(userId);
Tony Makec7c6962017-05-26 15:38:09 +0100124 latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
Sudheer Shanka53c23fd2016-08-17 19:34:58 -0700125
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700126 mRunner.pauseTiming();
Bookatz312da052019-04-11 09:24:54 -0700127 removeUser(userId);
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700128 mRunner.resumeTiming();
Sudheer Shanka53c23fd2016-08-17 19:34:58 -0700129 }
130 }
131
132 @Test
Sudheer Shankaa319f8b2017-07-11 15:28:48 -0700133 public void switchUser() throws Exception {
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700134 while (mRunner.keepRunning()) {
135 mRunner.pauseTiming();
Sudheer Shanka53c23fd2016-08-17 19:34:58 -0700136 final int startUser = mAm.getCurrentUser();
Bookatz312da052019-04-11 09:24:54 -0700137 final int userId = createUser();
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700138 mRunner.resumeTiming();
Sudheer Shanka53c23fd2016-08-17 19:34:58 -0700139
Bookatz312da052019-04-11 09:24:54 -0700140 switchUser(userId);
Sudheer Shanka53c23fd2016-08-17 19:34:58 -0700141
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700142 mRunner.pauseTiming();
Sudheer Shanka53c23fd2016-08-17 19:34:58 -0700143 switchUser(startUser);
Bookatz312da052019-04-11 09:24:54 -0700144 removeUser(userId);
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700145 mRunner.resumeTiming();
Sudheer Shanka53c23fd2016-08-17 19:34:58 -0700146 }
147 }
148
Bookatz52b12ac2019-02-28 17:29:26 -0800149 /** Tests switching to an already-created, but no-longer-running, user. */
150 @Test
151 public void switchUser_stopped() throws Exception {
152 while (mRunner.keepRunning()) {
153 mRunner.pauseTiming();
154 final int startUser = mAm.getCurrentUser();
155 final int testUser = initializeNewUserAndSwitchBack(/* stopNewUser */ true);
156 final CountDownLatch latch = new CountDownLatch(1);
157 registerBroadcastReceiver(Intent.ACTION_USER_UNLOCKED, latch, testUser);
158 mRunner.resumeTiming();
159
160 mAm.switchUser(testUser);
161 boolean success = latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
162
163 mRunner.pauseTiming();
164 attestTrue("Failed to achieve 2nd ACTION_USER_UNLOCKED for user " + testUser, success);
165 switchUser(startUser);
166 removeUser(testUser);
167 mRunner.resumeTiming();
168 }
169 }
170
171 /** Tests switching to an already-created already-running non-owner user. */
172 @Test
173 public void switchUser_running() throws Exception {
174 while (mRunner.keepRunning()) {
175 mRunner.pauseTiming();
176 final int startUser = mAm.getCurrentUser();
177 final int testUser = initializeNewUserAndSwitchBack(/* stopNewUser */ false);
178 mRunner.resumeTiming();
179
180 switchUser(testUser);
181
182 mRunner.pauseTiming();
183 attestTrue("Failed to switch to user " + testUser, mAm.isUserRunning(testUser));
184 switchUser(startUser);
185 removeUser(testUser);
186 mRunner.resumeTiming();
187 }
188 }
189
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700190 @Test
Sudheer Shankaa319f8b2017-07-11 15:28:48 -0700191 public void stopUser() throws Exception {
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700192 while (mRunner.keepRunning()) {
193 mRunner.pauseTiming();
Bookatz312da052019-04-11 09:24:54 -0700194 final int userId = createUser();
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700195 final CountDownLatch latch = new CountDownLatch(1);
Bookatz312da052019-04-11 09:24:54 -0700196 registerBroadcastReceiver(Intent.ACTION_USER_STARTED, latch, userId);
197 mIam.startUserInBackground(userId);
Tony Makec7c6962017-05-26 15:38:09 +0100198 latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700199 mRunner.resumeTiming();
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700200
Bookatz312da052019-04-11 09:24:54 -0700201 stopUser(userId, false);
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700202
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700203 mRunner.pauseTiming();
Bookatz312da052019-04-11 09:24:54 -0700204 removeUser(userId);
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700205 mRunner.resumeTiming();
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700206 }
207 }
208
209 @Test
Sudheer Shankaa319f8b2017-07-11 15:28:48 -0700210 public void lockedBootCompleted() throws Exception {
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700211 while (mRunner.keepRunning()) {
212 mRunner.pauseTiming();
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700213 final int startUser = mAm.getCurrentUser();
Bookatz312da052019-04-11 09:24:54 -0700214 final int userId = createUser();
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700215 final CountDownLatch latch = new CountDownLatch(1);
Bookatz312da052019-04-11 09:24:54 -0700216 registerUserSwitchObserver(null, latch, userId);
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700217 mRunner.resumeTiming();
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700218
Bookatz312da052019-04-11 09:24:54 -0700219 mAm.switchUser(userId);
Tony Makec7c6962017-05-26 15:38:09 +0100220 latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700221
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700222 mRunner.pauseTiming();
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700223 switchUser(startUser);
Bookatz312da052019-04-11 09:24:54 -0700224 removeUser(userId);
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700225 mRunner.resumeTiming();
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700226 }
227 }
228
229 @Test
Bookatz5df3c642019-04-11 09:22:49 -0700230 public void ephemeralUserStopped() throws Exception {
231 while (mRunner.keepRunning()) {
232 mRunner.pauseTiming();
233 final int startUser = mAm.getCurrentUser();
Bookatz312da052019-04-11 09:24:54 -0700234 final int userId = createUser(UserInfo.FLAG_EPHEMERAL | UserInfo.FLAG_DEMO);
235 switchUser(userId);
Bookatz5df3c642019-04-11 09:22:49 -0700236 final CountDownLatch latch = new CountDownLatch(1);
237 InstrumentationRegistry.getContext().registerReceiver(new BroadcastReceiver() {
238 @Override
239 public void onReceive(Context context, Intent intent) {
240 if (Intent.ACTION_USER_STOPPED.equals(intent.getAction()) && intent.getIntExtra(
Bookatz312da052019-04-11 09:24:54 -0700241 Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL) == userId) {
Bookatz5df3c642019-04-11 09:22:49 -0700242 latch.countDown();
243 }
244 }
245 }, new IntentFilter(Intent.ACTION_USER_STOPPED));
246 final CountDownLatch switchLatch = new CountDownLatch(1);
247 registerUserSwitchObserver(switchLatch, null, startUser);
248 mRunner.resumeTiming();
249
250 mAm.switchUser(startUser);
251 latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
252
253 mRunner.pauseTiming();
254 switchLatch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
Bookatz312da052019-04-11 09:24:54 -0700255 removeUser(userId);
Bookatz5df3c642019-04-11 09:22:49 -0700256 mRunner.resumeTiming();
257 }
258 }
259
Bookatz312da052019-04-11 09:24:54 -0700260 /** Tests creating a new profile. */
261 @Test
262 public void managedProfileCreate() throws Exception {
263 while (mRunner.keepRunning()) {
264 final int userId = createManagedProfile();
265
266 mRunner.pauseTiming();
267 attestTrue("Failed creating profile " + userId, mUm.isManagedProfile(userId));
268 removeUser(userId);
269 mRunner.resumeTiming();
270 }
271 }
272
273 /** Tests starting (unlocking) a newly-created profile. */
Bookatz5df3c642019-04-11 09:22:49 -0700274 @Test
Sudheer Shankaa319f8b2017-07-11 15:28:48 -0700275 public void managedProfileUnlock() throws Exception {
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700276 while (mRunner.keepRunning()) {
277 mRunner.pauseTiming();
Bookatz312da052019-04-11 09:24:54 -0700278 final int userId = createManagedProfile();
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700279 mRunner.resumeTiming();
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700280
Bookatz312da052019-04-11 09:24:54 -0700281 startUserInBackground(userId);
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700282
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700283 mRunner.pauseTiming();
Bookatz312da052019-04-11 09:24:54 -0700284 removeUser(userId);
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700285 mRunner.resumeTiming();
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700286 }
287 }
288
Bookatz312da052019-04-11 09:24:54 -0700289 /** Tests starting (unlocking) an already-created, but no-longer-running, profile. */
Bookatz57908d92019-03-29 10:40:10 -0700290 @Test
291 public void managedProfileUnlock_stopped() throws Exception {
292 while (mRunner.keepRunning()) {
293 mRunner.pauseTiming();
Bookatz312da052019-04-11 09:24:54 -0700294 final int userId = createManagedProfile();
Bookatz57908d92019-03-29 10:40:10 -0700295 // Start the profile initially, then stop it. Similar to setQuietModeEnabled.
Bookatz312da052019-04-11 09:24:54 -0700296 startUserInBackground(userId);
297 stopUser(userId, true);
Bookatz57908d92019-03-29 10:40:10 -0700298 mRunner.resumeTiming();
299
Bookatz312da052019-04-11 09:24:54 -0700300 startUserInBackground(userId);
Bookatz57908d92019-03-29 10:40:10 -0700301
302 mRunner.pauseTiming();
Bookatz312da052019-04-11 09:24:54 -0700303 removeUser(userId);
Bookatz57908d92019-03-29 10:40:10 -0700304 mRunner.resumeTiming();
305 }
306 }
307
Bookatz312da052019-04-11 09:24:54 -0700308 /**
309 * Tests starting (unlocking) and launching an already-installed app in a newly-created profile.
310 */
311 @Test
312 public void managedProfileUnlockAndLaunchApp() throws Exception {
313 while (mRunner.keepRunning()) {
314 mRunner.pauseTiming();
315 final int userId = createManagedProfile();
316 WindowManagerGlobal.getWindowManagerService().dismissKeyguard(null, null);
317 installPreexistingApp(userId, DUMMY_PACKAGE_NAME);
318 mRunner.resumeTiming();
Tony Makec7c6962017-05-26 15:38:09 +0100319
Bookatz312da052019-04-11 09:24:54 -0700320 startUserInBackground(userId);
321 startApp(userId, DUMMY_PACKAGE_NAME);
322
323 mRunner.pauseTiming();
324 removeUser(userId);
325 mRunner.resumeTiming();
326 }
327 }
328
Bookatz5f870192019-05-30 10:04:30 -0700329 /**
330 * Tests starting (unlocking) and launching a previously-launched app
331 * in an already-created, but no-longer-running, profile.
332 * A sort of combination of {@link #managedProfileUnlockAndLaunchApp} and
333 * {@link #managedProfileUnlock_stopped}}.
334 */
335 @Test
336 public void managedProfileUnlockAndLaunchApp_stopped() throws Exception {
337 while (mRunner.keepRunning()) {
338 mRunner.pauseTiming();
339 final int userId = createManagedProfile();
340 WindowManagerGlobal.getWindowManagerService().dismissKeyguard(null, null);
341 installPreexistingApp(userId, DUMMY_PACKAGE_NAME);
342 startUserInBackground(userId);
343 startApp(userId, DUMMY_PACKAGE_NAME);
344 stopUser(userId, true);
345 TimeUnit.SECONDS.sleep(1); // Brief cool-down before re-starting profile.
346 mRunner.resumeTiming();
347
348 startUserInBackground(userId);
349 startApp(userId, DUMMY_PACKAGE_NAME);
350
351 mRunner.pauseTiming();
352 removeUser(userId);
353 mRunner.resumeTiming();
354 }
355 }
356
Bookatz312da052019-04-11 09:24:54 -0700357 /** Tests installing a pre-existing app in a newly-created profile. */
358 @Test
359 public void managedProfileInstall() throws Exception {
360 while (mRunner.keepRunning()) {
361 mRunner.pauseTiming();
362 final int userId = createManagedProfile();
363 mRunner.resumeTiming();
364
365 installPreexistingApp(userId, DUMMY_PACKAGE_NAME);
366
367 mRunner.pauseTiming();
368 removeUser(userId);
369 mRunner.resumeTiming();
370 }
371 }
372
373 /**
374 * Tests creating a new profile, starting (unlocking) it, installing an app,
375 * and launching that app in it.
376 */
377 @Test
378 public void managedProfileCreateUnlockInstallAndLaunchApp() throws Exception {
379 final String packageName = "perftests.multiuser.apps.dummyapp";
380 while (mRunner.keepRunning()) {
381 mRunner.pauseTiming();
382 WindowManagerGlobal.getWindowManagerService().dismissKeyguard(null, null);
383 mRunner.resumeTiming();
384
385 final int userId = createManagedProfile();
386 startUserInBackground(userId);
387 installPreexistingApp(userId, DUMMY_PACKAGE_NAME);
388 startApp(userId, DUMMY_PACKAGE_NAME);
389
390 mRunner.pauseTiming();
391 removeUser(userId);
392 mRunner.resumeTiming();
393 }
394 }
395
396 /** Tests stopping a profile. */
Tony Makec7c6962017-05-26 15:38:09 +0100397 @Test
Sudheer Shankaa319f8b2017-07-11 15:28:48 -0700398 public void managedProfileStopped() throws Exception {
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700399 while (mRunner.keepRunning()) {
400 mRunner.pauseTiming();
Bookatz312da052019-04-11 09:24:54 -0700401 final int userId = createManagedProfile();
402 startUserInBackground(userId);
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700403 mRunner.resumeTiming();
Tony Makec7c6962017-05-26 15:38:09 +0100404
Bookatz312da052019-04-11 09:24:54 -0700405 stopUser(userId, true);
Tony Makec7c6962017-05-26 15:38:09 +0100406
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700407 mRunner.pauseTiming();
Bookatz312da052019-04-11 09:24:54 -0700408 removeUser(userId);
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700409 mRunner.resumeTiming();
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700410 }
411 }
412
Bookatz312da052019-04-11 09:24:54 -0700413 /** Creates a new user, returning its userId. */
414 private int createUser() {
415 return createUser(0);
416 }
417
418 /** Creates a new user with the given flags, returning its userId. */
419 private int createUser(int flags) {
420 int userId = mUm.createUser("TestUser", flags).id;
421 mUsersToRemove.add(userId);
422 return userId;
423 }
424
425 /** Creates a managed (work) profile under the current user, returning its userId. */
426 private int createManagedProfile() {
427 final UserInfo userInfo = mUm.createProfileForUser("TestProfile",
428 UserInfo.FLAG_MANAGED_PROFILE, mAm.getCurrentUser());
429 mUsersToRemove.add(userInfo.id);
430 return userInfo.id;
431 }
432
433 /**
434 * Start user in background and wait for it to unlock (equivalent to ACTION_USER_UNLOCKED).
435 * To start in foreground instead, see {@link #switchUser(int)}.
436 * This should always be used for profiles since profiles cannot be started in foreground.
437 */
438 private void startUserInBackground(int userId) {
439 final ProgressWaiter waiter = new ProgressWaiter();
440 try {
441 mIam.startUserInBackgroundWithListener(userId, waiter);
442 boolean success = waiter.waitForFinish(TIMEOUT_IN_SECOND);
443 attestTrue("Failed to start user " + userId + " in background.", success);
444 } catch (RemoteException e) {
445 Log.e(TAG, "startUserInBackground failed", e);
446 }
447 }
448
449 /** Starts the given user in the foreground. */
Sudheer Shanka53c23fd2016-08-17 19:34:58 -0700450 private void switchUser(int userId) throws Exception {
451 final CountDownLatch latch = new CountDownLatch(1);
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700452 registerUserSwitchObserver(latch, null, userId);
Sudheer Shanka53c23fd2016-08-17 19:34:58 -0700453 mAm.switchUser(userId);
Tony Makec7c6962017-05-26 15:38:09 +0100454 latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
Sudheer Shanka53c23fd2016-08-17 19:34:58 -0700455 }
456
Tony Makec7c6962017-05-26 15:38:09 +0100457 private void stopUser(int userId, boolean force) throws Exception {
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700458 final CountDownLatch latch = new CountDownLatch(1);
Tony Makec7c6962017-05-26 15:38:09 +0100459 mIam.stopUser(userId, force /* force */, new IStopUserCallback.Stub() {
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700460 @Override
461 public void userStopped(int userId) throws RemoteException {
462 latch.countDown();
463 }
Sudheer Shanka53c23fd2016-08-17 19:34:58 -0700464
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700465 @Override
466 public void userStopAborted(int userId) throws RemoteException {
467 }
468 });
Tony Makec7c6962017-05-26 15:38:09 +0100469 latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700470 }
471
Bookatz52b12ac2019-02-28 17:29:26 -0800472 /**
473 * Creates a user and waits for its ACTION_USER_UNLOCKED.
474 * Then switches to back to the original user and waits for its switchUser() to finish.
475 *
476 * @param stopNewUser whether to stop the new user after switching to otherUser.
477 * @return userId of the newly created user.
478 */
479 private int initializeNewUserAndSwitchBack(boolean stopNewUser) throws Exception {
480 final int origUser = mAm.getCurrentUser();
481 // First, create and switch to testUser, waiting for its ACTION_USER_UNLOCKED
Bookatz312da052019-04-11 09:24:54 -0700482 final int testUser = createUser();
Bookatz52b12ac2019-02-28 17:29:26 -0800483 final CountDownLatch latch1 = new CountDownLatch(1);
484 registerBroadcastReceiver(Intent.ACTION_USER_UNLOCKED, latch1, testUser);
485 mAm.switchUser(testUser);
486 attestTrue("Failed to achieve initial ACTION_USER_UNLOCKED for user " + testUser,
487 latch1.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS));
488
489 // Second, switch back to origUser, waiting merely for switchUser() to finish
490 switchUser(origUser);
491 attestTrue("Didn't switch back to user, " + origUser, origUser == mAm.getCurrentUser());
492
493 if (stopNewUser) {
494 stopUser(testUser, true);
495 attestFalse("Failed to stop user " + testUser, mAm.isUserRunning(testUser));
496 }
497
498 return testUser;
499 }
500
Bookatz312da052019-04-11 09:24:54 -0700501 /**
502 * Installs the given package in the given user.
503 */
504 private void installPreexistingApp(int userId, String packageName) throws RemoteException {
505 final CountDownLatch latch = new CountDownLatch(1);
506
507 final IntentSender sender = new IntentSender((IIntentSender) new IIntentSender.Stub() {
508 @Override
509 public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
510 IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
511 latch.countDown();
512 }
513 });
514
515 final IPackageInstaller installer = AppGlobals.getPackageManager().getPackageInstaller();
Philip P. Moltmannbfcffa02019-05-13 17:10:46 -0700516 installer.installExistingPackage(packageName,
517 PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS,
518 PackageManager.INSTALL_REASON_UNKNOWN, sender, userId, null);
Bookatz312da052019-04-11 09:24:54 -0700519
520 try {
521 latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
522 } catch (InterruptedException e) {
523 Log.e(TAG, "Thread interrupted unexpectedly.", e);
524 }
525 }
526
527 /**
528 * Launches the given package in the given user.
529 * Make sure the keyguard has been dismissed prior to calling.
530 */
531 private void startApp(int userId, String packageName) throws RemoteException {
532 final Context context = InstrumentationRegistry.getContext();
533 final WaitResult result = ActivityTaskManager.getService().startActivityAndWait(null, null,
534 context.getPackageManager().getLaunchIntentForPackage(packageName),
535 null, null, null, 0, 0, null, null,
536 userId);
537 attestTrue("User " + userId + " failed to start " + packageName,
538 result.result == ActivityManager.START_SUCCESS);
539 }
540
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700541 private void registerUserSwitchObserver(final CountDownLatch switchLatch,
542 final CountDownLatch bootCompleteLatch, final int userId) throws Exception {
Sudheer Shankadc589ac2016-11-10 15:30:17 -0800543 ActivityManager.getService().registerUserSwitchObserver(
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700544 new UserSwitchObserver() {
Sudheer Shanka53c23fd2016-08-17 19:34:58 -0700545 @Override
546 public void onUserSwitchComplete(int newUserId) throws RemoteException {
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700547 if (switchLatch != null && userId == newUserId) {
548 switchLatch.countDown();
549 }
Sudheer Shanka53c23fd2016-08-17 19:34:58 -0700550 }
551
552 @Override
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700553 public void onLockedBootComplete(int newUserId) {
554 if (bootCompleteLatch != null && userId == newUserId) {
555 bootCompleteLatch.countDown();
556 }
Sudheer Shanka53c23fd2016-08-17 19:34:58 -0700557 }
Sudheer Shanka2d0278b2017-07-12 18:12:31 -0700558 }, TAG);
Sudheer Shanka53c23fd2016-08-17 19:34:58 -0700559 }
560
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700561 private void registerBroadcastReceiver(final String action, final CountDownLatch latch,
562 final int userId) {
563 InstrumentationRegistry.getContext().registerReceiverAsUser(new BroadcastReceiver() {
564 @Override
565 public void onReceive(Context context, Intent intent) {
566 if (action.equals(intent.getAction()) && intent.getIntExtra(
567 Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL) == userId) {
568 latch.countDown();
569 }
570 }
571 }, UserHandle.of(userId), new IntentFilter(action), null, null);
572 }
573
Bookatz312da052019-04-11 09:24:54 -0700574 private class ProgressWaiter extends IProgressListener.Stub {
575 private final CountDownLatch mFinishedLatch = new CountDownLatch(1);
576
577 @Override
578 public void onStarted(int id, Bundle extras) {}
579
580 @Override
581 public void onProgress(int id, int progress, Bundle extras) {}
582
583 @Override
584 public void onFinished(int id, Bundle extras) {
585 mFinishedLatch.countDown();
586 }
587
588 public boolean waitForFinish(long timeoutSecs) {
589 try {
590 return mFinishedLatch.await(timeoutSecs, TimeUnit.SECONDS);
591 } catch (InterruptedException e) {
592 Log.e(TAG, "Thread interrupted unexpectedly.", e);
593 return false;
594 }
595 }
596 }
597
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700598 private void removeUser(int userId) {
599 try {
600 mUm.removeUser(userId);
601 final long startTime = System.currentTimeMillis();
Tony Makec7c6962017-05-26 15:38:09 +0100602 final long timeoutInMs = TIMEOUT_IN_SECOND * 1000;
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700603 while (mUm.getUserInfo(userId) != null &&
Tony Makec7c6962017-05-26 15:38:09 +0100604 System.currentTimeMillis() - startTime < timeoutInMs) {
605 TimeUnit.MILLISECONDS.sleep(CHECK_USER_REMOVED_INTERVAL_MS);
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700606 }
607 } catch (InterruptedException e) {
608 Thread.currentThread().interrupt();
609 } catch (Exception e) {
610 // Ignore
Sudheer Shanka53c23fd2016-08-17 19:34:58 -0700611 }
612 if (mUm.getUserInfo(userId) != null) {
613 mUsersToRemove.add(userId);
614 }
615 }
Bookatz52b12ac2019-02-28 17:29:26 -0800616
Bookatz312da052019-04-11 09:24:54 -0700617 private void attestTrue(String message, boolean assertion) {
618 if (!assertion) {
Bookatz52b12ac2019-02-28 17:29:26 -0800619 Log.w(TAG, message);
620 }
621 }
622
Bookatz312da052019-04-11 09:24:54 -0700623 private void attestFalse(String message, boolean assertion) {
624 attestTrue(message, !assertion);
Bookatz52b12ac2019-02-28 17:29:26 -0800625 }
John Reck62e5fea2016-10-12 15:27:52 -0700626}