本博客日IP超过2000,PV 3000 左右,急需赞助商。
极客时间所有课程通过我的二维码购买后返现24元微信红包,请加博主新的微信号:xttblog2,之前的微信号好友位已满,备注:返现
受密码保护的文章请关注“业余草”公众号,回复关键字“0”获得密码
所有面试题(java、前端、数据库、springboot等)一网打尽,请关注文末小程序
腾讯云】1核2G5M轻量应用服务器50元首年,高性价比,助您轻松上云
前面一章我写了Atlas框架的常见问题总结《atlas 框架开发常见问题总结》,本章我们来解剖一下它的实现原理。
继 Weex 之后,阿里在移动技术领域又有开源大动作。
3月13日,手机淘宝安卓客户端容器化框架 Atlas 正式宣布开源。Atlas 由阿里巴巴移动团队自研,以容器化思路解决大规模团队协作问题,实现并行开发、快速迭代和动态部署,适用于 Android 4.x 以上系统版本的大小型 App 开发。
Atlas 容器框架
如上图所示,atlas主要分为以下几个层级:
-
最底下的hack工具层: 包括了容器所需的所有系统层面的注入和hack的工具类初始化和校验,容器启动时先校验设备是否支持容器运行,不支持则采取降级并记录原因;
-
runtime层:主要包括清单管理、版本管理、以及系统代理三大块,基于不同的触发点按需执行bundle的安装和加载;runtime层同时提供了开发期快速debug支持和监控两个功能模块。从Delegate层可以看到,最核心的两个代理点:一个是DelegateClassLoader:负责路由class加载到各个bundle内部,第二个是DelegateResource:负责资源查找时能够找到bundle内的资源;这是bundle能够真正运行起来的根本;其余的代理点均是为了保证在必要的时机按需加载起来目标bundle,让其可以被DelegateClassloader和DelegateResource使用
-
对外接入层:AtlasBridgeApplication是atlas框架下apk的真正Application,在基于Atlas框架构建的过程中会替换原有manifest中的application,所以Atlas没入的接入并不存在任何初始化代码,构建脚本完成了接入的过程。AtlasBridgeApplication里面除了完成了Atlas的初始化功能,同时内置了multidex的功能,这样做的原因有两个:
①很多大型的app不合理的初始化导致用multidex分包逻辑拆分的时候主dex的代码就有可能方法数超过65536,?AtlasBridgeApplication与业务代码完全解耦,所以拆分上面只要保证atlas框架在主dex,其他代码无论怎么拆分都不会有问题;
②如果不替换Application,那么atlas的初始化就会在application里面,由于基于Atlas的动态部署实际上是类替换的机制,那么这种机制就会必然存在包括Application及其import的class等部分代码在dalvik不支持部署的情况,这个在使用过程中造成一定成本,需要小心的使用以避免dalivk内部class resolve机制导致部分class没成功,替换以后该问题得到最好的解决,除atlas本身以外,所有业务代码均可以动态部署;
另外内置的原生的multidex在dalvik上面性能并不好,atlas内部对其进行了优化提高了在dalvik上面的体验。
除AtlasBridgeApplication之外,接入层对外提供了部分工具类,包括主动install bundle,start bundle,以及获取全局的application等各种功能。
Bundle生命周期
每个bundle的生命周期如下图所示:
Installed bundle被安装到storage目录
Resolved classloader被创建,assetpatch注入DelegateResoucces
Active bundle的安全校验通过;bundle的dex检测已经成功dexopt(or dex2oat),resource已经成功注入
Started bundle开始运行,bundle application的onCreate方法被调用
Atlas 类加载机制
Atlas里面通常会创建了两种classLoader,第一个是DelegateClassLoader,他作为类查找的一个路由器而存在,本身并不负责真正类的加载;DelegateClassLoader启动时被atlas注入LoadedApk中,替换原有的PathClassLoader;第二个是BundleClassLoader,参考OSGI的实现,每个bundle resolve时会分配一个BundleClassLoader,负责该bundle的类加载。关系如下图所示: DelegateClassLoader以PathClassLoader为parent,同时在路由过程中能够找到所有bundle的classloader;
BundleClassLoader以BootClassLoader为parent,同时引用PathClassLoader,BundleClassLoader自身findClass的顺序为
- findOwn: 查找bundle dex 自身内部的class
- findDependency: 查找bundle依赖的bundle内的class
- findPath: 查找主apk中的class
Atlas 实例
下图是容器中类加载的大致顺序; 可以认为是一个Bundle的Activity启动的类加载过程来帮助理解(假设Activity所在的bundle已经安装);
- ActivityThread从LoadedApk中获取classloader去load Activity Class;
- 根据上面的classloader关系,先去parent里面加载class;
- 由于class在bundle里面,所以pathclassloader内查找失败,接着delegateclassloader根据bundleinfo信息查找到classloader在bundle中(假设为bundleA);
- 从bundleA中加载class,并且创建class;
- 后面在Activity起来后,如果bundleA对bundleB有依赖关系,那么如果用到了bundleB的class,又会根据bundlA的bundleClassloader的dependency去获取bundleB的classloader去加载;
Atlas 的资源加载机制
类似ClassLoader,LoadedApk中的Resources被替换成Atlas内部的DelegateResources,同时在每个Bundle安装的过程中,每个bundle的assetspath会被更新到DelegateResources的AssetsManager中;每个bundle的资源特征如图可知:
- bundle构建过程中,每个bundle会被独立进行分区,packageId保证全局唯一,packageID在host的构建工程内会有个packageIdFile.properties进行统一分配;
- 虽然每个bundle的manifest都声明了自己的packagename,但是在aapt过程中,arsc文件里面所有bundle的packagename均被统一为hostApk的package,比如在手淘内就都是com.taobao.taobao;这样改的目的是为了解决在资源查找中一些兼容性问题;
最后,欢迎关注我的个人微信公众号:业余草(yyucao)!可加作者微信号:xttblog2。备注:“1”,添加博主微信拉你进微信群。备注错误不会同意好友申请。再次感谢您的关注!后续有精彩内容会第一时间发给您!原创文章投稿请发送至532009913@qq.com邮箱。商务合作也可添加作者微信进行联系!
本文原文出处:业余草: » 详解 Atlas 框架原理