很多时候,我们会在编译期间,利用 Transform ,通过 javassist,asm等在一些类的方法中插入一些代码逻辑。
插入代码之后,如果该类在线上发生异常崩溃,发生异常的方法调用所对应的行号,在Java源文件中还能对应上吗?
如果对应不上,那么有什么办法可以让其对应上呢?
本题难度 5 颗星。
更多问答 >>
-
每日一问 | RecyclerView的多级缓存机制,每级缓存到底起到什么样的作用?
2020-07-19 23:56 -
每日一问 | 比 removeView 更轻量的操作,你了解过吗?
2020-07-27 01:14 -
每日一问| View 绘制的一个细节,如何修改 View 绘制的顺序?
2020-08-12 10:21 -
每日一问 | apply plugin: 'com.android.application' 背后发生了什么?
2020-08-16 19:56 -
2020-08-23 23:54
-
每日一问 | Android P 上,需要配置 network_security_config ,才能抓包,正确吗?
2020-06-29 21:26 -
每日一问 | 曾经的记忆中“onSaveInstanceState 会在系统意外杀死 Activity 时调用”,正确吗?
2020-07-12 23:49 -
2020-06-09 23:17
-
每日一问 | Activity与Fragment的那些事,“用起来没问题,我都要走了,你崩溃了?”
2020-06-22 00:39 -
2020-06-07 20:55
回答具有误导性,应该要深入到asm的方法具体对字节码做了啥来解答这个问题,答案就不删了,留个纪念。
java的class文件里面包含有代码行号与具体指令行对应的属性,如下(每一个方法都有,可以通过javap命令来查看):
只要把那个弄正确就可以,原理应该是这样
比如你有如下代码:
其对应的字节码以及行号等如下(javap命令查看到的):
我们想将其插桩为如下代码:
插装完成后期的字节码如下:
那么原有的行号表如果asm框架没去维护的话,依然是:
那么当我们的代码报错时定位到的行号肯定就有问题了,对应这种简单的情况字需要在字节码行号上加上偏移,比如本例加上13,就能够定位到了。
ps:本人未验证过,还有诸如报错的字节码是插入的直接骂如何处理等问题。
其实要是学过java字节码,大致就能想明白异常打印的处理,就是在出现异常的时候,首先去异常表里去查,看这个异常有没有指定跳到多少行去,如果有就跳到对应的字节码行去执行(对应于java代码就是try住了异常),如果没有那么方法出栈,进入到方法的调用地方,重复上一个检查,并且出栈的时候通过代码行号表,class文件记录的java文件名来生成一条信息,然后再往上,直到全部方法出栈也没有处理异常就结束,然后打印异常信息。
可以看到字节码的行号信息里清清楚楚记录着代码行号
ps,其实debug也是考的这个来确定执行一行代码时,字节码执行多少行
其实通过上面的分析,就算是爆了错误的行数,也可以通过对app的字节码分析,来定位到实际报错的字节码,从而定位到实际异常的java代码
还能对应上,因为插入代码后不会影响原来代码的行号。假如某一行原来有代码,新插入的代码会放到原来代码后面,和原来的代码在同一行
个人看法,由于transform的都是基于输入流和输出流的。
添加一个gradle task 在transform全部执行完成之后,基于gradle task 的依赖顺序。然后将transfrom执行之前的输入文件夹路径内的class和jar包,即是原始class进行一次读取,之后对转化后的class进行一次读取,生成对应的mapping映射关系,是不是可以解决这个问题。
transform并不是插桩的修改核心,这里讨论的插桩后LineNumberTable会不会跟进改变应该是class层面的讨论
如果你进行字节码插桩的话是可以对应上的