原文出處——>[Xposed源碼剖析——Xposed初始化](http://blog.csdn.net/yzzst/article/details/47834077)
承接上文[Xposed源碼剖析——app_process作用詳解](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()方法,并傳入不同的映射表參數即可。
- 前言
- Android系統的體系結構
- Dalvik VM 和 JVM 的比較
- Android 打包應用程序并安裝的過程
- Android ADB工具
- Android應用開發
- Android UI相關知識總結
- Android 中window 、view、 Activity的關系
- Android應用界面
- Android中的drawable和bitmap
- AndroidUI組件adapterView及其子類和Adapter的關系
- Android四大組件
- Android 數據存儲
- SharedPreference
- Android應用的資源
- 數組資源
- 使用Drawable資源
- Material Design
- Android 進程和線程
- 進程
- 線程
- Android Application類的介紹
- 意圖(Intent)
- Intent 和 Intent 過濾器(Google官網介紹)
- Android中關于任務棧的總結
- 任務和返回棧(官網譯文)
- 總結
- Android應用安全現狀與解決方案
- Android 安全開發
- HTTPS
- 安卓 代碼混淆與打包
- 動態注入技術(hook技術)
- 一、什么是hook技術
- 二、常用的Hook 工具
- Xposed源碼剖析——概述
- Xposed源碼剖析——app_process作用詳解
- Xposed源碼剖析——Xposed初始化
- Xposed源碼剖析——hook具體實現
- 無需Root也能Hook?——Depoxsed框架演示
- 三、HookAndroid應用
- 四、Hook原生應用程序
- 五、Hook 檢測/修復
- Android 應用的逆向與加固保護技術
- OpenCV在Android中的開發
- Android高級開發進階
- 高級UI
- UI繪制流程及原理
- Android新布局ConstraintLayout約束布局
- 關鍵幀動畫
- 幀動畫共享元素變換
- Android異步消息處理機制完全解析,帶你從源碼的角度徹底理解
- Android中為什么主線程不會因為Looper.loop()里的死循環卡死?
- 為什么 Android 要采用 Binder 作為 IPC 機制?
- JVM 中一個線程的 Java 棧和寄存器中分別放的是什么?
- Android源碼的Binder權限是如何控制?
- 如何詳解 Activity 的生命周期?
- 為什么Android的Handler采用管道而不使用Binder?
- ThreadLocal,你真的懂了嗎?
- Android屏幕刷新機制