Merge "Add usermanager related perf tests - part2"
diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTest.java b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTest.java
index bd0139f..cdbca63 100644
--- a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTest.java
+++ b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTest.java
@@ -18,7 +18,8 @@
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.IActivityManager;
-import android.app.SynchronousUserSwitchObserver;
+import android.app.IStopUserCallback;
+import android.app.UserSwitchObserver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -43,18 +44,36 @@
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 MIN_REPEAT_TIMES = 4;
- private final int TIMEOUT_REMOVE_USER_SEC = 4;
+ 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;
@@ -78,7 +97,11 @@
@After
public void tearDown() {
for (int userId : mUsersToRemove) {
- mUm.removeUser(userId);
+ try {
+ mUm.removeUser(userId);
+ } catch (Exception e) {
+ // Ignore
+ }
}
}
@@ -88,14 +111,7 @@
final UserInfo userInfo = mUm.createUser("TestUser", 0);
final CountDownLatch latch = new CountDownLatch(1);
- InstrumentationRegistry.getContext().registerReceiverAsUser(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (Intent.ACTION_USER_STARTED.equals(intent.getAction())) {
- latch.countDown();
- }
- }
- }, UserHandle.ALL, new IntentFilter(Intent.ACTION_USER_STARTED), null, null);
+ registerBroadcastReceiver(Intent.ACTION_USER_STARTED, latch, userInfo.id);
mIam.startUserInBackground(userInfo.id);
latch.await(TIMEOUT_USER_START_SEC, TimeUnit.SECONDS);
@@ -122,37 +138,163 @@
}
}
+ @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);
+ registerUserSwitchObserver(latch, null, userId);
mAm.switchUser(userId);
latch.await(TIMEOUT_USER_SWITCH_SEC, TimeUnit.SECONDS);
}
- private void registerUserSwitchObserver(final CountDownLatch latch) throws Exception {
- ActivityManagerNative.getDefault().registerUserSwitchObserver(
- new SynchronousUserSwitchObserver() {
- @Override
- public void onUserSwitching(int newUserId) throws RemoteException {
- }
+ 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 {
+ ActivityManagerNative.getDefault().registerUserSwitchObserver(
+ new UserSwitchObserver() {
@Override
public void onUserSwitchComplete(int newUserId) throws RemoteException {
- latch.countDown();
+ if (switchLatch != null && userId == newUserId) {
+ switchLatch.countDown();
+ }
}
@Override
- public void onForegroundProfileSwitch(int newProfileId) throws RemoteException {
+ public void onLockedBootComplete(int newUserId) {
+ if (bootCompleteLatch != null && userId == newUserId) {
+ bootCompleteLatch.countDown();
+ }
}
}, "UserLifecycleTest");
}
- private void removeUser(int userId) throws Exception {
- mUm.removeUser(userId);
- final long startTime = System.currentTimeMillis();
- while (mUm.getUserInfo(userId) != null &&
- System.currentTimeMillis() - startTime < TIMEOUT_REMOVE_USER_SEC) {
- Thread.sleep(CHECK_USER_REMOVED_INTERVAL_MS);
+ 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);
diff --git a/core/java/android/app/IUserSwitchObserver.aidl b/core/java/android/app/IUserSwitchObserver.aidl
index caee14f..234da8f 100644
--- a/core/java/android/app/IUserSwitchObserver.aidl
+++ b/core/java/android/app/IUserSwitchObserver.aidl
@@ -23,4 +23,5 @@
void onUserSwitching(int newUserId, IRemoteCallback reply);
void onUserSwitchComplete(int newUserId);
void onForegroundProfileSwitch(int newProfileId);
+ void onLockedBootComplete(int newUserId);
}
diff --git a/core/java/android/app/SynchronousUserSwitchObserver.java b/core/java/android/app/SynchronousUserSwitchObserver.java
index 6d929f9..3a73888 100644
--- a/core/java/android/app/SynchronousUserSwitchObserver.java
+++ b/core/java/android/app/SynchronousUserSwitchObserver.java
@@ -25,7 +25,7 @@
*
* @hide
*/
-public abstract class SynchronousUserSwitchObserver extends IUserSwitchObserver.Stub {
+public abstract class SynchronousUserSwitchObserver extends UserSwitchObserver {
/**
* Calls {@link #onUserSwitching(int)} and notifies {@code reply} by calling
* {@link IRemoteCallback#sendResult(Bundle)}.
diff --git a/core/java/android/app/UserSwitchObserver.java b/core/java/android/app/UserSwitchObserver.java
new file mode 100644
index 0000000..c0f7a4c
--- /dev/null
+++ b/core/java/android/app/UserSwitchObserver.java
@@ -0,0 +1,41 @@
+/*
+ * 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.app;
+
+import android.os.IRemoteCallback;
+import android.os.RemoteException;
+
+/**
+ * @hide
+ */
+public class UserSwitchObserver extends IUserSwitchObserver.Stub {
+ @Override
+ public void onUserSwitching(int newUserId, IRemoteCallback reply) throws RemoteException {
+ if (reply != null) {
+ reply.sendResult(null);
+ }
+ }
+
+ @Override
+ public void onUserSwitchComplete(int newUserId) throws RemoteException {}
+
+ @Override
+ public void onForegroundProfileSwitch(int newProfileId) throws RemoteException {}
+
+ @Override
+ public void onLockedBootComplete(int newUserId) throws RemoteException {}
+}
\ No newline at end of file
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 66e1b27..e7ecd29 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -29,8 +29,8 @@
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.AlarmManager;
-import android.app.IUserSwitchObserver;
import android.app.PendingIntent;
+import android.app.UserSwitchObserver;
import android.app.admin.DevicePolicyManager;
import android.app.trust.TrustManager;
import android.content.BroadcastReceiver;
@@ -1071,7 +1071,7 @@
mSubscriptionManager.addOnSubscriptionsChangedListener(mSubscriptionListener);
try {
ActivityManagerNative.getDefault().registerUserSwitchObserver(
- new IUserSwitchObserver.Stub() {
+ new UserSwitchObserver() {
@Override
public void onUserSwitching(int newUserId, IRemoteCallback reply) {
mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCHING,
@@ -1082,10 +1082,6 @@
mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCH_COMPLETE,
newUserId, 0));
}
- @Override
- public void onForegroundProfileSwitch(int newProfileId) {
- // Ignore.
- }
}, TAG);
} catch (RemoteException e) {
e.rethrowAsRuntimeException();
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 0e957b9..2f88223 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1526,6 +1526,7 @@
static final int VR_MODE_APPLY_IF_NEEDED_MSG = 69;
static final int SHOW_UNSUPPORTED_DISPLAY_SIZE_DIALOG_MSG = 70;
static final int HANDLE_TRUST_STORAGE_UPDATE_MSG = 71;
+ static final int REPORT_LOCKED_BOOT_COMPLETE_MSG = 72;
static final int START_USER_SWITCH_FG_MSG = 712;
static final int FIRST_ACTIVITY_STACK_MSG = 100;
@@ -2274,6 +2275,9 @@
case REPORT_USER_SWITCH_COMPLETE_MSG: {
mUserController.dispatchUserSwitchComplete(msg.arg1);
} break;
+ case REPORT_LOCKED_BOOT_COMPLETE_MSG: {
+ mUserController.dispatchLockedBootComplete(msg.arg1);
+ } break;
case SHUTDOWN_UI_AUTOMATION_CONNECTION_MSG: {
IUiAutomationConnection connection = (IUiAutomationConnection) msg.obj;
try {
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 0407361..ba42d3f 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -32,6 +32,7 @@
import static com.android.server.am.ActivityManagerService.ALLOW_NON_FULL;
import static com.android.server.am.ActivityManagerService.ALLOW_NON_FULL_IN_PROFILE;
import static com.android.server.am.ActivityManagerService.MY_PID;
+import static com.android.server.am.ActivityManagerService.REPORT_LOCKED_BOOT_COMPLETE_MSG;
import static com.android.server.am.ActivityManagerService.REPORT_USER_SWITCH_COMPLETE_MSG;
import static com.android.server.am.ActivityManagerService.REPORT_USER_SWITCH_MSG;
import static com.android.server.am.ActivityManagerService.SYSTEM_USER_CURRENT_MSG;
@@ -259,6 +260,8 @@
MetricsLogger.histogram(mInjector.getContext(), "framework_locked_boot_completed",
uptimeSeconds);
+ mHandler.sendMessage(mHandler.obtainMessage(REPORT_LOCKED_BOOT_COMPLETE_MSG,
+ userId, 0));
Intent intent = new Intent(Intent.ACTION_LOCKED_BOOT_COMPLETED, null);
intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT
@@ -1053,6 +1056,18 @@
mUserSwitchObservers.finishBroadcast();
}
+ void dispatchLockedBootComplete(int userId) {
+ final int observerCount = mUserSwitchObservers.beginBroadcast();
+ for (int i = 0; i < observerCount; i++) {
+ try {
+ mUserSwitchObservers.getBroadcastItem(i).onLockedBootComplete(userId);
+ } catch (RemoteException e) {
+ // Ignore
+ }
+ }
+ mUserSwitchObservers.finishBroadcast();
+ }
+
private void stopBackgroundUsersIfEnforced(int oldUserId) {
// Never stop system user
if (oldUserId == UserHandle.USER_SYSTEM) {
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 73c8469..5addffb 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -1068,14 +1068,6 @@
mHandler.obtainMessage(MSG_USER_SWITCHING, newUserId, 0 /* unused */)
.sendToTarget();
}
- @Override
- public void onUserSwitchComplete(int newUserId) throws RemoteException {
- // Ignore.
- }
- @Override
- public void onForegroundProfileSwitch(int newProfileId) {
- // Ignore.
- }
}, TAG);
} catch (RemoteException e) {
Slog.w(TAG, "Failed to listen for user switching event" ,e);
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 3b20fb1..5514551 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -27,10 +27,10 @@
import android.app.ActivityManagerNative;
import android.app.AppGlobals;
import android.app.AppOpsManager;
-import android.app.IUserSwitchObserver;
import android.app.IWallpaperManager;
import android.app.IWallpaperManagerCallback;
import android.app.PendingIntent;
+import android.app.UserSwitchObserver;
import android.app.WallpaperInfo;
import android.app.WallpaperManager;
import android.app.admin.DevicePolicyManager;
@@ -933,20 +933,11 @@
try {
ActivityManagerNative.getDefault().registerUserSwitchObserver(
- new IUserSwitchObserver.Stub() {
+ new UserSwitchObserver() {
@Override
public void onUserSwitching(int newUserId, IRemoteCallback reply) {
switchUser(newUserId, reply);
}
-
- @Override
- public void onUserSwitchComplete(int newUserId) throws RemoteException {
- }
-
- @Override
- public void onForegroundProfileSwitch(int newProfileId) {
- // Ignore.
- }
}, TAG);
} catch (RemoteException e) {
e.rethrowAsRuntimeException();