Origin: code review of PR #45 (screen-lock app gate). Below-the-cut correctness items — real but lower-severity than the 15 headline fixes being applied on a fix branch.
Problem
The key-invalidation recovery restart is unreliable in two ways:
Same-process self-restart race (AppLockViewModel.restartProcess): context.startActivity(launchIntent) is followed immediately by Runtime.getRuntime().exit(0) in the same process. ActivityManager may schedule the relaunch into the process being killed, so the restart is intermittently dropped and the app just closes (this is exactly why ProcessPhoenix uses a separate :process trampoline). Recovery then only happens on the next manual launch (the CLEAR_PENDING flag persists), i.e. a one-time silent app close.
Lost syncNow() enqueue (clearCacheAndRestart): syncScheduler.syncNow() is a fire-and-forget WorkManager.enqueueUniqueWork whose WorkSpec is persisted asynchronously on WorkManager's serial task executor; exit(0) races that insert, so the comment "persisted by WorkManager; survives the restart" is not guaranteed. (Currently masked by the account-wipe bug being fixed separately — once accounts survive, the lost re-sync becomes user-visible as an empty mailbox until the next periodic sync.)
Suggested fix
Use a separate-process trampoline (ProcessPhoenix-style) for the restart, or at minimum await the enqueue Operation (with a timeout) before exiting, and issue the restart from a component that survives the killed process. Verify the wipe+resync completes end-to-end on device.
Origin: code review of PR #45 (screen-lock app gate). Below-the-cut correctness items — real but lower-severity than the 15 headline fixes being applied on a fix branch.
## Problem
The key-invalidation recovery restart is unreliable in two ways:
- **Same-process self-restart race** (`AppLockViewModel.restartProcess`): `context.startActivity(launchIntent)` is followed immediately by `Runtime.getRuntime().exit(0)` in the *same* process. ActivityManager may schedule the relaunch into the process being killed, so the restart is intermittently dropped and the app just closes (this is exactly why ProcessPhoenix uses a separate `:process` trampoline). Recovery then only happens on the next manual launch (the `CLEAR_PENDING` flag persists), i.e. a one-time silent app close.
- **Lost `syncNow()` enqueue** (`clearCacheAndRestart`): `syncScheduler.syncNow()` is a fire-and-forget `WorkManager.enqueueUniqueWork` whose WorkSpec is persisted asynchronously on WorkManager's serial task executor; `exit(0)` races that insert, so the comment "persisted by WorkManager; survives the restart" is not guaranteed. (Currently masked by the account-wipe bug being fixed separately — once accounts survive, the lost re-sync becomes user-visible as an empty mailbox until the next periodic sync.)
## Suggested fix
Use a separate-process trampoline (ProcessPhoenix-style) for the restart, or at minimum `await` the enqueue `Operation` (with a timeout) before exiting, and issue the restart from a component that survives the killed process. Verify the wipe+resync completes end-to-end on device.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Origin: code review of PR #45 (screen-lock app gate). Below-the-cut correctness items — real but lower-severity than the 15 headline fixes being applied on a fix branch.
Problem
The key-invalidation recovery restart is unreliable in two ways:
AppLockViewModel.restartProcess):context.startActivity(launchIntent)is followed immediately byRuntime.getRuntime().exit(0)in the same process. ActivityManager may schedule the relaunch into the process being killed, so the restart is intermittently dropped and the app just closes (this is exactly why ProcessPhoenix uses a separate:processtrampoline). Recovery then only happens on the next manual launch (theCLEAR_PENDINGflag persists), i.e. a one-time silent app close.syncNow()enqueue (clearCacheAndRestart):syncScheduler.syncNow()is a fire-and-forgetWorkManager.enqueueUniqueWorkwhose WorkSpec is persisted asynchronously on WorkManager's serial task executor;exit(0)races that insert, so the comment "persisted by WorkManager; survives the restart" is not guaranteed. (Currently masked by the account-wipe bug being fixed separately — once accounts survive, the lost re-sync becomes user-visible as an empty mailbox until the next periodic sync.)Suggested fix
Use a separate-process trampoline (ProcessPhoenix-style) for the restart, or at minimum
awaitthe enqueueOperation(with a timeout) before exiting, and issue the restart from a component that survives the killed process. Verify the wipe+resync completes end-to-end on device.