作者:苏彦郊(木磊)

Android 项目一般使用 gradle 作为构建打包工具,gradle 简洁、动态的功能特性为人津津乐道,同样,构建执行速度缓慢的缺陷也一直为人诟病。

近年来,随着优酷功能特性日益丰富,优酷的代码规模也急剧增加,同时,庞大的代码规模也带来了构建耗时的不断增加。整包构建耗时一度高达35min,严重影响集成与迭代效率。因此构建速度优化势在必行。截止 2021年 11 月份,优酷构建耗时优化取得较为理想的优化结果(如下),现将构建速度优化的实践方案记录成文。

android debug 包构建耗时12min2.5min
android release 包构建耗时35 min12min

方案与收益统计图:

优化思路

技术优化类项目一般采用照设定数据指标、技术优化、成果防腐化三个维度展开。套用技术优化类项拆解可知,我们需要完成如下三个子项目:

  1. 设定数据指标:即收集与选取核心优化的数据指标,体现成果价值。本文选取构建耗时、构建失败率、小时维度构建次数等指标作为成果优化的数据支撑;
  2. 技术优化:通过影响构建速度的影响因素可知,包括软件与硬件两部分,所以构建速度优化可分为软件优化与硬件优化两大方向;
  3. 成果防腐化: 即维持技术优化指标不恶化,保障优化成果。

接下来,我将按照设定数据指标与结果防腐、技术优化——软件优化、技术优化——硬件优化三个部分展开。

优化方案

设定数据指标与结果防腐

优化类项目需要建立健全相应的数据指标体系,借由数据评判体积优化项与优化方案进行有效性判定。进行构建优化前,笔者基于阿里巴巴Aone FaaS( Severless 服务)平台搭建了数据评判与监控大盘。该大盘有构建类型、构建时间、构建成功率、构建任务耗时等多项指标,满足构建优化项目需要根据类型、任务频率、高耗时任务排查的需求。

完成相关数据能力建设后,通过构建关键数据指标——构建耗时与构建成功率的追踪和分析,进而得出构建耗时的主要影响因素为高耗时任务,构建成功率的主要影响因素为不合理的构建任务。因此,我们可以通过高耗时任务报警与不合理任务报警,快速发现并分析构建速度恶化情形,进而保障构建耗时优化成果。

软件优化

构建侧去atlas

Atlas是伴随着手机淘宝的不断发展,进而衍生出来的一个运行于android系统上的容器化框架,我们也叫动态组件化(Dynamic Bundle)框架。它主要提供了解耦化、组件化、动态性的支持。覆盖了工程师的工程编码期、Apk运行期以及后续运维期的各种问题。

依托于深度定制的产物结构与高度复杂、深度hook 的运行时框架,Atlas可以视为移动端 OSGI 实现方案与组件化方案。但随着优酷移动端架构调整与自研远程化方案落地,Atlas运行时框架逐渐丧失了OSGI框架作用,遂在运行期去除Atals 框架。

当运行期将Atlas依赖去除后,Atlas的复杂构建流程(如下图所示)也失去了存在意义。随即,优酷启动了构建侧Atlas 去除项目,目标是将Atlas构建插件去除、构建原生化、纯净化、精简化。通过产物原生化、构建任务清理、工具链升级等一系列动作,在完成了构建侧Atlas去除目标的同时,构建性能也有部分提升。

收益:debug 包构建耗时降低 3min左右。release 包构建耗时降低4min-5min。

gradle 升级和android gradle plugin 升级

gradle 团队一直在持续优化gradle 的构建速度等性能指标, 同时 google 团队也在持续优化 android gradle plugin 构建工具性能。为了进一步提升优酷android 端构建性能,决定对优酷android构建系统进行升级,将android gradle plugin 构建工具版本由3.0.1(2017年)提升至3.4.3(2019年)版本,将gradle构建工具由4.4(2017)至5.5 (2019年)版本。

对比升级前后构建耗时,可以发现构建工具升级后,性能提升主要源于三个方面:

  1. 随android gradle plugin 升级,aapt2、proguard 等构建工具也进行了升级,这部分工具升级后,构建性能有小幅提升;
  2. 更好任务排布与并行化机制:升级gradle 与agp 后,agp 3.4.3 版本进行了签名、压缩、对齐任务的整合优化;
  3. 配置按需加载与异步化策略:android gradle plugin 3.4.3 采用资源的异步加载策略,即configuaration 阶段仅做依赖拉取工作,不再进行产物的解压、过滤、合并工作,这样可以有效避免io 拥塞问题,避免cpu 忙等现象。

收益:debug 包构建耗时降低 2min左右 。release 包构建耗时降低4min左右。

dx 构建优化

升级到 android gradle plugin 3.4.2 版本后,agp 新增了三个个dx构建参数,经过测试可以显著提升dx处理class文件速度。经过测试 设置如下三个属性降低构建耗时。

android.dexingNumberOfBuckets=16
android.dexingWriteBuffer.size=256
android.dexingReadBuffer.size=256

仔细阅读agp源码可知,这几个参数构建构建内存中dx 缓存大小、dex 读取写入片大小。默认dexingNumberOfBuckets 为cpu个数的一半、读取写入大小为1KB。这样就造成高io情形下,cpu 忙等情形。采用降低磁盘写入次数、增加缓存方式能够明显降低构建耗时。

收益:debug release 包构建耗时降低3min左右。

冗余任务整理

随着我们不断迭代、平台升级,一些 构建任务、构建功能等已经废弃,但由于构建系统的特殊性——无产物回滚能力,导致构建系统的任务一直处于单增状态。且由于构建系统高风险、低收益、逻辑功能复杂陈旧的特点,导致构建速度治理动力不足。

针对上述问题,通过构建逻辑梳理、构建配置项清理、 单任务调试等手段,逐步摸清构建每个构建任务的功能,并对postPackageDebug等30+ 无用任务进行清理、对transform管理、任务管理等核心功能进行简化。下表为构建冗余任务清理列表。

postPackageDebugapk后处理可以废弃
remoteSignAppDebug远程签名可以废弃
DexCountDebugdex个数可以废弃
ChannelPackageDebug渠道包构建可以废弃
generateAppInfoDebugappinfo生成可以废弃
uploadBuildFilesDebug文件上传可以废弃
buildPatchBaseApkDebug热修复构建可以废弃
....

收益:debug 包构建耗时降低 15s+ ,release 包构建耗时降低20s+。

任务pipeline化

gradle 采用任务情形进行构建任务排布,基于这一拓展特性可以对产物进行后置处理。例如对 apk 后置处理有渠道处理、arsc 处理、对齐、签名、分包处理、图片压缩等任务,每一个任务都需要apk进行反复的解压、压缩、拷贝操作,浪费cpu 、系统io,徒增构建耗时。

为了降低apk构建耗时、简化apk产物操作复杂,我们对现有任务进行重整与拓展、实现了一种低拷贝、一次解压、一次压缩的产物pipeline处理机制,下图为构建过程apk后处理机制流程图。

收益:debug 包耗时降低21s,release 包耗时降低11s。

构建模版优化

按照用途区分 android 有多种构建变种,debug版本、release版本、远程与非远程等。对于开发阶段来说,一些插件的优化功能如turbo dex 缩减、7zip 压缩完全无必要,可以直接禁止掉。

收益:debug 缩短1-2min 左右,release 包无变化。

缩减代码规模

构建耗时中 java 代码混淆耗时约占整体构建耗时的60%,同时混淆耗时与代码规模正相关。所以构建耗时与代码规模成正相关关系。

代码规模的膨胀一部分来源于业务扩张,一部分来源于冗余代码的工程腐化。自2020年下半年至 2021年上半年期间,优酷进行了常态化的包体积治理,包体积取得了较为优异的成果,代码腐化问题也得到了部分缓解。

如下图所示优酷android 端自2020下半年至今,可知 android 端 java 代码规模降低25%,构建速度贡献约为45s+。

收益:release 包构建耗时降低约为45s+。debug 包构建耗时约为5s-10s。

硬件优化

私有构建租户池

采用iostat、tsar 等linux 性能分析工具对优酷android 端构建过程分析(如下图)可知。整个构建流程cpu io-wait 现象严重,即构建过程中存在大量的io操作,由于构建机器io性能不足,导致构建耗时偏长, 侧面印证软件优化中降低io能够构建速度的有效性。

针对io瓶颈问题,主要有两种解决办法:采用buffered io 处理、提升 Io 性能:

  1. 首先,仅保留agp插件进行构建,发现并无构建速度明显提升。证明:自定义插件无io 优化空间;
  2. 其次,对android 构建流程分析,io 碎片化写入较少,所有采用buffered io 处理 io 瓶颈,优化空间不大;
  3. 最后,通过采用使用SSD 替换机械硬盘效果较好。物理机构建比较数据如下:
组一(台式机)12min57s21 minSSD Ex900 521G / 写入峰值约900Mb/s / intel 2.9Ghz 16线程 /16G内存
组二(Dell R740 刀片服务器)25min40min机械硬盘 /写入峰值约254Mb/s / 骁龙 2.1Ghz 24线程/ 48G内存
组三(Dell WorkStation)19min58s27minSSD EX900 521G / 写入峰值约900Mb/s /骁龙 2.2Ghz 20线程 /32G内存
组四(台式机)10min10s23minSSD 512G / 写入峰值约1G/s AMD 3.5Ghz 24线程 32G内存
组五(devops集群)23min40min多为机械硬盘,视调度具体机器而定

收益:debug 减少5min 左右,release 包减少10min。

总结

综上所述,为了维护构建速度优化的成果,我们可以进行如下方面的工作:

  1. 为了满足数据指标设定与构建优化防腐的需求,我们需要设置构建优化指标,建立合理的数据评测体系;
  2. 通过对构建模板拆分、冗余任务清理、gradle 升级和android gradle plugin 升级、合理设定构建相关参数——dx构建优化等软件优化手段,我们可以获得大部分构建速度优化成果;
  3. 硬件优化部分需要建立构建流程关键瓶颈的分析上,各应用构建瓶颈可能不同。

受限于技术手段与稳定性问题, 构建速度优化还有如下未完成部分。

  1. 混淆规则控制与清理:混淆任务执行速度与混淆规则数量存在正相关关系,不合理的混淆规则会导致混淆任务耗时增长;
  2. 工程腐化程度治理:无用代码规模是工程腐化程度的重要标志,同时无用代码规模是影响构建速度的重要因素。但是如何治理大型项目的工程腐化程度,是应用架构以及全体应用开发需要探索的下一个重要课题;
  3. r8构建优化:通过对android dex 构建工具链——r8 的升级测试发现,优酷release 包构建有较为明显的构建速度提升。但由于部分google bug 导致r8 优化delay。

未来,优酷技术团队也将针对上述问题,持续优化构建耗时,欢迎大家随时与我们交流讨论。

【相关文档】

我们招聘啦!

优酷 — 技术中心 — 架构团队招人,描述如下。

【职位描述】

  1. 负责以优酷为核心的android基础架构工作,包括基础框架、中间件等。
  2. 负责app的稳定性、性能、包瘦身等长效治理工作,提升基础用户体验。
  3. 研究移动端前沿技术工程化,以及技术趋势探索。
  4. 解决各类疑难问题,支撑业务快速、稳定、高效迭代。

【职位要求】

  1. 熟悉Android SDK、Framework等基础技术,并有较好的源码分析能力。
  2. 精通Java语言,基本功扎实,有Kotlin、C/C++开发能力者优先。
  3. 对Dalvik/Art虚拟机中,任意部分有经验者优先。
  4. 有关键技术选型、疑难Bug修复、内存优化等经验者优先。

简历投至方式[email protected]

关注【阿里巴巴移动技术】微信公众号,每周 3 篇移动技术实践&干货给你思考!

03-05 15:23