Loading core/java/android/content/pm/PackageManager.java +9 −1 Original line number Diff line number Diff line Loading @@ -946,7 +946,8 @@ public abstract class PackageManager { INSTALL_REASON_POLICY, INSTALL_REASON_DEVICE_RESTORE, INSTALL_REASON_DEVICE_SETUP, INSTALL_REASON_USER INSTALL_REASON_USER, INSTALL_REASON_ROLLBACK }) @Retention(RetentionPolicy.SOURCE) public @interface InstallReason {} Loading Loading @@ -976,6 +977,13 @@ public abstract class PackageManager { */ public static final int INSTALL_REASON_USER = 4; /** * Code indicating that the package installation was a rollback initiated by RollbackManager. * * @hide */ public static final int INSTALL_REASON_ROLLBACK = 5; /** * @hide */ Loading core/java/android/content/rollback/IRollbackManager.aidl +2 −1 Original line number Diff line number Diff line Loading @@ -44,9 +44,10 @@ interface IRollbackManager { // Used by the staging manager to notify the RollbackManager that a session is // being staged. In the case of multi-package sessions, the specified sessionId // is that of the parent session. // Returns the rollback id if rollback was enabled successfully, or -1 if not. // // NOTE: This call is synchronous. boolean notifyStagedSession(int sessionId); int notifyStagedSession(int sessionId); // Used by the staging manager to notify the RollbackManager of the apk // session for a staged session. Loading services/core/java/com/android/server/pm/ApexManager.java +5 −10 Original line number Diff line number Diff line Loading @@ -17,11 +17,11 @@ package com.android.server.pm; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.apex.ApexInfo; import android.apex.ApexInfoList; import android.apex.ApexSessionInfo; import android.apex.ApexSessionParams; import android.apex.IApexService; import android.content.BroadcastReceiver; import android.content.Context; Loading Loading @@ -176,13 +176,9 @@ abstract class ApexManager { * enough for it to be activated at the next boot, the caller needs to call * {@link #markStagedSessionReady(int)}. * * @param sessionId the identifier of the {@link PackageInstallerSession} being submitted. * @param childSessionIds if {@code sessionId} is a multi-package session, this should contain * an array of identifiers of all the child sessions. Otherwise it should * be an empty array. * @throws PackageManagerException if call to apexd fails */ abstract ApexInfoList submitStagedSession(int sessionId, @NonNull int[] childSessionIds) abstract ApexInfoList submitStagedSession(ApexSessionParams params) throws PackageManagerException; /** Loading Loading @@ -450,11 +446,10 @@ abstract class ApexManager { } @Override ApexInfoList submitStagedSession(int sessionId, @NonNull int[] childSessionIds) throws PackageManagerException { ApexInfoList submitStagedSession(ApexSessionParams params) throws PackageManagerException { try { final ApexInfoList apexInfoList = new ApexInfoList(); mApexService.submitStagedSession(sessionId, childSessionIds, apexInfoList); mApexService.submitStagedSession(params, apexInfoList); return apexInfoList; } catch (RemoteException re) { Slog.e(TAG, "Unable to contact apexservice", re); Loading Loading @@ -686,7 +681,7 @@ abstract class ApexManager { } @Override ApexInfoList submitStagedSession(int sessionId, int[] childSessionIds) ApexInfoList submitStagedSession(ApexSessionParams params) throws PackageManagerException { throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, "Device doesn't support updating APEX"); Loading services/core/java/com/android/server/pm/StagingManager.java +61 −23 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.annotation.Nullable; import android.apex.ApexInfo; import android.apex.ApexInfoList; import android.apex.ApexSessionInfo; import android.apex.ApexSessionParams; import android.content.Context; import android.content.IIntentReceiver; import android.content.IIntentSender; Loading @@ -36,6 +37,8 @@ import android.content.pm.PackageParser.SigningDetails; import android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion; import android.content.pm.ParceledListSlice; import android.content.rollback.IRollbackManager; import android.content.rollback.RollbackInfo; import android.content.rollback.RollbackManager; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; Loading @@ -49,6 +52,7 @@ import android.os.storage.StorageManager; import android.util.IntArray; import android.util.Slog; import android.util.SparseArray; import android.util.SparseIntArray; import android.util.apk.ApkSignatureVerifier; import com.android.internal.annotations.GuardedBy; Loading Loading @@ -82,6 +86,9 @@ public class StagingManager { @GuardedBy("mStagedSessions") private final SparseArray<PackageInstallerSession> mStagedSessions = new SparseArray<>(); @GuardedBy("mStagedSessions") private final SparseIntArray mSessionRollbackIds = new SparseIntArray(); StagingManager(PackageInstallerService pi, ApexManager am, Context context) { mPi = pi; mApexManager = am; Loading Loading @@ -166,18 +173,32 @@ public class StagingManager { private List<PackageInfo> submitSessionToApexService( @NonNull PackageInstallerSession session) throws PackageManagerException { final IntArray childSessionsIds = new IntArray(); final IntArray childSessionIds = new IntArray(); if (session.isMultiPackage()) { for (int id : session.getChildSessionIds()) { if (isApexSession(mStagedSessions.get(id))) { childSessionsIds.add(id); childSessionIds.add(id); } } } ApexSessionParams apexSessionParams = new ApexSessionParams(); apexSessionParams.sessionId = session.sessionId; apexSessionParams.childSessionIds = childSessionIds.toArray(); if (session.params.installReason == PackageManager.INSTALL_REASON_ROLLBACK) { apexSessionParams.isRollback = true; apexSessionParams.rollbackId = retrieveRollbackIdForCommitSession(session.sessionId); } else { synchronized (mStagedSessions) { int rollbackId = mSessionRollbackIds.get(session.sessionId, -1); if (rollbackId != -1) { apexSessionParams.hasRollbackEnabled = true; apexSessionParams.rollbackId = rollbackId; } } } // submitStagedSession will throw a PackageManagerException if apexd verification fails, // which will be propagated to populate stagedSessionErrorMessage of this session. final ApexInfoList apexInfoList = mApexManager.submitStagedSession(session.sessionId, childSessionsIds.toArray()); final ApexInfoList apexInfoList = mApexManager.submitStagedSession(apexSessionParams); final List<PackageInfo> result = new ArrayList<>(); for (ApexInfo apexInfo : apexInfoList.apexInfos) { final PackageInfo packageInfo; Loading Loading @@ -208,6 +229,19 @@ public class StagingManager { return result; } private int retrieveRollbackIdForCommitSession(int sessionId) throws PackageManagerException { RollbackManager rm = mContext.getSystemService(RollbackManager.class); List<RollbackInfo> rollbacks = rm.getRecentlyCommittedRollbacks(); for (RollbackInfo rollback : rollbacks) { if (rollback.getCommittedSessionId() == sessionId) { return rollback.getRollbackId(); } } throw new PackageManagerException( "Could not find rollback id for commit session: " + sessionId); } private void checkRequiredVersionCode(final PackageInstallerSession session, final PackageInfo activePackage) throws PackageManagerException { if (session.params.requiredInstalledVersionCode == PackageManager.VERSION_CODE_HIGHEST) { Loading Loading @@ -633,6 +667,7 @@ public class StagingManager { void abortSession(@NonNull PackageInstallerSession session) { synchronized (mStagedSessions) { mStagedSessions.remove(session.sessionId); mSessionRollbackIds.delete(session.sessionId); } } Loading Loading @@ -865,6 +900,28 @@ public class StagingManager { */ private void handlePreRebootVerification_Start(@NonNull PackageInstallerSession session) { Slog.d(TAG, "Starting preRebootVerification for session " + session.sessionId); if ((session.params.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) { // If rollback is enabled for this session, we call through to the RollbackManager // with the list of sessions it must enable rollback for. Note that // notifyStagedSession is a synchronous operation. final IRollbackManager rm = IRollbackManager.Stub.asInterface( ServiceManager.getService(Context.ROLLBACK_SERVICE)); try { // NOTE: To stay consistent with the non-staged install flow, we don't fail the // entire install if rollbacks can't be enabled. int rollbackId = rm.notifyStagedSession(session.sessionId); if (rollbackId != -1) { synchronized (mStagedSessions) { mSessionRollbackIds.put(session.sessionId, rollbackId); } } } catch (RemoteException re) { Slog.e(TAG, "Failed to notifyStagedSession for session: " + session.sessionId, re); } } notifyPreRebootVerification_Start_Complete(session.sessionId); } Loading Loading @@ -929,25 +986,6 @@ public class StagingManager { * </ul></p> */ private void handlePreRebootVerification_End(@NonNull PackageInstallerSession session) { if ((session.params.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) { // If rollback is enabled for this session, we call through to the RollbackManager // with the list of sessions it must enable rollback for. Note that // notifyStagedSession is a synchronous operation. final IRollbackManager rm = IRollbackManager.Stub.asInterface( ServiceManager.getService(Context.ROLLBACK_SERVICE)); try { // NOTE: To stay consistent with the non-staged install flow, we don't fail the // entire install if rollbacks can't be enabled. if (!rm.notifyStagedSession(session.sessionId)) { Slog.e(TAG, "Unable to enable rollback for session: " + session.sessionId); } } catch (RemoteException re) { Slog.e(TAG, "Failed to notifyStagedSession for session: " + session.sessionId, re); } } // Proactively mark session as ready before calling apexd. Although this call order // looks counter-intuitive, this is the easiest way to ensure that session won't end up // in the inconsistent state: Loading services/core/java/com/android/server/rollback/Rollback.java +3 −1 Original line number Diff line number Diff line Loading @@ -418,6 +418,7 @@ class Rollback { if (isStaged()) { parentParams.setStaged(); } parentParams.setInstallReason(PackageManager.INSTALL_REASON_ROLLBACK); int parentSessionId = packageInstaller.createSession(parentParams); PackageInstaller.Session parentSession = packageInstaller.openSession( Loading Loading @@ -484,6 +485,7 @@ class Rollback { synchronized (mLock) { mState = ROLLBACK_STATE_AVAILABLE; mRestoreUserDataInProgress = false; info.setCommittedSessionId(-1); } sendFailure(context, statusReceiver, RollbackManager.STATUS_FAILURE_INSTALL, Loading @@ -500,7 +502,6 @@ class Rollback { mRestoreUserDataInProgress = false; } info.setCommittedSessionId(parentSessionId); info.getCausePackages().addAll(causePackages); RollbackStore.deletePackageCodePaths(this); RollbackStore.saveRollback(this); Loading Loading @@ -528,6 +529,7 @@ class Rollback { ); mState = ROLLBACK_STATE_COMMITTED; info.setCommittedSessionId(parentSessionId); mRestoreUserDataInProgress = true; parentSession.commit(receiver.getIntentSender()); } catch (IOException e) { Loading Loading
core/java/android/content/pm/PackageManager.java +9 −1 Original line number Diff line number Diff line Loading @@ -946,7 +946,8 @@ public abstract class PackageManager { INSTALL_REASON_POLICY, INSTALL_REASON_DEVICE_RESTORE, INSTALL_REASON_DEVICE_SETUP, INSTALL_REASON_USER INSTALL_REASON_USER, INSTALL_REASON_ROLLBACK }) @Retention(RetentionPolicy.SOURCE) public @interface InstallReason {} Loading Loading @@ -976,6 +977,13 @@ public abstract class PackageManager { */ public static final int INSTALL_REASON_USER = 4; /** * Code indicating that the package installation was a rollback initiated by RollbackManager. * * @hide */ public static final int INSTALL_REASON_ROLLBACK = 5; /** * @hide */ Loading
core/java/android/content/rollback/IRollbackManager.aidl +2 −1 Original line number Diff line number Diff line Loading @@ -44,9 +44,10 @@ interface IRollbackManager { // Used by the staging manager to notify the RollbackManager that a session is // being staged. In the case of multi-package sessions, the specified sessionId // is that of the parent session. // Returns the rollback id if rollback was enabled successfully, or -1 if not. // // NOTE: This call is synchronous. boolean notifyStagedSession(int sessionId); int notifyStagedSession(int sessionId); // Used by the staging manager to notify the RollbackManager of the apk // session for a staged session. Loading
services/core/java/com/android/server/pm/ApexManager.java +5 −10 Original line number Diff line number Diff line Loading @@ -17,11 +17,11 @@ package com.android.server.pm; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.apex.ApexInfo; import android.apex.ApexInfoList; import android.apex.ApexSessionInfo; import android.apex.ApexSessionParams; import android.apex.IApexService; import android.content.BroadcastReceiver; import android.content.Context; Loading Loading @@ -176,13 +176,9 @@ abstract class ApexManager { * enough for it to be activated at the next boot, the caller needs to call * {@link #markStagedSessionReady(int)}. * * @param sessionId the identifier of the {@link PackageInstallerSession} being submitted. * @param childSessionIds if {@code sessionId} is a multi-package session, this should contain * an array of identifiers of all the child sessions. Otherwise it should * be an empty array. * @throws PackageManagerException if call to apexd fails */ abstract ApexInfoList submitStagedSession(int sessionId, @NonNull int[] childSessionIds) abstract ApexInfoList submitStagedSession(ApexSessionParams params) throws PackageManagerException; /** Loading Loading @@ -450,11 +446,10 @@ abstract class ApexManager { } @Override ApexInfoList submitStagedSession(int sessionId, @NonNull int[] childSessionIds) throws PackageManagerException { ApexInfoList submitStagedSession(ApexSessionParams params) throws PackageManagerException { try { final ApexInfoList apexInfoList = new ApexInfoList(); mApexService.submitStagedSession(sessionId, childSessionIds, apexInfoList); mApexService.submitStagedSession(params, apexInfoList); return apexInfoList; } catch (RemoteException re) { Slog.e(TAG, "Unable to contact apexservice", re); Loading Loading @@ -686,7 +681,7 @@ abstract class ApexManager { } @Override ApexInfoList submitStagedSession(int sessionId, int[] childSessionIds) ApexInfoList submitStagedSession(ApexSessionParams params) throws PackageManagerException { throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, "Device doesn't support updating APEX"); Loading
services/core/java/com/android/server/pm/StagingManager.java +61 −23 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.annotation.Nullable; import android.apex.ApexInfo; import android.apex.ApexInfoList; import android.apex.ApexSessionInfo; import android.apex.ApexSessionParams; import android.content.Context; import android.content.IIntentReceiver; import android.content.IIntentSender; Loading @@ -36,6 +37,8 @@ import android.content.pm.PackageParser.SigningDetails; import android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion; import android.content.pm.ParceledListSlice; import android.content.rollback.IRollbackManager; import android.content.rollback.RollbackInfo; import android.content.rollback.RollbackManager; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; Loading @@ -49,6 +52,7 @@ import android.os.storage.StorageManager; import android.util.IntArray; import android.util.Slog; import android.util.SparseArray; import android.util.SparseIntArray; import android.util.apk.ApkSignatureVerifier; import com.android.internal.annotations.GuardedBy; Loading Loading @@ -82,6 +86,9 @@ public class StagingManager { @GuardedBy("mStagedSessions") private final SparseArray<PackageInstallerSession> mStagedSessions = new SparseArray<>(); @GuardedBy("mStagedSessions") private final SparseIntArray mSessionRollbackIds = new SparseIntArray(); StagingManager(PackageInstallerService pi, ApexManager am, Context context) { mPi = pi; mApexManager = am; Loading Loading @@ -166,18 +173,32 @@ public class StagingManager { private List<PackageInfo> submitSessionToApexService( @NonNull PackageInstallerSession session) throws PackageManagerException { final IntArray childSessionsIds = new IntArray(); final IntArray childSessionIds = new IntArray(); if (session.isMultiPackage()) { for (int id : session.getChildSessionIds()) { if (isApexSession(mStagedSessions.get(id))) { childSessionsIds.add(id); childSessionIds.add(id); } } } ApexSessionParams apexSessionParams = new ApexSessionParams(); apexSessionParams.sessionId = session.sessionId; apexSessionParams.childSessionIds = childSessionIds.toArray(); if (session.params.installReason == PackageManager.INSTALL_REASON_ROLLBACK) { apexSessionParams.isRollback = true; apexSessionParams.rollbackId = retrieveRollbackIdForCommitSession(session.sessionId); } else { synchronized (mStagedSessions) { int rollbackId = mSessionRollbackIds.get(session.sessionId, -1); if (rollbackId != -1) { apexSessionParams.hasRollbackEnabled = true; apexSessionParams.rollbackId = rollbackId; } } } // submitStagedSession will throw a PackageManagerException if apexd verification fails, // which will be propagated to populate stagedSessionErrorMessage of this session. final ApexInfoList apexInfoList = mApexManager.submitStagedSession(session.sessionId, childSessionsIds.toArray()); final ApexInfoList apexInfoList = mApexManager.submitStagedSession(apexSessionParams); final List<PackageInfo> result = new ArrayList<>(); for (ApexInfo apexInfo : apexInfoList.apexInfos) { final PackageInfo packageInfo; Loading Loading @@ -208,6 +229,19 @@ public class StagingManager { return result; } private int retrieveRollbackIdForCommitSession(int sessionId) throws PackageManagerException { RollbackManager rm = mContext.getSystemService(RollbackManager.class); List<RollbackInfo> rollbacks = rm.getRecentlyCommittedRollbacks(); for (RollbackInfo rollback : rollbacks) { if (rollback.getCommittedSessionId() == sessionId) { return rollback.getRollbackId(); } } throw new PackageManagerException( "Could not find rollback id for commit session: " + sessionId); } private void checkRequiredVersionCode(final PackageInstallerSession session, final PackageInfo activePackage) throws PackageManagerException { if (session.params.requiredInstalledVersionCode == PackageManager.VERSION_CODE_HIGHEST) { Loading Loading @@ -633,6 +667,7 @@ public class StagingManager { void abortSession(@NonNull PackageInstallerSession session) { synchronized (mStagedSessions) { mStagedSessions.remove(session.sessionId); mSessionRollbackIds.delete(session.sessionId); } } Loading Loading @@ -865,6 +900,28 @@ public class StagingManager { */ private void handlePreRebootVerification_Start(@NonNull PackageInstallerSession session) { Slog.d(TAG, "Starting preRebootVerification for session " + session.sessionId); if ((session.params.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) { // If rollback is enabled for this session, we call through to the RollbackManager // with the list of sessions it must enable rollback for. Note that // notifyStagedSession is a synchronous operation. final IRollbackManager rm = IRollbackManager.Stub.asInterface( ServiceManager.getService(Context.ROLLBACK_SERVICE)); try { // NOTE: To stay consistent with the non-staged install flow, we don't fail the // entire install if rollbacks can't be enabled. int rollbackId = rm.notifyStagedSession(session.sessionId); if (rollbackId != -1) { synchronized (mStagedSessions) { mSessionRollbackIds.put(session.sessionId, rollbackId); } } } catch (RemoteException re) { Slog.e(TAG, "Failed to notifyStagedSession for session: " + session.sessionId, re); } } notifyPreRebootVerification_Start_Complete(session.sessionId); } Loading Loading @@ -929,25 +986,6 @@ public class StagingManager { * </ul></p> */ private void handlePreRebootVerification_End(@NonNull PackageInstallerSession session) { if ((session.params.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) { // If rollback is enabled for this session, we call through to the RollbackManager // with the list of sessions it must enable rollback for. Note that // notifyStagedSession is a synchronous operation. final IRollbackManager rm = IRollbackManager.Stub.asInterface( ServiceManager.getService(Context.ROLLBACK_SERVICE)); try { // NOTE: To stay consistent with the non-staged install flow, we don't fail the // entire install if rollbacks can't be enabled. if (!rm.notifyStagedSession(session.sessionId)) { Slog.e(TAG, "Unable to enable rollback for session: " + session.sessionId); } } catch (RemoteException re) { Slog.e(TAG, "Failed to notifyStagedSession for session: " + session.sessionId, re); } } // Proactively mark session as ready before calling apexd. Although this call order // looks counter-intuitive, this is the easiest way to ensure that session won't end up // in the inconsistent state: Loading
services/core/java/com/android/server/rollback/Rollback.java +3 −1 Original line number Diff line number Diff line Loading @@ -418,6 +418,7 @@ class Rollback { if (isStaged()) { parentParams.setStaged(); } parentParams.setInstallReason(PackageManager.INSTALL_REASON_ROLLBACK); int parentSessionId = packageInstaller.createSession(parentParams); PackageInstaller.Session parentSession = packageInstaller.openSession( Loading Loading @@ -484,6 +485,7 @@ class Rollback { synchronized (mLock) { mState = ROLLBACK_STATE_AVAILABLE; mRestoreUserDataInProgress = false; info.setCommittedSessionId(-1); } sendFailure(context, statusReceiver, RollbackManager.STATUS_FAILURE_INSTALL, Loading @@ -500,7 +502,6 @@ class Rollback { mRestoreUserDataInProgress = false; } info.setCommittedSessionId(parentSessionId); info.getCausePackages().addAll(causePackages); RollbackStore.deletePackageCodePaths(this); RollbackStore.saveRollback(this); Loading Loading @@ -528,6 +529,7 @@ class Rollback { ); mState = ROLLBACK_STATE_COMMITTED; info.setCommittedSessionId(parentSessionId); mRestoreUserDataInProgress = true; parentSession.commit(receiver.getIntentSender()); } catch (IOException e) { Loading