update something of Openthos, update some cmds

This commit is contained in:
shzhxh 2019-12-12 16:48:57 +08:00
parent 95e4bdc217
commit 2b8478050d
10 changed files with 266 additions and 86 deletions

View File

@ -0,0 +1,102 @@
在Android7.0之前使用的是GNU Make。从Android7.0开始引入Soong。
#### Android.bp文件的格式
Android.bp的设计原则是简约它不包含条件或控制流语句所有的复杂性都是由go语言写的内在逻辑来控制的。
##### 模块Modules
模块类型详见:[module type](https://ci.android.com/builds/submitted/6066704/linux/latest/view/soong_build.html)。模块是由模块类型+一组键值对组成的。格式如下:
```
cc_binary {
name: "gzip",
srcs: ["src/test/minigzip.c"],
shared_libs: ["libz"],
stl: "none",
}
```
- 模块名
cc_binary用于生成可以在设备上跑的二进制。
filegroup包含一个文件的列表用于其它模块里属性的引用(使用`:<name>`语法),或者在包之间导出文件。
- 属性
`name`属性是必须的,它表示模块的名称。其值在所有模块里必须是唯一的。
`srcs`表示用来编译C/C++模块的源文件列表。也可以使用语法`:module`来引用其它模块的输出。
`shared_libs`,表示其它模块的列表,这些模块将被动态链接到本模块中。
`stl`选项要使用的STL库。可能的值是"libc++", "libc++_static", "libstdc++"或"none"。
##### 类型Types
变量和属性是强制类型的,变量的类型由第一次赋值时自动设定,属性的类型由模块类型静态设定。支持的类型有:
- 布尔型(true, false)
- 整型(int)
- 字符串(string)
- 字符串列表(["string1","string2"])
- Maps ({key1: "value1", key2: ["value2"]})
Maps可以包含任何类型的值包括嵌套maps。
##### Globs
Glob模式是包含通配符的匹配模式。`*`可以匹配多个字符,`**`可以匹配多个路径。
##### 变量Variables
变量的作用域为文件的剩余部分以及子bp文件里。变量是不可变的但有一个例外可以使用`+=`来追加一个值,但仅限于它们被引用前。
##### 注释Comments
支持`/* */`和`//`。
##### 操作符Operators
可以使用`+`操作符追加字符串字符串列表或maps。也可以用`+`给整数求和。两个map执行`+`操作将使它们各自拥有对方的键值。
##### 条件判断Conditionals
大多数情况下条件判断都可以写成map里的一个属性由顶层的属性来决定使用哪一个的值。
例如,为了支持不同架构:
```
cc_library {
...
srcs: ["generic.cpp"],
arch: {
arm: {
srcs: ["arm.cpp"],
},
x86: {
srcs: ["x86.cpp"],
},
},
}
```
##### 规范化Formatter
```
bpfmt -w . # 递归地重新格式化当前目录下的所有的Android.bp文件
```
规范的格式包括:
- 四个空格的缩进
- 多元素列表中每个元素后的新行
- 列表和maps里的尾随逗号
#### 参考文档
- [Soong build system](https://source.android.com/setup/build)

View File

@ -54,7 +54,7 @@ init是第一个进程也叫root进程或所有进程的父进程。在此阶
如果当前运行的程序名是modprobe则执行`modprobe_main`,应该是用来加载内核模块的。
如果当前运行的程序名是ueventd则执行`ueventd_main`,进行设备节点的创建和权限设定。
如果当前运行的程序名是ueventd则执行`ueventd_main`,进行设备节点的创建和权限设定。对于ueventd_main首先把umask修改为0然后使用InitKernelLogging函数初始化内核的Log系统这样ueventd就能通过内核的Log系统输出到串口了然后注册selinux的回调函数用于打印LogCreateDeviceHandler使用parser.ParseConfig来解析rc文件
如果当前运行的程序名是watchdogd则执行`watchdogd_main`,用于系统出问题时重启系统。
@ -162,13 +162,23 @@ init是第一个进程也叫root进程或所有进程的父进程。在此阶
2. 加入一些事件和Action
am.QueueEventTrigger("early-init")用于触发early-init事件
am.QueueEventTrigger("early-init")用于把early-init事件放到事件队列里
am.QueueBuiltinAction用于添加Action第一个参数是要执行的command第二个参数是trigger。
am.QueueEventTrigger("init")用来触发所有的boot actions。
am.QueueEventTrigger("init")用来把init事件放到事件队列里init事件的作用触发所有的boot actions。
bootmode是个全局静态变量用来标示启动模式android的启动模式分为正常开机流程和关机充电流程。
bootmode是个全局静态变量用来标示启动模式android的启动模式分为正常开机流程和关机充电流程。如果bootmode为"charge"则是关机充电流程则把事件charge放到事件队列里否则就是就是正常开机流程这会把事件late-init放到事件队列里。
3. 事件队列里Action的执行过程
Action的执行次序是early-init, init, late-init。
在early-init里首先是设置init进程及其子进程的oom_adj然后禁用键盘中断然后是创建一些目录挂载一些设备最后启动uenventd服务。uenventd在/sbin/uenventd是指向init的软链接在init的main函数里可见最终调用的是ueventd_main函数。
在init里干了大部分的初始化工作。
在late-init里是把更多的Action加到了事件队列里。
##### init进程第二阶段之服务处理
@ -207,7 +217,7 @@ Zygote是一个虚拟机进程由init进程启动。Zygote预加载以及初
zygote程序是app_process64zygote_secondary程序是app_process32。两者的参数和属性基本相同。
- 在init.cpp的main里触发late-init在init.rc的late-init里触发zygote-start在init.rc的zygote-start里启动zygote进程和zygote_secondary进程。
- 在init.cpp的main里把late-init加入运行队列在init.rc的late-init里把zygote-start加入运行队列在init.rc的zygote-start里启动zygote进程和zygote_secondary进程。
- 在init/builtins.cpp的builtin_functions里定义了start命令对应的函数do_startdo_start函数最终是调用对应server的Start方法Start方法主要是fork一个新进程然后执行对应server的二进制文件。
@ -296,7 +306,7 @@ Zygote启动系统服务即ZygoteInit类里的startSystemServer方法。
从整体来看一个rc文件是由若干个段组成的。一个段只能是Actions或Server其中之一
- Actions由trigger和它下面的一堆Commands组成。
- Servers由一堆Options组成。
- Servers由一堆Options组成。需要注意的是Servers的启动也是在Actions里指定的(使用class_start命令或者start命令).
注意Actions和Servers不能重名。如果重名了后出现的定义将会作为错误而忽略掉。
@ -338,43 +348,21 @@ name是程序名pathname是程序所在的路径argument是程序的参数
Options是Services的修改器它们影响init进程如何运行service以及何时运行service。
- console此服务需要一个console。默认设备为`/dev/console`。也可自己指定,如`console /dev/tty0`,其中`/dev/`是可忽略的,即等同于`console tty0`。
- ctitical此服务是一个设备关键服务。如果在4分钟内退出4次设备将会重启进入recovery模式。
- disabled此服务无法通过它所属的类型(class)来启动必须通过它的名字来启动。这就意味着启动一个类型的服务时这种服务是不会被启动的也就是它被disable掉了。
- setenv在启动的进程里设置环境变量。
- socket \<name> \<type> \<perm> [\<user> [\<group>]]
创建一个unix域socket它的名字叫/dev/socket/\<name>并将它的fd传给启动的进程。
- file打开一个文件并将它的fd传给启动的进程。
- user在执行服务前改变用户(user)默认的用户是root。
- group在执行服务前改变组名。
- animation将会包含所有启动和关闭animation所必须的服务。
- capabilities在执行服务的时候设置capabilities.
- seclabel在执行服务前改变为seclabel。
- oneshot当服务退出后不要重启它。
- class为服务指定所属的类型。在同一个类型里的服务可以同时打开或关闭。如不使用此选项明确指定服务所属的类型则默认在default里。
- animation将会包含所有启动和关闭animation所必须的服务
- console此服务需要一个console。默认设备为`/dev/console`。也可自己指定,如`console /dev/tty0`,其中`/dev/`是可忽略的,即等同于`console tty0`。
- onrestart当服务重启的时候执行一条命令
- critical此服务是一个设备关键服务。如果在4分钟内退出4次设备将会重启进入recovery模式。
- writepid当子进程forks的时候将其pid写到给定文件中
- disabled此服务无法通过它所属的类型(class)来启动必须通过它的名字来启动。这就意味着启动一个类型的服务时这种服务是不会被启动的也就是它被disable掉了。
- priority调度service进程的优先级
- file打开一个文件并将它的fd传给启动的进程。
- namespace当forking一个服务的时候进入一个新的PID或挂载namespace。
- oom_score_adjust设置子进程的变量值。
- group在执行服务前改变组名默认的组是root。
- memcg.swappiness设置子进程的变量值。
@ -382,8 +370,30 @@ Options是Services的修改器它们影响init进程如何运行service以及
- memcg.limit_in_bytes设置子进程的变量值。
- namespace当forking一个服务的时候进入一个新的PID或挂载namespace。
- oneshot当服务退出后不要重启它。如果一个程序不是守护进程应该使用这个选项。
- onrestart当服务重启的时候执行一条命令。
- oom_score_adjust设置子进程的变量值。
- priority调度service进程的优先级。
- seclabel在执行服务前改变为seclabel。
- setenv在启动的进程里设置环境变量。
- shutdown设置关机的时候此service进程的行为。默认是关机进程通过传递SIGTERM和SIGKILL来杀死此服务。
- socket \<name> \<type> \<perm> [\<user> [\<group>]]
创建一个unix域socket它的名字叫/dev/socket/\<name>并将它的fd传给启动的进程。
- user在执行服务前改变用户(user)默认的用户是root。
- writepid当子进程forks的时候将其pid写到给定文件中。
##### Triggers
Triggers就是个字符串用来匹配特定事件和触发一个action。分为事件触发器和权限触发器。
@ -552,11 +562,10 @@ Triggers就是个字符串用来匹配特定事件和触发一个action。分
> Create a symbolic link at _path_ with the value _target_
`sysclktz <mins_west_of_gmt>`
> Set the system clock base (0 if system clock ticks in GMT)
> 设置系统时钟基础(0代表GMTGMT的意思是格林尼治标准时间)。
`trigger <event>`
> Trigger an event. Used to queue an action from another
> action.
> 触发一个事件。用于从其它动作里把一个动作加到队列里。
`umount <path>`
> Unmount the filesystem mounted at that path.
@ -580,11 +589,19 @@ Triggers就是个字符串用来匹配特定事件和触发一个action。分
> immediately.
`write <path> <content>`
> 把<content>写到<path>里。<content>里的属性将会展开。
##### Imports
解析init配置文件扩展当前配置。
`import <path>`
> 解析init配置文件扩展当前配置。如果path是目录此目录下的所有文件都将作为配置文件被解析但这样的解析不是递归的下级目录将不会被解析。
>
> import是个关键字(keyword)而不是命令(command)它不会是Action的一部分它本身就是个独立的段(section),它的执行逻辑如下:
>
> - 如果是一个文件则解析这个文件,如果是一个目录则按字母序解析这个目录下的所有文件
> - 如果文件里依然有import语句则继续解析之(这意味着import不管出现在文件的什么位置它总是最后执行的)
#### 参考文档

View File

@ -56,76 +56,74 @@ lunch命令定义在build/envsetup.sh里用来让用户选择编译设备与
### make
Android.mk和Android.bp都会转化成ninja文件ninja才是真正的编译配置文件
- make命令定义在build/envsetup.sh里
Android.mk收集生成out/build-openthos_x86_64.ninja。Android.bp收集生成out/soong/build.ninja.d进而生成out/soong/build.ninja。out/combined-openthos_x86_64.ninja用于将如上两个文件组织起来。
```
function make()
{
_wrap_build $(get_make_command) "$@"
}
```
#### 构建的起点
- 依据`get_make_command`函数的定义,$(get_make_command)的值是"build/soong/soong_ui.bash --make-mode"。
在`build/core/main.mk`如没有指定编译目标则默认编译目标是droid。droid的目标是编译出整个系统的镜像对于openthos来说就会编译出openthos的镜像。
- 在`_wrap_build`函数可见,第二行"$@"已经执行完所有的编译过程了,其它部分只不过是输出一些统计信息而已
droid依赖droid_targetsdroid_targets依赖blueprint_tools, apps_only, droidcore, dist_files。blueprint_tools是编译工具apps_only会编译出不含user, userdebug和eng参数的应用程序droidcore用来构建整个系统它依赖了更多的目标本身不进行任何处理dist_files用来复制文件到out/dist目录默认的编译目标是不会产生out/dist目录的out/dist目录用于存放为多种分发而准备的包
- build/soonn/soong_ui.bash。首先执行build/soong/cmd/microfactory/microfactory.bash定义了两个工具函数`getoutdir`用来查找out目录`build_go`用来编译所需的二进制(参数1是所要编译的二进制的名字参数2是包名)然后用build_go来编译soong_ui最后执行的是`out/soong_ui $@`完成构建的过程
droidcore依赖files, systemimage和一堆$(INSTALLED_*)。files依赖了更多的目标本身不进行任何处理systemimage用来生成system.img将被挂载为/system其它依赖作用如下
- 函数build_go的执行逻辑如果$mf_bin存在且$mf_version的值等于$mf_version_file里保存的值说明$mf_bin存在且是最新的此时它就是$mf_cmd否则说明$mf_bin不存在或它的版本不是最新的这时就需要构建新的$mf_cmd它的值为`go run $mf_src/microfactory.go`。`$mf_cmd ...`那行是真正干活的,-s用来指示microfactory的源码目录-b用来指示microfactory二进制的位置-pkg-path是从包前缀到文件路径的映射-trimpath用于从记录的源文件路径中删除前缀-o用于指定输出文件的名称。
- $(INSTALLED_BOOTIMAGE_TARGET) 生成boot.img
- $(INSTALLED_RECOVERYIMAGE_TARGET)生成recovery.img
- $(INSTALLED_VBMETAIMAGE_TARGET)
- $(INSTALLED_USERDATAIMAGE_TARGET) 生成userdata.img
- $(INSTALLED_CACHEIMAGE_TARGET) 生成cache.img
- $(INSTALLED_BPTIMAGE_TARGET)
- $(INSTALLED_VENDORIMAGE_TARGET)
- $(INSTALLED_SYSTEMOTHERIMAGE_TARGET)
- $(INSTALLED_FILES_FILE) 生成installed-files.txt文件记录了当前镜像中已安装的文件列表。
- $(INSTALLED_FILES_FILE_VENDOR)
- $(INSTALLED_FILES_FILE_SYSTEMOTHER)
#### 构建的过程
files依赖的目标如下
- $(modules_to_install) :编译当前配置下所有需要被安装的模块
- $(INSTALLED_ANDROID_INFO_TXT_TARGET)生成android-info.txt文件记录当前build配置的设备信息。
构建的起点在`build/core/main.mk`,可以看到整个文件的结构如下:
```
49 include $(BUILD_SYSTEM)/config.mk # 定义基于配置和宿主信息的变量
86 include $(BUILD_SYSTEM)/cleanbuild.mk # 定义删除编译结果的函数和目标
133 include $(BUILD_SYSTEM)/definitions.mk # 定义编译过程中用到的变量和宏
138~283 # 检查TARGET_BUILD_VARIANT变量有效性
根据make参数决定编译目标
419~423 # 加载所有子目录下的Android.mk
从Android.md中筛选出TARGET_BUILD_VARIANT目标
包含Makefile
930~1183 定义一些目标
ifndef KATI
...
else # KATI
...
endif # KATI
```
由于没有定义KATI所以走的是ifndef流程。MAKECMDGOALS是make执行时后面的参数这意味着不管执行什么目标最终都执行的都是run_soong_ui这个目标。这样编译的控制权就交到了soong手上后面的事就跟make没有关系了。
soong_ui代码在`build/soong/cmd/soong_ui/main.go`真正干活的是main函数里的最后一句
```
build.Build(buildCtx, config, build.BuildAll)
```
build.Build在`ui/build/build.go`从中可以看到执行soong的流程
1. `runMakeProductConfig`在ui/build/make.go用来配置编译参数。在这里可以看到[第一段输出](# 第一段输出)
2. `runSoongBootstrap`和`runSoong`在ui/build/soong.go分别运行的是`./bootstrap.bash`和`soong`两个命令。在这里可以看到[第二段输出](# 第二段输出)和[第三段输出](# 第三段输出)
`./bootstrap.bash`的最后一句会执行`build/blueprint/bootstrap.bash $@`如不带参数则生成minibp如带参数则生成一个基于Blueprint的构建系统。
3. `runKati`在ui/build/kati.go运行的是ckati命令。把所有的Android.mk文件生成ninja文件。
4. `createCombinedBuildNinjaFile`在ui/build/build.go在out/combined-openthos_x86_64.ninja文件里用include关键字把前两步生成的ninja文件包含进来。
5. `runNinja`在ui/build/ninja.go运行ninja命令执行构建过程所使用的配置文件就是第四步生成的combined-openthos_x86_64.ninja。在这里看到[第四段输出](# 第四段输出)
#### 第一段输出
在`build/core/dumpvar.mk`,输出的是关于编译环境的若干变量。
包含的次序main.mk --> config.mk --> dumpvar.mk
输出的是关于编译环境的若干变量。
#### 第二段输出
在`build/soong/build.ninja.in`,编译生成`out/soong/.bootstrap`下的文件。源文件在build/blueprint。
包含的次序main.mk -->
#### 第三段输出
搜集所有的`Android.bp`文件生成build.ninja。
#### 第四段输出
编译生成`out/soong/.bootstrap`下的文件。
#### 第五段输出
看起来是包含更多的文件,包括`*.h *.cpp Android.bp`等。
#### 第六段输出
详细的编译过程
#### 第七段编译目标oto_img
##### 第四段之生成oto_img
在bootable/newinstaller/Android.mk
@ -224,4 +222,6 @@ unsquashfs system.sfs
[理解安卓build系统](https://www.ibm.com/developerworks/cn/opensource/os-cn-android-build/)
[Android.bp及其工具链](http://note.qidong.name/2017/08/android-blueprint/)
[Android.bp及其工具链](http://note.qidong.name/2017/08/android-blueprint/)
[Android Soong build系统介绍](https://www.jianshu.com/p/80013a768a45)

View File

@ -0,0 +1,5 @@
```
source <filename> [arguments] # 在当前shell下执行filename里的命令
# 返回filename里最后一条命令的返回值。如果filename不可读则错误。
```

View File

@ -21,6 +21,9 @@ ctrl + b
c # 创建新窗口
& # 关闭当前窗口
数字键 # 切换到指定窗口
l # 切换到上一个窗口
f # 依据窗口编号向前切换
n # 住所窗口编号向后切换
```

View File

@ -141,6 +141,7 @@ V # 选择,以行为单位
w //移动到下个单词的第一个字符
e //移动到下个单词的最后一个字符
b # 移到上一个单词
0 //移动到行首
```

View File

@ -49,7 +49,8 @@ $(findstring)
$(firstword)
$(patsubst PATTERN,REPLACEMENT,TEXT)
# 将TEXT中符合PATTERN的单词替换为PEPLACEMENT
$(sort)
$(sort <list>)
# 给字符串<list>中的单词按升序排序,返回排序后的字符串。
$(strip)
$(subst)
$(wildcard <PATTERN...>)

View File

@ -0,0 +1,35 @@
```
go <command> [arguments]
```
#### 命令
```
clean
doc
env
fix
fmt
get
install
list
test
tool
version
vet
```
##### build
```
go build [-o output] [build flags] [packages] # 编译包和依赖
# 选项
```
##### run
```
run [build flags] <gofiles> [arguments]
# 编译和运行Go程序。关于[build flags]请查询"go-build"。
```

View File

@ -39,12 +39,12 @@
-o file
-O [type]
-p, --print-data-base
-q
-q, --question # 不运行任何命令也不打印任何东西只返回一个退出的状态。如果编译目标已经更新则返回0否则返回其它数字。
-r
-R
-s
-S
-t
-t, --touch # 更新文件的日期从而不执行它所依赖的命令。这实际上就是假装命令已经执行过了以便make将来调用的时候欺骗它。
--trace
-v
-w

View File

@ -0,0 +1,16 @@
一个构建工具它的作用和make命令是一样的。
#### ninja文件介绍
```
# 规则(rule)
rule <rule_name>
command = gcc ...
description =
# build语句
build <target_name> : <rule_name> <inputs>
# subninja和include都是用来引入其它的ninja文件。不同点是subninja引入的子模块可以使用父模块的变量include引入的子模块不可以使用交模块中的变量。
```