blob: f56c76332faa6b7cd5f7a0003305ffdd587d5d9e [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.multiuser;
import android.app.ActivityManager;
import android.app.IActivityManager;
import android.app.IStopUserCallback;
import android.app.UserSwitchObserver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.UserInfo;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.LargeTest;
import android.support.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.ArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
* Perf tests for user life cycle events.
*
* Running the tests:
* make MultiUserPerfTests &&
* adb install -r \
* ${ANDROID_PRODUCT_OUT}/data/app/MultiUserPerfTests/MultiUserPerfTests.apk &&
* adb shell am instrument -e class android.multiuser.UserLifecycleTest \
* -w com.android.perftests.multiuser/android.support.test.runner.AndroidJUnitRunner
*/
@LargeTest
@RunWith(AndroidJUnit4.class)
public class UserLifecycleTest {
private final int TIMEOUT_REMOVE_USER_MS = 4 * 1000; // 4 sec
private final int CHECK_USER_REMOVED_INTERVAL_MS = 200; // 0.2 sec
private final int TIMEOUT_USER_START_SEC = 4; // 4 sec
private final int TIMEOUT_USER_SWITCH_SEC = 8; // 8 sec
private final int TIMEOUT_USER_STOP_SEC = 1; // 1 sec
private final int TIMEOUT_MANAGED_PROFILE_UNLOCK_SEC = 2; // 2 sec
private final int TIMEOUT_LOCKED_BOOT_COMPLETE_MS = 5 * 1000; // 5 sec
private final int TIMEOUT_EPHERMAL_USER_STOP_SEC = 6; // 6 sec
private UserManager mUm;
private ActivityManager mAm;
private IActivityManager mIam;
private BenchmarkState mState;
private ArrayList<Integer> mUsersToRemove;
@Rule
public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@Before
public void setUp() {
final Context context = InstrumentationRegistry.getContext();
mUm = UserManager.get(context);
mAm = context.getSystemService(ActivityManager.class);
mIam = ActivityManager.getService();
mState = mPerfStatusReporter.getBenchmarkState();
mUsersToRemove = new ArrayList<>();
}
@After
public void tearDown() {
for (int userId : mUsersToRemove) {
try {
mUm.removeUser(userId);
} catch (Exception e) {
// Ignore
}
}
}
@Test
public void createAndStartUserPerf() throws Exception {
while (mState.keepRunning()) {
final UserInfo userInfo = mUm.createUser("TestUser", 0);
final CountDownLatch latch = new CountDownLatch(1);
registerBroadcastReceiver(Intent.ACTION_USER_STARTED, latch, userInfo.id);
mIam.startUserInBackground(userInfo.id);
latch.await(TIMEOUT_USER_START_SEC, TimeUnit.SECONDS);
mState.pauseTiming();
removeUser(userInfo.id);
mState.resumeTiming();
}
}
@Test
public void switchUserPerf() throws Exception {
while (mState.keepRunning()) {
mState.pauseTiming();
final int startUser = mAm.getCurrentUser();
final UserInfo userInfo = mUm.createUser("TestUser", 0);
mState.resumeTiming();
switchUser(userInfo.id);
mState.pauseTiming();
switchUser(startUser);
removeUser(userInfo.id);
mState.resumeTiming();
}
}
@Test
public void stopUserPerf() throws Exception {
while (mState.keepRunning()) {
mState.pauseTiming();
final UserInfo userInfo = mUm.createUser("TestUser", 0);
final CountDownLatch latch = new CountDownLatch(1);
registerBroadcastReceiver(Intent.ACTION_USER_STARTED, latch, userInfo.id);
mIam.startUserInBackground(userInfo.id);
latch.await(TIMEOUT_USER_START_SEC, TimeUnit.SECONDS);
mState.resumeTiming();
stopUser(userInfo.id);
mState.pauseTiming();
removeUser(userInfo.id);
mState.resumeTiming();
}
}
@Test
public void lockedBootCompletedPerf() throws Exception {
while (mState.keepRunning()) {
mState.pauseTiming();
final int startUser = mAm.getCurrentUser();
final UserInfo userInfo = mUm.createUser("TestUser", 0);
final CountDownLatch latch = new CountDownLatch(1);
registerUserSwitchObserver(null, latch, userInfo.id);
mState.resumeTiming();
mAm.switchUser(userInfo.id);
latch.await(TIMEOUT_LOCKED_BOOT_COMPLETE_MS, TimeUnit.SECONDS);
mState.pauseTiming();
switchUser(startUser);
removeUser(userInfo.id);
mState.resumeTiming();
}
}
@Test
public void managedProfileUnlockPerf() throws Exception {
while (mState.keepRunning()) {
mState.pauseTiming();
final UserInfo userInfo = mUm.createProfileForUser("TestUser",
UserInfo.FLAG_MANAGED_PROFILE, mAm.getCurrentUser());
final CountDownLatch latch = new CountDownLatch(1);
registerBroadcastReceiver(Intent.ACTION_USER_UNLOCKED, latch, userInfo.id);
mState.resumeTiming();
mIam.startUserInBackground(userInfo.id);
latch.await(TIMEOUT_MANAGED_PROFILE_UNLOCK_SEC, TimeUnit.SECONDS);
mState.pauseTiming();
removeUser(userInfo.id);
mState.resumeTiming();
}
}
@Test
public void ephemeralUserStoppedPerf() throws Exception {
while (mState.keepRunning()) {
mState.pauseTiming();
final int startUser = mAm.getCurrentUser();
final UserInfo userInfo = mUm.createUser("TestUser",
UserInfo.FLAG_EPHEMERAL | UserInfo.FLAG_DEMO);
switchUser(userInfo.id);
final CountDownLatch latch = new CountDownLatch(1);
InstrumentationRegistry.getContext().registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_USER_STOPPED.equals(intent.getAction()) && intent.getIntExtra(
Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL) == userInfo.id) {
latch.countDown();
}
}
}, new IntentFilter(Intent.ACTION_USER_STOPPED));
final CountDownLatch switchLatch = new CountDownLatch(1);
registerUserSwitchObserver(switchLatch, null, startUser);
mState.resumeTiming();
mAm.switchUser(startUser);
latch.await(TIMEOUT_EPHERMAL_USER_STOP_SEC, TimeUnit.SECONDS);
mState.pauseTiming();
switchLatch.await(TIMEOUT_USER_SWITCH_SEC, TimeUnit.SECONDS);
removeUser(userInfo.id);
mState.resumeTiming();
}
}
private void switchUser(int userId) throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
registerUserSwitchObserver(latch, null, userId);
mAm.switchUser(userId);
latch.await(TIMEOUT_USER_SWITCH_SEC, TimeUnit.SECONDS);
}
private void stopUser(int userId) throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
mIam.stopUser(userId, false /* force */, new IStopUserCallback.Stub() {
@Override
public void userStopped(int userId) throws RemoteException {
latch.countDown();
}
@Override
public void userStopAborted(int userId) throws RemoteException {
}
});
latch.await(TIMEOUT_USER_STOP_SEC, TimeUnit.SECONDS);
}
private void registerUserSwitchObserver(final CountDownLatch switchLatch,
final CountDownLatch bootCompleteLatch, final int userId) throws Exception {
ActivityManager.getService().registerUserSwitchObserver(
new UserSwitchObserver() {
@Override
public void onUserSwitchComplete(int newUserId) throws RemoteException {
if (switchLatch != null && userId == newUserId) {
switchLatch.countDown();
}
}
@Override
public void onLockedBootComplete(int newUserId) {
if (bootCompleteLatch != null && userId == newUserId) {
bootCompleteLatch.countDown();
}
}
}, "UserLifecycleTest");
}
private void registerBroadcastReceiver(final String action, final CountDownLatch latch,
final int userId) {
InstrumentationRegistry.getContext().registerReceiverAsUser(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (action.equals(intent.getAction()) && intent.getIntExtra(
Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL) == userId) {
latch.countDown();
}
}
}, UserHandle.of(userId), new IntentFilter(action), null, null);
}
private void removeUser(int userId) {
try {
mUm.removeUser(userId);
final long startTime = System.currentTimeMillis();
while (mUm.getUserInfo(userId) != null &&
System.currentTimeMillis() - startTime < TIMEOUT_REMOVE_USER_MS) {
Thread.sleep(CHECK_USER_REMOVED_INTERVAL_MS);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (Exception e) {
// Ignore
}
if (mUm.getUserInfo(userId) != null) {
mUsersToRemove.add(userId);
}
}
}