1# Copyright (C) 2022 The Android Open Source Project 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15load("@bazel_skylib//lib:paths.bzl", "paths") 16load(":installable_info.bzl", "InstallableInfo", "installable_aspect") 17 18# TODO(b/249685973): Reenable the partition rule 19product_config = {} 20 21_IMAGE_TYPES = [ 22 "system", 23 "system_other", 24 "userdata", 25 "cache", 26 "vendor", 27 "product", 28 "system_ext", 29 "odm", 30 "vendor_dlkm", 31 "system_dlkm", 32 "oem", 33] 34 35def _p(varname, default = ""): 36 return product_config.get(varname, default) 37 38def _add_common_flags_to_image_props(image_props, image_type): 39 image_props[image_type + "_selinux_fc"] = _p("SELINUX_FC", "") 40 image_props["building_" + image_type + "_image"] = _p("BUILDING_" + image_type.upper() + "_IMAGE", "") 41 42def _add_common_ro_flags_to_image_props(image_props, image_type): 43 image_type = image_type.lower() 44 IMAGE_TYPE = image_type.upper() 45 46 def add_board_var(varname, finalname = None): 47 if not finalname: 48 finalname = varname 49 if _p("BOARD_" + IMAGE_TYPE + "IMAGE_" + varname.upper()): 50 image_props[image_type + "_" + finalname.lower()] = _p("BOARD_" + IMAGE_TYPE + "IMAGE_" + varname.upper()) 51 52 add_board_var("EROFS_COMPRESSOR") 53 add_board_var("EROFS_COMPRESS_HINTS") 54 add_board_var("EROFS_PCLUSTER_SIZE") 55 add_board_var("EXTFS_INODE_COUNT") 56 add_board_var("EXTFS_RSV_PCT") 57 add_board_var("F2FS_SLOAD_COMPRESS_FLAGS", "f2fs_sldc_flags") 58 add_board_var("FILE_SYSTEM_COMPRESS", "f2fs_compress") 59 add_board_var("FILE_SYSTEM_TYPE", "fs_type") 60 add_board_var("JOURNAL_SIZE", "journal_size") 61 add_board_var("PARTITION_RESERVED_SIZE", "reserved_size") 62 add_board_var("PARTITION_SIZE", "size") 63 add_board_var("SQUASHFS_BLOCK_SIZE") 64 add_board_var("SQUASHFS_COMPRESSOR") 65 add_board_var("SQUASHFS_COMPRESSOR_OPT") 66 add_board_var("SQUASHFS_DISABLE_4K_ALIGN") 67 if _p("PRODUCT_" + IMAGE_TYPE + "_BASE_FS_PATH"): 68 image_props[image_type + "_base_fs_file"] = _p("PRODUCT_" + IMAGE_TYPE + "_BASE_FS_PATH") 69 70 if not (_p("BOARD_" + IMAGE_TYPE + "IMAGE_PARTITION_SIZE") or 71 _p("BOARD_" + IMAGE_TYPE + "IMAGE_PARTITION_RESERVED_SIZE") or 72 _p("PRODUCT_" + IMAGE_TYPE + "_HEADROOM")): 73 image_props[image_type + "_disable_sparse"] = "true" 74 75 _add_common_flags_to_image_props(image_props, image_type) 76 77def _generate_image_prop_dictionary(ctx, image_types, extra_props = {}): 78 """Generates the image properties file. 79 80 Args: 81 file: The file that will be written to 82 types: A list of one or more of "system", "system_other", 83 "userdata", "cache", "vendor", "product", "system_ext", 84 "odm", "vendor_dlkm", "system_dlkm", or "oem" 85 extra_props: A dictionary of props to append at the end of the file. 86 """ 87 # TODO(b/237106430): This should probably be mostly replaced with attributes on the system_image rule, 88 # and then there can be a separate macro to adapt product config variables to a 89 # correctly-spec'd system_image rule. 90 91 toolchain = ctx.toolchains[":partition_toolchain_type"].toolchain_info 92 93 for image_type in image_types: 94 if image_type not in _IMAGE_TYPES: 95 fail("Image type %s unknown. Valid types are %s", image_type, _IMAGE_TYPES) 96 image_props = {} 97 98 if "system" in image_types: 99 if _p("INTERNAL_SYSTEM_OTHER_PARTITION_SIZE"): 100 image_props["system_other_size"] = _p("INTERNAL_SYSTEM_OTHER_PARTITION_SIZE") 101 if _p("PRODUCT_SYSTEM_HEADROOM"): 102 image_props["system_headroom"] = _p("PRODUCT_SYSTEM_HEADROOM") 103 _add_common_ro_flags_to_image_props(image_props, "system") 104 if "system_other" in image_types: 105 image_props["building_system_other_image"] = _p("BUILDING_SYSTEM_OTHER_IMAGE", "") 106 if _p("INTERNAL_SYSTEM_OTHER_PARTITION_SIZE"): 107 image_props["system_other_disable_sparse"] = "true" 108 if "userdata" in image_types: 109 if _p("PRODUCT_FS_CASEFOLD"): 110 image_props["needs_casefold"] = _p("PRODUCT_FS_CASEFOLD") 111 if _p("PRODUCT_QUOTA_PROJID"): 112 image_props["needs_projid"] = _p("PRODUCT_QUOTA_PROJID") 113 if _p("PRODUCT_FS_COMPRESSION"): 114 image_props["needs_compress"] = _p("PRODUCT_FS_COMPRESSION") 115 _add_common_ro_flags_to_image_props(image_props, "userdata") 116 if "cache" in image_types: 117 _add_common_ro_flags_to_image_props(image_props, "cache") 118 if "vendor" in image_types: 119 _add_common_ro_flags_to_image_props(image_props, "vendor") 120 if "product" in image_types: 121 _add_common_ro_flags_to_image_props(image_props, "product") 122 if "system_ext" in image_types: 123 _add_common_ro_flags_to_image_props(image_props, "system_ext") 124 if "odm" in image_types: 125 _add_common_ro_flags_to_image_props(image_props, "odm") 126 if "vendor_dlkm" in image_types: 127 _add_common_ro_flags_to_image_props(image_props, "vendor_dlkm") 128 if "odm_dlkm" in image_types: 129 _add_common_ro_flags_to_image_props(image_props, "odm_dlkm") 130 if "system_dlkm" in image_types: 131 _add_common_ro_flags_to_image_props(image_props, "system_dlkm") 132 if "oem" in image_types: 133 if _p("BOARD_OEMIMAGE_EXTFS_INODE_COUNT"): 134 image_props["oem_extfs_inode_count"] = _p("BOARD_OEMIMAGE_EXTFS_INODE_COUNT") 135 if _p("BOARD_OEMIMAGE_EXTFS_RSV_PCT"): 136 image_props["oem_extfs_rsv_pct"] = _p("BOARD_OEMIMAGE_EXTFS_RSV_PCT") 137 _add_common_ro_flags_to_image_props(image_props, "oem") 138 image_props["ext_mkuserimg"] = toolchain.mkuserimg_mke2fs.path #_p("MKEXTUSRIMG") 139 140 if _p("TARGET_USERIMAGES_USE_EXT2") == "true": 141 image_props["fs_type"] = "ext2" 142 elif _p("TARGET_USERIMAGES_USE_EXT3") == "true": 143 image_props["fs_type"] = "ext3" 144 elif _p("TARGET_USERIMAGES_USE_EXT4") == "true": 145 image_props["fs_type"] = "ext4" 146 147 if _p("TARGET_USERIMAGES_SPARSE_EXT_DISABLED") != "true": 148 image_props["extfs_sparse_flag"] = "-s" 149 if _p("TARGET_USERIMAGES_SPARSE_EROFS_DISABLED") != "true": 150 image_props["erofs_sparse_flag"] = "-s" 151 if _p("TARGET_USERIMAGES_SPARSE_SQUASHFS_DISABLED") != "true": 152 image_props["squashfs_sparse_flag"] = "-s" 153 if _p("TARGET_USERIMAGES_SPARSE_F2FS_DISABLED") != "true": 154 image_props["f2fs_sparse_flag"] = "-S" 155 if _p("BOARD_EROFS_COMPRESSOR"): 156 image_props["erofs_default_compressor"] = _p("BOARD_EROFS_COMPRESSOR") 157 if _p("BOARD_EROFS_COMPRESS_HINTS"): 158 image_props["erofs_default_compress_hints"] = _p("BOARD_EROFS_COMPRESS_HINTS") 159 if _p("BOARD_EROFS_PCLUSTER_SIZE"): 160 image_props["erofs_pcluster_size"] = _p("BOARD_EROFS_PCLUSTER_SIZE") 161 if _p("BOARD_EROFS_SHARE_DUP_BLOCKS"): 162 image_props["erofs_share_dup_blocks"] = _p("BOARD_EROFS_SHARE_DUP_BLOCKS") 163 if _p("BOARD_EROFS_USE_LEGACY_COMPRESSION"): 164 image_props["erofs_use_legacy_compression"] = _p("BOARD_EROFS_USE_LEGACY_COMPRESSION") 165 if _p("BOARD_EXT4_SHARE_DUP_BLOCKS"): 166 image_props["ext4_share_dup_blocks"] = _p("BOARD_EXT4_SHARE_DUP_BLOCKS") 167 if _p("BOARD_FLASH_LOGICAL_BLOCK_SIZE"): 168 image_props["flash_logical_block_size"] = _p("BOARD_FLASH_LOGICAL_BLOCK_SIZE") 169 if _p("BOARD_FLASH_ERASE_BLOCK_SIZE"): 170 image_props["flash_erase_block_size"] = _p("BOARD_FLASH_ERASE_BLOCK_SIZE") 171 if _p("PRODUCT_SUPPORTS_BOOT_SIGNER"): 172 image_props["boot_signer"] = _p("PRODUCT_SUPPORTS_BOOT_SIGNER") 173 if _p("PRODUCT_SUPPORTS_VERITY"): 174 image_props["verity"] = _p("PRODUCT_SUPPORTS_VERITY") 175 image_props["verity_key"] = _p("PRODUCT_VERITY_SIGNING_KEY") 176 image_props["verity_signer_cmd"] = paths.basename(_p("VERITY_SIGNER")) 177 if _p("PRODUCT_SUPPORTS_VERITY_FEC"): 178 image_props["verity_fec"] = _p("PRODUCT_SUPPORTS_VERITY_FEC") 179 if _p("TARGET_BUILD_VARIANT") == "eng": 180 image_props["verity_disable"] = "true" 181 if _p("PRODUCT_SYSTEM_VERITY_PARTITION"): 182 image_props["system_verity_block_device"] = _p("PRODUCT_SYSTEM_VERITY_PARTITION") 183 if _p("PRODUCT_VENDOR_VERITY_PARTITION"): 184 image_props["vendor_verity_block_device"] = _p("PRODUCT_VENDOR_VERITY_PARTITION") 185 if _p("PRODUCT_PRODUCT_VERITY_PARTITION"): 186 image_props["product_verity_block_device"] = _p("PRODUCT_PRODUCT_VERITY_PARTITION") 187 if _p("PRODUCT_SYSTEM_EXT_VERITY_PARTITION"): 188 image_props["system_ext_verity_block_device"] = _p("PRODUCT_SYSTEM_EXT_VERITY_PARTITION") 189 if _p("PRODUCT_VENDOR_DLKM_VERITY_PARTITION"): 190 image_props["vendor_dlkm_verity_block_device"] = _p("PRODUCT_VENDOR_DLKM_VERITY_PARTITION") 191 if _p("PRODUCT_ODM_DLKM_VERITY_PARTITION"): 192 image_props["odm_dlkm_verity_block_device"] = _p("PRODUCT_ODM_DLKM_VERITY_PARTITION") 193 if _p("PRODUCT_SYSTEM_DLKM_VERITY_PARTITION"): 194 image_props["system_dlkm_verity_block_device"] = _p("PRODUCT_SYSTEM_DLKM_VERITY_PARTITION") 195 if _p("PRODUCT_SUPPORTS_VBOOT"): 196 image_props["vboot"] = _p("PRODUCT_SUPPORTS_VBOOT") 197 image_props["vboot_key"] = _p("PRODUCT_VBOOT_SIGNING_KEY") 198 image_props["vboot_subkey"] = _p("PRODUCT_VBOOT_SIGNING_SUBKEY") 199 image_props["futility"] = paths.basename(_p("FUTILITY")) 200 image_props["vboot_signer_cmd"] = _p("VBOOT_SIGNER") 201 202 # TODO(b/237106430): Avb code is commented out because it's not yet functional 203 # if _p("BOARD_AVB_ENABLE"): 204 # image_props["avb_avbtool"] = paths.basename(_p("AVBTOOL")) 205 # image_props["avb_system_hashtree_enable"] = _p("BOARD_AVB_ENABLE") 206 # image_props["avb_system_add_hashtree_footer_args"] = _p("BOARD_AVB_SYSTEM_ADD_HASHTREE_FOOTER_ARGS") 207 # if _p("BOARD_AVB_SYSTEM_KEY_PATH"): 208 # image_props["avb_system_key_path"] = _p("BOARD_AVB_SYSTEM_KEY_PATH") 209 # image_props["avb_system_algorithm"] = _p("BOARD_AVB_SYSTEM_ALGORITHM") 210 # image_props["avb_system_rollback_index_location"] = _p("BOARD_AVB_SYSTEM_ROLLBACK_INDEX_LOCATION") 211 # image_props["avb_system_other_hashtree_enable"] = _p("BOARD_AVB_ENABLE") 212 # image_props["avb_system_other_add_hashtree_footer_args"] = _p("BOARD_AVB_SYSTEM_OTHER_ADD_HASHTREE_FOOTER_ARGS") 213 # if _p("BOARD_AVB_SYSTEM_OTHER_KEY_PATH"): 214 # image_props["avb_system_other_key_path"] = _p("BOARD_AVB_SYSTEM_OTHER_KEY_PATH") 215 # image_props["avb_system_other_algorithm"] = _p("BOARD_AVB_SYSTEM_OTHER_ALGORITHM") 216 # image_props["avb_vendor_hashtree_enable"] = _p("BOARD_AVB_ENABLE") 217 # image_props["avb_vendor_add_hashtree_footer_args"] = _p("BOARD_AVB_VENDOR_ADD_HASHTREE_FOOTER_ARGS") 218 # if _p("BOARD_AVB_VENDOR_KEY_PATH"): 219 # image_props["avb_vendor_key_path"] = _p("BOARD_AVB_VENDOR_KEY_PATH") 220 # image_props["avb_vendor_algorithm"] = _p("BOARD_AVB_VENDOR_ALGORITHM") 221 # image_props["avb_vendor_rollback_index_location"] = _p("BOARD_AVB_VENDOR_ROLLBACK_INDEX_LOCATION") 222 # image_props["avb_product_hashtree_enable"] = _p("BOARD_AVB_ENABLE") 223 # image_props["avb_product_add_hashtree_footer_args"] = _p("BOARD_AVB_PRODUCT_ADD_HASHTREE_FOOTER_ARGS") 224 # if _p("BOARD_AVB_PRODUCT_KEY_PATH"): 225 # image_props["avb_product_key_path"] = _p("BOARD_AVB_PRODUCT_KEY_PATH") 226 # image_props["avb_product_algorithm"] = _p("BOARD_AVB_PRODUCT_ALGORITHM") 227 # image_props["avb_product_rollback_index_location"] = _p("BOARD_AVB_PRODUCT_ROLLBACK_INDEX_LOCATION") 228 # image_props["avb_system_ext_hashtree_enable"] = _p("BOARD_AVB_ENABLE") 229 # image_props["avb_system_ext_add_hashtree_footer_args"] = _p("BOARD_AVB_SYSTEM_EXT_ADD_HASHTREE_FOOTER_ARGS") 230 # if _p("BOARD_AVB_SYSTEM_EXT_KEY_PATH"): 231 # image_props["avb_system_ext_key_path"] = _p("BOARD_AVB_SYSTEM_EXT_KEY_PATH") 232 # image_props["avb_system_ext_algorithm"] = _p("BOARD_AVB_SYSTEM_EXT_ALGORITHM") 233 # image_props["avb_system_ext_rollback_index_location"] = _p("BOARD_AVB_SYSTEM_EXT_ROLLBACK_INDEX_LOCATION") 234 # image_props["avb_odm_hashtree_enable"] = _p("BOARD_AVB_ENABLE") 235 # image_props["avb_odm_add_hashtree_footer_args"] = _p("BOARD_AVB_ODM_ADD_HASHTREE_FOOTER_ARGS") 236 # if _p("BOARD_AVB_ODM_KEY_PATH"): 237 # image_props["avb_odm_key_path"] = _p("BOARD_AVB_ODM_KEY_PATH") 238 # image_props["avb_odm_algorithm"] = _p("BOARD_AVB_ODM_ALGORITHM") 239 # image_props["avb_odm_rollback_index_location"] = _p("BOARD_AVB_ODM_ROLLBACK_INDEX_LOCATION") 240 # image_props["avb_vendor_dlkm_hashtree_enable"] = _p("BOARD_AVB_ENABLE") 241 # image_props["avb_vendor_dlkm_add_hashtree_footer_args"] = _p("BOARD_AVB_VENDOR_DLKM_ADD_HASHTREE_FOOTER_ARGS") 242 # if _p("BOARD_AVB_VENDOR_DLKM_KEY_PATH"): 243 # image_props["avb_vendor_dlkm_key_path"] = _p("BOARD_AVB_VENDOR_DLKM_KEY_PATH") 244 # image_props["avb_vendor_dlkm_algorithm"] = _p("BOARD_AVB_VENDOR_DLKM_ALGORITHM") 245 # image_props["avb_vendor_dlkm_rollback_index_location"] = _p("BOARD_AVB_VENDOR_DLKM_ROLLBACK_INDEX_LOCATION") 246 # image_props["avb_odm_dlkm_hashtree_enable"] = _p("BOARD_AVB_ENABLE") 247 # image_props["avb_odm_dlkm_add_hashtree_footer_args"] = _p("BOARD_AVB_ODM_DLKM_ADD_HASHTREE_FOOTER_ARGS") 248 # if _p("BOARD_AVB_ODM_DLKM_KEY_PATH"): 249 # image_props["avb_odm_dlkm_key_path"] = _p("BOARD_AVB_ODM_DLKM_KEY_PATH") 250 # image_props["avb_odm_dlkm_algorithm"] = _p("BOARD_AVB_ODM_DLKM_ALGORITHM") 251 # image_props["avb_odm_dlkm_rollback_index_location"] = _p("BOARD_AVB_ODM_DLKM_ROLLBACK_INDEX_LOCATION") 252 # image_props["avb_system_dlkm_hashtree_enable"] = _p("BOARD_AVB_ENABLE") 253 # image_props["avb_system_dlkm_add_hashtree_footer_args"] = _p("BOARD_AVB_SYSTEM_DLKM_ADD_HASHTREE_FOOTER_ARGS") 254 # if _p("BOARD_AVB_SYSTEM_DLKM_KEY_PATH"): 255 # image_props["avb_system_dlkm_key_path"] = _p("BOARD_AVB_SYSTEM_DLKM_KEY_PATH") 256 # image_props["avb_system_dlkm_algorithm"] = _p("BOARD_AVB_SYSTEM_DLKM_ALGORITHM") 257 # image_props["avb_system_dlkm_rollback_index_location"] = _p("BOARD_SYSTEM_SYSTEM_DLKM_ROLLBACK_INDEX_LOCATION") 258 if _p("BOARD_USES_RECOVERY_AS_BOOT") == "true": 259 image_props["recovery_as_boot"] = "true" 260 if _p("BOARD_BUILD_GKI_BOOT_IMAGE_WITHOUT_RAMDISK") == "true": 261 image_props["gki_boot_image_without_ramdisk"] = "true" 262 263 #image_props["root_dir"] = _p("TARGET_ROOT_OUT") # TODO: replace with actual path 264 if _p("PRODUCT_USE_DYNAMIC_PARTITION_SIZE") == "true": 265 image_props["use_dynamic_partition_size"] = "true" 266 for k, v in extra_props.items(): 267 image_props[k] = v 268 269 result = "\n".join([k + "=" + v for k, v in image_props.items()]) 270 if result: 271 result += "\n" 272 return result 273 274def get_python3(ctx): 275 python_interpreter = ctx.toolchains["@bazel_tools//tools/python:toolchain_type"].py3_runtime.interpreter 276 if python_interpreter.basename == "python3": 277 return python_interpreter 278 279 renamed = ctx.actions.declare_file("python3") 280 ctx.actions.symlink( 281 output = renamed, 282 target_file = python_interpreter, 283 is_executable = True, 284 ) 285 return renamed 286 287def _partition_impl(ctx): 288 if ctx.attr.type != "system": 289 fail("currently only system images are supported") 290 291 toolchain = ctx.toolchains[":partition_toolchain_type"].toolchain_info 292 python_interpreter = get_python3(ctx) 293 294 # build_image requires that the output file be named specifically <type>.img, so 295 # put all the outputs under a name-qualified folder. 296 image_info = ctx.actions.declare_file(ctx.attr.name + "/image_info.txt") 297 output_image = ctx.actions.declare_file(ctx.attr.name + "/" + ctx.attr.type + ".img") 298 ctx.actions.write(image_info, _generate_image_prop_dictionary(ctx, [ctx.attr.type], {"skip_fsck": "true"})) 299 300 files = {} 301 for dep in ctx.attr.deps: 302 files.update(dep[InstallableInfo].files) 303 304 for v in files.keys(): 305 if not v.startswith("/system"): 306 fail("Files outside of /system are not currently supported: %s", v) 307 308 file_mapping_file = ctx.actions.declare_file(ctx.attr.name + "/partition_file_mapping.json") 309 310 # It seems build_image will prepend /system to the paths when building_system_image=true 311 ctx.actions.write(file_mapping_file, json.encode({k.removeprefix("/system"): v.path for k, v in files.items()})) 312 313 staging_dir = ctx.actions.declare_directory(ctx.attr.name + "_staging_dir") 314 315 ctx.actions.run( 316 inputs = [ 317 image_info, 318 file_mapping_file, 319 ] + files.keys(), 320 tools = [ 321 toolchain.build_image, 322 toolchain.mkuserimg_mke2fs, 323 python_interpreter, 324 ], 325 outputs = [output_image], 326 executable = ctx.executable._staging_dir_builder, 327 arguments = [ 328 file_mapping_file.path, 329 staging_dir.path, 330 toolchain.build_image.path, 331 staging_dir.path, 332 image_info.path, 333 output_image.path, 334 staging_dir.path, 335 ], 336 mnemonic = "BuildPartition", 337 # TODO: the /usr/bin addition is because build_image uses the du command 338 # in GetDiskUsage(). This can probably be rewritten to just use python code 339 # instead. 340 env = {"PATH": python_interpreter.dirname + ":/usr/bin"}, 341 ) 342 343 return DefaultInfo(files = depset([output_image])) 344 345_partition = rule( 346 implementation = _partition_impl, 347 attrs = { 348 "type": attr.string( 349 mandatory = True, 350 values = _IMAGE_TYPES, 351 ), 352 "deps": attr.label_list( 353 providers = [[InstallableInfo]], 354 aspects = [installable_aspect], 355 ), 356 "_staging_dir_builder": attr.label( 357 cfg = "exec", 358 doc = "The tool used to build a staging directory, because if bazel were to build it it would be entirely symlinks.", 359 executable = True, 360 default = "//build/bazel/rules:staging_dir_builder", 361 ), 362 }, 363 toolchains = [ 364 ":partition_toolchain_type", 365 "@bazel_tools//tools/python:toolchain_type", 366 ], 367) 368 369def partition(target_compatible_with = [], **kwargs): 370 target_compatible_with = select({ 371 "//build/bazel/platforms/os:android": [], 372 "//conditions:default": ["@platforms//:incompatible"], 373 }) + target_compatible_with 374 _partition( 375 target_compatible_with = target_compatible_with, 376 **kwargs 377 ) 378