加入自己的理解,转载自:https://blog.csdn.net/zjx839524906/article/details/81046844
一 概述
Xposed通过替换/system/bin/app_process程序控制zygote进程,使得app_process在启动过程中会加载XposedBridge.jar这个jar包,从而完成对Zygote进程及其创建的Dalvik Art虚拟机的劫持。
- XposedBridge.jar:XposedBridge.jar是Xposed提供的jar文件,负责在Native层与FrameWork层进行交互。/system/bin/app_process进程启动过程中会加载该jar包,其它的Modules的开发与运行都是基于该jar包的。
- Xposed:Xposed的C++部分,主要是用来替换/system/bin/app_process,并为XposedBridge提供JNI方法。
- XposedTool: xposed编译的工具
二 xposed zygote 启动流程
2.1 替换Zygote
- /system/bin/app_process就是zygote进程,对应app_main.cpp,即可以启动zygote进程也可以启动app进程。
- xposed通过替换app_process(对应xposed/app_main2.cpp, app_main.cpp为Davlik),使每个进程在启动时就加载XposedBridge.jar。
- XposedBridge有一个Native(JNI)方法hookMethodNative,这个方法也在app_process中使用。这个函数提供一个方法对象利用Java的Reflection机制来对内置方法覆写。
//zygote 替换过程 xposed 刷机包中 flash-script.sh
install_and_link() { //1.将老的文件备份为_original 2.复制新的文件 3.通过ln命令链接新的文件
TARGET=$1
XPOSED="${1}_xposed"
BACKUP="${1}_original"
if [ ! -f ./$XPOSED ]; then
return
fi
cp_perm ./$XPOSED $XPOSED $2 $3 $4 $5
if [ ! -f $BACKUP ]; then
mv $TARGET $BACKUP || exit 1
ln -s $XPOSED $TARGET || exit 1
chcon -h 'u:object_r:system_file:s0' $TARGET 2>/dev/null
fi
}
install_and_link /system/bin/app_process32 0 2000 0755 u:object_r:zygote_exec:s0
install_overwrite /system/bin/dex2oat 0 2000 0755 u:object_r:dex2oat_exec:s0
install_overwrite /system/bin/oatdump 0 2000 0755
install_overwrite /system/bin/patchoat 0 2000 0755 u:object_r:dex2oat_exec:s0
install_overwrite /system/lib/libart.so 0 0 0644
install_overwrite /system/lib/libart-compiler.so 0 0 0644
install_overwrite /system/lib/libart-disassembler.so 0 0 0644
install_overwrite /system/lib/libsigchain.so 0 0 0644
install_nobackup /system/lib/libxposed_art.so 0 0 0644
if [ $IS64BIT ]; then
install_and_link /system/bin/app_process64 0 2000 0755 u:object_r:zygote_exec:s0
install_overwrite /system/lib64/libart.so 0 0 0644
install_overwrite /system/lib64/libart-compiler.so 0 0 0644
install_overwrite /system/lib64/libart-disassembler.so 0 0 0644
install_overwrite /system/lib64/libsigchain.so 0 0 0644
install_nobackup /system/lib64/libxposed_art.so 0 0 0644
fi
2.2 加载XPosedBridge.jar
- Init.rc启动app_process进程,以及被xposed替换。
// xposed app_main代码。
int main(int argc, char* const argv[])
{
//......
// Parse runtime arguments. Stop at first unrecognized option.
bool zygote = false;
bool startSystemServer = false;
bool application = false;
String8 niceName;
String8 className;
//......
if (zygote) {
//初始化xposed的一些参数设置,导入XposedBridge.jar
isXposedLoaded = xposed::initialize(true, startSystemServer, NULL, argc, argv);
//启动Zygote进程
runtimeStart(runtime, isXposedLoaded ? XPOSED_CLASS_DOTS_ZYGOTE : "com.android.internal.os.ZygoteInit", args, zygote);
} else if (className) {
isXposedLoaded = xposed::initialize(false, false, className, argc, argv);
//启动普通进程
runtimeStart(runtime, isXposedLoaded ? XPOSED_CLASS_DOTS_TOOLS : "com.android.internal.os.RuntimeInit", args, zygote);
} else {
fprintf(stderr, "Error: no class name or --zygote supplied.\n");
app_usage();
LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
return 10;
}
}
- xposed::initialize 初始化xposed的相关参数,环境变量等,将XposedBridge加入到JavaPath中
/** 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->zygote = zygote;
xposed->startSystemServer = startSystemServer;
xposed->startClassName = className;
xposed->xposedVersionInt = xposedVersionInt;
#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) {
if (!determineXposedInstallerUidGid() || !xposed::service::startAll()) {
return false;
}
xposed::logcat::start();
#if XPOSED_WITH_SELINUX
} else if (xposed->isSELinuxEnabled) {
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;
// 将XposedBridge加入到JavaPath中
return addJarToClasspath();
}
2.3 runtimeStart
// app_main2.cpp
static void runtimeStart(AppRuntime& runtime, const char *classname, const Vector& options, bool zygote)
{
#if PLATFORM_SDK_VERSION >= 23
runtime.start(classname, options, zygote);
#else
//......
#endif
}
- AppRuntime的父类是AndroidRuntime,其start函数的代码如下,主要功能包括启动虚拟机,并利用反射调用className.main()。这里className=XposedBridge(在app_main main函数中传入)。
void AndroidRuntime::start(const char* className, const Vector& options, bool zygote)
{
ALOGD(">>>>>> START %s uid %d <<<<<<\n",
className != NULL ? className : "(unknown)", getuid());
static const String8 startSystemServer("start-system-server");
/*
* 'startSystemServer == true' 意味着runtime被废弃,并且不再从init.rc中启动
* 所以我们打印除了启动事件
*/
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);
/* 开启虚拟机 */
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
if (startVm(&mJavaVM, &env, zygote) != 0) {
return;
}
onVmCreated(env);
/*
* 注册android函数
*/
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
/*
* 利用反射调用输入类的main方法,并输入相关的参数列表,此处包括两个参数,类名和选项字符串
*/
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);
}
/*
* 开启VM,该进程将称为VM的主要进程,并且一直运行直到VM退出
*/
char* slashClassName = toSlashClassName(className != NULL ? className : "");
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
/* keep going */
} else {
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 {
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");
}
2.4 AppRuntime.onVmCreated
// app_main2.cpp
virtual void onVmCreated(JNIEnv* env)
{
if (isXposedLoaded)
xposed::onVmCreated(env);
if (mClassName.isEmpty()) {
return; // Zygote. Nothing to do here.
}
char* slashClassName = toSlashClassName(mClassName.string());
mClass = env->FindClass(slashClassName);
if (mClass == NULL) {
ALOGE("ERROR: could not find class '%s'\n", mClassName.string());
env->ExceptionDescribe();
}
free(slashClassName);
mClass = reinterpret_cast(env->NewGlobalRef(mClass));
}
2.5 xposed::onVmCreated
- 开启VM:xposed部分,主要功能包括确定当前运行时(dalvik或art),加载libxposed_art.so,初始化库文件
//xposed.cpp
void onVmCreated(JNIEnv* env) {
// 确定当前运行时,dalvik或art
const char* xposedLibPath = NULL;
if (!determineRuntime(&xposedLibPath)) {
ALOGE("Could not determine runtime, not loading Xposed");
return;
}
// 加载合适的 libxposed_*.so
void* xposedLibHandle = dlopen(xposedLibPath, RTLD_NOW);
if (!xposedLibHandle) {
ALOGE("Could not load libxposed: %s", dlerror());
return;
}
// Clear previous errors
dlerror();
// 初始化库文件
bool (*xposedInitLib)(XposedShared* shared) = NULL;
*(void **) (&xposedInitLib) = dlsym(xposedLibHandle, "xposedInitLib");
if (!xposedInitLib) {
ALOGE("Could not find function xposedInitLib");
return;
}
#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
// 初始化XposedShared数据结构,并通过函数指针来调用xposed::onVmCreatedCommon
if (xposedInitLib(xposed)) {
xposed->onVmCreated(env);
}
}
- 通过库文件名称来确定运行时,dalvik或这art
static bool determineRuntime(const char** xposedLibPath) {
FILE *fp = fopen("/proc/self/maps", "r");
if (fp == NULL) {
ALOGE("Could not open /proc/self/maps: %s", strerror(errno));
return false;
}
bool success = false;
char line[256];
while (fgets(line, sizeof(line), fp) != NULL) {
char* libname = strrchr(line, '/');
if (!libname)
continue;
libname++;
if (strcmp("libdvm.so\n", libname) == 0) {
ALOGI("Detected Dalvik runtime");
*xposedLibPath = XPOSED_LIB_DALVIK;
success = true;
break;
} else if (strcmp("libart.so\n", libname) == 0) {
ALOGI("Detected ART runtime");
*xposedLibPath = XPOSED_LIB_ART;
success = true;
break;
}
}
fclose(fp);
return success;
}
2.6 xposedInitLib
- 初始化XposedShared数据结构,并调用onVmCreatedCommon
bool xposedInitLib(xposed::XposedShared* shared) {
xposed = shared;
xposed->onVmCreated = &onVmCreatedCommon;
return true;
}
- 可以看到xposed->onVmCreated指向onVmCreatedCommon,所以2.5中调用的xposed->onVmCreated(env) <=> onVmCreatedCommon(env)
2.7 onVmCreatedCommon
void onVmCreatedCommon(JNIEnv* env) {
//初始化XposedBridge环境和ZygoteService环境
if (!initXposedBridge(env) || !initZygoteService(env)) {
return;
}
// 开启虚拟机
if (!onVmCreated(env)) {
return;
}
xposedLoadedSuccessfully = true;
return;
}
2.8 initXposedBridge
- 主要功能是找到XposedBridge类,利用反射获取到地址,并注册XposedBridge的native函数
bool initXposedBridge(JNIEnv* env) {
classXposedBridge = env->FindClass(CLASS_XPOSED_BRIDGE);
if (classXposedBridge == NULL) {
ALOGE("Error while loading Xposed class '%s':", CLASS_XPOSED_BRIDGE);
logExceptionStackTrace();
env->ExceptionClear();
return false;
}
classXposedBridge = reinterpret_cast(env->NewGlobalRef(classXposedBridge));
ALOGI("Found Xposed class '%s', now initializing", CLASS_XPOSED_BRIDGE);
if (register_natives_XposedBridge(env, classXposedBridge) != JNI_OK) {
ALOGE("Could not register natives for '%s'", CLASS_XPOSED_BRIDGE);
logExceptionStackTrace();
env->ExceptionClear();
return false;
}
// 初始化methodXposedBridgeHandleHookedMethod,其值为XposedBridge.handleHookedMethod的函数ID
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) {
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"),
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));
}
2.9 initZygoteService
- 主要功能是初始化classFileResult和constructorFileResult 注册 ZygoteService native函数
bool initZygoteService(JNIEnv* env) {
// 寻找类 de/robv/android/xposed/services/ZygoteService
jclass zygoteServiceClass = env->FindClass(CLASS_ZYGOTE_SERVICE);
if (zygoteServiceClass == NULL) {
ALOGE("Error while loading ZygoteService class '%s':", CLASS_ZYGOTE_SERVICE);
logExceptionStackTrace();
env->ExceptionClear();
return false;
}
// 注册native函数
if (register_natives_ZygoteService(env, zygoteServiceClass) != JNI_OK) {
ALOGE("Could not register natives for '%s'", CLASS_ZYGOTE_SERVICE);
env->ExceptionClear();
return false;
}
//寻找类 de/robv/android/xposed/services/FileResult
classFileResult = env->FindClass(CLASS_FILE_RESULT);
if (classFileResult == NULL) {
ALOGE("Error while loading FileResult class '%s':", CLASS_FILE_RESULT);
logExceptionStackTrace();
env->ExceptionClear();
return false;
}
classFileResult = reinterpret_cast(env->NewGlobalRef(classFileResult));
// 获取init的函数ID
constructorFileResult = env->GetMethodID(classFileResult, "", "(JJ)V");
if (constructorFileResult == NULL) {
ALOGE("ERROR: could not find constructor %s(long, long)", CLASS_FILE_RESULT);
logExceptionStackTrace();
env->ExceptionClear();
return false;
}
return true;
}
int register_natives_ZygoteService(JNIEnv* env, jclass clazz) {
const JNINativeMethod methods[] = {
NATIVE_METHOD(ZygoteService, checkFileAccess, "(Ljava/lang/String;I)Z"),
NATIVE_METHOD(ZygoteService, statFile, "(Ljava/lang/String;)L" CLASS_FILE_RESULT ";"),
NATIVE_METHOD(ZygoteService, readFile, "(Ljava/lang/String;)[B"),
};
return env->RegisterNatives(clazz, methods, NELEM(methods));
}
2.10 onVmCreated
- 此函数在启动VM过程中很早阶段被调用,主要功能为获取invokeOriginalMethodNative函数地址,并设置native方法
//libxposed_dalvik.cpp
bool onVmCreated(JNIEnv* env) {
if (!initMemberOffsets(env))
return false;
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();
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;
}
/** libxposed_art.cpp */
bool onVmCreated(JNIEnv*) {
// TODO: Handle CLASS_MIUI_RESOURCES?
ArtMethod::xposed_callback_class = classXposedBridge;
ArtMethod::xposed_callback_method = methodXposedBridgeHandleHookedMethod;
return true;
}
三 XposedBridge启动流程
3.1 XposedBridge.main
- XposedBridge.jar的入口函数,主要功能包括初始化资源,配置SELinux,加载模块等。
protected static void main(String[] args) {
// Initialize the Xposed framework and modules
try {
if (!hadInitErrors()) {
initXResources();
SELinuxHelper.initOnce();
SELinuxHelper.initForProcess(null);
runtime = getRuntime();
XPOSED_BRIDGE_VERSION = getXposedVersion();
if (isZygote) {
XposedInit.hookResources();
XposedInit.initForZygote();
}
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
if (isZygote) {
ZygoteInit.main(args);
} else {
RuntimeInit.main(args);
}
}
3.2 XposedBridge.initXResource
- 初始化Xposed的资源,包括载入Dex文件,drawables文件,类加载器等
- 此处应该是为hook resource做准备。在/data/dalvik-cache目录下 生成了xposed_XResourcesSuperClass.dex ,xposed_XTypedArraySuperClass.dex 两个文件。具体代码参考DexCreator.java
private static void initXResources() throws IOException {
// 创建 XResources父类
Resources res = Resources.getSystem();
File resDexFile = ensureSuperDexFile("XResources", res.getClass(), Resources.class);
// 创建 XTypedArray父类
Class taClass = TypedArray.class;
try {
TypedArray ta = res.obtainTypedArray(res.getIdentifier("preloaded_drawables", "array", "android"));
taClass = ta.getClass();
ta.recycle();
} catch (Resources.NotFoundException nfe) {
XposedBridge.log(nfe);
}
Runtime.getRuntime().gc();
File taDexFile = ensureSuperDexFile("XTypedArray", taClass, TypedArray.class);
// 为创建类注入一个ClassLoader,来作为XposedBridge ClassLoader的父类
ClassLoader myCL = XposedBridge.class.getClassLoader();
String paths = resDexFile.getAbsolutePath() + File.pathSeparator + taDexFile.getAbsolutePath();
PathClassLoader dummyCL = new PathClassLoader(paths, myCL.getParent());
setObjectField(myCL, "parent", dummyCL);
}
3.3 SELinuxHelper.initOnce
static void initOnce() {
try {
sIsSELinuxEnabled = SELinux.isSELinuxEnabled();
} catch (NoClassDefFoundError ignored) {}
}
3.4 SELinuxHelper.initForProcess
- 如果系统SELinux开启状态,启动新的ZygoteService,启动新的system_server
static void initForProcess(String packageName) {
if (sIsSELinuxEnabled) {
if (packageName == null) { // Zygote
sServiceAppDataFile = new ZygoteService();
} else if (packageName.equals("android")) { //system_server
sServiceAppDataFile = BinderService.getService(BinderService.TARGET_APP);
} else { // app
sServiceAppDataFile = new DirectAccessService();
}
} else {
sServiceAppDataFile = new DirectAccessService();
}
}
3.5 XposedInit.hookResources
static void hookResources() throws Throwable {
if (SELinuxHelper.getAppDataFileService().checkFileExists(BASE_DIR + "conf/disable_resources")) {
Log.w(TAG, "Found " + BASE_DIR + "conf/disable_resources, not hooking resources");
disableResources = true;
return;
}
//初始化Resource的native方法
if (!XposedBridge.initXResourcesNative()) {
Log.e(TAG, "Cannot hook resources");
disableResources = true;
return;
}
/*
* getTopLevelResources(a)
* -> getTopLevelResources(b)
* -> key = new ResourcesKey()
* -> r = new Resources()
* -> mActiveResources.put(key, r)
* -> return r
*/
final Class classGTLR;
final Class classResKey;
final ThreadLocal