prebid / prebid-mobile-android

Prebid Mobile SDK for Android applications
Apache License 2.0
57 stars 82 forks source link

Getting fatal java.lang.RuntimeException when calling Prebid.init #97

Closed wisey29 closed 5 years ago

wisey29 commented 5 years ago

I am using org.prebid:prebid-mobile-sdk:0.5.3. From Crashlytics, I'm seeing huge number of crashes coming from Android 9 device. The crash logs:

Caused by java.lang.RuntimeException: Using WebView from more than one process at once with the same data directory is not supported. https://crbug.com/558377
       at xN.c(xN.java:105)
       at xN.b(xN.java:180)
       at xN.e(xN.java:197)
       at com.android.webview.chromium.WebViewChromiumFactoryProvider.getStatics(WebViewChromiumFactoryProvider.java:214)
       at android.webkit.WebSettings.getDefaultUserAgent(WebSettings.java:1266)
       at org.prebid.mobile.prebidserver.internal.Settings.update(Settings.java:75)
       at org.prebid.mobile.prebidserver.PrebidServerAdapter.getPostData(PrebidServerAdapter.java:238)
       at org.prebid.mobile.prebidserver.PrebidServerAdapter.requestBid(PrebidServerAdapter.java:54)
       at org.prebid.mobile.core.BidManager.requestBidsForAdUnits(BidManager.java:96)
       at org.prebid.mobile.core.Prebid.init(Prebid.java:148)
       at com.thecarousell.Carousell.ads.PrebidManagerImpl.requestAdsBids(PrebidManagerImpl.java:37)
       at com.thecarousell.Carousell.CarousellAppInitializer.configureAdsHeaderBidding(CarousellAppInitializer.java:365)
       at com.thecarousell.Carousell.CarousellApp.onCreate(CarousellApp.java:109)
       at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1154)
       at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6217)
       at android.app.ActivityThread.access$1200(ActivityThread.java:237)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1785)
       at android.os.Handler.dispatchMessage(Handler.java:106)
       at android.os.Looper.loop(Looper.java:214)
       at android.app.ActivityThread.main(ActivityThread.java:7045)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:964)

This issue is related to https://developer.android.com/about/versions/pie/android-9.0-changes-28#web-data-dirs

The exception is throws from the library. May I know if there is any workarounds to prevent this crash as it is affecting our users on Android 9 device? Thanks.

ppuviarasu commented 5 years ago

@yurain we are not supporting 0.5.3 anymore. Can you please update to the latest SDK 1.0 and let us know if you are facing these issues

wisey29 commented 5 years ago

@ppuviarasu I have checked SDK 1.0. There is a change in the architecture but the part to get userAgent is still essentially the same as SDK 0.5, which also produce crashes on Android 8 device. The part which will still potentially throw exceptions in SDK 1.0:

if (userAgent == null) {
            // todo update this to latest method in API 0.5.1
            Handler handler = new Handler(Looper.getMainLooper());
            handler.post(new Runnable() {
                @Override
                public void run() {
                    try {
                        WebView wv = new WebView(context);
                        userAgent = wv.getSettings().getUserAgentString();
                    } catch (AndroidRuntimeException e) {
                        userAgent = "unavailable";
                    }
                }
            });
        }

I noticed that the SDK does catch AndroidRuntimeException in SDK 0.5, 0.5.3, 1 but client still receives exception from the OS. Can you help to confirm that this is a known issue?

ppuviarasu commented 5 years ago

Hey @yurain we did the test on both Android 8 & 9 emulators with SDK 1.0 and we are not able to reproduce it... We have the same logic on all our SDK's and it just works fine. Need to understand the exact steps if reproducible consistently.

AntoineJac commented 5 years ago

@ppuviarasu , issue with the current method is that creating the webview is taking time and some ressource on the app. Can we use the below code I proposed on 0.5.1 to retrieve the UA from the settings without the need to create a webview?

        if (userAgent == null) {
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
                try {
                    userAgent = WebSettings.getDefaultUserAgent(context);
                } catch (AndroidRuntimeException e) {
                    userAgent = "unavailable";
                }
            } else {
                Handler handler = new Handler(Looper.getMainLooper());
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            WebView wv = new WebView(context);
                            userAgent = wv.getSettings().getUserAgentString();
                        } catch (AndroidRuntimeException e) {
                            userAgent = "unavailable";
                        }
                    }
                });
            }
        }
yoalex5 commented 5 years ago

Information Android 9 (API level 28) introduces Web-based data directories separated by process

How to reproduce

  1. Make sure that targetSdkVersion is 28 or more
  2. Create an application using multi-processing approach (Manifest component element with android:process attribute)
  3. Create new WebView instances in the separate processes (new WebView(context);)
  4. Build, run and walk through different processes

For example using DemoApp change

<activity android:name=".DemoActivity"/>

to

<activity android:name=".DemoActivity"
 android:process=":processB"/>

The java.lang.RuntimeException: Using WebView from more than one process.. exception will be thrown by:

  1. MoPub.initializeSdk(this, sdkConfiguration, null); in CustomApplication.java - each app process has is own Application instance
  2. new WebView(context); in PrebidServerSettings.java. The same behavior has WebSettings.getDefaultUserAgent(context);
  3. dfpView.loadAd(request) in DemoActivity.java

Resolution Android doc says using WebView.setDataDirectorySuffix(). If add this method to the SDK we get java.lang.IllegalStateException: Can't set data directory suffix: WebView already initialized because AdManagerView(e.g. PublisherAdView) has been initialized by a client code in the same process before.

I think that the best way is to make change in a client code because PrebidSDK relies on the client process

AntoineJac commented 5 years ago

@yoalex5 , I agree the only way seem to either:

In the parent activity:

demoActivityIntent.putExtra("DemoActivityFirstCall", firstCall);
        startActivity(demoActivityIntent);
        firstCall = "1";

In the activity where dfp is called:

if (intent.getStringExtra("DemoActivityFirstCall").equals(String.valueOf(0))) {
            WebView.setDataDirectorySuffix("test");
}
yoalex5 commented 5 years ago

Thanks for contributing to this issue. This issue is closing because it doesn't relate to PrebidSDK If that's not the case, please do feel free to either reopen this issue or open a new one.

shayanzoro commented 3 years ago

Hi,

I would like to reopen this issue, because I'm facing a similar problem which is not fixed by the workarounds mentioned above.

I'm using org.prebid:prebid-mobile-sdk:1.10 on our Android app, which is NOT a multiprocess app. I see a significant & increasing number of crash reports related to 2 processes using the same WebView directory, which is cause by PrebidServerSettings.java:83:

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 com.myapp.package (pid 2048), lock owner com.myapp.package (pid 5388)
       at org.chromium.android_webview.AwDataDirLock.b(AwDataDirLock.java:27)
       at sp0.j(sp0.java:31)
       at sp0.b(sp0.java:22)
       at sp0.l(sp0.java:2)
       at com.android.webview.chromium.WebViewChromiumFactoryProvider.g(WebViewChromiumFactoryProvider.java:2)
       at com.android.webview.chromium.WebViewChromium.init(WebViewChromium.java:14)
       at android.webkit.WebView.<init>(WebView.java:435)
       at android.webkit.WebView.<init>(WebView.java:355)
       at android.webkit.WebView.<init>(WebView.java:337)
       at android.webkit.WebView.<init>(WebView.java:324)
       at android.webkit.WebView.<init>(WebView.java:314)
       at org.prebid.mobile.PrebidServerSettings$1.run(PrebidServerSettings.java:83)
       at android.os.Handler.handleCallback(Handler.java:938)
       at android.os.Handler.dispatchMessage(Handler.java:99)
       at android.os.Looper.loop(Looper.java:246)
       at android.app.ActivityThread.main(ActivityThread.java:8506)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130)

This happens on Android 9, 10 & 11 (mostly on Android 11) Unfortunately I haven't been able to reproduce this on my devices. I suspect the issue is related to what is being discussed here: https://bugs.chromium.org/p/chromium/issues/detail?id=558377#c126

There's a long-existing bug in Android which can cause two copies of an app to be running at the same time for a short period of time. It only happens under very specific conditions and even then only causes app issues in some cases

(So if in that moment the app tires to create a Webview, a RuntimeException will be thrown)

In our app, this happens when initialising the prebid library via this line:

PrebidMobile.setApplicationContext(applicationContext);

And PrebidServerSettings tries to create a Webview at the app start, which fails due to RuntimeException.

My suggestions:

  1. Could Prebid library use another method to get the userAgent instead of creating a WebView?
  2. Could Prebid library catch RuntimeException instead of AndroidRuntimeException? that would at least not cause the app to crash.

If any more information is needed, I'll be happy to provide. Thank you!

Regards, Shayan Aryan

baptistecassar commented 3 years ago

Hi, I am having the same issue than @shayanzoro. @shayanzoro if you managed to fix this issue, I am interested in your solution.

shayanzoro commented 3 years ago

Hi, I am having the same issue than @shayanzoro. @shayanzoro if you managed to fix this issue, I am interested in your solution.

Hi. I managed to have a workaround only to prevent the crash: Before initialising Prebid library, I initialise a WebView, wrapped inside try-catch, if it fails with the exception above, I set an empty user agent field inside Prebid. Then I initialise the Prebid. Note that this affects the ad personalisation.