android编译_android编译系统 - CSDN
精华内容
参与话题
  • ANDROID系统编译过程详解

    千次阅读 2019-06-17 16:08:23
    在研究Android编译系统之前,我们首先需要了解Linux系统的make命令。在Linux系统中,我们可以通过make命令来编译代码。Make命令在执行的时候,默认会在当前目录找到一个Makefile文件,然后根据Makefile文件中的指令...

    第一部分:概述

     

    在研究Android编译系统之前,我们首先需要了解Linux系统的make命令。在Linux系统中,我们可以通过make命令来编译代码。Make命令在执行的时候,默认会在当前目录找到一个Makefile文件,然后根据Makefile文件中的指令来对代码进行编译。也就是说,make命令执行的是Makefile文件中的指令。Makefile文件中的指令可以是编译命令,例如gcc,也可以是其它命令,例如Linux系统中的shell命令cp、rm等等。理解这一点非常重要,因为虽然通常我们说make命令是可以编译代码的,但是它实际上可以做任何事情。

            看到这里,有的小伙伴可能会说,在Linux系统中,直接通过shell命令也可以做很多事情啊,它和make命令有什么区别呢?通过前面的介绍可以知道,make命令事实也是通过shell命令来完成任务的,但是它的神奇之处是可以帮我们处理好文件之间的依赖关系。我们通常都有会这样的一个需求,假设有一个文件T,它依赖于另外一个文件D,要求只有当文件D的内容发生变化,才重新生成文件T。这种需求在编译系统中表现得尤其典型,当一个*.c文件include的*.h文件发生变化时,需要重新编译该*.c文件,或者当一个模块A所引用的模块B发生变化时,重新编译模块B。正是由于编译系统中存在这种典型的文件依赖需求,而make命令又是专门用来解决这种文件依赖问题的,因此我们通常认为make命令是用来编译代码的。

     Make命令是怎么知道两个文件之间存在依赖关系,以及当被依赖文件发生变化时如何处理目标文件的呢?答案就在前面提到的Makefile文件。Makefile文件实际上是一个脚本文件,就像普通的shell脚本文件一样,只不过它遵循的是Makefile语法。Makefile文件最基础的功能就是描述文件之间的依赖关系,以及怎么处理这些依赖关系。例如,假设有一个目录文件target,它依赖于文件dependency,并且当文件dependency发生变化时,需要通过command命令来重新生成文件T,这时候我们就可以在Makefile编写以下语句:

     

    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
     
     
    1. target: dependency  
    2. <tab>command -o target -i dependency  
            我们假设命令command的-o选项指定的是输出文件,而-i选项指定的是输入文件。此外,命令command必须是另起一行,并且以tab键开头。

     

            这就是最基础也是最主要的Makefile文件语法。当然,Makefile文件还有很多其它的语法,这里不可能一一描述。推荐一本书《GNU make中文手册》,里面非常详细地介绍了make以及Makefile文件语法。

     

     

    整个工程只有一个Makefile,听起来似乎是一件很疯狂的事情,因为这个Makefile可能会变得无比庞大和复杂。其实不用担心,我们可以按照模块来将这个Makefile划分成一个个Makefile片段(fragement),然后通过Makefile的include指令来将这些Makefile片段组装在一个Makefile中。与递归Makefile相比,每一个模块现在拥有的是一个Makefile片段,而不是一个Makefile文件。这正是Android编译系统的设计思想和原则,也就是说,我们平时所编写的Android.mk编译脚本都只不过是整个Android编译系统的一个Makefile片段。

            明白了Android编译系统的设计思想和原则之后,我们就可以通过图5来观察一下Android编译系统的整体架构了:

    图5 Android编译系统架构

           在使用Android编译系统之前,我们需要打开一个shell进入到Android源码根目录中,并且在该shell中将build/envsetup.sh脚本文件source进来。脚本文件build/envsetup.sh被source到当前shell的过程中,会在vendor和device两个目录将厂商指定的envsetup.sh也source到当前shell当中,这样就可以获得厂商提供的产品配置信息。此外,脚本文件build/envsetup.sh还提供了以下几个重要的命令来帮助我们编译Android源码:

           1. lunch

            用来初始化编译环境,例如设置环境变量和指定目标产品型号。Lunch命令在执行的时候,主要做两件事情。第一件事情是设置TARGET_PRODUCT、TARGET_BUILD_VARIANT、TARGET_BUILD_TYPE和TARGET_BUILD_APPS等环境变量,用来指定目标产品类型和编译类型。第二件事情是通过make命令执行build/core/config.mk脚本,并且通过加载另外一个脚本build/core/dumpvar.mk打印出当前的编译环境配置信息。注意,build/core/config.mk和build/core/dumpvar.mk均为Makefile脚本,因此它们可以通过make命令来执行。另外,build/core/config.mk脚本还会加载一个名称为BoradConfig.mk的脚本以及build/core/envsetup.mk脚本来配置目标产品型号的相关信息。

           2. m

           相当于是在执行make命令。对整个Android源码进行编译。

           3. mm

           如果是在Android源码根目录下执行,那么就相当于是执行make命令对整个源码进行编译。如果是在Android源码根目录下的某一个子目录执行,那么就在会在从该子目录开始,一直往上一个目录直至到根目录,寻找是否存在一个Android.mk文件。如果存在的话,那么就通过make命令对该Android.mk文件描述的模块进行编译。

           4. mmm

           后面可以跟一个或者若干个目录。如果指定了多个目录,那么目录之间以空格分隔,并且每一个目录下都必须存在一个Android,mk文件。如果没有在目录后面通过冒号指定模块名称,那么在Android.mk文件中描述的所有模块都会被编译,否则只有指定的模块会被编译。如果需要同时指定多个模块,那么这些模块名称必须以逗号分隔。它的语法如下所示:

     

    [html] view plaincopy在CODE上查看代码片派生到我的代码片
     
     
    1. mmm <dir-1<dir-2> ... <dir-N>[:module-1,module-2,...,module-M]  
           该命令会通过make命令来执行Android源码根目录下的Makefile文件,该Makefile文件又会将build/core/main.mk加载进来。文件build/core/main.mk在加载的过程中,还会加载以下几个主要的文件:

     

           (1). build/core/config.mk

           该文件根据lunch命令所配置的产品信息在build/target/board、vendor或者device目录中找到对应的BoradConfig.mk文件,以及通过加载build/core/product_config.mk文件在build/target/product、vendor或者device目录中找到对应的AndroidProducts.mk文件,来进一步对编译环境进行配置,以便接下来编译指定模块时可以获得必要的信息。

           (2). build/core/definitions.mk

           该文件定义了在编译过程需要调用到的各种自定义函数。

           (3). 指定的Android.mk

           这些指定的Android.mk环境是由mmm命令通过环境变量ONE_SHOT_MAKEFILE传递给build/core/main.mk文件使用的。这些Android.mk文件一般还会通过环境变量BUILD_PACKAGE、BUILD_JAVA_LIBRARY、BUILD_STATIC_JAVA_LIBRARY、BUILD_SHARED_LIBRARY、BUILD_STATIC_LIBRARY、BUILD_EXECUTABLE和BUILD_PREBUILT将build/core/package.mk、build/core/java_library.mk、build/core/static_java_library.mk、build/core/shared_library.mk、build/core/static_library.mk、build/core/executable.mk和build/core/prebuilt.mk等编译片段模板文件加载进来,来表示要编译是APK、Java库、Linux动态库/静态库/可执行文件或者预先编译好的文件等等。

           (4). build/core/Makefile

           该文件包含了用来制作system.img、ramdisk.img、boot.img和recovery.img等镜像文件的脚本。


     

    第二部分:Android编译环境初始化

     

    对编译环境进行初始化,其中最主要就是指定编译的类型和目标设备的型号。Android的编译类型主要有eng、userdebug和user三种,而支持的目标设备型号则是不确定的,它们由当前的源码配置情况所决定。为了确定源码支持的所有目标设备型号,Android编译系统在初始化的过程中,需要在特定的目录中加载特定的配置文件。

     


     

    Android的优势就在于其开源,

    我们在对Android的源码进行定制的时候,很有必要了解下,Android的编译过程。

    如果你从来没有做过Android代码的编译,那么最官方的编译过程就是查看Android的官方网站:http://source.android.com/source/building.html

    但是,这儿只是告诉你了如何去编译一个通用的系统,并没有详细告诉你细节,我们跟着编译过程来了解下。

     

    按照google给出的编译步骤如下:

       1> source build/envsetup.sh:加载命令

       2> lunch:选择平台编译选项

       3> make:执行编译

    我们按照编译步骤来分析编译过程的细节,最终添加自己的平台编译选项。

    1. source build/envsetup.sh

    这个命令是用来将envsetup.sh里的所有用到的命令加载到环境变量里去,我们来分析下它。

    envsetup.sh里的主要命令如下:

     

     

    [html] view plain copy
     
    1. function help()                  # 显示帮助信息  
    2. function get_abs_build_var()           # 获取绝对变量  
    3. function get_build_var()             # 获取绝对变量  
    4. function check_product()             # 检查product  
    5. function check_variant()             # 检查变量  
    6. function setpaths()                # 设置文件路径  
    7. function printconfig()              # 打印配置  
    8. function set_stuff_for_environment()        # 设置环境变量  
    9. function set_sequence_number()            # 设置序号  
    10. function settitle()                # 设置标题  
    11. function choosetype()               # 设置type  
    12. function chooseproduct()              # 设置product  
    13. function choosevariant()              # 设置variant  
    14. function tapas()                  # 功能同choosecombo  
    15. function choosecombo()               # 设置编译参数  
    16. function add_lunch_combo()             # 添加lunch项目  
    17. function print_lunch_menu()            # 打印lunch列表  
    18. function lunch()                 # 配置lunch  
    19. function m()                   # make from top  
    20. function findmakefile()              # 查找makefile  
    21. function mm()                   # make from current directory  
    22. function mmm()                   # make the supplied directories  
    23. function croot()                 # 回到根目录  
    24. function cproj()  
    25. function pid()  
    26. function systemstack()  
    27. function gdbclient()  
    28. function jgrep()                 # 查找java文件  
    29. function cgrep()                  # 查找c/cpp文件  
    30. function resgrep()  
    31. function tracedmdump()  
    32. function runhat()  
    33. function getbugreports()  
    34. function startviewserver()  
    35. function stopviewserver()  
    36. function isviewserverstarted()  
    37. function smoketest()  
    38. function runtest()  
    39. function godir ()                 # 跳到指定目录 405  
    40.   
    41.  # add_lunch_combo函数被多次调用,就是它来添加Android编译选项  
    42.  # Clear this variable.  It will be built up again when the vendorsetup.sh  
    43.  # files are included at the end of this file.  
    44.  # 清空LUNCH_MENU_CHOICES变量,用来存在编译选项  
    45.  unset LUNCH_MENU_CHOICES  
    46. function add_lunch_combo()     
    47. {  
    48.      local new_combo=$1         # 获得add_lunch_combo被调用时的参数  
    49.      local c  
    50.      # 依次遍历LUNCH_MENU_CHOICES里的值,其实该函数第一次调用时,该值为空  
    51.      for c in ${LUNCH_MENU_CHOICES[@]} ; do   
    52.          if [ "$new_combo" = "$c" ] ; then    # 如果参数里的值已经存在于LUNCH_MENU_CHOICES变量里,则返回  
    53.              return  
    54.          fi  
    55.      done  
    56.      # 如果参数的值不存在,则添加到LUNCH_MENU_CHOICES变量里  
    57.      LUNCH_MENU_CHOICES=(${LUNCH_MENU_CHOICES[@]} $new_combo)  
    58. }  
    59.   
    60.   
    61. # 这是系统自动增加了一个默认的编译项 generic-eng  
    62. # add the default one here  
    63. add_lunch_combo generic-eng    # 调用上面的add_lunch_combo函数,将generic-eng作为参数传递过去  
    64.    
    65. # if we're on linux, add the simulator.  There is a special case  
    66. # in lunch to deal with the simulator  
    67. if [ "$(uname)" = "Linux" ] ; then  
    68.      add_lunch_combo simulator  
    69. fi  
    70.   
    71. # 下面的代码很重要,它要从vendor目录下查找vendorsetup.sh文件,如果查到了,就加载它  
    72. # Execute the contents of any vendorsetup.sh files we can find.  
    73. for f in `/bin/ls vendor/*/vendorsetup.sh vendor/*/build/vendorsetup.sh 2> /dev/null`  
    74.    do  
    75.      echo "including $f"  
    76.      . $f       # 执行找到的脚本,其实里面就是厂商自己定义的编译选项  
    77.    done  
    78. unset f  



     

    envsetup.sh其主要作用如下:

      1. 加载了编译时使用到的函数命令,如:help,lunch,m,mm,mmm等
      2. 添加了两个编译选项:generic-eng和simulator,这两个选项是系统默认选项
      3. 查找vendor/<-厂商目录>/和vendor/<厂商目录>/build/目录下的vendorsetup.sh,如果存在的话,加载执行它,添加厂商自己定义产品的编译选项
     其实,上述第3条是向编译系统添加了厂商自己定义产品的编译选项,里面的代码就是:add_lunch_combo xxx-xxx。

    根据上面的内容,可以推测出,如果要想定义自己的产品编译项,简单的办法是直接在envsetup.sh最后,添加上add_lunch_combo myProduct-eng,当然这么做,不太符合上面代码最后的本意,我们还是老实的在vendor目录下创建自己公司名字,然后在公司目录下创建一个新的vendorsetup.sh,在里面添加上自己的产品编译项

     

    #mkdir vendor/farsight/
    #touch vendor/farsight/vendorsetup.sh
    #echo "add_lunch_combo fs100-eng" > vendor/farsight/vendorsetup.sh

     

    这样,当我们在执行source build/envsetup.sh命令的时候,可以在shell上看到下面的信息:

     

    including vendor/farsight/vendorsetup.sh

     
    2. 按照android官网的步骤,开始执行lunch full-eng

     

    当然如果你按上述命令执行,它编译的还是通用的eng版本系统,不是我们个性系统,我们可以执行lunch命令,它会打印出一个选择菜单,列出可用的编译选项

    如果你按照第一步中添加了vendorsetup.sh那么,你的选项中会出现:

     

    You're building on Linux
     
    generic-eng simulator fs100-eng
    Lunch menu... pick a combo:
         1. generic-eng
         2. simulator
         3. fs100-eng

     

    其中第3项是我们自己添加的编译项。

     

    lunch命令是envsetup.sh里定义的一个命令,用来让用户选择编译项,来定义Product和编译过程中用到的全局变量。

    我们一直没有说明前面的fs100-eng是什么意思,现在来说明下,fs100是我定义的产品的名字,eng是产品的编译类型,除了eng外,还有user, userdebug,分别表示:

    eng: 工程机,

    user:最终用户机

    userdebug:调试测试机

    tests:测试机 

    由此可见,除了eng和user外,另外两个一般不能交给最终用户的,记得m8出来的时候,先放出了一部分eng工程机,然后出来了user机之后,可以用工程机换。

     

    那么这四个类型是干什么用的呢?其实,在main.mk里有说明,在Android的源码里,每一个目标(也可以看成工程)目录都有一个Android.mk的makefile,每个目标的Android.mk中有一个类型声明:LOCAL_MODULE_TAGS,这个TAGS就是用来指定,当前的目标编译完了属于哪个分类里。

     

        PS:Android.mk和Linux里的makefile不太一样,它是Android编译系统自己定义的一个makefile来方便编译成:c,c++的动态、静态库或可执行程序,或java库或android的程序,

     

    好了,我们来分析下lunch命令干了什么?

     

     

    [html] view plain copy
     
    1. function lunch()  
    2. {  
    3.     local answer  
    4.   
    5.     if [ "$1" ] ; then  
    6.        # lunch后面直接带参数  
    7.         answer=$1  
    8.     else  
    9.        # lunch后面不带参数,则打印处所有的target product和variant菜单提供用户选择  
    10.         print_lunch_menu     
    11.         echo -n "Which would you like? [generic-eng] "  
    12.         read answer  
    13.     fi  
    14.   
    15.     local selection=  
    16.   
    17.     if [ -z "$answer" ]  
    18.     then  
    19.            # 如果用户在菜单中没有选择,直接回车,则为系统缺省的generic-eng  
    20.         selection=generic-eng  
    21.     elif [ "$answer" = "simulator" ]  
    22.     then  
    23.         # 如果是模拟器  
    24.         selection=simulator  
    25.     elif (echo -n $answer | grep -q -e "^[0-9][0-9]*$")  
    26.     then  
    27.         # 如果answer是选择菜单的数字,则获取该数字对应的字符串  
    28.         if [ $answer -le ${#LUNCH_MENU_CHOICES[@]} ]  
    29.         then  
    30.             selection=${LUNCH_MENU_CHOICES[$(($answer-$_arrayoffset))]}  
    31.         fi  
    32.         # 如果 answer字符串匹配 *-*模式(*的开头不能为-)  
    33.     elif (echo -n $answer | grep -q -e "^[^\-][^\-]*-[^\-][^\-]*$")  
    34.     then  
    35.         selection=$answer  
    36.     fi  
    37.   
    38.     if [ -z "$selection" ]  
    39.     then  
    40.         echo  
    41.         echo "Invalid lunch combo: $answer"  
    42.         return 1  
    43.     fi  
    44.   
    45.     # special case the simulator  
    46.     if [ "$selection" = "simulator" ]  
    47.     then  
    48.         # 模拟器模式  
    49.         export TARGET_PRODUCT=sim  
    50.         export TARGET_BUILD_VARIANT=eng  
    51.         export TARGET_SIMULATOR=true  
    52.         export TARGET_BUILD_TYPE=debug  
    53.     else  
    54.   
    55.         # 将 product-variant模式中的product分离出来  
    56.         local product=$(echo -n $selection | sed -e "s/-.*$//")  
    57.   
    58.         # 检查之,调用关系 check_product()->get_build_var()->build/core/config.mk比较罗嗦,不展开了  
    59.         check_product $product  
    60.         if [ $? -ne 0 ]  
    61.         then  
    62.             echo  
    63.             echo "** Don't have a product spec for: '$product'"  
    64.             echo "** Do you have the right repo manifest?"  
    65.             product=  
    66.         fi  
    67.   
    68.         # 将 product-variant模式中的variant分离出来  
    69.         local variant=$(echo -n $selection | sed -e "s/^[^\-]*-//")  
    70.   
    71.         # 检查之,看看是否在 (user userdebug eng) 范围内  
    72.         check_variant $variant  
    73.         if [ $? -ne 0 ]  
    74.         then  
    75.             echo  
    76.             echo "** Invalid variant: '$variant'"  
    77.             echo "** Must be one of ${VARIANT_CHOICES[@]}"  
    78.             variant=  
    79.         fi  
    80.   
    81.         if [ -z "$product" -o -z "$variant" ]  
    82.         then  
    83.             echo  
    84.             return 1  
    85.         fi  
    86.  #  导出环境变量,这里很重要,因为后面的编译系统都是依赖于这里定义的几个变量的  
    87.         export TARGET_PRODUCT=$product  
    88.         export TARGET_BUILD_VARIANT=$variant  
    89.         export TARGET_SIMULATOR=false  
    90.         export TARGET_BUILD_TYPE=release  
    91.     fi # !simulator  
    92.   
    93.     echo  
    94.   
    95.     # 设置到环境变量,比较多,不再一一列出,最简单的方法 set >env.txt 可获得  
    96.     set_stuff_for_environment  
    97.     # 打印一些主要的变量, 调用关系 printconfig()->get_build_var()->build/core/config.mk->build/core/envsetup.mk 比较罗嗦,不展开了  
    98.     printconfig  
    99. }  



     

     

    由上面分析可知,lunch命令可以带参数和不带参数,最终导出一些重要的环境变量,从而影响编译系统的编译结果。导出的变量如下(以实际运行情况为例)

     

    TARGET_PRODUCT=fs100
    TARGET_BUILD_VARIANT=eng
    TARGET_SIMULATOR=false
    TARGET_BUILD_TYPE=release

     
    执行完上述两个步骤,就该执行:make命令了,下篇来分析。


     

     

    1. make 

    执行make命令的结果就是去执行当前目录下的Makefile文件,我们来看下它的内容:

    ### DO NOT EDIT THIS FILE ###
    include build/core/main.mk
    ### DO NOT EDIT THIS FILE ###


    呵呵,看到上面 的内容,我们都会笑,这是我见过最简单的Makefile了,我们再看下build/core/main.mk

    main.mk文件里虽然脚本不多,但是却定义了整个Android的编译关系,它主要引入了下列几个重要的mk文件:

    49 include $(BUILD_SYSTEM)/config.mk

    55 include $(BUILD_SYSTEM)/cleanbuild.mk

    142 include $(BUILD_SYSTEM)/definitions.mk

    当然每个mk文件都有自己独特的意义,我们一并将主线流程相关mk文件都列出来,大概来介绍下,先有个整体的概念,然后再细化了解。

    所有的Makefile都通过build/core/main.mk这个文件组织在一起,它定义了一个默认goals:droid,当我们在TOP目录下,敲Make实际上就等同于我们执行make droid。

    当Make include所有的文件,完成对所有make我文件的解析以后就会寻找生成droid的规则,依次生成它的依赖,直到所有满足的模块被编译好,然后使用相应的工具打包成相应的img。其中,config.mk,envsetup.mk,product_config.mk文件是编译用户指定平台系统的关键文件。上图中红色部分是用户指定平台产品的编译主线,我们先来看下config.mk的主要作用。

     

    2. build/core/config.mk

    该文件被main.mk包含。

    定义了以下环境变量:

    16 SRC_HEADERS := \
     17     $(TOPDIR)system/core/include \
     18     $(TOPDIR)hardware/libhardware/include \
     19     $(TOPDIR)hardware/libhardware_legacy/include \
     20     $(TOPDIR)hardware/ril/include \
     21     $(TOPDIR)dalvik/libnativehelper/include \
     22     $(TOPDIR)frameworks/base/include \
     23     $(TOPDIR)frameworks/base/opengl/include \
     24     $(TOPDIR)external/skia/include
     25 SRC_HOST_HEADERS:=$(TOPDIR)tools/include
     26 SRC_LIBRARIES:= $(TOPDIR)libs
     27 SRC_SERVERS:= $(TOPDIR)servers
     28 SRC_TARGET_DIR := $(TOPDIR)build/target
     29 SRC_API_DIR := $(TOPDIR)frameworks/base/api
    .....然后定义了下面几个重要的编译命令 43 CLEAR_VARS:= $(BUILD_SYSTEM)/clear_vars.mk
     44 BUILD_HOST_STATIC_LIBRARY:= $(BUILD_SYSTEM)/host_static_library.mk
     45 BUILD_HOST_SHARED_LIBRARY:= $(BUILD_SYSTEM)/host_shared_library.mk
     46 BUILD_STATIC_LIBRARY:= $(BUILD_SYSTEM)/static_library.mk
     47 BUILD_RAW_STATIC_LIBRARY := $(BUILD_SYSTEM)/raw_static_library.mk
     48 BUILD_SHARED_LIBRARY:= $(BUILD_SYSTEM)/shared_library.mk
     49 BUILD_EXECUTABLE:= $(BUILD_SYSTEM)/executable.mk
     50 BUILD_RAW_EXECUTABLE:= $(BUILD_SYSTEM)/raw_executable.mk
     51 BUILD_HOST_EXECUTABLE:= $(BUILD_SYSTEM)/host_executable.mk
     52 BUILD_PACKAGE:= $(BUILD_SYSTEM)/package.mk
     53 BUILD_HOST_PREBUILT:= $(BUILD_SYSTEM)/host_prebuilt.mk
     54 BUILD_PREBUILT:= $(BUILD_SYSTEM)/prebuilt.mk
     55 BUILD_MULTI_PREBUILT:= $(BUILD_SYSTEM)/multi_prebuilt.mk
     56 BUILD_JAVA_LIBRARY:= $(BUILD_SYSTEM)/java_library.mk
     57 BUILD_STATIC_JAVA_LIBRARY:= $(BUILD_SYSTEM)/static_java_library.mk
     58 BUILD_HOST_JAVA_LIBRARY:= $(BUILD_SYSTEM)/host_java_library.mk
     59 BUILD_DROIDDOC:= $(BUILD_SYSTEM)/droiddoc.mk
     60 BUILD_COPY_HEADERS := $(BUILD_SYSTEM)/copy_headers.mk
     61 BUILD_KEY_CHAR_MAP := $(BUILD_SYSTEM)/key_char_map.mk

     

    [plain] view plain copy
     
    1. 上述命令变量其实是对应的mk文件名,所有的Android.mk文件里基本上都包含上述命令变量,如:  

    CLEAR_VARS:用来清除之前定义的环境变量

    BUILD_SHARED_LIBRARY:用来指定编译动态库过程

    109 # ---------------------------------------------------------------
    110 # Define most of the global variables.  These are the ones that
    111 # are specific to the user's build configuration.
    112 include $(BUILD_SYSTEM)/envsetup.mk
    113
    114 # Boards may be defined under $(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)
    115 # or under vendor/*/$(TARGET_DEVICE).  Search in both places, but
    116 # make sure only one exists.
    117 # Real boards should always be associated with an OEM vendor.
    118 board_config_mk := \
    119     $(strip $(wildcard \
    120         $(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)/BoardConfig.mk \
    121         vendor/*/$(TARGET_DEVICE)/BoardConfig.mk \
    122     ))
    123 ifeq ($(board_config_mk),)
    124   $(error No config file found for TARGET_DEVICE $(TARGET_DEVICE))
    125 endif
    126 ifneq ($(words $(board_config_mk)),1)
    127   $(error Multiple board config files for TARGET_DEVICE $(TARGET_DEVICE): $(board_config_mk))
    128 endif
    129 include $(board_config_mk)
    130 TARGET_DEVICE_DIR := $(patsubst %/,%,$(dir $(board_config_mk)))
    131 board_config_mk :=

     

    112行又包含了另外一个重要的mk文件envsetup.mk,我们来看一下。

     

    3. envsetup.mk

     

    复制代码
    复制代码
     25 ifeq ($(TARGET_PRODUCT),)    #判断TARGET_PRODUCT是否为空,
     26 ifeq ($(TARGET_SIMULATOR),true)
     27 TARGET_PRODUCT := sim
     28 else
     29 TARGET_PRODUCT := generic
     30 endif
     31 endif
    复制代码
    复制代码

     

    第25行,判断TARGET_PRODUCT是否为空,根据上一节分析可知,TARGET_PRODUCT=fs100 

    复制代码
    复制代码
     34 # the variant -- the set of files that are included for a build
     35 ifeq ($(strip $(TARGET_BUILD_VARIANT)),)
     36 TARGET_BUILD_VARIANT := eng
     37 endif
     38 
     39 # Read the product specs so we an get TARGET_DEVICE and other
     40 # variables that we need in order to locate the output files.
     41 include $(BUILD_SYSTEM)/product_config.mk
    复制代码
    复制代码

     

    在41行又包含了product_config.mk文件,等会我们再分析它,先看下面的

     

    复制代码
    复制代码
    148 # ---------------------------------------------------------------
    149 # figure out the output directories
    150 
    151 ifeq (,$(strip $(OUT_DIR)))
    152 OUT_DIR := $(TOPDIR)out
    153 endif
    154 
    155 DEBUG_OUT_DIR := $(OUT_DIR)/debug
    156 
    157 # Move the host or target under the debug/ directory
    158 # if necessary.
    159 TARGET_OUT_ROOT_release := $(OUT_DIR)/target
    160 TARGET_OUT_ROOT_debug := $(DEBUG_OUT_DIR)/target
    161 TARGET_OUT_ROOT := $(TARGET_OUT_ROOT_$(TARGET_BUILD_TYPE))
    162 
    ...
    184 PRODUCT_OUT := $(TARGET_PRODUCT_OUT_ROOT)/$(TARGET_DEVICE)
    187 
    188 HOST_OUT_EXECUTABLES:= $(HOST_OUT)/bin
    189 HOST_OUT_SHARED_LIBRARIES:= $(HOST_OUT)/lib
    190 HOST_OUT_JAVA_LIBRARIES:= $(HOST_OUT)/framework
    191 HOST_OUT_SDK_ADDON := $(HOST_OUT)/sdk_addon
    ...
    200 TARGET_OUT_INTERMEDIATES := $(PRODUCT_OUT)/obj
    201 TARGET_OUT_HEADERS:= $(TARGET_OUT_INTERMEDIATES)/include
    202 TARGET_OUT_INTERMEDIATE_LIBRARIES := $(TARGET_OUT_INTERMEDIATES)/lib
    203 TARGET_OUT_COMMON_INTERMEDIATES := $(TARGET_COMMON_OUT_ROOT)/obj
    204 
    205 TARGET_OUT := $(PRODUCT_OUT)/system
    206 TARGET_OUT_EXECUTABLES:= $(TARGET_OUT)/bin
    207 TARGET_OUT_OPTIONAL_EXECUTABLES:= $(TARGET_OUT)/xbin
    208 TARGET_OUT_SHARED_LIBRARIES:= $(TARGET_OUT)/lib
    209 TARGET_OUT_JAVA_LIBRARIES:= $(TARGET_OUT)/framework
    210 TARGET_OUT_APPS:= $(TARGET_OUT)/app
    211 TARGET_OUT_KEYLAYOUT := $(TARGET_OUT)/usr/keylayout
    212 TARGET_OUT_KEYCHARS := $(TARGET_OUT)/usr/keychars
    213 TARGET_OUT_ETC := $(TARGET_OUT)/etc
    214 TARGET_OUT_STATIC_LIBRARIES:= $(TARGET_OUT_INTERMEDIATES)/lib
    215 TARGET_OUT_NOTICE_FILES:=$(TARGET_OUT_INTERMEDIATES)/NOTICE_FILES
    216 
    217 TARGET_OUT_DATA := $(PRODUCT_OUT)/data
    218 TARGET_OUT_DATA_EXECUTABLES:= $(TARGET_OUT_EXECUTABLES)
    219 TARGET_OUT_DATA_SHARED_LIBRARIES:= $(TARGET_OUT_SHARED_LIBRARIES)
    220 TARGET_OUT_DATA_JAVA_LIBRARIES:= $(TARGET_OUT_JAVA_LIBRARIES)
    221 TARGET_OUT_DATA_APPS:= $(TARGET_OUT_DATA)/app
    222 TARGET_OUT_DATA_KEYLAYOUT := $(TARGET_OUT_KEYLAYOUT)
    223 TARGET_OUT_DATA_KEYCHARS := $(TARGET_OUT_KEYCHARS)
    224 TARGET_OUT_DATA_ETC := $(TARGET_OUT_ETC)
    225 TARGET_OUT_DATA_STATIC_LIBRARIES:= $(TARGET_OUT_STATIC_LIBRARIES)
    226 
    227 TARGET_OUT_UNSTRIPPED := $(PRODUCT_OUT)/symbols
    228 TARGET_OUT_EXECUTABLES_UNSTRIPPED := $(TARGET_OUT_UNSTRIPPED)/system/bin
    229 TARGET_OUT_SHARED_LIBRARIES_UNSTRIPPED := $(TARGET_OUT_UNSTRIPPED)/system/lib
    230 TARGET_ROOT_OUT_UNSTRIPPED := $(TARGET_OUT_UNSTRIPPED)
    231 TARGET_ROOT_OUT_SBIN_UNSTRIPPED := $(TARGET_OUT_UNSTRIPPED)/sbin
    232 TARGET_ROOT_OUT_BIN_UNSTRIPPED := $(TARGET_OUT_UNSTRIPPED)/bin
    233 
    234 TARGET_ROOT_OUT := $(PRODUCT_OUT)/root
    235 TARGET_ROOT_OUT_BIN := $(TARGET_ROOT_OUT)/bin
    236 TARGET_ROOT_OUT_SBIN := $(TARGET_ROOT_OUT)/sbin
    237 TARGET_ROOT_OUT_ETC := $(TARGET_ROOT_OUT)/etc
    238 TARGET_ROOT_OUT_USR := $(TARGET_ROOT_OUT)/usr
    239 
    240 TARGET_RECOVERY_OUT := $(PRODUCT_OUT)/recovery
    241 TARGET_RECOVERY_ROOT_OUT := $(TARGET_RECOVERY_OUT)/root
    242 
    243 TARGET_SYSLOADER_OUT := $(PRODUCT_OUT)/sysloader
    244 TARGET_SYSLOADER_ROOT_OUT := $(TARGET_SYSLOADER_OUT)/root
    245 TARGET_SYSLOADER_SYSTEM_OUT := $(TARGET_SYSLOADER_OUT)/root/system
    246 
    247 TARGET_INSTALLER_OUT := $(PRODUCT_OUT)/installer
    248 TARGET_INSTALLER_DATA_OUT := $(TARGET_INSTALLER_OUT)/data
    249 TARGET_INSTALLER_ROOT_OUT := $(TARGET_INSTALLER_OUT)/root
    250 TARGET_INSTALLER_SYSTEM_OUT := $(TARGET_INSTALLER_OUT)/root/system
    复制代码
    复制代码

     

    上面的代码是指定了目标输出代码的位置和主机输出代码的位置,重要的几个如下:

     

    复制代码
    复制代码
    PRODUCT_OUT = 这个的结果要根据product_config.mk文件内容来决定,其实是out/target/product/fs100/
    TARGET_OUT = $(PRODUCT_OUT)/system
    TARGET_OUT_EXECUTABLES =  $(PRODUCT_OUT)/system/bin
    TARGET_OUT_SHARED_LIBRARIES =  $(PRODUCT_OUT)/system/lib
    TARGET_OUT_JAVA_LIBRARIES = $(PRODUCT_OUT)/system/framework
    TARGET_OUT_APPS = $(PRODUCT_OUT)/system/app
    TARGET_OUT_ETC = $(PRODUCT_OUT)/system/etc
    TARGET_OUT_STATIC_LIBRARIES  = $(PRODUCT_OUT)/obj/lib
    TARGET_OUT_DATA = $(PRODUCT_OUT)/data
    TARGET_OUT_DATA_APPS = $(PRODUCT_OUT)/data/app
    TARGET_ROOT_OUT = $(PRODUCT_OUT)/root
    TARGET_ROOT_OUT_BIN = $(PRODUCT_OUT)/bin
    TARGET_ROOT_OUT_SBIN  = $(PRODUCT_OUT)/system/sbin
    TARGET_ROOT_OUT_ETC = $(PRODUCT_OUT)/system/etc
    TARGET_ROOT_OUT_USR = $(PRODUCT_OUT)/system/usr
    复制代码
    复制代码

     

    总结下:

    envsetup.mk文件主要包含了product_config.mk文件,然后指定了编译时要输出的所有文件的OUT目录。


    4. build/core/product_config.mk

     

    复制代码
    复制代码
    157 include $(BUILD_SYSTEM)/product.mk
    ...
    160 # Read in all of the product definitions specified by the AndroidProducts.mk
    161 # files in the tree.
    162 #
    163 #TODO: when we start allowing direct pointers to product files,
    164 #    guarantee that they're in this list.
    165 $(call import-products, $(get-all-product-makefiles))
    166 $(check-all-products)
    ...
    170 # Convert a short name like "sooner" into the path to the product
    171 # file defining that product.
    172 #
    173 INTERNAL_PRODUCT := $(call resolve-short-product-name, $(TARGET_PRODUCT))
    ...
    176 # Find the device that this product maps to.
    177 TARGET_DEVICE := $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_DEVICE)
    复制代码
    复制代码

     

    157行,我靠,又包含了product.mk文件

     

    165行,调用函数import-products, $(get-all-product-makefiles),这儿我们看上面的注释:

        Read in all of the product definitions specified by the AndroidProducts.mk files in the tree.
        TODO: when we start allowing direct pointers to product files, guarantee that they're in this list.

     

        意思是说:读取指定的目录下所有的AndrodProducts.mk文件中定义的产品信息

        其实get-all-product-makefiles返回所有的产品文件xxx.mk

        import-products函数去验证这些产品配置文件是否都包含有必须的配置信息,细节后面分析。

    173行调用了resolve-short-product-name函数,它将返回TARGET_PRODUCT产品的配置文件目录,并赋给INTERNAL_PRODUCT

        也就是说:

        INTERNAL_PRODUCT = vendor/farsight/products/fs100.mk
        TARGET_DEVICE = fs100

           如果调试看其结果,可以在167行,将#$(dump-product)取消注释

         然后在175行添加: $(info $(INTERNAL_PRODUCT))

           在178行添加: $(info $(TARGET_DEVICE )),查看调试结果。

    总结一下:

    接合前面的图,product_config.mk主要读取vendor目录下不同厂商自己定义的AndrodProducts.mk文件,从该文件里取得所有产品的配置文件,然后再根据lunch选择的编译项TARGET_PRODUCT,找到与之对应的配置文件,然后设置TARGET_DEVICE变量,用于后续编译。

     

    5. build/core/product.mk

     

    复制代码
    复制代码
    17 #
     18 # Functions for including AndroidProducts.mk files
     19 #
     20 
     21 #
     22 # Returns the list of all AndroidProducts.mk files.
     23 # $(call ) isn't necessary.
     24 #
     25 define _find-android-products-files
     26 $(shell test -d vendor && find vendor -maxdepth 6 -name AndroidProducts.mk) \
     27   $(SRC_TARGET_DIR)/product/AndroidProducts.mk
     28 endef
     29 
     30 #
     31 # Returns the sorted concatenation of all PRODUCT_MAKEFILES
     32 # variables set in all AndroidProducts.mk files.
     33 # $(call ) isn't necessary.
     34 #
     35 define get-all-product-makefiles
     36 $(sort \
     37   $(foreach f,$(_find-android-products-files), \
     38     $(eval PRODUCT_MAKEFILES :=) \
     39     $(eval LOCAL_DIR := $(patsubst %/,%,$(dir $(f)))) \
     40     $(eval include $(f)) \
     41     $(PRODUCT_MAKEFILES) \
     42    ) \
     43   $(eval PRODUCT_MAKEFILES :=) \
     44   $(eval LOCAL_DIR :=) \
     45  )
     46 endef
    复制代码
    复制代码

     

    [plain] view plain copy
     
    1. 通过注释可知,本文件中主要是一些用来处理AndroidProduct.mk的函数<br style="box-sizing: border-box;" /><span style="box-sizing: border-box;">_find-android-products-files:</span>  

        用来获得vendor目录下,所有名字为AndroidProduct.mk的文件列表。
    get-all-product-makefiles:

        用来获得所有AndroidProduct.mk文件里定义的PRODUCT_MAKEFILES的值(其实是产品文件路径名)。


    在vendor目录下,每个公司目录下都会存在一个AndroidProduct.mk文件,这个文件是用来定义这个公司的产品列表,每个产品用<product_name>.mk来表示
    如Android给的示例:

    [plain] view plain copy
     
    1. vendor/sample/products/AndroidProduct.mk  

    其内容如下:

    复制代码
    复制代码
    1 #
      2 # This file should set PRODUCT_MAKEFILES to a list of product makefiles
      3 # to expose to the build system.  LOCAL_DIR will already be set to
      4 # the directory containing this file. 
      5 #
      6 # This file may not rely on the value of any variable other than
      7 # LOCAL_DIR; do not use any conditionals, and do not look up the
      8 # value of any variable that isn't set in this file or in a file that
      9 # it includes.
     10 #
     11 
     12 PRODUCT_MAKEFILES := \
     13   $(LOCAL_DIR)/sample_addon.mk
    复制代码
    复制代码

     

    [plain] view plain copy
     
    1. 里面只定义了一个产品配置文件,即当前目录下的sample_addon.mk:  
      1 # List of apps and optional libraries (Java and native) to put in the add-on system image.
      2 PRODUCT_PACKAGES := \
      3     PlatformLibraryClient \
      4     com.example.android.platform_library \
      5     libplatform_library_jni

     

    上述文件里定义了产品相关个性化信息,如,PRODUCT_PACKAGES表示要在当前产品里添加一些安装包。
    由此可见,get-all-product-makefiles函数,其实就是返回了当前公司里全部的产品对应的mk文件列表。

     


    总结:

    如果用户想个性定制自己的产品,应该有以下流程,包含上一节内容:

    1. 创建公司目录

        #mkdir vendor/farsight

    2. 创建一个vendorsetup.sh文件,将当前产品编译项添加到lunch里,让lunch能找到用户个性定制编译项

        #echo "add_lunch_combo fs100-eng" > vendor/farsight/vendorsetup.sh

    3. 仿着Android示例代码,在公司目录下创建products目录

        #mkdir -p vendor/farsight/products

    4. 仿着Android示例代码,在products目录下创建两个mk文件

        #touch vendor/farsight/products/AndroidProduct.mk vendor/farsight/products/fs100.mk

    在AndroidProduct.mk里添加如下内容:

     

    [plain] view plain copy
     
    1. PRODUCT_MAKEFILES := $(LOCAL_DIR)/fs100.mk  

    表示只有一个产品fs100,它对应的配置文件在当前目录下的fs100.mk。

     

    5. 在产品配置文件里添加最基本信息

     

    复制代码
    复制代码
      1 
      2 PRODUCT_PACKAGES := \
      3     IM \
      4     VoiceDialer
      5 
      6 $(call inherit-product, build/target/product/generic.mk)  ##从某一默认配置开始派生余下内容参考派生起点
      7 
      8 # Overrides
      9 PRODUCT_MANUFACTURER := farsight
     10 PRODUCT_NAME := fs100
     11 PRODUCT_DEVICE := fs100
    复制代码
    复制代码

     


     

    前面两节讲解了自定义Android编译项和创建Product产品配置文件,除了编译和定义产品相关环境变量外,还需要定义Board相关环境变量。

    1. build/core/config.mk

    
    
    复制代码
    复制代码
    109 # ---------------------------------------------------------------  
    110 # Define most of the global variables.  These are the ones that  
    111 # are specific to the user's build configuration.  
    112 include $(BUILD_SYSTEM)/envsetup.mk  
    113   
    114 # Boards may be defined under $(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)  
    115 # or under vendor/*/$(TARGET_DEVICE).  Search in both places, but  
    116 # make sure only one exists.  
    117 # Real boards should always be associated with an OEM vendor.  
    118 board_config_mk := \  
    119     $(strip $(wildcard \  
    120         $(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)/BoardConfig.mk \  
    121         vendor/*/$(TARGET_DEVICE)/BoardConfig.mk \  
    122     ))  
    123 ifeq ($(board_config_mk),)  
    124   $(error No config file found for TARGET_DEVICE $(TARGET_DEVICE))  
    125 endif  
    126 ifneq ($(words $(board_config_mk)),1)  
    127   $(error Multiple board config files for TARGET_DEVICE $(TARGET_DEVICE): $(board_config_mk))  
    128 endif  
    129 include $(board_config_mk)  
    130 TARGET_DEVICE_DIR := $(patsubst %/,%,$(dir $(board_config_mk)))  
    131 board_config_mk :=  
    复制代码
    复制代码
    [plain] view plain copy
     
    1. <span style="box-sizing: border-box;">上述代码在上一节已经见到过,只是分析了112行的envsetup.mk,根据上一节内容可知,</span>envsetup.mk设置了很多OUT变量,最终在build/core/product_config.mk文件里,设置了TARGET_DEVICE = fs100。  

     

    我们从114行继续分析。

    从114~117行解释大意可知:

        Board相关配置文件会存在于$(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)/或vendor/*/$(TARGET_DEVICE)/目录中,一个Vendor厂商只能有一个对应的Board配置文件。

    118行定义board_config_mk变量:

        $(wildcard xxx)函数就是找到与xxx的匹配项放到空格列表里,前面定义TARGET_DEVICE变量 = fs100,所以$(SRC_TARGET_DIR)/board/fs100/BoardConfig.mk不存在,必须要存在vendor/*/fs100/BoardConfig.mk文件来定义开发板配置信息。

    129行,通过include将vendor/*/fs100/BoardConfig.mk包含进来,

    130行,TARGET_DEVICE_DIR为board_config_mk的路径,即:vendor/*/fs100

    总结:

       一个vendor厂商必须要有一个对应的Board配置文件,即:vendor/*/fs100/BoardConfig.mk

        定义了TARGET_DEVICE_DIR变量,为board_config_mk的路径,即:vendor/*/fs100

    指定board 相关特性,一定要包含:
    TARGET_CPU_ABI := armeabi/...
    其他属性参见其他board样例.(build/target/board/XXX

     

    2.  build/core/main.mk

     

    复制代码
    复制代码
    141 # Bring in standard build system definitions.
    142 include $(BUILD_SYSTEM)/definitions.mk
    ...
    347 ifeq ($(SDK_ONLY),true)
    348 
    349 # ----- SDK for Windows ------
    350 # These configure the build targets that are available for the SDK under Cygwin.
    351 # The first section defines all the C/C++ tools that can be compiled under Cygwin,
    352 # the second section defines all the Java ones (assuming javac is available.)
    353 
    354 subdirs := \
    355     prebuilt \
    356     build/libs/host \
    357     build/tools/zipalign \
    ...
    382 # The following can only be built if "javac" is available.
    383 # This check is used when building parts of the SDK under Cygwin.
    384 ifneq (,$(shell which javac 2>/dev/null))
    385 $(warning sdk-only: javac available.)
    386 subdirs += \
    387     build/tools/signapk \
    388     dalvik/dx \
    389     dalvik/libcore \
    ...
    414 else    # !SDK_ONLY
    415 ifeq ($(BUILD_TINY_ANDROID), true)
    416 
    417 # TINY_ANDROID is a super-minimal build configuration, handy for board 
    418 # bringup and very low level debugging
    419 
    420 subdirs := \
    421     bionic \
    422     system/core \
    423     build/libs \
    424     build/target \
    ...
    433 else    # !BUILD_TINY_ANDROID
    434 
    435 #
    436 # Typical build; include any Android.mk files we can find.
    437 #
    438 subdirs := $(TOP)
    439 
    440 FULL_BUILD := true
    441 
    442 endif   # !BUILD_TINY_ANDROID
    443 
    444 endif   # !SDK_ONLY
    ...
    464 #
    465 # Include all of the makefiles in the system
    466 #
    467 
    468 # Can't use first-makefiles-under here because
    469 # --mindepth=2 makes the prunes not work.
    470 subdir_makefiles := \
    471     $(shell build/tools/findleaves.py --prune=out --prune=.repo --prune=.git $(subdirs) Android.mk)
    472 
    473 include $(subdir_makefiles)
    复制代码
    复制代码

     

    上一节只是讲了main.mk第49行中包含了config.mk,我们继续分析。

    142行包含了:build/core/definitions.mk,该文件定义了很多全局变量与函数。

    如下列常见函数:

        my-dir:返回当前路径

        all-java-files-under:获得指定目录及子目录一所有java文件

        all-subdir-c-files:获得当前目录下及子目录下所有c文件

    354~444行,定义了subdirs变量,依据不同的用户编译条件,而包含Android源码中不同的目录。

    470行,定义了subdir_makefile变量,其值为subdirs定义的目录中的Android.mk文件。

    473行,将所有编译目录中的Android.mk文件包含进来。

    3. build/target/board/Android.mk

    复制代码
    复制代码
     26 ifeq (,$(wildcard $(TARGET_DEVICE_DIR)/AndroidBoard.mk))
     27   ifeq (,$(wildcard $(TARGET_DEVICE_DIR)/Android.mk))
     28     $(error Missing "$(TARGET_DEVICE_DIR)/AndroidBoard.mk")
     29   else
     30     # TODO: Remove this check after people have had a chance to switch,
     31     # after April 2009.
     32     $(error Please rename "$(TARGET_DEVICE_DIR)/Android.mk" to "$(TARGET_DEVICE_DIR)/AndroidBoard.mk")
     33   endif
     34 endif
     35 include $(TARGET_DEVICE_DIR)/AndroidBoard.mk
    复制代码
    复制代码
    [plain] view plain copy
     
    1. 由于将所有目录中Android.mk文件include进来,build/target/board/Android.mk自然被包含进来,根据前面分析,TARGET_DEVICE_DIR = </span>vendor/*/fs100,<span style="box-sizing: border-box;">其中26~35行用来判断对应的产品目录下是否存在AndrodiBoard.mk,如果不存在,提示出错退出,如果存在,将其包含到编译脚本中。  

     

    由此可见:我们必须要在产品目录下创建AndrodiBoard.mk文件,来描述开发板相关配置项,我们可以借鉴:build/target/board/generic/AndroidBoard.mk内容,同时根据前面所分析,还要创建BoardConfig.mk文件。

     

    $cp build/target/board/generic/AndroidBoard.mk build/target/board/generic/BoardConfig.mk  vendor/farsight/fs100/

     

    [plain] view plain copy
     
    1. <span style="box-sizing: border-box;">至此,自定义Android编译选项基本步骤已经分部分析完,细节还需要针对不同开发板具体分析。</span>  

     

    总结:

    build/core/main.mk包含了config.mk,它主要定义了编译全部代码的依赖关系

          build/core/config.mk         定义了大量的编译脚本命令,编译时用到的环境变量,引入了envsetup.mk 文件,加载board相关配置文件。
          build/core/envsetup.mk   定义了编译时用到的大量OUT输出目录,加载product_config.mk文件
          build/core/product_config.mk 定义了Vendor目录下Product相关配置文件解析脚本,读取AndrodProducts.mk生成TARGET_DEVICE变量
          build/target/product          product config
          build/target/board            board config
          build/core/combo             build flags config 

          这里解释下这里的board和product。borad主要是设计到硬件芯片的配置,比如是否提供硬件的某些功能,比如说GPU等等,或者芯片支持浮 点运算等等。product是指针对当前的芯片配置定义你将要生产产品的个性配置,主要是指APK方面的配置,哪些APK会包含在哪个product中, 哪些APK在当前product中是不提供的。
          config.mk是一个总括性的东西,它里面定义了各种module编译所需要使用的HOST工具以及如何来编译各种模块,比如说 BUILT_PREBUILT就定义了如何来编译预编译模块。envsetup.mk主要会读取由envsetup.sh写入环境变量中的一些变量来配置编译过程中的输出目录,combo里面主要定义了各种Host和Target结合的编译器和编译选项。

    1. 在vendor目录下创建自己公司目录,然后在公司目录下创建一个新的vendorsetup.sh,在里面添加上自己的产品编译项

    $mkdir vendor/farsight/  
    $touch vendor/farsight/vendorsetup.sh  
    $echo "add_lunch_combo fs100-eng" > vendor/farsight/vendorsetup.sh  

     

    [plain] view plain copy
     
    1. <span style="box-sizing: border-box;">2. </span>仿着Android示例代码,在公司目录下创建products目录  
     $mkdir -p vendor/farsight/products
    [plain] view plain copy
     
    1. <span style="box-sizing: border-box;">3. </span>仿着Android示例代码,在products目录下创建两个mk文件  
    $touch vendor/farsight/products/AndroidProduct.mk vendor/farsight/products/fs100.mk
    [plain] view plain copy
     
    1.     在AndroidProduct.mk里添加如下内容:  
    PRODUCT_MAKEFILES := $(LOCAL_DIR)/fs100.mk  
    [plain] view plain copy
     
    1.     在产品配置文件里添加最基本信息  
    复制代码
    复制代码
     PRODUCT_PACKAGES := \  
         IM \  
         VoiceDialer  
    

    $(call inherit-product, build/target/product/generic.mk)

    Overrides

    PRODUCT_MANUFACTURER := farsight
    PRODUCT_NAME := fs100
    PRODUCT_DEVICE := fs100

    复制代码
    复制代码
    [plain] view plain copy
     
    1. 借鉴build/target/board/generic/AndroidBoard.mk和BoardConfig.mk,创建对应文件。  
    $cp build/target/board/generic/AndroidBoard.mk build/target/board/generic/BoardConfig.mk  vendor/farsight/fs100/

     


     

     

     

     

     

     

     

     

    展开全文
  • Android 系统源码——下载到编译

    万次阅读 2020-09-30 15:19:26
    一直想下载、编译、调试一下Android源码 ,加强对一些framework的理解,搞了好多次,终于可以正常调试了。这里进行一些总结和分享。 Android源码到模拟器运行,主要有的四个步骤: 下载源码 搭建编译环境 准备...

    一直想下载、编译、调试一下Android源码 ,加强对一些framework的理解,搞了好多次,终于可以正常调试了。这里进行一些总结和分享。

    Android源码到模拟器运行,主要有的四个步骤:

    1. 下载源码
    2. 搭建编译环境
    3. 准备编译

    我使用的环境是Ubuntu16.04 、openJDK8、Android 8.0.0

    硬件软件要求

    官方文档:要求

    硬件要求:

    • 如果是 Android 2.3.x (Gingerbread) 及更高版本(包括 master 分支),需要使用 64 位环境。如果是较低的版本,则可以在 32 位系统中进行编译。
    • 如果要检出代码,至少需要 250GB 可用磁盘空间;如果要进行编译,则还需要 150GB。如果要进行多次编译,则需要更多空间。
    • 如果在虚拟机中运行 Linux,则至少需要 16GB 的 RAM/交换空间。

    我的电脑是双系统,ubuntu 空间划分不集中,分区空间不够,导致编译失败。我在实践过程中,发现不需要官方声明的那么多空间,下载初始化包.repo 40G左右,检出代码(Android 8.0.0),又占用了40G左右,编译用了60G左右。总共算下来160G的分区空间应该是够用了。

    一、 下载源码

    Android 源码是非常庞大的,而且每个模块都是用git来进行管理 ,整个Android源码是由很多个git项目构成,Google对Android代码的更新也是更新到相应模块的git项目上。

    那对于需要编译Android的开发者来说,要分别clone 每个git项目而且还要放到固定的位置确实是件惨绝人寰的事,所以Google就开发了一个基于Python编写的帮助开发者管理多个项目的工具,这个工具就叫repo,repo就是封装了git命令的python脚本。

    由于国内网络的原因,我们使用国内的清华源下载源码和repo工具

    1.1、下载repo

    下面的命令,是从清华源下载repo工具,这样脚本中的路径就是指向清华源的aosp

    mkdir ~/bin   # 在home下创建bin文件夹
    PATH=~/bin:$PATH   # 把bin文件夹加入环境变量的
    curl https://mirrors.tuna.tsinghua.edu.cn/git/git-repo  > ~/bin/repo #下载repo脚本
    chmod a+x ~/bin/repo #添加权限
    

    repo 工具讲解

    我们有个非常庞大的项目Pre,该项目由很多个子项目R1,R2,…Rn等组成,为了方便管理和协同开发,我们为每个子项目创立自己的仓库,整个项目的结构如下:

    在这里插入图片描述

    项目Pre进行分库的好处就是,只需要创建需要开发的模块分支,代码量减少了很多。检出的时候也可以只检出某一模块的代码。

    会遇到这么一个问题:如果我们想要创建Pre分支来做feature开发,这就意味着,我们需要到每个子项目中分别创建对应的分支,这个过程如果纯粹靠手工做,那简直是个灾难,于是会写个自动化处理程序(我们假设这个工具叫做RepoUtil)来帮助我们解决这个问题。这个RepoUtil也会有版本管理之类的需求,因此我们也用Git对其管理,并为其创建对应的仓库。此时整个项目的结构如下:

    在这里插入图片描述

    这里RepoUtil知道整个项目Pre下的每个子项目(即维护子项目的列表),同时提供对这些子项目的管理功能,比如统一创建分支等。但是从"单一职责"角度来看,RepoUitl这个工具的功能过于复杂,我们完全可以将维护子项目列表这个功能抽取出来作为一个新项目sub_projects,因为子项目也会变化。因此,为其创建对应的仓库,并用Git管理,RepoUtil只需要通过简单的对ub_projects进行依赖即可,此时整个项目的结构如下:
    在这里插入图片描述

    AOSP项目结构

    • .repo工具对应RepoUtil
    • mainfest对应sub_projects

    在mainfest文件夹中,执行git branch -a 就可以看到所有的分支

    1.2、下载源码

    下载源码有两种方法:

    1)Android 官方下载源代码

    官方文档:下载源代码

    2)使用初始化包(建议)

    初始化包每月都会进行更新,由于首次同步需要下载约 30GB 数据,如果上面的方法,过程中任何网络故障都可能造成同步失败,我第一次是使用官方的方法,失败过一次。后来都是用这个方法。

    下载 https://mirrors.tuna.tsinghua.edu.cn/aosp-monthly/aosp-latest.tar,下载完成后记得根据 checksum.txt 的内容校验一下。

    由于所有代码都是从隐藏的 .repo 目录中 checkout 出来的,所以我们只保留了 .repo 目录,下载后解压 再 repo sync 一遍即可得到完整的目录。

    使用方法如下:

    wget -c https://mirrors.tuna.tsinghua.edu.cn/aosp-monthly/aosp-latest.tar # 下载初始化包
    tar xf aosp-latest.tar
    cd AOSP   # 解压得到的 AOSP 工程目录
    # 这时 ls 的话什么也看不到,因为只有一个隐藏的 .repo 目录
    repo init -u https://aosp.tuna.tsinghua.edu.cn/platform/manifest -b android-8.0.1_r1 # 可选命令,指定版本,如果未指定,则使用最新的版本
    repo sync # 正常同步一遍即可得到完整目录
    # 或 repo sync -l 仅checkout代码
    

    Android各版本列表:https://source.android.google.cn/setup/start/build-numbers.html#source-code-tags-and-builds

    二、搭建编译环境

    官方文档:搭建编译环境

    安装openJDK8

    sudo apt-get update
    sudo apt-get install openjdk-8-jdk
    

    安装软件包

    官方文档没有介绍Ubuntu 16.04所需的软件包。使用Ubuntu 16.04的小伙伴,需要安装下面的软件

    sudo apt-get install libx11-dev:i386 libreadline6-dev:i386 libgl1-mesa-dev g++-multilib 
    sudo apt-get install -y git flex bison gperf build-essential libncurses5-dev:i386 
    sudo apt-get install tofrodos python-markdown libxml2-utils xsltproc zlib1g-dev:i386 
    sudo apt-get install dpkg-dev libsdl1.2-dev libesd0-dev
    sudo apt-get install git-core gnupg flex bison gperf build-essential  
    sudo apt-get install zip curl zlib1g-dev gcc-multilib g++-multilib 
    sudo apt-get install libc6-dev-i386 
    sudo apt-get install lib32ncurses5-dev x11proto-core-dev libx11-dev 
    sudo apt-get install libgl1-mesa-dev libxml2-utils xsltproc unzip m4
    sudo apt-get install lib32z-dev ccache
    
    

    三、准备编译

    设置环境

    使用 envsetup.sh 脚本初始化环境。请注意,将 source 替换成 .(一个点)可以省去一些字符,这种简写形式在文档中更为常用。

    source build/envsetup.sh
    

    或者

    . build/envsetup.sh
    

    选择目标

    使用 lunch 选择要编译的目标。确切的配置可作为参数进行传递。例如,以下命令表示针对模拟器进行完整编译,并且所有调试功能均处于启用状态。

    lunch aosp_arm-eng
    

    直接运行 lunch (没有参数),会列出所有支持的类型,输入对应的序号来进行选择。
    在这里插入图片描述

    所有编译目标都采用 BUILD-BUILDTYPE 形式,其中 BUILD 是表示特定功能组合的代号。BUILDTYPE 是以下类型之一:

    编译类型 使用情况
    user 权限受限;适用于生产环境
    userdebug 与“user”类似,但具有 root 权限和可调试性;是进行调试时的首选编译类型
    eng 具有额外调试工具的开发配置

    源码编译

    您可以使用 make 编译任何代码。GNU make 可以借助 -jN 参数处理并行任务,通常使用的任务数 N 介于编译时所用计算机上硬件线程数的 1-2 倍之间。例如,在一台双核 E5520 计算机(2 个 CPU,每个 CPU 4 个内核,每个内核 2 个线程)上,要实现最快的编译速度,可以使用介于 make -j16 到 make -j32 之间的命令。

    make -j4
    

    如果编译完一个版本后想重新编译一个,可以使用 make clobber清除之前编译生成的文件。我们编译产生的文件都在 out文件夹下。

    启动模拟器

    编译成功后,输入emulator可启动模拟器

    四、如何查看源码的版本

    方法一:

    每次执行完lunch后下次进入基本就忘记上次编译的参数设置,可以使用printconfig命令显示当前的设置

    方法二:

    1、 从代码中查看当前版本,找到如下文件

    build\make\core\version_defaults.mk
    

    搜索关键字 PLATFORM_VERSION

    # This is the canonical definition of the platform version,
    # which is the version that we reveal to the end user.
    # Update this value when the platform version changes (rather
    # than overriding it somewhere else).  Can be an arbitrary string.
    
    # When you add a new PLATFORM_VERSION which will result in a new
    # PLATFORM_SDK_VERSION please ensure you add a corresponding isAtLeast*
    # method in the following java file:
    # frameworks/support/compat/gingerbread/android/support/v4/os/BuildCompat.java
    
    # When you change PLATFORM_VERSION for a given PLATFORM_SDK_VERSION
    # please add that PLATFORM_VERSION to the following text file:
    # cts/tests/tests/os/assets/platform_versions.txt
    PLATFORM_VERSION.OPR1 := 8.0.0
    

    五、错误及解决方法

    由于在Ubuntu上开发,很多常用软件都没有,所以后来又在mac上编译源码,遇到不少问题,下面来分享一下

    错误 1、Could not find a supported mac sdk: [“10.10” “10.11” “10.12” “10.13” “10.14”]

    两种解决方法:

    1. 把当前系统有的sdk 版本,加入到这个列表中
    2. 下载列表中的sdk

    具体操作,下载地址,可以参考这里

    错误 2、在mac 10.15.4 上编译Android 8.0.0_r1 ,出现bad cpu type in executable

    这篇文章 也遇到这个错误,但是报错细节、Android版本号 和我的不一样,所以我暂时没有去尝试

    在苹果官网看到 关于bad cpu type in executable 回复 的,

    想了一下,既然Mac 10.15 支持64位,不支持32位,那就用新版Android吧,免得Android 8.0.0_r1 上越改问题越多

    错误3、在mac 10.15.4上编译Android10.0.0_r1,

    Android10.0.0_r1 是支持64位的,但是在编译过程中一定会遇到这个错误

    FAILED: build out/target/product/generic_x86_64/obj/ETC/sepolicy_tests_intermediates/sepolicy_tests
    Outputs: out/target/product/generic_x86_64/obj/ETC/sepolicy_tests_intermediates/sepolicy_tests
    Error: exited with code: 1
    Command: /bin/bash -c "(out/host/darwin-x86/bin/sepolicy_tests -l out/host/darwin-x86/lib64/libsepolwrap.dylib       -f out/target/product/generic_x86_64/obj/ETC/plat_file_contexts_intermediates/plat_file_contexts  -f out/target/product/generic_x86_64/obj/ETC/vendor_file_contexts_intermediates/vendor_file_contexts  -p out/target/product/generic_x86_64/obj/ETC/sepolicy_intermediates/sepolicy ) && (touch out/target/product/generic_x86_64/obj/ETC/sepolicy_tests_intermediates/sepolicy_tests )"
    Output:
    /bin/bash: line 1: 28159 Segmentation fault: 11  ( out/host/darwin-x86/bin/sepolicy_tests -l out/host/darwin-x86/lib64/libsepolwrap.dylib -f out/target/product/generic_x86_64/obj/ETC/plat_file_contexts_intermediates/plat_file_contexts -f out/target/product/generic_x86_64/obj/ETC/vendor_file_contexts_intermediates/vendor_file_contexts -p out/target/product/generic_x86_64/obj/ETC/sepolicy_intermediates/sepolicy )
    

    这个错误是与mac 10.15 兼容问题,可通过这个临时解决

    make SELINUX_IGNORE_NEVERALLOWS=true
    

    还有个官方方案,打上下面的patch:(我是使用这个方法解决的)
    1f944107a3341ab593c93bbdf09e22436cc0e3d3

    官方就是修改 system/sepolicy/tests/Android.bp 去掉stl: “libc++_static”,

    下面这个是Catalina MacOS SDK 10.15的patch:
    89dad60ed5ec30b0f732b612d454151abdb4e449

    出自这篇文章:AOSP SELinux error

    错误4、Mac 下编译 关于 文件格式

    注意在mac 上编译,磁盘格式最好使用 Mac OS扩展(区分大小写,日志式),我在APFS 上解压aosp-laster.rar、同步代码、编译,完整操作了两次都不行。遇到同样的错误,也没再网上找到答案。也有可能是其它原因,按照官方的最好

    六、使用Android studio 查看源码

    Android Studio 导入 Android 源码

    IntelliJ IDEA导入Android源码

    注意:执行命令的时候,需要在bash 环境下,不能再zsh 环境下

    参考:
    官方文档:准备编译
    自己动手编译Android源码(超详细)
    Android 源码下载 到 编译全过程
    从源码中查看当前android版本
    android aosp编译的一些辅助命令

    展开全文
  • Android 源码下载 到 编译全过程

    千次阅读 2018-08-19 21:37:32
    近日网速还算可以,于是乎决定下载一下Android源...那对于需要编译Android的开发者来说,要分别clone 每个git项目而且还要放到固定的位置确实是件惨绝人寰的w事,所以Google就开发了一个基于Python编写的帮助开发...

    近日网速还算可以,于是乎决定下载一下Android源代码以供在家研究学习。下载之前先认识一下repo,整个Android源码是由很多个git项目构成,Google对Android代码的更新也是更新到相应模块的git项目上。那对于需要编译Android的开发者来说,要分别clone 每个git项目而且还要放到固定的位置确实是件惨绝人寰的w事,所以Google就开发了一个基于Python编写的帮助开发者管理多个项目的工具,这个工具就叫repo,说白了repo就是封装了git命令的python脚本。

    知道repo之后就下来就来研究一下怎么把Android源码弄下来,下载Android通常有两种方式,一种是直接用repo命令,直接了当,但是问题是需要浪费很长的时间,具体操作如下

    • 下载repo

                Google的repo下载比较麻烦,需要翻墙。建议用清华源上提供的,点击查看。

    • repo init -u https://aosp.tuna.tsinghua.edu.cn/platform/manifest -b android-cts-7.0_r22
    • repo sync -j6  -f (这个过程经常中断,要多执行几次才可以)
       

    第二种Android源码的方式是先下载个初始包,然后在执行repo sync进行代码同步即可

    • wget -c -t 0 https://mirrors.tuna.tsinghua.edu.cn/aosp-monthly/aosp-latest.tar
    • tar -xvf aosp-latest.tar
    • repo init -u https://aosp.tuna.tsinghua.edu.cn/platform/manifest -b android-cts-7.0_r22
    • repo sync

    无论以上那种方式获取Android代码都是一个非常耗时的过程,建议在临睡觉前进行代码同步,等第二天醒来就差不多同步完成了。

    获取完代码之后接下来就是紧张又刺激的编译环节

    1. 首先进入Android源码目录,进行如下操作
    ll@ll-pc:~/android/aosp$ source build/envsetup.sh 
    including device/generic/mini-emulator-arm64/vendorsetup.sh
    including device/generic/mini-emulator-armv7-a-neon/vendorsetup.sh
    including device/generic/mini-emulator-x86_64/vendorsetup.sh
    including device/generic/mini-emulator-x86/vendorsetup.sh
    including device/google/dragon/vendorsetup.sh
    including device/google/marlin/vendorsetup.sh
    including device/huawei/angler/vendorsetup.sh
    including device/lge/bullhead/vendorsetup.sh
    including device/linaro/hikey/vendorsetup.sh
    including sdk/bash_completion/adb.bash
    ll@ll-pc:~/android/aosp$ 
    ll@ll-pc:~/android/aosp$ lunch 
    
    You're building on Linux
    
    Lunch menu... pick a combo:
         1. aosp_arm-eng
         2. aosp_arm64-eng
         3. aosp_mips-eng
         4. aosp_mips64-eng
         5. aosp_x86-eng
         6. aosp_x86_64-eng
         7. mini_emulator_arm64-userdebug
         8. m_e_arm-userdebug
         9. mini_emulator_x86_64-userdebug
         10. mini_emulator_x86-userdebug
         11. aosp_dragon-userdebug
         12. aosp_dragon-eng
         13. aosp_marlin-userdebug
         14. aosp_sailfish-userdebug
         15. aosp_angler-userdebug
         16. aosp_bullhead-userdebug
         17. hikey-userdebug
    
    Which would you like? [aosp_arm-eng] 9
    
    ============================================
    PLATFORM_VERSION_CODENAME=REL
    PLATFORM_VERSION=7.1.1
    TARGET_PRODUCT=mini_emulator_x86_64
    TARGET_BUILD_VARIANT=userdebug
    TARGET_BUILD_TYPE=release
    TARGET_BUILD_APPS=
    TARGET_ARCH=x86_64
    TARGET_ARCH_VARIANT=x86_64
    TARGET_CPU_VARIANT=
    TARGET_2ND_ARCH=x86
    TARGET_2ND_ARCH_VARIANT=x86
    TARGET_2ND_CPU_VARIANT=
    HOST_ARCH=x86_64
    HOST_2ND_ARCH=x86
    HOST_OS=linux
    HOST_OS_EXTRA=Linux-4.13.0-45-generic-x86_64-with-Ubuntu-16.04-xenial
    HOST_CROSS_OS=windows
    HOST_CROSS_ARCH=x86
    HOST_CROSS_2ND_ARCH=x86_64
    HOST_BUILD_TYPE=release
    BUILD_ID=N9F27M
    OUT_DIR=out
    ============================================
    ll@ll-pc:~/android/aosp$ 
    

     

    ll@ll-pc:~/android/aosp$ make -j8
    

    接下来就是漫长的等待过程,上面执行lunch之后的选项是针对不同平台的,根据实际情况去选择,我这里选择了9,make -j8 中的8 是指线程的数量,就是要用几个线程去编译,通常是cpu核心的2倍。

     

    Android编译过程会遇到各式各样的问题,不同的主机也会出现不同的问题,这时就需要我们沉着面对、冷静思考,多搜搜资料问题肯定会被解决的。下面是我这次编译过程所遇到的问题

    1. including ./art/Android.mk ...
      build/core/java.mk:26: *** art/tools/amm: Invalid LOCAL_SDK_VERSION 'current' Choices are: test_current .
      build/core/ninja.mk:163: recipe for target 'out/build-mini_emulator_x86_64.ninja' failed
      make: *** [out/build-mini_emulator_x86_64.ninja] Error 1
      
      解决方法:由于本人的疏忽大意,没有对manifest.xml 进行初始化,而是直接使用的是master分支上的manifest.xml,repo sync之后使用repo forall -c git checkut  android-7.1.1_r22强制切换的分支,导致源码不完整或者源码各模块版本不一致,从而导致了这个问题,解决办法是在repo sync 之前先执行 repo init -u https://aosp.tuna.tsinghua.edu.cn/platform/manifest -b android-cts-7.0_r22,然后再repo sync,这个问题就解决了。
    2. [  0% 8/27631] host C: libcrypto-host_32 <= external/boringssl/src/crypto/rsa/padding.c
      ninja: build stopped: subcommand failed.
      build/core/ninja.mk:148: recipe for target 'ninja_wrapper' failed
      make: *** [ninja_wrapper] Error 1
      解决方法:刚开始编译就出现问题,首先想到的就是环境没有配对,又出现了
      "ninja_wrapper"

      这样的字样,估计是jack的问题,于是看了下home下是否有jack相关配置文件,结果不出所料,没有看到jack的配置文件,于是执行如下命令进行jack 初始化配置即解决问题

      ll@ll-pc:~/android/aosp/prebuilts/sdk/tools$ ls
      Android.mk                jack-server-4.8.ALPHA.jar
      darwin                    jack_server_setup.mk
      dx                        jack_versions.mk
      jack                      jills
      jack-admin                lib
      jack-annotations.jar      linux
      jack-coverage-plugin.jar  mainDexClasses
      jack-diagnose             mainDexClasses.rules
      jack_for_module.mk        README-jack-code-coverage.md
      jack-jacoco-reporter.jar  README-jack-server.md
      jack-launcher.jar         windows
      jacks
      ll@ll-pc:~/android/aosp/prebuilts/sdk/tools$ ./jack-admin install-server jack-launcher.jar jack-server-4.8.ALPHA.jar
      Installing jack server in "/home/ll/.jack-server"
      
      Warning:
      JKS 密钥库使用专用格式。建议使用 "keytool -importkeystore -srckeystore /home/ll/.jack-server/server.jks -destkeystore /home/ll/.jack-server/server.jks -deststoretype pkcs12" 迁移到行业标准格式 PKCS12。
      
      Warning:
      JKS 密钥库使用专用格式。建议使用 "keytool -importkeystore -srckeystore /home/ll/.jack-server/client.jks -destkeystore /home/ll/.jack-server/client.jks -deststoretype pkcs12" 迁移到行业标准格式 PKCS12。
      ll@ll-pc:~/android/aosp/prebuilts/sdk/tools$ 
      jack-server-4.8.ALPHA.jar
      darwin                    jack_server_setup.mk
      dx                        jack_versions.mk
      jack                      jills
      jack-admin                lib
      jack-annotations.jar      linux
      jack-coverage-plugin.jar  mainDexClasses
      jack-diagnose             mainDexClasses.rules
      jack_for_module.mk        README-jack-code-coverage.md
      jack-jacoco-reporter.jar  README-jack-server.md
      jack-launcher.jar         windows
      jacks
      ll@ll-pc:~/android/aosp/prebuilts/sdk/tools$ ./jack-admin install-server jack-launcher.jar jack-server-4.8.ALPHA.jar
      Installing jack server in "/home/ll/.jack-server"
      
      Warning:
      JKS 密钥库使用专用格式。建议使用 "keytool -importkeystore -srckeystore /home/ll/.jack-server/server.jks -destkeystore /home/ll/.jack-server/server.jks -deststoretype pkcs12" 迁移到行业标准格式 PKCS12。
      
      Warning:
      JKS 密钥库使用专用格式。建议使用 "keytool -importkeystore -srckeystore /home/ll/.jack-server/client.jks -destkeystore /home/ll/.jack-server/client.jks -deststoretype pkcs12" 迁移到行业标准格式 PKCS12。
      ll@ll-pc:~/android/aosp/prebuilts/sdk/tools$ 
      

       
    3. intermediates/build.prop ) && (cat out/target/product/mini-emulator-armv7-a-neon/android-info.txt | grep 'require version-' | sed -e 's/require version-/ro.build.expect./g' >> out/target/product/mini-emulator-armv7-a-neon/obj/ETC/system_build_prop_intermediates/build.prop ) && (build/tools/post_process_props.py out/target/product/mini-emulator-armv7-a-neon/obj/ETC/system_build_prop_intermediates/build.prop )"
      error: ro.build.fingerprint cannot exceed 91 bytes: Android/mini_emulator_arm64/mini-emulator-armv7-a-neon:7.1.1/N8I11B/ll07151211:userdebug/test-keys (98)
      [ 17% 5755/33411] host C: sqlite3 <= external/sqlite/dist/sqlite3.c
      ninja: build stopped: subcommand failed.
      build/core/ninja.mk:148: recipe for target 'ninja_wrapper' failed
      make: *** [ninja_wrapper] Error error: ro.build.fingerprint cannot exceed 91 bytes: Android/mini_emulator_arm64/mini-emulator-armv7-a-neon:7.1.1/N8I11B/ll07151211:userdebug/test-keys (98)
      [ 17% 5755/33411] host C: sqlite3 <= external/sqlite/dist/sqlite3.c
      ninja: build stopped: subcommand failed.
      build/core/ninja.mk:148: recipe for target 'ninja_wrapper' failed
      make: *** [ninja_wrapper] Error 

    解决方法

    这里是说value的长度超过限制

     

    • 修改 build/tools/post_process_props.py 如下:

    PROP_NAME_MAX = 31

    # PROP_VALUE_MAX = 91

    PROP_VALUE_MAX = 127
     

    • 修改 bionic/libc/include/sys/system_properties.h 如下:

    #define PROP_NAME_MAX   32
    // #define PROP_VALUE_MAX  92
    #define PROP_VALUE_MAX  128

        

     

    •  修改  native/cmds/installd/installd_deps.h

    // Size constants. Should be checked to be equal to the cutils requirements.
    constexpr size_t kPropertyKeyMax = 32u;
    //constexpr size_t kPropertyValueMax = 92u;
    constexpr size_t kPropertyValueMax = 128u;

     

     

    经过漫长的等待,终于编译完成

    [ 94% 13560/14334] host Java: ahat-tests (out/...VA_LIBRARIES/ahat-tests_intermediates/classes)
    注: art/tools/ahat/test/SortTest.java使用了未经检查或不安全的操作。
    注: 有关详细信息, 请使用 -Xlint:unchecked 重新编译。
    [ 95% 13721/14334] host Java: android-icu4j-ho...RIES/android-icu4j-host_intermediates/classes)
    注: 某些输入文件使用或覆盖了已过时的 API。
    注: 有关详细信息, 请使用 -Xlint:deprecation 重新编译。
    注: external/icu/android_icu4j/src/main/java/android/icu/impl/Relation.java使用了未经检查或不安全的操作。
    注: 有关详细信息, 请使用 -Xlint:unchecked 重新编译。
    [ 96% 13859/14334] host Java: android-icu4j-te...ndroid-icu4j-tests-host_intermediates/classes)
    注: 某些输入文件使用或覆盖了已过时的 API。
    注: 有关详细信息, 请使用 -Xlint:deprecation 重新编译。
    注: 某些输入文件使用了未经检查或不安全的操作。
    注: 有关详细信息, 请使用 -Xlint:unchecked 重新编译。
    [100% 14334/14334] host Executable: primitives...itives_tests_intermediates/primitives_tests32)
    
    #### make completed successfully (01:10:01 (hh:mm:ss)) ####

    因为我编译的是

     mini_emulator_x86_64-userdebug

    模拟器版本,所以可以在pc端打开虚拟机

     

    展开全文
  • Android9.0 系统源码编译

    千次阅读 2019-10-31 17:57:15
    Android P 发布已经好久了,今天来尝一尝这块Pie。 编译环境 Ubuntu18.04, 双系统环境 PC机,内存32G,CPU 16 核心,I7八代。 源码下载 镜像源 : https://aosp.tuna.tsinghua.edu.cn 准备环境 下载 git : sudo ...

    两个多月没写博客了,感觉不会再爱了。Android P 发布已经好久了,今天来尝一尝这块Pie。

    编译环境

    1. Ubuntu18.04, 双系统环境
    2. PC机,内存32G,CPU 16 核心,I7八代。

    源码下载

    1. 镜像源 : https://aosp.tuna.tsinghua.edu.cn
    2. 准备环境

    下载 git :

    sudo apt-get install git
    

    安装curl库:

    sudo apt-get install curl
    

    下载repo并设置权限:

    curl https://mirrors.tuna.tsinghua.edu.cn/git/git-repo > ~/bin/repo
    chmod a+x ~/bin/repo
    

    安装python :

    sudo apt-get install python
    
    1. 下载源码

    建立工程目录:

    mkdir aosp
    cd aosp
    

    使用tanna源

    export REPO_URL='https://mirrors.tuna.tsinghua.edu.cn/git/git-repo/'
    

    设置账户:

    git config --global user.email "xxxxxxx@gmail.com"
    git config --global user.name "xxxxx"
    

    初始化仓库:

    repo init -u https://aosp.tuna.tsinghua.edu.cn/platform/manifest
    

    指定Android版本并初始化:

    repo init -u https://aosp.tuna.tsinghua.edu.cn/platform/manifest -b android-9.0.0_r8
    

    同步源码:

    repo sync
    

    最终源码下载结果:

    在这里插入图片描述

    源码编译

    1. 安装openjdk8
    2. 安装依赖
    sudo apt-get install libx11-dev:i386 libreadline6-dev:i386 libgl1-mesa-dev g++-multilib
    sudo apt-get install -y git flex bison gperf build-essential libncurses5-dev:i386
    sudo apt-get install tofrodos python-markdown libxml2-utils xsltproc zlib1g-dev:i386
    sudo apt-get install dpkg-dev libsdl1.2-dev libesd0-dev
    sudo apt-get install git-core gnupg flex bison gperf build-essential
    sudo apt-get install zip curl zlib1g-dev gcc-multilib g++-multilib
    sudo apt-get install libc6-dev-i386
    sudo apt-get install lib32ncurses5-dev x11proto-core-dev libx11-dev
    sudo apt-get install libgl1-mesa-dev libxml2-utils xsltproc unzip m4
    sudo apt-get install lib32z-dev ccache
    sudo apt-get install libssl-dev
    
    1. 开始编译, launch后选择要编译的工程版本,输入序列号
    source build/envsetup.sh
    lunch 6
    make -j16
    

    编译结果如下,耗时 01:44:59 ( hh::mm::ss )
    在这里插入图片描述
    编译后整个aosp目录和out目录大小为:119.2GB 和 82.7GB, 占用空间很大。out目录中有分析用的重要的中间文件。

    展开全文
  • 自己动手编译Android源码(超详细) 涅槃1992 2016.06.20 02:12* 字数 43...
  • Android编译过程

    千次阅读 2018-08-21 18:36:13
    当前目录下编译执行,相当于在android目录下执行make 本文介绍Android编译过程及各种mk文件的导入 1.编译 a.编译步骤 清理 sh $ make clobber 初始化环境 sh $ source ./build/envetup.sh # 这个...
  • Android的Build系统非常的庞大,他是基于GUN Make以及shell来构建的,我们主要的面对方向是Android.mk文件,这也是Android为我们处理好的,不用直接跟shell打交道,Build不光可以处理系统的编译打包,还能生成img...
  • MNN编译安装 (Android编译) 二. 测试benchmark (Benchmark工具) 一. MNN编译安装 (Android编译) 1.编译选项 cmake_minimum_required(VERSION 2.8) project(MNN) # complier options set(CMAKE_C_STANDARD 99...
  • Android Studio设置自动编译工程

    万次阅读 2014-06-30 13:47:51
    在Eclipse使用习惯了自动编译的兄弟们,刚迁移到Android Studio,肯定也很怀念这功能,自动编译意味着每次运行都能缩短很多时间。 Android Studio里面其实也是有自动编译功能的,不过个人觉得还是不如Eclipse好使。...
  • 1.更新到最新版本androidstudio2.随便编译一个demo.apk,记得是发布版本3.编译完成后点击Module 'app': locate or analyze the APK. 4.选择任何一个apk
  • Android Studio 单独编译一个 Module

    万次阅读 2016-10-14 10:57:16
    现在我的一个 project 下面有多个 moudle ,一开始不知道如何单独编译某个 moudle , 现在记录下./grawdlew your_moudle_name:task_name
  • android源码根目录下,执行以下三步即可编译android: 1. build/envsetup.sh #这个脚本用来设置android编译环境; 2. lunch #选择编译目标 3. make #编译android整个系统android平台提供了三个命令用于编译,这...
  • 1.第一次因为项目开始使用Android Studio,觉得还不错。提高了不少开发效率。然后令人头疼的就是编译慢成一坨翔,Clean一次就要7分钟多。而且还各种郁闷,同样的代码,在同事电脑就可以运行,在我这里却报错。 2....
  • Android Studio编译好的apk放在哪里?

    万次阅读 多人点赞 2014-07-11 11:07:06
    Eclipse中编译好的apk文件时在bin文件里面的,但是在Android Studio有一个比较大的改动了,编译好的apk在android studio里面是直接看不到了,而且apk文件所在目录也变了,那apk文件放在哪呢,你要在硬盘中找到对应的...
  •  在一个项目中,如果我们想要对全部类文件及配置文件进行重新编译,在Eclipse可以采取如下办法: 在Eclipse下,选中Project下的Clean一项,进入之后可以看到Clean all projects选后点“OK”就可以了。...
  • androidkiller反编译失败可能解决方案

    万次阅读 2019-03-01 10:05:01
    Exception in thread “main” java.lang.ClassCastException反编译核心都是apktool,出现以上报错可能是你反编译的apk编写的版本比较高,我们只需要简单把apktool版本替换到最高 1.apktool官网下载2.这个是我整理...
  • 有很多东西都是值得我们研究的,它的运行速度影响着我们编程的效率,当android studio使用了一段时间后它的运行速度和编译速度都是有可能会变慢的,我们可以通过进行相关的设置来解决android studio运行编译速度慢的...
  • Android Studio提高编译速度的方法

    万次阅读 2017-12-22 13:47:35
    Android Studio编译速度有时候是非常慢的,每次会自动检查依赖的库文件是否更新,受制于国内网络和翻墙更新一些资源限制gradle的编译速度是非常慢的,接下来介绍几个方法能够快速的提高变速度。 第一步:  减少...
  • 1、在源码目录的根目录下,makeclean; 2、进到源码的\linux\kernel\目录下,执行makemrproper; 3、再退回到根目录,执行sourcebuild/envsetup.sh,lunch,make.
  • 在目录C:\Users.gradle下添加gradle.properties文件,设置守护进程,编译速度9s 1. org.gradle.daemon=true 开启守护进程 2. org.gradle.parallel=true 开启并行编译 3. org.gradle.configureondemand=tr...
1 2 3 4 5 ... 20
收藏数 311,662
精华内容 124,664
关键字:

android编译