前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Atlas 带你畅游动态性容器框架之旅

Atlas 带你畅游动态性容器框架之旅

作者头像
开发者技术前线
发布2020-11-23 15:03:45
5480
发布2020-11-23 15:03:45
举报

Atlas是阿里巴巴在淘宝不断演化中在Android系统上推出的一个容器化框架,也叫动态组件化(Dynamic Bundle)框架。它主要提供了解耦化、组件化、动态性的支持。覆盖了工程师的工程编码期、Apk运行期以及后续运维期的各种问题。

在工程期,实现工程独立开发,调试的功能,工程模块可以独立。

在运行期,实现完整的组件生命周期的映射,类隔离等机制。

在运维期,提供快速增量的更新修复能力,快速升级。

Atlas是工程期和运行期共同起作用的框架,我们尽量将一些工作放到工程期,这样保证运行期更简单,更稳定。快速开发的同时,能够进行灵活发布,动态更新以及提供了线上故障快速修复的能力。

与点评,360的插件框架不同的是,atlas是一个组件框架,atlas不是一个多进程的框架,主要完成的就是在运行环境中按需地去完成各个bundle的安装,加载类和资源。

技术术语

Bundle: 类似OSGI规范里面bundle(组件)的概念,每个bundle有自己的classloader,与其他bundle相隔离,同时Atlas框架下bundle有自身的资源段(PackageID,打包时AAPT指定);另外与原有OSGI所定义的service格式不同之处是Atlas里面Bundle透出所有定义在Manifest里面的component,随着service,activity的触发执行bundle的安装,运行。

awb: android wireless bundle的缩写,实际上同AAR类似,是最终构建整包前的中间产物。每个awb最终会打成一个bundle。awb与aar的唯一不同之处是awb与之对应有个packageId的定义。

host: 宿主的概念,所有的bundle可以直接调用host内的代码和资源,所以host常常集合了公共的中间件,UI资源等。host和bundle的依赖关系如下图所示:

host: 宿主的概念,所有的bundle可以直接调用host内的代码和资源,所以host常常集合了公共的中间件,UI资源等。host和bundle的依赖关系如下图所示:

框架剖析

从上图也可以看出基于Atlas构建后大致工程的结构:

首先有个构建整体APK工程Apk_builder,里面管理着所有的依赖(包括atlas)及其版本,Apk_builder本身可能不包含任何代码,只负责构建使用 host内部包含独立的中间件,以及一个Base的工程,里面可能包含应用的Application,应用icon等基础性内容(如果足够独立,application也可以直接放在apk_builder内); 业务层基本上以bundle为边界自上而下与host发生调用,同时bundle之间允许存在依赖关系;相对业务独立的bundle如果存在接口耦合建议封装成aidl service的方式保证自身封装性;同时某些中间件如果只存在若干bundle使用的也可以封装bundle的方式提供出来,以保证host内容精简

remote bundle: 远程bundle,远程bundle只是apk构建时并未打到apk内部,而是单独放在了云端;同时远程bundle的限制条件是第一次被触发的前提是bundle内的Activity需要被start,此时基于Atlas内的ClassNotFoundInterceptorCallback可以进行跳转的重定向,提示用户下载具体bundle,待用户确定后进行异步下载同时完成后再跳转到目标bundle(此部分代码由于涉及下载及UI展示等内容并未包含在开源仓库中,有需要可以根据ClassNotFoundInterceptorCallback自行实现)

APK结构

基于Atlas构建后的APK结构如下图,host与普通Apk无异,但是Manifest和assets会添加一些额外的内容,同时在armeabi目录中会增加若干个bundle构建的产物,取名为String.format(lib%s.so,packagename.replace(".","_"));packagename为bundle的AndroidManifest中的packagename,这些so都是正常的apk结构,改为so放入lib目录只是为了安装时借用系统的能力从apk中解压出来,方便后续安装

原理剖析

容器框架

如上图所示,atlas主要分为以下几个层级:

  1. 最底下的hack工具层: 包括了容器所需的所有系统层面的注入和hack的工具类初始化和校验,容器启动时先校验设备是否支持容器运行,不支持则采取降级并记录原因;
  2. Bundle Framework 负责bundle的安装 更新 操作以及管理整个bundle的生命周期;
  3. runtime层:主要包括清单管理、版本管理、以及系统代理三大块,基于不同的触发点按需执行bundle的安装和加载;runtime层同时提供了开发期快速debug支持和监控两个功能模块。从Delegate层可以看到,最核心的两个代理点:一个是DelegateClassLoader:负责路由class加载到各个bundle内部,第二个是DelegateResource:负责资源查找时能够找到bundle内的资源;这是bundle能够真正运行起来的根本;其余的代理点均是为了保证在必要的时机按需加载起来目标bundle,让其可以被DelegateClassloader和DelegateResource使用
  4. 对外接入层:AtlasBridgeApplication是atlas框架下apk的真正Application,在基于Atlas框架构建的过程中会替换原有manifest中的application,所以Atlas没入的接入并不存在任何初始化代码,构建脚本完成了接入的过程。AtlasBridgeApplication里面除了完成了Atlas的初始化功能,同时内置了multidex的功能,这样做的原因有两个:
    1. 很多大型的app不合理的初始化导致用multidex分包逻辑拆分的时候主dex的代码就有可能方法数超过65536,AtlasBridgeApplication与业务代码完全解耦,所以拆分上面只要保证atlas框架在主dex,其他代码无论怎么拆分都不会有问题;
    2. 如果不替换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里面通常会创建了两种classLoader,第一个是DelegateClassLoader,他作为类查找的一个路由器而存在,本身并不负责真正类的加载;DelegateClassLoader启动时被atlas注入LoadedApk中,替换原有的PathClassLoader;第二个是BundleClassLoader,参考OSGI的实现,每个bundle resolve时会分配一个BundleClassLoader,负责该bundle的类加载。关系如下图所示: DelegateClassLoader以PathClassLoader为parent,同时在路由过程中能够找到所有bundle的classloader;

BundleClassLoader以BootClassLoader为parent,同时引用PathClassLoader,BundleClassLoader自身findClass的顺序为

1. findOwn: 查找bundle dex 自身内部的class

2. findDependency: 查找bundle依赖的bundle内的class

3. findPath: 查找主apk中的class

示列

下图是容器中类加载的大致顺序; 可以认为是一个Bundle的Activity启动的类加载过程来帮助理解(假设Activity所在的bundle已经安装);

  1. ActivityThread从LoadedApk中获取classloader去load Activity Class;
  2. 根据上面的classloader关系,先去parent里面加载class;
  3. 由于class在bundle里面,所以pathclassloader内查找失败,接着delegateclassloader根据bundleinfo信息查找到classloader在bundle中(假设为bundleA);
  4. 从bundleA中加载class,并且创建class;
  5. 后面在Activity起来后,如果bundleA对bundleB有依赖关系,那么如果用到了bundleB的class,又会根据bundlA的bundleClassloader的dependency去获取bundleB的classloader去加载;

资源加载机制

类似ClassLoader,LoadedApk中的Resources被替换成Atlas内部的DelegateResources,同时在每个Bundle安装的过程中,每个bundle的assetspath会被更新到DelegateResources的AssetsManager中;每个bundle的资源特征如图可知:

  1. bundle构建过程中,每个bundle会被独立进行分区,packageId保证全局唯一,packageID在host的构建工程内会有个packageIdFile.properties进行统一分配;
  2. 虽然每个bundle的manifest都声明了自己的packagename,但是在aapt过程中,arsc文件里面所有bundle的packagename均被统一为hostApk的package,比如在手淘内就都是com.taobao.taobao;这样改的目的是为了解决在资源查找中一些兼容性问题;

更新原理

通Apk的更新的过程为构建->安装->生效,与之相对应,动态部署也可以分为三个过程:

  1. 构建 不同于Apk更新产物就是一个完整的Apk,动态部署的构建产物是一个后缀为tpatch格式的文件
  2. merge 下载到tpatch文件后,动态部署sdk会在后台完成merge到安装的过程,整个过程对用户透明
  3. 生效 merge完以后,当前的应用处于一个等待生效的状态,会在合适的时机选择进程重启来生效此次的动态部署,且在生效前不会再接收新的动态部署行为,进程重启以后表示一次完整的动态部署过程结束

官方GitHub:https://github.com/alibaba/atlas 素材和技术均来自atlas官网。

技术 - 资讯 - 感悟

END

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-05-31,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 开发者技术前线 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 容器框架
  • Bundle生命周期
  • 类加载机制
  • 资源加载机制
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档