当系统进程加载WebView时会报错:UnsupportedOperationException:
如下
java.lang.UnsupportedOperationException: For security reasons, WebView is not allowed in privileged processes
at android.webkit.WebViewFactory.getProvider(WebViewFactory.java:96)
at android.webkit.WebView.getFactory(WebView.java:2194)
at android.webkit.WebView.ensureProviderCreated(WebView.java:2189)
at android.webkit.WebView.setOverScrollMode(WebView.java:2248)
at android.view.View.<init>(View.java:3588)
at android.view.View.<init>(View.java:3682)
at android.view.ViewGroup.<init>(ViewGroup.java:497)
at android.widget.AbsoluteLayout.<init>(AbsoluteLayout.java:55)
at android.webkit.WebView.<init>(WebView.java:544)
at android.webkit.WebView.<init>(WebView.java:489)
at android.webkit.WebView.<init>(WebView.java:472)
at android.webkit.WebView.<init>(WebView.java:459)
at android.webkit.WebView.<init>(WebView.java:449)
通过log分析原因是:
因为安全问题,WebView禁止在系统进程中加载。这肯定是因为WebView众所周知的安全漏洞,可以通过JSBridge调Android内部函数,从而引起安全问题
有兴趣详细了解这个问题可以移步这里。WebView详解及安全问题
源码分析:
在源码中看下异常抛出的位置
代码具体位置AndroidXref 注:android 8.0
通过代码发现当WebView启动时调到这个getProvide函数,然后会判断进程的uid,如果是上面那几种就挂了。
解决办法 -- HOOK
思路-1:在使用 WebView 之前,我们先 Hook WebViewFactory,创建 sProviderInstance 对象,从而绕过系统检查。
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.debug("sProviderInstance isn't null");
return;
}
Method getProviderClassMethod;
if (sdkInt > 22) {
getProviderClassMethod = factoryClass.getDeclaredMethod("getProviderClass");
} else if (sdkInt == 22) {
getProviderClassMethod = factoryClass.getDeclaredMethod("getFactoryClass");
} else {
log.info("Don't need to Hook WebView");
return;
}
getProviderClassMethod.setAccessible(true);
Class<?> providerClass = (Class<?>) getProviderClassMethod.invoke(factoryClass);
Class<?> delegateClass = Class.forName("android.webkit.WebViewDelegate");
Constructor<?> providerConstructor = providerClass.getConstructor(delegateClass);
if (providerConstructor != null) {
providerConstructor.setAccessible(true);
Constructor<?> declaredConstructor = delegateClass.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
sProviderInstance = providerConstructor.newInstance(declaredConstructor.newInstance());
log.debug("sProviderInstance:{}", sProviderInstance);
field.set("sProviderInstance", sProviderInstance);
}
log.debug("Hook done!");
} catch (Throwable e) {
log.error(e);
}
}
思路-2 : Hook进程UID
从源码中可以看出其uid的获取方式
final int uid = android.os.Process.myUid();
所以HOOK这个函数,使其返回的UID不在下面UID之列即可。
我是用Xposed HOOK的,不过应该可以按着这个思路用其他方式HOOK。
XposedBridge.hookAllMethods(Process.class, "myUid", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
Throwable t = new Throwable();
StackTraceElement[] traces = t.getStackTrace();
if(traces.length < 4)
return;
StackTraceElement trace = traces[3];
if(WebViewFactoryClassName.equals(trace.getClassName()) && GetProviderMethodName.equals(trace.getMethodName())){
param.setResult(10010);
}
}
});
最后, 同学点个赞吧!!! 加个关注好么
参考文章
https://blog.csdn.net/codingnotes/article/details/79020542