一、背景

随着Android应用范围越来越广泛,用户对Android的需求也越来越趋于复杂,在开发Android应用以及底层产品驱动时,往往两套产品所需要的硬件平台就大不相同,而软件功能却相差不大。在这种纷繁的情况下,是否每种产品就需要一套源代码来维护。如果真这么做的话,那工作量就太大了。所以提出了产品分支的概念。在Android源码中提供了这么一种强大的功能。

公司正在Android上针对硬件平台做调整和开发,手上现有多种方案,有的需要无线wifi,有的底层芯片不一致。在这种情况下,公司使用Android lunch的方式使用一套源代码维护多种方案。

二、文档目的

当前网络上没有成体系的对Android lunch调用关系的研究,所以将Android lunch分析以及产品分支构建这份文档共享出来以帮助对此过程不了解的开发者。如有疑问和建议,请留言。

三、Android lunch调用关系

1.调用流程图:

Android lunch分析以及产品分支构建_第1张图片

2.调用关系分析

在编译Android产品的时候我们首先会导入. build/envsetup.sh ,然后lunch,这时候我们可以看到几个基本的产品版本。

从现象回推,首先查看envsetup.sh文件中的lunch函数:

具体分析见:lunch函数分析

在envsetup.sh中,有几个比较重要的函数。Lunch(),check_product(),print_lunch_menu(),get_build_var(),gettop,add_lunch_combo(),set_stuff_for_environment(),set_java_home(),findmakefile()。

1)lunch

[plain] view plain copy
  1. functionlunch()
  2. {
  3. localanswer
  4. if["$1"];then
  5. #lunch后面直接带参数
  6. answer=$1
  7. else
  8. #lunch后面不带参数,则打印处所有的targetproduct和variant菜单提供用户选择
  9. print_lunch_menu
  10. echo-n"Whichwouldyoulike?[generic-eng]"
  11. readanswer
  12. fi
  13. localselection=
  14. if[-z"$answer"]
  15. then
  16. #如果用户在菜单中没有选择,直接回车,则为系统缺省的generic-eng
  17. selection=generic-eng
  18. elif["$answer"="simulator"]
  19. then
  20. #如果是模拟器
  21. selection=simulator
  22. elif(echo-n$answer|grep-q-e"^[0-9][0-9]*{1}quot;)
  23. then
  24. #如果answer是选择菜单的数字,则获取该数字对应的字符串
  25. if[$answer-le${#LUNCH_MENU_CHOICES[@]}]
  26. then
  27. selection=${LUNCH_MENU_CHOICES[$(($answer-$_arrayoffset))]}
  28. fi
  29. #如果answer字符串匹配*-*模式(*的开头不能为-)
  30. elif(echo-n$answer|grep-q-e"^[^\-][^\-]*-[^\-][^\-]*{1}quot;)
  31. then
  32. selection=$answer
  33. fi
  34. if[-z"$selection"]
  35. then
  36. echo
  37. echo"Invalidlunchcombo:$answer"
  38. return1
  39. fi
  40. #specialcasethesimulator
  41. if["$selection"="simulator"]
  42. then
  43. #模拟器模式
  44. exportTARGET_PRODUCT=sim
  45. exportTARGET_BUILD_VARIANT=eng
  46. exportTARGET_SIMULATOR=true
  47. exportTARGET_BUILD_TYPE=debug
  48. else
  49. #将product-variant模式种的product分离出来
  50. localproduct=$(echo-n$selection|sed-e"s/-.*$//")
  51. #检查product,调用关系check_product()->get_build_var()->build/core/config.mk
  52. check_product$product
  53. if[$?-ne0]
  54. then
  55. echo
  56. echo"**Don'thaveaproductspecfor:'$product'"
  57. echo"**Doyouhavetherightrepomanifest?"
  58. product=
  59. fi
  60. #将product-variant模式种的variant分离出来
  61. localvariant=$(echo-n$selection|sed-e"s/^[^\-]*-//")
  62. #检查之,看看是否在(useruserdebugeng)范围内
  63. check_variant$variant
  64. if[$?-ne0]
  65. then
  66. echo
  67. echo"**Invalidvariant:'$variant'"
  68. echo"**Mustbeoneof${VARIANT_CHOICES[@]}"
  69. variant=
  70. fi
  71. if[-z"$product"-o-z"$variant"]
  72. then
  73. echo
  74. return1
  75. fi
  76. exportTARGET_PRODUCT=$product
  77. exportTARGET_BUILD_VARIANT=$variant
  78. exportTARGET_SIMULATOR=false
  79. exportTARGET_BUILD_TYPE=release
  80. fi#!simulator


2)Check_product:

[plain] view plain copy
  1. functioncheck_product()
  2. {
  3. T=$(gettop)
  4. if[!"$T"];then
  5. echo"Couldn'tlocatethetopofthetree.TrysettingTOP.">&2
  6. return
  7. fi
  8. CALLED_FROM_SETUP=trueBUILD_SYSTEM=build/core\
  9. TARGET_PRODUCT=$1TARGET_BUILD_VARIANT=\
  10. TARGET_SIMULATOR=TARGET_BUILD_TYPE=\
  11. TARGET_BUILD_APPS=\
  12. get_build_varTARGET_DEVICE>/dev/null
  13. #hidesuccessfulanswers,butallowtheerrorstoshow
  14. }
检查指定的TARGET_PRODUCT是否允许,默认的有sim和generic。如果不允许,则输出错误信息,允许则不显示

3)Print_lunch_menu()

[plain] view plain copy
  1. functionprint_lunch_menu()
  2. {
  3. localuname=$(uname)
  4. echo
  5. echo"You'rebuildingon"$uname
  6. echo
  7. echo"Lunchmenu...pickacombo:"
  8. locali=1
  9. localchoice
  10. #循环查找LUNCH_MENU_CHOICES中的版本
  11. forchoicein${LUNCH_MENU_CHOICES[@]}
  12. do
  13. echo"$i.$choice"
  14. i=$(($i+1))
  15. done
  16. echo
  17. }
该函数负责打印已经定义的版本

4)Get_build_var()

[plain] view plain copy
  1. functionget_build_var()
  2. {
  3. T=$(gettop)
  4. if[!"$T"];then
  5. echo"Couldn'tlocatethetopofthetree.TrysettingTOP.">&2
  6. return
  7. fi
  8. CALLED_FROM_SETUP=trueBUILD_SYSTEM=build/core\
  9. make--no-print-directory-C"$T"-fbuild/core/config.mkdumpvar-$1
  10. }
列出make脚本中某变量的值,当前为build/core/config.mk

5)Gettop()

[plain] view plain copy
  1. functiongettop
  2. {
  3. localTOPFILE=build/core/envsetup.mk
  4. if[-n"$TOP"-a-f"$TOP/$TOPFILE"];then
  5. echo$TOP
  6. #如果TOP不为空,并且envsetup.mk存在,函数直接返回TOP对应路径
  7. else
  8. #否则(指找不到envsetup.mk)如下处理
  9. if[-f$TOPFILE];then
  10. #Thefollowingcircumlocution(repeatedbelowaswell)ensures
  11. #thatwerecordthetruedirectorynameandnotonethatis
  12. #fakedupwithsymlinknames.
  13. PWD=/bin/pwd
  14. else
  15. #Weredirectcdto/dev/nullincaseit'saliasedto
  16. #acommandthatprintssomethingasaside-effect
  17. #(likepushd)
  18. localHERE=$PWD
  19. T=
  20. while[\(!\(-f$TOPFILE\)\)-a\($PWD!="/"\)];do
  21. cd..>/dev/null
  22. T=`PWD=/bin/pwd`
  23. done
  24. cd$HERE>/dev/null
  25. if[-f"$T/$TOPFILE"];then
  26. echo$T
  27. fi
  28. fi
  29. fi
  30. }
返回当前android代码树的顶层路径。前提是当前路径位于android代码树中

6)Add_lunch_combo()

[plain] view plain copy
  1. functionadd_lunch_combo()
  2. {
  3. localnew_combo=$1
  4. localc
  5. forcin${LUNCH_MENU_CHOICES[@]};do
  6. if["$new_combo"="$c"];then
  7. return
  8. fi
  9. done
  10. LUNCH_MENU_CHOICES=(${LUNCH_MENU_CHOICES[@]}$new_combo)
  11. }
向环境变量LUNCH_MENU_CHOICES标识的列表中添加项

7)Set_stuff_for_environment()

[plain] view plain copy
  1. functionset_stuff_for_environment()
  2. {
  3. settitle
  4. set_java_home
  5. setpaths
  6. set_sequence_number
  7. exportANDROID_BUILD_TOP=$(gettop)
  8. }
设置android编译需要的环境变量

8)Set_java_home

[plain] view plain copy
  1. functionset_java_home(){
  2. if[!"$JAVA_HOME"];then
  3. case`uname-s`in
  4. Darwin)
  5. exportJAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/1.6/Home
  6. ;;
  7. *)
  8. exportJAVA_HOME=/usr/lib/jvm/java-6-sun
  9. ;;
  10. esac
  11. fi
  12. }
设置java运行环境

9)findmakefile

[plain] view plain copy
  1. functionfindmakefile()
  2. {
  3. TOPFILE=build/core/envsetup.mk
  4. #Weredirectcdto/dev/nullincaseit'saliasedto
  5. #acommandthatprintssomethingasaside-effect
  6. #(likepushd)
  7. localHERE=$PWD
  8. T=
  9. while[\(!\(-f$TOPFILE\)\)-a\($PWD!="/"\)];do
  10. T=$PWD
  11. if[-f"$T/Android.mk"];then
  12. echo$T/Android.mk
  13. #如果找到Android.mk,echo出来的全路径将作为函数的返回值赋给某个变量
  14. cd$HERE>/dev/null
  15. return
  16. fi
  17. cd..>/dev/null
  18. done
  19. cd$HERE>/dev/null
  20. }
此外还有一段比较重要的代码 [plain] view plain copy
  1. #Executethecontentsofanyvendorsetup.shfileswecanfind.
  2. forfin`/bin/lsvendor/*/vendorsetup.shvendor/*/build/vendorsetup.shdevice/*/*/vendorsetup.sh2>/dev/null`
  3. do
  4. echo"including$f"
  5. .$f
  6. done
  7. unsetf


这段代码寻找vendor,build,device指定目录下的vendorsetup.sh。在vendorsetup.sh中定义了各版本的产品。

注:/dev/null 是 Unix/Linux 里的【无底洞】,任何的 output 送去了【无底洞】就再也没了,一般情况下,要是你不想看到 output 或者output 太多太大了,有可能把硬碟给挤爆了的时候,程序的设计就会考虑把 output 送到 /dev/null 了

四、Android lunch产品分支构建

背景:南京广义软件有限公司英文名generalizesoft,所以此处使用generalize来命名总的产品目录。其中generalizex和genx则是对公司产品共性的描述。每套产品将差异性的部分定义在自己产品当中。再调用共性的部分,形成一个完整的产品。这样做日后需要维护所有产品的时候只需要维护一套代码,而不是每套产品有一套代码,修改的内容页不方便管理。

1. 目录结构:

Android lunch分析以及产品分支构建_第2张图片

2. 搭建步骤

1) 在device目录下创建一个名为generalize的文件夹

Android lunch分析以及产品分支构建_第3张图片

Android lunch分析以及产品分支构建_第4张图片

Android lunch分析以及产品分支构建_第5张图片

2) 对其中的文件分别进行编辑。generalize.mk 对应我们第一套产品的mk文件,这是差异性文件。不同的产品需要不同的mk文件。而generalizex.mk是无差异文件,意为产品的共性。所以在generalize.mk中定义如下,它需要引用generalizex.mk中定义的部分。这样做方便以后的产品差异性对比。同样的,BoardConfigCommon.mk定义了generalize一系列产品板文件的共性。在调用关系中可以看出它们之间的关系

Android lunch分析以及产品分支构建_第6张图片

3) Vendorsetup文件是定义lunch内容的文件。在其中加上我们产品。

Android lunch分析以及产品分支构建_第7张图片

4) 上述步骤处理完之后。运行envsetup.sh:

. build/envsetup.sh

之后再使用lunch,就可以看到基础效果图:

Android lunch分析以及产品分支构建_第8张图片

Android lunch分析以及产品分支构建_第9张图片

5) 编译android


更多相关文章

  1. 招聘正在进行时,315晚会使用的高科技产品,难道你们不知道嘛<( ̄︶ ̄)↗[G
  2. Android 将少量的数据文件保存在 data/data 目录下
  3. Android编译系统中头文件搜索路径的顺序问题
  4. Android 如何利用proc有上层想kernel写文件
  5. 仿微信、短信、QQ等消息数目右上角红色小圆球气泡显示(基于Androi
  6. Android运行时ART加载OAT文件的过程分析
  7. 批量处理ios破解后的资源文件为android所用
  8. Android中的R.java文件你知多少

随机推荐

  1. 在Windows下搭建Android开发环境
  2. Android Activity 切屏处理
  3. android中AudioRecord使用详解
  4. android五种布局模式
  5. 【Android学习笔记】AutoCompleteTextVie
  6. Android timer
  7. 如何在Android平板电脑POWER按钮菜单中添
  8. 【Android】利用adt-bundle在Linux下轻松
  9. android framework 输入事件分析
  10. Android已有项目接入Flutter及互相通信