Android编译过程总结及android中各种img文件的作用以及系统启动过程

编译环境: ubuntu 10.04 (或者更高)( windows 平台目前不被支持)

本文以编译android2.3为例,64位操作系统

1、编译环境的准备

 (1)确保安装有ubuntu系统或者虚拟机

2)安装JDK1.6(对于Android2.3以上代码)

$ sudo add-apt-repository "debhttp://archive.canonical.com/ lucid partner"

$ sudo add-apt-repository "deb-srchttp://archive.canonical.com/ubuntu lucid partner"

$ sudo apt-get update

$ sudo apt-get installsun-java6-jdk

3)安装一些需要软件包

$ sudo apt-get install git-coregnupg flex bison gperf build-essential \

zip curl zlib1g-dev libc6-devlib32ncurses5-dev ia32-libs \

x11proto-core-dev libx11-devlib32readline5-dev lib32z-dev \

libgl1-mesa-dev g++-multilibmingw32 tofrodos

4)安装repo

$ git clonegit://android.git.kernel.org/tools/repo.git

$ mkdir ~/bin

$ cp repo-script/repo~/bin

$ vim ~/.bashrc,~/bin加入PARH环境变量,如:

$ exportPATH=~/bin:$PATH 

保存后,同步更新source~/.bashrc

5)设置git

执行以下语句
$git config --globaluser.name
"你的名字"
$git config --global user.email"
你的email地址"

(6)同步源代码

1)创建工程目录:
$ mkdir myandroid
$ cd myandroid

2repo初始化以及同步代码

$repo init [email protected]:git库名/manifest.git -b 主分支名

在此过程中需要输入名字和email地址。初始化成功后,会显示:repo initialized in /android
~/android下会有一个.repo的隐藏目录

$repo sync(这一步会花费很长时间)

2、编译

(1)注意事项

执行ls -la /bin/sh命令,如果输出/bin/sh -> dash,

请执行$ sudo dpkg-reconfigure dash命令修改sh版本,并选择“否”;

此处如果不改好的话,编译时会出现错误。

(2)代码下载完成后就可以进行编译了

$ cd myandroid

$ make(此过程需要很长时间)

(3)编译完成后的代码结构

Android编译完成之后,将会在根目录下生成一个out文件夹,所有生成的内容均放在这个文件夹中。

Out文件夹的内容以及结构如下:

out/
  |--CaseCheck.txt
  |--casecheck.txt
  |--host
  ||-- common
  |`-- linux-x86
  `--target
  |--common
  `--product

两个主要的目录为hosttargethost表示主机(x86)生成的工具,target表示目标机运行的内容。

Host目录的结构如下所示

out/host/
  |--common
  | `--objJAVA库)
  `--linux-x86
  |--bin(二进制程序)
  |--frameworkJAVA,.jar文件)
  |--lib(共享库*.so
  `--obj(中间生成的目标文件)

host目录是一些在主机上用的工具,有一些是JAVA的程序。

Target目录的结构如下:

out/target/
  |--common
  | |--R(资源文件)
  ||-- docs
  | `--obj(目标文件)
  `--product
  `--generic

其中common目录表示通用的内容,product表示的产品的内容。

common目录的obj中,包含两个重要的目录:

APPS:包含了JAVA应用程序生成的目标,每个应用程序对应其中的一个子目录,将结合每个应用程序的原始文件生成Android应用程序的APK包。

JAVA_LIBRARIES中包含了JAVA的库,每个库对应其中的一个子目录。

在默认情况下,Android编译将生成generic目录,如果选定产品还可以生成其他的目录(如ventana)。generic一般包含以下内容:

out/target/product/generic/
  |--android-info.txt
  |--clean_steps.mk
  |--data
  |--obj
  |--ramdisk.img
  |--root
  |--symbols
  |--system
  |--system.img
  |--userdata.img
  

generic/obj/APPS目录中包含可各种JAVA应用,这与common/APPS想对应,但是已经打成了APK包。

system目录是主要的文件系统;data目录是存放数据的文件系统。

obj/SHARED_LIBRARIES中存放所有的动态库;STATIC_LIBRARIES中存放所有的静态库。

img结尾的文件是目标映像文件,其中ramdisk.img是作为内存盘的根文件系统映像,system.img是主要文件系统的映像,userdata.img是数据内容映像。这几个Image文件是运行时真正需要的文件。

(4)编译单个模块

android中的一个应用程序可以单独编译,生成想对应的APK包,以Email为例。

$ sourcebuild/envsetup.sh

就多出一些命令:
- croot: Changes directory to the topof the tree.
- m: Makes from the top of thetree.
- mm: Builds all of the modules inthe current directory.
- mmm: Builds all of the modules inthe supplied directories.
- cgrep: Greps on all local C/C++files.
- jgrep: Greps on all local Javafiles.
- resgrep: Greps on all localres/*.xml files.
- godir: Go to the directorycontaining a file.

$ mm Email

编译之后生成out/target/product/generic/system/app/Email.apk

3、编译文件分类

1)配置类

主要用来配置productboard,以及根据你的HostTarget选择相应的工具以及设定相应的通用编译选项:

config文件

说明

build/core/config.mk

Config文件的概括性说明

build/core/envsetup.mk

generate目录构成等配置

build/target/product

产品相关配置

build/target/board

硬件相关的配置

build/core/combo

编译选项配置

Config.mk是一个总括性的东西,它里面定义了各种midule编译所需要使用的HOST工具以及如何来编译各种模块。envsetup.mk主要会读取由envsetup.sh写入环境变量中的一些变量来配置编译过程中的输出目录,combo里面主要定义了各种HostTarget结合的编译器和编译选项。

board主要是涉及到硬件芯片的配置,比如是否提供硬件的某些功能,或者芯片支持浮点运算等等。product针对当前的芯片配置来定义你将要生产产品的个性配置,只要指APK方面的配置,如哪些APK会包含在哪个product中,哪些APK在当前product中是不提供的。

这类文件主要定义了如何来处理ModuleAndroid.mk,以及采用何种方式来生成目标模块,这些模块的规则都定义在config.mk里面,如下:

CLEAR_VARS:=$(BUILD_SYSTEM)/clear_vars.mk

BUILD_HOST_STATIC_LIBRARY:=$(BUILD_SYSTEM)/host_static_library.mk

BUILD_HOST_SHARED_LIBRARY:=$(BUILD_SYSTEM)/host_shared_library.mk

BUILD_STATIC_LIBRARY:=$(BUILD_SYSTEM)/static_library.mk

BUILD_RAW_STATIC_LIBRARY :=$(BUILD_SYSTEM)/raw_static_library.mk

BUILD_SHARED_LIBRARY:=$(BUILD_SYSTEM)/shared_library.mk

BUILD_EXECUTABLE:=$(BUILD_SYSTEM)/executable.mk

BUILD_RAW_EXECUTABLE:=$(BUILD_SYSTEM)/raw_executable.mk

BUILD_HOST_EXECUTABLE:=$(BUILD_SYSTEM)/host_executable.mk

BUILD_PACKAGE:=$(BUILD_SYSTEM)/package.mk

BUILD_PHONY_PACKAGE:=$(BUILD_SYSTEM)/phony_package.mk

BUILD_HOST_PREBUILT:=$(BUILD_SYSTEM)/host_prebuilt.mk

BUILD_PREBUILT:=$(BUILD_SYSTEM)/prebuilt.mk

BUILD_MULTI_PREBUILT:=$(BUILD_SYSTEM)/multi_prebuilt.mk

BUILD_JAVA_LIBRARY:=$(BUILD_SYSTEM)/java_library.mk

BUILD_STATIC_JAVA_LIBRARY:=$(BUILD_SYSTEM)/static_java_library.mk

BUILD_HOST_JAVA_LIBRARY:=$(BUILD_SYSTEM)/host_java_library.mk

BUILD_DROIDDOC:=$(BUILD_SYSTEM)/droiddoc.mk

BUILD_COPY_HEADERS :=$(BUILD_SYSTEM)/copy_headers.mk

BUILD_KEY_CHAR_MAP :=$(BUILD_SYSTEM)/key_char_map.mk

除了CLEAR_VARS是清除本地变量之外,其他所有的都对应了一种模块的生成规则,每一个本地模块最后都会include其中的一种来生成目标模块。大部分上面的.mk都会包含base_rules.mk,这是对模块进行处理的基础文件。

3)单个模块的编译

本地模块的Makefile文件就是Android.mk文件Android进行编译的时候会通过下面的函数来遍历所有子目录中的Android.mk,一旦找到就不会再往层子目录继续寻找(所有你的模块定义的顶层Android.mk必须包含自己定义的子目录中的Android.mk)

subdir_makefiles += \

$(shellbuild/tools/findleaves.sh--prune="./out" $(subdirs) Android.mk)

不同类型的本地模块具有不同的语法,但基本上是相通的,只有个别变量的不同。

Android通过LOCAL_MODULE_TAGS来决定哪些本地模块会不会编译进系统,通过PRODUCTLOCAL_MODULE_TAGS来决定哪些应用包会编译进系统,如果用户不指定LOCAL_MODULE_TAGS,默认它的值是user。此外用户可以通过buildspec.mk来指定你需要编译进系统的模块。用户也可以通过mm来编译指定模块,或者通过make clean-module_name来删除指定模块。

4)系统生成类

主要指build/core/Makefile文件,这个文件定义了生成各种img的方式,包括ramdisk.img, urerdata.img, system.img,recovery.img等。

所有的Makefile都通过build/core/main.mk这个文件组织在一起,它定义了一个默认goalsdroid,当我们在TOP目录下敲Make实际上就等同于我们执行make droid。当Makeinclude所有的文件,完成对所有make文件的解析以后就会寻找生成droid的规则,依次生成它的依赖,直到所有满足的模块被编译好,然后使用相应的工具打包成相应的img

4make命令

make clean删除本次配置所编译输出的结果文件。类似于:rm –rf./out/<configuration>

makeshowcommands:在编译的时候显示脚本的命令,而不是显示编译的简报。用于调试脚本

make:映像编译成功后会在目录~/android/src/out/target/product/generic下产生一些image文件ramdisk.imgsystem.img userdata.img




首先通过编译,先将android内核编译成功。正常情况下,在目录out/target.product/generic/(但是有的就没有generic文件,如freescale和iriver;但是lonshinetech下面就有这个文件,依据情况而定,只要能找到生成的三个文件就可以。例如:~/freescale/R9.2/out/target/product/imx51_bbg$)下会生成三个文件:ramdisk.img,system.img,userdata.img。这三个文件的作用如下:

(1)ramdisk.img
     一个分区影像文件,它会在kernel 启动的时候,以只读的方式被 mount , 这个文件中只是包含了 /init以及一些配置文件,这个ramdisk 被用来调用init,以及把真正的root file system mount起来。
     #其实ramdisk.img的内容就是/out/target/product/generic/root目录的压缩而已。
    
 方法1:  android编译生成后的ramdisk.img是一个gzip格式的文件,输入命令 #file ramdisk.img, 会得到 =>ramdisk.img: gzip compressed data, fromUnix
      
     那么先解压ramdisk.img,因为后缀不是.gz,所以用—S选项, # gunzip -S .imgramdisk.img
     这样就得到一个新文件ramdisk.img,用 # file ramdisk 查看格式 , 得到 =>ramdisk: ASCII cpio archive (SVR4 with no CRC)

         可以看出解压生成的ramdisk是cpio格式的文件,再次解压,为了防止解压后文件混乱,
         首次建立一个目录如: # mkdir rfs //rfs可以用来放ramdisk解压后的文件,  进入 # cd rfs
         解压 # cpio -i -F ../ramdisk

  方法2:将ramdisk.img复制一份到任何其他目录下,将其改名为ramdisk.img.gz,然后使用命令 # gunzipramdisk.img.gz,
        然后新建一个文件夹ramdisk,进入,输入命令 # cpio -i -F ../ramdisk.img



      得到结果如下
   drwxr-xr-x  8 rootroot   4096 2011-01-12 11:36./
   drwxr-xr-x 13 rootroot   4096 2011-01-12 11:35../
   drwxrwx--x  2 rootroot   4096 2011-01-12 11:36data/
   -rw-r--r--  1 rootroot    1182011-01-12 11:36 default.prop
   drwxr-xr-x  2 rootroot   4096 2011-01-12 11:36dev/
   -rwxr-x---  1 root root 1077842011-01-12 11:36 init*
   -rwxr-x---  1 rootroot    4922011-01-12 11:36 init.freescale.rc*
   -rwxr-x---  1 rootroot   1677 2011-01-12 11:36init.goldfish.rc*
   -rwxr-x---  1 rootroot  18263 2011-01-12 11:36 init.rc*
   drwxr-xr-x  2 rootroot   4096 2011-01-12 11:36proc/
   drwxr-x---  2 rootroot   4096 2011-01-12 11:36sbin/
   drwxr-xr-x  2 rootroot   4096 2011-01-12 11:36sys/
   drwxr-xr-x  2 rootroot   4096 2011-01-12 11:36system/

 #可以看出这写文件是和root目录下的内容完全一样,其实就是对root目录的打包和压缩。可以是用tree -L1来查看root的目录

(2)system.img
     它包含了整个系统,android 的framework,application 等等,会被挂接到 "/"上,包含了系统中所有的二进制文件
    #system.img是out/target.product/generic/目录下system目录的一个映射,类似与根文件系统的映像,放着android的应用程序、配置文件和字体等。

   root@root-OptiPlex-380:~/lonshinetech/src/SPU_B0_R0_0/out/target/product/generic/system$tree -L 1
   .
   |-- bin
   |-- build.prop
   |-- etc
   |-- fonts
   |-- framework
   |-- lib
   |-- usr
     -- xbin

重新打包system.img 具体办法
 a)在android编译后生成的out目录中查找这个工具 mkyaffs2image
   # find out/ -name mkyaffs2image
   得到=>out/host/linux-x86/bin/mkyaffs2image
 b)android编译后会生成system/ 这个目录,而这个目录就是用来生成system.img的
  #  mkyaffs2image system/ system.img

(3)userdata.img

   将会被挂接到 /data 下,包含了所有应用相关的配置文件,以及用户相关的数据 。

 

(4)Android启动过程


    Android启动过程使,会由UBOOT传入一个init参数,这个init参数制定了开机的时候运行的第一个运行的程序,默认就是init程序,这个程序就在ramdisk.img中,可以分析一下它的代码,看看在其中到底做了一些什么样的初始化任务,它的源文件在system/core/init/init.c中。

   它会调用init.rc初始化这个文件,这个文件在out/target/product/generic/root下。
   android启动时首先加载的是ramdisk.img镜像,并挂载到/目录下,并进行一系列的初始化动作,包括创建各种需要的目录,初始化console,开启服务等。system.img是在init.rc中指定一些脚本命令,通过init.c进行解析并挂载到根目录下的/system目录下的。

你可能感兴趣的:(java,android,System,Build,library,makefile)