问题描述
在系统进程中使用 WebView 时,会抛出
AndroidRuntime: Caused by: java.lang.UnsupportedOperationException: For security reasons, WebView is not allowed in privileged processes
特权进程包括sharedUserId为ROOT_UID和SYSTEM_UID的进程
错误日志
Process: com.android.androidx, PID: 5044 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.android.androidx/com.android.activityx.ChargeActivity}: android.view.InflateException: Binary XML file line #7 in com.android.androidx:layout/layout_charge: Binary XML file line #7 in com.android.androidx:layout/layout_charge: Error inflating class android.webkit.WebView at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3298) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3437) at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83) at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2041) at android.os.Handler.dispatchMessage(Handler.java:107) at android.os.Looper.loop(Looper.java:214) at android.app.ActivityThread.main(ActivityThread.java:7386) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:980) Caused by: android.view.InflateException: Binary XML file line #7 in com.android.androidx:layout/layout_charge: Binary XML file line #7 in com.android.androidx:layout/layout_charge: Error inflating class android.webkit.WebView Caused by: android.view.InflateException: Binary XML file line #7 in com.android.androidx:layout/layout_charge: Error inflating class android.webkit.WebView 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:854) at android.view.LayoutInflater.createView(LayoutInflater.java:776) at com.android.internal.policy.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:58) at android.view.LayoutInflater.onCreateView(LayoutInflater.java:930) at android.view.LayoutInflater.onCreateView(LayoutInflater.java:950) at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:1006) at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:961) at android.view.LayoutInflater.rInflate(LayoutInflater.java:1140) at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1101) at android.view.LayoutInflater.inflate(LayoutInflater.java:682) at android.view.LayoutInflater.inflate(LayoutInflater.java:534) at android.view.LayoutInflater.inflate(LayoutInflater.java:481) at com.android.internal.policy.PhoneWindow.setContentView(PhoneWindow.java:438) at android.app.Activity.setContentView(Activity.java:3324) at com.android.activityx.ChargeActivity.onCreate(ChargeActivity.java:40) at android.app.Activity.performCreate(Activity.java:7802) at android.app.Activity.performCreate(Activity.java:7791) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1306) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3273) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3437) at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83) at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2041) at android.os.Handler.dispatchMessage(Handler.java:107) at android.os.Looper.loop(Looper.java:214) at android.app.ActivityThread.main(ActivityThread.java:7386) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:980) 2020-10-05 14:50:47.621 5044-5044/? E/AndroidRuntime: Caused by: java.lang.UnsupportedOperationException: For security reasons, WebView is not allowed in privileged processes at android.webkit.WebViewFactory.getProvider(WebViewFactory.java:236) at android.webkit.WebView.getFactory(WebView.java:2551) at android.webkit.WebView.ensureProviderCreated(WebView.java:2545) at android.webkit.WebView.setOverScrollMode(WebView.java:2613) at android.view.View.<init>(View.java:5062) at android.view.View.<init>(View.java:5203) at android.view.ViewGroup.<init>(ViewGroup.java:676) at android.widget.AbsoluteLayout.<init>(AbsoluteLayout.java:56) at android.webkit.WebView.<init>(WebView.java:410) at android.webkit.WebView.<init>(WebView.java:353) at android.webkit.WebView.<init>(WebView.java:336) at android.webkit.WebView.<init>(WebView.java:323) ... 32 more
解决办法
通过 hook 加载过程避免
在项目的 Application OnCreate() 或者要加载的 Activity setContentView() 前调用 hookWebView()
再次运行问题解决
public static void hookWebView(){ int sdkInt = Build.VERSION.SDK_INT; try { Class<?> factoryClass = Class.forName("android.webkit.WebViewFactory"); Field field = factoryClass.getDeclaredField("sProviderInstance"); field.setAccessible(true); Object sProviderInstance = field.get(null); if (sProviderInstance != null) { Log.i("hook","sProviderInstance isn't null"); return; } Method getProviderClassMethod; if (sdkInt > 22) { getProviderClassMethod = factoryClass.getDeclaredMethod("getProviderClass"); } else if (sdkInt == 22) { getProviderClassMethod = factoryClass.getDeclaredMethod("getFactoryClass"); } else { Log.i("hook","Don't need to Hook WebView"); return; } getProviderClassMethod.setAccessible(true); Class<?> factoryProviderClass = (Class<?>) getProviderClassMethod.invoke(factoryClass); Class<?> delegateClass = Class.forName("android.webkit.WebViewDelegate"); Constructor<?> delegateConstructor = delegateClass.getDeclaredConstructor(); delegateConstructor.setAccessible(true); if(sdkInt < 26){//低于Android O版本 Constructor<?> providerConstructor = factoryProviderClass.getConstructor(delegateClass); if (providerConstructor != null) { providerConstructor.setAccessible(true); sProviderInstance = providerConstructor.newInstance(delegateConstructor.newInstance()); } } else { Field chromiumMethodName = factoryClass.getDeclaredField("CHROMIUM_WEBVIEW_FACTORY_METHOD"); chromiumMethodName.setAccessible(true); String chromiumMethodNameStr = (String)chromiumMethodName.get(null); if (chromiumMethodNameStr == null) { chromiumMethodNameStr = "create"; } Method staticFactory = factoryProviderClass.getMethod(chromiumMethodNameStr, delegateClass); if (staticFactory!=null){ sProviderInstance = staticFactory.invoke(null, delegateConstructor.newInstance()); } } if (sProviderInstance != null){ field.set("sProviderInstance", sProviderInstance); Log.i("hook","Hook success!"); } else { Log.i("hook","Hook failed!"); } } catch (Throwable e) { Log.w("hook",e); e.printStackTrace(); }