• 欢迎访问web前端中文站,JavaScript,CSS3,HTML5,web前端demo
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏web前端中文站吧

Android 热更新热升级访问权限和即时生效问题

JAVA web前端中文站 3年前 (2017-05-20) 1769次浏览 已收录 0个评论
文章目录[隐藏]

前段时间 IOS 取消了相关框架的热更,在 CSDN 社区专家群引起了大量的讨论。大家纷纷发表自己的看法和技术解决方案。本文不是 IOS 相关的问题的解决方案,主要围绕 Android 的热更新进行学习!

更多精彩内容请看 web 前端中文站
http://www.lisa33xiaoq.net 可按 Ctrl + D 进行收藏

综合前面的几篇文章《Android 热修复升级原理和实践》《详解 Android 热更新升级如何突破底层结构差异?》

看了前面的几篇文章,你可能会有疑惑:我们只是替换了 ArtMethod 的内容,但新替换的方法的所属类,和原先方法的所属类,是不同的类,被替换的方法有权限访问这个类的其他 private 方法吗?

以这段简单的代码为例

 public class Demo{  Demo{   func();  }  private void func(){} }

Demo 构造函数调用私有函数 func 所对应的 Dex Code 和 Native Code 为

Android 热更新热升级访问权限和即时生效问题

这个调用逻辑和之前 Activity 的例子大同小异,需要注意的地方是,在构造函数调用同一个类下的私有方法 func 时,没有做任何权限检查。也就是说,这时即使我把 func 方法的偷梁换柱,也能直接跳过去正常执行而不会报错。

可以推测,在 dex2oat 生成 AOT 机器码时是有做一些检查和优化的,由于在 dex2oat 编译机器码时确认了两个方法同属一个类,所以机器码中就不存在权限检查的相关代码。

同包名下的权限问题

但是,并非所有方法都可以这么顺利地进行访问的。我们发现补丁中的类在访问同包名下的类时,会报出访问权限异常:

Android 热更新热升级访问权限和即时生效问题

虽然 com.patch.demo.BaseBug 和 com.patch.demo.MyClass 是同一个包 com.patch.demo 下面的,但是由于我们替换了 com.patch.demo.BaseBug.test,而这个替换了的 BaseBug.test 是从补丁包的 Classloader 加载的,与原先的 base 包就不是同一个 Classloader 了,这样就导致两个类无法被判别为同包名。具体的校验逻辑是在虚拟机代码的 Class::IsInSamePackage 中:

Android 热更新热升级访问权限和即时生效问题

关键点在于,Class loaders must match 这行注释。

知道了原因就好解决了,我们只要设置新类的 Classloader 为原来类就可以了。而这一步同样不需要在 JNI 层构造底层的结构,只需要通过反射进行设置。这样仍旧能够保证良好的兼容性。

实现代码如下:

Android 热更新热升级访问权限和即时生效问题

这样就解决了同包名下的访问权限问题。

反射调用非静态方法产生的问题

当一个非静态方法被热替换后,在反射调用这个方法时,会抛出异常。

比如下面这个例子:

 //BaseBug.test 方法已经被热替换了。 ... ... BaseBug bb = new BaseBug(); Method testMeth = BaseBug.class.getDeclaredMethod("test"); testMeth.invoke(bb);

invoke 的时候就会报:

Android 热更新热升级访问权限和即时生效问题

这里面,expected receiver 的 BaseBug,和 got 到的 BaseBug,虽然都叫 com.patch.demo.BaseBug,但却是不同的类。

前者是被热替换的方法所属的类,由于我们把它的 ArtMethod 的 declaring_class_ 替换了,因此就是新的补丁类。而后者作为被调用的实例对象 bb 的所属类,是原有的 BaseBug。两者是不同的。

在反射 invoke 这个方法时,在底层会调用到 InvokeMethod:

Android 热更新热升级访问权限和即时生效问题

这里面会调用 VerifyObjectIsClass 函数做验证。

Android 热更新热升级访问权限和即时生效问题

o 表示 Method.invoke 传入的第一个参数,也就是作用的对象。
c 表示 ArtMethod 所属的 Class。

因此,只有 o 是 c 的一个实例才能够通过验证,才能继续执行后面的反射调用流程。

由此可知,这种热替换方式所替换的非静态方法,在进行反射调用时,由于 VerifyObjectIsClass 时旧类和新类不匹配,就会导致校验不通过,从而抛出上面那个异常。

那为什么方法是非静态才有这个问题呢?因为如果是静态方法,是在类的级别直接进行调用的,就不需要接收对象实例作为参数。所以就没有这方面的检查了。

对于这种反射调用非静态方法的问题,我们会采用另一种冷启动机制对付,本文在最后会说明如何解决。

即时生效所带来的限制

除了反射的问题,像本方案以及 Andfix 这样直接在运行期修改底层结构的热修复,都存在着一个限制,那就是只能支持方法的替换。而对于补丁类里面存在方法增加和减少,以及成员字段的增加和减少的情况,都是不适用的。

原因是这样的,一旦补丁类中出现了方法的增加和减少,就会导致这个类以及整个 Dex 的方法数的变化。方法数的变化伴随着方法索引的变化,这样在访问方法时就无法正常地索引到正确的方法了。

而如果字段发生了增加和减少,和方法变化的情况一样,所有字段的索引都会发生变化。并且更严重的问题是,如果在程序运行中间某个类突然增加了一个字段,那么对于原先已经产生的这个类的实例,它们还是原来的结构,这是无法改变的。而新方法使用到这些老的实例对象时,访问新增字段就会产生不可预期的结果。

不过新增一个完整的、原先包里面不存在的新类是可以的,这个不受限制。

总之,只有两种情况是不适用的:

  1. 引起原有了类中发生结构变化的修改
  2. 修复了的非静态方法会被反射调用,而对于其他情况,这种方式的热修复都可以任意使用。

总结

虽然有着一些使用限制,但一旦满足使用条件,这种热修复方式是十分出众的,它补丁小,加载迅速,能够实时生效无需重新启动 app,并且具有着完美的设备兼容性。对于较小程度的修复再适合不过了。

本修复方案将最先在阿里 Hotfix 最新版本(Sophix)上应用,由手机淘宝技术团队与阿里云联合发布。

Sophix 提供了一套更加完美的客户端服务端一体的热更新方案。针对小修改可以采用本文这种即时生效的热修复,并且可以结合资源修复,做到资源和代码的即时生效。

而如果触及了本文提到的热替换使用限制,对于比较大的代码改动以及被修复方法反射调用情况,Sophix 也提供了另一种完整代码修复机制,不过是需要 app 重新冷启动,来发挥其更加完善的修复及更新功能。从而可以做到无感知的应用更新。

并且 Sophix 做到了图形界面一键打包、加密传输、签名校验和服务端控制发布与灰度功能,让你用最少的时间实现最强大可靠的全方位热更新

一张表格来说明一下各个版本热修复的差别:

方案对比 Andfix 开源版本 阿里 Hotfix 1.X 阿里 Hotfix 最新版(Sophix)
方法替换 支持,除部分情况[0] 支持,除部分情况 全部支持
方法增加减少 不支持 不支持 以冷启动方式支持[1]
方法反射调用 只支持静态方法 只支持静态方法 以冷启动方式支持
即时生效 支持 支持 视情况支持[2]
多 DEX 不支持 支持 支持
资源更新 不支持 不支持 支持
so 库更新 不支持 不支持 支持
Android 版本 支持 2.3~7.0 支持 2.3~6.0 全部支持包含 7.0 以上
已有机型 大部分支持[3] 大部分支持 全部支持
安全机制 加密传输及签名校验 加密传输及签名校验
性能损耗 低,几乎无损耗 低,几乎无损耗 低,仅冷启动情况下有些损耗
生成补丁 繁琐,命令行操作 繁琐,命令行操作 便捷,图形化界面
补丁大小 不大,仅变动的类 小,仅变动的方法 不大,仅变动的资源和代码[4]
服务端支持 支持服务端控制[5] 支持服务端控制

说明:

  1. 部分情况指的是构造方法、参数数目大于 8 或者参数包括 long,double,float 基本类型的方法。
  2. 冷启动方式,指的是需要重启 app 在下次启动时才能生效。
  3. 对于 Andfix 及 Hotfix 1.X 能够支持的代码变动情况,都能做到即时生效。而对于 Andfix 及 Hotfix 1.X 不支持的代码变动情况,会走冷启动方式,此时就无法做到即时生效。
  4. Hotfix 1.X 已经支持绝大部分主流手机,只是在 X86 设备以及修改了虚拟机底层结构的 ROM 上不支持。
  5. 由于支持了资源和库,如果有这些方面的更新,就会导致的补丁变大一些,这个是很正常的。并且由于只包含差异的部分,所以补丁已经是最大程度的小了。
  6. 提供服务端的补丁发布和停发、版本控制和灰度功能,存储开发者上传的补丁包。

【注:本文源自网络文章资源,由站长整理发布】


web 前端中文站 , 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:Android 热更新热升级访问权限和即时生效问题
喜欢 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址