✍️ Describe the bug
The app crashes immediately on startup on a Pixel 9 Pro running GrapheneOS/Android 16. I gather this happens because EncryptedSharedPreferences fails to decrypt the stored data due to an invalidated or corrupted master key in the Android Keystore (likely triggered by a recent OS update).
Instead of handling the cryptographic failure gracefully, the app throws an unhandled RuntimeException during MainActivity initialization, locking the user into a permanent crash loop.
💣 Steps to reproduce
- Open the app after an Android system update or Keystore modification.
- The app crashes instantly during the launch/onCreate phase.
🔧 Expected behavior
The app should catch the cryptographic exception. Instead of crashing, it should restore from a previously auto-created backup file. This would allow to handle the failure gracefully (e.g., by wiping the corrupted encrypted preferences file and starting fresh Form the last known good file). This prevents the app from becoming completely unusable.
📷 Screenshots
Not applicable, as the app crashes instantly on launch.
📱 Tech info
- Device: Pixel 9 Pro ("caiman")
- OS: GrapheneOS Android 16 (Build: BP4A.260205.002 / 2026052401)
- App Version: 1.4.0 (Package version code: 14, targetSdk 36, Installed via F-Droid)
📄 Additional context
Bug report created by a user with next to no Java/Kotlin knowledge.
An AI helped draft this patch
fun getEncryptedSharedPreferences(context: Context): SharedPreferences {
return try {
createEncryptedSharedPreferencesInstance(context)
} catch (e: Exception) {
if (e is GeneralSecurityException || e is IOException) {
// Clear corrupted preferences file and master keys to recover
context.deleteSharedPreferences(PREF_FILE_NAME)
// Re-attempt creation
createEncryptedSharedPreferencesInstance(context)
} else {
throw e
}
}
}
Crash Log / Stacktrace
type: crash
osVersion: google/caiman/caiman:16/BP4A.260205.002/2026052401:user/release-keys
flags: dev options enabled
package: rocks.poopjournal.fucksgiven:14, targetSdk 36
process: rocks.poopjournal.fucksgiven
processUptime: 66 + 44 ms
installer: org.fdroid.fdroid
java.lang.RuntimeException: Unable to start activity ComponentInfo{rocks.poopjournal.fucksgiven/rocks.poopjournal.fucksgiven.MainActivity}
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:4517)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4720)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:224)
at android.app.servertransaction.TransactionExecutor.executeNonLifecycleItem(TransactionExecutor.java:133)
at android.app.servertransaction.TransactionExecutor.executeTransactionItems(TransactionExecutor.java:103)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:80)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2973)
at android.os.Handler.dispatchMessage(Handler.java:132)
at android.os.Looper.dispatchMessage(Looper.java:333)
at android.os.Looper.loopOnce(Looper.java:263)
at android.os.Looper.loop(Looper.java:367)
at android.app.ActivityThread.main(ActivityThread.java:9332)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:566)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:955)
Caused by: javax.crypto.AEADBadTagException
at android.security.keystore2.AndroidKeyStoreCipherSpiBase.engineDoFinal(AndroidKeyStoreCipherSpiBase.java:632)
at javax.crypto.Cipher.doFinal(Cipher.java:2132)
at com.google.crypto.tink.integration.android.AndroidKeystoreAesGcm.decryptInternal(AndroidKeystoreAesGcm.java:118)
at com.google.crypto.tink.integration.android.AndroidKeystoreAesGcm.decrypt(AndroidKeystoreAesGcm.java:101)
at com.google.crypto.tink.KeysetHandle.decrypt(KeysetHandle.java:919)
at com.google.crypto.tink.KeysetHandle.readWithAssociatedData(KeysetHandle.java:804)
at com.google.crypto.tink.KeysetHandle.read(KeysetHandle.java:785)
at com.google.crypto.tink.integration.android.AndroidKeysetManager$Builder.readMasterkeyDecryptAndParseKeyset(AndroidKeysetManager.java:381)
at com.google.crypto.tink.integration.android.AndroidKeysetManager$Builder.build(AndroidKeysetManager.java:297)
at androidx.security.crypto.EncryptedSharedPreferences.create(EncryptedSharedPreferences.java:169)
at rocks.poopjournal.fucksgiven.data.SecureStorage.getEncryptedSharedPreferences(SecureStorage.kt:30)
at rocks.poopjournal.fucksgiven.data.SecureStorage.<init>(SecureStorage.kt:21)
at rocks.poopjournal.fucksgiven.DaggerFucksGivenApplication_HiltComponents_SingletonC$SingletonCImpl$SwitchingProvider.get(DaggerFucksGivenApplication_HiltComponents_SingletonC.java:663)
at dagger.internal.DoubleCheck.getSynchronized(DoubleCheck.java:54)
at dagger.internal.DoubleCheck.get(DoubleCheck.java:45)
at rocks.poopjournal.fucksgiven.DaggerFucksGivenApplication_HiltComponents_SingletonC$ActivityCImpl.injectMainActivity2(DaggerFucksGivenApplication_HiltComponents_SingletonC.java:418)
at rocks.poopjournal.fucksgiven.DaggerFucksGivenApplication_HiltComponents_SingletonC$ActivityCImpl.injectMainActivity(DaggerFucksGivenApplication_HiltComponents_SingletonC.java:413)
at rocks.poopjournal.fucksgiven.Hilt_MainActivity.inject(Hilt_MainActivity.java:100)
at rocks.poopjournal.fucksgiven.Hilt_MainActivity$1.onContextAvailable(Hilt_MainActivity.java:47)
at androidx.activity.contextaware.ContextAwareHelper.dispatchOnContextAvailable(ContextAwareHelper.kt:78)
at androidx.activity.ComponentActivity.onCreate(ComponentActivity.kt:327)
at androidx.fragment.app.FragmentActivity.onCreate(FragmentActivity.java:217)
at rocks.poopjournal.fucksgiven.Hilt_MainActivity.onCreate(Hilt_MainActivity.java:64)
at rocks.poopjournal.fucksgiven.MainActivity.onCreate(MainActivity.kt:35)
at android.app.Activity.performCreate(Activity.java:9364)
at android.app.Activity.performCreate(Activity.java:9342)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1551)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:4501)
... 14 more
Caused by: android.security.KeyStoreException: Signature/MAC verification failed (internal Keystore code: -30 message: system/security/keystore2/src/operation.rs:853: KeystoreOperation::finish
Caused by:
0: system/security/keystore2/src/operation.rs:434: Finish failed for AppUid(10312)
1: Error::Km(r#VERIFICATION_FAILED)) (public error code: 10 internal Keystore code: -30)
at android.security.KeyStore2.getKeyStoreException(KeyStore2.java:429)
at android.security.KeyStoreOperation.handleExceptions(KeyStoreOperation.java:79)
at android.security.KeyStoreOperation.finish(KeyStoreOperation.java:132)
at android.security.keystore2.KeyStoreCryptoOperationChunkedStreamer$MainDataStream.finish(KeyStoreCryptoOperationChunkedStreamer.java:228)
at android.security.keystore2.KeyStoreCryptoOperationChunkedStreamer.doFinal(KeyStoreCryptoOperationChunkedStreamer.java:181)
at android.security.keystore2.AndroidKeyStoreAuthenticatedAESCipherSpi$BufferAllOutputUntilDoFinalStreamer.doFinal(AndroidKeyStoreAuthenticatedAESCipherSpi.java:396)
at android.security.keystore2.AndroidKeyStoreCipherSpiBase.engineDoFinal(AndroidKeyStoreCipherSpiBase.java:624)
... 41 more
✍️ Describe the bug
The app crashes immediately on startup on a Pixel 9 Pro running GrapheneOS/Android 16. I gather this happens because
EncryptedSharedPreferencesfails to decrypt the stored data due to an invalidated or corrupted master key in the Android Keystore (likely triggered by a recent OS update).Instead of handling the cryptographic failure gracefully, the app throws an unhandled
RuntimeExceptionduringMainActivityinitialization, locking the user into a permanent crash loop.💣 Steps to reproduce
🔧 Expected behavior
The app should catch the cryptographic exception. Instead of crashing, it should restore from a previously auto-created backup file. This would allow to handle the failure gracefully (e.g., by wiping the corrupted encrypted preferences file and starting fresh Form the last known good file). This prevents the app from becoming completely unusable.
📷 Screenshots
Not applicable, as the app crashes instantly on launch.
📱 Tech info
📄 Additional context
Bug report created by a user with next to no Java/Kotlin knowledge.
An AI helped draft this patch
Crash Log / Stacktrace