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 */ 16package android.multiuser; 17 18import android.app.ActivityManager; 19import android.app.IActivityManager; 20import android.app.IStopUserCallback; 21import android.app.UserSwitchObserver; 22import android.content.BroadcastReceiver; 23import android.content.Context; 24import android.content.Intent; 25import android.content.IntentFilter; 26import android.content.pm.UserInfo; 27import android.os.RemoteException; 28import android.os.UserHandle; 29import android.os.UserManager; 30import android.support.test.InstrumentationRegistry; 31import android.support.test.filters.LargeTest; 32import android.support.test.runner.AndroidJUnit4; 33 34import org.junit.After; 35import org.junit.Before; 36import org.junit.Rule; 37import org.junit.Test; 38import org.junit.runner.RunWith; 39 40import java.util.ArrayList; 41import java.util.concurrent.CountDownLatch; 42import java.util.concurrent.TimeUnit; 43 44/** 45 * Perf tests for user life cycle events. 46 * 47 * Running the tests: 48 * 49 * make MultiUserPerfTests && 50 * adb install -r \ 51 * ${ANDROID_PRODUCT_OUT}/data/app/MultiUserPerfTests/MultiUserPerfTests.apk && 52 * adb shell am instrument -e class android.multiuser.UserLifecycleTests \ 53 * -w com.android.perftests.multiuser/android.support.test.runner.AndroidJUnitRunner 54 * 55 * or 56 * 57 * bit MultiUserPerfTests:android.multiuser.UserLifecycleTests 58 * 59 * Note: If you use bit for running the tests, benchmark results won't be printed on the host side. 60 * But in either case, results can be checked on the device side 'adb logcat -s UserLifecycleTests' 61 */ 62@LargeTest 63@RunWith(AndroidJUnit4.class) 64public class UserLifecycleTests { 65 private static final String TAG = UserLifecycleTests.class.getSimpleName(); 66 67 private final int TIMEOUT_IN_SECOND = 30; 68 private final int CHECK_USER_REMOVED_INTERVAL_MS = 200; 69 70 private UserManager mUm; 71 private ActivityManager mAm; 72 private IActivityManager mIam; 73 private ArrayList<Integer> mUsersToRemove; 74 75 private final BenchmarkRunner mRunner = new BenchmarkRunner(); 76 @Rule 77 public BenchmarkResultsReporter mReporter = new BenchmarkResultsReporter(mRunner); 78 79 @Before 80 public void setUp() { 81 final Context context = InstrumentationRegistry.getContext(); 82 mUm = UserManager.get(context); 83 mAm = context.getSystemService(ActivityManager.class); 84 mIam = ActivityManager.getService(); 85 mUsersToRemove = new ArrayList<>(); 86 } 87 88 @After 89 public void tearDown() { 90 for (int userId : mUsersToRemove) { 91 try { 92 mUm.removeUser(userId); 93 } catch (Exception e) { 94 // Ignore 95 } 96 } 97 } 98 99 @Test 100 public void createAndStartUser() throws Exception { 101 while (mRunner.keepRunning()) { 102 final UserInfo userInfo = mUm.createUser("TestUser", 0); 103 104 final CountDownLatch latch = new CountDownLatch(1); 105 registerBroadcastReceiver(Intent.ACTION_USER_STARTED, latch, userInfo.id); 106 mIam.startUserInBackground(userInfo.id); 107 latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS); 108 109 mRunner.pauseTiming(); 110 removeUser(userInfo.id); 111 mRunner.resumeTiming(); 112 } 113 } 114 115 @Test 116 public void switchUser() throws Exception { 117 while (mRunner.keepRunning()) { 118 mRunner.pauseTiming(); 119 final int startUser = mAm.getCurrentUser(); 120 final UserInfo userInfo = mUm.createUser("TestUser", 0); 121 mRunner.resumeTiming(); 122 123 switchUser(userInfo.id); 124 125 mRunner.pauseTiming(); 126 switchUser(startUser); 127 removeUser(userInfo.id); 128 mRunner.resumeTiming(); 129 } 130 } 131 132 @Test 133 public void stopUser() throws Exception { 134 while (mRunner.keepRunning()) { 135 mRunner.pauseTiming(); 136 final UserInfo userInfo = mUm.createUser("TestUser", 0); 137 final CountDownLatch latch = new CountDownLatch(1); 138 registerBroadcastReceiver(Intent.ACTION_USER_STARTED, latch, userInfo.id); 139 mIam.startUserInBackground(userInfo.id); 140 latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS); 141 mRunner.resumeTiming(); 142 143 stopUser(userInfo.id, false); 144 145 mRunner.pauseTiming(); 146 removeUser(userInfo.id); 147 mRunner.resumeTiming(); 148 } 149 } 150 151 @Test 152 public void lockedBootCompleted() throws Exception { 153 while (mRunner.keepRunning()) { 154 mRunner.pauseTiming(); 155 final int startUser = mAm.getCurrentUser(); 156 final UserInfo userInfo = mUm.createUser("TestUser", 0); 157 final CountDownLatch latch = new CountDownLatch(1); 158 registerUserSwitchObserver(null, latch, userInfo.id); 159 mRunner.resumeTiming(); 160 161 mAm.switchUser(userInfo.id); 162 latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS); 163 164 mRunner.pauseTiming(); 165 switchUser(startUser); 166 removeUser(userInfo.id); 167 mRunner.resumeTiming(); 168 } 169 } 170 171 @Test 172 public void managedProfileUnlock() throws Exception { 173 while (mRunner.keepRunning()) { 174 mRunner.pauseTiming(); 175 final UserInfo userInfo = mUm.createProfileForUser("TestUser", 176 UserInfo.FLAG_MANAGED_PROFILE, mAm.getCurrentUser()); 177 final CountDownLatch latch = new CountDownLatch(1); 178 registerBroadcastReceiver(Intent.ACTION_USER_UNLOCKED, latch, userInfo.id); 179 mRunner.resumeTiming(); 180 181 mIam.startUserInBackground(userInfo.id); 182 latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS); 183 184 mRunner.pauseTiming(); 185 removeUser(userInfo.id); 186 mRunner.resumeTiming(); 187 } 188 } 189 190 @Test 191 public void ephemeralUserStopped() throws Exception { 192 while (mRunner.keepRunning()) { 193 mRunner.pauseTiming(); 194 final int startUser = mAm.getCurrentUser(); 195 final UserInfo userInfo = mUm.createUser("TestUser", 196 UserInfo.FLAG_EPHEMERAL | UserInfo.FLAG_DEMO); 197 switchUser(userInfo.id); 198 final CountDownLatch latch = new CountDownLatch(1); 199 InstrumentationRegistry.getContext().registerReceiver(new BroadcastReceiver() { 200 @Override 201 public void onReceive(Context context, Intent intent) { 202 if (Intent.ACTION_USER_STOPPED.equals(intent.getAction()) && intent.getIntExtra( 203 Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL) == userInfo.id) { 204 latch.countDown(); 205 } 206 } 207 }, new IntentFilter(Intent.ACTION_USER_STOPPED)); 208 final CountDownLatch switchLatch = new CountDownLatch(1); 209 registerUserSwitchObserver(switchLatch, null, startUser); 210 mRunner.resumeTiming(); 211 212 mAm.switchUser(startUser); 213 latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS); 214 215 mRunner.pauseTiming(); 216 switchLatch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS); 217 removeUser(userInfo.id); 218 mRunner.resumeTiming(); 219 } 220 } 221 222 @Test 223 public void managedProfileStopped() throws Exception { 224 while (mRunner.keepRunning()) { 225 mRunner.pauseTiming(); 226 final UserInfo userInfo = mUm.createProfileForUser("TestUser", 227 UserInfo.FLAG_MANAGED_PROFILE, mAm.getCurrentUser()); 228 final CountDownLatch latch = new CountDownLatch(1); 229 registerBroadcastReceiver(Intent.ACTION_USER_UNLOCKED, latch, userInfo.id); 230 mIam.startUserInBackground(userInfo.id); 231 latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS); 232 mRunner.resumeTiming(); 233 234 stopUser(userInfo.id, true); 235 236 mRunner.pauseTiming(); 237 removeUser(userInfo.id); 238 mRunner.resumeTiming(); 239 } 240 } 241 242 private void switchUser(int userId) throws Exception { 243 final CountDownLatch latch = new CountDownLatch(1); 244 registerUserSwitchObserver(latch, null, userId); 245 mAm.switchUser(userId); 246 latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS); 247 } 248 249 private void stopUser(int userId, boolean force) throws Exception { 250 final CountDownLatch latch = new CountDownLatch(1); 251 mIam.stopUser(userId, force /* force */, new IStopUserCallback.Stub() { 252 @Override 253 public void userStopped(int userId) throws RemoteException { 254 latch.countDown(); 255 } 256 257 @Override 258 public void userStopAborted(int userId) throws RemoteException { 259 } 260 }); 261 latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS); 262 } 263 264 private void registerUserSwitchObserver(final CountDownLatch switchLatch, 265 final CountDownLatch bootCompleteLatch, final int userId) throws Exception { 266 ActivityManager.getService().registerUserSwitchObserver( 267 new UserSwitchObserver() { 268 @Override 269 public void onUserSwitchComplete(int newUserId) throws RemoteException { 270 if (switchLatch != null && userId == newUserId) { 271 switchLatch.countDown(); 272 } 273 } 274 275 @Override 276 public void onLockedBootComplete(int newUserId) { 277 if (bootCompleteLatch != null && userId == newUserId) { 278 bootCompleteLatch.countDown(); 279 } 280 } 281 }, TAG); 282 } 283 284 private void registerBroadcastReceiver(final String action, final CountDownLatch latch, 285 final int userId) { 286 InstrumentationRegistry.getContext().registerReceiverAsUser(new BroadcastReceiver() { 287 @Override 288 public void onReceive(Context context, Intent intent) { 289 if (action.equals(intent.getAction()) && intent.getIntExtra( 290 Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL) == userId) { 291 latch.countDown(); 292 } 293 } 294 }, UserHandle.of(userId), new IntentFilter(action), null, null); 295 } 296 297 private void removeUser(int userId) { 298 try { 299 mUm.removeUser(userId); 300 final long startTime = System.currentTimeMillis(); 301 final long timeoutInMs = TIMEOUT_IN_SECOND * 1000; 302 while (mUm.getUserInfo(userId) != null && 303 System.currentTimeMillis() - startTime < timeoutInMs) { 304 TimeUnit.MILLISECONDS.sleep(CHECK_USER_REMOVED_INTERVAL_MS); 305 } 306 } catch (InterruptedException e) { 307 Thread.currentThread().interrupt(); 308 } catch (Exception e) { 309 // Ignore 310 } 311 if (mUm.getUserInfo(userId) != null) { 312 mUsersToRemove.add(userId); 313 } 314 } 315} 316