Xposed源码剖析——Xposed初始化
来源:互联网 发布:步兵升级数据 编辑:程序博客网 时间:2024/05/22 14:17
Xposed源码剖析——Xposed初始化
承接上文 http://blog.csdn.net/yzzst/article/details/47829657
之前我们看过了app_main.cpp源码,知道了在其中,启动了XposedBridge.jar方法。那么,其中还做了些什么事情呢?
之前我们也看到了在app_main.cpp还有几处新增的逻辑。xposed::initialize和onVmCreated回调。下面我在仔细的阅读以下源码。
xposed::initialize初始化
对于xposed::initalize的初始化工作,我们能够在xposed.cpp中看到其具体的逻辑实现。
/** * 初始化xposed */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 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) { xposed::logcat::start(); } 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) { if (!xposed::service::startAll()) return false;#if XPOSED_WITH_SELINUX } else if (xposed->isSELinuxEnabled) { if (!xposed::service::startMembased()) return false;#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.jar的路径添加到环境变量classpath中 return addJarToClasspath();}
* onVmCreated 初始化后的准备工作 *
其具体的逻辑如下所示:
/** * 向当前的runtime中载入libxposed_*.so */void onVmCreated(JNIEnv* env) { // Determine the currently active runtime const char* xposedLibPath = NULL; if (!determineRuntime(&xposedLibPath)) { ALOGE("Could not determine runtime, not loading Xposed"); return; } // Load the suitable libxposed_*.so for it const char *error; void* xposedLibHandle = dlopen(xposedLibPath, RTLD_NOW); if (!xposedLibHandle) { ALOGE("Could not load libxposed: %s", dlerror()); return; } // Clear previous errors dlerror(); // Initialize the library 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 // 这里的xposed变量,其实是一个全局的XposedShare。 // 调用XposedShare的onVmCreated则会根据不同的vm架构针对不同的实现。 if (xposedInitLib(xposed)) { xposed->onVmCreated(env); }}
* libxposed_dalvik.cpp hook环境初始化*
/** Called by Xposed's app_process replacement. * 在被替换后的app_process中调用 */bool xposedInitLib(xposed::XposedShared* shared) { xposed = shared; // 将自己的onVmCreated方法,指向onVmCreated方法 xposed->onVmCreated = &onVmCreated; return true;}/** Called very early during VM startup. * 在VM启动的时候调用,而且调用时机比较早 */void onVmCreated(JNIEnv* env) { if (!initMemberOffsets(env)) return; // 找到小米系统的MIUI_RESOURCE做特殊处理 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(); jclass classXTypedArray = env->FindClass(CLASS_XTYPED_ARRAY); if (classXTypedArray == NULL) { ALOGE("Error while loading XTypedArray class '%s':", CLASS_XTYPED_ARRAY); dvmLogExceptionStackTrace(); env->ExceptionClear(); return; } prepareSubclassReplacement(classXTypedArray); // 获取到全局的XposedBridge classXposedBridge = env->FindClass(CLASS_XPOSED_BRIDGE); classXposedBridge = reinterpret_cast<jclass>(env->NewGlobalRef(classXposedBridge)); if (classXposedBridge == NULL) { ALOGE("Error while loading Xposed class '%s':", CLASS_XPOSED_BRIDGE); dvmLogExceptionStackTrace(); env->ExceptionClear(); return; } // 注册一些 XposedBridge 的 native 方法 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); dvmLogExceptionStackTrace(); env->ExceptionClear(); return; } xposedLoadedSuccessfully = true;}
JNI方法注册逻辑
这里注册的几个方法都是,Xposed核心的几个方法函数。
int register_natives_XposedBridge(JNIEnv* env, jclass clazz) { const JNINativeMethod methods[] = { NATIVE_METHOD(XposedBridge, getStartClassName, "()Ljava/lang/String;"), // 获得Runtime NATIVE_METHOD(XposedBridge, getRuntime, "()I"), // 启动SystemServer NATIVE_METHOD(XposedBridge, startsSystemServer, "()Z"), // 获取Xposed的版本信息 NATIVE_METHOD(XposedBridge, getXposedVersion, "()I"), // 初始化navtive NATIVE_METHOD(XposedBridge, initNative, "()Z"), // hook一个方法的native实现 NATIVE_METHOD(XposedBridge, hookMethodNative, "(Ljava/lang/reflect/Member;Ljava/lang/Class;ILjava/lang/Object;)V"),#ifdef ART_TARGET NATIVE_METHOD(XposedBridge, invokeOriginalMethodNative, "(Ljava/lang/reflect/Member;I[Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"),#endif 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;"), }; return env->RegisterNatives(clazz, methods, NELEM(methods));}
我们看到RegisterNatives这个方法的时候不是很理解,这里做一个简介。
以前在jni中写本地方法时,都会写成 Java_com_example_hellojni_HelloJni_stringFromJNI的形式,函数名很长,而且当类名变了的时候,函数名必须一个一个的改,麻烦。
现在好了有了RegisterNatives,可以简化我们的书写
和传统方法相比,使用RegisterNatives的好处有三点:
1. C++中函数命名自由,不必像javah自动生成的函数声明那样,拘泥特定的命名方式;
2. 效率高。传统方式下,Java类call本地函数时,通常是依靠VM去动态寻找.so中的本地函数(因此它们才需要特定规则的命名格式),而使用RegisterNatives将本地函数向VM进行登记,可以让其更有效率的找到函数;
3. 运行时动态调整本地函数与Java函数值之间的映射关系,只需要多次call RegisterNatives()方法,并传入不同的映射表参数即可。
/*
* @author zhoushengtao(周圣韬)
* @since 2015年8月21 日 23:51:32
* @weixin stchou_zst
* @blog http://blog.csdn.net/yzzst
* @交流学习QQ群:341989536
* @私人QQ:445914891
/
- Xposed源码剖析——Xposed初始化
- Xposed源码剖析——Xposed初始化
- Xposed源码剖析——Xposed初始化
- Xposed源码剖析——概述
- Xposed源码剖析——概述
- Xposed源码剖析——概述
- Xposed源码剖析——概述
- Xposed源码剖析——概述
- Xposed源码剖析——app_process作用详解
- Xposed源码剖析——hook具体实现
- Xposed源码剖析——app_process作用详解
- Xposed源码剖析——hook具体实现
- Xposed源码剖析——app_process作用详解
- Xposed源码剖析——hook具体实现
- Android Root插件模式:Xposed源码剖析
- Xposed
- Xposed
- 安卓神框架——xposed
- remove all the same elements
- 解析XML
- 获取设备唯一标识码
- 使用7zip压解各种文件的常用命令
- M3U8简介
- Xposed源码剖析——Xposed初始化
- POJ--3529--Wormholes
- 用selenium下载图片java代码
- 下半部和推后执行的工作
- 如何将未发布到App Store的app安装到指定用户手机上
- Echarts 标签过长如何让axisLabel换行
- 条码读码器提供更高的读取率
- jquery mobile 自动弹出框
- MVVM设计模式基础知识--ICommand接口