dalvik 调试

来源:互联网 发布:淘宝活动回复流程 编辑:程序博客网 时间:2024/05/17 02:45

http://hi.baidu.com/seucrcr/item/87835ec3c4c78351bcef6977

Dalvik——tests工具学习文档1

1 测试工具的实现
1.1 调研目的
    目前正在进行针对Unicore架构的Dalvik虚拟机改写,为了保证整个Android操作系统在Unicore上的正常运行,我们试图先独立测试改写后的Dalvik虚拟机;而Android2.1源码中包含了dalvik虚拟机的测试工具,其目录位于/android2.1/dalvik/tests下,我们先对它进行调研,看能否用它来测试我们改写后的dalvik虚拟机。
    调研分为三部分进行,首先了解该测试工具的实现方式,其次介绍它的使用方法,最后评估用它测试修改后的dalvik虚拟机的可行性。
1.2 tests简介
首先分析/android2.1/dalvik/tests目录的结构:
-tests dalvik测试工具和测试代码文件夹。
--001——078   文件夹,保存了78个测试代码,主要由/src/*.java(测试所需代码)
以及xpected.txt(测试期望结果文档)和info.txt(测试说明文档);
--ect     试工具的最终实现脚本,用Linux shell命令格式写成;
--run-all-tests   执行文件,测试所有78个测试代码;
--run-test   可执行文件,指定参数来测试特定的测试代码。

1.3 测试工具的实现
    通过上节的介绍,要理解测试工具是如何实现对dalvik虚拟机的测试,就必须理解run-test可执行文件(run-all-tests可以看做是逐一调用run-tests),下面将具体介绍该可执行文件的实现方式。
1.3.1 run-test的参数
1.3.1.1 综述
    进入/android2.1/dalvik/tests,在Linux shell下输入命令:
./run-test –help
    可以出现使用帮助,罗列并解释如下:
run-test –help        打印帮助信息
run-test [options] [test-name]    正常运行命令的格式
run-test --dev [options] [test-name]    开发模式(运行结果dump到stdout)
run-test --update [options] [test-name] 更新模式(运行结果代替expect.txt)
运行参数:
--fast    使用快速解释器(默认)
   -jit     使用JIT
   --portable   使用可移植的解释器
   --debug    等待调试器的连接
   --no-verify   关闭校对功能(默认打开)
   --no-optimize     关闭代码优化功能(默认打开)
   --no-precise   关闭精确GC功能(默认打开)
   --zygote    从Zygote进程创建当前进程,如果使用,当前运行参数会被忽视
--local    使用主机-本地(host-local)模拟器
--valgrind    本地运行时使用内存监测
--reference   使用主机-本地参考(host-local reference)模拟器

    通过帮助信息我们了解到,run-test有正常模式、开发模式、更新模式三种模式和多种参数,下面对参数的含义进行更详细的说明,并评估了该参数对于我们使用本测试工具的价值,在下文中我们根据需要进一步调研一部分参数:
参数                                                含义                                                                              价值
fast                              dalvik的解释器采用快速解释器,与可移植型解释器相对                     高
jit                                  android2.2开始采用的jit技术                                                               低
portable                       dalvik解释器采用可移植型解释器,与快速解释器相对                         高
debug                         调试用,等待调试器连接                                                                     高
verify                          dexopt的校对模式,dexopt用于dex代码的优化                                    中
optimize                       dexopt的优化模式                                                                                中
precise                        GC管理的一个选项                                                                              低
zygote                         直接从Zygote进程创建测试进程                                                          中
local                             使用local设备(不是host上的虚拟机)来测试                                     高
valgrind                       --local并且添加了内存管理的东西                                                        低
reference                    可使用host上的模拟器,模拟local设备的虚拟机进行测试                    高

1.3.1.2 debug
        该参数的帮助文档是:等待调试器的连接(wait for debugger to attach)。为了使用该参数必须实现android的调试器(Debugger),dalvik虚拟机支持许多开发环境下的源码级的调试,任何基于JDWP(Java Debug Wire Protocol)的远程调试工具都可以,包括JDB、Eclipse、JSwat等。
        首先,介绍该参数的实现原理。在本测试的脚本文件/android2.1/dalvik/tests/ect/push-and-run-test-jar(下文将解释为什么是这个)中可以看出,debug参数是通过以下命令才实现的:
代码位置:/android2.1/dalvik/tests/ect/push-and-run-test-jar
源代码:
调试参数设定:
if [ "$DEBUG" = "y" ]; then
    DEX_DEBUG="-agentlib:jdwp=transport=dt_android_adb,server=y,suspend=y"
fi
执行命令:
adb shell cd /data \; dalvikvm $DEX_VERIFY $DEX_OPTIMIZE $DEX_DEBUG \
$GC_OPTS -cp test.jar "-Xint:${INTERP}" -ea Main "$@"
参数解释如下:
transport: 所使用的传输机制,dalvik支持TCP/IP socket、通过adb(dt_android_adb)访
问USB的方式;
server:   决定虚拟机是作为服务器(server)还是客户端(client),作为服务器时,虚拟机等待调试器连接,反之,虚拟机主动试图连接调试器;
suspend: 如果是y,虚拟机在调试器连接之前不运行任何代码,连接时,它会告诉调试器它挂起了,直到有新的指令它才会运行。
    最终--debug的参数变为dalvikvm可执行文件的参数来执行。至于JDWP的工作原理,在此不展开讨论。
下面,介绍--debug参数的具体使用方法(以在Linux下运行android模拟器、执行本测试方法第17号源码为例进行介绍)。
1、在本地Linux环境启动android模拟器
cd /android2.1/out/host/linux-x86/bin (添加了环境变量后就可以在任意目录输入emulator)
emulator
2、运行本测试工具
cd /android2.1/dalvik/tests
./run-test --debug 017
此时在shell下将显示如下内容:
[seucr@android2 tests]$ ./run-test --debug 017-float/
/home/seucr/android2.1_r2/dalvik/tests/017-float: running...
(等待调试器连接)
3、运行DDMS
DDMS(Dalvik Debug Monitor Server)可以看做连接设备和JDWP调试器的桥梁,它显示设备当前的进程、方法等内容,允许向设备发送命令,调试器可以通过它看到设备底层的PID号、进程号等内容。
cd /android2.1/out/host/linux-x86/bin
ddms
此时在DDMS界面上可以看到当前模拟器的运行状态。由于此时已经在运行debug下的测试,因此在DDMS上可以看到一个进程名叫“?”,点击它。
4、运行JDB调试
jdb -attach localhost:8700
此时shell会显示如下内容:
[seucr@android2 bin]$ jdb -attach localhost:8700
Set uncaught java.lang.Throwable
Set deferred uncaught java.lang.Throwable
Initializing jdb ...
>
VM Started: "thread=<3> main", dalvik.system.NativeStart.main(), line=-1 bci=-1
<3> main[1]
此时就已经进入了调试界面,通过help命令可以看到可执行的命令,包括run、step、stepi等很多。直接运行run可以跑完测试程序。
5、结果分析
最终的结果很有可能是测试FAILED(判断依据下文将详细叙述)。这是因为在执行build时前期会导致:
DDM dispatch reg wait timeout
Can't dispatch DDM chunk 52454151: no handler defined
错误,后来就可以正常运行,具体原因不详。但是对比expect.txt和output.txt,可以看出期望的结果已经运行出来了。


1.3.2 run-test的实现——基础
run-test可执行文件是一个Linux Shell的脚本文件,下面分析它的执行流程,从而调研本测试工具是如何测试dalvik虚拟机的。
run-test的执行流程图如下所示:



对于我们使用run-test来说,没有必要详细介绍内部的信息传递机制、具体参数的含义,只需要了解到它是怎么实现对dalvik虚拟机的测试的,下面具体就最后一个模块“选择要执行的脚本”来进行阐述。
我们以使用默认的不含运行时参数的run-test命令为例进行介绍:

代码位置:/android2.1/dalvik/tests/run-test 第218——230行
其代码可简化为如下流程图:


从这张流程图中可以清晰地看到执行的过程和判断的依据,但是又会产生两个疑问:这样为什么就能测试dalvik虚拟机了呢?宏build和run又是怎样、是在哪儿执行的呢?

1.3.3 run-test的实现——进阶
1.3.3.1 测试dalvik原理
首先解决第一个疑问,为什么这样就能测试dalvik虚拟机。
dalvik虚拟机的作用包括两部分:解释和运行。解释是将android应用程序、framework层等处所用的JAVA代码解释为.dex格式,运行是通过dalvik虚拟机来执行该.dex文件。如果有本地调用则通过JNI Call Bridge来解决。而上述流程图中可以明显看出,run-test可执行文件正是重复了dalvik虚拟机的工作,并且将当前dalvik虚拟机的代码运行结果和标准android2.1的dalvik虚拟机的运行结果比对从而判断虚拟机能否正常运行。
下图表示了android对于*.java的处理流程,可以粗略表征dalvik虚拟机的工作流程。



1.3.3.2 run-test最终实现方式
下面解决第二个问题:宏build和run又是怎样、是在哪儿执行的呢?
在run-test中有如下定义:

代码位置:/android2.1/dalvik/tests/run-test
源代码:
39      export JAVA="java"
export JAVAC="javac -target 1.5"
export RUN="${progdir}/etc/push-and-run-test-jar"
44    build="build"
run="run"
192    if [ '!' -r "$build" ]; then
       cp "${progdir}/etc/default-build" build
fi
if [ '!' -r "$run" ]; then
       cp "${progdir}/etc/default-run" run
fi
从这里可以清晰地看出,最终执行没有运行时参数的run-test的宏build和run的是/tests/ect/default-build和/tests/ect/default-run(其实是/tests/ect/push-and-run-test-jar)脚本文件。其中default-build将.jar转化为.dex(解释的功能),default-run将执行push-and-run-test-jar脚本,它通过如下语句来实现dalvik的运行功能:

代码位置:/android2.1/dalvik/tests/ect/push-and-run-test-jar
源代码:
108    adb push test.jar /data
       adb push test-ex.jar /data
130    adb shell cd /data \; dalvikvm $DEX_VERIFY $DEX_OPTIMIZE $DEX_DEBUG \
          $GC_OPTS -cp test.jar "-Xint:${INTERP}" -ea Main "$@"
这里也就解释了宏build和run事实上是在一个运行android的镜像的ARM设备(device)上执行的,因为它必须要执行adb shell、adb push,必须要执行镜像根目录下的/system/bin/dalvikvm可执行文件来解析.jar,而在当前dalvikvm是基于ARM架构编译出来的,在本地(host)上是不可执行的文件。

1.3.4 测试源代码
测试代码并不是没有针对性的任意JAVA程序,其组成都有如下规律:
1、代码结构:
--src   保存了源代码
   -Main.java   执行的java代码(有点像C里面的main()函数的意思)
   -*.java    Main.java要调用的其他方法(面向对象而已)
--expect.txt   保存了android2.1的官方dalvik运行Main.java的结果
--info.txt    介绍了这个测试的内容
--src2 少数有,用于在更换了编译生成了.class文件导致的“API不匹配”情况处理
2、代码测试目标明确,分门别类地测试了参数设定、参数传递、进程管理、指针、线程、gc等等各个方面,通过查看哪个代码测试结果和expect.txt不同,可以了解到dalvik虚拟机在处理哪方面问题上有错误。

2 测试工具的使用

2.1 测试工具在ARM设备上的使用方法
2.1.1 使用条件
从1.3.3节的分析可知,本测试工具的使用目前必须有以下两个条件:
1、 有ARM架构的android设备或者本地虚拟机(?可能由--local参数决定);
2、 在Linux环境下可连接到该设备;
其中第一个条件是由/android2.1/dalvik/tests/ect/push-and-run-test-jar中的adb命令、dalvikvm可执行文件(android整体编译生成,目前TARGET-ARCH为ARM)决定的,对于将.java解释为.dex是否需要设备还没有进行测试,第二个条件是由/android2.1/dalvik/tests/下的脚本文件写法决定的,它使用了Linux shell,因此只能在Linux下执行,不能在windows下运行该脚本。

2.1.2 使用方法
根据上述条件,可以写出本测试工具的使用流程。
1、进入android2.1目录,编译android源码

cd /USERDIR/android2.1
make
编译结束后,进入/out/target/product/generic/system/bin,查看是否生成了dalvikvm,如果没有,编译错误,重新检查并编译。
2、在本地Linux环境android模拟器上测试其虚拟机(可省略,直接做第三步,但不推荐)
(1)启动模拟器

cd /out/host/linux-x86/bin      (添加了环境变量后就可以在任意目录输入emulator)
emulator
(2)进入/android2.1/dalvik/tests/目录,shell下输入:

./run-test 代码文件夹名称   测试指定文件夹的代码
./run-all-tests      测试整个tests的78个代码
即可运行本测试工具。
在本模式下可以用的参数包括—fast、--portable、--no-verify、--no-optimize和--reference,--debug和--zygote没有测试,--local、--vargrind不可用。
3、在ARM架构的android设备上测试其虚拟机
(1)连接Linux环境(VMware虚拟机、Linux操作系统等等)到外部android设备。该步方法不统一,但衡量标准是,能在Linux下敲adb shell能连接到该设备。
(2)进入/android2.1/dalvik/tests/目录,shell下输入:

./run-test 代码文件夹名称   测试指定文件夹的代码
./run-all-tests      测试整个tests的78个代码
即可运行本测试工具。

2.1.3 测试结果分析
对于任何一个测试,评判测试成功与否的标准是对比android2.1官方dalvik运行该测试代码的结果(expect.txt)和用户dalvik运行测试代码的结果(output.txt)是否相同。
如果结果相同,则测试成功,会在shell下显示

android2.1_r2/dalvik/tests/代码文件夹名称: succeeded!
如果结果不相同,则测试失败,会在shell下显示

/android2.1_r2/dalvik/tests/017-float: FAILED!
#################info
CONTENT 测试内容
#################diffs
--- expect.txt        2010-06-23 08:58:55.000000000 +0800
+++ output.txt 生成时间
CONTENT 不同的地方
#################

file left in /tmp/test-NUM 测试生成的东西
根据这些可以找出哪里不同,从/tmp/test-NUM(/是LINUX的根目录)文件夹下可以查看到dalvik运行的结果,更方便查处错误的所在。需要注意的是,不是报FAILED错就代表着dalvik有问题。例如浮点运算会和具体硬件有关,测试结果和expect.txt很有可能不同,因此如果发现错误,需要逐个分析再对dalvik功能下结论。

3 后记

         本测试工具的使用必须是在android设备运行起来、能使用adb和dalvikvm可执行文件的情况下, 对该设备的虚拟机工作功能正确性进行测试。因此,本测试应该是放在dalvik修改工作的最后进行。





原创粉丝点击