Iterable / iterable-android-sdk

Iterable's Android SDK. Receive and track pushes to Iterable from your Android app.
https://iterable.com/
MIT License
30 stars 28 forks source link

Iterable causes ANR #631

Open baole opened 1 year ago

baole commented 1 year ago

I have several ANR reports on Play store console which are caused by Iterable SDK

[samsung j2corelte (Galaxy J2 Core)]/[Android 8.1 (SDK 27)]

"main" tid=1 Runnable
  at com.google.crypto.tink.aead.AesCtrHmacAeadKeyManager.createKeyFormat (AesCtrHmacAeadKeyManager.java)
  at com.google.crypto.tink.aead.AesCtrHmacAeadKeyManager.createKeyFormat (AesCtrHmacAeadKeyManager.java)
  at com.google.crypto.tink.aead.AesCtrHmacAeadKeyManager.access$000 (AesCtrHmacAeadKeyManager.java)
  at com.google.crypto.tink.aead.AesCtrHmacAeadKeyManager$2.keyFormats (AesCtrHmacAeadKeyManager.java)
  at com.google.crypto.tink.Registry.registerKeyManager (Registry.java)
  at com.google.crypto.tink.aead.AesCtrHmacAeadKeyManager.register (AesCtrHmacAeadKeyManager.java)
  at com.google.crypto.tink.aead.AeadConfig.register (AeadConfig.java)
  at com.google.crypto.tink.aead.AeadConfig.init (AeadConfig.java)
  at com.google.crypto.tink.aead.AeadConfig.<clinit> (AeadConfig.java)
  at com.google.crypto.tink.aead.AeadConfig.register (AeadConfig.java)
  at androidx.security.crypto.EncryptedSharedPreferences.create (EncryptedSharedPreferences.java)
  at androidx.security.crypto.EncryptedSharedPreferences.create (EncryptedSharedPreferences.java)
  at com.iterable.iterableapi.IterableKeychain.<init> (IterableKeychain.kt)
  at com.iterable.iterableapi.IterableApi.getKeychain (IterableApi.java)
  at com.iterable.iterableapi.IterableApi.retrieveEmailAndUserId (IterableApi.java)
  at com.iterable.iterableapi.IterableApi.initialize (IterableApi.java)
  at net.tandem.core_new.analytics.IterableHelperImpl.init (IterableHelperImpl.kt)
  at net.tandem.TandemApp.onCreate (TandemApp.kt)
  at android.app.Instrumentation.callApplicationOnCreate (Instrumentation.java:1119)
  at android.app.ActivityThread.handleBindApplication (ActivityThread.java:5770)
  at android.app.ActivityThread.-wrap1 (ActivityThread.java)
  at android.app.ActivityThread$H.handleMessage (ActivityThread.java:1662)
  at android.os.Handler.dispatchMessage (Handler.java:106)
  at android.os.Looper.loop (Looper.java:164)
  at android.app.ActivityThread.main (ActivityThread.java:6543)
  at java.lang.reflect.Method.invoke (Native method)
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:440)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:810)
"main" tid=1 Runnable
  at com.iterable.iterableapi.IterableAuthManager.scheduleAuthTokenRefresh (IterableAuthManager.java)
  at com.iterable.iterableapi.IterableAuthManager.queueExpirationRefresh (IterableAuthManager.java)
  at com.iterable.iterableapi.IterableApi.retrieveEmailAndUserId (IterableApi.java)
  at com.iterable.iterableapi.IterableApi.initialize (IterableApi.java)
  at net.tandem.core_new.analytics.IterableHelperImpl.init (IterableHelperImpl.kt)
  at net.tandem.TandemApp.onCreate (TandemApp.kt)
  at android.app.Instrumentation.callApplicationOnCreate (Instrumentation.java:1119)
  at android.app.ActivityThread.handleBindApplication (ActivityThread.java:5770)
  at android.app.ActivityThread.-wrap1 (ActivityThread.java)
  at android.app.ActivityThread$H.handleMessage (ActivityThread.java:1662)
  at android.os.Handler.dispatchMessage (Handler.java:106)
  at android.os.Looper.loop (Looper.java:164)
  at android.app.ActivityThread.main (ActivityThread.java:6543)
  at java.lang.reflect.Method.invoke (Native method)
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:440)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:810)

[samsung a51 (Galaxy A51)][Android 13 (SDK 33)]

at javax.crypto.Cipher$SpiAndProviderUpdater.updateAndGetSpiAndProvider (Cipher.java:2787)
  at javax.crypto.Cipher.chooseProvider (Cipher.java:774)
  at javax.crypto.Cipher.init (Cipher.java:1144)
  at javax.crypto.Cipher.init (Cipher.java:1085)
  at com.google.crypto.tink.subtle.PrfAesCmac.compute (PrfAesCmac.java:69)
  at com.google.crypto.tink.subtle.AesSiv.s2v (AesSiv.java:103)
  at com.google.crypto.tink.subtle.AesSiv.encryptDeterministically (AesSiv.java:114)
  at com.google.crypto.tink.daead.DeterministicAeadWrapper$WrappedDeterministicAead.encryptDeterministically (DeterministicAeadWrapper.java:78)
  at androidx.security.crypto.EncryptedSharedPreferences.encryptKey (EncryptedSharedPreferences.java:611)
  at androidx.security.crypto.EncryptedSharedPreferences.getDecryptedObject (EncryptedSharedPreferences.java:546)
  at androidx.security.crypto.EncryptedSharedPreferences.getString (EncryptedSharedPreferences.java)
  at com.iterable.iterableapi.IterableKeychain.getAuthToken (IterableKeychain.kt:105)
  at com.iterable.iterableapi.IterableApi.retrieveEmailAndUserId (IterableApi.java:361)
  at com.iterable.iterableapi.IterableApi.initialize (IterableApi.java:512)
  at net.tandem.core_new.analytics.IterableHelperImpl.init (IterableHelperImpl.kt:118)
  at net.tandem.TandemApp.onCreate (TandemApp.kt:140)
  at android.app.Instrumentation.callApplicationOnCreate (Instrumentation.java:1266)
  at android.app.ActivityThread.handleBindApplication (ActivityThread.java:7614)
  at android.app.ActivityThread.-$$Nest$mhandleBindApplication (unavailable)
  at android.app.ActivityThread$H.handleMessage (ActivityThread.java:2400)
  at android.os.Handler.dispatchMessage (Handler.java:106)
  at android.os.Looper.loopOnce (Looper.java:226)
  at android.os.Looper.loop (Looper.java:313)
  at android.app.ActivityThread.main (ActivityThread.java:8757)
  at java.lang.reflect.Method.invoke (Native method)
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:571)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1067)

[Infinix Infinix-X689B (Infinix HOT 10S)][Android 11 (SDK 30)]

#00  pc 0x000000000004b50c  /apex/com.android.runtime/lib64/bionic/libc.so (syscall+28)
  #01  pc 0x00000000001b07a4  /apex/com.android.art/lib64/libart.so (art::ConditionVariable::WaitHoldingLocks(art::Thread*)+148)
  #02  pc 0x0000000000674730  /apex/com.android.art/lib64/libart.so (art::GoToRunnable(art::Thread*)+480)
  #03  pc 0x000000000067450c  /apex/com.android.art/lib64/libart.so (art::JniMethodEnd(unsigned int, art::Thread*)+28)
  at android.os.BinderProxy.transactNative (Native method)
This Binder call may be taking too long, causing the main thread to wait, and triggering the ANR

  at android.os.BinderProxy.transact (BinderProxy.java:559)
  at android.security.keystore.IKeystoreService$Stub$Proxy.begin (IKeystoreService.java:1465)
  at android.security.KeyStore.begin (KeyStore.java:864)
  at android.security.keystore.AndroidKeyStoreCipherSpiBase.ensureKeystoreOperationInitialized (AndroidKeyStoreCipherSpiBase.java:248)
  at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineInit (AndroidKeyStoreCipherSpiBase.java:109)
  at javax.crypto.Cipher.tryTransformWithProvider (Cipher.java:2984)
  at javax.crypto.Cipher.tryCombinations (Cipher.java:2891)
  at javax.crypto.Cipher$SpiAndProviderUpdater.updateAndGetSpiAndProvider (Cipher.java:2796)
  at javax.crypto.Cipher.chooseProvider (Cipher.java:773)
  at javax.crypto.Cipher.init (Cipher.java:1143)
  at javax.crypto.Cipher.init (Cipher.java:1084)
  at com.google.crypto.tink.integration.android.AndroidKeystoreAesGcm.encryptInternal (AndroidKeystoreAesGcm.java)
  at com.google.crypto.tink.integration.android.AndroidKeystoreAesGcm.encrypt (AndroidKeystoreAesGcm.java)
  at com.google.crypto.tink.integration.android.AndroidKeystoreKmsClient.validateAead (AndroidKeystoreKmsClient.java)
  at com.google.crypto.tink.integration.android.AndroidKeystoreKmsClient.getAead (AndroidKeystoreKmsClient.java)
  at com.google.crypto.tink.integration.android.AndroidKeysetManager$Builder.readMasterkeyDecryptAndParseKeyset (AndroidKeysetManager.java)
  at com.google.crypto.tink.integration.android.AndroidKeysetManager$Builder.build (AndroidKeysetManager.java)
  at androidx.security.crypto.EncryptedSharedPreferences.create (EncryptedSharedPreferences.java)
  at androidx.security.crypto.EncryptedSharedPreferences.create (EncryptedSharedPreferences.java)
  at com.iterable.iterableapi.IterableKeychain.<init> (IterableKeychain.kt)
  at com.iterable.iterableapi.IterableApi.getKeychain (IterableApi.java)
  at com.iterable.iterableapi.IterableApi.retrieveEmailAndUserId (IterableApi.java)
  at com.iterable.iterableapi.IterableApi.initialize (IterableApi.java)
  at net.tandem.core_new.analytics.IterableHelperImpl.init (IterableHelperImpl.kt)
Your app's code results in the Binder call above. Code that triggers Binder calls should be moved out of the main thread.

  at net.tandem.TandemApp.onCreate (TandemApp.kt)
  at android.app.Instrumentation.callApplicationOnCreate (Instrumentation.java:1198)
  at android.app.ActivityThread.handleBindApplication (ActivityThread.java:7051)
  at android.app.ActivityThread.access$1600 (ActivityThread.java:257)
  at android.app.ActivityThread$H.handleMessage (ActivityThread.java:2038)
  at android.os.Handler.dispatchMessage (Handler.java:106)
  at android.os.Looper.loop (Looper.java:268)
  at android.app.ActivityThread.main (ActivityThread.java:8017)
  at java.lang.reflect.Method.invoke (Native method)
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:627)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:997)

Iterable SDK v3.4.15. It happens on almost any device/any Android version. It's on production app and I couldn't reproduce reliably in my dev environment.

Any tips on how to fix? Can I move IterableApi.initialize to a background thread?

baole commented 10 months ago

@Ayyanchira https://github.com/Iterable/iterable-android-sdk/pull/635 doesn't fix the issue. The fact is that Iterable SDK uses I/O (read files) when calling IterableApi.initialize(). The below stacktrack is reported by the system when enables StrictMode.

Is it safe to call IterableApi.initialize() in a background thread/coroutine?

  StrictMode policy violation; ~duration=93 ms: android.os.strictmode.DiskReadViolation
    at android.os.StrictMode$AndroidBlockGuardPolicy.onReadFromDisk(StrictMode.java:1666)
    at libcore.io.BlockGuardOs.access(BlockGuardOs.java:74)
    at libcore.io.ForwardingOs.access(ForwardingOs.java:128)
    at android.app.ActivityThread$AndroidOs.access(ActivityThread.java:8071)
    at java.io.UnixFileSystem.checkAccess(UnixFileSystem.java:313)
    at java.io.File.exists(File.java:813)
    at android.app.ContextImpl.ensurePrivateDirExists(ContextImpl.java:790)
    at android.app.ContextImpl.ensurePrivateDirExists(ContextImpl.java:781)
    at android.app.ContextImpl.getPreferencesDir(ContextImpl.java:737)
    at android.app.ContextImpl.getSharedPreferencesPath(ContextImpl.java:962)
    at android.app.ContextImpl.getSharedPreferences(ContextImpl.java:583)
    at android.content.ContextWrapper.getSharedPreferences(ContextWrapper.java:221)
    at com.google.crypto.tink.integration.android.AndroidKeysetManager$Builder.readKeysetFromPrefs(AndroidKeysetManager.java:250)
    at com.google.crypto.tink.integration.android.AndroidKeysetManager$Builder.build(AndroidKeysetManager.java:287)
    at androidx.security.crypto.EncryptedSharedPreferences.create(EncryptedSharedPreferences.java:169)
    at androidx.security.crypto.EncryptedSharedPreferences.create(EncryptedSharedPreferences.java:130)
    at com.iterable.iterableapi.IterableKeychain.<init>(IterableKeychain.kt:38)
    at com.iterable.iterableapi.IterableApi.getKeychain(IterableApi.java:142)
    at com.iterable.iterableapi.IterableApi.retrieveEmailAndUserId(IterableApi.java:364)
    at com.iterable.iterableapi.IterableApi.initialize(IterableApi.java:516)
    at net.tandem.core_new.analytics.IterableHelperImpl.init(IterableHelperImpl.kt:120)
    at net.tandem.TandemApp.onCreate(TandemApp.kt:161)
    at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1316)
    at android.app.ActivityThread.handleBindApplication(ActivityThread.java:7015)
    at android.app.ActivityThread.-$$Nest$mhandleBindApplication(Unknown Source:0)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2241)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loopOnce(Looper.java:205)
    at android.os.Looper.loop(Looper.java:294)
    at android.app.ActivityThread.main(ActivityThread.java:8194)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)
sgong-pdftron commented 6 months ago

@baole were you able to resolve this issue? If so, is it possible if you could share how you did it? Thank you!

henieek commented 5 months ago

Hey, we're facing the same issue. I could workaround it easily by moving the IterableApi.initialize() call to a background thread, but could anyone please confirm that it's safe to do so? Thanks!