fix: resolve SQLite unique constraint crash in Work Profiles#2504
Open
domedav wants to merge 1 commit into
Open
fix: resolve SQLite unique constraint crash in Work Profiles#2504domedav wants to merge 1 commit into
domedav wants to merge 1 commit into
Conversation
… 15) Fixed a critical ANR / Crash cycle occurring on Android 15 when the app is running within a Work Profile. The crash was caused by a SQLiteConstraintException in the ProxyApplicationMapping table. During profile refreshes or package updates, Android 15 sometimes reassigns UIDs in a way that creates collisions with existing database entries. The previous tombstoneApp implementation performed a blind update, which triggered a unique constraint violation and corrupted the database state.
hussainmohd-a
approved these changes
Feb 19, 2026
Contributor
There was a problem hiding this comment.
Pull request overview
Fixes a crash/ANR loop caused by SQLiteConstraintException when updating ProxyApplicationMapping UIDs (notably in Android 15 Work Profiles), by replacing a single SQL update with a transactional sequence intended to avoid unique/primary-key collisions.
Changes:
- Converts
tombstoneApp(oldUid, newUid)from a singleUPDATEquery into a@Transactionmethod that deletes conflicting rows before updating UIDs. - Adds DAO helpers to delete by UID and to update UID using
UPDATE OR IGNOREas an extra safety measure.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+105
to
+123
| @Transaction | ||
| fun tombstoneApp(oldUid: Int, newUid: Int) { | ||
| // Only apply the logic bellow, if the uid is from a work profile | ||
| if (newUid >= 1_000_000) { | ||
| // If a record with the 'newUid' already exists, delete it first | ||
| // This prevents an application crash: database constraint | ||
| deleteMappingByUid(newUid) | ||
| } | ||
|
|
||
| // Now that the slot is empty, move the 'oldUid' records to 'newUid' | ||
| updateUidByOldUid(oldUid, newUid) | ||
| } | ||
|
|
||
| @Query("delete from ProxyApplicationMapping where uid = :uid") | ||
| fun deleteMappingByUid(uid: Int) | ||
|
|
||
| // 'ignore' provides an extra layer of safety | ||
| @Query("update or ignore ProxyApplicationMapping set uid = :newUid where uid = :oldUid") | ||
| fun updateUidByOldUid(oldUid: Int, newUid: Int) |
Comment on lines
+107
to
+108
| // Only apply the logic bellow, if the uid is from a work profile | ||
| if (newUid >= 1_000_000) { |
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.
Fixed a critical ANR / Crash cycle occurring on Android 15 when the app is running within a Work Profile.
The crash was caused by a SQLiteConstraintException in the ProxyApplicationMapping table. During profile refreshes or package updates, Android 15 sometimes reassigns UIDs in a way that creates collisions with existing database entries. The previous tombstoneApp implementation performed a blind update, which triggered a unique constraint violation and corrupted the database state.