Android编译系统过程研究
大家平时用虚拟机编译Android系统源码的时候,无非就是下面三个步骤:
<!–[if !supportLists]–>1、<!–[endif]–>执行source build/envsetup.sh命令
<!–[if !supportLists]–>2、<!–[endif]–>执行lunch命令,选择需要编译的系统版本
<!–[if !supportLists]–>3、<!–[endif]–>执行make命令,然后就是编译你选择好的系统版本
那么研究Android的编译过程,无非也就是研究这三个步骤各自做了哪些操作。
接下来,将会对这三个步骤进行详细的分析。
一、bulid/envsetup.sh脚本分析
source build/envsetup.sh这个命令就是将envsetup.sh定义的所有命令加载到环境变量中,像后面要使用的lunch、make命令就是这里定义的。打开这个脚本文件,发现里面定义了很多函数(以function为开头),下面分析一下主要函数的一些功能:
function hmm():显示帮助信息,列出所有支持的命令,比如lunch、mm、mmm等
function get_abs_build_var():获取编译时一些变量的绝对路径(比如BUILD_SYSTEM)
function get_build_var():获取编译时一些变量的路径
function check_product():检查产品是否支持编译
function check_variant():检查变量variant是否有效,只能是user、userdebug、eng
function setpaths():设置一些文件路径,并将一些编译所需的路径添加到环境变量中去
function printconfig():打印配置信息
function set_sequence_number():设置BUILD_ENV_SEQUENCE_NUMBER的值
function settitle():设置PROMPT_COMMAND的值
function set_java_home():设置java主目录
function set_stuff_for_environment():调用setpaths、settitle、set_java_home、set_sequence_number函数,并设置ANDROID_BUILD_TOP值为Android源码目录
function choosetype():选择编译类型,release和debug中的一个
function chooseproduct():用户输入编译产品
function choosevariant():用户选择variant,只能是user、userdebug、eng中的一个
function choosecombo():调用choosetype、chooseproduct、choosevariant等函数
function add_lunch_combo():增加lunch命令的选择项
function print_lunch_menu():打印lunch命令可选择的项目列表
function lunch():lunch命令的执行逻辑
function gettop():获取Android源码根目录
function m():m命令的执行逻辑
function findmakefile():查找当前目录下Android.mk文件路径
function mm():mm命令的执行逻辑
function mmm():mmm命令的执行逻辑
function croot():进入Android源码根目录
function pid():查看某个进程的id
function runtest():执行测试脚本
function godir ():进入用户输入文件的所在目录
function set_java_home():设置环境变量JAVA_HOME
除了定义了很多函数之外,还执行了下面的操作:
for f in `test -d device && find -L device -maxdepth 4 -name ‘vendorsetup.sh’ 2> /dev/null` \
`test -d vendor && find -L vendor -maxdepth 4 -name ‘vendorsetup.sh’ 2> /dev/null`
do
echo “including $f”
. $f
done
unset f
addcompletions
这里的操作就是查找vendor目录和device目录下的vendorsetup.sh文件,查找到之后就执行这些脚本文件。addcompletions函数主要是查找sdk/bash_completion目录下所有的.bash文件,找到之后执行这些文件。
1.1、执行vendorsetup.sh
vendorsetup.sh脚本都是类似“add_lunch_combo sp7731geaplus_dt-userdebug”这样的内容,也就是调用add_lunch_combo这个函数,将各自产品添加到LUNCH_MENU_CHOICES变量中去。
1.2、执行.bash脚本
这些脚本
主要是为命令提供tab支持,有了这些tab支持,输入命令后如果某个选项忘记了,只需要敲tab键,就能获得提示,使用命令更加方便
。例如
sdk/bash_completion/adb.bash
就是为
adb命令提供tab键提示功能。
二、lunch命令
接下来就分析一下lunch命令的流程,找到
envsetup.sh脚本中lunch函数:
function lunch()
{
local answer
if [ “$1” ] ; then
answer=$1
else
#如果没有输入参数,则打印出产品列表,让用户选择
print_lunch_menu
echo -n “Which would you like? [aosp_arm-eng] ”
read answer
fi
local selection=
if [ -z “$answer” ]
then
selection=aosp_arm-eng #默认产品为aosp_arm-eng
elif (echo -n $answer | grep -q -e “^[0-9][0-9]*$”)
#用户输入的是数字
then
if [ $answer -le ${#LUNCH_MENU_CHOICES[@]} ]
then
selection=${LUNCH_MENU_CHOICES[$(($answer-1))]}
fi
elif (echo -n $answer | grep -q -e “^[^\-][^\-]*-[^\-][^\-]*$”)
#用户输入的是文字
then
selection=$answer
fi
if [ -z “$selection” ]
then
echo
echo “Invalid lunch combo: $answer”
return 1
fi
export TARGET_BUILD_APPS=
#从用户的选择中提取出product
local product=$(echo -n $selection | sed -e “s/-.*$//”)
#检查产品是否支持
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
#从用户选择中提取出variant
local variant=$(echo -n $selection | sed -e “s/^[^\-]*-//”)
#检查variant是否支持
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
#设置相关环境变量的属性
export TARGET_PRODUCT=$product
export TARGET_BUILD_VARIANT=$variant
export TARGET_BUILD_TYPE=release
echo
#设置编译相关环境变量属性
set_stuff_for_environment
#打印配置信息
printconfig
}
<!–[if !supportLists]–>三、<!–[endif]–>make命令
Make命令就是去执行Android源码根目录下是Makefile脚本,脚本内容如下:
### DO NOT EDIT THIS FILE ###
include build/core/main.mk
### DO NOT EDIT THIS FILE ###
意思就是去加载并执行build/core/main.mk脚本。
接下来分析main.mk脚本的执行流程:
<!–[if !supportLists]–>1、<!–[endif]–>根据ANDROID_BUILD_SHELL的定义来选择编译系统需要的SHELL,分别为/bin/sh和/bin/bash
ifdef ANDROID_BUILD_SHELL
SHELL := $(ANDROID_BUILD_SHELL)
else
SHELL := /bin/bash
endif
<!–[if !supportLists]–>2、<!–[endif]–>检查MAKE_VERSION,必须大于或等于3.81
ifeq (,$(findstring CYGWIN,$(shell uname -sm)))
ifneq (1,$(strip $(shell expr $(MAKE_VERSION) \>= 3.81)))
endif
endif
<!–[if !supportLists]–>3、<!–[endif]–>定义一些编译时所需的变量值和默认目标droid(make命令不加任何参数就执行这个)
PWD := $(shell pwd)
TOP := .
TOPDIR :=
BUILD_SYSTEM := $(TOPDIR)build/core
BUILD_SYSTEM_VENDOR := $(TOPDIR)build/vendor
.PHONY: droid
DEFAULT_GOAL := droid
$(DEFAULT_GOAL):
<!–[if !supportLists]–>4、<!–[endif]–>加载一些其他的.mk脚本
include $(BUILD_SYSTEM)/help.mk
include $(BUILD_SYSTEM)/config.mk
include $(BUILD_SYSTEM)/cleanbuild.mk
<!–[if !supportLists]–>5、<!–[endif]–>检查java版本、jdk版本、javac版本
ifeq ($(LEGACY_USE_JAVA6),)
required_version := “1.7.x”
required_javac_version := “1.7”
java_version := $(shell echo ‘$(java_version_str)’ | grep ‘^java .*[ “]1\.7[\. “$$]’)
javac_version := $(shell echo ‘$(javac_version_str)’ | grep ‘[ “]1\.7[\. “$$]’)
else # if LEGACY_USE_JAVA6
required_version := “1.6.x”
required_javac_version := “1.6”
java_version := $(shell echo ‘$(java_version_str)’ | grep ‘^java .*[ “]1\.6[\. “$$]’)
javac_version := $(shell echo ‘$(javac_version_str)’ | grep ‘[ “]1\.6[\. “$$]’)
endif # if LEGACY_USE_JAVA6
ifeq ($(strip $(java_version)),)
$(info ************************************************************)
$(info You are attempting to build with the incorrect version)
$(info of java.)
$(info $(space))
$(info Your version is: $(java_version_str).)
$(info The required version is: $(required_version))
$(info $(space))
$(info Please follow the machine setup instructions at)
$(info $(space)$(space)$(space)$(space)https://source.android.com/source/initializing.html)
$(info ************************************************************)
$(error stop)
endif
ifeq ($(requires_openjdk), true)
ifeq ($(shell echo ‘$(java_version_str)’ | grep -i openjdk),)
$(info ************************************************************)
$(info You asked for an OpenJDK 7 build but your version is)
$(info $(java_version_str).)
$(info ************************************************************)
$(error stop)
endif # java version is not OpenJdk
else # if requires_openjdk
ifneq ($(shell echo ‘$(java_version_str)’ | grep -i openjdk),)
$(info ************************************************************)
$(info You are attempting to build with an unsupported JDK.)
$(info $(space))
$(info You use OpenJDK but only Sun/Oracle JDK is supported.)
$(info Please follow the machine setup instructions at)
$(info $(space)$(space)$(space)$(space)https://source.android.com/source/download.html)
$(info ************************************************************)
$(error stop)
endif # java version is not Sun Oracle JDK
endif # if requires_openjdk
ifeq ($(strip $(javac_version)),)
$(info ************************************************************)
$(info You are attempting to build with the incorrect version)
$(info of javac.)
$(info $(space))
$(info Your version is: $(javac_version_str).)
$(info The required version is: $(required_javac_version))
$(info $(space))
$(info Please follow the machine setup instructions at)
$(info $(space)$(space)$(space)$(space)https://source.android.com/source/download.html)
$(info ************************************************************)
$(error stop)
endif
6、加载一些.mk脚本,并确定好TARGET_BUILD_VARIANT变量的值(user/userdebug/eng)
include $(BUILD_SYSTEM)/definitions.mk
include $(BUILD_SYSTEM)/dex_preopt.mk
ifneq ($(filter user userdebug eng,$(MAKECMDGOALS)),)
$(info ***************************************************************)
$(info ***************************************************************)
$(info Do not pass ‘$(filter user userdebug eng,$(MAKECMDGOALS))’ on \
the make command line.)
$(info Set TARGET_BUILD_VARIANT in buildspec.mk, or use lunch or)
$(info choosecombo.)
$(info ***************************************************************)
$(info ***************************************************************)
$(error stopping)
endif
ifneq ($(filter-out $(INTERNAL_VALID_VARIANTS),$(TARGET_BUILD_VARIANT)),)
$(info ***************************************************************)
$(info ***************************************************************)
$(info Invalid variant: $(TARGET_BUILD_VARIANT)
$(info Valid values are: $(INTERNAL_VALID_VARIANTS)
$(info ***************************************************************)
$(info ***************************************************************)
$(error stopping)
endif
<!–[if !supportLists]–>7、<!–[endif]–>确定is_sdk_build的值(后面需要用到)
is_sdk_build :=
ifneq ($(filter sdk win_sdk sdk_addon,$(MAKECMDGOALS)),)
is_sdk_build := true
endif
<!–[if !supportLists]–>8、<!–[endif]–>根据TARGET_BUILD_VARIANT的值,设置不同的ro属性
user_variant := $(filter user userdebug,$(TARGET_BUILD_VARIANT))
enable_target_debugging := true
tags_to_install :=
ifneq (,$(user_variant))
ADDITIONAL_DEFAULT_PROPERTIES += ro.secure=1
ifeq ($(user_variant),userdebug)
tags_to_install += debug
ADDITIONAL_BUILD_PROPERTIES += dalvik.vm.lockprof.threshold=500
else
enable_target_debugging :=
endif
ifeq (,$(WITH_DEXPREOPT))
ifeq ($(DALVIK_VM_LIB),libdvm.so)
ifeq ($(user_variant),user)
ifeq ($(HOST_OS),linux)
WITH_DEXPREOPT := true
endif
endif
endif
endif
else # !user_variant
ADDITIONAL_BUILD_PROPERTIES += ro.kernel.android.checkjni=1
ADDITIONAL_DEFAULT_PROPERTIES += ro.secure=0
ADDITIONAL_DEFAULT_PROPERTIES += ro.allow.mock.location=1
endif # !user_variant
ifeq (true,$(strip $(enable_target_debugging)))
ADDITIONAL_DEFAULT_PROPERTIES += ro.debuggable=1
INCLUDE_TEST_OTA_KEYS := true
else # !enable_target_debugging
ADDITIONAL_DEFAULT_PROPERTIES += ro.debuggable=0
endif # !enable_target_debugging
ifeq ($(TARGET_BUILD_VARIANT),eng)
tags_to_install := debug eng
ifneq ($(filter ro.setupwizard.mode=ENABLED, $(call collapse-pairs, $(ADDITIONAL_BUILD_PROPERTIES))),)
# Don’t require the setup wizard on eng builds
ADDITIONAL_BUILD_PROPERTIES := $(filter-out ro.setupwizard.mode=%,\
$(call collapse-pairs, $(ADDITIONAL_BUILD_PROPERTIES))) \
ro.setupwizard.mode=OPTIONAL
endif
ifndef is_sdk_build
ADDITIONAL_BUILD_PROPERTIES += dalvik.vm.image-dex2oat-filter=verify-none
ADDITIONAL_BUILD_PROPERTIES += dalvik.vm.dex2oat-filter=interpret-only
endif
endif
9、判断是否sdk编译,如果是则检查MAKECMDGOALS的值并设置一些属性的值
ifdef is_sdk_build
sdk_repo_goal := $(strip $(filter sdk_repo,$(MAKECMDGOALS)))
MAKECMDGOALS := $(strip $(filter-out sdk_repo,$(MAKECMDGOALS)))
ifneq ($(words $(filter-out $(INTERNAL_MODIFIER_TARGETS) checkbuild emulator_tests target-files-package,$(MAKECMDGOALS))),1)
$(error The ‘sdk’ target may not be specified with any other targets)
endif
tags_to_install := debug eng
ADDITIONAL_BUILD_PROPERTIES += xmpp.auto-presence=true
ADDITIONAL_BUILD_PROPERTIES += ro.config.nocheckin=yes
else # !sdk
endif
<!–[if !supportLists]–>10、<!–[endif]–>判断PRODUCT_TAGS的值,然后设置虚拟机的一些参数
ifneq ($(filter dalvik.gc.type-precise,$(PRODUCT_TAGS)),)
ADDITIONAL_BUILD_PROPERTIES += dalvik.vm.dexopt-flags=m=y
endif
ADDITIONAL_BUILD_PROPERTIES += net.bt.name=Android
ADDITIONAL_BUILD_PROPERTIES += dalvik.vm.stack-trace-file=/data/anr/traces.txt
11、通过findleaves.py工具查找subdir下所有的mk文件
subdir_makefiles := \
$(shell build/tools/findleaves.py –prune=$(OUT_DIR) –prune=.repo –prune=.git $(subdirs) Android.mk)
$(foreach mk, $(subdir_makefiles), $(info including $(mk) …)$(eval include $(mk)))
<!–[if !supportLists]–>12、<!–[endif]–>加载一些.mk文件
include $(BUILD_SYSTEM)/post_clean.mk
ifeq ($(stash_product_vars),true)
$(call assert-product-vars, __STASHED)
endif
include $(BUILD_SYSTEM)/legacy_prebuilts.mk
ifneq ($(filter-out $(GRANDFATHERED_ALL_PREBUILT),$(strip $(notdir $(ALL_PREBUILT)))),)
$(warning *** Some files have been added to ALL_PREBUILT.)
$(warning *)
$(warning * ALL_PREBUILT is a deprecated mechanism that)
$(warning * should not be used for new files.)
$(warning * As an alternative, use PRODUCT_COPY_FILES in)
$(warning * the appropriate product definition.)
$(warning * build/target/product/core.mk is the product)
$(warning * definition used in all products.)
$(warning *)
$(foreach bad_prebuilt,$(filter-out $(GRANDFATHERED_ALL_PREBUILT),$(strip $(notdir $(ALL_PREBUILT)))),$(warning * unexpected $(bad_prebuilt) in ALL_PREBUILT))
$(warning *)
$(error ALL_PREBUILT contains unexpected files)
endif
<!–[if !supportLists]–>13、<!–[endif]–>处理编译依赖,包含32位/64位系统的编译
define get-32-bit-modules
$(strip $(foreach m,$(1),\
$(if $(ALL_MODULES.$(m)$(TARGET_2ND_ARCH_MODULE_SUFFIX).CLASS),\
$(m)$(TARGET_2ND_ARCH_MODULE_SUFFIX))))
endef
define get-32-bit-modules-if-we-can
$(strip $(foreach m,$(1),\
$(if $(ALL_MODULES.$(m)$(TARGET_2ND_ARCH_MODULE_SUFFIX).CLASS),\
$(m)$(TARGET_2ND_ARCH_MODULE_SUFFIX),
$(m))))
endef
$(foreach m,$(ALL_MODULES),\
$(eval r := $(ALL_MODULES.$(m).REQUIRED))\
$(if $(r),\
$(if $(ALL_MODULES.$(m).FOR_2ND_ARCH),\
$(eval r_r := $(call get-32-bit-modules-if-we-can,$(r))),\
$(if $(filter EXECUTABLES SHARED_LIBRARIES,$(ALL_MODULES.$(m).CLASS)),\
$(eval r_r := $(r)),\
$(eval r_r := $(r) $(call get-32-bit-modules,$(r)))\
)\
)\
$(eval ALL_MODULES.$(m).REQUIRED := $(strip $(r_r)))\
)\
)
r_r :=
define add-required-deps
$(1): | $(2)
endef
14、根据FULL_BUILD的值,确定product_FILES和product_MODULES的值
ifdef FULL_BUILD
product_MODULES := $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_PACKAGES)
# Filter out the overridden packages before doing expansion
product_MODULES := $(filter-out $(foreach p, $(product_MODULES), \
$(PACKAGES.$(p).OVERRIDES)), $(product_MODULES))
# Resolve the :32 :64 module name
modules_32 := $(patsubst %:32,%,$(filter %:32, $(product_MODULES)))
modules_64 := $(patsubst %:64,%,$(filter %:64, $(product_MODULES)))
modules_rest := $(filter-out %:32 %:64,$(product_MODULES))
# Note for 32-bit product, $(modules_32) and $(modules_64) will be
# added as their original module names.
product_MODULES := $(call get-32-bit-modules-if-we-can, $(modules_32))
product_MODULES += $(modules_64)
# For the rest we add both
product_MODULES += $(call get-32-bit-modules, $(modules_rest))
product_MODULES += $(modules_rest)
$(call expand-required-modules,product_MODULES,$(product_MODULES))
product_FILES := $(call module-installed-files, $(product_MODULES))
ifeq (0,1)
$(info product_FILES for $(TARGET_DEVICE) ($(INTERNAL_PRODUCT)):)
$(foreach p,$(product_FILES),$(info : $(p)))
$(error done)
endif
else
# We’re not doing a full build, and are probably only including
# a subset of the module makefiles. Don’t try to build any modules
# requested by the product, because we probably won’t have rules
# to build them.
product_FILES :=
endif
<!–[if !supportLists]–>15、<!–[endif]–>检查我们构建的模块是否冗余了
modules_to_check := $(foreach m,$(ALL_MODULES),$(ALL_MODULES.$(m).CHECKED))
ifneq ($(filter all,$(MAKECMDGOALS)),)
modules_to_check += $(foreach m,$(ALL_MODULES),$(ALL_MODULES.$(m).BUILT))
endif
# for easier debugging
modules_to_check := $(sort $(modules_to_check))
<!–[if !supportLists]–>16、<!–[endif]–>上面的都是配置操作,接下来就是整个项目的编译操作,确定好要生成的目标并开始编译。make默认执行droid,droid依赖于droidcore,droidcore依赖于files等等,这些依赖关系就控制着整个项目的编译流程。
.PHONY: files
files: prebuilt \
$(modules_to_install) \
$(INSTALLED_ANDROID_INFO_TXT_TARGET)
.PHONY: droidcore
droidcore: files \
systemimage \
$(INSTALLED_CHIPRAM_TARGET) \
$(INSTALLED_UBOOT_TARGET) \
$(INSTALLED_BOOTIMAGE_TARGET) \
$(INSTALLED_RECOVERYIMAGE_TARGET) \
$(INSTALLED_USERDATAIMAGE_TARGET) \
$(INSTALLED_CACHEIMAGE_TARGET) \
$(INSTALLED_PRODNVIMAGE_TARGET) \
$(INSTALLED_VENDORIMAGE_TARGET) \
$(INSTALLED_FILES_FILE)
四、加载的其他mk脚本分析
1、help.mk的分析
这个脚本功能主要是打印出编译时的一些帮助信息
.PHONY: help
help:
@echo
@echo “Common make targets:”
@echo “———————————————————————————-”
@echo “droid Default target”
@echo “clean (aka clobber) equivalent to rm -rf out/”
@echo “snod Quickly rebuild the system image from built packages”
@echo “offline-sdk-docs Generate the HTML for the developer SDK docs”
@echo “doc-comment-check-docs Check HTML doc links & validity, without generating HTML”
@echo “libandroid_runtime All the JNI framework stuff”
@echo “framework All the java framework stuff”
@echo “services The system server (Java) and friends”
@echo “help You’re reading it right now”
.PHONY: out
out:
@echo “I’m sure you’re nice and all, but no thanks.”
2、config.mk的分析
2.1、定义一些文件路径变量
SRC_DOCS:= $(TOPDIR)docs
SRC_HEADERS := \
$(TOPDIR)system/core/include \
$(TOPDIR)hardware/libhardware/include \
$(TOPDIR)hardware/libhardware_legacy/include \
$(TOPDIR)hardware/ril/include \
$(TOPDIR)libnativehelper/include \
$(TOPDIR)frameworks/native/include \
$(TOPDIR)frameworks/native/opengl/include \
$(TOPDIR)frameworks/av/include \
$(TOPDIR)frameworks/base/include
SRC_HOST_HEADERS:=$(TOPDIR)tools/include
SRC_LIBRARIES:= $(TOPDIR)libs
SRC_SERVERS:= $(TOPDIR)servers
SRC_TARGET_DIR := $(TOPDIR)build/target
SRC_API_DIR := $(TOPDIR)prebuilts/sdk/api
SRC_SYSTEM_API_DIR := $(TOPDIR)prebuilts/sdk/system-api
SRC_DROIDDOC_DIR := $(TOPDIR)build/tools/droiddoc
2.2、加载pathmap.mk脚本文件,这个文件主要定义了一些绝对路径变量,便于其他脚本调用。
include $(BUILD_SYSTEM)/pathmap.mk
2.3、定义一些重要编译命令
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_RAW_STATIC_LIBRARY := $(BUILD_SYSTEM)/raw_static_library.mk
BUILD_SHARED_LIBRARY:= $(BUILD_SYSTEM)/shared_library.mk
BUILD_EXECUTABLE:= $(BUILD_SYSTEM)/executable.mk
BUILD_RAW_EXECUTABLE:= $(BUILD_SYSTEM)/raw_executable.mk
BUILD_HOST_EXECUTABLE:= $(BUILD_SYSTEM)/host_executable.mk
BUILD_PACKAGE:= $(BUILD_SYSTEM)/package.mk
BUILD_PHONY_PACKAGE:= $(BUILD_SYSTEM)/phony_package.mk
BUILD_HOST_PREBUILT:= $(BUILD_SYSTEM)/host_prebuilt.mk
BUILD_PREBUILT:= $(BUILD_SYSTEM)/prebuilt.mk
BUILD_MULTI_PREBUILT:= $(BUILD_SYSTEM)/multi_prebuilt.mk
BUILD_JAVA_LIBRARY:= $(BUILD_SYSTEM)/java_library.mk
BUILD_STATIC_JAVA_LIBRARY:= $(BUILD_SYSTEM)/static_java_library.mk
BUILD_HOST_JAVA_LIBRARY:= $(BUILD_SYSTEM)/host_java_library.mk
BUILD_DROIDDOC:= $(BUILD_SYSTEM)/droiddoc.mk
BUILD_COPY_HEADERS := $(BUILD_SYSTEM)/copy_headers.mk
BUILD_NATIVE_TEST := $(BUILD_SYSTEM)/native_test.mk
BUILD_HOST_NATIVE_TEST := $(BUILD_SYSTEM)/host_native_test.mk
BUILD_SHARED_TEST_LIBRARY := $(BUILD_SYSTEM)/shared_test_lib.mk
BUILD_HOST_SHARED_TEST_LIBRARY := $(BUILD_SYSTEM)/host_shared_test_lib.mk
BUILD_STATIC_TEST_LIBRARY := $(BUILD_SYSTEM)/static_test_lib.mk
BUILD_HOST_STATIC_TEST_LIBRARY := $(BUILD_SYSTEM)/host_static_test_lib.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
############# vendor configs ################
BUILD_THEME_PACKAGE := $(BUILD_SYSTEM_VENDOR)/themepackage.mk
BUILD_ADDON_PACKAGE := $(BUILD_PACKAGE)
APPLY_PRODUCT_REVISION:= build/vendor/product_config.mk
其中
CLEAR_VARS:用来清除之前定义的环境变量
BUILD_SHARED_LIBRARY:用来指定编译动态库过程
2.4、打包后缀名的设置
COMMON_PACKAGE_SUFFIX := .zip
COMMON_JAVA_PACKAGE_SUFFIX := .jar
COMMON_ANDROID_PACKAGE_SUFFIX := .apk
2.5、加载一些其他mk文件
ifndef ANDROID_BUILDSPEC
ANDROID_BUILDSPEC := $(TOPDIR)buildspec.mk
endif
-include $(ANDROID_BUILDSPEC)
# —————————————————————
# 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)/combo/select.mk
2.6、判断支持32位编译还是64位编译
ifeq (,$(TARGET_CPU_ABI_LIST))
ifeq ($(TARGET_IS_64_BIT)|$(TARGET_PREFER_32_BIT_APPS),true|true)
TARGET_CPU_ABI_LIST := $(TARGET_CPU_ABI_LIST_32_BIT) $(TARGET_CPU_ABI_LIST_64_BIT)
else
TARGET_CPU_ABI_LIST := $(TARGET_CPU_ABI_LIST_64_BIT) $(TARGET_CPU_ABI_LIST_32_BIT)
endif
endif
2.7、加载javac.mk脚本
include $(BUILD_SYSTEM)/combo/javac.mk
2.8、设置一些命令的变量(比如aapt、aidl等)
AAPT := $(HOST_OUT_EXECUTABLES)/aapt$(HOST_EXECUTABLE_SUFFIX)
AIDL := $(HOST_OUT_EXECUTABLES)/aidl$(HOST_EXECUTABLE_SUFFIX)
PROTOC := $(HOST_OUT_EXECUTABLES)/aprotoc$(HOST_EXECUTABLE_SUFFIX)
SIGNAPK_JAR := $(HOST_OUT_JAVA_LIBRARIES)/signapk$(COMMON_JAVA_PACKAGE_SUFFIX)
MKBOOTFS := $(HOST_OUT_EXECUTABLES)/mkbootfs$(HOST_EXECUTABLE_SUFFIX)
MINIGZIP := $(HOST_OUT_EXECUTABLES)/minigzip$(HOST_EXECUTABLE_SUFFIX)
ifeq (,$(strip $(BOARD_CUSTOM_MKBOOTIMG)))
MKBOOTIMG := $(HOST_OUT_EXECUTABLES)/mkbootimg$(HOST_EXECUTABLE_SUFFIX)
else
MKBOOTIMG := $(BOARD_CUSTOM_MKBOOTIMG)
endif
MKYAFFS2 := $(HOST_OUT_EXECUTABLES)/mkyaffs2image$(HOST_EXECUTABLE_SUFFIX)
APICHECK := $(HOST_OUT_EXECUTABLES)/apicheck$(HOST_EXECUTABLE_SUFFIX)
FS_GET_STATS := $(HOST_OUT_EXECUTABLES)/fs_get_stats$(HOST_EXECUTABLE_SUFFIX)
MKEXT2IMG := $(HOST_OUT_EXECUTABLES)/genext2fs$(HOST_EXECUTABLE_SUFFIX)
MAKE_EXT4FS := $(HOST_OUT_EXECUTABLES)/make_ext4fs$(HOST_EXECUTABLE_SUFFIX)
MKEXTUSERIMG := $(HOST_OUT_EXECUTABLES)/mkuserimg.sh
MAKE_F2FS := $(HOST_OUT_EXECUTABLES)/make_f2fs$(HOST_EXECUTABLE_SUFFIX)
MKF2FSUSERIMG := $(HOST_OUT_EXECUTABLES)/mkf2fsuserimg.sh
MKEXT2BOOTIMG := external/genext2fs/mkbootimg_ext2.sh
SIMG2IMG := $(HOST_OUT_EXECUTABLES)/simg2img$(HOST_EXECUTABLE_SUFFIX)
E2FSCK := $(HOST_OUT_EXECUTABLES)/e2fsck$(HOST_EXECUTABLE_SUFFIX)
MKTARBALL := build/tools/mktarball.sh
TUNE2FS := $(HOST_OUT_EXECUTABLES)/tune2fs$(HOST_EXECUTABLE_SUFFIX)
E2FSCK := $(HOST_OUT_EXECUTABLES)/e2fsck$(HOST_EXECUTABLE_SUFFIX)
JARJAR := $(HOST_OUT_JAVA_LIBRARIES)/jarjar.jar
PROGUARD := external/proguard/bin/proguard.sh
JAVATAGS := build/tools/java-event-log-tags.py
LLVM_RS_CC := $(HOST_OUT_EXECUTABLES)/llvm-rs-cc$(HOST_EXECUTABLE_SUFFIX)
BCC_COMPAT := $(HOST_OUT_EXECUTABLES)/bcc_compat$(HOST_EXECUTABLE_SUFFIX)
LINT := prebuilts/sdk/tools/lint
RMTYPEDEFS := $(HOST_OUT_EXECUTABLES)/rmtypedefs
APPEND2SIMG := $(HOST_OUT_EXECUTABLES)/append2simg
VERITY_SIGNER := $(HOST_OUT_EXECUTABLES)/verity_signer
BUILD_VERITY_TREE := $(HOST_OUT_EXECUTABLES)/build_verity_tree
BOOT_SIGNER := $(HOST_OUT_EXECUTABLES)/boot_signer
2.9、执行shell脚本去查找jdk的tools和jar,根据系统环境的不同(OS、32位和64位)执行不同的java操作
ifeq ($(HOST_OS),darwin)
ifeq ($(LEGACY_USE_JAVA6),)
HOST_JDK_TOOLS_JAR:= $(shell $(BUILD_SYSTEM)/find-jdk-tools-jar.sh)
else
# Deliberately set to blank for Java 6 installations on MacOS. These
# versions allegedly use a non-standard directory structure.
HOST_JDK_TOOLS_JAR :=
endif
else
HOST_JDK_TOOLS_JAR:= $(shell $(BUILD_SYSTEM)/find-jdk-tools-jar.sh)
endif
ifneq ($(HOST_JDK_TOOLS_JAR),)
ifeq ($(wildcard $(HOST_JDK_TOOLS_JAR)),)
$(error Error: could not find jdk tools.jar, please check if your JDK was installed correctly)
endif
endif
2.10、根据TARGET_BUILD_VARIANT(debug、user、userdebug)的不同,设置不同的签名
ifdef PRODUCT_DEFAULT_DEV_CERTIFICATE
DEFAULT_SYSTEM_DEV_CERTIFICATE := $(PRODUCT_DEFAULT_DEV_CERTIFICATE)
else
ifeq ($(strip $(TARGET_BUILD_VARIANT)),user)
DEFAULT_SYSTEM_DEV_CERTIFICATE := build/target/product/security/release/releasekey
BUILD_KEYS := release-keys
else
DEFAULT_SYSTEM_DEV_CERTIFICATE := build/target/product/security/testkey
endif
endif
2.11、DEX2OAT运行的一些变量配置
DEX2OAT_TARGET_ARCH := $(TARGET_ARCH)
DEX2OAT_TARGET_CPU_VARIANT := $(TARGET_CPU_VARIANT)
DEX2OAT_TARGET_INSTRUCTION_SET_FEATURES := default
ifneq (,$(filter $(DEX2OAT_TARGET_CPU_VARIANT),cortex-a7 cortex-a15 krait denver))
DEX2OAT_TARGET_INSTRUCTION_SET_FEATURES := div
endif
ifdef TARGET_2ND_ARCH
$(TARGET_2ND_ARCH_VAR_PREFIX)DEX2OAT_TARGET_ARCH := $(TARGET_2ND_ARCH)
$(TARGET_2ND_ARCH_VAR_PREFIX)DEX2OAT_TARGET_CPU_VARIANT := $(TARGET_2ND_CPU_VARIANT)
$(TARGET_2ND_ARCH_VAR_PREFIX)DEX2OAT_TARGET_INSTRUCTION_SET_FEATURES := default
ifneq (,$(filter $($(TARGET_2ND_ARCH_VAR_PREFIX)DEX2OAT_TARGET_CPU_VARIANT),cortex-a7 cortex-a15 krait denver))
$(TARGET_2ND_ARCH_VAR_PREFIX)DEX2OAT_TARGET_INSTRUCTION_SET_FEATURES := div
endif
endif
3、envsetup.mk的分析
3.1、加载version_defaults.mk脚本
include $(BUILD_SYSTEM)/version_defaults.mk
3.2、设置一些变量的值
# —————————————————————
# If you update the build system such that the environment setup
# or buildspec.mk need to be updated, increment this number, and
# people who haven’t re-run those will have to do so before they
# can build. Make sure to also update the corresponding value in
# buildspec.mk.default and envsetup.sh.
CORRECT_BUILD_ENV_SEQUENCE_NUMBER := 10
# —————————————————————
# The product defaults to generic on hardware
# NOTE: This will be overridden in product_config.mk if make
# was invoked with a PRODUCT-xxx-yyy goal.
ifeq ($(TARGET_PRODUCT),)
TARGET_PRODUCT := full
endif
# the variant — the set of files that are included for a build
ifeq ($(strip $(TARGET_BUILD_VARIANT)),)
TARGET_BUILD_VARIANT := eng
endif
3.3、根据shell命令uname -sm执行结果,也就是当前编译系统的环境,来设置一些变量的值,我这边虚拟机运行的结果是:Linux x86_64
UNAME := $(shell uname -sm)
# HOST_OS
ifneq (,$(findstring Linux,$(UNAME)))
HOST_OS := linux
endif
ifneq (,$(findstring Darwin,$(UNAME)))
HOST_OS := darwin
endif
ifneq (,$(findstring Macintosh,$(UNAME)))
HOST_OS := darwin
endif
ifneq (,$(findstring CYGWIN,$(UNAME)))
HOST_OS := windows
endif
# BUILD_OS is the real host doing the build.
BUILD_OS := $(HOST_OS)
# Under Linux, if USE_MINGW is set, we change HOST_OS to Windows to build the
# Windows SDK. Only a subset of tools and SDK will manage to build properly.
ifeq ($(HOST_OS),linux)
ifneq ($(USE_MINGW),)
HOST_OS := windows
endif
endif
ifeq ($(HOST_OS),)
$(error Unable to determine HOST_OS from uname -sm: $(UNAME)!)
endif
# TODO: Replace BUILD_HOST_64bit with a flag that forces 32-bit build,
# after we default to 64-bit host build.
ifeq (,$(BUILD_HOST_64bit))
# Default to 32-bit-by-default multilib host build.
HOST_PREFER_32_BIT := true
endif
# HOST_ARCH
ifneq (,$(findstring x86_64,$(UNAME)))
HOST_ARCH := x86_64
HOST_2ND_ARCH := x86
HOST_IS_64_BIT := true
endif
ifeq ($(HOST_PREFER_32_BIT),true)
SDK_HOST_ARCH := x86
else
SDK_HOST_ARCH := $(HOST_ARCH)
endif
BUILD_ARCH := $(HOST_ARCH)
BUILD_2ND_ARCH := $(HOST_2ND_ARCH)
ifeq ($(HOST_ARCH),)
$(error Unable to determine HOST_ARCH from uname -sm: $(UNAME)!)
endif
# the host build defaults to release, and it must be release or debug
ifeq ($(HOST_BUILD_TYPE),)
HOST_BUILD_TYPE := release
endif
ifneq ($(HOST_BUILD_TYPE),release)
ifneq ($(HOST_BUILD_TYPE),debug)
$(error HOST_BUILD_TYPE must be either release or debug, not ‘$(HOST_BUILD_TYPE)’)
endif
endif
# We don’t want to move all the prebuilt host tools to a $(HOST_OS)-x86_64 dir.
HOST_PREBUILT_ARCH := x86
# This is the standard way to name a directory containing prebuilt host
# objects. E.g., prebuilt/$(HOST_PREBUILT_TAG)/cc
ifeq ($(HOST_OS),windows)
HOST_PREBUILT_TAG := windows
else
HOST_PREBUILT_TAG := $(HOST_OS)-$(HOST_PREBUILT_ARCH)
endif
3.4、设置输出目录名称
TARGET_COPY_OUT_SYSTEM := system
TARGET_COPY_OUT_DATA := data
TARGET_COPY_OUT_OEM := oem
TARGET_COPY_OUT_ROOT := root
TARGET_COPY_OUT_RECOVERY := recovery
3.5、加载product_config.mk脚本
include $(BUILD_SYSTEM)/product_config.mk
3.6、根据TARGET_DEVICE的值寻找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)
3.7、根据系统环境设置输出目录的路径
TARGET_OS := linux
# TARGET_ARCH should be set by BoardConfig.mk and will be checked later
ifneq ($(filter %64,$(TARGET_ARCH)),)
TARGET_IS_64_BIT := true
endif
# the target build type defaults to release
ifneq ($(TARGET_BUILD_TYPE),debug)
TARGET_BUILD_TYPE := release
endif
# —————————————————————
# figure out the output directories
ifeq (,$(strip $(OUT_DIR)))
ifeq (,$(strip $(OUT_DIR_COMMON_BASE)))
OUT_DIR := $(TOPDIR)out
else
OUT_DIR := $(OUT_DIR_COMMON_BASE)/$(notdir $(PWD))
endif
endif
DEBUG_OUT_DIR := $(OUT_DIR)/debug
# Move the host or target under the debug/ directory
# if necessary.
TARGET_OUT_ROOT_release := $(OUT_DIR)/target
TARGET_OUT_ROOT_debug := $(DEBUG_OUT_DIR)/target
TARGET_OUT_ROOT := $(TARGET_OUT_ROOT_$(TARGET_BUILD_TYPE))
HOST_OUT_ROOT_release := $(OUT_DIR)/host
HOST_OUT_ROOT_debug := $(DEBUG_OUT_DIR)/host
HOST_OUT_ROOT := $(HOST_OUT_ROOT_$(HOST_BUILD_TYPE))
<!–[if !supportLists]–>
4、
<!–[endif]–>
product_config.mk分析
4.1、定义函数find-copy-subdir-files,执行shell命令查找子目录下指定文件用于PRODUCT_COPY_FILES和PRODUCT_SDK_ADDON_COPY_FILES
###########################################################
## List all of the files in a subdirectory in a format
## suitable for PRODUCT_COPY_FILES and
## PRODUCT_SDK_ADDON_COPY_FILES
##
## $(1): Glob to match file name
## $(2): Source directory
## $(3): Target base directory
###########################################################
define find-copy-subdir-files
$(shell find $(2) -name “$(1)” | $(SED_EXTENDED) “s:($(2)/?(.*)):\\1\\:$(3)/\\2:” | sed “s://:/:g”)
endef
4.2、确定TARGET_BUILD_VARIANT和TARGET_PRODUCT的值
# These are the valid values of TARGET_BUILD_VARIANT. Also, if anything else is passed
# as the variant in the PRODUCT-$TARGET_BUILD_PRODUCT-$TARGET_BUILD_VARIANT form,
# it will be treated as a goal, and the eng variant will be used.
INTERNAL_VALID_VARIANTS := user userdebug eng
# —————————————————————
# Provide “PRODUCT-<prodname>-<goal>” targets, which lets you build
# a particular configuration without needing to set up the environment.
#
product_goals := $(strip $(filter PRODUCT-%,$(MAKECMDGOALS)))
ifdef product_goals
# Scrape the product and build names out of the goal,
# which should be of the form PRODUCT-<productname>-<buildname>.
#
ifneq ($(words $(product_goals)),1)
$(error Only one PRODUCT-* goal may be specified; saw “$(product_goals)”)
endif
goal_name := $(product_goals)
product_goals := $(patsubst PRODUCT-%,%,$(product_goals))
product_goals := $(subst -, ,$(product_goals))
ifneq ($(words $(product_goals)),2)
$(error Bad PRODUCT-* goal “$(goal_name)”)
endif
# The product they want
TARGET_PRODUCT := $(word 1,$(product_goals))
# The variant they want
TARGET_BUILD_VARIANT := $(word 2,$(product_goals))
ifeq ($(TARGET_BUILD_VARIANT),tests)
$(error “tests” has been deprecated as a build variant. Use it as a build goal instead.)
endif
# The build server wants to do make PRODUCT-dream-installclean
# which really means TARGET_PRODUCT=dream make installclean.
ifneq ($(filter-out $(INTERNAL_VALID_VARIANTS),$(TARGET_BUILD_VARIANT)),)
MAKECMDGOALS := $(MAKECMDGOALS) $(TARGET_BUILD_VARIANT)
TARGET_BUILD_VARIANT := eng
default_goal_substitution :=
else
default_goal_substitution := $(DEFAULT_GOAL)
endif
4.3、加载一些其他的mk脚本
include $(BUILD_SYSTEM)/node_fns.mk
include $(BUILD_SYSTEM)/product.mk
include $(BUILD_SYSTEM)/device.mk
4.4、搜索所有的AndroidProducts.mk文件,找到当前产品的配置文件
ifneq ($(strip $(TARGET_BUILD_APPS)),)
# An unbundled app build needs only the core product makefiles.
all_product_configs := $(call get-product-makefiles,\
$(SRC_TARGET_DIR)/product/AndroidProducts.mk)
else
# Read in all of the product definitions specified by the AndroidProducts.mk
# files in the tree.
all_product_configs := $(get-all-product-makefiles)
endif
# Find the product config makefile for the current product.
# all_product_configs consists items like:
# <product_name>:<path_to_the_product_makefile>
# or just <path_to_the_product_makefile> in case the product name is the
# same as the base filename of the product config makefile.
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))
4.5、调用clear-var-list函数去清除一些变量,并设置产品的运行时态product_runtimes
$(call clear-var-list, $(_product_var_list))
# Set PRODUCT_RUNTIMES, allowing buildspec to override using OVERRIDE_RUNTIMES
product_runtimes := $(sort $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_RUNTIMES))
ifneq ($(OVERRIDE_RUNTIMES),)
$(info Overriding PRODUCT_RUNTIMES=$(product_runtimes) with $(OVERRIDE_RUNTIMES))
product_runtimes := $(OVERRIDE_RUNTIMES)
endif
$(foreach runtime, $(product_runtimes), $(eval include $(SRC_TARGET_DIR)/product/$(runtime).mk))
$(foreach v, $(_product_var_list), $(if $($(v)),\
$(eval PRODUCTS.$(INTERNAL_PRODUCT).$(v) += $(sort $($(v))))))
$(call clear-var-list, $(_product_var_list))
# Now we can assign to PRODUCT_RUNTIMES
PRODUCT_RUNTIMES := $(product_runtimes)
product_runtimes :=
PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_PROPERTY_OVERRIDES += persist.sys.dalvik.vm.lib.2=$(DALVIK_VM_LIB)
ifeq ($(words $(PRODUCT_RUNTIMES)),1)
# If we only have one runtime, we can strip classes.dex by default during dex_preopt
DEX_PREOPT_DEFAULT := true
else
# If we have more than one, we leave the classes.dex alone for post-boot analysis
DEX_PREOPT_DEFAULT := nostripping
endif
4.6、获取BOOTCLASSPATH中的所有jar文件
# A list of module names of BOOTCLASSPATH (jar files)
PRODUCT_BOOT_JARS := $(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_BOOT_JARS))
PRODUCT_SYSTEM_SERVER_JARS := $(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SYSTEM_SERVER_JARS))
4.7、设置TARGET_DEVICE和PRODUCT_LOCALES的值
# Find the device that this product maps to.
TARGET_DEVICE := $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_DEVICE)
# Figure out which resoure configuration options to use for this
# product.
PRODUCT_LOCALES := $(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_LOCALES))
# TODO: also keep track of things like “port”, “land” in product files.
# If CUSTOM_LOCALES contains any locales not already included
# in PRODUCT_LOCALES, add them to PRODUCT_LOCALES.
extra_locales := $(filter-out $(PRODUCT_LOCALES),$(CUSTOM_LOCALES))
ifneq (,$(extra_locales))
ifneq ($(CALLED_FROM_SETUP),true)
# Don’t spam stdout, because envsetup.sh may be scraping values from it.
$(info Adding CUSTOM_LOCALES [$(extra_locales)] to PRODUCT_LOCALES [$(PRODUCT_LOCALES)])
endif
PRODUCT_LOCALES += $(extra_locales)
extra_locales :=
endif
4.8、配置aapt的相关属性
# Add PRODUCT_LOCALES to PRODUCT_AAPT_CONFIG
PRODUCT_AAPT_CONFIG := $(strip $(PRODUCT_LOCALES) $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_AAPT_CONFIG))
PRODUCT_AAPT_PREF_CONFIG := $(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_AAPT_PREF_CONFIG))
PRODUCT_AAPT_PREBUILT_DPI := $(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_AAPT_PREBUILT_DPI))
# Keep a copy of the space-separated config
PRODUCT_AAPT_CONFIG_SP := $(PRODUCT_AAPT_CONFIG)
# Convert spaces to commas.
PRODUCT_AAPT_CONFIG := \
$(subst $(space),$(comma),$(strip $(PRODUCT_AAPT_CONFIG)))
# product-scoped aapt flags
PRODUCT_AAPT_FLAGS :=
ifneq ($(filter en_XA ar_XB,$(PRODUCT_LOCALES)),)
# Force generating resources for pseudo-locales.
PRODUCT_AAPT_FLAGS += –pseudo-localize
endif
4.9、设置一些变量的值
PRODUCT_BRAND := $(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_BRAND))
PRODUCT_MODEL := $(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_MODEL))
ifndef PRODUCT_MODEL
PRODUCT_MODEL := $(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_NAME))
endif
PRODUCT_MANUFACTURER := \
$(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_MANUFACTURER))
ifndef PRODUCT_MANUFACTURER
PRODUCT_MANUFACTURER := unknown
endif
ifeq ($(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_CHARACTERISTICS),)
TARGET_AAPT_CHARACTERISTICS := default
else
TARGET_AAPT_CHARACTERISTICS := $(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_CHARACTERISTICS))
endif
PRODUCT_DEFAULT_WIFI_CHANNELS := \
$(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_DEFAULT_WIFI_CHANNELS))
PRODUCT_DEFAULT_DEV_CERTIFICATE := \
$(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_DEFAULT_DEV_CERTIFICATE))
ifdef PRODUCT_DEFAULT_DEV_CERTIFICATE
ifneq (1,$(words $(PRODUCT_DEFAULT_DEV_CERTIFICATE)))
$(error PRODUCT_DEFAULT_DEV_CERTIFICATE=’$(PRODUCT_DEFAULT_DEV_CERTIFICATE)’, \
only 1 certificate is allowed.)
endif
endif
<!–[if !supportLists]–>
5、
<!–[endif]–>
definitions.mk分析
这个脚本主要是定义了很多函数,相当于一个函数库用于编译所需
define print-vars
$(foreach var,$(1), \
$(info $(var):) \
$(foreach word,$($(var)), \
$(info $(space)$(space)$(word)) \
) \
)
endef
define true-or-empty
$(filter true, $(1))
endef
define my-dir
$(strip \
$(eval LOCAL_MODULE_MAKEFILE := $$(lastword $$(MAKEFILE_LIST))) \
$(if $(filter $(BUILD_SYSTEM)/% $(OUT_DIR)/%,$(LOCAL_MODULE_MAKEFILE)), \
$(error my-dir must be called before including any other makefile.) \
, \
$(patsubst %/,%,$(dir $(LOCAL_MODULE_MAKEFILE))) \
) \
)
endef
五、Android.mk分析
Android.mk是用来向编译系统描述你的源代码,也就是告诉编译系统你的源代码需要编译成什么样。你可以在一个Android.mk文件中定义一个或者多个模块,模块的类型包括:
1)APK程序,一般的Android程序,编译打包生成apk文件
2)Java库,java类库,编译打包生成jar文件
3) C\C++应用程序,可执行的C\C++应用程序
4)C\C++静态库,编译生成C\C++静态库,并打包成.a文件
5)C\C++共享库, 编译生成共享库(动态链接库),并打包成.so文件,有且只有共享库才能被安装/复制到您的应用软件(APK)包中。
下面是一个Android.mk的例子:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := settings_talpa
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := APPS
LOCAL_MODULE_SUFFIX := .apk
LOCAL_SRC_FILES := Settings.apk
LOCAL_MODULE_PATH := $(TARGET_OUT_APPS_PRIVILEGED)
LOCAL_CERTIFICATE := platform
LOCAL_OVERRIDES_PACKAGES := Settings
include $(BUILD_PREBUILT)
接下来根据这个例子来解释每一行代码
<!–[if !supportLists]–>1、<!–[endif]–>LOCAL_PATH := $(call my-dir)
每个Android.mk必须定义LOCAL_PATH这个变量,它用于在开发树中查找源文件。my-dir是一个函数名,由编译系统提供,用于返回当前Android.mk的目录路径。$(call my-dir)表示的就是去调用my-dir这个函数
2、include $(CLEAR_VARS)
CLEAR_VARS是由编译系统提供的变量,config.mk文件中能找到其定义,前面也提到过,它的值是$(BUILD_SYSTEM)/clear_vars.mk,这句代码表示去加载并执行这个mk脚本,清理掉local_xxx这样的一些变量。
<!–[if !supportLists]–>3、<!–[endif]–>LOCAL_MODULE := settings_talpa
LOCAL_MODULE也是必须定义的变量,表示模块的名字,这个名字必须唯一且不包含空格。编译系统会自动添加适当的前缀和后缀。
4、LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_TAGS表示当前模块在哪种模式下编译,模式包含user eng tests optional。
user: 指该模块只在user版本下才编译
eng: 指该模块只在eng版本下才编译
tests: 指该模块只在tests版本下才编译
optional:指该模块在所有版本下都编译
5、LOCAL_MODULE_CLASS := APPS
LOCAL_MODULE_CLASS 指定模块的文件类型,apk文件用APPS, 并且 会检查 是否是apk文件,动态库so文件用SHARED_LIBRARIES ,bin文件用EXECUTABLES,其他文件 用ETC
6、LOCAL_MODULE_SUFFIX := .apk
LOCAL_MODULE_SUFFIX指定模块的后缀
<!–[if !supportLists]–>7、<!–[endif]–>LOCAL_SRC_FILES
LOCAL_SRC_FILES指定需要打包进模块的文件
<!–[if !supportLists]–>8、<!–[endif]–>LOCAL_MODULE_PATH
LOCAL_MODULE_PATH指定模块的安装路径
$(TARGET_OUT_APPS_PRIVILEGED):system/priv-app/
$(TARGET_OUT_APPS):system/app/
9、LOCAL_CERTIFICATE := platform
LOCAL_CERTIFICATE指定模块的签名key值,包含media、shared、platform、
PRESIGNED
(表示已经签过名,不需要签名)
<!–[if !supportLists]–>10、<!–[endif]–>LOCAL_OVERRIDES_PACKAGES := Settings
LOCAL_OVERRIDES_PACKAGES表示当前模块需要覆盖系统原有的哪个模块名
11、include $(BUILD_PREBUILT)
这句代码同样也是加载其他的脚本
BUILD_PACKAGE
:指向build/core/package.mk,用来编译APK文件。
BUILD_JAVA_LIBRARY
:指向build/core/java_library.mk,用来编译Java库文件。
BUILD_STATIC_JAVA_LIBRARY
:指向build/core/tatic_java_library.mk,用来编译Java静态库文件。
BUILD_STATIC_LIBRARY
:指向build/core/static_library.mk,用来编译静态库文件。也就是.a文件。
BUILD_EXECUTABLE
:指向build/core/executable.mk,用来编译可执行文件。
BUILD_PREBUILT
:指向build/core/prebuilt.mk。用来编译已经预编译好的第三方库文件,实际上是将这些预编译好的第三方库文件拷贝到合适的位置去,以便可以让其它模块引用。
六、Android源码各级目录分析
我们知道Android平台分为四层架构,分别是应用程序层、应用框架层、运行库层和Linux内核层,这四层架构和Android源码目录的对应关系如下:
<!–[if !supportLists]–>
1、
<!–[endif]–>
应用程序层对应的是packages/apps
<!–[if !supportLists]–>
2、
<!–[endif]–>
应用框架层对应的是frameworks
<!–[if !supportLists]–>
3、
<!–[endif]–>
运行库层对应的是libcore、dalvik
<!–[if !supportLists]–>
4、
<!–[endif]–>
Linux内核层对应的是kernel
下面详细介绍Android源码的目录结构:
B
ionic:包含一些C语言库,比如内核层的一些头文件、时区的相关代码等等
B
ootable:启动引导的相关代码,包含bootloader、ota、recovery等等
B
uild:存放系统编译规则以及编译所需的基础包和相关工具
C
ts:
Android兼容性测试套件标准
D
alvik:dalvik虚拟机的相关代码
D
evelopment:应用程序开发所需的一些例子源码和相关工具
E
xternal:Android的一些开源模块,比如加密、xml解析、压缩、数据库等等
F
rameworks:Android的核心框架(Java和C++语言),比如WiFi、蓝牙、通讯等等
H
ardware:
部分厂家开源的硬解适配层HAL代码
P
ackages:Android应用程序包,比如浏览器、计算器、相机、多媒体应用等等
P
rebuilt:
x86和arm架构下预编译的一些资源
S
dk:Android的SDK和模拟器
S
ystem:
底层文件系统库、应用及组件
V
endor:厂商定制代码
K
ernel:Linux内核相关代码和脚本
O
ut:系统编译输出目录,包含相关基础包以及相关镜像文件
D
evice:产品的相关描述文件(与编译系统有关)
关注我的个人公众号,提供更丰富的技术资讯和相关资源