2011-10-29 02:02:30 +02:00
|
|
|
#!/usr/bin/env python
|
|
|
|
#
|
|
|
|
# Copyright (C) 2011 The Android Open Source Project
|
|
|
|
#
|
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
# you may not use this file except in compliance with the License.
|
|
|
|
# You may obtain a copy of the License at
|
|
|
|
#
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
#
|
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
# See the License for the specific language governing permissions and
|
|
|
|
# limitations under the License.
|
|
|
|
|
|
|
|
"""
|
2017-12-07 19:33:00 +01:00
|
|
|
Builds output_image from the given input_directory, properties_file,
|
|
|
|
and writes the image to target_output_directory.
|
2011-10-29 02:02:30 +02:00
|
|
|
|
2019-05-07 22:12:21 +02:00
|
|
|
Usage: build_image input_directory properties_file output_image \\
|
2019-04-09 19:03:57 +02:00
|
|
|
target_output_directory
|
2011-10-29 02:02:30 +02:00
|
|
|
"""
|
2017-12-07 19:33:00 +01:00
|
|
|
|
|
|
|
from __future__ import print_function
|
|
|
|
|
2018-10-12 19:30:39 +02:00
|
|
|
import logging
|
2011-10-29 02:02:30 +02:00
|
|
|
import os
|
2012-11-27 03:10:23 +01:00
|
|
|
import os.path
|
2015-06-23 20:16:05 +02:00
|
|
|
import re
|
2017-12-07 19:33:00 +01:00
|
|
|
import shutil
|
2011-10-29 02:02:30 +02:00
|
|
|
import sys
|
2017-12-07 19:33:00 +01:00
|
|
|
|
2015-06-10 00:48:14 +02:00
|
|
|
import common
|
2018-10-11 23:08:45 +02:00
|
|
|
import verity_utils
|
2011-10-29 02:02:30 +02:00
|
|
|
|
2018-10-12 19:30:39 +02:00
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
2015-06-10 00:48:14 +02:00
|
|
|
OPTIONS = common.OPTIONS
|
2018-10-11 23:08:45 +02:00
|
|
|
BLOCK_SIZE = common.BLOCK_SIZE
|
2018-06-19 01:32:35 +02:00
|
|
|
BYTES_IN_MB = 1024 * 1024
|
2014-05-17 04:14:30 +02:00
|
|
|
|
2017-12-07 19:33:00 +01:00
|
|
|
|
2018-09-28 01:58:00 +02:00
|
|
|
class BuildImageError(Exception):
|
|
|
|
"""An Exception raised during image building."""
|
|
|
|
|
|
|
|
def __init__(self, message):
|
|
|
|
Exception.__init__(self, message)
|
|
|
|
|
|
|
|
|
2018-06-19 01:32:35 +02:00
|
|
|
def GetDiskUsage(path):
|
2018-09-28 01:58:00 +02:00
|
|
|
"""Returns the number of bytes that "path" occupies on host.
|
2018-06-19 01:32:35 +02:00
|
|
|
|
|
|
|
Args:
|
2018-10-19 22:44:36 +02:00
|
|
|
path: The directory or file to calculate size on.
|
2018-09-28 01:58:00 +02:00
|
|
|
|
2018-06-19 01:32:35 +02:00
|
|
|
Returns:
|
2018-10-19 22:44:36 +02:00
|
|
|
The number of bytes based on a 1K block_size.
|
2018-06-19 01:32:35 +02:00
|
|
|
"""
|
2018-10-19 22:44:36 +02:00
|
|
|
cmd = ["du", "-k", "-s", path]
|
2018-10-25 21:23:12 +02:00
|
|
|
output = common.RunAndCheckOutput(cmd, verbose=False)
|
2018-10-19 22:44:36 +02:00
|
|
|
return int(output.split()[0]) * 1024
|
|
|
|
|
|
|
|
|
|
|
|
def GetInodeUsage(path):
|
|
|
|
"""Returns the number of inodes that "path" occupies on host.
|
|
|
|
|
|
|
|
Args:
|
|
|
|
path: The directory or file to calculate inode number on.
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
The number of inodes used.
|
|
|
|
"""
|
|
|
|
cmd = ["find", path, "-print"]
|
2018-10-25 21:23:12 +02:00
|
|
|
output = common.RunAndCheckOutput(cmd, verbose=False)
|
2019-01-08 17:17:46 +01:00
|
|
|
# increase by > 4% as number of files and directories is not whole picture.
|
2019-01-16 17:03:10 +01:00
|
|
|
inodes = output.count('\n')
|
|
|
|
spare_inodes = inodes * 4 // 100
|
2019-01-16 17:03:10 +01:00
|
|
|
min_spare_inodes = 12
|
2019-01-16 17:03:10 +01:00
|
|
|
if spare_inodes < min_spare_inodes:
|
|
|
|
spare_inodes = min_spare_inodes
|
|
|
|
return inodes + spare_inodes
|
2018-10-19 22:44:36 +02:00
|
|
|
|
|
|
|
|
2019-01-10 23:30:51 +01:00
|
|
|
def GetFilesystemCharacteristics(image_path, sparse_image=True):
|
|
|
|
"""Returns various filesystem characteristics of "image_path".
|
2018-10-19 22:44:36 +02:00
|
|
|
|
|
|
|
Args:
|
2019-01-10 23:30:51 +01:00
|
|
|
image_path: The file to analyze.
|
|
|
|
sparse_image: Image is sparse
|
2018-10-19 22:44:36 +02:00
|
|
|
|
|
|
|
Returns:
|
|
|
|
The characteristics dictionary.
|
|
|
|
"""
|
2019-01-10 23:30:51 +01:00
|
|
|
unsparse_image_path = image_path
|
|
|
|
if sparse_image:
|
|
|
|
unsparse_image_path = UnsparseImage(image_path, replace=False)
|
2018-10-19 22:44:36 +02:00
|
|
|
|
|
|
|
cmd = ["tune2fs", "-l", unsparse_image_path]
|
|
|
|
try:
|
|
|
|
output = common.RunAndCheckOutput(cmd, verbose=False)
|
2018-10-25 21:23:12 +02:00
|
|
|
finally:
|
2019-01-10 23:30:51 +01:00
|
|
|
if sparse_image:
|
|
|
|
os.remove(unsparse_image_path)
|
2018-10-25 21:23:12 +02:00
|
|
|
fs_dict = {}
|
2018-10-19 22:44:36 +02:00
|
|
|
for line in output.splitlines():
|
|
|
|
fields = line.split(":")
|
|
|
|
if len(fields) == 2:
|
|
|
|
fs_dict[fields[0].strip()] = fields[1].strip()
|
|
|
|
return fs_dict
|
2018-06-19 01:32:35 +02:00
|
|
|
|
|
|
|
|
2013-12-06 02:09:18 +01:00
|
|
|
def UnsparseImage(sparse_image_path, replace=True):
|
2013-06-17 02:26:08 +02:00
|
|
|
img_dir = os.path.dirname(sparse_image_path)
|
|
|
|
unsparse_image_path = "unsparse_" + os.path.basename(sparse_image_path)
|
|
|
|
unsparse_image_path = os.path.join(img_dir, unsparse_image_path)
|
|
|
|
if os.path.exists(unsparse_image_path):
|
2013-12-06 02:09:18 +01:00
|
|
|
if replace:
|
|
|
|
os.unlink(unsparse_image_path)
|
|
|
|
else:
|
2018-09-28 01:58:00 +02:00
|
|
|
return unsparse_image_path
|
2013-06-17 02:26:08 +02:00
|
|
|
inflate_command = ["simg2img", sparse_image_path, unsparse_image_path]
|
2018-10-05 00:46:16 +02:00
|
|
|
try:
|
|
|
|
common.RunAndCheckOutput(inflate_command)
|
|
|
|
except:
|
2013-06-17 02:26:08 +02:00
|
|
|
os.remove(unsparse_image_path)
|
2018-10-05 00:46:16 +02:00
|
|
|
raise
|
2018-09-28 01:58:00 +02:00
|
|
|
return unsparse_image_path
|
2013-06-17 02:26:08 +02:00
|
|
|
|
2017-12-07 19:33:00 +01:00
|
|
|
|
2016-03-03 06:07:23 +01:00
|
|
|
def ConvertBlockMapToBaseFs(block_map_file):
|
2017-12-25 19:43:47 +01:00
|
|
|
base_fs_file = common.MakeTempFile(prefix="script_gen_", suffix=".base_fs")
|
2016-03-03 06:07:23 +01:00
|
|
|
convert_command = ["blk_alloc_to_base_fs", block_map_file, base_fs_file]
|
2018-10-05 00:46:16 +02:00
|
|
|
common.RunAndCheckOutput(convert_command)
|
2018-09-28 01:58:00 +02:00
|
|
|
return base_fs_file
|
2016-03-03 06:07:23 +01:00
|
|
|
|
2017-12-08 08:01:25 +01:00
|
|
|
|
2018-07-20 23:44:46 +02:00
|
|
|
def SetUpInDirAndFsConfig(origin_in, prop_dict):
|
|
|
|
"""Returns the in_dir and fs_config that should be used for image building.
|
|
|
|
|
2018-08-09 23:26:00 +02:00
|
|
|
When building system.img for all targets, it creates and returns a staged dir
|
|
|
|
that combines the contents of /system (i.e. in the given in_dir) and root.
|
2018-07-20 23:44:46 +02:00
|
|
|
|
|
|
|
Args:
|
|
|
|
origin_in: Path to the input directory.
|
|
|
|
prop_dict: A property dict that contains info like partition size. Values
|
|
|
|
may be updated.
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
A tuple of in_dir and fs_config that should be used to build the image.
|
|
|
|
"""
|
|
|
|
fs_config = prop_dict.get("fs_config")
|
2018-08-09 23:26:00 +02:00
|
|
|
|
|
|
|
if prop_dict["mount_point"] == "system_other":
|
|
|
|
prop_dict["mount_point"] = "system"
|
|
|
|
return origin_in, fs_config
|
|
|
|
|
|
|
|
if prop_dict["mount_point"] != "system":
|
2018-07-20 23:44:46 +02:00
|
|
|
return origin_in, fs_config
|
|
|
|
|
2018-10-19 22:44:36 +02:00
|
|
|
if "first_pass" in prop_dict:
|
|
|
|
prop_dict["mount_point"] = "/"
|
|
|
|
return prop_dict["first_pass"]
|
|
|
|
|
2018-07-20 23:44:46 +02:00
|
|
|
# Construct a staging directory of the root file system.
|
|
|
|
in_dir = common.MakeTempDir()
|
|
|
|
root_dir = prop_dict.get("root_dir")
|
|
|
|
if root_dir:
|
|
|
|
shutil.rmtree(in_dir)
|
|
|
|
shutil.copytree(root_dir, in_dir, symlinks=True)
|
|
|
|
in_dir_system = os.path.join(in_dir, "system")
|
|
|
|
shutil.rmtree(in_dir_system, ignore_errors=True)
|
|
|
|
shutil.copytree(origin_in, in_dir_system, symlinks=True)
|
|
|
|
|
|
|
|
# Change the mount point to "/".
|
|
|
|
prop_dict["mount_point"] = "/"
|
|
|
|
if fs_config:
|
|
|
|
# We need to merge the fs_config files of system and root.
|
|
|
|
merged_fs_config = common.MakeTempFile(
|
|
|
|
prefix="merged_fs_config", suffix=".txt")
|
|
|
|
with open(merged_fs_config, "w") as fw:
|
|
|
|
if "root_fs_config" in prop_dict:
|
|
|
|
with open(prop_dict["root_fs_config"]) as fr:
|
|
|
|
fw.writelines(fr.readlines())
|
|
|
|
with open(fs_config) as fr:
|
|
|
|
fw.writelines(fr.readlines())
|
|
|
|
fs_config = merged_fs_config
|
2018-10-19 22:44:36 +02:00
|
|
|
prop_dict["first_pass"] = (in_dir, fs_config)
|
2018-07-20 23:44:46 +02:00
|
|
|
return in_dir, fs_config
|
|
|
|
|
|
|
|
|
2017-12-08 08:01:25 +01:00
|
|
|
def CheckHeadroom(ext4fs_output, prop_dict):
|
|
|
|
"""Checks if there's enough headroom space available.
|
|
|
|
|
|
|
|
Headroom is the reserved space on system image (via PRODUCT_SYSTEM_HEADROOM),
|
|
|
|
which is useful for devices with low disk space that have system image
|
|
|
|
variation between builds. The 'partition_headroom' in prop_dict is the size
|
|
|
|
in bytes, while the numbers in 'ext4fs_output' are for 4K-blocks.
|
|
|
|
|
|
|
|
Args:
|
|
|
|
ext4fs_output: The output string from mke2fs command.
|
|
|
|
prop_dict: The property dict.
|
|
|
|
|
2018-01-03 06:19:27 +01:00
|
|
|
Raises:
|
|
|
|
AssertionError: On invalid input.
|
2018-09-28 01:58:00 +02:00
|
|
|
BuildImageError: On check failure.
|
2017-12-08 08:01:25 +01:00
|
|
|
"""
|
2018-01-03 06:19:27 +01:00
|
|
|
assert ext4fs_output is not None
|
|
|
|
assert prop_dict.get('fs_type', '').startswith('ext4')
|
|
|
|
assert 'partition_headroom' in prop_dict
|
|
|
|
assert 'mount_point' in prop_dict
|
|
|
|
|
2017-12-08 08:01:25 +01:00
|
|
|
ext4fs_stats = re.compile(
|
|
|
|
r'Created filesystem with .* (?P<used_blocks>[0-9]+)/'
|
|
|
|
r'(?P<total_blocks>[0-9]+) blocks')
|
2017-12-07 19:33:00 +01:00
|
|
|
last_line = ext4fs_output.strip().split('\n')[-1]
|
|
|
|
m = ext4fs_stats.match(last_line)
|
2017-12-08 08:01:25 +01:00
|
|
|
used_blocks = int(m.groupdict().get('used_blocks'))
|
|
|
|
total_blocks = int(m.groupdict().get('total_blocks'))
|
2018-10-19 22:44:36 +02:00
|
|
|
headroom_blocks = int(prop_dict['partition_headroom']) // BLOCK_SIZE
|
2017-12-08 08:01:25 +01:00
|
|
|
adjusted_blocks = total_blocks - headroom_blocks
|
|
|
|
if used_blocks > adjusted_blocks:
|
2018-01-03 06:19:27 +01:00
|
|
|
mount_point = prop_dict["mount_point"]
|
2018-09-28 01:58:00 +02:00
|
|
|
raise BuildImageError(
|
|
|
|
"Error: Not enough room on {} (total: {} blocks, used: {} blocks, "
|
|
|
|
"headroom: {} blocks, available: {} blocks)".format(
|
|
|
|
mount_point, total_blocks, used_blocks, headroom_blocks,
|
|
|
|
adjusted_blocks))
|
2017-12-08 08:01:25 +01:00
|
|
|
|
|
|
|
|
2018-11-07 16:40:31 +01:00
|
|
|
def BuildImageMkfs(in_dir, prop_dict, out_file, target_out, fs_config):
|
|
|
|
"""Builds a pure image for the files under in_dir and writes it to out_file.
|
2018-07-20 23:44:46 +02:00
|
|
|
|
2011-10-29 02:02:30 +02:00
|
|
|
Args:
|
2018-07-20 23:44:46 +02:00
|
|
|
in_dir: Path to input directory.
|
|
|
|
prop_dict: A property dict that contains info like partition size. Values
|
|
|
|
will be updated with computed values.
|
|
|
|
out_file: The output image file.
|
|
|
|
target_out: Path to the TARGET_OUT directory as in Makefile. It actually
|
|
|
|
points to the /system directory under PRODUCT_OUT. fs_config (the one
|
|
|
|
under system/core/libcutils) reads device specific FS config files from
|
|
|
|
there.
|
2018-11-07 16:40:31 +01:00
|
|
|
fs_config: The fs_config file that drives the prototype
|
2011-10-29 02:02:30 +02:00
|
|
|
|
2018-09-28 01:58:00 +02:00
|
|
|
Raises:
|
|
|
|
BuildImageError: On build image failures.
|
2011-10-29 02:02:30 +02:00
|
|
|
"""
|
|
|
|
build_command = []
|
|
|
|
fs_type = prop_dict.get("fs_type", "")
|
2017-12-07 19:33:00 +01:00
|
|
|
run_e2fsck = False
|
2013-06-17 02:26:08 +02:00
|
|
|
|
2011-10-29 02:02:30 +02:00
|
|
|
if fs_type.startswith("ext"):
|
2016-11-19 02:06:29 +01:00
|
|
|
build_command = [prop_dict["ext_mkuserimg"]]
|
2011-10-29 02:02:30 +02:00
|
|
|
if "extfs_sparse_flag" in prop_dict:
|
|
|
|
build_command.append(prop_dict["extfs_sparse_flag"])
|
2017-12-07 19:33:00 +01:00
|
|
|
run_e2fsck = True
|
2011-10-29 02:02:30 +02:00
|
|
|
build_command.extend([in_dir, out_file, fs_type,
|
|
|
|
prop_dict["mount_point"]])
|
2018-09-28 00:31:11 +02:00
|
|
|
build_command.append(prop_dict["image_size"])
|
2014-11-19 03:03:13 +01:00
|
|
|
if "journal_size" in prop_dict:
|
|
|
|
build_command.extend(["-j", prop_dict["journal_size"]])
|
2013-12-06 00:54:55 +01:00
|
|
|
if "timestamp" in prop_dict:
|
|
|
|
build_command.extend(["-T", str(prop_dict["timestamp"])])
|
2015-03-25 03:07:40 +01:00
|
|
|
if fs_config:
|
2014-06-16 18:10:55 +02:00
|
|
|
build_command.extend(["-C", fs_config])
|
2015-07-09 18:54:55 +02:00
|
|
|
if target_out:
|
|
|
|
build_command.extend(["-D", target_out])
|
2015-03-25 03:07:40 +01:00
|
|
|
if "block_list" in prop_dict:
|
|
|
|
build_command.extend(["-B", prop_dict["block_list"]])
|
2016-03-03 06:07:23 +01:00
|
|
|
if "base_fs_file" in prop_dict:
|
|
|
|
base_fs_file = ConvertBlockMapToBaseFs(prop_dict["base_fs_file"])
|
|
|
|
build_command.extend(["-d", base_fs_file])
|
2014-12-17 21:34:12 +01:00
|
|
|
build_command.extend(["-L", prop_dict["mount_point"]])
|
2016-10-20 19:58:12 +02:00
|
|
|
if "extfs_inode_count" in prop_dict:
|
|
|
|
build_command.extend(["-i", prop_dict["extfs_inode_count"]])
|
2018-03-23 19:36:43 +01:00
|
|
|
if "extfs_rsv_pct" in prop_dict:
|
|
|
|
build_command.extend(["-M", prop_dict["extfs_rsv_pct"]])
|
2017-01-06 01:48:14 +01:00
|
|
|
if "flash_erase_block_size" in prop_dict:
|
|
|
|
build_command.extend(["-e", prop_dict["flash_erase_block_size"]])
|
|
|
|
if "flash_logical_block_size" in prop_dict:
|
|
|
|
build_command.extend(["-o", prop_dict["flash_logical_block_size"]])
|
2017-09-23 00:45:33 +02:00
|
|
|
# Specify UUID and hash_seed if using mke2fs.
|
2018-08-16 01:16:21 +02:00
|
|
|
if prop_dict["ext_mkuserimg"] == "mkuserimg_mke2fs":
|
2017-09-23 00:45:33 +02:00
|
|
|
if "uuid" in prop_dict:
|
|
|
|
build_command.extend(["-U", prop_dict["uuid"]])
|
|
|
|
if "hash_seed" in prop_dict:
|
|
|
|
build_command.extend(["-S", prop_dict["hash_seed"]])
|
2018-01-22 22:15:46 +01:00
|
|
|
if "ext4_share_dup_blocks" in prop_dict:
|
|
|
|
build_command.append("-c")
|
2019-01-08 19:08:04 +01:00
|
|
|
build_command.extend(["--inode_size", "256"])
|
2015-03-25 03:07:40 +01:00
|
|
|
if "selinux_fc" in prop_dict:
|
2012-04-08 19:42:34 +02:00
|
|
|
build_command.append(prop_dict["selinux_fc"])
|
2015-03-03 21:30:37 +01:00
|
|
|
elif fs_type.startswith("squash"):
|
|
|
|
build_command = ["mksquashfsimage.sh"]
|
|
|
|
build_command.extend([in_dir, out_file])
|
2015-12-16 03:00:14 +01:00
|
|
|
if "squashfs_sparse_flag" in prop_dict:
|
|
|
|
build_command.extend([prop_dict["squashfs_sparse_flag"]])
|
2015-03-03 21:30:37 +01:00
|
|
|
build_command.extend(["-m", prop_dict["mount_point"]])
|
2015-07-09 18:54:55 +02:00
|
|
|
if target_out:
|
|
|
|
build_command.extend(["-d", target_out])
|
2016-04-08 07:10:51 +02:00
|
|
|
if fs_config:
|
|
|
|
build_command.extend(["-C", fs_config])
|
2015-03-25 03:07:40 +01:00
|
|
|
if "selinux_fc" in prop_dict:
|
2015-03-03 21:30:37 +01:00
|
|
|
build_command.extend(["-c", prop_dict["selinux_fc"]])
|
2016-06-13 18:46:58 +02:00
|
|
|
if "block_list" in prop_dict:
|
|
|
|
build_command.extend(["-B", prop_dict["block_list"]])
|
2018-01-20 00:51:46 +01:00
|
|
|
if "squashfs_block_size" in prop_dict:
|
|
|
|
build_command.extend(["-b", prop_dict["squashfs_block_size"]])
|
2015-06-17 21:35:15 +02:00
|
|
|
if "squashfs_compressor" in prop_dict:
|
|
|
|
build_command.extend(["-z", prop_dict["squashfs_compressor"]])
|
|
|
|
if "squashfs_compressor_opt" in prop_dict:
|
|
|
|
build_command.extend(["-zo", prop_dict["squashfs_compressor_opt"]])
|
2017-12-07 19:33:00 +01:00
|
|
|
if prop_dict.get("squashfs_disable_4k_align") == "true":
|
2016-06-16 00:53:07 +02:00
|
|
|
build_command.extend(["-a"])
|
2014-06-16 23:17:40 +02:00
|
|
|
elif fs_type.startswith("f2fs"):
|
|
|
|
build_command = ["mkf2fsuserimg.sh"]
|
2018-09-28 00:31:11 +02:00
|
|
|
build_command.extend([out_file, prop_dict["image_size"]])
|
2017-11-29 04:21:28 +01:00
|
|
|
if fs_config:
|
|
|
|
build_command.extend(["-C", fs_config])
|
|
|
|
build_command.extend(["-f", in_dir])
|
|
|
|
if target_out:
|
|
|
|
build_command.extend(["-D", target_out])
|
|
|
|
if "selinux_fc" in prop_dict:
|
|
|
|
build_command.extend(["-s", prop_dict["selinux_fc"]])
|
|
|
|
build_command.extend(["-t", prop_dict["mount_point"]])
|
|
|
|
if "timestamp" in prop_dict:
|
|
|
|
build_command.extend(["-T", str(prop_dict["timestamp"])])
|
|
|
|
build_command.extend(["-L", prop_dict["mount_point"]])
|
2011-10-29 02:02:30 +02:00
|
|
|
else:
|
2018-09-28 01:58:00 +02:00
|
|
|
raise BuildImageError(
|
|
|
|
"Error: unknown filesystem type: {}".format(fs_type))
|
2011-10-29 02:02:30 +02:00
|
|
|
|
2018-10-05 00:46:16 +02:00
|
|
|
try:
|
|
|
|
mkfs_output = common.RunAndCheckOutput(build_command)
|
|
|
|
except:
|
2018-09-28 01:58:00 +02:00
|
|
|
try:
|
|
|
|
du = GetDiskUsage(in_dir)
|
|
|
|
du_str = "{} bytes ({} MB)".format(du, du // BYTES_IN_MB)
|
2018-10-05 00:46:16 +02:00
|
|
|
# Suppress any errors from GetDiskUsage() to avoid hiding the real errors
|
|
|
|
# from common.RunAndCheckOutput().
|
2018-10-12 19:30:39 +02:00
|
|
|
except Exception: # pylint: disable=broad-except
|
|
|
|
logger.exception("Failed to compute disk usage with du")
|
2018-09-28 01:58:00 +02:00
|
|
|
du_str = "unknown"
|
2018-07-23 22:05:00 +02:00
|
|
|
print(
|
2018-11-07 16:40:31 +01:00
|
|
|
"Out of space? Out of inodes? The tree size of {} is {}, "
|
|
|
|
"with reserved space of {} bytes ({} MB).".format(
|
2018-07-20 23:44:46 +02:00
|
|
|
in_dir, du_str,
|
2018-07-23 22:05:00 +02:00
|
|
|
int(prop_dict.get("partition_reserved_size", 0)),
|
|
|
|
int(prop_dict.get("partition_reserved_size", 0)) // BYTES_IN_MB))
|
2018-09-28 00:31:11 +02:00
|
|
|
print(
|
2018-10-19 22:44:36 +02:00
|
|
|
"The max image size for filesystem files is {} bytes ({} MB), out of a "
|
2018-09-28 00:31:11 +02:00
|
|
|
"total partition size of {} bytes ({} MB).".format(
|
|
|
|
int(prop_dict["image_size"]),
|
|
|
|
int(prop_dict["image_size"]) // BYTES_IN_MB,
|
|
|
|
int(prop_dict["partition_size"]),
|
|
|
|
int(prop_dict["partition_size"]) // BYTES_IN_MB))
|
2018-10-05 00:46:16 +02:00
|
|
|
raise
|
2012-11-27 03:10:23 +01:00
|
|
|
|
2018-11-07 16:40:31 +01:00
|
|
|
if run_e2fsck and prop_dict.get("skip_fsck") != "true":
|
|
|
|
unsparse_image = UnsparseImage(out_file, replace=False)
|
|
|
|
|
|
|
|
# Run e2fsck on the inflated image file
|
|
|
|
e2fsck_command = ["e2fsck", "-f", "-n", unsparse_image]
|
|
|
|
try:
|
|
|
|
common.RunAndCheckOutput(e2fsck_command)
|
|
|
|
finally:
|
|
|
|
os.remove(unsparse_image)
|
|
|
|
|
|
|
|
return mkfs_output
|
|
|
|
|
|
|
|
|
|
|
|
def BuildImage(in_dir, prop_dict, out_file, target_out=None):
|
|
|
|
"""Builds an image for the files under in_dir and writes it to out_file.
|
|
|
|
|
|
|
|
Args:
|
|
|
|
in_dir: Path to input directory.
|
|
|
|
prop_dict: A property dict that contains info like partition size. Values
|
|
|
|
will be updated with computed values.
|
|
|
|
out_file: The output image file.
|
|
|
|
target_out: Path to the TARGET_OUT directory as in Makefile. It actually
|
|
|
|
points to the /system directory under PRODUCT_OUT. fs_config (the one
|
|
|
|
under system/core/libcutils) reads device specific FS config files from
|
|
|
|
there.
|
|
|
|
|
|
|
|
Raises:
|
|
|
|
BuildImageError: On build image failures.
|
|
|
|
"""
|
|
|
|
in_dir, fs_config = SetUpInDirAndFsConfig(in_dir, prop_dict)
|
|
|
|
|
|
|
|
build_command = []
|
|
|
|
fs_type = prop_dict.get("fs_type", "")
|
|
|
|
|
|
|
|
fs_spans_partition = True
|
|
|
|
if fs_type.startswith("squash"):
|
|
|
|
fs_spans_partition = False
|
|
|
|
|
|
|
|
# Get a builder for creating an image that's to be verified by Verified Boot,
|
|
|
|
# or None if not applicable.
|
|
|
|
verity_image_builder = verity_utils.CreateVerityImageBuilder(prop_dict)
|
|
|
|
|
|
|
|
if (prop_dict.get("use_dynamic_partition_size") == "true" and
|
|
|
|
"partition_size" not in prop_dict):
|
|
|
|
# If partition_size is not defined, use output of `du' + reserved_size.
|
|
|
|
size = GetDiskUsage(in_dir)
|
|
|
|
logger.info(
|
|
|
|
"The tree size of %s is %d MB.", in_dir, size // BYTES_IN_MB)
|
|
|
|
# If not specified, give us 16MB margin for GetDiskUsage error ...
|
|
|
|
reserved_size = int(prop_dict.get("partition_reserved_size", BYTES_IN_MB * 16))
|
|
|
|
partition_headroom = int(prop_dict.get("partition_headroom", 0))
|
|
|
|
if fs_type.startswith("ext4") and partition_headroom > reserved_size:
|
|
|
|
reserved_size = partition_headroom
|
|
|
|
size += reserved_size
|
|
|
|
# Round this up to a multiple of 4K so that avbtool works
|
|
|
|
size = common.RoundUpTo4K(size)
|
|
|
|
if fs_type.startswith("ext"):
|
|
|
|
prop_dict["partition_size"] = str(size)
|
|
|
|
prop_dict["image_size"] = str(size)
|
|
|
|
if "extfs_inode_count" not in prop_dict:
|
|
|
|
prop_dict["extfs_inode_count"] = str(GetInodeUsage(in_dir))
|
|
|
|
logger.info(
|
|
|
|
"First Pass based on estimates of %d MB and %s inodes.",
|
|
|
|
size // BYTES_IN_MB, prop_dict["extfs_inode_count"])
|
|
|
|
BuildImageMkfs(in_dir, prop_dict, out_file, target_out, fs_config)
|
2019-01-10 23:30:51 +01:00
|
|
|
sparse_image = False
|
|
|
|
if "extfs_sparse_flag" in prop_dict:
|
|
|
|
sparse_image = True
|
|
|
|
fs_dict = GetFilesystemCharacteristics(out_file, sparse_image)
|
2018-11-07 16:40:31 +01:00
|
|
|
os.remove(out_file)
|
|
|
|
block_size = int(fs_dict.get("Block size", "4096"))
|
|
|
|
free_size = int(fs_dict.get("Free blocks", "0")) * block_size
|
|
|
|
reserved_size = int(prop_dict.get("partition_reserved_size", 0))
|
|
|
|
partition_headroom = int(fs_dict.get("partition_headroom", 0))
|
|
|
|
if fs_type.startswith("ext4") and partition_headroom > reserved_size:
|
|
|
|
reserved_size = partition_headroom
|
|
|
|
if free_size <= reserved_size:
|
|
|
|
logger.info(
|
|
|
|
"Not worth reducing image %d <= %d.", free_size, reserved_size)
|
|
|
|
else:
|
|
|
|
size -= free_size
|
|
|
|
size += reserved_size
|
2019-01-10 17:36:34 +01:00
|
|
|
if reserved_size == 0:
|
2019-01-16 17:03:10 +01:00
|
|
|
# add .3% margin
|
|
|
|
size = size * 1003 // 1000
|
2019-01-10 17:36:34 +01:00
|
|
|
# Use a minimum size, otherwise we will fail to calculate an AVB footer
|
|
|
|
# or fail to construct an ext4 image.
|
|
|
|
size = max(size, 256 * 1024)
|
2018-11-07 16:40:31 +01:00
|
|
|
if block_size <= 4096:
|
|
|
|
size = common.RoundUpTo4K(size)
|
|
|
|
else:
|
|
|
|
size = ((size + block_size - 1) // block_size) * block_size
|
|
|
|
extfs_inode_count = prop_dict["extfs_inode_count"]
|
|
|
|
inodes = int(fs_dict.get("Inode count", extfs_inode_count))
|
|
|
|
inodes -= int(fs_dict.get("Free inodes", "0"))
|
2019-01-16 17:03:10 +01:00
|
|
|
# add .2% margin or 1 inode, whichever is greater
|
|
|
|
spare_inodes = inodes * 2 // 1000
|
|
|
|
min_spare_inodes = 1
|
|
|
|
if spare_inodes < min_spare_inodes:
|
|
|
|
spare_inodes = min_spare_inodes
|
|
|
|
inodes += spare_inodes
|
2018-11-07 16:40:31 +01:00
|
|
|
prop_dict["extfs_inode_count"] = str(inodes)
|
|
|
|
prop_dict["partition_size"] = str(size)
|
|
|
|
logger.info(
|
|
|
|
"Allocating %d Inodes for %s.", inodes, out_file)
|
|
|
|
if verity_image_builder:
|
|
|
|
size = verity_image_builder.CalculateDynamicPartitionSize(size)
|
|
|
|
prop_dict["partition_size"] = str(size)
|
|
|
|
logger.info(
|
|
|
|
"Allocating %d MB for %s.", size // BYTES_IN_MB, out_file)
|
|
|
|
|
|
|
|
prop_dict["image_size"] = prop_dict["partition_size"]
|
|
|
|
|
|
|
|
# Adjust the image size to make room for the hashes if this is to be verified.
|
|
|
|
if verity_image_builder:
|
|
|
|
max_image_size = verity_image_builder.CalculateMaxImageSize()
|
|
|
|
prop_dict["image_size"] = str(max_image_size)
|
|
|
|
|
|
|
|
mkfs_output = BuildImageMkfs(in_dir, prop_dict, out_file, target_out, fs_config)
|
|
|
|
|
2017-12-08 08:01:25 +01:00
|
|
|
# Check if there's enough headroom space available for ext4 image.
|
2017-12-07 23:07:44 +01:00
|
|
|
if "partition_headroom" in prop_dict and fs_type.startswith("ext4"):
|
2018-09-28 01:58:00 +02:00
|
|
|
CheckHeadroom(mkfs_output, prop_dict)
|
2015-06-23 20:16:05 +02:00
|
|
|
|
2018-10-03 23:23:59 +02:00
|
|
|
if not fs_spans_partition and verity_image_builder:
|
|
|
|
verity_image_builder.PadSparseImage(out_file)
|
2015-03-24 20:42:03 +01:00
|
|
|
|
2017-12-07 19:33:00 +01:00
|
|
|
# Create the verified image if this is to be verified.
|
2018-10-03 23:23:59 +02:00
|
|
|
if verity_image_builder:
|
|
|
|
verity_image_builder.Build(out_file)
|
2016-09-30 23:29:22 +02:00
|
|
|
|
2011-10-29 02:02:30 +02:00
|
|
|
|
|
|
|
def ImagePropFromGlobalDict(glob_dict, mount_point):
|
|
|
|
"""Build an image property dictionary from the global dictionary.
|
|
|
|
|
|
|
|
Args:
|
|
|
|
glob_dict: the global dictionary from the build system.
|
|
|
|
mount_point: such as "system", "data" etc.
|
|
|
|
"""
|
2013-12-06 20:53:27 +01:00
|
|
|
d = {}
|
2015-09-28 22:44:13 +02:00
|
|
|
|
2015-10-01 01:01:14 +02:00
|
|
|
if "build.prop" in glob_dict:
|
|
|
|
bp = glob_dict["build.prop"]
|
|
|
|
if "ro.build.date.utc" in bp:
|
|
|
|
d["timestamp"] = bp["ro.build.date.utc"]
|
2011-11-04 19:37:01 +01:00
|
|
|
|
|
|
|
def copy_prop(src_p, dest_p):
|
2018-03-23 19:36:43 +01:00
|
|
|
"""Copy a property from the global dictionary.
|
|
|
|
|
|
|
|
Args:
|
|
|
|
src_p: The source property in the global dictionary.
|
|
|
|
dest_p: The destination property.
|
|
|
|
Returns:
|
|
|
|
True if property was found and copied, False otherwise.
|
|
|
|
"""
|
2011-11-04 19:37:01 +01:00
|
|
|
if src_p in glob_dict:
|
|
|
|
d[dest_p] = str(glob_dict[src_p])
|
2018-03-23 19:36:43 +01:00
|
|
|
return True
|
|
|
|
return False
|
2011-11-04 19:37:01 +01:00
|
|
|
|
2011-10-29 02:02:30 +02:00
|
|
|
common_props = (
|
|
|
|
"extfs_sparse_flag",
|
2015-12-16 03:00:14 +01:00
|
|
|
"squashfs_sparse_flag",
|
2013-02-27 22:54:02 +01:00
|
|
|
"skip_fsck",
|
2016-11-19 02:06:29 +01:00
|
|
|
"ext_mkuserimg",
|
2013-06-17 02:26:08 +02:00
|
|
|
"verity",
|
|
|
|
"verity_key",
|
2015-05-20 08:30:57 +02:00
|
|
|
"verity_signer_cmd",
|
2016-09-30 23:29:22 +02:00
|
|
|
"verity_fec",
|
2017-10-11 10:21:48 +02:00
|
|
|
"verity_disable",
|
2017-05-26 12:30:04 +02:00
|
|
|
"avb_enable",
|
2017-09-28 02:17:43 +02:00
|
|
|
"avb_avbtool",
|
|
|
|
"avb_salt",
|
2018-07-31 21:47:27 +02:00
|
|
|
"use_dynamic_partition_size",
|
2017-09-28 02:17:43 +02:00
|
|
|
)
|
2011-10-29 02:02:30 +02:00
|
|
|
for p in common_props:
|
2011-11-04 19:37:01 +01:00
|
|
|
copy_prop(p, p)
|
2011-10-29 02:02:30 +02:00
|
|
|
|
|
|
|
d["mount_point"] = mount_point
|
|
|
|
if mount_point == "system":
|
2017-05-26 12:30:04 +02:00
|
|
|
copy_prop("avb_system_hashtree_enable", "avb_hashtree_enable")
|
|
|
|
copy_prop("avb_system_add_hashtree_footer_args",
|
|
|
|
"avb_add_hashtree_footer_args")
|
|
|
|
copy_prop("avb_system_key_path", "avb_key_path")
|
|
|
|
copy_prop("avb_system_algorithm", "avb_algorithm")
|
2011-11-04 19:37:01 +01:00
|
|
|
copy_prop("fs_type", "fs_type")
|
2017-05-03 22:43:27 +02:00
|
|
|
# Copy the generic system fs type first, override with specific one if
|
2015-03-24 03:13:21 +01:00
|
|
|
# available.
|
2015-03-03 21:30:37 +01:00
|
|
|
copy_prop("system_fs_type", "fs_type")
|
2017-05-03 22:43:27 +02:00
|
|
|
copy_prop("system_headroom", "partition_headroom")
|
2011-11-04 19:37:01 +01:00
|
|
|
copy_prop("system_size", "partition_size")
|
2018-03-31 19:27:35 +02:00
|
|
|
if not copy_prop("system_journal_size", "journal_size"):
|
|
|
|
d["journal_size"] = "0"
|
2014-07-11 00:42:38 +02:00
|
|
|
copy_prop("system_verity_block_device", "verity_block_device")
|
2015-04-01 20:21:55 +02:00
|
|
|
copy_prop("system_root_image", "system_root_image")
|
2018-07-21 00:20:28 +02:00
|
|
|
copy_prop("root_dir", "root_dir")
|
|
|
|
copy_prop("root_fs_config", "root_fs_config")
|
2018-01-22 22:15:46 +01:00
|
|
|
copy_prop("ext4_share_dup_blocks", "ext4_share_dup_blocks")
|
2015-06-17 21:35:15 +02:00
|
|
|
copy_prop("system_squashfs_compressor", "squashfs_compressor")
|
|
|
|
copy_prop("system_squashfs_compressor_opt", "squashfs_compressor_opt")
|
2016-05-24 21:59:30 +02:00
|
|
|
copy_prop("system_squashfs_block_size", "squashfs_block_size")
|
2016-06-16 00:53:07 +02:00
|
|
|
copy_prop("system_squashfs_disable_4k_align", "squashfs_disable_4k_align")
|
2016-03-03 06:07:23 +01:00
|
|
|
copy_prop("system_base_fs_file", "base_fs_file")
|
2016-10-20 19:58:12 +02:00
|
|
|
copy_prop("system_extfs_inode_count", "extfs_inode_count")
|
2018-03-23 19:36:43 +01:00
|
|
|
if not copy_prop("system_extfs_rsv_pct", "extfs_rsv_pct"):
|
|
|
|
d["extfs_rsv_pct"] = "0"
|
2018-06-19 01:32:35 +02:00
|
|
|
copy_prop("system_reserved_size", "partition_reserved_size")
|
2019-05-14 00:58:14 +02:00
|
|
|
copy_prop("system_selinux_fc", "selinux_fc")
|
2016-06-16 23:47:10 +02:00
|
|
|
elif mount_point == "system_other":
|
2017-12-07 19:33:00 +01:00
|
|
|
# We inherit the selinux policies of /system since we contain some of its
|
|
|
|
# files.
|
2019-01-23 15:19:19 +01:00
|
|
|
copy_prop("avb_system_other_hashtree_enable", "avb_hashtree_enable")
|
|
|
|
copy_prop("avb_system_other_add_hashtree_footer_args",
|
2017-05-26 12:30:04 +02:00
|
|
|
"avb_add_hashtree_footer_args")
|
2019-01-23 15:19:19 +01:00
|
|
|
copy_prop("avb_system_other_key_path", "avb_key_path")
|
|
|
|
copy_prop("avb_system_other_algorithm", "avb_algorithm")
|
2016-06-16 23:47:10 +02:00
|
|
|
copy_prop("fs_type", "fs_type")
|
|
|
|
copy_prop("system_fs_type", "fs_type")
|
2019-01-29 06:30:18 +01:00
|
|
|
copy_prop("system_other_size", "partition_size")
|
2018-03-31 19:27:35 +02:00
|
|
|
if not copy_prop("system_journal_size", "journal_size"):
|
|
|
|
d["journal_size"] = "0"
|
2016-06-16 23:47:10 +02:00
|
|
|
copy_prop("system_verity_block_device", "verity_block_device")
|
2018-10-29 18:55:06 +01:00
|
|
|
copy_prop("ext4_share_dup_blocks", "ext4_share_dup_blocks")
|
2016-06-16 23:47:10 +02:00
|
|
|
copy_prop("system_squashfs_compressor", "squashfs_compressor")
|
|
|
|
copy_prop("system_squashfs_compressor_opt", "squashfs_compressor_opt")
|
|
|
|
copy_prop("system_squashfs_block_size", "squashfs_block_size")
|
|
|
|
copy_prop("system_base_fs_file", "base_fs_file")
|
2016-10-20 19:58:12 +02:00
|
|
|
copy_prop("system_extfs_inode_count", "extfs_inode_count")
|
2018-03-23 19:36:43 +01:00
|
|
|
if not copy_prop("system_extfs_rsv_pct", "extfs_rsv_pct"):
|
|
|
|
d["extfs_rsv_pct"] = "0"
|
2018-06-19 01:32:35 +02:00
|
|
|
copy_prop("system_reserved_size", "partition_reserved_size")
|
2019-05-14 00:58:14 +02:00
|
|
|
copy_prop("system_selinux_fc", "selinux_fc")
|
2011-10-29 02:02:30 +02:00
|
|
|
elif mount_point == "data":
|
2014-06-16 23:17:40 +02:00
|
|
|
# Copy the generic fs type first, override with specific one if available.
|
2011-11-04 19:37:01 +01:00
|
|
|
copy_prop("fs_type", "fs_type")
|
2014-06-16 23:17:40 +02:00
|
|
|
copy_prop("userdata_fs_type", "fs_type")
|
2011-11-04 19:37:01 +01:00
|
|
|
copy_prop("userdata_size", "partition_size")
|
2017-12-07 19:33:00 +01:00
|
|
|
copy_prop("flash_logical_block_size", "flash_logical_block_size")
|
2017-01-06 01:48:14 +01:00
|
|
|
copy_prop("flash_erase_block_size", "flash_erase_block_size")
|
2019-05-14 00:58:14 +02:00
|
|
|
copy_prop("userdata_selinux_fc", "selinux_fc")
|
2011-11-04 19:37:01 +01:00
|
|
|
elif mount_point == "cache":
|
|
|
|
copy_prop("cache_fs_type", "fs_type")
|
|
|
|
copy_prop("cache_size", "partition_size")
|
2019-05-14 00:58:14 +02:00
|
|
|
copy_prop("cache_selinux_fc", "selinux_fc")
|
2013-03-20 19:02:05 +01:00
|
|
|
elif mount_point == "vendor":
|
2017-05-26 12:30:04 +02:00
|
|
|
copy_prop("avb_vendor_hashtree_enable", "avb_hashtree_enable")
|
|
|
|
copy_prop("avb_vendor_add_hashtree_footer_args",
|
|
|
|
"avb_add_hashtree_footer_args")
|
|
|
|
copy_prop("avb_vendor_key_path", "avb_key_path")
|
|
|
|
copy_prop("avb_vendor_algorithm", "avb_algorithm")
|
2013-03-20 19:02:05 +01:00
|
|
|
copy_prop("vendor_fs_type", "fs_type")
|
|
|
|
copy_prop("vendor_size", "partition_size")
|
2018-03-31 19:27:35 +02:00
|
|
|
if not copy_prop("vendor_journal_size", "journal_size"):
|
|
|
|
d["journal_size"] = "0"
|
2014-07-11 00:42:38 +02:00
|
|
|
copy_prop("vendor_verity_block_device", "verity_block_device")
|
2018-01-22 22:15:46 +01:00
|
|
|
copy_prop("ext4_share_dup_blocks", "ext4_share_dup_blocks")
|
2016-02-10 00:40:38 +01:00
|
|
|
copy_prop("vendor_squashfs_compressor", "squashfs_compressor")
|
|
|
|
copy_prop("vendor_squashfs_compressor_opt", "squashfs_compressor_opt")
|
2016-05-24 21:59:30 +02:00
|
|
|
copy_prop("vendor_squashfs_block_size", "squashfs_block_size")
|
2016-06-16 00:53:07 +02:00
|
|
|
copy_prop("vendor_squashfs_disable_4k_align", "squashfs_disable_4k_align")
|
2016-03-03 06:07:23 +01:00
|
|
|
copy_prop("vendor_base_fs_file", "base_fs_file")
|
2016-10-20 19:58:12 +02:00
|
|
|
copy_prop("vendor_extfs_inode_count", "extfs_inode_count")
|
2018-03-23 19:36:43 +01:00
|
|
|
if not copy_prop("vendor_extfs_rsv_pct", "extfs_rsv_pct"):
|
|
|
|
d["extfs_rsv_pct"] = "0"
|
2018-06-20 01:23:16 +02:00
|
|
|
copy_prop("vendor_reserved_size", "partition_reserved_size")
|
2019-05-14 00:58:14 +02:00
|
|
|
copy_prop("vendor_selinux_fc", "selinux_fc")
|
2017-11-27 09:04:47 +01:00
|
|
|
elif mount_point == "product":
|
|
|
|
copy_prop("avb_product_hashtree_enable", "avb_hashtree_enable")
|
|
|
|
copy_prop("avb_product_add_hashtree_footer_args",
|
|
|
|
"avb_add_hashtree_footer_args")
|
|
|
|
copy_prop("avb_product_key_path", "avb_key_path")
|
|
|
|
copy_prop("avb_product_algorithm", "avb_algorithm")
|
|
|
|
copy_prop("product_fs_type", "fs_type")
|
|
|
|
copy_prop("product_size", "partition_size")
|
2018-03-31 19:27:35 +02:00
|
|
|
if not copy_prop("product_journal_size", "journal_size"):
|
|
|
|
d["journal_size"] = "0"
|
2017-11-27 09:04:47 +01:00
|
|
|
copy_prop("product_verity_block_device", "verity_block_device")
|
2018-10-29 18:55:06 +01:00
|
|
|
copy_prop("ext4_share_dup_blocks", "ext4_share_dup_blocks")
|
2017-11-27 09:04:47 +01:00
|
|
|
copy_prop("product_squashfs_compressor", "squashfs_compressor")
|
|
|
|
copy_prop("product_squashfs_compressor_opt", "squashfs_compressor_opt")
|
|
|
|
copy_prop("product_squashfs_block_size", "squashfs_block_size")
|
|
|
|
copy_prop("product_squashfs_disable_4k_align", "squashfs_disable_4k_align")
|
|
|
|
copy_prop("product_base_fs_file", "base_fs_file")
|
|
|
|
copy_prop("product_extfs_inode_count", "extfs_inode_count")
|
2018-03-23 19:36:43 +01:00
|
|
|
if not copy_prop("product_extfs_rsv_pct", "extfs_rsv_pct"):
|
|
|
|
d["extfs_rsv_pct"] = "0"
|
2018-07-21 00:19:34 +02:00
|
|
|
copy_prop("product_reserved_size", "partition_reserved_size")
|
2019-05-14 00:58:14 +02:00
|
|
|
copy_prop("product_selinux_fc", "selinux_fc")
|
2019-06-25 08:58:13 +02:00
|
|
|
elif mount_point == "system_ext":
|
|
|
|
copy_prop("avb_system_ext_hashtree_enable", "avb_hashtree_enable")
|
|
|
|
copy_prop("avb_system_ext_add_hashtree_footer_args",
|
2018-05-29 14:09:01 +02:00
|
|
|
"avb_add_hashtree_footer_args")
|
2019-06-25 08:58:13 +02:00
|
|
|
copy_prop("avb_system_ext_key_path", "avb_key_path")
|
|
|
|
copy_prop("avb_system_ext_algorithm", "avb_algorithm")
|
|
|
|
copy_prop("system_ext_fs_type", "fs_type")
|
|
|
|
copy_prop("system_ext_size", "partition_size")
|
|
|
|
if not copy_prop("system_ext_journal_size", "journal_size"):
|
2018-05-29 14:09:01 +02:00
|
|
|
d["journal_size"] = "0"
|
2019-06-25 08:58:13 +02:00
|
|
|
copy_prop("system_ext_verity_block_device", "verity_block_device")
|
2018-10-29 18:55:06 +01:00
|
|
|
copy_prop("ext4_share_dup_blocks", "ext4_share_dup_blocks")
|
2019-06-25 08:58:13 +02:00
|
|
|
copy_prop("system_ext_squashfs_compressor", "squashfs_compressor")
|
|
|
|
copy_prop("system_ext_squashfs_compressor_opt",
|
2018-05-29 14:09:01 +02:00
|
|
|
"squashfs_compressor_opt")
|
2019-06-25 08:58:13 +02:00
|
|
|
copy_prop("system_ext_squashfs_block_size", "squashfs_block_size")
|
|
|
|
copy_prop("system_ext_squashfs_disable_4k_align",
|
2018-05-29 14:09:01 +02:00
|
|
|
"squashfs_disable_4k_align")
|
2019-06-25 08:58:13 +02:00
|
|
|
copy_prop("system_ext_base_fs_file", "base_fs_file")
|
|
|
|
copy_prop("system_ext_extfs_inode_count", "extfs_inode_count")
|
|
|
|
if not copy_prop("system_ext_extfs_rsv_pct", "extfs_rsv_pct"):
|
2018-05-29 14:09:01 +02:00
|
|
|
d["extfs_rsv_pct"] = "0"
|
2019-06-25 08:58:13 +02:00
|
|
|
copy_prop("system_ext_reserved_size", "partition_reserved_size")
|
|
|
|
copy_prop("system_ext_selinux_fc", "selinux_fc")
|
2017-11-14 16:42:30 +01:00
|
|
|
elif mount_point == "odm":
|
|
|
|
copy_prop("avb_odm_hashtree_enable", "avb_hashtree_enable")
|
|
|
|
copy_prop("avb_odm_add_hashtree_footer_args",
|
|
|
|
"avb_add_hashtree_footer_args")
|
|
|
|
copy_prop("avb_odm_key_path", "avb_key_path")
|
|
|
|
copy_prop("avb_odm_algorithm", "avb_algorithm")
|
|
|
|
copy_prop("odm_fs_type", "fs_type")
|
|
|
|
copy_prop("odm_size", "partition_size")
|
|
|
|
if not copy_prop("odm_journal_size", "journal_size"):
|
|
|
|
d["journal_size"] = "0"
|
|
|
|
copy_prop("odm_verity_block_device", "verity_block_device")
|
2018-10-29 18:55:06 +01:00
|
|
|
copy_prop("ext4_share_dup_blocks", "ext4_share_dup_blocks")
|
2017-11-14 16:42:30 +01:00
|
|
|
copy_prop("odm_squashfs_compressor", "squashfs_compressor")
|
|
|
|
copy_prop("odm_squashfs_compressor_opt", "squashfs_compressor_opt")
|
|
|
|
copy_prop("odm_squashfs_block_size", "squashfs_block_size")
|
|
|
|
copy_prop("odm_squashfs_disable_4k_align", "squashfs_disable_4k_align")
|
|
|
|
copy_prop("odm_base_fs_file", "base_fs_file")
|
|
|
|
copy_prop("odm_extfs_inode_count", "extfs_inode_count")
|
|
|
|
if not copy_prop("odm_extfs_rsv_pct", "extfs_rsv_pct"):
|
|
|
|
d["extfs_rsv_pct"] = "0"
|
|
|
|
copy_prop("odm_reserved_size", "partition_reserved_size")
|
2019-05-14 00:58:14 +02:00
|
|
|
copy_prop("odm_selinux_fc", "selinux_fc")
|
2014-03-12 01:13:27 +01:00
|
|
|
elif mount_point == "oem":
|
|
|
|
copy_prop("fs_type", "fs_type")
|
|
|
|
copy_prop("oem_size", "partition_size")
|
2018-03-31 19:27:35 +02:00
|
|
|
if not copy_prop("oem_journal_size", "journal_size"):
|
|
|
|
d["journal_size"] = "0"
|
2016-10-20 19:58:12 +02:00
|
|
|
copy_prop("oem_extfs_inode_count", "extfs_inode_count")
|
2018-10-29 18:55:06 +01:00
|
|
|
copy_prop("ext4_share_dup_blocks", "ext4_share_dup_blocks")
|
2018-03-23 19:36:43 +01:00
|
|
|
if not copy_prop("oem_extfs_rsv_pct", "extfs_rsv_pct"):
|
|
|
|
d["extfs_rsv_pct"] = "0"
|
2019-05-14 00:58:14 +02:00
|
|
|
copy_prop("oem_selinux_fc", "selinux_fc")
|
2016-09-30 23:29:22 +02:00
|
|
|
d["partition_name"] = mount_point
|
2011-10-29 02:02:30 +02:00
|
|
|
return d
|
|
|
|
|
|
|
|
|
|
|
|
def LoadGlobalDict(filename):
|
|
|
|
"""Load "name=value" pairs from filename"""
|
|
|
|
d = {}
|
|
|
|
f = open(filename)
|
|
|
|
for line in f:
|
|
|
|
line = line.strip()
|
|
|
|
if not line or line.startswith("#"):
|
|
|
|
continue
|
|
|
|
k, v = line.split("=", 1)
|
|
|
|
d[k] = v
|
|
|
|
f.close()
|
|
|
|
return d
|
|
|
|
|
|
|
|
|
2018-06-19 01:32:35 +02:00
|
|
|
def GlobalDictFromImageProp(image_prop, mount_point):
|
|
|
|
d = {}
|
|
|
|
def copy_prop(src_p, dest_p):
|
|
|
|
if src_p in image_prop:
|
|
|
|
d[dest_p] = image_prop[src_p]
|
|
|
|
return True
|
|
|
|
return False
|
2018-07-23 22:05:00 +02:00
|
|
|
|
2018-06-19 01:32:35 +02:00
|
|
|
if mount_point == "system":
|
2018-09-28 00:31:11 +02:00
|
|
|
copy_prop("partition_size", "system_size")
|
2018-06-19 01:32:35 +02:00
|
|
|
elif mount_point == "system_other":
|
2019-01-29 06:30:18 +01:00
|
|
|
copy_prop("partition_size", "system_other_size")
|
2018-06-20 01:23:16 +02:00
|
|
|
elif mount_point == "vendor":
|
2018-09-28 00:31:11 +02:00
|
|
|
copy_prop("partition_size", "vendor_size")
|
2017-11-14 16:42:30 +01:00
|
|
|
elif mount_point == "odm":
|
2018-09-28 00:31:11 +02:00
|
|
|
copy_prop("partition_size", "odm_size")
|
2018-07-21 00:19:34 +02:00
|
|
|
elif mount_point == "product":
|
2018-09-28 00:31:11 +02:00
|
|
|
copy_prop("partition_size", "product_size")
|
2019-06-25 08:58:13 +02:00
|
|
|
elif mount_point == "system_ext":
|
|
|
|
copy_prop("partition_size", "system_ext_size")
|
2018-06-19 01:32:35 +02:00
|
|
|
return d
|
|
|
|
|
|
|
|
|
2011-10-29 02:02:30 +02:00
|
|
|
def main(argv):
|
2019-04-09 19:03:57 +02:00
|
|
|
if len(argv) != 4:
|
2017-12-07 19:33:00 +01:00
|
|
|
print(__doc__)
|
2011-10-29 02:02:30 +02:00
|
|
|
sys.exit(1)
|
|
|
|
|
2018-10-12 19:30:39 +02:00
|
|
|
common.InitLogging()
|
|
|
|
|
2011-10-29 02:02:30 +02:00
|
|
|
in_dir = argv[0]
|
|
|
|
glob_dict_file = argv[1]
|
|
|
|
out_file = argv[2]
|
2015-07-09 18:54:55 +02:00
|
|
|
target_out = argv[3]
|
2011-10-29 02:02:30 +02:00
|
|
|
|
|
|
|
glob_dict = LoadGlobalDict(glob_dict_file)
|
Support to configure and build multiple custom images.
Build additional images requested by the product makefile.
This script gives the ability to build multiple additional images and
you can configure what modules/files to include in each image.
1. Define PRODUCT_CUSTOM_IMAGE_MAKEFILES in your product makefile.
PRODUCT_CUSTOM_IMAGE_MAKEFILES is a list of makefiles.
Each makefile configures an image.
For image configuration makefile foo/bar/xyz.mk, the built image
file name
will be xyz.img. So make sure they won't conflict.
2. In each image's configuration makefile, you can define variables:
- CUSTOM_IMAGE_MOUNT_POINT, the mount point, such as "oem", "odm"
etc.
- CUSTOM_IMAGE_PARTITION_SIZE
- CUSTOM_IMAGE_FILE_SYSTEM_TYPE
- CUSTOM_IMAGE_DICT_FILE, a text file defining a dictionary
accepted by BuildImage() in tools/releasetools/build_image.py.
- CUSTOM_IMAGE_MODULES, a list of module names you want to include
in the image; Not only the module itself will be installed to proper
path in the image, you can also piggyback additional files/directories
with the module's LOCAL_PICKUP_FILES.
- CUSTOM_IMAGE_COPY_FILES, a list of "<src>:<dest>" to be copied to
the image. <dest> is relativ to the root of the image.
To build all those images, run "make custom_images".
Bug: 19609718
Change-Id: Ic73587e08503a251be27797c7b00329716051927
(cherry picked from commit 5fcf1094f9cf4d57c2598237f99621f254130d71)
2015-03-13 02:30:39 +01:00
|
|
|
if "mount_point" in glob_dict:
|
2018-10-19 22:44:36 +02:00
|
|
|
# The caller knows the mount point and provides a dictionary needed by
|
2015-06-23 20:16:05 +02:00
|
|
|
# BuildImage().
|
Support to configure and build multiple custom images.
Build additional images requested by the product makefile.
This script gives the ability to build multiple additional images and
you can configure what modules/files to include in each image.
1. Define PRODUCT_CUSTOM_IMAGE_MAKEFILES in your product makefile.
PRODUCT_CUSTOM_IMAGE_MAKEFILES is a list of makefiles.
Each makefile configures an image.
For image configuration makefile foo/bar/xyz.mk, the built image
file name
will be xyz.img. So make sure they won't conflict.
2. In each image's configuration makefile, you can define variables:
- CUSTOM_IMAGE_MOUNT_POINT, the mount point, such as "oem", "odm"
etc.
- CUSTOM_IMAGE_PARTITION_SIZE
- CUSTOM_IMAGE_FILE_SYSTEM_TYPE
- CUSTOM_IMAGE_DICT_FILE, a text file defining a dictionary
accepted by BuildImage() in tools/releasetools/build_image.py.
- CUSTOM_IMAGE_MODULES, a list of module names you want to include
in the image; Not only the module itself will be installed to proper
path in the image, you can also piggyback additional files/directories
with the module's LOCAL_PICKUP_FILES.
- CUSTOM_IMAGE_COPY_FILES, a list of "<src>:<dest>" to be copied to
the image. <dest> is relativ to the root of the image.
To build all those images, run "make custom_images".
Bug: 19609718
Change-Id: Ic73587e08503a251be27797c7b00329716051927
(cherry picked from commit 5fcf1094f9cf4d57c2598237f99621f254130d71)
2015-03-13 02:30:39 +01:00
|
|
|
image_properties = glob_dict
|
2011-11-04 19:37:01 +01:00
|
|
|
else:
|
Support to configure and build multiple custom images.
Build additional images requested by the product makefile.
This script gives the ability to build multiple additional images and
you can configure what modules/files to include in each image.
1. Define PRODUCT_CUSTOM_IMAGE_MAKEFILES in your product makefile.
PRODUCT_CUSTOM_IMAGE_MAKEFILES is a list of makefiles.
Each makefile configures an image.
For image configuration makefile foo/bar/xyz.mk, the built image
file name
will be xyz.img. So make sure they won't conflict.
2. In each image's configuration makefile, you can define variables:
- CUSTOM_IMAGE_MOUNT_POINT, the mount point, such as "oem", "odm"
etc.
- CUSTOM_IMAGE_PARTITION_SIZE
- CUSTOM_IMAGE_FILE_SYSTEM_TYPE
- CUSTOM_IMAGE_DICT_FILE, a text file defining a dictionary
accepted by BuildImage() in tools/releasetools/build_image.py.
- CUSTOM_IMAGE_MODULES, a list of module names you want to include
in the image; Not only the module itself will be installed to proper
path in the image, you can also piggyback additional files/directories
with the module's LOCAL_PICKUP_FILES.
- CUSTOM_IMAGE_COPY_FILES, a list of "<src>:<dest>" to be copied to
the image. <dest> is relativ to the root of the image.
To build all those images, run "make custom_images".
Bug: 19609718
Change-Id: Ic73587e08503a251be27797c7b00329716051927
(cherry picked from commit 5fcf1094f9cf4d57c2598237f99621f254130d71)
2015-03-13 02:30:39 +01:00
|
|
|
image_filename = os.path.basename(out_file)
|
|
|
|
mount_point = ""
|
|
|
|
if image_filename == "system.img":
|
|
|
|
mount_point = "system"
|
2016-06-16 23:47:10 +02:00
|
|
|
elif image_filename == "system_other.img":
|
|
|
|
mount_point = "system_other"
|
Support to configure and build multiple custom images.
Build additional images requested by the product makefile.
This script gives the ability to build multiple additional images and
you can configure what modules/files to include in each image.
1. Define PRODUCT_CUSTOM_IMAGE_MAKEFILES in your product makefile.
PRODUCT_CUSTOM_IMAGE_MAKEFILES is a list of makefiles.
Each makefile configures an image.
For image configuration makefile foo/bar/xyz.mk, the built image
file name
will be xyz.img. So make sure they won't conflict.
2. In each image's configuration makefile, you can define variables:
- CUSTOM_IMAGE_MOUNT_POINT, the mount point, such as "oem", "odm"
etc.
- CUSTOM_IMAGE_PARTITION_SIZE
- CUSTOM_IMAGE_FILE_SYSTEM_TYPE
- CUSTOM_IMAGE_DICT_FILE, a text file defining a dictionary
accepted by BuildImage() in tools/releasetools/build_image.py.
- CUSTOM_IMAGE_MODULES, a list of module names you want to include
in the image; Not only the module itself will be installed to proper
path in the image, you can also piggyback additional files/directories
with the module's LOCAL_PICKUP_FILES.
- CUSTOM_IMAGE_COPY_FILES, a list of "<src>:<dest>" to be copied to
the image. <dest> is relativ to the root of the image.
To build all those images, run "make custom_images".
Bug: 19609718
Change-Id: Ic73587e08503a251be27797c7b00329716051927
(cherry picked from commit 5fcf1094f9cf4d57c2598237f99621f254130d71)
2015-03-13 02:30:39 +01:00
|
|
|
elif image_filename == "userdata.img":
|
|
|
|
mount_point = "data"
|
|
|
|
elif image_filename == "cache.img":
|
|
|
|
mount_point = "cache"
|
|
|
|
elif image_filename == "vendor.img":
|
|
|
|
mount_point = "vendor"
|
2017-11-14 16:42:30 +01:00
|
|
|
elif image_filename == "odm.img":
|
|
|
|
mount_point = "odm"
|
Support to configure and build multiple custom images.
Build additional images requested by the product makefile.
This script gives the ability to build multiple additional images and
you can configure what modules/files to include in each image.
1. Define PRODUCT_CUSTOM_IMAGE_MAKEFILES in your product makefile.
PRODUCT_CUSTOM_IMAGE_MAKEFILES is a list of makefiles.
Each makefile configures an image.
For image configuration makefile foo/bar/xyz.mk, the built image
file name
will be xyz.img. So make sure they won't conflict.
2. In each image's configuration makefile, you can define variables:
- CUSTOM_IMAGE_MOUNT_POINT, the mount point, such as "oem", "odm"
etc.
- CUSTOM_IMAGE_PARTITION_SIZE
- CUSTOM_IMAGE_FILE_SYSTEM_TYPE
- CUSTOM_IMAGE_DICT_FILE, a text file defining a dictionary
accepted by BuildImage() in tools/releasetools/build_image.py.
- CUSTOM_IMAGE_MODULES, a list of module names you want to include
in the image; Not only the module itself will be installed to proper
path in the image, you can also piggyback additional files/directories
with the module's LOCAL_PICKUP_FILES.
- CUSTOM_IMAGE_COPY_FILES, a list of "<src>:<dest>" to be copied to
the image. <dest> is relativ to the root of the image.
To build all those images, run "make custom_images".
Bug: 19609718
Change-Id: Ic73587e08503a251be27797c7b00329716051927
(cherry picked from commit 5fcf1094f9cf4d57c2598237f99621f254130d71)
2015-03-13 02:30:39 +01:00
|
|
|
elif image_filename == "oem.img":
|
|
|
|
mount_point = "oem"
|
2017-11-27 09:04:47 +01:00
|
|
|
elif image_filename == "product.img":
|
|
|
|
mount_point = "product"
|
2019-06-25 08:58:13 +02:00
|
|
|
elif image_filename == "system_ext.img":
|
|
|
|
mount_point = "system_ext"
|
Support to configure and build multiple custom images.
Build additional images requested by the product makefile.
This script gives the ability to build multiple additional images and
you can configure what modules/files to include in each image.
1. Define PRODUCT_CUSTOM_IMAGE_MAKEFILES in your product makefile.
PRODUCT_CUSTOM_IMAGE_MAKEFILES is a list of makefiles.
Each makefile configures an image.
For image configuration makefile foo/bar/xyz.mk, the built image
file name
will be xyz.img. So make sure they won't conflict.
2. In each image's configuration makefile, you can define variables:
- CUSTOM_IMAGE_MOUNT_POINT, the mount point, such as "oem", "odm"
etc.
- CUSTOM_IMAGE_PARTITION_SIZE
- CUSTOM_IMAGE_FILE_SYSTEM_TYPE
- CUSTOM_IMAGE_DICT_FILE, a text file defining a dictionary
accepted by BuildImage() in tools/releasetools/build_image.py.
- CUSTOM_IMAGE_MODULES, a list of module names you want to include
in the image; Not only the module itself will be installed to proper
path in the image, you can also piggyback additional files/directories
with the module's LOCAL_PICKUP_FILES.
- CUSTOM_IMAGE_COPY_FILES, a list of "<src>:<dest>" to be copied to
the image. <dest> is relativ to the root of the image.
To build all those images, run "make custom_images".
Bug: 19609718
Change-Id: Ic73587e08503a251be27797c7b00329716051927
(cherry picked from commit 5fcf1094f9cf4d57c2598237f99621f254130d71)
2015-03-13 02:30:39 +01:00
|
|
|
else:
|
2018-10-12 19:30:39 +02:00
|
|
|
logger.error("Unknown image file name %s", image_filename)
|
2017-12-25 19:43:47 +01:00
|
|
|
sys.exit(1)
|
Support to configure and build multiple custom images.
Build additional images requested by the product makefile.
This script gives the ability to build multiple additional images and
you can configure what modules/files to include in each image.
1. Define PRODUCT_CUSTOM_IMAGE_MAKEFILES in your product makefile.
PRODUCT_CUSTOM_IMAGE_MAKEFILES is a list of makefiles.
Each makefile configures an image.
For image configuration makefile foo/bar/xyz.mk, the built image
file name
will be xyz.img. So make sure they won't conflict.
2. In each image's configuration makefile, you can define variables:
- CUSTOM_IMAGE_MOUNT_POINT, the mount point, such as "oem", "odm"
etc.
- CUSTOM_IMAGE_PARTITION_SIZE
- CUSTOM_IMAGE_FILE_SYSTEM_TYPE
- CUSTOM_IMAGE_DICT_FILE, a text file defining a dictionary
accepted by BuildImage() in tools/releasetools/build_image.py.
- CUSTOM_IMAGE_MODULES, a list of module names you want to include
in the image; Not only the module itself will be installed to proper
path in the image, you can also piggyback additional files/directories
with the module's LOCAL_PICKUP_FILES.
- CUSTOM_IMAGE_COPY_FILES, a list of "<src>:<dest>" to be copied to
the image. <dest> is relativ to the root of the image.
To build all those images, run "make custom_images".
Bug: 19609718
Change-Id: Ic73587e08503a251be27797c7b00329716051927
(cherry picked from commit 5fcf1094f9cf4d57c2598237f99621f254130d71)
2015-03-13 02:30:39 +01:00
|
|
|
|
|
|
|
image_properties = ImagePropFromGlobalDict(glob_dict, mount_point)
|
2011-10-29 02:02:30 +02:00
|
|
|
|
2018-09-28 01:58:00 +02:00
|
|
|
try:
|
|
|
|
BuildImage(in_dir, image_properties, out_file, target_out)
|
|
|
|
except:
|
2018-10-12 19:30:39 +02:00
|
|
|
logger.error("Failed to build %s from %s", out_file, in_dir)
|
2018-09-28 01:58:00 +02:00
|
|
|
raise
|
2011-10-29 02:02:30 +02:00
|
|
|
|
2018-10-12 19:30:39 +02:00
|
|
|
|
2011-10-29 02:02:30 +02:00
|
|
|
if __name__ == '__main__':
|
2017-12-25 19:43:47 +01:00
|
|
|
try:
|
|
|
|
main(sys.argv[1:])
|
|
|
|
finally:
|
|
|
|
common.Cleanup()
|