1# Copyright (C) 2021 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("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo") 17load("@soong_injection//apex_toolchain:constants.bzl", "default_manifest_version") 18load("//build/bazel/platforms:platform_utils.bzl", "platforms") 19load("//build/bazel/rules:build_fingerprint.bzl", "BuildFingerprintInfo") 20load("//build/bazel/rules:common.bzl", "get_dep_targets") 21load("//build/bazel/rules:metadata.bzl", "MetadataFileInfo") 22load("//build/bazel/rules:prebuilt_file.bzl", "PrebuiltFileInfo") 23load("//build/bazel/rules:sh_binary.bzl", "ShBinaryInfo") 24load("//build/bazel/rules:toolchain_utils.bzl", "verify_toolchain_exists") 25load("//build/bazel/rules/android:android_app_certificate.bzl", "AndroidAppCertificateInfo", "NoAndroidAppCertificateInfo", "android_app_certificate_with_default_cert") 26load("//build/bazel/rules/android:manifest_fixer.bzl", "manifest_fixer") 27load("//build/bazel/rules/apex:cc.bzl", "ApexCcInfo", "ApexCcMkInfo", "apex_cc_aspect") 28load("//build/bazel/rules/apex:sdk_versions.bzl", "maybe_override_min_sdk_version") 29load("//build/bazel/rules/apex:transition.bzl", "apex_transition", "shared_lib_transition_32", "shared_lib_transition_64") 30load("//build/bazel/rules/cc:clang_tidy.bzl", "collect_deps_clang_tidy_info") 31load("//build/bazel/rules/cc:stripped_cc_common.bzl", "CcUnstrippedInfo", "StrippedCcBinaryInfo") 32load("//build/bazel/rules/common:api.bzl", "api") 33load( 34 "//build/bazel/rules/license:license_aspect.bzl", 35 "RuleLicensedDependenciesInfo", 36 "license_aspect", 37 "license_map", 38 "license_map_notice_files", 39 "license_map_to_json", 40) 41load(":apex_available.bzl", "ApexAvailableInfo", "apex_available_aspect") 42load(":apex_deps_validation.bzl", "ApexDepsInfo", "apex_deps_validation_aspect", "validate_apex_deps") 43load(":apex_info.bzl", "ApexInfo", "ApexMkInfo") 44load(":apex_key.bzl", "ApexKeyInfo") 45load(":bundle.bzl", "apex_zip_files") 46 47def _create_file_mapping(ctx): 48 """Create a file mapping for the APEX filesystem image. 49 50 This returns a Dict[File, str] where the dictionary keys are paths in the 51 apex staging dir / filesystem image, and the values are the files and other 52 metadata that should be installed there. 53 54 It also returns other data structures, such as: 55 - requires: libs that this apex depend on from other apex or the platform 56 - provides: libs that this apex provide to other apex or the platform 57 - make_modules_to_install: make module names of libs that needs to be installed onto the platform in a bundled build (LOCAL_REQUIRED_MODULES) 58 - make_files_info: metadata about this apex's payload to be used for other packaging steps. 59 """ 60 61 # Dictionary mapping from paths in the apex to the files and associated metadata to be put there 62 file_mapping = {} 63 requires = {} 64 provides = {} 65 make_modules_to_install = {} 66 metadata_file_mapping = {} 67 68 # Generate a str -> str dictionary to define Make modules and variables for the 69 # packaging step in a mixed build. This is necessary as long as there are 70 # Make-derived actions that operate on bazel's outputs. If we move all Make 71 # packaging actions to Bazel, there's no need for this data flow. 72 make_files_info = {} 73 74 arch = platforms.get_target_arch(ctx.attr._platform_utils) 75 is_target_64_bit = platforms.get_target_bitness(ctx.attr._platform_utils) == 64 76 77 def add_file_mapping(install_dir, basename, bazel_file, klass, owner, arch = None, unstripped = None, metadata_file = None): 78 installed_path = paths.join(install_dir, basename) 79 if installed_path in file_mapping and file_mapping[installed_path] != bazel_file: 80 # TODO: we should figure this out and make it a failure 81 print("Warning: %s in this apex is already installed to %s, overwriting it with %s" % 82 (file_mapping[installed_path].path, installed_path, bazel_file.path)) 83 file_mapping[installed_path] = bazel_file 84 metadata_file_mapping[installed_path] = metadata_file 85 86 files_info = { 87 "built_file": bazel_file.path, 88 "class": klass, 89 "install_dir": install_dir, 90 "basename": basename, 91 "package": owner.package, 92 "make_module_name": owner.name, 93 "arch": arch, 94 } 95 if unstripped: 96 files_info["unstripped_built_file"] = unstripped.path 97 make_files_info[installed_path] = files_info 98 99 def _add_lib_files(directory, libs, arch): 100 for dep in libs: 101 apex_cc_info = dep[ApexCcInfo] 102 for lib in apex_cc_info.requires_native_libs.to_list(): 103 requires[lib] = True 104 for lib in apex_cc_info.provides_native_libs.to_list(): 105 provides[lib] = True 106 for lib_file in apex_cc_info.transitive_shared_libs.to_list(): 107 stripped = lib_file.stripped 108 unstripped = lib_file.unstripped 109 add_file_mapping( 110 directory, 111 stripped.basename, 112 stripped, 113 "nativeSharedLib", 114 lib_file.generating_rule_owner, 115 arch = arch, 116 unstripped = unstripped, 117 metadata_file = lib_file.metadata_file, 118 ) 119 120 # For bundled builds. 121 apex_cc_mk_info = dep[ApexCcMkInfo] 122 for mk_module in apex_cc_mk_info.make_modules_to_install.to_list(): 123 make_modules_to_install[mk_module] = True 124 125 if is_target_64_bit: 126 _add_lib_files("lib64", ctx.attr.native_shared_libs_64, arch) 127 128 secondary_arch = platforms.get_target_secondary_arch(ctx.attr._platform_utils) 129 if secondary_arch: 130 _add_lib_files("lib", ctx.attr.native_shared_libs_32, secondary_arch) 131 else: 132 _add_lib_files("lib", ctx.attr.native_shared_libs_32, arch) 133 134 backing_libs = [] 135 for lib in file_mapping.values(): 136 if lib.basename not in backing_libs: 137 backing_libs.append(lib.basename) 138 backing_libs = sorted(backing_libs) 139 140 # Handle prebuilts 141 for dep in ctx.attr.prebuilts: 142 prebuilt_file_info = dep[PrebuiltFileInfo] 143 if prebuilt_file_info.filename: 144 filename = prebuilt_file_info.filename 145 else: 146 filename = dep.label.name 147 add_file_mapping( 148 prebuilt_file_info.dir, 149 filename, 150 prebuilt_file_info.src, 151 "etc", 152 dep.label, 153 arch = arch, 154 metadata_file = dep[MetadataFileInfo].metadata_file, 155 ) 156 157 # Handle binaries 158 for dep in ctx.attr.binaries: 159 if ShBinaryInfo in dep: 160 # sh_binary requires special handling on directory/filename construction. 161 sh_binary_info = dep[ShBinaryInfo] 162 if sh_binary_info: 163 directory = "bin" 164 if sh_binary_info.sub_dir: 165 directory = paths.join("bin", sh_binary_info.sub_dir) 166 167 filename = dep.label.name 168 if sh_binary_info.filename: 169 filename = sh_binary_info.filename 170 171 add_file_mapping( 172 directory, 173 filename, 174 dep[DefaultInfo].files_to_run.executable, 175 "shBinary", 176 dep.label, 177 arch = arch, 178 metadata_file = dep[MetadataFileInfo].metadata_file, 179 ) 180 elif ApexCcInfo in dep: 181 # cc_binary just takes the final executable from the runfiles. 182 add_file_mapping( 183 "bin", 184 dep.label.name, 185 dep[DefaultInfo].files_to_run.executable, 186 "nativeExecutable", 187 dep.label, 188 arch, 189 unstripped = dep[CcUnstrippedInfo].unstripped[0].files.to_list()[0], 190 metadata_file = dep[MetadataFileInfo].metadata_file, 191 ) 192 193 # Add transitive shared lib deps of apex binaries to the apex. 194 if is_target_64_bit: 195 _add_lib_files("lib64", [dep], arch) 196 else: 197 _add_lib_files("lib", [dep], arch) 198 199 return ( 200 file_mapping, 201 sorted(requires.keys(), key = lambda x: x.name), # sort on just the name of the target, not package 202 sorted(provides.keys(), key = lambda x: x.name), 203 backing_libs, 204 sorted(make_modules_to_install), 205 sorted(make_files_info.values(), key = lambda x: ":".join([x["package"], x["make_module_name"], x["arch"]])), 206 metadata_file_mapping, 207 ) 208 209def _add_so(label): 210 return label.name + ".so" 211 212def _add_apex_manifest_information( 213 ctx, 214 apex_toolchain, 215 requires_native_libs, 216 provides_native_libs): 217 apex_manifest_json = ctx.file.manifest 218 apex_manifest_full_json = ctx.actions.declare_file(ctx.attr.name + "_apex_manifest_full.json") 219 220 args = ctx.actions.args() 221 args.add(apex_manifest_json) 222 args.add_all(["-a", "requireNativeLibs"]) 223 args.add_all(requires_native_libs, map_each = _add_so) # e.g. turn "//foo/bar:baz" to "baz.so" 224 args.add_all(["-a", "provideNativeLibs"]) 225 args.add_all(provides_native_libs, map_each = _add_so) 226 227 manifest_version = default_manifest_version 228 if ctx.attr.variant_version != "": 229 manifest_version = manifest_version + int(ctx.attr.variant_version) 230 override_manifest_version = ctx.attr._override_apex_manifest_default_version[BuildSettingInfo].value 231 if override_manifest_version: 232 manifest_version = override_manifest_version 233 args.add_all(["-se", "version", "0", manifest_version]) 234 235 # TODO: support other optional flags like -v name and -a jniLibs 236 args.add_all(["-o", apex_manifest_full_json]) 237 238 ctx.actions.run( 239 inputs = [apex_manifest_json], 240 outputs = [apex_manifest_full_json], 241 executable = apex_toolchain.jsonmodify[DefaultInfo].files_to_run, 242 arguments = [args], 243 mnemonic = "ApexManifestModify", 244 ) 245 246 return apex_manifest_full_json 247 248# conv_apex_manifest - Convert the JSON APEX manifest to protobuf, which is needed by apexer. 249def _convert_apex_manifest_json_to_pb(ctx, apex_toolchain, apex_manifest_json): 250 apex_manifest_pb = ctx.actions.declare_file(ctx.attr.name + "_apex_manifest.pb") 251 252 ctx.actions.run( 253 outputs = [apex_manifest_pb], 254 inputs = [apex_manifest_json], 255 executable = apex_toolchain.conv_apex_manifest[DefaultInfo].files_to_run, 256 arguments = [ 257 "proto", 258 apex_manifest_json.path, 259 "-o", 260 apex_manifest_pb.path, 261 ], 262 mnemonic = "ConvApexManifest", 263 ) 264 265 return apex_manifest_pb 266 267def _generate_canned_fs_config(ctx, filepaths): 268 """Generate filesystem config. 269 270 This encodes the filemode, uid, and gid of each file in the APEX, 271 including apex_manifest.json and apex_manifest.pb. 272 NOTE: every file must have an entry. 273 """ 274 275 # Ensure all paths don't start with / and are normalized 276 filepaths = [paths.normalize(f).lstrip("/") for f in filepaths] 277 278 # Soong also sorts the config lines to be consistent with bazel 279 filepaths = sorted([f for f in filepaths if f]) 280 281 # First, collect a set of all the directories in the apex 282 apex_subdirs_set = {} 283 for f in filepaths: 284 d = paths.dirname(f) 285 if d != "": # The root dir is handled manually below 286 # Make sure all the parent dirs of the current subdir are in the set, too 287 dirs = d.split("/") 288 for i in range(1, len(dirs) + 1): 289 apex_subdirs_set["/".join(dirs[:i])] = True 290 291 config_lines = [] 292 config_lines.append("/ 1000 1000 0755") 293 config_lines.append("/apex_manifest.json 1000 1000 0644") 294 config_lines.append("/apex_manifest.pb 1000 1000 0644") 295 296 # Readonly if not executable. filepaths is already sorted. 297 config_lines += ["/" + f + " 1000 1000 0644" for f in filepaths if not f.startswith("bin/")] 298 299 # Mark all binaries as executable. filepaths is already sorted. 300 config_lines += ["/" + f + " 0 2000 0755" for f in filepaths if f.startswith("bin/")] 301 302 # All directories have the same permission. 303 config_lines += ["/" + d + " 0 2000 0755" for d in sorted(apex_subdirs_set.keys())] 304 305 output = ctx.actions.declare_file(ctx.attr.name + "_canned_fs_config.txt") 306 307 config_lines = "\n".join(config_lines) + "\n" 308 ctx.actions.write(output, config_lines) 309 310 if ctx.attr.canned_fs_config: 311 # Append the custom fs config content to the existing file 312 combined_output = ctx.actions.declare_file(ctx.attr.name + "_combined_canned_fs_config.txt") 313 ctx.actions.run_shell( 314 inputs = [ctx.file.canned_fs_config, output], 315 outputs = [combined_output], 316 mnemonic = "AppendCustomFsConfig", 317 command = "cat {i} {canned_fs_config} > {o}".format( 318 i = output.path, 319 o = combined_output.path, 320 canned_fs_config = ctx.file.canned_fs_config.path, 321 ), 322 ) 323 output = combined_output 324 325 return output 326 327# Append an entry for apex_manifest.pb to the file_contexts file for this APEX, 328# which is either from /system/sepolicy/apex/<apexname>-file_contexts (set in 329# the apex macro) or custom file_contexts attribute value of this APEX. This 330# ensures that the manifest file is correctly labeled as system_file. 331def _generate_file_contexts(ctx): 332 file_contexts = ctx.actions.declare_file(ctx.attr.name + "-file_contexts") 333 334 ctx.actions.run_shell( 335 inputs = [ctx.file.file_contexts], 336 outputs = [file_contexts], 337 mnemonic = "GenerateApexFileContexts", 338 command = "cat {i} > {o} && echo >> {o} && echo /apex_manifest\\\\.pb u:object_r:system_file:s0 >> {o} && echo / u:object_r:system_file:s0 >> {o}" 339 .format(i = ctx.file.file_contexts.path, o = file_contexts.path), 340 ) 341 342 return file_contexts 343 344def _mark_manifest_as_test_only(ctx, apex_toolchain): 345 android_manifest = ctx.file.android_manifest 346 dir_name = android_manifest.dirname 347 base_name = android_manifest.basename 348 android_manifest_fixed = ctx.actions.declare_file(paths.join(dir_name, "manifest_fixer", base_name)) 349 manifest_fixer.fix( 350 ctx, 351 manifest_fixer = apex_toolchain.manifest_fixer[DefaultInfo].files_to_run, 352 in_manifest = android_manifest, 353 out_manifest = android_manifest_fixed, 354 mnemonic = "MarkAndroidManifestTestOnly", 355 test_only = True, 356 ) 357 return android_manifest_fixed 358 359# Generate <APEX>_backing.txt file which lists all libraries used by the APEX. 360def _generate_apex_backing_file(ctx, backing_libs): 361 backing_file = ctx.actions.declare_file(ctx.attr.name + "_backing.txt") 362 ctx.actions.write( 363 output = backing_file, 364 content = " ".join(backing_libs) + "\n", 365 ) 366 return backing_file 367 368# Generate installed-files.txt which lists all installed files by the APEX. 369def _generate_installed_files_list(ctx, file_mapping): 370 installed_files = ctx.actions.declare_file(ctx.attr.name + "-installed-files.txt") 371 command = [] 372 for device_path, bazel_file in file_mapping.items(): 373 command.append("echo $(stat -L -c %%s %s) ./%s" % (bazel_file.path, device_path)) 374 ctx.actions.run_shell( 375 inputs = file_mapping.values(), 376 outputs = [installed_files], 377 mnemonic = "GenerateApexInstalledFileList", 378 command = "(" + "; ".join(command) + ") | sort -nr > " + installed_files.path, 379 ) 380 return installed_files 381 382def _generate_notices(ctx, apex_toolchain): 383 licensees = license_map(ctx.attr.binaries + ctx.attr.prebuilts + ctx.attr.native_shared_libs_32 + ctx.attr.native_shared_libs_64) 384 licenses_file = ctx.actions.declare_file(ctx.attr.name + "_licenses.json") 385 ctx.actions.write(licenses_file, "[\n%s\n]\n" % ",\n".join(license_map_to_json(licensees))) 386 387 # Run HTML notice file generator. 388 notice_file = ctx.actions.declare_file(ctx.attr.name + "_notice_dir/NOTICE.html.gz") 389 notice_generator = apex_toolchain.notice_generator[DefaultInfo].files_to_run 390 391 args = ctx.actions.args() 392 args.add_all(["-o", notice_file, licenses_file]) 393 394 # TODO(asmundak): should we extend it with license info for self 395 # (the case when APEX itself has applicable_licenses attribute)? 396 inputs = license_map_notice_files(licensees) + [licenses_file] 397 ctx.actions.run( 398 mnemonic = "GenerateNoticeFile", 399 inputs = inputs, 400 outputs = [notice_file], 401 executable = notice_generator, 402 tools = [notice_generator], 403 arguments = [args], 404 ) 405 return notice_file 406 407def _use_api_fingerprint(ctx): 408 if not ctx.attr._unbundled_build[BuildSettingInfo].value: 409 return False 410 if ctx.attr._always_use_prebuilt_sdks[BuildSettingInfo].value: 411 return False 412 if not ctx.attr._unbundled_build_target_sdk_with_api_fingerprint[BuildSettingInfo].value: 413 return False 414 return True 415 416# apexer - generate the APEX file. 417def _run_apexer(ctx, apex_toolchain): 418 # Inputs 419 apex_key_info = ctx.attr.key[ApexKeyInfo] 420 privkey = apex_key_info.private_key 421 pubkey = apex_key_info.public_key 422 android_jar = apex_toolchain.android_jar 423 424 file_mapping, requires_native_libs, provides_native_libs, backing_libs, make_modules_to_install, make_files_info, metadata_file_mapping = _create_file_mapping(ctx) 425 canned_fs_config = _generate_canned_fs_config(ctx, file_mapping.keys()) 426 file_contexts = _generate_file_contexts(ctx) 427 full_apex_manifest_json = _add_apex_manifest_information(ctx, apex_toolchain, requires_native_libs, provides_native_libs) 428 apex_manifest_pb = _convert_apex_manifest_json_to_pb(ctx, apex_toolchain, full_apex_manifest_json) 429 notices_file = _generate_notices(ctx, apex_toolchain) 430 api_fingerprint_file = None 431 432 staging_dir_builder_options_file = ctx.actions.declare_file(ctx.attr.name + "_staging_dir_builder_options.json") 433 ctx.actions.write(staging_dir_builder_options_file, json.encode({ 434 "file_mapping": {k: v.path for k, v in file_mapping.items()}, 435 })) 436 437 # Outputs 438 apex_output_file = ctx.actions.declare_file(ctx.attr.name + ".apex.unsigned") 439 440 apexer_files = apex_toolchain.apexer[DefaultInfo].files_to_run 441 442 # Arguments 443 command = [ctx.executable._staging_dir_builder.path, staging_dir_builder_options_file.path] 444 445 # start of apexer cmd 446 command.append(apexer_files.executable.path) 447 448 command.append("--force") 449 command.append("--include_build_info") 450 command.extend(["--canned_fs_config", canned_fs_config.path]) 451 command.extend(["--manifest", apex_manifest_pb.path]) 452 command.extend(["--file_contexts", file_contexts.path]) 453 command.extend(["--key", privkey.path]) 454 command.extend(["--pubkey", pubkey.path]) 455 command.extend(["--payload_type", "image"]) 456 command.extend(["--payload_fs_type", "ext4"]) 457 command.extend(["--assets_dir", notices_file.dirname]) 458 459 # Override the package name, if it's expicitly specified 460 if ctx.attr.package_name: 461 command.extend(["--override_apk_package_name", ctx.attr.package_name]) 462 else: 463 override_package_name = _override_manifest_package_name(ctx) 464 if override_package_name: 465 command.extend(["--override_apk_package_name", override_package_name]) 466 467 if ctx.attr.logging_parent: 468 command.extend(["--logging_parent", ctx.attr.logging_parent]) 469 470 use_api_fingerprint = _use_api_fingerprint(ctx) 471 472 target_sdk_version = str(api.final_or_future(api.default_app_target_sdk())) 473 if use_api_fingerprint: 474 api_fingerprint_file = ctx.file._api_fingerprint_txt 475 sdk_version_suffix = ".$(cat {})".format(api_fingerprint_file.path) 476 target_sdk_version = ctx.attr._platform_sdk_codename[BuildSettingInfo].value + sdk_version_suffix 477 478 command.extend(["--target_sdk_version", target_sdk_version]) 479 480 # TODO(b/215339575): This is a super rudimentary way to convert "current" to a numerical number. 481 # Generalize this to API level handling logic in a separate Starlark utility, preferably using 482 # API level maps dumped from api_levels.go 483 min_sdk_version = ctx.attr.min_sdk_version 484 if min_sdk_version == "current": 485 min_sdk_version = "10000" 486 487 override_min_sdk_version = ctx.attr._apex_global_min_sdk_version_override[BuildSettingInfo].value 488 min_sdk_version = str(maybe_override_min_sdk_version(min_sdk_version, override_min_sdk_version)) 489 490 if min_sdk_version == "10000" and use_api_fingerprint: 491 min_sdk_version = ctx.attr._platform_sdk_codename[BuildSettingInfo].value + sdk_version_suffix 492 command.append(api_fingerprint_file.path) 493 command.extend(["--min_sdk_version", min_sdk_version]) 494 495 # apexer needs the list of directories containing all auxilliary tools invoked during 496 # the creation of an apex 497 avbtool_files = apex_toolchain.avbtool[DefaultInfo].files_to_run 498 e2fsdroid_files = apex_toolchain.e2fsdroid[DefaultInfo].files_to_run 499 mke2fs_files = apex_toolchain.mke2fs[DefaultInfo].files_to_run 500 resize2fs_files = apex_toolchain.resize2fs[DefaultInfo].files_to_run 501 sefcontext_compile_files = apex_toolchain.sefcontext_compile[DefaultInfo].files_to_run 502 staging_dir_builder_files = ctx.attr._staging_dir_builder[DefaultInfo].files_to_run 503 apexer_tool_paths = [ 504 apex_toolchain.aapt2.dirname, 505 apexer_files.executable.dirname, 506 avbtool_files.executable.dirname, 507 e2fsdroid_files.executable.dirname, 508 mke2fs_files.executable.dirname, 509 resize2fs_files.executable.dirname, 510 sefcontext_compile_files.executable.dirname, 511 ] 512 513 command.extend(["--apexer_tool_path", ":".join(apexer_tool_paths)]) 514 515 android_manifest = ctx.file.android_manifest 516 if android_manifest != None: 517 if ctx.attr.testonly: 518 android_manifest = _mark_manifest_as_test_only(ctx, apex_toolchain) 519 command.extend(["--android_manifest", android_manifest.path]) 520 elif ctx.attr.testonly: 521 command.append("--test_only") 522 523 command.append("STAGING_DIR_PLACEHOLDER") 524 command.append(apex_output_file.path) 525 526 inputs = [ 527 ctx.executable._staging_dir_builder, 528 staging_dir_builder_options_file, 529 canned_fs_config, 530 apex_manifest_pb, 531 file_contexts, 532 notices_file, 533 privkey, 534 pubkey, 535 android_jar, 536 ] + file_mapping.values() 537 if use_api_fingerprint: 538 inputs.append(api_fingerprint_file) 539 540 if android_manifest != None: 541 inputs.append(android_manifest) 542 543 # This is run_shell instead of run because --target_sdk_version may 544 # use the API fingerprinting file contents using bash expansion, 545 # and only run_shell can support that by executing the whole command with 546 # /bin/bash -c. Regular run would quote the --target_sdk_version value with 547 # single quotes ('--target_sdk_version=ABC.$(cat version.txt)'), preventing 548 # bash expansion. 549 ctx.actions.run_shell( 550 inputs = inputs, 551 tools = [ 552 apexer_files, 553 avbtool_files, 554 e2fsdroid_files, 555 mke2fs_files, 556 resize2fs_files, 557 sefcontext_compile_files, 558 apex_toolchain.aapt2, 559 staging_dir_builder_files, 560 ], 561 outputs = [apex_output_file], 562 command = " ".join(command), 563 mnemonic = "Apexer", 564 ) 565 return struct( 566 unsigned_apex = apex_output_file, 567 requires_native_libs = requires_native_libs, 568 provides_native_libs = provides_native_libs, 569 backing_libs = _generate_apex_backing_file(ctx, backing_libs), 570 symbols_used_by_apex = _generate_symbols_used_by_apex(ctx, apex_toolchain, file_mapping), 571 java_symbols_used_by_apex = _generate_java_symbols_used_by_apex(ctx, apex_toolchain), 572 installed_files = _generate_installed_files_list(ctx, file_mapping), 573 make_modules_to_install = make_modules_to_install, 574 make_files_info = make_files_info, 575 file_mapping = file_mapping, 576 metadata_file_mapping = metadata_file_mapping, 577 ) 578 579def _run_signapk(ctx, unsigned_file, signed_file, private_key, public_key, mnemonic): 580 """Sign a file with signapk.""" 581 582 # Arguments 583 args = ctx.actions.args() 584 args.add_all(["-a", 4096]) 585 args.add_all(["--align-file-size"]) 586 args.add_all([public_key, private_key]) 587 args.add_all([unsigned_file, signed_file]) 588 589 ctx.actions.run( 590 inputs = [ 591 unsigned_file, 592 private_key, 593 public_key, 594 ctx.executable._signapk, 595 ], 596 outputs = [signed_file], 597 executable = ctx.executable._signapk, 598 arguments = [args], 599 mnemonic = mnemonic, 600 ) 601 602 return signed_file 603 604# See also getOverrideManifestPackageName 605# https://cs.android.com/android/platform/superproject/+/master:build/soong/apex/builder.go;l=1000;drc=241e738c7156d928e9a993b15993cb3297face45 606def _override_manifest_package_name(ctx): 607 apex_name = ctx.attr.name 608 overrides = ctx.attr._manifest_package_name_overrides[BuildSettingInfo].value 609 if not overrides: 610 return None 611 612 matches = [o for o in overrides if o.split(":")[0] == apex_name] 613 614 if not matches: 615 return None 616 617 if len(matches) > 1: 618 fail("unexpected multiple manifest package overrides for %s, %s" % (apex_name, matches)) 619 620 return matches[0].split(":")[1] 621 622# https://cs.android.com/android/platform/superproject/+/master:build/soong/android/config.go;drc=5ca657189aac546af0aafaba11bbc9c5d889eab3;l=1501 623# In Soong, we don't check whether the current apex is part of Unbundled_apps. 624# Hence, we might simplify the logic by just checking product_vars["Unbundled_build"] 625# TODO(b/271474456): Eventually we might default to unbundled mode in bazel-only mode 626# so that we don't need to check Unbundled_apps. 627def _compression_enabled(ctx): 628 compressed_apex = ctx.attr._compressed_apex[BuildSettingInfo].value 629 unbundled_apps = ctx.attr._unbundled_build_apps[BuildSettingInfo].value 630 631 return compressed_apex and len(unbundled_apps) == 0 632 633# Compress a file with apex_compression_tool. 634def _run_apex_compression_tool(ctx, apex_toolchain, input_file, output_file_name): 635 avbtool_files = apex_toolchain.avbtool[DefaultInfo].files_to_run 636 apex_compression_tool_files = apex_toolchain.apex_compression_tool[DefaultInfo].files_to_run 637 638 # Outputs 639 compressed_file = ctx.actions.declare_file(output_file_name) 640 641 # Arguments 642 args = ctx.actions.args() 643 args.add_all(["compress"]) 644 tool_dirs = [apex_toolchain.soong_zip.dirname, avbtool_files.executable.dirname] 645 args.add_all(["--apex_compression_tool", ":".join(tool_dirs)]) 646 args.add_all(["--input", input_file]) 647 args.add_all(["--output", compressed_file]) 648 649 ctx.actions.run( 650 inputs = [input_file], 651 tools = [ 652 avbtool_files, 653 apex_compression_tool_files, 654 apex_toolchain.soong_zip, 655 ], 656 outputs = [compressed_file], 657 executable = apex_compression_tool_files, 658 arguments = [args], 659 mnemonic = "BazelApexCompressing", 660 ) 661 return compressed_file 662 663# Generate <module>_using.txt, which contains a list of versioned NDK symbols 664# dynamically linked to by this APEX's contents. This is used for coverage 665# checks. 666def _generate_symbols_used_by_apex(ctx, apex_toolchain, file_mapping): 667 staging_dir_builder_options_file = ctx.actions.declare_file(ctx.attr.name + "_generate_symbols_used_by_apex_staging_dir_builder_options.json") 668 ctx.actions.write(staging_dir_builder_options_file, json.encode({ 669 "file_mapping": {k: v.path for k, v in file_mapping.items()}, 670 })) 671 symbols_used_by_apex = ctx.actions.declare_file(ctx.attr.name + "_using.txt") 672 ctx.actions.run( 673 outputs = [symbols_used_by_apex], 674 inputs = [staging_dir_builder_options_file] + file_mapping.values(), 675 tools = [ 676 apex_toolchain.readelf.files_to_run, 677 apex_toolchain.gen_ndk_usedby_apex.files_to_run, 678 ], 679 executable = ctx.executable._staging_dir_builder, 680 arguments = [ 681 staging_dir_builder_options_file.path, 682 apex_toolchain.gen_ndk_usedby_apex.files_to_run.executable.path, 683 "STAGING_DIR_PLACEHOLDER", 684 apex_toolchain.readelf.files_to_run.executable.path, 685 symbols_used_by_apex.path, 686 ], 687 progress_message = "Generating dynamic NDK symbol list used by the %s apex" % ctx.attr.name, 688 mnemonic = "ApexUsingNDKSymbolsForCoverage", 689 ) 690 return symbols_used_by_apex 691 692# Generate <module>_using.xml, which contains a list of java API metadata used 693# by this APEX's contents. This is used for coverage checks. 694# 695# TODO(b/257954111): Add JARs and APKs as inputs to this action when we start 696# building Java mainline modules. 697def _generate_java_symbols_used_by_apex(ctx, apex_toolchain): 698 java_symbols_used_by_apex = ctx.actions.declare_file(ctx.attr.name + "_using.xml") 699 ctx.actions.run( 700 outputs = [java_symbols_used_by_apex], 701 inputs = [], 702 tools = [ 703 apex_toolchain.dexdeps.files_to_run, 704 apex_toolchain.gen_java_usedby_apex.files_to_run, 705 ], 706 executable = apex_toolchain.gen_java_usedby_apex.files_to_run, 707 arguments = [ 708 apex_toolchain.dexdeps.files_to_run.executable.path, 709 java_symbols_used_by_apex.path, 710 ], 711 progress_message = "Generating Java symbol list used by the %s apex" % ctx.attr.name, 712 mnemonic = "ApexUsingJavaSymbolsForCoverage", 713 ) 714 return java_symbols_used_by_apex 715 716def _validate_apex_deps(ctx): 717 transitive_deps = depset( 718 transitive = [ 719 d[ApexDepsInfo].transitive_deps 720 for d in ( 721 ctx.attr.native_shared_libs_32 + 722 ctx.attr.native_shared_libs_64 + 723 ctx.attr.binaries + 724 ctx.attr.prebuilts 725 ) 726 ], 727 ) 728 validation_files = [] 729 if not ctx.attr._unsafe_disable_apex_allowed_deps_check[BuildSettingInfo].value: 730 validation_files.append(validate_apex_deps(ctx, transitive_deps, ctx.file.allowed_apex_deps_manifest)) 731 732 transitive_unvalidated_targets = [] 733 transitive_invalid_targets = [] 734 for _, attr_deps in get_dep_targets(ctx.attr, predicate = lambda target: ApexAvailableInfo in target).items(): 735 for dep in attr_deps: 736 transitive_unvalidated_targets.append(dep[ApexAvailableInfo].transitive_unvalidated_targets) 737 transitive_invalid_targets.append(dep[ApexAvailableInfo].transitive_invalid_targets) 738 739 invalid_targets = depset(transitive = transitive_invalid_targets).to_list() 740 if len(invalid_targets) > 0: 741 invalid_targets_msg = "\n ".join([ 742 "{label}; apex_available tags: {tags}".format(label = target.label, tags = list(apex_available_tags)) 743 for target, apex_available_tags in invalid_targets 744 ]) 745 msg = ("`{apex_name}` apex has transitive dependencies that do not include the apex in " + 746 "their apex_available tags:\n {invalid_targets_msg}").format( 747 apex_name = ctx.label, 748 invalid_targets_msg = invalid_targets_msg, 749 ) 750 fail(msg) 751 752 transitive_unvalidated_targets_output_file = ctx.actions.declare_file(ctx.attr.name + "_unvalidated_deps.txt") 753 ctx.actions.write( 754 transitive_unvalidated_targets_output_file, 755 "\n".join([ 756 str(label) + ": " + str(reason) 757 for label, reason in depset(transitive = transitive_unvalidated_targets).to_list() 758 ]), 759 ) 760 return transitive_deps, transitive_unvalidated_targets_output_file, validation_files 761 762def _verify_updatability(ctx): 763 # TODO(b/274732759): Add these checks as more APEXes are converted to Bazel. 764 # 765 # Keep this in sync with build/soong/apex/apex.go#checkUpdatable. 766 # 767 # - Cannot use platform APIs. 768 # - Cannot use external VNDK libs. 769 # - Does not set future_updatable. 770 771 if not ctx.attr.min_sdk_version: 772 fail("updatable APEXes must set min_sdk_version.") 773 774def _generate_sbom(ctx, file_mapping, metadata_file_mapping, apex_file): 775 apex_filename = paths.basename(apex_file.path) 776 sbom_metadata_csv = ctx.actions.declare_file(apex_filename + "-sbom-metadata.csv") 777 command = [] 778 metadata_files = [] 779 sbom_metadata_csv_columns = [ 780 "installed_file", 781 "module_path", 782 "soong_module_type", 783 "is_prebuilt_make_module", 784 "product_copy_files", 785 "kernel_module_copy_files", 786 "is_platform_generated", 787 "build_output_path", 788 "static_libraries", 789 "whole_static_libraries", 790 "is_static_lib", 791 ] 792 command.append("echo " + ",".join(sbom_metadata_csv_columns)) 793 command.append("echo %s,%s,,,,,,%s,,," % (apex_filename, ctx.label.package, apex_file.path)) 794 for installed_file, bazel_output_file in file_mapping.items(): 795 if metadata_file_mapping[installed_file]: 796 metadata_files.append(metadata_file_mapping[installed_file]) 797 command.append("echo %s,%s,,,,,,%s,,," % (installed_file, paths.dirname(bazel_output_file.short_path), bazel_output_file.path)) 798 ctx.actions.run_shell( 799 inputs = file_mapping.values(), 800 outputs = [sbom_metadata_csv], 801 mnemonic = "GenerateSBOMMetadata", 802 command = "(" + "; ".join(command) + ") > " + sbom_metadata_csv.path, 803 ) 804 805 sbom_file = ctx.actions.declare_file(apex_filename + ".spdx.json") 806 sbom_fragment_file = ctx.actions.declare_file(apex_filename + "-fragment.spdx") 807 inputs = [ 808 apex_file, 809 sbom_metadata_csv, 810 ctx.executable._generate_sbom, 811 ] 812 inputs += file_mapping.values() 813 inputs += metadata_files 814 815 build_fingerprint = ctx.attr._build_fingerprint[BuildFingerprintInfo].fingerprint_blank_build_number 816 ctx.actions.run( 817 inputs = inputs, 818 outputs = [sbom_file, sbom_fragment_file], 819 arguments = [ 820 "--output_file", 821 sbom_file.path, 822 "--metadata", 823 sbom_metadata_csv.path, 824 "--build_version", 825 build_fingerprint, 826 "--product_mfr", 827 ctx.attr._product_manufacturer[BuildSettingInfo].value, 828 "--json", 829 "--unbundled_apex", 830 ], 831 mnemonic = "GenerateSBOM", 832 executable = ctx.executable._generate_sbom, 833 ) 834 return [sbom_file, sbom_fragment_file] 835 836# See the APEX section in the README on how to use this rule. 837def _apex_rule_impl(ctx): 838 verify_toolchain_exists(ctx, "//build/bazel/rules/apex:apex_toolchain_type") 839 if ctx.attr.updatable: 840 _verify_updatability(ctx) 841 842 apex_toolchain = ctx.toolchains["//build/bazel/rules/apex:apex_toolchain_type"].toolchain_info 843 844 apexer_outputs = _run_apexer(ctx, apex_toolchain) 845 unsigned_apex = apexer_outputs.unsigned_apex 846 847 if AndroidAppCertificateInfo in ctx.attr.certificate_override[0]: 848 apex_cert_info = ctx.attr.certificate_override[0][AndroidAppCertificateInfo] 849 else: 850 apex_cert_info = ctx.attr.certificate[0][AndroidAppCertificateInfo] 851 852 private_key = apex_cert_info.pk8 853 public_key = apex_cert_info.pem 854 855 signed_apex = ctx.actions.declare_file(ctx.attr.name + ".apex") 856 signed_capex = None 857 858 _run_signapk(ctx, unsigned_apex, signed_apex, private_key, public_key, "BazelApexSigning") 859 860 if ctx.attr.compressible and _compression_enabled(ctx): 861 compressed_apex_output_file = _run_apex_compression_tool(ctx, apex_toolchain, signed_apex, ctx.attr.name + ".capex.unsigned") 862 signed_capex = ctx.actions.declare_file(ctx.attr.name + ".capex") 863 _run_signapk(ctx, compressed_apex_output_file, signed_capex, private_key, public_key, "BazelCompressedApexSigning") 864 865 apex_key_info = ctx.attr.key[ApexKeyInfo] 866 867 arch = platforms.get_target_arch(ctx.attr._platform_utils) 868 zip_files = apex_zip_files( 869 actions = ctx.actions, 870 name = ctx.label.name, 871 tools = struct( 872 aapt2 = apex_toolchain.aapt2, 873 zip2zip = ctx.executable._zip2zip, 874 merge_zips = ctx.executable._merge_zips, 875 soong_zip = apex_toolchain.soong_zip, 876 ), 877 apex_file = signed_apex, 878 arch = arch, 879 secondary_arch = platforms.get_target_secondary_arch(ctx.attr._platform_utils), 880 ) 881 882 transitive_apex_deps, transitive_unvalidated_targets_output_file, apex_deps_validation_files = _validate_apex_deps(ctx) 883 884 optional_output_groups = {} 885 if signed_capex: 886 optional_output_groups["signed_compressed_output"] = [signed_capex] 887 888 return [ 889 DefaultInfo(files = depset([signed_apex])), 890 ApexInfo( 891 signed_output = signed_apex, 892 signed_compressed_output = signed_capex, 893 unsigned_output = unsigned_apex, 894 requires_native_libs = apexer_outputs.requires_native_libs, 895 provides_native_libs = apexer_outputs.provides_native_libs, 896 bundle_key_info = apex_key_info, 897 container_key_info = apex_cert_info, 898 package_name = ctx.attr.package_name, 899 backing_libs = apexer_outputs.backing_libs, 900 symbols_used_by_apex = apexer_outputs.symbols_used_by_apex, 901 installed_files = apexer_outputs.installed_files, 902 java_symbols_used_by_apex = apexer_outputs.java_symbols_used_by_apex, 903 base_file = zip_files.apex_only, 904 base_with_config_zip = zip_files.apex_with_config, 905 ), 906 OutputGroupInfo( 907 coverage_files = [apexer_outputs.symbols_used_by_apex], 908 java_coverage_files = [apexer_outputs.java_symbols_used_by_apex], 909 backing_libs = depset([apexer_outputs.backing_libs]), 910 installed_files = depset([apexer_outputs.installed_files]), 911 transitive_unvalidated_targets = depset([transitive_unvalidated_targets_output_file]), 912 apex_sbom = depset(_generate_sbom(ctx, apexer_outputs.file_mapping, apexer_outputs.metadata_file_mapping, signed_apex)), 913 capex_sbom = depset(_generate_sbom(ctx, apexer_outputs.file_mapping, apexer_outputs.metadata_file_mapping, signed_capex) if signed_capex else []), 914 _validation = apex_deps_validation_files, 915 **optional_output_groups 916 ), 917 ApexDepsInfo(transitive_deps = transitive_apex_deps), 918 ApexMkInfo( 919 make_modules_to_install = apexer_outputs.make_modules_to_install, 920 files_info = apexer_outputs.make_files_info, 921 ), 922 collect_deps_clang_tidy_info(ctx), 923 ] 924 925# These are the standard aspects that should be applied on all edges that 926# contribute to an APEX's payload. 927STANDARD_PAYLOAD_ASPECTS = [ 928 license_aspect, 929 apex_available_aspect, 930 apex_deps_validation_aspect, 931] 932 933_apex = rule( 934 implementation = _apex_rule_impl, 935 attrs = { 936 # Attributes that configure the APEX container. 937 "manifest": attr.label(allow_single_file = [".json"]), 938 "android_manifest": attr.label(allow_single_file = [".xml"]), 939 "package_name": attr.string(), 940 "logging_parent": attr.string(), 941 "file_contexts": attr.label(allow_single_file = True, mandatory = True), 942 "canned_fs_config": attr.label( 943 allow_single_file = True, 944 doc = """Path to the canned fs config file for customizing file's 945uid/gid/mod/capabilities. The content of this file is appended to the 946default config, so that the custom entries are preferred. 947 948The format is /<path_or_glob> <uid> <gid> <mode> [capabilities=0x<cap>], where 949path_or_glob is a path or glob pattern for a file or set of files, uid/gid 950are numerial values of user ID and group ID, mode is octal value for the 951file mode, and cap is hexadecimal value for the capability.""", 952 ), 953 "key": attr.label(providers = [ApexKeyInfo], mandatory = True), 954 "certificate": attr.label( 955 providers = [AndroidAppCertificateInfo], 956 mandatory = True, 957 cfg = apex_transition, 958 ), 959 "certificate_override": attr.label( 960 providers = [[AndroidAppCertificateInfo], [NoAndroidAppCertificateInfo]], 961 mandatory = True, 962 cfg = apex_transition, 963 ), 964 "min_sdk_version": attr.string( 965 default = "current", 966 doc = """The minimum SDK version that this APEX must support at minimum. This is usually set to 967the SDK version that the APEX was first introduced. 968 969When not set, defaults to "10000" (or "current").""", 970 ), 971 "updatable": attr.bool(default = True, doc = """Whether this APEX is considered updatable or not. 972 973When set to true, this will enforce additional rules for making sure that the 974APEX is truly updatable. To be updatable, min_sdk_version should be set as well."""), 975 "installable": attr.bool(default = True), 976 "compressible": attr.bool(default = False), 977 "base_apex_name": attr.string( 978 default = "", 979 doc = "The name of the base apex of this apex. For example, the AOSP variant of this apex.", 980 ), 981 "apex_available_name": attr.string( 982 default = "", 983 doc = "The name that dependencies can specify in their apex_available " + 984 "properties to refer to this module. If not specified, this " + 985 "defaults to Soong module name.", 986 ), 987 "variant_version": attr.string( 988 default = "", 989 doc = "Variant version of the mainline module. Must be an integer between 0-9", 990 values = [""] + [str(i) for i in range(10)], 991 ), 992 993 # Attributes that contribute to the payload. 994 "native_shared_libs_32": attr.label_list( 995 providers = [ApexCcInfo, ApexCcMkInfo, RuleLicensedDependenciesInfo], 996 aspects = STANDARD_PAYLOAD_ASPECTS + [apex_cc_aspect], 997 cfg = shared_lib_transition_32, 998 doc = "The libs compiled for 32-bit", 999 ), 1000 "native_shared_libs_64": attr.label_list( 1001 providers = [ApexCcInfo, ApexCcMkInfo, RuleLicensedDependenciesInfo], 1002 aspects = STANDARD_PAYLOAD_ASPECTS + [apex_cc_aspect], 1003 cfg = shared_lib_transition_64, 1004 doc = "The libs compiled for 64-bit", 1005 ), 1006 "binaries": attr.label_list( 1007 providers = [ 1008 # The dependency must produce _all_ of the providers in _one_ of these lists. 1009 [ShBinaryInfo, RuleLicensedDependenciesInfo], # sh_binary 1010 [StrippedCcBinaryInfo, CcInfo, ApexCcInfo, ApexCcMkInfo, RuleLicensedDependenciesInfo], # cc_binary (stripped) 1011 ], 1012 cfg = apex_transition, 1013 aspects = STANDARD_PAYLOAD_ASPECTS + [apex_cc_aspect], 1014 ), 1015 "prebuilts": attr.label_list( 1016 providers = [PrebuiltFileInfo, RuleLicensedDependenciesInfo], 1017 cfg = apex_transition, 1018 aspects = STANDARD_PAYLOAD_ASPECTS, 1019 ), 1020 1021 # Required to use apex_transition. This is an acknowledgement to the risks of memory bloat when using transitions. 1022 "_allowlist_function_transition": attr.label(default = "@bazel_tools//tools/allowlists/function_transition_allowlist"), 1023 1024 # Tools that are not part of the apex_toolchain. 1025 "_staging_dir_builder": attr.label( 1026 cfg = "exec", 1027 doc = "The staging dir builder to avoid the problem where symlinks are created inside apex image.", 1028 executable = True, 1029 default = "//build/bazel/rules:staging_dir_builder", 1030 ), 1031 "_signapk": attr.label( 1032 cfg = "exec", 1033 doc = "The signapk tool.", 1034 executable = True, 1035 default = "//build/make/tools/signapk", 1036 ), 1037 "_zip2zip": attr.label( 1038 cfg = "exec", 1039 allow_single_file = True, 1040 doc = "The tool zip2zip. Used to convert apex file to the expected directory structure.", 1041 default = "//build/soong/cmd/zip2zip:zip2zip", 1042 executable = True, 1043 ), 1044 "_merge_zips": attr.label( 1045 cfg = "exec", 1046 allow_single_file = True, 1047 doc = "The tool merge_zips. Used to combine base zip and config file into a single zip for mixed build aab creation.", 1048 default = "//build/soong/cmd/merge_zips", 1049 executable = True, 1050 ), 1051 "_platform_utils": attr.label( 1052 default = "//build/bazel/platforms:platform_utils", 1053 ), 1054 "_build_fingerprint": attr.label( 1055 default = "//build/bazel/rules:build_fingerprint", 1056 ), 1057 "_generate_sbom": attr.label( 1058 cfg = "exec", 1059 doc = "SBOM generation tool", 1060 executable = True, 1061 default = "//build/make/tools/sbom:generate-sbom", 1062 ), 1063 1064 # allowed deps check 1065 "_unsafe_disable_apex_allowed_deps_check": attr.label( 1066 default = "//build/bazel/rules/apex:unsafe_disable_apex_allowed_deps_check", 1067 ), 1068 "allowed_apex_deps_manifest": attr.label( 1069 allow_single_file = True, 1070 default = "//packages/modules/common/build:allowed_deps.txt", 1071 ), 1072 1073 # Build settings. 1074 "_always_use_prebuilt_sdks": attr.label( 1075 default = "//build/bazel/product_config:always_use_prebuilt_sdks", 1076 ), 1077 "_apex_global_min_sdk_version_override": attr.label( 1078 default = "//build/bazel/product_config:apex_global_min_sdk_version_override", 1079 doc = "If specified, override the min_sdk_version of this apex and in the transition and checks for dependencies.", 1080 ), 1081 "_compressed_apex": attr.label( 1082 default = "//build/bazel/product_config:compressed_apex", 1083 ), 1084 "_manifest_package_name_overrides": attr.label( 1085 default = "//build/bazel/product_config:manifest_package_name_overrides", 1086 ), 1087 "_override_apex_manifest_default_version": attr.label( 1088 default = "//build/bazel/rules/apex:override_apex_manifest_default_version", 1089 doc = "If specified, override 'version: 0' in apex_manifest.json with this value instead of the branch default. Non-zero versions will not be changed.", 1090 ), 1091 "_product_manufacturer": attr.label( 1092 default = "//build/bazel/product_config:product_manufacturer", 1093 ), 1094 "_unbundled_build_apps": attr.label( 1095 default = "//build/bazel/product_config:unbundled_build_apps", 1096 ), 1097 "_unbundled_build": attr.label( 1098 default = "//build/bazel/product_config:unbundled_build", 1099 ), 1100 1101 # Api_fingerprint 1102 "_unbundled_build_target_sdk_with_api_fingerprint": attr.label( 1103 default = "//build/bazel/rules/apex:unbundled_build_target_sdk_with_api_fingerprint", 1104 ), 1105 "_platform_sdk_codename": attr.label( 1106 default = "//build/bazel/rules/apex:platform_sdk_codename", 1107 ), 1108 "_api_fingerprint_txt": attr.label( 1109 default = "//frameworks/base/api:api_fingerprint", 1110 allow_single_file = True, 1111 ), 1112 }, 1113 # The apex toolchain is not mandatory so that we don't get toolchain resolution errors even 1114 # when the apex is not compatible with the current target (via target_compatible_with). 1115 toolchains = [config_common.toolchain_type("//build/bazel/rules/apex:apex_toolchain_type", mandatory = False)], 1116 fragments = ["platform"], 1117) 1118 1119def apex( 1120 name, 1121 manifest = "apex_manifest.json", 1122 android_manifest = None, 1123 file_contexts = None, 1124 key = None, 1125 certificate = None, 1126 certificate_name = None, 1127 min_sdk_version = None, 1128 updatable = True, 1129 installable = True, 1130 compressible = False, 1131 native_shared_libs_32 = [], 1132 native_shared_libs_64 = [], 1133 binaries = [], 1134 prebuilts = [], 1135 package_name = None, 1136 logging_parent = None, 1137 canned_fs_config = None, 1138 testonly = False, 1139 # TODO(b/255400736): tests are not fully supported yet. 1140 tests = [], 1141 target_compatible_with = [], 1142 **kwargs): 1143 "Bazel macro to correspond with the APEX bundle Soong module." 1144 1145 # If file_contexts is not specified, then use the default from //system/sepolicy/apex. 1146 # https://cs.android.com/android/platform/superproject/+/master:build/soong/apex/builder.go;l=259-263;drc=b02043b84d86fe1007afef1ff012a2155172215c 1147 if file_contexts == None: 1148 file_contexts = "//system/sepolicy/apex:" + name + "-file_contexts" 1149 1150 if testonly: 1151 compressible = False 1152 elif tests: 1153 fail("Apex with tests attribute needs to be testonly.") 1154 1155 if certificate and certificate_name: 1156 fail("Cannot use both certificate_name and certificate attributes together. Use only one of them.") 1157 app_cert_name = name + "_app_certificate" 1158 if certificate_name: 1159 # use the name key in the default cert dir 1160 android_app_certificate_with_default_cert( 1161 name = app_cert_name, 1162 cert_name = certificate_name, 1163 ) 1164 certificate_label = ":" + app_cert_name 1165 elif certificate: 1166 certificate_label = certificate 1167 else: 1168 # use the default testkey 1169 android_app_certificate_with_default_cert(name = app_cert_name) 1170 certificate_label = ":" + app_cert_name 1171 1172 target_compatible_with = select({ 1173 "//build/bazel_common_rules/platforms/os:android": [], 1174 "//conditions:default": ["@platforms//:incompatible"], 1175 }) + target_compatible_with 1176 1177 # This flag will be set based on the value of PRODUCT_CERTIFICATE_OVERRIDES 1178 native.label_flag( 1179 name = name + "_certificate_override", 1180 build_setting_default = "//build/bazel/rules/android:no_android_app_certificate", 1181 ) 1182 1183 _apex( 1184 name = name, 1185 manifest = manifest, 1186 android_manifest = android_manifest, 1187 file_contexts = file_contexts, 1188 key = key, 1189 certificate = certificate_label, 1190 certificate_override = ":" + name + "_certificate_override", 1191 min_sdk_version = min_sdk_version, 1192 updatable = updatable, 1193 installable = installable, 1194 compressible = compressible, 1195 native_shared_libs_32 = native_shared_libs_32, 1196 native_shared_libs_64 = native_shared_libs_64, 1197 binaries = binaries, 1198 prebuilts = prebuilts, 1199 package_name = package_name, 1200 logging_parent = logging_parent, 1201 canned_fs_config = canned_fs_config, 1202 testonly = testonly, 1203 target_compatible_with = target_compatible_with, 1204 **kwargs 1205 ) 1206