跳至主要內容

创建属于自己的产品


创建属于自己的产品

我们先梳理清楚我们在编译的时候,这个过得干了啥!!

首次我们是设置环境

aosp@ubuntu:~/android5.1$ source build/envsetup.sh 
including device/lge/hammerhead/vendorsetup.sh
including device/lge/mako/vendorsetup.sh
including device/samsung/manta/vendorsetup.sh
including device/generic/mini-emulator-arm64/vendorsetup.sh
including device/generic/mini-emulator-x86_64/vendorsetup.sh
including device/generic/mini-emulator-armv7-a-neon/vendorsetup.sh
including device/generic/mini-emulator-x86/vendorsetup.sh
including device/generic/mini-emulator-mips/vendorsetup.sh
including device/moto/shamu/vendorsetup.sh
including device/asus/flo/vendorsetup.sh
including device/asus/tilapia/vendorsetup.sh
including device/asus/deb/vendorsetup.sh
including device/asus/grouper/vendorsetup.sh
including device/asus/fugu/vendorsetup.sh
including device/htc/flounder/vendorsetup.sh
including sdk/bash_completion/adb.bash

然后加载编译目标

aosp@ubuntu:~/android5.1$ 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. aosp_hammerhead-userdebug
     8. aosp_mako-userdebug
     9. aosp_manta-userdebug
     10. mini_emulator_arm64-userdebug
     11. mini_emulator_x86_64-userdebug
     12. m_e_arm-userdebug
     13. mini_emulator_x86-userdebug
     14. mini_emulator_mips-userdebug
     15. aosp_shamu-userdebug
     16. aosp_flo-userdebug
     17. aosp_tilapia-userdebug
     18. aosp_deb-userdebug
     19. aosp_grouper-userdebug
     20. full_fugu-userdebug
     21. aosp_fugu-userdebug
     22. aosp_flounder-userdebug

Which would you like? [aosp_arm-eng] 

okay,到这里,我们的疑问就来了,这些构建目标是怎么来的呢?

首先是我们的lunch命令,如果不source build/envsetup.sh是没有这个命令的。

我们可以看一下build/envsetup.sh脚本的代码,可以发现launch就在里面

function lunch()
{
	# 选项结果,也就是我们前面输入的5
    local answer
	
	# 有携带参数,直接结果就是参数了
    if [ "$1" ] ; then
        answer=$1
    else
    # 没有携带参数,那么就输出lunch列表
    #print_lunch_menu就是我们看到的列表了
        print_lunch_menu
        echo -n "Which would you like? [aosp_arm-eng] "
        # 读取选项值
        read answer
    fi
    ....省略代码....
}

先看到这里,我们就知道了,列表是print_lunch_menu输出的

我们接下来的课程,创建属于自己的产品,就是在这里有个编译选项,然后去编译我们自己的内容。

所以呢,我们看看这个输出列表是怎么来的。

function print_lunch_menu()
{
    local uname=$(uname)
    echo
    echo "You're building on" $uname
    echo
    echo "Lunch menu... pick a combo:"

    local i=1
    local choice
    # 列表在这里:
    for choice in ${LUNCH_MENU_CHOICES[@]}
    do
        echo "     $i. $choice"
        i=$(($i+1))
    done

    echo
}

那么我们就看看LUNCH_MENU_CHOICES这个是在哪里赋值的

# Clear this variable.  It will be built up again when the vendorsetup.sh
# files are included at the end of this file.
unset LUNCH_MENU_CHOICES
function add_lunch_combo()
{
    local new_combo=$1
    local c
    for c in ${LUNCH_MENU_CHOICES[@]} ; do
        if [ "$new_combo" = "$c" ] ; then
            return
        fi
    done
    LUNCH_MENU_CHOICES=(${LUNCH_MENU_CHOICES[@]} $new_combo)
}

# add the default one here
add_lunch_combo aosp_arm-eng
add_lunch_combo aosp_arm64-eng
add_lunch_combo aosp_mips-eng
add_lunch_combo aosp_mips64-eng
add_lunch_combo aosp_x86-eng
add_lunch_combo aosp_x86_64-eng

这样子,前6个就有了,我们可以做一下实验,注释掉看看。

修改了envsetup.sh文件,需要重新载入到环境中,再lunch一次,我们就会发现没了。

okay,到这里可以确定,这个是在这里添加了。

接下来呢,我们探讨一下其他的是在哪里添加的。同学们凭借着自己的经验,知道如何寻找出来吗?

如果你不知道的,可以搜索,如果你代码经验,第一反映应该是这些地方调用了add_lunch_combo

aosp@ubuntu:~/android5.1$ source build/envsetup.sh 
including device/lge/hammerhead/vendorsetup.sh
including device/lge/mako/vendorsetup.sh
including device/samsung/manta/vendorsetup.sh
including device/generic/mini-emulator-arm64/vendorsetup.sh
including device/generic/mini-emulator-x86_64/vendorsetup.sh
including device/generic/mini-emulator-armv7-a-neon/vendorsetup.sh
including device/generic/mini-emulator-x86/vendorsetup.sh
including device/generic/mini-emulator-mips/vendorsetup.sh
including device/moto/shamu/vendorsetup.sh
including device/asus/flo/vendorsetup.sh
including device/asus/tilapia/vendorsetup.sh
including device/asus/deb/vendorsetup.sh
including device/asus/grouper/vendorsetup.sh
including device/asus/fugu/vendorsetup.sh
including device/htc/flounder/vendorsetup.sh
including sdk/bash_completion/adb.bash

那这些又是在哪里include的呢?

# Execute the contents of any vendorsetup.sh files we can find.
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

在我们的device目录下第一层

image-20211123222504246
image-20211123222504246

最深不超过4层,找到vendorsetup.sh,以及vendor目录下,一般厂商定义的会在vendor目录下。但是我们平时开发一般不遵守的,因为打开文件的时候真的麻烦。打开两个地方。

到这里,我们随便找一个vendorsetup.sh文件查看一下。

比如说:

including device/lge/hammerhead/vendorsetup.sh

我们就发现

add_lunch_combo aosp_hammerhead-userdebug

卧草,这不就是跟前面一样,okay,这样子就添加进列表里去了。那添加进去只是个名字呀,这个名字怎么样起作用呢?

我们双回到最开始lunch的命令下,看看我们选择了5以后,干了啥。

function lunch()
{
    local answer

 	....省略代码,目标列表已经输出,answer值也得到了....

	# 定义一个选项变量
    local selection=

	# 如果答案长度为0,那默认是aosp_arm-eng
    if [ -z "$answer" ]
    then
        selection=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
        # 如果输入的是名字串,直接就等于answer了
        # 这里其实不安全的,同学们可以模拟一下骗过它,不过后面还有判断,也没关系
    elif (echo -n $answer | grep -q -e "^[^\-][^\-]*-[^\-][^\-]*$")
    then
        selection=$answer
    fi
	# 一顿操作之后,判断是不是选了存在的,如果不存在就告诉你这玩意无效
    if [ -z "$selection" ]
    then
        echo
        echo "Invalid lunch combo: $answer"
        return 1
    fi

	# 到这里selection是有值的了
	# 把环境中的TARGET_BUILD_APPS设置为空
    export TARGET_BUILD_APPS=
	
	# 对名字串里的-xxx替换掉
	# aosp_x86-eng变成aosp_x86
    local product=$(echo -n $selection | sed -e "s/-.*$//")
    # 检查产品是否有的,如果返回值不为0,说明产品不对,也就是选择的/输入的不对。
    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
    ....省略代码....
}

到这里我们先去看一个分支,检查产品,看看检查产品干了啥

# check to see if the supplied product is one we can build
function check_product()
{
	# 获取到工作目录/home/aosp/android5.1
    T=$(gettop)
    if [ ! "$T" ]; then
        echo "Couldn't locate the top of the tree.  Try setting TOP." >&2
        return
    fi
        TARGET_PRODUCT=$1 \
        TARGET_BUILD_VARIANT= \
        TARGET_BUILD_TYPE= \
        TARGET_BUILD_APPS= \
        get_build_var TARGET_DEVICE > /dev/null
    # hide successful answers, but allow the errors to show
}

设置TARGET_PRODUCT变量值,$1就是我们前面传进来的第一个参数$product

然后调用get_build_var

# Get the exact value of a build variable.
function get_build_var()
{
    T=$(gettop)
    if [ ! "$T" ]; then
        echo "Couldn't locate the top of the tree.  Try setting TOP." >&2
        return
    fi
    # 设置变量,载入config.mk文件,mk文件由make去解析
    (\cd $T; CALLED_FROM_SETUP=true BUILD_SYSTEM=build/core \
      command make --no-print-directory -f build/core/config.mk dumpvar-$1)
}

也没干啥,设置变量,执行config.mk

我们回到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
    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=
    local product=$(echo -n $selection | sed -e "s/-.*$//")
	
	# 如果返回值不为0,那么就输出提示信息
    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

	# aosp_x86-eng变成eng了,也就是获取到构建类型是user版本,还是userdebug版本,又或者debug版本
	# 详情请看下方的构建类型说明
    local variant=$(echo -n $selection | sed -e "s/^[^\-]*-//")
    # 检查是不是对的
    check_variant $variant
    if [ $? -ne 0 ]
    then
        echo
        echo "** Invalid variant: '$variant'"
        echo "** Must be one of ${VARIANT_CHOICES[@]}"
        variant=
    fi
	...省略代码...
}

关于构建类型的说明:

image-20211127201332324
image-20211127201332324

check_variant $variant

VARIANT_CHOICES=(user userdebug eng)

# check to see if the supplied variant is valid
function check_variant()
{
    for v in ${VARIANT_CHOICES[@]}
    do
        if [ "$v" = "$1" ]
        then
            return 0
        fi
    done
    return 1
}

可以看出,只有三种构建类型。

okay,继续往下去看看

function lunch()
{
   	
   	...省略代码...
   	# 再对产品和构建类型进行检查
    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
}

set_stuff_for_environment,这里面又分了几个分支去做其他事情

  • settitle 设置标题
  • set_java_home 设置java的路径
  • setpaths 设置环境变量
  • set_sequence_number 设置序号
function set_stuff_for_environment()
{
    settitle
    set_java_home
    setpaths
    set_sequence_number

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

printconfig 输出配置信息

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

下面我们对比一下,lunch前后的配置信息

============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=5.1
TARGET_PRODUCT=full
TARGET_BUILD_VARIANT=eng
TARGET_BUILD_TYPE=release
TARGET_BUILD_APPS=
TARGET_ARCH=arm
TARGET_ARCH_VARIANT=armv7-a
TARGET_CPU_VARIANT=generic
TARGET_2ND_ARCH=
TARGET_2ND_ARCH_VARIANT=
TARGET_2ND_CPU_VARIANT=
HOST_ARCH=x86_64
HOST_OS=linux
HOST_OS_EXTRA=Linux-5.4.0-90-generic-x86_64-with-Ubuntu-18.04-bionic
HOST_BUILD_TYPE=release
BUILD_ID=LMY47D
OUT_DIR=out
============================================

lunch 5. aosp_x86-eng 之后

============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=5.1
TARGET_PRODUCT=aosp_x86
TARGET_BUILD_VARIANT=eng
TARGET_BUILD_TYPE=release
TARGET_BUILD_APPS=
TARGET_ARCH=x86
TARGET_ARCH_VARIANT=x86
TARGET_CPU_VARIANT=
TARGET_2ND_ARCH=
TARGET_2ND_ARCH_VARIANT=
TARGET_2ND_CPU_VARIANT=
HOST_ARCH=x86_64
HOST_OS=linux
HOST_OS_EXTRA=Linux-5.4.0-90-generic-x86_64-with-Ubuntu-18.04-bionic
HOST_BUILD_TYPE=release
BUILD_ID=LMY47D
OUT_DIR=out
============================================

环境变量前后的区别

lunch之前的环境变量内容

aosp@ubuntu:~$ export
declare -x CLUTTER_IM_MODULE="xim"
declare -x COLORTERM="truecolor"
declare -x DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/1000/bus"
declare -x DESKTOP_AUTOSTART_ID="10d28aafa23347d7f3163801459414654300000034500007"
declare -x DESKTOP_SESSION="ubuntu"
declare -x DISPLAY=":0"
declare -x GDMSESSION="ubuntu"
declare -x GNOME_DESKTOP_SESSION_ID="this-is-deprecated"
declare -x GNOME_SHELL_SESSION_MODE="ubuntu"
declare -x GNOME_TERMINAL_SCREEN="/org/gnome/Terminal/screen/c3085c45_2cae_4799_afb9_524095904c0b"
declare -x GNOME_TERMINAL_SERVICE=":1.88"
declare -x GPG_AGENT_INFO="/run/user/1000/gnupg/S.gpg-agent:0:1"
declare -x GTK_IM_MODULE="ibus"
declare -x GTK_MODULES="gail:atk-bridge"
declare -x HOME="/home/aosp"
declare -x IM_CONFIG_PHASE="2"
declare -x JAVA_HOME="/home/aosp/devTools/jdk1.7.0_80"
declare -x LANG="en_US.UTF-8"
declare -x LESSCLOSE="/usr/bin/lesspipe %s %s"
declare -x LESSOPEN="| /usr/bin/lesspipe %s"
declare -x LIBVIRT_DEFAULT_URI="qemu:///system"
declare -x LOGNAME="aosp"
declare -x LS_COLORS="rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.zst=01;31:*.tzst=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.wim=01;31:*.swm=01;31:*.dwm=01;31:*.esd=01;31:*.jpg=01;35:*.jpeg=01;35:*.mjpg=01;35:*.mjpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36:"
declare -x OLDPWD
declare -x PATH="/home/aosp/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/home/aosp/devTools/jdk1.7.0_80/bin"
declare -x PWD="/home/aosp"
declare -x QT4_IM_MODULE="xim"
declare -x QT_ACCESSIBILITY="1"
declare -x QT_IM_MODULE="ibus"
declare -x REPO_URL="https://mirrors.tuna.tsinghua.edu.cn/git/git-repo"
declare -x SESSION_MANAGER="local/ubuntu:@/tmp/.ICE-unix/3450,unix/ubuntu:/tmp/.ICE-unix/3450"
declare -x SHELL="/bin/bash"
declare -x SHLVL="1"
declare -x SSH_AGENT_PID="3552"
declare -x SSH_AUTH_SOCK="/run/user/1000/keyring/ssh"
declare -x TERM="xterm-256color"
declare -x TEXTDOMAIN="im-config"
declare -x TEXTDOMAINDIR="/usr/share/locale/"
declare -x USER="aosp"
declare -x USERNAME="aosp"
declare -x VTE_VERSION="5202"
declare -x WINDOWPATH="2"
declare -x XAUTHORITY="/run/user/1000/gdm/Xauthority"
declare -x XDG_CONFIG_DIRS="/etc/xdg/xdg-ubuntu:/etc/xdg"
declare -x XDG_CURRENT_DESKTOP="ubuntu:GNOME"
declare -x XDG_DATA_DIRS="/usr/share/ubuntu:/usr/local/share/:/usr/share/:/var/lib/snapd/desktop"
declare -x XDG_MENU_PREFIX="gnome-"
declare -x XDG_RUNTIME_DIR="/run/user/1000"
declare -x XDG_SEAT="seat0"
declare -x XDG_SESSION_DESKTOP="ubuntu"
declare -x XDG_SESSION_ID="2"
declare -x XDG_SESSION_TYPE="x11"
declare -x XDG_VTNR="2"
declare -x XMODIFIERS="@im=ibus"
aosp@ubuntu:~$ 

lunch之后

aosp@ubuntu:~/android5.1$ export
declare -x ANDROID_BUILD_PATHS="/home/aosp/android5.1/out/host/linux-x86/bin:/home/aosp/android5.1/prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.8/bin:/home/aosp/android5.1/prebuilts/gcc/linux-x86/:/home/aosp/android5.1/development/scripts:/home/aosp/android5.1/prebuilts/devtools/tools:/home/aosp/android5.1/prebuilts/android-emulator/linux-x86_64:"
declare -x ANDROID_BUILD_TOP="/home/aosp/android5.1"
declare -x ANDROID_DEV_SCRIPTS="/home/aosp/android5.1/development/scripts:/home/aosp/android5.1/prebuilts/devtools/tools"
declare -x ANDROID_EMULATOR_PREBUILTS="/home/aosp/android5.1/prebuilts/android-emulator/linux-x86_64"
declare -x ANDROID_HOST_OUT="/home/aosp/android5.1/out/host/linux-x86"
declare -x ANDROID_JAVA_TOOLCHAIN="/home/aosp/devTools/jdk1.7.0_80/bin"
declare -x ANDROID_PRE_BUILD_PATHS="/home/aosp/devTools/jdk1.7.0_80/bin:"
declare -x ANDROID_PRODUCT_OUT="/home/aosp/android5.1/out/target/product/generic_x86"
declare -x ANDROID_TOOLCHAIN="/home/aosp/android5.1/prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.8/bin"
declare -x ANDROID_TOOLCHAIN_2ND_ARCH="/home/aosp/android5.1/prebuilts/gcc/linux-x86/"
declare -x BUILD_ENV_SEQUENCE_NUMBER="10"
declare -x CLUTTER_IM_MODULE="xim"
declare -x COLORTERM="truecolor"
declare -x DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/1000/bus"
declare -x DESKTOP_AUTOSTART_ID="10d28aafa23347d7f3163801459414654300000034500007"
declare -x DESKTOP_SESSION="ubuntu"
declare -x DISPLAY=":0"
declare -x GCC_COLORS="error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01"
declare -x GDMSESSION="ubuntu"
declare -x GNOME_DESKTOP_SESSION_ID="this-is-deprecated"
declare -x GNOME_SHELL_SESSION_MODE="ubuntu"
declare -x GNOME_TERMINAL_SCREEN="/org/gnome/Terminal/screen/c3085c45_2cae_4799_afb9_524095904c0b"
declare -x GNOME_TERMINAL_SERVICE=":1.88"
declare -x GPG_AGENT_INFO="/run/user/1000/gnupg/S.gpg-agent:0:1"
declare -x GTK_IM_MODULE="ibus"
declare -x GTK_MODULES="gail:atk-bridge"
declare -x HOME="/home/aosp"
declare -x IM_CONFIG_PHASE="2"
declare -x JAVA_HOME="/home/aosp/devTools/jdk1.7.0_80"
declare -x LANG="en_US.UTF-8"
declare -x LC_ALL="C"
declare -x LESSCLOSE="/usr/bin/lesspipe %s %s"
declare -x LESSOPEN="| /usr/bin/lesspipe %s"
declare -x LIBVIRT_DEFAULT_URI="qemu:///system"
declare -x LOGNAME="aosp"
declare -x LS_COLORS="rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.zst=01;31:*.tzst=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.wim=01;31:*.swm=01;31:*.dwm=01;31:*.esd=01;31:*.jpg=01;35:*.jpeg=01;35:*.mjpg=01;35:*.mjpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36:"
declare -x OLDPWD="/home/aosp"
declare -x OUT="/home/aosp/android5.1/out/target/product/generic_x86"
declare -x PATH="/home/aosp/devTools/jdk1.7.0_80/bin:/home/aosp/android5.1/out/host/linux-x86/bin:/home/aosp/android5.1/prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.8/bin:/home/aosp/android5.1/prebuilts/gcc/linux-x86/:/home/aosp/android5.1/development/scripts:/home/aosp/android5.1/prebuilts/devtools/tools:/home/aosp/android5.1/prebuilts/android-emulator/linux-x86_64:/home/aosp/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/home/aosp/devTools/jdk1.7.0_80/bin"
declare -x PROMPT_COMMAND="echo -ne \"\\033]0;[x86-aosp_x86-eng] aosp@ubuntu: /home/aosp/android5.1\\007\""
declare -x PWD="/home/aosp/android5.1"
declare -x QT4_IM_MODULE="xim"
declare -x QT_ACCESSIBILITY="1"
declare -x QT_IM_MODULE="ibus"
declare -x REPO_URL="https://mirrors.tuna.tsinghua.edu.cn/git/git-repo"
declare -x SESSION_MANAGER="local/ubuntu:@/tmp/.ICE-unix/3450,unix/ubuntu:/tmp/.ICE-unix/3450"
declare -x SHELL="/bin/bash"
declare -x SHLVL="1"
declare -x SSH_AGENT_PID="3552"
declare -x SSH_AUTH_SOCK="/run/user/1000/keyring/ssh"
declare -x TARGET_BUILD_APPS=""
declare -x TARGET_BUILD_TYPE="release"
declare -x TARGET_BUILD_VARIANT="eng"
declare -x TARGET_GCC_VERSION="4.8"
declare -x TARGET_PRODUCT="aosp_x86"
declare -x TERM="xterm-256color"
declare -x TEXTDOMAIN="im-config"
declare -x TEXTDOMAINDIR="/usr/share/locale/"
declare -x USER="aosp"
declare -x USERNAME="aosp"
declare -x VTE_VERSION="5202"
declare -x WINDOWPATH="2"
declare -x XAUTHORITY="/run/user/1000/gdm/Xauthority"
declare -x XDG_CONFIG_DIRS="/etc/xdg/xdg-ubuntu:/etc/xdg"
declare -x XDG_CURRENT_DESKTOP="ubuntu:GNOME"
declare -x XDG_DATA_DIRS="/usr/share/ubuntu:/usr/local/share/:/usr/share/:/var/lib/snapd/desktop"
declare -x XDG_MENU_PREFIX="gnome-"
declare -x XDG_RUNTIME_DIR="/run/user/1000"
declare -x XDG_SEAT="seat0"
declare -x XDG_SESSION_DESKTOP="ubuntu"
declare -x XDG_SESSION_ID="2"
declare -x XDG_SESSION_TYPE="x11"
declare -x XDG_VTNR="2"
declare -x XMODIFIERS="@im=ibus"

注意观察ANDROID开关的,到这里我们就看完了lunch的过程了

接下来我们要创建属于我们自己的产品。

make 开始编译

我们lunch完选择构建目标,然后就make -j8,或者输出log的方式编译make -j8 2>&1 | tee build.log进行编译

那么make的时候到底是干了啥,入口是哪里呢?

首先,我们在源码根目录下make,这里面有一个文件叫做Makefile

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

它就include了build/core/main.mk,可以理解为调用这个文件,这个就是我们系统编译的入口了。

image-20211128124010265 这里可以看到我们的又include其他文件了

这里面有include和-include这两个的区别是啥呢?-include的话如果这个文件不存在,也会继续往下执行,如果是include就会提示no rule to make target

以上我们可以大概地得到这样一个关系图

image-20211128141147694
image-20211128141147694

在整个编译系统中,Android的makefile文件主要分成三类

  • 编译框架,也就是我们build/core目录下的mk文件,它其实就是控制我们编译的一个框架了,也就是控制编译的流程。
  • 产品定义,一般是在device目录下,或者vendor下。这就是为什么在创建产品之前和大家一直来了解编译流程,了解这些才知道如何去添加自己的产品。
    • 产品相关的,主板相关的
  • Android.mk,这个前面已经和大家接触过了,我们编译jar包,编译可执行文件,编译apk之类的。

由此我们知道,编译框架,就会去include产品的,各个模块里的Android.mk文件

产品的在哪里添加呢?

这个路线是这样子的:

main.mk--->config.mk--->envsetup.mk---->product_config.mk

image-20211128183257545
image-20211128183257545

在product.mk里,就会去查找device目录下,vendor目录下,target目录下的AndroidProducts.mk文件

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

_find-android-products-files就是所找到的AndroidProducts.mk文件列表了

然后值就到了get-all-product-makefiles

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

#
# Returns the sorted concatenation of all PRODUCT_MAKEFILES
# variables set in all AndroidProducts.mk files.
# $(call ) isn't necessary.
#
define get-all-product-makefiles
$(call get-product-makefiles,$(_find-android-products-files))
endef

再回到product_config.mk上,给到了all_product_configs,TARGET_BUILD_APPS这个值为空的,所以走的是else的逻辑,也就是前面我们load的列表

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

all_product_configs这个在哪里处理呢?同样在product_config.mk里

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))

我们可以输出一下,就知道这个当前的current_product_makefile了

$(error $(current_product_makefile))

输出了log

build/core/product_config.mk:216: *** build/target/product/aosp_x86.mk.  Stop.

其实后面载入的是build/target/product/aosp_x86.mk

当我们选择其他编译项的时候呢? 如说我选择19. aosp_grouper-userdebug

那么它的产品makefile是啥呢? 输出的Log就是这个了

build/core/product_config.mk:215: *** device/asus/grouper/aosp_grouper.mk.  Stop.

可以看到,前面我们的aosp_x86是在build/target目录下的,而后面这个是在device目录下的,现在你知道为什么扫描会扫描build/target目录,会扫描device目录以及vendor目录了吧里的AndroidProducts.mk文件。

品牌的创建

那么我们创建自己的产品是不是就有头绪了呢?以iphone为例子

第一步:有自己的一个vendorsetup.sh,里面add_lunch_combo iphone,这样子,我们在lunch的时候,就会有我们自己的选项了,那么怎么样才能让它编译我们的主板和产品配置呢?

第二步:在device目录下,或者在vendor目录下,或者在target目录下,通常我们在device目录下去创建属于自己的文件夹,我们这个名字就叫iphone吧,里面有内容,我们是不是可以去复制x86的呀。因为我们是模拟器,如果是芯片商给你提供的,其实已经创建好的了,你去复制一份即可,然后修改成自己的。

第三步:尝试编译,如果通过了,再去修改产品配置,我们是模拟器,主板配置基本上没有修改的。

实际来干吧,先来个文件夹

image-20211202224427976
image-20211202224427976

然后复制一个vendorsetup.sh过来,里面改成:

add_lunch_combo iphone-userdebug

保存,然后重新载入一下evnsetup.sh

image-20211202224819697
image-20211202224819697

这样子就有了我们这个产品了,那么怎么样才能让它找到我们的配置呢?还是拷贝,我们可以参考一下x86的,具体内容请看视频,或者看资料里的最后结果。

由品牌创建产品

完成了前面的工作,我们已经完成了iphone的品牌创建了。在实际开发中,是不需要自己创建这个的,一般来说,芯片厂商给到你的一套代码,已经包含了。你自己拷贝一份,去修改即可。

接下来我们创建iphone12这个产品