blob: c458d1190e511f2fe62b1cd1ea3282365ee27f3c [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
jovanak5982cd92019-08-08 11:27:56 -070018import static org.junit.Assume.assumeTrue;
19
Sudheer Shanka53c23fd2016-08-17 19:34:58 -070020import android.app.ActivityManager;
Bookatz312da052019-04-11 09:24:54 -070021import android.app.ActivityTaskManager;
22import android.app.AppGlobals;
Sudheer Shanka53c23fd2016-08-17 19:34:58 -070023import android.app.IActivityManager;
Sudheer Shanka2c4522c2016-08-27 20:53:28 -070024import android.app.IStopUserCallback;
25import android.app.UserSwitchObserver;
Bookatz312da052019-04-11 09:24:54 -070026import android.app.WaitResult;
Sudheer Shanka53c23fd2016-08-17 19:34:58 -070027import android.content.BroadcastReceiver;
28import android.content.Context;
Bookatz312da052019-04-11 09:24:54 -070029import android.content.IIntentReceiver;
30import android.content.IIntentSender;
Sudheer Shanka53c23fd2016-08-17 19:34:58 -070031import android.content.Intent;
32import android.content.IntentFilter;
Bookatz312da052019-04-11 09:24:54 -070033import android.content.IntentSender;
34import android.content.pm.IPackageInstaller;
35import android.content.pm.PackageManager;
Sudheer Shanka53c23fd2016-08-17 19:34:58 -070036import android.content.pm.UserInfo;
Bookatz312da052019-04-11 09:24:54 -070037import android.os.Bundle;
38import android.os.IBinder;
39import android.os.IProgressListener;
Sudheer Shanka53c23fd2016-08-17 19:34:58 -070040import android.os.RemoteException;
Bookatz04d7ae52019-08-05 14:07:12 -070041import android.os.SystemProperties;
Sudheer Shanka53c23fd2016-08-17 19:34:58 -070042import android.os.UserHandle;
43import android.os.UserManager;
Bookatz04d7ae52019-08-05 14:07:12 -070044import android.perftests.utils.ShellHelper;
Bookatz52b12ac2019-02-28 17:29:26 -080045import android.util.Log;
Bookatz312da052019-04-11 09:24:54 -070046import android.view.WindowManagerGlobal;
KOUSHIK PANUGANTI130f0a52018-12-17 14:41:06 -080047
48import androidx.test.InstrumentationRegistry;
49import androidx.test.filters.LargeTest;
50import androidx.test.runner.AndroidJUnit4;
Sudheer Shanka53c23fd2016-08-17 19:34:58 -070051
52import org.junit.After;
53import org.junit.Before;
54import org.junit.Rule;
55import org.junit.Test;
56import org.junit.runner.RunWith;
57
58import java.util.ArrayList;
59import java.util.concurrent.CountDownLatch;
60import java.util.concurrent.TimeUnit;
61
Sudheer Shanka2c4522c2016-08-27 20:53:28 -070062/**
63 * Perf tests for user life cycle events.
64 *
65 * Running the tests:
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -070066 *
Sudheer Shanka2c4522c2016-08-27 20:53:28 -070067 * make MultiUserPerfTests &&
68 * adb install -r \
69 * ${ANDROID_PRODUCT_OUT}/data/app/MultiUserPerfTests/MultiUserPerfTests.apk &&
Sudheer Shanka2d0278b2017-07-12 18:12:31 -070070 * adb shell am instrument -e class android.multiuser.UserLifecycleTests \
KOUSHIK PANUGANTI130f0a52018-12-17 14:41:06 -080071 * -w com.android.perftests.multiuser/androidx.test.runner.AndroidJUnitRunner
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -070072 *
73 * or
74 *
Sudheer Shanka2d0278b2017-07-12 18:12:31 -070075 * bit MultiUserPerfTests:android.multiuser.UserLifecycleTests
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -070076 *
77 * 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 -070078 * But in either case, results can be checked on the device side 'adb logcat -s UserLifecycleTests'
Sudheer Shanka2c4522c2016-08-27 20:53:28 -070079 */
Sudheer Shanka53c23fd2016-08-17 19:34:58 -070080@LargeTest
81@RunWith(AndroidJUnit4.class)
Sudheer Shanka2d0278b2017-07-12 18:12:31 -070082public class UserLifecycleTests {
83 private static final String TAG = UserLifecycleTests.class.getSimpleName();
84
Bookatz312da052019-04-11 09:24:54 -070085 private static final int TIMEOUT_IN_SECOND = 30;
86 private static final int CHECK_USER_REMOVED_INTERVAL_MS = 200;
87
88 private static final String DUMMY_PACKAGE_NAME = "perftests.multiuser.apps.dummyapp";
Sudheer Shanka2c4522c2016-08-27 20:53:28 -070089
Bookatz04d7ae52019-08-05 14:07:12 -070090 // Copy of UserSystemPackageInstaller whitelist mode constants.
91 private static final String PACKAGE_WHITELIST_MODE_PROP =
92 "persist.debug.user.package_whitelist_mode";
93 private static final int USER_TYPE_PACKAGE_WHITELIST_MODE_DISABLE = 0;
94 private static final int USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE = 0b001;
95 private static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST = 0b100;
96 private static final int USER_TYPE_PACKAGE_WHITELIST_MODE_DEVICE_DEFAULT = -1;
97
Sudheer Shanka53c23fd2016-08-17 19:34:58 -070098 private UserManager mUm;
99 private ActivityManager mAm;
100 private IActivityManager mIam;
jovanak5982cd92019-08-08 11:27:56 -0700101 private PackageManager mPm;
Sudheer Shanka53c23fd2016-08-17 19:34:58 -0700102 private ArrayList<Integer> mUsersToRemove;
jovanak5982cd92019-08-08 11:27:56 -0700103 private boolean mHasManagedUserFeature;
Sudheer Shanka53c23fd2016-08-17 19:34:58 -0700104
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700105 private final BenchmarkRunner mRunner = new BenchmarkRunner();
Sudheer Shanka53c23fd2016-08-17 19:34:58 -0700106 @Rule
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700107 public BenchmarkResultsReporter mReporter = new BenchmarkResultsReporter(mRunner);
Sudheer Shanka53c23fd2016-08-17 19:34:58 -0700108
109 @Before
110 public void setUp() {
111 final Context context = InstrumentationRegistry.getContext();
112 mUm = UserManager.get(context);
113 mAm = context.getSystemService(ActivityManager.class);
Sudheer Shankadc589ac2016-11-10 15:30:17 -0800114 mIam = ActivityManager.getService();
Sudheer Shanka53c23fd2016-08-17 19:34:58 -0700115 mUsersToRemove = new ArrayList<>();
jovanak5982cd92019-08-08 11:27:56 -0700116 mPm = context.getPackageManager();
117 mHasManagedUserFeature = mPm.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS);
Sudheer Shanka53c23fd2016-08-17 19:34:58 -0700118 }
119
120 @After
121 public void tearDown() {
122 for (int userId : mUsersToRemove) {
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700123 try {
124 mUm.removeUser(userId);
125 } catch (Exception e) {
126 // Ignore
127 }
Sudheer Shanka53c23fd2016-08-17 19:34:58 -0700128 }
129 }
130
131 @Test
jovanak6e6c6bf2019-09-04 11:14:49 -0700132 public void createUser() {
133 while (mRunner.keepRunning()) {
134 final int userId = createUserNoFlags();
135
136 mRunner.pauseTiming();
137 removeUser(userId);
138 mRunner.resumeTiming();
139 }
140 }
141
142 @Test
Sudheer Shankaa319f8b2017-07-11 15:28:48 -0700143 public void createAndStartUser() throws Exception {
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700144 while (mRunner.keepRunning()) {
jovanak6e6c6bf2019-09-04 11:14:49 -0700145 final int userId = createUserNoFlags();
Sudheer Shanka53c23fd2016-08-17 19:34:58 -0700146
147 final CountDownLatch latch = new CountDownLatch(1);
Bookatz312da052019-04-11 09:24:54 -0700148 registerBroadcastReceiver(Intent.ACTION_USER_STARTED, latch, userId);
jovanak288a18f2019-12-17 17:25:26 -0800149 // Don't use this.startUserInBackgroundAndWaitForUnlock() since only waiting until
150 // ACTION_USER_STARTED.
Bookatz312da052019-04-11 09:24:54 -0700151 mIam.startUserInBackground(userId);
Tony Makec7c6962017-05-26 15:38:09 +0100152 latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
Sudheer Shanka53c23fd2016-08-17 19:34:58 -0700153
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700154 mRunner.pauseTiming();
Bookatz312da052019-04-11 09:24:54 -0700155 removeUser(userId);
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700156 mRunner.resumeTiming();
Sudheer Shanka53c23fd2016-08-17 19:34:58 -0700157 }
158 }
159
jovanak288a18f2019-12-17 17:25:26 -0800160 /**
161 * Measures the time until ACTION_USER_STARTED is received.
162 */
163 @Test
164 public void startUser() throws Exception {
165 while (mRunner.keepRunning()) {
166 mRunner.pauseTiming();
167 final int userId = createUserNoFlags();
168 final CountDownLatch latch = new CountDownLatch(1);
169 registerBroadcastReceiver(Intent.ACTION_USER_STARTED, latch, userId);
170 mRunner.resumeTiming();
171
172 mIam.startUserInBackground(userId);
173 latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
174
175 mRunner.pauseTiming();
176 removeUser(userId);
177 mRunner.resumeTiming();
178 }
179 }
180
181 /**
182 * Measures the time until unlock listener is triggered and user is unlocked.
183 */
184 @Test
185 public void startAndUnlockUser() throws Exception {
186 while (mRunner.keepRunning()) {
187 mRunner.pauseTiming();
188 final int userId = createUserNoFlags();
189 mRunner.resumeTiming();
190
191 // Waits for UserState.mUnlockProgress.finish().
192 startUserInBackgroundAndWaitForUnlock(userId);
193
194 mRunner.pauseTiming();
195 removeUser(userId);
196 mRunner.resumeTiming();
197 }
198 }
199
200
201
Sudheer Shanka53c23fd2016-08-17 19:34:58 -0700202 @Test
Sudheer Shankaa319f8b2017-07-11 15:28:48 -0700203 public void switchUser() throws Exception {
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700204 while (mRunner.keepRunning()) {
205 mRunner.pauseTiming();
Sudheer Shanka53c23fd2016-08-17 19:34:58 -0700206 final int startUser = mAm.getCurrentUser();
jovanak6e6c6bf2019-09-04 11:14:49 -0700207 final int userId = createUserNoFlags();
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700208 mRunner.resumeTiming();
Sudheer Shanka53c23fd2016-08-17 19:34:58 -0700209
Bookatz312da052019-04-11 09:24:54 -0700210 switchUser(userId);
Sudheer Shanka53c23fd2016-08-17 19:34:58 -0700211
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700212 mRunner.pauseTiming();
Sudheer Shanka53c23fd2016-08-17 19:34:58 -0700213 switchUser(startUser);
Bookatz312da052019-04-11 09:24:54 -0700214 removeUser(userId);
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700215 mRunner.resumeTiming();
Sudheer Shanka53c23fd2016-08-17 19:34:58 -0700216 }
217 }
218
Bookatz52b12ac2019-02-28 17:29:26 -0800219 /** Tests switching to an already-created, but no-longer-running, user. */
220 @Test
221 public void switchUser_stopped() throws Exception {
222 while (mRunner.keepRunning()) {
223 mRunner.pauseTiming();
224 final int startUser = mAm.getCurrentUser();
225 final int testUser = initializeNewUserAndSwitchBack(/* stopNewUser */ true);
226 final CountDownLatch latch = new CountDownLatch(1);
227 registerBroadcastReceiver(Intent.ACTION_USER_UNLOCKED, latch, testUser);
228 mRunner.resumeTiming();
229
230 mAm.switchUser(testUser);
231 boolean success = latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
232
233 mRunner.pauseTiming();
234 attestTrue("Failed to achieve 2nd ACTION_USER_UNLOCKED for user " + testUser, success);
235 switchUser(startUser);
236 removeUser(testUser);
237 mRunner.resumeTiming();
238 }
239 }
240
241 /** Tests switching to an already-created already-running non-owner user. */
242 @Test
243 public void switchUser_running() throws Exception {
244 while (mRunner.keepRunning()) {
245 mRunner.pauseTiming();
246 final int startUser = mAm.getCurrentUser();
247 final int testUser = initializeNewUserAndSwitchBack(/* stopNewUser */ false);
248 mRunner.resumeTiming();
249
250 switchUser(testUser);
251
252 mRunner.pauseTiming();
253 attestTrue("Failed to switch to user " + testUser, mAm.isUserRunning(testUser));
254 switchUser(startUser);
255 removeUser(testUser);
256 mRunner.resumeTiming();
257 }
258 }
259
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700260 @Test
Sudheer Shankaa319f8b2017-07-11 15:28:48 -0700261 public void stopUser() throws Exception {
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700262 while (mRunner.keepRunning()) {
263 mRunner.pauseTiming();
jovanak6e6c6bf2019-09-04 11:14:49 -0700264 final int userId = createUserNoFlags();
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700265 final CountDownLatch latch = new CountDownLatch(1);
Bookatz312da052019-04-11 09:24:54 -0700266 registerBroadcastReceiver(Intent.ACTION_USER_STARTED, latch, userId);
267 mIam.startUserInBackground(userId);
Tony Makec7c6962017-05-26 15:38:09 +0100268 latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700269 mRunner.resumeTiming();
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700270
Bookatz312da052019-04-11 09:24:54 -0700271 stopUser(userId, false);
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700272
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700273 mRunner.pauseTiming();
Bookatz312da052019-04-11 09:24:54 -0700274 removeUser(userId);
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700275 mRunner.resumeTiming();
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700276 }
277 }
278
279 @Test
Sudheer Shankaa319f8b2017-07-11 15:28:48 -0700280 public void lockedBootCompleted() throws Exception {
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700281 while (mRunner.keepRunning()) {
282 mRunner.pauseTiming();
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700283 final int startUser = mAm.getCurrentUser();
jovanak6e6c6bf2019-09-04 11:14:49 -0700284 final int userId = createUserNoFlags();
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700285 final CountDownLatch latch = new CountDownLatch(1);
Bookatz312da052019-04-11 09:24:54 -0700286 registerUserSwitchObserver(null, latch, userId);
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700287 mRunner.resumeTiming();
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700288
Bookatz312da052019-04-11 09:24:54 -0700289 mAm.switchUser(userId);
Tony Makec7c6962017-05-26 15:38:09 +0100290 latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700291
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700292 mRunner.pauseTiming();
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700293 switchUser(startUser);
Bookatz312da052019-04-11 09:24:54 -0700294 removeUser(userId);
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700295 mRunner.resumeTiming();
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700296 }
297 }
298
299 @Test
Bookatz5df3c642019-04-11 09:22:49 -0700300 public void ephemeralUserStopped() throws Exception {
301 while (mRunner.keepRunning()) {
302 mRunner.pauseTiming();
303 final int startUser = mAm.getCurrentUser();
jovanak6e6c6bf2019-09-04 11:14:49 -0700304 final int userId = createUserWithFlags(UserInfo.FLAG_EPHEMERAL | UserInfo.FLAG_DEMO);
Bookatz312da052019-04-11 09:24:54 -0700305 switchUser(userId);
Bookatz5df3c642019-04-11 09:22:49 -0700306 final CountDownLatch latch = new CountDownLatch(1);
307 InstrumentationRegistry.getContext().registerReceiver(new BroadcastReceiver() {
308 @Override
309 public void onReceive(Context context, Intent intent) {
310 if (Intent.ACTION_USER_STOPPED.equals(intent.getAction()) && intent.getIntExtra(
Bookatz312da052019-04-11 09:24:54 -0700311 Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL) == userId) {
Bookatz5df3c642019-04-11 09:22:49 -0700312 latch.countDown();
313 }
314 }
315 }, new IntentFilter(Intent.ACTION_USER_STOPPED));
316 final CountDownLatch switchLatch = new CountDownLatch(1);
317 registerUserSwitchObserver(switchLatch, null, startUser);
318 mRunner.resumeTiming();
319
320 mAm.switchUser(startUser);
321 latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
322
323 mRunner.pauseTiming();
324 switchLatch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
Bookatz312da052019-04-11 09:24:54 -0700325 removeUser(userId);
Bookatz5df3c642019-04-11 09:22:49 -0700326 mRunner.resumeTiming();
327 }
328 }
329
Bookatz312da052019-04-11 09:24:54 -0700330 /** Tests creating a new profile. */
331 @Test
332 public void managedProfileCreate() throws Exception {
jovanak5982cd92019-08-08 11:27:56 -0700333 assumeTrue(mHasManagedUserFeature);
334
Bookatz312da052019-04-11 09:24:54 -0700335 while (mRunner.keepRunning()) {
336 final int userId = createManagedProfile();
337
338 mRunner.pauseTiming();
339 attestTrue("Failed creating profile " + userId, mUm.isManagedProfile(userId));
340 removeUser(userId);
341 mRunner.resumeTiming();
342 }
343 }
344
345 /** Tests starting (unlocking) a newly-created profile. */
Bookatz5df3c642019-04-11 09:22:49 -0700346 @Test
Sudheer Shankaa319f8b2017-07-11 15:28:48 -0700347 public void managedProfileUnlock() throws Exception {
jovanak5982cd92019-08-08 11:27:56 -0700348 assumeTrue(mHasManagedUserFeature);
349
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700350 while (mRunner.keepRunning()) {
351 mRunner.pauseTiming();
Bookatz312da052019-04-11 09:24:54 -0700352 final int userId = createManagedProfile();
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700353 mRunner.resumeTiming();
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700354
jovanak288a18f2019-12-17 17:25:26 -0800355 startUserInBackgroundAndWaitForUnlock(userId);
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700356
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700357 mRunner.pauseTiming();
Bookatz312da052019-04-11 09:24:54 -0700358 removeUser(userId);
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700359 mRunner.resumeTiming();
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700360 }
361 }
362
Bookatz312da052019-04-11 09:24:54 -0700363 /** Tests starting (unlocking) an already-created, but no-longer-running, profile. */
Bookatz57908d92019-03-29 10:40:10 -0700364 @Test
365 public void managedProfileUnlock_stopped() throws Exception {
jovanak5982cd92019-08-08 11:27:56 -0700366 assumeTrue(mHasManagedUserFeature);
367
Bookatz57908d92019-03-29 10:40:10 -0700368 while (mRunner.keepRunning()) {
369 mRunner.pauseTiming();
Bookatz312da052019-04-11 09:24:54 -0700370 final int userId = createManagedProfile();
Bookatz57908d92019-03-29 10:40:10 -0700371 // Start the profile initially, then stop it. Similar to setQuietModeEnabled.
jovanak288a18f2019-12-17 17:25:26 -0800372 startUserInBackgroundAndWaitForUnlock(userId);
Bookatz312da052019-04-11 09:24:54 -0700373 stopUser(userId, true);
Bookatz57908d92019-03-29 10:40:10 -0700374 mRunner.resumeTiming();
375
jovanak288a18f2019-12-17 17:25:26 -0800376 startUserInBackgroundAndWaitForUnlock(userId);
Bookatz57908d92019-03-29 10:40:10 -0700377
378 mRunner.pauseTiming();
Bookatz312da052019-04-11 09:24:54 -0700379 removeUser(userId);
Bookatz57908d92019-03-29 10:40:10 -0700380 mRunner.resumeTiming();
381 }
382 }
383
Bookatz312da052019-04-11 09:24:54 -0700384 /**
385 * Tests starting (unlocking) and launching an already-installed app in a newly-created profile.
386 */
387 @Test
388 public void managedProfileUnlockAndLaunchApp() throws Exception {
jovanak5982cd92019-08-08 11:27:56 -0700389 assumeTrue(mHasManagedUserFeature);
390
Bookatz312da052019-04-11 09:24:54 -0700391 while (mRunner.keepRunning()) {
392 mRunner.pauseTiming();
393 final int userId = createManagedProfile();
394 WindowManagerGlobal.getWindowManagerService().dismissKeyguard(null, null);
395 installPreexistingApp(userId, DUMMY_PACKAGE_NAME);
396 mRunner.resumeTiming();
Tony Makec7c6962017-05-26 15:38:09 +0100397
jovanak288a18f2019-12-17 17:25:26 -0800398 startUserInBackgroundAndWaitForUnlock(userId);
Bookatz312da052019-04-11 09:24:54 -0700399 startApp(userId, DUMMY_PACKAGE_NAME);
400
401 mRunner.pauseTiming();
402 removeUser(userId);
403 mRunner.resumeTiming();
404 }
405 }
406
Bookatz5f870192019-05-30 10:04:30 -0700407 /**
408 * Tests starting (unlocking) and launching a previously-launched app
409 * in an already-created, but no-longer-running, profile.
410 * A sort of combination of {@link #managedProfileUnlockAndLaunchApp} and
411 * {@link #managedProfileUnlock_stopped}}.
412 */
413 @Test
414 public void managedProfileUnlockAndLaunchApp_stopped() throws Exception {
jovanak5982cd92019-08-08 11:27:56 -0700415 assumeTrue(mHasManagedUserFeature);
416
Bookatz5f870192019-05-30 10:04:30 -0700417 while (mRunner.keepRunning()) {
418 mRunner.pauseTiming();
419 final int userId = createManagedProfile();
420 WindowManagerGlobal.getWindowManagerService().dismissKeyguard(null, null);
421 installPreexistingApp(userId, DUMMY_PACKAGE_NAME);
jovanak288a18f2019-12-17 17:25:26 -0800422 startUserInBackgroundAndWaitForUnlock(userId);
Bookatz5f870192019-05-30 10:04:30 -0700423 startApp(userId, DUMMY_PACKAGE_NAME);
424 stopUser(userId, true);
425 TimeUnit.SECONDS.sleep(1); // Brief cool-down before re-starting profile.
426 mRunner.resumeTiming();
427
jovanak288a18f2019-12-17 17:25:26 -0800428 startUserInBackgroundAndWaitForUnlock(userId);
Bookatz5f870192019-05-30 10:04:30 -0700429 startApp(userId, DUMMY_PACKAGE_NAME);
430
431 mRunner.pauseTiming();
432 removeUser(userId);
433 mRunner.resumeTiming();
434 }
435 }
436
Bookatz312da052019-04-11 09:24:54 -0700437 /** Tests installing a pre-existing app in a newly-created profile. */
438 @Test
439 public void managedProfileInstall() throws Exception {
jovanak5982cd92019-08-08 11:27:56 -0700440 assumeTrue(mHasManagedUserFeature);
441
Bookatz312da052019-04-11 09:24:54 -0700442 while (mRunner.keepRunning()) {
443 mRunner.pauseTiming();
444 final int userId = createManagedProfile();
445 mRunner.resumeTiming();
446
447 installPreexistingApp(userId, DUMMY_PACKAGE_NAME);
448
449 mRunner.pauseTiming();
450 removeUser(userId);
451 mRunner.resumeTiming();
452 }
453 }
454
455 /**
456 * Tests creating a new profile, starting (unlocking) it, installing an app,
457 * and launching that app in it.
458 */
459 @Test
460 public void managedProfileCreateUnlockInstallAndLaunchApp() throws Exception {
jovanak5982cd92019-08-08 11:27:56 -0700461 assumeTrue(mHasManagedUserFeature);
462
Bookatz312da052019-04-11 09:24:54 -0700463 while (mRunner.keepRunning()) {
464 mRunner.pauseTiming();
465 WindowManagerGlobal.getWindowManagerService().dismissKeyguard(null, null);
466 mRunner.resumeTiming();
467
468 final int userId = createManagedProfile();
jovanak288a18f2019-12-17 17:25:26 -0800469 startUserInBackgroundAndWaitForUnlock(userId);
Bookatz312da052019-04-11 09:24:54 -0700470 installPreexistingApp(userId, DUMMY_PACKAGE_NAME);
471 startApp(userId, DUMMY_PACKAGE_NAME);
472
473 mRunner.pauseTiming();
474 removeUser(userId);
475 mRunner.resumeTiming();
476 }
477 }
478
479 /** Tests stopping a profile. */
Tony Makec7c6962017-05-26 15:38:09 +0100480 @Test
Sudheer Shankaa319f8b2017-07-11 15:28:48 -0700481 public void managedProfileStopped() throws Exception {
jovanak5982cd92019-08-08 11:27:56 -0700482 assumeTrue(mHasManagedUserFeature);
483
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700484 while (mRunner.keepRunning()) {
485 mRunner.pauseTiming();
Bookatz312da052019-04-11 09:24:54 -0700486 final int userId = createManagedProfile();
jovanak288a18f2019-12-17 17:25:26 -0800487 startUserInBackgroundAndWaitForUnlock(userId);
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700488 mRunner.resumeTiming();
Tony Makec7c6962017-05-26 15:38:09 +0100489
Bookatz312da052019-04-11 09:24:54 -0700490 stopUser(userId, true);
Tony Makec7c6962017-05-26 15:38:09 +0100491
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700492 mRunner.pauseTiming();
Bookatz312da052019-04-11 09:24:54 -0700493 removeUser(userId);
Sudheer Shanka5f76e1f2017-06-25 19:40:53 -0700494 mRunner.resumeTiming();
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700495 }
496 }
497
Bookatz04d7ae52019-08-05 14:07:12 -0700498 // TODO: This is just a POC. Do this properly and add more.
499 /** Tests starting (unlocking) a newly-created profile using the user-type-pkg-whitelist. */
500 @Test
501 public void managedProfileUnlock_usingWhitelist() throws Exception {
502 assumeTrue(mHasManagedUserFeature);
503 final int origMode = getUserTypePackageWhitelistMode();
504 setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE
505 | USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST);
506
507 try {
508 while (mRunner.keepRunning()) {
509 mRunner.pauseTiming();
510 final int userId = createManagedProfile();
511 mRunner.resumeTiming();
512
jovanak288a18f2019-12-17 17:25:26 -0800513 startUserInBackgroundAndWaitForUnlock(userId);
Bookatz04d7ae52019-08-05 14:07:12 -0700514
515 mRunner.pauseTiming();
516 removeUser(userId);
517 mRunner.resumeTiming();
518 }
519 } finally {
520 setUserTypePackageWhitelistMode(origMode);
521 }
522 }
523 /** Tests starting (unlocking) a newly-created profile NOT using the user-type-pkg-whitelist. */
524 @Test
525 public void managedProfileUnlock_notUsingWhitelist() throws Exception {
526 assumeTrue(mHasManagedUserFeature);
527 final int origMode = getUserTypePackageWhitelistMode();
528 setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_DISABLE);
529
530 try {
531 while (mRunner.keepRunning()) {
532 mRunner.pauseTiming();
533 final int userId = createManagedProfile();
534 mRunner.resumeTiming();
535
jovanak288a18f2019-12-17 17:25:26 -0800536 startUserInBackgroundAndWaitForUnlock(userId);
Bookatz04d7ae52019-08-05 14:07:12 -0700537
538 mRunner.pauseTiming();
539 removeUser(userId);
540 mRunner.resumeTiming();
541 }
542 } finally {
543 setUserTypePackageWhitelistMode(origMode);
544 }
545 }
546
Bookatz312da052019-04-11 09:24:54 -0700547 /** Creates a new user, returning its userId. */
jovanak6e6c6bf2019-09-04 11:14:49 -0700548 private int createUserNoFlags() {
549 return createUserWithFlags(/* flags= */ 0);
Bookatz312da052019-04-11 09:24:54 -0700550 }
551
552 /** Creates a new user with the given flags, returning its userId. */
jovanak6e6c6bf2019-09-04 11:14:49 -0700553 private int createUserWithFlags(int flags) {
Bookatz312da052019-04-11 09:24:54 -0700554 int userId = mUm.createUser("TestUser", flags).id;
555 mUsersToRemove.add(userId);
556 return userId;
557 }
558
559 /** Creates a managed (work) profile under the current user, returning its userId. */
560 private int createManagedProfile() {
561 final UserInfo userInfo = mUm.createProfileForUser("TestProfile",
Bookatz029832a2019-10-04 16:50:22 -0700562 UserManager.USER_TYPE_PROFILE_MANAGED, /* flags */ 0, mAm.getCurrentUser());
Bookatz04d7ae52019-08-05 14:07:12 -0700563 if (userInfo == null) {
564 throw new IllegalStateException("Creating managed profile failed. Most likely there is "
565 + "already a pre-existing profile on the device.");
566 }
Bookatz312da052019-04-11 09:24:54 -0700567 mUsersToRemove.add(userInfo.id);
568 return userInfo.id;
569 }
570
571 /**
jovanak288a18f2019-12-17 17:25:26 -0800572 * Start user in background and wait for it to unlock by waiting for
573 * UserState.mUnlockProgress.finish().
574 * <p> To start in foreground instead, see {@link #switchUser(int)}.
575 * <p> This should always be used for profiles since profiles cannot be started in foreground.
Bookatz312da052019-04-11 09:24:54 -0700576 */
jovanak288a18f2019-12-17 17:25:26 -0800577 private void startUserInBackgroundAndWaitForUnlock(int userId) {
Bookatz312da052019-04-11 09:24:54 -0700578 final ProgressWaiter waiter = new ProgressWaiter();
579 try {
580 mIam.startUserInBackgroundWithListener(userId, waiter);
581 boolean success = waiter.waitForFinish(TIMEOUT_IN_SECOND);
582 attestTrue("Failed to start user " + userId + " in background.", success);
583 } catch (RemoteException e) {
jovanak288a18f2019-12-17 17:25:26 -0800584 Log.e(TAG, "startUserInBackgroundAndWaitForUnlock failed", e);
Bookatz312da052019-04-11 09:24:54 -0700585 }
586 }
587
588 /** Starts the given user in the foreground. */
Sudheer Shanka53c23fd2016-08-17 19:34:58 -0700589 private void switchUser(int userId) throws Exception {
590 final CountDownLatch latch = new CountDownLatch(1);
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700591 registerUserSwitchObserver(latch, null, userId);
Sudheer Shanka53c23fd2016-08-17 19:34:58 -0700592 mAm.switchUser(userId);
Tony Makec7c6962017-05-26 15:38:09 +0100593 latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
Sudheer Shanka53c23fd2016-08-17 19:34:58 -0700594 }
595
Tony Makec7c6962017-05-26 15:38:09 +0100596 private void stopUser(int userId, boolean force) throws Exception {
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700597 final CountDownLatch latch = new CountDownLatch(1);
Tony Makec7c6962017-05-26 15:38:09 +0100598 mIam.stopUser(userId, force /* force */, new IStopUserCallback.Stub() {
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700599 @Override
600 public void userStopped(int userId) throws RemoteException {
601 latch.countDown();
602 }
Sudheer Shanka53c23fd2016-08-17 19:34:58 -0700603
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700604 @Override
605 public void userStopAborted(int userId) throws RemoteException {
606 }
607 });
Tony Makec7c6962017-05-26 15:38:09 +0100608 latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700609 }
610
Bookatz52b12ac2019-02-28 17:29:26 -0800611 /**
612 * Creates a user and waits for its ACTION_USER_UNLOCKED.
613 * Then switches to back to the original user and waits for its switchUser() to finish.
614 *
615 * @param stopNewUser whether to stop the new user after switching to otherUser.
616 * @return userId of the newly created user.
617 */
618 private int initializeNewUserAndSwitchBack(boolean stopNewUser) throws Exception {
619 final int origUser = mAm.getCurrentUser();
620 // First, create and switch to testUser, waiting for its ACTION_USER_UNLOCKED
jovanak6e6c6bf2019-09-04 11:14:49 -0700621 final int testUser = createUserNoFlags();
Bookatz52b12ac2019-02-28 17:29:26 -0800622 final CountDownLatch latch1 = new CountDownLatch(1);
623 registerBroadcastReceiver(Intent.ACTION_USER_UNLOCKED, latch1, testUser);
624 mAm.switchUser(testUser);
625 attestTrue("Failed to achieve initial ACTION_USER_UNLOCKED for user " + testUser,
626 latch1.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS));
627
628 // Second, switch back to origUser, waiting merely for switchUser() to finish
629 switchUser(origUser);
630 attestTrue("Didn't switch back to user, " + origUser, origUser == mAm.getCurrentUser());
631
632 if (stopNewUser) {
633 stopUser(testUser, true);
634 attestFalse("Failed to stop user " + testUser, mAm.isUserRunning(testUser));
635 }
636
637 return testUser;
638 }
639
Bookatz312da052019-04-11 09:24:54 -0700640 /**
641 * Installs the given package in the given user.
642 */
643 private void installPreexistingApp(int userId, String packageName) throws RemoteException {
644 final CountDownLatch latch = new CountDownLatch(1);
645
646 final IntentSender sender = new IntentSender((IIntentSender) new IIntentSender.Stub() {
647 @Override
648 public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
649 IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
650 latch.countDown();
651 }
652 });
653
654 final IPackageInstaller installer = AppGlobals.getPackageManager().getPackageInstaller();
Philip P. Moltmannbfcffa02019-05-13 17:10:46 -0700655 installer.installExistingPackage(packageName,
656 PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS,
657 PackageManager.INSTALL_REASON_UNKNOWN, sender, userId, null);
Bookatz312da052019-04-11 09:24:54 -0700658
659 try {
660 latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
661 } catch (InterruptedException e) {
662 Log.e(TAG, "Thread interrupted unexpectedly.", e);
663 }
664 }
665
666 /**
667 * Launches the given package in the given user.
668 * Make sure the keyguard has been dismissed prior to calling.
669 */
670 private void startApp(int userId, String packageName) throws RemoteException {
671 final Context context = InstrumentationRegistry.getContext();
Robert Horvath5f47c592019-07-24 16:28:29 +0200672 final WaitResult result = ActivityTaskManager.getService().startActivityAndWait(null,
Philip P. Moltmann9c5226f2020-01-10 08:53:43 -0800673 context.getPackageName(), context.getFeatureId(),
Robert Horvath5f47c592019-07-24 16:28:29 +0200674 context.getPackageManager().getLaunchIntentForPackage(packageName), null, null,
675 null, 0, 0, null, null, userId);
Bookatz312da052019-04-11 09:24:54 -0700676 attestTrue("User " + userId + " failed to start " + packageName,
677 result.result == ActivityManager.START_SUCCESS);
678 }
679
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700680 private void registerUserSwitchObserver(final CountDownLatch switchLatch,
681 final CountDownLatch bootCompleteLatch, final int userId) throws Exception {
Sudheer Shankadc589ac2016-11-10 15:30:17 -0800682 ActivityManager.getService().registerUserSwitchObserver(
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700683 new UserSwitchObserver() {
Sudheer Shanka53c23fd2016-08-17 19:34:58 -0700684 @Override
685 public void onUserSwitchComplete(int newUserId) throws RemoteException {
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700686 if (switchLatch != null && userId == newUserId) {
687 switchLatch.countDown();
688 }
Sudheer Shanka53c23fd2016-08-17 19:34:58 -0700689 }
690
691 @Override
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700692 public void onLockedBootComplete(int newUserId) {
693 if (bootCompleteLatch != null && userId == newUserId) {
694 bootCompleteLatch.countDown();
695 }
Sudheer Shanka53c23fd2016-08-17 19:34:58 -0700696 }
Sudheer Shanka2d0278b2017-07-12 18:12:31 -0700697 }, TAG);
Sudheer Shanka53c23fd2016-08-17 19:34:58 -0700698 }
699
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700700 private void registerBroadcastReceiver(final String action, final CountDownLatch latch,
701 final int userId) {
702 InstrumentationRegistry.getContext().registerReceiverAsUser(new BroadcastReceiver() {
703 @Override
704 public void onReceive(Context context, Intent intent) {
705 if (action.equals(intent.getAction()) && intent.getIntExtra(
706 Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL) == userId) {
707 latch.countDown();
708 }
709 }
710 }, UserHandle.of(userId), new IntentFilter(action), null, null);
711 }
712
Bookatz312da052019-04-11 09:24:54 -0700713 private class ProgressWaiter extends IProgressListener.Stub {
714 private final CountDownLatch mFinishedLatch = new CountDownLatch(1);
715
716 @Override
717 public void onStarted(int id, Bundle extras) {}
718
719 @Override
720 public void onProgress(int id, int progress, Bundle extras) {}
721
722 @Override
723 public void onFinished(int id, Bundle extras) {
724 mFinishedLatch.countDown();
725 }
726
727 public boolean waitForFinish(long timeoutSecs) {
728 try {
729 return mFinishedLatch.await(timeoutSecs, TimeUnit.SECONDS);
730 } catch (InterruptedException e) {
731 Log.e(TAG, "Thread interrupted unexpectedly.", e);
732 return false;
733 }
734 }
735 }
736
Bookatz04d7ae52019-08-05 14:07:12 -0700737 /** Gets the PACKAGE_WHITELIST_MODE_PROP System Property. */
738 private int getUserTypePackageWhitelistMode() {
739 return SystemProperties.getInt(PACKAGE_WHITELIST_MODE_PROP,
740 USER_TYPE_PACKAGE_WHITELIST_MODE_DEVICE_DEFAULT);
741 }
742
743 /** Sets the PACKAGE_WHITELIST_MODE_PROP System Property to the given value. */
744 private void setUserTypePackageWhitelistMode(int mode) {
745 String result = ShellHelper.runShellCommand(
746 String.format("setprop %s %d", PACKAGE_WHITELIST_MODE_PROP, mode));
747 attestFalse("Failed to set sysprop " + PACKAGE_WHITELIST_MODE_PROP + ": " + result,
748 result != null && result.contains("Failed"));
749 }
750
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700751 private void removeUser(int userId) {
752 try {
753 mUm.removeUser(userId);
754 final long startTime = System.currentTimeMillis();
Tony Makec7c6962017-05-26 15:38:09 +0100755 final long timeoutInMs = TIMEOUT_IN_SECOND * 1000;
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700756 while (mUm.getUserInfo(userId) != null &&
Tony Makec7c6962017-05-26 15:38:09 +0100757 System.currentTimeMillis() - startTime < timeoutInMs) {
758 TimeUnit.MILLISECONDS.sleep(CHECK_USER_REMOVED_INTERVAL_MS);
Sudheer Shanka2c4522c2016-08-27 20:53:28 -0700759 }
760 } catch (InterruptedException e) {
761 Thread.currentThread().interrupt();
762 } catch (Exception e) {
763 // Ignore
Sudheer Shanka53c23fd2016-08-17 19:34:58 -0700764 }
765 if (mUm.getUserInfo(userId) != null) {
766 mUsersToRemove.add(userId);
767 }
768 }
Bookatz52b12ac2019-02-28 17:29:26 -0800769
Bookatz312da052019-04-11 09:24:54 -0700770 private void attestTrue(String message, boolean assertion) {
771 if (!assertion) {
Bookatz52b12ac2019-02-28 17:29:26 -0800772 Log.w(TAG, message);
773 }
774 }
775
Bookatz312da052019-04-11 09:24:54 -0700776 private void attestFalse(String message, boolean assertion) {
777 attestTrue(message, !assertion);
Bookatz52b12ac2019-02-28 17:29:26 -0800778 }
John Reck62e5fea2016-10-12 15:27:52 -0700779}