From 94c30cbf9d45c40ea38de97ab147c26798a5dbcf Mon Sep 17 00:00:00 2001 From: Yasin Kilicdere Date: Wed, 17 Aug 2022 15:52:43 +0100 Subject: [PATCH] Exclude running code for receivers and observers from timing. Exclude time used by registering/unregistering broadcast receivers and user switch observers from the time measuraments of the tests. In this CL mRunner.resumeTiming(); calls are moved after the broadcastWaiter initialisation. Also UserSwitchWaiter was not unregistering UserSwitchObserver. That is imlemented and the class is refactored to keep registering and unregistering out of the timed portion by putting those logic into the setUp and the tearDown of the test. Bug: 169449457 Test: atest MultiUserPerfTests:android.multiuser.UserLifecycleTests --no-bazel-mode Change-Id: I04fdaf04ba8440889d60d6cf6f7b5554539af13a --- .../android/multiuser/UserLifecycleTests.java | 13 +-- .../android/multiuser/UserSwitchWaiter.java | 80 ++++++++++++------- 2 files changed, 60 insertions(+), 33 deletions(-) diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java index 448ee6160ce08..a6db310d3e7d1 100644 --- a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java +++ b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java @@ -155,6 +155,7 @@ public class UserLifecycleTests { public void tearDown() throws Exception { setSystemProperty("debug.usercontroller.user_switch_timeout_ms", mUserSwitchTimeoutMs); mBroadcastWaiter.close(); + mUserSwitchWaiter.close(); for (int userId : mUsersToRemove) { try { mUm.removeUser(userId); @@ -207,10 +208,10 @@ public class UserLifecycleTests { while (mRunner.keepRunning()) { mRunner.pauseTiming(); final int userId = createUserNoFlags(); - mRunner.resumeTiming(); - Log.i(TAG, "Starting timer"); - runThenWaitForBroadcasts(userId, () -> { + mRunner.resumeTiming(); + Log.i(TAG, "Starting timer"); + mIam.startUserInBackground(userId); }, Intent.ACTION_USER_STARTED); @@ -362,10 +363,10 @@ public class UserLifecycleTests { }, Intent.ACTION_MEDIA_MOUNTED); mUserSwitchWaiter.runThenWaitUntilSwitchCompleted(startUser, () -> { - mRunner.resumeTiming(); - Log.i(TAG, "Starting timer"); - runThenWaitForBroadcasts(userId, () -> { + mRunner.resumeTiming(); + Log.i(TAG, "Starting timer"); + mAm.switchUser(startUser); }, Intent.ACTION_USER_STOPPED); diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/UserSwitchWaiter.java b/apct-tests/perftests/multiuser/src/android/multiuser/UserSwitchWaiter.java index 228d14c3a05b2..82245977760bf 100644 --- a/apct-tests/perftests/multiuser/src/android/multiuser/UserSwitchWaiter.java +++ b/apct-tests/perftests/multiuser/src/android/multiuser/UserSwitchWaiter.java @@ -17,61 +17,87 @@ package android.multiuser; import android.app.ActivityManager; +import android.app.IActivityManager; +import android.app.IUserSwitchObserver; import android.app.UserSwitchObserver; import android.os.RemoteException; import android.util.Log; import com.android.internal.util.FunctionalUtils; -import java.util.concurrent.CountDownLatch; +import java.io.Closeable; +import java.io.IOException; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; -public class UserSwitchWaiter { +public class UserSwitchWaiter implements Closeable { private final String mTag; private final int mTimeoutInSecond; + private final IActivityManager mActivityManager; + private final IUserSwitchObserver mUserSwitchObserver = new UserSwitchObserver() { + @Override + public void onUserSwitchComplete(int newUserId) { + getSemaphoreSwitchComplete(newUserId).release(); + } - public UserSwitchWaiter(String tag, int timeoutInSecond) { + @Override + public void onLockedBootComplete(int newUserId) { + getSemaphoreBootComplete(newUserId).release(); + } + }; + + private final Map mSemaphoresMapSwitchComplete = new ConcurrentHashMap<>(); + private Semaphore getSemaphoreSwitchComplete(final int userId) { + return mSemaphoresMapSwitchComplete.computeIfAbsent(userId, + (Integer absentKey) -> new Semaphore(0)); + } + + private final Map mSemaphoresMapBootComplete = new ConcurrentHashMap<>(); + private Semaphore getSemaphoreBootComplete(final int userId) { + return mSemaphoresMapBootComplete.computeIfAbsent(userId, + (Integer absentKey) -> new Semaphore(0)); + } + + public UserSwitchWaiter(String tag, int timeoutInSecond) throws RemoteException { mTag = tag; mTimeoutInSecond = timeoutInSecond; + mActivityManager = ActivityManager.getService(); + + mActivityManager.registerUserSwitchObserver(mUserSwitchObserver, mTag); + } + + @Override + public void close() throws IOException { + try { + mActivityManager.unregisterUserSwitchObserver(mUserSwitchObserver); + } catch (RemoteException e) { + Log.e(mTag, "Failed to unregister user switch observer", e); + } } public void runThenWaitUntilSwitchCompleted(int userId, FunctionalUtils.ThrowingRunnable runnable, Runnable onFail) throws RemoteException { - final CountDownLatch latch = new CountDownLatch(1); - ActivityManager.getService().registerUserSwitchObserver( - new UserSwitchObserver() { - @Override - public void onUserSwitchComplete(int newUserId) throws RemoteException { - if (userId == newUserId) { - latch.countDown(); - } - } - }, mTag); + final Semaphore semaphore = getSemaphoreSwitchComplete(userId); + semaphore.drainPermits(); runnable.run(); - waitForLatch(latch, onFail); + waitForSemaphore(semaphore, onFail); } public void runThenWaitUntilBootCompleted(int userId, FunctionalUtils.ThrowingRunnable runnable, Runnable onFail) throws RemoteException { - final CountDownLatch latch = new CountDownLatch(1); - ActivityManager.getService().registerUserSwitchObserver( - new UserSwitchObserver() { - @Override - public void onLockedBootComplete(int newUserId) { - if (userId == newUserId) { - latch.countDown(); - } - } - }, mTag); + final Semaphore semaphore = getSemaphoreBootComplete(userId); + semaphore.drainPermits(); runnable.run(); - waitForLatch(latch, onFail); + waitForSemaphore(semaphore, onFail); } - private void waitForLatch(CountDownLatch latch, Runnable onFail) { + private void waitForSemaphore(Semaphore semaphore, Runnable onFail) { boolean success = false; try { - success = latch.await(mTimeoutInSecond, TimeUnit.SECONDS); + success = semaphore.tryAcquire(mTimeoutInSecond, TimeUnit.SECONDS); } catch (InterruptedException e) { Log.e(mTag, "Thread interrupted unexpectedly.", e); }