当前位置:文档之家› Android系统镜像文件的打包过程分析资料

Android系统镜像文件的打包过程分析资料

Android系统镜像文件的打包过程分析资料
Android系统镜像文件的打包过程分析资料

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

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

从前面和这两篇文章可以知道,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

......

ifdef FULL_BUILD

# The base list of modules to build for this product is specified

# by the appropriate product definition file, which was included

# by product_config.make.

product_MODULES := $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_PACKAGES) # Filter out the overridden packages before doing expansion

product_MODULES := $(filter-out $(foreach p, $(product_MODULES), \

$(PACKAGES.$(p).OVERRIDES)), $(product_MODULES))

$(call expand-required-modules,product_MODULES,$(product_MODULES))

product_FILES := $(call module-installed-files, $(product_MODULES))

else

# We're not doing a full build, and are probably only including

# a subset of the module makefiles. Don't try to build any modules

# requested by the product, because we probably won't have rules

# to build them.

product_FILES :=

endif

......

modules_to_install := $(sort \

$(ALL_DEFAULT_INSTALLED_MODULES) \

$(product_FILES) \

$(foreach tag,$(tags_to_install),$($(tag)_MODULES)) \

$(call get-tagged-modules, shell_$(TARGET_SHELL)) \

$(CUSTOM_MODULES) \

)

# Some packages may override others using LOCAL_OVERRIDES_PACKAGES.

# Filter out (do not install) any overridden packages.

overridden_packages := $(call get-package-overrides,$(modules_to_install))

ifdef overridden_packages

# old_modules_to_install := $(modules_to_install)

modules_to_install := \

$(filter-out $(foreach p,$(overridden_packages),$(p) %/$(p).apk), \

$(modules_to_install))

endif

......

# Install all of the host modules

modules_to_install += $(sort $(modules_to_install) $(ALL_HOST_INSTALLED_FILES))

# build/core/Makefile contains extra stuff that we don't want to pollute this

# top-level makefile with. It expects that ALL_DEFAULT_INSTALLED_MODULES

# contains everything that's built during the current make, but it also further

# extends ALL_DEFAULT_INSTALLED_MODULES.

ALL_DEFAULT_INSTALLED_MODULES := $(modules_to_install)

include $(BUILD_SYSTEM)/Makefile

modules_to_install := $(sort $(ALL_DEFAULT_INSTALLED_MODULES))

ALL_DEFAULT_INSTALLED_MODULES :=

......

.PHONY: ramdisk

ramdisk: $(INSTALLED_RAMDISK_TARGET)

.PHONY: userdataimage

userdataimage: $(INSTALLED_USERDATAIMAGE_TARGET)

......

.PHONY: bootimage

bootimage: $(INSTALLED_BOOTIMAGE_TARGET)

......

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

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

我们知道,Android源码中自带了很多默认的APK模块。如果我们想用自己编写的一个APK来代替某一个系统自带的APK,那么就可以通过变量PACKAGES..OVERRIDES := 来说明。其中,表示用来替换的APK,而表示被替换的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 在CODE上查看代码片派生到我的代码片

# Rules that need to be present for the all targets, even

# if they don't do anything.

.PHONY: systemimage

systemimage:

......

INSTALLED_SYSTEMIMAGE := $(PRODUCT_OUT)/system.img

......

$(INSTALLED_SYSTEMIMAGE): $(BUILT_SYSTEMIMAGE) $(RECOVERY_FROM_BOOT_PA TCH) | $(ACP)

@echo "Install system fs image: $@"

$(copy-file-to-target)

$(hide) $(call assert-max-image-size,$@ $(RECOVERY_FROM_BOOT_PA TCH),$(BOARD_SYSTEMIMAGE_PARTITION_SIZE),yaff s)

systemimage: $(INSTALLED_SYSTEMIMAGE)

.PHONY: systemimage-nodeps snod

systemimage-nodeps snod: $(filter-out systemimage-nodeps snod,$(MAKECMDGOALS)) \

| $(INTERNAL_USERIMAGES_DEPS)

@echo "make $@: ignoring dependencies"

$(call build-systemimage-target,$(INSTALLED_SYSTEMIMAGE))

$(hide) $(call assert-max-image-size,$(INSTALLED_SYSTEMIMAGE),$(BOARD_SYSTEMIMAGE_PARTI TION_SIZE),yaffs)

从这里就可以看出,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_PA TCH和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_PA TCH描述的是一个patch文件,它的依赖规则如下所示:

[plain] view plain copy 在CODE上查看代码片派生到我的代码片

# The system partition needs room for the recovery image as well. We

# now store the recovery image as a binary patch using the boot image

# as the source (since they are very similar). Generate the patch so

# we can see how big it's going to be, and include that in the system

# image size check calculation.

ifneq ($(INSTALLED_RECOVERYIMAGE_TARGET),)

intermediates := $(call intermediates-dir-for,PACKAGING,recovery_patch)

RECOVERY_FROM_BOOT_PATCH := $(intermediates)/recovery_from_boot.p $(RECOVERY_FROM_BOOT_PA TCH): $(INSTALLED_RECOVERYIMAGE_TARGET) \

$(INSTALLED_BOOTIMAGE_TARGET) \

$(HOST_OUT_EXECUTABLES)/imgdiff \

$(HOST_OUT_EXECUTABLES)/bsdiff

@echo "Construct recovery from boot"

mkdir -p $(dir $@)

PATH=$(HOST_OUT_EXECUTABLES):$$PATH

$(HOST_OUT_EXECUTABLES)/imgdiff $(INSTALLED_BOOTIMAGE_TARGET) $(INSTALLED_RECOVERYIMAGE_TARGET) $@

endif

这个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 在CODE上查看代码片派生到我的代码片

systemimage_intermediates := \

$(call intermediates-dir-for,PACKAGING,systemimage)

BUILT_SYSTEMIMAGE := $(systemimage_intermediates)/system.img

# $(1): output file

define build-systemimage-target

@echo "Target system fs image: $(1)"

@mkdir -p $(dir $(1)) $(systemimage_intermediates) && rm -rf $(systemimage_intermediates)/system_image_info.txt

$(call generate-userimage-prop-dictionary, $(systemimage_intermediates)/system_image_info.txt)

$(hide) PATH=$(foreach p,$(INTERNAL_USERIMAGES_BINARY_PA THS),$(p):)$$PATH \ ./build/tools/releasetools/build_image.py \

$(TARGET_OUT) $(systemimage_intermediates)/system_image_info.txt $(1)

endef

$(BUILT_SYSTEMIMAGE): $(FULL_SYSTEMIMAGE_DEPS) $(INSTALLED_FILES_FILE) $(call build-systemimage-target,$@)

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 在CODE上查看代码片派生到我的代码片

# -----------------------------------------------------------------

# installed file list

# Depending on anything that $(BUILT_SYSTEMIMAGE) depends on.

# We put installed-files.txt ahead of image itself in the dependency graph

# so that we can get the size stat even if the build fails due to too large

# system image.

INSTALLED_FILES_FILE := $(PRODUCT_OUT)/installed-files.txt

$(INSTALLED_FILES_FILE): $(FULL_SYSTEMIMAGE_DEPS)

@echo Installed file list: $@

@mkdir -p $(dir $@)

@rm -f $@

$(hide) build/tools/fileslist.py $(TARGET_OUT) > $@

INSTALLED_FILES_FILE描述的是$(PRODUCT_OUT)/installed-files.txt文件,该文件描述了要打包在system.img镜像中去的文件列表,同时它与INSTALLED_SYSTEMIMAGE一样,也依赖于FULL_SYSTEMIMAGE_DEPS。

FULL_SYSTEMIMAGE_DEPS的定义如下所示:

[plain] view plain copy 在CODE上查看代码片派生到我的代码片

FULL_SYSTEMIMAGE_DEPS := $(INTERNAL_SYSTEMIMAGE_FILES) $(INTERNAL_USERIMAGES_DEPS)

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

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

[plain] view plain copy 在CODE上查看代码片派生到我的代码片

INTERNAL_SYSTEMIMAGE_FILES := $(filter $(TARGET_OUT)/%, \

$(ALL_PREBUILT) \

$(ALL_COPIED_HEADERS) \

$(ALL_GENERA TED_SOURCES) \

$(ALL_DEFAULT_INSTALLED_MODULES) \

$(PDK_FUSION_SYSIMG_FILES) \

$(RECOVERY_RESOURCE_ZIP))

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

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

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

ALL_GENERA TED_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的开发节奏。具体可以参考这篇文章:https://www.doczj.com/doc/f85968282.html,/release/af360/67079.shtml。

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

注意,ALL_DEFAULT_INSTALLED_MODULES描述的文件除了在build/core/main.mk文件中定义的模块文件之外,还包含以下这些文件:

1. 通过PRODUCT_COPY_FILES定义的要拷贝到目标设备上去的文件

[plain] view plain copy 在CODE上查看代码片派生到我的代码片

unique_product_copy_files_pairs :=

$(foreach cf,$(PRODUCT_COPY_FILES), \

$(if $(filter $(unique_product_copy_files_pairs),$(cf)),,\

$(eval unique_product_copy_files_pairs += $(cf))))

unique_product_copy_files_destinations :=

$(foreach cf,$(unique_product_copy_files_pairs), \

$(eval _src := $(call word-colon,1,$(cf))) \

$(eval _dest := $(call word-colon,2,$(cf))) \

$(call check-product-copy-files,$(cf)) \

$(if $(filter $(unique_product_copy_files_destinations),$(_dest)), \

$(info PRODUCT_COPY_FILES $(cf) ignored.), \

$(eval _fulldest := $(call append-path,$(PRODUCT_OUT),$(_dest))) \

$(if $(filter %.xml,$(_dest)),\

$(eval $(call copy-xml-file-checked,$(_src),$(_fulldest))),\

$(eval $(call copy-one-file,$(_src),$(_fulldest)))) \

$(eval ALL_DEFAULT_INSTALLED_MODULES += $(_fulldest)) \

$(eval unique_product_copy_files_destinations += $(_dest))))

2. 由ADDITIONAL_DEFAULT_PROPERTIES定义的属性所组成的default.prop 文件

[plain] view plain copy 在CODE上查看代码片派生到我的代码片

INSTALLED_DEFAULT_PROP_TARGET := $(TARGET_ROOT_OUT)/default.prop

ALL_DEFAULT_INSTALLED_MODULES += $(INSTALLED_DEFAULT_PROP_TARGET)

ADDITIONAL_DEFAULT_PROPERTIES := \

$(call collapse-pairs, $(ADDITIONAL_DEFAULT_PROPERTIES))

ADDITIONAL_DEFAULT_PROPERTIES += \

$(call collapse-pairs, $(PRODUCT_DEFAULT_PROPERTY_OVERRIDES)) ADDITIONAL_DEFAULT_PROPERTIES := $(call uniq-pairs-by-first-component, \ $(ADDITIONAL_DEFAULT_PROPERTIES),=)

$(INSTALLED_DEFAULT_PROP_TARGET):

@echo Target buildinfo: $@

@mkdir -p $(dir $@)

$(hide) echo "#" > $@; \

echo "# ADDITIONAL_DEFAULT_PROPERTIES" >> $@; \

echo "#" >> $@;

$(hide) $(foreach line,$(ADDITIONAL_DEFAULT_PROPERTIES), \

echo "$(line)" >> $@;)

build/tools/post_process_props.py $@

3. 由ADDITIONAL_BUILD_PROPERTIES等定义的属性所组成的build.prop文件[plain] view plain copy 在CODE上查看代码片派生到我的代码片

INSTALLED_BUILD_PROP_TARGET := $(TARGET_OUT)/build.prop

ALL_DEFAULT_INSTALLED_MODULES += $(INSTALLED_BUILD_PROP_TARGET)

ADDITIONAL_BUILD_PROPERTIES := \

$(call collapse-pairs, $(ADDITIONAL_BUILD_PROPERTIES))

ADDITIONAL_BUILD_PROPERTIES := $(call uniq-pairs-by-first-component, \

$(ADDITIONAL_BUILD_PROPERTIES),=)

......

BUILDINFO_SH := build/tools/buildinfo.sh

$(INSTALLED_BUILD_PROP_TARGET): $(BUILDINFO_SH) $(INTERNAL_BUILD_ID_MAKEFILE) $(BUILD_SYSTEM)/version_defaults.mk $(wildcard $(TARGET_DEVICE_DIR)/system.prop)

@echo Target buildinfo: $@

@mkdir -p $(dir $@)

$(hide) TARGET_BUILD_TYPE="$(TARGET_BUILD_V ARIANT)" \

TARGET_DEVICE="$(TARGET_DEVICE)" \

PRODUCT_NAME="$(TARGET_PRODUCT)" \

PRODUCT_BRAND="$(PRODUCT_BRAND)" \

PRODUCT_DEFAULT_LANGUAGE="$(call

default-locale-language,$(PRODUCT_LOCALES))" \

PRODUCT_DEFAULT_REGION="$(call

default-locale-region,$(PRODUCT_LOCALES))" \

PRODUCT_DEFAULT_WIFI_CHANNELS="$(PRODUCT_DEFAULT_WIFI_CHANNELS)" \ PRODUCT_MODEL="$(PRODUCT_MODEL)" \

PRODUCT_MANUFACTURER="$(PRODUCT_MANUFACTURER)" \

PRIV A TE_BUILD_DESC="$(PRIV A TE_BUILD_DESC)" \

BUILD_ID="$(BUILD_ID)" \

BUILD_DISPLAY_ID="$(BUILD_DISPLAY_ID)" \

BUILD_NUMBER="$(BUILD_NUMBER)" \

PLATFORM_VERSION="$(PLATFORM_VERSION)" \

PLATFORM_SDK_VERSION="$(PLATFORM_SDK_VERSION)" \

PLATFORM_VERSION_CODENAME="$(PLATFORM_VERSION_CODENAME)" \

BUILD_VERSION_TAGS="$(BUILD_VERSION_TAGS)" \

TARGET_BOOTLOADER_BOARD_NAME="$(TARGET_BOOTLOADER_BOARD_NAME) " \

BUILD_FINGERPRINT="$(BUILD_FINGERPRINT)" \

TARGET_BOARD_PLATFORM="$(TARGET_BOARD_PLATFORM)" \

TARGET_CPU_ABI="$(TARGET_CPU_ABI)" \

TARGET_CPU_ABI2="$(TARGET_CPU_ABI2)" \

TARGET_AAPT_CHARACTERISTICS="$(TARGET_AAPT_CHARACTERISTICS)" \ bash $(BUILDINFO_SH) > $@

$(hide) if [ -f $(TARGET_DEVICE_DIR)/system.prop ]; then \

cat $(TARGET_DEVICE_DIR)/system.prop >> $@; \

fi

$(if $(ADDITIONAL_BUILD_PROPERTIES), \

$(hide) echo >> $@; \

echo "#" >> $@; \

echo "# ADDITIONAL_BUILD_PROPERTIES" >> $@; \

echo "#" >> $@; )

$(hide) $(foreach line,$(ADDITIONAL_BUILD_PROPERTIES), \

echo "$(line)" >> $@;)

$(hide) build/tools/post_process_props.py $@

4. 用来描述event类型日志格式的event-log-tags文件

[plain] view plain copy 在CODE上查看代码片派生到我的代码片

all_event_log_tags_file := $(TARGET_OUT_COMMON_INTERMEDIATES)/all-event-log-tags.txt

event_log_tags_file := $(TARGET_OUT)/etc/event-log-tags

# Include tags from all packages that we know about

all_event_log_tags_src := \

$(sort $(foreach m, $(ALL_MODULES), $(ALL_MODULES.$(m).EVENT_LOG_TAGS)))

# PDK builds will already have a full list of tags that needs to get merged

# in with the ones from source

pdk_fusion_log_tags_file := $(patsubst $(PRODUCT_OUT)/%,$(_pdk_fusion_intermediates)/%,$(filter

$(event_log_tags_file),$(ALL_PDK_FUSION_FILES)))

$(all_event_log_tags_file): PRIV ATE_SRC_FILES := $(all_event_log_tags_src) $(pdk_fusion_log_tags_file)

$(hide) mkdir -p $(dir $@)

$(hide) build/tools/merge-event-log-tags.py -o $@ $(PRIV ATE_SRC_FILES)

# Include tags from all packages included in this product, plus all

# tags that are part of the system (ie, not in a vendor/ or device/

# directory).

event_log_tags_src := \

$(sort $(foreach m,\

$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_PACKAGES) \

$(call module-names-for-tag-list,user), \

$(ALL_MODULES.$(m).EVENT_LOG_TAGS)) \

$(filter-out vendor/% device/% out/%,$(all_event_log_tags_src)))

$(event_log_tags_file): PRIV ATE_SRC_FILES := $(event_log_tags_src) $(pdk_fusion_log_tags_file)

$(event_log_tags_file): PRIV ATE_MERGED_FILE := $(all_event_log_tags_file)

$(event_log_tags_file): $(event_log_tags_src) $(all_event_log_tags_file) $(pdk_fusion_log_tags_file)

$(hide) mkdir -p $(dir $@)

$(hide) build/tools/merge-event-log-tags.py -o $@ -m $(PRIV ATE_MERGED_FILE) $(PRIV ATE_SRC_FILES)

event-log-tags: $(event_log_tags_file)

ALL_DEFAULT_INSTALLED_MODULES += $(event_log_tags_file)

关于Android系统的event日志,可以参考和这个系列的文章。

5. 由于使用了BSD、GPL和Apache许可的模块而必须在发布时附带的Notice文件

[plain] view plain copy 在CODE上查看代码片派生到我的代码片

target_notice_file_txt := $(TARGET_OUT_INTERMEDIATES)/NOTICE.txt

target_notice_file_html := $(TARGET_OUT_INTERMEDIATES)/NOTICE.html

target_notice_file_html_gz := $(TARGET_OUT_INTERMEDIATES)/NOTICE.html.gz

tools_notice_file_txt := $(HOST_OUT_INTERMEDIATES)/NOTICE.txt

tools_notice_file_html := $(HOST_OUT_INTERMEDIATES)/NOTICE.html

kernel_notice_file := $(TARGET_OUT_NOTICE_FILES)/src/kernel.txt

pdk_fusion_notice_files := $(filter $(TARGET_OUT_NOTICE_FILES)/%, $(ALL_PDK_FUSION_FILES))

......

# Install the html file at /system/etc/NOTICE.html.gz.

# This is not ideal, but this is very late in the game, after a lot of

# the module processing has already been done -- in fact, we used the

# fact that all that has been done to get the list of modules that we

# need notice files for.

$(target_notice_file_html_gz): $(target_notice_file_html) | $(MINIGZIP)

$(hide) $(MINIGZIP) -9 < $< > $@

installed_notice_html_gz := $(TARGET_OUT)/etc/NOTICE.html.gz

$(installed_notice_html_gz): $(target_notice_file_html_gz) | $(ACP)

$(copy-file-to-target)

# if we've been run my mm, mmm, etc, don't reinstall this every time

ifeq ($(ONE_SHOT_MAKEFILE),)

ALL_DEFAULT_INSTALLED_MODULES += $(installed_notice_html_gz)

endif

6. 用来验证OTA更新的证书文件

[plain] view plain copy 在CODE上查看代码片派生到我的代码片

ALL_DEFAULT_INSTALLED_MODULES += $(TARGET_OUT_ETC)/security/otacerts.zip

$(TARGET_OUT_ETC)/security/otacerts.zip: KEY_CERT_PAIR := $(DEFAULT_KEY_CERT_PAIR)

$(TARGET_OUT_ETC)/security/otacerts.zip:

$(addsuffix .x509.pem,$(DEFAULT_KEY_CERT_PAIR))

$(hide) rm -f $@

$(hide) mkdir -p $(dir $@)

$(hide) zip -qj $@ $<

.PHONY: otacerts

otacerts: $(TARGET_OUT_ETC)/security/otacerts.zip

二. boot.img

从前面的分析可以知道,build/core/main.mk文件定义了boot.img镜像文件的依赖规则,我们可以通过执行make bootimage命令来执行。其中,bootimage是一个伪目标,它依赖于INSTALLED_BOOTIMAGE_TARGET。

INSTALLED_BOOTIMAGE_TARGET定义在build/core/Makefile文件中,如下所示:

[plain] view plain copy 在CODE上查看代码片派生到我的代码片

ifneq ($(strip $(TARGET_NO_KERNEL)),true)

# -----------------------------------------------------------------

# the boot image, which is a collection of other images.

INTERNAL_BOOTIMAGE_ARGS := \

$(addprefix --second ,$(INSTALLED_2NDBOOTLOADER_TARGET)) \

--kernel $(INSTALLED_KERNEL_TARGET) \

--ramdisk $(INSTALLED_RAMDISK_TARGET)

INTERNAL_BOOTIMAGE_FILES := $(filter-out --%,$(INTERNAL_BOOTIMAGE_ARGS))

BOARD_KERNEL_CMDLINE := $(strip $(BOARD_KERNEL_CMDLINE))

ifdef BOARD_KERNEL_CMDLINE

INTERNAL_BOOTIMAGE_ARGS += --cmdline "$(BOARD_KERNEL_CMDLINE)"

endif

BOARD_KERNEL_BASE := $(strip $(BOARD_KERNEL_BASE))

ifdef BOARD_KERNEL_BASE

INTERNAL_BOOTIMAGE_ARGS += --base $(BOARD_KERNEL_BASE)

endif

BOARD_KERNEL_PAGESIZE := $(strip $(BOARD_KERNEL_PAGESIZE))

ifdef BOARD_KERNEL_PAGESIZE

INTERNAL_BOOTIMAGE_ARGS += --pagesize $(BOARD_KERNEL_PAGESIZE)

endif

INSTALLED_BOOTIMAGE_TARGET := $(PRODUCT_OUT)/boot.img

ifeq ($(TARGET_BOOTIMAGE_USE_EXT2),true)

tmp_dir_for_image := $(call intermediates-dir-for,EXECUTABLES,boot_img)/bootimg INTERNAL_BOOTIMAGE_ARGS += --tmpdir $(tmp_dir_for_image)

INTERNAL_BOOTIMAGE_ARGS += --genext2fs $(MKEXT2IMG)

$(INSTALLED_BOOTIMAGE_TARGET): $(MKEXT2IMG) $(INTERNAL_BOOTIMAGE_FILES)

$(call pretty,"Target boot image: $@")

$(hide) $(MKEXT2BOOTIMG) $(INTERNAL_BOOTIMAGE_ARGS) --output $@

else # TARGET_BOOTIMAGE_USE_EXT2 != true

$(INSTALLED_BOOTIMAGE_TARGET): $(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_FILES)

$(call pretty,"Target boot image: $@")

$(hide) $(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_ARGS) $(BOARD_MKBOOTIMG_ARGS) --output $@

$(hide) $(call assert-max-image-size,$@,$(BOARD_BOOTIMAGE_PARTITION_SIZE),raw)

endif # TARGET_BOOTIMAGE_USE_EXT2

else # TARGET_NO_KERNEL

# HACK: The top-level targets depend on the bootimage. Not all targets

# can produce a bootimage, though, and emulator targets need the ramdisk

# instead. Fake it out by calling the ramdisk the https://www.doczj.com/doc/f85968282.html,otimage.

# TODO: make the emulator use bootimages, and make mkbootimg accept

# kernel-less inputs.

INSTALLED_BOOTIMAGE_TARGET := $(INSTALLED_RAMDISK_TARGET)

endif

在介绍boot.img之前,我们首先要介绍BootLoader。我们都知道,PC启动的时候,首先执行的是在BIOS上的代码,然后再由BIOS负责将Kernel加载起来执行。在嵌入式世界里,BootLoader的作用就相当于PC的BIOS。

BootLoader的启动通常分为两个阶段。第一阶段在固态存储中(Flash)执行,负责初始化硬件,例如设置CPU工作模式、时钟频率以及初始化内存等,并且将第二阶段拷贝到RAM去准备执行。第二阶段就是在RAM中执行,因此速度会更快,主要负责建立内存映像,以及加载Kernel镜像和Ramdisk镜像。

BootLoader的第二阶段执行完成后,就开始启动Kernel了。Kernel负责启动各个子系统,例如CPU调度子系统和内存管理子系统等等。Kernel启动完成之后,就会将Ramdisk 镜像安装为根系统,并且在其中找到一个init文件,将其启动为第一个进程。init进程启动就意味着系统进入到用户空间执行了,这时候各种用户空间运行时以及守护进程就会被加载起来。最终完成整个系统的启动过程。

BootLoader的第一阶段是固化在硬件中的,而boot.img的存在就是为BootLoader

的第一阶段提供第二阶段、Kernel镜像、Ramdisk镜像,以及相应的启动参数等等。也就是说,boot.img主要包含有BootLoader的第二阶段、Kernel镜像和Ramdisk镜像。当然,BootLoader的第二阶段是可选的。当不存在BootLoader的第二阶段的时候,BootLoader的第一阶段启动完成后,就直接进入到kernel启动阶段。

boot.img镜像的文件格式定义在system/core/mkbootimg/bootimg.h中,如下所示:

[plain] view plain copy 在CODE上查看代码片派生到我的代码片

/*

** +-----------------+

** | boot header | 1 page

** +-----------------+

** | kernel | n pages

** +-----------------+

** | ramdisk | m pages

** +-----------------+

** | second stage | o pages

** +-----------------+

**

** n = (kernel_size + page_size - 1) / page_size

** m = (ramdisk_size + page_size - 1) / page_size

** o = (second_size + page_size - 1) / page_size

**

** 0. all entities are page_size aligned in flash

** 1. kernel and ramdisk are required (size != 0)

** 2. second is optional (second_size == 0 -> no second)

** 3. load each element (kernel, ramdisk, second) at

** the specified physical address (kernel_addr, etc)

** 4. prepare tags at tag_addr. kernel_args[] is

** appended to the kernel commandline in the tags.

** 5. r0 = 0, r1 = MACHINE_TYPE, r2 = tags_addr

** 6. if second_size != 0: jump to second_addr

** else: jump to kernel_addr

*/

它由4部分组成:boot header、kernel、ramdisk和second state。每一个部分的大小都是以页为单位的,其中,boot header描述了kernel、ramdisk、sencond stage的加载地址、大小,以及kernel启动参数等等信息。

boot header的结构同样是定义在system/core/mkbootimg/bootimg.h中,如下所示:

[cpp] view plain copy 在CODE上查看代码片派生到我的代码片

struct boot_img_hdr

{

unsigned char magic[BOOT_MAGIC_SIZE];

unsigned kernel_size; /* size in bytes */

unsigned kernel_addr; /* physical load addr */

unsigned ramdisk_size; /* size in bytes */

unsigned ramdisk_addr; /* physical load addr */

unsigned second_size; /* size in bytes */

unsigned second_addr; /* physical load addr */

unsigned tags_addr; /* physical addr for kernel tags */

unsigned page_size; /* flash page size we assume */

unsigned unused[2]; /* future expansion: should be 0 */

unsigned char name[BOOT_NAME_SIZE]; /* asciiz product name */

unsigned char cmdline[BOOT_ARGS_SIZE];

unsigned id[8]; /* timestamp / checksum / sha1 / etc */

};

各个成员变量的含义如下所示:

magic:魔数,等于“ANDROID!”。

kernel_size:Kernel大小,以字节为单位。

kernel_addr:Kernel加载的物理地址。

ramdisk_size:Ramdisk大小,以字节为单位。

ramdisk_addr:Ramdisk加载的物理地址。

second_size:BootLoader第二阶段的大小,以字节为单位。

second_addr:BootLoader第二阶段加载的物理地址。

tags_addr:Kernel启动之前,它所需要的启动参数都会填入到由tags_addr所描述的一个物理地址中去。

unused:保留以后使用。

page_size:页大小。

name:产品名称。

id:时间戳、校验码等等。

理解了BootLoader的启动过程,以及boot.img的文件结构之后,就不难理解boot.img文件的生成过程了。

首先检查变量TARGET_NO_KERNEL的值是否等于true。如果等于true的话,那么就表示boot.img不包含有BootLoader第二阶段和Kernel,即它等同于Ramdisk镜像。如果不等于true的话,那么就通过INSTALLED_2NDBOOTLOADER_TARGET、INSTALLED_KERNEL_TARGET和INSTALLED_RAMDISK_TARGET获得BootLoader第二阶段、Kernel和Ramdisk对应的镜像文件,以及通过BOARD_KERNEL_CMDLINE、BOARD_KERNEL_BASE和BOARD_KERNEL_PAGESIZE获得Kernel启动命令行参数、内核基地址和页大小等参数。最后根据TARGET_BOOTIMAGE_USE_EXT2的值来决定是使用genext2fs还是mkbootimg工具来生成boot.img。

三. ramdisk.img

从前面的分析可以知道,build/core/main.mk文件定义了ramdisk.img镜像文件的依赖规则,我们可以通过执行make ramdisk命令来执行。其中,ramdisk是一个伪目标,它依赖于INSTALLED_RAMDISK_TARGET。

INSTALLED_RAMDISK_TARGET定义在build/core/Makefile文件中,如下所示:

[plain] view plain copy 在CODE上查看代码片派生到我的代码片

INTERNAL_RAMDISK_FILES := $(filter $(TARGET_ROOT_OUT)/%, \

$(ALL_PREBUILT) \

$(ALL_COPIED_HEADERS) \

$(ALL_GENERA TED_SOURCES) \

$(ALL_DEFAULT_INSTALLED_MODULES))

BUILT_RAMDISK_TARGET := $(PRODUCT_OUT)/ramdisk.img

# We just build this directly to the install location.

INSTALLED_RAMDISK_TARGET := $(BUILT_RAMDISK_TARGET)

$(INSTALLED_RAMDISK_TARGET): $(MKBOOTFS) $(INTERNAL_RAMDISK_FILES) | $(MINIGZIP)

$(call pretty,"Target ram disk: $@")

$(hide) $(MKBOOTFS) $(TARGET_ROOT_OUT) | $(MINIGZIP) > $@

ALL_PREBUILT、ALL_COPIED_HEADERS、ALL_GENERATED_SOURCES和ALL_DEFAULT_INSTALLED_MODULES这几个变量的含义前面分析system.img的生成过程时已经介绍过了。因此,这里我们就很容易知道,ramdisk.img镜像实际上就是由这几个变量所描述的、保存在TARGET_ROOT_OUT目录中的文件所组成。与此相对应的是,system.img由保存在TARGET_OUT目录中的文件组成。

TARGET_ROOT_OUT和TARGET_OUT又分别是指向什么目录呢?假设我们的编译目标产品是模拟器,那么TARGET_ROOT_OUT和TARGET_OUT对应的目录就分别为

out/target/product/generic/root和out/target/product/generic/system。

收集好对应的文件之后,就可以通过MKBOOTFS和MINIGZIP这两个变量描述的mkbootfs和minigzip工具来生成一个格式为cpio的ramdisk.img了。mkbootfs和minigzip这两个工具对应的源码分别位于system/core/cpio和external/zlib目录中。

四. userdata.img

userdata.img镜像描述的是Android系统的data分区,即/data目录,里面包含了用户安装的APP以及数据等等。

从前面的分析可以知道,build/core/main.mk文件定义了userdata.img镜像文件的依赖规则,我们可以通过执行make userdataimage命令来执行。其中,userdataimage是一个伪目标,它依赖于INSTALLED_USERDA TAIMAGE_TARGET。

INSTALLED_USERDA TAIMAGE_TARGET定义在build/core/Makefile文件中,如下所示:

[plain] view plain copy 在CODE上查看代码片派生到我的代码片

INTERNAL_USERDA TAIMAGE_FILES := \

$(filter $(TARGET_OUT_DA TA)/%,$(ALL_DEFAULT_INSTALLED_MODULES))

$(info $(TARGET_OUT_DATA))

# If we build "tests" at the same time, make sure $(tests_MODULES) get covered.

ifdef is_tests_build

INTERNAL_USERDA TAIMAGE_FILES += \

$(filter $(TARGET_OUT_DA TA)/%,$(tests_MODULES))

endif

userdataimage_intermediates := \

$(call intermediates-dir-for,PACKAGING,userdata)

BUILT_USERDATAIMAGE_TARGET := $(PRODUCT_OUT)/userdata.img

define build-userdataimage-target

$(call pretty,"Target userdata fs image: $(INSTALLED_USERDATAIMAGE_TARGET)")

@mkdir -p $(TARGET_OUT_DATA)

@mkdir -p $(userdataimage_intermediates) && rm -rf $(userdataimage_intermediates)/userdata_image_info.txt

$(call generate-userimage-prop-dictionary, $(userdataimage_intermediates)/userdata_image_info.txt)

$(hide) PATH=$(foreach p,$(INTERNAL_USERIMAGES_BINARY_PA THS),$(p):)$$PATH \ ./build/tools/releasetools/build_image.py \

$(TARGET_OUT_DATA) $(userdataimage_intermediates)/userdata_image_info.txt

$(INSTALLED_USERDATAIMAGE_TARGET)

$(hide) $(call assert-max-image-size,$(INSTALLED_USERDATAIMAGE_TARGET),$(BOARD_USERDATA IMAGE_PARTITION_SIZE),yaffs)

endef

# We just build this directly to the install location.

INSTALLED_USERDATAIMAGE_TARGET := $(BUILT_USERDATAIMAGE_TARGET) $(INSTALLED_USERDATAIMAGE_TARGET): $(INTERNAL_USERIMAGES_DEPS) \

$(INTERNAL_USERDA TAIMAGE_FILES) $(build-userdataimage-target)

INSTALLED_USERDA TAIMAGE_TARGET的值等于BUILT_USERDATAIMAGE_TARGET,后者指向的就是userdata.img文件,它依赖于INTERNAL_USERDA TAIMAGE_FILES描述的文件,即那些由ALL_DEFAULT_INSTALLED_MODULES描述的、并且位于TARGET_OUT_DA TA目录下的文件。假设我们的编译目标产品是模拟器,那么TARGET_OUT_DATA对应的目录就为out/target/product/generic/data。此外,如果我们在make userdataimage的时候,还带有一个额外的tests目标,那么那些将自己的tag设置为tests的模块也会被打包到userdata.img镜像中。

INSTALLED_USERDA TAIMAGE_TARGET还依赖于INTERNAL_USERIMAGES_DEPS。前面在分析system.img镜像的生成过程时提到,INTERNAL_USERIMAGES_DEPS描述的是制作userdata.img镜像所依赖的工具。例如,如果要制作的userdata.img使用的是yaffs2文件系统,那么对应工具就是mkyaffs2image。

INSTALLED_USERDA TAIMAGE_TARGET规则由函数build-userdataimage-target 来执行,该函数通过build_image.py脚本来生成userdata.img镜像文件。

与system.img镜像类似,userdata.img镜像的生成也可以通过一个没有任何依赖的伪目标userdataimage-nodeps生成,如下所示:

[plain] view plain copy 在CODE上查看代码片派生到我的代码片

.PHONY: userdataimage-nodeps

userdataimage-nodeps: | $(INTERNAL_USERIMAGES_DEPS)

$(build-userdataimage-target)

当我们执行make userdataimage-nodeps的时候,函数build-userdataimage-target就会被调用直接生成userdata.img文件。

五. recovery.img

recovery.img是设备进入recovery模式时所加载的镜像。recovery模式就是用来更新系统的,我们可以认为我们的设备具有两个系统。一个是正常的系统,它由boot.img、system.img、ramdisk.img和userdata.img等组成,另外一个就是recovery系统,由recovery.img 组成。平时我们进入的都是正常的系统,只有当我们需要更新这个正常的系统时,才会进入到recovery系统。因此,我们可以将recovery系统理解为在Linux Kernel之上运行的一个小小的用户空间运行时。这个用户空间运行时可以访问我们平时经常使用的那个系统的文件,从而实现对它的更新。

在build/core/Makefile文件中,定义了一个伪目标recoveryimage,用来生成recovery.img,如下所示:

[plain] view plain copy 在CODE上查看代码片派生到我的代码片

.PHONY: recoveryimage

recoveryimage: $(INSTALLED_RECOVERYIMAGE_TARGET) $(RECOVERY_RESOURCE_ZIP)

INSTALLED_RECOVERYIMAGE_TARGET描述的是组成recovery系统的模块文件,而RECOVERY_RESOURCE_ZIP描述的是recovery系统使用的资源包,它的定义如下所示:

[plain] view plain copy 在CODE上查看代码片派生到我的代码片

INSTALLED_RECOVERYIMAGE_TARGET := $(PRODUCT_OUT)/recovery.img

recovery_initrc := $(call include-path-for, recovery)/etc/init.rc

recovery_kernel := $(INSTALLED_KERNEL_TARGET) # same as a non-recovery system recovery_ramdisk := $(PRODUCT_OUT)/ramdisk-recovery.img

recovery_build_prop := $(INSTALLED_BUILD_PROP_TARGET)

recovery_binary := $(call intermediates-dir-for,EXECUTABLES,recovery)/recovery

recovery_resources_common := $(call include-path-for, recovery)/res

recovery_resources_private := $(strip $(wildcard $(TARGET_DEVICE_DIR)/recovery/res)) recovery_resource_deps := $(shell find $(recovery_resources_common) \

$(recovery_resources_private) -type f)

recovery_fstab := $(strip $(wildcard $(TARGET_DEVICE_DIR)/recovery.fstab))

# Named '.dat' so we don't attempt to use imgdiff for patching it.

RECOVERY_RESOURCE_ZIP := $(TARGET_OUT)/etc/recovery-resource.dat

......

INTERNAL_RECOVERYIMAGE_ARGS := \

$(addprefix --second ,$(INSTALLED_2NDBOOTLOADER_TARGET)) \

--kernel $(recovery_kernel) \

--ramdisk $(recovery_ramdisk)

# Assumes this has already been stripped

ifdef BOARD_KERNEL_CMDLINE

INTERNAL_RECOVERYIMAGE_ARGS += --cmdline "$(BOARD_KERNEL_CMDLINE)" endif

ifdef BOARD_KERNEL_BASE

INTERNAL_RECOVERYIMAGE_ARGS += --base $(BOARD_KERNEL_BASE)

endif

BOARD_KERNEL_PAGESIZE := $(strip $(BOARD_KERNEL_PAGESIZE))

ifdef BOARD_KERNEL_PAGESIZE

INTERNAL_RECOVERYIMAGE_ARGS += --pagesize $(BOARD_KERNEL_PAGESIZE)

android系统开机启动流程分析

一,系统引导bootloader 加电,cpu执行bootloader程序,正常启动系统,加载boot.img【其中包含内核。还有ramdisk】 二,内核kernel bootloader加载kernel,kernel自解压,初始化,载入built-in驱动程序,完成启动。 内核启动后会创建若干内核线程,在后装入并执行程序/sbin/init/,载入init process,切换至用户空间(user-space) 内核zImage解压缩 head.S【这是ARM-Linux运行的第一个文件,这些代码是一个比较独立的代码包裹器。其作用就是解压Linux内核,并将PC指针跳到内核(vmlinux)的第一条指令】首先初始化自解压相关环境(内存等),调用decompress_kernel进行解压,解压后调用start_kernel启动内核【start_kernel是任何版本linux内核的通用初始化函数,它会初始化很多东西,输出linux版本信息,设置体系结构相关的环境,页表结构初始化,设置系 统自陷入口,初始化系统IRQ,初始化核心调度器等等】,最后调用rest_init【rest_init 会调用kernel_init启动init进程(缺省是/init)。然后执行schedule开始任务调度。这个init是由android的./system/core/init下的代码编译出来的,由此进入了android的代码】。 三,Init进程启动 【init是kernel启动的第一个进程,init启动以后,整个android系统就起来了】 init进程启动后,根据init.rc 和init. .rc脚本文件建立几个基本 服务(servicemanager zygote),然后担当property service 的功能 打开.rc文件,解析文件内容。【system/core/init/init.c】将service信息放置到service.list中【system/core/init/init_parser.c】。 建立service进程。【service_start(…) execve(…)】 在init.c中,完成以下工作 1、初始化log系统【解析/init.rc和init.%hardware%.rc文件,在两个 文件解析步骤2时执行“early-init”行动】 2、初始化设备【在/dev下创建所有设备节点,下载firmwares】 3、初始化属性服务器【在两个文件解析步骤2时执行“init”行动】

Android 开机启动流程

Android的开机流程 1. 系统引导bootloader 1) 源码:bootable/bootloader/* 2) 说明:加电后,CPU将先执行bootloader程序,此处有三种选择 a) 开机按Camera+Power启动到fastboot,即命令或SD卡烧写模式,不加载内核及文件系统,此处可以进行工厂模式的烧写 b) 开机按Home+Power启动到recovery模式,加载recovery.img,recovery.i mg包含内核,基本的文件系统,用于工程模式的烧写 c) 开机按Power,正常启动系统,加载boot.img,boot.img包含内核,基本文件系统,用于正常启动手机(以下只分析正常启动的情况) 2. 内核kernel 1) 源码:kernel/* 2) 说明:kernel由bootloader加载 3. 文件系统及应用init 1) 源码:system/core/init/* 2) 配置文件:system/rootdir/init.rc, 3) 说明:init是一个由内核启动的用户级进程,它按照init.rc中的设置执行:启动服务(这里的服务指linux底层服务,如adbd提供adb支持,vold提供SD卡挂载等),执行命令和按其中的配置语句执行相应功能 4. 重要的后台程序zygote 1)源码:frameworks/base/cmds/app_main.cpp等 2) 说明:zygote是一个在init.rc中被指定启动的服务,该服务对应的命令是/system/bin/app_process a)建立Java Runtime,建立虚拟机 b) 建立Socket接收ActivityManangerService的请求,用于Fork应用程序 c) 启动System Server 5. 系统服务system server 1)源码:frameworks/base/services/java/com/android/server/SystemServer.jav a 2) 说明:被zygote启动,通过SystemManager管理android的服务(这里的服务指frameworks/base/services下的服务,如卫星定位服务,剪切板服务等) 6. 桌面launcher 1)源码:ActivityManagerService.java为入口,packages/apps/launcher*实现 2) 说明:系统启动成功后SystemServer使用xxx.systemReady()通知各个服务,系统已经就绪,桌面程序Home就是在ActivityManagerService.systemReady()通知的过程中建立的,最终调用()启launcher 7. 解锁 1) 源码: frameworks/policies/base/phone/com/android/internal/policy/impl/*lock* 2) 说明:系统启动成功后SystemServer调用wm.systemReady()通知WindowManagerService,进而调用PhoneWindowManager,最终通过LockPatternKeyguardView显示解锁界面,跟踪代码可以看到解锁界面并不是一个Activity,这是只是向特定层上绘图,其代码了存放在特殊的位置

分析Android 开机启动慢的原因

开机启动花了40多秒,正常开机只需要28秒就能开机起来。 内核的启动我没有去分析,另一个同事分析的。我主要是分析从SystemServer启来到开机动画结束显示解锁界面的这段时间,也就是开机动画的第三个动画开始到结束这段时间,这是个比较耗时阶段,一般都在17秒左右(见过牛B的手机,只需5秒)。 SystemServer分两步执行:init1和init2。init1主要是初始化native的服务,代码在sy stem_init.cpp的system_init,初始化了SurfaceFlinger和SensorService这两个native的服务。init2启动的是java的服务,比如ActivityManagerService、WindowManagerService、PackageManagerService等,在这个过程中PackageManagerService用的时间最长,因为PackageManagerService会去扫描特定目录下的jar包和apk文件。 在开机时间需要40多秒的时,从Log上可以看到,从SurfaceFlinger初始化到动画结束,要27秒左右的时间,即从SurfaceFlinger::init的LOGI("SurfaceFlinger is starting")这句Log到void SurfaceFlinger::bootFinished()的LOGI("Boot is finished (%ld ms)", long(ns 2ms(duration)) ),需要27秒左右的时间,这显然是太长了,但到底是慢在哪了呢?应该在个中间的点,二分一下,于是想到了以启动服务前后作为分隔:是服务启动慢了,还是在服务启动后的这段时间慢?以ActivityManagerService的Slog.i(TAG, "System now ready")的这句Log为分割点,对比了一下,在从SurfaceFlinger is starting到System now read y多了7秒左右的时间,这说明SystemServer在init1和init2过程中启动慢了,通过排查,发现在init1启动的时候,花了7秒多的时间,也就是system_init的LOGI("Entered system _init()")到LOGI("System server: starting Android runtime.\n")这段时间用了7秒多,而正常情况是400毫秒便可以初始化完,通过添加Log看到,在SensorService启动时,用了比较长的时间。 不断的添加Log发现,在启动SensorService时候,关闭设备文件变慢了,每次关闭一个/dev/input/下的设备文件需要100ms左右,而SensorService有60~70次的关闭文件,大概有7s左右的时间。 调用流程是: frameworks/base/cmds/system_server/library/system_init.cpp: system_init->SensorServi ce::instantiate frameworks/native/services/sensorservice/SensorService.cpp: void SensorService::onFi rstRef()->SensorDevice& dev(SensorDevice::getInstance()) hardware/libsensors/SensorDevice.cpp: SensorDevice::SensorDevice()->sensors_open hardware/libsensors/sensors.cpp: open_sensors->sensors_poll_context_t sensors_poll_context_t执行打开每个传感器设备时,遍历/dev/input/目录下的设备文件,以匹配当前需要打开的设备,遍历文件是在 hardware/libsensors/SensorBase.cpp的openInput下实现,如果打开的设备文件不是正在打开的设备文件,会执行下面语句的else部分: if (!strcmp(name, inputName)) { strcpy(input_name, filename); break;

基于安卓操作系统的移动智能终端文件系统老化模型和测评方法

电信终端产业协会标准 TAF-WG2-AS0021-V1.0.0:2018 基于安卓操作系统的移动智能终端文件系 统老化模型和测评方法 Module and Test Method of Aging Test on File System Based on Android Mobiles and Smart Terminals 2018-09-04发布2018-09-04实施

目次 前言................................................................................ II 基于安卓操作系统的移动智能终端文件系统老化模型和测评方法 .. (1) 1 范围 (1) 2 规范性引用文件 (1) 3 术语和定义 (1) 4 文件系统老化模型 (1) 4.1 文件系统老化模型概述 (1) 4.2 剩余存储空间分析 (1) 4.3 碎片化方法分析 (2) 4.4 静态资源分析 (2) 4.5 10个月老化模型 (2) 4.6 18个月老化模型 (3) 4.7 24个月老化模型 (3) 5 文件系统老化方法 (3) 5.1 文件系统老化方法概述 (3) 5.2 文件系统碎片化方法 (4) 5.3 用户媒体文件填充方法 (4) 5.4 用户数据库文件填充方法 (4) 6 文件系统老化前后的性能评估 (4) 6.1 测试方法 (4) 6.2 评估方法 (4) 附录 A (规范性附录)标准修订历史 (5) 附录 B (资料性附录)附录 (6) 参考文献 (7)

前言 本标准按照 GB/T 1.1-2009给出的规则编写。 本标准由电信终端产业协会提出并归口。 本标准起草单位:中国信息通信研究院 本标准主要起草人:李隽、崔雪然、苏兆飞、孟凡玲、郭隆庆

基于MT6752的 android 系统启动流程分析报告

基于MT6752的Android系统启动流程分析报告 1、Bootloader引导 (2) 2、Linux内核启动 (23) 3、Android系统启动 (23) 报告人: 日期:2016.09.03

对于Android整个启动过程来说,基本可以划分成三个阶段:Bootloader引导、Linux kernel启动、Android启动。但根据芯片架构和平台的不同,在启动的Bootloader阶段会有所差异。 本文以MTK的MT6752平台为例,分析一下基于该平台的Android系统启动流程。 1、Bootloader引导 1.1、Bootloader基本介绍 BootLoader是在操作系统运行之前运行的一段程序,它可以将系统的软硬件环境带到一个合适状态,为运行操作系统做好准备,目的就是引导linux操作系统及Android框架(framework)。 它的主要功能包括设置处理器和内存的频率、调试信息端口、可引导的存储设备等等。在可执行环境创建好之后,接下来把software装载到内存并执行。除了装载software,一个外部工具也能和bootloader握手(handshake),可指示设备进入不同的操作模式,比如USB下载模式和META模式。就算没有外部工具的握手,通过外部任何组合或是客户自定义按键,bootloader也能够进入这些模式。 由于不同处理器芯片厂商对arm core的封装差异比较大,所以不同的arm处理器,对于上电引导都是由特定处理器芯片厂商自己开发的程序,这个上电引导程序通常比较简单,会初始化硬件,提供下载模式等,然后才会加载通常的bootloader。 下面是几个arm平台的bootloader方案: marvell(pxa935) : bootROM + OBM + BLOB informax(im9815) : bootROM + barbox + U-boot mediatek(mt6517) : bootROM + pre-loader + U-boot broadcom(bcm2157) : bootROM + boot1/boot2 + U-boot 而对MT6752平台,MTK对bootloader引导方案又进行了调整,它将bootloader分为以下两个部分: (1) 第1部分bootloader,是MTK内部(in-house)的pre-loader,这部分依赖平台。 (2) 第2部分bootloader,是LK(little kernel的缩写,作用同常见的u-boot差不多),这部分依赖操作系统,负责引导linux操作系统和Android框架。 1.2、bootloader的工作流程 1.2.1 bootloader正常的启动流程 先来看启动流程图:

linux内核启动 Android系统启动过程详解

linux内核启动+Android系统启动过程详解 第一部分:汇编部分 Linux启动之 linux-rk3288-tchip/kernel/arch/arm/boot/compressed/ head.S分析这段代码是linux boot后执行的第一个程序,完成的主要工作是解压内核,然后跳转到相关执行地址。这部分代码在做驱动开发时不需要改动,但分析其执行流程对是理解android的第一步 开头有一段宏定义这是gnu arm汇编的宏定义。关于GUN 的汇编和其他编译器,在指令语法上有很大差别,具体可查询相关GUN汇编语法了解 另外此段代码必须不能包括重定位部分。因为这时一开始必须要立即运行的。所谓重定位,比如当编译时某个文件用到外部符号是用动态链接库的方式,那么该文件生成的目标文件将包含重定位信息,在加载时需要重定位该符号,否则执行时将因找不到地址而出错 #ifdef DEBUG//开始是调试用,主要是一些打印输出函数,不用关心 #if defined(CONFIG_DEBUG_ICEDCC)

……具体代码略 #endif 宏定义结束之后定义了一个段, .section ".start", #alloc, #execinstr 这个段的段名是 .start,#alloc表示Section contains allocated data, #execinstr表示Section contains executable instructions. 生成最终映像时,这段代码会放在最开头 .align start: .type start,#function /*.type指定start这个符号是函数类型*/ .rept 8 mov r0, r0 //将此命令重复8次,相当于nop,这里是为中断向量保存空间 .endr b 1f .word 0x016f2818 @ Magic numbers to help the loader

Android开机启动流程样本

Android的开机流程 1. 系统引导bootloader 1) 源码: bootable/bootloader/* 2) 说明: 加电后, CPU将先执行bootloader程序, 此处有三种选择 a) 开机按Camera+Power启动到fastboot, 即命令或SD卡烧写模式, 不加载内核及文件系统, 此处能够进行工厂模式的烧写 b) 开机按Home+Power启动到recovery模式, 加载recovery.img, recovery.img包含内核, 基本的文件系统, 用于工程模式的烧写 c) 开机按Power, 正常启动系统, 加载boot.img, boot.img包含内核, 基本文件系统, 用于正常启动手机( 以下只分析正常启动的情况) 2. 内核kernel 1) 源码: kernel/* 2) 说明: kernel由bootloader加载 3. 文件系统及应用init 1) 源码: system/core/init/* 2) 配置文件: system/rootdir/init.rc, 3) 说明: init是一个由内核启动的用户级进程, 它按照init.rc中的设置执行: 启动服务( 这里的服务指linux底层服务, 如adbd提供adb支持, vold提供SD卡挂载等) , 执行命令和按其中的配置语句执行相应功能 4. 重要的后台程序zygote 1) 源码: frameworks/base/cmds/app_main.cpp等 2) 说明: zygote是一个在init.rc中被指定启动的服务, 该服务对应的命令是/system/bin/app_process

Android 文件系统制作教程

android文件系统制作教程 1)认识android文件系统分区 splash1 :开机画面,Nandroid备份为splash1.img recovery :设备序列号为mtd1,该分区是恢复模式(即开机按Home+End进入的界面),Nandroid备份为recovery.img boot :设备序列号为mtd2,底层操作系统内核启动分区,挂载为/目录,Nandroid备份为boot.img system :设备序列号为mtd3,G1的Android核心平台,挂载为/system目录,通常为只读,Nandroid备份为system.img cache :设备序列号为mtd4,G1的缓存临时文件夹,挂载为 /cache目录,事实上除了T-mobile的OTA更新外,别无用处,Nandroid备份为cache.img userdata:设备序列号为mtd5,G1中用户安装的软件以及各种数据,挂载为/data目录,Nandroid备份为data.img 2)常用的fastboot命令 重启G1: $ fastboot reboot 刷所有分区并重启手机 $ fastboot flashall 刷指定分区: $ fastboot flash {partition} {file.img} 如:fastboot flash system /备份/system.img 擦除分区: $ fastboot erase {partition} 如:fastboot erase system 使用update.zip整体刷新 $ fastboot update {update.zip} 刷自定义开机画面: $ fasboot flash splash1 mysplash.rgb565 3)利用Makefile制作update.zip 从update.zip这个刷机包反推的介绍整个android文件系统的制作过程 并编写了一个Makefile文件,利用 Makefile的”依赖检查”机制管理各种文件的生成步骤和依赖关系;

Android系统启动过程详解

Android系统启动过程详解 Android系统启动过程 首先Android框架架构图:(来自网上,我觉得这张图看起来很清晰) Linux内核启动之后就到Android Init进程,进而启动Android相关的服务和应用。 启动的过程如下图所示:(图片来自网上,后面有地址)

下面将从Android4.0源码中,和网络达人对此的总结中,对此过程加以学习了解和总结, 以下学习过程中代码片段中均有省略不完整,请参照源码。

一Init进程的启动 init进程,它是一个由内核启动的用户级进程。内核自行启动(已经被载入内存,开始运行, 并已初始化所有的设备驱动程序和数据结构等)之后,就通过启动一个用户级程序init的方式,完成引导进程。init始终是第一个进程。 启动过程就是代码init.c中main函数执行过程:system\core\init\init. c 在函数中执行了:文件夹建立,挂载,rc文件解析,属性设置,启动服务,执行动作,socket监听…… 下面看两个重要的过程:rc文件解析和服务启动。 1 rc文件解析 .rc文件是Android使用的初始化脚本文件(System/Core/Init/readm e.txt中有描述: four broad classes of statements which are Actions, Commands, Services, and Options.) 其中Command 就是系统支持的一系列命令,如:export,hostname,mkdir,mount,等等,其中一部分是linux 命令, 还有一些是android 添加的,如:class_start :启动服务,class_stop :关闭服务,等等。 其中Options是针对Service 的选项的。 系统初始化要触发的动作和要启动的服务及其各自属性都在rc脚本文件中定义。具体看一下启动脚本:\system\core\rootdir\init.rc 在解析rc脚本文件时,将相应的类型放入各自的List中: \system\core\init\Init_parser.c :init_parse_config_file( )存入到 action_queue、action_list、service_list中,解析过程可以看一下parse_config函数,类似状态机形式挺有意思。 这其中包含了服务:adbd、servicemanager、vold、ril-daemon、deb uggerd、surfaceflinger、zygote、media…… 2 服务启动 文件解析完成之后将service放入到service_list中。 文件解析完成之后将service放入到service_list中。 \system\core\init\builtins.c

Android SystemBar启动流程分析

Android SystemBar启动流程分析 SystemBars的服务被start时,最终会调用该类的onNoService()方法。 @Override public void start() { if (DEBUG) Log.d(TAG, "start"); ServiceMonitor mServiceMonitor = new ServiceMonitor(TAG, DEBUG, mContext, Settings.Secure.BAR_SERVICE_COMPONENT, this); mServiceMonitor.start(); // will call onNoService if no remote service is found } @Override public void onNoService() { if (DEBUG) Log.d(TAG, "onNoService"); createStatusBarFromConfig(); // fallback to using an in-process implementation } private void createStatusBarFromConfig() { … mStatusBar = (BaseStatusBar) cls.newInstance(); … mStatusBar.start(); } BaseStatusBar是一个抽象类,故调用其子类的PhoneStatusBar的start 函数。 @Override public void start() { … super.start(); … } 子类的start又调用了父类的start public void start() { … createAndAddWindows(); … }

AndroidL系统启动及加载流程分析

Android L系统启动及加载流程分析 1、概述 Android L的启动可以分为几个步骤:Linux内核启动、init进程启动、native系统服务及java系统服务启动、Home启动,主要过程如下图: 图1 整个启动流程跟4.4及之前的版本相差不多,只是有个别不同之处,本文我们主要分析Linux内核启动之后的过程。

2、启动过程分析 2.1 init进程启动 当系统内核加载完成之后,会启动init守护进程,它是内核启动的第一个用户级进程,是Android的一个进程,进程号为1,init进程启动后执行入口函数main(),主要操作为: 图2 AndroidL上将selinux的安全等级提高了,设为了enforcing模式,4.4上是permissive模式。 解析rc脚本文件,即init.rc脚本,该文件是Android初始化脚本,定义了一系列的动作和执行这些动作的时间阶段e aryl-init、init、early-boot、boot、post-fs等阶段。init进程main 函数中会根据这些阶段进行解析执行。AndroidL上为了流程更清晰,增加了charger(充电开机)、ffbm(工厂模式)、以及late-init阶段,实际上这些阶段是对其他阶段的组合执行,比如late-init:

2.2 ServiceManager的启动 servicemanager的启动就是init进程通过init.rc脚本启动的: 源码在frameworks/native/cmds/servicemanager/service_manager.c中,servicemanager是服务管理器,它本身也是一个服务(handle=0),通过binder调用,为native和Java系统服务提供注册和查询服务的,即某个服务启动后,需要将自己注册到servicemanager中,供其他服务或者应用查询使用。AndroidL上servicemanger中在处理注册和查询动作之前添加了selinux安全检测相关的处理。 2.3 SurfaceFinger、MediaServer进程启动 Android4.4以前,surfacefinger的启动根据属性system_init.startsurfaceflinger,决定是通过init.rc启动还是systemserver进程启动,之后的版本包括AndoridL都是通过init.rc启动的: 启动后会向servicemanager进程注册服务中,该服务启动时主要功能是初始化整个显

Android本质上就是一个基于Linux内核的操作系统

Android本质上就是一个基于Linux内核的操作系统。与Ubuntu Linux、Fedora Linux 类似。只是Android在应用层专门为移动设备添加了一些特有的支持。既然Android是Linux内核的系统,那么基本的启动过程也应符合Linux的规则。如果研究过其他Linux 系统应该了解,一个完整的Linux系统首先会将一个Linux内核装载到内存,也就是编译Linux内核源代码生成的bzImage文件,对于为Android优化的Linux内核源代码会生成zImage文件。该文件就是Linux内核的二进制版本。由于zImage在内核空间运行,而我们平常使用的软件都是在应用空间运行(关于内核空间和应用空间的详细描述,可以参考《Android深度探索(卷1):HAL与驱动开发》一书的内容,在后续的各卷中将会对Android的整体体系进行全方位的剖析)。内核空间和应用空间是不能直接通过内存地址级别访问的,所以就需要建立某种通讯机制。 目前Linux有很多通讯机制可以在用户空间和内核空间之间交互,例如设备驱动文件(位于/dev目录中)、内存文件(/proc、/sys目录等)。了解Linux的同学都应该知道Linux的重要特征之一就是一切都是以文件的形式存在的,例如,一个设备通常与一个或多个设备文件对应。这些与内核空间交互的文件都在用户空间,所以在Linux内核装载完,需要首先建立这些文件所在的目录。而完成这些工作的程序就是本文要介绍的init。Init是一个命令行程序。其主要工作之一就是建立这些与内核空间交互的文件所在的目录。当Linux内核加载完后,要做的第一件事就是调用init程序,也就是说,init是用户空间执行的第一个程序。 在分析init的核心代码之前,还需要初步了解init除了建立一些目录外,还做了如下的工作 1. 初始化属性 2. 处理配置文件的命令(主要是init.rc文件),包括处理各种Action。 3. 性能分析(使用bootchart工具)。 4. 无限循环执行command(启动其他的进程)。 尽管init完成的工作不算很多,不过代码还是非常复杂的。Init程序并不是由一个源代码文件组成的,而是由一组源代码文件的目标文件链接而成的。这些文件位于如下的目录。 /system/core/init 其中init.c是init的主文件,现在打开该文件,看看其中的内容。由于init是命令行程序,所以分析init.c首先应从main函数开始,现在好到main函数,代码如下: int main(int argc, char **argv) { int fd_count = 0; struct pollfd ufds[4]; char *tmpdev; char* debuggable; char tmp[32]; int property_set_fd_init = 0; int signal_fd_init = 0;

android开机启动流程简单分析

android开机启动流程简单分析 android启动 当引导程序启动Linux内核后,会加载各种驱动和数据结构,当有了驱动以后,开始启动Android系统同时会加载用户级别的第一个进程init(system\core\init\init.cpp)代码如下: int main(int argc, char** argv) { ..... //创建文件夹,挂载 // Get the basic filesystem setup we need put together in the initramdisk // on / and then we'll let the rc file figure out the rest. if (is_first_stage) { mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755"); mkdir("/dev/pts", 0755); mkdir("/dev/socket", 0755); mount("devpts", "/dev/pts", "devpts", 0, NULL); #define MAKE_STR(x) __STRING(x) mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC)); mount("sysfs", "/sys", "sysfs", 0, NULL); } ..... //打印日志,设置log的级别 klog_init(); klog_set_level(KLOG_NOTICE_LEVEL); ..... Parser& parser = Parser::GetInstance(); parser.AddSectionParser("service",std::make_unique()); parser.AddSectionParser("on", std::make_unique()); parser.AddSectionParser("import", std::make_unique()); // 加载init.rc配置文件 parser.ParseConfig("/init.rc"); } 加载init.rc文件,会启动一个Zygote进程,此进程是Android系统的一个母进程,用来启动Android的其他服务进程,代码: 从Android L开始,在/system/core/rootdir 目录中有4 个zygote 相关的启动脚本如下图:

Android SDCard操作(文件读写,容量计算)(An-Beer 工作室)

Android SDCard操作(文件读写,容量计算) android.os.Environment 提供访问环境变量 https://www.doczj.com/doc/f85968282.html,ng.Object android.os.Environment Environment 静态方法: 方法: getDataDirectory () 返回: File 解释: 返回Data的目录 方法: getDownloadCacheDirectory () 返回: File 解释: 返回下载缓冲区目录 方法: getExternalStorageDirectory () 返回: File 解释: 返回扩展存储区目录(SDCard) 方法: getExternalStoragePublicDirectory (String type) 返回: File 解释: 返回一个高端的公用的外部存储器目录来摆放某些类型的文件(来自网上) 方法: getRootDirectory () 返回: File 解释: 返回Android的根目录 方法: getExternalStorageState () 返回: String

解释: 返回外部存储设备的当前状态 getExternalStorageState () 返回的状态String类型常量:常量: MEDIA_BAD_REMOVAL 值 : "bad_removal" 解释: 在没有正确卸载SDCard之前移除了 常量:MEDIA_CHECKING 值 : "checking" 解释: 正在磁盘检查 常量: MEDIA_MOUNTED 值 : "mounted" 解释: 已经挂载并且拥有可读可写权限 常量: MEDIA_MOUNTED_READ_ONLY 值 : "mounted_ro" 解释: 已经挂载,但只拥有可读权限 常量:MEDIA_NOFS 值 : "nofs" 解释: 对象空白,或者文件系统不支持 常量: MEDIA_REMOVED 值 : "removed" 解释: 已经移除扩展设备 常量: MEDIA_SHARED 值 : "shared" 解释: 如果SDCard未挂载,并通过USB大容量存储共享 常量: MEDIA_UNMOUNTABLE

Android ninja 编译启动过程分析

Android ninja编译启动过程分析 ---make是如何转换到到ninja编译的 1.首先你的得对make的工作机制有个大概的了解: 运行的命令在要编译的目录下运行make,或者make target_name a.分析处理保存阶段(没有实际编译动作):它首先对当前目录下的Makefile文件的做一次扫描,语法分析,还有处理,主要是变量的保存,目标依赖列表生成,目标下的action列表的生成,然后记住 b.然后按记住的目标执行action列表动作(有实际编译动作). 编译启动的入口方式还是运行make: 2开始make-jxxx方式进入.....(xxx是本机cpu的数量) make开始做进行第一次扫描.... 目前USE_NINJA还是没有定义,估计以后很久很久才能启用的了! BUILDING_WITH_NINJA开始也是没定义的 看make扫描入口文件: Makefile: include build/core/main.mk 在build/core/main.mk: 在ninia之前都有include help.mk和config.mk 97include$(BUILD_SYSTEM)/help.mk 98 99#Set up various standard variables based on configuration 100#and host information. 101include$(BUILD_SYSTEM)/config.mk 说明make help//显示make帮助make config//当前显示配置 103relaunch_with_ninja:= 104ifneq($(USE_NINJA),false) 105ifndef BUILDING_WITH_NINJA<==第二次扫描不会到这里了 106relaunch_with_ninja:=true 107endif 108endif 116ifeq($(relaunch_with_ninja),true)<===第一次扫描入这里了 117#Mark this is a ninja build. 118$(shell mkdir-p$(OUT_DIR)&&touch$(OUT_DIR)/ninja_build) 119include build/core/ninja.mk//---进入ninja.mk 第一次扫描到此为止就结束掉了,因为在当前ifeq else endif后面没有代码了 120else#///!relaunch_with_ninja<===第二次扫描入这里了

android系统目录各文件简介

android系统目录各文件简介 2012-05-04 22:24:43| 分类:工作资料|举报|字号订阅 一个完整的ROM根目录会有以下几个文件夹及文件: data META-IN system boot.img 系统目录说明 1. 应用程序安装目录 1) 系统应用程序所在目录 /system/app/*.apk 2)用户安装应用程序所在目录 /data/app/*.apk 3) 注意: a)在模拟器中,每重启一次,/system/app/下的应用都会被还原,有时/data/app 下也会被清除 b)若在/system/app和/data/app下有重名的应用,不一定会启动哪一个,尤其是在adb install杀死正在运行的程序时,有时旧的就会被启动 2.用户数据所在目录 /data/data/应用包名/shared_prefs 配置文件 /data/data/应用包名/databases/* 库文件所在目录 3. SD卡对应目录 /sdcard/ 而我们需要处理的只是两个文件夹里面的内容: data/app –该文本夹里的文件可以全删,也可以自由添加自已所需安装的应用软件,刷机安装后可以自由删除。 system/app –在这个文件夹下的程序为系统默认的组件,可以看到都是以APK 格式结尾的文件,但有些自制的ROM里面还有和APK文件名对应的odex文件。我们主要是针对该文件夹里的文件进行精简,如果有odex文件的,删除APK文

件名时同时也删除与其对应的odex文件。 虽然一般定制时只是对以上两个文件夹里的文件做相应的增减,但我们还是一起来了解system相应目录相应文件的用途吧。(rom版本不同里面的APK也会不一样) \\system\\app \\system\\app\\AlarmClock.apk 闹钟 \\system\\app\\Browser.apk 浏览器 \\system\\app\\Bugreport.apk Bug报告 \\system\\app\\Calculator.apk 计算器 \\system\\app\\Calendar.apk 日历 \\system\\app\\CalendarProvider.apk 日历提供 \\system\\app\\Camera.apk 照相机 \\system\\app\\com.amazon.mp3.apk 亚马逊音乐 \\system\\app\\Contacts.apk 联系人 \\system\\app\\DownloadProvider.apk 下载提供 \\system\\app\\DrmProvider.apk DRM数字版权提供 \\system\\app\\Email.apk 电子邮件客户端 \\system\\app\\FieldTest.apk 测试程序 \\system\\app\\GDataFeedsProvider.apk GoogleData提供 \\system\\app\\Gmail.apk Gmail电子邮件 \\system\\app\\GmailProvider.apk Gmail提供 \\system\\app\\GoogleApps.apk 谷歌程序包 \\system\\app\\GoogleSearch.apk 搜索工具 \\system\\app\\gtalkservice.apk GTalk服务 \\system\\app\\HTMLViewer.apk HTML查看器 \\system\\app\\HtcTwitter.apk 集成Twitter客户端PEEP \\system\\app\\IM.apk 即使通讯组件包含MSN、yahoo通 \\system\\app\\ImCredentialProvider.apk \\system\\app\\ImProvider.apk \\system\\app\\Launcher.apk 启动加载器 \\system\\app\\HtcNaviPanel.apk 导航软件 \\system\\app\\Maps.apk 电子地图 \\system\\app\\MediaProvider.apk 多媒体播放提供

相关主题
文本预览
相关文档 最新文档