TraceView issue

来源:互联网 发布:数据脱敏系统 编辑:程序博客网 时间:2024/06/11 10:32

使用traceview时,遇到一个这样的问题:

Exception in thread "main" java.lang.RuntimeException: Method exit (android/widget/AbsListView.startScrollIfNeeded (I)Z) does not match current method (java/lang/Math.abs (I)I)

这个是google自己bug,貌似出现在android4.0-4.2之间,主要是在mips架构里面发现的,不过现在的最新版本已修复此bug。

如果不幸拿到的android源码还存在这个bug,需要自己修复。

traceiew的工作原理是跟踪函数的调用路径,然后计算整条调用路径或者单个函数的执行时间,进而测试系统或者应用程序的性能。实际上,traceiew只是在pc端运行的一个工具,它用来解析目标设备上生成的.trace文件。所以,traceview本身没有问题,只是目标设备上生成的.trace文件有问题。目标设备上是使用profile生成.trace文件的。profile把函数的进入(entry)和退出(exit)都记录在.trace文件中,记录的存储方式是按照栈(stack)的方式,所以traceiew解析.trace文件时也需要用栈的方式。

现在出现错误的原因是函数的进入(entry)和退出(exit)不配对,也就是说有些函数的进入或者退出没有被记录下来。这就需要跟踪.trace文件是如何生成的。

详细的过程就不螯述了,这里只说一下跟踪的路径吧,有兴趣的朋友可以看下。经过的文件有:

frameworks/base/cmds/am/src/com/android/commands/am/Am.java

frameworks/base/services/java/com/android/server/am/ActivityManagerService.java

frameworks/base/core/java/android/app/ActivityThread.java

frameworks/base/core/java/android/os/Debug.java

libcore/dalvik/src/main/java/dalvik/system/VMDebug.java

dalvik/vm/native/dalvik_system_VMDebug.cpp

dalvik/vm/Profile.cpp

.trace最主要的生成过程是在dalvik/vm/Profile.cpp中,后来发现最可能出错的地方是,其中只有一个记录函数进入的地方,然而却有两个记录退出的地方。所以有可能是退出时使用了错误的函数。

记录进入的函数:

dvmFastMethodTraceEnter

记录退出的两个函数:

dvmFastNativeMethodTraceExit

dvmFastMethodTraceExit

这些函数是在汇编代码里边调用的,涉及到汇编代码就是架构相关了。android支持的架构有ARM,MIPS和X86。既然是在MIPS发现了这个问题,所以就看MIPS架构相关的代码,后来发现在:

dalvik/vm/mterp/mips/OP_EXECUTE_INLINE.S

dalvik/vm/mterp/mips/OP_EXECUTE_INLINE_RANGE.S

dalvik/vm/mterp/out/InterpAsm-mips.S

这三个文件里面都调用了上面的函数。第三个文件是由很多.S文件(包括第一和第二个文件)生成的,可以忽视。所以调查前两个文件。

OP_EXECUTE_INLINE.S里调用的代码片段:

.L${opcode}_debugmode:    move      a0, rBIX    JAL(dvmResolveInlineNative)    beqz      v0, .L${opcode}_resume       #  did it resolve? no, just move on    move      rOBJ, v0                     #  remember method    move      a0, v0    move      a1, rSELF    JAL(dvmFastMethodTraceEnter)           #  (method, self)    addu      a1, rSELF, offThread_retval  #  a1<- &self->retval    GET_OPB(a0)                            #  a0 <- B    # Stack should have 16/20 available    sw        a1, 16(sp)                   #  push &self->retval    BAL(.L${opcode}_continue)              #  make call; will return after    lw        gp, STACK_OFFSET_GP(sp)      #  restore gp    move      rINST, v0                    #  save result of inline    move      a0, rOBJ                     #  a0<- method    move      a1, rSELF                    #  a1<- self    JAL(dvmFastMethodTraceExit)            #  (method, self)    beqz      v0, common_exceptionThrown   #  returned false, handle exception    FETCH_ADVANCE_INST(3)                  #  advance rPC, load rINST    GET_INST_OPCODE(t0)                    #  extract opcode from rINST    GOTO_OPCODE(t0)                        #  jump to next instruction

OP_EXECUTE_INLINE_RANGE.S里面的调用片段:

/*     * We're debugging or profiling.     * rBIX: opIndex     */.L${opcode}_debugmode:    move      a0, rBIX    JAL(dvmResolveInlineNative)    beqz      v0, .L${opcode}_resume       #  did it resolve? no, just move on    move      rOBJ, v0                     #  remember method    move      a0, v0    move      a1, rSELF    JAL(dvmFastMethodTraceEnter)           #  (method, self)    addu      a1, rSELF, offThread_retval  #  a1<- &self->retval    GET_OPA(a0)                            #  a0 <- A    # Stack should have 16/20 available    sw        a1, 16(sp)                   #  push &self->retval    move      rINST, rOBJ                  #  rINST<- method    BAL(.L${opcode}_continue)              #  make call; will return after    lw        gp, STACK_OFFSET_GP(sp)      #  restore gp    move      rOBJ, v0                     #  save result of inline    move      a0, rINST                    #  a0<- method    move      a1, rSELF                    #  a1<- self    JAL(dvmFastNativeMethodTraceExit)      #  (method, self)    beqz      rOBJ, common_exceptionThrown #  returned false, handle exception    FETCH_ADVANCE_INST(3)                  #  advance rPC, load rINST    GET_INST_OPCODE(t0)                    #  extract opcode from rINST    GOTO_OPCODE(t0)                        #  jump to next instruction

其中,OP_EXECUTE_INLINE.S调用的组合是:

dvmFastMethodTraceEnter

dvmFastMethodTraceExit

OP_EXECUTE_INLINE_RANGE.S调用的组合是:

dvmFastMethodTraceEnter

dvmFastNativeMethodTraceExit

但是,我发现OP_EXECUTE_INLINE.S里面的调用是不符合逻辑的。

请看:

    move      a0, rOBJ                     #  a0<- method    move      a1, rSELF                    #  a1<- self    JAL(dvmFastMethodTraceExit)            #  (method, self)
这段代码,程序准备了a0 和a1两个参数,但是回头看看dvmFastMethodTraceExit和dvmFastNativeMethodTraceExit的函数原型:

void dvmFastMethodTraceExit(Thread* self)

void dvmFastNativeMethodTraceExit(const Method* method, Thread* self)

很明显,dvmFastMethodTraceExit只有一个参数,所以没必要准备两个参数。所以,这段代码的编写者原意应该是想要调用dvmFastNativeMethodTraceExit的。把OP_EXECUTE_INLINE.S里面的dvmFastMethodTraceExit换成dvmFastNativeMethodTraceExit,执行dalvik/vm/mterp/rebuild.sh重新生成dalvik/vm/mterp/out/InterpAsm-mips.S,然后重编dalvik,启动运行,生成.trace文件,traceiew解析,成功了!

原创粉丝点击