SuperIC社区_

标题: Android系统镜像文件的打包|过程分析 [打印本页]

作者: liuwei    时间: 2016-9-28 13:12
标题: Android系统镜像文件的打包|过程分析

  在前面一篇文章中,我们分析了Android模块的编译过程。当Android系统的所有模块都编译好之后,我们就可以对编译出来的模块文件进行打包了。打包结果是获得一系列的镜像文件,例如system.img、boot.img、ramdisk.img、userdata.img和recovery.img等。这些镜像文件最终可以烧录到手机上运行。在本文中,我们就详细分析Android系统的镜像文件的打**程。

       Android系统镜像文件的打包工作同样是由Android编译系统来完成的,如图1所示:

图1 Android系统镜像文件的打**程

       从前面Android编译系统环境初始化过程分析和Android源代码编译命令m/mm/mmm/make分析这两篇文章可以知道,Android编译系统在初始化的过程中,会通过根目录下的Makefile脚本加载build/core/main.mk脚本,接着build/core/main.mk脚本又会加载build/core/Makefile脚本,而Android系统镜像文件就是由build/core/Makefile脚本负责打包生成的。

       在build/core/main.mk文件中,与Android系统镜像文件打**程相关的内容如下所示:


[plain] view plain copy



       如果定义在FULL_BUILD这个变量,就意味着我们是要对整个系统进行编译,并且编译完成之后 ,需要将编译得到的文件进行打包,以便可以得到相应的镜像文件,否则的话,就仅仅是对某些模块进行编译。

       在前面Android编译系统环境初始化过程分析一篇文章中,我们提到,变量INTERNAL_PRODUCT描述的是执行lunch命令时所选择的产品所对应的产品Makefile文件,而变量PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_PACKAGES描述的是在该产品Makefile文件中通过变量PRODUCT_PACKAGES所定义的模块名称列表。因此,我们得到的变量product_MODULES描述的就是要安装的模块名称列表。

       我们知道,Android源码中自带了很多默认的APK模块。如果我们想用自己编写的一个APK来代替某一个系统自带的APK,那么就可以通过变量PACKAGES.<new>.OVERRIDES := <old>来说明。其中,<new>表示用来替换的APK,而<old>表示被替换的APK。在这种情况下,被替换的APK是不应该被打包到系统镜像中去的。因此,我们需要从上一步得到的模块名称列表中剔除那些被替换的APK,这是通过Makefile脚本提供的filter-out函数来完成的。

       一个模块可以通过LOCAL_REQUIRED_MODULES变量来指定它所依赖的其它模块,因此,当一个模块被安装的时候,它所依赖的其它模块也会一起被安装。调用函数expand-required-modules获得的就是所有要安装的模块所依赖的其它模块,并且将这些被依赖的模块也一起保存在变量product_MODULES中。

       注意,这时候我们得到的product_MODULES描述的仅仅是要安装的模块的名称,但是我们实际需要的这些模块对应的具体文件,因此,需要进一步调用函数module-installed-files来获得要安装的模块所对应的文件,也就是要安装的模块经过编译之后生成的文件,这些文件就保存在变量product_FILES中。

       最终需要安装的文件除了变量product_FILES所描述的文件之后, 还包含以下四类模块文件:

       1. 变量ALL_DEFAULT_INSTALLED_MODULES描述的文件。

       2. 变量CUSTOM_MODULES描述的文件。

       3. 与当前编译类型对应的模块文件。例如,如果当前设定的编译类型为debug,那么所有通过将变量LOCAL_MODULE_TAGS将自己设置为debug的模块也会被打包到系统镜像文件中去。

       4. 与当前shell名称对应的模块文件。例如,如果当前使用的shell是mksh,那么所有通过将变量LOCAL_MODULE_TAGS将自己设置为shell_mksh的模块也会被打包到系统镜像文件中去。

       最后,modules_to_install就描述当前需要打包到系统镜像中去的模块文件。实际上,我们除了可以通过PACKAGES.$(p).OVERRIDES来描述要替换的APK之后,还可以在一个模块中通过LOCAL_OVERRIDES_PACKAGES来描述它所替换的模块。因此,我们需要通过函数get-package-overrides来获得此类被替换的模块文件,并且将它们从modules_to_install中剔除,这样得到的模块文件才是最终需要安装的。

       确定了要安装的所有模块文件之后,就可以将build/core/Makefile文件加载进来了。注意,文件build/core/Makefile是通过变量ALL_DEFAULT_INSTALLED_MODULES来获得当前所有要打包到系统镜像文件中去的模块文件的。

       文件build/core/Makefile主要就是用来打包各种Android系统镜像文件的,当然它也是通过make规则来执行各种Android系统镜像文件打包命令的。每一个Android镜像文件都对应有一个make伪目标。例如,在build/core/main.mk文件中,就定义了三个make伪目标ramdisk、userdataimage和bootimage,它们分别依赖于变量INSTALLED_USERDATAIMAGE_TARGET、INSTALLED_USERDATAIMAGE_TARGET和INSTALLED_BOOTIMAGE_TARGET所描述的文件,并且它们分别表示的就是ramdisk.img、userdata.img和boot.img文件。

        变量INSTALLED_USERDATAIMAGE_TARGET、INSTALLED_USERDATAIMAGE_TARGET和INSTALLED_BOOTIMAGE_TARGET都是在build/core/Makefile文件中定义的。此外,build/core/Makefile文件还定义了另外两个镜像文件system.img和recovery.img的生成规则。接下来,我们就分别对这些镜像文件的打**程进行分析。

        一. system.img

        system.img镜像文件描述的是设备上的system分区,即/system目录,它是在build/core/Makefile文件中生成的,相关的内容如下所示:


[plain] view plain copy




       从这里就可以看出,build/core/Makefile文件定义了两个伪目标来生成system.img:1. systemimg;2. systemimg-nodeps或者snod。伪目标systemimg表示在打包system.img之前,要根据依赖规则重新生成所有要进行打包的文件,而伪目标systemimg-nodeps则不需要根据依赖规则重新生成所有需要打包的文件而直接打包system.img文件。因此,执行systemimg-nodep比执行systemimg要快很多。通常,如果我们在Android源码中修改了某一个模块,并且这个模块不被其它模块依赖,那么对这个模块进行编译之后,就可以简单地执行make systemimg-nodeps来重新打包system.img。但是,如果我们修改的模块会被其它模块引用,例如,我们修改了Android系统的核心模块framework.jar和services.jar,那么就需要执行make systemimg来更新所有依赖于framework.jar和services.jar的模块,那么最后得到的system.img才是正确的镜像。否则的话,会导致Android系统启动失败。

       接下来,我们就主要关注伪目标systemimg生成system.img镜像文件的过程。伪目标systemimg依赖于INSTALLED_SYSTEMIMAGE,也就是最终生成的$(PRODUCT_OUT)/system.img文件。INSTALLED_SYSTEMIMAGE又依赖于BUILT_SYSTEMIMAGE、RECOVERY_FROM_BOOT_PATCH和ACP。注意,BUILT_SYSTEMIMAGE、RECOVERY_FROM_BOOT_PATCH和ACP之间有一个管道符号相隔。在一个make规则之中,一个目标的依赖文件可以划分为两类。一个类是普通依赖文件,它们位于管道符号的左则,另一类称为“order-only”依赖文件,它们位于管理符号的右侧。每一个普通依赖文件发生修改后,目标都会被更新。但是"order-only"依赖文件发生修改时,却不一定会导致目标更新。只有当目标文件不存在的情况下,"order-only"依赖文件的修改才会更新目标文件。也就是说,只有在目标文件不存在的情况下,“order-only”依赖文件才会参与到规则的执行过程中去。

        ACP描述的是一个Android专用的cp命令,在生成system.img镜像文件的过程中是需要用到的。普通的cp命令在不同的平台(Mac OS X、MinGW/Cygwin和Linux)的实现略有差异,并且可能会导致一些问题,于是Android编译系统就重写了自己的cp命令,使得它在不同平台下执行具有统一的行为,并且解决普通cp命令可能会出现的问题。例如,在Linux平台上,当我们把一个文件从NFS文件系统拷贝到本地文件系统时,普通的cp命令总是会认为在NFS文件系统上的文件比在本地文件系统上的文件要新,因为前者的时间戳精度是微秒,而后者的时间戳精度不是微秒。Android专用的cp命令源码可以参考build/tools/acp目录。

        RECOVERY_FROM_BOOT_PATCH描述的是一个patch文件,它的依赖规则如下所示:


[plain] view plain copy



       这个patch文件的名称为recovery_from_boot.p,保存在设备上system分区中,描述的是recovery.img与boot.img之间的差异。也就是说,在设备上,我们可以通过boot.img和recovery_from_boot.p文件生成一个recovery.img文件,使得设备可以进入recovery模式。

       INSTALLED_SYSTEMIMAGE描述的是system.img镜像所包含的核心文件,它的依赖规则如下所示:


[plain] view plain copy




        INSTALLED_SYSTEMIMAGE描述的是$(systemimage_intermediates)/system.img文件,它依赖于FULL_SYSTEMIMAGE_DEPS和INSTALLED_FILES_FILE,并且是通过调用函数build-systemimage-target来生成,而函数build-systemimage-target实际上又是通过调用python脚本build_image.py来生成system.img文件的。

        INSTALLED_FILES_FILE的依赖规则如下所示:


[plain] view plain copy



        INSTALLED_FILES_FILE描述的是$(PRODUCT_OUT)/installed-files.txt文件,该文件描述了要打包在system.img镜像中去的文件列表,同时它与INSTALLED_SYSTEMIMAGE一样,也依赖于FULL_SYSTEMIMAGE_DEPS。        
        FULL_SYSTEMIMAGE_DEPS的定义如下所示:[plain] view plain copy



        INTERNAL_USERIMAGES_DEPS描述的是制作system.img镜像所依赖的工具。例如,如果要制作的system.img使用的是yaffs2文件系统,那么对应工具就是mkyaffs2image。

        INTERNAL_SYSTEMIMAGE_FILES描述的是用来制作system.img镜像的文件,它的定义如下所示:


[plain] view plain copy



        从这里就可以看出,INTERNAL_SYSTEMIMAGE_FILES描述的就是从ALL_PREBUILT、ALL_COPIED_HEADERS、ALL_GENERATED_SOURCES、ALL_DEFAULT_INSTALLED_MODULES、PDK_FUSION_SYSIMG_FILES和RECOVERY_RESOURCE_ZIP中过滤出来的存放在TARGET_OUT目录下的那些文件,即在目标产品输出目录中的system子目录下那些文件。

        ALL_PREBUILT是一个过时的变量,用来描述要拷贝到目标设备上去的文件,现在建议使用PRODUCT_COPY_FILES来描述要拷贝到目标设备上去的文件。

        ALL_COPIED_HEADERS描述的是要拷贝到目标设备上去的头文件。

        ALL_GENERATED_SOURCES描述的是要拷贝到目标设备上去的由工具自动生成的源代码文件。

        ALL_DEFAULT_INSTALLED_MODULES描述的就是要安装要目标设备上的模块文件,这些模块文件是在build/core/main.mk文件中设置好并且传递给build/core/Makefile文件使用的。

        PDK_FUSION_SYSIMG_FILES是从PDK(Platform Development Kit)提取出来的相关文件。PDK是Google为了解决Android碎片化问题而为手机厂商提供的一个新版本的、还未发布的Android开发包,目的是为了让手机厂商跟上官方新版Android的开发节奏。具体可以参考这篇文章:http://www.xinwengao.net/release/af360/67079.shtml

        RECOVERY_RESOURCE_ZIP描述的是Android的recovery系统要使用的资源文件,对应于/system/etc目录下的recovery-resource.dat文件。




作者: liuwei    时间: 2016-9-28 14:09





欢迎光临 SuperIC社区_ (/) Powered by Discuz! X3.3