Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5a8283d7 authored by Mohammad Islam's avatar Mohammad Islam Committed by Gerrit Code Review
Browse files

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
parents 299036ea 40110561
Loading
Loading
Loading
Loading
+164 −25
Original line number Diff line number Diff line
@@ -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.");