Xposed加載JNI庫

在項(xiàng)目開發(fā)中,時常會用到 JNI 庫,以提供一些特定的功能,而在 xposed 開發(fā)中,也會有這樣的需求,然而,在 xposed 的條件下,要加載一個 so 可不是一件容易的事。

首先的問題是跨進(jìn)程,由于 xposed 程序在執(zhí)行時,xposed 模塊與主包并不在同一進(jìn)程,因此無法直接使用以下代碼對 JNI 庫進(jìn)行加載:

init {
    System.loadLibrary("xpjni")
}

如果這么做,那么只會得到一個 UnsatisfiedLinkError,因?yàn)樵?xposed 進(jìn)程所可以訪問的空間內(nèi),找不到這個 so。

那么是否可以使用另一個加載方法,即 System.load 呢?如下的代碼:

init {
    System.load("/data/app/com.rarnu.xpjni.demo-1/lib/arm/libxpjni.so")
}

這樣的代碼在部分手機(jī)上可以工作,但是在部分手機(jī)上依然得到了一個 UnsatisfiedLinkError,但是具體的出錯信息變了:

java.lang.UnsatisfiedLinkError: dlopen failed: 
"/data/app/com.rarnu.xpjni.demo-2/lib/arm/libxpjni.so" 
is 32-bit instead of 64-bit

看出錯信息,是在一個 64 位的進(jìn)程內(nèi),加載了 32 位的庫,于是在這里就會有一個時機(jī)的問題,需要先判斷進(jìn)程的位數(shù),而在 64 位的設(shè)備上,默認(rèn)的 xposed 進(jìn)程也是 64 位的。以下就有兩個解決方案:

方案一:編譯 arm64-v8a 架構(gòu)的庫,然后在加載時,加載 64 位的庫

init {
    System.load("/data/app/com.rarnu.xpjni.demo-1/lib/arm64/libxpjni.so")
}

這樣就可以適應(yīng) 64 位的設(shè)備。具體的位數(shù)判斷可以反射 dalvik.system. VMRuntime 類,并且調(diào)用其中的 is64Bit 方法。

方案二:改變 JNI 庫的加載時機(jī),將初始化時的加載修改到 hook 到指定 32 位包的加載時進(jìn)行加載。

override fun handleLoadPackage(loadPackageParam: XC_LoadPackage.LoadPackageParam) {
    if (loadPackageParam.packageName == "com.rarnu.xpjni.demo") {
            System.load("/data/app/com.rarnu.xpjni.demo-1/lib/arm/libxpjni.so")
    }
}

由于自己的程序只有 32 位的 JNI 庫,因此會加載為 32 位的應(yīng)用,在自身被加載時加載 JNI 庫,就可以順利加載到 32 位的庫了,此時即使設(shè)備是 64 位的,也可以正常加載到 32 位的庫。

在加載完成后,再做一個簡單的函數(shù)調(diào)用,或是實(shí)現(xiàn) JNI_OnLoad 即可進(jìn)行測試,最終實(shí)現(xiàn)的效果如下:

E/XposedModule: jni library path => /data/app/com.rarnu.xpjni.demo-2/lib/arm/libxpjni.so
E/XpJNI_Native: JNI_Load
E/XposedModule: jni library loaded
E/XposedModule: jni call => 300

本文中所使用的代碼工程已上傳到 github(),若有不清楚的地方,還是直接看代碼吧。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容