Atlas-组件化框架 入门

ps:如果您看过atlas的官方介绍,本片文章可以略过,期待我们追溯源码的过程中有你的参与

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

Android方向的大牛们都已经深入了解了插件化所带来的巨大的便利,一直也没时间去搞一套详细的记忆,在这里,仅以源码分析的形式进行插件化框架的巩固,文集中会具体分析源码,框架结构,运行原理等方面,除了加深记忆,也让我们一起进步

本片

为引导篇,请注意后续更新。

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

https://github.com/alibaba/atlas

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

http://atlas.taobao.org/docs/

容器

框架结构图

Atlas是一个Android客户端容器化框架,主要提供了组件化、动态性、解耦化的支持。

将开发过程高度解耦,分别在工程期,运行期和运维期都得到了极大的提升

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

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

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

Atlas首先要解决的问题是大规模团队的协作问题,诉求包括并行开发、快速迭代、工程解耦,然后解决的问题是客户端动态更新的问题。

Atlas

组件化实现

组件化,业界称为插件化,不过这里Atlas的组件化和现在的插件化有一些不一样的地方。组件化是需要去知道组件的功能,设计更规范。

手机淘宝的apk目录结构如图所示,展示的是一个apk的一般结构架构,不同的是我们看到了很多的so文件,对于不同的so文件其实就是不同的插件,只是把每一个apk文件的后缀改成了.so放到的armeabi静态库中(这样在加载的过程中不会被解压校验),在运行期解压进行oat等操作

模块划分,atlas把工程分为两部分,分别是插件工程和宿主工程,插件工程可以共享宿主工程的资源文件也可以共享lib库或assert等一切可共享的文件,而宿主工程中包含引擎和共享资源等功能支持

Altas的整体设计分为5层

第一层我们称之为Hack层,包括OS Hack toolkit & verifier,这里我们对系统能力做一些扩展,然后做一些安全校验。

第二层是Bundle Framework,就是我们的容器基础框架,提供Bundle管理、加载、生命周期、安全等一些最基本的能力。

第三层是运行期管理层,包括清单,我们会把所有的Bundle和它们的能力列在一个清单上,在调用时方便查找;另外是版本管理,会对所有Bundle的版本进行管理;再就是代理,这里就是和业界一些插件化框架机制类似的地方,我们会代理系统的运行环境,让Bundle运行在我们的容器框架上;然后还有调试和监控工具,是为了方便工程期开发调试。

第四层是业务层了,这里我们向业务方暴露了一些接口,如框架生命周期、配置文件、工具库等等。

第五层,最上面一层是应用接入层,就是我们的业务代码了。

所以Atlas作为一个框架提供了相对完整的能力,业务层的开发可以在框架生命周期的各个环节做一些自定义的动作,也可以自由的调用系统、框架,乃至其它组件释放的能力。

组件化加载细节

前面讲的是容器层面的比较概要的东西,下面我们会讲一些具体的细节。

关于Bundle的生命周期会提供细粒度的节点,比如下面是一个Bundle从加载到运行的周期:

startInstall:开始加载。这个时候框架会做一些拷贝文件、释放lib、加载Bundle的事情;

Installed:加载完毕。这时框架会注入资源路径,创建class loader;

resolved:解析完毕,框架会检查组件配置是否合法,是否能被解析;

active:运行组件,即开始运行组件Bundle;

started:运行成功。

组件化涉及到的

第一个问题是Manifest处理,一个是因为来源很多,有宿主Manifest、Aar Manifest以及组件Manifest,另外不同组件的Manifest经常发生变化,要求我们灵活地去处理。这里的做法是在工程期将所有的Manifest进行Merge操作,这里需要注意的是Bundle的依赖单独Merge,因为这里涉及到依赖仲裁的问题。最后解析各个Bundle的Merge Manifest,得到整包的BundleInfoList,就是上面我们提到的Bundle信息清单。

类加

第二个是类加载,这里利用Delegate ClassLoader来动态加载组件的类。Delegate ClassLoader先查找宿主Bundle的PathClassLoader,然后根据前面的BundleList找到对应的BundleClassLoader.

资源

管理

第三个是资源,我们会用自己的DelegeteResources替换掉系统的resource,Bundle的资源会逐个在安装的时候添加到AssertPath,由于添加Bundle的顺序非固定,不分区会导致资源查找错乱。

另外,Dalvik和ART上的资源查找过程顺序是不一样的,加上小米等系统会重写自己的resources,所以我们会适配不同的机型,往后追加AssetsPath或者往前追加,系统AssetManager是个单例,默认往后追加,如果往前追加,则需要重新创建AssetsManager对象,同样主dex动态部署的时候要达到替换原有resource的目的,必须保证插入顺序与查找顺序一致。

还有需要注意的是,每次更新resourceTable的时候,必须保证apkresource,runtime的系统resource,例如webview,bundle resource都已经添加成功,而且唯一,顺序正确。

不同Bundle的资源可能发生命名冲突,我们是用了一种相对来说简单的方法,将各自的Bundle分配成不同的ID,保证所有的业务资源不会产生冲突,尽量将问题放到工程期解决。在很多代码里,通过反射来调用整个资源,在5.0以上的系统是没有问题的,它只找第一个,对业务代码而言,原来是怎么写的,今天还是怎么去写。

关于组件化性能这一部分,我们引入了按需加载,因为手淘APK有70多个Bundle,每个用户真正用的时候只需要5或10个,所以不需要加载所有的Bundle。Bundle之间进行隔离,通过Android四大原生组件进行交互,这样Bundle之间可以比较好的解耦。我们所有调用的入口都是基于BundleInfolist去做的,根据这个清单信息,得到组件所在Bundle,如果需要加载,我们就进行install、dexopt等操作。

另外,对于解决组件依赖问题,定义了两种新的组件格式Awb(业务Bundle)和solib(so库),前者与AAR一致,不过不添加本地lib,在构建的时候做依赖仲裁区分,后者是Native so库的依赖。Awb其实就是AAR,只是后缀修改了,如果你的包放在宿主Bundle就用AAR,如果是组件Bundle就用Awb。

对于业务Bundle的依赖,我们在构建期会将宿主Bundle和业务Bundle及其依赖分别打包,然后按照最短路径、第一声明原则进行树状仲裁,得到每个Bundle需要的依赖,在打包的时候会将依赖库放到各自的Bundle里去。

apk构

最后是APK构建,我们对它做了比较大的调整。上面的图中,其实左边这一部分是一个标准的APK的构建过程,包括处理,编译,到签名的过程。我们这个不同的地方是多了Awb需要特殊处理,其中Awb的资源根据宿主的resource.ap_和包内资源构建,R文件由Bundle R资源和宿主R资源合并而来,然后我们对Aapt进行了修改,对每个awb分配不同的packageId,然后进行统一混淆,生产各个AWB的Dex,打包为APK,签名之后复制到libs,改名为so文件,然后合并到taobao APK. 这就是我们组件化的整个过程。

Atla

s动态化

在一个容器框架内,组件化和动态化是相辅相成的,组件只是解决了解耦的问题,但我们如果想要随时发包,就必须让容器框架具备动态化能力。我们在完成了Atlas的组件化之后,做了动态化的支持。动态化的好处一个是包的大小缩减,我们可以将一些包在运行后下载到应用中,另一个是具备动态发版和修复能力。

增量

动态化方案

Atlas提供了动态部署的能力,主要目标是动态业务发布,以及问题修复。它基于手淘自研差量算法,主Bundle基于ClassLoader机制,业务Bundle基于差量merge,支持全业务类型。

另外,Atlas也支持Andfix作为插件使用,目标是快速故障修复,它的原理基于Native hook,主要做方法的修改,在实际中可以两个一起用。在工程构建期适配之后,可以做到一套代码两套方案通用。

动态

部署

自研动态部署功能实现原理,首先,对于Dex Patch的生成,我们通过修改Dex的字节码实现,将Dex文件转为Smali,对其中的ClassDef和ClassDataMethod结构体进行分析,可以实现删除、新增、修改类,然后通过Diff处理得到差量文件,再通过Merge处理即生成补丁。

其次是整个资源Patch的生成,分为两块,一个是业务Bundle,本来是一个不断加载的过程,它实现起来会比较简单,通过Md5 diff/BSDiff即可得到。对于主Bundle,因为安卓本身有一个限制,所有的资源必须得在base包里,新增一个资源是不生效的。所以一个做法是在打包的时候预留很多空资源。另外更新已有的资源则通过资源覆盖来完成。

最后,如果新加业务的话,会新加Activity,我们的做法首先在Manifest预埋一个StubActivity,然后在Instrumentation.execStartActivity()阶段进行替换,同时配合Intent setFlag模拟Activity launch mode并继续startActivity,接着System_server进程进行处理,更新ActivityStack,创建binder,并通知ActivityThread进行实例创建,最后我们在ActivityThread的handler里面进行拦截,更新ActivityInfo等信息,创建目标Activity。

另外在工程实践上,因为补丁的生成会涉及到Dex和资源的基线,我们会在部署的时候,每次发布APK包同步发布AP(基线包)到Maven,AP基线包里是所有影响基线的文件,第一是安卓APK,第二是Mapping.txt,最后是Dependency.txt,这样的话整个构建的速度会非常的快。

所以我们这种方式,版本的升级是不同的方式。比如今天手淘的详情要更新,会发布版本,这个版本可能不是到应用市场的版本,而是一个Patch包。业务版本的动态部署,是同步的,这样一个好处是只要容器版本没有升级,只要有需求,patch就可以一直升级,而且是无感知的差量升级。

上述了atlas很多的优点,但是也有缺点所在,大家应该看到,宿主工程和插件工程之间的相互调用是基于反射方式,而一般情况下发版的release包都要进行代码混淆,这里的atlas就相当于赤裸裸的暴露在了外界,对于逆向调试来说简直是丰盛的。atlas还有很多的弊端,当然,好处是数不胜数的

期待

我们下次的见面

原文发布于微信公众号 - Android历练记(gh_db8538619cdd)

原文发表时间:2017-11-29

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Android开发经验

Android USB转串口通信开发基本流程

2613
来自专栏杨建荣的学习笔记

Oracle Cloud初体验

Oracle 18c自去年OpenWorld首次预发布以来,确实引起了很多DBA的好奇和兴趣,在2月份左右先行发布了部分版本(Exadata和Super...

1822
来自专栏ChaMd5安全团队

赛博地球杯初赛第三名,ChaMd5安全团队的writeup

WEB 大量设备报表不见了(签道题) 访问index.php会被跳转到index.php?id=1 而且还有写送分题,尝试很多后,发现是考验爆破,上burpsu...

3989
来自专栏FreeBuf

Android 5.x漏洞:黑客可以绕过屏幕密码进入系统

很多Android用户会选择使用锁屏密码保护设备,但最新爆出的漏洞却令人震惊:任何人无需复杂的操作即可绕过锁屏直接进入你的系统! 攻击者可以通过漏洞导获取上锁...

23010
来自专栏Golang语言社区

Go 1.11 Beta 3 发布

版权申明:内容来源网络,版权归原创者所有。除非无法确认,我们都会标明作者及出处,如有侵权烦请告知,我们会立即删除并表示歉意。谢谢。

882
来自专栏北京马哥教育

专为渗透测试人员设计的Python工具大合集

如果你对漏洞挖掘、逆向工程分析或渗透测试感兴趣的话,我第一个要推荐给你的就是Python编程语言。Python不仅语法简单上手容易,而且它还有大量功能强大的库和...

3857
来自专栏草根专栏

使用 Moq 测试.NET Core - Why Moq?

在一个项目里, 我们经常需要把某一部分程序独立出来以便我们可以对这部分进行测试. 这就要求我们不要考虑项目其余部分的复杂性, 我们只想关注需要被测试的那部分. ...

1463
来自专栏向治洪

社会化分享

实现微信(好友、朋友圈)、QQ(好友、空间)、新浪微博等社会化分享方式。 前言 现在的app几乎里面都包括社会化分享和第三方登录这两个功能,前段时间给大家...

2326
来自专栏BaronTalk

58无埋点数据采集技术在Android端实践

作为国内最大分类信息生活服务平台,58集团旗下各个产品都会投入大量人力进行用户行为的分析,来提升运营效率。但是各个产品对用户行为的分析需求基本是相似的。在这样的...

3702
来自专栏Android 开发者

Android 9 Pie 兼容性常见问题及注意事项

使用了系统的 ClassLoader 加载 org.apache.http.* 的库

2622

扫码关注云+社区

领取腾讯云代金券