android8-0-0源码分析-art的启动

前言

2014年6月25日,Android L-5.0 正式亮相于召开的谷歌I/O大会,Android L 改动幅度较大,谷歌将直接删除Dalvik,代替它的是传闻已久的ART。

安装后:data/data放应用私有数据,data/app放apk、lib、oat(vdex\odex\art 文件魔数为vdex、elf、art)
date/dalvik-cache放虚拟机执行码的(vdex\oat\art)

旧的优化叫dexopt,现安装时调用/system/bin/dex2oat(8.1.0下存在)编译

无论是对dex字节码进行优化,还是将dex字节码翻译成本地机器码,最终得到的结果都是保存在相同名称的一个odex文件里面的,但是前者对应的是一个dey文件(表示这是一个优化过的dex),后者对应的是一个oat文件(实际上是一个自定义的elf文件,里面包含的都是本地机器指令)。

应用程序的安装发生在两个时机,第一个时机是系统启动的时候,第二个时机系统启动完成后用户自行安装的时候。在第一个时机中,系统除了会对/system/app和/data/app目录下的所有APK进行dex字节码到本地机器码的翻译之外,还会对/system/framework目录下的APK或者JAR文件,以及这些APK所引用的外部JAR,进行dex字节码到本地机器码的翻译。这些都挂载在存储中了。

在ART中,打包在APK里面的Dex字节码是通过LLVM翻译成本地机器指令的–现在的加固也需要研究这个。

oat结构:

加了俩个段oatdata和oatexec,分别用来储存原来打包在APK里面的dex文件和翻译这个dex文件里面的类方法得到本地机器指令。
动态段(dymanic section,用于以数组指向动态连接器所需信息,该段在程序头表与节头表中都有指向)中添加了三个符号oatdata、oatexec和oatlastword分别用来描述oatdata和oatexec段加段到内存后的起止地址。
在oatdata段中,包含了两个重要的信息,一个信息是原来的classes.dex文件的完整内容,另一个信息引导ART找到classes.dex文件里面的类方法所对应的本地机器指令,这些本地机器指令就保存在oatexec段中。
可见oat中含有完整的dex文件。

我们在classes.dex文件中有一个类A,那么当我们知道类A的名字后,就可以通过保存在oatdata段的dex文件得到类A的所有信息,比如它的父类、成员变量和成员函数等。另一方面,类A在oatdata段中有一个对应的OatClass结构体。这个OatClass结构体描述了类A的每一个方法所对应的本地机器指令在oatexec段的位置。也就是说,当我们知道一个类及其某一个方法的名字(签名)之后,就可以通过oatdata段的dex文件内容和OatClass结构体找到其在oatexec段的本地机器指令,这样就可以执行这个类方法了。

art加载运行壳时是加载优化后的oat代码,但壳用classloader加载dex时会为其生成oat文件,可能会破坏处理的dex,hook掉可以运行dex但会慢,所以为了提升速度不会阻止dex优化为oat,也就是说原dex尽力保留了,因此采用大块的native化进行加固!

art虚拟机的启动

先记住一张图…要不然看代码经常会忘了在哪…..

接下来按着这个图上的标号分析

1.main

这个就是之前分析过的http://xn–74q78i15hxv3arigm4e.cn/2018/09/21/android8-0-0%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90-zygote%E7%9A%84%E5%90%AF%E5%8A%A8/
中init进程所调用的android启动函数

2.start

之前的runtime.start

3.jni_invocation.Init

加载libart.so导出其接口

4.AppRuntime.startVm

startVm(&mJavaVM, &env, zygote)
经过参数设置调用JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs)
JNI_CreateJavaVM就是之前虚拟机导出的三个接口之一

5/6.JNI_CreateJavaVM

经过一层JniInvocation类内调用后,8.0的实现位于art\runtime\java_vm_ext.cc

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
// JNI Invocation interface.
extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
ScopedTrace trace(__FUNCTION__);
const JavaVMInitArgs* args = static_cast<JavaVMInitArgs*>(vm_args);//vm_args转换为一个JavaVMInitArgs对象
if (JavaVMExt::IsBadJniVersion(args->version)) {
LOG(ERROR) << "Bad JNI version passed to CreateJavaVM: " << args->version;
return JNI_EVERSION;
}
RuntimeOptions options; //按照Key-Value的组织形式保存一个Options向量
for (int i = 0; i < args->nOptions; ++i) {
JavaVMOption* option = &args->options[i];
options.push_back(std::make_pair(std::string(option->optionString), option->extraInfo));
}
bool ignore_unrecognized = args->ignoreUnrecognized;
//Runtime静态函数create在进程中创建一个虚拟机,c++对静态属性、函数用类名操作用的是::
if (!Runtime::Create(options, ignore_unrecognized)) {
return JNI_ERR;
}
// Initialize native loader. This step makes sure we have
// everything set up before we start using JNI.
android::InitializeNativeLoader();
Runtime* runtime = Runtime::Current(); //获取当前Runtime,Current:当前
bool started = runtime->Start();//启动虚拟机
if (!started) {
delete Thread::Current()->GetJniEnv();
delete runtime->GetJavaVM();
LOG(WARNING) << "CreateJavaVM failed";
return JNI_ERR;
}
*p_env = Thread::Current()->GetJniEnv();
*p_vm = runtime->GetJavaVM();
return JNI_OK;
}

作用:

  1. 参数以key-value形式保存于options向量
  2. 用Runtime类的静态成员函数create创建art虚拟机,属于该进程
  3. 获取当前Runtime对象实例,并调用start启动
  4. 获取JNIEnv与JavaVm返回。

7.Runtime.Create

Runtime::Create(options, ignore_unrecognized)
Runtime类的静态成员函数Create
在art\runtime\runtime.cc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
bool Runtime::Create(RuntimeArgumentMap&& runtime_options) {
// TODO: acquire a static mutex on Runtime to avoid racing.
if (Runtime::instance_ != nullptr) {
return false;
}
instance_ = new Runtime;//instance为Runtime单例静态变量,描述art虚拟机实例-进程的
Locks::SetClientCallback(IsSafeToCallAbort);
if (!instance_->Init(std::move(runtime_options))) {//初始化instance
// TODO: Currently deleting the instance will abort the runtime on destruction. Now This will
// leak memory, instead. Fix the destructor. b/19100793.
// delete instance_;
instance_ = nullptr;
return false;
}
return true;
}
bool Runtime::Create(const RuntimeOptions& raw_options, bool ignore_unrecognized) {
RuntimeArgumentMap runtime_options;//吧设置和忽略无法识别都输入
return ParseOptions(raw_options, ignore_unrecognized, &runtime_options) &&
Create(std::move(runtime_options));//std::move语句可以将左值变为右值避免拷贝构造
}

创建唯一的Runtime对象:Runtime::instance_实例,进行初始化。
注意该对象属于进程,线程私有空间有限:栈以及系统提供的线程信息区域TLS,代码以及堆是共享的,因此类中指向的全局变量进程唯一。

Runtime构造函数:在art\runtime\runtime.cc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Runtime::Runtime()
: resolution_method_(nullptr),
imt_conflict_method_(nullptr),
imt_unimplemented_method_(nullptr),
instruction_set_(kNone),
compiler_callbacks_(nullptr),
......
zygote_no_threads_(false),
cha_(nullptr) {
CheckAsmSupportOffsetsAndSizes();
std::fill(callee_save_methods_, callee_save_methods_ + arraysize(callee_save_methods_), 0u);
interpreter::CheckInterpreterAsmConstants();
callbacks_.reset(new RuntimeCallbacks());
for (size_t i = 0; i <= static_cast<size_t>(DeoptimizationKind::kLast); ++i) {
deoptimization_counts_[i] = 0u;
}
}

为基本属性的初始化

8.Runtime.init

instance_->Init(std::move(runtime_options))
在art\runtime\runtime.cc

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
74
75
76
bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) {
......
RuntimeArgumentMap runtime_options(std::move(runtime_options_in));//参数map
using Opt = RuntimeArgumentMap;
...... 一堆参数设置
boot_class_path_string_ = runtime_options.ReleaseOrDefault(Opt::BootClassPath);//启动类路径
image_location_ = runtime_options.GetOrDefault(Opt::Image);;//art所使用image文件
compiler_executable_ = runtime_options.ReleaseOrDefault(Opt::Compiler);//art是执行还是编译dex的
//创建虚拟机堆
heap_ = new gc::Heap(runtime_options.GetOrDefault(Opt::MemoryInitialSize),
runtime_options.GetOrDefault(Opt::HeapGrowthLimit),
runtime_options.GetOrDefault(Opt::HeapMinFree),
runtime_options.GetOrDefault(Opt::HeapMaxFree),
runtime_options.GetOrDefault(Opt::HeapTargetUtilization),
runtime_options.GetOrDefault(Opt::ForegroundHeapGrowthMultiplier),
runtime_options.GetOrDefault(Opt::MemoryMaximumSize),
runtime_options.GetOrDefault(Opt::NonMovingSpaceCapacity),
runtime_options.GetOrDefault(Opt::Image),
runtime_options.GetOrDefault(Opt::ImageInstructionSet),
// Override the collector type to CC if the read barrier config.
kUseReadBarrier ? gc::kCollectorTypeCC : xgc_option.collector_type_,
kUseReadBarrier ? BackgroundGcOption(gc::kCollectorTypeCCBackground)
: runtime_options.GetOrDefault(Opt::BackgroundGc),
runtime_options.GetOrDefault(Opt::LargeObjectSpace),
runtime_options.GetOrDefault(Opt::LargeObjectThreshold),
runtime_options.GetOrDefault(Opt::ParallelGCThreads),
runtime_options.GetOrDefault(Opt::ConcGCThreads),
runtime_options.Exists(Opt::LowMemoryMode),
runtime_options.GetOrDefault(Opt::LongPauseLogThreshold),
runtime_options.GetOrDefault(Opt::LongGCLogThreshold),
runtime_options.Exists(Opt::IgnoreMaxFootprint),
runtime_options.GetOrDefault(Opt::UseTLAB),
xgc_option.verify_pre_gc_heap_,
xgc_option.verify_pre_sweeping_heap_,
xgc_option.verify_post_gc_heap_,
xgc_option.verify_pre_gc_rosalloc_,
xgc_option.verify_pre_sweeping_rosalloc_,
xgc_option.verify_post_gc_rosalloc_,
xgc_option.gcstress_,
xgc_option.measure_,
runtime_options.GetOrDefault(Opt::EnableHSpaceCompactForOOM),
runtime_options.GetOrDefault(Opt::HSpaceCompactForOOMMinIntervalsMs));
......
//创建java_vm_实例
java_vm_ = JavaVMExt::Create(this, runtime_options, &error_msg);
......
Thread::Startup();//线程类启动
// ClassLinker needs an attached thread, but we can't fully attach a thread without creating
// objects. We can't supply(供应) a thread group yet; it will be fixed later. Since we are the main
// thread, we do not get a java peer(同辈).
Thread* self = Thread::Attach("main", false, nullptr, false);//将当前作为主线程。使当前可以调用jni
......
//获取当前的堆,GetContinuousSpaces可以获得堆里面的连续空间列表
CHECK_GE(GetHeap()->GetContinuousSpaces().size(), 1U);
//创建ClassLinker对象 加载java类用
class_linker_ = new ClassLinker(intern_table_);
......
return true;
}

classlinker = new ClassLinker(interntable);

class_linker主要是解析一些系统java类,比如classloader等系统资源load到内存,作为之后加载其他java类的基础,这里只是简单说明下,涉及到art的几个很重要的结构,Class和ArtMethod,DexCache,在boot.oat可执行文件的结构中,每一个Java Class对应一个OatClass,OatClass中保存分别有dex class和本地机器码的地址,在解释执行模式下,每一个方法的调用是通过DexCache来中转的,DexCache,根据method找到指定的ArtMethod,这里class_link主要负责协调管理。

此处实现在分析art运行时再开

9.Heap.Heap

看一下堆的构造Heap类——art虚拟机的堆
位于:art\runtime\gc\heap.cc

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
Heap::Heap(size_t initial_size,
size_t growth_limit,
size_t min_free,
size_t max_free,
double target_utilization,
double foreground_heap_growth_multiplier,
size_t capacity,
size_t non_moving_space_capacity,
const std::string& image_file_name,//虚拟机镜像文件
const InstructionSet image_instruction_set,
CollectorType foreground_collector_type,
CollectorType background_collector_type,
space::LargeObjectSpaceType large_object_space_type,
size_t large_object_threshold,
size_t parallel_gc_threads,
size_t conc_gc_threads,
bool low_memory_mode,
size_t long_pause_log_threshold,
size_t long_gc_log_threshold,
bool ignore_max_footprint,
bool use_tlab,
bool verify_pre_gc_heap,
bool verify_pre_sweeping_heap,
bool verify_post_gc_heap,
bool verify_pre_gc_rosalloc,
bool verify_pre_sweeping_rosalloc,
bool verify_post_gc_rosalloc,
bool gc_stress_mode,
bool measure_gc_performance,
bool use_homogeneous_space_compaction_for_oom,
uint64_t min_interval_homogeneous_space_compaction_by_oom)
:
......
// Load image space(s). 加载镜像空间
if (space::ImageSpace::LoadBootImage(image_file_name,
image_instruction_set,
&boot_image_spaces_,
&requested_alloc_space_begin)) {
for (auto space : boot_image_spaces_) {
AddSpace(space);
}
}
......

image_file_name描述image文件路径 默认为/system/framework/arm64/boot.art
用space::ImageSpace::LoadBootImage加载到boot_imagespaces中,之后用Heap类的成员函数AddSpace加入堆空间
注意android7之后被分为多个文件:boot-.oat/art,因此这里用for加入。art中的内容为类对象映像,包含了所有framework/base/preloaded-classes文件列出的所有类。这些类会被一次性的载入到内存中,并可以被直接使用

LoadBootImage在\art\runtime\gc\space\image_space.cc

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
74
75
bool ImageSpace::LoadBootImage(const std::string& image_file_name,
const InstructionSet image_instruction_set,
std::vector<space::ImageSpace*>* boot_image_spaces,
uint8_t** oat_file_end) {
DCHECK(boot_image_spaces != nullptr);
DCHECK(boot_image_spaces->empty());
DCHECK(oat_file_end != nullptr);
DCHECK_NE(image_instruction_set, InstructionSet::kNone);
if (image_file_name.empty()) {
return false;
}
// For code reuse, handle this like a work queue.
std::vector<std::string> image_file_names;
image_file_names.push_back(image_file_name);
bool error = false;
uint8_t* oat_file_end_tmp = *oat_file_end;
for (size_t index = 0; index < image_file_names.size(); ++index) {
std::string& image_name = image_file_names[index];
std::string error_msg;
std::unique_ptr<space::ImageSpace> boot_image_space_uptr = CreateBootImage(
image_name.c_str(),
image_instruction_set,
index > 0,
&error_msg);
if (boot_image_space_uptr != nullptr) {
space::ImageSpace* boot_image_space = boot_image_space_uptr.release();
boot_image_spaces->push_back(boot_image_space);
// Oat files referenced by image files immediately follow them in memory, ensure alloc space
// isn't going to get in the middle
uint8_t* oat_file_end_addr = boot_image_space->GetImageHeader().GetOatFileEnd();
CHECK_GT(oat_file_end_addr, boot_image_space->End());
oat_file_end_tmp = AlignUp(oat_file_end_addr, kPageSize);
if (index == 0) {
// If this was the first space, check whether there are more images to load.
const OatFile* boot_oat_file = boot_image_space->GetOatFile();
if (boot_oat_file == nullptr) {
continue;
}
const OatHeader& boot_oat_header = boot_oat_file->GetOatHeader();
const char* boot_classpath =
boot_oat_header.GetStoreValueByKey(OatHeader::kBootClassPathKey);
if (boot_classpath == nullptr) {
continue;
}
ExtractMultiImageLocations(image_file_name, boot_classpath, &image_file_names);
}
} else {
error = true;
LOG(ERROR) << "Could not create image space with image file '" << image_file_name << "'. "
<< "Attempting to fall back to imageless running. Error was: " << error_msg
<< "\nAttempted image: " << image_name;
break;
}
}
if (error) {
// Remove already loaded spaces.
for (space::Space* loaded_space : *boot_image_spaces) {
delete loaded_space;
}
boot_image_spaces->clear();
return false;
}
*oat_file_end = oat_file_end_tmp;
return true;
}

检查:boot.art、dalvik-cache是否存在该镜像文件,没有就创建。最后加载进boot_image_spaces中

Heap::AddSpace
位于art\runtime\gc\heap.cc

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
void Heap::AddSpace(space::Space* space) {
CHECK(space != nullptr);
WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
if (space->IsContinuousSpace()) {//是连续的space
DCHECK(!space->IsDiscontinuousSpace());
space::ContinuousSpace* continuous_space = space->AsContinuousSpace(); //作为连续的空间
// Continuous spaces don't necessarily have bitmaps.
accounting::ContinuousSpaceBitmap* live_bitmap = continuous_space->GetLiveBitmap();
accounting::ContinuousSpaceBitmap* mark_bitmap = continuous_space->GetMarkBitmap();
// The region space bitmap is not added since VisitObjects visits the region space objects with
// special handling.
if (live_bitmap != nullptr && !space->IsRegionSpace()) {
CHECK(mark_bitmap != nullptr);
live_bitmap_->AddContinuousSpaceBitmap(live_bitmap);
mark_bitmap_->AddContinuousSpaceBitmap(mark_bitmap);
}
continuous_spaces_.push_back(continuous_space); //加入堆中的连续空间
// Ensure that spaces remain sorted in increasing order of start address.
std::sort(continuous_spaces_.begin(), continuous_spaces_.end(),
[](const space::ContinuousSpace* a, const space::ContinuousSpace* b) {
return a->Begin() < b->Begin();
});
} else {
CHECK(space->IsDiscontinuousSpace());
space::DiscontinuousSpace* discontinuous_space = space->AsDiscontinuousSpace();
live_bitmap_->AddLargeObjectBitmap(discontinuous_space->GetLiveBitmap());
mark_bitmap_->AddLargeObjectBitmap(discontinuous_space->GetMarkBitmap());
discontinuous_spaces_.push_back(discontinuous_space);
}
if (space->IsAllocSpace()) { //是否允许分配
alloc_spaces_.push_back(space->AsAllocSpace());
}
}

Heap类中分别用成员变量continuousspaces和discontinuousspaces分别保存整个堆中的连续空间和非连续空间,这里讲space加载进heap

10.JavaVMExt.Create

Runtime::Init的JavaVMExt::Create
实现在art\runtime\java_vm_ext.cc

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
class JavaVMExt : public JavaVM
......
// Checking "globals" and "weak_globals" usually requires locks, but we
// don't need the locks to check for validity when constructing the
// object. Use NO_THREAD_SAFETY_ANALYSIS for this.
std::unique_ptr<JavaVMExt> JavaVMExt::Create(Runtime* runtime,
const RuntimeArgumentMap& runtime_options,
std::string* error_msg) NO_THREAD_SAFETY_ANALYSIS {
std::unique_ptr<JavaVMExt> java_vm(new JavaVMExt(runtime, runtime_options, error_msg));
if (java_vm && java_vm->globals_.IsValid() && java_vm->weak_globals_.IsValid()) {
return java_vm;
}
return nullptr;
}
JavaVMExt::JavaVMExt(Runtime* runtime,
const RuntimeArgumentMap& runtime_options,
std::string* error_msg)
: runtime_(runtime),
check_jni_abort_hook_(nullptr),
check_jni_abort_hook_data_(nullptr),
check_jni_(false), // Initialized properly in the constructor body below.
force_copy_(runtime_options.Exists(RuntimeArgumentMap::JniOptsForceCopy)),
tracing_enabled_(runtime_options.Exists(RuntimeArgumentMap::JniTrace)
|| VLOG_IS_ON(third_party_jni)),
trace_(runtime_options.GetOrDefault(RuntimeArgumentMap::JniTrace)),
globals_(kGlobalsMax, kGlobal, IndirectReferenceTable::ResizableCapacity::kNo, error_msg),
libraries_(new Libraries),
unchecked_functions_(&gJniInvokeInterface),
weak_globals_(kWeakGlobalsMax,
kWeakGlobal,
IndirectReferenceTable::ResizableCapacity::kNo,
error_msg),
allow_accessing_weak_globals_(true),
weak_globals_add_condition_("weak globals add condition",
(CHECK(Locks::jni_weak_globals_lock_ != nullptr),
*Locks::jni_weak_globals_lock_)),
env_hooks_() {
functions = unchecked_functions_;
SetCheckJniEnabled(runtime_options.Exists(RuntimeArgumentMap::CheckJni));
}
const JNIInvokeInterface gJniInvokeInterface = {
nullptr, // reserved0
nullptr, // reserved1
nullptr, // reserved2
JII::DestroyJavaVM,
JII::AttachCurrentThread,
JII::DetachCurrentThread,
JII::GetEnv,
JII::AttachCurrentThreadAsDaemon
};

初始化JavaVMExt继承自JavaVM,functions为一函数指针结构体,存有JavaVM的进程相关方法。
该对象存有Runtime并唯一。

11.Thread.Startup

Thread::Startup()
在/art/runtime/thread.cc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void Thread::Startup() {
CHECK(!is_started_);
is_started_ = true;
{
// MutexLock to keep annotalysis happy.
//
// Note we use null for the thread because Thread::Current can
// return garbage since (is_started_ == true) and
// Thread::pthread_key_self_ is not yet initialized.
// This was seen on glibc.
MutexLock mu(nullptr, *Locks::thread_suspend_count_lock_);
resume_cond_ = new ConditionVariable("Thread resumption condition variable",
*Locks::thread_suspend_count_lock_);
}
// Allocate a TLS slot.
CHECK_PTHREAD_CALL(pthread_key_create, (&Thread::pthread_key_self_, Thread::ThreadExitCallback),
"self key");
// Double-check the TLS slot allocation.
if (pthread_getspecific(pthread_key_self_) != nullptr) {
LOG(FATAL) << "Newly-created pthread TLS slot is not nullptr";
}
}

Thread类是art虚拟机管理线程的类,里面jvm创建与native创建的线程都有表示,是一一对应的。因为jvm的线程调度是由操作系统实现的

12.Thread.Attach

Thread* self = Thread::Attach(“main”, false, nullptr, false);
位于art/runtime/thread.cc

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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
Thread* Thread::Attach(const char* thread_name,
bool as_daemon, //daemon:守护进程
jobject thread_group,
bool create_peer) {
auto create_peer_action = [&](Thread* self) {
// If we're the main thread, ClassLinker won't be created until after we're attached,
// so that thread needs a two-stage attach. Regular threads don't need this hack.
// In the compiler, all threads need this hack, because no-one's going to be getting
// a native peer!
//如果我们在主线程,ClassLinker还没创建,因此我们需要俩步来附上jvm与本地的线程。
//规则的线程不需要
if (create_peer) {
self->CreatePeer(thread_name, as_daemon, thread_group);
if (self->IsExceptionPending()) {
// We cannot keep the exception around, as we're deleting self. Try to be helpful and log it.
{
ScopedObjectAccess soa(self);
LOG(ERROR) << "Exception creating thread peer:";
LOG(ERROR) << self->GetException()->Dump();
self->ClearException();
}
return false;
}
} else {
// These aren't necessary, but they improve diagnostics for unit tests & command-line tools.
if (thread_name != nullptr) {
self->tlsPtr_.name->assign(thread_name);
::art::SetThreadName(thread_name);
} else if (self->GetJniEnv()->check_jni) {
LOG(WARNING) << *Thread::Current() << " attached without supplying a name";
}
}
return true;
};
return Attach(thread_name, as_daemon, create_peer_action);//调用的是下面那个,第三个是一个lambda表达式生成的函数指针
}
template <typename PeerAction>
Thread* Thread::Attach(const char* thread_name, bool as_daemon, PeerAction peer_action) {
Runtime* runtime = Runtime::Current();
if (runtime == nullptr) {
LOG(ERROR) << "Thread attaching to non-existent runtime: " << thread_name;
return nullptr;
}
Thread* self;
{
MutexLock mu(nullptr, *Locks::runtime_shutdown_lock_);
if (runtime->IsShuttingDownLocked()) {
LOG(WARNING) << "Thread attaching while runtime is shutting down: " << thread_name;
return nullptr;
} else {
Runtime::Current()->StartThreadBirth();
self = new Thread(as_daemon);
bool init_success = self->Init(runtime->GetThreadList(), runtime->GetJavaVM()); //init线程传入ThreadList和JavaVM
//
Runtime::Current()->EndThreadBirth();
if (!init_success) {
delete self;
return nullptr;
}
}
}
self->InitStringEntryPoints();
CHECK_NE(self->GetState(), kRunnable);
self->SetState(kNative);
// Run the action that is acting on the peer.
if (!peer_action(self)) {
runtime->GetThreadList()->Unregister(self);
// Unregister deletes self, no need to do this here.
return nullptr;
}
if (VLOG_IS_ON(threads)) {
if (thread_name != nullptr) {
VLOG(threads) << "Attaching thread " << thread_name;
} else {
VLOG(threads) << "Attaching unnamed thread.";
}
ScopedObjectAccess soa(self);
self->Dump(LOG_STREAM(INFO));
}
{
ScopedObjectAccess soa(self);
runtime->GetRuntimeCallbacks()->ThreadStart(self);
}
return self;
}

创建Thread实例,调用init函数,传入该进程的ThreadList和JavaVM。
同时在init中创建该线程的JNIEnvExt对象。
JNIEnvExt类的构造函数将父类JNIEnv的成员变量functions初始化为全局变量gJniNativeInterface。也就是说,JNI函数表实际是由全局变量gJniNativeInterface来描述的。其中均是jni的静态函数。

16.Runtime.Start

bool started = runtime->Start();//启动虚拟机
art\runtime\runtime.cc

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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
bool Runtime::Start() {
......
Thread* self = Thread::Current();
self->TransitionFromRunnableToSuspended(kNative);
started_ = true;
if (!IsImageDex2OatEnabled() || !GetHeap()->HasBootImageSpace()) {
ScopedObjectAccess soa(self);
StackHandleScope<2> hs(soa.Self());
auto class_class(hs.NewHandle<mirror::Class>(mirror::Class::GetJavaLangClass()));
auto field_class(hs.NewHandle<mirror::Class>(mirror::Field::StaticClass()));
class_linker_->EnsureInitialized(soa.Self(), class_class, true, true);
// Field class is needed for register_java_net_InetAddress in libcore, b/28153851.
class_linker_->EnsureInitialized(soa.Self(), field_class, true, true);
}
// InitNativeMethods needs to be after started_ so that the classes
// it touches will have methods linked to the oat file if necessary.
{
ScopedTrace trace2("InitNativeMethods");
InitNativeMethods();
}
// Initialize well known thread group values that may be accessed threads while attaching.
InitThreadGroups(self);
Thread::FinishStartup();
// Create the JIT either if we have to use JIT compilation or save profiling info. This is
// done after FinishStartup as the JIT pool needs Java thread peers, which require the main
// ThreadGroup to exist.
//
// TODO(calin): We use the JIT class as a proxy for JIT compilation and for
// recoding profiles. Maybe we should consider changing the name to be more clear it's
// not only about compiling. b/28295073.
if (jit_options_->UseJitCompilation() || jit_options_->GetSaveProfilingInfo()) {
std::string error_msg;
if (!IsZygote()) {
// If we are the zygote then we need to wait until after forking to create the code cache
// due to SELinux restrictions on r/w/x memory regions.
CreateJit();
} else if (jit_options_->UseJitCompilation()) {
if (!jit::Jit::LoadCompilerLibrary(&error_msg)) {
// Try to load compiler pre zygote to reduce PSS. b/27744947
LOG(WARNING) << "Failed to load JIT compiler with error " << error_msg;
}
}
}
// Send the start phase event. We have to wait till here as this is when the main thread peer
// has just been generated, important root clinits have been run and JNI is completely functional.
{
ScopedObjectAccess soa(self);
callbacks_->NextRuntimePhase(RuntimePhaseCallback::RuntimePhase::kStart);
}
system_class_loader_ = CreateSystemClassLoader(this);
if (!is_zygote_) {
if (is_native_bridge_loaded_) {
PreInitializeNativeBridge(".");
}
NativeBridgeAction action = force_native_bridge_
? NativeBridgeAction::kInitialize
: NativeBridgeAction::kUnload;
InitNonZygoteOrPostFork(self->GetJniEnv(),
/* is_system_server */ false,
action,
GetInstructionSetString(kRuntimeISA));
}
// Send the initialized phase event. Send it before starting daemons, as otherwise
// sending thread events becomes complicated.
{
ScopedObjectAccess soa(self);
callbacks_->NextRuntimePhase(RuntimePhaseCallback::RuntimePhase::kInit);
}
StartDaemonThreads();
{
ScopedObjectAccess soa(self);
self->GetJniEnv()->locals.AssertEmpty();
}
VLOG(startup) << "Runtime::Start exiting";
finished_starting_ = true;
if (trace_config_.get() != nullptr && trace_config_->trace_file != "") {
ScopedThreadStateChange tsc(self, kWaitingForMethodTracingStart);
Trace::Start(trace_config_->trace_file.c_str(),
-1,
static_cast<int>(trace_config_->trace_file_size),
0,
trace_config_->trace_output_mode,
trace_config_->trace_mode,
0);
}
return true;
}
  1. 初始化基本类class_class ,即java.lang.Class类,这是最基础的类;
  2. InitNativeMethods(): 将java.lang下面最基础的类的JNI接口进行初始化;
  3. InitZygote:这是zygote程序在调用时,需要做的事情。app_main.cpp文件不仅是zygote的主程序,也是安卓的am命令行的主程序,故此这里做了区分;
  4. StartDemonThreads,调用java.lang.Daemons.start,启动一组线程,它们的作用是,执行GC、调用finalize方法、 处理ReferenceQueue等一系列工作。

17.AndroidRuntime.startReg

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
/*static*/ int AndroidRuntime::startReg(JNIEnv* env)
{
ATRACE_NAME("RegisterAndroidNatives");
/*
* This hook causes all future threads created in this process to be
* attached to the JavaVM. (This needs to go away in favor of JNI
* Attach calls.)
*/
androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);
ALOGV("--- registering native functions ---\n");
/*
* Every "register" function calls one or more things that return
* a local reference (e.g. FindClass). Because we haven't really
* started the VM yet, they're all getting stored in the base frame
* and never released. Use Push/Pop to manage the storage.
*/
env->PushLocalFrame(200);
if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
env->PopLocalFrame(NULL);
return -1;
}
env->PopLocalFrame(NULL);
//createJavaThread("fubar", quickTest, (void*) "hello");
return 0;
}

注册android系统依赖的本地jni方法

18.jni方法

调用之前注册好的本地方法

后记

基本启动过程如上….由于老罗的版本有些久远…art的c++源码庞大复杂…..经过一段时间的摸索仍在雾中。art加载执行部分无法自行分析懂,因此接下来从apk安装、运行角度分析。让逆向相关流程更为明确。
老罗的分析:https://blog.csdn.net/luoshengyang/article/details/39256813
虚拟机本质还是一个c++程序。它解释自定义的执行文件格式。