-
-
[原创]ART/Dalvik环境下Xposed实现异同分析
-
发表于: 2021-4-29 19:17 5233
-
写了一部分,先占个坑,后续补完
了解到ART/Dalvik
的异同之后,我们再来看看我们的主题,当Android虚拟机
从Dalvik
到ART
,Xposed
针对这种变化对其底层实现逻辑做了哪些变更呢?
首先从源头入手,Xposed
框架在编译app_main
文件时做了系统适配处理,针对不同版本的系统使用不同的app_main
文件
那么下面我们分析下这两份文件的实现
可以看到,在两份文件中针对AppRuntime
类的修改大致是相同的,同样都是调用了xposed::onVmCreated
到目前为止可以看到关于xposed::onVmCreated
的调用流程最终走到了两份文件自己的onVmCreated
方法,下面来看看这两个方法的差异
Dalvik
版本的onVmCreated
函数做的是为Java层invokeOriginalMethodNative
设置Native方法,将原本的方法转成native
的XposedBridge_invokeOriginalMethodNative
方法,再回调Java
层的方法
ART
版本的onVmCreated
函数做的是为ArtMethod
赋值,classXposedBridge
和methodXposedBridgeHandleHookedMethod
都是之前在initXposedBridge
函数中设置好的
现在关于onVmCreated
的函数变更已经分析好了,下面正式开始分析main
函数
同样都是调用xposed::initialize
函数
xposed::initialize
函数主要做了些初始化的工作:为xposed
结构体赋值、启动各个子线程、最后将xposed_bridge.jar
引入,执行完xposed::initialize
函数之后会返回一个isXposedLoaded
标识,会根据这个标识决定是否具体传入的包名,之前步骤执行正确的话传入的包名应该是"de.robv.android.xposed.XposedBridge"
,来看看具体的runtime.start
函数是怎样执行的
runtime.start
函数调用的是AndroidRuntime
的start
函数,关键点在于startVm
(虚拟机的创建)、onVmCreated
(虚拟机创建完成之后的初始化),CallStaticVoidMethod main
(反射调用类的main函数),onVmCreated
已经分析过了,下面分析下XposedBridge
的main
函数
XposedBridge.main
函数关键在于三个函数的调用:
我们重点关注下initForZygote
和loadModules
两个方法
我们分成几部分来看
nativeForkAndSpecialize
和nativeForkSystemServer
同样都是利用Zygote
利用fork
来创建子进程的,我们看下Xposed
框架会对这两个方法做什么操作
closeFilesBeforeForkNative
和reopenFilesAfterForkNative
这两个方法同属于native
,属于XposedBridge
的native
方法一般都是在initXposedBridge
中动态注册的,方法是存在于各自的libxposed_xxx.so
文件当中,不过这两个方法只存在于高版本系统中
这一部分的主要逻辑是针对ActivityThread
的handleBindApplication
方法做了hook
操作,具体的操作就是设置ActivityThread
的mBoundApplication
的值,并实例化LoadPackageParam
进行赋值,这里的LoadPackageParam
实例也就是我们在开发过程中的lpparam
了
我们从代码中已经知道了当lpparam
封装好之后会调用它的callbacks
数组每个对象的handleLoadPackage
方法,那这个数组是什么时候被赋值的呢?从代码中可以发现数组是XposedBridge.sLoadedPackageCallbacks
,它在下面这段代码中被赋值
hookLoadPackage
是在loadModules
方法中被调用,这个部分我们在loadModules
的时候再说
这一部分和上一部分道理相同,只是Hook
点的不同,一个是针对App
启动过程中,一个是针对system server
对于loadModules
的流程我们也大致了解了
那么,对于xposed::initialize
函数的分析就到这里,到目前为止,我们梳理完了Xposed
框架的启动流程以及它在启动过程中做了哪些工作,当然,我们的主题是ART/Dalvik
环境下Xposed
框架实现的异同,我们在app_main
文件变更这个步骤只发现了它们对于onVmCreated
的实现做了改变
从刚才的initForZygote
函数中,我们可以发现使用了大量的findAndHookMethod
,当然,这个函数也是我们在接触Xposed
框架的时候最先学会的函数,标准的模板调用是这么来使用的
我们跟踪下findAndHookMethod
的实现
先来看看Dalvik
时期的,XposedBridge_hookMethodNative
实现在libxposed_dalvik.cpp
文件中
invokeOriginalMethodNative
是native
函数,想想它是在什么时候变成native
函数的呢?
在onVmCreated
函数执行的时候,回顾一下
通过dvmSetNativeFunc
将xposedInvokeOriginalMethodNative
的真正执行函数变为xposedInvokeOriginalMethodNative
xposedInvokeOriginalMethodNative
方法我们之前也分析过,主要是通过dvmInvokeMethod
来反射调用Java
层的方法
分析完了Dalvik
时期的hookMethodNative
流程,下面来看看ART
时期的hookMethodNative
做了哪些改变,省略掉相同的步骤,我们直接看libxposed_art.cpp
的XposedBridge_hookMethodNative
函数实现
关键点在于函数的入口点的替换,由entry_point_from_quick_compiled_code_
替换成了GetQuickProxyInvokeHandler
看看GetQuickProxyInvokeHandler
的实现
GetQuickProxyInvokeHandler
的具体逻辑由art_quick_proxy_invoke_handler
方法来实现
从汇编文件入手
回到handleHookedMethod
方法之后就和dalvik
的执行逻辑一样了
[1] https://bbs.pediy.com/thread-257844.htm
[2] https://blog.csdn.net/zjx839524906/article/details/81046844
# Android.mk
# PLATFORM_SDK_VERSION字段
# 参考xref: /build/core/version_defaults.mk
# PLATFORM_VERSION := 7.1.2
# PLATFORM_SDK_VERSION := 25
# 根据系统版本不同,7以上的版本使用app_main2.cpp来编译
ifeq (
1
,$(strip $(shell expr $(PLATFORM_SDK_VERSION) \>
=
21
)))
LOCAL_SRC_FILES :
=
app_main2.cpp
LOCAL_MULTILIB :
=
both
LOCAL_MODULE_STEM_32 :
=
app_process32_xposed
LOCAL_MODULE_STEM_64 :
=
app_process64_xposed
else
LOCAL_SRC_FILES :
=
app_main.cpp
LOCAL_MODULE_STEM :
=
app_process_xposed
endif
##########################################################
# Library for Dalvik-/ART-specific functions
##########################################################
# 针对libxposed_xxx.cpp文件也是同样的道理
ifeq (
1
,$(strip $(shell expr $(PLATFORM_SDK_VERSION) \>
=
21
)))
include frameworks
/
base
/
cmds
/
xposed
/
ART.mk
else
include frameworks
/
base
/
cmds
/
xposed
/
Dalvik.mk
endif
# Android.mk
# PLATFORM_SDK_VERSION字段
# 参考xref: /build/core/version_defaults.mk
# PLATFORM_VERSION := 7.1.2
# PLATFORM_SDK_VERSION := 25
# 根据系统版本不同,7以上的版本使用app_main2.cpp来编译
ifeq (
1
,$(strip $(shell expr $(PLATFORM_SDK_VERSION) \>
=
21
)))
LOCAL_SRC_FILES :
=
app_main2.cpp
LOCAL_MULTILIB :
=
both
LOCAL_MODULE_STEM_32 :
=
app_process32_xposed
LOCAL_MODULE_STEM_64 :
=
app_process64_xposed
else
LOCAL_SRC_FILES :
=
app_main.cpp
LOCAL_MODULE_STEM :
=
app_process_xposed
endif
##########################################################
# Library for Dalvik-/ART-specific functions
##########################################################
# 针对libxposed_xxx.cpp文件也是同样的道理
ifeq (
1
,$(strip $(shell expr $(PLATFORM_SDK_VERSION) \>
=
21
)))
include frameworks
/
base
/
cmds
/
xposed
/
ART.mk
else
include frameworks
/
base
/
cmds
/
xposed
/
Dalvik.mk
endif
/
/
xposed.cpp
/
*
*
Load the libxposed_
*
.so library
for
the currently active runtime.
*
/
/
/
同样都是调用了xposed.cpp的onVmCreated函数
void onVmCreated(JNIEnv
*
env) {
/
/
Determine the currently active runtime
/
/
初始化xposed lib路径
const char
*
xposedLibPath
=
NULL;
/
/
轮询
/
proc
/
self
/
maps结果,查看系统到底是art还是dalvik再决定赋值
/
/
xposed.h
/
/
#define XPOSED_LIB_DALVIK XPOSED_LIB_DIR "libxposed_dalvik.so"
/
/
#define XPOSED_LIB_ART XPOSED_LIB_DIR "libxposed_art.so"
if
(!determineRuntime(&xposedLibPath)) {
ALOGE(
"Could not determine runtime, not loading Xposed"
);
return
;
}
/
/
通过dlopen so文件,so文件由之前的determineRuntime函数配置
/
/
Load the suitable libxposed_
*
.so
for
it
void
*
xposedLibHandle
=
dlopen(xposedLibPath, RTLD_NOW);
if
(!xposedLibHandle) {
ALOGE(
"Could not load libxposed: %s"
, dlerror());
return
;
}
/
/
Clear previous errors
dlerror();
/
/
Initialize the library
/
/
dlsym 执行so文件中xposedInitLib函数,so文件就是上面被赋值的文件
bool
(
*
xposedInitLib)(XposedShared
*
shared)
=
NULL;
*
(void
*
*
) (&xposedInitLib)
=
dlsym(xposedLibHandle,
"xposedInitLib"
);
if
(!xposedInitLib) {
ALOGE(
"Could not find function xposedInitLib"
);
return
;
}
/
/
xposedInitLib函数如下,赋予xposed的onVmCreated为onVmCreatedCommon
/
/
也就是libxposed_common.cpp的onVmCreatedCommon方法
/
/
bool
xposedInitLib(XposedShared
*
shared) {
/
/
xposed
=
shared;
/
/
xposed
-
>onVmCreated
=
&onVmCreatedCommon;
/
/
return
true;
/
/
}
#if XPOSED_WITH_SELINUX
xposed
-
>zygoteservice_accessFile
=
&service::membased::accessFile;
xposed
-
>zygoteservice_statFile
=
&service::membased::statFile;
xposed
-
>zygoteservice_readFile
=
&service::membased::readFile;
#endif // XPOSED_WITH_SELINUX
/
/
方法返回true,执行onVmCreatedCommon方法,到目前为止,流程都是相同的
if
(xposedInitLib(xposed)) {
xposed
-
>onVmCreated(env);
}
}
/
/
xposed.cpp
/
*
*
Load the libxposed_
*
.so library
for
the currently active runtime.
*
/
/
/
同样都是调用了xposed.cpp的onVmCreated函数
void onVmCreated(JNIEnv
*
env) {
/
/
Determine the currently active runtime
/
/
初始化xposed lib路径
const char
*
xposedLibPath
=
NULL;
/
/
轮询
/
proc
/
self
/
maps结果,查看系统到底是art还是dalvik再决定赋值
/
/
xposed.h
/
/
#define XPOSED_LIB_DALVIK XPOSED_LIB_DIR "libxposed_dalvik.so"
/
/
#define XPOSED_LIB_ART XPOSED_LIB_DIR "libxposed_art.so"
if
(!determineRuntime(&xposedLibPath)) {
ALOGE(
"Could not determine runtime, not loading Xposed"
);
return
;
}
/
/
通过dlopen so文件,so文件由之前的determineRuntime函数配置
/
/
Load the suitable libxposed_
*
.so
for
it
void
*
xposedLibHandle
=
dlopen(xposedLibPath, RTLD_NOW);
if
(!xposedLibHandle) {
ALOGE(
"Could not load libxposed: %s"
, dlerror());
return
;
}
/
/
Clear previous errors
dlerror();
/
/
Initialize the library
/
/
dlsym 执行so文件中xposedInitLib函数,so文件就是上面被赋值的文件
bool
(
*
xposedInitLib)(XposedShared
*
shared)
=
NULL;
*
(void
*
*
) (&xposedInitLib)
=
dlsym(xposedLibHandle,
"xposedInitLib"
);
if
(!xposedInitLib) {
ALOGE(
"Could not find function xposedInitLib"
);
return
;
}
/
/
xposedInitLib函数如下,赋予xposed的onVmCreated为onVmCreatedCommon
/
/
也就是libxposed_common.cpp的onVmCreatedCommon方法
/
/
bool
xposedInitLib(XposedShared
*
shared) {
/
/
xposed
=
shared;
/
/
xposed
-
>onVmCreated
=
&onVmCreatedCommon;
/
/
return
true;
/
/
}
#if XPOSED_WITH_SELINUX
xposed
-
>zygoteservice_accessFile
=
&service::membased::accessFile;
xposed
-
>zygoteservice_statFile
=
&service::membased::statFile;
xposed
-
>zygoteservice_readFile
=
&service::membased::readFile;
#endif // XPOSED_WITH_SELINUX
/
/
方法返回true,执行onVmCreatedCommon方法,到目前为止,流程都是相同的
if
(xposedInitLib(xposed)) {
xposed
-
>onVmCreated(env);
}
}
/
/
libxposed_common.cpp
/
/
两份文件公有部分
void onVmCreatedCommon(JNIEnv
*
env) {
/
/
判断xposed_bridge.jar是否正常载入以及zygote服务启动是否正常
if
(!initXposedBridge(env) || !initZygoteService(env)) {
return
;
}
/
/
判断虚拟机是否正常启动,这里调用onVmCreated就是libxposed_xx.so文件中自己的onVmCreated函数了,这里应该就是第一个变化点
if
(!onVmCreated(env)) {
return
;
}
/
/
多重判断之后,返回xposed已正确安装标识
xposedLoadedSuccessfully
=
true;
return
;
}
bool
initXposedBridge(JNIEnv
*
env) {
/
/
#define CLASS_XPOSED_BRIDGE "de/robv/android/xposed/XposedBridge"
/
/
通过FindClass获取XposedBridge类,判断xposed_bridge类是否正常加载
classXposedBridge
=
env
-
>FindClass(CLASS_XPOSED_BRIDGE);
if
(classXposedBridge
=
=
NULL) {
ALOGE(
"Error while loading Xposed class '%s':"
, CLASS_XPOSED_BRIDGE);
logExceptionStackTrace();
env
-
>ExceptionClear();
return
false;
}
/
/
PS:这里没有理解做了什么
classXposedBridge
=
reinterpret_cast<jclass>(env
-
>NewGlobalRef(classXposedBridge));
ALOGI(
"Found Xposed class '%s', now initializing"
, CLASS_XPOSED_BRIDGE);
/
/
xposed_bridge的函数是否通过RegisterNatives动态注册成功
if
(register_natives_XposedBridge(env, classXposedBridge) !
=
JNI_OK) {
ALOGE(
"Could not register natives for '%s'"
, CLASS_XPOSED_BRIDGE);
logExceptionStackTrace();
env
-
>ExceptionClear();
return
false;
}
/
/
判断通过jni获取handleHookedMethod函数是否成功
methodXposedBridgeHandleHookedMethod
=
env
-
>GetStaticMethodID(classXposedBridge,
"handleHookedMethod"
,
"(Ljava/lang/reflect/Member;ILjava/lang/Object;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"
);
if
(methodXposedBridgeHandleHookedMethod
=
=
NULL) {
ALOGE(
"ERROR: could not find method %s.handleHookedMethod(Member, int, Object, Object, Object[])"
, CLASS_XPOSED_BRIDGE);
logExceptionStackTrace();
env
-
>ExceptionClear();
return
false;
}
return
true;
}
int
register_natives_XposedBridge(JNIEnv
*
env, jclass clazz) {
/
/
动态注册XposedBridge相关的函数,形式如XposedBridge_hookMethodNative
const JNINativeMethod methods[]
=
{
NATIVE_METHOD(XposedBridge, hadInitErrors,
"()Z"
),
NATIVE_METHOD(XposedBridge, getStartClassName,
"()Ljava/lang/String;"
),
NATIVE_METHOD(XposedBridge, getRuntime,
"()I"
),
NATIVE_METHOD(XposedBridge, startsSystemServer,
"()Z"
),
NATIVE_METHOD(XposedBridge, getXposedVersion,
"()I"
),
NATIVE_METHOD(XposedBridge, initXResourcesNative,
"()Z"
),
/
/
关键函数,之后在findandhook中会涉及
NATIVE_METHOD(XposedBridge, hookMethodNative,
"(Ljava/lang/reflect/Member;Ljava/lang/Class;ILjava/lang/Object;)V"
),
NATIVE_METHOD(XposedBridge, setObjectClassNative,
"(Ljava/lang/Object;Ljava/lang/Class;)V"
),
NATIVE_METHOD(XposedBridge, dumpObjectNative,
"(Ljava/lang/Object;)V"
),
NATIVE_METHOD(XposedBridge, cloneToSubclassNative,
"(Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;"
),
NATIVE_METHOD(XposedBridge, removeFinalFlagNative,
"(Ljava/lang/Class;)V"
),
#if PLATFORM_SDK_VERSION >= 21
NATIVE_METHOD(XposedBridge, invokeOriginalMethodNative,
"!(Ljava/lang/reflect/Member;I[Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"
),
NATIVE_METHOD(XposedBridge, closeFilesBeforeForkNative,
"()V"
),
NATIVE_METHOD(XposedBridge, reopenFilesAfterForkNative,
"()V"
),
#endif
#if PLATFORM_SDK_VERSION >= 24
NATIVE_METHOD(XposedBridge, invalidateCallersNative,
"([Ljava/lang/reflect/Member;)V"
),
#endif
};
return
env
-
>RegisterNatives(clazz, methods, NELEM(methods));
}
/
/
libxposed_common.cpp
/
/
两份文件公有部分
void onVmCreatedCommon(JNIEnv
*
env) {
/
/
判断xposed_bridge.jar是否正常载入以及zygote服务启动是否正常
if
(!initXposedBridge(env) || !initZygoteService(env)) {
return
;
}
/
/
判断虚拟机是否正常启动,这里调用onVmCreated就是libxposed_xx.so文件中自己的onVmCreated函数了,这里应该就是第一个变化点
if
(!onVmCreated(env)) {
return
;
}
/
/
多重判断之后,返回xposed已正确安装标识
xposedLoadedSuccessfully
=
true;
return
;
}
bool
initXposedBridge(JNIEnv
*
env) {
/
/
#define CLASS_XPOSED_BRIDGE "de/robv/android/xposed/XposedBridge"
/
/
通过FindClass获取XposedBridge类,判断xposed_bridge类是否正常加载
classXposedBridge
=
env
-
>FindClass(CLASS_XPOSED_BRIDGE);
if
(classXposedBridge
=
=
NULL) {
ALOGE(
"Error while loading Xposed class '%s':"
, CLASS_XPOSED_BRIDGE);
logExceptionStackTrace();
env
-
>ExceptionClear();
return
false;
}
/
/
PS:这里没有理解做了什么
classXposedBridge
=
reinterpret_cast<jclass>(env
-
>NewGlobalRef(classXposedBridge));
ALOGI(
"Found Xposed class '%s', now initializing"
, CLASS_XPOSED_BRIDGE);
/
/
xposed_bridge的函数是否通过RegisterNatives动态注册成功
if
(register_natives_XposedBridge(env, classXposedBridge) !
=
JNI_OK) {
ALOGE(
"Could not register natives for '%s'"
, CLASS_XPOSED_BRIDGE);
logExceptionStackTrace();
env
-
>ExceptionClear();
return
false;
}
/
/
判断通过jni获取handleHookedMethod函数是否成功
methodXposedBridgeHandleHookedMethod
=
env
-
>GetStaticMethodID(classXposedBridge,
"handleHookedMethod"
,
"(Ljava/lang/reflect/Member;ILjava/lang/Object;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"
);
if
(methodXposedBridgeHandleHookedMethod
=
=
NULL) {
ALOGE(
"ERROR: could not find method %s.handleHookedMethod(Member, int, Object, Object, Object[])"
, CLASS_XPOSED_BRIDGE);
logExceptionStackTrace();
env
-
>ExceptionClear();
return
false;
}
return
true;
}
int
register_natives_XposedBridge(JNIEnv
*
env, jclass clazz) {
/
/
动态注册XposedBridge相关的函数,形式如XposedBridge_hookMethodNative
const JNINativeMethod methods[]
=
{
NATIVE_METHOD(XposedBridge, hadInitErrors,
"()Z"
),
NATIVE_METHOD(XposedBridge, getStartClassName,
"()Ljava/lang/String;"
),
NATIVE_METHOD(XposedBridge, getRuntime,
"()I"
),
NATIVE_METHOD(XposedBridge, startsSystemServer,
"()Z"
),
NATIVE_METHOD(XposedBridge, getXposedVersion,
"()I"
),
NATIVE_METHOD(XposedBridge, initXResourcesNative,
"()Z"
),
/
/
关键函数,之后在findandhook中会涉及
NATIVE_METHOD(XposedBridge, hookMethodNative,
"(Ljava/lang/reflect/Member;Ljava/lang/Class;ILjava/lang/Object;)V"
),
NATIVE_METHOD(XposedBridge, setObjectClassNative,
"(Ljava/lang/Object;Ljava/lang/Class;)V"
),
NATIVE_METHOD(XposedBridge, dumpObjectNative,
"(Ljava/lang/Object;)V"
),
NATIVE_METHOD(XposedBridge, cloneToSubclassNative,
"(Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;"
),
NATIVE_METHOD(XposedBridge, removeFinalFlagNative,
"(Ljava/lang/Class;)V"
),
#if PLATFORM_SDK_VERSION >= 21
NATIVE_METHOD(XposedBridge, invokeOriginalMethodNative,
"!(Ljava/lang/reflect/Member;I[Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"
),
NATIVE_METHOD(XposedBridge, closeFilesBeforeForkNative,
"()V"
),
NATIVE_METHOD(XposedBridge, reopenFilesAfterForkNative,
"()V"
),
#endif
#if PLATFORM_SDK_VERSION >= 24
NATIVE_METHOD(XposedBridge, invalidateCallersNative,
"([Ljava/lang/reflect/Member;)V"
),
#endif
};
return
env
-
>RegisterNatives(clazz, methods, NELEM(methods));
}
/
/
libxposed_dalvik.cpp
/
*
*
Called very early during VM startup.
*
/
bool
onVmCreated(JNIEnv
*
env) {
if
(!initMemberOffsets(env))
return
false;
/
/
#define CLASS_MIUI_RESOURCES "android/content/res/MiuiResources"
jclass classMiuiResources
=
env
-
>FindClass(CLASS_MIUI_RESOURCES);
if
(classMiuiResources !
=
NULL) {
ClassObject
*
clazz
=
(ClassObject
*
)dvmDecodeIndirectRef(dvmThreadSelf(), classMiuiResources);
if
(dvmIsFinalClass(clazz)) {
ALOGD(
"Removing final flag for class '%s'"
, CLASS_MIUI_RESOURCES);
clazz
-
>accessFlags &
=
~ACC_FINAL;
}
}
env
-
>ExceptionClear();
/
/
关键点
/
/
获取invokeOriginalMethodNative方法的jmethodId
/
/
将invokeOriginalMethodNative的native方法关联到XposedBridge_invokeOriginalMethodNative方法,为后续调用的时候使用
Method
*
xposedInvokeOriginalMethodNative
=
(Method
*
) env
-
>GetStaticMethodID(classXposedBridge,
"invokeOriginalMethodNative"
,
"(Ljava/lang/reflect/Member;I[Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"
);
if
(xposedInvokeOriginalMethodNative
=
=
NULL) {
ALOGE(
"ERROR: could not find method %s.invokeOriginalMethodNative(Member, int, Class[], Class, Object, Object[])"
, CLASS_XPOSED_BRIDGE);
dvmLogExceptionStackTrace();
env
-
>ExceptionClear();
return
false;
}
dvmSetNativeFunc(xposedInvokeOriginalMethodNative, XposedBridge_invokeOriginalMethodNative, NULL);
objectArrayClass
=
dvmFindArrayClass(
"[Ljava/lang/Object;"
, NULL);
if
(objectArrayClass
=
=
NULL) {
ALOGE(
"Error while loading Object[] class"
);
dvmLogExceptionStackTrace();
env
-
>ExceptionClear();
return
false;
}
return
true;
}
void XposedBridge_invokeOriginalMethodNative(const u4
*
args, JValue
*
pResult,
const Method
*
method, ::Thread
*
self
) {
/
/
获取method
Method
*
meth
=
(Method
*
) args[
1
];
if
(meth
=
=
NULL) {
/
/
反射获取
meth
=
dvmGetMethodFromReflectObj((
Object
*
) args[
0
]);
if
(isMethodHooked(meth)) {
meth
=
(Method
*
) meth
-
>insns;
}
}
ArrayObject
*
params
=
(ArrayObject
*
) args[
2
];
ClassObject
*
returnType
=
(ClassObject
*
) args[
3
];
Object
*
thisObject
=
(
Object
*
) args[
4
];
/
/
null
for
static methods
ArrayObject
*
argList
=
(ArrayObject
*
) args[
5
];
/
/
invoke the method
/
/
通过dvmInvokeMethod执行方法,dvmInvokeMethod是在虚拟机中执行java方法的方法,可以理解为c语言执行java方法
pResult
-
>l
=
dvmInvokeMethod(thisObject, meth, argList, params, returnType, true);
return
;
}
/
/
libxposed_dalvik.cpp
/
*
*
Called very early during VM startup.
*
/
bool
onVmCreated(JNIEnv
*
env) {
if
(!initMemberOffsets(env))
return
false;
/
/
#define CLASS_MIUI_RESOURCES "android/content/res/MiuiResources"
jclass classMiuiResources
=
env
-
>FindClass(CLASS_MIUI_RESOURCES);
if
(classMiuiResources !
=
NULL) {
ClassObject
*
clazz
=
(ClassObject
*
)dvmDecodeIndirectRef(dvmThreadSelf(), classMiuiResources);
if
(dvmIsFinalClass(clazz)) {
ALOGD(
"Removing final flag for class '%s'"
, CLASS_MIUI_RESOURCES);
clazz
-
>accessFlags &
=
~ACC_FINAL;
}
}
env
-
>ExceptionClear();
/
/
关键点
/
/
获取invokeOriginalMethodNative方法的jmethodId
/
/
将invokeOriginalMethodNative的native方法关联到XposedBridge_invokeOriginalMethodNative方法,为后续调用的时候使用
Method
*
xposedInvokeOriginalMethodNative
=
(Method
*
) env
-
>GetStaticMethodID(classXposedBridge,
"invokeOriginalMethodNative"
,
"(Ljava/lang/reflect/Member;I[Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"
);
if
(xposedInvokeOriginalMethodNative
=
=
NULL) {
ALOGE(
"ERROR: could not find method %s.invokeOriginalMethodNative(Member, int, Class[], Class, Object, Object[])"
, CLASS_XPOSED_BRIDGE);
dvmLogExceptionStackTrace();
env
-
>ExceptionClear();
return
false;
}
dvmSetNativeFunc(xposedInvokeOriginalMethodNative, XposedBridge_invokeOriginalMethodNative, NULL);
objectArrayClass
=
dvmFindArrayClass(
"[Ljava/lang/Object;"
, NULL);
if
(objectArrayClass
=
=
NULL) {
ALOGE(
"Error while loading Object[] class"
);
dvmLogExceptionStackTrace();
env
-
>ExceptionClear();
return
false;
}
return
true;
}
void XposedBridge_invokeOriginalMethodNative(const u4
*
args, JValue
*
pResult,
const Method
*
method, ::Thread
*
self
) {
/
/
获取method
Method
*
meth
=
(Method
*
) args[
1
];
if
(meth
=
=
NULL) {
/
/
反射获取
meth
=
dvmGetMethodFromReflectObj((
Object
*
) args[
0
]);
if
(isMethodHooked(meth)) {
meth
=
(Method
*
) meth
-
>insns;
}
}
ArrayObject
*
params
=
(ArrayObject
*
) args[
2
];
ClassObject
*
returnType
=
(ClassObject
*
) args[
3
];
Object
*
thisObject
=
(
Object
*
) args[
4
];
/
/
null
for
static methods
ArrayObject
*
argList
=
(ArrayObject
*
) args[
5
];
/
/
invoke the method
/
/
通过dvmInvokeMethod执行方法,dvmInvokeMethod是在虚拟机中执行java方法的方法,可以理解为c语言执行java方法
pResult
-
>l
=
dvmInvokeMethod(thisObject, meth, argList, params, returnType, true);
return
;
}
/
/
libxposed_art.cpp
/
*
*
Called very early during VM startup.
*
/
bool
onVmCreated(JNIEnv
*
) {
/
/
没有针对Resource的操作
/
/
TODO: Handle CLASS_MIUI_RESOURCES?
/
/
为ArtMethod的两个属性赋值,而这个ArtMethod定义来自于Xposed的android_art
/
/
classXposedBridge和methodXposedBridgeHandleHookedMethod被赋值是在libxposed_common的initXposedBridge函数中
/
/
classXposedBridge
=
env
-
>FindClass(CLASS_XPOSED_BRIDGE);
/
/
methodXposedBridgeHandleHookedMethod
=
env
-
>GetStaticMethodID(classXposedBridge,
"handleHookedMethod"
,
"(Ljava/lang/reflect/Member;ILjava/lang/Object;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"
);
ArtMethod::xposed_callback_class
=
classXposedBridge;
ArtMethod::xposed_callback_method
=
methodXposedBridgeHandleHookedMethod;
return
true;
}
/
/
libxposed_art.cpp
/
*
*
Called very early during VM startup.
*
/
bool
onVmCreated(JNIEnv
*
) {
/
/
没有针对Resource的操作
/
/
TODO: Handle CLASS_MIUI_RESOURCES?
/
/
为ArtMethod的两个属性赋值,而这个ArtMethod定义来自于Xposed的android_art
/
/
classXposedBridge和methodXposedBridgeHandleHookedMethod被赋值是在libxposed_common的initXposedBridge函数中
/
/
classXposedBridge
=
env
-
>FindClass(CLASS_XPOSED_BRIDGE);
/
/
methodXposedBridgeHandleHookedMethod
=
env
-
>GetStaticMethodID(classXposedBridge,
"handleHookedMethod"
,
"(Ljava/lang/reflect/Member;ILjava/lang/Object;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"
);
ArtMethod::xposed_callback_class
=
classXposedBridge;
ArtMethod::xposed_callback_method
=
methodXposedBridgeHandleHookedMethod;
return
true;
}
/
/
xposed.cpp
/
*
*
Initialize Xposed (unless it
is
disabled).
*
/
bool
initialize(
bool
zygote,
bool
startSystemServer, const char
*
className,
int
argc, char
*
const argv[]) {
#if !defined(XPOSED_ENABLE_FOR_TOOLS)
if
(!zygote)
return
false;
#endif
if
(isMinimalFramework()) {
ALOGI(
"Not loading Xposed for minimal framework (encrypted device)"
);
return
false;
}
/
/
xposed结构体赋值
xposed
-
>zygote
=
zygote;
xposed
-
>startSystemServer
=
startSystemServer;
xposed
-
>startClassName
=
className;
xposed
-
>xposedVersionInt
=
xposedVersionInt;
/
/
针对selinux做的操作
#if XPOSED_WITH_SELINUX
xposed
-
>isSELinuxEnabled
=
is_selinux_enabled()
=
=
1
;
xposed
-
>isSELinuxEnforcing
=
xposed
-
>isSELinuxEnabled && security_getenforce()
=
=
1
;
#else
xposed
-
>isSELinuxEnabled
=
false;
xposed
-
>isSELinuxEnforcing
=
false;
#endif // XPOSED_WITH_SELINUX
if
(startSystemServer) {
xposed::logcat::printStartupMarker();
}
else
if
(zygote) {
/
/
TODO Find a better solution
for
this
/
/
Give the primary Zygote process a little time to start first.
/
/
This also makes the log easier to read, as logs
for
the two Zygotes are
not
mixed up.
sleep(
10
);
}
/
/
打印rom信息
printRomInfo();
if
(startSystemServer) {
/
/
在Android中一个UID的对应的就是一个可执行的程序,对于普通的程序其UID就是对应与GID,程序在Android系统留存期间,其UID不变。
/
/
xposed::service::startAll() fork子进程启动system context service和app context service
/
/
启动xposed_service_system xposed_service_app
if
(!determineXposedInstallerUidGid() || !xposed::service::startAll()) {
return
false;
}
/
/
fork调用xposed logcat进程,负责打印xposed日志
xposed::logcat::start();
#if XPOSED_WITH_SELINUX
}
else
if
(xposed
-
>isSELinuxEnabled) {
/
/
启动xposed_zygote_service
if
(!xposed::service::startMembased()) {
return
false;
}
#endif // XPOSED_WITH_SELINUX
}
#if XPOSED_WITH_SELINUX
/
/
Don't let
any
further forks access the Zygote service
if
(xposed
-
>isSELinuxEnabled) {
xposed::service::membased::restrictMemoryInheritance();
}
#endif // XPOSED_WITH_SELINUX
/
/
FIXME Zygote has no access to
input
devices, this would need to be check
in
system_server context
if
(zygote && !isSafemodeDisabled() && detectSafemodeTrigger(shouldSkipSafemodeDelay()))
disableXposed();
if
(isDisabled() || (!zygote && shouldIgnoreCommand(argc, argv)))
return
false;
/
/
把jar包加入到classpath当中
return
addJarToClasspath();
}
/
*
*
Add XposedBridge.jar to the Java classpath.
*
/
bool
addJarToClasspath() {
ALOGI(
"-----------------"
);
/
/
Do we have a new version
and
are (re)starting zygote? Then load it!
/
*
FIXME
if
you can
if
(xposed
-
>startSystemServer && access(XPOSED_JAR_NEWVERSION, R_OK)
=
=
0
) {
ALOGI(
"Found new Xposed jar version, activating it"
);
if
(rename(XPOSED_JAR_NEWVERSION, XPOSED_JAR) !
=
0
) {
ALOGE(
"Could not move %s to %s"
, XPOSED_JAR_NEWVERSION, XPOSED_JAR);
return
false;
}
}
*
/
if
(access(XPOSED_JAR, R_OK)
=
=
0
) {
/
/
#define XPOSED_JAR "/system/framework/XposedBridge.jar"
将xposed_bridge的jar加入classpath
if
(!addPathToEnv(
"CLASSPATH"
, XPOSED_JAR))
return
false;
ALOGI(
"Added Xposed (%s) to CLASSPATH"
, XPOSED_JAR);
return
true;
}
else
{
ALOGE(
"ERROR: Could not access Xposed jar '%s'"
, XPOSED_JAR);
return
false;
}
}
/
/
xposed.cpp
/
*
*
Initialize Xposed (unless it
is
disabled).
*
/
bool
initialize(
bool
zygote,
bool
startSystemServer, const char
*
className,
int
argc, char
*
const argv[]) {
#if !defined(XPOSED_ENABLE_FOR_TOOLS)
if
(!zygote)
return
false;
#endif
if
(isMinimalFramework()) {
ALOGI(
"Not loading Xposed for minimal framework (encrypted device)"
);
return
false;
}
/
/
xposed结构体赋值
xposed
-
>zygote
=
zygote;
xposed
-
>startSystemServer
=
startSystemServer;
xposed
-
>startClassName
=
className;
xposed
-
>xposedVersionInt
=
xposedVersionInt;
/
/
针对selinux做的操作
#if XPOSED_WITH_SELINUX
xposed
-
>isSELinuxEnabled
=
is_selinux_enabled()
=
=
1
;
xposed
-
>isSELinuxEnforcing
=
xposed
-
>isSELinuxEnabled && security_getenforce()
=
=
1
;
#else
xposed
-
>isSELinuxEnabled
=
false;
xposed
-
>isSELinuxEnforcing
=
false;
#endif // XPOSED_WITH_SELINUX
if
(startSystemServer) {
xposed::logcat::printStartupMarker();
}
else
if
(zygote) {
/
/
TODO Find a better solution
for
this
/
/
Give the primary Zygote process a little time to start first.
/
/
This also makes the log easier to read, as logs
for
the two Zygotes are
not
mixed up.
sleep(
10
);
}
/
/
打印rom信息
printRomInfo();
if
(startSystemServer) {
/
/
在Android中一个UID的对应的就是一个可执行的程序,对于普通的程序其UID就是对应与GID,程序在Android系统留存期间,其UID不变。
/
/
xposed::service::startAll() fork子进程启动system context service和app context service
/
/
启动xposed_service_system xposed_service_app
if
(!determineXposedInstallerUidGid() || !xposed::service::startAll()) {
return
false;
}
/
/
fork调用xposed logcat进程,负责打印xposed日志
xposed::logcat::start();
#if XPOSED_WITH_SELINUX
}
else
if
(xposed
-
>isSELinuxEnabled) {
/
/
启动xposed_zygote_service
if
(!xposed::service::startMembased()) {
return
false;
}
#endif // XPOSED_WITH_SELINUX
}
#if XPOSED_WITH_SELINUX
/
/
Don't let
any
further forks access the Zygote service
if
(xposed
-
>isSELinuxEnabled) {
xposed::service::membased::restrictMemoryInheritance();
}
#endif // XPOSED_WITH_SELINUX
/
/
FIXME Zygote has no access to
input
devices, this would need to be check
in
system_server context
if
(zygote && !isSafemodeDisabled() && detectSafemodeTrigger(shouldSkipSafemodeDelay()))
disableXposed();
if
(isDisabled() || (!zygote && shouldIgnoreCommand(argc, argv)))
return
false;
/
/
把jar包加入到classpath当中
return
addJarToClasspath();
}
/
*
*
Add XposedBridge.jar to the Java classpath.
*
/
bool
addJarToClasspath() {
ALOGI(
"-----------------"
);
/
/
Do we have a new version
and
are (re)starting zygote? Then load it!
/
*
FIXME
if
you can
if
(xposed
-
>startSystemServer && access(XPOSED_JAR_NEWVERSION, R_OK)
=
=
0
) {
ALOGI(
"Found new Xposed jar version, activating it"
);
if
(rename(XPOSED_JAR_NEWVERSION, XPOSED_JAR) !
=
0
) {
ALOGE(
"Could not move %s to %s"
, XPOSED_JAR_NEWVERSION, XPOSED_JAR);
return
false;
}
}
*
/
if
(access(XPOSED_JAR, R_OK)
=
=
0
) {
/
/
#define XPOSED_JAR "/system/framework/XposedBridge.jar"
将xposed_bridge的jar加入classpath
if
(!addPathToEnv(
"CLASSPATH"
, XPOSED_JAR))
return
false;
ALOGI(
"Added Xposed (%s) to CLASSPATH"
, XPOSED_JAR);
return
true;
}
else
{
ALOGE(
"ERROR: Could not access Xposed jar '%s'"
, XPOSED_JAR);
return
false;
}
}
/
/
frameworks
/
base
/
core
/
jni
/
AndroidRuntime.cpp
/
/
runtime.start()函数
void AndroidRuntime::start(const char
*
className, const Vector<String8>& options,
bool
zygote)
{
ALOGD(
">>>>>> START %s uid %d <<<<<<\n"
,
className !
=
NULL ? className :
"(unknown)"
, getuid());
static const String8 startSystemServer(
"start-system-server"
);
/
*
*
'startSystemServer == true'
means runtime
is
obsolete
and
not
run
from
*
init.rc anymore, so we
print
out the boot start event here.
*
/
for
(size_t i
=
0
; i < options.size();
+
+
i) {
if
(options[i]
=
=
startSystemServer) {
/
*
track our progress through the boot sequence
*
/
const
int
LOG_BOOT_PROGRESS_START
=
3000
;
LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START, ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
}
}
const char
*
rootDir
=
getenv(
"ANDROID_ROOT"
);
if
(rootDir
=
=
NULL) {
rootDir
=
"/system"
;
if
(!hasDir(
"/system"
)) {
LOG_FATAL(
"No root directory specified, and /android does not exist."
);
return
;
}
setenv(
"ANDROID_ROOT"
, rootDir,
1
);
}
/
/
const char
*
kernelHack
=
getenv(
"LD_ASSUME_KERNEL"
);
/
/
ALOGD(
"Found LD_ASSUME_KERNEL='%s'\n"
, kernelHack);
/
*
start the virtual machine
*
/
JniInvocation jni_invocation;
/
/
加载虚拟机的核心库
/
/
没有具体分析,加载的是libart.so
/
libdalvik.so
jni_invocation.Init(NULL);
JNIEnv
*
env;
/
/
创建虚拟机
if
(startVm(&mJavaVM, &env, zygote) !
=
0
) {
return
;
}
/
/
这个函数被xposed替换
onVmCreated(env);
/
*
*
Register android functions.
*
/
/
/
注册andorid native函数
if
(startReg(env) <
0
) {
ALOGE(
"Unable to register all android natives\n"
);
return
;
}
/
*
*
We want to call main() with a String array with arguments
in
it.
*
At present we have two arguments, the
class
name
and
an option string.
*
Create an array to hold them.
*
/
jclass stringClass;
jobjectArray strArray;
jstring classNameStr;
/
/
可以理解为为字符串申请空间
stringClass
=
env
-
>FindClass(
"java/lang/String"
);
assert
(stringClass !
=
NULL);
strArray
=
env
-
>NewObjectArray(options.size()
+
1
, stringClass, NULL);
assert
(strArray !
=
NULL);
classNameStr
=
env
-
>NewStringUTF(className);
assert
(classNameStr !
=
NULL);
env
-
>SetObjectArrayElement(strArray,
0
, classNameStr);
for
(size_t i
=
0
; i < options.size();
+
+
i) {
jstring optionsStr
=
env
-
>NewStringUTF(options.itemAt(i).string());
assert
(optionsStr !
=
NULL);
env
-
>SetObjectArrayElement(strArray, i
+
1
, optionsStr);
}
/
*
*
Start VM. This thread becomes the main thread of the VM,
and
will
*
not
return
until the VM exits.
*
/
char
*
slashClassName
=
toSlashClassName(className);
/
/
获取字符串对应的类,此时类为xposed_bridge类,由于在initialize方法中已经被加入到classpath中,因此可以获取到
jclass startClass
=
env
-
>FindClass(slashClassName);
if
(startClass
=
=
NULL) {
ALOGE(
"JavaVM unable to locate class '%s'\n"
, slashClassName);
/
*
keep going
*
/
}
else
{
/
/
获取类的main方法jmethodID
jmethodID startMeth
=
env
-
>GetStaticMethodID(startClass,
"main"
,
"([Ljava/lang/String;)V"
);
if
(startMeth
=
=
NULL) {
ALOGE(
"JavaVM unable to find main() in '%s'\n"
, className);
/
*
keep going
*
/
}
else
{
/
/
执行main函数
env
-
>CallStaticVoidMethod(startClass, startMeth, strArray);
#if 0
if
(env
-
>ExceptionCheck())
threadExitUncaughtException(env);
#endif
}
}
free(slashClassName);
ALOGD(
"Shutting down VM\n"
);
if
(mJavaVM
-
>DetachCurrentThread() !
=
JNI_OK)
ALOGW(
"Warning: unable to detach main thread\n"
);
if
(mJavaVM
-
>DestroyJavaVM() !
=
0
)
ALOGW(
"Warning: VM did not shut down cleanly\n"
);
}
/
/
frameworks
/
base
/
core
/
jni
/
AndroidRuntime.cpp
/
/
runtime.start()函数
void AndroidRuntime::start(const char
*
className, const Vector<String8>& options,
bool
zygote)
{
ALOGD(
">>>>>> START %s uid %d <<<<<<\n"
,
className !
=
NULL ? className :
"(unknown)"
, getuid());
static const String8 startSystemServer(
"start-system-server"
);
/
*
*
'startSystemServer == true'
means runtime
is
obsolete
and
not
run
from
*
init.rc anymore, so we
print
out the boot start event here.
*
/
for
(size_t i
=
0
; i < options.size();
+
+
i) {
if
(options[i]
=
=
startSystemServer) {
/
*
track our progress through the boot sequence
*
/
const
int
LOG_BOOT_PROGRESS_START
=
3000
;
LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START, ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
}
}
const char
*
rootDir
=
getenv(
"ANDROID_ROOT"
);
if
(rootDir
=
=
NULL) {
rootDir
=
"/system"
;
if
(!hasDir(
"/system"
)) {
LOG_FATAL(
"No root directory specified, and /android does not exist."
);
return
;
}
setenv(
"ANDROID_ROOT"
, rootDir,
1
);
}
/
/
const char
*
kernelHack
=
getenv(
"LD_ASSUME_KERNEL"
);
/
/
ALOGD(
"Found LD_ASSUME_KERNEL='%s'\n"
, kernelHack);
/
*
start the virtual machine
*
/
JniInvocation jni_invocation;
/
/
加载虚拟机的核心库
/
/
没有具体分析,加载的是libart.so
/
libdalvik.so
jni_invocation.Init(NULL);
JNIEnv
*
env;
/
/
创建虚拟机
if
(startVm(&mJavaVM, &env, zygote) !
=
0
) {
return
;
}
/
/
这个函数被xposed替换
onVmCreated(env);
/
*
*
Register android functions.
*
/
/
/
注册andorid native函数
if
(startReg(env) <
0
) {
ALOGE(
"Unable to register all android natives\n"
);
return
;
}
/
*
*
We want to call main() with a String array with arguments
in
it.
*
At present we have two arguments, the
class
name
and
an option string.
*
Create an array to hold them.
*
/
jclass stringClass;
jobjectArray strArray;
jstring classNameStr;
/
/
可以理解为为字符串申请空间
stringClass
=
env
-
>FindClass(
"java/lang/String"
);
assert
(stringClass !
=
NULL);
strArray
=
env
-
>NewObjectArray(options.size()
+
1
, stringClass, NULL);
assert
(strArray !
=
NULL);
classNameStr
=
env
-
>NewStringUTF(className);
assert
(classNameStr !
=
NULL);
env
-
>SetObjectArrayElement(strArray,
0
, classNameStr);
for
(size_t i
=
0
; i < options.size();
+
+
i) {
jstring optionsStr
=
env
-
>NewStringUTF(options.itemAt(i).string());
assert
(optionsStr !
=
NULL);
env
-
>SetObjectArrayElement(strArray, i
+
1
, optionsStr);
}
/
*
*
Start VM. This thread becomes the main thread of the VM,
and
will
*
not
return
until the VM exits.
*
/
char
*
slashClassName
=
toSlashClassName(className);
/
/
获取字符串对应的类,此时类为xposed_bridge类,由于在initialize方法中已经被加入到classpath中,因此可以获取到
jclass startClass
=
env
-
>FindClass(slashClassName);
if
(startClass
=
=
NULL) {
ALOGE(
"JavaVM unable to locate class '%s'\n"
, slashClassName);
/
*
keep going
*
/
}
else
{
/
/
获取类的main方法jmethodID
jmethodID startMeth
=
env
-
>GetStaticMethodID(startClass,
"main"
,
"([Ljava/lang/String;)V"
);
if
(startMeth
=
=
NULL) {
ALOGE(
"JavaVM unable to find main() in '%s'\n"
, className);
/
*
keep going
*
/
}
else
{
/
/
执行main函数
env
-
>CallStaticVoidMethod(startClass, startMeth, strArray);
#if 0
if
(env
-
>ExceptionCheck())
threadExitUncaughtException(env);
#endif
}
}
free(slashClassName);
ALOGD(
"Shutting down VM\n"
);
if
(mJavaVM
-
>DetachCurrentThread() !
=
JNI_OK)
ALOGW(
"Warning: unable to detach main thread\n"
);
if
(mJavaVM
-
>DestroyJavaVM() !
=
0
)
ALOGW(
"Warning: VM did not shut down cleanly\n"
);
}
/
/
XposedBridge
/
XposedBridge.java
@SuppressWarnings
(
"deprecation"
)
protected static void main(String[] args) {
/
/
Initialize the Xposed framework
and
modules
/
/
XposedBridge的入口
try
{
if
(!hadInitErrors()) {
/
/
获取资源文件
initXResources();
SELinuxHelper.initOnce();
SELinuxHelper.initForProcess(null);
runtime
=
getRuntime();
XPOSED_BRIDGE_VERSION
=
getXposedVersion();
/
/
三个关键步骤
if
(isZygote) {
/
/
针对资源文件的hook
XposedInit.hookResources();
/
/
针对方法的hook
XposedInit.initForZygote();
}
/
/
加载hook模块列表的模块
XposedInit.loadModules();
}
else
{
Log.e(TAG,
"Not initializing Xposed because of previous errors"
);
}
} catch (Throwable t) {
Log.e(TAG,
"Errors during Xposed initialization"
, t);
disableHooks
=
true;
}
/
/
Call the original startup code
/
/
最后回到了基本的zygote启动流程,不影响正常的启动,之前的操作都是为了hook的初始化
if
(isZygote) {
ZygoteInit.main(args);
}
else
{
RuntimeInit.main(args);
}
}
/
/
XposedBridge
/
XposedBridge.java
@SuppressWarnings
(
"deprecation"
)
protected static void main(String[] args) {
/
/
Initialize the Xposed framework
and
modules
/
/
XposedBridge的入口
try
{
if
(!hadInitErrors()) {
/
/
获取资源文件
initXResources();
SELinuxHelper.initOnce();
SELinuxHelper.initForProcess(null);
runtime
=
getRuntime();
XPOSED_BRIDGE_VERSION
=
getXposedVersion();
/
/
三个关键步骤
if
(isZygote) {
/
/
针对资源文件的hook
XposedInit.hookResources();
/
/
针对方法的hook
XposedInit.initForZygote();
}
/
/
加载hook模块列表的模块
XposedInit.loadModules();
}
else
{
Log.e(TAG,
"Not initializing Xposed because of previous errors"
);
}
} catch (Throwable t) {
Log.e(TAG,
"Errors during Xposed initialization"
, t);
disableHooks
=
true;
}
/
/
Call the original startup code
/
/
最后回到了基本的zygote启动流程,不影响正常的启动,之前的操作都是为了hook的初始化
if
(isZygote) {
ZygoteInit.main(args);
}
else
{
RuntimeInit.main(args);
}
}
/
/
XposedBridge
/
XposedInit.java
if
(needsToCloseFilesForFork()) {
/
/
匿名内部类实例化XC_MethodHook抽象类
XC_MethodHook callback
=
new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
XposedBridge.closeFilesBeforeForkNative();
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
XposedBridge.reopenFilesAfterForkNative();
}
};
Class<?> zygote
=
findClass(
"com.android.internal.os.Zygote"
, null);
/
/
hook nativeForkAndSpecialize
/
/
nativeForkAndSpecialize是Zygote的forkAndSpecialize的底层实现,调用fork()创建新进程,设置新进程的主线程
id
,重置gc性能数据,设置信号处理函数等功能
hookAllMethods(zygote,
"nativeForkAndSpecialize"
, callback);
/
/
hook nativeForkSystemServer
/
/
forkSystemServer是由Zygote的forkSystemServer的底层实现,调用fork()创建system server服务
hookAllMethods(zygote,
"nativeForkSystemServer"
, callback);
}
/
/
XposedBridge
/
XposedInit.java
if
(needsToCloseFilesForFork()) {
/
/
匿名内部类实例化XC_MethodHook抽象类
XC_MethodHook callback
=
new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
XposedBridge.closeFilesBeforeForkNative();
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
XposedBridge.reopenFilesAfterForkNative();
}
};
Class<?> zygote
=
findClass(
"com.android.internal.os.Zygote"
, null);
/
/
hook nativeForkAndSpecialize
/
/
nativeForkAndSpecialize是Zygote的forkAndSpecialize的底层实现,调用fork()创建新进程,设置新进程的主线程
id
,重置gc性能数据,设置信号处理函数等功能
hookAllMethods(zygote,
"nativeForkAndSpecialize"
, callback);
/
/
hook nativeForkSystemServer
/
/
forkSystemServer是由Zygote的forkSystemServer的底层实现,调用fork()创建system server服务
hookAllMethods(zygote,
"nativeForkSystemServer"
, callback);
}
/
/
libxposed_common.cpp
#if PLATFORM_SDK_VERSION >= 21
NATIVE_METHOD(XposedBridge, invokeOriginalMethodNative,
"!(Ljava/lang/reflect/Member;I[Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"
),
NATIVE_METHOD(XposedBridge, closeFilesBeforeForkNative,
"()V"
),
NATIVE_METHOD(XposedBridge, reopenFilesAfterForkNative,
"()V"
),
#endif
/
/
libxposed_art.cpp
/
/
不太清楚做了什么
void XposedBridge_closeFilesBeforeForkNative(JNIEnv
*
, jclass) {
gClosedFdTable
=
FileDescriptorTable::Create();
}
void XposedBridge_reopenFilesAfterForkNative(JNIEnv
*
, jclass) {
gClosedFdTable
-
>Reopen();
delete gClosedFdTable;
gClosedFdTable
=
NULL;
}
/
/
libxposed_common.cpp
#if PLATFORM_SDK_VERSION >= 21
NATIVE_METHOD(XposedBridge, invokeOriginalMethodNative,
"!(Ljava/lang/reflect/Member;I[Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"
),
NATIVE_METHOD(XposedBridge, closeFilesBeforeForkNative,
"()V"
),
NATIVE_METHOD(XposedBridge, reopenFilesAfterForkNative,
"()V"
),
#endif
/
/
libxposed_art.cpp
/
/
不太清楚做了什么
void XposedBridge_closeFilesBeforeForkNative(JNIEnv
*
, jclass) {
gClosedFdTable
=
FileDescriptorTable::Create();
}
void XposedBridge_reopenFilesAfterForkNative(JNIEnv
*
, jclass) {
gClosedFdTable
-
>Reopen();
delete gClosedFdTable;
gClosedFdTable
=
NULL;
}
/
/
normal process initialization (
for
new Activity, Service, BroadcastReceiver etc.)
/
/
hook ActivityThread.handleBindApplication()方法的hook
findAndHookMethod(ActivityThread.
class
,
"handleBindApplication"
,
"android.app.ActivityThread.AppBindData"
, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
/
/
获取activityThread
ActivityThread activityThread
=
(ActivityThread) param.thisObject;
/
/
获取AppBindData的appInfo
ApplicationInfo appInfo
=
(ApplicationInfo) getObjectField(param.args[
0
],
"appInfo"
);
String reportedPackageName
=
appInfo.packageName.equals(
"android"
) ?
"system"
: appInfo.packageName;
SELinuxHelper.initForProcess(reportedPackageName);
/
/
获取AppBindData的instrumentationName
ComponentName instrumentationName
=
(ComponentName) getObjectField(param.args[
0
],
"instrumentationName"
);
if
(instrumentationName !
=
null) {
Log.w(TAG,
"Instrumentation detected, disabling framework for "
+
reportedPackageName);
XposedBridge.disableHooks
=
true;
return
;
}
CompatibilityInfo compatInfo
=
(CompatibilityInfo) getObjectField(param.args[
0
],
"compatInfo"
);
if
(appInfo.sourceDir
=
=
null)
return
;
/
/
设置mBoundApplication属性为AppBindData
setObjectField(activityThread,
"mBoundApplication"
, param.args[
0
]);
loadedPackagesInProcess.add(reportedPackageName);
/
/
通过activityThread获取当前已加载的apk
LoadedApk loadedApk
=
activityThread.getPackageInfoNoCheck(appInfo, compatInfo);
XResources.setPackageNameForResDir(appInfo.packageName, loadedApk.getResDir());
/
/
打包成LoadPackageParam对象
XC_LoadPackage.LoadPackageParam lpparam
=
new XC_LoadPackage.LoadPackageParam(XposedBridge.sLoadedPackageCallbacks);
lpparam.packageName
=
reportedPackageName;
lpparam.processName
=
(String) getObjectField(param.args[
0
],
"processName"
);
lpparam.classLoader
=
loadedApk.getClassLoader();
lpparam.appInfo
=
appInfo;
lpparam.isFirstApplication
=
true;
/
/
针对lpparam的所有callback函数进行调用
XC_LoadPackage.callAll(lpparam);
if
(reportedPackageName.equals(INSTALLER_PACKAGE_NAME))
hookXposedInstaller(lpparam.classLoader);
}
});
/
/
XCallback.java
public static void callAll(Param param) {
if
(param.callbacks
=
=
null)
throw new IllegalStateException(
"This object was not created for use with callAll"
);
/
/
调用每个参数的callbacks数组每个对象的call方法
for
(
int
i
=
0
; i < param.callbacks.length; i
+
+
) {
try
{
((XCallback) param.callbacks[i]).call(param);
} catch (Throwable t) { XposedBridge.log(t); }
}
}
/
/
XC_LoadPackage.java
@Override
protected void call(Param param) throws Throwable {
/
/
也就是调用callbacks数组每个对象的handleLoadPackage方法
if
(param instanceof LoadPackageParam)
handleLoadPackage((LoadPackageParam) param);
}
/
/
normal process initialization (
for
new Activity, Service, BroadcastReceiver etc.)
/
/
hook ActivityThread.handleBindApplication()方法的hook
findAndHookMethod(ActivityThread.
class
,
"handleBindApplication"
,
"android.app.ActivityThread.AppBindData"
, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
/
/
获取activityThread
ActivityThread activityThread
=
(ActivityThread) param.thisObject;
/
/
获取AppBindData的appInfo
ApplicationInfo appInfo
=
(ApplicationInfo) getObjectField(param.args[
0
],
"appInfo"
);
String reportedPackageName
=
appInfo.packageName.equals(
"android"
) ?
"system"
: appInfo.packageName;
SELinuxHelper.initForProcess(reportedPackageName);
/
/
获取AppBindData的instrumentationName
ComponentName instrumentationName
=
(ComponentName) getObjectField(param.args[
0
],
"instrumentationName"
);
if
(instrumentationName !
=
null) {
Log.w(TAG,
"Instrumentation detected, disabling framework for "
+
reportedPackageName);
XposedBridge.disableHooks
=
true;
return
;
}
CompatibilityInfo compatInfo
=
(CompatibilityInfo) getObjectField(param.args[
0
],
"compatInfo"
);
if
(appInfo.sourceDir
=
=
null)
return
;
/
/
设置mBoundApplication属性为AppBindData
setObjectField(activityThread,
"mBoundApplication"
, param.args[
0
]);
loadedPackagesInProcess.add(reportedPackageName);
/
/
通过activityThread获取当前已加载的apk
LoadedApk loadedApk
=
activityThread.getPackageInfoNoCheck(appInfo, compatInfo);
XResources.setPackageNameForResDir(appInfo.packageName, loadedApk.getResDir());
/
/
打包成LoadPackageParam对象
XC_LoadPackage.LoadPackageParam lpparam
=
new XC_LoadPackage.LoadPackageParam(XposedBridge.sLoadedPackageCallbacks);
lpparam.packageName
=
reportedPackageName;
lpparam.processName
=
(String) getObjectField(param.args[
0
],
"processName"
);
lpparam.classLoader
=
loadedApk.getClassLoader();
lpparam.appInfo
=
appInfo;
lpparam.isFirstApplication
=
true;
/
/
针对lpparam的所有callback函数进行调用
XC_LoadPackage.callAll(lpparam);
if
(reportedPackageName.equals(INSTALLER_PACKAGE_NAME))
hookXposedInstaller(lpparam.classLoader);
}
});
/
/
XCallback.java
public static void callAll(Param param) {
if
(param.callbacks
=
=
null)
throw new IllegalStateException(
"This object was not created for use with callAll"
);
/
/
调用每个参数的callbacks数组每个对象的call方法
for
(
int
i
=
0
; i < param.callbacks.length; i
+
+
) {
try
{
((XCallback) param.callbacks[i]).call(param);
} catch (Throwable t) { XposedBridge.log(t); }
}
}
/
/
XC_LoadPackage.java
@Override
protected void call(Param param) throws Throwable {
/
/
也就是调用callbacks数组每个对象的handleLoadPackage方法
if
(param instanceof LoadPackageParam)
handleLoadPackage((LoadPackageParam) param);
}
public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam lpparam) throws Throwable
public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam lpparam) throws Throwable
/
/
XposedBridge
/
XposedBridge.java
public static void hookLoadPackage(XC_LoadPackage callback) {
synchronized (sLoadedPackageCallbacks) {
sLoadedPackageCallbacks.add(callback);
}
}
/
/
XposedBridge
/
XposedBridge.java
public static void hookLoadPackage(XC_LoadPackage callback) {
synchronized (sLoadedPackageCallbacks) {
sLoadedPackageCallbacks.add(callback);
}
}
/
/
system_server initialization
/
/
主要是对system_server做处理
if
(Build.VERSION.SDK_INT <
21
) {
findAndHookMethod(
"com.android.server.ServerThread"
, null,
Build.VERSION.SDK_INT <
19
?
"run"
:
"initAndLoop"
, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
SELinuxHelper.initForProcess(
"android"
);
loadedPackagesInProcess.add(
"android"
);
/
/
道理同上
XC_LoadPackage.LoadPackageParam lpparam
=
new XC_LoadPackage.LoadPackageParam(XposedBridge.sLoadedPackageCallbacks);
lpparam.packageName
=
"android"
;
lpparam.processName
=
"android"
;
/
/
it's actually system_server, but other functions
return
this as well
lpparam.classLoader
=
XposedBridge.BOOTCLASSLOADER;
lpparam.appInfo
=
null;
lpparam.isFirstApplication
=
true;
XC_LoadPackage.callAll(lpparam);
}
});
}
else
if
(startsSystemServer) {
findAndHookMethod(ActivityThread.
class
,
"systemMain"
, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
final ClassLoader cl
=
Thread.currentThread().getContextClassLoader();
findAndHookMethod(
"com.android.server.SystemServer"
, cl,
"startBootstrapServices"
, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
SELinuxHelper.initForProcess(
"android"
);
loadedPackagesInProcess.add(
"android"
);
/
/
道理同上
XC_LoadPackage.LoadPackageParam lpparam
=
new XC_LoadPackage.LoadPackageParam(XposedBridge.sLoadedPackageCallbacks);
lpparam.packageName
=
"android"
;
lpparam.processName
=
"android"
;
/
/
it's actually system_server, but other functions
return
this as well
lpparam.classLoader
=
cl;
lpparam.appInfo
=
null;
lpparam.isFirstApplication
=
true;
XC_LoadPackage.callAll(lpparam);
}
});
}
});
}
/
/
system_server initialization
/
/
主要是对system_server做处理
if
(Build.VERSION.SDK_INT <
21
) {
findAndHookMethod(
"com.android.server.ServerThread"
, null,
Build.VERSION.SDK_INT <
19
?
"run"
:
"initAndLoop"
, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
SELinuxHelper.initForProcess(
"android"
);
loadedPackagesInProcess.add(
"android"
);
/
/
道理同上
XC_LoadPackage.LoadPackageParam lpparam
=
new XC_LoadPackage.LoadPackageParam(XposedBridge.sLoadedPackageCallbacks);
lpparam.packageName
=
"android"
;
lpparam.processName
=
"android"
;
/
/
it's actually system_server, but other functions
return
this as well
lpparam.classLoader
=
XposedBridge.BOOTCLASSLOADER;
lpparam.appInfo
=
null;
lpparam.isFirstApplication
=
true;
XC_LoadPackage.callAll(lpparam);
}
});
}
else
if
(startsSystemServer) {
findAndHookMethod(ActivityThread.
class
,
"systemMain"
, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
final ClassLoader cl
=
Thread.currentThread().getContextClassLoader();
findAndHookMethod(
"com.android.server.SystemServer"
, cl,
"startBootstrapServices"
, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
SELinuxHelper.initForProcess(
"android"
);
loadedPackagesInProcess.add(
"android"
);
/
/
道理同上
XC_LoadPackage.LoadPackageParam lpparam
=
new XC_LoadPackage.LoadPackageParam(XposedBridge.sLoadedPackageCallbacks);
lpparam.packageName
=
"android"
;
lpparam.processName
=
"android"
;
/
/
it's actually system_server, but other functions
return
this as well
lpparam.classLoader
=
cl;
lpparam.appInfo
=
null;
lpparam.isFirstApplication
=
true;
XC_LoadPackage.callAll(lpparam);
}
});
}
});
}
/
/
XposedBridge
/
XposedInit
static void loadModules() throws IOException {
final String filename
=
BASE_DIR
+
"conf/modules.list"
;
BaseService service
=
SELinuxHelper.getAppDataFileService();
if
(!service.checkFileExists(filename)) {
Log.e(TAG,
"Cannot load any modules because "
+
filename
+
" was not found"
);
return
;
}
/
/
public static final ClassLoader BOOTCLASSLOADER
=
ClassLoader.getSystemClassLoader();
/
/
获取classloader
ClassLoader topClassLoader
=
XposedBridge.BOOTCLASSLOADER;
ClassLoader parent;
while
((parent
=
topClassLoader.getParent()) !
=
null) {
topClassLoader
=
parent;
}
InputStream stream
=
service.getFileInputStream(filename);
BufferedReader apks
=
new BufferedReader(new InputStreamReader(stream));
String apk;
/
/
每行读取apk,调用loadMudle()
while
((apk
=
apks.readLine()) !
=
null) {
loadModule(apk, topClassLoader);
}
apks.close();
}
/
/
XposedBridge
/
XposedInit
static void loadModules() throws IOException {
final String filename
=
BASE_DIR
+
"conf/modules.list"
;
BaseService service
=
SELinuxHelper.getAppDataFileService();
if
(!service.checkFileExists(filename)) {
Log.e(TAG,
"Cannot load any modules because "
+
filename
+
" was not found"
);
return
;
}
/
/
public static final ClassLoader BOOTCLASSLOADER
=
ClassLoader.getSystemClassLoader();
/
/
获取classloader
ClassLoader topClassLoader
=
XposedBridge.BOOTCLASSLOADER;
ClassLoader parent;
while
((parent
=
topClassLoader.getParent()) !
=
null) {
topClassLoader
=
parent;
}
InputStream stream
=
service.getFileInputStream(filename);
BufferedReader apks
=
new BufferedReader(new InputStreamReader(stream));
String apk;
/
/
每行读取apk,调用loadMudle()
while
((apk
=
apks.readLine()) !
=
null) {
loadModule(apk, topClassLoader);
}
apks.close();
}
/
/
XposedBridge
/
XposedInit
private static void loadModule(String apk, ClassLoader topClassLoader) {
Log.i(TAG,
"Loading modules from "
+
apk);
/
/
判断Xposed模块是否存在
if
(!new
File
(apk).exists()) {
Log.e(TAG,
" File does not exist"
);
return
;
}
DexFile dexFile;
try
{
dexFile
=
new DexFile(apk);
} catch (IOException e) {
Log.e(TAG,
" Cannot load module"
, e);
return
;
}
if
(dexFile.loadClass(INSTANT_RUN_CLASS, topClassLoader) !
=
null) {
Log.e(TAG,
" Cannot load module, please disable \"Instant Run\" in Android Studio."
);
closeSilently(dexFile);
return
;
}
if
(dexFile.loadClass(XposedBridge.
class
.getName(), topClassLoader) !
=
null) {
Log.e(TAG,
" Cannot load module:"
);
Log.e(TAG,
" The Xposed API classes are compiled into the module's APK."
);
Log.e(TAG,
" This may cause strange issues and must be fixed by the module developer."
);
Log.e(TAG,
" For details, see: http://api.xposed.info/using.html"
);
closeSilently(dexFile);
return
;
}
closeSilently(dexFile);
ZipFile zipFile
=
null;
InputStream
is
;
try
{
zipFile
=
new ZipFile(apk);
/
/
获取模块中的assets
/
xposed_init,也就是我们开发过程中指定Xposed入口的文件
ZipEntry zipEntry
=
zipFile.getEntry(
"assets/xposed_init"
);
if
(zipEntry
=
=
null) {
Log.e(TAG,
" assets/xposed_init not found in the APK"
);
closeSilently(zipFile);
return
;
}
is
=
zipFile.getInputStream(zipEntry);
} catch (IOException e) {
Log.e(TAG,
" Cannot read assets/xposed_init in the APK"
, e);
closeSilently(zipFile);
return
;
}
ClassLoader mcl
=
new PathClassLoader(apk, XposedBridge.BOOTCLASSLOADER);
/
/
读取assets
/
xposed_init文件
BufferedReader moduleClassesReader
=
new BufferedReader(new InputStreamReader(
is
));
try
{
String moduleClassName;
while
((moduleClassName
=
moduleClassesReader.readLine()) !
=
null) {
moduleClassName
=
moduleClassName.trim();
if
(moduleClassName.isEmpty() || moduleClassName.startsWith(
"#"
))
continue
;
try
{
/
/
获取Xposed模块入口类名
Log.i(TAG,
" Loading class "
+
moduleClassName);
Class<?> moduleClass
=
mcl.loadClass(moduleClassName);
if
(!IXposedMod.
class
.isAssignableFrom(moduleClass)) {
Log.e(TAG,
" This class doesn't implement any sub-interface of IXposedMod, skipping it"
);
continue
;
}
else
if
(disableResources && IXposedHookInitPackageResources.
class
.isAssignableFrom(moduleClass)) {
Log.e(TAG,
" This class requires resource-related hooks (which are disabled), skipping it."
);
continue
;
}
/
/
获取实例
final
Object
moduleInstance
=
moduleClass.newInstance();
if
(XposedBridge.isZygote) {
if
(moduleInstance instanceof IXposedHookZygoteInit) {
IXposedHookZygoteInit.StartupParam param
=
new IXposedHookZygoteInit.StartupParam();
param.modulePath
=
apk;
param.startsSystemServer
=
startsSystemServer;
((IXposedHookZygoteInit) moduleInstance).initZygote(param);
}
if
(moduleInstance instanceof IXposedHookLoadPackage)
/
/
调用内部类IXposedHookLoadPackage.Wrapper构造方法生成XC_LoadPackage类,就可以被hookLoadPackage调用
XposedBridge.hookLoadPackage(new IXposedHookLoadPackage.Wrapper((IXposedHookLoadPackage) moduleInstance));
if
(moduleInstance instanceof IXposedHookInitPackageResources)
XposedBridge.hookInitPackageResources(new IXposedHookInitPackageResources.Wrapper((IXposedHookInitPackageResources) moduleInstance));
}
else
{
if
(moduleInstance instanceof IXposedHookCmdInit) {
IXposedHookCmdInit.StartupParam param
=
new IXposedHookCmdInit.StartupParam();
param.modulePath
=
apk;
param.startClassName
=
startClassName;
((IXposedHookCmdInit) moduleInstance).initCmdApp(param);
}
}
} catch (Throwable t) {
Log.e(TAG,
" Failed to load class "
+
moduleClassName, t);
}
}
} catch (IOException e) {
Log.e(TAG,
" Failed to load module from "
+
apk, e);
}
finally
{
closeSilently(
is
);
closeSilently(zipFile);
}
}
}
/
/
XposedBridge
/
XposedInit
private static void loadModule(String apk, ClassLoader topClassLoader) {
Log.i(TAG,
"Loading modules from "
+
apk);
/
/
判断Xposed模块是否存在
if
(!new
File
(apk).exists()) {
Log.e(TAG,
" File does not exist"
);
return
;
}
DexFile dexFile;
try
{
dexFile
=
new DexFile(apk);
} catch (IOException e) {
Log.e(TAG,
" Cannot load module"
, e);
return
;
}
if
(dexFile.loadClass(INSTANT_RUN_CLASS, topClassLoader) !
=
null) {
Log.e(TAG,
" Cannot load module, please disable \"Instant Run\" in Android Studio."
);
closeSilently(dexFile);
return
;
}
if
(dexFile.loadClass(XposedBridge.
class
.getName(), topClassLoader) !
=
null) {
Log.e(TAG,
" Cannot load module:"
);
Log.e(TAG,
" The Xposed API classes are compiled into the module's APK."
);
Log.e(TAG,
" This may cause strange issues and must be fixed by the module developer."
);
Log.e(TAG,
" For details, see: http://api.xposed.info/using.html"
);
closeSilently(dexFile);
return
;
}
closeSilently(dexFile);
ZipFile zipFile
=
null;
InputStream
is
;
try
{
zipFile
=
new ZipFile(apk);
/
/
获取模块中的assets
/
xposed_init,也就是我们开发过程中指定Xposed入口的文件
ZipEntry zipEntry
=
zipFile.getEntry(
"assets/xposed_init"
);
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课