Dalvik
Dalvik
Dalvik
Virtual Machine
cyanogen-ics$ out/host/linux-x86/bin/dalvik
E( 6983) No valid entries found in bootclasspath
'/tmp/cyanogen-ics/out/host/linux-x86/framework/core-
hostdex.jar:/tmp/cyanogen-ics/out/host/linux-
x86/framework/bouncycastle-hostdex.jar:/tmp/cyanogen-
ics/out/host/linux-x86/framework/apache-xml-
hostdex.jar' (dalvikvm)
E( 6983) VM aborting (dalvikvm)
...
out/host/linux-x86/bin/dalvik: line 28: 6983
Segmentation fault (core dumped)
ANDROID_PRINTF_LOG=tag ANDROID_LOG_TAGS=""
ANDROID_DATA=/tmp/android-data
ANDROID_ROOT=$ANDROID_BUILD_TOP/out/host/linux-x86
LD_LIBRARY_PATH=$ANDROID_BUILD_TOP/out/host/linux-x86/lib
$ANDROID_BUILD_TOP/out/host/linux-x86/bin/dalvikvm -Xbootclasspath:
$ANDROID_BUILD_TOP/out/host/linux-x86/framework/core-hostdex.jar:
$ANDROID_BUILD_TOP/out/host/linux-x86/framework/bouncycastle-
hostdex.jar: \
$ANDROID_BUILD_TOP/out/host/linux-x86/framework/apache-xml-
hostdex.jar $*
Satisfy Dalvik Runtime Dependency
cyanogen-ics$ ls /data/dalvik-cache/
tmp@cyanogen-ics@out@host@linux-x86@framework@apache-xml-
hostdex.jar@classes.dex
tmp@cyanogen-ics@out@host@linux-x86@framework@bouncycastle-
hostdex.jar@classes.dex
tmp@cyanogen-ics@out@host@linux-x86@framework@core-
hostdex.jar@classes.dex
Class
Classfile
Loader
javaframe
optop
method
Class fields
pc
others
{Variables locales }
vars
Segment
javaframe
vars
Environnement cotext
javaframe_i optop
optop_i
registres
Example: JVM
$ javac Foo.java
$ javap -v Foo
Compiled from "Foo.java"
class Foo extends java.lang.Object
...
int calc(int, int);
Code:
Stack=3, Locals=4, Args_size=3
0: iconst_2
1: iload_1
2: iload_2
3: iadd
4: imul
5: istore_3
6: iload_3
7: ireturn
Bytecode execution
c := 2 * (a + b)
• Example bytecode
– iconst 2
– iload a
– iload b
– iadd
– imul
– istore c
Example bytecode:
iconst 2
iload a a 42
iload b b 7
iadd c 0
imul 2
istore c
Computes: c := 2 * (a + b)
Example:
iconst 2
iload a a 42
iload b b 7
iadd c 0 42
imul 2
istore c
Computes: c := 2 * (a + b)
Example:
iconst 2
iload a a 42
iload b b 7 7
iadd c 0 42
imul 2
istore c
Computes: c := 2 * (a + b)
Example:
iconst 2
iload a a 42
iload b b 7
iadd c 0 49
imul 2
istore c
Computes: c := 2 * (a + b)
Example:
iconst 2
iload a a 42
iload b b 7
iadd c 0
imul 98
istore c
Computes: c := 2 * (a + b)
Example:
iconst 2
iload a a 42
iload b b 7
iadd c 98
imul
istore c
Computes: c := 2 * (a + b)
iadd in specification and implementation
③ add
value1 + value2
④ push
① pop
value2
② pop value1 +
value1 value2
case SVM_INSTRUCTION_IADD: {
/* instruction body */
jint value1 = stack[stack_size - 2].jint; ②
jint value2 = stack[--stack_size].jint; ①
stack[stack_size - 1].jint = value1 +
④ value2; ③
/* dispatch */
goto dispatch;
} Taken from SableVM
sablevm/src/libsablevm/instructions_switch.c
Example: Dalvik VM
• Instruction traslation
• one Dalvik instruction → multiple Java
instructions
Dalvik VM Execution on ARM Target
◦ Class 文件格式版本号
◦ 各部分的数量与大小
元数据
◦ 类 / 继承的超类 / 实现的接口的声明信息
◦ 域与方法声明信息
◦ 常量池
◦ 用户自定义的、 RetentionPolicy为 CLASS 或 RUNTIME 的注解
◦ —— 对应 Java 源代码中“声明”与“常量”对应的信息
方法信息
◦ 字节码
◦ 异常处理器表
◦ 操作数栈与局部变量区大小
◦ 操作数栈的类型记录( StackMapTable , Java 6 开始)
◦ 调试用符号信息(如 LineNumberTable 、 LocalVariableTable )
◦ —— 对应 Java 源代码中“语句”与“表达式”对应的信息
输出调试符号信息
编译 Java 源码
javac -g Foo.java
public Foo();
Signature: ()V
LineNumberTable:
方法 line 2: 0
元数据
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this LFoo;
Code:
字节码 Stack=1, Locals=1, Args_size=1
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
Class 文件例子
public void bar();
Signature: ()V
LineNumberTable:
line 4: 0
line 5: 3
line 6: 7
line 8: 10
LocalVariableTable:
方法 Start Length Slot Name
元数据 Signature
10 0 2 j I
0 11 0 this Java 6 开始,有分支
LFoo; 控制流的方法会带有
3 8 1 i I StackMapTable,记
录每个基本块开头处
StackMapTable: number_of_entries = 1
frame_type = 252 /* append */
操作数栈的类型状态
offset_delta = 10
locals = [ int ]
Code:
Stack=1, Locals=3, Args_size=1
0: bipush 31
字节码 2: istore_1
3: iload_1
4: ifle 10
7: bipush 42
9: istore_2
10: return
基于栈与基于寄存器的体系结构的区别
public class Demo {
public static void foo() {
int a = 1;
int b = 2;
int c = (a + b) * 5;
}
}
Decode excute
hello.class “Data” Section (Number)
DX Decode
(Compiler)
“Text” Section Fetch PC fetch
Class Definition:
Access flags
Class names
Data:
Method code
Info related to methods
Variables
Dalvik Architecture
• Register architecture
• 216 available registers
• Instruction set has 218 opcodes
– JVM: 200 opcodes
• 30% fewer instructions, but 35% larger code size
(bytes) compared to JVM
Constant Pool
• Dalvik
– Single pool
– dx eliminates some constants by inlining their
values directly into the bytecode
• JVM
– Multiple
Primitive Types
0: bipush 18
2: newarray char
4: dup
|0000: const/16 v0, #int 18
5: iconst_0 |0002: new-array v0, v0, [C
6: bipush 65 |0004: fill-array-data v0,
8: castore 0000000a
... |0007: sput-object v0,
101: bipush 17 LDemo;.DATA:[C
|0009: return-void
103: bipush 100 |000a: array-data (22 units)
105: castore
106: putstatic #2; // DATA
109: return
Shared constant pool
• Zapper.java
public interface Zapper {
public String zap(String s, Object o);
}
public class Blort implements Zapper {
public String zap(String s, Object o) { … }
}
public class ZapUser {
public void useZap(Zapper z) { z.zap(...); }
}
Shared constant pool
Shared constant pool
Shared constant pool (memory usage)
• minimal repetition
• per-type pools (implicit typing)
• implicit labeling
public static long sumArray(int[] arr) {
long sum = 0;
for (int i : arr) {
sum += i;
}
return sum;
Java class
}
public static long sumArray(int[] arr) {
long sum = 0;
for (int i : arr) { bytes dispatches reads writes
sum += i;
}
.class 25 14 45 16
return sum; .dex 18 6 19 6
}
Dalvik DEX
Comparison between Dalvik VM and JVM
• Reliability Comparison
• Multiple instance and JIT Comparison
• Concurrent GC
AST to Bytecode
Java source
double return_a_double(int a) {
if (a != 1)
return 2.5;
else
return 1.2;
}
DEX Bytecode
double return_a_double(int)
0: const/4 v0,1
1: if-eq v3,v0,6
3: const-wide/high16 v0,16388
5: return-wide v0
6: const-wide v0,4608083138725491507
11: goto 5
public class ZZZZ {
private int value;
public void foo() {
int v = this.value;
}
}
Java source …
2a /* aload_0 */
javac b40002 /* getfield #2; //Field value:I */
3c /* istore_1 */
…
Classfile
JVM …
Method foo()V
Host …
instructions dcd00100 /* fast_iaccess_0 #1 */
3c /* istore_1 */
…
…
8b4108 ; mov eax,dword ptr ds:[ecx+8]
…
Efficient Interpreter in Android
After:
+invoke-virtual-quick {v0, v1}, [002c] // vtable #002c
• When to compile
– install time, launch time, method invoke time, instruction
fetch time
• What to compile
– whole program, shared library, page, method, trace, single
instruction
• Android needs a combination that meet the needs of a mobile
– Minimal additional memory usage
– Coexist with Dalvik’s container-based security model
– Quick delivery of performance boost
– Smooth transition between interpretation & compiled code
Android system_server example
Source: Google I/O 2010 - A JIT Compiler for Android's Dalvik VM
• Compiled Code takes up memory - want the benefits of JIT with small memory footprint
• Small amount compilation provides a big benefit
• In test program, 4.5MB of byte code - 8% of methods: 390K was hot; 25% of code in
methods was hot - so 2% in the end
• 90% of time in 10% of the code may be generous
Trace JIT
apkbuilder -u
Source
Source code
code
Create unsigned apk
unsigned
unsigned apk
apk
Libraries
Libraries
adb
Key
Key Publish or
Sign apk signed
signed apk
apk Test 87
jarsigner
APK content
$ unzip Angry+Birds.apk
Archive: Angry+Birds.apk
...
inflating: AndroidManifest.xml
extracting: resources.arsc
extracting: res/drawable-hdpi/icon.png
extracting: res/drawable-ldpi/icon.png
extracting: res/drawable-mdpi/icon.png
inflating: classes.dex Dalvik DEX
inflating: lib/armeabi/libangrybirds.so JNI
inflating: lib/armeabi-v7a/libangrybirds.so
inflating: META-INF/MANIFEST.MF
inflating: META-INF/CERT.SF
manifest +
inflating: META-INF/CERT.RSA signature
APK content
$ unzip Angry+Birds.apk
Archive: Angry+Birds.apk
...
inflating: AndroidManifest.xml
Name: extracting:
classes.dex resources.arsc
extracting: res/drawable-hdpi/icon.png
SHA1-Digest: I9Vne//i/5Wyzs5HhBVu9dIoHDY=
extracting: res/drawable-ldpi/icon.png
Name: lib/armeabi/libangrybirds.so
extracting:
SHA1-Digest: res/drawable-mdpi/icon.png
pSdb9FYauyfjDUxM8L6JDmQk4qQ=
inflating: classes.dex
inflating: lib/armeabi/libangrybirds.so
inflating: lib/armeabi-v7a/libangrybirds.so
inflating: META-INF/MANIFEST.MF
inflating: META-INF/CERT.SF
inflating: META-INF/CERT.RSA
AndroidManifest
$ unzip Angry+Birds.apk
Archive: Angry+Birds.apk
...
...
inflating: AndroidManifest.xml
extracting: resources.arsc
extracting: res/drawable-hdpi/icon.png
$ file AndroidManifest.xml
extracting: res/drawable-ldpi/icon.png
AndroidManifest.xml: DBase 3 data file (2328 records)
extracting: res/drawable-mdpi/icon.png
$ apktool d ../AngryBirds/Angry+Birds.apk
inflating: classes.dex
I: Baksmaling...
inflating:
I: Loading resource lib/armeabi/libangrybirds.so
table...
...
inflating:
I: Decoding lib/armeabi-v7a/libangrybirds.so
file-resources...
inflating:
I: Decoding META-INF/MANIFEST.MF
values*/* XMLs...
I: Done.
inflating: META-INF/CERT.SF
I: Copying assets and libs...
$ fileinflating: META-INF/CERT.RSA
Angry+Birds/AndroidManifest.xml
Angry+Birds/AndroidManifest.xml: XML document text
Use JDB to Trace Android Application
#!/bin/bash
adb wait-for-device
adb shell am start \
-e debug true \
-a android.intent.action.MAIN \
-c android.intent.category.LAUNCHER \
-n org.jfedor.frozenbubble/.FrozenBubble &
debug_port=$(adb jdwp | tail -1);
adb forward tcp:29882 jdwp:$debug_port &
jdb -J-Duser.home=. -connect \
com.sun.jdi.SocketAttach:hostname=localhost,port=29882 &
• http://code.google.com/p/smali/
• smali: The assembler
• baksmali: The disassembler
• Fully integrated in apktool
$ apktool d ../AngryBirds/Angry+Birds.apk
I: Baksmaling...
I: Loading resource table...
...
I: Decoding fileresources...
I: Decoding values*/* XMLs...
I: Done.
I: Copying assets and libs...
Disassembly
$ mkdir workspace smalisrc
$ cd workspace
$ unzip ../FrozenBubbleorig.apk
Archive: ../FrozenBubbleorig.apk
inflating: METAINF/MANIFEST.MF
inflating: METAINF/CERT.SF
inflating: METAINF/CERT.RSA
inflating: AndroidManifest.xml
...
extracting: resources.arsc
$ bin/baksmali o smalisrc workspace/classes.dex
Output
org.jfedor.frozenbubble/.FrozenBubble
smalisrc$ find
./org/jfedor/frozenbubble/FrozenBubble.smali
./org/jfedor/frozenbubble/R$id.smali
./org/jfedor/frozenbubble/GameView.smali
./org/jfedor/frozenbubble/SoundManager.smali
./org/jfedor/frozenbubble/LaunchBubbleSprite.smali
./org/jfedor/frozenbubble/Compressor.smali
./org/jfedor/frozenbubble/R$attr.smali
./org/jfedor/frozenbubble/BubbleFont.smali
./org/jfedor/frozenbubble/PenguinSprite.smali
./org/jfedor/frozenbubble/GameView$GameThread.smali
./org/jfedor/frozenbubble/LevelManager.smali
./org/jfedor/frozenbubble/BubbleSprite.smali
./org/jfedor/frozenbubble/R$string.smali
...
Generated
from resources
Dexmaker: bytecode generator
http://code.google.com/p/dexmaker/
• A Java-language API for doing compile time or
runtime code generation targeting the Dalvik VM.
Unlike cglib or ASM, this library creates Dalvik .dex
files instead of Java .class files.
• It has a small, close-to-the-metal API. This API
mirrors the Dalvik bytecode specification giving you
tight control over the bytecode emitted.
• Code is generated instruction-by-instruction; you
bring your own abstract syntax tree if you need one.
And since it uses Dalvik's dx tool as a backend, you
get efficient register allocation and regular/wide
instruction selection for free.
Reference