0%

看 Android 是如何加载 Class 的

不知读者在平时的 Android 或 Java 开发中,对于 Class 如何加载至虚拟机中并执行,存在过多多少少的好奇吗?

或许你和笔者一样,读过好几本有关 JVM 的书籍,又或看过好几篇讲解 Class 加载的博文,但总感觉脱离源码的理论学习未免太过晦涩难懂。

故本文就从 Android Native 源码的角度,简略阅读分析下 Class 加载的部分关键流程代码实现,希望读者和我都能够从此次分析中有所收获。

双亲委派模型

首先,讲 Class 的加载,避免不了双亲委派模型,其实很好理解,就是将 Class 的加载优先代理给父级 Class Loader 进行处理,实现在 Java 层,直接看代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
// 判断是否已经加载过
Class<?> c = findLoadedClass(name);
if (c == null) {
try {
// 优先交给父级 Class Loader
if (parent != null) {
c = parent.loadClass(name, false);
} else {
// Bootstrap Class Loader
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
}

// 再由当前 Class Loader 处理
if (c == null) {
c = findClass(name);
}
}
return c;
}

Class 加载的 Native 层入口

Native 层的类加载是从 Class.forname 方法开始的,实现在 art/runtime/native/java_lang_Class.cc 文件中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
static jclass Class_classForName(JNIEnv* env, jclass, jstring javaName, jboolean initialize,
jobject javaLoader) {
...

Handle<mirror::Class> c(
hs.NewHandle(class_linker->FindClass(soa.Self(), descriptor.c_str(), class_loader)));
if (c == nullptr) {
...
if (cnfe != nullptr) {
// Make sure allocation didn't fail with an OOME.
env->Throw(cnfe);
}
return nullptr;
}
if (initialize) {
class_linker->EnsureInitialized(soa.Self(), c, true, true);
}
return soa.AddLocalReference<jclass>(c.Get());
}

ClassLinker::FindClass 的实现有以下流程

  1. 类名是单个字符,查找基本类型的 Class
  2. 从已加载的 Class Table 中查找,确保 Class 已经 Resolve 后直接返回
  3. Class Loader 为空,则从 boot_class_path_ 中查找类
  4. 如果是数组,则运行时创建数组 Class;非数组,则从 BaseDexClassLoader 中查找
  5. 插入到 Class Loader 的 Class Table 记录中

基本类型的 Class 寻找

1
2
3
4
5
6
7
8
9
mirror::Class* ClassLinker::CreatePrimitiveClass(Thread* self, Primitive::Type type) {
ObjPtr<mirror::Class> klass =
AllocClass(self, mirror::Class::PrimitiveClassSize(image_pointer_size_));
if (UNLIKELY(klass == nullptr)) {
self->AssertPendingOOMException();
return nullptr;
}
return InitializePrimitiveClass(klass, type);
}

在堆上开辟内存

image-20190717120418590

kMovingClasses 定义在 art/runtime/globals.h:100 常量中,当不支持 Mark-Compact GC 时,恒为 true

初始化 Class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
mirror::Class* ClassLinker::InitializePrimitiveClass(ObjPtr<mirror::Class> primitive_class,
Primitive::Type type) {
...
Handle<mirror::Class> h_class(hs.NewHandle(primitive_class));
ObjectLock<mirror::Class> lock(self, h_class);
// 初始化 Class
// 注意: 基本类型的 Class 竟然是 public final abstract
h_class->SetAccessFlags(kAccPublic | kAccFinal | kAccAbstract);
h_class->SetPrimitiveType(type);
h_class->SetIfTable(GetClassRoot(kJavaLangObject)->GetIfTable());
mirror::Class::SetStatus(h_class, mirror::Class::kStatusInitialized, self);
const char* descriptor = Primitive::Descriptor(type);
// 放进已加载的 Class Table
ObjPtr<mirror::Class> existing = InsertClass(descriptor,
h_class.Get(),
ComputeModifiedUtf8Hash(descriptor));
CHECK(existing == nullptr) << "InitPrimitiveClass(" << type << ") failed";
return h_class.Get();
}

启动类的寻找

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
if (descriptor[0] != '[' && class_loader == nullptr) {
// 非数组类,并且应用 boot_class_loader,则从 boot_class_path_ 查找
ClassPathEntry pair = FindInClassPath(descriptor, hash, boot_class_path_);
if (pair.second != nullptr) {
// 定义 Class
return DefineClass(self,
descriptor,
hash,
ScopedNullHandle<mirror::ClassLoader>(),
*pair.first,
*pair.second);
} else {
// 未找到
ObjPtr<mirror::Throwable> pre_allocated =
Runtime::Current()->GetPreAllocatedNoClassDefFoundError();
self->SetException(pre_allocated);
return nullptr;
}
}

FindInClassPath 函数中,通过遍历 boot_class_path_ 寻找正确的 Class Def

1
2
3
4
5
6
for (const DexFile* dex_file : class_path) {
const DexFile::ClassDef* dex_class_def = OatDexFile::FindClassDef(*dex_file, descriptor, hash);
if (dex_class_def != nullptr) {
return ClassPathEntry(dex_file, dex_class_def);
}
}

在 DexFile 中查找 Class Def 是对 TypeLookupTable 表进行 hash 查找

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const DexFile::ClassDef* OatFile::OatDexFile::FindClassDef(const DexFile& dex_file,
const char* descriptor,
size_t hash) {
...
if (LIKELY((oat_dex_file != nullptr) && (oat_dex_file->GetTypeLookupTable() != nullptr))) {
// 从 TypeLookupTable 中查找 Class Def
const uint32_t class_def_idx = oat_dex_file->GetTypeLookupTable()->Lookup(descriptor, hash);
return (class_def_idx != DexFile::kDexNoIndex) ? &dex_file.GetClassDef(class_def_idx) : nullptr;
}
...
const DexFile::TypeId* type_id = dex_file.FindTypeId(descriptor);
if (type_id != nullptr) {
dex::TypeIndex type_idx = dex_file.GetIndexForTypeId(*type_id);
return dex_file.FindClassDef(type_idx);
}
return nullptr;
}

Class Def 的结构定义中主要是 Class 文件各部分内容的地址信息

1
2
3
4
5
6
7
8
9
10
11
12
13
struct ClassDef {
dex::TypeIndex class_idx_; // index into type_ids_ array for this class
uint16_t pad1_; // padding = 0
uint32_t access_flags_;
dex::TypeIndex superclass_idx_; // index into type_ids_ array for superclass
uint16_t pad2_; // padding = 0
uint32_t interfaces_off_; // file offset to TypeList
dex::StringIndex source_file_idx_; // index into string_ids_ for source file name
uint32_t annotations_off_; // file offset to annotations_directory_item
uint32_t class_data_off_; // file offset to class_data_item
uint32_t static_values_off_; // file offset to EncodedArray
...
};

Class 的定义

拿到 ClassDef,接下来则是调用 ClassLinker::DefineClass,定义在 art/runtime/class_linker.cc:2693

内部 Class

判断是否为 JDK 内部 Class,若是内部 Class,则直接赋值为已完成创建的系统 Class

1
2
3
4
5
6
7
8
9
10
11
12
13
if (strcmp(descriptor, "Ljava/lang/Object;") == 0) {
klass.Assign(GetClassRoot(kJavaLangObject));
} else if (strcmp(descriptor, "Ljava/lang/Class;") == 0) {
klass.Assign(GetClassRoot(kJavaLangClass));
} else if (strcmp(descriptor, "Ljava/lang/String;") == 0) {
klass.Assign(GetClassRoot(kJavaLangString));
} else if (strcmp(descriptor, "Ljava/lang/ref/Reference;") == 0) {
klass.Assign(GetClassRoot(kJavaLangRefReference));
} else if (strcmp(descriptor, "Ljava/lang/DexCache;") == 0) {
klass.Assign(GetClassRoot(kJavaLangDexCache));
} else if (strcmp(descriptor, "Ldalvik/system/ClassExt;") == 0) {
klass.Assign(GetClassRoot(kDalvikSystemClassExt));
}

在堆中分配内存

1
klass.Assign(AllocClass(self, SizeOfClassWithoutEmbeddedTables(dex_file, dex_class_def)));

对 Class 进行 PreDefine

实现在 art/runtime/openjdkjvmti/ti_class.cc:133 中 ClassPreDefine 方法

其中,首先拷贝 DexFile 并发送全局事件给 Transformer 来进行 Hook 处理(猜测是暴露给应用层进行 Dex 预处理)

1
2
3
4
std::unique_ptr<FixedUpDexFile> dex_file_copy(FixedUpDexFile::Create(initial_dex_file));
// 发送事件
event_handler->DispatchEvent<ArtJvmtiEvent::kClassFileLoadHookNonRetransformable>(...);
event_handler->DispatchEvent<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(...);

Hook 预处理后,会生成新的 DexFile 和 ClassDef

1
2
3
4
5
std::unique_ptr<const art::DexFile> dex_file(MakeSingleDexFile(self,
descriptor,
initial_dex_file.GetLocation(),
final_len,
final_dex_data));

注册 DexFile

ClassLinker::RegisterDexFile 方法实现 DexFile 的注册,此处会通过 FindDexCacheDataLocked 方法,尝试从缓存中读取,此处讨论首次无缓存的情况。首先会对 Class Loader 进行必要的初始化

1
2
3
4
5
6
7
8
9
// Allocator 分配器
LinearAlloc* const linear_alloc = GetOrCreateAllocatorForClassLoader(class_loader);
DCHECK(linear_alloc != nullptr);
ClassTable* table;
{
WriterMutexLock mu(self, *Locks::classlinker_classes_lock_);
// 添加 Class Table
table = InsertClassTableForClassLoader(class_loader);
}

这里跟进下 Class Table 是如何加进去的

image-20190718112701529

DexFile 的注册关键代码如下

1
2
3
4
5
6
7
8
9
// 初始化 DexCache,其中包含 string、type、field 等的空间初始化
mirror::DexCache::InitializeDexCache(self,
h_dex_cache.Get(),
h_location.Get(),
&dex_file,
linear_alloc,
image_pointer_size_);
// 注册逻辑
RegisterDexFileLocked(dex_file, h_dex_cache.Get(), h_class_loader.Get());

注册 DexFile 其实就是将其放在全局变量 dex_caches_ 中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 找到旧的记录
for (auto it = dex_caches_.begin(); it != dex_caches_.end(); ) {
DexCacheData data = *it;
if (self->IsJWeakCleared(data.weak_root)) {
vm->DeleteWeakGlobalRef(self, data.weak_root);
it = dex_caches_.erase(it);
} else {
++it;
}
}
jweak dex_cache_jweak = vm->AddWeakGlobalRef(self, dex_cache);
dex_cache->SetDexFile(&dex_file);
DexCacheData data;
data.weak_root = dex_cache_jweak;
data.dex_file = dex_cache->GetDexFile();
data.resolved_methods = dex_cache->GetResolvedMethods();
data.class_table = ClassTableForClassLoader(class_loader);
DCHECK(data.class_table != nullptr);
// 放在 dex_caches_
dex_caches_.push_back(data);

最后确保 Class Loader 相同,DexCache 中的 Class Loader 要和当前加载的 Class Loader 一致,这里直接判断 Class Table 是否相同来实现

1
2
3
4
5
6
7
8
9
10
ObjPtr<mirror::DexCache> ClassLinker::EnsureSameClassLoader(
...
if (data.class_table != ClassTableForClassLoader(class_loader)) {
self->ThrowNewExceptionF("Ljava/lang/InternalError;",
"Attempt to register dex file %s with multiple class loaders",
data.dex_file->GetLocation().c_str());
return nullptr;
}
return dex_cache;
}

至此,DexFile 注册就完成了,将 DexCache 置放在 kClass 即可

1
klass->SetDexCache(dex_cache);

配置 Class 字段

ClassLinker::SetupClass 中对 Class 的信息字段进行了配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void ClassLinker::SetupClass(const DexFile& dex_file,
const DexFile::ClassDef& dex_class_def,
Handle<mirror::Class> klass,
ObjPtr<mirror::ClassLoader> class_loader) {
...
// Class
klass->SetClass(GetClassRoot(kJavaLangClass));
uint32_t access_flags = dex_class_def.GetJavaAccessFlags();
CHECK_EQ(access_flags & ~kAccJavaFlagsMask, 0U);
// 修饰符
klass->SetAccessFlags(access_flags);
klass->SetClassLoader(class_loader);
DCHECK_EQ(klass->GetPrimitiveType(), Primitive::kPrimNot);
mirror::Class::SetStatus(klass, mirror::Class::kStatusIdx, nullptr);

// ClassDef
klass->SetDexClassDefIndex(dex_file.GetIndexForClassDef(dex_class_def));
klass->SetDexTypeIndex(dex_class_def.class_idx_);
}

添加到 Class Table

ClassLinker::InsertClass 方法中将 Class 哈希插入到 Class Table 中

1
2
3
4
5
6
7
ClassTable* const class_table = InsertClassTableForClassLoader(class_loader);
ObjPtr<mirror::Class> existing = class_table->Lookup(descriptor, hash);
if (existing != nullptr) {
return existing.Ptr();
}
VerifyObject(klass);
class_table->InsertWithHash(klass, hash);

加载 Class

ClassLinker::LoadClass 中对类成员进行加载

1
2
3
4
5
6
7
8
9
10
11
12
void ClassLinker::LoadClass(Thread* self,
const DexFile& dex_file,
const DexFile::ClassDef& dex_class_def,
Handle<mirror::Class> klass) {
// 获取 Class 数据的地址偏移
const uint8_t* class_data = dex_file.GetClassData(dex_class_def);
if (class_data == nullptr) {
// 无字段和方法的类或接口
return;
}
LoadClassMembers(self, dex_file, class_data, klass);
}

类成员加载的实现在 ClassLinker::LoadClassMembers 方法中

第一步,加载静态变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
LinearAlloc* const allocator = GetAllocatorForClassLoader(klass->GetClassLoader());
// DexFile 字段迭代器
ClassDataItemIterator it(dex_file, class_data);
LengthPrefixedArray<ArtField>* sfields = AllocArtFieldArray(self,
allocator,
// 静态变量数目
it.NumStaticFields());
size_t num_sfields = 0;
uint32_t last_field_idx = 0u;
// 迭代器的 next() 方法,会将地址下移,赋值给迭代器的 filed 字段
for (; it.HasNextStaticField(); it.Next()) {
uint32_t field_idx = it.GetMemberIndex();
...
if (num_sfields == 0 || LIKELY(field_idx > last_field_idx)) {
// 递增地加载每个字段
LoadField(it, klass, &sfields->At(num_sfields));
++num_sfields;
last_field_idx = field_idx;
}
}

LoadFiled 为每个 Field 进行初始化,包括地址、所属 Class 以及修饰符

1
2
3
4
5
6
7
8
void ClassLinker::LoadField(const ClassDataItemIterator& it,
Handle<mirror::Class> klass,
ArtField* dst) {
const uint32_t field_idx = it.GetMemberIndex();
dst->SetDexFieldIndex(field_idx);
dst->SetDeclaringClass(klass.Get());
dst->SetAccessFlags(it.GetFieldAccessFlags());
}

注意,迭代器之所以能够按序遍历,先从 static 开始,是因为地址排序就是按如此的顺序

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
inline void Next() {
pos_++;
if (pos_ < EndOfStaticFieldsPos()) {
last_idx_ = GetMemberIndex();
ReadClassDataField();
} else if (pos_ == EndOfStaticFieldsPos() && NumInstanceFields() > 0) {
last_idx_ = 0; // transition to next array, reset last index
ReadClassDataField();
} else if (pos_ < EndOfInstanceFieldsPos()) {
last_idx_ = GetMemberIndex();
ReadClassDataField();
} else if (pos_ == EndOfInstanceFieldsPos() && NumDirectMethods() > 0) {
last_idx_ = 0; // transition to next array, reset last index
ReadClassDataMethod();
} else if (pos_ < EndOfDirectMethodsPos()) {
last_idx_ = GetMemberIndex();
ReadClassDataMethod();
} else if (pos_ == EndOfDirectMethodsPos() && NumVirtualMethods() > 0) {
last_idx_ = 0; // transition to next array, reset last index
ReadClassDataMethod();
} else if (pos_ < EndOfVirtualMethodsPos()) {
last_idx_ = GetMemberIndex();
ReadClassDataMethod();
} else {
DCHECK(!HasNext());
}
}

第二步,加载实例字段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Load instance fields.
LengthPrefixedArray<ArtField>* ifields = AllocArtFieldArray(self,
allocator,
it.NumInstanceFields());
size_t num_ifields = 0u;
last_field_idx = 0u;
for (; it.HasNextInstanceField(); it.Next()) {
uint32_t field_idx = it.GetMemberIndex();
DCHECK_GE(field_idx, last_field_idx); // Ordering enforced by DexFileVerifier.
if (num_ifields == 0 || LIKELY(field_idx > last_field_idx)) {
DCHECK_LT(num_ifields, it.NumInstanceFields());
LoadField(it, klass, &ifields->At(num_ifields));
++num_ifields;
last_field_idx = field_idx;
}
}

LoadField 与静态字段实现一致,不赘述。

静态字段和实例字段都加载完后,为 Class 赋值

1
2
klass->SetSFieldsPtr(sfields);
klass->SetIFieldsPtr(ifields);

第三步,加载方法

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
// 先赋值地址
klass->SetMethodsPtr(
AllocArtMethodArray(self, allocator, it.NumDirectMethods() + it.NumVirtualMethods()),
it.NumDirectMethods(),
it.NumVirtualMethods());
size_t class_def_method_index = 0;
uint32_t last_dex_method_index = DexFile::kDexNoIndex;
size_t last_class_def_method_index = 0;
// 普通方法
for (size_t i = 0; it.HasNextDirectMethod(); i++, it.Next()) {
ArtMethod* method = klass->GetDirectMethodUnchecked(i, image_pointer_size_);
// 加载方法
LoadMethod(dex_file, it, klass, method);
// 链接代码
LinkCode(this, method, oat_class_ptr, class_def_method_index);
uint32_t it_method_index = it.GetMemberIndex();
if (last_dex_method_index == it_method_index) {
// 重复
method->SetMethodIndex(last_class_def_method_index);
} else {
method->SetMethodIndex(class_def_method_index);
last_dex_method_index = it_method_index;
last_class_def_method_index = class_def_method_index;
}
class_def_method_index++;
}
// 抽象方法
for (size_t i = 0; it.HasNextVirtualMethod(); i++, it.Next()) {
ArtMethod* method = klass->GetVirtualMethodUnchecked(i, image_pointer_size_);
LoadMethod(dex_file, it, klass, method);
DCHECK_EQ(class_def_method_index, it.NumDirectMethods() + i);
LinkCode(this, method, oat_class_ptr, class_def_method_index);
class_def_method_index++;
}

接下来,看具体的 ClassLinker::LoadMethod 方法的实现

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
void ClassLinker::LoadMethod(const DexFile& dex_file,
const ClassDataItemIterator& it,
Handle<mirror::Class> klass,
ArtMethod* dst) {
// 基本属性赋值
dst->SetDexMethodIndex(dex_method_idx);
dst->SetDeclaringClass(klass.Get());
dst->SetCodeItemOffset(it.GetMethodCodeItemOffset());
dst->SetDexCacheResolvedMethods(klass->GetDexCache()->GetResolvedMethods(), image_pointer_size_);

uint32_t access_flags = it.GetMethodAccessFlags();

if (UNLIKELY(strcmp("finalize", method_name) == 0)) {
// 设置 finalize 属性
if (strcmp("V", dex_file.GetShorty(method_id.proto_idx_)) == 0) {
// Void return type.
if (klass->GetClassLoader() != nullptr) {
// 非 BootClassLoader 的,均可 finalize
klass->SetFinalizable();
} else {
std::string temp;
const char* klass_descriptor = klass->GetDescriptor(&temp);
// The Enum class declares a "final" finalize() method to prevent subclasses from
// introducing a finalizer. We don't want to set the finalizable flag for Enum or its
// subclasses, so we exclude it here.
// We also want to avoid setting the flag on Object, where we know that finalize() is
// empty.
if (strcmp(klass_descriptor, "Ljava/lang/Object;") != 0 &&
strcmp(klass_descriptor, "Ljava/lang/Enum;") != 0) {
// 非 Object、非 Enum 也可 finalize
klass->SetFinalizable();
}
}
}
} else if (method_name[0] == '<') {
bool is_init = (strcmp("<init>", method_name) == 0);
bool is_clinit = !is_init && (strcmp("<clinit>", method_name) == 0);
if (UNLIKELY(!is_init && !is_clinit)) {
// 如果是非实例或静态初始化方法
LOG(WARNING) << "Unexpected '<' at start of method name " << method_name;
} else {
// 初始化方法,但却无修饰符
if (UNLIKELY((access_flags & kAccConstructor) == 0)) {
LOG(WARNING) << method_name << " didn't have expected constructor access flag in class "
<< klass->PrettyDescriptor() << " in dex file " << dex_file.GetLocation();
// 则加上构造器修饰符
access_flags |= kAccConstructor;
}
}
}
// 权限修饰符
dst->SetAccessFlags(access_flags);
}

LinkCode 的工作主要是对 Method 的入口地址进行赋值

1
2
3
4
5
6
7
8
void OatFile::OatMethod::LinkMethod(ArtMethod* method) const {
CHECK(method != nullptr);
method->SetEntryPointFromQuickCompiledCode(GetQuickCode());
}

inline const void* OatFile::OatMethod::GetQuickCode() const {
return GetOatPointer<const void*>(GetCodeOffset());
}

至此,Class 的 Define 过程就结束了,可以看到主要是对 Class 对象进行内存分配和属性赋值。

数组 Class 的创建

对于数组的 Class,其数组元素是由 Class Loader 进行加载的,而本身则并不是,而是运行时创建的,具体实现在 ClassLinker::CreateArrayClass 方法中。

数组类的描述符是以 “[“ 中括号前缀的,如 “[C”、”[[[[B” 或 “[Ljava/lang/String;”

首先,通过递归 FindClass 方法获取元素的 Class

1
2
MutableHandle<mirror::Class> component_type(hs.NewHandle(FindClass(self, descriptor + 1,
class_loader)));

拿到元素的 Class 类型后,会断言其 null 或 void,之后判断当前 Class Loader 与 数组元素的 Class Loader 是否相同

1
2
3
4
5
6
7
8
if (class_loader.Get() != component_type->GetClassLoader()) {
// 如果 Class Loader 不同,那应该使用
ObjPtr<mirror::Class> new_class =
LookupClass(self, descriptor, hash, component_type->GetClassLoader());
if (new_class != nullptr) {
return new_class.Ptr();
}
}

接下来,对于元素 Class 为内置类型的 Array,赋值为预加载的 Class,而对于用户定义的 Class 则分配内存空间

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
auto new_class = hs.NewHandle<mirror::Class>(nullptr);
if (UNLIKELY(!init_done_)) {
// 内置类型
if (strcmp(descriptor, "[Ljava/lang/Class;") == 0) {
new_class.Assign(GetClassRoot(kClassArrayClass));
} else if (strcmp(descriptor, "[Ljava/lang/Object;") == 0) {
new_class.Assign(GetClassRoot(kObjectArrayClass));
} else if (strcmp(descriptor, GetClassRootDescriptor(kJavaLangStringArrayClass)) == 0) {
new_class.Assign(GetClassRoot(kJavaLangStringArrayClass));
} else if (strcmp(descriptor, "[C") == 0) {
new_class.Assign(GetClassRoot(kCharArrayClass));
} else if (strcmp(descriptor, "[I") == 0) {
new_class.Assign(GetClassRoot(kIntArrayClass));
} else if (strcmp(descriptor, "[J") == 0) {
new_class.Assign(GetClassRoot(kLongArrayClass));
}
}
// 非内置类型
if (new_class == nullptr) {
// 直接新开辟内存进行分配
new_class.Assign(AllocClass(self, mirror::Array::ClassSize(image_pointer_size_)));
if (new_class == nullptr) {
self->AssertPendingOOMException();
return nullptr;
}
new_class->SetComponentType(component_type.Get());
}

对 Class 的基本属性进行赋值

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
ObjPtr<mirror::Class> java_lang_Object = GetClassRoot(kJavaLangObject);
new_class->SetSuperClass(java_lang_Object);
new_class->SetVTable(java_lang_Object->GetVTable());
new_class->SetPrimitiveType(Primitive::kPrimNot);
new_class->SetClassLoader(component_type->GetClassLoader());
if (component_type->IsPrimitive()) {
new_class->SetClassFlags(mirror::kClassFlagNoReferenceFields);
} else {
new_class->SetClassFlags(mirror::kClassFlagObjectArray);
}
mirror::Class::SetStatus(new_class, mirror::Class::kStatusLoaded, self);
new_class->PopulateEmbeddedVTable(image_pointer_size_);
ImTable* object_imt = java_lang_Object->GetImt(image_pointer_size_);
new_class->SetImt(object_imt, image_pointer_size_);
mirror::Class::SetStatus(new_class, mirror::Class::kStatusInitialized, self);
{
// 单例接口 java/lang/Cloneable 和 java/io/Serializable
ObjPtr<mirror::IfTable> array_iftable = array_iftable_.Read();
CHECK(array_iftable != nullptr);
new_class->SetIfTable(array_iftable);
}

int access_flags = new_class->GetComponentType()->GetAccessFlags();
// 丢弃修饰符
access_flags &= kAccJavaFlagsMask;
// 添加 "abstract final"
access_flags |= kAccAbstract | kAccFinal;
access_flags &= ~kAccInterface;
new_class->SetAccessFlags(access_flags);

最后,置入 Class Table 中并返回

1
2
3
4
5
6
7
8
ObjPtr<mirror::Class> existing = InsertClass(descriptor, new_class.Get(), hash);
if (existing == nullptr) {
Runtime::Current()->GetRuntimeCallbacks()->ClassLoad(new_class);
Runtime::Current()->GetRuntimeCallbacks()->ClassPrepare(new_class, new_class);

jit::Jit::NewTypeLoadedIfUsingJit(new_class.Get());
return new_class.Get();
}

非启动类的寻找

对于非 Boot Class Loader 的类,Class 的加载是在 ClassLinker::FindClassInBaseDexClassLoader 方法中实现的

1
2
3
FindClassInBaseDexClassLoader(soa, self, descriptor, hash, class_loader, &result_ptr);
...
return result_ptr.Ptr();

首先,对 Boot Class Loader 进行判断,满足则跳转到 Boot Class 的流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
if (IsBootClassLoader(soa, class_loader.Get())) {
// The boot class loader, search the boot class path.
ClassPathEntry pair = FindInClassPath(descriptor, hash, boot_class_path_);
if (pair.second != nullptr) {
ObjPtr<mirror::Class> klass = LookupClass(self, descriptor, hash, nullptr);
if (klass != nullptr) {
*result = EnsureResolved(self, descriptor, klass);
} else {
*result = DefineClass(self,
descriptor,
hash,
ScopedNullHandle<mirror::ClassLoader>(),
*pair.first,
*pair.second);
}
if (*result == nullptr) {
CHECK(self->IsExceptionPending()) << descriptor;
self->ClearException();
}
} else {
*result = nullptr;
}
return true;
}

判断 Class 是否满足 PathClassLoader 或 DexClassLoader,否则为不支持的 Class Loader

1
2
3
4
5
6
7
8
9
// 不支持的 Class Loader
if (soa.Decode<mirror::Class>(WellKnownClasses::dalvik_system_PathClassLoader) !=
class_loader->GetClass()) {
if (soa.Decode<mirror::Class>(WellKnownClasses::dalvik_system_DexClassLoader) !=
class_loader->GetClass()) {
*result = nullptr;
return false;
}
}

之后,找到对应的 DexFile 地址

1
2
3
4
5
6
7
ArtField* const cookie_field =
jni::DecodeArtField(WellKnownClasses::dalvik_system_DexFile_cookie);
ArtField* const dex_file_field =
jni::DecodeArtField(WellKnownClasses::dalvik_system_DexPathList__Element_dexFile);
ObjPtr<mirror::Object> dex_path_list =
jni::DecodeArtField(WellKnownClasses::dalvik_system_BaseDexClassLoader_pathList)->
GetObject(class_loader.Get());

然后从 DexFile 中拿到 Class 定义,再走 Class 定义的流程就完成 Class 的加载

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
ObjPtr<mirror::Object> dex_file = dex_file_field->GetObject(element);
if (dex_file != nullptr) {
ObjPtr<mirror::LongArray> long_array = cookie_field->GetObject(dex_file)->AsLongArray();
if (long_array == nullptr) {
LOG(WARNING) << "Null DexFile::mCookie for " << descriptor;
break;
}
int32_t long_array_size = long_array->GetLength();
// 遍历
for (int32_t j = kDexFileIndexStart; j < long_array_size; ++j) {
const DexFile* cp_dex_file = reinterpret_cast<const DexFile*>(static_cast<uintptr_t>(
long_array->GetWithoutChecks(j)));
// 拿 Class 的定义
const DexFile::ClassDef* dex_class_def =
OatDexFile::FindClassDef(*cp_dex_file, descriptor, hash);
if (dex_class_def != nullptr) {
ObjPtr<mirror::Class> klass = DefineClass(self,
descriptor,
hash,
class_loader,
*cp_dex_file,
*dex_class_def);
if (klass == nullptr) {
CHECK(self->IsExceptionPending()) << descriptor;
self->ClearException();
return true;
}
*result = klass;
return true;
}
}

更新 Class Table

Class 寻找的最后一步,就是将已实例化的 Class 对象置入到 Class Table 中

1
2
3
4
5
6
7
8
9
ClassTable* const class_table = InsertClassTableForClassLoader(class_loader.Get());
old = class_table->Lookup(descriptor, hash);
if (old == nullptr) {
old = result_ptr;
if (descriptor_equals) {
class_table->InsertWithHash(result_ptr.Ptr(), hash);
Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(class_loader.Get());
}
}

Class Table 是 Native 层存放 Class 的集合类,在 Java 层表现为 Class Loader 中的 classTable 地址指针

获取 Class Table 的逻辑实现在 ClassLinker::InsertClassTableForClassLoader 方法中

1
2
3
4
5
6
7
8
9
10
11
12
ClassTable* ClassLinker::InsertClassTableForClassLoader(ObjPtr<mirror::ClassLoader> class_loader) {
if (class_loader == nullptr) {
return &boot_class_table_;
}
ClassTable* class_table = class_loader->GetClassTable();
if (class_table == nullptr) {
RegisterClassLoader(class_loader); // 开辟新空间存放 Class Table
class_table = class_loader->GetClassTable();
DCHECK(class_table != nullptr);
}
return class_table;
}

总结

回顾本文,跟进了基本类型 Class、数组类 Class、一般类 Class 查找和定义过程的 Native 层实现,能够让读者对 Android 中 Class 的加载过程有进一步的理解。而此时,本文对 Class 加载的分析就基本结束了,但对于理解完整的 Class 加载过程,文中提及的仅仅是冰山一角,还需要我们多钻研多学习。