Merge "releasetools: Fix an issue in image size computation."
This commit is contained in:
@@ -425,6 +425,52 @@ def ConvertBlockMapToBaseFs(block_map_file):
|
||||
return base_fs_file if exit_code == 0 else None
|
||||
|
||||
|
||||
def SetUpInDirAndFsConfig(origin_in, prop_dict):
|
||||
"""Returns the in_dir and fs_config that should be used for image building.
|
||||
|
||||
If the target uses system_root_image and it's building system.img, it creates
|
||||
and returns a staged dir that combines the contents of /system (i.e. in the
|
||||
given in_dir) and root.
|
||||
|
||||
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")
|
||||
if (prop_dict.get("system_root_image") != "true" or
|
||||
prop_dict["mount_point"] != "system"):
|
||||
return origin_in, fs_config
|
||||
|
||||
# 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
|
||||
return in_dir, fs_config
|
||||
|
||||
|
||||
def CheckHeadroom(ext4fs_output, prop_dict):
|
||||
"""Checks if there's enough headroom space available.
|
||||
|
||||
@@ -468,40 +514,25 @@ def CheckHeadroom(ext4fs_output, prop_dict):
|
||||
|
||||
|
||||
def BuildImage(in_dir, prop_dict, out_file, target_out=None):
|
||||
"""Build an image to out_file from in_dir with property prop_dict.
|
||||
After the function call, values in prop_dict is updated with
|
||||
computed values.
|
||||
"""Builds an image for the files under in_dir and writes it to out_file.
|
||||
|
||||
When using system_root_image, it will additionally look for the files under
|
||||
root (specified by 'root_dir') and builds an image that contains both sources.
|
||||
|
||||
Args:
|
||||
in_dir: path of input directory.
|
||||
prop_dict: property dictionary.
|
||||
out_file: path of the output image file.
|
||||
target_out: path of the product out directory to read device specific FS
|
||||
config files.
|
||||
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.
|
||||
|
||||
Returns:
|
||||
True iff the image is built successfully.
|
||||
"""
|
||||
# system_root_image=true: build a system.img that combines the contents of
|
||||
# /system and root, which should 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 = common.MakeTempDir()
|
||||
# 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
|
||||
in_dir, fs_config = SetUpInDirAndFsConfig(in_dir, prop_dict)
|
||||
|
||||
build_command = []
|
||||
fs_type = prop_dict.get("fs_type", "")
|
||||
@@ -518,11 +549,11 @@ def BuildImage(in_dir, prop_dict, out_file, target_out=None):
|
||||
if (prop_dict.get("use_logical_partitions") == "true" and
|
||||
"partition_size" not in prop_dict):
|
||||
# if partition_size is not defined, use output of `du' + reserved_size
|
||||
success, size = GetDiskUsage(origin_in)
|
||||
success, size = GetDiskUsage(in_dir)
|
||||
if not success:
|
||||
return False
|
||||
if OPTIONS.verbose:
|
||||
print("The tree size of %s is %d MB." % (origin_in, size // BYTES_IN_MB))
|
||||
print("The tree size of %s is %d MB." % (in_dir, size // BYTES_IN_MB))
|
||||
size += int(prop_dict.get("partition_reserved_size", 0))
|
||||
# Round this up to a multiple of 4K so that avbtool works
|
||||
size = common.RoundUpTo4K(size)
|
||||
@@ -643,27 +674,17 @@ def BuildImage(in_dir, prop_dict, out_file, target_out=None):
|
||||
print("Error: unknown filesystem type '%s'" % (fs_type))
|
||||
return False
|
||||
|
||||
if in_dir != origin_in:
|
||||
# Construct a staging directory of the root file system.
|
||||
root_dir = prop_dict.get("root_dir")
|
||||
if root_dir:
|
||||
shutil.rmtree(in_dir)
|
||||
shutil.copytree(root_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)
|
||||
|
||||
(mkfs_output, exit_code) = RunCommand(build_command)
|
||||
if exit_code != 0:
|
||||
print("Error: '%s' failed with exit code %d:\n%s" % (
|
||||
build_command, exit_code, mkfs_output))
|
||||
success, du = GetDiskUsage(origin_in)
|
||||
success, du = GetDiskUsage(in_dir)
|
||||
du_str = ("%d bytes (%d MB)" % (du, du // BYTES_IN_MB)
|
||||
) if success else "unknown"
|
||||
print(
|
||||
"Out of space? The tree size of {} is {}, with reserved space of {} "
|
||||
"bytes ({} MB).".format(
|
||||
origin_in, du_str,
|
||||
in_dir, du_str,
|
||||
int(prop_dict.get("partition_reserved_size", 0)),
|
||||
int(prop_dict.get("partition_reserved_size", 0)) // BYTES_IN_MB))
|
||||
if "original_partition_size" in prop_dict:
|
||||
|
@@ -14,10 +14,12 @@
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
import filecmp
|
||||
import os.path
|
||||
import unittest
|
||||
|
||||
import common
|
||||
from build_image import CheckHeadroom, RunCommand
|
||||
from build_image import CheckHeadroom, RunCommand, SetUpInDirAndFsConfig
|
||||
|
||||
|
||||
class BuildImageTest(unittest.TestCase):
|
||||
@@ -26,6 +28,9 @@ class BuildImageTest(unittest.TestCase):
|
||||
EXT4FS_OUTPUT = (
|
||||
"Created filesystem with 2777/129024 inodes and 515099/516099 blocks")
|
||||
|
||||
def tearDown(self):
|
||||
common.Cleanup()
|
||||
|
||||
def test_CheckHeadroom_SizeUnderLimit(self):
|
||||
# Required headroom: 1000 blocks.
|
||||
prop_dict = {
|
||||
@@ -91,4 +96,95 @@ class BuildImageTest(unittest.TestCase):
|
||||
}
|
||||
self.assertFalse(CheckHeadroom(ext4fs_output, prop_dict))
|
||||
|
||||
common.Cleanup()
|
||||
def test_SetUpInDirAndFsConfig_SystemRootImageFalse(self):
|
||||
prop_dict = {
|
||||
'fs_config': 'fs-config',
|
||||
'mount_point': 'system',
|
||||
}
|
||||
in_dir, fs_config = SetUpInDirAndFsConfig('/path/to/in_dir', prop_dict)
|
||||
self.assertEqual('/path/to/in_dir', in_dir)
|
||||
self.assertEqual('fs-config', fs_config)
|
||||
self.assertEqual('system', prop_dict['mount_point'])
|
||||
|
||||
def test_SetUpInDirAndFsConfig_SystemRootImageTrue_NonSystem(self):
|
||||
prop_dict = {
|
||||
'fs_config': 'fs-config',
|
||||
'mount_point': 'vendor',
|
||||
'system_root_image': 'true',
|
||||
}
|
||||
in_dir, fs_config = SetUpInDirAndFsConfig('/path/to/in_dir', prop_dict)
|
||||
self.assertEqual('/path/to/in_dir', in_dir)
|
||||
self.assertEqual('fs-config', fs_config)
|
||||
self.assertEqual('vendor', prop_dict['mount_point'])
|
||||
|
||||
@staticmethod
|
||||
def _gen_fs_config(partition):
|
||||
fs_config = common.MakeTempFile(suffix='.txt')
|
||||
with open(fs_config, 'w') as fs_config_fp:
|
||||
fs_config_fp.write('fs-config-{}\n'.format(partition))
|
||||
return fs_config
|
||||
|
||||
def test_SetUpInDirAndFsConfig_SystemRootImageTrue(self):
|
||||
root_dir = common.MakeTempDir()
|
||||
with open(os.path.join(root_dir, 'init'), 'w') as init_fp:
|
||||
init_fp.write('init')
|
||||
|
||||
origin_in = common.MakeTempDir()
|
||||
with open(os.path.join(origin_in, 'file'), 'w') as in_fp:
|
||||
in_fp.write('system-file')
|
||||
os.symlink('../etc', os.path.join(origin_in, 'symlink'))
|
||||
|
||||
fs_config_system = self._gen_fs_config('system')
|
||||
|
||||
prop_dict = {
|
||||
'fs_config': fs_config_system,
|
||||
'mount_point': 'system',
|
||||
'root_dir': root_dir,
|
||||
'system_root_image': 'true',
|
||||
}
|
||||
in_dir, fs_config = SetUpInDirAndFsConfig(origin_in, prop_dict)
|
||||
|
||||
self.assertTrue(filecmp.cmp(
|
||||
os.path.join(in_dir, 'init'), os.path.join(root_dir, 'init')))
|
||||
self.assertTrue(filecmp.cmp(
|
||||
os.path.join(in_dir, 'system', 'file'),
|
||||
os.path.join(origin_in, 'file')))
|
||||
self.assertTrue(os.path.islink(os.path.join(in_dir, 'system', 'symlink')))
|
||||
|
||||
self.assertTrue(filecmp.cmp(fs_config_system, fs_config))
|
||||
self.assertEqual('/', prop_dict['mount_point'])
|
||||
|
||||
def test_SetUpInDirAndFsConfig_SystemRootImageTrue_WithRootFsConfig(self):
|
||||
root_dir = common.MakeTempDir()
|
||||
with open(os.path.join(root_dir, 'init'), 'w') as init_fp:
|
||||
init_fp.write('init')
|
||||
|
||||
origin_in = common.MakeTempDir()
|
||||
with open(os.path.join(origin_in, 'file'), 'w') as in_fp:
|
||||
in_fp.write('system-file')
|
||||
os.symlink('../etc', os.path.join(origin_in, 'symlink'))
|
||||
|
||||
fs_config_system = self._gen_fs_config('system')
|
||||
fs_config_root = self._gen_fs_config('root')
|
||||
|
||||
prop_dict = {
|
||||
'fs_config': fs_config_system,
|
||||
'mount_point': 'system',
|
||||
'root_dir': root_dir,
|
||||
'root_fs_config': fs_config_root,
|
||||
'system_root_image': 'true',
|
||||
}
|
||||
in_dir, fs_config = SetUpInDirAndFsConfig(origin_in, prop_dict)
|
||||
|
||||
self.assertTrue(filecmp.cmp(
|
||||
os.path.join(in_dir, 'init'), os.path.join(root_dir, 'init')))
|
||||
self.assertTrue(filecmp.cmp(
|
||||
os.path.join(in_dir, 'system', 'file'),
|
||||
os.path.join(origin_in, 'file')))
|
||||
self.assertTrue(os.path.islink(os.path.join(in_dir, 'system', 'symlink')))
|
||||
|
||||
with open(fs_config) as fs_config_fp:
|
||||
fs_config_data = fs_config_fp.readlines()
|
||||
self.assertIn('fs-config-system\n', fs_config_data)
|
||||
self.assertIn('fs-config-root\n', fs_config_data)
|
||||
self.assertEqual('/', prop_dict['mount_point'])
|
||||
|
Reference in New Issue
Block a user