今天手淘技术团队宣布正式开源它们的容器框架Atlas,项目地址:

https://github.com/alibaba/atlas

同时他们还推出了项目官网,上线了技术文档:

http://atlas.taobao.org/

下面让Atlas团队来介绍下该项目的历史、原理和未来。

Atlas是什么

Atlas是古希腊神话中的天神,是波士顿动力公司的机器人,借助搜索引擎,得以发现这个名词背后许许多多的含义。在手机淘宝,Atlas是一个扎根于Android客户端的一个组件化容器框架,相比神话中用手和头支撑起苍天的泰坦神族,Atlas在手淘默默无闻地承载着手淘上丰富业务的运行,伴随着数不清的功能在用户手中经历新老交替。

插件化的历史

在阿里,在手机淘宝,移动客户端的迭代更新可以说是整个移动互联网从新起到繁荣的见证。伴随着越来越多业务的诞生,越来越多的代码开始往小小的客户端涌入,而无论是iOS还是Android,各种客户端的体积也经历着快速的增长。而由于客户端的推广成本较高,各个业务线都有很强的需求接入手机淘宝客户端。所以在当时航母战略的背景下,迫切需要一种技术能把客户端化整为零,这些模块可以自由组合,并且当部分功能变更时只需要更新对应模块。

我们在2012年底的时候就开始研究Android上的插件化技术,并与2013年初把Atlas作为插件化框架接入手机淘宝。基于插件化的能力,一个普通的Android应用可以低成本地转为符合Atlas规范的插件,使Apk既可以以插件方式运行也可以独立安装运行。一个大的Android客户端项目可以分割成数个插件,做到代码隔离,降低了开发、维护、部署的成本。

当时插件化的方案可分为三类:Web、WebApp、Native。各种方案在手淘内都在有同学进行深入的研究。

Native形式的插件由于技术门槛较高,当时业界采用的并不多见。但是由于其比WebApp有良好的性能和体验,同时对于许多已经成型的小客户端推广的迫切需求,尤其值得我们去探索。

上图是当时插件化的技术原理的简图,其实跟现在业界的插件化方案主要的设计思路基本一致。Atlas作为一个模拟的Android运行环境,每个插件以一个独立的进程运行在各自的沙箱环境中。同时由于接入成本较低,其他的业务应用基本可以算是零成本的方式接入到手淘环境,同时也可以随时发布新的版本进行更新。

插件化的方案有其特有的优势,独立的进程保证了业务的绝对隔离,同时也便于隔离风险。聚划算、天猫、彩票一个个独立应用开始起降于手淘这架航母。甜蜜的成长总是短暂,插件化发展很快,随着手淘All In方案的深入,一些隐患开始展现。

性能:新进程的开辟极大影响每个业务的进入速度,同时由于手淘的插件并不是用完即走的场景,比如说从首页->聚划算->详情->店铺->下单各个环节是存在着一定的关联,各个插件的进程无法退出。而多进程的机制又极大的占用了内存,同时也引起许多用户的质疑

复用:插件的独立限制了许多中间件的复用,AIDL的方式并不适合中间件能力的输出,独立的apk直接进入的同时也携带了大量重复的二方库,也一方面极大增大的应用的体积

稳定:插件化需要一个模拟的Android运行环境,在Android多版本以及国产ROM的兼容中需要做大量的工作,同时多插件运行过程中在低端设备上很容易遇到进程被回收或者三方应用强杀的情况,没有良好的恢复机制会极大降低用户的体验

组件化的诞生

伴随着All In的进行,在手淘内部发起了对大型app进行重构的计划。我们需要这样一个框架:

支持大量丰富业务的接入,同时业务之间能够保持清晰的边界,各自可以继续灵活迭代;

用一批统一的中间件去支撑起各种业务的底层功能,保持中间件代码的全面复用;

能够尽量保持对系统的低侵入,尊重原生运行机制以降低后期的维护成本;

在用户设备上尽量体现一个简单客户端的特性,同时特定的业务功能按需获取,保持体积的可控;

↑新容器化结构设想↑

基于对插件化框架对Android运行机制的理解,参考了OSGI在服务端框架,在开发IDE等领域"高复用、低耦合、可插拔"的优势,我们借鉴了OSGI规范开发了基于组件化的Atlas容器化框架。

下图是基于组件化框架的系统结构

最底层的tookit verifier全面罗列了上层需要反射使用的注入和代理的Api,会在应用启动时先进性全局性的校验,以避免程序运行中遇到不兼容的情况;

往上Bundle Framework负责组件的安装 更新 操作以及管理所有组件的生命周期,这里组件的边界隔离就遵循了OSGI的规范,每个组件分配独立的classloader,同时组件有各自的资源,每个资源在构建期间由AAPT分配独立的package ID;

Runtime层 主要包括清单管理、版本管理、以及系统代理三大块:

版本:每个组件在构建期间就由构建插件分配自己的版本号,同时安装期间也有各自的版本目录,每个bundle的启动加载都需要经过版本的校验,组件发生更新同时也下发最新的版本信息。依托版本管理机制组件的热更新能力水到渠成。

清单:OSGI规范中每个组件通常通过OSGI.MF来暴露自身的component,这是与Atlas容器所不同的地方。在Android设备上,多文件的形式很容易受IO异常的影响干扰bundle正常运行,所以我们采用了构建期间集中生成清单的方式,清单里面记录bundle所有的component(Android四大组件),依赖、packagename等内容。

代理:各个系统关键点的注入使得bundle可以做到按需加载,避免了像原生MultiDex方案由于首次启动时多dex同步安装而造成UI卡顿的情况,代理层的核心DelegateClassLoader负责类的查找和路由,DelegateResource管理所有bundle的资源,它们在容器启动时进行注入,并在运行过程中随着bundle的不断载入进行更新。

接入层 简单是美-复杂的东西留给自己。为了方便,Atlas容器有自身独立的Application负责启动,同时在构建期间会由插件替换应用原有的Application。运行期间应用首先由AtlasBridgeApplication负责启动,并在容器启动完毕后全权代理给应用真正的Application;同时对需要自定义和由外部决策的功能,容器开放接口由接入方简单设置。

解耦和依赖

依托classloader,组件的独立性有了充分的保证,同时由于BundleClassloader保持了对PatchClassLoader的引用,使得宿主的中间件就如同普通APK开发一样可以被组件简单调用;同时组件之间除了基于AIDL的服务调用,组件之间提供了静态依赖和运行时依赖,相互依赖的组件可以通过配置打成,这在一定程度上使某些偏功能的代码或者UI的重用成为可能,同时配置的方式使组件之间的关系可以清晰追溯。

性能的演进

异步按需:由于每个组件是一个小型Apk的结构,每个组件安装使其涉及到文件的拷贝、native lib的解压以及校验载入等过程。特别是Service等后台component触发组件安装和前台Activity引发组件安装并行时UI的流畅很受影响。为了降低对UI的影响,每个组件的安装都在一个统一的异步安装线程中进行。Activity、Service、Receiver等的发起都被进行了异步的处理。

解释执行组件的代码在安装后还需要dexopt才能使用,这一过程在ART上的时间消耗尤为明显,为了降低用户等待时间,Atlas框架对dalivk系统上首次使用bundle时关闭了verify,在ART系统上首次使用时关闭了dex2oat走解释执行,保障bundle首次进入尽可能地高效,同时后台通过异步任务走原生的dexopt过程,为下次使用做好准备。

动态性的增强

远程组件:插件化时代的按需下载并没有被废弃,独立的远程组件可以满足用户的个性化需求。基于用户的操作和清单机制远程组件在用户需要时只需要简单地等待或者授权就可以从远端拉倒本地。同时当用户设备因为空间紧张时容器也可以清理掉一些长期不用的组件以释放拥挤的空间

动态部署:动态部署是容器一个最重要的功能。基于此,业务可以灵活发布自己的需求;有故障的业务可以及时修复或者回滚;同时动态部署的快速覆盖能力在灰度等场景下可以更快地收到所需的效果。动态部署的范围也通过改造进行扩大,从最初的组件部署到现在支持除Atlas容器小部分核心代码外的所有代码,部署patch包的体积和性能的改进也在不断的进行改进。

diff

每次大版本的发版,集成平台会保留该次发版的AP(Ap中记录所有参与构建的二方库的版本,组件的依赖,混淆的mapping等各种信息),在手淘接下来每周一次的动态部署迭代中,动态部署的构建会与之前的dex进行字节码级别的diff,生成tpatch包,最终下发到用户手机的patch仅包含变化class组成的dex和更改或者新增的资源文件

Bundle的Merge

patch收到后,客户端的merge过程会根据patch信息,取到source 组件,source dex和patch dex进行dex合并,合成新的dex,同时变化的资源覆盖老的资源最终形成新的组件。

中间件部署

动态部署能力的增强少不了对底层中间件的支持,部署的机制也与bundle截然不同

1. 中间件代码部署

Dalvik和Art在merge过程中都会形成新patch zip,zip中dex以多dex的方式命名,patch dex为classes.dex,原始apk中的classes.dex以此根据序号+1放入zip中,不同的是dalvik由于preVerify的限制写入zip中的源dex会先经过处理,剔除在patchdex中已有的class,确保被patch的dex无法被打上preVerify的标签。

安装过程中则多个dex依次dexopt,同时插入到dexpatch的第一位。而ART由于无preVerify校验,但是Android到ART后原有的dexopt会改为dex2oat.

运行时代码由原来的解释执行改为直接运行native代码,之前的使用过程中发现单纯得往前面追加patch的dex并不能完全解决动态部署的问题,dex2oat的过程优化了class的执行代码,比如说内敛,虚函数的校验等。就有可能在运行过程中直接在native层执行老的优化过的class代码而不是从新patch的dex中load新的class去使用。

所以在ART上类似Dalivk,放入源dex,只是源dex不会做任何处理,然后合并在一起做一遍dex2oat,这样能使新的class覆盖老的class参与dex2oat并完成优化的过程,

2. 中间件资源部署

资源部署基于overlay机制达成,不过dalivk上这个机制并不支持新增资源,在overlay的包里面如果读到了一个资源,dalvik系统会去校验该资源ID在base中值,如果不存在则抛错,所以动态部署为了利用这一特性同时支持新增资源的需求,在打基线包的时候就在每个不同的type里面预留了128个资源ID供后续动态部署使用。

同时打动态部署的patch时会以之前的ID分配的内容作为输入,保证已有的资源分配到的ID保持不变,同时如果资源没有发生变更,则剔除该资源,所以aapt dump resource patch的时候我们看到的INVALID TYPE 的资源段就表示没有发生变更的资源,如果有发生了变更,且之前有这个资源,就会在原有的资源ID分配过去,同时新的资源文件打入patch包或者新的资源文本写入arsc,如果是新增的资源,则使用预留的资源段进行分配。整个替换过程如下图所示

Atlas动态部署的能力随着手淘的需求不断进行着演进,随着整个框架的开源,自然需求会变得更加广泛。比如在手淘内部一周一发版的节奏下,动态部署对新增component的某些需求并不强烈,而开源后此类功能可能会尤为重要,所以接下来容器的更新迭代中此类的功能也会及时上线。拥抱开源社区会是Atlas重新审视自己,继续发展的关键一步。

未来的路

相比于iOS,Android的推陈出新的速度是极快的。Google在Android系统的改进深入到方方面面,组件化的发展也需要紧跟Android步伐。

Atlas起步的时候MultiDex还未出来,解决方法数的问题就能带来足够的愉悦。现在Atlas基于组件化减少主dex方法数的同时,也支持主dex原生MultiDex的能力。目前Atlas内部集成了MultiDex的能力,外部只需要打开MultiDex开关即可。这么做的目的一方面避免外部初始化实际的误解,另一方面我们也意识到原生的mulitdex在性能上还有很多优化的点,我们会在后面及时进行优化。

在开发调试方面,Atlas容器框架基于动态部署的能力支持单个组件的独立编译调试,但是相比instantrun的速度,目前还有很大提高。而基于Instant Run改造的单组件秒级编译也已经在紧锣密鼓的开发中,后续基于框架的独立调试插件也将会在Android Studio插件库中上线。

Android系统机制的演进也鞭策着动态部署前行。比如16年Android 7.0的混合编译当时也给Atlas造成了不小的挑战,服务于亿级的UV,动态部署的能力的覆盖面、到达率都还有进一步提升的空间,相比andfix等热部署修复方案,动态部署需要重启来打到更新的能力可能也需要有新的转变。

市面上许许多多的容器框架,基本思路就大致两三种。Atlas本身也没有特别新的技术,有的是基于已有的知识进行不断的重组和优化。在手淘内部,追求更高的稳定性和性能,亿级的UV需要及其稳定的容器来承载,同时Atlas也不断尝试新的方案,在创新与实用之间不断权衡。

Atlas是一个结构简明的容器框架,通过尽量简单的思路去解决移动应用从开发到运维中的的桎梏,让开发中的复杂简单化,让维护中的复杂简单化,让开发从流水线上忙碌的工作回到专注于对最终目标的精耕细作,抛开嘈杂的干扰,拨开虚无缥缈,到达云和山的彼端!

扫描下面二维码直达Atlas项目官网:

活动推荐:

由InfoQ主办的第二届GMTC全球移动技术大会开始报名了!大会将于6月9-10日在北京举行。本届大会,我们将探讨智能时代的大前端,在动态化、React Native等逐渐流行的现在,移动和前端的融合将会发生怎样的变化?点击阅读原文进入大会官网,6折报名火热开启!

Atlas-手淘组件化框架的前世今生和未来的路的更多相关文章

  1. 从零开始搭建Android组件化框架

    问题 在已经开发过几个项目的童鞋,如果这时需要重新开发一个新项目,是否需要自己重新搭建框架呢,还是从老项目中拷贝粘贴? 我们是否可以封装一个底层的lib库,这个底层的公共基础库 包括了一些第三方库(如 ...

  2. Android组件化框架设计与实践

    在目前移动互联网时代,每个 APP 就是流量入口,与过去 PC Web 浏览器时代不同的是,APP 的体验与迭代速度影响着用户的粘性,这同时也对从事移动开发人员提出更高要求,进而移动端框架也层出不穷. ...

  3. 小程序组件化框架 WePY 在性能调优上做出的探究

    作者:龚澄 导语 性能调优是一个亘古不变的话题,无论是在传统H5上还是小程序中.因为实现机制不同,可能导致传统H5中的某些优化方式在小程序上并不适用.因此必须另开辟蹊径找出适合小程序的调估方式. 本文 ...

  4. [Android Pro] 终极组件化框架项目方案详解

    cp from : https://blog.csdn.net/pochenpiji159/article/details/78660844 前言 本文所讲的组件化案例是基于自己开源的组件化框架项目g ...

  5. Android组件化框架项目详解

    简介 什么是组件化? 项目发展到一定阶段时,随着需求的增加以及频繁地变更,项目会越来越大,代码变得越来越臃肿,耦合会越来越多,开发效率也会降低,这个时候我们就需要对旧项目进行重构即模块的拆分,官方的说 ...

  6. 组件化框架设计之AOP&IOC(四)

    阿里P7移动互联网架构师进阶视频(每日更新中)免费学习请点击:https://space.bilibili.com/474380680 本篇文章将从以下两个方面来介绍组件化框架设计: [AOP(面向切 ...

  7. 组件化框架设计之Java SPI机制(三)

    阿里P7移动互联网架构师进阶视频(每日更新中)免费学习请点击:https://space.bilibili.com/474380680 本篇文章将从深入理解java SPI机制来介绍组件化框架设计: ...

  8. 组件化框架设计之apt编译时期自动生成代码&动态类加载(二)

    阿里P7移动互联网架构师进阶视频(每日更新中)免费学习请点击:https://space.bilibili.com/474380680 本篇文章将继续从以下两个内容来介绍组件化框架设计: apt编译时 ...

  9. client高性能组件化框架React简单介绍、特点、环境搭建及经常使用语法

    [本文源址:http://blog.csdn.net/q1056843325/article/details/54729657 转载请加入该地址] 明天就是除夕了 预祝大家新春快乐 [ ]~( ̄▽ ̄) ...

随机推荐

  1. Unable to resolve target 'android-XX'解决办法

    在搭建好安卓编译环境后,我用Eclipse导入冲git上下载的安卓源码编译时,会提示 Unable to resolve target 'android-17' 等 “Unable to resolv ...

  2. lufylegend库 LGraphics扭曲图片

    lufylegend库 LGraphics扭曲图片 <!DOCTYPE html> <html lang="en"> <head> <me ...

  3. eclipse自定义new建

    Window->Perspective->Customize Perspective->Shortcuts   找到适合的选中然后OK即可

  4. asp.net客户端IP跟踪

    /// <summary> /// 获取客户端IP地址(无视代理) /// </summary> /// <returns>若失败则返回回送地址</retur ...

  5. 访问 Neutron 外部网络 - 每天5分钟玩转 OpenStack(143)

    前面我们学习了位于不同 Neutron subnet 的 instance 可以通过 router 通信,今天开始讨论 instance 如何访问外部网络. 这里的外部网络是指的租户网络以外的网络.租 ...

  6. [html5] 学习笔记-Canvas应用

    通过使用HTML5游戏开发的引擎CreatJS,创建HTML5 Canvas上的更好交互. 1.认识CreateJS CreateJS是一个外部库,用它可以比Canvas更方便的绘制图形. 官网:ht ...

  7. [html] 学习笔记-Canvas图形绘制处理

    使用Canvas API 可以将一个图形重叠绘制在另外一个图形上,也可以给图形添加阴影效果. 1.Canvas 图形组合 通过 globalCompositeOperation = 属性 来指定重叠效 ...

  8. npm 不是内部命令

    最近办公室流行给电脑装win10系统,于是在重新装好电脑系统后,再次运行thinkjs项目的时候,就发现了之前做过的项目打不开了,待再确认问题出在哪里的时候,才发现”nodejs以及npm不是内部或者 ...

  9. 【物联网云端对接-1】 通过HTTP协议与微软Azure IoT hub进行云端通信

    在2015年曾写过一篇文章<从微软build 2015,展望微软未来发展>,提到了微软的Azure和Windows 10 IoT,那算是初次接触微软物联网技术.比较幸运的是在后续的时间里, ...

  10. MongoDB学习总结(一) —— Windows平台下安装

    > 基本概念 MongoDB是一个基于分布式文件存储的开源数据库系统,皆在为WEB应用提供可扩展的高性能数据存储解决方案.MongoDB将数据存储为一个文档,数据结构由键值key=>val ...