summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMohammad Islam <samiul@google.com>2019-10-09 08:34:34 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2019-10-09 08:34:34 +0000
commit5a8283d7fd8f3dee8d33ae91784a31907200aaa7 (patch)
tree9c96b912e5e452e54558ceb42b5209118f02caed
parent299036ea2fd4bde2330fbac8dfb3bea2e50c2f91 (diff)
parent40110561de02add5f2ad1b22812e8caa1c204ab3 (diff)
downloadbase-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.java189
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.");