欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android so的熱升級(jí)嘗試

 更新時(shí)間:2017年11月22日 10:12:45   作者:瘋中之瘋  
這篇文章主要介紹了Android so的熱升級(jí)嘗試的相關(guān)知識(shí),非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下

一、So的熱升級(jí)嘗試

在Android代碼中,加載so庫(kù)是通過(guò)調(diào)用System.loadLibrary函數(shù)實(shí)現(xiàn)的。但和Android的許多特性一樣,只提供了加載,而沒(méi)有卸載和更換等功能。為了研究能否實(shí)現(xiàn)卸載和升級(jí)等功能,首先要了解清楚JNI so加載的流程。

 

在以上流程中,使用dlopen加載so之后,會(huì)繼續(xù)調(diào)用JNI_Onload函數(shù),通過(guò)系統(tǒng)提供的RegisterNatives函數(shù)完成一些列初始化,向虛擬機(jī)注冊(cè)so庫(kù)提供的JNI函數(shù)。So庫(kù)也可以不實(shí)現(xiàn)JNI_Onload函數(shù),而是采用自動(dòng)查找的方式。

Android虛擬機(jī)會(huì)在首次調(diào)用JNI函數(shù)時(shí)按照J(rèn)NI規(guī)范的命名規(guī)則自動(dòng)查找。通過(guò)分析Android代碼,這種方法最終也會(huì)調(diào)用到上圖中的dvmSetNativeFunc等函數(shù),將函數(shù)地址保存到虛擬機(jī)中供下次調(diào)用。

二、卸載及重新加載

如果想要提供熱升級(jí)的能力,首先要做的是關(guān)閉已打開的so文件。但Android虛擬機(jī)沒(méi)有提供unloadLibrary這樣的接口,因此需要我們自己自己實(shí)現(xiàn)。

根據(jù)上一節(jié)的分析,loadLibrary在native層加載文件使用的是dlopen,與之對(duì)應(yīng)的系統(tǒng)接口是dlclose。而接下來(lái)的RegisterNatives由于沒(méi)有對(duì)應(yīng)的unRegister,我們暫且先放一放,看看卸載的效果再來(lái)處理。

卸載so

提供卸載能力的接口需要完成以下幾項(xiàng)任務(wù):

1、找到要卸載so的句柄;

2、調(diào)用JNI_OnUnload;

3、調(diào)用dlclose卸載。

如下便是我們寫出的卸載函數(shù):

void JNICALL Java_com_example_Unloader_unload(JNIEnv* env, jobject obj)
{
void* handle = dlopen(“/data/data/com.example.unloader/lib/libtest.so”, RTLD_GLOBAL);
if(!handle) return;
LOGD(“unload so: 0x%x\n”, (unsigned int)handle);
void* symbol = dlsym(handle, “JNI_OnUnload”);
if(symbol)
{
OnLoadFunc func = (OnLoadFunc)symbol;
JavaVM* jvm = 0;
(*env)->GetJavaVM(env, &jvm);
if(jvm)
(*func)(jvm, 0);
}
int result = dlclose(handle);
LOGD(“unload result %d\n”, result);
result = dlclose(handle);
result = dlclose(handle);
LOGD(“unload result %d\n”, result);
}

其中dlclose調(diào)用了2次,因?yàn)楹瘮?shù)內(nèi)的dlopen會(huì)增加handle的引用計(jì)數(shù)。

卸載之后如果我們先嘗試調(diào)用原來(lái)的JNI函數(shù),會(huì)發(fā)生什么事呢?顯而易見會(huì)出現(xiàn)crash。

 

究其原因,是由于so在加載或使用時(shí)已經(jīng)在虛擬機(jī)中注冊(cè)了JNI函數(shù)的地址,卸載后原地址變?yōu)榉欠ǖ刂?,?dǎo)致crash。那我們?cè)僦匦录虞dso會(huì)發(fā)生什么呢?

重新加載so

分析代碼可得知,由于so已經(jīng)使用System.loadLibrary加載過(guò),我們之前在卸載時(shí)也沒(méi)有觸及到JNI層,因此重復(fù)調(diào)用loadLibrary并不會(huì)重新加載so。我們可以按照dvmLoadNativeCode的流程,在native層用dlopen重新加載so。

按照之前的分析,很容易就能寫出加載函數(shù):

void JNICALL Java_com_example_Unloader_load(JNIEnv* env, jobject obj)
{
void* handle = dlopen(“/data/data/com.example.Unloader/lib/libtest.so”, RTLD_GLOBAL);
if(!handle) return;
LOGD(“l(fā)oad so: 0x%x\n”, (unsigned int)handle);
void* symbol = dlsym(handle, “JNI_OnLoad”);
if(symbol)
{
OnLoadFunc func = (OnLoadFunc)symbol;
JavaVM* jvm = 0;
(*env)->GetJavaVM(env, &jvm);
if(jvm)
(*func)(jvm, 0);
}
}

三、問(wèn)題及解決

重新加載so后,再次調(diào)用原來(lái)的JNI函數(shù)。發(fā)現(xiàn)有時(shí)候會(huì)成功,但有時(shí)候也會(huì)crash。經(jīng)過(guò)追蹤后注意到,報(bào)錯(cuò)的函數(shù)地址和卸載前一樣,但so加載的地址變化了。

 

由于dlopen加載so時(shí),并不能保證每次都加載在同一地址上。即使能夠加載到同一地址,如果升級(jí)造成so文件變化,那函數(shù)地址也是不準(zhǔn)確的。所以要使新的so工作,那我們也必須要設(shè)法更新虛擬機(jī)已經(jīng)保存的函數(shù)指針,將其指向新加載so的正確地址。

這時(shí)候就需要我們之前忽略的RegisterNatives登場(chǎng)了,這個(gè)函數(shù)可以用來(lái)手動(dòng)注冊(cè)JNI函數(shù)地址。讓我們重復(fù)與第一節(jié)文字相似但含義不同的這段話:

在以上流程中,so庫(kù)在使用dlopen加載后,還需要調(diào)用JNI_Onload函數(shù),通過(guò)系統(tǒng)提供的RegisterNatives函數(shù)完成一些列初始化,向虛擬機(jī)注冊(cè)新的JNI函數(shù)地址。

static JNINativeMethod gMethods[] = {
{ “foo”, “()V”, (void*)Java_com_tencent_example_foo },
};
// Register several native methods for one class.
static int registerNativeMethods(JNIEnv* env, const char* className,
JNINativeMethod* gMethods, int numMethods)
{
jclass clazz = (*env)->FindClass(env, className);
if (clazz == NULL) {
return JNI_FALSE;
}
if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0) {
return JNI_FALSE;
}
return JNI_TRUE;
}

使用RegisterNatives注冊(cè)后,即使so的地址發(fā)生變化,也能夠更新虛擬機(jī)中記錄的函數(shù)地址。

 

本篇小結(jié)

如果想要在運(yùn)行時(shí)更新so,則新的so文件必須要實(shí)現(xiàn)JNI_Onload函數(shù),并且在JNI_Onload中調(diào)用系統(tǒng)提供的RegisterNatives注冊(cè)所有的JNI函數(shù),不能使用自動(dòng)查找JNI函數(shù)名的方式。

四、其他問(wèn)題

以上方案主要解決了so的卸載,重加載和JNI函數(shù)調(diào)用問(wèn)題。但除了這些問(wèn)題之外,so代碼的細(xì)節(jié)上還有許多要注意的地方。

CRASH

卸載so后,除了JNI函數(shù)的指針,其它指向so地址的指針也都會(huì)失效,包括指向靜態(tài)變量,常量,native函數(shù)的指針等。所有引用到該so地址的指針都需要更新。

內(nèi)存和資源泄漏

native代碼中可能存在各種分配內(nèi)存和資源的行為,使用以上方法更新so前,如果沒(méi)有仔細(xì)處理這些資源,就會(huì)丟失原指針,造成內(nèi)存泄漏。

1、malloc/mmap/shmem等方式分配的內(nèi)存。

2、socket, pipe, mutex, thread等各種系統(tǒng)資源。

3、使用NewGlobalRef分配并持有Java對(duì)象,丟失指針后會(huì)造成虛擬機(jī)的Java內(nèi)存泄漏。

綜上所述,對(duì)于所有可能丟失,造成泄露的資源,必須在卸載so前設(shè)法保存或刪除。這些工作可以在卸載時(shí)調(diào)用的JNI_OnUnload中完成。

版權(quán)所屬,禁止轉(zhuǎn)載

相關(guān)文章

  • Android九宮格手勢(shì)密碼代碼設(shè)計(jì)

    Android九宮格手勢(shì)密碼代碼設(shè)計(jì)

    這篇文章主要為大家詳細(xì)介紹了Android九宮格手勢(shì)密碼的代碼設(shè)計(jì)思路,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-03-03
  • Android之側(cè)滑菜單DrawerLayout的使用介紹

    Android之側(cè)滑菜單DrawerLayout的使用介紹

    本篇文章主要介紹了Android之側(cè)滑菜單DrawerLayout的使用介紹,可以生成通過(guò)在屏幕上水平滑動(dòng)打開或者關(guān)閉菜單,能給用戶一個(gè)不錯(cuò)的體驗(yàn)效果
    2017-02-02
  • Android  AsyncTask的缺陷和問(wèn)題總結(jié)

    Android AsyncTask的缺陷和問(wèn)題總結(jié)

    這篇文章主要介紹了Android AsyncTask的缺陷和問(wèn)題總結(jié)的相關(guān)資料,需要的朋友可以參考下
    2017-03-03
  • Flutter路由的跳轉(zhuǎn)、動(dòng)畫和傳參詳解(最簡(jiǎn)單)

    Flutter路由的跳轉(zhuǎn)、動(dòng)畫和傳參詳解(最簡(jiǎn)單)

    這篇文章主要給大家介紹了關(guān)于Flutter路由的跳轉(zhuǎn)、動(dòng)畫和傳參的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-01-01
  • Android開發(fā)之圖片壓縮實(shí)現(xiàn)方法分析

    Android開發(fā)之圖片壓縮實(shí)現(xiàn)方法分析

    這篇文章主要介紹了Android開發(fā)之圖片壓縮實(shí)現(xiàn)方法,結(jié)合實(shí)例形式分析了Android圖片壓縮的原理、實(shí)現(xiàn)方法及相關(guān)操作注意事項(xiàng),需要的朋友可以參考下
    2019-03-03
  • Android解讀Native崩潰棧信息的方法詳解

    Android解讀Native崩潰棧信息的方法詳解

    大部分的 Android 開發(fā)者使用的主要語(yǔ)言都是 Kotlin / Java,他們的崩潰棧信息非常清晰,也非常好定位到問(wèn)題,本文小編給大家介紹了Android如何解讀Native崩潰棧信息,需要的朋友可以參考下
    2023-11-11
  • Android編程實(shí)現(xiàn)簡(jiǎn)單流量管理功能實(shí)例

    Android編程實(shí)現(xiàn)簡(jiǎn)單流量管理功能實(shí)例

    這篇文章主要介紹了Android編程實(shí)現(xiàn)簡(jiǎn)單流量管理功能的方法,結(jié)合實(shí)例形式分析了Android實(shí)現(xiàn)流量監(jiān)控所涉及的功能模塊與布局技巧,需要的朋友可以參考下
    2016-02-02
  • Android設(shè)置項(xiàng)目為系統(tǒng)APP方法

    Android設(shè)置項(xiàng)目為系統(tǒng)APP方法

    大家好,本篇文章講的是Android設(shè)置項(xiàng)目為系統(tǒng)APP介紹,感興趣的同學(xué)趕快來(lái)看一看吧,希望本篇文章對(duì)你起到幫助
    2021-11-11
  • Android自定義attr的各種坑

    Android自定義attr的各種坑

    開發(fā)過(guò)程中經(jīng)常會(huì)自定義View來(lái)實(shí)現(xiàn)各種各樣炫酷的效果,在實(shí)現(xiàn)這些效果的同時(shí),我們往往會(huì)定義很多attr屬性這篇文章主要介紹了Android自定義attr的各種坑,需要的朋友可以參考下
    2016-04-04
  • Android使用AlertDialog實(shí)現(xiàn)對(duì)話框

    Android使用AlertDialog實(shí)現(xiàn)對(duì)話框

    本文主要介紹了Android使用AlertDialog實(shí)現(xiàn)對(duì)話框的相關(guān)知識(shí),具有很好的參考價(jià)值。下面跟著小編一起來(lái)看下吧
    2017-03-03

最新評(píng)論