• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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