Closed MTermLyo closed 3 years ago
Are you by chance calling Firestore from multiple threads very early in the life of your application?
Are you by chance calling Firestore from multiple threads very early in the life of your application?
No, we are calling Firestore always from "Thread[main,5,main]". From the logs that we got, we tried to reproduce the error in real devices like: Xiaomi Mi A1, Huawei Mate 9 but without success.
Hrm. We recently found an initialization race condition in the iOS port (firebase/firebase-ios-sdk#3967), but I could not find an equivalent issue with on Android. If you were using multiple threads that could have pointed to a similar issue here.
Since you're not using multiple threads I don't have much to offer you: the exception indicates that one instance of Firestore has the underlying database open and then somehow you're managing to start another one. I'll consult internally to see if there are any other explanations for this, but without a way to reproduce and understand how this is happening we're not going to be able to make much progress on this.
Could you post your fully merged manifest? Note that if all the crashes are coming from the main thread that might might something else is opening Firestore first.
Could you post your fully merged manifest? Note that if all the crashes are coming from the main thread that might might something else is opening Firestore first.
Apologies for the delay. Although the crashes are coming from the main thread, we are opening the Firestore in the main thread. We are handling always the same instance of the Firestore.
I would like to mention something interesting. Almost all the crashes are coming from the same device type: Xiaomi Blackshark 1 (Android 9). When I searched in Google I found also that other app had a similar issue with the Firestore-SQLiteDatabaseLockedException from the mentioned device type.
I realized that Xiaomi Blackshark 1 is a niche device (gaming phone), so I'm not sure if this problem could be something between this device type and Firebase SDK. We do not own this type of device so I'm not able to reproduce the error in other devices/emulators.
Yes. Only BlackShark Has the issue. We do not know how to fix it.
I've checked and unfortunately we don't have any of these devices with which to test either.
How prevalent is this issue?
If possible could you collect logs from affected devices? You can enable logging like so: https://gist.github.com/katowulf/0475fb7a5907ed757f687aab6ed15878.
Unfortunately, this only reports log messages logcat, which does not get collected by Crashlytics. You could capture logcat messages using something like this: https://github.com/Ereza/LogcatReporter.
Absent more data on how this is happening or a way to reproduce this issue there isn't much we can do about it.
I also encounter this problem as well on user device Xiaomi Shark (but with firebase realtime database). The program will crash when offline persistence is enabled. Here is the error from crashlytics
java.lang.RuntimeException:
at com.google.firebase.database.android.AndroidPlatform$1$1.run (AndroidPlatform.java)
at android.os.Handler.handleCallback (Handler.java:873)
at android.os.Handler.dispatchMessage (Handler.java:99)
at android.os.Looper.loop (Looper.java:193)
at android.app.ActivityThread.main (ActivityThread.java:6758)
at java.lang.reflect.Method.invoke (Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:499)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:858)
Caused by: com.google.firebase.database.DatabaseException:
at com.google.firebase.database.android.SqlPersistenceStorageEngine.buildAncestorWhereClause (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.commaSeparatedList (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.deserializeNode (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.joinBytes (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.loadTrackedQueryKeys (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.loadUserWrites (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.mergeIntoServerCache (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.mergeIntoServerCache (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.openDatabase (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.partKey (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.pathPrefixStartToPrefixEnd (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.pruneCache (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.pruneTreeRecursive (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.removeNested (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.removeUserWrite (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.saveTrackedQuery (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.saveTrackedQueryKeys (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.saveUserMerge (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.saveUserOverwrite (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.saveWrite (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.serializeObject (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.serverCache (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.splitBytes (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.splitNodeRunLength (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.updateServerCache (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.updateTrackedQueryKeys (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.<init> (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.AndroidPlatform.access$000 (AndroidPlatform.java)
at com.google.firebase.database.android.AndroidPlatform.createPersistenceManager (AndroidPlatform.java)
at com.google.firebase.database.android.AndroidPlatform.getSSLCacheDirectory (AndroidPlatform.java)
at com.google.firebase.database.android.AndroidPlatform.getUserAgent (AndroidPlatform.java)
at com.google.firebase.database.android.AndroidPlatform.newLogger (AndroidPlatform.java)
at com.google.firebase.database.android.AndroidPlatform.newPersistentConnection (AndroidPlatform.java)
at com.google.firebase.database.core.Context.freeze (Context.java)
at com.google.firebase.database.core.Context.getPersistenceManager (Context.java)
at com.google.firebase.database.core.Repo.access$200 (Repo.java)
at com.google.firebase.database.core.Repo.deferredInitialization (Repo.java)
at com.google.firebase.database.core.Repo.abortTransactions (Repo.java)
at com.google.firebase.database.core.Repo.abortTransactionsAtNode (Repo.java)
at com.google.firebase.database.core.Repo.access$000 (Repo.java)
at com.google.firebase.database.core.Repo.access$1100 (Repo.java)
at com.google.firebase.database.core.Repo.access$1200 (Repo.java)
at com.google.firebase.database.core.Repo.access$1900 (Repo.java)
at com.google.firebase.database.core.Repo.access$3000 (Repo.java)
at com.google.firebase.database.core.Repo.access$3100 (Repo.java)
at com.google.firebase.database.core.Repo.access$500 (Repo.java)
at com.google.firebase.database.core.Repo.access$600 (Repo.java)
at com.google.firebase.database.core.Repo.access$700 (Repo.java)
at com.google.firebase.database.core.Repo.access$800 (Repo.java)
at com.google.firebase.database.core.Repo.ackWriteAndRerunTransactions (Repo.java)
at com.google.firebase.database.core.Repo.addEventCallback (Repo.java)
at com.google.firebase.database.core.Repo.aggregateTransactionQueues (Repo.java)
at com.google.firebase.database.core.Repo.buildTransactionQueue (Repo.java)
at com.google.firebase.database.core.Repo.callOnComplete (Repo.java)
at com.google.firebase.database.core.Repo.getAncestorTransactionNode (Repo.java)
at com.google.firebase.database.core.Repo.getLatestState (Repo.java)
at com.google.firebase.database.core.Repo.keepSynced (Repo.java)
at com.google.firebase.database.core.Repo.onAuthStatus (Repo.java)
at com.google.firebase.database.core.Repo.onConnect (Repo.java)
at com.google.firebase.database.core.Repo.onDataUpdate (Repo.java)
at com.google.firebase.database.core.Repo.onDisconnectCancel (Repo.java)
at com.google.firebase.database.core.Repo.onDisconnectSetValue (Repo.java)
at com.google.firebase.database.core.Repo.onDisconnectUpdate (Repo.java)
at com.google.firebase.database.core.Repo.onRangeMergeUpdate (Repo.java)
at com.google.firebase.database.core.Repo.onServerInfoUpdate (Repo.java)
at com.google.firebase.database.core.Repo.onServerInfoUpdate (Repo.java)
at com.google.firebase.database.core.Repo.postEvent (Repo.java)
at com.google.firebase.database.core.Repo.postEvents (Repo.java)
at com.google.firebase.database.core.Repo.rerunTransactionQueue (Repo.java)
at com.google.firebase.database.core.Repo.restoreWrites (Repo.java)
at com.google.firebase.database.core.Repo.startTransaction (Repo.java)
at com.google.firebase.database.core.Repo.updateChildren (Repo.java)
at com.google.firebase.database.core.Repo.warnIfWriteFailed (Repo.java)
at com.google.firebase.database.core.Repo$1.run (Repo.java)
at java.util.concurrent.Executors$RunnableAdapter.call (Executors.java:458)
at java.util.concurrent.FutureTask.run (FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run (ScheduledThreadPoolExecutor.java:301)
at java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:641)
at java.lang.Thread.run (Thread.java:764)
Caused by: android.database.sqlite.SQLiteDatabaseLockedException:
at android.database.sqlite.SQLiteConnection.nativeExecute (SQLiteConnection.java)
at android.database.sqlite.SQLiteConnection.execute (SQLiteConnection.java:572)
at android.database.sqlite.SQLiteSession.beginTransactionUnchecked (SQLiteSession.java:323)
at android.database.sqlite.SQLiteSession.beginTransaction (SQLiteSession.java:298)
at android.database.sqlite.SQLiteDatabase.beginTransaction (SQLiteDatabase.java:549)
at android.database.sqlite.SQLiteDatabase.beginTransaction (SQLiteDatabase.java:460)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.buildAncestorWhereClause (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.commaSeparatedList (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.deserializeNode (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.joinBytes (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.loadTrackedQueryKeys (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.loadUserWrites (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.mergeIntoServerCache (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.mergeIntoServerCache (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.openDatabase (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.partKey (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.pathPrefixStartToPrefixEnd (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.pruneCache (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.pruneTreeRecursive (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.removeNested (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.removeUserWrite (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.saveTrackedQuery (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.saveTrackedQueryKeys (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.saveUserMerge (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.saveUserOverwrite (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.saveWrite (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.serializeObject (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.serverCache (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.splitBytes (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.splitNodeRunLength (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.updateServerCache (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.updateTrackedQueryKeys (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.SqlPersistenceStorageEngine.<init> (SqlPersistenceStorageEngine.java)
at com.google.firebase.database.android.AndroidPlatform.access$000 (AndroidPlatform.java)
at com.google.firebase.database.android.AndroidPlatform.createPersistenceManager (AndroidPlatform.java)
at com.google.firebase.database.android.AndroidPlatform.getSSLCacheDirectory (AndroidPlatform.java)
at com.google.firebase.database.android.AndroidPlatform.getUserAgent (AndroidPlatform.java)
at com.google.firebase.database.android.AndroidPlatform.newLogger (AndroidPlatform.java)
at com.google.firebase.database.android.AndroidPlatform.newPersistentConnection (AndroidPlatform.java)
at com.google.firebase.database.core.Context.freeze (Context.java)
at com.google.firebase.database.core.Context.getPersistenceManager (Context.java)
at com.google.firebase.database.core.Repo.access$200 (Repo.java)
at com.google.firebase.database.core.Repo.deferredInitialization (Repo.java)
at com.google.firebase.database.core.Repo.abortTransactions (Repo.java)
at com.google.firebase.database.core.Repo.abortTransactionsAtNode (Repo.java)
at com.google.firebase.database.core.Repo.access$000 (Repo.java)
at com.google.firebase.database.core.Repo.access$1100 (Repo.java)
at com.google.firebase.database.core.Repo.access$1200 (Repo.java)
at com.google.firebase.database.core.Repo.access$1900 (Repo.java)
at com.google.firebase.database.core.Repo.access$3000 (Repo.java)
at com.google.firebase.database.core.Repo.access$3100 (Repo.java)
at com.google.firebase.database.core.Repo.access$500 (Repo.java)
at com.google.firebase.database.core.Repo.access$600 (Repo.java)
at com.google.firebase.database.core.Repo.access$700 (Repo.java)
at com.google.firebase.database.core.Repo.access$800 (Repo.java)
at com.google.firebase.database.core.Repo.ackWriteAndRerunTransactions (Repo.java)
at com.google.firebase.database.core.Repo.addEventCallback (Repo.java)
at com.google.firebase.database.core.Repo.aggregateTransactionQueues (Repo.java)
at com.google.firebase.database.core.Repo.buildTransactionQueue (Repo.java)
at com.google.firebase.database.core.Repo.callOnComplete (Repo.java)
at com.google.firebase.database.core.Repo.getAncestorTransactionNode (Repo.java)
at com.google.firebase.database.core.Repo.getLatestState (Repo.java)
at com.google.firebase.database.core.Repo.keepSynced (Repo.java)
at com.google.firebase.database.core.Repo.onAuthStatus (Repo.java)
at com.google.firebase.database.core.Repo.onConnect (Repo.java)
at com.google.firebase.database.core.Repo.onDataUpdate (Repo.java)
at com.google.firebase.database.core.Repo.onDisconnectCancel (Repo.java)
at com.google.firebase.database.core.Repo.onDisconnectSetValue (Repo.java)
at com.google.firebase.database.core.Repo.onDisconnectUpdate (Repo.java)
at com.google.firebase.database.core.Repo.onRangeMergeUpdate (Repo.java)
at com.google.firebase.database.core.Repo.onServerInfoUpdate (Repo.java)
at com.google.firebase.database.core.Repo.onServerInfoUpdate (Repo.java)
at com.google.firebase.database.core.Repo.postEvent (Repo.java)
at com.google.firebase.database.core.Repo.postEvents (Repo.java)
at com.google.firebase.database.core.Repo.rerunTransactionQueue (Repo.java)
at com.google.firebase.database.core.Repo.restoreWrites (Repo.java)
at com.google.firebase.database.core.Repo.startTransaction (Repo.java)
at com.google.firebase.database.core.Repo.updateChildren (Repo.java)
at com.google.firebase.database.core.Repo.warnIfWriteFailed (Repo.java)
at com.google.firebase.database.core.Repo$1.run (Repo.java)
at java.util.concurrent.Executors$RunnableAdapter.call (Executors.java:458)
at java.util.concurrent.FutureTask.run (FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run (ScheduledThreadPoolExecutor.java:301)
at java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:641)
at java.lang.Thread.run (Thread.java:764)
@sapjunior Very interesting! Thanks for letting us know. That strongly suggests this is not specific to our code (since Firestore and RTDB are pretty different codebases) and is a broader issue with Xiaomi Shark. Though I'm not able to find other reports out there for this exception on Xiaomi Shark. So I'm not sure what's going on...
Unfortunately I'm not sure how to move this forward. In general you would expect to see this kind of error if there were multiple instances of the app running at once or if you were initializing Firestore (or RTDB) in multiple threads at the same time. I assume that shouldn't be the case for your apps?
The only workaround I can suggest for now is to disable persistence.
If anybody is able to reproduce the issue manually or help narrow down the scope, please let us know!
Hey @MTermLyo. We need more information to resolve this issue but there hasn't been an update in 7 days. I'm marking the issue as stale and if there are no new updates in the next 3 days I will close it automatically.
If you have more information that will help us get to the bottom of this, just add a comment!
Since there haven't been any recent updates here, I am going to close this issue.
@MTermLyo if you're still experiencing this problem and want to continue the discussion just leave a comment here and we are happy to re-open this.
Caused by java.lang.RuntimeException: Failed to gain exclusive lock to the Cloud Firestore client's offline persistence. This generally means you are using Cloud Firestore 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 Cloud Firestore in your Application class. If you are intentionally using Cloud Firestore from multiple processes, you can only enable offline persistence (that is, call setPersistenceEnabled(true)) in one of them. at d.m.d.q.a0.u0.f(com.google.firebase:firebase-firestore@@21.2.1:20) at d.m.d.q.z.s.a(com.google.firebase:firebase-firestore@@21.2.1:18) at d.m.d.q.z.p.run(com.google.firebase:firebase-firestore@@21.2.1:5) at d.m.d.q.e0.a.call(com.google.firebase:firebase-firestore@@21.2.1:1) at d.m.d.q.e0.c$c.a(com.google.firebase:firebase-firestore@@21.2.1:10) at d.m.d.q.e0.f.run(:4) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:458) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) at d.m.d.q.e0.c$c$b.run(com.google.firebase:firebase-firestore@@21.2.1:3) at java.lang.Thread.run(Thread.java:764)
Caused by java.lang.RuntimeException: java.lang.RuntimeException: Failed to gain exclusive lock to the Cloud Firestore client's offline persistence. This generally means you are using Cloud Firestore 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 Cloud Firestore in your Application class. If you are intentionally using Cloud Firestore from multiple processes, you can only enable offline persistence (that is, call setPersistenceEnabled(true)) in one of them. at d.m.d.q.e0.c$c.a(com.google.firebase:firebase-firestore@@21.2.1:13) at d.m.d.q.e0.f.run(:4) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:458) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) at d.m.d.q.e0.c$c$b.run(com.google.firebase:firebase-firestore@@21.2.1:3) at java.lang.Thread.run(Thread.java:764)
裝置 品牌: blackshark 型號: Shark 1S 螢幕方向: 縱向 可用 RAM: 2.89 GB 可用磁碟空間: 33.49 GB 作業系統 版本: 9 螢幕方向: 縱向 是否取得 Root 權限: 否 當機 日期: 2019年11月20日 下午12:29:00 應用程式版本: 1.4.6 (46)
I also have encountered this crash on Shark 1S blackshark
ZTE Blade A0722 (8.1.0) also has crash
OPPO F11 (9) hit the same issue
Black Shark SKR-H0 (9) also has crash
ZTE Blade A0722( 8.1.0)
Black Shark SKR-H0 also has crash very long time after update to Android 9
I got the same crash in Black Shark(9.0) and LG Nexus 5X(6.0.1)
BlackShark Model: SKR-A0 (9) also has crash 100%
me too, on BlackShark SKR-A0.. Any Solution?
This issue has 217191 crashes affecting 20663 users - Last 90 days - Dec 17 – Mar 15
The last summary of this issue was https://github.com/firebase/firebase-android-sdk/issues/953#issuecomment-552054012, wherein we stated that we need your help reproducing this issue. Further stating that this is happening isn't really helping--we definitely understand that this is happening in the wild but don't have any ideas for what could be causing this.
What is your application doing in the background that could be contributing to this?
If you have this kind of device, what steps are you taking to reproduce this issue?
Recently we also discovered that devices encounter the same exception. We use the following version:
implementation 'com.google.firebase:firebase-firestore:21.3.1'
implementation 'com.google.firebase:firebase-database:19.2.1'
Basically we use the firebase in our background service. In the service's onStartCommand, it will try to init firebase and then registered onDocumentChange event and check any message received from the host. After the message finished poccessing, we will update the status in the map and write it back to the document.
We use ARCA to catch any uncaught exception and found recently the service suffer from the named exception randomly. Sometimes it happened once per few days. Change setPersistenceEnabled(false) also cannot help
Here I post the full source code for your reference:
`/ This service will try to get the message in firebase /
class FirebaseMessageService : Service() { private val tag = "FirebaseMessageService"
private var firebaseDocChangeListener: ListenerRegistration? = null
/**
* Temporarily save handled task to avoid doing same task more than once
*/
private val localHandledTaskList = mutableListOf<String>()
// private val tmsServiceCheckTimeSecond = 60 * 60L
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.d(tag, "onStartCommand")
firebaseDocChangeListener?.remove() //remove any existing listener first
//To test this service, try create a database with
// SET: messages
// doc: YOUR_DEVICE_ID (e.g. 7C29509)
// K,V : message, MESSAGE_YOU_WANT
val firebaseConfig = PaymentApplication.getTmsConfigV3(true, this).firebase
initFirebase(firebaseConfig)
//Use identity as doc name in firebase
val firebaseDocName = NetworkConfigHelper.getNetworkToken()
if (firebaseDocName == "") {
Log.d(tag, "identity null device inactive")
} else {
Log.d(tag, "Listen to $firebaseDocName")
val remotePath = firebaseConfig?.remotePath.orEmpty()
//make sure firebase initialized
if (FirebaseApp.getApps(this).any { it.name == remotePath }) {
//Disable Offline Capabilities
FirebaseDatabase.getInstance(FirebaseApp.getInstance(remotePath)).setPersistenceEnabled(true)
firebaseDocChangeListener =
FirebaseFirestore.getInstance(FirebaseApp.getInstance(remotePath))
.collection(remotePath)
.document(firebaseDocName)
.addSnapshotListener { snapShot: DocumentSnapshot?, firestoreException: FirebaseFirestoreException? ->
val isDocumentExists = snapShot?.exists()
if (isDocumentExists == true && firestoreException == null) {
try {
onDocumentChange(remotePath, snapShot, firebaseDocName)
} catch (e: Exception) {
PaymentLogManager.e(tag, "onDocumentChange exception: $e")
}
} else {
PaymentLogManager.e(tag, "onDocumentChange failed, is document exists: $isDocumentExists, exception: $firestoreException")
}
}
}
}
return START_STICKY
}
private fun initFirebase(firebaseConfig: FirebaseConfig?) {
val encryptedString = firebaseConfig?.clientAppKey
val identity = PaymentApplication.getLocalConfig().identity
val hashedIdentity = identity.toUpperCase(Locale.ENGLISH).md5()
val googleServiceJson: JSONObject?
try {
googleServiceJson = JSONObject(AesUtils.decrypt(encryptedString, hashedIdentity))
} catch (e: Exception) {
PaymentLogManager.e(tag, "fail to get google service json with key $hashedIdentity: $e")
return
}
val projectInfo = googleServiceJson.optJSONObject("project_info")
val client = ((googleServiceJson.optJSONArray("client")[0] as JSONObject))
//remove & init again
FirebaseApp.getApps(this).forEach {
if (it.name == firebaseConfig?.remotePath.orEmpty()) {
it.delete()
}
}
FirebaseApp.initializeApp(
this,
FirebaseOptions.Builder()
.setProjectId(projectInfo.optString("project_id"))
.setDatabaseUrl(projectInfo.optString("firebase_url"))
.setStorageBucket(projectInfo.optString("storage_bucket"))
.setApiKey((client.optJSONArray("api_key")[0] as JSONObject).optString("current_key"))
.setApplicationId(client.optJSONObject("client_info").optString("mobilesdk_app_id"))
.build(),
firebaseConfig?.remotePath.orEmpty()
)
Log.d(tag, "firebase initialized: ${firebaseConfig?.remotePath.orEmpty()}")
}
private fun onDocumentChange(remotePath: String, snapShot: DocumentSnapshot?, firebaseDocName: String) {
Log.d(tag, "onDocumentChange: number of actions: ${snapShot?.data?.size}")
snapShot?.data?.let { map ->
for ((key, obj) in map) {
Log.i(tag, "doing task $key")
if (obj is MutableMap<*, *>) {
try {
val status = obj["status"] as String
val action = obj["action"] as String
val arg = obj["argument"] as String?
if (status == TMSTask.ActionResult.PENDING.toString() && !localHandledTaskList.contains(key)) {
localHandledTaskList.add(key)
val task = TMSTask(action, arg)
val result = task.doAction(this.applicationContext)
Log.d(tag, "do action :${task.action} arg:${task.argument} result $result")
@Suppress("UNCHECKED_CAST")
(obj as MutableMap<String, Any>)["status"] = result.toString()
Log.d(tag, "Task finished with result $result")
FirebaseFirestore.getInstance(FirebaseApp.getInstance(remotePath))
.collection(remotePath)
.document(firebaseDocName)
.set(map.toMap())
.addOnSuccessListener {
Log.d(tag, "Update task $key for action status success")
}
.addOnFailureListener {
PaymentLogManager.w(tag, "Update task $key for action status failed: ${it.cause}, ${it.message}")
}
.addOnCompleteListener {
if (localHandledTaskList.contains(key)) {
localHandledTaskList.remove(key)
}
}
} else {
Log.d(tag, "task $key already done")
}
} catch (ex: Exception) {
PaymentLogManager.w(tag, "error during parsing task $key")
}
} else {
PaymentLogManager.w(tag, "key $key value unknown format $obj")
}
}
}
}
override fun onBind(intent: Intent?): IBinder? {
return null
}
}`
Having the same crashes on multiple devices
Even i am facing the same issue on Realme 1 and Realme 2 pro. I am accessing the firestore using a thread safe approach.
public static synchronized FirebaseFirestore getmFirestore() { if (mFirestore == null) { FirebaseFirestoreSettings.Builder firebaseFirestoreSettingsBuilder = new FirebaseFirestoreSettings.Builder(); firebaseFirestoreSettingsBuilder.setPersistenceEnabled(true); mFirestore = FirebaseFirestore.getInstance(); mFirestore.setFirestoreSettings(firebaseFirestoreSettingsBuilder.build()); } return mFirestore; }
Did anyone come to know the root cause for this?
Have the same issue. How to do a workaround?
Anyone find a solution for this problem? Here just Blackshark with this problem, we're using version 21.4.2
Hey @MTermLyo. We need more information to resolve this issue but there hasn't been an update in 5 weekdays. I'm marking the issue as stale and if there are no new updates in the next 5 days I will close it automatically.
If you have more information that will help us get to the bottom of this, just add a comment!
Since there haven't been any recent updates here, I am going to close this issue.
@MTermLyo if you're still experiencing this problem and want to continue the discussion just leave a comment here and we are happy to re-open this.
Happening with us too.
E/AndroidRuntime: FATAL EXCEPTION: main Process: me.dozee.dozee.debug, PID: 25221 java.lang.RuntimeException: Internal error in Cloud Firestore (21.3.1). at com.google.firebase.firestore.util.AsyncQueue.lambda$panic$3(com.google.firebase:firebase-firestore@@21.3.1:529) at com.google.firebase.firestore.util.AsyncQueue$$Lambda$3.run(Unknown Source:2) at android.os.Handler.handleCallback(Handler.java:900) at android.os.Handler.dispatchMessage(Handler.java:103) at android.os.Looper.loop(Looper.java:219) at android.app.ActivityThread.main(ActivityThread.java:8349) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1055) Caused by: java.lang.RuntimeException: java.lang.RuntimeException: Failed to gain exclusive lock to the Cloud Firestore client's offline persistence. This generally means you are using Cloud Firestore 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 Cloud Firestore in your Application class. If you are intentionally using Cloud Firestore from multiple processes, you can only enable offline persistence (that is, call setPersistenceEnabled(true)) in one of them. at com.google.firebase.firestore.util.AsyncQueue$SynchronizedShutdownAwareExecutor.lambda$executeAndReportResult$1(com.google.firebase:firebase-firestore@@21.3.1:320) at com.google.firebase.firestore.util.AsyncQueue$SynchronizedShutdownAwareExecutor$$Lambda$2.run(Unknown Source:4) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:462) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) at com.google.firebase.firestore.util.AsyncQueue$SynchronizedShutdownAwareExecutor$DelayedStartFactory.run(com.google.firebase:firebase-firestore@@21.3.1:224) at java.lang.Thread.run(Thread.java:929) Caused by: java.lang.RuntimeException: Failed to gain exclusive lock to the Cloud Firestore client's offline persistence. This generally means you are using Cloud Firestore 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 Cloud Firestore in your Application class. If you are intentionally using Cloud Firestore from multiple processes, you can only enable offline persistence (that is, call setPersistenceEnabled(true)) in one of them. at com.google.firebase.firestore.local.SQLitePersistence.start(com.google.firebase:firebase-firestore@@21.3.1:132) at com.google.firebase.firestore.core.FirestoreClient.initialize(com.google.firebase:firebase-firestore@@21.3.1:269) at com.google.firebase.firestore.core.FirestoreClient.lambda$new$0(com.google.firebase:firebase-firestore@@21.3.1:108) at com.google.firebase.firestore.core.FirestoreClient$$Lambda$1.run(Unknown Source:8) at com.google.firebase.firestore.util.AsyncQueue.lambda$enqueue$2(com.google.firebase:firebase-firestore@@21.3.1:431) at com.google.firebase.firestore.util.AsyncQueue$$Lambda$2.call(Unknown Source:2) at com.google.firebase.firestore.util.AsyncQueue$SynchronizedShutdownAwareExecutor.lambda$executeAndReportResult$1(com.google.firebase:firebase-firestore@@21.3.1:317) at com.google.firebase.firestore.util.AsyncQueue$SynchronizedShutdownAwareExecutor$$Lambda$2.run(Unknown Source:4) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:462) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) at com.google.firebase.firestore.util.AsyncQueue$SynchronizedShutdownAwareExecutor$DelayedStartFactory.run(com.google.firebase:firebase-firestore@@21.3.1:224) at java.lang.Thread.run(Thread.java:929) Caused by: android.database.sqlite.SQLiteDatabaseLockedException: database is locked (Sqlite code 5 SQLITE_BUSY), (OS error - 2:No such file or directory) at android.database.sqlite.SQLiteConnection.nativeExecute(Native Method) at android.database.sqlite.SQLiteConnection.execute(SQLiteConnection.java:692) E/AndroidRuntime: at android.database.sqlite.SQLiteSession.beginTransactionUnchecked(SQLiteSession.java:335) at android.database.sqlite.SQLiteSession.beginTransaction(SQLiteSession.java:310) at android.database.sqlite.SQLiteDatabase.beginTransaction(SQLiteDatabase.java:594) at android.database.sqlite.SQLiteDatabase.beginTransaction(SQLiteDatabase.java:504) at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:428) at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:332) at com.google.firebase.firestore.local.SQLitePersistence.start(com.google.firebase:firebase-firestore@@21.3.1:129) ... 14 more
[REQUIRED] Step 2: Describe your environment
[REQUIRED] Step 3: Describe the problem
The results that we got from Firebase Crashlytics show that some users faced the problem with Firestore. One of the errors described below says that: This generally means you are using Cloud Firestore from multiple processes in your app -> We are accessing it always in the same process.
isPersistenceEnabled = true // by default