1.Dalvik虚拟机
1.1Dalvik虚拟机特点
体积小;
专有DEX(Dalvik Executable)可执行文件格式;
常量池采用32位索引值,对类方法名,字段名,常量的寻址快;
基于寄存器架构;
1.2Dalvik虚拟机与Java虚拟机的区别
1.运行的字节码不同
Java通过编译,生成java字节码保存在class文件中;所有Dalvik字节码都由java字节码转化而来,并打包到一个dex可执行文件中。
2.Dalvik可执行文件的体积更小
dx能够重新排列java类文件,去除其中的冗余信息。
3.虚拟机架构不同
jvm是基于栈架构的,dalvik基于寄存器架构
测试代码:
public class Hello {
public int foo(int a, int b){
return (a+b)*(a-b);
}
public static void main(String[] args) {
Hello hello = new Hello();
System.out.println(hello.foo(5, 3));
}
}
保存为Hello.java,用javac编译得到Hello.class文件。
注:指定JDK版本低于7(对应1.7)才可用dx命令,
javac -source 1.7 -target 1.7 Hello.java
使用dx将class文件生成dex文件。
注:dx,dexdump均位于android SDK的platform-tools目录下,将此目录添加到环境变量中即可;
如果dx命令失败,可能是前面代码中自动加了包名,将其删去就好,或者直接复制上面代码保存。
dx --dex --output=Hello.dex Hello.class
使用javap反编译Hello.class
javap -c -classpath .Hello
得到如下代码:
public class Hello {
public Hello();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public int foo(int, int);
Code:
0: iload_1
1: iload_2
2: iadd
3: iload_1
4: iload_2
5: isub
6: imul
7: ireturn
......
可以看出foo函数占8字节,每条指令一字节且没有参数。对java程序来说,每个线程执行时都有一个PC计数器和java栈。
iload_1:i是指令前缀,表示类型为int;load表示将局部变量存入Java栈;1表示是哪个局部变量。索引值从0开始计数。
isub:表示从栈顶弹出两个int类型的值并求他们的差,并把结果压回栈顶。
用dexdump查看Dalvik字节码
dexdump -d Hello.dex
Virtual methods -
#0 : (in LHello;)
name : 'foo'
type : '(II)I'
access : 0x0001 (PUBLIC)
code -
registers : 5
ins : 3
outs : 0
insns size : 6 16-bit code units
000198: |[000198] Hello.foo:(II)I
0001a8: 9000 0304 |0000: add-int v0, v3, v4
0001ac: 9101 0304 |0002: sub-int v1, v3, v4
0001b0: b210 |0004: mul-int/2addr v0, v1
0001b2: 0f00 |0005: return v0
catches : (none)
positions :
0x0000 line=4
locals :
0x0000 - 0x0006 reg=2 this LHello;
source_file_idx : 1 (Hello.java)
Dalvik字节码只用四条指令即可完成操作,
第一条指令是将v3,v4相加,结果存到v0寄存器中,add是加,int表明是整数类型。
mul-int/2addr v0, v1:表示将v0,v1寄存器的值相乘,结果保存到v0寄存器中。
Dalvik虚拟机运行时也为每个线程维护了一个PC计数器和一个调用栈,但是这个调用栈维护了一个寄存器列表。
1.3虚拟机的执行流程
Android启动流程:
1、启动电源,引导芯片代码执行。加载BootLoader程序到RAM中执行。
2、在系统文件中寻找init.rc文件,并启动init进程。init进程是Android系统中用户空间的第一个进程,进程号为1。
3、init启动Zygote进程。Zygote创建Java虚拟机并注册JNI方法,创建服务端Socket,启动SystemServer进程。
4、SystemServer启动Binder线程池和SystemServiceManager,并启动各种线程服务。
5、被SystemServer启动的AMS(ActivityManagerService)会启动Launcher,Launcher会将已安装应用的图标显示到界面上。
Zygote有三种创建进程的方法:
fork():创建一个Zygote进程(实际上不被调用)
forkAndSpecialize():创建一个非Zygote进程
forkSystemServer():创建一个SystemServer进程
参考书目:《Android软件安全权威指南》《Android进阶解密》