中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Android so庫的熱更新問題

發布時間:2020-10-02 06:59:50 來源:腳本之家 閱讀:138 作者:_區長 欄目:移動開發

本來想寫資源的熱修復的,雖然方案差不多已經完成了,但是考慮到一些敏感問題,資源修復就不寫了。那就來寫寫so的熱修復,其原理和class的修復是一樣的,但是so的熱修復的需求并不高,就當做學習吧。

首先來總結一下Android的ClassLoader方式的熱更新,這種方式類的查找過程是通過BaseDexClassLoader來完成的,最終會通過成員變量DexPathList對象中的findClass方法來查找類,代碼如下:

public Class findClass(String name, List<Throwable> suppressed) {
  for (Element element : dexElements) {
    DexFile dex = element.dexFile;
    if (dex != null) {
      Class clazz = dex.loadClassBinaryName(name, definingContext, suppressed);
      if (clazz != null) {
        return clazz;
      }
    }
  }
  if (dexElementsSuppressedExceptions != null) {
    suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions));
  }
  return null;
}

只需將patch的class插入到dexElements最前面即可完成熱更新,當然還需要防止類被打上校驗的標記,做法就是在class中插入一段字節碼引用其他dex中的類。

參考class的修復方式,我們可以在BaseDexClassLoader中找到加載so的邏輯。

@Override
public String findLibrary(String name) {
  return pathList.findLibrary(name);
}

最終也會調用DexPathList對象中的方法進行處理,其函數內容為

public String findLibrary(String libraryName) {
  String fileName = System.mapLibraryName(libraryName);
  for (File directory : nativeLibraryDirectories) {
    String path = new File(directory, fileName).getPath();
    if (IoUtils.canOpenReadOnly(path)) {
      return path;
    }
  }
  return null;
}

可以看到邏輯和class是類似的,首先會調用System.mapLibraryName函數獲得so的名字,比如我傳入的參數是Test(這個Test就是在調用System.loadLibrary(“Test”)時傳入的),則這個函數的作用就是將其轉換為類似libTest.so這樣的名字,然后遍歷nativeLibraryDirectories數組,這是一個File文件夾數組,看其文件夾下是否存在對應的so,并且是否可讀,如果滿足條件,則直接返回。

那么我們就可以將我們的patch的so所在目錄插入到這個數組最前面即可完成so的修復。具體代碼就不貼了,實踐后得出的結論是這種方式是完全可行的,只不過Android 6.0中這部分代碼邏輯發生了改變。

在Android 4.0-5.1中,只需要將文件夾目錄插入到nativeLibraryDirectories數組最前面即可,這個過程直接使用反射插入patch的so所在目錄到數組最前面。

/** List of native library directories. */
private final File[] nativeLibraryDirectories;

但是在Android 6.0中,查找邏輯轉為了Elements查找

/** List of native library path elements. */
private final Element[] nativeLibraryPathElements;
public String findLibrary(String libraryName) {
  String fileName = System.mapLibraryName(libraryName);
  for (Element element : nativeLibraryPathElements) {
    String path = element.findNativeLibrary(fileName);
    if (path != null) {
      return path;
    }
  }
  return null;
}

所以在6.0中需要將so的patch目錄轉換為Element對象,插入到nativeLibraryPathElements最前面,Element的對象可以直接用反射去實現下面的代碼進行構造即可。

//偽代碼,類不可見,需要用反射
Element e=new Element(fileDir, true, null, null)

當然你也可以直接反射調用makePathElements方法創建Element數組。

最后的難點就是如何將對應cpu類型的so拿到,這個過程還是十分復雜的,比如說一個so同時存在x86,armeabi-v7a,armeabi的patch,而手機cpu是armeabi-v7a的,這時候就應該加載armeabi-v7a的so。總之這種情況組合起來會十分復雜了。

手機的cpu結構類型可以通過Build.CPU_ABI和Build.CPU_ABI2拿到,后面做的事就是根據這兩個值去加載對應目錄下的so,其實把這兩個目錄都插進去就沒問題了。

總結

以上所述是小編給大家介紹的Android so庫的熱更新問題,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對億速云網站的支持!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

屯留县| 黔西| 色达县| 河北区| 客服| 中江县| 商城县| 抚州市| 仙居县| 曲阳县| 辰溪县| 方山县| 玉溪市| 临清市| 都兰县| 辽中县| 蓬安县| 达日县| 峡江县| 鄯善县| 安国市| 齐齐哈尔市| 溧阳市| 尤溪县| 江津市| 乐山市| 莱芜市| 东阳市| 奉新县| 清新县| 巢湖市| 赣榆县| 古浪县| 格尔木市| 洛隆县| 绥江县| 溧阳市| 定边县| 灌云县| 台江县| 淮北市|