diff options
author | Mohammad Islam <samiul@google.com> | 2019-10-09 08:34:34 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2019-10-09 08:34:34 +0000 |
commit | 5a8283d7fd8f3dee8d33ae91784a31907200aaa7 (patch) | |
tree | 9c96b912e5e452e54558ceb42b5209118f02caed | |
parent | 299036ea2fd4bde2330fbac8dfb3bea2e50c2f91 (diff) | |
parent | 40110561de02add5f2ad1b22812e8caa1c204ab3 (diff) | |
download | base-5a8283d7fd8f3dee8d33ae91784a31907200aaa7.tar.gz |
Merge changes from topic "wait-for-staged-session"
* changes:
Merge get-stagedsessions with `pm list` and improve on it
Add flag for staged session to get ready during installation
-rw-r--r-- | services/core/java/com/android/server/pm/PackageManagerShellCommand.java | 189 |
1 files changed, 164 insertions, 25 deletions
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index 44338ac8bc05..5ce215b306da 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -93,9 +93,11 @@ import android.text.TextUtils; import android.text.format.DateUtils; import android.util.ArraySet; import android.util.PrintWriterPrinter; +import android.util.SparseArray; import com.android.internal.content.PackageHelper; import com.android.internal.util.ArrayUtils; +import com.android.internal.util.IndentingPrintWriter; import com.android.server.LocalServices; import com.android.server.SystemConfig; @@ -129,6 +131,7 @@ class PackageManagerShellCommand extends ShellCommand { private static final String STDIN_PATH = "-"; /** Path where ART profiles snapshots are dumped for the shell user */ private final static String ART_PROFILE_SNAPSHOT_DEBUG_LOCATION = "/data/misc/profman/"; + private static final int DEFAULT_WAIT_MS = 60 * 1000; final IPackageManager mInterface; final private WeakHashMap<String, Resources> mResourceCache = @@ -269,7 +272,7 @@ class PackageManagerShellCommand extends ShellCommand { case "get-harmful-app-warning": return runGetHarmfulAppWarning(); case "get-stagedsessions": - return getStagedSessions(); + return runListStagedSessions(); case "uninstall-system-updates": return uninstallSystemUpdates(); case "rollback-app": @@ -341,28 +344,6 @@ class PackageManagerShellCommand extends ShellCommand { return 1; } - private int getStagedSessions() { - final PrintWriter pw = getOutPrintWriter(); - try { - List<SessionInfo> stagedSessionsList = - mInterface.getPackageInstaller().getStagedSessions().getList(); - for (SessionInfo session: stagedSessionsList) { - pw.println("appPackageName = " + session.getAppPackageName() - + "; sessionId = " + session.getSessionId() - + "; isStaged = " + session.isStaged() - + "; isStagedSessionReady = " + session.isStagedSessionReady() - + "; isStagedSessionApplied = " + session.isStagedSessionApplied() - + "; isStagedSessionFailed = " + session.isStagedSessionFailed() + ";"); - } - } catch (RemoteException e) { - pw.println("Failure [" - + e.getClass().getName() + " - " - + e.getMessage() + "]"); - return 0; - } - return 1; - } - private int uninstallSystemUpdates() { final PrintWriter pw = getOutPrintWriter(); List<String> failedUninstalls = new LinkedList<>(); @@ -535,6 +516,8 @@ class PackageManagerShellCommand extends ShellCommand { return runListPermissionGroups(); case "permissions": return runListPermissions(); + case "staged-sessions": + return runListStagedSessions(); case "users": ServiceManager.getService("user").shellCommand( getInFileDescriptor(), getOutFileDescriptor(), getErrFileDescriptor(), @@ -871,6 +854,103 @@ class PackageManagerShellCommand extends ShellCommand { return 0; } + private static class SessionDump { + boolean onlyParent; // Show parent sessions only + boolean onlyReady; // Show only staged sessions that are in ready state + boolean onlySessionId; // Show sessionId only + } + + // Returns true if the provided flag is a session flag and given SessionDump was updated + private boolean setSessionFlag(String flag, SessionDump sessionDump) { + switch (flag) { + case "--only-parent": + sessionDump.onlyParent = true; + break; + case "--only-ready": + sessionDump.onlyReady = true; + break; + case "--only-sessionid": + sessionDump.onlySessionId = true; + break; + default: + return false; + } + return true; + } + + private int runListStagedSessions() { + final IndentingPrintWriter pw = new IndentingPrintWriter( + getOutPrintWriter(), /* singleIndent */ " ", /* wrapLength */ 120); + + SessionDump sessionDump = new SessionDump(); + String opt; + while ((opt = getNextOption()) != null) { + if (!setSessionFlag(opt, sessionDump)) { + pw.println("Error: Unknown option: " + opt); + return -1; + } + } + + try { + List<SessionInfo> stagedSessions = + mInterface.getPackageInstaller().getStagedSessions().getList(); + printSessionList(pw, stagedSessions, sessionDump); + } catch (RemoteException e) { + pw.println("Failure [" + + e.getClass().getName() + " - " + + e.getMessage() + "]"); + return -1; + } + return 1; + } + + private void printSessionList(IndentingPrintWriter pw, List<SessionInfo> stagedSessions, + SessionDump sessionDump) { + final SparseArray<SessionInfo> sessionById = new SparseArray<>(stagedSessions.size()); + for (SessionInfo session : stagedSessions) { + sessionById.put(session.getSessionId(), session); + } + for (SessionInfo session: stagedSessions) { + if (sessionDump.onlyReady && !session.isStagedSessionReady()) { + continue; + } + if (session.getParentSessionId() != SessionInfo.INVALID_ID) { + continue; + } + printSession(pw, session, sessionDump); + if (session.isMultiPackage() && !sessionDump.onlyParent) { + pw.increaseIndent(); + final int[] childIds = session.getChildSessionIds(); + for (int i = 0; i < childIds.length; i++) { + final SessionInfo childSession = sessionById.get(childIds[i]); + if (childSession == null) { + if (sessionDump.onlySessionId) { + pw.println(childIds[i]); + } else { + pw.println("sessionId = " + childIds[i] + "; not found"); + } + } else { + printSession(pw, childSession, sessionDump); + } + } + pw.decreaseIndent(); + } + } + } + + private static void printSession(PrintWriter pw, SessionInfo session, SessionDump sessionDump) { + if (sessionDump.onlySessionId) { + pw.println(session.getSessionId()); + return; + } + pw.println("sessionId = " + session.getSessionId() + + "; appPackageName = " + session.getAppPackageName() + + "; isStaged = " + session.isStaged() + + "; isReady = " + session.isStagedSessionReady() + + "; isApplied = " + session.isStagedSessionApplied() + + "; isFailed = " + session.isStagedSessionFailed() + ";"); + } + private Intent parseIntentAndUser() throws URISyntaxException { mTargetUser = UserHandle.USER_CURRENT; mBrief = false; @@ -1078,6 +1158,45 @@ class PackageManagerShellCommand extends ShellCommand { return 1; } abandonSession = false; + + if (!params.sessionParams.isStaged || !params.waitForStagedSessionReady) { + pw.println("Success"); + return 0; + } + + long timeoutMs = params.timeoutMs <= 0 + ? DEFAULT_WAIT_MS + : params.timeoutMs; + PackageInstaller.SessionInfo si = mInterface.getPackageInstaller() + .getSessionInfo(sessionId); + long currentTime = System.currentTimeMillis(); + long endTime = currentTime + timeoutMs; + // Using a loop instead of BroadcastReceiver since we can receive session update + // broadcast only if packageInstallerName is "android". We can't always force + // "android" as packageIntallerName, e.g, rollback auto implies + // "-i com.android.shell". + while (currentTime < endTime) { + if (si != null + && (si.isStagedSessionReady() || si.isStagedSessionFailed())) { + break; + } + SystemClock.sleep(Math.min(endTime - currentTime, 100)); + currentTime = System.currentTimeMillis(); + si = mInterface.getPackageInstaller().getSessionInfo(sessionId); + } + if (si == null) { + pw.println("Failure [failed to retrieve SessionInfo]"); + return 1; + } + if (!si.isStagedSessionReady() && !si.isStagedSessionFailed()) { + pw.println("Failure [timed out after " + timeoutMs + " ms]"); + return 1; + } + if (!si.isStagedSessionReady()) { + pw.println("Error [" + si.getStagedSessionErrorCode() + "] [" + + si.getStagedSessionErrorMessage() + "]"); + return 1; + } pw.println("Success"); return 0; } finally { @@ -2368,6 +2487,8 @@ class PackageManagerShellCommand extends ShellCommand { SessionParams sessionParams; String installerPackageName; int userId = UserHandle.USER_ALL; + boolean waitForStagedSessionReady = false; + long timeoutMs = DEFAULT_WAIT_MS; } private InstallParams makeInstallParams() { @@ -2493,6 +2614,14 @@ class PackageManagerShellCommand extends ShellCommand { } sessionParams.installFlags |= PackageManager.INSTALL_ENABLE_ROLLBACK; break; + case "--wait": + params.waitForStagedSessionReady = true; + try { + params.timeoutMs = Long.parseLong(peekNextArg()); + getNextArg(); + } catch (NumberFormatException ignore) { + } + break; default: throw new IllegalArgumentException("Unknown option " + opt); } @@ -3023,6 +3152,12 @@ class PackageManagerShellCommand extends ShellCommand { pw.println(" -d: only list dangerous permissions"); pw.println(" -u: list only the permissions users will see"); pw.println(""); + pw.println(" list staged-sessions [--only-ready] [--only-sessionid] [--only-parent]"); + pw.println(" Displays list of all staged sessions on device."); + pw.println(" --only-ready: show only staged sessions that are ready"); + pw.println(" --only-sessionid: show only sessionId of each session"); + pw.println(" --only-parent: hide all children sessions"); + pw.println(""); pw.println(" resolve-activity [--brief] [--components] [--query-flags FLAGS]"); pw.println(" [--user USER_ID] INTENT"); pw.println(" Prints the activity that resolves to the given INTENT."); @@ -3045,7 +3180,8 @@ class PackageManagerShellCommand extends ShellCommand { pw.println(" [--referrer URI] [--abi ABI_NAME] [--force-sdk]"); pw.println(" [--preload] [--instantapp] [--full] [--dont-kill]"); pw.println(" [--enable-rollback]"); - pw.println(" [--force-uuid internal|UUID] [--pkg PACKAGE] [-S BYTES] [--apex]"); + pw.println(" [--force-uuid internal|UUID] [--pkg PACKAGE] [-S BYTES]"); + pw.println(" [--apex] [--wait TIMEOUT]"); pw.println(" [PATH|-]"); pw.println(" Install an application. Must provide the apk data to install, either as a"); pw.println(" file path or '-' to read from stdin. Options are:"); @@ -3075,6 +3211,9 @@ class PackageManagerShellCommand extends ShellCommand { pw.println(" 3=device setup, 4=user request"); pw.println(" --force-uuid: force install on to disk volume with given UUID"); pw.println(" --apex: install an .apex file, not an .apk"); + pw.println(" --wait: when performing staged install, wait TIMEOUT milliseconds"); + pw.println(" for pre-reboot verification to complete. If TIMEOUT is not"); + pw.println(" specified it will wait for " + DEFAULT_WAIT_MS + " milliseconds."); pw.println(""); pw.println(" install-create [-lrtsfdg] [-i PACKAGE] [--user USER_ID|all|current]"); pw.println(" [-p INHERIT_PACKAGE] [--install-location 0/1/2]"); @@ -3257,7 +3396,7 @@ class PackageManagerShellCommand extends ShellCommand { pw.println(" uninstall-system-updates"); pw.println(" Remove updates to all system applications and fall back to their /system " + "version."); - pw.println(); + pw.println(""); pw.println(" get-moduleinfo [--all | --installed] [module-name]"); pw.println(" Displays module info. If module-name is specified only that info is shown"); pw.println(" By default, without any argument only installed modules are shown."); |