博客
关于我
Android热修复升级探索——SO库修复方案
阅读量:148 次
发布时间:2019-02-27

本文共 1755 字,大约阅读时间需要 5 分钟。

Android热补丁方案:SO库修复的实现与分析

在Android开发中,热补丁方案旨在在不重新启动应用程序的情况下修复已安装的应用程序。通常情况下,开发者希望通过热补丁实现多方面的修复,包括类修复、资源修复以及SO库的修复。以下将详细介绍Android下的SO库修复思路,分析其实现原理以及在不同虚拟机(如Dalvik和Art)下的兼容性问题。


一、SO库加载原理

在Android中,Java API提供了两种加载SO库的接口:

  • System.loadLibrary(String libName):传入的参数是SO库的名称,表示SO库文件位于APK压缩文件中的libs目录下。系统会将该SO库复制到APK安装目录下,最后通过nativeLoad方法加载该SO库。

  • System.load(String pathName):传入的参数是SO库在磁盘中的完整路径,用于加载一个自定义外部的SO库文件。

  • 这两种方式最终都调用nativeLoad方法来加载SO库,参数为SO库的文件名。JNI编程中,动态注册的native方法必须实现JNI_OnLoad方法,而静态注册的native方法则必须以类名+方法名的格式进行注册。


    二、SO库热部署实时生效可行性分析

    为了实现SO库的实时修复,我们需要分析动态注册和静态注册native方法在不同虚拟机下的兼容性。

    1. 动态注册native方法实时生效

    动态注册的native方法通过JNI_OnLoad方法重新映射,前提是SO库已经加载过一次。我们可以先加载原SO库,然后再加载补丁SO库,从而实现动态注册native方法的实时修复。

    关键点:

    • Dalvik虚拟机:在Dalvik中,通过修改SO库的文件名(例如添加时间戳),确保在hashtable中查找到的句柄指向补丁SO库,从而实现动态注册方法的实时生效。
    • Art虚拟机:Art虚拟机直接通过System.load方法加载补丁SO库,调用补丁SO库的JNI_OnLoad方法,实现动态注册方法的实时生效。

    2. 静态注册native方法实时生效

    静态注册的native方法在第一次执行时完成映射,无法直接通过补丁SO库实现实时修复。我们需要解注册这些方法,然后重新加载补丁SO库。

    关键点:

    • 需要解注册静态注册的native方法,重新加载补丁SO库。
    • 由于无法直接知道哪些静态注册的native方法发生了变更,需依赖补丁SO库的重命名来确保加载新的方法。

    三、SO库实时生效的局限性

    尽管SO库的实时生效在动态注册方法中实现了兼容性,但静态注册方法的实时修复存在局限性:

    • 需要解注册静态注册的native方法,这在实际应用中难以实现,因为无法直接知道哪些方法发生了变更。
    • 补丁SO库的加载可能导致内存泄漏或OutOfMemoryError(OOM),尤其是在SO库较大或补丁较多的情况下。

    因此,最终放弃了SO库的实时生效需求,转而采用冷部署重启生效的方案。


    四、SO库冷部署重启生效的实现方案

    方案1:接口调用替换

    通过替换System.loadLibrary接口,优先加载补丁SO库:

    • 如果存在补丁SO库,优先加载补丁SO库;否则加载原SO库。

    优点:无需对不同SDK版本进行区分处理,实现简单。

    缺点:需要强制侵入用户接口调用,无法修复三方库的SO库。

    方案2:反射注入

    通过反射注入修改DexPathList.findLibrary方法,插入补丁SO库的路径:

    • findLibrary方法中,插入补丁SO库的路径到nativeLibraryDirectories数组的最前面。

    优点:可以修复三方库的SO库,不依赖于用户接口调用。

    缺点:需对SDK进行适配,findLibrary实现在SDK23之前和之后有所不同。同时,需选择合适的CPU架构的SO库文件进行修复。


    五、小结

    SO库修复方案目前主要采用接口调用替换和反射注入两种方式:

    • 接口调用替换:简单易行,但无法修复三方库的SO库。
    • 反射注入:实现普适性更强,但需对SDK进行适配。

    对于实时生效的需求,可以通过SO库的重命名确保动态注册方法的实时生效,但静态注册方法仍存在局限性。因此,推荐采用冷部署重启生效的方案,兼顾通用性和实现复杂度。

    转载地址:http://vkrb.baihongyu.com/

    你可能感兴趣的文章
    Objective-C实现列主元高斯消去法(附完整源码)
    查看>>
    Objective-C实现创建一个链表和打印该链表算法(附完整源码)
    查看>>
    Objective-C实现创建多级目录(附完整源码)
    查看>>
    Objective-C实现删除文件中的指定内容(附完整源码)
    查看>>
    Objective-C实现删除文本文件空行(附完整源码)
    查看>>
    Objective-C实现删除重复的字母字符算法(附完整源码)
    查看>>
    Objective-C实现判断32位的数字是否为正数isPositive算法(附完整源码)
    查看>>
    Objective-C实现判断A数组是否为B数组的子集(附完整源码)
    查看>>
    Objective-C实现判断位是不是偶数isEven算法(附完整源码)
    查看>>
    Objective-C实现判断字符串是否包含特殊字符算法(附完整源码)
    查看>>
    Objective-C实现判断字符串是否回文palindrome算法(附完整源码)
    查看>>
    Objective-C实现判断整数是否为2的幂isPowerOfTwo算法(附完整源码)
    查看>>
    Objective-C实现利用stack对输入的式子进行计算算法(附完整源码)
    查看>>
    Objective-C实现十进制转N进制算法(附完整源码)
    查看>>
    Objective-C实现十进制转二进制(附完整源码)
    查看>>
    Objective-C实现十进制转八进制算法(附完整源码)
    查看>>
    Objective-C实现华氏温度转摄氏温度(附完整源码)
    查看>>
    Objective-C实现单例模式(附完整源码)
    查看>>
    Objective-C实现单向链表的反转(附完整源码)
    查看>>
    Objective-C实现单向链表的反转(附完整源码)
    查看>>