了解一下,Android 10 Build系统

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情

源起

因工作原因不得不重新抄起Android源代码开始看。这次就直接上Android 10.0了。当把代码导入Source Insight后,感慨万千。我一度觉得对TA的熟悉简直超过对自己的身体...毕竟,摸了有9年了...。不过好在Android还在快速发展。例如,仅仅是编译出一个可供模拟器加载的镜像,我就在这个过程中发现了不少新鲜的东西。所以,我想后面可能需要来一系列短小精悍“了解一下,Android 10 XXX”这样的文章来弥补心中的缺憾。

消极苦痛和积极苦痛

先来一碗不那么毒的鸡汤,至少对我还是有点效果。最近读到一本书,提到王国维里的一段话。

王国维认为,人心一个最基本的特点便是无时无刻不在运动。你可以想东,也可以想西,但完全不去想任何事,很难做到。心只有充分活动起来才能获得快感,一旦无所事事,就会陷入苦痛——这是一种“消极苦痛”,即百无聊赖,混吃等死。与之相对的是“积极苦痛”,比如你夙兴夜寐,努力上进,却不为领导赏识,遭到同事忌恨。虽说也很难受,但内心一直都在剧烈运动,顺应天性,故依然包含着快乐的元素。相比之下,“消极苦痛”因违背心性,更加难以忍受。人们为了免除此苦,在工作之余的闲暇时间发明了种种“消遣”,从而产生了种种嗜好。清代词人项鸿祚在解释自己为何填词时说:“不为无益之事,何以遣有涯之生?”

王国维这段话出自他的《人间嗜好之研究》,此书的作者将其转化成了现代汉语。其实,上面这段话核心意思就是——人呐,不要闲死。闲死是最难受的。看来,我之前说“宁愿闲得蛋疼也不要乱动”是违反人性的......。既然如此,那我们就Android 10搞起来,积极得痛苦一段时间。

Android 10 Build系统简介

Android 10的Build系统是有名字的,它叫Soong。Soong之前,Android的编译系统也有名字,不过比较土,就叫Make——意思是基于Makefile文件的编译系统。Soong其实也不是陌生人,大概在Android 7就崭露头角了。

Soong的宏伟目标是干掉Make。但直到Android 10,这个看起来比较容易的小目标也还未完全实现。为什么呢?

  1. 写Makefile文件的语言属于Domain Specific 的Languange(领域语言),它是图灵完备的。所以,Makefile可以写得巨复杂。

  2. AOSP本身是一个非常庞大和复杂的系统。这就导致AOSP里有着成千上万的Makefile文件。各种依赖,组合等等。

OMG...所以,Soong想把Make很快的干掉也不是一件容易的事情。

....继续来看。

先看Android 10源码中的build目录,现在是这个样子:

其中有两个比较重要的内容需要了解:

  • 原来的make那套东西,放在make目录下。为了对使用者屏蔽切换编译系统的差异,envsetup.sh等依然还在。

  • 增加了blueprintkatisoong三个目录。这三位(还得加上一个ninja)一起组成了AOSP的新的Soong编译系统。下图是Soong编译系统中的几位重要成员。

对Android系统的使用者来说:

  • 使用方法和以前一样。先引入build/envsetup,sh,然后执行m/mm/mmm等命令。只不过现在的m/mm/mmm命令将调用Soong中的对应工具。

  • Soong将把.bp文件交给blueprint工具集来处理。blueprint工具集是用go语言写的。官方文档对它的描述是:a meta-build system。输入为.bp文件。输出为.ninja文件

  • Soong把.mk/Makefile文件交给kati/ckati工具来处理。kati是go语言写的,而ckati是c++写的。kati官方文档对它的描述是:kati is an experimental GNU make clone。也就是说,kati是对等make命令的。只不过kati并不执行具体的编译工作,而是生成ninja文件。

  • ninja是一个神奇的东西,它是忍者桃太郎的意思。ninja本身不是编译器,它是去调用具体编译器的工具。真正的编译工作还是由编译器来完成,比如gcc,clang,java等。ninja读取的是.ninja结尾的编译配置文件,然后调起对应的编译器。

好了,上面是整个Soong编译系统的Big picture。现在我们需要对其中一些小问题做一些了解。

ninja是什么

ninja是忍者桃太郎。它最初来自谷歌chrome团队。因为工程师发现原来使用的make系统比较慢。所以考虑要优化优化。题外话,我对谷歌这个工程师文化还是蛮敬佩的,很难想象国内哪个公司还能允许一个团队去优化一个运行得好好的编译系统,而且当时肯定不知道最终能优化成什么样.....

Anyway,ninja的思想还是极具远见的。Makefile文件中如果写了太多if/else,这个管理起来(包含修改)的复杂度就大幅提升。我其实在自己工作中也发现了这个问题。比如,现在Android APP编译的gradle文件也比较复杂了。因为不同渠道,debug/release的原因,if/else这样的代码语句也出现在了gradle文件里。我曾经考虑过能不能有个更高层级的工具,它能生成专门用于比如debug版本的gradle文件。这样,在debug版本里的gradle文件就不需要if/else来区分了。

没想到我的这个想法和ninja的思路是一致的。总结来说,ninja的输入文件(.ninja)是没有if/else这样的分支逻辑。它包含的就是单纯的编译规则。至于debug/release这样的区分,则由更高层级的工具来编写,比如用调试更为方便的python、go等语言编写。

所以,.ninja文件号称编译系统里的汇编文件,既然是汇编文件,自然也不希望你去修改.ninja文件,而是拜托大家去调整生成.ninja文件的地方。比如上图中的blueprint或者kati。所以,ninja是一个比较底层的东西,应该把它嵌入到一个大的编译系统中去。然后由更高层次的工具生成ninja文件并交给ninja去处理。这就是ninja的逻辑。其官网地址是:https://ninja-build.org

.bp和blueprint是什么

Soong系统使用.bp作为编译配置文件,替代了之前的Makefile文件。相比复杂的Makefile,.bp是一个类似json一样的文件。bp就是blueprint的缩写,待会我们会介绍blueprint。

首先,.bp从样子上看就清爽很多,连gradle都不能与之相比。下面是某个bp文件的样子。

.bp文件的内容很明显是借鉴了Google内部的Bazel编译系统。不过,Android中的.bp没有完全照搬bazel,而是省略了对分支逻辑的支持。

另外,bp写起来是比较简单,但是由于正式的文档很稀少,要写对了也不是一件容易的事情。比如,上面的tidy_checks什么意思?可以取哪些值?人民群众急需一个正式而严密的文档!!!。

Android中的.bp文件由谁处理呢?答案是blueprint。blueprint读取.bp然后转成.ninja文件。blueprint本身是一个比较复杂的工具,它是由go语言写的。这里不打算介绍太多,牢记我们的目标是“了解一下”,其官网地址是https://github.com/google/blueprint

kati/ckati是什么

Android 10还未将所有.mk文件转成.bp文件。所以,还需要一个工具用于将.mk/Makefile文件转换成.ninja。这就冒出来了新的工具kati。kati的文档较少。要了解它的话,源码中build/kati下的README.md和INTERNALS.md是最好的材料,尤其是INTERNALS.md,更是无情得打了go的一点点脸

根据上面的文档,kati才是肩负干掉make系统重任的家伙。只不过现在变成soong了,那么kati就降格为将Makefile文件转成.ninja的工具。正是在kati的文档里,我才意识到Make是一个多么复杂的东西。

kati最开始用go写,然后发现速度不行,最后改为C++。所以有两个版本,katickati。为何go版本的kati速度不行呢?作者说,主要是GC慢了。AOSP编译系统大概包含了100万个变量并且不会释放.......。

当然,打脸的事情一定是无图无真相:

m命令的执行

当我们source build/envsetup.sh后,就可以通过m、mm或mmm来编译系统或者某个模块了。这个用法倒是和以前一样,只不过内部实现切换到了soong。这里简单看看envsetup.sh里是怎么和soong勾搭上的。主要了解下m命令即可,来看下图。

m是envsetup.sh里定义的一个函数,它将执行脚本build/soong/soong_ui.bash。而这个soong_ui.bash的核心就是下面这个图:

最后执行的是soong_ui命令。而这个soong_ui的源码位于build/soong/cmd/soong_ui/main.go中。

另外,

  • 以前编译系统的时候需要执行lunch。现在其实不需要lunch了。只要使用m PRODUCT-aosp_x86_64-eng就可以编译aosp_x86_64-eng这个设备的eng系统。

  • 以前要编译某个模块,比如make libart。现在只需要使用m libart即可。好像是方便一点了。

小提示,大家不妨用vscode,配置好go环境,然后调试下这个main.go,切身体验下soong......

其他的内容

envsetup.sh提供了更多的命令,hmm执行下即可获取全部信息。如下图:

比如,

  • allmod可以获得编译目标下的所有模块

  • 比如,pathmod libart将获取libart所在的源码目录。答案是art/runtime。

allmod、pathmod等命令其实是解析了out/module-info.json这个文件——通过调用python的相关工具。从这一点可以看出,AOSP编译系统其实俨然是一个各种综合技术高度聚集的地方,绝非以前写写Makefile就行。

另外,AOSP 10中有很多编译的小秘密隐藏在一些偷偷生成的文件里,比如下图out/.module_paths目录:

编译中遇到的所有mk文件、bp文件信息等都存到对应的.list里。当然,除了这个.moduel_paths之外,还有更多的秘密等待大家去发现。

后续的安排

AOSP 10源码撸了大概五天,发现其中有一些需要了解的知识,比如APEX、ART等。接下来会对这些东西做一系列的“了解”。在此也欢迎大家提供一些目标,好让我们的"了解Android 10”系列飞得更远一点。

最后的最后

  • 我期望的结果不是朋友们从我的书、文章、博客后学会了什么知识,干成了什么,而应该是说,神农,我可是踩在你的肩膀上的喔。

  • 关于学习方面的问题,我已经讨论完了。后面这个公众号将对一些基础的技术,新技术做一些学习和分享。也欢迎你的投稿。不过,正如我在公众号“联系方式”里说的那样——郑渊洁在童话大王《智齿》里有一句话令我印象深刻,大意是“我有权保持沉默,但你说的每一句话都可能成为我灵感的源泉”。所以,影响不是单向的,很可能我从你那学到的东西更多。

神农和朋友们的杂文集

长按识别二维码关注我们

配置 build --- Android Gradle 插件 ---了解Android构建系统 Android 构建系统会编译应用资源和源代码,然后将它们打包成 APK 或 Android App Bundle 文件,供您测试、部署、签名和分发。 Android Studio 使用高级构建工具包 Gradle 来自动执行和管理构建流程,同时也允许您自行指定灵活的 build 配置。每项 build 配置均可定义各自的一组代码和资源,同时重复利用所有应用版本共用的部分。Android Gradle 插件与该构建工具包搭配使用,提供专用于构建和测试 Android 应用的流程和可配置设置。 阅读详情

相关推荐

Window10系统Ubuntu编译Android源码出错 Build sandboxing disabled due to nsjail error

Window10系统Ubuntu编译Android源码出错 FAILED: ninja: ./build/blueprint/bootstrap/build.ninja:11: loading ‘out/soong/.minibootstrap/build-globs.ninja’: Exec format error subninja 09:26:18 Build sandboxing disabled due to nsjail error. This may become fatal in the

weixin_38299799的博客 8154

深入理解Android Build系统

概述Android Build 系统是用来编译 Android 系统Android SDK 以及相关文档的一套框架。在Android系统中,Android 的源码中包含了许许多多的模块。 不同产商的不同设备对于 Android 系统的定制都是不一样的。如何将这些模块统一管理起来,如何能够在不同的操作系统上进行编译,如何在编译时能够支持面向不同的硬件设备,不同的编译类型,且还要提供面向各个产商的定制

xiangzhihong8的专栏 7606

[超详细][Gradle Build Failed已解决] Unity2018安卓开发

[超详细]Unity2018开发安卓教程 最近有一个项目需要把游戏发布到安卓平台,搞了一天都没弄明白,但是却在Unity官方文档找到了突破口(我们的文档实在是太厉害啦!) 回归正题,大体的步骤有以下几点: 1、使用UnityHub安装 Unity 2018.4 LTS 2、使用AndroidStudio(以下简称AS)自带的SDK 1、在UnityHub安装Unity2018 这里建议最好还是勾上这两个。因为我们使用的是AS的SDK,而其他设置默认即可 之后就是漫长的等待时间⌚ 2、使用Unit

1eonChan的博客 2619

Android】编译系统之 make 和 Soong

make 是一个自动化构建工具,make 通过读取一种叫做Makefile的文件,将源代码自动构建成可执行程序和库文件。而 Makefile 文件中定义了目标程序的依赖关系和生成目标程序的相关规则。在早期, make 被包含在Unix系统中,随着GNU/Linux从Unix衍生出来并发扬光大,GNU/Linux保留并扩展了原始的make,加入了许多内置函数和自动变量等等,形成了GNU make。.........

yang553566463的博客 4239

三、soong_ui.bash脚本

文章目录soong_ui.bash调用地方soong_ui.bash在envsetup.sh中的调用soong_ui.bash在main.mk中的调用soong_ui.bash在其他地方的调用soong_ui.bash分析soong_ui的调用顺序/build/soong/soong_ui.bash/build/soong/scripts/microfactory.bash/build/blueprint/microfactory/microfactory.bash展开`soong_build_go soo

王涵的博客 3513

编译系统总结篇-Android10.0编译系统(十一)

[Android取经之路] 的源码都基于Android-Q(10.0) 进行分析 [Android取经之路] 系列文章: 《系统启动篇》 Android系统架构 Android是怎么启动的 Android 10.0系统启动之init进程 Android10.0系统启动之Zygote进程 Android 10.0 系统启动之SystemServer进程 Android 10.0 系统服务之ActivityMnagerService Android10.0系统启动之Launcher(桌面)启动流程 And

纸上得来终觉浅,绝知此事要躬行 2911

Soong 构建系统

在最新的Android R(11)中,Google已经移除了/build/kati目录,只保留了一个预先编译出来的可执行文件:prebuilts/build-tools/linux-x86/bin/ckati kata是go语言写的,ckatai是C++写的。它利用Kati GNU Make 和Ninja构建系统组件来构建Android Soong是用Go语言写的,go环境在prebuilts/go环境下,Soong在编译时,解析bp文件,转化成Ninja文件,完成Android的选择编译,解析配置过程。

u010386121的博客 2150

Android构建系统了解Soong构建系统

bp文件.go文件语法声明式,类JSON命令式,Go语言灵活性有限,无逻辑控制高,可编程适用场景模块定义、静态依赖动态逻辑、构建规则扩展维护者开发者构建系统工程师/高级开发者。

hongyeying的专栏 1928

Android Build 系统

目录 一、概述 二、编译 Android 系统 1.执行编译 2.常用的编译命令 三、Build 结果的目录结构 1.Build 生成的镜像文件 四、Make 文件说明 五、Make 目标说明 1.make /make droid 2.其他目标 六、在 Build 系统中添加新的内容 1.添加新的产品 2.添加新的模块 3.build.prop系统属性添加 一、概述 Build 系统中最主要的处理逻辑都在 Make 文件中,而其他的脚本文件只是起到一些辅助作用...

即将秃头的吕同学的博客 1936

[Unity]-[Build]-[Android] 关于安卓打包以及真机调试

在安装SDK之后,在Platform中选择Android,再点击Build Settings中Switch Platform之后,会导入一些打包工具,然后按钮会变成BuildBuild And Run。这两个在Project Setting的player设置中,命名注意点和上面一样,注意PackageName是可以Override Write的。可以直接在unity hub上添加模块或者自己在官网下载然后放到指定的SDK路径。这三篇博客都把真机调试的流程写的很详细了。这个是真的把我的坏习惯给改了。

sky_smile_Allen的博客 2911

Android Build类获取系统信息

Android中可以Build类来获取一些系统信息,本文介绍了Build类的使用,可获取的系统信息列表。并详细介绍了Build类获取系统信息的流程,以及Build类获取到系统信息的来源。最后介绍了如何修改部分系统信息。

ccpat的专栏 2万+

安卓编译时android.bp和build.gradle的区别

:用途:专为 Android 开源项目(AOSP)设计,用于系统级开发(如 ROM 内置系统应用)。构建系统:基于 Soong(替代 Make 的现代构建系统),与 Ninja 结合生成底层构建规则。环境:仅适用于 AOSP 源码环境,需通过 或 命令编译。:用途:适用于标准 Android 应用开发,通过 Android Studio 管理。构建系统:基于 Gradle(使用 Kotlin 脚本替代 Groovy),支持灵活的构建流程和插件扩展。环境:独立于 AOSP,依赖 Android Gradl

Megumi99的博客 654

编译安卓系统源码时,执行 source build/envsetup.sh 的目的

是为了确保你的当前 shell 环境中具备编译安卓系统所需的所有设置和函数。这样,当你执行后续的编译命令时,系统才能正确识别和执行这些命令,从而顺利地进行安卓系统源码的编译工作。这个命令会列出可用的编译目标,包括不同的设备和版本。你可以根据提示选择适合你的目标,比如选择要编译的设备型号(如。的目的是设置环境变量和提供一些编译所需的函数和工具。脚本虽然设置了编译所需的环境变量和函数,但还没有指定具体要编译的设备或版本。命令是选择编译目标的关键步骤,是确保编译系统正确工作的重要一步。设置了必要的环境,但。

weixin_44909190的博客 1074

Android build系统详解

概论 Androidbuild系统是基于GNU Make和shell构建的一套编译环境,Android的编译比较庞大,所以为了统一管理,Android退出了build来统一管理Android的编译。 build处理完成对目标系统的二进制文件,APK运用编译,链接,打包等工作外,还需要生成目标系统的镜像和各种配置文件,同时还维护各个模块间的依赖关系。 build系统可分为三大块,一:位于build/core下的文件,这是build系统的框架和和兴,二:位于device目录下,存放产品的配置参数,三:是各个模

madannasf的博客 506

Android 10.0修改系统版本号(Build.DISPLAY)和系统ID(Build.ID)

对于定制化开发的,由于硬件板卡不同,系统源码中,对于系统属性的值也需要做相应的修改 今天就来实现对Build.ID和Build.DISPLAY的值来做修改 先看下Build.java的源码 public class Build { private static final String TAG = "Build"; /** Value used for when a build property is unknown. */ public static final String U

安卓兼职framework和app工程师的博客 4921

Android Build系列专题【篇五:构建系统build.prop生成机制】

这里我们主要介绍一下android构建系统的主入口文件build/core/makefile,它承担着整个编译的启动和调度工作。该文件作为构建系统的起点,负责初始化编译环境并包含所有必要的子模块文件。Android构建系统采用模块化设计,位于build/core/目录下,由makefile和多个mk文件组成。makefile作为启动入口,main.mk作为核心流程文件,通过包含关系组织起整个构建框架。由于整个流程过于复杂,这里只记录我跟读过的一些模块。

qq_27672101的博客 1311

[Android 基础] -- 深入理解 Android Build 系统

概述: Android Build 系统是用来编译 Android 系统Android SDK 以及相关文档的一套框架。在 Android 系统中,Android 的源码中包含了许许多多的模块。不同产商的不同设备对于 Android 系统的定制都是不一样的。如何将这些模块统一管理起来,如何能够在不同的操作系统上进行编译,如何在编译时能够支持面向不同的硬件设备,不同的编译类型,且还要提供面向各个...

u014674293的博客 1788

Android 10.0修改系统型号(Build.MODEL)

在开发板卡系统中,由于每个硬件型号不同,所以在系统中也要修改成相应的型号 而在Build.java中各种系统信息都是从系统属性中获取的 来看下Build.java的类 /** * Information about the current build, extracted from system properties. */ public class Build { private static final String TAG = "Build"; /** Value used fo

安卓兼职framework和app工程师的博客 4702
上一篇: 近来学习的一些东西和思考(2)
下一篇: 了解一下,Android 10中镜像文件的制作
阿拉神农
阿拉神农 《深入理解Android》 作者 《深入理解Android》 作者 领域专家: 操作系统技术领域 领域专家: 操作系统技术领域
博客等级 码龄20年 1万+粉丝 229原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值