From fddf07e8adf1c7e6e97cc8a2a5658da7116407da Mon Sep 17 00:00:00 2001 From: jovanak Date: Thu, 31 Oct 2019 16:49:24 -0700 Subject: [PATCH 1/3] Add wait flag to am switch-user command. Previously, command returns right away. CTS tests that use it are forced to loop waiting for the change in am get-current-user to see if the switch completed. This method is unreliable because it returns the new user id before UserController.mCurrentUser updated. Adding "-w" to the switch command will make it wait for the switch to be completed. Fixes:141998718 Test: manual switch-user tests with -w flag Change-Id: I41bbcff0c79677ba3bf6b58e1fc96cd13a681b33 Merged-In: I41bbcff0c79677ba3bf6b58e1fc96cd13a681b33 --- .../am/ActivityManagerShellCommand.java | 44 ++++++++++++++++++- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 972b10608056c..3257f73e24df7 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -36,6 +36,7 @@ import android.app.IStopUserCallback; import android.app.IUidObserver; import android.app.KeyguardManager; import android.app.ProfilerInfo; +import android.app.UserSwitchObserver; import android.app.WaitResult; import android.app.usage.AppStandbyInfo; import android.app.usage.ConfigurationStats; @@ -1708,6 +1709,30 @@ final class ActivityManagerShellCommand extends ShellCommand { return 0; } + private void switchUserAndWaitForComplete(int userId) throws RemoteException { + // Register switch observer. + final CountDownLatch switchLatch = new CountDownLatch(1); + mInterface.registerUserSwitchObserver( + new UserSwitchObserver() { + @Override + public void onUserSwitchComplete(int newUserId) { + if (userId == newUserId) { + switchLatch.countDown(); + } + } + }, ActivityManagerShellCommand.class.getName()); + + // Switch. + mInterface.switchUser(userId); + + // Wait. + try { + switchLatch.await(USER_OPERATION_TIMEOUT_MS, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + getErrPrintWriter().println("Thread interrupted unexpectedly."); + } + } + int runSwitchUser(PrintWriter pw) throws RemoteException { UserManager userManager = mInternal.mContext.getSystemService(UserManager.class); final int userSwitchable = userManager.getUserSwitchability(); @@ -1715,8 +1740,23 @@ final class ActivityManagerShellCommand extends ShellCommand { getErrPrintWriter().println("Error: " + userSwitchable); return -1; } - String user = getNextArgRequired(); - mInterface.switchUser(Integer.parseInt(user)); + boolean wait = false; + String opt; + while ((opt = getNextOption()) != null) { + if ("-w".equals(opt)) { + wait = true; + } else { + getErrPrintWriter().println("Error: unknown option: " + opt); + return -1; + } + } + + int userId = Integer.parseInt(getNextArgRequired()); + if (wait) { + switchUserAndWaitForComplete(userId); + } else { + mInterface.switchUser(userId); + } return 0; } From 2d950c12b5597681162b13ce87f3cd7e64904f6b Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Tue, 21 Jan 2020 14:22:14 -0800 Subject: [PATCH 2/3] Improved 'am switch' to handle errors. Bug: 146207078 Test: adb shell am switch-user 42 ; echo $? Change-Id: I005c76652be1fd0908f5c2b40e2513362b5ce5ac Merged-In: I005c76652be1fd0908f5c2b40e2513362b5ce5ac --- .../server/am/ActivityManagerShellCommand.java | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 3257f73e24df7..7118899d37fa7 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -1709,7 +1709,7 @@ final class ActivityManagerShellCommand extends ShellCommand { return 0; } - private void switchUserAndWaitForComplete(int userId) throws RemoteException { + private boolean switchUserAndWaitForComplete(int userId) throws RemoteException { // Register switch observer. final CountDownLatch switchLatch = new CountDownLatch(1); mInterface.registerUserSwitchObserver( @@ -1723,7 +1723,7 @@ final class ActivityManagerShellCommand extends ShellCommand { }, ActivityManagerShellCommand.class.getName()); // Switch. - mInterface.switchUser(userId); + boolean switched = mInterface.switchUser(userId); // Wait. try { @@ -1731,6 +1731,7 @@ final class ActivityManagerShellCommand extends ShellCommand { } catch (InterruptedException e) { getErrPrintWriter().println("Thread interrupted unexpectedly."); } + return switched; } int runSwitchUser(PrintWriter pw) throws RemoteException { @@ -1752,12 +1753,18 @@ final class ActivityManagerShellCommand extends ShellCommand { } int userId = Integer.parseInt(getNextArgRequired()); + boolean switched; if (wait) { - switchUserAndWaitForComplete(userId); + switched = switchUserAndWaitForComplete(userId); } else { - mInterface.switchUser(userId); + switched = mInterface.switchUser(userId); + } + if (switched) { + return 0; + } else { + pw.printf("Failed to switch to user %d\n", userId); + return 1; } - return 0; } int runGetCurrentUser(PrintWriter pw) throws RemoteException { From 9950e5a81d37f49a72c88a2e0e6e2e3b14c88e65 Mon Sep 17 00:00:00 2001 From: jovanak Date: Fri, 21 Feb 2020 14:45:49 -0800 Subject: [PATCH 3/3] Fixes switch-user -w command. We handle failures better and exit early if already switched to a current user. Fixes: 150019926 Test: manual verification Change-Id: Ib3d70d21cc379f136983f9ddcda31f5bab3f045e Merged-In: Ib3d70d21cc379f136983f9ddcda31f5bab3f045e --- .../server/am/ActivityManagerShellCommand.java | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 7118899d37fa7..af582c42855fe 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -1710,6 +1710,12 @@ final class ActivityManagerShellCommand extends ShellCommand { } private boolean switchUserAndWaitForComplete(int userId) throws RemoteException { + UserInfo currentUser = mInterface.getCurrentUser(); + if (currentUser != null && userId == currentUser.id) { + // Already switched to the correct user, exit early. + return true; + } + // Register switch observer. final CountDownLatch switchLatch = new CountDownLatch(1); mInterface.registerUserSwitchObserver( @@ -1724,13 +1730,18 @@ final class ActivityManagerShellCommand extends ShellCommand { // Switch. boolean switched = mInterface.switchUser(userId); + if (!switched) { + // Switching failed, don't wait for the user switch observer. + return false; + } // Wait. try { - switchLatch.await(USER_OPERATION_TIMEOUT_MS, TimeUnit.MILLISECONDS); + switched = switchLatch.await(USER_OPERATION_TIMEOUT_MS, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { - getErrPrintWriter().println("Thread interrupted unexpectedly."); + getErrPrintWriter().println("Error: Thread interrupted unexpectedly."); } + return switched; } @@ -1762,7 +1773,7 @@ final class ActivityManagerShellCommand extends ShellCommand { if (switched) { return 0; } else { - pw.printf("Failed to switch to user %d\n", userId); + pw.printf("Error: Failed to switch to user %d\n", userId); return 1; } }