对Android ART的分析,主要包括ART Runtime启动过程以及dex2oat的分析。
由于代码量较多,忽略了很多细节,所以分析过程会存在错误;ART Runtime采用单例模式,启动过程中参数解析实例化会对后续dex2oat的分析有所影响,但是我在分析过程中没有去特别关注每个参数,有兴趣的可以自行分析!另外ART Runtime还可以继续深入分析!
BTW,附件中是分析中使用的javax.obex.jar以及转换后的OAT文件!Android ART 分析
MindMac
2014/1/11
Google 在 Android4.4 中新增加了 ART(Android Run Time)用来替代之前的 Dalvik,关于 ART
的基本知识可以参考 Google 官方的 Introduction ,XDA 的 Android 4.4 KitKat’s ART and App
Compatibility 以及 Android Police 对 ART 的相关介绍 。在 Settings->Developer options 中可以选
择运行时环境,默认为 Dalvik,可以选择 ART,改变运行时环境后系统会重新启动,如图 1。图 1 Android4.4 选择 ART 运行环境
与 Dalvik 不同的是,ART 不再使用 DEX 文件,而是 OAT 格式的文件,所以在重启过程中,系
统会完成从 DEX 到 OAT 格式的转换。本文主要分析 Android4.4 中 DEX 到 OAT 的转换过程。ZIP 文件结构
在开始分析 Android ART 之前有必要先介绍下 ZIP 文件的格式。关于 ZIP 文件的结构可以
参考 The Great Android Security Hole Of ’08 ? – Part One: ZIP Files ,更详细的解释可以参看.ZIP
File Format Specification 。
一个 ZIP 文件的基本结构如图 2 所示。No.1 到 No.n 分别代表了 ZIP 压缩文件中的文件,
n 表示所有的文件个数(包含文件目录)。新建一个 hello 文件夹,并在其下创建两个名为
helloone.txt 和 hello2.txt 的文件,其中内容分别为 contentone 和 contenttwo,将 hello 文件夹
压缩为 hello.zip 文件,以便后面的分析。图 2 ZIP 文件基本结构 Local File Header
Local File Header 的结构如表 1 所示。其中 local file header signature 值固定为 0x04034b50。
使用 010Editor 打开,并应用 ZIP 模板,hellotwo.txt 文件的 Local File Header 如图 3 所示,由
于没有 extra 内容,因此 extra field length 为 0 且没有 extra field 字段。另外要注意的是,
hellotwo.txt 的 Local File Header 起始地址是 0x39,也就是 57,如图 4 所示。表 1 Local File Header 各字段及大小
字段 字节数
local file header signature 4
version needed to extract 2
general purpose bit flag 2
compression method 2
last mod file time 2
last mod file date 2
crc-32 4
compressed size 4
uncompressed size 4
file name length 2
extra filed length 2
file name 可变长度(size of file name)
extra filed 可变长度(size of file name)
字段 字节数
central file header signature 4
version made by 2
version needed to extract 2
general purpose bit flag 2
compression method 2
last mod file time 2
last mod file date 2
crc-32 4
compressed size 4
uncompressed size 4
file name length 2
extra field length 2
file comment length 2
disk number start 2
internal file attribute 2
external file attributes 4
relative offset of local header 4
file name 可变长度(size of file name)
extra field 可变长度(size of file name)
file comment 可变长度(size of file name)
字段 字节数
end of central directory signature 4
number of this disk 2
number of the disk with the start of the central directory 2
total number of entries in the central directory on this disk 2
total number of entries in the central directory 2
size of the central directory 4
offset of start of central directory 4
ZIP file comment length 2
ZIP file comment 可变长度
1. if (zygote) {
2. runtime.start("com.android.internal.os.ZygoteInit",
3. startSystemServer ? "start-system-server" : "");
4. }
1. void AndroidRuntime::start(const char* className, const char* options)
2. {
3. ......
4. JniInvocation jni_invocation;
5. jni_invocation.Init(NULL);
6. JNIEnv* env;
7. if (startVm(&mJavaVM, &env) != 0) {
8. return;
9. }
10. ......
11. }
1. bool JniInvocation::Init(const char* library) {
2. #ifdef HAVE_ANDROID_OS
3. char default_library[PROPERTY_VALUE_MAX];
4. property_get("persist.sys.dalvik.vm.lib", default_library, "libdvm.so");
5. #else
6. const char* default_library = "libdvm.so";
7. #endif
8. if (library == NULL) {
9. library = default_library;
10. }
11. handle_ = dlopen(library, RTLD_NOW);
12. ......
13. if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetDefaultJavaVMInitArgs_),
14. "JNI_GetDefaultJavaVMInitArgs")) {
15. return false;
16. }
17. if (!FindSymbol(reinterpret_cast<void**>(&JNI_CreateJavaVM_),
18. "JNI_CreateJavaVM")) {
19. return false;
20. }
21. if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetCreatedJavaVMs_),
22. "JNI_GetCreatedJavaVMs")) {
23. return false;
24. }
25. return true;
26. }
1. extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
2. const JavaVMInitArgs* args = static_cast<JavaVMInitArgs*>(vm_args);
3. ......
4. Runtime::Options options;
5. for (int i = 0; i < args->nOptions; ++i) {
6. JavaVMOption* option = &args->options[i];
7. options.push_back(std::make_pair(std::string(option->optionString),
option->extraInfo));
8. }
9. bool ignore_unrecognized = args->ignoreUnrecognized;
10. if (!Runtime::Create(options, ignore_unrecognized)) {
11. return JNI_ERR;
12. }
13. Runtime* runtime = Runtime::Current();
14. bool started = runtime->Start();
15. .....
16. return JNI_OK;
17. }
1. bool Runtime::Create(const Options& options, bool ignore_unrecognized) {
2. ......
3. InitLogging(NULL);
4. instance_ = new Runtime;
5. if (!instance_->Init(options, ignore_unrecognized)) {
6. .....
7. return false;
8. }
9. return true;
10. }
1. bool Runtime::Start() {
2. ......
3. Thread* self = Thread::Current();
4. self->TransitionFromRunnableToSuspended(kNative);
5. started_ = true;
6. InitNativeMethods();
7. ......
8. if (is_zygote_) {
9. if (!InitZygote()) {
10. return false;
11. }
12. } else {
13. DidForkFromZygote();
14. }
15. StartDaemonThreads();
16. ......
17. return true;
18. }
1. void Runtime::InitNativeMethods() {
2. .....
3. JNIEnv* env = self->GetJniEnv();
4. ......
5. RegisterRuntimeNativeMethods(env);
6. ......
7. }
1. public void initAndLoop(){
2. ......
3. Slog.i(TAG, "Waiting for installd to be ready.");
4. installer = new Installer();
5. installer.ping();
6. ......
7. pm = PackageManagerService.main(context, installer,
8. actoryTest != SystemServer.FACTORY_TEST_OFF, onlyCore);
9. ......
10. }
1. public static final IPackageManager main(Context context, Installer installer,
2. boolean factoryTest, boolean onlyCore) {
3. PackageManagerService m = new PackageManagerService(context, installer,
4. factoryTest, onlyCore);
5. ServiceManager.addService("package", m);
6. return m;
7. }
1. public PackageManagerService(Context context, Installer installer,
2. boolean factoryTest, boolean onlyCore) {
3. ......
4. mInstaller = installer;
5. ......
6. if (mSharedLibraries.size() > 0) {
7. Iterator<SharedLibraryEntry> libs = mSharedLibraries.values().iterator();
8. while (libs.hasNext()) {
9. String lib = libs.next().path;
10. ......
11. try {
12. if (dalvik.system.DexFile.isDexOptNeeded(lib)) {
13. alreadyDexOpted.add(lib);
14. mInstaller.dexopt(lib, Process.SYSTEM_UID, true);
15. didDexOpt = true;
16. }
18. }
19. }
20. }
21. ......
22. }
1. native public static boolean isDexOptNeeded(String fileName)
2. throws FileNotFoundException, IOException;
1. static jboolean DexFile_isDexOptNeeded(JNIEnv* env, jclass, jstring javaFilename)
{
2. ......
3. ScopedUtfChars filename(env, javaFilename);
4. ......
5. Runtime* runtime = Runtime::Current();
6. ClassLinker* class_linker = runtime->GetClassLinker();
7. const std::vector<const DexFile*>& boot_class_path = class_linker ->
GetBootClassPath();
8. for (size_t i = 0; i < boot_class_path.size(); i++) {
9. if (boot_class_path[i]->GetLocation() == filename.c_str()) {
10. return JNI_FALSE;
11. }
12. }
13. ......
14. std::string cache_location(GetDalvikCacheFilenameOrDie(filename.c_str()));
15. oat_file.reset(OatFile::Open(cache_location, filename.c_str(), NULL, false));
16. if (oat_file.get() == NULL) {
17. LOG(INFO) << "DexFile_isDexOptNeeded cache file " << cache_location
18. << " does not exist for " << filename.c_str();
19. return JNI_TRUE;
20. }
21. ......
22. }
1. public int dexopt(String apkPath, int uid, boolean isPublic) {
2. StringBuilder builder = new StringBuilder("dexopt");
3. builder.append(' ');
4. builder.append(apkPath);
5. builder.append(' ');
6. builder.append(uid);
7. builder.append(isPublic ? " 1" : " 0");
8. return execute(builder.toString());
9. }
1. private int execute(String cmd) {
2. String res = transaction(cmd);
3. try {
4. return Integer.parseInt(res);
5. } catch (NumberFormatException ex) {
6. return -1;
7. }
8. }
1. private synchronized String transaction(String cmd) {
2.if (!connect()) {
3. Slog.e(TAG, "connection failed");
4. return "-1";
5. }
6. if (!writeCommand(cmd)) {
7. Slog.e(TAG, "write command failed? reconnect!");
8. if (!connect() || !writeCommand(cmd)) {
9. return "-1";
10. }
11. }
12. ......
13. }
1. int main(const int argc, const char *argv[]) {
2. ......
3. for (;;) {
4. alen = sizeof(addr);
5. s = accept(lsocket, &addr, &alen);
6. ......
7. ALOGI("new connection\n");
8. for (;;) {
9. unsigned short count;
10. if (readx(s, &count, sizeof(count))) {
11. ALOGE("failed to read size\n");
12. break;
13. }
14. if ((count < 1) || (count >= BUFFER_MAX)) {
15. ALOGE("invalid size %d\n", count);
16. break;
17. }
18. if (readx(s, buf, count)) {
19. ALOGE("failed to read command\n");
20. break;
21. }
22. buf[count] = 0;
23. if (execute(s, buf)) break;
24. }
25. ALOGI("closing connection\n");
26. close(s);
27. }
28.
29. return 0;
30. }
1. static int do_dexopt(char **arg, char reply[REPLY_MAX])
2. {
3.return dexopt(arg[0], atoi(arg[1]), atoi(arg[2]));
4. }
1. int dexopt(const char *apk_path, uid_t uid, int is_public)
2. {
3. struct utimbuf ut;
4. struct stat apk_stat, dex_stat;
5. char out_path[PKG_PATH_MAX];
6. char dexopt_flags[PROPERTY_VALUE_MAX];
7. char persist_sys_dalvik_vm_lib[PROPERTY_VALUE_MAX];
8. char *end;
9. int res, zip_fd=-1, out_fd=-1;
10. if (strlen(apk_path) >= (PKG_PATH_MAX - 8)) {
11. return -1;
12. }
13. property_get("persist.sys.dalvik.vm.lib", persist_sys_dalvik_vm_lib,
"libdvm.so");
14. sprintf(out_path, "%s%s", apk_path, ".odex");
15. if (stat(out_path, &dex_stat) == 0) {
16. return 0;
17. }
18. if (create_cache_path(out_path, apk_path)) {
19. return -1;
20. }
21. ......
22. pid_t pid;
23. pid = fork();
24. if (pid == 0) {
25. ......
26. if (strncmp(persist_sys_dalvik_vm_lib, "libdvm", 6) == 0) {
27. run_dexopt(zip_fd, out_fd, apk_path, out_path, dexopt_flags);
28. } else if (strncmp(persist_sys_dalvik_vm_lib, "libart", 6) == 0) {
29. run_dex2oat(zip_fd, out_fd, apk_path, out_path, dexopt_flags);
30. } else {
31. exit(69); /* Unexpected persist.sys.dalvik.vm.lib value */
32. }
33. exit(68); /* only get here on exec failure */
34. }
35. ......
36. }
1. static void run_dex2oat(int zip_fd, int oat_fd, const char* input_file_name,
2. const char* output_file_name, const char* dexopt_flags)
3. {
4. static const char* DEX2OAT_BIN = "/system/bin/dex2oat";
5. static const int MAX_INT_LEN = 12;
6. char zip_fd_arg[strlen("--zip-fd=") + MAX_INT_LEN];
7. char zip_location_arg[strlen("--zip-location=") + PKG_PATH_MAX];
8. char oat_fd_arg[strlen("--oat-fd=") + MAX_INT_LEN];
9. char oat_location_arg[strlen("--oat-name=") + PKG_PATH_MAX];
10.
11. sprintf(zip_fd_arg, "--zip-fd=%d", zip_fd);
12. sprintf(zip_location_arg, "--zip-location=%s", input_file_name);
13. sprintf(oat_fd_arg, "--oat-fd=%d", oat_fd);
14. sprintf(oat_location_arg, "--oat-location=%s", output_file_name);
15. execl(DEX2OAT_BIN, DEX2OAT_BIN,
16. zip_fd_arg, zip_location_arg,
17. oat_fd_arg, oat_location_arg,
18. (char*) NULL);
19. }
1. int main(int argc, char** argv) {
2. return art::dex2oat(argc, argv);
3. }
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
上传的附件: