Loading services/core/java/com/android/server/pm/PackageManagerShellCommand.java +164 −25 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 = Loading Loading @@ -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": Loading Loading @@ -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<>(); Loading Loading @@ -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(), Loading Loading @@ -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; Loading Loading @@ -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 { Loading Loading @@ -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() { Loading Loading @@ -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); } Loading Loading @@ -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."); Loading @@ -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:"); Loading Loading @@ -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]"); Loading Loading @@ -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."); Loading Loading
services/core/java/com/android/server/pm/PackageManagerShellCommand.java +164 −25 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 = Loading Loading @@ -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": Loading Loading @@ -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<>(); Loading Loading @@ -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(), Loading Loading @@ -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; Loading Loading @@ -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 { Loading Loading @@ -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() { Loading Loading @@ -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); } Loading Loading @@ -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."); Loading @@ -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:"); Loading Loading @@ -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]"); Loading Loading @@ -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."); Loading