Android源码编译之lunch流程分析

通过之前介绍的source导入编译源码的相关配置,下面就进入了lunch操作。用户通过source build/envsetup.sh命令后,系统初始化相关变量环境工作,脚本提供一个lunch函数,让用户选择自己想要编译的版本分支,下面我们就来具体分析一下。

lunch选择合适的编译版本

在source流程之后,紧接着就是执行lunch操作,lunch操作执行的其实就是build/envsetup.sh脚本中的lunch函数,下面看看lunch函数如何执行。由于lunch代码众多,这里就不总的例举,下面分模块进行具体分析。

lunch参数处理

读取lunch参数

获取用户编译目标到answer变量,如果用户没有输入参数,调用print_lunch_menu打印可选编译项,提示用户继续输入

local answer

if [ "$1" ] ; then
    # lunch后面直接带参数
    answer=$1
else
    # lunch后面不带参数,则打印处所有的target product和variant菜单提供用户选择
    print_lunch_menu
    echo -n "Which would you like? [aosp_arm-eng] "
    read answer
fi

打印函数print_lunch_menu如下:

#该函数负责打印已经定义的版本
function print_lunch_menu()
{
    local uname=$(uname)
    echo
    echo "You're building on" $uname
    echo
    echo "Lunch menu... pick a combo:"

    local i=1
    local choice
    for choice in ${LUNCH_MENU_CHOICES[@]}
    do
        echo "     $i. $choice"
        # i自增1
        i=$(($i+1))
    done

    echo
}
根据参数,判断选择对应的编译版本
如果判断answer值是否为空,空即默认值缺省值aosp_arm-eng。之后对answer进行异常判断,因为用户输入多样性,需要适当的过滤。

    local selection=

    if [ -z "$answer" ]
    then
        # 如果用户在菜单中没有选择,直接回车,则为系统缺省的aosp_arm-eng
        selection=aosp_arm-eng
    # 不换行输出answer值,静默指定字符匹配开头数字两位内容
    elif (echo -n $answer | grep -q -e "^[0-9][0-9]*$")
    then
        # 如果answer是选择菜单的数字,则获取该数字对应的字符串
        if [ $answer -le ${#LUNCH_MENU_CHOICES[@]} ]
        then
            selection=${LUNCH_MENU_CHOICES[$(($answer-1))]}
        fi
    # 如果 answer字符串匹配 *-*模式(*的开头不能为-)
    elif (echo -n $answer | grep -q -e "^[^\-][^\-]*-[^\-][^\-]*$")
    then
        selection=$answer
    fi

    if [ -z "$selection" ]
    then
        echo
        echo "Invalid lunch combo: $answer"
        return 1
    fi

筛选过程总结如下:

  1. 输入为空,静默值aosp_arm-eng

  2. 输入数字,取出数字前两位

  3. 输入数字前两位小于编译版本可选项,选定指定数字的编译版本(可选项存在数组,下标为0,需要answer-1)

  4. 输入字符串,进行匹配过滤。字符串使用”-”连接,而且”-”连接的前后两个子串中都没有”-”,则认为是板型名称字符串,直接赋给selection

经过筛选,selection值还是空,直接报错。

分离selection中参数product

将 product-variant模式中的product分离出来,类似从字符串”aosp_arm-eng”中取出”aosp_arm”,具体如下:

export TARGET_BUILD_APPS=

# 将 product-variant模式中的product分离出来
local product=$(echo -n $selection | sed -e "s/-.*$//")

# 检查product,调用关系 check_product()->get_build_var()->build/core/config.mk
check_product $product
if [ $? -ne 0 ]
then
    echo
    echo "** Don't have a product spec for: '$product'"
    echo "** Do you have the right repo manifest?"
    product=
fi

代码具体流程如下:

  1. echo -n $selection | sed -e “s/-.*$//“

    不换行取出用户输入的selection,使用sed -e “s/-.$//“过滤掉selection字符串中”-**“的部分后,例如从”aosp_arm-eng”过滤”-eng”得到”aosp_arm”,赋值到product中

2.调用check_product,传入product赋值到TARGET_PRODUCT,之后流程如下:

# 检查指定的TARGET_PRODUCT是否允许,默认的有sim和generic。如果不允许,则输出错误信息,允许则不显示
function check_product()
{
    T=$(gettop)
    if [ ! "$T" ]; then
        echo "Couldn't locate the top of the tree.  Try setting TOP." >&2
        return
    fi
        TARGET_PRODUCT=$1 \
        TARGET_BUILD_VARIANT= \
        TARGET_BUILD_TYPE= \
        TARGET_BUILD_APPS= \
        get_build_var TARGET_DEVICE > /dev/null
    # hide successful answers, but allow the errors to show
}        

# 列出make脚本中某变量的值,当前为build/core/config.mk
function get_build_var()
{
    T=$(gettop)
    if [ ! "$T" ]; then
        echo "Couldn't locate the top of the tree.  Try setting TOP." >&2
        return
    fi
    (\cd $T; CALLED_FROM_SETUP=true BUILD_SYSTEM=build/core \
      command make --no-print-directory -f build/core/config.mk dumpvar-$1)
}

T=$(gettop)获取源码顶层目录,这里不做过多解释。下面是get_build_var中比较复杂的部分:

(\cd $T; CALLED_FROM_SETUP=true BUILD_SYSTEM=build/core \
              command make --no-print-directory -f build/core/config.mk dumpvar-$1)
  1. 首先进入源码根目录

  2. 设置两个静态变量 CALLED_FROM_SETUP=true BUILD_SYSTEM=build/core

  3. shell环境中command命令执行make,指定文件build/core/config.mk

  4. config.mk会include dumpvar.mk,这个文件中会提取我们传入的dumpvar-TARGET_DEVICE变量中的TARGET_DEVICE,打印TARGET_PRODUCT

总之,函数get_build_var实际上就是通过make命令在Android源代码工程根目录中执行build/core/config.mk文件,并且将make目标设置为dumpvar-$1,也就是dumpvar-TARGET_DEVICE。这里函数如果执行成功,便返回0

文件build/core/config.mk的内容比较多,这里我们只关注与产品名称合法性检查相关的逻辑,这些逻辑也基本上涵盖了Android编译系统初始化的逻辑,下面具体分析。

依赖mk文件的导入分析

相关mk文件的导入

build/core/config.mk 中 include 了众多的mk文件,这里例举其中重要的部分:

...

# Various mappings to avoid hard-coding paths all over the place
include $(BUILD_SYSTEM)/pathmap.mk

# ---------------------------------------------------------------
# Define most of the global variables.  These are the ones that
# are specific to the user's build configuration.
include $(BUILD_SYSTEM)/envsetup.mk

...

include $(BUILD_SYSTEM)/dumpvar.mk

其中比较重要的是中间的 envsetup.mk 这个文件

envsetup.mk 文件分析

envsetup.mk 文件中逻辑众多,这里我们只关注重要的两个逻辑:AndroidProduct.mk和BoardCong.mk 文件的搜集工作。代码如下:

...

# 搜集AndroidProduct.mk文件
include $(BUILD_SYSTEM)/product_config.mk

# 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.
# 搜集BoardConfig.mk文件
board_config_mk := \
    $(strip $(wildcard \
        $(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)/BoardConfig.mk \
        $(shell test -d device && find device -maxdepth 4 -path '*/$(TARGET_DEVICE)/BoardConfig.mk') \
        $(shell test -d vendor && find 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
include $(board_config_mk)
ifeq ($(TARGET_ARCH),)
  $(error TARGET_ARCH not defined by board config: $(board_config_mk))
endif
TARGET_DEVICE_DIR := $(patsubst %/,%,$(dir $(board_config_mk)))
board_config_mk :=

...
AndroidProducts.mk文件搜集及TARGET_DEVICE值的确定

envsetup.mk 文件首先会 include product_config.mk文件,这个文件中设置了相关的变量,如下:

# 步骤1
ifneq ($(strip $(TARGET_BUILD_APPS)),)
all_product_configs := $(call get-product-makefiles,\
    $(SRC_TARGET_DIR)/product/AndroidProducts.mk)
else
all_product_configs := $(get-all-product-makefiles)
endif

# 步骤2
current_product_makefile :=
all_product_makefiles :=
$(foreach f, $(all_product_configs),\
    $(eval _cpm_words := $(subst :,$(space),$(f)))\
    $(eval _cpm_word1 := $(word 1,$(_cpm_words)))\
    $(eval _cpm_word2 := $(word 2,$(_cpm_words)))\
    $(if $(_cpm_word2),\
        $(eval all_product_makefiles += $(_cpm_word2))\
        $(if $(filter $(TARGET_PRODUCT),$(_cpm_word1)),\
            $(eval current_product_makefile += $(_cpm_word2)),),\
        $(eval all_product_makefiles += $(f))\
        $(if $(filter $(TARGET_PRODUCT),$(basename $(notdir $(f)))),\
            $(eval current_product_makefile += $(f)),)))
_cpm_words :=
_cpm_word1 :=
_cpm_word2 :=
current_product_makefile := $(strip $(current_product_makefile))
all_product_makefiles := $(strip $(all_product_makefiles))

# 步骤3
ifneq (,$(filter product-graph dump-products, $(MAKECMDGOALS)))
$(call import-products, $(all_product_makefiles))
else
ifndef current_product_makefile
$(error Can not locate config makefile for product "$(TARGET_PRODUCT)")
endif
ifneq (1,$(words $(current_product_makefile)))
$(error Product "$(TARGET_PRODUCT)" ambiguous: matches $(current_product_makefile))
endif
$(call import-products, $(current_product_makefile))
endif  # Import all or just the current product makefile

$(check-all-products)

ifneq ($(filter dump-products, $(MAKECMDGOALS)),)
$(dump-products)
$(error done)
endif

# 步骤4
INTERNAL_PRODUCT := $(call resolve-short-product-name, $(TARGET_PRODUCT))
ifneq ($(current_product_makefile),$(INTERNAL_PRODUCT))
$(error PRODUCT_NAME inconsistent in $(current_product_makefile) and $(INTERNAL_PRODUCT))
endif
current_product_makefile :=
all_product_makefiles :=
all_product_configs :=

# 步骤5
PRODUCT_BOOT_JARS := $(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_BOOT_JARS))
PRODUCT_SYSTEM_SERVER_JARS := $(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SYSTEM_SERVER_JARS))

TARGET_DEVICE := $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_DEVICE)
  1. 检查环境变量TARGET_BUILD_APPS的值是否等于空。如果不等于空,那么就说明此次编译不是针对整个系统,因此只要将核心的产品相关的Makefile文件加载进来就行了,否则的话,就要将所有与产品相关的Makefile文件加载进来的。核心产品Makefile文件在$(SRC_TARGET_DIR)/product/AndroidProducts.mk文件中指定,也就是在build/target/product/AndroidProducts.mk文件,通过调用函数get-product-makefiles可以获得。所有与产品相关的Makefile文件可以通过另外一个函数get-all-product-makefiles获得。无论如何,最终获得的产品Makefie文件列表保存在变量all_product_configs中。

  2. 遍历变量all_product_configs所描述的产品Makefile列表,并且在这些Makefile文件中,找到名称与环境变量TARGET_PRODUCT的值相同的文件,保存在另外一个变量current_product_makefile中,作为需要为当前指定的产品所加载的Makefile文件列表。在这个过程当中,上一步找到的所有的产品Makefile文件也会保存在变量all_product_makefiles中。注意,环境变量TARGET_PRODUCT的值是在我们执行lunch命令的时候设置并且传递进来的。

  3. 如果指定的make目标等于product-graph或者dump-products,那么就将所有的产品相关的Makefile文件加载进来,否则的话,只加载与目标产品相关的Makefile文件。从前面的分析可以知道,此时的make目标为dumpvar-TARGET_DEVICE,因此接下来只会加载与目标产品,即$(TARGET_PRODUCT),相关的Makefile文件,这是通过调用另外一个函数import-products实现的。

  4. 调用函数resolve-short-product-name解析环境变量TARGET_PRODUCT的值,将它变成一个Makefile文件路径。并且保存在变量INTERNAL_PRODUCT中。这里要求变量INTERNAL_PRODUCT和current_product_makefile的值相等,否则的话,就说明用户指定了一个非法的产品名称。

  5. 找到一个名称为PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_DEVICE的变量,并且将它的值保存另外一个变量TARGET_DEVICE中。变量PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_DEVICE是在加载产品Makefile文件的过程中定义的,用来描述当前指定的产品的名称

上述过程主要涉及到了get-all-product-makefiles、import-products和resolve-short-product-name三个关键函数,理解它们的执行过程对理解Android编译系统的初始化过程很有帮助,接下来我们分别分析它们的实现。

查找product相关文件的mk实现

其主要方法集中在 build/core/product.mk 文件中,下面具体分析:

  1. get-all-product-makefiles的具体实现

    define get-all-product-makefiles
    $(call get-product-makefiles,$(_find-android-products-files))
    endef
    

    首先是调用函数_find-android-products-files来找到Android源代码目录中定义的所有AndroidProducts.mk文件,然后再调用函数get-product-makefiles获得在这里AndroidProducts.mk文件里面定义的产品Makefile文件。

  2. _find-android-products-files的具体实现

    define _find-android-products-files
    $(shell test -d device && find device -maxdepth 6 -name AndroidProducts.mk) \
      $(shell test -d vendor && find vendor -maxdepth 6 -name AndroidProducts.mk) \
      $(SRC_TARGET_DIR)/product/AndroidProducts.mk
    endef
    

    从这里就可以看出,Android源代码目录中定义的所有AndroidProducts.mk文件位于device、vendor或者build/target/product目录或者相应的子目录(最深是6层)中。

  3. get-product-makefiles的具体实现

    define get-product-makefiles
    $(sort \
      $(foreach f,$(1), \
        $(eval PRODUCT_MAKEFILES :=) \
        $(eval LOCAL_DIR := $(patsubst %/,%,$(dir $(f)))) \
        $(eval include $(f)) \
        $(PRODUCT_MAKEFILES) \
       ) \
      $(eval PRODUCT_MAKEFILES :=) \
      $(eval LOCAL_DIR :=) \
     )
    endef
    

    这个函数实际上就是遍历参数$1所描述的AndroidProucts.mk文件列表,并且将定义在这些AndroidProucts.mk文件中的变量PRODUCT_MAKEFILES的值提取出来,形成一个列表返回给调用者。

    例如:在build/target/product/AndroidProducts.mk文件中,变量PRODUCT_MAKEFILES的值如下所示:

    ifneq ($(TARGET_BUILD_APPS),)
    PRODUCT_MAKEFILES := \
        $(LOCAL_DIR)/aosp_arm.mk \
        $(LOCAL_DIR)/full.mk \
        ...
        $(LOCAL_DIR)/aosp_mips64.mk \
        $(LOCAL_DIR)/aosp_x86_64.mk
    else
    PRODUCT_MAKEFILES := \
        $(LOCAL_DIR)/core.mk \
        $(LOCAL_DIR)/generic.mk \
        $(LOCAL_DIR)/generic_x86.mk \
        ...
    endif
    

    这里列出的每一个文件都对应于一个产品

  4. import-products的具体实现

    define import-products
    $(call import-nodes,PRODUCTS,$(1),$(_product_var_list))
    endef
    

    它调用另外一个函数import-nodes来加载由参数$1所指定的产品Makefile文件,并且指定了另外两个参数PRODUCTS和$(_product_var_list)。其中,变量_product_var_list也是定义在文件build/core/product.mk中,它的值如下所示:

    _product_var_list := \
        PRODUCT_NAME \
        PRODUCT_MODEL \
        PRODUCT_LOCALES \
        PRODUCT_AAPT_CONFIG \
        PRODUCT_AAPT_PREF_CONFIG \
        PRODUCT_AAPT_PREBUILT_DPI \
        PRODUCT_PACKAGES \
        PRODUCT_PACKAGES_DEBUG \
        PRODUCT_PACKAGES_ENG \
        PRODUCT_PACKAGES_TESTS \
        PRODUCT_DEVICE \
        ...
    

    它描述的是在产品Makefile文件中定义在各种变量。import-nodes定义在文件build/core/node_fns.mk中,如下所示:

    #
    # $(1): output list variable name, like "PRODUCTS" or "DEVICES"
    # $(2): list of makefiles representing nodes to import
    # $(3): list of node variable names
    #
    define import-nodes
    $(if \
      $(foreach _in,$(2), \
        $(eval _node_import_context := _nic.$(1).[[$(_in)]]) \
        $(if $(_include_stack),$(eval $(error ASSERTION FAILED: _include_stack \
                    should be empty here: $(_include_stack))),) \
        $(eval _include_stack := ) \
        $(call _import-nodes-inner,$(_node_import_context),$(_in),$(3)) \
        $(call move-var-list,$(_node_import_context).$(_in),$(1).$(_in),$(3)) \
        $(eval _node_import_context :=) \
        $(eval $(1) := $($(1)) $(_in)) \
        $(if $(_include_stack),$(eval $(error ASSERTION FAILED: _include_stack \
                    should be empty here: $(_include_stack))),) \
       ) \
    ,)
    endef
    
    1. 调用函数_import-nodes-inner将参数$2描述的每一个产品Makefile文件加载进来。

      1. 调用函数move-var-list将定义在前面所加载的产品Makefile文件里面的由参数$3指定的变量的值分别拷贝到另外一组独立的变量中。

      2. 将参数$2描述的每一个产品Makefile文件路径以空格分隔保存在参数$1所描述的变量中,也就是保存在变量PRODUCTS中。

      上述第二件事情需要进一步解释一下。由于当前加载的每一个文件都会定义相同的变量,为了区分这些变量,我们需要在这些变量前面加一些前缀。例如,假设加载了build/target/product/full.mk这个产品Makefile文件,它里面定义了以下几个变量:

      PRODUCT_NAME := full
      PRODUCT_DEVICE := generic
      PRODUCT_BRAND := Android
      PRODUCT_MODEL := Full Android on Emulator

      当调用了函数move-var-list对它进行解析后,就会得到以下的新变量:

      PRODUCTS.build/target/product/full.mk.PRODUCT_NAME := full
      PRODUCTS.build/target/product/full.mk.PRODUCT_DEVICE := generic
      PRODUCTS.build/target/product/full.mk.PRODUCT_BRAND := Android
      PRODUCTS.build/target/product/full.mk.PRODUCT_MODEL := Full Android on Emulator

      正是由于调用了函数move-var-list,我们在build/core/product_config.mk文件中可以通过PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_DEVICE来设置变量TARGET_DEVICE的值,这样就确定了PRODUCT_DEVICE的值。

BoardConfig.mk文件的加载过程

分析完AndroidProduct.mk文件的加载,回到build/core/config.mk文件中,接下来我们再看BoardConfig.mk文件的加载过程。

BoardConfig.mk文件加载
# 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.
# 搜集BoardConfig.mk文件
board_config_mk := \
    $(strip $(wildcard \
        $(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)/BoardConfig.mk \
        $(shell test -d device && find device -maxdepth 4 -path '*/$(TARGET_DEVICE)/BoardConfig.mk') \
        $(shell test -d vendor && find 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
include $(board_config_mk)
ifeq ($(TARGET_ARCH),)
  $(error TARGET_ARCH not defined by board config: $(board_config_mk))
endif
TARGET_DEVICE_DIR := $(patsubst %/,%,$(dir $(board_config_mk)))
board_config_mk :=

其中注释内容已经说的很明白了,board_config_mk 实现了查找BoardConfig.mk文件的具体方法。对应的文件的路径存在两个路径下:(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)和vendor/*/$(TARGET_DEVICE)。

  1. strip $(wildcard \

    $(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)/BoardConfig.mk \
    $(***))
    

    wildcard 表示扩展通配符,将(***)内容匹配到$(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)/BoardConfig.mk形式中去

    strip 表示去除结果中的空字符串

  2. shell test -d device && find device -maxdepth 4 -path ‘*/$(TARGET_DEVICE)/BoardConfig.mk’

    shell脚本检查device是否为文件夹,之后查找其内部深度最大4级下,用户选定的编译版本(TARGET_DEVICE)目录下是否存在BoardConfig.mk文件。

BoardConfig.mk文件的位置主要就是由环境变量TARGET_DEVICE来确定,它是用来描述目标产品的硬件模块信息的,例如CPU体系结构。环境变量TARGET_DEVICE用来描述目标设备,它的值是在envsetup.mk文件加载的过程中确定的。一旦目标设备确定后,就可以在$(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)、device//$(TARGET_DEVICE)和vendor//$(TARGET_DEVICE)目录中找到对应的BoradConfig.mk文件。注意,变量SRC_TARGET_DIR的值等于build/target。

小结依赖mk文件的导入

  • build/core/config.mk 通过 include 操作依赖众多相关mk文件,比较重要的有以下几个:

    build/envsetup.mk
    build/dumpvar.mk
    
  • 其中envsetup.mk包含了:

    build/product_config.mk
    build/board_config.mk
    
  • product_config.mk 中实现了product相关方法的实现,完成 AndroidProduct.mk 文件的查找和解析,确定了 TARGET_DECVICE 。其依赖的mk有:

    build/node_fns.mk
    build/product.mk
    build/device.mk
    
  • board_config.mk 中实现了 BoardConfig.mk 文件的查找,确定主板配置的相关编译信息。

继续分析lunch参数的处理

分离selection中参数variant

接着上面从selection中分离参数product后,便执行分离variant参数的操作,流程如下:

# 将 product-variant模式中的variant分离出来
local variant=$(echo -n $selection | sed -e "s/^[^\-]*-//")

# 检查之,看看是否在 (user userdebug eng) 范围内
check_variant $variant
if [ $? -ne 0 ]
then
    echo
    echo "** Invalid variant: '$variant'"
    echo "** Must be one of ${VARIANT_CHOICES[@]}"
    variant=
fi

if [ -z "$product" -o -z "$variant" ]
then
    echo
    return 1
fi

步骤分析如下:

  1. echo -n $selection | sed -e “s/^[^-]*-//“

    获取过滤字符串中最后一个不是以”-“结尾,且删除”-“之前字符串后剩下的字符串

  2. riant $variant

    function check_variant()
    {
        for v in ${VARIANT_CHOICES[@]}
        do
            if [ "$v" = "$1" ]
            then
                return 0
            fi
        done
        return 1
    }
    

    检查获取的variant值是否在可选编译项中,在则返回0,否则返回1

导出变量
export TARGET_PRODUCT=$product
export TARGET_BUILD_VARIANT=$variant
export TARGET_BUILD_TYPE=release

echo

代码执行到此处,导出三个系统全局变量TARGET_PRODUCT,TARGET_BUILD_VARIANT,TARGET_BUILD_TYPE

设置其他编译环境,打印配置信息

到这里,基本就完成了编译选项的信息采集,下面最后的工作,设置编译环境参数和打印配置信息

设置其他编译环境
set_stuff_for_environment
printconfig

set_stuff_for_environment 补充剩余环境参数

# 设置android编译需要的环境变量
function set_stuff_for_environment()
{
    settitle
    set_java_home
    setpaths
    set_sequence_number
    # MStar Android Patch Begin
    set_ota
    # MStar Android Patch End

    export ANDROID_BUILD_TOP=$(gettop)
    # With this environment variable new GCC can apply colors to warnings/errors
    export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01'
    export ASAN_OPTIONS=detect_leaks=0
}

此函数继续补充编译中的一些其他变量。其中set_java_home会检查导出JAVA_HOME这个环境变量,这个环境变量就是JDK所在的路径;setpaths函数会给PATH环境变量补充编译Android需要的一些路径;set_ota则是本源码分支(MSTAR电视系统)配置ota升级文件的相关配置

打印配置信息

调用 get_build_var函数,参数 report_config,来打印配置信息

function printconfig()
{
    T=$(gettop)
    if [ ! "$T" ]; then
        echo "Couldn't locate the top of the tree.  Try setting TOP." >&2
        return
    fi
    get_build_var report_config
}

至此,lunch流程就分析完毕了。

make正式编译系统

具体流程请待下节分析。


说明

本内容针对 MASTR定制的安卓6.0电视系统,本人能力有限,在分析过程查找了相关的资料,比较有参考价值的在下面链接中提到。

参考博客

老罗的Android之旅

坚持原创技术分享,您的支持将鼓励我继续创作!