Open zengjingfang opened 6 years ago
@TargetApi(Build.VERSION_CODES.KITKAT)
private static String getWakeLockTag(PowerManager.WakeLock wakeLock) {
String tag = "Default-WakeLock-Tag";
if (wakeLock == null) {
return tag;
}
try {
Method getTagMethod = wakeLock.getClass().getDeclaredMethod("getTag");
getTagMethod.setAccessible(true);
tag = (String) getTagMethod.invoke(wakeLock, (Object[]) null);
} catch (ReflectiveOperationException e) {
LogUtil.w(TAG,e);
} catch (Exception e) {
LogUtil.w(TAG,e);
}
return tag;
}
查看手机系统为Android4.2.2.r1源码:
有wakeLock 这个内部类,但是没有getTag这个方法。
且来看看高版本的方法:
/** @hide */
public void setTag(String tag) {
mTag = tag;
}
/** @hide */
public String getTag() {
return mTag;
}
可以看出加了 @hide 对外不公开,但是系统内部可见的,所以这里要用反射。
java.lang.VerifyError: com/xxx/xxx/xxx/xxx/manager/WakeLockManager
getWakeLockTag 是上述类WakeLockManager中的一个方法
查资料说是JVM加载类的时候,“校验器”检查文件格式虽然正确,但是内部的存在不一致性和安全性的问题,所以抛出了该错误。
不同的虚拟编译器不一样,所以抛出的错误信息叶铿不一样。
异常名称 异常栈中的段落信息 可能原因
java.lang.VerifyError Call to wrong initialization method 可能是在调用构造函数即
java.lang.VerifyError Incompatible object argument for function call 同样是方法调用的时候出现的错误。看时候有参数设置错误了
java.lang.VerifyError Stack size too large 设置的最大栈空间大小不够
java.lang.VerifyError Illegal local variable number 可能是设置的最大局部变量大小不够,也可能是访问的局部变量的index不对
java.lang.VerifyError Must call initializers using invokespecial 在你调用
java.lang.VerifyError Expecting to find integer on stack 可能是在赋值的时候类型不匹配,典型的就是将int类型直接赋值到Integer这之类的。固然在写java代码的时候可以直接赋值,但是在字节码的时候先要调用Integer的valueOf方法创建一个Integer对象再赋值
java.lang.ClassFormatError Arguments can't fit into locals in class file 可能是设置的最大局部变量大小不够
Android 虚拟机注意 ART 模式下面,可能不会报告错误 但是在 Davlik 虚拟机下,会在运行时编译,检测器就会工作 导致在5.0及其以上的设备工作正常,但在操作系统5.0以下(部分4.4开启了ART不会出现)以下报告java.lang.VerifyError` 错误
导致这个错误的原因有2个
三方jar包本身有错误 反编译smali代码修改继承或者申请寄存器操作错误
作者:泛原罪 链接:https://www.jianshu.com/p/07873b237b86
接着看到另外一篇文章 Android 不想和你说话,抛了个 java.lang.VerifyError
文中说明出现这个异常的问题主要在类文件校验错误,出现这种情况的情况有:
但是,这个地方既然已经用了反射的,为什么还会报这个错误?
@TargetApi(Build.VERSION_CODES.KITKAT)
马上就发现,这个ReflectiveOperationException在19之后才加入,所以我们添加了注解:
@TargetApi(Build.VERSION_CODES.KITKAT)
那么,加了该注解,我们应该对低版本进行下兼容处理。
@TargetApi(Build.VERSION_CODES.KITKAT)
private static String getWakeLockTag(PowerManager.WakeLock wakeLock,String wakeLockName) {
String tag = "Default-WakeLock-Tag";
if (wakeLock == null) {
return tag;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
try {
Method getTagMethod = wakeLock.getClass().getDeclaredMethod("getTag");
getTagMethod.setAccessible(true);
tag = (String) getTagMethod.invoke(wakeLock, (Object[]) null);
} catch (ReflectiveOperationException e) {
LogUtil.w(TAG,e);
} catch (Exception e) {
LogUtil.w(TAG,e);
}
}else {
LogUtil.d(TAG, "api < 19 ,so wakeLockName: " + wakeLockName);
return wakeLockName;
}
return tag;
}
AndroidRuntime: FATAL EXCEPTION: Thread-21891
java.lang.VerifyError: com/xxx/xxx/xxx/xxx/xxx/WakeLockManager
at com.xxx.xxx.xxx.xxx.b.b.b(Unknown Source)
at com.xxx.xxx.xxx.xxx.b.b.a(Unknown Source)
at com.xxx.xxx.xxx.xxx.b.b$1.run(Unknown Source)
如果在5.0.0的机器上跑,则不存在该问题。
实际只需要将ReflectiveOperationException的变成Exception也不会有问题。
捕获的异常:java.lang.NoSuchMethodException: getTag []
基本说明了是运行时加载Class存在问题。
Constant pool:
#63 = Class #191 // java/lang/ReflectiveOperationException
#117 = Utf8 Ljava/lang/ReflectiveOperationException;
#119 = Class #191 // java/lang/ReflectiveOperationException
#191 = Utf8 java/lang/ReflectiveOperationException
查JVM虚拟机类加载机制中验证步骤,发现:
ReflectiveOperationException这个就是在低版本Android系统中不被支持的,所以在低版本Android系统中加载该WakeLockManager类时就报:java.lang.VerifyError。
上述的说法并不完全正确,因为发现如果我们修改代码如下:
private static String getWakeLockTag(PowerManager.WakeLock wakeLock,String wakeLockName) {
String tag = "Default-WakeLock-Tag";
if (wakeLock == null) {
return tag;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
try {
Method getTagMethod = wakeLock.getClass().getDeclaredMethod("getTag");
getTagMethod.setAccessible(true);
new ReflectiveOperationException("test");// 直接New一个,而不是在catch的代码块里面
tag = (String) getTagMethod.invoke(wakeLock, (Object[]) null);
}catch (Exception e) {
LogUtil.w(TAG,e);
}
}else {
LogUtil.d(TAG, "api < 19 ,so wakeLockName: " + wakeLockName);
return wakeLockName;
}
return tag;
}
这样在运行时,并不会报错。
所以,出现了上述的现象。在代码中 new ReflectiveOperationException("test");并没有真正的运行,但是在catch代码块中直接就爆出了
java.lang.VerifyError`。
反射获取getTag接口报ReflectiveOperationException