Support to build image of root file system with /system and ramdisk combined.

Added support to build system.img that combines contents of /system and
the ramdisk, and can be mounted at the root of the file system.
To enable this feature, define BoardConfig.mk variable:
BOARD_BUILD_SYSTEM_ROOT_IMAGE := true

Ideally we would just change TARGET_OUT (the path of the staging system
directory) to under TARGET_ROOT_OUT. But at this point many places in
the build system assume TARGET_OUT is independent of TARGET_ROOT_OUT and
we can't make it easily configurable.
Instead this implementation takes the least intrusive approach:
We don't change TARGET_OUT or TARGET_ROOT_OUT. We just assemble a
temporary staging directory that contains contents of both TARGET_OUT
and TARGET_ROOT_OUT, in build_image.BuildImage() of
tools/releasetools/build_image.py.
When build_image.py is directly called from the makefile, we pass in the
parameters from the global dictionary; when build_image.BuildImage() is
called from add_img_to_target_files.py, we need to override values to
point to files extracted from the target_files zip file.
We need to combine the fs_config files of both /system and ramdisk,
when fs_config is enabled.

Also this change refactored build_image.BuildImage() by moving the extra
parameters to the image property dictionary.

(cherry-picked from commit 0eabd4f2c5)

Bug:19868522
Change-Id: Iafc467a0e3427b0d6ad3b575abcc98ddcc9ea0f1
This commit is contained in:
Ying Wang 2015-03-24 19:07:40 -07:00
parent e7173cee10
commit a2292c94d1
3 changed files with 64 additions and 24 deletions

View File

@ -717,6 +717,9 @@ $(if $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VERITY),$(hide) echo "verit
$(if $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VERITY),$(hide) echo "verity_signer_cmd=$(VERITY_SIGNER)" >> $(1)) $(if $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VERITY),$(hide) echo "verity_signer_cmd=$(VERITY_SIGNER)" >> $(1))
$(if $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SYSTEM_VERITY_PARTITION),$(hide) echo "system_verity_block_device=$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SYSTEM_VERITY_PARTITION)" >> $(1)) $(if $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SYSTEM_VERITY_PARTITION),$(hide) echo "system_verity_block_device=$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SYSTEM_VERITY_PARTITION)" >> $(1))
$(if $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_VENDOR_VERITY_PARTITION),$(hide) echo "vendor_verity_block_device=$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_VENDOR_VERITY_PARTITION)" >> $(1)) $(if $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_VENDOR_VERITY_PARTITION),$(hide) echo "vendor_verity_block_device=$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_VENDOR_VERITY_PARTITION)" >> $(1))
$(if $(filter true,$(BOARD_BUILD_SYSTEM_ROOT_IMAGE)),\
$(hide) echo "system_root_image=true" >> $(1);\
echo "ramdisk_dir=$(TARGET_ROOT_OUT)" >> $(1))
$(if $(2),$(hide) $(foreach kv,$(2),echo "$(kv)" >> $(1);)) $(if $(2),$(hide) $(foreach kv,$(2),echo "$(kv)" >> $(1);))
endef endef
@ -1417,7 +1420,7 @@ endif
$(hide) mkdir -p $(zip_root)/META $(hide) mkdir -p $(zip_root)/META
$(hide) $(ACP) $(APKCERTS_FILE) $(zip_root)/META/apkcerts.txt $(hide) $(ACP) $(APKCERTS_FILE) $(zip_root)/META/apkcerts.txt
$(hide) if test -e $(tool_extensions)/releasetools.py; then $(ACP) $(tool_extensions)/releasetools.py $(zip_root)/META/; fi $(hide) if test -e $(tool_extensions)/releasetools.py; then $(ACP) $(tool_extensions)/releasetools.py $(zip_root)/META/; fi
$(hide) echo "$(PRODUCT_OTA_PUBLIC_KEYS)" > $(zip_root)/META/otakeys.txt $(hide) echo "$(PRODUCT_OTA_PUBLIC_KEYS)" > $(zip_root)/META/otakeys.txt
$(hide) echo "recovery_api_version=$(PRIVATE_RECOVERY_API_VERSION)" > $(zip_root)/META/misc_info.txt $(hide) echo "recovery_api_version=$(PRIVATE_RECOVERY_API_VERSION)" > $(zip_root)/META/misc_info.txt
$(hide) echo "fstab_version=$(PRIVATE_RECOVERY_FSTAB_VERSION)" >> $(zip_root)/META/misc_info.txt $(hide) echo "fstab_version=$(PRIVATE_RECOVERY_FSTAB_VERSION)" >> $(zip_root)/META/misc_info.txt
ifdef BOARD_FLASH_BLOCK_SIZE ifdef BOARD_FLASH_BLOCK_SIZE

View File

@ -135,11 +135,20 @@ def CreateImage(input_dir, info_dict, what, block_list=None):
fc_config = os.path.join(input_dir, "BOOT/RAMDISK/file_contexts") fc_config = os.path.join(input_dir, "BOOT/RAMDISK/file_contexts")
if not os.path.exists(fc_config): fc_config = None if not os.path.exists(fc_config): fc_config = None
# Override values loaded from info_dict.
if fs_config:
image_props["fs_config"] = fs_config
if fc_config:
image_props["selinux_fc"] = fc_config
if block_list:
image_props["block_list"] = block_list
if image_props.get("system_root_image") == "true":
image_props["ramdisk_dir"] = os.path.join(input_dir, "BOOT/RAMDISK")
image_props["ramdisk_fs_config"] = os.path.join(
input_dir, "META/boot_filesystem_config.txt")
succ = build_image.BuildImage(os.path.join(input_dir, what), succ = build_image.BuildImage(os.path.join(input_dir, what),
image_props, img, image_props, img)
fs_config=fs_config,
fc_config=fc_config,
block_list=block_list)
assert succ, "build " + what + ".img image failed" assert succ, "build " + what + ".img image failed"
return img return img

View File

@ -198,25 +198,39 @@ def MakeVerityEnabledImage(out_file, prop_dict):
shutil.rmtree(tempdir_name, ignore_errors=True) shutil.rmtree(tempdir_name, ignore_errors=True)
return True return True
def BuildImage(in_dir, prop_dict, out_file, def BuildImage(in_dir, prop_dict, out_file):
fs_config=None,
fc_config=None,
block_list=None):
"""Build an image to out_file from in_dir with property prop_dict. """Build an image to out_file from in_dir with property prop_dict.
Args: Args:
in_dir: path of input directory. in_dir: path of input directory.
prop_dict: property dictionary. prop_dict: property dictionary.
out_file: path of the output image file. out_file: path of the output image file.
fs_config: path to the fs_config file (typically
META/filesystem_config.txt). If None then the configuration in
the local client will be used.
fc_config: path to the SELinux file_contexts file. If None then
the value from prop_dict['selinux_fc'] will be used.
Returns: Returns:
True iff the image is built successfully. True iff the image is built successfully.
""" """
# system_root_image=true: build a system.img that combines the contents of /system
# and the ramdisk, and can be mounted at the root of the file system.
origin_in = in_dir
fs_config = prop_dict.get("fs_config")
if (prop_dict.get("system_root_image") == "true"
and prop_dict["mount_point"] == "system"):
in_dir = tempfile.mkdtemp()
# Change the mount point to "/"
prop_dict["mount_point"] = "/"
if fs_config:
# We need to merge the fs_config files of system and ramdisk.
fd, merged_fs_config = tempfile.mkstemp(prefix="root_fs_config",
suffix=".txt")
os.close(fd)
with open(merged_fs_config, "w") as fw:
if "ramdisk_fs_config" in prop_dict:
with open(prop_dict["ramdisk_fs_config"]) as fr:
fw.writelines(fr.readlines())
with open(fs_config) as fr:
fw.writelines(fr.readlines())
fs_config = merged_fs_config
build_command = [] build_command = []
fs_type = prop_dict.get("fs_type", "") fs_type = prop_dict.get("fs_type", "")
run_fsck = False run_fsck = False
@ -244,22 +258,18 @@ def BuildImage(in_dir, prop_dict, out_file,
build_command.extend(["-j", prop_dict["journal_size"]]) build_command.extend(["-j", prop_dict["journal_size"]])
if "timestamp" in prop_dict: if "timestamp" in prop_dict:
build_command.extend(["-T", str(prop_dict["timestamp"])]) build_command.extend(["-T", str(prop_dict["timestamp"])])
if fs_config is not None: if fs_config:
build_command.extend(["-C", fs_config]) build_command.extend(["-C", fs_config])
if block_list is not None: if "block_list" in prop_dict:
build_command.extend(["-B", block_list]) build_command.extend(["-B", prop_dict["block_list"]])
build_command.extend(["-L", prop_dict["mount_point"]]) build_command.extend(["-L", prop_dict["mount_point"]])
if fc_config is not None: if "selinux_fc" in prop_dict:
build_command.append(fc_config)
elif "selinux_fc" in prop_dict:
build_command.append(prop_dict["selinux_fc"]) build_command.append(prop_dict["selinux_fc"])
elif fs_type.startswith("squash"): elif fs_type.startswith("squash"):
build_command = ["mksquashfsimage.sh"] build_command = ["mksquashfsimage.sh"]
build_command.extend([in_dir, out_file]) build_command.extend([in_dir, out_file])
build_command.extend(["-m", prop_dict["mount_point"]]) build_command.extend(["-m", prop_dict["mount_point"]])
if fc_config is not None: if "selinux_fc" in prop_dict:
build_command.extend(["-c", fc_config])
elif "selinux_fc" in prop_dict:
build_command.extend(["-c", prop_dict["selinux_fc"]]) build_command.extend(["-c", prop_dict["selinux_fc"]])
elif fs_type.startswith("f2fs"): elif fs_type.startswith("f2fs"):
build_command = ["mkf2fsuserimg.sh"] build_command = ["mkf2fsuserimg.sh"]
@ -274,7 +284,23 @@ def BuildImage(in_dir, prop_dict, out_file,
build_command.append(prop_dict["selinux_fc"]) build_command.append(prop_dict["selinux_fc"])
build_command.append(prop_dict["mount_point"]) build_command.append(prop_dict["mount_point"])
exit_code = RunCommand(build_command) if in_dir != origin_in:
# Construct a staging directory of the root file system.
ramdisk_dir = prop_dict.get("ramdisk_dir")
if ramdisk_dir:
shutil.rmtree(in_dir)
shutil.copytree(ramdisk_dir, in_dir, symlinks=True)
staging_system = os.path.join(in_dir, "system")
shutil.rmtree(staging_system, ignore_errors=True)
shutil.copytree(origin_in, staging_system, symlinks=True)
try:
exit_code = RunCommand(build_command)
finally:
if in_dir != origin_in:
# Clean up temporary directories and files.
shutil.rmtree(in_dir, ignore_errors=True)
if fs_config:
os.remove(fs_config)
if exit_code != 0: if exit_code != 0:
return False return False
@ -334,6 +360,8 @@ def ImagePropFromGlobalDict(glob_dict, mount_point):
copy_prop("system_size", "partition_size") copy_prop("system_size", "partition_size")
copy_prop("system_journal_size", "journal_size") copy_prop("system_journal_size", "journal_size")
copy_prop("system_verity_block_device", "verity_block_device") copy_prop("system_verity_block_device", "verity_block_device")
copy_prop("system_root_image","system_root_image")
copy_prop("ramdisk_dir","ramdisk_dir")
elif mount_point == "data": elif mount_point == "data":
# Copy the generic fs type first, override with specific one if available. # Copy the generic fs type first, override with specific one if available.
copy_prop("fs_type", "fs_type") copy_prop("fs_type", "fs_type")