`
yaolinnan
  • 浏览: 58590 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
文章分类
社区版块
存档分类
最新评论

Android编译系统过程研究

 
阅读更多

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]-->定义一些编译时所需的变量值和默认目标droidmake命令不加任何参数就执行这个)

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_FILESproduct_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默认执行droiddroid依赖于droidcoredroidcore依赖于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脚本分析

1help.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."

 

 

 

 

2config.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、设置一些命令的变量(比如aaptaidl等)

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脚本去查找jdktoolsjar,根据系统环境的不同(OS32位和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_VARIANTdebuguseruserdebug)的不同,设置不同的签名

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.11DEX2OAT运行的一些变量配置

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

 

3envsetup.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_FILESPRODUCT_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_VARIANTTARGET_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_DEVICEPRODUCT_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源码的目录结构:

Bionic:包含一些C语言库,比如内核层的一些头文件、时区的相关代码等等

Bootable:启动引导的相关代码,包含bootloader、ota、recovery等等

Build:存放系统编译规则以及编译所需的基础包和相关工具

Cts:Android兼容性测试套件标准

Dalvik:dalvik虚拟机的相关代码

Development:应用程序开发所需的一些例子源码和相关工具

External:Android的一些开源模块,比如加密、xml解析、压缩、数据库等等

Frameworks:Android的核心框架(Java和C++语言),比如WiFi、蓝牙、通讯等等

Hardware:部分厂家开源的硬解适配层HAL代码

Packages:Android应用程序包,比如浏览器、计算器、相机、多媒体应用等等

Prebuilt:x86和arm架构下预编译的一些资源

Sdk:Android的SDK和模拟器

System:底层文件系统库、应用及组件

Vendor:厂商定制代码

Kernel:Linux内核相关代码和脚本

Out:系统编译输出目录,包含相关基础包以及相关镜像文件

Device:产品的相关描述文件(与编译系统有关)

 

精彩科技工作室
0
2
分享到:
评论

相关推荐

    android编译系统框架分析及main.mk分析

    本文旨在详细分析Android编译系统的核心组件——main.mk文件,以便更好地理解Android编译过程。 #### 二、Android编译系统概述 Android编译系统不仅负责编译生成目标系统的二进制文件和Java应用程序,还包括管理...

    PCL for Android 编译过程遇到的问题及办法

    ### PCL for Android 编译过程遇到的问题及解决办法 #### 环境配置与工具安装 在开始PCL(Point Cloud Library)for Android的编译之前,首先需要准备一些必要的开发环境和工具: 1. **CMake安装**:CMake是一种...

    PJSIP编译出来的android例程

    编译PJSIP和PJSUA2到Android的过程通常包括以下步骤: 1. **获取源代码**:从PJSIP官方网站下载最新源代码。 2. **配置环境**:设置Android NDK路径,配置编译选项以适应Android平台。 3. **编译库**:使用NDK的...

    Android反编译工具

    首先,Android反编译工具.exe和Android反编译工具(64位).exe是两个可执行文件,可能是用于在Windows操作系统上运行的反编译软件。这些工具通常能够解析APK文件,将其Java字节码(Dalvik Executable, .dex)转换回源...

    linux 内核启动过程以及挂载android 根文件系统的过程

    ### Linux内核启动过程及Android根文件系统的挂载 #### Linux内核启动流程概览 Linux内核的启动过程是一个复杂而...了解这些内容不仅有助于开发者更好地调试和优化系统,也为进一步研究Android平台提供了坚实的基础。

    Android 反编译工具 APKDB

    在Android开发领域,有时我们需要对APK文件进行深入的研究,比如查看源代码、修改资源或者分析功能实现。这时,就需要用到反编译工具。本文将详细介绍“Android反编译工具APKDB”,以及如何利用它来提升我们的...

    android反编译xml、layout

    - **版本管理**: `apktool1.5.2`是`apktool`的一个旧版本,随着Android系统的更新,新版本的`apktool`会增加对新特性和支持,因此在进行反编译时,建议使用最新稳定版以确保兼容性。 - **依赖库**: `apktool`需要...

    android 反编译工具集

    - 反编译过程可能会丢失原代码的一些信息,如注释、变量名等,因为这些在编译过程中会被优化或删除。 总之,"android 反编译工具集"中的dex2jar和apktool是Android开发和逆向工程中的利器,它们可以帮助我们深入...

    Android 反编译 apk

    Android反编译是针对APK(Android应用程序)进行逆向工程的过程,以便查看、修改或分析其源代码和资源。这个过程通常由开发者、安全研究人员或逆向工程师执行,以理解应用程序的工作原理、查找漏洞、优化性能或者...

    【Mac】Caffe 编译android so文件记录

    标题【Mac】Caffe 编译android so文件记录表明本文将会讲述在Mac操作系统平台上,如何搭建环境并编译生成适用于Android平台的Caffe库文件(so文件)。Caffe是一个深度学习框架,专注于速度和模块化,广泛应用于图像...

    Android一键反编译

    "Android一键反编译"是这样的一个工具,它简化了原本复杂的过程,让开发者和逆向工程师可以更高效地探索APK的内部工作原理。下面将详细介绍这个主题,并涵盖相关知识点。 **反编译概念** 反编译是将已编译的二进制...

    AndroidKiller 反编译

    2. **日志系统**:工具内置的日志功能可以记录反编译过程中产生的信息和错误,帮助用户跟踪和解决可能出现的问题,提高了工作效率。 3. **再次签名打包**:反编译后,用户可能需要对修改过的APK重新签名以确保其可...

    Android反编译全套工具

    本资源"Android反编译全套工具"提供了一套常用的Android反编译工具,包括dex2jar、apktool和jd-gui,这些工具对于理解APK的工作原理、查找bug或者研究竞品功能非常有帮助。 1. **dex2jar**:这个工具主要用于将...

    2018Android反编译工具合集

    在Android应用开发的世界里,有时候我们可能需要对已有的APK文件进行逆向工程,以了解其...同时,持续关注并更新这些工具至最新版本,可以确保更高效、准确地完成反编译任务,适应不断变化的Android系统和应用环境。

    Android反编译工具包

    本篇将详细介绍压缩包中包含的四个核心工具:apktool、dex2jar、jd-gui以及AXMLPrinter2.S.jar,并探讨它们在Android反编译过程中的作用。 1. **apktool**:这是一个用于解包和重新打包Android APK文件的工具,由...

    android编译大全_完全指南

    ### Android编译大全_完全指南 #### 知识点概览 1. **编译环境的搭建** - Ubuntu 9.10 虚拟机的构建与配置 - 必需软件包的安装 2. **Sourcecode的获取** - 使用`repo`工具初始化并同步代码库 3. **编译源代码**...

    jadx android反编译工具

    JADX是一款强大的Android应用反编译工具,它为开发者和安全研究人员提供了一种高效的方式来查看和分析APK文件的源代码。这款工具以其易用性和详细性而受到广泛赞誉,允许用户深入理解APK内部的工作机制,无论是为了...

    AndroidKiller修复反编译源码卡死

    AndroidKiller是一款常用的Android应用分析工具,它可以帮助开发者或安全研究人员查看APK的源代码、资源文件、反编译Dex文件等,以理解应用的工作原理或寻找潜在的安全漏洞。 在描述中提到的“修复反编译源码卡死”...

    Android反编译全家桶

    在Android开发领域,有时我们需要对APK文件进行逆向工程,以分析其内部结构、查看源...此外,随着Android系统的不断更新,反编译工具也在不断进化,以应对新的安全措施和加密技术,所以保持工具的最新版本至关重要。

    Android系统架构及其驱动研究 pdf

    此外,文档可能还涵盖了Android的编译和构建过程,包括使用Android Build System如何将源代码编译成可执行文件,以及如何通过AOSP(Android Open Source Project)源码进行定制开发。这对于开发者来说,是理解...

Global site tag (gtag.js) - Google Analytics