Merge "Revert "Revert^2: Change command-line flags of hiddenapi""
diff --git a/Changes.md b/Changes.md
index 4aa7ea2..2d5cd97 100644
--- a/Changes.md
+++ b/Changes.md
@@ -1,5 +1,22 @@
# Build System Changes for Android.mk Writers
+## `BUILD_NUMBER` removal from Android.mk {#BUILD_NUMBER}
+
+`BUILD_NUMBER` should not be used directly in Android.mk files, as it would
+trigger them to be re-read every time the `BUILD_NUMBER` changes (which it does
+on every build server build). If possible, just remove the use so that your
+builds are more reproducible. If you do need it, use `BUILD_NUMBER_FROM_FILE`:
+
+``` make
+$(LOCAL_BUILT_MODULE):
+ mytool --build_number $(BUILD_NUMBER_FROM_FILE) -o $@
+```
+
+That will expand out to a subshell that will read the current `BUILD_NUMBER`
+whenever it's run. It will not re-run your command if the build number has
+changed, so incremental builds will have the build number from the last time
+the particular output was rebuilt.
+
## `DIST_DIR`, `dist_goal`, and `dist-for-goals` {#dist}
`DIST_DIR` and `dist_goal` are no longer available when reading Android.mk
diff --git a/core/Makefile b/core/Makefile
index c21c517..9dbf6e4 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -1206,7 +1206,7 @@
ifeq ($(INTERNAL_USERIMAGES_USE_EXT),true)
INTERNAL_USERIMAGES_DEPS := $(SIMG2IMG)
-INTERNAL_USERIMAGES_DEPS += $(MKEXTUSERIMG) $(MAKE_EXT4FS) $(E2FSCK)
+INTERNAL_USERIMAGES_DEPS += $(MKEXTUSERIMG) $(MAKE_EXT4FS) $(E2FSCK) $(TUNE2FS)
ifeq ($(TARGET_USERIMAGES_USE_F2FS),true)
INTERNAL_USERIMAGES_DEPS += $(MKF2FSUSERIMG) $(MAKE_F2FS)
endif
@@ -3099,6 +3099,7 @@
$(HOST_OUT_EXECUTABLES)/mke2fs \
$(HOST_OUT_EXECUTABLES)/mkuserimg_mke2fs \
$(HOST_OUT_EXECUTABLES)/e2fsdroid \
+ $(HOST_OUT_EXECUTABLES)/tune2fs \
$(HOST_OUT_EXECUTABLES)/mksquashfsimage.sh \
$(HOST_OUT_EXECUTABLES)/mksquashfs \
$(HOST_OUT_EXECUTABLES)/mkf2fsuserimg.sh \
diff --git a/core/android_manifest.mk b/core/android_manifest.mk
index 8608ca1..c3af942 100644
--- a/core/android_manifest.mk
+++ b/core/android_manifest.mk
@@ -71,6 +71,11 @@
ifeq ($(LOCAL_PRIVATE_PLATFORM_APIS),true)
my_manifest_fixer_flags += --uses-non-sdk-api
endif
+
+ifeq (true,$(LOCAL_PREFER_INTEGRITY))
+ my_manifest_fixer_flags += --prefer-integrity
+endif
+
$(fixed_android_manifest): PRIVATE_MANIFEST_FIXER_FLAGS := $(my_manifest_fixer_flags)
# These two libs are added as optional dependencies (<uses-library> with
# android:required set to false). This is because they haven't existed in pre-P
diff --git a/core/clear_vars.mk b/core/clear_vars.mk
index 07e34e1..7f8e9c3 100644
--- a/core/clear_vars.mk
+++ b/core/clear_vars.mk
@@ -213,6 +213,7 @@
LOCAL_PREBUILT_OBJ_FILES:=
LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES:=
LOCAL_PREBUILT_STRIP_COMMENTS:=
+LOCAL_PREFER_INTEGRITY:=
LOCAL_PRESUBMIT_DISABLED:=
LOCAL_PRIVATE_PLATFORM_APIS:=
LOCAL_PRIVILEGED_MODULE:=
@@ -274,6 +275,7 @@
LOCAL_STATIC_JAVA_AAR_LIBRARIES:=
LOCAL_STATIC_JAVA_LIBRARIES:=
LOCAL_STATIC_LIBRARIES:=
+LOCAL_STRIP_DEX:=
LOCAL_STRIP_MODULE:=
LOCAL_SYSTEM_SHARED_LIBRARIES:=none
LOCAL_TARGET_REQUIRED_MODULES:=
@@ -284,6 +286,7 @@
LOCAL_TIDY:=
LOCAL_TIDY_CHECKS:=
LOCAL_TIDY_FLAGS:=
+LOCAL_UNCOMPRESS_DEX:=
LOCAL_UNINSTALLABLE_MODULE:=
LOCAL_UNSTRIPPED_PATH:=
LOCAL_USE_AAPT2:=$(USE_AAPT2)
diff --git a/core/definitions.mk b/core/definitions.mk
index baa2342..c9df700 100644
--- a/core/definitions.mk
+++ b/core/definitions.mk
@@ -2640,12 +2640,12 @@
# Copy an apk to a target location while removing classes*.dex
# $(1): source file
# $(2): destination file
-# $(3): LOCAL_DEX_PREOPT, if nostripping then leave classes*.dex
+# $(3): LOCAL_STRIP_DEX, if non-empty then strip classes*.dex
define dexpreopt-copy-jar
$(2): $(1)
@echo "Copy: $$@"
$$(copy-file-to-target)
- $(if $(filter nostripping,$(3)),,$$(call dexpreopt-remove-classes.dex,$$@))
+ $(if $(3),$$(call dexpreopt-remove-classes.dex,$$@))
endef
# $(1): the .jar or .apk to remove classes.dex. Note that if all dex files
diff --git a/core/dex_preopt.mk b/core/dex_preopt.mk
index 1527047..92ed970 100644
--- a/core/dex_preopt.mk
+++ b/core/dex_preopt.mk
@@ -73,7 +73,7 @@
_dbj_jar_no_dex := $(DEXPREOPT_BOOT_JAR_DIR_FULL_PATH)/$(1)_nodex.jar
_dbj_src_jar := $(call intermediates-dir-for,JAVA_LIBRARIES,$(1),,COMMON)/javalib.jar
-$(call dexpreopt-copy-jar,$$(_dbj_src_jar),$$(_dbj_jar_no_dex),$(DEX_PREOPT_DEFAULT))
+$(call dexpreopt-copy-jar,$$(_dbj_src_jar),$$(_dbj_jar_no_dex),$(filter-out nostripping,$(DEX_PREOPT_DEFAULT)))
_dbj_jar_no_dex :=
_dbj_src_jar :=
diff --git a/core/dex_preopt_odex_install.mk b/core/dex_preopt_odex_install.mk
index cd78eda..6a892e2 100644
--- a/core/dex_preopt_odex_install.mk
+++ b/core/dex_preopt_odex_install.mk
@@ -3,9 +3,14 @@
# Output variables: LOCAL_DEX_PREOPT, LOCAL_UNCOMPRESS_DEX, built_odex,
# dexpreopt_boot_jar_module
+ifeq (true,$(LOCAL_PREFER_INTEGRITY))
+ LOCAL_UNCOMPRESS_DEX := true
+else
+ LOCAL_UNCOMPRESS_DEX :=
+endif
+
# We explicitly uncompress APKs of privileged apps, and used by
# privileged apps
-LOCAL_UNCOMPRESS_DEX := false
ifneq (true,$(DONT_UNCOMPRESS_PRIV_APPS_DEXS))
ifeq (true,$(LOCAL_PRIVILEGED_MODULE))
LOCAL_UNCOMPRESS_DEX := true
@@ -33,6 +38,13 @@
endif
endif
+ifeq (nostripping,$(LOCAL_DEX_PREOPT))
+ LOCAL_DEX_PREOPT := true
+ LOCAL_STRIP_DEX :=
+else
+ LOCAL_STRIP_DEX := true
+endif
+
ifeq (false,$(LOCAL_DEX_PREOPT))
LOCAL_DEX_PREOPT :=
endif
@@ -43,7 +55,7 @@
endif
# If we have product-specific config for this module?
-ifeq (disable,$(DEXPREOPT.$(TARGET_PRODUCT).$(LOCAL_MODULE).CONFIG))
+ifneq (,$(filter $(LOCAL_MODULE),$(DEXPREOPT_DISABLED_MODULES)))
LOCAL_DEX_PREOPT :=
endif
@@ -81,14 +93,14 @@
ifeq ($(LOCAL_DEX_PREOPT),true)
# Don't strip with dexes we explicitly uncompress (dexopt will not store the dex code).
ifeq ($(LOCAL_UNCOMPRESS_DEX),true)
- LOCAL_DEX_PREOPT := nostripping
+ LOCAL_STRIP_DEX :=
endif # LOCAL_UNCOMPRESS_DEX
# system_other isn't there for an OTA, so don't strip
# if module is on system, and odex is on system_other.
ifeq ($(BOARD_USES_SYSTEM_OTHER_ODEX),true)
ifneq ($(call install-on-system-other, $(my_module_path)),)
- LOCAL_DEX_PREOPT := nostripping
+ LOCAL_STRIP_DEX :=
endif # install-on-system-other
endif # BOARD_USES_SYSTEM_OTHER_ODEX
@@ -320,7 +332,8 @@
ifeq (true,$(my_generate_dm))
LOCAL_DEX_PREOPT_FLAGS += --copy-dex-files=false
- LOCAL_DEX_PREOPT := nostripping
+ LOCAL_DEX_PREOPT := true
+ LOCAL_STRIP_DEX :=
my_built_dm := $(dir $(LOCAL_BUILT_MODULE))generated.dm
my_installed_dm := $(patsubst %.apk,%,$(LOCAL_INSTALLED_MODULE)).dm
my_copied_vdex := $(dir $(LOCAL_BUILT_MODULE))primary.vdex
diff --git a/core/java_library.mk b/core/java_library.mk
index 5716f4c..e4e51d8 100644
--- a/core/java_library.mk
+++ b/core/java_library.mk
@@ -96,7 +96,7 @@
@echo "Dexpreopt Jar: $(PRIVATE_MODULE) ($@)"
$(call dexpreopt-one-file,$<,$@)
-$(eval $(call dexpreopt-copy-jar,$(common_javalib.jar),$(LOCAL_BUILT_MODULE),$(LOCAL_DEX_PREOPT)))
+$(eval $(call dexpreopt-copy-jar,$(common_javalib.jar),$(LOCAL_BUILT_MODULE),$(LOCAL_STRIP_DEX)))
endif # ! boot jar
diff --git a/core/main.mk b/core/main.mk
index 6ff5f93..461c3b4 100644
--- a/core/main.mk
+++ b/core/main.mk
@@ -66,12 +66,15 @@
$(shell mkdir -p $(OUT_DIR) && \
echo -n $(BUILD_NUMBER) > $(OUT_DIR)/build_number.txt)
BUILD_NUMBER_FILE := $(OUT_DIR)/build_number.txt
+.KATI_READONLY := BUILD_NUMBER_FILE
+$(KATI_obsolete_var BUILD_NUMBER,See https://android.googlesource.com/platform/build/+/master/Changes.md#BUILD_NUMBER)
ifeq ($(HOST_OS),darwin)
DATE_FROM_FILE := date -r $(BUILD_DATETIME_FROM_FILE)
else
DATE_FROM_FILE := date -d @$(BUILD_DATETIME_FROM_FILE)
endif
+.KATI_READONLY := DATE_FROM_FILE
# Pick a reasonable string to use to identify files.
ifeq ($(strip $(HAS_BUILD_NUMBER)),false)
@@ -81,6 +84,7 @@
else
FILE_NAME_TAG := $(file <$(BUILD_NUMBER_FILE))
endif
+.KATI_READONLY := FILE_NAME_TAG
# Make an empty directory, which can be used to make empty jars
EMPTY_DIRECTORY := $(OUT_DIR)/empty
diff --git a/core/package_internal.mk b/core/package_internal.mk
index 84d1c2c..9a52af7 100644
--- a/core/package_internal.mk
+++ b/core/package_internal.mk
@@ -665,7 +665,7 @@
@# Keep a copy of apk with classes.dex unstripped
$(hide) cp -f $@ $(dir $@)package.dex.apk
endif # BUILD_PLATFORM_ZIP
-ifneq (nostripping,$(LOCAL_DEX_PREOPT))
+ifdef LOCAL_STRIP_DEX
$(call dexpreopt-remove-classes.dex,$@)
endif
endif # LOCAL_DEX_PREOPT
diff --git a/core/prebuilt_internal.mk b/core/prebuilt_internal.mk
index 809c572..a4b58fc 100644
--- a/core/prebuilt_internal.mk
+++ b/core/prebuilt_internal.mk
@@ -380,9 +380,9 @@
$(run-appcompat)
endif # module_run_appcompat
ifdef LOCAL_DEX_PREOPT
-ifneq (nostripping,$(LOCAL_DEX_PREOPT))
+ifdef LOCAL_STRIP_DEX
$(call dexpreopt-remove-classes.dex,$@)
-endif # LOCAL_DEX_PREOPT != nostripping
+endif # LOCAL_STRIP_DEX
endif # LOCAL_DEX_PREOPT
$(sign-package)
# No need for align-package because sign-package takes care of alignment
@@ -400,7 +400,7 @@
# can do optimizations based on whether the built module only
# contains uncompressed dex code.
ifdef LOCAL_DEX_PREOPT
-ifeq (nostripping,$(LOCAL_DEX_PREOPT))
+ifndef LOCAL_STRIP_DEX
$(built_odex) : $(built_module)
$(call dexpreopt-one-file,$<,$@)
else
@@ -470,7 +470,7 @@
@echo "Dexpreopt Jar: $(PRIVATE_MODULE) ($@)"
$(call dexpreopt-one-file,$<,$@)
-$(eval $(call dexpreopt-copy-jar,$(my_prebuilt_src_file),$(built_module),$(LOCAL_DEX_PREOPT)))
+$(eval $(call dexpreopt-copy-jar,$(my_prebuilt_src_file),$(built_module),$(LOCAL_STRIP_DEX)))
endif # boot jar
else # ! LOCAL_DEX_PREOPT
$(built_module) : $(my_prebuilt_src_file)
diff --git a/core/product_config.mk b/core/product_config.mk
index 27af09e..577bafe 100644
--- a/core/product_config.mk
+++ b/core/product_config.mk
@@ -423,6 +423,7 @@
# Resolve and setup per-module dex-preopt configs.
PRODUCT_DEX_PREOPT_MODULE_CONFIGS := \
$(strip $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_DEX_PREOPT_MODULE_CONFIGS))
+DEXPREOPT_DISABLED_MODULES :=
# If a module has multiple setups, the first takes precedence.
_pdpmc_modules :=
$(foreach c,$(PRODUCT_DEX_PREOPT_MODULE_CONFIGS),\
@@ -431,7 +432,9 @@
$(eval _pdpmc_modules += $(m))\
$(eval cf := $(patsubst $(m)=%,%,$(c)))\
$(eval cf := $(subst $(_PDPMC_SP_PLACE_HOLDER),$(space),$(cf)))\
- $(eval DEXPREOPT.$(TARGET_PRODUCT).$(m).CONFIG := $(cf))))
+ $(if $(filter disable,$(cf)),\
+ $(eval DEXPREOPT_DISABLED_MODULES += $(m)),\
+ $(eval DEXPREOPT.$(TARGET_PRODUCT).$(m).CONFIG := $(cf)))))
_pdpmc_modules :=
# Resolve and setup per-module sanitizer configs.
diff --git a/core/soong_app_prebuilt.mk b/core/soong_app_prebuilt.mk
index d34f367..31cb28e 100644
--- a/core/soong_app_prebuilt.mk
+++ b/core/soong_app_prebuilt.mk
@@ -69,7 +69,7 @@
ifdef LOCAL_DEX_PREOPT
$(built_odex): $(LOCAL_SOONG_DEX_JAR)
$(call dexpreopt-one-file,$<,$@)
- $(eval $(call dexpreopt-copy-jar,$(LOCAL_PREBUILT_MODULE_FILE),$(LOCAL_BUILT_MODULE),$(LOCAL_DEX_PREOPT)))
+ $(eval $(call dexpreopt-copy-jar,$(LOCAL_PREBUILT_MODULE_FILE),$(LOCAL_BUILT_MODULE),$(LOCAL_STRIP_DEX)))
else
$(eval $(call copy-one-file,$(LOCAL_PREBUILT_MODULE_FILE),$(LOCAL_BUILT_MODULE)))
endif
diff --git a/core/soong_config.mk b/core/soong_config.mk
index 2f978fa..7a884e0 100644
--- a/core/soong_config.mk
+++ b/core/soong_config.mk
@@ -123,6 +123,11 @@
$(call add_json_list, Platform_systemsdk_versions, $(PLATFORM_SYSTEMSDK_VERSIONS))
$(call add_json_bool, Malloc_not_svelte, $(call invert_bool,$(filter true,$(MALLOC_SVELTE))))
$(call add_json_str, Override_rs_driver, $(OVERRIDE_RS_DRIVER))
+$(call add_json_bool, UncompressPrivAppDex, $(call invert_bool,$(filter true,$(DONT_UNCOMPRESS_PRIV_APPS_DEXS))))
+$(call add_json_list, ModulesLoadedByPrivilegedModules, $(PRODUCT_LOADED_BY_PRIVILEGED_MODULES))
+$(call add_json_bool, DefaultStripDex, $(call invert_bool,$(filter nostripping,$(DEX_PREOPT_DEFAULT))))
+$(call add_json_bool, DisableDexPreopt, $(filter false,$(WITH_DEXPREOPT)))
+$(call add_json_list, DisableDexPreoptModules, $(DEXPREOPT_DISABLED_MODULES))
$(call add_json_bool, Product_is_iot, $(filter true,$(PRODUCT_IOT)))
diff --git a/core/soong_java_prebuilt.mk b/core/soong_java_prebuilt.mk
index 20bfc66..288a763 100644
--- a/core/soong_java_prebuilt.mk
+++ b/core/soong_java_prebuilt.mk
@@ -108,7 +108,7 @@
@echo "Dexpreopt Jar: $(PRIVATE_MODULE) ($@)"
$(call dexpreopt-one-file,$<,$@)
- $(eval $(call dexpreopt-copy-jar,$(common_javalib.jar),$(LOCAL_BUILT_MODULE),$(LOCAL_DEX_PREOPT)))
+ $(eval $(call dexpreopt-copy-jar,$(common_javalib.jar),$(LOCAL_BUILT_MODULE),$(LOCAL_STRIP_DEX)))
endif # ! boot jar
else # LOCAL_DEX_PREOPT
$(eval $(call copy-one-file,$(common_javalib.jar),$(LOCAL_BUILT_MODULE)))
diff --git a/tools/releasetools/build_image.py b/tools/releasetools/build_image.py
index 4a013c2..b88171f 100755
--- a/tools/releasetools/build_image.py
+++ b/tools/releasetools/build_image.py
@@ -54,23 +54,53 @@
"""Returns the number of bytes that "path" occupies on host.
Args:
- path: The directory or file to calculate size on
+ path: The directory or file to calculate size on.
Returns:
- The number of bytes.
-
- Raises:
- BuildImageError: On error.
+ The number of bytes based on a 1K block_size.
"""
- env_copy = os.environ.copy()
- env_copy["POSIXLY_CORRECT"] = "1"
- cmd = ["du", "-s", path]
+ cmd = ["du", "-k", "-s", path]
+ output = common.RunAndCheckOutput(cmd, verbose=False)
+ 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"]
+ output = common.RunAndCheckOutput(cmd, verbose=False)
+ # increase by > 4% as number of files and directories is not whole picture.
+ return output.count('\n') * 25 // 24
+
+
+def GetFilesystemCharacteristics(sparse_image_path):
+ """Returns various filesystem characteristics of "sparse_image_path".
+
+ Args:
+ sparse_image_path: The file to analyze.
+
+ Returns:
+ The characteristics dictionary.
+ """
+ unsparse_image_path = UnsparseImage(sparse_image_path, replace=False)
+
+ cmd = ["tune2fs", "-l", unsparse_image_path]
try:
- output = common.RunAndCheckOutput(cmd, verbose=False, env=env_copy)
- except common.ExternalError:
- raise BuildImageError("Failed to get disk usage:\n{}".format(output))
- # POSIX du returns number of blocks with block size 512
- return int(output.split()[0]) * 512
+ output = common.RunAndCheckOutput(cmd, verbose=False)
+ finally:
+ os.remove(unsparse_image_path)
+ fs_dict = {}
+ for line in output.splitlines():
+ fields = line.split(":")
+ if len(fields) == 2:
+ fs_dict[fields[0].strip()] = fields[1].strip()
+ return fs_dict
def UnsparseImage(sparse_image_path, replace=True):
@@ -121,6 +151,10 @@
if prop_dict["mount_point"] != "system":
return origin_in, fs_config
+ if "first_pass" in prop_dict:
+ prop_dict["mount_point"] = "/"
+ return prop_dict["first_pass"]
+
# Construct a staging directory of the root file system.
in_dir = common.MakeTempDir()
root_dir = prop_dict.get("root_dir")
@@ -144,6 +178,7 @@
with open(fs_config) as fr:
fw.writelines(fr.readlines())
fs_config = merged_fs_config
+ prop_dict["first_pass"] = (in_dir, fs_config)
return in_dir, fs_config
@@ -175,7 +210,7 @@
m = ext4fs_stats.match(last_line)
used_blocks = int(m.groupdict().get('used_blocks'))
total_blocks = int(m.groupdict().get('total_blocks'))
- headroom_blocks = int(prop_dict['partition_headroom']) / BLOCK_SIZE
+ headroom_blocks = int(prop_dict['partition_headroom']) // BLOCK_SIZE
adjusted_blocks = total_blocks - headroom_blocks
if used_blocks > adjusted_blocks:
mount_point = prop_dict["mount_point"]
@@ -202,6 +237,7 @@
Raises:
BuildImageError: On build image failures.
"""
+ original_mount_point = prop_dict["mount_point"]
in_dir, fs_config = SetUpInDirAndFsConfig(in_dir, prop_dict)
build_command = []
@@ -233,7 +269,8 @@
size = GetDiskUsage(in_dir)
logger.info(
"The tree size of %s is %d MB.", in_dir, size // BYTES_IN_MB)
- size += int(prop_dict.get("partition_reserved_size", 0))
+ # If not specified, give us 16MB margin for GetDiskUsage error ...
+ size += int(prop_dict.get("partition_reserved_size", BYTES_IN_MB * 16))
# Round this up to a multiple of 4K so that avbtool works
size = common.RoundUpTo4K(size)
# Adjust partition_size to add more space for AVB footer, to prevent
@@ -244,6 +281,35 @@
lambda x: verity_utils.AVBCalcMaxImageSize(
avbtool, avb_footer_type, x, avb_signing_args))
prop_dict["partition_size"] = str(size)
+ if fs_type.startswith("ext"):
+ 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"])
+ prop_dict["mount_point"] = original_mount_point
+ BuildImage(in_dir, prop_dict, out_file, target_out)
+ fs_dict = GetFilesystemCharacteristics(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))
+ if free_size <= reserved_size:
+ logger.info(
+ "Not worth reducing image %d <= %d.", free_size, reserved_size)
+ else:
+ size -= free_size
+ size += reserved_size
+ 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"))
+ prop_dict["extfs_inode_count"] = str(inodes)
+ prop_dict["partition_size"] = str(size)
+ logger.info(
+ "Allocating %d Inodes for %s.", inodes, out_file)
logger.info(
"Allocating %d MB for %s.", size // BYTES_IN_MB, out_file)
@@ -363,7 +429,7 @@
int(prop_dict.get("partition_reserved_size", 0)),
int(prop_dict.get("partition_reserved_size", 0)) // BYTES_IN_MB))
print(
- "The max image size for filsystem files is {} bytes ({} MB), out of a "
+ "The max image size for filesystem files is {} bytes ({} MB), out of a "
"total partition size of {} bytes ({} MB).".format(
int(prop_dict["image_size"]),
int(prop_dict["image_size"]) // BYTES_IN_MB,
@@ -677,7 +743,7 @@
glob_dict = LoadGlobalDict(glob_dict_file)
if "mount_point" in glob_dict:
- # The caller knows the mount point and provides a dictionay needed by
+ # The caller knows the mount point and provides a dictionary needed by
# BuildImage().
image_properties = glob_dict
else:
diff --git a/tools/releasetools/test_build_image.py b/tools/releasetools/test_build_image.py
index 634c6b1..1cebd0c 100644
--- a/tools/releasetools/test_build_image.py
+++ b/tools/releasetools/test_build_image.py
@@ -19,7 +19,7 @@
import common
from build_image import (
- BuildImageError, CheckHeadroom, SetUpInDirAndFsConfig)
+ BuildImageError, CheckHeadroom, GetFilesystemCharacteristics, SetUpInDirAndFsConfig)
from test_utils import ReleaseToolsTestCase
@@ -176,3 +176,25 @@
self.assertIn('fs-config-system\n', fs_config_data)
self.assertIn('fs-config-root\n', fs_config_data)
self.assertEqual('/', prop_dict['mount_point'])
+
+ def test_GetFilesystemCharacteristics(self):
+ input_dir = common.MakeTempDir()
+ output_image = common.MakeTempFile(suffix='.img')
+ command = ['mkuserimg_mke2fs', input_dir, output_image, 'ext4',
+ '/system', '409600', '-j', '0']
+ proc = common.Run(command)
+ ext4fs_output, _ = proc.communicate()
+ self.assertEqual(0, proc.returncode)
+
+ output_file = common.MakeTempFile(suffix='.img')
+ cmd = ["img2simg", output_image, output_file]
+ p = common.Run(cmd)
+ p.communicate()
+ self.assertEqual(0, p.returncode)
+
+ fs_dict = GetFilesystemCharacteristics(output_file)
+ self.assertEqual(int(fs_dict['Block size']), 4096)
+ self.assertGreaterEqual(int(fs_dict['Free blocks']), 0) # expect ~88
+ self.assertGreater(int(fs_dict['Inode count']), 0) # expect ~64
+ self.assertGreaterEqual(int(fs_dict['Free inodes']), 0) # expect ~53
+ self.assertGreater(int(fs_dict['Inode count']), int(fs_dict['Free inodes']))