Android源码编译详解(二)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/MonaLisaTearr/article/details/80769307

        在上一篇笔记中,分享了Android源码编译的第一个阶段的过程,如果没看过的话可以回头去看下,要不然接下来看这些东西会有些莫名奇妙,本人也开始系统开发没多久,只是想记录以及分享自己的学习过程,如果有出现错误的地方,欢迎大家指正,共同进步!那么接下来进入Android源码编译的第二个阶段。。。

Android源码编译详解(一)

一、lunch命令

1、首先我们看看lunch命令执行之后出现了什么


出现了上述信息,就是等待我们选择编译的平台,这里所谓的平台说白了就是指我们所编译的系统适合运行在什么设备上,并且是user版本还是eng版本,又或者说是debug版本,我们确定版本之后,输入数字按回车就选择好了!

2、至于选哪个,需要根根据你的设备而定,又或者参考google给出的指定文档,这里不展开说明了!

3、这里要说的是user,eng,userdebug这里些版本所代表的,我们该怎么选?首先我们对三个不同类型进行简要说明:

  • user版本:user版本其实就是指可以发放到用户手上的版本了,就比如说我们平时正常的去手机店买手机的时候就是user版本了。
  • eng版本:这个版本是我们平时所说的工程机一般都是用这个版本,有时候这个版本的机子也会发给用户试用。
  •  userdebug版本:这个是调试版本,开发人员调试的时候用这个版本即可,当然也可以直接用eng版本。

4、下面看下其他网友对这几个版本不同的总结:

user userdebug eng
仅安装标签为 user 的模块 安装标签为 user、debug 的模块 安装标签为 user、debug、eng 的模块
设定属性 ro.secure=1,打开安全检查功能 设定属性 ro.secure=1,打开安全检查功能 设定属性 ro.secure=0,关闭安全检查功能
 设定属性 ro.debuggable=0,关闭应用调试功能 设定属性 ro.debuggable=1,启用应用调试功能 设定属性 ro.debuggable=1,启用应用调试功能
    ro.kernel.android.checkjni=1,启用 JNI 调用检查
 默认关闭 adb 功能 默认打开 adb 功能 默认打开 adb 功能
打开 Proguard 混淆器 打开 Proguard 混淆器 关闭 Proguard 混淆器
打开 DEXPREOPT 预先编译优化 打开 DEXPREOPT 预先编译优化 关闭 DEXPREOPT 预先编译优化

在上面我们仅仅是知道我们执行胃lunch命令之后,弹出来那么一堆东西,但是我们并不知道这堆东西是怎么来的,又有什么用?我们不妨进入源码看下,源码编译的第一个阶段我们指导,envsetup.sh干的其中一件事就是定义了很多的函数,而这些函数之中,就有lunch,所以走进envsetup.sh中去看看吧!

二、lunch源码分析(平台列表如何来的)

1、首先我们看看执行lunch命令之后平台菜单是怎么来的,下面是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

从代码中我们可以看到,当我们执行命令的时候可以有两种方式,第一种就是直接指定编译平台的话可以通过lunch xxx_xxx_eng这样的带参数的方式执行,这样会通过$1将第一个参数保存到answer中,第二中就是不带参数的,这里我们执行的是第二种,那么代码就会走到print_lunch_menu。

2、接下来我们看下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这个数组,我们接下来看下这个数组的数据是怎么来的

3、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

在这段代码中,我们看到,程序通过不断的调用add_lunch_combo函数,添加默认的编译平台选项到LUNCH_MENU_CHOICES中,这就是我们在执行lunch命令后出现的平台列表的数据来源了!但是有信息的朋友可能就发现了,这里只不过给我们添加了6个默认值,可是我们从前面的打印出来的列表中看一看到有二十多个呢,其它的哪来的呢?

不知道大家还记不记得,我们讲android源码编译第一个阶段的时候envsetup.sh的做的其中一件事(不记得得可以回头看一眼android源码编译详解(一)),就是通过下面的代码加载了很多的vendorsetup.sh脚本:

# 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 | sort` \
         `test -d vendor && find -L vendor -maxdepth 4 -name 'vendorsetup.sh' 2> /dev/null | sort` \
         `test -d product && find -L product -maxdepth 4 -name 'vendorsetup.sh' 2> /dev/null | sort`
do
    echo "including $f"
    . $f
done
unset f

之前我们并没有说这些脚本是用来干嘛的,那么现在我们看下这些脚本里面都有些什么内容:

#
# Copyright 2013 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#


add_lunch_combo aosp_deb-userdebug

怎么样?很惊喜吧,从代码中我们看到,只有add_lunch_combo aosp_deb-userdebug这句是有效的,有没有似曾相识的感觉?完全就是在通过add_lunch_combo函数给LUNCH_MENU_CHOICES添加数据嘛,,这下知道那么多平台列表是哪来的了吧?也就是说,当我们定制了自己的系统,我们只需要在vendor目录下创建对应的目录,并且创建我们所需的vendorsetup.sh脚本调用add_lunch_combo函数就可以添加我们对应平台的标识了!至于这个标识有什么用后面再给大家说明。

三、继续lunch剩下的源码

function lunch()
{
    ......
    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/-.*$//")
    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

    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

    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
}

上面的代码不算少,但是我们只需要关注这段代码做的下面三件事即可

1、检查answer合法性,并给selection赋值

我们首先看第一个判断if [ -z "$answer" ],表示如果用户没有输入任何东西直接回车的话,就会通过selection=aosp_arm-eng指定缺省的编译选项。

其实这里我们只需要关注 elif (echo -n $answer | grep -q -e "^[0-9][0-9]*$")这个判断即可,走入这个判断就证明我们有手动指定了编译选项,然后通过selection=${LUNCH_MENU_CHOICES[$(($answer-1))]}给selection赋值,做完了一系列的判断赋值之后通过 if [ -z "$selection" ]判断selection是否被赋值,如果没有则退出程序并通知。

2、按照 product-variant的格式拆分selection并做合法性校验

 这里我们先说明下,什么是product-variant,这里的product指的是我们的产品型号、而variant就是编译类型,以aosp_arm-eng为列,这里的product=aosp_arm,variant=eng;

那么上面的代码中,我们看到local product=$(echo -n $selection | sed -e "s/-.*$//")提取product,并通过check_product函数进行检验,同样的local variant=$(echo -n $selection | sed -e "s/^[^\-]*-//")对variant进行了分离,然后通过check_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
}

其实很简单,只不过是判断我们分离出来的variant是否在VARIANT_CHOICES中,如果在就证明是合法的,返回0,否则返回1,紧接着通过if [ $? -ne 0 ]判断,如果$?(上一个指令返回的值)不等于0就将variant置空并打印提示,

3、设置环境变量

接下来我们看到,程序分别对下面几个环境遍历进行了的赋值处理。
    export TARGET_PRODUCT=$product

    export TARGET_BUILD_VARIANT=$variant
    export TARGET_BUILD_TYPE=release

其实这真个lunch的过程还设置了大量的环境变量,涉及到的函数有set_stuff_for_environment、printconfig等,这里就不细细展开,lunch说白了就是一个设置环境变量的过程,最后你会发现他做了那么多事,只为了最后的那一段环境变量而已,如图:



好了到这里我们第二阶段已经基本完成大体的分析(太过细节的东西我也不是非常了解),强调一点的是我这里是基于android6.0的脚本文件进行说明的,其它版本的脚本文件应该会有些小改变!


猜你喜欢

转载自blog.csdn.net/MonaLisaTearr/article/details/80769307