首页
chatGPT
关于
友链
其它
统计
更多
壁纸
留言
Search
1
cgroup--(4)cgroup v1和cgroup v2的详细介绍
6,456 阅读
2
修改Linux Kernel defconfig的标准方法
6,399 阅读
3
Android系统之VINTF(1)manifests&compatibility matrices
6,000 阅读
4
使用git生成patch和应用patch
3,479 阅读
5
c语言的__attribute__
3,176 阅读
默认分类
文章收集
学习总结
算法
环境配置
知识点
入门系列
vim
shell
Git
Make
Android
Linux
Linux命令
内存管理
Linux驱动
Language
C++
C
工具
软件工具
Bug
COMPANY
登录
Search
标签搜索
shell
Linux
c
uboot
Vim
vintf
Linux驱动
Android
device_tree
git
DEBUG
arm64
链表
数据结构
IDR
内核
ELF
gcc
ARM
网址
adtxl
累计撰写
367
篇文章
累计收到
14
条评论
首页
栏目
默认分类
文章收集
学习总结
算法
环境配置
知识点
入门系列
vim
shell
Git
Make
Android
Linux
Linux命令
内存管理
Linux驱动
Language
C++
C
工具
软件工具
Bug
COMPANY
页面
chatGPT
关于
友链
其它
统计
壁纸
留言
搜索到
51
篇与
的结果
2021-06-30
如何解压缩boot.img?
如何解压缩boot.img?mkbootimg github code
2021年06月30日
1,495 阅读
0 评论
0 点赞
2021-04-23
Android的adb网络调试方法
[转载]
2021年04月23日
1,651 阅读
0 评论
0 点赞
2021-04-01
Android10.0的init执行顺序
暂无简介
2021年04月01日
844 阅读
0 评论
0 点赞
2021-03-03
[转载]android 8.1 安全机制 — SEAndroid & SELinux
版权声明:本文为CSDN博主「岁月斑驳7」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/qq_19923217/article/details/81240027
2021年03月03日
1,323 阅读
0 评论
0 点赞
2021-03-02
Android系统之VINTF(1)manifests&compatibility matrices
暂无简介
2021年03月02日
6,000 阅读
0 评论
0 点赞
2021-03-01
添加新设备类型-Android编译系统(4)
1.理解构建层构建层次结构包括与设备的物理结构对应的抽象层。下表中介绍了这些层。每一层都与上一层存在一对多的关系。例如,一个架构(ARCH)可以有多个主板(Board/device),一个主板可以有多个产品(Product)。您可以将指定层中的某个元素定义为同一层中某个元素的特化元素,这样可以免去复制操作并简化维护工作。LayerExampleDescriptionProductmyProduct, myProduct_eu, myProduct_eu_fr, j2, sdkThe product layer defines the feature specification of a shipping product such as the modules to build, locales supported, and configuration for various locales. In other words, this is the name of the overall product. Product-specific variables are defined in product definition makefiles. A product can inherit from other product definitions, which simplifies maintenance. A common method is to create a base product that contains features that apply to all products, then create product variants based on that base product. For example, two products that differ only by their radios (CDMA versus GSM) can inherit from the same base product that doesn't define a radio.Board/devicemarlin, blueline, coralThe board/device layer represents the physical layer of plastic on the device (that is, the industrial design of the device). This layer also represents the bare schematics of a product. These include the peripherals on the board and their configuration. The names used are merely codes for different board/device configurations.Archarm, x86, arm64, x86_64The architecture layer describes the processor configuration and application binary interface (ABI) running on the board.2.使用build variants在针对特定产品进行构建时,如果能在最终发布 build 的基础上有细微的变化,会非常有用。在模块定义中,模块可以通过 LOCAL_MODULE_TAGS 指定标记,这些标记可以是以下一个或多个值:optional(默认值)、debug 和 eng。如果某个模块没有通过 LOCAL_MODULE_TAGS 指定标记,则其标记默认设置为 optional。仅当 PRODUCT_PACKAGES 的产品配置需要可选模块时,系统才会安装可选模块。下面是当前定义的构建变体(build variants)。VariantDescriptionengThis is the default flavor. - Installs modules tagged with eng or debug.- Installs modules according to the product definition files, in addition to tagged modules.- ro.secure=0- ro.debuggable=1- ro.kernel.android.checkjni=1- adb is enabled by default.userThe variant intended to be the final release bits.- Installs modules tagged with user.- Installs modules according to the product definition files, in addition to tagged modules.- ro.secure=1- ro.debuggable=0- adb is disabled by default.userdebugThe same as user, with these exceptions:- Also installs modules tagged with debug.- ro.debuggable=1- adb is enabled by default.aosp为build系统提供三种Product配置,文档里叫做build variants,分别是:eng : 对应到工程版。编译打包所有模块。表示adbd处于ROOT状态,所有调试开关打开userdebug : 对应到用户调试版。打开调试开关,但并没有放开ROOT权限user : 对应到用户版。关闭调试开关,关闭ROOT权限。最终发布到用户手上的版本,通常都是user版。2.1 userdebug的准则在测试中运行 userdebug build 有助于设备开发者了解开发中版本的性能和功耗。为了让 user build 和 userdebug build 保持一致,并在用于调试的 build 中获得可靠的指标,设备开发者应遵循以下准则:userdebug 定义为已启用 root 权限的 user build,但以下情况除外:仅由用户视需要运行且仅用于 userdebug build 的应用仅在空闲维护(连接充电器/充满电)期间执行的操作,例如,使用 dex2oatd 而不是 dex2oat 来进行后台编译不要添加根据构建类型默认启用/停用的功能。建议开发者不要使用任何影响电池续航时间的日志记录形式(例如调试日志记录或堆转储)。在 userdebug build 中默认启用的任何调试功能都应明确定义,并告知处理相关项目的所有开发者。您应该只在限定的时间内启用调试功能,直到您尝试调试的问题得到解决。3. Customizing the build with resource overlays(利用资源叠加层自定义build)Android 构建系统会在构建时使用资源叠加层来自定义产品。资源叠加层用于指定在默认文件之上应用的资源文件。如需使用资源叠加层,请修改项目构建文件,将 PRODUCT_PACKAGE_OVERLAYS 设为相对于顶级目录的路径。当构建系统搜索资源时,该路径会变为影子根目录,系统除了在当前根目录中进行搜索外,还会一并在该路径中进行搜索。最常自定义的设置包含在 frameworks/base/core/res/res/values/config.xml 文件中。如需在此文件上设置资源叠加层,请使用以下某个命令将叠加层目录添加到项目构建文件:PRODUCT_PACKAGE_OVERLAYS := device/device-implementer/device-name/overlay例如:或PRODUCT_PACKAGE_OVERLAYS := vendor/vendor-name/overlay然后,将一个叠加层文件添加到该目录下,例如:vendor/foobar/overlay/frameworks/base/core/res/res/config.xml在叠加层 config.xml 文件中找到的所有字符串或字符串数组都会替换在原始文件中找到的对应字符串或字符串数组。4. 构建产品您可以通过多种不同的方式来组织设备的源文件。下面简要说明了 Pixel 实现的一种组织方式。为 Pixel 实现名为 marlin 的主设备配置。根据此设备配置,为产品创建产品定义 Makefile,用于声明关于设备的产品特定信息,例如名称和型号。您可以查看 device/google/marlin 目录,了解所有相关配置的具体设置方式。4.1 编写产品Makefile以下步骤介绍了如何采用与设置 Pixel 产品线类似的方式设置产品 Makefile:为您的产品创建一个 device/<company-name>/<device-name> 目录。例如,device/google/marlin。此目录将包含您设备的源代码以及构建这些代码所需的 Makefile。创建一个 device.mk Makefile,用来声明设备所需的文件和模块。有关示例,请查看 device/google/marlin/device-marlin.mk。创建一个产品定义 Makefile,以便基于设备创建具体产品。以下示例 Makefile 来自于 device/google/marlin/aosp_marlin.mk。请注意,该产品会通过 Makefile 沿用 device/google/marlin/device-marlin.mk 和 vendor/google/marlin/device-vendor-marlin.mk 文件中的设置,同时还会声明产品特定信息,例如名称、品牌和型号。# Inherit from the common Open Source product configuration $(call inherit-product, $(SRC_TARGET_DIR)/product/core_64_bit.mk) $(call inherit-product, $(SRC_TARGET_DIR)/product/aosp_base_telephony.mk) PRODUCT_NAME := aosp_marlin PRODUCT_DEVICE := marlin PRODUCT_BRAND := Android PRODUCT_MODEL := AOSP on msm8996 PRODUCT_MANUFACTURER := Google PRODUCT_RESTRICT_VENDOR_FILES := true PRODUCT_COPY_FILES += device/google/marlin/fstab.common:$(TARGET_COPY_OUT_VENDOR)/etc/fstab.marlin $(call inherit-product, device/google/marlin/device-marlin.mk) $(call inherit-product-if-exists, vendor/google_devices/marlin/device-vendor-marlin.mk) PRODUCT_PACKAGES += \ Launcher3QuickStep \ WallpaperPicker如需了解可添加到 Makefile 的其他产品特定变量,请参阅设置产品定义变量(4.2小节)。创建一个指向产品的 Makefile文件AndroidProducts.mk。在此示例中,仅需要产品定义 Makefile。以下示例来自于 device/google/marlin/AndroidProducts.mk(该文件同时包含 marlin (Pixel) 和 sailfish (Pixel XL),它们共享大部分配置):PRODUCT_MAKEFILES := \ $(LOCAL_DIR)/aosp_marlin.mk \ $(LOCAL_DIR)/aosp_sailfish.mk COMMON_LUNCH_CHOICES := \ aosp_marlin-userdebug \ aosp_sailfish-userdebug创建一个包含主板特定配置的Makefile文件BoardConfig.mk 。如需查看示例,请查看 device/google/marlin/BoardConfig.mk。创建一个 vendorsetup.sh 文件,以便将您的产品(“午餐套餐”)与构建变体(使用短划线将两者分隔开)一起添加到 build 中。例如:add_lunch_combo <product-name>-userdebug这一步显得多余了,谷歌已经不建议这样了这时,您就可以基于同一设备创建更多产品变体了。4.2 设置产品定义变量产品特定变量在产品的 Makefile 中进行定义。下表显示了在产品定义文件中维护的部分变量。变量说明示例PRODUCT_AAPT_CONFIGaapt configurations to use when creating packages. PRODUCT_BRANDThe brand (for example, carrier) the software is customized for, if any. PRODUCT_CHARACTERISTICSaapt characteristics to allow adding variant-specific resources to a package.tablet, nosdcardPRODUCT_COPY_FILESList of words like source_path:destination_path. The file at the source path should be copied to the destination path when building this product. The rules for the copy steps are defined in config/makefile. PRODUCT_DEVICEName of the industrial design. This is also the board name, and the build system uses it to locate BoardConfig.mk.tunaPRODUCT_LOCALESA space-separated list of two-letter language code, two-letter country code pairs that describe several settings for the user, such as the UI language and time, date, and currency formatting. The first locale listed in PRODUCT_LOCALES is used as the product's default locale.en_GB, de_DE, es_ES, fr_CAPRODUCT_MANUFACTURERName of the manufacturer.acmePRODUCT_MODELEnd-user-visible name for the end product. PRODUCT_NAMEEnd-user-visible name for the overall product. Appears in the Settings > About screen. PRODUCT_OTA_PUBLIC_KEYSList of over-the-air (OTA) public keys for the product. PRODUCT_PACKAGESList of the APKs and modules to install.Calendar contactsPRODUCT_PACKAGE_OVERLAYSIndicates whether to use default resources or add any product specific overlays.vendor/acme/overlayPRODUCT_SYSTEM_PROPERTIESList of the system property assignments in the format "key=value" for the system partition. System properties for other partitions can be set via PRODUCT_<PARTITION>_PROPERTIES as in PRODUCT_VENDOR_PROPERTIES for the vendor partition. Supported partition names: SYSTEM, VENDOR, ODM, SYSTEM_EXT, and PRODUCT. 4.3 设置ADB_VENDOR_KEYS以通过USB进行连接借助 ADB_VENDOR_KEYS 环境变量,设备制造商无需手动授权,即可通过 adb 访问可调试的 build(userdebug build 和 eng build,但不能访问 user build)。通常,adb 会为每台客户端计算机生成一个唯一的 RSA 身份验证密钥,并将其发送到所有已连接的设备。这就是 adb 授权对话框中显示的 RSA 密钥。或者,您也可以将已知密钥构建到系统映像中,并将其分享给相应的 adb 客户端。这对于操作系统开发来说很有用,对测试来说尤其有用,因为此做法无需与 adb 授权对话框手动进行交互。如需创建供应商密钥,应安排一个人(通常为发布管理员)执行以下操作:使用 adb keygen 生成密钥对。对于 Google 设备,Google 会为每个新操作系统版本生成一个新密钥对。将密钥对签入源代码树中的某个位置。例如,Google 会将其存储在 vendor/google/security/adb/ 中。设置构建变体 PRODUCT_ADB_KEYS,使其指向您的密钥目录。为此,Google 会在密钥目录中添加一个 Android.mk 文件,其内容为 PRODUCT_ADB_KEYS := $(LOCAL_PATH)/$(PLATFORM_VERSION).adb_key.pub,以帮助确保我们记得为每个操作系统版本生成新的密钥对。以下是 Google 在该目录(我们将各版本的已签入密钥对存储在此处)中使用的 Makefile:PRODUCT_ADB_KEYS := $(LOCAL_PATH)/$(PLATFORM_VERSION).adb_key.pub ifeq ($(wildcard $(PRODUCT_ADB_KEYS)),) $(warning ========================) $(warning The adb key for this release) $(warning ) $(warning $(PRODUCT_ADB_KEYS)) $(warning ) $(warning does not exist. Most likely PLATFORM_VERSION in build/core/version_defaults.mk) $(warning has changed and a new adb key needs to be generated.) $(warning ) $(warning Please run the following commands to create a new key:) $(warning ) $(warning make -j8 adb) $(warning LOGNAME=android-eng HOSTNAME=google.com adb keygen $(patsubst %.pub,%,$(PRODUCT_ADB_KEYS))) $(warning ) $(warning and upload/review/submit the changes) $(warning ========================) $(error done) endif如需使用这些供应商密钥,工程师只需将 ADB_VENDOR_KEYS 环境变量设为指向存储相应密钥对的目录。这会告知 adb 先尝试这些规范密钥,然后回退到需要手动授权的已生成主机密钥。当 adb 无法连接到未获授权的设备时,系统会显示错误消息,提示您设置 ADB_VENDOR_KEYS(如果尚未设置)。参考:Android系统之添加ProductAdding a New Device
2021年03月01日
1,143 阅读
0 评论
0 点赞
2021-03-01
[转载]编译环境初始化-Android10.0编译系统(二)
版权声明:本文为CSDN博主「IngresGe」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/yiranfeng/article/details/1090837541. 概述上一节针对Android编译系统做了一个笼统的说明,这一节针对编译环境初始化做一下详细的展示。2. 编译环境初始化初始化命令:source build/envsetup.shenvsetup.sh 主要做了下面几个事情:envsetup.sh 构建代码: ... validate_current_shell source_vendorsetup addcompletions2.1 hmm查看支持接口输入hmm可以看到envsetup支持的一些接口命令说明lunchlunch <product_name>-<build_variant>选择<product_name>作为要构建的产品,<build_variant>作为要构建的变体,并将这些选择存储在环境中,以便后续调用“m”等读取。tapas交互方式:tapas [<App1> <App2> ...] [arm\x86\mips\arm64\x86_64\mips64] [eng\userdebug\user]croot将目录更改到树的顶部或其子目录。m编译整个源码,可以不用切换到根目录mm编译当前目录下的源码,包含他们的依赖模块(11包含)mmm编译指定目录下的所有模块,包含他们的依赖模块(11包含) 例如:mmm dir/:target1,target2.mma编译当前目录下的源码,包含他们的依赖模块mmma编译指定目录下的所模块,包含他们的依赖模块provision具有所有必需分区的闪存设备。选项将传递给fastboot。cgrep对系统本地所有的C/C++ 文件执行grep命令ggrep对系统本地所有的Gradle文件执行grep命令jgrep对系统本地所有的Java文件执行grep命令resgrep对系统本地所有的res目录下的xml文件执行grep命令mangrep对系统本地所有的AndroidManifest.xml文件执行grep命令mgrep对系统本地所有的Makefiles文件执行grep命令sepgrep对系统本地所有的sepolicy文件执行grep命令sgrep对系统本地所有的source文件执行grep命令godir根据godir后的参数文件名在整个目录下查找,并且切换目录allmod列出所有模块gomod转到包含模块的目录pathmod获取包含模块的目录refreshmod刷新allmod/gomod的模块列表2.2 validate_current_shell确定当前的shell环境,建立shell命令function validate_current_shell() { local current_sh="$(ps -o command -p $$)" case "$current_sh" in *bash*) function check_type() { type -t "$1"; } ;; *zsh*) function check_type() { type "$1"; } enable_zsh_completion ;; *) echo -e "WARNING: Only bash and zsh are supported.\nUse of other shell would lead to erroneous results." ;; esac }2.3 source_vendorsetup从device\vendor\product等目录遍历搜索vendorsetup.sh,并source进来function source_vendorsetup() { allowed= for f in $(find -L device vendor product -maxdepth 4 -name 'allowed-vendorsetup_sh-files' 2>/dev/null | sort); do if [ -n "$allowed" ]; then echo "More than one 'allowed_vendorsetup_sh-files' file found, not including any vendorsetup.sh files:" echo " $allowed" echo " $f" return fi allowed="$f" done allowed_files= [ -n "$allowed" ] && allowed_files=$(cat "$allowed") for dir in device vendor product; do for f in $(test -d $dir && \ find -L $dir -maxdepth 4 -name 'vendorsetup.sh' 2>/dev/null | sort); do if [[ -z "$allowed" || "$allowed_files" =~ $f ]]; then echo "including $f"; . "$f" else echo "ignoring $f, not in $allowed" fi done done }例:1.建立一个目录:/vendor/ingres/build2.创建一个vendorsetup.sh写一个log: echo "vendor build test."3.执行source build/envsetup.shsource后打印:including vendor/ingres/build/vendorsetup.sh vendor build test.2.4 addcompletionsfunction addcompletions() { local T dir f # Keep us from trying to run in something that's neither bash nor zsh. # 检测shell版本字符串BASH_VERSION 或ZSH_VERSION长度为0时,返回 if [ -z "$BASH_VERSION" -a -z "$ZSH_VERSION" ]; then return fi # Keep us from trying to run in bash that's too old. # 检测bash主版本低于3时返回 if [ -n "$BASH_VERSION" -a ${BASH_VERSINFO[0]} -lt 3 ]; then return fi # 指定bash文件目录并检查是否存在 local completion_files=( system/core/adb/adb.bash system/core/fastboot/fastboot.bash tools/asuite/asuite.sh ) # Completion can be disabled selectively to allow users to use non-standard completion. # e.g. # ENVSETUP_NO_COMPLETION=adb # -> disable adb completion # ENVSETUP_NO_COMPLETION=adb:bit # -> disable adb and bit completion #*.bash文件列表,并将这些*.bash文件包含进来 for f in ${completion_files[*]}; do if [ -f "$f" ] && should_add_completion "$f"; then # 对*.bash文件执行'.'操作 . $f fi done if should_add_completion bit ; then complete -C "bit --tab" bit fi if [ -z "$ZSH_VERSION" ]; then # Doesn't work in zsh. complete -o nospace -F _croot croot fi complete -F _lunch lunch # _lunch命令提供lunch命令的补全操作 complete -F _complete_android_module_names gomod complete -F _complete_android_module_names m }3. lunch aosp_arm_eng3.1 lunch说明环境变量初始化完成后,我们需要选择一个编译目标。lunch 主要作用是根据用户输入或者选择的产品名来设置与具体产品相关的环境变量。执行命令:lunch 1, 可以看到配置的一些环境变量lunch结果说明PLATFORM_VERSION_CODENAME=REL表示平台版本的名称PLATFORM_VERSION=10Android平台的版本号TARGET_PRODUCT=aosp_arm所编译的产品名称TARGET_BUILD_VARIANT=userdebug所编译产品的类型TARGET_BUILD_TYPE=release编译的类型,debug和releaseTARGET_ARCH=arm表示编译目标的CPU架构TARGET_ARCH_VARIANT=armv7-a-neon表示编译目标的CPU架构版本TARGET_CPU_VARIANT=generic表示编译目标的CPU代号HOST_ARCH=x86_64表示编译平台的架构HOST_2ND_ARCH=x86表示编译平台的第二CPU架构HOST_OS=linux表示编译平台的操作系统HOST_OS_EXTRA=Linux-4.15.0-112-generic-x86_64-Ubuntu-16.04.6-LTS编译系统之外的额外信息HOST_CROSS_OS=windows HOST_CROSS_ARCH=x86 HOST_CROSS_2ND_ARCH=x86_64 HOST_BUILD_TYPE=release编译类型BUILD_ID=QQ1D.200205.002BUILD_ID会出现在版本信息中,可以利用OUT_DIR=out编译结果输出的路径lunch aosp_arm-eng 结束后,后创建一个out文件夹,生成一些中间文件如下图所示:3.2 lunch()lunch命令用来设置 TARGET_PRODUCT、TARGET_BUILD_VARIANT、TARGET_PLATFORM_VERSION、TARGET_BUILD_TYPE、TARGET_BUILD_APPS等环境变量lunch操作流程如下:1.获取lunch操作的参数,如果参数不为空,参数则为指定要编译的设备型号和编译类型;如果参数为空,会调用print_lunch_menu来显示Lunch菜单项,读取用户的输入,存入answer2.如果answer为空,即之前在lunch菜单用,用户只敲了一个回车。会将默认选项改为aosp_arm-eng,结果存入selection3.如果lunch操作得到的输入是数字,则将数字转换为LUNCH_MENU_CHOICES中的字符串,结果存入selection4.解析selection的值,得到product = aosp_arm 和variant = eng, 把他们分别保存到TARGET_PRODUCT 和 TARGET_BUILD_VARIANT 中5.根据前面的设置,调用build_build_var_cache 来更新编译环境相关变量6.export 编译选项TARGET_PRODUCT, TARGET_BUILD_VARIANT和TARGET_BUILD_TYPE三元组7.调用set_stuff_for_environment 来设置其他环境变量,如PROMPT_COMMAND,编译toolchain和tools相关的路径等8.调用printconfig 来输出当前的设置选项function lunch() { local answer # 获取lunch操作的参数 if [ "$1" ] ; then answer=$1 else # lunch操作不带参数,则先显示lunch menu,然后读取用户输入 print_lunch_menu echo -n "Which would you like? [aosp_arm-eng] " read answer fi local selection= # lunch操作得到的结果为空(例如用户直接在lunch要求输入时回车的情况) # 则将选项默认为"aosp_arm-eng" if [ -z "$answer" ] then selection=aosp_arm-eng # lunch操作得到的输入是数字,则将数字转换为LUNCH_MENU_CHOICES中的字符串 elif (echo -n $answer | grep -q -e "^[0-9][0-9]*$") then local choices=($(TARGET_BUILD_APPS= get_build_var COMMON_LUNCH_CHOICES)) if [ $answer -le ${#choices[@]} ] then # array in zsh starts from 1 instead of 0. if [ -n "$ZSH_VERSION" ] then selection=${choices[$(($answer))]} else selection=${choices[$(($answer-1))]} fi fi else selection=$answer fi export TARGET_BUILD_APPS= local product variant_and_version variant version product=${selection%%-*} # Trim everything after first dash variant_and_version=${selection#*-} # Trim everything up to first dash if [ "$variant_and_version" != "$selection" ]; then variant=${variant_and_version%%-*} if [ "$variant" != "$variant_and_version" ]; then version=${variant_and_version#*-} fi fi if [ -z "$product" ] then echo echo "Invalid lunch combo: $selection" return 1 fi # 设置TARGET_PRODUCT和TARGET_BUILD_VARIANT TARGET_PRODUCT=$product \ TARGET_BUILD_VARIANT=$variant \ TARGET_PLATFORM_VERSION=$version \ # 根据前面的设置,更新编译环境相关变量 build_build_var_cache #参考[3.1.1] if [ $? -ne 0 ] then return 1 fi # export 编译选项TARGET_PRODUCT, TARGET_BUILD_VARIANT和TARGET_BUILD_TYPE三元组 export TARGET_PRODUCT=$(get_build_var TARGET_PRODUCT) export TARGET_BUILD_VARIANT=$(get_build_var TARGET_BUILD_VARIANT) if [ -n "$version" ]; then export TARGET_PLATFORM_VERSION=$(get_build_var TARGET_PLATFORM_VERSION) else unset TARGET_PLATFORM_VERSION fi export TARGET_BUILD_TYPE=release echo set_stuff_for_environment # 设置其他环境变量,如PROMPT_COMMAND,编译toolchain和tools相关的路径等 printconfig # 输出当前的设置选项 destroy_build_var_cache }3.1.1 build_build_var_cache()根据前面的设置,更新编译环境相关变量主要通过执行 "build/soong/soong_ui.bash --dumpvars-mode" 完成最终执行的是 "./out/soog_ui --dumpvars-mode"function build_build_var_cache() { local T=$(gettop) # Grep out the variable names from the script. cached_vars=(`cat $T/build/envsetup.sh | tr '()' ' ' | awk '{for(i=1;i<=NF;i++) if($i~/get_build_var/) print $(i+1)}' | sort -u | tr '\n' ' '`) cached_abs_vars=(`cat $T/build/envsetup.sh | tr '()' ' ' | awk '{for(i=1;i<=NF;i++) if($i~/get_abs_build_var/) print $(i+1)}' | sort -u | tr '\n' ' '`) # Call the build system to dump the "<val>=<value>" pairs as a shell script. build_dicts_script=`\builtin cd $T; build/soong/soong_ui.bash --dumpvars-mode \ --vars="${cached_vars[*]}" \ --abs-vars="${cached_abs_vars[*]}" \ --var-prefix=var_cache_ \ --abs-var-prefix=abs_var_cache_` local ret=$? if [ $ret -ne 0 ] then unset build_dicts_script return $ret fi # Execute the script to store the "<val>=<value>" pairs as shell variables. eval "$build_dicts_script" ret=$? unset build_dicts_script if [ $ret -ne 0 ] then return $ret fi BUILD_VAR_CACHE_READY="true" }soong_ui 由build/soong/cmd/soong_ui/main.go编译生成[build/soong/cmd/soong_ui/main.go] func main() { ... if os.Args[1] == "--dumpvar-mode" { dumpVar(buildCtx, config, os.Args[2:]) } else if os.Args[1] == "--dumpvars-mode" { dumpVars(buildCtx, config, os.Args[2:]) } else { ... } ... } [build/soong/cmd/soong_ui/main.go] func dumpVars(ctx build.Context, config build.Config, args []string) { varData, err := build.DumpMakeVars(ctx, config, nil, allVars) }最后调用到了ckati执行-f build/make/core/config.mk[/build/soong/ui/build/dumpvars.go] func dumpMakeVars(ctx Context, config Config, goals, vars []string, write_soong_vars bool) (map[string]string, error) { ctx.BeginTrace(metrics.RunKati, "dumpvars") defer ctx.EndTrace() cmd := Command(ctx, config, "dumpvars", config.PrebuiltBuildTool("ckati"), "-f", "build/make/core/config.mk", "--color_warnings", "--kati_stats", "dump-many-vars", "MAKECMDGOALS="+strings.Join(goals, " ")) cmd.Environment.Set("CALLED_FROM_SETUP", "true") if write_soong_vars { cmd.Environment.Set("WRITE_SOONG_VARIABLES", "true") } cmd.Environment.Set("DUMP_MANY_VARS", strings.Join(vars, " ")) cmd.Sandbox = dumpvarsSandbox output := bytes.Buffer{} cmd.Stdout = &output pipe, err := cmd.StderrPipe() if err != nil { ctx.Fatalln("Error getting output pipe for ckati:", err) } cmd.StartOrFatal() // TODO: error out when Stderr contains any content status.KatiReader(ctx.Status.StartTool(), pipe) cmd.WaitOrFatal() ret := make(map[string]string, len(vars)) ... return ret, nil }下面我们单独研究一下config.mk。4. config.mk 说明:config.mk首先加载了build/make/common 中的core.mk、math.mk、strings.mk、json.mk 用来配置一些shell环境、math函数、string和json的一些支持函数。最主要的操作还是加载build/make/core中的envsetup.mk和dumpvar.mk ... #配置两个目录的变量,供之后的mk使用 BUILD_SYSTEM :=$= build/make/core BUILD_SYSTEM_COMMON :=$= build/make/common #加载core.mk, 只使用ANDROID_BUILD_SHELL来包装bash。 include $(BUILD_SYSTEM_COMMON)/core.mk #设置make中使用的有效数学函数。 include $(BUILD_SYSTEM_COMMON)/math.mk include $(BUILD_SYSTEM_COMMON)/strings.mk include $(BUILD_SYSTEM_COMMON)/json.mk # 避免硬件解码路径被覆盖的调用pathmap.mk建立硬解映射 include $(BUILD_SYSTEM)/pathmap.mk # 允许项目定义自己的全局可用变量 include $(BUILD_SYSTEM)/project_definitions.mk # ############################################################### # Build system internal files # ############################################################### # 构建系统内部文件(写Android.mk时会调用include头文件,也就是这些makefile文件) BUILD_COMBOS:= $(BUILD_SYSTEM)/combo CLEAR_VARS:= $(BUILD_SYSTEM)/clear_vars.mk BUILD_HOST_STATIC_LIBRARY:= $(BUILD_SYSTEM)/host_static_library.mk BUILD_HOST_SHARED_LIBRARY:= $(BUILD_SYSTEM)/host_shared_library.mk BUILD_STATIC_LIBRARY:= $(BUILD_SYSTEM)/static_library.mk ... BUILD_NOTICE_FILE := $(BUILD_SYSTEM)/notice_files.mk BUILD_HOST_DALVIK_JAVA_LIBRARY := $(BUILD_SYSTEM)/host_dalvik_java_library.mk BUILD_HOST_DALVIK_STATIC_JAVA_LIBRARY := $(BUILD_SYSTEM)/host_dalvik_static_java_library.mk BUILD_HOST_TEST_CONFIG := $(BUILD_SYSTEM)/host_test_config.mk BUILD_TARGET_TEST_CONFIG := $(BUILD_SYSTEM)/target_test_config.mk #定义大多数全局变量。这些是特定于用户的构建配置的。 include $(BUILD_SYSTEM)/envsetup.mk #构建系统为在哪里找到内核公开了几个变量 #(1)TARGET_DEVICE_KERNEL_HEADERS是为当前正在构建的设备自动创建的。 #它被设置为$(TARGET_DEVICE_DIR)/kernel headers, #例如DEVICE/samsung/tuna/kernel headers。此目录不是由任何人显式设置的,生成系统总是添加此子目录。 TARGET_DEVICE_KERNEL_HEADERS := $(strip $(wildcard $(TARGET_DEVICE_DIR)/kernel-headers)) #(2)TARGET_BOARD_KERNEL_HEADERS由BoardConfig.mk允许包含其他目录的文件。 #如果有一些常见的地方为一组设备保留了一些报头,那么这很有用。 #例如,device/<vendor>/common/kernel头可以包含一些<vendor>设备的头。 TARGET_BOARD_KERNEL_HEADERS := $(strip $(wildcard $(TARGET_BOARD_KERNEL_HEADERS))) TARGET_BOARD_KERNEL_HEADERS := $(patsubst %/,%,$(TARGET_BOARD_KERNEL_HEADERS)) $(call validate-kernel-headers,$(TARGET_BOARD_KERNEL_HEADERS)) #(3)TARGET_PRODUCT_KERNEL_头由产品继承图生成。 #这允许体系结构产品为使用该体系结构的设备提供报头。 TARGET_PRODUCT_KERNEL_HEADERS := $(strip $(wildcard $(PRODUCT_VENDOR_KERNEL_HEADERS))) TARGET_PRODUCT_KERNEL_HEADERS := $(patsubst %/,%,$(TARGET_PRODUCT_KERNEL_HEADERS)) $(call validate-kernel-headers,$(TARGET_PRODUCT_KERNEL_HEADERS)) # 选择一个Java编译器 include $(BUILD_SYSTEM)/combo/javac.mk # A list of SEPolicy versions, besides PLATFORM_SEPOLICY_VERSION, that the framework supports. #框架支持的SEPolicy版本列表,除了PLATFORM_SEPOLICY_VERSION PLATFORM_SEPOLICY_COMPAT_VERSIONS := \ 26.0 \ 27.0 \ 28.0 \ ifeq ($(CALLED_FROM_SETUP),true) include $(BUILD_SYSTEM)/ninja_config.mk include $(BUILD_SYSTEM)/soong_config.mk endif #加载dumpvar.mk,用来生成make目标 include $(BUILD_SYSTEM)/dumpvar.mk4.1 build/make/core/envsetup.mkenvsetup.mk 主要加载了product_config.mk和board_config.mk,用来得到TARGET_DEVICE和其他变量。... #设置host和target编译链相关的变量 include $(BUILD_SYSTEM)/combo/select.mk #(1)阅读产品规格,这样我们就可以得到TARGET_DEVICE和其他变量,我们需要找到输出文件 include $(BUILD_SYSTEM)/product_config.mk include $(BUILD_SYSTEM)/board_config.mk ...4.2 build/make/core/product_config.mk阅读产品规格,这样我们就可以得到TARGET_DEVICE和其他变量,我们需要找到输出文件。... # --------------------------------------------------------------- # Include the product definitions. # We need to do this to translate TARGET_PRODUCT into its # underlying TARGET_DEVICE before we start defining any rules. # include $(BUILD_SYSTEM)/node_fns.mk include $(BUILD_SYSTEM)/product.mk include $(BUILD_SYSTEM)/device.mk ... ############################################################################# # Sanity check and assign default values TARGET_DEVICE := $(PRODUCT_DEVICE) ...4.3 build/make/core/board_config.mk板级可以在$(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)下定义,也可以在vendor/\*/$(TARGET_DEVICE)下定义。在这两个地方搜索,但要确保只存在一个。真正的板级应始终与OEM vendor相关联。... # Boards may be defined under $(SRC_TARGET_DIR)/board/$(TARGET_DEVICE) # or under vendor/*/$(TARGET_DEVICE). Search in both places, but # make sure only one exists. # Real boards should always be associated with an OEM vendor. ifdef TARGET_DEVICE_DIR ifneq ($(origin TARGET_DEVICE_DIR),command line) $(error TARGET_DEVICE_DIR may not be set manually) endif board_config_mk := $(TARGET_DEVICE_DIR)/BoardConfig.mk else board_config_mk := \ $(strip $(sort $(wildcard \ $(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)/BoardConfig.mk \ $(shell test -d device && find -L device -maxdepth 4 -path '*/$(TARGET_DEVICE)/BoardConfig.mk') \ $(shell test -d vendor && find -L vendor -maxdepth 4 -path '*/$(TARGET_DEVICE)/BoardConfig.mk') \ ))) ifeq ($(board_config_mk),) $(error No config file found for TARGET_DEVICE $(TARGET_DEVICE)) endif ifneq ($(words $(board_config_mk)),1) $(error Multiple board config files for TARGET_DEVICE $(TARGET_DEVICE): $(board_config_mk)) endif TARGET_DEVICE_DIR := $(patsubst %/,%,$(dir $(board_config_mk))) .KATI_READONLY := TARGET_DEVICE_DIR endif include $(board_config_mk) ...5. 总结至此,envsetup.sh 和lunch()的初始化流程基本上理清了,主要就是加载了环境变量,并选择了编译目标,后面只要执行一下make就能够进行启动编译,下一节让我们一起看看敲下make后到底发生了什么。
2021年03月01日
1,200 阅读
0 评论
0 点赞
2021-03-01
[转载]编译系统入门篇-Android10.0编译系统(一)
转载自编译系统入门篇-Android10.0编译系统(一)版权声明:本文为CSDN博主「IngresGe」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/yiranfeng/article/details/1090824891. 概述在 Android 7.0 之前,Android 编译系统使用 GNU Make 描述和shell来构建编译规则,模块定义都使用Android.mk进行定义,Android.mk的本质就是Makefile,但是随着Android的工程越来越大,模块越来越多,Makefile组织的项目编译时间越来越长。这样下去Google工程师觉得不行,得要优化。因此,在Android7.0开始,Google采用ninja来代取代之前使用的make,由于之前的Android.mk数据实在巨大,因此Google加入了一个kati工具,用于将Android.mk转换成ninja的构建规则文件buildxxx.ninja,再使用ninja来进行构建工作。ninja的网址:https://ninja-build.org编译速度快了一些,但是既然要干, 那就干个大的,最终目标要把make都取代,于是从Android8.0开始,Google为了进一步淘汰Makefile,因此引入了Android.bp文件来替换之前的Android.mk。Android.bp只是一个纯粹的配置文件,不包括分支、循环语句等控制流程,本质上就是一个json配置文件。Android.bp 通过Blueprint+soong转换成ninja的构建规则文件build.ninja,再使用ninja来进行构建工作。Android10.0上,mk和bp编译的列表可以从 \out.module_paths中的Android.bp.list、Android.mk.list中看到,Android10.0还有400多个mk文件没有被替换完,Google任重道远。Android编译演进过程:Android7.0之前 使用GNU MakeAndroid7.0 引入ninja、kati、Android.bp和soong构建系统Android8.0 默认打开Android.bpAndroid9.0 强制使用Android.bpGoogle在 Android 7.0之后,引入了Soong构建系统,旨在取代make,它利用 Kati GNU Make 克隆工具和 Ninja 构建系统组件来加速 Android 的构建。Make 构建系统得到了广泛的支持和使用,但在 Android 层面变得缓慢、容易出错、无法扩展且难以测试。Soong 构建系统正好提供了 Android build 所需的灵活性。Android系统的编译历程:2. 编译流程2.1 编译构成Android的编译目录在/build 中,看一下Android 10源码中的build目录,现在是这个样子: 这个目录中可以看到core文件夹被link到了make/core,envsetup.sh被link到make/envsetup.sh,这主要是为了对使用者屏蔽切换编译系统的差异。这里重点看四个文件夹:blueprint、kati、make、soongblueprint:用于处理Android.bp,编译生成*.ninja文件,用于做ninja的处理kati:用于处理Android.mk,编译生成*.ninja文件,用于做ninja的处理make:文件夹还是原始的make那一套流程,比如envsetup.shsoong:构建系统,核心编译为soong_ui.bash Soong编译系统家族成员及各自关系如下图所示:在编译过程中,Android.bp会被收集到out/soong/build.ninja.d,blueprint以此为基础,生成out/soong/build.ninjaAndroid.mk会由kati/ckati生成为out/build-aosp_arm.ninja两个ninja文件会被整合进入out/combined-aosp_arm.ninjaout/combined-aosp_arm.ninja内容如下所示:builddir = out pool local_pool depth = 42 build _kati_always_build_: phony subninja out/build-aosp_arm.ninja subninja out/build-aosp_arm-package.ninja subninja out/soong/build.ninja2.2 编译步骤source build/envsetup.shlunch aosp_arm-eng // 或者 m PRODUCT-aosp_x86_64-eng ,Android10.0不一定需要lunch命令make -j8 //编译模块也可以直接用 m libartAndroid10.0编译步骤如下图所示:3. 编译环境初始化3.1 envsetup说明 source build/envsetup.sh这里的envsetup.sh被link到了 build/make/envsetup.shenvsetup.sh 主要做了下面几个事情:在source build/envsetup.sh后,输入hmm可以看到envsetup支持的一些接口:命令说明lunchlunch <product_name>-<build_variant>选择<product_name>作为要构建的产品,<build_variant>作为要构建的变体,并将这些选择存储在环境中,以便后续调用“m”等读取。tapas交互方式:tapas [<App1> <App2> ...] [arm\x86\mips\arm64\x86_64\mips64] [eng\userdebug\user]croot将目录更改到树的顶部或其子目录。m编译整个源码,可以不用切换到根目录mm编译当前目录下的源码,不包含他们的依赖模块mmm编译指定目录下的所有模块,不包含他们的依赖模块 例如:mmm dir/:target1,target2.mma编译当前目录下的源码,包含他们的依赖模块mmma编译指定目录下的所模块,包含他们的依赖模块provision具有所有必需分区的闪存设备。选项将传递给fastboot。cgrep对系统本地所有的C/C++ 文件执行grep命令ggrep对系统本地所有的Gradle文件执行grep命令jgrep对系统本地所有的Java文件执行grep命令resgrep对系统本地所有的res目录下的xml文件执行grep命令mangrep对系统本地所有的AndroidManifest.xml文件执行grep命令mgrep对系统本地所有的Makefiles文件执行grep命令sepgrep对系统本地所有的sepolicy文件执行grep命令sgrep对系统本地所有的source文件执行grep命令godir根据godir后的参数文件名在整个目录下查找,并且切换目录allmod列出所有模块gomod转到包含模块的目录pathmod获取包含模块的目录refreshmod刷新allmod/gomod的模块列表3.2 Lunch说明环境变量初始化完成后,我们需要选择一个编译目标。lunch 主要作用是根据用户输入或者选择的产品名来设置与具体产品相关的环境变量。如果你不知道想要编译的目标是什么,直接执行一个lunch命令,会列出所有的目标,直接回车,会默认使用aosp\_arm-eng这个目标。执行命令:lunch 1, 可以看到配置的一些环境变量这些环境变量的含义如下:lunch结果说明PLATFORM_VERSION_CODENAME=REL表示平台版本的名称PLATFORM_VERSION=10Android平台的版本号TARGET_PRODUCT=aosp_arm所编译的产品名称TARGET_BUILD_VARIANT=userdebug所编译产品的类型TARGET_BUILD_TYPE=release编译的类型,debug和releaseTARGET_ARCH=arm表示编译目标的CPU架构TARGET_ARCH_VARIANT=armv7-a-neon表示编译目标的CPU架构版本TARGET_CPU_VARIANT=generic表示编译目标的CPU代号HOST_ARCH=x86_64表示编译平台的架构HOST_2ND_ARCH=x86表示编译平台的第二CPU架构HOST_OS=linux表示编译平台的操作系统HOST_OS_EXTRA=Linux-4.15.0-112-generic-x86_64-Ubuntu-16.04.6-LTS编译系统之外的额外信息HOST_CROSS_OS=windows HOST_CROSS_ARCH=x86 HOST_CROSS_2ND_ARCH=x86_64 HOST_BUILD_TYPE=release编译类型BUILD_ID=QQ1D.200205.002BUILD_ID会出现在版本信息中,可以利用OUT_DIR=out编译结果输出的路径4. Make说明执行完lunch命令后,就可以使用make命令来执行编译Build。Android10.0上是通过soong执行编译构建,这里执行make命令时,main.mk文件把一些环境变量和目标都配置好后,会执行envsetup.sh中的make()进行编译。如果找到“build/soong/soong_ui.bash”,就使用soong_ui.bash 来进行编译,否则使用原始的make命令进行编译。function make() { _wrap_build $(get_make_command "$@") "$@" } function get_make_command() { # If we're in the top of an Android tree, use soong_ui.bash instead of make if [ -f build/soong/soong_ui.bash ]; then # Always use the real make if -C is passed in for arg in "$@"; do if [[ $arg == -C* ]]; then echo command make return fi done echo build/soong/soong_ui.bash --make-mode else echo command make fi }配置一些资源环境,得到一些函数命令,例如:soong_build_go,最终回退到根目录,执行out/soong_ui --make-mode进行真正的构建soong_build_go soong_ui android/soong/cmd/soong_ui 是通过编译android/soong/cmd/soong_ui/main.go来编译生成soong_ui。[build/soong/soong_ui.bash] # Save the current PWD for use in soong_ui export ORIGINAL_PWD=${PWD} export TOP=$(gettop) source ${TOP}/build/soong/scripts/microfactory.bash soong_build_go soong_ui android/soong/cmd/soong_ui cd ${TOP} exec "$(getoutdir)/soong_ui" "$@" “echo build/soong/soong_ui.bash --make-mode ”最终会执行 exec out/soong_ui --make-mode 进行编译soong的编译过程如下图所示:执行runKatiBuild时,有个重要的步骤,就是加载build/make/core/main.mk,main.mk文件是Android Build系统的主控文件。从main.mk开始,将通过include命令将其所有需要的.mk文件包含进来,最终在内存中形成一个包括所有编译脚本的集合,这个相当于一个巨大Makefile文件。Makefile文件看上去很庞大,其实主要由三种内容构成: 变量定义、函数定义和目标依赖规则,此外mk文件之间的包含也很重要。main.mk的包含关系如下图所示:一些关键的mk文件说明:文件说明build/make/core/main.mkBuild的主控文件,主要作用是包含其他mk,以及定义几个最重要的编译目标,同时检查编译工具的版本,例如如gcc、clang、java等build/make/core/config.mkBuild的配置文件,主要是区分各个产品的配置,并将这些编译器参数引入产品配置 BoardConfig.mk,同时也配置了一些编译器的路径等build/make/core/clang/config.mkclang编译的配置文件build/make/core/definitions.mk最重要的 Make 文件之一,在其中定义了大量的函数。这些函数都是 Build 系统的其他文件将用到的。例如:my-dir,all-subdir-makefiles,find-subdir-files,sign-package 等,关于这些函数的说明请参见每个函数的代码注释。build/make/core/dex_preopt.mk定义了dex优化相关的路径和参数build/make/core/pdk_config.mk编译pdk的配置文件build/make/core/Makefile系统最终编译完成所需要的各种目标和规则build/make/core/envsetup.mk包含进product_config.mk文件并且根据其内容设置编译产品所需要的环境变量,并检查合法性,指定输出路径等build/make/core/combo/select.mk根据当前编译器的平台选择平台相关的 Make 文件build/make/core/ninja_config.mk解析makefile的的列表,传给kati,配置传给ninja和kati的目标build/make/core/soong_config.mk配置soong的环境变量,建立go变量和mk变量的json映射关系,让go变量可以获取到mk中定义的变量值5. 编译工具链说明Android10.0的编译系统中,涉及以下一些工具链,由这些工具链相辅相成,才最终编译出了我们所需要的镜像版本。Android10.0编译工具链:soong\kati\blueprint\ninja 5.1 Soong说明Soong 构建系统是在 Android 7.0 (Nougat) 中引入的,旨在取代 Make。它利用 Kati GNU Make 克隆工具和 Ninja 构建系统组件来加速 Android 的构建。Soong是由Go语言写的一个项目,从Android 7.0开始,在prebuilts/go/目录下新增了Go语言所需的运行环境,Soong在编译时使用,解析Android.bp,将之转化为Ninja文件,完成Android的选择编译,解析配置工作等。故Soong相当于Makefile编译系统的核心,即build/make/core下面的内容。另外Soong还会编译产生一个androidmk命令,可以用来手动将Android.mk转换成Android.bp文件。不过这只对无选择、循环等复杂流程控制的Android.mk生效。soong脚本和代码目录:/build/soong5.2 kati说明kati是一个基于Makefile来生成ninja.build的小项目。主要用于把Makefiel转成成ninja file,自身没有编译能力,转换后使用Ninja编译。在编译过程中,kati负责把既有的Makefile、Android.mk文件,转换成Ninja文件。在Android 8.0以后,它与Soong一起,成为Ninja文件的两大来源。Kati更像是Google过渡使用的一个工具,等所有Android.mk都被替换成Android.bp之后,Kati有可能退出Android编译过程.在单独使用时,它对普通的小项目还能勉强生效。面对复杂的、多嵌套的Makefile时,它往往无法支持,会出现各种各样的问题。当然,也可以理解为,它只为Android而设计。kati脚本和代码目录:/build/kati5.3 blueprint说明Blueprint由Go语言编写,是生成、解析Android.bp的工具,是Soong的一部分。Soong则是专为Android编译而设计的工具,Blueprint只是解析文件的形式,而Soong则解释内容的含义。在Android编译最开始的准备阶段,会执行build/soong/soong_ui.bash进行环境准备。 对blueprint项目编译完成之后会在out/soong/host/linux-x86/bin目录下生成soong编译需要的5个执行文件(bpfix,bpfmt,bpmodify,microfatory,bpmodify)。Soong是与Android强关联的一个项目,而Blueprint则相对比较独立,可以单独编译、使用。blueprint代码目录:/build/blueprint5.4 ninja说明最开始,Ninja 是用于Chromium 浏览器中,Android 在SDK 7.0 中也引入了Ninja。Ninja是一个致力于速度的小型编译系统(类似于Make),如果把其他编译系统比做高级语言的话,Ninja就是汇编语言。通常使用Kati或soong把makefile转换成Ninja files,然后用Ninja编译。主要两个特点:1)可以通过其他高级的编译系统生成其输入文件;2)它的设计就是为了更快的编译;ninja核心是由C/C++编写的,同时有一部分辅助功能由python和shell实现。由于其开源性,所以可以利用ninja的开源代码进行各种个性化的编译定制。从Android 7开始,编译时默认使用Ninja。但是,Android项目里是没有.ninja文件的。遵循Ninja的设计哲学,编译时,会先把Makefile通过kati转换成.ninja文件,然后使用ninja命令进行编译。这些.ninja文件,都产生在out/目录下,共有三类:第一类是build-*.ninja文件,通常非常大,几十到几百MB。对make全编译,命名是build-<product_name>.ninja。如果Makefile发生修改,需要重新产生Ninja文件。mm、mma的Ninja文件,命名是build-<product_name>-<path_to_Android.mk>.ninja。而mmm、mmma的Ninja文件,命名是build-<product_name>-_<path_to_Android.mk>.ninja。第二类是combined-*.ninja文件。在使用了Soong后,除了build-*.ninja之外,还会产生对应的combined-*.ninja,二者的*内容相同。这类是组合文件,是把build-*.ninja和out/soong/build.ninja组合起来。所以,使用Soong后,combined-*.ninja是编译执行的真正入口。第三类是out/soong/build.ninja文件,它是从所有的Android.bp转换过来的。build-*.ninja是从所有的Makefile,用Kati转换过来的,包括build/core/*.mk和所有的Android.mk。所以,在不使用Soong时,它是唯一入口。在使用了Soong以后,会新增源于Android.bp的out/soong/build.ninja,所以需要combined-*.ninja来组合一下。6. 工具链Android.mk文件、Android.bp、kati、Soong、Blueprint、Ninja之间的关系如下:Android.bp --> Blueprint --> Soong --> Ninja Makefile or Android.mk --> kati --> Ninja (Android.mk --> Soong --> Blueprint --> Android.bp)Blueprint是生成、解析Android.bp的工具,是Soong的一部分。Soong则是专为Android编译而设计的工具,Blueprint只是解析文件的形式,而Soong则解释内容的含义。 Android.mk可以通过Soong提供的androidmk转换成Android.bp,但仅限简单配置。目前Oreo的编译流程中,仍然是使用kati来做的转换。 现存的Android.mk文件、既有的Android.bp,都会分别被转换成Ninja。从Android.mk与其它Makefile,会生成out/build-<product_name>.ninja文件。而从Android.bp,则会生成out/soong/build.ninja。此外,还会生成一个较小的out/combined-<product_name>.ninja文件,负责把二者组合起来,作为执行入口。最终,Ninja文件才是真正直接控制源码编译的工具。7. 总结Android10.0中,mk文件通过kati\ckati编译生成 build-aosp_arm.ninja, bp文件通过blueprint-soong解析编译生成为build.ninja ,这些ninja文件会合并成combined-aosp_arm.ninja,最终通过ninja工具进行最终的编译。随着Google的不停演进,make的编译会最终退出历史舞台,kati\ckati也会退出,最终全部切到 blueprint-soong的编译。
2021年03月01日
2,637 阅读
0 评论
1 点赞
2021-02-04
Android init.rc文件
最好直接去看Android的官方文档,那里更完整准确,system/core/init/README.md1. 文件简介Android init.rc文件由系统第一个启动的init程序解析,此文件由语句组成,主要包含了四种类型的语句:Action,Commands,Services,Options.在init.rc文件中一条语句通常是占据一行.单词之间是通过空格符来相隔的.如果需要在单词内使用空格,那么得使用转义字符”\”,如果在一行的末尾有一个反斜杠,那么是换行折叠符号,应该和下一行合并成一起来处理,这样做主要是为了避免一行的字符太长,与C语言中的含义是一致的。注释是以#号开头。 Action和services显式声明了一个语句块,而commands和options属于最近声明的语句块。在第一个语句块之前 的commands和options会被忽略.init.rc:Android在启动过程中读取的启动脚本文件,主要完成一些初级的初始化,在/system/core/init/init.cpp中解析。rc 经常被用作程序之启动脚本的文件名。它是“run commands”(运行命令)的缩写。init.xx.rc:与具体CPU相关的启动脚本,比如对于MTK的CPU,名字为init.usb.rc,init.trace.rc。在init.rc之后得到解析。厂商的rc文件一般位于device目录2.init.rc和init.xx.rc文件的修改我们以 init.rc 来入手,学习 rc 的用法。2.1 文件结构init.rc 基本单位是 section(语句块)。一个Section以Service或On开头的语句块.以Service开头的Section叫做服务,而以On开头的叫做动作(Action).services: 服务.Action: 动作commands:命令.options:选项.trigger:触发器,或者叫做触发条件.class: 类属,即可以为多个service指定一个相同的类属,方便操作同时启动或停止.section 有三种类型:onserviceimporton 类型作表示了一组命令(commands)组成.动作包含一个触发器,决定了何时执行这个动作。当触发器的条件满足时,这个动作会被加入到已被执行的队列尾。如果此动作在队列中已经存在,那么它将不会执行. 一个动作所包含的命令将被依次执行。动作的语法如下所示:on <trigger> <command> <command> ...on 类型 表示一系列的命令组合,eg:on init # See storage config details at http://source.android.com/tech/storage/ #mkdir /storage/sdcard 0555 root root #export EXTERNAL_STORAGE /storage/sdcard # Support legacy paths #symlink /storage/sdcard /sdcard #symlink /storage/sdcard /mnt/sdcard # mkdir /tmp 01775 root root # mount tmpfs tmpfs /tmp size=25m mkdir /dev/cpuctl/bg_non_interactive chown system system /dev/cpuctl/bg_non_interactive/tasks chmod 0666 /dev/cpuctl/bg_non_interactive/tasks # KSM config write /sys/kernel/mm/ksm/pages_to_scan 100 write /sys/kernel/mm/ksm/sleep_millisecs 500 write /sys/kernel/mm/ksm/run 1 write /sys/block/zram0/comp_algorithm lz4 write /sys/block/zram0/max_comp_streams 2 # Swap in only 1 page at a time write /proc/sys/vm/page-cluster 0 这样一个 section 里面包含了多个命令。命令的执行是以 section 为单位的。上面这些命令都会一起顺序执行,不会单独执行。service 类型服务是指那些需要在系统初始化时就启动或退出时自动重启的程序.它的语法结构如下所示:service <name> <pathname> [<argument>]* <option> <option> ...service 类型 的section 表示一个可执行的程序,下面是个人工作内容中片段代码:service submcu_srv /vendor/bin/submcu_srv class core user root group root oneshotsubmcu_srv作为一个名字标识了这个 service,这个可执行程序的位置在 /vendor/bin/submcu_srv下面的oneshot 被称为 options,options 是用来描述的 service 的特点,不同的 service 有不同的 options。service 的执行总存在于某个 on 类型的section 中作为一个服务启动的动作(Action)。例如,这个submcu_srv可以在on fs中启动on fs export OMX_BELLAGIO_REGISTRY /vendor/etc/omxregister start submcu_srv例二:service yo_service1 /system/bin/yo_service1 class core user system disabled group system radio shell oneshot on yo_fs class_start core 其中 yo_service1 这个 service 的类型是 core。在 yo_fs 被调用的时候则将会 class_start 而执行所有类型为 core 的 service。options(选项)选项是用来修饰服务的。它们影响如何及何时运行这个服务.trigger(触发器)触发器用来描述一个触发条件,当这个触发条件满足时可以执行动作。commands(命令)propertiesinit程序在运行时会更新属性系统的一些属性,提供程序内部正在执行的信息.import类型import 类型表示包含了另外一些 section,在解析完 init.rc 后会继续调用 init_parse_config_file 来解析引入的 .rc 文件。(最新的android11不一定是这个函数了)eg:比如我们在 init.sc8830.rc 的开始可以看到import /init.usb.rc import /init.trace.rc表示在运行完本 rc 后还将继续运行 init.usb.rc 和 init.trace.rc。2.2 调试注意事项在默认情况下,通过init程序启动的程序的标准输出stdout和标准错误输出stderr会重定向到/dev/null.如:service akmd /system/bin/logwrapper /sbin/akmd为了更方便调试你的程序,你可以使用Android的log系统,标准输出和标准错误输出会重定义到Android的log系统中来.参考文献:init.rc介绍
2021年02月04日
1,224 阅读
0 评论
0 点赞
2021-02-04
Android.bp简介
转载自Android.bp 语法浅析-Android10.0编译系统1.概述在 Android 7.0 之前,Android 编译系统使用 GNU Make 描述和shell来构建编译规则,模块定义都使用Android.mk进行定义,Android.mk的本质就是Makefile,但是随着Android的工程越来越大,模块越来越多,Makefile组织的项目编译时间越来越长。这样下去Google工程师觉得不行,得要优化。因此,在Android7.0开始,Google采用ninja来代取代之前使用的make,由于之前的Android.mk数据实在巨大,因此Google加入了一个kati工具,用于将Android.mk转换成ninja的构建规则文件buildxxx.ninja,再使用ninja来进行构建工作。ninja的网址:https://ninja-build.org编译速度快了一些,但是既然要干, 那就干个大的,最终目标要把make都取代,于是从Android8.0开始,Google为了进一步淘汰Makefile,因此引入了Android.bp文件来替换之前的Android.mk。 Android系统的编译历程: 2.Android.bp文件格式根据设计,Android.bp 文件很简单。它们不包含任何条件语句,也不包含控制流语句;所有复杂问题都由用 Go 编写的构建逻辑处理。Android.bp 文件的语法和语义都尽可能与 Bazel BUILD 文件类似。2.1 模块Android.bp 文件中的模块以模块类型开头,后跟一组 name: "value", 格式的属性:cc_binary { name: "gzip", srcs: ["src/test/minigzip.c"], shared_libs: ["libz"], stl: "none", }每个模块都必须具有 name 属性,并且相应值在所有 name 文件中必须是唯一的,仅有两个例外情况是命名空间和预构建模块中的 Android.bp 属性值,这两个值可能会重复。srcs 属性以字符串列表的形式指定用于构建模块的源文件。您可以使用模块引用语法 ":<module-name>" 来引用生成源文件的其他模块的输出,如 genrule 或 filegroup。如需有效模块类型及其属性的列表,请参阅 Soong 模块参考:https://www.cnblogs.com/linhaostudy/p/12361659.html常用模块类型:cc_binarycc_librarycc_library_staticandroid_appjava_libraryhidl_interfaceaidl_interface2.2 类型变量和属性是强类型,变量根据第一项赋值动态变化,属性由模块类型静态设置。支持的类型为:布尔值Bool(true 或 false)整数Integers (int)字符串Strings ("string")字符串列表List of string (["string1", "string2"])映射Maps ({key1: "value1", key2: ["value2"]})映射可以包含任何类型的值,包括嵌套映射。列表和映射可能在最后一个值后面有终止逗号。2.3 Glob接受文件列表的属性(例如 srcs)也可以采用 glob 模式。glob 模式可以包含普通的 UNIX 通配符 *,例如 *.java。glob 模式还可以包含单个 ** 通配符作为路径元素,与零个或多个路径元素匹配。例如,java/**/*.java 同时匹配 java/Main.java 和 java/com/android/Main.java 模式。2.4 变量Android.bp 文件可能包含顶级变量赋值:gzip_srcs = ["src/test/minigzip.c"] cc_binary { srcs: gzip_srcs, shared_libs: ["libz"], stl: "none", }变量的作用域限定在声明它们的文件的其余部分,以及所有子 Android.bp文件,可以使用 “=” 号赋值, 但是不能使用 “:=” 赋值。变量是不可变的,但有一个例外情况:可以使用 += 赋值将变量附加到别处,但只能在引用它们之前附加。例:gzip_srcs = ["src/test/minigzip.c"] gzip_srcs += [ "src/test/test.cpp", ] cc_binary { srcs: gzip_srcs, shared_libs: ["libz"], stl: "none", }2.5 注释Android.bp 文件可以包含 C 样式的多行 / / 注释以及 C++ 样式的单行 // 注释。2.6 运算符可以使用 + 运算符附加字符串、字符串列表和映射。可以使用 + 运算符对整数求和。附加映射会生成两个映射中键的并集,并附加在两个映射中都存在的所有键的值。2.7 条件语句Soong 不支持 Android.bp 文件中的条件语句。但是,编译规则中需要条件语句的复杂问题将在 Go(在这种语言中,您可以使用高级语言功能,并且可以跟踪条件语句引入的隐式依赖项)中处理。大多数条件语句都会转换为映射属性,其中选择了映射中的某个值并将其附加到顶级属性。例如,要支持特定于架构的文件,请使用以下命令:cc_library { ... srcs: ["generic.cpp"], arch: { arm: { srcs: ["arm.cpp"], }, x86: { srcs: ["x86.cpp"], }, }, }2.8 格式设置语句Soong 包含一个针对 Blueprint 文件的规范格式设置工具,类似于 gofmt。如需以递归方式重新设置当前目录中所有 Android.bp 文件的格式,请运行以下命令:bpfmt -w .规范格式包括缩进四个空格、多元素列表的每个元素后面有换行符,以及列表和映射末尾有英文逗号。2.9 默认模块默认模块可用于在多个模块中重复使用相同的属性。例如:cc_defaults { name: "gzip_defaults", shared_libs: ["libz"], stl: "none", } cc_binary { name: "gzip", defaults: ["gzip_defaults"], srcs: ["src/test/minigzip.c"], }2.10 预编译的模块某些预构建的模块类型允许模块与其基于源代码的对应模块具有相同的名称。例如,如果已有同名的 cc_binary,也可以将 cc_prebuilt_binary 命名为 foo。这让开发者可以灵活地选择要纳入其最终产品中的版本。如果编译配置包含两个版本,则预编译模块定义中的 prefer 标记值会指示哪个版本具有优先级。请注意,某些预编译模块的名称不能以 prebuilt开头,例如 android_app_import。2.11 命名空间模块在 Android 完全从 Make 转换为 Soong 之前,Make 产品配置必须指定 PRODUCT_SOONG_NAMESPACES 值。它的值应该是一个以空格分隔的列表,其中包含 Soong 导出到 Make 以使用 m 命令进行编译的命名空间。在 Android 完成到 Soong 的转换之后,启用命名空间的详细信息可能会发生变化。Soong 可以让不同目录中的模块指定相同的名称,只要每个模块都在单独的命名空间中声明即可。可以按如下方式声明命名空间:soong_namespace { imports: ["path/to/otherNamespace1", "path/to/otherNamespace2"], }请注意,命名空间没有 name 属性;其路径会自动指定为其名称。系统会根据每个 Soong 模块在树中的位置为其分配命名空间。每个 Soong 模块都会被视为处于 Android.bp(位于当前目录或最近的父级目录中的 soong_namespace 文件内)定义的命名空间中。如果未找到此类 soong_namespace 模块,则认为该模块位于隐式根命名空间中。下面是一个示例:Soong尝试解析由模块 M 在名称空间 N(导入命名空间 I1、I2、I3…)中声明的依赖项D。如果 D 是 //namespace:module 格式的完全限定名称,系统将仅在指定的命名空间中搜索指定的模块名称。否则,Soong 将首先查找在命名空间 N 中声明的名为 D 的模块。如果该模块不存在,Soong 会在命名空间 I1、I2、I3…中查找名为 D 的模块。最后,Soong 在根命名空间中查找。2.12 Android.mk文件 自动转Android.bp方法Android源码里边提供了快捷直接Android.mk转换成Android.bp的工具:androidmk。androidmk源码位置: build/soong/androidmk/cmd/androidmk/androidmk.go编译出来后androidmk可执行文件位置:aosp/out/soong/host/linux-x86/bin/androidmk转换方法:aosp/out/soong/host/linux-x86/bin/androidmk [Android.mk PATH] > [Android.bp PATH]该工具可以转换变量、模块、注释和一些条件,但任何自定义生成文件规则、复杂条件或额外的包含都必须手动转换。
2021年02月04日
1,744 阅读
0 评论
0 点赞
1
...
4
5
6