Android系统启动篇
4,《Android SystemServer进程启动流程》
Android系统开发准备篇
3,《Android Framework代码IDE加载和调试》
Android系统开发实践篇
4,《android单独编译framework模块并push》
Android系统开发核心知识储备篇
1,《Android编译系统-envsetup和lunch代码篇》
6,《Android中Activity、View和Window关系详解》
11,《android中AMS进程通知Zygote进程fork新进程的通信方式》
Android核心功能详解篇
2,《Android 手势导航(从下往上滑动进入多任务页面)》
3,《android手势分析(应用界面左往右边滑动退出应用)》
———————————————————————————————————————————
目录
一, 编译环境初始化
1.1 初始化命令
$ source build/envsetup.sh
envsetup.sh 主要做了下面几个事情:
envsetup.sh 文件代码,
...
validate_current_shell
source_vendorsetup
addcompletions
1.2 validate_current_shell
从接口的名字可以看出,validate_current_shell()主要检查shell环境,
function validate_current_shell() {
local current_sh="$(ps -o command -p $$)"
case "$current_sh" in
*bash*)
function check_type() { type -t "$1"; }
;;
*zsh*)
function check_type() { type "$1"; }
enable_zsh_completion ;;
*)
echo -e "WARNING: Only bash and zsh are supported.\nUse of other shell would lead to erroneous results."
;;
esac
}
1.3 source_vendorsetup
从device、vendor和product等目录遍历搜索vendorsetup.sh,并source进来,
# Execute the contents of any vendorsetup.sh files we can find.
# Unless we find an allowed-vendorsetup_sh-files file, in which case we'll only
# load those.
#
# This allows loading only approved vendorsetup.sh files
function source_vendorsetup() {
unset VENDOR_PYTHONPATH
allowed=
for f in $(find -L device vendor product -maxdepth 4 -name 'allowed-vendorsetup_sh-files' 2>/dev/null | sort); do
if [ -n "$allowed" ]; then
echo "More than one 'allowed_vendorsetup_sh-files' file found, not including any vendorsetup.sh files:"
echo " $allowed"
echo " $f"
return
fi
allowed="$f"
done
allowed_files=
[ -n "$allowed" ] && allowed_files=$(cat "$allowed")
for dir in device vendor product; do
for f in $(test -d $dir && \
find -L $dir -maxdepth 4 -name 'vendorsetup.sh' 2>/dev/null | sort); do
if [[ -z "$allowed" || "$allowed_files" =~ $f ]]; then
echo "including $f"; . "$f"
else
echo "ignoring $f, not in $allowed"
fi
done
done
}
1.4 addcompletions
function addcompletions()
{
local T dir f
# Keep us from trying to run in something that's neither bash nor zsh.
if [ -z "$BASH_VERSION" -a -z "$ZSH_VERSION" ]; then
return
fi
# Keep us from trying to run in bash that's too old.
if [ -n "$BASH_VERSION" -a ${BASH_VERSINFO[0]} -lt 3 ]; then
return
fi
local completion_files=(
system/core/adb/adb.bash
system/core/fastboot/fastboot.bash
tools/asuite/asuite.sh
)
# Completion can be disabled selectively to allow users to use non-standard completion.
# e.g.
# ENVSETUP_NO_COMPLETION=adb # -> disable adb completion
# ENVSETUP_NO_COMPLETION=adb:bit # -> disable adb and bit completion
for f in ${completion_files[*]}; do
if [ -f "$f" ] && should_add_completion "$f"; then
. $f
fi
done
if should_add_completion bit ; then
complete -C "bit --tab" bit
fi
if [ -z "$ZSH_VERSION" ]; then
# Doesn't work in zsh.
complete -o nospace -F _croot croot
fi
complete -F _lunch lunch
complete -F _complete_android_module_names gomod
complete -F _complete_android_module_names m
}
二,lunch命令
lunch命令用来设置 TARGET_PRODUCT、TARGET_BUILD_VARIANT、TARGET_PLATFORM_VERSION、TARGET_BUILD_TYPE、TARGET_BUILD_APPS等环境变量。
lunch操作流程如下:
1.获取lunch操作的参数,如果参数不为空,参数则为指定要编译的设备型号和编译类型;如果参数为空,会调用print_lunch_menu来显示Lunch菜单项,读取用户的输入,存入answer
2.如果answer为空,即之前在lunch菜单用,用户只敲了一个回车。会将默认选项改为aosp_arm-eng,结果存入selection
3.如果lunch操作得到的输入是数字,则将数字转换为LUNCH_MENU_CHOICES中的字符串,结果存入selection
4.解析selection的值,得到product = aosp_arm 和variant = eng, 把他们分别保存到TARGET_PRODUCT 和 TARGET_BUILD_VARIANT 中
5.根据前面的设置,调用build_build_var_cache 来更新编译环境相关变量
6.export 编译选项TARGET_PRODUCT, TARGET_BUILD_VARIANT和TARGET_BUILD_TYPE三元组
7.调用set_stuff_for_environment 来设置其他环境变量,如PROMPT_COMMAND,编译toolchain和tools相关的路径等
8.调用printconfig 来输出当前的设置选项
function lunch()
{
local answer
# 获取lunch操作的参数
if [ "$1" ] ; then
answer=$1
else
# lunch操作不带参数,则先显示lunch menu,然后读取用户输入
print_lunch_menu
echo -n "Which would you like? [aosp_arm-eng] "
read answer
fi
local selection=
# lunch操作得到的结果为空(例如用户直接在lunch要求输入时回车的情况)
# 则将选项默认为"aosp_arm-eng"
if [ -z "$answer" ]
then
selection=aosp_arm-eng
# lunch操作得到的输入是数字,则将数字转换为LUNCH_MENU_CHOICES中的字符串
elif (echo -n $answer | grep -q -e "^[0-9][0-9]*$")
then
local choices=($(TARGET_BUILD_APPS= get_build_var COMMON_LUNCH_CHOICES))
if [ $answer -le ${#choices[@]} ]
then
# array in zsh starts from 1 instead of 0.
if [ -n "$ZSH_VERSION" ]
then
selection=${choices[$(($answer))]}
else
selection=${choices[$(($answer-1))]}
fi
fi
else
selection=$answer
fi
export TARGET_BUILD_APPS=
local product variant_and_version variant version
product=${selection%%-*} # Trim everything after first dash
variant_and_version=${selection#*-} # Trim everything up to first dash
if [ "$variant_and_version" != "$selection" ]; then
variant=${variant_and_version%%-*}
if [ "$variant" != "$variant_and_version" ]; then
version=${variant_and_version#*-}
fi
fi
if [ -z "$product" ]
then
echo
echo "Invalid lunch combo: $selection"
return 1
fi
# 设置TARGET_PRODUCT和TARGET_BUILD_VARIANT
TARGET_PRODUCT=$product \
TARGET_BUILD_VARIANT=$variant \
TARGET_PLATFORM_VERSION=$version \
# 根据前面的设置,更新编译环境相关变量
build_build_var_cache #参考[3.1.1]
if [ $? -ne 0 ]
then
return 1
fi
# export 编译选项TARGET_PRODUCT, TARGET_BUILD_VARIANT和TARGET_BUILD_TYPE三元组
export TARGET_PRODUCT=$(get_build_var TARGET_PRODUCT)
export TARGET_BUILD_VARIANT=$(get_build_var TARGET_BUILD_VARIANT)
if [ -n "$version" ]; then
export TARGET_PLATFORM_VERSION=$(get_build_var TARGET_PLATFORM_VERSION)
else
unset TARGET_PLATFORM_VERSION
fi
export TARGET_BUILD_TYPE=release
echo
set_stuff_for_environment # 设置其他环境变量,如PROMPT_COMMAND,编译toolchain和tools相关的路径等
printconfig # 输出当前的设置选项
destroy_build_var_cache
}
2.1 build_build_var_cache()
根据前面的设置,更新编译环境相关变量
主要通过执行 "build/soong/soong_ui.bash --dumpvars-mode" 完成
最终执行的是 "./out/soog_ui --dumpvars-mode"
function build_build_var_cache()
{
local T=$(gettop)
# Grep out the variable names from the script.
cached_vars=(`cat $T/build/envsetup.sh | tr '()' ' ' | awk '{for(i=1;i<=NF;i++) if($i~/get_build_var/) print $(i+1)}' | sort -u | tr '\n' ' '`)
cached_abs_vars=(`cat $T/build/envsetup.sh | tr '()' ' ' | awk '{for(i=1;i<=NF;i++) if($i~/get_abs_build_var/) print $(i+1)}' | sort -u | tr '\n' ' '`)
# Call the build system to dump the "<val>=<value>" pairs as a shell script.
build_dicts_script=`\builtin cd $T; build/soong/soong_ui.bash --dumpvars-mode \
--vars="${cached_vars[*]}" \
--abs-vars="${cached_abs_vars[*]}" \
--var-prefix=var_cache_ \
--abs-var-prefix=abs_var_cache_`
local ret=$?
if [ $ret -ne 0 ]
then
unset build_dicts_script
return $ret
fi
# Execute the script to store the "<val>=<value>" pairs as shell variables.
eval "$build_dicts_script"
ret=$?
unset build_dicts_script
if [ $ret -ne 0 ]
then
return $ret
fi
BUILD_VAR_CACHE_READY="true"
}
soong_ui 由build/soong/cmd/soong_ui/main.go编译生成
[build/soong/cmd/soong_ui/main.go]
func main() {
...
if os.Args[1] == "--dumpvar-mode" {
dumpVar(buildCtx, config, os.Args[2:])
} else if os.Args[1] == "--dumpvars-mode" {
dumpVars(buildCtx, config, os.Args[2:])
} else {
...
}
...
}
[build/soong/cmd/soong_ui/main.go]
func dumpVars(ctx build.Context, config build.Config, args []string) {
varData, err := build.DumpMakeVars(ctx, config, nil, allVars)
}
最后调用到了ckati执行-f build/make/core/config.mk
[/build/soong/ui/build/dumpvars.go]
func dumpMakeVars(ctx Context, config Config, goals, vars []string, write_soong_vars bool) (map[string]string, error) {
ctx.BeginTrace(metrics.RunKati, "dumpvars")
defer ctx.EndTrace()
cmd := Command(ctx, config, "dumpvars",
config.PrebuiltBuildTool("ckati"),
"-f", "build/make/core/config.mk",
"--color_warnings",
"--kati_stats",
"dump-many-vars",
"MAKECMDGOALS="+strings.Join(goals, " "))
cmd.Environment.Set("CALLED_FROM_SETUP", "true")
if write_soong_vars {
cmd.Environment.Set("WRITE_SOONG_VARIABLES", "true")
}
cmd.Environment.Set("DUMP_MANY_VARS", strings.Join(vars, " "))
cmd.Sandbox = dumpvarsSandbox
output := bytes.Buffer{}
cmd.Stdout = &output
pipe, err := cmd.StderrPipe()
if err != nil {
ctx.Fatalln("Error getting output pipe for ckati:", err)
}
cmd.StartOrFatal()
// TODO: error out when Stderr contains any content
status.KatiReader(ctx.Status.StartTool(), pipe)
cmd.WaitOrFatal()
ret := make(map[string]string, len(vars))
...
return ret, nil
}