Краш на 3.2.0
dementia2029 opened this issue · 8 comments
В Application инициализирую свою Firebase Database
FirebaseApp.initializeApp(this);
if (!FirebaseApp.getApps(this).isEmpty()){
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
}
Затем метрику
YandexMetricaConfig.Builder configBuilder = YandexMetricaConfig.newConfigBuilder(YANDEX_KEY);
YandexMetrica.activate(getApplicationContext(), configBuilder.build());
// Отслеживание активности пользователей
YandexMetrica.enableActivityAutoTracking(this);
После этого примерно раз в 10 секунд крашится метркика и вылазит алерт, который не дает нормально работать с приложением.
Проверено на Android 7.1 и 9.0. Версия метрики 3.2.0. Application унаследован от MultiDexApplication
2018-07-30 10:04:13.147 5570-5658/com.owlylabs.dukan:Metrica E/SQLiteLog: (5) database is locked
2018-07-30 10:04:13.154 5570-5658/com.owlylabs.dukan:Metrica E/SQLiteDatabase: Failed to open database '/data/user/0/com.owlylabs.dukan/databases/dukan-d4f2f.firebaseio.com_default'.
android.database.sqlite.SQLiteDatabaseLockedException: database is locked (code 5): , while compiling: PRAGMA journal_mode
at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:889)
at android.database.sqlite.SQLiteConnection.executeForString(SQLiteConnection.java:634)
at android.database.sqlite.SQLiteConnection.setJournalMode(SQLiteConnection.java:320)
at android.database.sqlite.SQLiteConnection.setWalModeFromConfiguration(SQLiteConnection.java:294)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:215)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:193)
at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:463)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:185)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:177)
at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:808)
at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:793)
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:696)
at android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:652)
at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:289)
at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:223)
at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:163)
at com.google.android.gms.internal.firebase_database.zzu.zza(Unknown Source)
at com.google.android.gms.internal.firebase_database.zzu.<init>(Unknown Source)
at com.google.android.gms.internal.firebase_database.zzq.zza(Unknown Source)
at com.google.android.gms.internal.firebase_database.zzbz.zzq(Unknown Source)
at com.google.android.gms.internal.firebase_database.zzck.zzca(Unknown Source)
at com.google.android.gms.internal.firebase_database.zzck.zza(Unknown Source)
at com.google.android.gms.internal.firebase_database.zzcl.run(Unknown Source)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:428)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:272)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
at java.lang.Thread.run(Thread.java:761)
2018-07-30 10:04:13.161 5570-5658/com.owlylabs.dukan:Metrica E/RunLoop: com.google.firebase.database.DatabaseException: Failed to gain exclusive lock to Firebase Database's offline persistence. This generally means you are using Firebase Database from multiple processes in your app. Keep in mind that multi-process Android apps execute the code in your Application class in all processes, so you may need to avoid initializing FirebaseDatabase in your Application class. If you are intentionally using Firebase Database from multiple processes, you can only enable offline persistence (i.e. call setPersistenceEnabled(true)) in one of them.
at com.google.android.gms.internal.firebase_database.zzu.zza(Unknown Source)
at com.google.android.gms.internal.firebase_database.zzu.<init>(Unknown Source)
at com.google.android.gms.internal.firebase_database.zzq.zza(Unknown Source)
at com.google.android.gms.internal.firebase_database.zzbz.zzq(Unknown Source)
at com.google.android.gms.internal.firebase_database.zzck.zzca(Unknown Source)
at com.google.android.gms.internal.firebase_database.zzck.zza(Unknown Source)
at com.google.android.gms.internal.firebase_database.zzcl.run(Unknown Source)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:428)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:272)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
at java.lang.Thread.run(Thread.java:761)
Caused by: android.database.sqlite.SQLiteDatabaseLockedException: database is locked (code 5): , while compiling: PRAGMA journal_mode
at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:889)
at android.database.sqlite.SQLiteConnection.executeForString(SQLiteConnection.java:634)
at android.database.sqlite.SQLiteConnection.setJournalMode(SQLiteConnection.java:320)
at android.database.sqlite.SQLiteConnection.setWalModeFromConfiguration(SQLiteConnection.java:294)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:215)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:193)
at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:463)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:185)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:177)
at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:808)
at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:793)
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:696)
at android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:652)
at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:289)
at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:223)
at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:163)
at com.google.android.gms.internal.firebase_database.zzu.zza(Unknown Source)
at com.google.android.gms.internal.firebase_database.zzu.<init>(Unknown Source)
at com.google.android.gms.internal.firebase_database.zzq.zza(Unknown Source)
at com.google.android.gms.internal.firebase_database.zzbz.zzq(Unknown Source)
at com.google.android.gms.internal.firebase_database.zzck.zzca(Unknown Source)
at com.google.android.gms.internal.firebase_database.zzck.zza(Unknown Source)
at com.google.android.gms.internal.firebase_database.zzcl.run(Unknown Source)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:428)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:272)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
at java.lang.Thread.run(Thread.java:761)
2018-07-30 10:04:13.163 5570-5570/com.owlylabs.dukan:Metrica D/AndroidRuntime: Shutting down VM
--------- beginning of crash
2018-07-30 10:04:13.179 5570-5570/com.owlylabs.dukan:Metrica E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.owlylabs.dukan:Metrica, PID: 5570
java.lang.RuntimeException:
at com.google.android.gms.internal.firebase_database.zzs.run(Unknown Source)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6186)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:889)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:779)
Caused by: com.google.firebase.database.DatabaseException: Failed to gain exclusive lock to Firebase Database's offline persistence. This generally means you are using Firebase Database from multiple processes in your app. Keep in mind that multi-process Android apps execute the code in your Application class in all processes, so you may need to avoid initializing FirebaseDatabase in your Application class. If you are intentionally using Firebase Database from multiple processes, you can only enable offline persistence (i.e. call setPersistenceEnabled(true)) in one of them.
at com.google.android.gms.internal.firebase_database.zzu.zza(Unknown Source)
at com.google.android.gms.internal.firebase_database.zzu.<init>(Unknown Source)
at com.google.android.gms.internal.firebase_database.zzq.zza(Unknown Source)
at com.google.android.gms.internal.firebase_database.zzbz.zzq(Unknown Source)
at com.google.android.gms.internal.firebase_database.zzck.zzca(Unknown Source)
at com.google.android.gms.internal.firebase_database.zzck.zza(Unknown Source)
at com.google.android.gms.internal.firebase_database.zzcl.run(Unknown Source)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:428)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:272)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
at java.lang.Thread.run(Thread.java:761)
Caused by: android.database.sqlite.SQLiteDatabaseLockedException: database is locked (code 5): , while compiling: PRAGMA journal_mode
at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:889)
at android.database.sqlite.SQLiteConnection.executeForString(SQLiteConnection.java:634)
at android.database.sqlite.SQLiteConnection.setJournalMode(SQLiteConnection.java:320)
at android.database.sqlite.SQLiteConnection.setWalModeFromConfiguration(SQLiteConnection.java:294)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:215)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:193)
at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:463)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:185)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:177)
at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:808)
at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:793)
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:696)
at android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:652)
at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:289)
at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:223)
at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:163)
at com.google.android.gms.internal.firebase_database.zzu.zza(Unknown Source)
at com.google.android.gms.internal.firebase_database.zzu.<init>(Unknown Source)
at com.google.android.gms.internal.firebase_database.zzq.zza(Unknown Source)
at com.google.android.gms.internal.firebase_database.zzbz.zzq(Unknown Source)
at com.google.android.gms.internal.firebase_database.zzck.zzca(Unknown Source)
at com.google.android.gms.internal.firebase_database.zzck.zza(Unknown Source)
at com.google.android.gms.internal.firebase_database.zzcl.run(Unknown Source)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:428)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:272)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
at java.lang.Thread.run(Thread.java:761)
Если я отключу у себя оффлайн базу
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
тогда краша нет.
Ребята, как вы вообще пишите такой продукт? Неужели нельзя было зависимость от Firebase Database зделать внешней? Я поражаюсь, как много дыр в вашей метрике. Исправьте хотя бы это.
Аналогичная проблема:
https://stackoverflow.com/questions/50334705/android-firebase-and-appmetrica-conflict
Еще инфа:
на Android P смог запустить версию 2.80 с помошью строки в билдградле
useLibrary 'org.apache.http.legacy'
Если инициализировать фаербейз датабайз и метрику таким образом:
FirebaseApp.initializeApp(this);
if (!FirebaseApp.getApps(this).isEmpty()){
//FirebaseDatabase.getInstance().setPersistenceEnabled(true);
}
YandexMetrica.activate(getApplicationContext(), YANDEX_KEY);
// Отслеживание активности пользователей
YandexMetrica.enableActivityAutoTracking(this);
То в итоге оффлайн база данных работает, мое приложение может отправлять данные в нашу облачную бд после выхода с офлайна.
Если же использовать версии 3.0.0+ и инициализировать фаербейз датабайз и метрику таким образом:
FirebaseApp.initializeApp(this);
if (!FirebaseApp.getApps(this).isEmpty()){
//FirebaseDatabase.getInstance().setPersistenceEnabled(true);
}
YandexMetricaConfig.Builder configBuilder = YandexMetricaConfig.newConfigBuilder(YANDEX_KEY);
YandexMetrica.activate(getApplicationContext(), configBuilder.build());
// Отслеживание активности пользователей
YandexMetrica.enableActivityAutoTracking(this);
То офлайн не работет, мы теряем данные.
Если эже хоть в версии 2.80, хоть в 3.0.0+ фключить офлайн раскомментировав строку
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
то ловим бесконечные краши
Выходит, что в версии 2.80 метрика лучше ловила состояние фаербес датабейз и внутри себя включала офлайн режим. В версии 3.0.0 стало только хуже.
Привет.
Для того, чтобы понять, какое sdk падает, следует пройтись по стектрейсу, обращая внимания на имена пакетов вызовов.
В рассматриваемом выше стектрейсе присутствует:
at com.google.android.gms.internal.firebase_database.zzu.zza(Unknown Source)
at com.google.android.gms.internal.firebase_database.zzu.<init>(Unknown Source)
at com.google.android.gms.internal.firebase_database.zzq.zza(Unknown Source)
at com.google.android.gms.internal.firebase_database.zzbz.zzq(Unknown Source)
at com.google.android.gms.internal.firebase_database.zzck.zzca(Unknown Source)
at com.google.android.gms.internal.firebase_database.zzck.zza(Unknown Source)
at com.google.android.gms.internal.firebase_database.zzcl.run(Unknown Source)
Эти вызовы относятся к Firebase SDK.
Далее, в стектрейсе отсутствует упоминание вызовов AppMetrica:com.yandex.metrica
.
Вызвавший путаницу участок стектрейса:
2018-07-30 10:04:13.179 5570-5570/com.owlylabs.dukan:Metrica E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.owlylabs.dukan:Metrica, PID: 5570
всего лишь означает, что падение произошло в процессе AppMetrica.
Для понимания проблемы нужно обязательно изучить процессы в Android, ознакомиться с
документацией о том, что апметрика запускает отдельный процесс, а также
изучить документацию по классу Application
.
Далее становится очевидно, что Firebase SDK не может работать одновременно в нескольких процессах. В то же время в Application#onCreate()
стоит помещать исключительно тот код, который должен быть вызван во всех процессах.
Для устранения проблемы необходимо вынести код инициализации Firebase Database из Application#onCreate()
так, чтобы он вызывался исключительно из процесса приложения:
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
Поместить этот код лучше всего туда, где происходит первое обращение к Firebase Database, например, в соответствующие вызовы Activity или Service.
В этом случае падения больше не будет.
@alexklints здравствуйте.
Зачем вы закрыли репорт, проблема решена?
Я оставил Вам еще аналогичное обращение на stackoverflow. Вы можете подтвердить, что в приложении допустимо только раз вызвать setPersistenceEnabled(true), не важно, 1 процесс или несколько?
Если Вы считаете, что можно только один раз, то тогда как заставить приложение, которое использует датабейз, работать с вашей метрикой?
Если Вы считаете, что можно более одного раза, но в разных процессах, то что вы скажете на
If you are intentionally using Firebase Database from multiple processes, you can only enable offline persistence (i.e. call setPersistenceEnabled(true)) in one of them.
Если я отключаю метрику в проекте, то и краша нет.
@alexklints Считаю, что проблема в Вашем непонимании простой вещи, что только один процесс может иметь офлайн базу. Из этого выходит, что либо Ваша библиотека должна быть в 1 процессе с приложением, при чем включение офлайна должно быть ручное, а не внутри библиотеки чтобы не было конфликтов, либо добавить возможность отключения офлайна по умолчанию.
Скорее это вы не понимаете, что AppMetrica не использует Firebase Database в принципе. Мы не требуем этой зависимости, в чем вы можете убедиться, если откроете pom-файл репозитория. Включение офлайн режима для firebase происходит исключительно потому, что вы делаете это из Application#onCreate
. Вызов Application#onCreate
происходит по одному разу для каждого процесса. То есть это вы сами включаете такой режим использования Firebase SDK для процесса AppMetrica, хотя он совершенно не нужен.
Я же написал, что достаточно вынести
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
в другое место и проблема уйдет.
@alexklints Приношу извинение за безграмотность, да, my fault.