aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bazel.WORKSPACE24
-rwxr-xr-xci/bp2build.sh2
-rw-r--r--examples/partitions/BUILD10
-rw-r--r--product_config/BUILD0
-rw-r--r--product_config/product_config_repository_rule.bzl71
-rw-r--r--rules/partitions/BUILD23
-rw-r--r--rules/partitions/installable_info.bzl44
-rw-r--r--rules/partitions/partition.bzl364
-rw-r--r--rules/partitions/toolchain.bzl40
-rw-r--r--tests/partitions/BUILD8
-rw-r--r--tests/partitions/image_contents_test.bzl30
11 files changed, 615 insertions, 1 deletions
diff --git a/bazel.WORKSPACE b/bazel.WORKSPACE
index d847c636..b2a19ea4 100644
--- a/bazel.WORKSPACE
+++ b/bazel.WORKSPACE
@@ -15,8 +15,27 @@ soong_injection_repository(name="soong_injection")
load("//build/bazel/rules:make_injection.bzl", "make_injection_repository")
make_injection_repository(
name = "make_injection",
+ binaries = [
+ "build_image",
+ "mkuserimg_mke2fs",
+ ],
target_module_files = {},
- watch_android_bp_files = [],
+ watch_android_bp_files = [
+ "//:build/make/tools/releasetools/Android.bp", # for build_image
+ "//:system/extras/ext4_utils/Android.bp", # for mkuserimg_mke2fs
+ ],
+)
+# ! WARNING ! WARNING ! WARNING !
+
+# ! WARNING ! WARNING ! WARNING !
+# This is an experimental product configuration repostory rule.
+# It currently has incrementality issues, and will not rebuild
+# when the product config is changed. Use @soong_injection//product_config
+# instead. b/237004497 tracks fixing this issue and consolidating
+# it with soong_injection.
+load("//build/bazel/product_config:product_config_repository_rule.bzl", "product_config")
+product_config(
+ name = "product_config",
)
# ! WARNING ! WARNING ! WARNING !
@@ -52,6 +71,9 @@ register_toolchains(
# For APEX rules
"//build/bazel/rules/apex:all",
+
+ # For partition rules
+ "//build/bazel/rules/partitions:all"
)
bind(
diff --git a/ci/bp2build.sh b/ci/bp2build.sh
index 9bfe4bb2..7140f443 100755
--- a/ci/bp2build.sh
+++ b/ci/bp2build.sh
@@ -99,9 +99,11 @@ HOST_INCOMPATIBLE_TARGETS=(
# TODO(b/217756861): Apex toolchain is incompatible with host arches but apex modules do
# not have this restriction
-//build/bazel/examples/apex/...
+ -//build/bazel/examples/partitions/...
-//build/bazel/ci/dist/...
-//build/bazel/rules/apex/...
-//build/bazel/tests/apex/...
+ -//build/bazel/tests/partitions/...
-//packages/modules/adb/apex:com.android.adbd
-//system/timezone/apex:com.android.tzdata
diff --git a/examples/partitions/BUILD b/examples/partitions/BUILD
new file mode 100644
index 00000000..404371af
--- /dev/null
+++ b/examples/partitions/BUILD
@@ -0,0 +1,10 @@
+load("//build/bazel/rules/partitions:partition.bzl", "partition")
+package(default_visibility = ["//visibility:public"])
+
+partition(
+ name = "system_image",
+ type = "system",
+ deps = [
+ "//build/bazel/examples/apex/minimal:build.bazel.examples.apex.minimal",
+ ],
+)
diff --git a/product_config/BUILD b/product_config/BUILD
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/product_config/BUILD
diff --git a/product_config/product_config_repository_rule.bzl b/product_config/product_config_repository_rule.bzl
new file mode 100644
index 00000000..8f974cfc
--- /dev/null
+++ b/product_config/product_config_repository_rule.bzl
@@ -0,0 +1,71 @@
+# Copyright (C) 2022 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.
+
+def _make_vars_to_starlark(txt):
+ lines = []
+ for l in txt.split('\n'):
+ l = l.strip()
+ if not l or l.startswith('$'):
+ continue
+ parts = l.split(':=', 1)
+ parts[0] = parts[0].strip().replace('"', '\\"')
+ parts[1] = parts[1].strip().replace('"', '\\"')
+ lines.append(parts)
+
+ return '''product_config = {
+ %s
+}
+''' % "\n ".join(['"'+x[0]+'": "'+x[1]+'",' for x in lines])
+
+def _impl(rctx):
+ workspace_root = str(rctx.path(Label("//:WORKSPACE")).dirname)
+ output_file = rctx.path("out/rbc_variable_dump.txt")
+
+ res = rctx.execute(["mkdir", str(output_file.dirname)])
+ if res.return_code != 0:
+ fail("mkdir "+str(output_file.dirname)+" failed to run\n"+res.stderr)
+
+ res = rctx.execute([
+ 'prebuilts/build-tools/linux-x86/bin/ckati',
+ '-f',
+ 'build/make/core/config.mk'
+ ], environment={
+ "OUT_DIR": str(rctx.path("out")),
+ "TMPDIR": str(rctx.path("tmp")),
+ "BUILD_DATETIME_FILE": str(rctx.path("out/build_date.txt")),
+ "CALLED_FROM_SETUP": 'true',
+ "TARGET_PRODUCT": rctx.os.environ.get("TARGET_PRODUCT", "aosp_arm"),
+ "TARGET_BUILD_VARIANT": rctx.os.environ.get("TARGET_BUILD_VARIANT", "eng"),
+ "RBC_DUMP_CONFIG_FILE": str(output_file),
+ }, working_directory = workspace_root)
+ if res.return_code != 0:
+ fail("ckati -f config.mk failed to run\n"+res.stderr)
+
+ res = rctx.execute(["cat", str(output_file)])
+ if res.return_code != 0:
+ fail("cat "+str(output_file)+" failed to run\n"+res.stderr)
+
+
+ rctx.file("product_config.bzl", _make_vars_to_starlark(res.stdout), executable=False)
+ exports_files = ("""exports_files([
+ %s
+])
+""" % ",\n ".join(["\"product_config.bzl\""]))
+ rctx.file("BUILD", exports_files, executable=False)
+
+product_config = repository_rule(
+ implementation=_impl,
+ local=True,
+ environ=["TARGET_PRODUCT", "TARGET_BUILD_VARIANT"],
+)
diff --git a/rules/partitions/BUILD b/rules/partitions/BUILD
new file mode 100644
index 00000000..717cd84c
--- /dev/null
+++ b/rules/partitions/BUILD
@@ -0,0 +1,23 @@
+load(":toolchain.bzl", "partition_toolchain")
+
+
+toolchain_type(name = "partition_toolchain_type")
+
+partition_toolchain(
+ name = "partition_toolchain",
+ build_image = "@make_injection//:host/linux-x86/bin/build_image",
+ mkuserimg_mke2fs = "@make_injection//:host/linux-x86/bin/mkuserimg_mke2fs"
+)
+
+toolchain(
+ name = "partition_toolchain_def",
+ exec_compatible_with = [
+ "//build/bazel/platforms/arch:x86_64",
+ "//build/bazel/platforms/os:linux",
+ ],
+ target_compatible_with = [
+ "//build/bazel/platforms/os:android",
+ ],
+ toolchain = ":partition_toolchain",
+ toolchain_type = ":partition_toolchain_type",
+)
diff --git a/rules/partitions/installable_info.bzl b/rules/partitions/installable_info.bzl
new file mode 100644
index 00000000..8b07756e
--- /dev/null
+++ b/rules/partitions/installable_info.bzl
@@ -0,0 +1,44 @@
+"""
+Copyright (C) 2022 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.
+"""
+load("//build/bazel/rules/apex:apex.bzl", "ApexInfo")
+
+InstallableInfo = provider(
+ "If a target provides InstallableInfo, it means it can be installed on a partition image.",
+ fields = {
+ "files": "A dictionary mapping from the path to the file to install to the path it should have in the partition.",
+ },
+)
+
+def _installable_aspect_impl(target, ctx):
+ installed_files = {}
+ if ApexInfo in target:
+ apex = target[ApexInfo].signed_output
+ installed_files[apex] = "/system/apex/" + apex.basename
+
+ if not installed_files:
+ return []
+
+ return [
+ InstallableInfo(
+ files = installed_files
+ ),
+ ]
+
+# This aspect is intended to be applied on a apex.native_shared_libs attribute
+installable_aspect = aspect(
+ implementation = _installable_aspect_impl,
+ attrs = {},
+)
diff --git a/rules/partitions/partition.bzl b/rules/partitions/partition.bzl
new file mode 100644
index 00000000..743a35b1
--- /dev/null
+++ b/rules/partitions/partition.bzl
@@ -0,0 +1,364 @@
+"""
+Copyright (C) 2022 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.
+"""
+load("@bazel_skylib//lib:dicts.bzl", "dicts")
+load("@bazel_skylib//lib:paths.bzl", "paths")
+load("@product_config//:product_config.bzl", "product_config")
+load(":installable_info.bzl", "InstallableInfo", "installable_aspect")
+
+
+_IMAGE_TYPES = [
+ "system",
+ "system_other",
+ "userdata",
+ "cache",
+ "vendor",
+ "product",
+ "system_ext",
+ "odm",
+ "vendor_dlkm",
+ "system_dlkm",
+ "oem"
+]
+
+def _p(varname, default=""):
+ return product_config.get(varname, default)
+
+def _add_common_flags_to_image_props(image_props, image_type):
+ image_props[image_type + "_selinux_fc"] = _p("SELINUX_FC", "")
+ image_props["building_" + image_type + "_image"] = _p("BUILDING_" + image_type.upper() + "_IMAGE", "")
+
+def _add_common_ro_flags_to_image_props(image_props, image_type):
+ image_type = image_type.lower()
+ IMAGE_TYPE = image_type.upper()
+ def add_board_var(varname, finalname = None):
+ if not finalname:
+ finalname = varname
+ if _p("BOARD_"+IMAGE_TYPE+"IMAGE_"+varname.upper()):
+ image_props[image_type+"_"+finalname.lower()] = _p("BOARD_"+IMAGE_TYPE+"IMAGE_"+varname.upper())
+
+ add_board_var("EROFS_COMPRESSOR")
+ add_board_var("EROFS_COMPRESS_HINTS")
+ add_board_var("EROFS_PCLUSTER_SIZE")
+ add_board_var("EXTFS_INODE_COUNT")
+ add_board_var("EXTFS_RSV_PCT")
+ add_board_var("F2FS_SLOAD_COMPRESS_FLAGS", "f2fs_sldc_flags")
+ add_board_var("FILE_SYSTEM_COMPRESS", "f2fs_compress")
+ add_board_var("FILE_SYSTEM_TYPE", "fs_type")
+ add_board_var("JOURNAL_SIZE", "journal_size")
+ add_board_var("PARTITION_RESERVED_SIZE", "reserved_size")
+ add_board_var("PARTITION_SIZE", "size")
+ add_board_var("SQUASHFS_BLOCK_SIZE")
+ add_board_var("SQUASHFS_COMPRESSOR")
+ add_board_var("SQUASHFS_COMPRESSOR_OPT")
+ add_board_var("SQUASHFS_DISABLE_4K_ALIGN")
+ if _p("PRODUCT_"+IMAGE_TYPE+"_BASE_FS_PATH"):
+ image_props[image_type+"_base_fs_file"] = _p("PRODUCT_"+IMAGE_TYPE+"_BASE_FS_PATH")
+
+ if not (_p("BOARD_"+IMAGE_TYPE+"IMAGE_PARTITION_SIZE") or
+ _p("BOARD_"+IMAGE_TYPE+"IMAGE_PARTITION_RESERVED_SIZE") or
+ _p("PRODUCT_"+IMAGE_TYPE+"_HEADROOM")):
+ image_props[image_type + "_disable_sparse"] = "true"
+
+ _add_common_flags_to_image_props(image_props, image_type)
+
+def _generate_image_prop_dictionary(ctx, image_types, extra_props = {}):
+ """Generates the image properties file.
+
+ Args:
+ file: The file that will be written to
+ types: A list of one or more of "system", "system_other",
+ "userdata", "cache", "vendor", "product", "system_ext",
+ "odm", "vendor_dlkm", "system_dlkm", or "oem"
+ extra_props: A dictionary of props to append at the end of the file.
+ """
+ # TODO(b/237106430): This should probably be mostly replaced with attributes on the system_image rule,
+ # and then there can be a separate macro to adapt product config variables to a
+ # correctly-spec'd system_image rule.
+
+ toolchain = ctx.toolchains[":partition_toolchain_type"].toolchain_info
+
+ for image_type in image_types:
+ if image_type not in _IMAGE_TYPES:
+ fail("Image type %s unknown. Valid types are %s", image_type, _IMAGE_TYPES)
+ image_props = {}
+
+ if "system" in image_types:
+ if _p("INTERNAL_SYSTEM_OTHER_PARTITION_SIZE"):
+ image_props["system_other_size"] = _p("INTERNAL_SYSTEM_OTHER_PARTITION_SIZE")
+ if _p("PRODUCT_SYSTEM_HEADROOM"):
+ image_props["system_headroom"]=_p("PRODUCT_SYSTEM_HEADROOM")
+ _add_common_ro_flags_to_image_props(image_props, "system")
+ if "system_other" in image_types:
+ image_props["building_system_other_image"] = _p("BUILDING_SYSTEM_OTHER_IMAGE", "")
+ if _p("INTERNAL_SYSTEM_OTHER_PARTITION_SIZE"):
+ image_props["system_other_disable_sparse"] = "true"
+ if "userdata" in image_types:
+ if _p("PRODUCT_FS_CASEFOLD"):
+ image_props["needs_casefold"] = _p("PRODUCT_FS_CASEFOLD")
+ if _p("PRODUCT_QUOTA_PROJID"):
+ image_props["needs_projid"] = _p("PRODUCT_QUOTA_PROJID")
+ if _p("PRODUCT_FS_COMPRESSION"):
+ image_props["needs_compress"] = _p("PRODUCT_FS_COMPRESSION")
+ _add_common_ro_flags_to_image_props(image_props, "userdata")
+ if "cache" in image_types:
+ _add_common_ro_flags_to_image_props(image_props, "cache")
+ if "vendor" in image_types:
+ _add_common_ro_flags_to_image_props(image_props, "vendor")
+ if "product" in image_types:
+ _add_common_ro_flags_to_image_props(image_props, "product")
+ if "system_ext" in image_types:
+ _add_common_ro_flags_to_image_props(image_props, "system_ext")
+ if "odm" in image_types:
+ _add_common_ro_flags_to_image_props(image_props, "odm")
+ if "vendor_dlkm" in image_types:
+ _add_common_ro_flags_to_image_props(image_props, "vendor_dlkm")
+ if "odm_dlkm" in image_types:
+ _add_common_ro_flags_to_image_props(image_props, "odm_dlkm")
+ if "system_dlkm" in image_types:
+ _add_common_ro_flags_to_image_props(image_props, "system_dlkm")
+ if "oem" in image_types:
+ if _p("BOARD_OEMIMAGE_EXTFS_INODE_COUNT"):
+ image_props["oem_extfs_inode_count"] = _p("BOARD_OEMIMAGE_EXTFS_INODE_COUNT")
+ if _p("BOARD_OEMIMAGE_EXTFS_RSV_PCT"):
+ image_props["oem_extfs_rsv_pct"] = _p("BOARD_OEMIMAGE_EXTFS_RSV_PCT")
+ _add_common_ro_flags_to_image_props(image_props, "oem")
+ image_props["ext_mkuserimg"] = toolchain.mkuserimg_mke2fs.path #_p("MKEXTUSRIMG")
+
+ if _p("TARGET_USERIMAGES_USE_EXT2") == "true":
+ image_props["fs_type"] = "ext2"
+ elif _p("TARGET_USERIMAGES_USE_EXT3") == "true":
+ image_props["fs_type"] = "ext3"
+ elif _p("TARGET_USERIMAGES_USE_EXT4") == "true":
+ image_props["fs_type"] = "ext4"
+
+ if _p("TARGET_USERIMAGES_SPARSE_EXT_DISABLED") != "true":
+ image_props["extfs_sparse_flag"] = "-s"
+ if _p("TARGET_USERIMAGES_SPARSE_EROFS_DISABLED") != "true":
+ image_props["erofs_sparse_flag"] = "-s"
+ if _p("TARGET_USERIMAGES_SPARSE_SQUASHFS_DISABLED") != "true":
+ image_props["squashfs_sparse_flag"] = "-s"
+ if _p("TARGET_USERIMAGES_SPARSE_F2FS_DISABLED") != "true":
+ image_props["f2fs_sparse_flag"] = "-S"
+ if _p("BOARD_EROFS_COMPRESSOR"):
+ image_props["erofs_default_compressor"] = _p("BOARD_EROFS_COMPRESSOR")
+ if _p("BOARD_EROFS_COMPRESS_HINTS"):
+ image_props["erofs_default_compress_hints"] = _p("BOARD_EROFS_COMPRESS_HINTS")
+ if _p("BOARD_EROFS_PCLUSTER_SIZE"):
+ image_props["erofs_pcluster_size"] = _p("BOARD_EROFS_PCLUSTER_SIZE")
+ if _p("BOARD_EROFS_SHARE_DUP_BLOCKS"):
+ image_props["erofs_share_dup_blocks"] = _p("BOARD_EROFS_SHARE_DUP_BLOCKS")
+ if _p("BOARD_EROFS_USE_LEGACY_COMPRESSION"):
+ image_props["erofs_use_legacy_compression"] = _p("BOARD_EROFS_USE_LEGACY_COMPRESSION")
+ if _p("BOARD_EXT4_SHARE_DUP_BLOCKS"):
+ image_props["ext4_share_dup_blocks"] = _p("BOARD_EXT4_SHARE_DUP_BLOCKS")
+ if _p("BOARD_FLASH_LOGICAL_BLOCK_SIZE"):
+ image_props["flash_logical_block_size"] = _p("BOARD_FLASH_LOGICAL_BLOCK_SIZE")
+ if _p("BOARD_FLASH_ERASE_BLOCK_SIZE"):
+ image_props["flash_erase_block_size"] = _p("BOARD_FLASH_ERASE_BLOCK_SIZE")
+ if _p("PRODUCT_SUPPORTS_BOOT_SIGNER"):
+ image_props["boot_signer"] = _p("PRODUCT_SUPPORTS_BOOT_SIGNER")
+ if _p("PRODUCT_SUPPORTS_VERITY"):
+ image_props["verity"] = _p("PRODUCT_SUPPORTS_VERITY")
+ image_props["verity_key"] = _p("PRODUCT_VERITY_SIGNING_KEY")
+ image_props["verity_signer_cmd"] = paths.basename(_p("VERITY_SIGNER"))
+ if _p("PRODUCT_SUPPORTS_VERITY_FEC"):
+ image_props["verity_fec"] = _p("PRODUCT_SUPPORTS_VERITY_FEC")
+ if _p("TARGET_BUILD_VARIANT") == "eng":
+ image_props["verity_disable"] = "true"
+ if _p("PRODUCT_SYSTEM_VERITY_PARTITION"):
+ image_props["system_verity_block_device"] = _p("PRODUCT_SYSTEM_VERITY_PARTITION")
+ if _p("PRODUCT_VENDOR_VERITY_PARTITION"):
+ image_props["vendor_verity_block_device"] = _p("PRODUCT_VENDOR_VERITY_PARTITION")
+ if _p("PRODUCT_PRODUCT_VERITY_PARTITION"):
+ image_props["product_verity_block_device"] = _p("PRODUCT_PRODUCT_VERITY_PARTITION")
+ if _p("PRODUCT_SYSTEM_EXT_VERITY_PARTITION"):
+ image_props["system_ext_verity_block_device"] = _p("PRODUCT_SYSTEM_EXT_VERITY_PARTITION")
+ if _p("PRODUCT_VENDOR_DLKM_VERITY_PARTITION"):
+ image_props["vendor_dlkm_verity_block_device"] = _p("PRODUCT_VENDOR_DLKM_VERITY_PARTITION")
+ if _p("PRODUCT_ODM_DLKM_VERITY_PARTITION"):
+ image_props["odm_dlkm_verity_block_device"] = _p("PRODUCT_ODM_DLKM_VERITY_PARTITION")
+ if _p("PRODUCT_SYSTEM_DLKM_VERITY_PARTITION"):
+ image_props["system_dlkm_verity_block_device"] = _p("PRODUCT_SYSTEM_DLKM_VERITY_PARTITION")
+ if _p("PRODUCT_SUPPORTS_VBOOT"):
+ image_props["vboot"] = _p("PRODUCT_SUPPORTS_VBOOT")
+ image_props["vboot_key"] = _p("PRODUCT_VBOOT_SIGNING_KEY")
+ image_props["vboot_subkey"] = _p("PRODUCT_VBOOT_SIGNING_SUBKEY")
+ image_props["futility"] = paths.basename(_p("FUTILITY"))
+ image_props["vboot_signer_cmd"] = _p("VBOOT_SIGNER")
+ # TODO(b/237106430): Avb code is commented out because it's not yet functional
+ # if _p("BOARD_AVB_ENABLE"):
+ # image_props["avb_avbtool"] = paths.basename(_p("AVBTOOL"))
+ # image_props["avb_system_hashtree_enable"] = _p("BOARD_AVB_ENABLE")
+ # image_props["avb_system_add_hashtree_footer_args"] = _p("BOARD_AVB_SYSTEM_ADD_HASHTREE_FOOTER_ARGS")
+ # if _p("BOARD_AVB_SYSTEM_KEY_PATH"):
+ # image_props["avb_system_key_path"] = _p("BOARD_AVB_SYSTEM_KEY_PATH")
+ # image_props["avb_system_algorithm"] = _p("BOARD_AVB_SYSTEM_ALGORITHM")
+ # image_props["avb_system_rollback_index_location"] = _p("BOARD_AVB_SYSTEM_ROLLBACK_INDEX_LOCATION")
+ # image_props["avb_system_other_hashtree_enable"] = _p("BOARD_AVB_ENABLE")
+ # image_props["avb_system_other_add_hashtree_footer_args"] = _p("BOARD_AVB_SYSTEM_OTHER_ADD_HASHTREE_FOOTER_ARGS")
+ # if _p("BOARD_AVB_SYSTEM_OTHER_KEY_PATH"):
+ # image_props["avb_system_other_key_path"] = _p("BOARD_AVB_SYSTEM_OTHER_KEY_PATH")
+ # image_props["avb_system_other_algorithm"] = _p("BOARD_AVB_SYSTEM_OTHER_ALGORITHM")
+ # image_props["avb_vendor_hashtree_enable"] = _p("BOARD_AVB_ENABLE")
+ # image_props["avb_vendor_add_hashtree_footer_args"] = _p("BOARD_AVB_VENDOR_ADD_HASHTREE_FOOTER_ARGS")
+ # if _p("BOARD_AVB_VENDOR_KEY_PATH"):
+ # image_props["avb_vendor_key_path"] = _p("BOARD_AVB_VENDOR_KEY_PATH")
+ # image_props["avb_vendor_algorithm"] = _p("BOARD_AVB_VENDOR_ALGORITHM")
+ # image_props["avb_vendor_rollback_index_location"] = _p("BOARD_AVB_VENDOR_ROLLBACK_INDEX_LOCATION")
+ # image_props["avb_product_hashtree_enable"] = _p("BOARD_AVB_ENABLE")
+ # image_props["avb_product_add_hashtree_footer_args"] = _p("BOARD_AVB_PRODUCT_ADD_HASHTREE_FOOTER_ARGS")
+ # if _p("BOARD_AVB_PRODUCT_KEY_PATH"):
+ # image_props["avb_product_key_path"] = _p("BOARD_AVB_PRODUCT_KEY_PATH")
+ # image_props["avb_product_algorithm"] = _p("BOARD_AVB_PRODUCT_ALGORITHM")
+ # image_props["avb_product_rollback_index_location"] = _p("BOARD_AVB_PRODUCT_ROLLBACK_INDEX_LOCATION")
+ # image_props["avb_system_ext_hashtree_enable"] = _p("BOARD_AVB_ENABLE")
+ # image_props["avb_system_ext_add_hashtree_footer_args"] = _p("BOARD_AVB_SYSTEM_EXT_ADD_HASHTREE_FOOTER_ARGS")
+ # if _p("BOARD_AVB_SYSTEM_EXT_KEY_PATH"):
+ # image_props["avb_system_ext_key_path"] = _p("BOARD_AVB_SYSTEM_EXT_KEY_PATH")
+ # image_props["avb_system_ext_algorithm"] = _p("BOARD_AVB_SYSTEM_EXT_ALGORITHM")
+ # image_props["avb_system_ext_rollback_index_location"] = _p("BOARD_AVB_SYSTEM_EXT_ROLLBACK_INDEX_LOCATION")
+ # image_props["avb_odm_hashtree_enable"] = _p("BOARD_AVB_ENABLE")
+ # image_props["avb_odm_add_hashtree_footer_args"] = _p("BOARD_AVB_ODM_ADD_HASHTREE_FOOTER_ARGS")
+ # if _p("BOARD_AVB_ODM_KEY_PATH"):
+ # image_props["avb_odm_key_path"] = _p("BOARD_AVB_ODM_KEY_PATH")
+ # image_props["avb_odm_algorithm"] = _p("BOARD_AVB_ODM_ALGORITHM")
+ # image_props["avb_odm_rollback_index_location"] = _p("BOARD_AVB_ODM_ROLLBACK_INDEX_LOCATION")
+ # image_props["avb_vendor_dlkm_hashtree_enable"] = _p("BOARD_AVB_ENABLE")
+ # image_props["avb_vendor_dlkm_add_hashtree_footer_args"] = _p("BOARD_AVB_VENDOR_DLKM_ADD_HASHTREE_FOOTER_ARGS")
+ # if _p("BOARD_AVB_VENDOR_DLKM_KEY_PATH"):
+ # image_props["avb_vendor_dlkm_key_path"] = _p("BOARD_AVB_VENDOR_DLKM_KEY_PATH")
+ # image_props["avb_vendor_dlkm_algorithm"] = _p("BOARD_AVB_VENDOR_DLKM_ALGORITHM")
+ # image_props["avb_vendor_dlkm_rollback_index_location"] = _p("BOARD_AVB_VENDOR_DLKM_ROLLBACK_INDEX_LOCATION")
+ # image_props["avb_odm_dlkm_hashtree_enable"] = _p("BOARD_AVB_ENABLE")
+ # image_props["avb_odm_dlkm_add_hashtree_footer_args"] = _p("BOARD_AVB_ODM_DLKM_ADD_HASHTREE_FOOTER_ARGS")
+ # if _p("BOARD_AVB_ODM_DLKM_KEY_PATH"):
+ # image_props["avb_odm_dlkm_key_path"] = _p("BOARD_AVB_ODM_DLKM_KEY_PATH")
+ # image_props["avb_odm_dlkm_algorithm"] = _p("BOARD_AVB_ODM_DLKM_ALGORITHM")
+ # image_props["avb_odm_dlkm_rollback_index_location"] = _p("BOARD_AVB_ODM_DLKM_ROLLBACK_INDEX_LOCATION")
+ # image_props["avb_system_dlkm_hashtree_enable"] = _p("BOARD_AVB_ENABLE")
+ # image_props["avb_system_dlkm_add_hashtree_footer_args"] = _p("BOARD_AVB_SYSTEM_DLKM_ADD_HASHTREE_FOOTER_ARGS")
+ # if _p("BOARD_AVB_SYSTEM_DLKM_KEY_PATH"):
+ # image_props["avb_system_dlkm_key_path"] = _p("BOARD_AVB_SYSTEM_DLKM_KEY_PATH")
+ # image_props["avb_system_dlkm_algorithm"] = _p("BOARD_AVB_SYSTEM_DLKM_ALGORITHM")
+ # image_props["avb_system_dlkm_rollback_index_location"] = _p("BOARD_SYSTEM_SYSTEM_DLKM_ROLLBACK_INDEX_LOCATION")
+ if _p("BOARD_USES_RECOVERY_AS_BOOT") == "true":
+ image_props["recovery_as_boot"] = "true"
+ if _p("BOARD_BUILD_SYSTEM_ROOT_IMAGE") == "true":
+ image_props["system_root_image"] = "true"
+ if _p("BOARD_BUILD_GKI_BOOT_IMAGE_WITHOUT_RAMDISK") == "true":
+ image_props["gki_boot_image_without_ramdisk"] = "true"
+ #image_props["root_dir"] = _p("TARGET_ROOT_OUT") # TODO: replace with actual path
+ if _p("PRODUCT_USE_DYNAMIC_PARTITION_SIZE") == "true":
+ image_props["use_dynamic_partition_size"] = "true"
+ for k, v in extra_props.items():
+ image_props[k] = v
+
+ result = "\n".join([k + "=" + v for k, v in image_props.items()])
+ if result:
+ result += "\n"
+ return result
+
+
+def get_python3(ctx):
+ python_interpreter = ctx.toolchains["@bazel_tools//tools/python:toolchain_type"].py3_runtime.interpreter
+ if python_interpreter.basename == "python3":
+ return python_interpreter
+
+ renamed = ctx.actions.declare_file("python3")
+ ctx.actions.symlink(
+ output=renamed,
+ target_file=python_interpreter,
+ is_executable=True,
+ )
+ return renamed
+
+
+def _partition_impl(ctx):
+ if ctx.attr.type != "system":
+ fail("currently only system images are supported")
+
+ toolchain = ctx.toolchains[":partition_toolchain_type"].toolchain_info
+ python_interpreter = get_python3(ctx)
+ # build_image requires that the output file be named specifically <type>.img, so
+ # put all the outputs under a name-qualified folder.
+ image_info = ctx.actions.declare_file(ctx.attr.name + "/image_info.txt")
+ output_image = ctx.actions.declare_file(ctx.attr.name + "/" + ctx.attr.type + ".img")
+ ctx.actions.write(image_info, _generate_image_prop_dictionary(ctx, [ctx.attr.type], {"skip_fsck": "true"}))
+
+ files = {}
+ for dep in ctx.attr.deps:
+ files.update(dep[InstallableInfo].files)
+
+ for v in files.values():
+ if not v.startswith('/system'):
+ fail('Files outside of /system are not currently supported: %s', v)
+
+ file_mapping_file = ctx.actions.declare_file(ctx.attr.name + '/partition_file_mapping.json')
+ # It seems build_image will prepend /system to the paths when building_system_image=true
+ ctx.actions.write(file_mapping_file, json.encode({k.path: v.removeprefix('/system') for k,v in files.items()}))
+
+ ctx.actions.run(
+ inputs = [
+ image_info,
+ file_mapping_file,
+ ] + files.keys(),
+ tools = [
+ toolchain.build_image,
+ toolchain.mkuserimg_mke2fs,
+ python_interpreter,
+ ],
+ outputs = [output_image],
+ executable = ctx.executable._staging_dir_builder,
+ arguments = [
+ file_mapping_file.path,
+ toolchain.build_image.path,
+ "STAGING_DIR_PLACEHOLDER",
+ image_info.path,
+ output_image.path,
+ "STAGING_DIR_PLACEHOLDER",
+ ],
+ mnemonic = "BuildPartition",
+ # TODO: the /usr/bin addition is because build_image uses the du command
+ # in GetDiskUsage(). This can probably be rewritten to just use python code
+ # instead.
+ env = {"PATH": python_interpreter.dirname + ":/usr/bin"},
+ )
+
+ return DefaultInfo(files=depset([output_image]))
+
+partition = rule(
+ implementation = _partition_impl,
+ attrs = {
+ "type": attr.string(
+ mandatory = True,
+ values = _IMAGE_TYPES
+ ),
+ "deps": attr.label_list(
+ providers = [[InstallableInfo]],
+ aspects = [installable_aspect]
+ ),
+ "_staging_dir_builder": attr.label(
+ cfg = "host",
+ doc = "The tool used to build a staging directory, because if bazel were to build it it would be entirely symlinks.",
+ executable = True,
+ default = "//build/bazel/rules:staging_dir_builder",
+ ),
+ },
+ toolchains = [
+ ":partition_toolchain_type",
+ "@bazel_tools//tools/python:toolchain_type",
+ ],
+)
diff --git a/rules/partitions/toolchain.bzl b/rules/partitions/toolchain.bzl
new file mode 100644
index 00000000..dae2573e
--- /dev/null
+++ b/rules/partitions/toolchain.bzl
@@ -0,0 +1,40 @@
+"""
+Copyright (C) 2022 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.
+"""
+
+PartitionToolchainInfo = provider(
+ doc = "Partitions toolchain",
+ fields = [
+ "build_image",
+ "mkuserimg_mke2fs",
+ ],
+)
+
+def _partition_toolchain_impl(ctx):
+ toolchain_info = platform_common.ToolchainInfo(
+ toolchain_info = PartitionToolchainInfo(
+ build_image = ctx.file.build_image,
+ mkuserimg_mke2fs = ctx.file.mkuserimg_mke2fs,
+ ),
+ )
+ return [toolchain_info]
+
+partition_toolchain = rule(
+ implementation = _partition_toolchain_impl,
+ attrs = {
+ "build_image": attr.label(allow_single_file = True, cfg = "host", executable = True, mandatory = True),
+ "mkuserimg_mke2fs": attr.label(allow_single_file = True, cfg = "host", executable = True, mandatory = True),
+ },
+)
diff --git a/tests/partitions/BUILD b/tests/partitions/BUILD
new file mode 100644
index 00000000..7b3071f2
--- /dev/null
+++ b/tests/partitions/BUILD
@@ -0,0 +1,8 @@
+load(":image_contents_test.bzl", "image_contents_test")
+
+image_contents_test(
+ name = "image_contains_apex_test",
+ image = "//build/bazel/examples/partitions:system_image",
+ path = "/system/apex/build.bazel.examples.apex.minimal.apex",
+ expected = "//build/bazel/examples/apex/minimal:build.bazel.examples.apex.minimal"
+)
diff --git a/tests/partitions/image_contents_test.bzl b/tests/partitions/image_contents_test.bzl
new file mode 100644
index 00000000..06cb1a06
--- /dev/null
+++ b/tests/partitions/image_contents_test.bzl
@@ -0,0 +1,30 @@
+load("@bazel_skylib//rules:diff_test.bzl", "diff_test")
+
+def image_contents_test(
+ name,
+ image,
+ path,
+ expected,
+ target_compatible_with = None,
+ expected_diff = None):
+ """A test that extracts a file from a disk image file, and then asserts that it's identical to some other file."""
+
+ extracted_path = name + path.replace('/', '_') + "_extracted.bin"
+
+ native.genrule(
+ name = name + "_extracted",
+ tools = [
+ "//external/e2fsprogs/debugfs:debugfs",
+ ],
+ srcs = [image],
+ outs = [extracted_path],
+ cmd = "$(location //external/e2fsprogs/debugfs:debugfs) -R 'dump " + path + " $@' $<",
+ tags = ["manual"],
+ )
+
+ diff_test(
+ name = name,
+ file1 = extracted_path,
+ file2 = expected,
+ target_compatible_with = target_compatible_with,
+ )