ankidroid / Anki-Android

AnkiDroid: Anki flashcards on Android. Your secret trick to achieve superhuman information retention.
GNU General Public License v3.0
8.7k stars 2.24k forks source link

[InitialActivity::getStartupFailureType] StorageAccessException: Failed to create AnkiDroid directory `/storage/emulated/0/AnkiDroid` #17373

Open david-allison opened 1 week ago

david-allison commented 1 week ago

InitialActivity::getStartupFailureType

https://ankidroid.org/acra/app/1/bug/250465/report/e6b0ece8-4a72-451e-957e-97b9ff508b12

com.ichi2.anki.exception.StorageAccessException: Failed to create AnkiDroid directory /storage/emulated/0/AnkiDroid
    at com.ichi2.anki.exception.StorageAccessException.<init>(StorageAccessException.kt:22)
    at com.ichi2.anki.exception.StorageAccessException.<init>(StorageAccessException.kt:19)
    at com.ichi2.anki.CollectionHelper.initializeAnkiDroidDirectory(CollectionHelper.kt:88)
    at com.ichi2.anki.CollectionManager.collectionPathInValidFolder(CollectionManager.kt:264)
    at com.ichi2.anki.CollectionManager.ensureOpenInner(CollectionManager.kt:243)
    at com.ichi2.anki.CollectionManager.getColUnsafe$lambda$11$lambda$10(CollectionManager.kt:299)
    at com.ichi2.anki.CollectionManager$withQueue$3.invokeSuspend(CollectionManager.kt:103)
    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
    at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:104)
    at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.java:111)
    at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:99)
    at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:584)
    at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:811)
    at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:715)
    at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:702)
11-07 10:10:46.431 I/AnkiDroid(14499): Timber config: PRODUCTION
11-07 10:10:46.431 I/AnkiDroid(14499): initialize()
11-07 10:10:46.530 I/AnkiDroid(14499): Not participating in analytics sample (sample percentage vs random: 10 24)
11-07 10:10:46.530 I/AnkiDroid(14499): setOptIn(): from false to false
11-07 10:10:46.530 I/AnkiDroid(14499): Not participating in analytics sample (sample percentage vs random: 10 23)
11-07 10:10:46.537 I/AnkiDroid(14499): Creating notification channel with id/name: General Notifications/AnkiDroid
11-07 10:10:46.538 I/AnkiDroid(14499): Creating notification channel with id/name: Synchronization/Sincronização
11-07 10:10:46.538 I/AnkiDroid(14499): Creating notification channel with id/name: Global Reminders/Cartões pendentes
11-07 10:10:46.538 I/AnkiDroid(14499): Creating notification channel with id/name: Deck Reminders/Lembretes
11-07 10:10:46.550 E/AnkiDroid(14499): Instrumentation/ Could not initialize AnkiDroid directory
11-07 10:10:46.550 E/AnkiDroid(14499): c4.a: Failed to create AnkiDroid directory /storage/emulated/0/AnkiDroid
11-07 10:10:46.550 E/AnkiDroid(14499):  at P3.l3.p(SourceFile:36)
11-07 10:10:46.550 E/AnkiDroid(14499):  at com.ichi2.anki.AnkiDroidApp.onCreate(SourceFile:671)
11-07 10:10:46.550 E/AnkiDroid(14499):  at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1279)
11-07 10:10:46.550 E/AnkiDroid(14499):  at android.app.ActivityThread.handleBindApplication(ActivityThread.java:7033)
11-07 10:10:46.550 E/AnkiDroid(14499):  at android.app.ActivityThread.-$$Nest$mhandleBindApplication(Unknown Source:0)
11-07 10:10:46.550 E/AnkiDroid(14499):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2243)
11-07 10:10:46.550 E/AnkiDroid(14499):  at android.os.Handler.dispatchMessage(Handler.java:111)
11-07 10:10:46.550 E/AnkiDroid(14499):  at android.os.Looper.loopOnce(Looper.java:238)
11-07 10:10:46.550 E/AnkiDroid(14499):  at android.os.Looper.loop(Looper.java:357)
11-07 10:10:46.550 E/AnkiDroid(14499):  at android.app.ActivityThread.main(ActivityThread.java:8194)
11-07 10:10:46.550 E/AnkiDroid(14499):  at java.lang.reflect.Method.invoke(Native Method)
11-07 10:10:46.550 E/AnkiDroid(14499):  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
11-07 10:10:46.550 E/AnkiDroid(14499):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:957)
11-07 10:10:46.550 E/AnkiDroid(14499): 
11-07 10:10:46.550 E/AnkiDroid(14499): c4.a: Failed to create AnkiDroid directory /storage/emulated/0/AnkiDroid
11-07 10:10:46.550 E/AnkiDroid(14499):  at P3.l3.p(SourceFile:36)
11-07 10:10:46.550 E/AnkiDroid(14499):  at com.ichi2.anki.AnkiDroidApp.onCreate(SourceFile:671)
11-07 10:10:46.550 E/AnkiDroid(14499):  at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1279)
11-07 10:10:46.550 E/AnkiDroid(14499):  at android.app.ActivityThread.handleBindApplication(ActivityThread.java:7033)
11-07 10:10:46.550 E/AnkiDroid(14499):  at android.app.ActivityThread.-$$Nest$mhandleBindApplication(Unknown Source:0)
11-07 10:10:46.550 E/AnkiDroid(14499):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2243)
11-07 10:10:46.550 E/AnkiDroid(14499):  at android.os.Handler.dispatchMessage(Handler.java:111)
11-07 10:10:46.550 E/AnkiDroid(14499):  at android.os.Looper.loopOnce(Looper.java:238)
11-07 10:10:46.550 E/AnkiDroid(14499):  at android.os.Looper.loop(Looper.java:357)
11-07 10:10:46.550 E/AnkiDroid(14499):  at android.app.ActivityThread.main(ActivityThread.java:8194)
11-07 10:10:46.550 E/AnkiDroid(14499):  at java.lang.reflect.Method.invoke(Native Method)
11-07 10:10:46.550 E/AnkiDroid(14499):  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
11-07 10:10:46.550 E/AnkiDroid(14499):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:957)
11-07 10:10:46.555 I/AnkiDroid(14499): AnkiDroidApp: Starting Services
11-07 10:10:46.555 W/AnkiDroid(14499): AnkiDroidApp/ BootService - unexpected action received, ignoring: null
11-07 10:10:46.564 I/AnkiDroid(14499): IntentHandler::onCreate
11-07 10:10:46.564 I/AnkiDroid(14499): Setting theme to BLACK
11-07 10:10:46.575 I/AnkiDroid(14499): Launching DeckPicker
11-07 10:10:46.657 I/AnkiDroid(14499): AnkiDroid Version = 2.19.1 (6953d60532ee2762d29b06fd1d76e69203ad8455)
11-07 10:10:46.657 I/AnkiDroid(14499): 
11-07 10:10:46.657 I/AnkiDroid(14499): Backend Version = 0.1.43-anki24.06.3 (24.06.3 d678e39350a2d243242a69f4e22f5192b04398f2)
11-07 10:10:46.657 I/AnkiDroid(14499): 
11-07 10:10:46.657 I/AnkiDroid(14499): Android Version = 13 (SDK 33)
11-07 10:10:46.657 I/AnkiDroid(14499): 
11-07 10:10:46.657 I/AnkiDroid(14499): ProductFlavor = play
11-07 10:10:46.657 I/AnkiDroid(14499): 
11-07 10:10:46.657 I/AnkiDroid(14499): Manufacturer = motorola
11-07 10:10:46.657 I/AnkiDroid(14499): 
11-07 10:10:46.657 I/AnkiDroid(14499): Model = motorola edge 40 neo
11-07 10:10:46.657 I/AnkiDroid(14499): 
11-07 10:10:46.657 I/AnkiDroid(14499): Hardware = mt6879
11-07 10:10:46.657 I/AnkiDroid(14499): 
11-07 10:10:46.657 I/AnkiDroid(14499): Webview User Agent = Mozilla/5.0 (Linux; Android 13; motorola edge 40 neo Build/T3TMS33.23-100-3-1; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/130.0.6723.86 Mobile Safari/537.36
11-07 10:10:46.657 I/AnkiDroid(14499): 
11-07 10:10:46.657 I/AnkiDroid(14499): ACRA UUID = 73a767f6-183a-409c-8e7a-3788c8d11119
11-07 10:10:46.657 I/AnkiDroid(14499): 
11-07 10:10:46.657 I/AnkiDroid(14499): FSRS = 0.6.4 (Enabled: null)
11-07 10:10:46.657 I/AnkiDroid(14499): 
11-07 10:10:46.657 I/AnkiDroid(14499): Crash Reports Enabled = true
11-07 10:10:46.661 I/AnkiDroid(14499): Setting theme to BLACK
11-07 10:10:46.668 I/AnkiDroid(14499): DeckPicker::onCreate
11-07 10:10:46.726 W/AnkiDroid(14499): Activity/ c4.a: Failed to create AnkiDroid directory /storage/emulated/0/AnkiDroid
11-07 10:10:46.726 W/AnkiDroid(14499):  at P3.l3.p(SourceFile:36)
11-07 10:10:46.726 W/AnkiDroid(14499):  at P3.s3.b(SourceFile:14)
11-07 10:10:46.726 W/AnkiDroid(14499):  at P3.s3.d(SourceFile:24)
11-07 10:10:46.726 W/AnkiDroid(14499):  at B4.q.invoke(SourceFile:312)
11-07 10:10:46.726 W/AnkiDroid(14499):  at P3.r3.q(SourceFile:10)
11-07 10:10:46.726 W/AnkiDroid(14499):  at p5.a.i(SourceFile:9)
11-07 10:10:46.726 W/AnkiDroid(14499):  at Q6.D.run(SourceFile:115)
11-07 10:10:46.726 W/AnkiDroid(14499):  at B1.d.run(SourceFile:828)
11-07 10:10:46.726 W/AnkiDroid(14499):  at X6.j.run(SourceFile:3)
11-07 10:10:46.726 W/AnkiDroid(14499):  at X6.a.run(SourceFile:96)
11-07 10:10:46.726 W/AnkiDroid(14499): 
11-07 10:10:46.726 W/AnkiDroid(14499): c4.a: Failed to create AnkiDroid directory /storage/emulated/0/AnkiDroid
11-07 10:10:46.726 W/AnkiDroid(14499):  at P3.l3.p(SourceFile:36)
11-07 10:10:46.726 W/AnkiDroid(14499):  at P3.s3.b(SourceFile:14)
11-07 10:10:46.726 W/AnkiDroid(14499):  at P3.s3.d(SourceFile:24)
11-07 10:10:46.726 W/AnkiDroid(14499):  at B4.q.invoke(SourceFile:312)
11-07 10:10:46.726 W/AnkiDroid(14499):  at P3.r3.q(SourceFile:10)
11-07 10:10:46.726 W/AnkiDroid(14499):  at p5.a.i(SourceFile:9)
11-07 10:10:46.726 W/AnkiDroid(14499):  at Q6.D.run(SourceFile:115)
11-07 10:10:46.726 W/AnkiDroid(14499):  at B1.d.run(SourceFile:828)
11-07 10:10:46.726 W/AnkiDroid(14499):  at X6.j.run(SourceFile:3)
11-07 10:10:46.726 W/AnkiDroid(14499):  at X6.a.run(SourceFile:96)
david-allison commented 3 days ago

Do we need to do anything here? This is what the user sees on Android 13 when this error is triggered:

I'd propose that we silence this exception if using the default path. Nothing further that we can do

Image

EDIT: Code I used to trigger the exception

Index: AnkiDroid/src/main/java/com/ichi2/anki/preferences/DevOptionsFragment.kt
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/preferences/DevOptionsFragment.kt b/AnkiDroid/src/main/java/com/ichi2/anki/preferences/DevOptionsFragment.kt
--- a/AnkiDroid/src/main/java/com/ichi2/anki/preferences/DevOptionsFragment.kt  (revision 6953d60532ee2762d29b06fd1d76e69203ad8455)
+++ b/AnkiDroid/src/main/java/com/ichi2/anki/preferences/DevOptionsFragment.kt  (date 1731426260433)
@@ -17,11 +17,13 @@

 import android.content.Context
 import androidx.appcompat.app.AlertDialog
+import androidx.core.content.edit
 import androidx.preference.Preference
 import androidx.preference.SwitchPreferenceCompat
+import com.ichi2.anki.AnkiDroidApp
 import com.ichi2.anki.BuildConfig
+import com.ichi2.anki.CollectionHelper
 import com.ichi2.anki.CollectionManager
-import com.ichi2.anki.CrashReportService
 import com.ichi2.anki.R
 import com.ichi2.anki.analytics.UsageAnalytics
 import com.ichi2.anki.launchCatchingTask
@@ -63,12 +65,12 @@
         }
         // Make it possible to test crash reporting
         requirePreference<Preference>(R.string.pref_trigger_crash_key).setOnPreferenceClickListener {
-            // If we don't delete the limiter data, our test crash may not go through,
-            // but we are triggering it very much on purpose, we want to see the crash in ACRA
-            this.context?.let { c -> CrashReportService.deleteACRALimiterData(c) }
+            val prefs = AnkiDroidApp.sharedPrefs()
+            prefs.edit {
+                putString(CollectionHelper.PREF_COLLECTION_PATH, "/storage/emulated/0/AnkiDroid")
+            }

-            Timber.w("Crash triggered on purpose from advanced preferences in debug mode")
-            throw RuntimeException("This is a test crash")
+            false
         }
         // Make it possible to test analytics
         requirePreference<Preference>(R.string.pref_analytics_debug_key).setOnPreferenceClickListener {
mikehardy commented 3 days ago

...is that the right basis text for the diff? seems like it's removing what we want in the trigger crash dev preference and adding in something totally unrelated?

david-allison commented 3 days ago

The Exception occurs when:

This is typically either after reinstalling, or after legacy permissions to the folder have been revoked by the Android system

The patch above quickly gets AnkiDroid into the same state and is what I used for testing