首页
社区
课程
招聘
6
[原创]Android ART分析
发表于: 2014-1-11 14:19 57255

[原创]Android ART分析

2014-1-11 14:19
57255

对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 的 f08K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6i4S2V1j5g2)9J5k6r3c8W2N6X3g2D9L8%4m8W2M7Y4y4Q4x3X3g2U0L8$3#2Q4x3V1k6S2L8X3c8J5L8$3W2V1i4K6u0r3j5h3&6V1M7X3!0A6k6q4)9J5k6o6c8Q4x3X3b7@1i4K6u0V1K9$3W2@1K9$3q4@1M7#2)9J5k6r3q4J5N6q4)9J5k6r3q4F1k6q4)9J5k6r3q4H3M7q4)9J5k6r3y4G2L8i4m8S2N6r3W2T1K9h3I4A6N6s2W2Q4x3V1j5`." target="_blank">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,更详细的解释可以参看71cK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6i4m8C8N6$3q4J5k6g2)9J5k6h3y4G2L8g2)9J5c8X3c8G2j5%4g2E0k6h3&6@1M7#2)9J5c8X3y4S2M7$3g2K6N6s2g2V1K9h3g2K6i4K6u0r3b7g2m8b7e0V1!0f1c8g2)9J5k6g2c8j5g2l9`.`." target="_blank">.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 各字段及大小

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
字段      字节数
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)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
字段             字节数  
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)
1
2
3
4
5
6
7
8
9
10
字段       字节数
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
2
3
4
5
6
7
1. if (zygote) {
 
2. runtime.start("com.android.internal.os.ZygoteInit",
 
3. startSystemServer ? "start-system-server" : "");
 
4. }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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
2
3
4
5
6
7
8
9
10
11
12
13
1. void Runtime::InitNativeMethods() {
 
2. .....
 
3. JNIEnv* env = self->GetJniEnv();
 
4. ......
 
5. RegisterRuntimeNativeMethods(env);
 
6. ......
 
7. }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
2
3
4
5
6
7
8
9
10
11
12
13
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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
2
3
1. native public static boolean isDexOptNeeded(String fileName)
  
2. throws FileNotFoundException, IOException;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
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
2
3
4
5
6
7
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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
2
3
4
5
1. int main(int argc, char** argv) {
  
2. return art::dex2oat(argc, argv);
 
3. }

[注意]看雪招聘,专注安全领域的专业人才平台!

上传的附件:
收藏
免费 6
支持
分享
赞赏记录
参与人
雪币
留言
时间
心游尘世外
为你点赞~
2024-5-31 07:27
QinBeast
为你点赞~
2024-5-31 07:18
飘零丶
为你点赞~
2024-5-31 01:51
shinratensei
为你点赞~
2024-5-31 01:36
PLEBFE
为你点赞~
2023-3-5 04:12
0x指纹
为你点赞~
2020-7-9 09:49
最新回复 (13)
雪    币: 13982
活跃值: (4976)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
我的NEXUS5开了ART感觉也没多大变化
而且兼容也还有问题。。。
楼主是用IDA调戏的?
2014-1-11 16:02
0
雪    币: 293
活跃值: (225)
能力值: (RANK:250 )
在线值:
发帖
回帖
粉丝
3
网上有相关的测评报告,确实有兼容性问题,可以看下这个http://www.xda-developers.com/android/android-4-4-kitkats-art-and-app-compatibility/,另外有一个兼容性列表http://www.androidruntime.com/list

分析的源代码,不需要IDA!
2014-1-11 17:20
0
雪    币: 13982
活跃值: (4976)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4

但列表毕竟是极少数
需要个人提交的
还以为楼主真机调试了
2014-1-11 18:42
0
雪    币: 28
活跃值: (100)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
5
第一次看见art的分析,nexus7fhd开ART变化确实不大,不过4.4更新到4.4.2之后,确实感觉流畅度高了一些,兼容性差是肯定的
2014-1-11 19:41
0
雪    币: 6
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
android4.4.2 还是有些不稳定~
2014-1-12 22:54
0
雪    币: 53
活跃值: (286)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
7
Posix.getenv native实现在:
libcore\luni\src\main\native\libcore_io_Posix.cpp
static jstring Posix_getenv(JNIEnv* env, jobject, jstring javaName) {
    ScopedUtfChars name(env, javaName);
    if (name.c_str() == NULL) {
        return NULL;
    }
    return env->NewStringUTF(getenv(name.c_str()));
}
注册在该文件底部:
void register_libcore_io_Posix(JNIEnv* env) {
    jniRegisterNativeMethods(env, "libcore/io/Posix", gMethods, NELEM(gMethods));
}
2014-1-14 10:59
0
雪    币: 293
活跃值: (225)
能力值: (RANK:250 )
在线值:
发帖
回帖
粉丝
8
Good! 多谢!
2014-1-14 21:37
0
雪    币: 105
活跃值: (226)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
9
很好很强大
2015-2-27 17:43
0
雪    币: 4
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
哈哈 ,我也是正式会员了、。。
2015-3-2 20:20
0
雪    币: 244
活跃值: (25)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
11
正在学习这部分,谢谢楼主分享
2015-3-3 11:40
0
雪    币: 168
活跃值: (32)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
很棒的帖子,谢谢楼主
2015-3-12 17:02
0
雪    币: 57
活跃值: (25)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
13
不明觉厉
2015-11-18 15:58
0
雪    币: 2700
活跃值: (63)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
nice
2020-7-9 07:22
0
游客
登录 | 注册 方可回帖
返回

账号登录
验证码登录

忘记密码?
没有账号?立即免费注册