Repository navigation
Conversation
The killing app options were named "Option One" and "Option II" without any hint about what they actually do, and none of them keeps an app from being restarted while its data is being archived. * Show how each option is implemented in the selection dialog and under the current selection of both the backup and the restore settings page. * Add KillAppOption.OPTION_III (Advanced pause): force-stop the package and suspend it with `pm suspend`, which the platform honours for every start request, so the launcher, broadcasts, services and jobs cannot bring the app back while it is processed. Its icon is greyed out meanwhile. * Lift the suspension in a finally block right after the package has been processed, and lift every leftover suspension when the next task starts, so an interrupted task cannot keep an app suspended forever. * Never suspend system packages (fall back to a force-stop) and never suspend the app itself. * Document all four options in docs/kill-app-options.md and its Chinese translation.
…acked up Opening a paused app while it is being backed up used to fail the package, even though the archive that was produced was perfectly readable. - `tar` exits with 1 when a file changes or disappears while it is being read, which is exactly what a launch attempt does. Exit code 1 is now accepted and the archive itself stays the verdict (`testArchive`); exit code 2, a timeout and a missing result still fail. - Kill, pause, resume and resume-all are best-effort helpers now and can no longer abort the task: `killApp`, `releaseApp`, `releaseApps`, `SuspendUtil` and `BaseUtil.suspendPackage` / `unsuspendPackage` are wrapped in `runCatching` and only log the failure. - A launch attempt is re-checked before the data is read: `reinforcePause` re-applies the pause after the APK, split APK and device-protected data passes of a backup, and after the install pass of a restore, so a package that got started in between is stopped again before its data is archived. - `SuspendUtil` runs on `Dispatchers.IO + NonCancellable`, so a cancelled task still lifts every suspension it applied, and `resumePackage` always unsuspends instead of trusting a possibly stale record.
Describe the three layers that make "cannot be opened" and "the attempt does not matter" hold at the same time: the suspension itself, the accepted `tar` exit code 1, `reinforcePause`, and the best-effort wrapping of every pause helper. Includes the control-group measurements from an android-33 emulator.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
The
Killing app optionslist only offered "Option One" / "Option II" with no hint about what they actually do, and none of the options keeps an app from being restarted while its data is being archived.1. Explain every option
kill_app_option_disabled_desc,kill_app_option_i_desc,kill_app_option_ii_desc,kill_app_option_iii_desc).zh-rCN,zh-rTWandzh-rHKand are ready for Weblate.2. New option: Advanced pause (
OPTION_III)am force-stop --user <id> <pkg>followed bypm suspend --user <id> <pkg>, executed through the root shell.releaseApp()lifts the suspension in afinallyblock right after the package has been processed (backup and restore), so it only lasts for one app instead of the whole task.SuspendUtilwrites every suspended package tofiles/suspended_packages.txtbefore suspending, andreleaseApps()unsuspends all leftovers when the next task starts, so a killed task cannot keep an app suspended forever.PackageEntity.isSystemApp) are only force-stopped, never suspended, because suspendingsystemuior the launcher can take the device down. The app never suspends itself either.3. Opening the app during a backup no longer fails it
The goal is that both statements hold at the same time: the app cannot be opened while it is being backed up, and trying to open it does not change the outcome of the backup. Three things were missing for the second half.
tarexit code 1 is accepted (PackagesBackupUtil.isAcceptableTarResult()).tarexits with 1 when a file changed or disappeared while it was being read – exactly what a launch attempt causes – and the archive is still readable. Exit code 1 therefore no longer fails the package;testArchive()stays the verdict on the archive. Exit code 2, a timeout and a missing result still fail.reinforcePause()re-applies the suspension between the passes of a backup (after the APK and the device-protected data) and before the data pass of a restore, so a package that got started in between is stopped again before its data is read.killApp(),releaseApp(),releaseApps(),SuspendUtilandBaseUtil.suspendPackage()/unsuspendPackage()only log a failure; a failed kill or a failed suspend can no longer abort the task.SuspendUtilalso runs onDispatchers.IO + NonCancellableso a cancelled task still lifts every suspension it applied, andresumePackage()always unsuspends instead of trusting a possibly stale record.Modules
app(resources,ids.xml)core:model,core:util,core:servicefeature:main:settingsTest evidence
./gradlew :core:service:compileDebugKotlin :feature:main:settings:compileDebugKotlin-> BUILD SUCCESSFUL./gradlew :app:processArm64-v8aFossDebugResources-> BUILD SUCCESSFUL (arrays / ids / strings / translations)./gradlew :app:assembleX86_64FossDebug :app:assembleArm64-v8aFossRelease :app:assembleArm64-v8aPremiumRelease-> BUILD SUCCESSFUL-writable-system, with a plain AOSPsureplaced by a root daemon:am startattempts while the archive is writtensuspendedstilltrueafterwardstarexit code 0, decompresses and lists, 4 × 50 MB payload intactam startpid: 20094, app recorded the launcham startpid: (none), app recorded nothingNotes
docs/kill-app-options.md(+docs/kill-app-options.zh-CN.md) documents all four options against the code, including the three layers above and the measurements.DialogRadioItem.descandSelectable.descslots, so the layout is unchanged.