-
-
[原创]加壳脱壳知识点总结--类加载、方法执行流程以及脱壳实战
-
发表于: 2024-6-11 18:12 6328
-
总结记录下ART环境下App启动流程中类加载流程以及相关知识,分析更深层次的脱壳点,加深对App加壳以及脱壳原理的理解。
环境:Android 8.0.0
这里直接从loadClass开始,DexClassloader,PathClassloader,InMemoryDexClassLoader这三个类的父类是BaseDexClassLoader,BaseDexClassLoader的父类是Classloader,在ClassLoader这个类里实现了loadClass。
protected Class<?> loadClass(String name, boolean resolve),这里官方的源码注释解释的比较清楚了,首先确定这个类是否被加载过,没有的话会开始走双亲委派的流程调用parent.loadClass,如果父加载器都没有加载过,则自己调用findClass开始查找class并加载
findClass在BaseDexClassLoader中重写了
DexPathList_public Class<?> findClass(String name, List<Throwable> suppressed) 这里的dexElements是在加载Dex时赋值的,保存的时当时加载的DexFile
Element_public Class<?> findClass(String name, ClassLoader definingContext,List<Throwable> suppressed),这个Element类是DexPathList的一个内部类
DexFile_loadClassBinaryName
DexFile_defineClass
DexFile_defineClassNative 这里进入了native层的DexFile中,这段代码在进行DexFile的注册。
__mirror::Class* ClassLinker::DefineClass__这里也是在初始化类,分配类空间等,有三个阶段SetupClass,LoadClass,LinkClass,关于类加载主要看LoadClass主要作用是将类的字段和方法信息从Dex文件中加载到内存中,并建立相应的数据结构。
ClassLinker::LoadClass
ClassLinker::LoadClassMembers 这里开始加载类的成员变量,方法,方法的加载有两步LoadMethod和LinkCode。
ClassLinker::LoadMethod LoadMethod为ArtMethod的基础属性赋值,并检查是否是构造函数,这里可以看到在设置CodeItemOffset,以前的函数抽取壳会在这个阶段回填字节码,通过hook LoadMethod即可脱到完整的Dex。
ClassLinker::LinkCode LinkCode的主要工作是把,以及一些相关操作例如分配空间,关联引用等,还有Native函数的绑定,最后会调用SetEntryPointFromQuickCompiledCode设置方法被调用时的入口,method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge())这段代码就是当oat被阻断后会把方法入口设置为解释执行入口。
类加载完成之后,一般就要调用类的方法了,所以继续看一下方法执行的流程,Android 8.0中主要是两种方法执行方式,解释执行和OAT的快速执行,解释执行主要是根据字节码执行方法,快速执行通过OAT中预先编译成的本地机器码来执行方法,对于加壳来说,阻断了OAT流程后系统会转向解释执行。
在安卓中,Java 函数可以通过两种主要的方式进行调用。一种是通过自然的代码执行路径进行调用,即在 Java 虚拟机中直接调用,另一种是通过 JNI进行调用,即通过本地代码与 Java 代码进行交互来实现函数调用,先说JNI调用的流程。
JNI调用Java函数主要是通过一系列的CallXXXMethod(+V代表无返回值+A代表参数以数组形式传递)JNI函数,这里找几个看一下实现方式,可以看到都调用了InvokeVirtualOrInterfaceWithVarArgs。
InvokeVirtualOrInterfaceWithVarArgs
InvokeWithArgArray
ArtMethod::invoke
这就到了比较关键的地方,通过反射和JNI调用都会走到这里,Invoke会判断方法调用的环境,方法类型,如果不是静态方法会进入art_quick_invoke_stub若目标方法已编译为快速路径,则经 INVOKE_STUB_CALL_AND_RETURN的汇编代码后,通过 PtrSizedFields 中的 entry_point_from_quick_compiled_code_ 跳转到目标方法的入口(entry_point_from_quick_compiled_code_ 也是自然通过代码执行Java代码的入口)。
这里有两种入口,一种是编译好的本地机器指令入口直接开始执行,另一种就是解释执行入口,在LinkCode函数说到当OAT被阻断后会调用method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge()),这样的话entry_point_from_quick_compiled_code_ 所指向的就是art_quick_to_interpreter_bridge这个桥函数了,这个桥函数也是汇编实现。
通过bl跳转到了artQuickToInterpreterBridge函数,之后的调用流程是artQuickToInterpreterBridge() → interpreter::EnterInterpreterFromEntryPoint() → interpreter::Execute()。
interpreter::Execute()
解释执行会通过kInterpreterImplKind的类型来判断执行哪种解释器,解释执行总的来说有三种方式goto型,汇编型和switch型,这三种的实现方式其实就和字面意思差不多,分别使用goto,汇编,switch来完成对字节码匹配执行,goto型在较早的版本还有,在本次分析的安卓8系统中已经不存在了,安卓8实现了汇编型和switch型,默认使用汇编型。
上面分析了类的加载流程和Java方法的调用流程,这里面大量出现了Dexfile,ArtMethod,两个地方都是可以用于脱壳,通过Dexfile可以直接dump Dexfile,而通过ArtMethod也可以间接获取到Dexfile对象,这里随便找一个,loadClassMember方法进行实战,还是用的frida hook的方式。
这里代码用上次的改一下即可
其实总结的知识点已经涉及到抽取壳脱壳了,抽取壳的脱壳后面再写。
https://blog.csdn.net/u013989732/article/details/80670989
https://blog.csdn.net/hl09083253cy/article/details/78418651
https://blog.csdn.net/hl09083253cy/article/details/78418702
https://rk700.github.io/2017/06/30/hook-on-android-n/
https://blog.csdn.net/u013989732/article/details/80717762/
public Class<?> loadClass(String name) throws ClassNotFoundException {
return
loadClass(name, false);
}
public Class<?> loadClass(String name) throws ClassNotFoundException {
return
loadClass(name, false);
}
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
/
/
First, check
if
the
class
has already been loaded
Class<?> c
=
findLoadedClass(name);
if
(c
=
=
null) {
try
{
if
(parent !
=
null) {
c
=
parent.loadClass(name, false);
}
else
{
c
=
findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
/
/
ClassNotFoundException thrown
if
class
not
found
/
/
from
the non
-
null parent
class
loader
}
if
(c
=
=
null) {
/
/
If still
not
found, then invoke findClass
in
order
/
/
to find the
class
.
c
=
findClass(name);
}
}
return
c;
}
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
/
/
First, check
if
the
class
has already been loaded
Class<?> c
=
findLoadedClass(name);
if
(c
=
=
null) {
try
{
if
(parent !
=
null) {
c
=
parent.loadClass(name, false);
}
else
{
c
=
findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
/
/
ClassNotFoundException thrown
if
class
not
found
/
/
from
the non
-
null parent
class
loader
}
if
(c
=
=
null) {
/
/
If still
not
found, then invoke findClass
in
order
/
/
to find the
class
.
c
=
findClass(name);
}
}
return
c;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
List
<Throwable> suppressedExceptions
=
new ArrayList<Throwable>();
Class c
=
pathList.findClass(name, suppressedExceptions);
if
(c
=
=
null) {
ClassNotFoundException cnfe
=
new ClassNotFoundException(
"Didn't find class \""
+
name
+
"\" on path: "
+
pathList);
for
(Throwable t : suppressedExceptions) {
cnfe.addSuppressed(t);
}
throw cnfe;
}
return
c;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
List
<Throwable> suppressedExceptions
=
new ArrayList<Throwable>();
Class c
=
pathList.findClass(name, suppressedExceptions);
if
(c
=
=
null) {
ClassNotFoundException cnfe
=
new ClassNotFoundException(
"Didn't find class \""
+
name
+
"\" on path: "
+
pathList);
for
(Throwable t : suppressedExceptions) {
cnfe.addSuppressed(t);
}
throw cnfe;
}
return
c;
}
public Class<?> findClass(String name,
List
<Throwable> suppressed) {
for
(Element element : dexElements) {
Class<?> clazz
=
element.findClass(name, definingContext, suppressed);
if
(clazz !
=
null) {
return
clazz;
}
}
if
(dexElementsSuppressedExceptions !
=
null) {
suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions));
}
return
null;
}
public Class<?> findClass(String name,
List
<Throwable> suppressed) {
for
(Element element : dexElements) {
Class<?> clazz
=
element.findClass(name, definingContext, suppressed);
if
(clazz !
=
null) {
return
clazz;
}
}
if
(dexElementsSuppressedExceptions !
=
null) {
suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions));
}
return
null;
}
public Class<?> findClass(String name, ClassLoader definingContext,
List
<Throwable> suppressed) {
return
dexFile !
=
null ? dexFile.loadClassBinaryName(name, definingContext, suppressed)
: null;
}
public Class<?> findClass(String name, ClassLoader definingContext,
List
<Throwable> suppressed) {
return
dexFile !
=
null ? dexFile.loadClassBinaryName(name, definingContext, suppressed)
: null;
}
public Class loadClassBinaryName(String name, ClassLoader loader,
List
<Throwable> suppressed) {
return
defineClass(name, loader, mCookie, this, suppressed);
}
public Class loadClassBinaryName(String name, ClassLoader loader,
List
<Throwable> suppressed) {
return
defineClass(name, loader, mCookie, this, suppressed);
}
private static Class defineClass(String name, ClassLoader loader,
Object
cookie,
DexFile dexFile,
List
<Throwable> suppressed) {
Class result
=
null;
try
{
result
=
defineClassNative(name, loader, cookie, dexFile);
} catch (NoClassDefFoundError e) {
if
(suppressed !
=
null) {
suppressed.add(e);
}
} catch (ClassNotFoundException e) {
if
(suppressed !
=
null) {
suppressed.add(e);
}
}
return
result;
}
private static Class defineClass(String name, ClassLoader loader,
Object
cookie,
DexFile dexFile,
List
<Throwable> suppressed) {
Class result
=
null;
try
{
result
=
defineClassNative(name, loader, cookie, dexFile);
} catch (NoClassDefFoundError e) {
if
(suppressed !
=
null) {
suppressed.add(e);
}
} catch (ClassNotFoundException e) {
if
(suppressed !
=
null) {
suppressed.add(e);
}
}
return
result;
}
static jclass DexFile_defineClassNative(JNIEnv
*
env,jclass,jstring javaName,jobject javaLoader, jobject cookie,jobject dexFile) {
...
for
(auto& dex_file : dex_files) {
const DexFile::ClassDef
*
dex_class_def
=
OatDexFile::FindClassDef(
*
dex_file, descriptor.c_str(),
hash
);
if
(dex_class_def !
=
nullptr) {
ScopedObjectAccess soa(env);
ClassLinker
*
class_linker
=
Runtime::Current()
-
>GetClassLinker();
StackHandleScope<
1
> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader(
hs.NewHandle(soa.Decode<mirror::ClassLoader>(javaLoader)));
ObjPtr<mirror::DexCache> dex_cache
=
class_linker
-
>RegisterDexFile(
*
dex_file, class_loader.Get());
if
(dex_cache
=
=
nullptr) {
/
/
OOME
or
InternalError (dexFile already registered with a different
class
loader).
soa.Self()
-
>AssertPendingException();
return
nullptr;
}
ObjPtr<mirror::Class> result
=
class_linker
-
>DefineClass(soa.Self(),descriptor.c_str(),
hash
,class_loader,
*
dex_file,
*
dex_class_def);
/
/
Add the used dex
file
. This only required
for
the DexFile.loadClass API since normal
/
/
class
loaders already keep their dex files live.
class_linker
-
>InsertDexFileInToClassLoader(soa.Decode<mirror::
Object
>(dexFile),class_loader.Get());
if
(result !
=
nullptr) {
VLOG(class_linker) <<
"DexFile_defineClassNative returning "
<< result
<<
" for "
<< class_name.c_str();
return
soa.AddLocalReference<jclass>(result);
}
}
}
VLOG(class_linker) <<
"Failed to find dex_class_def "
<< class_name.c_str();
return
nullptr;
}
static jclass DexFile_defineClassNative(JNIEnv
*
env,jclass,jstring javaName,jobject javaLoader, jobject cookie,jobject dexFile) {
...
for
(auto& dex_file : dex_files) {
const DexFile::ClassDef
*
dex_class_def
=
OatDexFile::FindClassDef(
*
dex_file, descriptor.c_str(),
hash
);
if
(dex_class_def !
=
nullptr) {
ScopedObjectAccess soa(env);
ClassLinker
*
class_linker
=
Runtime::Current()
-
>GetClassLinker();
StackHandleScope<
1
> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader(
hs.NewHandle(soa.Decode<mirror::ClassLoader>(javaLoader)));
ObjPtr<mirror::DexCache> dex_cache
=
class_linker
-
>RegisterDexFile(
*
dex_file, class_loader.Get());
if
(dex_cache
=
=
nullptr) {
/
/
OOME
or
InternalError (dexFile already registered with a different
class
loader).
soa.Self()
-
>AssertPendingException();
return
nullptr;
}
ObjPtr<mirror::Class> result
=
class_linker
-
>DefineClass(soa.Self(),descriptor.c_str(),
hash
,class_loader,
*
dex_file,
*
dex_class_def);
/
/
Add the used dex
file
. This only required
for
the DexFile.loadClass API since normal
/
/
class
loaders already keep their dex files live.
class_linker
-
>InsertDexFileInToClassLoader(soa.Decode<mirror::
Object
>(dexFile),class_loader.Get());
if
(result !
=
nullptr) {
VLOG(class_linker) <<
"DexFile_defineClassNative returning "
<< result
<<
" for "
<< class_name.c_str();
return
soa.AddLocalReference<jclass>(result);
}
}
}
VLOG(class_linker) <<
"Failed to find dex_class_def "
<< class_name.c_str();
return
nullptr;
}
mirror::Class
*
ClassLinker::DefineClass(Thread
*
self
,const char
*
escriptor,size_t
hash
,Handle<mirrr::ClassLoader> class_loader,const DexFile& dex_file,const DexFile::ClassDef dex_class_def) {
...
klass
-
>SetDexCache(dex_cache);
SetupClass(
*
new_dex_file,
*
new_class_def, klass, class_loader.Get());
...
/
/
Load the fields
and
other things after we arenserted
in
the table. This
is
so that we don't
/
/
end up allocating unfree
-
able linear alloc rources
and
then lose the race condition. The
/
/
other reason
is
that the field roots are onlvisited
from
the
class
table. So we need to be
/
/
inserted before we allocate
/
fill
in
these field
LoadClass(
self
,
*
new_dex_file,
*
new_class_def, klass);
...
if
(!LinkClass(
self
, descriptor, klass, interfaces, &h_new_class)) {
/
/
Linking failed.
if
(!klass
-
>IsErroneous()) {
mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorUnresolved,
self
);
}
return
nullptr;
}
...
mirror::Class
*
ClassLinker::DefineClass(Thread
*
self
,const char
*
escriptor,size_t
hash
,Handle<mirrr::ClassLoader> class_loader,const DexFile& dex_file,const DexFile::ClassDef dex_class_def) {
...
klass
-
>SetDexCache(dex_cache);
SetupClass(
*
new_dex_file,
*
new_class_def, klass, class_loader.Get());
...
/
/
Load the fields
and
other things after we arenserted
in
the table. This
is
so that we don't
/
/
end up allocating unfree
-
able linear alloc rources
and
then lose the race condition. The
/
/
other reason
is
that the field roots are onlvisited
from
the
class
table. So we need to be
/
/
inserted before we allocate
/
fill
in
these field
LoadClass(
self
,
*
new_dex_file,
*
new_class_def, klass);
...
if
(!LinkClass(
self
, descriptor, klass, interfaces, &h_new_class)) {
/
/
Linking failed.
if
(!klass
-
>IsErroneous()) {
mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorUnresolved,
self
);
}
return
nullptr;
}
...
void ClassLinker::LoadClass(Thread
*
self
,
const DexFile& dex_file,
const DexFile::ClassDef& dex_class_def,
Handle<mirror::Class> klass) {
const uint8_t
*
class_data
=
dex_file.GetClassData(dex_class_def);
if
(class_data
=
=
nullptr) {
return
;
/
/
no fields
or
methods
-
for
example a marker interface
}
LoadClassMembers(
self
, dex_file, class_data, klass);
}
void ClassLinker::LoadClass(Thread
*
self
,
const DexFile& dex_file,
const DexFile::ClassDef& dex_class_def,
Handle<mirror::Class> klass) {
const uint8_t
*
class_data
=
dex_file.GetClassData(dex_class_def);
if
(class_data
=
=
nullptr) {
return
;
/
/
no fields
or
methods
-
for
example a marker interface
}
LoadClassMembers(
self
, dex_file, class_data, klass);
}
void ClassLinker::LoadClassMembers(Thread
*
self
,const DexFile& dex_file,const uint8_t
*
class_data,Handle<mirror::Class> klass) {
{
/
/
Note: We cannot have thread suspension until the field
and
method arrays are setup
or
else
/
/
Class::VisitFieldRoots may miss some fields
or
methods.
ScopedAssertNoThreadSuspension nts(__FUNCTION__);
/
/
Load static fields.
...
for
(; it.HasNextStaticField(); it.
Next
()) {
uint32_t field_idx
=
it.GetMemberIndex();
DCHECK_GE(field_idx, last_field_idx);
/
/
Ordering enforced by DexFileVerifier.
if
(num_sfields
=
=
0
|| LIKELY(field_idx > last_field_idx)) {
DCHECK_LT(num_sfields, it.NumStaticFields());
LoadField(it, klass, &sfields
-
>At(num_sfields));
+
+
num_sfields;
last_field_idx
=
field_idx;
}
}
/
/
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;
}
}
...
/
/
Set
the field arrays.
klass
-
>SetSFieldsPtr(sfields);
DCHECK_EQ(klass
-
>NumStaticFields(), num_sfields);
klass
-
>SetIFieldsPtr(ifields);
DCHECK_EQ(klass
-
>NumInstanceFields(), num_ifields);
/
/
Load methods.
bool
has_oat_class
=
false;
const OatFile::OatClass oat_class
=
(Runtime::Current()
-
>IsStarted() && !Runtime::Current()
-
>IsAotCompiler())
? OatFile::FindOatClass(dex_file, klass
-
>GetDexClassDefIndex(), &has_oat_class)
: OatFile::OatClass::Invalid();
const OatFile::OatClass
*
oat_class_ptr
=
has_oat_class ? &oat_class : nullptr;
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
;
/
/
TODO These should really use the iterators.
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) {
/
/
duplicate case
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
+
+
;
}
DCHECK(!it.HasNext());
}
/
/
Ensure that the card
is
marked so that remembered sets pick up native roots.
Runtime::Current()
-
>GetHeap()
-
>WriteBarrierEveryFieldOf(klass.Get());
self
-
>AllowThreadSuspension();
}
void ClassLinker::LoadClassMembers(Thread
*
self
,const DexFile& dex_file,const uint8_t
*
class_data,Handle<mirror::Class> klass) {
{
/
/
Note: We cannot have thread suspension until the field
and
method arrays are setup
or
else
/
/
Class::VisitFieldRoots may miss some fields
or
methods.
ScopedAssertNoThreadSuspension nts(__FUNCTION__);
/
/
Load static fields.
...
for
(; it.HasNextStaticField(); it.
Next
()) {
uint32_t field_idx
=
it.GetMemberIndex();
DCHECK_GE(field_idx, last_field_idx);
/
/
Ordering enforced by DexFileVerifier.
if
(num_sfields
=
=
0
|| LIKELY(field_idx > last_field_idx)) {
DCHECK_LT(num_sfields, it.NumStaticFields());
LoadField(it, klass, &sfields
-
>At(num_sfields));
+
+
num_sfields;
last_field_idx
=
field_idx;
}
}
/
/
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;
}
}
...
/
/
Set
the field arrays.
klass
-
>SetSFieldsPtr(sfields);
DCHECK_EQ(klass
-
>NumStaticFields(), num_sfields);
klass
-
>SetIFieldsPtr(ifields);
DCHECK_EQ(klass
-
>NumInstanceFields(), num_ifields);
/
/
Load methods.
bool
has_oat_class
=
false;
const OatFile::OatClass oat_class
=
(Runtime::Current()
-
>IsStarted() && !Runtime::Current()
-
>IsAotCompiler())
? OatFile::FindOatClass(dex_file, klass
-
>GetDexClassDefIndex(), &has_oat_class)
: OatFile::OatClass::Invalid();
const OatFile::OatClass
*
oat_class_ptr
=
has_oat_class ? &oat_class : nullptr;
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
;
/
/
TODO These should really use the iterators.
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) {
/
/
duplicate case
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
+
+
;
}
DCHECK(!it.HasNext());
}
/
/
Ensure that the card
is
marked so that remembered sets pick up native roots.
Runtime::Current()
-
>GetHeap()
-
>WriteBarrierEveryFieldOf(klass.Get());
self
-
>AllowThreadSuspension();
}
void ClassLinker::LoadMethod(const DexFile& dex_file,const ClassDataItemIterator& it,Handle<mirror::Class> klass,ArtMethod
*
dst) {
uint32_t dex_method_idx
=
it.GetMemberIndex();
const DexFile::MethodId& method_id
=
dex_file.GetMethodId(dex_method_idx);
const char
*
method_name
=
dex_file.StringDataByIdx(method_id.name_idx_);
ScopedAssertNoThreadSuspension ants(
"LoadMethod"
);
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
)) {
}
else
if
(method_name[
0
]
=
=
'<'
) {
/
/
Fix broken access flags
for
initializers. Bug
11157540.
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
{
...
}
}
dst
-
>SetAccessFlags(access_flags);
}
void ClassLinker::LoadMethod(const DexFile& dex_file,const ClassDataItemIterator& it,Handle<mirror::Class> klass,ArtMethod
*
dst) {
uint32_t dex_method_idx
=
it.GetMemberIndex();
const DexFile::MethodId& method_id
=
dex_file.GetMethodId(dex_method_idx);
const char
*
method_name
=
dex_file.StringDataByIdx(method_id.name_idx_);
ScopedAssertNoThreadSuspension ants(
"LoadMethod"
);
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
)) {
}
else
if
(method_name[
0
]
=
=
'<'
) {
/
/
Fix broken access flags
for
initializers. Bug
11157540.
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
{
...
}
}
dst
-
>SetAccessFlags(access_flags);
}
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!