问题描述
在系统进程中使用 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){
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();
}
}