GithubHelp home page GithubHelp logo

Comments (11)

zengjingfang avatar zengjingfang commented on July 28, 2024

看代码发现 ClassNotFoundExceptione 是 ReflectiveOperationException 的子类,于是修改如下

    @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源码:

4.2.2_r1 PowerManager

有wakeLock 这个内部类,但是没有getTag这个方法。

且来看看高版本的方法:

   /** @hide */
   public void setTag(String tag) {
         mTag = tag;
   }
   
   /** @hide */
   public String getTag() {
        return mTag;
   }

可以看出加了 @hide 对外不公开,但是系统内部可见的,所以这里要用反射。

from androidbox.

zengjingfang avatar zengjingfang commented on July 28, 2024

以为万事大吉,谁知道报了

java.lang.VerifyError: com/xxx/xxx/xxx/xxx/manager/WakeLockManager

getWakeLockTag 是上述类WakeLockManager中的一个方法

查资料说是JVM加载类的时候,“校验器”检查文件格式虽然正确,但是内部的存在不一致性和安全性的问题,所以抛出了该错误。

不同的虚拟编译器不一样,所以抛出的错误信息叶铿不一样。

异常名称 异常栈中的段落信息 可能原因

  • java.lang.VerifyError Call to wrong initialization method 可能是在调用构造函数即的时候传进了错误的owner

  • 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 在你调用 方法的时候使用了非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

from androidbox.

zengjingfang avatar zengjingfang commented on July 28, 2024

看完上述的文章,还是没搞明白为什么会有这个错误

接着看到另外一篇文章
Android 不想和你说话,抛了个 java.lang.VerifyError

文中说明出现这个异常的问题主要在类文件校验错误,出现这种情况的情况有:

  • 去extends 一个final类,去override一个final方法等
  • 使用的方法高版本的SDK有但是低版本没有

但是,这个地方既然已经用了反射的,为什么还会报这个错误?

from androidbox.

zengjingfang avatar zengjingfang commented on July 28, 2024

怀疑修改后还是存在版本兼容性问题

于是删除方法的注解

  @TargetApi(Build.VERSION_CODES.KITKAT)

果然,发现编译器警告ReflectiveOperationException

image

这么说,是这个ReflectiveOperationException在低版本中JVM加载时存在错误,理论上说的通。

from androidbox.

zengjingfang avatar zengjingfang commented on July 28, 2024

查看了Android的API文档

马上就发现,这个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;
    }

from androidbox.

zengjingfang avatar zengjingfang commented on July 28, 2024

经过验证,还是报了如下相同异常

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的机器上跑,则不存在该问题。

from androidbox.

zengjingfang avatar zengjingfang commented on July 28, 2024

如图,注释掉该部分代码就正常了

image

实际只需要将ReflectiveOperationException的变成Exception也不会有问题。

捕获的异常:java.lang.NoSuchMethodException: getTag []

基本说明了是运行时加载Class存在问题。

from androidbox.

zengjingfang avatar zengjingfang commented on July 28, 2024

查看这个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

from androidbox.

zengjingfang avatar zengjingfang commented on July 28, 2024

查JVM虚拟机类加载机制中验证步骤,发现:

  • 常量池的常量中是否有不被支持的常量类型(检查常量tag标志)

ReflectiveOperationException这个就是在低版本Android系统中不被支持的,所以在低版本Android系统中加载该WakeLockManager类时就报:java.lang.VerifyError。

from androidbox.

zengjingfang avatar zengjingfang commented on July 28, 2024

上述的说法并不完全正确,因为发现如果我们修改代码如下:

 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;
    }

这样在运行时,并不会报错。

from androidbox.

zengjingfang avatar zengjingfang commented on July 28, 2024

那么catch里面和直接在代码里面直接去new有什么区别呢?

  • catch代码块在类加载时就会进行校验
  • 而try方法代码中需要运行时才会检测

所以,出现了上述的现象。在代码中 new ReflectiveOperationException("test");并没有真正的运行,但是在catch代码块中直接就爆出了 java.lang.VerifyError`。

from androidbox.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.