From 304ace5611bba777821f70266e8e131f7aa27908 Mon Sep 17 00:00:00 2001 From: Yasin Kilicdere Date: Tue, 25 Apr 2023 12:20:42 +0100 Subject: [PATCH 1/2] Move runShellCommandWithTimeout from UserLifecycleTests to ShellHelper Bug: 274491131 Test: atest UserLifecycleTests Change-Id: I9cfa39f119be60dae98cfab12bfe3f261dec83c0 --- .../android/multiuser/UserLifecycleTests.java | 43 ++----------------- .../android/perftests/utils/ShellHelper.java | 41 ++++++++++++++++++ 2 files changed, 44 insertions(+), 40 deletions(-) diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java index 9ba94c8b9d119..91f0681c9d7be 100644 --- a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java +++ b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java @@ -70,7 +70,6 @@ import java.util.ArrayList; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicReference; /** * Perf tests for user life cycle events. @@ -1472,7 +1471,8 @@ public class UserLifecycleTests { private void removeUser(int userId) throws RemoteException { stopUserAfterWaitingForBroadcastIdle(userId, true); try { - runShellCommandWithTimeout("pm remove-user -w " + userId, TIMEOUT_IN_SECOND); + ShellHelper.runShellCommandWithTimeout("pm remove-user -w " + userId, + TIMEOUT_IN_SECOND); } catch (TimeoutException e) { Log.e(TAG, String.format("Could not remove user %d in %d seconds", userId, TIMEOUT_IN_SECOND), e); @@ -1539,7 +1539,7 @@ public class UserLifecycleTests { private void waitForBroadcastIdle() { try { - runShellCommandWithTimeout("am wait-for-broadcast-idle", TIMEOUT_IN_SECOND); + ShellHelper.runShellCommandWithTimeout("am wait-for-broadcast-idle", TIMEOUT_IN_SECOND); } catch (TimeoutException e) { Log.e(TAG, "Ending waitForBroadcastIdle because it is taking too long", e); } @@ -1558,41 +1558,4 @@ public class UserLifecycleTests { waitForBroadcastIdle(); sleep(tenSeconds); } - - /** - * Runs a Shell command with a timeout, returning a trimmed response. - */ - private String runShellCommandWithTimeout(String command, long timeoutInSecond) - throws TimeoutException { - AtomicReference exception = new AtomicReference<>(null); - AtomicReference result = new AtomicReference<>(null); - - CountDownLatch latch = new CountDownLatch(1); - - new Thread(() -> { - try { - result.set(ShellHelper.runShellCommandRaw(command)); - } catch (Exception e) { - exception.set(e); - } finally { - latch.countDown(); - } - }).start(); - - try { - if (!latch.await(timeoutInSecond, TimeUnit.SECONDS)) { - throw new TimeoutException("Command: '" + command + "' could not run in " - + timeoutInSecond + " seconds"); - } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - - if (exception.get() != null) { - Log.e(TAG, "Command: '" + command + "' failed.", exception.get()); - throw new RuntimeException(exception.get()); - } - - return result.get(); - } } diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/ShellHelper.java b/apct-tests/perftests/utils/src/android/perftests/utils/ShellHelper.java index 7b52576c1abde..a35899ad541b9 100644 --- a/apct-tests/perftests/utils/src/android/perftests/utils/ShellHelper.java +++ b/apct-tests/perftests/utils/src/android/perftests/utils/ShellHelper.java @@ -24,12 +24,53 @@ import androidx.annotation.NonNull; import androidx.test.InstrumentationRegistry; import java.io.FileInputStream; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicReference; /** * Provides Shell-based utilities such as running a command. */ public final class ShellHelper { + /** + * Runs a Shell command with a timeout, returning a trimmed response. + */ + @NonNull + public static String runShellCommandWithTimeout(@NonNull String command, long timeoutInSecond) + throws TimeoutException { + AtomicReference exception = new AtomicReference<>(null); + AtomicReference result = new AtomicReference<>(null); + + CountDownLatch latch = new CountDownLatch(1); + + new Thread(() -> { + try { + result.set(runShellCommandRaw(command)); + } catch (Exception e) { + exception.set(e); + } finally { + latch.countDown(); + } + }).start(); + + try { + if (!latch.await(timeoutInSecond, TimeUnit.SECONDS)) { + throw new TimeoutException("Command: '" + command + "' could not run in " + + timeoutInSecond + " seconds"); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + + if (exception.get() != null) { + throw new AndroidRuntimeException(exception.get()); + } + + return result.get(); + } + /** * Runs a Shell command, returning a trimmed response. */ From 84ff04d3c285c98d1048f93b975a13210bd7c5d9 Mon Sep 17 00:00:00 2001 From: Yasin Kilicdere Date: Wed, 26 Apr 2023 12:51:13 +0100 Subject: [PATCH 2/2] Start user in background via adb command instead of calling the API. If the user to be started is a profile of a current foreground user, it should be started via IActivityManager.startProfileWithListener API instead of IActivityManager.startUserInBackgroundWithListener. This logic is already implemented in ActivityManagerShellCommand, so rather than duplicating it, we'll be doing it by running the shell command. Bug: 279403644 Test: atest UserLifecycleTests Change-Id: I4b9e6f1e565187e93e13ad94f41d51ee5f7e3e42 --- .../src/android/multiuser/UserLifecycleTests.java | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java index 91f0681c9d7be..e5d4a2087fd43 100644 --- a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java +++ b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java @@ -1261,15 +1261,13 @@ public class UserLifecycleTests { *

This should always be used for profiles since profiles cannot be started in foreground. */ private void startUserInBackgroundAndWaitForUnlock(int userId) { - final ProgressWaiter waiter = new ProgressWaiter(); - boolean success = false; try { - mIam.startUserInBackgroundWithListener(userId, waiter); - success = waiter.waitForFinish(TIMEOUT_IN_SECOND); - } catch (RemoteException e) { - Log.e(TAG, "startUserInBackgroundAndWaitForUnlock failed", e); + attestTrue("Failed to start user " + userId + " in background.", + ShellHelper.runShellCommandWithTimeout("am start-user -w " + userId, + TIMEOUT_IN_SECOND).startsWith("Success:")); + } catch (TimeoutException e) { + fail("Could not start user " + userId + " in " + TIMEOUT_IN_SECOND + " seconds"); } - attestTrue("Failed to start user " + userId + " in background.", success); } /** Starts the given user in the foreground. */