Influence of Android P behavior change on WebView

Posted by philip@hux.co.za on Wed, 09 Feb 2022 12:25:33 +0100

This problem was encountered years ago. On the first day of work after the year, I suddenly thought of the problem solved years ago when verifying other problems. I can't remember how to solve it at that time. I looked through the code and thought for a while before I remembered it. This is recorded here.

The error logs counted are as follows:

Process Name: 'com.xxxx.xxx'
Thread Name: 'main'
Back traces starts.

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.xxxx.xxxx/com.xuetian.player.player.live.LivePlayDocActivity}: android.view.InflateException: Binary XML file line #7 in com.xxx.xxx:layout/intro_layout: Binary XML file line #7 in com.xxx.xxx:layout/intro_layout: Error inflating class com.xuetian.common.ui.lib.widget.LollipopFixedWebView

at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3504)

at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3643)

at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)

at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:140)

at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:100)

at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2229)

at android.os.Handler.dispatchMessage(Handler.java:107)

at android.os.Looper.loop(Looper.java:238)

at android.app.ActivityThread.main(ActivityThread.java:7798)

at java.lang.reflect.Method.invoke(Native Method)

at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:512)

at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:995)

Caused by: android.view.InflateException: Binary XML file line #7 in com.xxx.xxx:layout/intro_layout: Binary XML file line #7 in com.xxx.xxx:layout/intro_layout: Error inflating class com.xuetian.common.ui.lib.widget.LollipopFixedWebView

Caused by: android.view.InflateException: Binary XML file line #7 in com.xxx.xxx:layout/intro_layout: Error inflating class com.xuetian.common.ui.lib.widget.LollipopFixedWebView

Caused by: java.lang.reflect.InvocationTargetException

at java.lang.reflect.Constructor.newInstance0(Native Method)

at java.lang.reflect.Constructor.newInstance(Constructor.java:343)

at android.view.LayoutInflater.createView(LayoutInflater.java:855)

at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:1008)

at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:963)

at android.view.LayoutInflater.rInflate(LayoutInflater.java:1125)

at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1086)

at android.view.LayoutInflater.inflate(LayoutInflater.java:682)

at android.view.LayoutInflater.inflate(LayoutInflater.java:534)

at com.xuetian.player.player.live.LiveIntroComponent.initIntroView(LiveIntroComponent.java:38)

at com.xuetian.player.player.live.LiveIntroComponent.<init>(LiveIntroComponent.java:28)

at com.xuetian.player.player.live.LivePlayDocActivity.initIntroLayout(LivePlayDocActivity.java:699)

at com.xuetian.player.player.live.LivePlayDocActivity.initComponents(LivePlayDocActivity.java:678)

at com.xuetian.player.player.live.LivePlayDocActivity.initViewPager(LivePlayDocActivity.java:564)

at com.xuetian.player.player.live.LivePlayDocActivity.onCreate(LivePlayDocActivity.java:141)

at android.app.Activity.performCreate(Activity.java:7963)

at android.app.Activity.performCreate(Activity.java:7952)

at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1307)

at com.qiyukf.unicorn.i.a.callActivityOnCreate(Unknown Source:2)

at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3479)

at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3643)

at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)

at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:140)

at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:100)

at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2229)

at android.os.Handler.dispatchMessage(Handler.java:107)

at android.os.Looper.loop(Looper.java:238)

at android.app.ActivityThread.main(ActivityThread.java:7798)

at java.lang.reflect.Method.invoke(Native Method)

at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:512)

at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:995)

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 org.chromium.android_webview.AwBrowserProcess.b(PG:11)

at D5.m(PG:33)

at D5.a(PG:48)

at D5.b(PG:16)

at com.android.webview.chromium.WebViewChromiumFactoryProvider.a(PG:32)

at com.android.webview.chromium.WebViewChromium.init(PG:12)

at android.webkit.WebView.<init>(WebView.java:435)

at android.webkit.WebView.<init>(WebView.java:359)

at android.webkit.WebView.<init>(WebView.java:342)

at android.webkit.WebView.<init>(WebView.java:329)

at com.xuetian.common.ui.lib.widget.LollipopFixedWebView.<init>(LollipopFixedWebView.java:24)

... 31 more

Back traces ends.

###1. Android Pie behavior change - set up network-based data directory according to process

In order to improve the application stability and data integrity in Android 9, applications can no longer allow multiple processes to share the same WebView data directory. Such data directories generally store cookies, HTTP caches, and other persistent and temporary storage related to web browsing.
In most cases, your application should only use Android in one process Classes in WebKit packages, such as WebView and CookieManager. For example, you should move all Activity objects that use WebView into the same process. You can execute the "one process only" rule more strictly by calling disableWebView() in other processes in the application. This call prevents WebView from being initialized incorrectly in these other processes, even if it is invoked from a content library.
If your application must use WebView instances in multiple processes, you must first use WebView The setdatadirectorysuffix() function specifies a unique data directory suffix for each process, and then uses the given instance of WebView in the process. This function will put the network data of each process into its own directory in the application data directory.
Note: even if you use setDataDirectorySuffix(), the system will not share cookies and other network data across the process boundaries of the application. If multiple processes in the application need to access the same network data, you need to copy the data between these processes by yourself. For example, you can call getCookie() And setCookie() , manually transfer Cookie data between different processes.

This problem was solved at the beginning of last year by calling the following code in the oncreat method of Application:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
  String processName =getProcessName();                            
  if(processName.equals("com.xxx.xxx")){
    WebView.setDataDirectorySuffix(processName);
  }
}

After the problem was solved in this way at that time, the error log statistics did not appear again. Until the end of last year, after using the reinforcement service, the error suddenly appeared again, and the error rate soared to 1.9%, which made the dragon's back tight. At that time, it was suspected that it was a reinforcement problem, but no mobile phone on hand could reproduce the problem, and the same models (model versions: PCHM10, PCLM50, etc.) with wrong statistics could not reproduce it. Later, I finally found a colleague's mobile phone to reproduce this problem, and it was completed (one plus mobile phone: OnePlus 9R).

It took nearly a day from encountering this problem again to completely solving it. During this period, it was even suspected that it was caused by the reinforcement service just purchased. However, the good thing is that it has been solved, which has reduced the error rate to 0.09% which is now acceptable. Let's talk about the specific situation below.

###2. After many attempts, it was finally found that the following methods can be solved

Start solving Code:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
  String processName =getProcessName();                            
  if(processName.equals("com.xxx.xxx")){
    WebView.setDataDirectorySuffix(processName);
  }
}

Final solution code after modification:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
  String processName =getProcessName(); 
  WebView.setDataDirectorySuffix(processName);
}

The device model and system WebView version are shown in the figure below:

Topics: Java Android webview