【Android Dalvik虚拟机探索之路系列】之一:Dalvik虚拟机简介

来源:互联网 发布:linux vim安装包 编辑:程序博客网 时间:2024/06/06 05:38

作者:郭嘉
邮箱:allenwells@163.com
博客:http://blog.csdn.net/allenwells
github:https://github.com/AllenWells

【Android SDK程序逆向分析与破解系列】章节索引

【Android SDK程序逆向分析与破解系列】之一:Android安装程序APK分析
【Android SDK程序逆向分析与破解系列】之二:Android可执行程序DEX分析(一)
【Android SDK程序逆向分析与破解系列】之三:Android可执行程序DEX分析(二)
【Android SDK程序逆向分析与破解系列】之四:Android可执行程序ODEX分析
【Android SDK程序逆向分析与破解系列】之五:Android APK的静态分析

一 Dalvik虚拟机的特点

Android Dalvik虚拟机出自于Dan Bomstein之手,它作为Android平台的核心组件,具有以下几个方面的特点。

  • 体积小,占用内存空间小;
  • 专有的DEX可执行文件,体积更小,执行速度更快;
  • 常量池采用32位索引值,寻址类方法名、字段名和常量更快;
  • 基于寄存器架构,并拥有一套完整的指令系统;
  • 提供了对象的生命周期管理、堆栈管理、安全管理和异常管理以及垃圾回收等重要功能
  • 所有的Android程序都运行在Android的系统进程里,每个进程对应着一个Dalvik虚拟机实例。

二 Dalvik虚拟机和Java虚拟机的区别

1 Dalvik虚拟机运行的是Dalvik字节码,Java虚拟机运行的是Java字节码。

2 Dalvik虚拟机基于寄存器,指令执行较快,但是需要更多的指令缓冲,指令更易失效。Java虚拟机基于,指令指令缓冲空间小,但执行相对较慢,需要耗费更多的CPU时间。

3 Dalvik虚拟机使用dex格式打包类文件,各个类中重复的字符串可以只保存一次,更加节省空间。Java虚拟机使用class格式打包类文件。
Android SDK使用DX工具将Java字节码转换为Dalvik字节码,生成DEX文件,常见的优化如下所示:

  • 将get/put指令中的field index转换为byte offset – 加快实例成员变量访问速度。
  • 将boolean/byte/char/short变种的get/put指令统一转换为32位的get/put指令 – 减小VM解释器的大小,从而更有效地利用CPU的i-cache。
  • 将高频调用的函数,例如String.length,转换为inline函数 – 消除函数调用开销。
  • 移除空函数,例如Object. -消除空函数调用。
  • 将可以预先计算的数据进行预处理,例如预先生成VM根据class name查询class的hash table – 节省Dex文件加载时间以及内存占用空间。

jar文件转换为DEX文件的过程如下图所示:

这里写图片描述

三 Dalvik虚拟机启动和执行程序的流程

  1. Android系统启动并加载内核;
  2. 执行init进程,init进程进行设备初始化工作,然后读取inic.rc文件并启动系统中重要的外部程序Zygote;
  3. Zygote启动后,首先初始化Dalvik虚拟机,然后启动system_server并进入Zygote模式,通过socke等候命令。
  4. 当执行Android程序时,system_server进程通过Binder IPC方式发送命令给Zygote,Zygote收到命令后通过fork自身创建一个Dalvik虚拟机实例来执行应用程序入口函数。当fork成功后,执行工作就由Dalvik虚拟机来完成。

Zygote启动流程如下图所示:

这里写图片描述

Dalvik执行程序流程

  1. 虚拟机线程
  2. 装载程序类,由loadClassFromDex()函数完成,解析成功的类会拥有一个ClassObject类型的数据存储在运行时环境中,Dalvik虚拟机使用gDvm.loadedClasses()全局哈希表来存储与查询装载进来的类;
  3. 验证字节码,由dvmVerifyCodeFlow()函数对装入的代码进程校验;
  4. 查找主类,由FindClass()函数查找并装载main()方法类;
  5. 执行字节码流,由dvmInterpre()函数来初始化解析器并执行字节码流。

Zygote提供了三种创建进程的方法:

  • fork(),创建一个Zygote进程,该方式不常用。
  • forkAndSpecialize(),创建一个非Zygote进程。
  • forkSystemService(),创建一个系统服务进程。

四 Dalvik虚拟机的即时编译

即时编译(Just in time Compilation),又称动态编译,是一种运行时将字节码翻译成机器码的技术。
JIT包含两种编译方式:

  • method方式:这个很好理解,就是以函数或方法为单位进行编译。
  • trace方式:程序在真正执行的时候很少会顺序执行,因此会分为,冷路径:不经常被执行的路径。热路径:经常被执行的路径。所谓trace方式编译,就是可以快速获取热路径代码,使用更短的时间和更少的内存来编译代码。

Dalvik虚拟机默认使用trace方式编译代码,同时也保留了method方式。

    -
0 0