From 71eee5ef917c3df35bac4c3fea4d63b3a3131378 Mon Sep 17 00:00:00 2001 From: Dario Freni Date: Thu, 6 Dec 2018 15:47:16 +0000 Subject: [PATCH] Add a state for Staged Sessions. The state is only kept up-to-date for staged sessions. Clients are in charge of checking whether the session has the isStaged bit set, before considering reading the StagedSessionState associated to that session. Test: retrieved mock staged session from a small app and verified state is correctly set. Bug: 118865310 Bug: 112669193 Bug: 120487127 Change-Id: I03590476dc353fee6d6edffb7ae579a9f9664664 --- api/current.txt | 7 ++ .../android/content/pm/PackageInstaller.java | 80 +++++++++++++++++++ .../server/pm/PackageInstallerSession.java | 14 ++++ 3 files changed, 101 insertions(+) diff --git a/api/current.txt b/api/current.txt index de4e82416193a..1ce1bdf406d2b 100644 --- a/api/current.txt +++ b/api/current.txt @@ -11366,13 +11366,20 @@ package android.content.pm { method public android.net.Uri getReferrerUri(); method public int getSessionId(); method public long getSize(); + method public int getStagedSessionErrorCode(); method public boolean isActive(); method public boolean isMultiPackage(); method public boolean isSealed(); + method public boolean isSessionApplied(); + method public boolean isSessionFailed(); + method public boolean isSessionReady(); method public boolean isStaged(); method public void writeToParcel(android.os.Parcel, int); + field public static final int ACTIVATION_FAILED = 2; // 0x2 field public static final android.os.Parcelable.Creator CREATOR; field public static final int INVALID_ID = -1; // 0xffffffff + field public static final int NO_ERROR = 0; // 0x0 + field public static final int VERIFICATION_FAILED = 1; // 0x1 } public static class PackageInstaller.SessionParams implements android.os.Parcelable { diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index f81eb7642443e..623bdda93b7e9 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -17,6 +17,7 @@ package android.content.pm; import android.Manifest; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -54,6 +55,8 @@ import java.io.Closeable; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.security.MessageDigest; import java.util.ArrayList; import java.util.Iterator; @@ -1594,6 +1597,29 @@ public class PackageInstaller { public static final int INVALID_ID = -1; /** {@hide} */ private static final int[] NO_SESSIONS = {}; + + /** @hide */ + @IntDef(value = {NO_ERROR, VERIFICATION_FAILED, ACTIVATION_FAILED}) + @Retention(RetentionPolicy.SOURCE) + public @interface StagedSessionErrorCode{} + /** + * Constant indicating that no error occurred during the preparation or the activation of + * this staged session. + */ + public static final int NO_ERROR = 0; + + /** + * Constant indicating that an error occurred during the verification phase (pre-reboot) of + * this staged session. + */ + public static final int VERIFICATION_FAILED = 1; + + /** + * Constant indicating that an error occurred during the activation phase (post-reboot) of + * this staged session. + */ + public static final int ACTIVATION_FAILED = 2; + /** {@hide} */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public int sessionId; @@ -1652,6 +1678,14 @@ public class PackageInstaller { /** {@hide} */ public int[] childSessionIds = NO_SESSIONS; + /** {@hide} */ + public boolean isSessionApplied; + /** {@hide} */ + public boolean isSessionReady; + /** {@hide} */ + public boolean isSessionFailed; + private int mStagedSessionErrorCode; + /** {@hide} */ @UnsupportedAppUsage public SessionInfo() { @@ -1686,6 +1720,10 @@ public class PackageInstaller { if (childSessionIds == null) { childSessionIds = NO_SESSIONS; } + isSessionApplied = source.readBoolean(); + isSessionReady = source.readBoolean(); + isSessionFailed = source.readBoolean(); + mStagedSessionErrorCode = source.readInt(); } /** @@ -1970,6 +2008,44 @@ public class PackageInstaller { return childSessionIds; } + /** + * Whether the staged session has been applied successfully, meaning that all of its + * packages have been activated and no further action is required. + * Only meaningful if {@code isStaged} is true. + */ + public boolean isSessionApplied() { + return isSessionApplied; + } + + /** + * Whether the staged session is ready to be applied at next reboot. Only meaningful if + * {@code isStaged} is true. + */ + public boolean isSessionReady() { + return isSessionReady; + } + + /** + * Whether something went wrong and the staged session is declared as failed, meaning that + * it will be ignored at next reboot. Only meaningful if {@code isStaged} is true. + */ + public boolean isSessionFailed() { + return isSessionFailed; + } + + /** + * If something went wrong with a staged session, clients can check this error code to + * understand which kind of failure happened. Only meaningful if {@code isStaged} is true. + */ + public int getStagedSessionErrorCode() { + return mStagedSessionErrorCode; + } + + /** {@hide} */ + public void setStagedSessionErrorCode(@StagedSessionErrorCode int errorCode) { + mStagedSessionErrorCode = errorCode; + } + @Override public int describeContents() { return 0; @@ -2001,6 +2077,10 @@ public class PackageInstaller { dest.writeBoolean(isStaged); dest.writeInt(parentSessionId); dest.writeIntArray(childSessionIds); + dest.writeBoolean(isSessionApplied); + dest.writeBoolean(isSessionReady); + dest.writeBoolean(isSessionFailed); + dest.writeInt(mStagedSessionErrorCode); } public static final Parcelable.Creator diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 206a88bde6164..0d0db94576720 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -250,6 +250,15 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @GuardedBy("mLock") private int mParentSessionId; + @GuardedBy("mLock") + private boolean mStagedSessionApplied; + @GuardedBy("mLock") + private boolean mStagedSessionReady; + @GuardedBy("mLock") + private boolean mStagedSessionFailed; + @GuardedBy("mLock") + private int mStagedSessionErrorCode = SessionInfo.NO_ERROR; + /** * Path to the validated base APK for this session, which may point at an * APK inside the session (when the session defines the base), or it may @@ -470,6 +479,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { if (info.childSessionIds == null) { info.childSessionIds = EMPTY_CHILD_SESSION_ARRAY; } + info.isSessionApplied = mStagedSessionApplied; + info.isSessionReady = mStagedSessionReady; + info.isSessionFailed = mStagedSessionFailed; + info.setStagedSessionErrorCode(mStagedSessionErrorCode); } return info; } @@ -1051,6 +1064,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } if (isStaged()) { // STOPSHIP: implement staged sessions + mStagedSessionReady = true; dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "Session staged", null); return; }