功能介绍:
在Android 10.0中,Google新增加了个功能。
如果用户对新升级的APP不满意,可以通过“回到过去”,回滚到旧版。
当然,如果新安装的apk出现了各种问题无法使用,也可以进行回滚的操作。
这样的确可以极大的提升用户的体验,但是因为这块的逻辑较复杂,我们以module_crash_rollback_test为例,来看下具体的实现逻辑。
代码路径如下:
./base/services/core/java/com/android/server/rollback
./base/core/java/android/content/rollback
工作原理:
如何验证这个功能是否逻辑生效,我们可以使用这个方法:
1. adb install -r -d --enable-rollback --staged ***.apk
2. adb reboot
3. adb shell dumpsys rollback
4. adb root
5. adb shell am crash *** (10 times)
6. adb reboot
7. adb wait-for-devices 1 mins
8. adb shell dumpsys rollback
我们即可从RollBack的状态,检查rollback机制是否被激活以及使用。
dumpsys的code在代码中对应如下:
代码路径为:frameworks/base/services/core/java/com/android/server/rollback/Rollback.java
void dump(IndentingPrintWriter ipw) {
synchronized (mLock) {
ipw.println(info.getRollbackId() + ":");
ipw.increaseIndent();
ipw.println("-state: " + getStateAsString());
ipw.println("-timestamp: " + getTimestamp());
if (getStagedSessionId() != -1) {
ipw.println("-stagedSessionId: " + getStagedSessionId());
}
ipw.println("-packages:");
ipw.increaseIndent();
for (PackageRollbackInfo pkg : info.getPackages()) {
ipw.println(pkg.getPackageName()
+ " " + pkg.getVersionRolledBackFrom().getLongVersionCode()
+ " -> " + pkg.getVersionRolledBackTo().getLongVersionCode());
}
ipw.decreaseIndent();
if (isCommitted()) {
ipw.println("-causePackages:");
ipw.increaseIndent();
for (VersionedPackage cPkg : info.getCausePackages()) {
ipw.println(cPkg.getPackageName() + " " + cPkg.getLongVersionCode());
}
ipw.decreaseIndent();
ipw.println("-committedSessionId: " + info.getCommittedSessionId());
}
if (mExtensionVersions.size() > 0) {
ipw.println("-extensionVersions:");
ipw.increaseIndent();
ipw.println(mExtensionVersions.toString());
ipw.decreaseIndent();
}
ipw.decreaseIndent();
}
}
从dumpsys中,我们就可以看到rollback的当前执行状态。
String getStateAsString() {
synchronized (mLock) {
return rollbackStateToString(mState);
}
}
逻辑很简单,即为将RollBack中的mState变量值置为String并且打出。
变量定义如下:
/**
* The current state of the rollback.
* ENABLING, AVAILABLE, or COMMITTED.
*/
@GuardedBy("mLock")
private @RollbackState int mState;
会有四个状态值,来对应当前的mState.
@IntDef(prefix = { "ROLLBACK_STATE_" }, value = {
ROLLBACK_STATE_ENABLING,
ROLLBACK_STATE_AVAILABLE,
ROLLBACK_STATE_COMMITTED,
ROLLBACK_STATE_DELETED
})
那么在执行module_crash_rollback_test的时候,我们的逻辑是怎么生效的呢?
首先是在rollbackmanagerservice中:
/**
* Service that manages APK level rollbacks. Publishes
* Context.ROLLBACK_SERVICE.
*
* @hide
*/
public final class RollbackManagerService extends SystemService {
private RollbackManagerServiceImpl mService;
public RollbackManagerService(Context context) {
super(context);
}
@Override
public void onStart() {
mService = new RollbackManagerServiceImpl(getContext());
publishBinderService(Context.ROLLBACK_SERVICE, mService);
}
@Override
public void onUnlockUser(int user) {
mService.onUnlockUser(user);
}
@Override
public void onBootPhase(int phase) {
if (phase == SystemService.PHASE_BOOT_COMPLETED) {
mService.onBootCompleted();
}
}
可以看到的是,在PHASE_BOOT_COMPLETED时,将会调用onBootCompleted的函数。
如果看过之前的文章的同学,可能也明白了这个函数是在系统启动完成后,针对全局发出的通知。
@AnyThread
void onBootCompleted() {
DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_ROLLBACK_BOOT,
mExecutor, properties -> updateRollbackLifetimeDurationInMillis());
getHandler().post(() -> {
updateRollbackLifetimeDurationInMillis();
runExpiration();
// Check to see if any rollback-enabled staged sessions or staged
// rollback sessions been applied.
List<Rollback> enabling = new ArrayList<>();
List<Rollback> restoreInProgress = new ArrayList<>();
Set<String> apexPackageNames = new HashSet<>();
synchronized (mLock) {
Iterator<Rollback> iter = mRollbacks.iterator();
while (iter.hasNext()) {
Rollback rollback = iter.next();
if (!rollback.isStaged()) {
// We only care about staged rollbacks here
continue;
}
PackageInstaller.SessionInfo session = mContext.getPackageManager()
.getPackageInstaller().getSessionInfo(rollback.getStagedSessionId());
if (session == null || session.isStagedSessionFailed()) {
iter.remove();
rollback.delete(mAppDataRollbackHelper);
continue;
}
if (session.isStagedSessionApplied()) {
if (rollback.isEnabling()) {
enabling.add(rollback);
} else if (rollback.isRestoreUserDataInProgress()) {
restoreInProgress.add(rollback);
}
}
apexPackageNames.addAll(rollback.getApexPackageNames());
}
}
for (Rollback rollback : enabling) {
makeRollbackAvailable(rollback);
}
for (Rollback rollback : restoreInProgress) {
rollback.setRestoreUserDataInProgress(false);
}
for (String apexPackageName : apexPackageNames) {
// We will not recieve notifications when an apex is updated,
// so check now in case any rollbacks ought to be expired. The
// onPackagedReplace function is safe to call if the package
// hasn't actually been updated.
onPackageReplaced(apexPackageName);
}
synchronized (mLock) {
mOrphanedApkSessionIds.clear();
}
mPackageHealthObserver.onBootCompletedAsync();
});
}
这段主要说的是在系统启动过程中,我们将会对rollback的功能开启,各个session的状态,以及实际的packageName进行replaced,restore userdata的操作。这边分析一下onPackageReplaced函数:
/**
* Called when a package has been replaced with a different version.
* Removes all backups for the package not matching the currently
* installed package version.
*/
@WorkerThread
private void onPackageReplaced(String packageName) {
// TODO: Could this end up incorrectly deleting a rollback for a
// package that is about to be installed?
long installedVersion = getInstalledPackageVersion(packageName);
synchronized (mLock) {
Iterator<Rollback> iter = mRollbacks.iterator();
while (iter.hasNext()) {
Rollback rollback = iter.next();
// TODO: Should we remove rollbacks in the ENABLING state here?
if ((rollback.isEnabling() || rollback.isAvailable())
&& rollback.includesPackageWithDifferentVersion(packageName,
installedVersion)) {
iter.remove();
rollback.delete(mAppDataRollbackHelper);
}
}
}
}
当包被其他版本替换时调用时,我们会通过installedVersion来保存APK的版本号,
并且在下面将会删除与当前安装的包版本不匹配的包的所有备份。
在操作完,将会执行onBootCompletedAsync函数,而这边是进行的通知。
/** Verifies the rollback state after a reboot and schedules polling for sometime after reboot
* to check for native crashes and mitigate them if needed.
*/
public void onBootCompletedAsync() {
mHandler.post(()->onBootCompleted());
}
那么这个onBootCompleted在做什么工作呢?
private void onBootCompleted() {
RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
if (!rollbackManager.getAvailableRollbacks().isEmpty()) {
// TODO(gavincorkery): Call into Package Watchdog from outside the observer
PackageWatchdog.getInstance(mContext).scheduleCheckAndMitigateNativeCrashes();
}
SparseArray<String> rollbackIds = popLastStagedRollbackIds();
for (int i = 0; i < rollbackIds.size(); i++) {
WatchdogRollbackLogger.logRollbackStatusOnBoot(mContext,
rollbackIds.keyAt(i), rollbackIds.valueAt(i),
rollbackManager.getRecentlyCommittedRollbacks());
}
}
这边的重头戏来了,scheduleCheckAndMitigateNativeCrashes看上去和我们要验证的module_crash_rollback_test非常的相似。
/**
* Since this method can eventually trigger a rollback, it should be called
* only once boot has completed {@code onBootCompleted} and not earlier, because the install
* session must be entirely completed before we try to rollback.
*/
public void scheduleCheckAndMitigateNativeCrashes() {
Slog.i(TAG, "Scheduling " + mNumberOfNativeCrashPollsRemaining + " polls to check "
+ "and mitigate native crashes");
mShortTaskHandler.post(()->checkAndMitigateNativeCrashes());
}
只是打印了log,就来执行check的操作。
/**
* This method should be only called on mShortTaskHandler, since it modifies
* {@link #mNumberOfNativeCrashPollsRemaining}.
*/
private void checkAndMitigateNativeCrashes() {
mNumberOfNativeCrashPollsRemaining--;
// Check if native watchdog reported a crash
if ("1".equals(SystemProperties.get("sys.init.updatable_crashing"))) {
// We rollback everything available when crash is unattributable
onPackageFailure(Collections.EMPTY_LIST, FAILURE_REASON_NATIVE_CRASH);
// we stop polling after an attempt to execute rollback, regardless of whether the
// attempt succeeds or not
} else {
if (mNumberOfNativeCrashPollsRemaining > 0) {
mShortTaskHandler.postDelayed(() -> checkAndMitigateNativeCrashes(),
NATIVE_CRASH_POLLING_INTERVAL_MILLIS);
}
}
}
这边就非常奇怪了,为什么会有sys.init.updatable_crashing这个systemproperties呢?
这个properties是定义在什么地方?
代码路径: system/core/init/service.cpp
// If we crash > 4 times in 4 minutes or before boot_completed,
// reboot into bootloader or set crashing property
boot_clock::time_point now = boot_clock::now();
if (((flags_ & SVC_CRITICAL) || is_process_updatable) && !(flags_ & SVC_RESTART)) {
bool boot_completed = android::base::GetBoolProperty("sys.boot_completed", false);
if (now < time_crashed_ + 4min || !boot_completed) {
if (++crash_count_ > 4) {
if (flags_ & SVC_CRITICAL) {
// Aborts into bootloader
LOG(FATAL) << "critical process '" << name_ << "' exited 4 times "
<< (boot_completed ? "in 4 minutes" : "before boot completed");
} else {
LOG(ERROR) << "updatable process '" << name_ << "' exited 4 times "
<< (boot_completed ? "in 4 minutes" : "before boot completed");
// Notifies update_verifier and apexd
SetProperty("sys.init.updatable_crashing_process_name", name_);
SetProperty("sys.init.updatable_crashing", "1");
}
}
} else {
time_crashed_ = now;
crash_count_ = 1;
}
}
这里其实是对Crash的一个检查,如果在开机以后,规定时间内有四次以上的crash,然后就会触发这个properties的定义。
同时会记录当前进程的名字:sys.init.updatable_crashing_process_name。
但是在正常的过程中,这个应该不会出现。
但是在我们之前测试步骤中,当我们连续crash apk多次,那么重启后是否就会激活rollback呢?
应该是的,我们继续看看状态的改变过程。
/**
* Called when a process fails due to a crash, ANR or explicit health check.
*
* <p>For each package contained in the process, one registered observer with the least user
* impact will be notified for mitigation.
*
* <p>This method could be called frequently if there is a severe problem on the device.
*/
public void onPackageFailure(List<VersionedPackage> packages,
@FailureReasons int failureReason) {
if (packages == null) {
Slog.w(TAG, "Could not resolve a list of failing packages");
return;
}
mLongTaskHandler.post(() -> {
synchronized (mLock) {
if (mAllObservers.isEmpty()) {
return;
}
boolean requiresImmediateAction = (failureReason == FAILURE_REASON_NATIVE_CRASH
|| failureReason == FAILURE_REASON_EXPLICIT_HEALTH_CHECK);
if (requiresImmediateAction) {
handleFailureImmediately(packages, failureReason);
} else {
for (int pIndex = 0; pIndex < packages.size(); pIndex++) {
VersionedPackage versionedPackage = packages.get(pIndex);
// Observer that will receive failure for versionedPackage
PackageHealthObserver currentObserverToNotify = null;
int currentObserverImpact = Integer.MAX_VALUE;
// Find observer with least user impact
for (int oIndex = 0; oIndex < mAllObservers.size(); oIndex++) {
ObserverInternal observer = mAllObservers.valueAt(oIndex);
PackageHealthObserver registeredObserver = observer.registeredObserver;
if (registeredObserver != null
&& observer.onPackageFailureLocked(
versionedPackage.getPackageName())) {
int impact = registeredObserver.onHealthCheckFailed(
versionedPackage, failureReason);
if (impact != PackageHealthObserverImpact.USER_IMPACT_NONE
&& impact < currentObserverImpact) {
currentObserverToNotify = registeredObserver;
currentObserverImpact = impact;
}
}
}
// Execute action with least user impact
if (currentObserverToNotify != null) {
currentObserverToNotify.execute(versionedPackage, failureReason);
}
}
}
}
});
}
当package failureReason 的原因为Native_Crash和FAILURE_REASON_EXPLICIT_HEALTH_CHECK时,将会立刻对问题进行处理。
使用函数为:handleFailureImmediately。
/**
* For native crashes or explicit health check failures, call directly into each observer to
* mitigate the error without going through failure threshold logic.
*/
private void handleFailureImmediately(List<VersionedPackage> packages,
@FailureReasons int failureReason) {
VersionedPackage failingPackage = packages.size() > 0 ? packages.get(0) : null;
PackageHealthObserver currentObserverToNotify = null;
int currentObserverImpact = Integer.MAX_VALUE;
for (ObserverInternal observer: mAllObservers.values()) {
PackageHealthObserver registeredObserver = observer.registeredObserver;
if (registeredObserver != null) {
int impact = registeredObserver.onHealthCheckFailed(
failingPackage, failureReason);
if (impact != PackageHealthObserverImpact.USER_IMPACT_NONE
&& impact < currentObserverImpact) {
currentObserverToNotify = registeredObserver;
currentObserverImpact = impact;
}
}
}
if (currentObserverToNotify != null) {
currentObserverToNotify.execute(failingPackage, failureReason);
}
}
在使用后,会执行execute的函数:
@Override
public boolean execute(@Nullable VersionedPackage failedPackage,
@FailureReasons int rollbackReason) {
if (rollbackReason == PackageWatchdog.FAILURE_REASON_NATIVE_CRASH) {
rollbackAll();
return true;
}
RollbackInfo rollback = getAvailableRollback(failedPackage);
if (rollback == null) {
Slog.w(TAG, "Expected rollback but no valid rollback found for " + failedPackage);
return false;
}
rollbackPackage(rollback, failedPackage, rollbackReason);
// Assume rollback executed successfully
return true;
}
这里面我们主要关注的是NATIVE_CRASH的实现,所以将会去看rollbackAll的具体实现。
private void rollbackAll() {
Slog.i(TAG, "Rolling back all available rollbacks");
RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
List<RollbackInfo> rollbacks = rollbackManager.getAvailableRollbacks();
// Add all rollback ids to mPendingStagedRollbackIds, so that we do not reboot before all
// pending staged rollbacks are handled.
synchronized (mPendingStagedRollbackIds) {
for (RollbackInfo rollback : rollbacks) {
if (rollback.isStaged()) {
mPendingStagedRollbackIds.add(rollback.getRollbackId());
}
}
}
for (RollbackInfo rollback : rollbacks) {
VersionedPackage sample = rollback.getPackages().get(0).getVersionRolledBackFrom();
rollbackPackage(rollback, sample, PackageWatchdog.FAILURE_REASON_NATIVE_CRASH);
}
}
RollBackPackage具体的实现逻辑如下:
/**
* Rolls back the session that owns {@code failedPackage}
*
* @param rollback {@code rollbackInfo} of the {@code failedPackage}
* @param failedPackage the package that needs to be rolled back
*/
private void rollbackPackage(RollbackInfo rollback, VersionedPackage failedPackage,
@FailureReasons int rollbackReason) {
final RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
int reasonToLog = WatchdogRollbackLogger.mapFailureReasonToMetric(rollbackReason);
final String failedPackageToLog;
if (rollbackReason == PackageWatchdog.FAILURE_REASON_NATIVE_CRASH) {
failedPackageToLog = SystemProperties.get(
"sys.init.updatable_crashing_process_name", "");
} else {
failedPackageToLog = failedPackage.getPackageName();
}
VersionedPackage logPackageTemp = null;
if (isModule(failedPackage.getPackageName())) {
logPackageTemp = WatchdogRollbackLogger.getLogPackage(mContext, failedPackage);
}
final VersionedPackage logPackage = logPackageTemp;
WatchdogRollbackLogger.logEvent(logPackage,
FrameworkStatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE,
reasonToLog, failedPackageToLog);
final LocalIntentReceiver rollbackReceiver = new LocalIntentReceiver((Intent result) -> {
int status = result.getIntExtra(RollbackManager.EXTRA_STATUS,
RollbackManager.STATUS_FAILURE);
if (status == RollbackManager.STATUS_SUCCESS) {
if (rollback.isStaged()) {
int rollbackId = rollback.getRollbackId();
synchronized (mPendingStagedRollbackIds) {
mPendingStagedRollbackIds.add(rollbackId);
}
BroadcastReceiver listener =
listenForStagedSessionReady(rollbackManager, rollbackId,
logPackage);
handleStagedSessionChange(rollbackManager, rollbackId, listener,
logPackage);
} else {
WatchdogRollbackLogger.logEvent(logPackage,
FrameworkStatsLog
.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS,
reasonToLog, failedPackageToLog);
}
} else {
if (rollback.isStaged()) {
markStagedSessionHandled(rollback.getRollbackId());
}
WatchdogRollbackLogger.logEvent(logPackage,
FrameworkStatsLog
.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE,
reasonToLog, failedPackageToLog);
}
});
mHandler.post(() ->
rollbackManager.commitRollback(rollback.getRollbackId(),
Collections.singletonList(failedPackage),
rollbackReceiver.getIntentSender()));
}
这里面我们不去具体的分析某个session,而是回到前文中,提到的具体的状态,这里就会看到最后的这么一个逻辑。
mHandler.post(() ->
rollbackManager.commitRollback(rollback.getRollbackId(),
Collections.singletonList(failedPackage),
rollbackReceiver.getIntentSender()));
这里面是调用了rollbackManager的commitRollback方法:
@Override
public void commitRollback(int rollbackId, ParceledListSlice causePackages,
String callerPackageName, IntentSender statusReceiver) {
enforceManageRollbacks("commitRollback");
final int callingUid = Binder.getCallingUid();
AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
appOps.checkPackage(callingUid, callerPackageName);
getHandler().post(() ->
commitRollbackInternal(rollbackId, causePackages.getList(),
callerPackageName, statusReceiver));
}
其实也就是获取package,然后去通过commitRollbackInternal处理。
/**
* Performs the actual work to commit a rollback.
* The work is done on the current thread. This may be a long running
* operation.
*/
@WorkerThread
private void commitRollbackInternal(int rollbackId, List<VersionedPackage> causePackages,
String callerPackageName, IntentSender statusReceiver) {
Slog.i(TAG, "commitRollback id=" + rollbackId + " caller=" + callerPackageName);
Rollback rollback = getRollbackForId(rollbackId);
if (rollback == null) {
sendFailure(
mContext, statusReceiver, RollbackManager.STATUS_FAILURE_ROLLBACK_UNAVAILABLE,
"Rollback unavailable");
return;
}
rollback.commit(mContext, causePackages, callerPackageName, statusReceiver);
}
rollback的commit将会去具体的更改某个rollback的状态:
/**
* Commits the rollback.
*/
void commit(final Context context, List<VersionedPackage> causePackages,
String callerPackageName, IntentSender statusReceiver) {
synchronized (mLock) {
if (!isAvailable()) {
sendFailure(context, statusReceiver,
RollbackManager.STATUS_FAILURE_ROLLBACK_UNAVAILABLE,
"Rollback unavailable");
return;
}
if (containsApex() && wasCreatedAtLowerExtensionVersion()) {
PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
if (extensionVersionReductionWouldViolateConstraint(mExtensionVersions, pmi)) {
sendFailure(context, statusReceiver, RollbackManager.STATUS_FAILURE,
"Rollback may violate a minExtensionVersion constraint");
return;
}
}
// Get a context to use to install the downgraded version of the package.
Context pkgContext;
try {
pkgContext = context.createPackageContextAsUser(callerPackageName, 0,
UserHandle.of(mUserId));
} catch (PackageManager.NameNotFoundException e) {
sendFailure(context, statusReceiver, RollbackManager.STATUS_FAILURE,
"Invalid callerPackageName");
return;
}
PackageManager pm = pkgContext.getPackageManager();
try {
PackageInstaller packageInstaller = pm.getPackageInstaller();
PackageInstaller.SessionParams parentParams = new PackageInstaller.SessionParams(
PackageInstaller.SessionParams.MODE_FULL_INSTALL);
parentParams.setRequestDowngrade(true);
parentParams.setMultiPackage();
if (isStaged()) {
parentParams.setStaged();
}
parentParams.setInstallReason(PackageManager.INSTALL_REASON_ROLLBACK);
int parentSessionId = packageInstaller.createSession(parentParams);
PackageInstaller.Session parentSession = packageInstaller.openSession(
parentSessionId);
for (PackageRollbackInfo pkgRollbackInfo : info.getPackages()) {
if (pkgRollbackInfo.isApkInApex()) {
// No need to issue a downgrade install request for apk-in-apex. It will
// be rolled back when its parent apex is downgraded.
continue;
}
PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
PackageInstaller.SessionParams.MODE_FULL_INSTALL);
String installerPackageName = mInstallerPackageName;
if (TextUtils.isEmpty(mInstallerPackageName)) {
installerPackageName = pm.getInstallerPackageName(
pkgRollbackInfo.getPackageName());
}
if (installerPackageName != null) {
params.setInstallerPackageName(installerPackageName);
}
params.setRequestDowngrade(true);
params.setRequiredInstalledVersionCode(
pkgRollbackInfo.getVersionRolledBackFrom().getLongVersionCode());
if (isStaged()) {
params.setStaged();
}
if (pkgRollbackInfo.isApex()) {
params.setInstallAsApex();
}
int sessionId = packageInstaller.createSession(params);
PackageInstaller.Session session = packageInstaller.openSession(sessionId);
File[] packageCodePaths = RollbackStore.getPackageCodePaths(
this, pkgRollbackInfo.getPackageName());
if (packageCodePaths == null) {
sendFailure(context, statusReceiver, RollbackManager.STATUS_FAILURE,
"Backup copy of package: "
+ pkgRollbackInfo.getPackageName() + " is inaccessible");
return;
}
for (File packageCodePath : packageCodePaths) {
try (ParcelFileDescriptor fd = ParcelFileDescriptor.open(packageCodePath,
ParcelFileDescriptor.MODE_READ_ONLY)) {
final long token = Binder.clearCallingIdentity();
try {
session.write(packageCodePath.getName(), 0,
packageCodePath.length(),
fd);
} finally {
Binder.restoreCallingIdentity(token);
}
}
}
parentSession.addChildSessionId(sessionId);
}
final LocalIntentReceiver receiver = new LocalIntentReceiver(
(Intent result) -> {
int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
PackageInstaller.STATUS_FAILURE);
if (status != PackageInstaller.STATUS_SUCCESS) {
// Committing the rollback failed, but we still have all the info we
// need to try rolling back again, so restore the rollback state to
// how it was before we tried committing.
// TODO: Should we just kill this rollback if commit failed?
// Why would we expect commit not to fail again?
// TODO: Could this cause a rollback to be resurrected
// if it should otherwise have expired by now?
synchronized (mLock) {
mState = ROLLBACK_STATE_AVAILABLE;
mRestoreUserDataInProgress = false;
info.setCommittedSessionId(-1);
}
sendFailure(context, statusReceiver,
RollbackManager.STATUS_FAILURE_INSTALL,
"Rollback downgrade install failed: "
+ result.getStringExtra(
PackageInstaller.EXTRA_STATUS_MESSAGE));
return;
}
synchronized (mLock) {
if (!isStaged()) {
// All calls to restoreUserData should have
// completed by now for a non-staged install.
mRestoreUserDataInProgress = false;
}
info.getCausePackages().addAll(causePackages);
RollbackStore.deletePackageCodePaths(this);
RollbackStore.saveRollback(this);
}
// Send success.
try {
final Intent fillIn = new Intent();
fillIn.putExtra(
RollbackManager.EXTRA_STATUS,
RollbackManager.STATUS_SUCCESS);
statusReceiver.sendIntent(context, 0, fillIn, null, null);
} catch (IntentSender.SendIntentException e) {
// Nowhere to send the result back to, so don't bother.
}
Intent broadcast = new Intent(Intent.ACTION_ROLLBACK_COMMITTED);
for (UserInfo userInfo : UserManager.get(context).getUsers(true)) {
context.sendBroadcastAsUser(broadcast,
userInfo.getUserHandle(),
Manifest.permission.MANAGE_ROLLBACKS);
}
}
);
mState = ROLLBACK_STATE_COMMITTED;
info.setCommittedSessionId(parentSessionId);
mRestoreUserDataInProgress = true;
parentSession.commit(receiver.getIntentSender());
} catch (IOException e) {
Slog.e(TAG, "Rollback failed", e);
sendFailure(context, statusReceiver, RollbackManager.STATUS_FAILURE,
"IOException: " + e.toString());
}
}
}
在执行完后,会将mState置为ROLLBACK_STATE_COMMITTED;
mState = ROLLBACK_STATE_COMMITTED;
所以,当我们检查初始化状态为
ROLLBACK_STATE_ENABLING,
开机后的状态为
ROLLBACK_STATE_AVAILABLE,
执行完crash,rollback后的状态为
ROLLBACK_STATE_COMMITTED
这个功能的实现和验证就成功了,实现应用回滚的具体操作。