diff options
| author | 2018-12-12 11:55:01 +0000 | |
|---|---|---|
| committer | 2018-12-12 11:55:01 +0000 | |
| commit | ec06c2536023f207d1c900c544932cc46699af66 (patch) | |
| tree | c7a0777ed1a05d55e5beb61643d991eb507b55a6 | |
| parent | ab11e004490229e41cbd3cc31361bb67bb8a3e07 (diff) | |
| parent | aac4ba4b24424479aa3ce9522e7f775e0c3e67ae (diff) | |
Merge "Add Mock APIs for staged installs."
7 files changed, 120 insertions, 2 deletions
diff --git a/api/current.txt b/api/current.txt index 4804136173f1..e43007e0b4de 100644 --- a/api/current.txt +++ b/api/current.txt @@ -11235,6 +11235,7 @@ package android.content.pm { method public java.util.List<android.content.pm.PackageInstaller.SessionInfo> getAllSessions(); method public java.util.List<android.content.pm.PackageInstaller.SessionInfo> getMySessions(); method public android.content.pm.PackageInstaller.SessionInfo getSessionInfo(int); + method public java.util.List<android.content.pm.PackageInstaller.SessionInfo> getStagedSessions(); method public android.content.pm.PackageInstaller.Session openSession(int) throws java.io.IOException; method public void registerSessionCallback(android.content.pm.PackageInstaller.SessionCallback); method public void registerSessionCallback(android.content.pm.PackageInstaller.SessionCallback, android.os.Handler); @@ -11273,6 +11274,7 @@ package android.content.pm { method public java.lang.String[] getNames() throws java.io.IOException; method public int getParentSessionId(); method public boolean isMultiPackage(); + method public boolean isStaged(); method public java.io.InputStream openRead(java.lang.String) throws java.io.IOException; method public java.io.OutputStream openWrite(java.lang.String, long, long) throws java.io.IOException; method public void removeChildSessionId(int); @@ -11311,6 +11313,7 @@ package android.content.pm { method public boolean isActive(); method public boolean isMultiPackage(); method public boolean isSealed(); + method public boolean isStaged(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.content.pm.PackageInstaller.SessionInfo> CREATOR; field public static final int INVALID_ID = -1; // 0xffffffff @@ -11329,6 +11332,7 @@ package android.content.pm { method public void setOriginatingUri(android.net.Uri); method public void setReferrerUri(android.net.Uri); method public void setSize(long); + method public void setStaged(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.content.pm.PackageInstaller.SessionParams> CREATOR; field public static final int MODE_FULL_INSTALL = 1; // 0x1 diff --git a/core/java/android/content/pm/IPackageInstaller.aidl b/core/java/android/content/pm/IPackageInstaller.aidl index ecc8cd678af1..a251c0036a78 100644 --- a/core/java/android/content/pm/IPackageInstaller.aidl +++ b/core/java/android/content/pm/IPackageInstaller.aidl @@ -42,6 +42,8 @@ interface IPackageInstaller { ParceledListSlice getAllSessions(int userId); ParceledListSlice getMySessions(String installerPackageName, int userId); + ParceledListSlice getStagedSessions(); + void registerCallback(IPackageInstallerCallback callback, int userId); void unregisterCallback(IPackageInstallerCallback callback); diff --git a/core/java/android/content/pm/IPackageInstallerSession.aidl b/core/java/android/content/pm/IPackageInstallerSession.aidl index cef21f607e5f..04e15c7957bd 100644 --- a/core/java/android/content/pm/IPackageInstallerSession.aidl +++ b/core/java/android/content/pm/IPackageInstallerSession.aidl @@ -38,9 +38,12 @@ interface IPackageInstallerSession { void commit(in IntentSender statusReceiver, boolean forTransferred); void transfer(in String packageName); void abandon(); + boolean isMultiPackage(); int[] getChildSessionIds(); void addChildSessionId(in int sessionId); void removeChildSessionId(in int sessionId); int getParentSessionId(); + + boolean isStaged(); } diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index 07672d979cf5..96c30f156105 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -463,6 +463,18 @@ public class PackageInstaller { } /** + * Return list of all staged install sessions. + */ + public @NonNull List<SessionInfo> getStagedSessions() { + try { + // TODO: limit this to the mUserId? + return mInstaller.getStagedSessions().getList(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Uninstall the given package, removing it completely from the device. This * method is available to: * <ul> @@ -779,6 +791,11 @@ public class PackageInstaller { * individual session IDs can be added with {@link #addChildSessionId(int)} * and commit of the multi-package session will result in all child sessions * being committed atomically. + * <p> + * If a package requires to be installed only at reboot, the session should + * be marked as a staged session by calling {@link SessionParams#setStaged()} + * with {@code true}. This can also apply to a multi-package session, in + * which case all the packages in the session will be applied at reboot. */ public static class Session implements Closeable { /** {@hide} */ @@ -1105,6 +1122,17 @@ public class PackageInstaller { } /** + * @return {@code true} if this session will be staged and applied at next reboot. + */ + public boolean isStaged() { + try { + return mSession.isStaged(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * @return the session ID of the multi-package session that this belongs to or * {@link SessionInfo#INVALID_ID} if it does not belong to a multi-package session. */ @@ -1227,6 +1255,8 @@ public class PackageInstaller { public String installerPackageName; /** {@hide} */ public boolean isMultiPackage; + /** {@hide} */ + public boolean isStaged; /** * Construct parameters for a new package install session. @@ -1257,6 +1287,7 @@ public class PackageInstaller { grantedRuntimePermissions = source.readStringArray(); installerPackageName = source.readString(); isMultiPackage = source.readBoolean(); + isStaged = source.readBoolean(); } /** @@ -1471,6 +1502,17 @@ public class PackageInstaller { this.isMultiPackage = true; } + /** + * Set this session to be staged to be installed at reboot. + * + * Staged sessions are scheduled to be installed at next reboot. Staged sessions can also be + * multi-package. In that case, if any of the children sessions fail to install at reboot, + * all the other children sessions are aborted as well. + */ + public void setStaged() { + this.isStaged = true; + } + /** {@hide} */ public void dump(IndentingPrintWriter pw) { pw.printPair("mode", mode); @@ -1488,6 +1530,7 @@ public class PackageInstaller { pw.printPair("grantedRuntimePermissions", grantedRuntimePermissions); pw.printPair("installerPackageName", installerPackageName); pw.printPair("isMultiPackage", isMultiPackage); + pw.printPair("isStaged", isStaged); pw.println(); } @@ -1514,6 +1557,7 @@ public class PackageInstaller { dest.writeStringArray(grantedRuntimePermissions); dest.writeString(installerPackageName); dest.writeBoolean(isMultiPackage); + dest.writeBoolean(isStaged); } public static final Parcelable.Creator<SessionParams> @@ -1593,6 +1637,8 @@ public class PackageInstaller { /** {@hide} */ public boolean isMultiPackage; /** {@hide} */ + public boolean isStaged; + /** {@hide} */ public int parentSessionId = INVALID_ID; /** {@hide} */ public int[] childSessionIds = NO_SESSIONS; @@ -1625,6 +1671,7 @@ public class PackageInstaller { grantedRuntimePermissions = source.readStringArray(); installFlags = source.readInt(); isMultiPackage = source.readBoolean(); + isStaged = source.readBoolean(); parentSessionId = source.readInt(); childSessionIds = source.createIntArray(); if (childSessionIds == null) { @@ -1892,6 +1939,13 @@ public class PackageInstaller { } /** + * Returns true if this session is a staged session which will be applied at next reboot. + */ + public boolean isStaged() { + return isStaged; + } + + /** * Returns the parent multi-package session ID if this session belongs to one, * {@link #INVALID_ID} otherwise. */ @@ -1935,6 +1989,7 @@ public class PackageInstaller { dest.writeStringArray(grantedRuntimePermissions); dest.writeInt(installFlags); dest.writeBoolean(isMultiPackage); + dest.writeBoolean(isStaged); dest.writeInt(parentSessionId); dest.writeIntArray(childSessionIds); } diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 2e9a71a178fb..57922d052984 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -164,6 +164,11 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements @GuardedBy("mSessions") private final SparseArray<PackageInstallerSession> mSessions = new SparseArray<>(); + // STOPSHIP: This is a temporary mock implementation of staged sessions. This variable + // shouldn't be needed at all. + @GuardedBy("mStagedSessions") + private final SparseArray<PackageInstallerSession> mStagedSessions = new SparseArray<>(); + /** Historical sessions kept around for debugging purposes */ @GuardedBy("mSessions") private final List<String> mHistoricalSessions = new ArrayList<>(); @@ -536,6 +541,11 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements synchronized (mSessions) { mSessions.put(sessionId, session); } + if (params.isStaged) { + synchronized (mStagedSessions) { + mStagedSessions.put(sessionId, session); + } + } mCallbacks.notifySessionCreated(session.sessionId, session.userId); writeSessionsAsync(); @@ -666,6 +676,18 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements } @Override + public ParceledListSlice<SessionInfo> getStagedSessions() { + final List<SessionInfo> result = new ArrayList<>(); + synchronized (mStagedSessions) { + for (int i = 0; i < mStagedSessions.size(); i++) { + final PackageInstallerSession session = mStagedSessions.valueAt(i); + result.add(session.generateInfo(false)); + } + } + return new ParceledListSlice<>(result); + } + + @Override public ParceledListSlice<SessionInfo> getAllSessions(int userId) { mPermissionManager.enforceCrossUserPermission( Binder.getCallingUid(), userId, true, false, "getAllSessions"); @@ -1110,6 +1132,18 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements mInstallHandler.post(new Runnable() { @Override public void run() { + // TODO: remove this mock implementation. + if (session.isStaged()) { + // If the session is aborted, don't keep it in memory. Only store + // sessions successfully staged. + if (!success) { + synchronized (mStagedSessions) { + mStagedSessions.remove(session.sessionId); + } + } else { + return; + } + } synchronized (mSessions) { mSessions.remove(session.sessionId); addHistoricalSessionLocked(session); diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index ea190a7301fc..26a92a4cdde4 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -125,7 +125,7 @@ import java.util.List; import java.util.concurrent.atomic.AtomicInteger; public class PackageInstallerSession extends IPackageInstallerSession.Stub { - private static final String TAG = "PackageInstaller"; + private static final String TAG = "PackageInstallerSession"; private static final boolean LOGD = true; private static final String REMOVE_SPLIT_MARKER_EXTENSION = ".removed"; @@ -147,6 +147,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { private static final String ATTR_SEALED = "sealed"; private static final String ATTR_MULTI_PACKAGE = "multiPackage"; private static final String ATTR_PARENT_SESSION_ID = "parentSessionId"; + private static final String ATTR_STAGED_SESSION = "stagedSession"; private static final String ATTR_MODE = "mode"; private static final String ATTR_INSTALL_FLAGS = "installFlags"; private static final String ATTR_INSTALL_LOCATION = "installLocation"; @@ -463,6 +464,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { info.grantedRuntimePermissions = params.grantedRuntimePermissions; info.installFlags = params.installFlags; info.isMultiPackage = params.isMultiPackage; + info.isStaged = params.isStaged; info.parentSessionId = mParentSessionId; info.childSessionIds = mChildSessionIds.copyKeys(); if (info.childSessionIds == null) { @@ -1047,6 +1049,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { if (committingSession == null) { return; } + if (isStaged()) { + // STOPSHIP: implement staged sessions + dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "Session staged", null); + return; + } if (isMultiPackage()) { final int[] childSessionIds = getChildSessionIds(); List<PackageManagerService.ActiveInstallSession> childSessions = @@ -1816,6 +1823,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } @Override + public boolean isStaged() { + return params.isStaged; + } + + @Override public int[] getChildSessionIds() { final int[] childSessionIds = mChildSessionIds.copyKeys(); if (childSessionIds != null) { @@ -1838,6 +1850,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { return; } session.setParentSessionId(this.sessionId); + // TODO: sanity check, if parent session is staged then child session should be + // marked as staged. addChildSessionIdInternal(sessionId); } } @@ -1975,6 +1989,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { pw.printPair("mFinalStatus", mFinalStatus); pw.printPair("mFinalMessage", mFinalMessage); pw.printPair("params.isMultiPackage", params.isMultiPackage); + pw.printPair("params.isStaged", params.isStaged); pw.println(); pw.decreaseIndent(); @@ -2026,6 +2041,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { writeBooleanAttribute(out, ATTR_SEALED, isSealed()); writeBooleanAttribute(out, ATTR_MULTI_PACKAGE, params.isMultiPackage); + writeBooleanAttribute(out, ATTR_STAGED_SESSION, params.isStaged); // TODO(patb,109941548): avoid writing to xml and instead infer / validate this after // we've read all sessions. writeIntAttribute(out, ATTR_PARENT_SESSION_ID, mParentSessionId); @@ -2140,6 +2156,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { final SessionParams params = new SessionParams( SessionParams.MODE_INVALID); params.isMultiPackage = readBooleanAttribute(in, ATTR_MULTI_PACKAGE, false); + params.isStaged = readBooleanAttribute(in, ATTR_STAGED_SESSION, false); params.mode = readIntAttribute(in, ATTR_MODE); params.installFlags = readIntAttribute(in, ATTR_INSTALL_FLAGS); params.installLocation = readIntAttribute(in, ATTR_INSTALL_LOCATION); diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index 77f8c3a0308a..ee9c5ce4a854 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -2284,6 +2284,9 @@ class PackageManagerShellCommand extends ShellCommand { case "--multi-package": sessionParams.setMultiPackage(); break; + case "--staged": + sessionParams.setStaged(); + break; default: throw new IllegalArgumentException("Unknown option " + opt); } @@ -2853,7 +2856,7 @@ class PackageManagerShellCommand extends ShellCommand { pw.println(" [--referrer URI] [--abi ABI_NAME] [--force-sdk]"); pw.println(" [--preload] [--instantapp] [--full] [--dont-kill]"); pw.println(" [--force-uuid internal|UUID] [--pkg PACKAGE] [--apex] [-S BYTES]"); - pw.println(" [--multi-package]"); + pw.println(" [--multi-package] [--staged]"); pw.println(" Like \"install\", but starts an install session. Use \"install-write\""); pw.println(" to push data into the session, and \"install-commit\" to finish."); pw.println(""); |