Merge changes I5062993d,I74063a62,Id95e9dd6,Ie8496976
* changes: RollbackManager: Check for applied staged sessions on boot. Handle enable rollback for the apk session part of a staged install Track the apkSessionId associated with a staged install. Notify RollbackManager of the apk session for a staged install.
This commit is contained in:
committed by
Android (Google) Code Review
commit
8e6dc3b7ab
@@ -47,4 +47,8 @@ interface IRollbackManager {
|
||||
//
|
||||
// NOTE: This call is synchronous.
|
||||
boolean notifyStagedSession(int sessionId);
|
||||
|
||||
// Used by the staging manager to notify the RollbackManager of the apk
|
||||
// session for a staged session.
|
||||
void notifyStagedApkSession(int originalSessionId, int apkSessionId);
|
||||
}
|
||||
|
||||
@@ -380,6 +380,19 @@ public class StagingManager {
|
||||
|
||||
private boolean commitApkSession(@NonNull PackageInstallerSession apkSession,
|
||||
int originalSessionId) {
|
||||
|
||||
if ((apkSession.params.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) {
|
||||
// If rollback is available for this session, notify the rollback
|
||||
// manager of the apk session so it can properly enable rollback.
|
||||
final IRollbackManager rm = IRollbackManager.Stub.asInterface(
|
||||
ServiceManager.getService(Context.ROLLBACK_SERVICE));
|
||||
try {
|
||||
rm.notifyStagedApkSession(originalSessionId, apkSession.sessionId);
|
||||
} catch (RemoteException re) {
|
||||
// Cannot happen, the rollback manager is in the same process.
|
||||
}
|
||||
}
|
||||
|
||||
final LocalIntentReceiver receiver = new LocalIntentReceiver();
|
||||
apkSession.commit(receiver.getIntentSender(), false);
|
||||
final Intent result = receiver.getResult();
|
||||
|
||||
@@ -63,6 +63,11 @@ class RollbackData {
|
||||
*/
|
||||
public boolean isAvailable;
|
||||
|
||||
/**
|
||||
* The id of the post-reboot apk session for a staged install, if any.
|
||||
*/
|
||||
public int apkSessionId = -1;
|
||||
|
||||
/**
|
||||
* Whether this Rollback is currently in progress. This field is true from the point
|
||||
* we commit a {@code PackageInstaller} session containing these packages to the point the
|
||||
|
||||
@@ -44,4 +44,11 @@ public final class RollbackManagerService extends SystemService {
|
||||
public void onUnlockUser(int user) {
|
||||
mService.onUnlockUser(user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBootPhase(int phase) {
|
||||
if (phase == SystemService.PHASE_BOOT_COMPLETED) {
|
||||
mService.onBootCompleted();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -486,6 +486,47 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
|
||||
});
|
||||
}
|
||||
|
||||
void onBootCompleted() {
|
||||
getHandler().post(() -> {
|
||||
// Check to see if any staged sessions with rollback enabled have
|
||||
// been applied.
|
||||
List<RollbackData> staged = new ArrayList<>();
|
||||
synchronized (mLock) {
|
||||
ensureRollbackDataLoadedLocked();
|
||||
for (RollbackData data : mAvailableRollbacks) {
|
||||
if (data.stagedSessionId != -1) {
|
||||
staged.add(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (RollbackData data : staged) {
|
||||
PackageInstaller installer = mContext.getPackageManager().getPackageInstaller();
|
||||
PackageInstaller.SessionInfo session = installer.getSessionInfo(
|
||||
data.stagedSessionId);
|
||||
if (session != null) {
|
||||
if (session.isSessionApplied()) {
|
||||
synchronized (mLock) {
|
||||
data.isAvailable = true;
|
||||
}
|
||||
try {
|
||||
mRollbackStore.saveAvailableRollback(data);
|
||||
} catch (IOException ioe) {
|
||||
Log.e(TAG, "Unable to save rollback info for : "
|
||||
+ data.rollbackId, ioe);
|
||||
}
|
||||
} else if (session.isSessionFailed()) {
|
||||
// TODO: Do we need to remove this from
|
||||
// mAvailableRollbacks, or is it okay to leave as
|
||||
// unavailable until the next reboot when it will go
|
||||
// away on its own?
|
||||
mRollbackStore.deleteAvailableRollback(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Load rollback data from storage if it has not already been loaded.
|
||||
* After calling this funciton, mAvailableRollbacks and
|
||||
@@ -725,6 +766,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
|
||||
// ourselves.
|
||||
PackageInstaller.SessionInfo session = null;
|
||||
|
||||
int parentSessionId = -1;
|
||||
PackageInstaller installer = mContext.getPackageManager().getPackageInstaller();
|
||||
for (PackageInstaller.SessionInfo info : installer.getAllSessions()) {
|
||||
if (info.isMultiPackage()) {
|
||||
@@ -732,12 +774,14 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
|
||||
PackageInstaller.SessionInfo child = installer.getSessionInfo(childId);
|
||||
if (sessionMatchesForEnableRollback(child, installFlags, newPackageCodePath)) {
|
||||
// TODO: Check we only have one matching session?
|
||||
parentSessionId = info.getSessionId();
|
||||
session = child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (sessionMatchesForEnableRollback(info, installFlags, newPackageCodePath)) {
|
||||
// TODO: Check we only have one matching session?
|
||||
parentSessionId = info.getSessionId();
|
||||
session = info;
|
||||
break;
|
||||
}
|
||||
@@ -748,6 +792,54 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check to see if this is the apk session for a staged session with
|
||||
// rollback enabled.
|
||||
// TODO: This check could be made more efficient.
|
||||
RollbackData rd = null;
|
||||
synchronized (mLock) {
|
||||
ensureRollbackDataLoadedLocked();
|
||||
for (int i = 0; i < mAvailableRollbacks.size(); ++i) {
|
||||
RollbackData data = mAvailableRollbacks.get(i);
|
||||
if (data.apkSessionId == parentSessionId) {
|
||||
rd = data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rd != null) {
|
||||
// This is the apk session for a staged session. We have already
|
||||
// backed up the apks, we just need to do user data backup.
|
||||
PackageParser.PackageLite newPackage = null;
|
||||
try {
|
||||
newPackage = PackageParser.parsePackageLite(
|
||||
new File(session.resolvedBaseCodePath), 0);
|
||||
} catch (PackageParser.PackageParserException e) {
|
||||
Log.e(TAG, "Unable to parse new package", e);
|
||||
return false;
|
||||
}
|
||||
String packageName = newPackage.packageName;
|
||||
for (PackageRollbackInfo info : rd.packages) {
|
||||
if (info.getPackageName().equals(packageName)) {
|
||||
IntArray pendingBackups = mUserdataHelper.snapshotAppData(
|
||||
packageName, installedUsers);
|
||||
info.getPendingBackups().addAll(pendingBackups);
|
||||
try {
|
||||
mRollbackStore.saveAvailableRollback(rd);
|
||||
} catch (IOException ioe) {
|
||||
// TODO: Hopefully this is okay because we will try
|
||||
// again to save the rollback when the staged session
|
||||
// is applied. Just so long as the device doesn't
|
||||
// reboot before then.
|
||||
Log.e(TAG, "Unable to save rollback info for : " + rd.rollbackId, ioe);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Log.e(TAG, "Unable to find package in apk session");
|
||||
return false;
|
||||
}
|
||||
|
||||
return enableRollbackForSession(session, installedUsers, true);
|
||||
}
|
||||
|
||||
@@ -928,6 +1020,32 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyStagedApkSession(int originalSessionId, int apkSessionId) {
|
||||
getHandler().post(() -> {
|
||||
RollbackData rd = null;
|
||||
synchronized (mLock) {
|
||||
ensureRollbackDataLoadedLocked();
|
||||
for (int i = 0; i < mAvailableRollbacks.size(); ++i) {
|
||||
RollbackData data = mAvailableRollbacks.get(i);
|
||||
if (data.stagedSessionId == originalSessionId) {
|
||||
data.apkSessionId = apkSessionId;
|
||||
rd = data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rd != null) {
|
||||
try {
|
||||
mRollbackStore.saveAvailableRollback(rd);
|
||||
} catch (IOException ioe) {
|
||||
Log.e(TAG, "Unable to save rollback info for : " + rd.rollbackId, ioe);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the version of the package currently installed.
|
||||
* Returns null if the package is not currently installed.
|
||||
|
||||
@@ -248,6 +248,7 @@ class RollbackStore {
|
||||
dataJson.put("timestamp", data.timestamp.toString());
|
||||
dataJson.put("stagedSessionId", data.stagedSessionId);
|
||||
dataJson.put("isAvailable", data.isAvailable);
|
||||
dataJson.put("apkSessionId", data.apkSessionId);
|
||||
|
||||
PrintWriter pw = new PrintWriter(new File(data.backupDir, "rollback.json"));
|
||||
pw.println(dataJson.toString());
|
||||
@@ -313,6 +314,7 @@ class RollbackStore {
|
||||
stagedSessionId, isAvailable);
|
||||
data.packages.addAll(packageRollbackInfosFromJson(dataJson.getJSONArray("packages")));
|
||||
data.timestamp = Instant.parse(dataJson.getString("timestamp"));
|
||||
data.apkSessionId = dataJson.getInt("apkSessionId");
|
||||
return data;
|
||||
} catch (JSONException | DateTimeParseException e) {
|
||||
throw new IOException(e);
|
||||
|
||||
Reference in New Issue
Block a user