Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[inappmessaging] The leakage of previous cached WebView in InAppMessaging.kt #18

Closed
AlanChiou opened this issue May 20, 2022 · 5 comments

Comments

@AlanChiou
Copy link

Expected Behavior

Before creating a new WebView,
you should release and destroy the previous cached WebView.

cachedWebView = IAMWebView(app.application) { uri: Uri ->

Current Behavior

When there is an existing WebView,
you create a new WebView and replace the variable.
It causes the previous one leaks.

Possible Solution

Destroy and release the previous one first.

        cachedWebView?.destroy()
        cachedWebView = null

Steps to Reproduce

  1. Launch an app.
  2. Calls KarteApp.renewVisitorId()
  3. InAppMessaging gets WebView with a new overlay URL.
  4. Previous WebView leaks.

SDK Version

  • core 2.13.0
  • inappmessaging 2.11.0
  • notifications N/A
  • variables 2.2.0
  • visualtracking N/A
  • Karte Gradle Plugin N/A

Android Version

Build Environment

  • Android Studio Version Chipmunk | 2021.2.1
  • Gradle Version 7.0.2
  • Android Gradle Plugin Version 7.0.3

Context Details

We received some crash reports of WebView. This is one of potential root causes.

Fatal Exception: java.lang.RuntimeException: Using WebView from more than one process at once with the same data directory is not supported. https://crbug.com/558377 : Current process jp.co.rakuten.smAndroid (pid 31072), lock owner jp.co.rakuten.smAndroid (pid 26033)
       at org.chromium.android_webview.AwDataDirLock.b(AwDataDirLock.java:106)
       at org.chromium.android_webview.AwBrowserProcess.j(AwBrowserProcess.java:142)
       at com.android.webview.chromium.b1.d(b1.java:228)
       at com.android.webview.chromium.b1.b(b1.java:347)
       at com.android.webview.chromium.WebViewChromiumFactoryProvider.k(WebViewChromiumFactoryProvider.java:321)
       at com.android.webview.chromium.WebViewChromium.init(WebViewChromium.java:300)
       at android.webkit.WebView.<init>(WebView.java:442)
       at android.webkit.WebView.<init>(WebView.java:359)
       at android.webkit.WebView.<init>(WebView.java:341)
       at android.webkit.WebView.<init>(WebView.java:328)
       at android.webkit.WebView.<init>(WebView.java:318)
       at jp.co.rakuten.smAndroid.sdk.login.AuthProviderIchibaWeb$requestToken$1.invokeSuspend(AuthProviderIchibaWeb.kt:186)
       at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
       at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
       at android.os.Handler.handleCallback(Handler.java:938)
       at android.os.Handler.dispatchMessage(Handler.java:99)
       at android.os.Looper.loop(Looper.java:223)
       at android.app.ActivityThread.main(ActivityThread.java:8240)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:979)

Logs

05-20 14:33:53.827  2862  2862 D Karte.InAppMessaging: reset pv_id. 7b1b459a-9476-4c8d-8bf0-064b3f912cca 8ab625ea-0c80-4f26-8b14-019708f679e3
05-20 14:33:53.827  2862  2862 D Karte.InAppMessaging: WebView recreate
05-20 14:33:54.127  2862  2862 D Karte.InAppMessaging: Dismiss by reset pv_id
05-20 14:33:54.159  2862  2862 D Karte.InAppMessaging: onActivityPaused prevent_relay flag: false
05-20 14:33:55.518  2862  2862 D Karte.InAppMessaging: reset pv_id. f66b83e6-a836-4ef3-9bea-91c5977260d3 8ab625ea-0c80-4f26-8b14-019708f679e3
05-20 14:33:55.540  2862  2862 D Karte.InAppMessaging: reset pv_id. 370e122b-e69d-42f2-b036-20c20f1a1b77 8ab625ea-0c80-4f26-8b14-019708f679e3
05-20 14:33:56.419  2862  2862 D Karte.InAppMessaging: Dismiss by reset pv_id
05-20 14:33:56.419  2862  2862 D Karte.InAppMessaging: Dismiss by reset pv_id
05-20 14:33:57.468  2862  2862 I chromium: [INFO:CONSOLE(1)] "setVisitor and reset storage. 97166b0b-2a54-45b6-a359-facb04de8814", source: https://static.karte.io/native_app_libs/tracker.js (1)
05-20 14:33:57.486  2862  2862 I chromium: [INFO:CONSOLE(1)] "sendDataToNative: state_changed{"state":"initialized"}", source: https://static.karte.io/native_app_libs/tracker.js (1)
05-20 14:33:57.524  2862  2862 D Karte.IAMWebView: Received state_change callback: state=initialized
05-20 14:33:57.525  2862  2862 D Karte.IAMWebView: OverlayView entered state: READY
05-20 14:34:01.694  2862  2862 D Karte.InAppMessaging: onActivityPaused prevent_relay flag: false
05-20 14:34:01.856  2862  2862 D Karte.InAppMessaging: reset pv_id. 4cffbca5-b556-4123-b799-62577e23276e 8ab625ea-0c80-4f26-8b14-019708f679e3
05-20 14:34:02.006  2862  2862 D Karte.InAppMessaging: Dismiss by reset pv_id
05-20 14:34:02.036  2862  2862 D Karte.InAppMessaging: onActivityPaused prevent_relay flag: false
05-20 14:34:02.290  2862  2862 D Karte.InAppMessaging: reset pv_id. 3b5097f9-c782-49ba-a33d-ade2da328927 8ab625ea-0c80-4f26-8b14-019708f679e3
05-20 14:34:02.475  2862  2862 D Karte.InAppMessaging: Dismiss by reset pv_id
05-20 14:34:02.782  2862  2862 D Karte.InAppMessaging: onActivityPaused prevent_relay flag: false
05-20 14:34:11.243  2862  2862 D Karte.InAppMessaging: onActivityPaused prevent_relay flag: false
05-20 14:34:11.302  2862  2862 D Karte.InAppMessaging: reset pv_id. 34c8681c-668f-44c3-89c2-5518c2249057 8ab625ea-0c80-4f26-8b14-019708f679e3
05-20 14:34:11.368  2862  2862 D Karte.InAppMessaging: Dismiss by reset pv_id
05-20 14:34:14.645  2862  3051 E chromium: [ERROR:ssl_client_socket_impl.cc(980)] handshake failed; returned -1, SSL error code 1, net_error -202
05-20 14:34:15.466  2862  3051 E chromium: [ERROR:ssl_client_socket_impl.cc(980)] handshake failed; returned -1, SSL error code 1, net_error -202
05-20 14:34:22.404  2862  2862 D Karte.InAppMessaging: onActivityPaused prevent_relay flag: false
05-20 14:34:22.638  2862  2862 D Karte.InAppMessaging: reset pv_id. b8f8c49a-f909-47b5-a7a2-1725726f6d14 8ab625ea-0c80-4f26-8b14-019708f679e3
05-20 14:34:22.772  2862  2862 D Karte.InAppMessaging: reset pv_id. c1998351-7343-4f45-b26a-be01fe82ca11 8ab625ea-0c80-4f26-8b14-019708f679e3
05-20 14:34:23.607  2862  2862 D Karte.InAppMessaging: Dismiss by reset pv_id
05-20 14:34:23.686  2862  2862 D Karte.InAppMessaging: Dismiss by reset pv_id
05-20 14:35:53.946  2862  2862 D Karte.InAppMessaging: reset pv_id. 49c4ea2b-97e9-45c5-bab5-9070a71bdd1e 8ab625ea-0c80-4f26-8b14-019708f679e3
05-20 14:35:54.526  2862  2862 D Karte.InAppMessaging: Dismiss by reset pv_id
05-20 14:36:02.412  2862  2862 D Karte.InAppMessaging: WebView recreate
05-20 14:36:03.340  2862  2862 I chromium: [INFO:CONSOLE(1)] "setVisitor and reset storage. 6f810602-1668-4af9-bdf3-5075bac01980", source: https://static.karte.io/native_app_libs/tracker.js (1)
05-20 14:36:03.349  2862  2862 I chromium: [INFO:CONSOLE(1)] "sendDataToNative: state_changed{"state":"initialized"}", source: https://static.karte.io/native_app_libs/tracker.js (1)
05-20 14:36:03.377  2862  2862 D Karte.IAMWebView: Received state_change callback: state=initialized
05-20 14:36:03.378  2862  2862 D Karte.IAMWebView: OverlayView entered state: READY

Possible Implementation

    private fun getWebView(url: String? = null): IAMWebView? {
        cachedWebView?.let {
            // urlが指定されている場合、読み込み済みのものと異なればcacheを使用しない
            if (url == null || url == it.url)
                return it
        }
        Logger.d(LOG_TAG, "WebView recreate")
        cachedWebView?.destroy()
        cachedWebView = null
        try {
            cachedWebView = IAMWebView(app.application) { uri: Uri ->
                Boolean
                Logger.d(LOG_TAG, " shouldOpenURL $delegate")
                delegate?.shouldOpenURL(uri) ?: true
            }.apply { loadUrl(url ?: generateOverlayURL()) }
        } catch (e: PackageManager.NameNotFoundException) {
            // WebViewアップデート中に初期化すると例外発生する可能性がある
            // NOTE: https://stackoverflow.com/questions/29575313/namenotfoundexception-webview
            // 4系,5.0系に多いが、その他でも発生しうる。
            Logger.e(LOG_TAG, "Failed to construct IAMWebView, because WebView is updating.", e)
        } catch (t: Throwable) {
            // 7系等入っているWebViewによってWebKit側のExceptionになってしまうのでThrowableでキャッチする
            // https://stackoverflow.com/questions/46278681/android-webkit-webviewfactorymissingwebviewpackageexception-from-android-7-0
            Logger.e(LOG_TAG, "Failed to construct IAMWebView", t)
        }

        return cachedWebView
    }
@wasnot
Copy link
Contributor

wasnot commented May 20, 2022

@AlanChiou
Thank you for your feedback.
As you pointed out, WebView leaks are likely to occur in that situation.

We will accept your proposal.
After fix, we will release it.
Please wait for a while.

@AlanChiou
Copy link
Author

@wasnot
Could you check if the using WebView is released properly when the user closes the app as well?

@wasnot
Copy link
Contributor

wasnot commented May 25, 2022

@AlanChiou
Sorry for the late reply.

Does "closes the app" mean that the app goes to the background?

Currently, the SDK does not release WebView when the app goes to the background.
We don't think it's a big problem because only one WebView is kept, just like when the app is in the foreground.
The scripts in the WebView are also stopped.

When the app is terminated, we think that the WebView is released with the app.
We have checked that the heap used by the app will be released.

As pointed out in the issue,
when using renewVisitorId, the problem that the old user's WebView remains is not considered.

@AlanChiou
Copy link
Author

@wasnot
"closes the app" means all activities of the app are destroyed.
Yes, WebView will be released in this case, because System will kill the process of the app.

@wasnot
Copy link
Contributor

wasnot commented Jun 2, 2022

@AlanChiou
Sorry I made you wait.
Today, we have released a version (inappmessaging 2.13.0) that adopts your proposal.

Please confirm.
Thank you very much.

@wasnot wasnot closed this as completed Jun 2, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants