功能介绍:

在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);}@Overridepublic void onStart() {mService = new RollbackManagerServiceImpl(getContext());publishBinderService(Context.ROLLBACK_SERVICE, mService);}@Overridepublic void onUnlockUser(int user) {mService.onUnlockUser(user);}@Overridepublic void onBootPhase(int phase) {if (phase == SystemService.PHASE_BOOT_COMPLETED) {mService.onBootCompleted();}}

可以看到的是,在PHASE_BOOT_COMPLETED时,将会调用onBootCompleted的函数。
如果看过之前的文章的同学,可能也明白了这个函数是在系统启动完成后,针对全局发出的通知。

    @AnyThreadvoid 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 herecontinue;}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.*/@WorkerThreadprivate 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 observerPackageWatchdog.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 crashif ("1".equals(SystemProperties.get("sys.init.updatable_crashing"))) {// We rollback everything available when crash is unattributableonPackageFailure(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 propertyboot_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 bootloaderLOG(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 apexdSetProperty("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 versionedPackagePackageHealthObserver currentObserverToNotify = null;int currentObserverImpact = Integer.MAX_VALUE;// Find observer with least user impactfor (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 impactif (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的函数:

    @Overridepublic 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 successfullyreturn 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方法:

    @Overridepublic 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.*/@WorkerThreadprivate 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

这个功能的实现和验证就成功了,实现应用回滚的具体操作。

Android RollBack机制实现原理剖析相关推荐

  1. android digest 认证,探究 Android 签名机制和原理

    背景 最近在调研一个测试工具的使用,在使用中发现被测试工具处理过的apk文件经安装后打开就会崩溃,分析崩溃日志后原因是签名不一致导致的. 说到Android中的签名,可能大家都知道签名的目的就是为了保 ...

  2. 事件争夺战 Android事件处理机制与原理分析

    事件争夺战 Android事件处理机制与原理分析 文章目录 事件争夺战 Android事件处理机制与原理分析 View的继承关系 View的事件处理源码 总结: ViewGroup的事件分发源码 总结 ...

  3. android handler的机制和原理_一文搞懂handler:彻底明白Android消息机制的原理及源码

    提起Android消息机制,想必都不陌生.其中包含三个部分:Handler,MessageQueue以及Looper,三者共同协作,完成消息机制的运行.本篇文章将由浅入深解析Android消息机制的运 ...

  4. 浏览器页面渲染机制-前端原理剖析

    浏览器页面渲染机制 前言 浏览器的内核是指支持浏览器运行的最核心的程序,分为两个部分,一是渲染引擎,另一个是JS引擎.渲染引擎在不同的浏览器中也不是都相同的.目前市面上常见的浏览器内核可以分为这四种: ...

  5. android okio使用方法,Android 开源框架 Okio 原理剖析

    Retrofit,OkHttp,Okio 是 Square 团队开源的安卓平台网络层三板斧,它们逐层分工,非常优雅地解决我们对网络请求甚至更广泛的 I/O 操作的需求.其中最底层的 Okio 堪称小而 ...

  6. Android 省电模式原理剖析

    Android的平台上,耗电量的问题一直被人所诟病.从Lollipop开始,Google也一直非常重视对于省电模式的改造.本篇文章将会基于最新的Android Pie的代码,来系统分析现在Androi ...

  7. Android刷新机制-View绘制原理

    Android刷新机制-View绘制原理 Android刷新机制-SurfaceFlinger原理 Android刷新机制-Choreographer原理 一.概述 本文将从startActivity ...

  8. Android View学习笔记(三):Scroller的原理剖析及使用(上)

    一.前言 上一篇文章中,讨论了View的几种基本滑动方式,但是这些滑动方式是生硬的,在一瞬间完成的,这给用户非常不好的体验,所以为了提高用户体验,我们需要将View弹性滑动.什么是弹性滑动?就是一个V ...

  9. Android 为什么要有handler机制?handler机制的原理

    为什么要有handler机制? 在Android的UI开发中,我们经常会使用Handler来控制主UI程序的界面变化.有关Handler的作用,我们总结为:与其他线程协同工作,接收其他线程的消息并通过 ...

最新文章

  1. 如何用Python处理分类和回归问题?附方法和代码
  2. curl抓取页面时遇到重定向的解决方法(转)
  3. *** Procedure 存储过程 ***
  4. 索引中丢失IN或OUT
  5. Spark SQL 加载数据
  6. hnu暑期CCF培训之多项式加法
  7. python怎么使用-如何正确使用Python进行表白
  8. [周榜单]极乐小程序榜单(第十一期)
  9. 目标检测(四)--ICF
  10. 如何安装Junit4
  11. md5 java_JAVA使用MD5加密解密
  12. 无线充电设计(一)-基本介绍
  13. 计算机发送到桌面快捷方式,win10系统右键菜单“发送到桌面快捷方式”选项不见了的详细步骤...
  14. Java Web学习day25------Vue和综合案例
  15. PS常用的三种抠图方法,能应对99%的抠图场景
  16. uni-app活动倒计时功能
  17. 幼儿园科学室创设特点
  18. Android apk打包命名规则
  19. WD_考研计算机C语言基础002【统考中的C语言】
  20. The default interactive shell is now zsh.

热门文章

  1. linux挂载实验箱闹钟,Linux/Ubuntu命令行下打造一个音乐闹钟
  2. ZOJ3716 Ribbon Gymnastics(贪心)
  3. ubuntu无法挂载大容量U盘
  4. web移动端开发-将网站分享朋友圈、微信空间、朋友圈功能
  5. 浅议石化企业DCS、FCS系统的应用和发展
  6. 协程爬取整站豆瓣网络
  7. lvds传输距离标准_信号链基础知识(第 37 部分):LVDS——低压差分信号传输
  8. ESP32设备驱动-LX1972可见光传感器驱动
  9. 计算机病毒通过读写或复制移动,计算机病毒除通过读写或复制移动存储器上带病毒的文件传染外,另一条主要的传染途径是...
  10. strictmath_Java StrictMath cosh()方法与示例