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("//build/bazel/rules:toolchain_utils.bzl", "verify_toolchain_exists") 17load(":apex_info.bzl", "ApexInfo") 18load(":bundle.bzl", "build_bundle_config") 19 20def _arch_transition_impl(settings, _attr): 21 """Implementation of arch_transition. 22 23 Six arch products are included for mainline modules: x86, x86_64, x86_64only, arm, arm64, arm64only. 24 """ 25 old_platform = str(settings["//command_line_option:platforms"][0]) 26 27 # We can't use platforms alone to differentiate between x86_64 and x86_64 28 # with a secondary arch, which is significant for apex packaging that can 29 # optionally include the secondary arch's libs. That is currently determined 30 # by DeviceSecondaryArch in apex's lib inclusion logic, so we explicitly set 31 # DeviceSecondaryArch to "" for the 64bit only cases. 32 33 # TODO(b/249685973) Instead of using these __internal_x86 platforms, use 34 # the mainline_modules_<arch> android products 35 return { 36 # these key names must correspond to mainline_modules_<arch> product name suffixes. 37 "arm": { 38 "//command_line_option:platforms": old_platform + "__internal_arm", 39 }, 40 "arm64": { 41 "//command_line_option:platforms": old_platform + "__internal_arm64", 42 }, 43 "arm64only": { 44 "//command_line_option:platforms": old_platform + "__internal_arm64only", 45 }, 46 "x86": { 47 "//command_line_option:platforms": old_platform + "__internal_x86", 48 }, 49 "x86_64": { 50 "//command_line_option:platforms": old_platform + "__internal_x86_64", 51 }, 52 "x86_64only": { 53 "//command_line_option:platforms": old_platform + "__internal_x86_64only", 54 }, 55 } 56 57# Multi-arch transition. 58arch_transition = transition( 59 implementation = _arch_transition_impl, 60 inputs = [ 61 "//command_line_option:platforms", 62 ], 63 outputs = [ 64 "//command_line_option:platforms", 65 ], 66) 67 68def _merge_base_files(ctx, module_name, base_files): 69 """Run merge_zips to merge all files created for each arch by _apex_base_file.""" 70 merged_base_file = ctx.actions.declare_file(module_name + "/" + module_name + ".zip") 71 72 # Arguments 73 args = ctx.actions.args() 74 args.add("--ignore-duplicates") 75 args.add(merged_base_file) 76 args.add_all(base_files) 77 78 ctx.actions.run( 79 inputs = base_files, 80 outputs = [merged_base_file], 81 executable = ctx.executable._merge_zips, 82 arguments = [args], 83 mnemonic = "ApexMergeBaseFiles", 84 ) 85 return merged_base_file 86 87def _apex_bundle(ctx, module_name, merged_base_file, bundle_config_file): 88 """Run bundletool to create the aab file.""" 89 90 # Outputs 91 bundle_file = ctx.actions.declare_file(module_name + "/" + module_name + ".aab") 92 93 # Arguments 94 args = ctx.actions.args() 95 args.add("build-bundle") 96 args.add_all(["--config", bundle_config_file]) 97 args.add_all(["--modules", merged_base_file]) 98 args.add_all(["--output", bundle_file]) 99 100 ctx.actions.run( 101 inputs = [ 102 bundle_config_file, 103 merged_base_file, 104 ], 105 outputs = [bundle_file], 106 executable = ctx.executable._bundletool, 107 arguments = [args], 108 mnemonic = "ApexBundleFile", 109 ) 110 return bundle_file 111 112def _sign_bundle(ctx, aapt2, avbtool, module_name, bundle_file, apex_info): 113 """ Run dev_sign_bundle to sign the bundle_file.""" 114 115 # Python3 interpreter for dev_sign_bundle to run other python scripts. 116 python_interpreter = ctx.toolchains["@bazel_tools//tools/python:toolchain_type"].py3_runtime.interpreter 117 if python_interpreter.basename != "python3": 118 python3 = ctx.actions.declare_file("python3") 119 ctx.actions.symlink( 120 output = python3, 121 target_file = python_interpreter, 122 is_executable = True, 123 ) 124 python_interpreter = python3 125 126 # Input directory for dev_sign_bundle. 127 input_bundle_file = ctx.actions.declare_file(module_name + "/sign_bundle/input_dir/" + bundle_file.basename) 128 ctx.actions.symlink( 129 output = input_bundle_file, 130 target_file = bundle_file, 131 ) 132 133 # Output directory for dev_sign_bundle 134 output_dir = ctx.actions.declare_directory(module_name + "/sign_bundle/output_dir") 135 136 # Temporary directory for dev_sign_bundle 137 tmp_dir = ctx.actions.declare_directory(module_name + "/sign_bundle/tmp_dir") 138 139 # Jar file of prebuilts/bundletool 140 bundletool_jarfile = ctx.attr._bundletool_lib.files.to_list()[0] 141 142 # Keystore file 143 keystore_file = ctx.attr.dev_keystore.files.to_list()[0] 144 145 # ANDROID_HOST_OUT environment 146 debugfs_static = ctx.actions.declare_file(module_name + "/sign_bundle/android_host_out/bin/debugfs_static") 147 ctx.actions.symlink( 148 output = debugfs_static, 149 target_file = ctx.executable._debugfs, 150 is_executable = True, 151 ) 152 fsck_erofs = ctx.actions.declare_file(module_name + "/sign_bundle/android_host_out/bin/fsck.erofs") 153 ctx.actions.symlink( 154 output = fsck_erofs, 155 target_file = ctx.executable._fsck_erofs, 156 is_executable = True, 157 ) 158 signapk_jar = ctx.actions.declare_file(module_name + "/sign_bundle/android_host_out/framework/signapk.jar") 159 ctx.actions.symlink( 160 output = signapk_jar, 161 target_file = ctx.attr._signapk_jar.files.to_list()[0], 162 is_executable = False, 163 ) 164 libconscrypt_openjdk_jni_so = ctx.actions.declare_file(module_name + "/sign_bundle/android_host_out/lib64/libconscrypt_openjdk_jni.so") 165 ctx.actions.symlink( 166 output = libconscrypt_openjdk_jni_so, 167 target_file = ctx.attr._libconscrypt_openjdk_jni.files.to_list()[1], 168 is_executable = False, 169 ) 170 171 java_runtime = ctx.attr._java_runtime[java_common.JavaRuntimeInfo] 172 173 # Tools 174 tools = [ 175 ctx.executable.dev_sign_bundle, 176 ctx.executable._deapexer, 177 ctx.executable._sign_apex, 178 ctx.executable._openssl, 179 ctx.executable._zip2zip, 180 ctx.executable._blkid, 181 aapt2, 182 avbtool.files_to_run.executable, 183 python_interpreter, 184 debugfs_static, 185 fsck_erofs, 186 bundletool_jarfile, 187 signapk_jar, 188 libconscrypt_openjdk_jni_so, 189 java_runtime.files, 190 ] 191 192 # Inputs 193 inputs = [ 194 input_bundle_file, 195 keystore_file, 196 apex_info.bundle_key_info.private_key, 197 apex_info.container_key_info.pem, 198 apex_info.container_key_info.pk8, 199 ] 200 201 # Outputs 202 outputs = [output_dir, tmp_dir] 203 204 # Arguments 205 java_bin = paths.join(java_runtime.java_home, "bin") 206 args = ctx.actions.args() 207 args.add_all(["--input_dir", input_bundle_file.dirname]) 208 args.add_all(["--output_dir", output_dir.path]) 209 args.add_all(["--temp_dir", tmp_dir.path]) 210 args.add_all(["--aapt2_path", aapt2.path]) 211 args.add_all(["--bundletool_path", bundletool_jarfile.path]) 212 args.add_all(["--deapexer_path", ctx.executable._deapexer.path]) 213 args.add_all(["--blkid_path", ctx.executable._blkid.path]) 214 args.add_all(["--debugfs_path", ctx.executable._debugfs.path]) 215 args.add_all(["--java_binary_path", paths.join(java_bin, "java")]) 216 args.add_all(["--apex_signer_path", ctx.executable._sign_apex]) 217 218 ctx.actions.run( 219 inputs = inputs, 220 outputs = outputs, 221 executable = ctx.executable.dev_sign_bundle, 222 arguments = [args], 223 tools = tools, 224 env = { 225 # necessary for dev_sign_bundle. 226 "BAZEL_ANDROID_HOST_OUT": paths.dirname(debugfs_static.dirname), 227 "PATH": ":".join( 228 [ 229 python_interpreter.dirname, 230 ctx.executable._deapexer.dirname, 231 avbtool.files_to_run.executable.dirname, 232 ctx.executable._openssl.dirname, 233 java_bin, 234 ], 235 ), 236 }, 237 mnemonic = "ApexSignBundleFile", 238 ) 239 240 apks_file = ctx.actions.declare_file(module_name + "/" + module_name + ".apks") 241 cert_info_file = ctx.actions.declare_file(module_name + "/" + module_name + ".cert_info.txt") 242 ctx.actions.run_shell( 243 inputs = [output_dir], 244 outputs = [apks_file, cert_info_file], 245 command = " ".join(["cp", output_dir.path + "/" + module_name + "/*", apks_file.dirname]), 246 ) 247 248 return [apks_file, cert_info_file] 249 250def _apex_aab_impl(ctx): 251 """Implementation of apex_aab rule. 252 253 This drives the process of creating aab file from apex files created for each arch.""" 254 verify_toolchain_exists(ctx, "//build/bazel/rules/apex:apex_toolchain_type") 255 apex_toolchain = ctx.toolchains["//build/bazel/rules/apex:apex_toolchain_type"].toolchain_info 256 257 prefixed_apex_files = [] 258 apex_base_files = [] 259 bundle_config_file = None 260 module_name = ctx.attr.mainline_module[0].label.name 261 for arch in ctx.split_attr.mainline_module: 262 apex_info = ctx.split_attr.mainline_module[arch][ApexInfo] 263 apex_base_files.append(apex_info.base_file) 264 265 arch_subdir = "mainline_modules_%s" % arch 266 267 # A mapping of files to a prefix directory they should be copied to. 268 # These files will be accessible with the apex_files output_group. 269 mapping = { 270 apex_info.base_file: arch_subdir, 271 apex_info.signed_output: arch_subdir, 272 apex_info.symbols_used_by_apex: arch_subdir + "/ndk_apis_usedby_apex", 273 apex_info.backing_libs: arch_subdir + "/ndk_apis_backedby_apex", 274 apex_info.java_symbols_used_by_apex: arch_subdir + "/java_apis_usedby_apex", 275 # TODO(b/262267680): create licensetexts 276 # TODO(b/262267551): create shareprojects 277 } 278 279 # Forward the individual files for all variants in an additional output group, 280 # so dependents can easily access the multi-arch base APEX files by building 281 # this target with --output_groups=apex_files. 282 # 283 # Copy them into an arch-specific directory, since they have the same basename. 284 for _file, _dir in mapping.items(): 285 _out = ctx.actions.declare_file(_dir + "/" + _file.basename) 286 ctx.actions.run_shell( 287 inputs = [_file], 288 outputs = [_out], 289 command = " ".join(["cp", _file.path, _out.path]), 290 ) 291 prefixed_apex_files.append(_out) 292 293 # Create .aab file 294 bundle_config_file = build_bundle_config(ctx.actions, ctx.label.name) 295 merged_base_file = _merge_base_files(ctx, module_name, apex_base_files) 296 bundle_file = _apex_bundle(ctx, module_name, merged_base_file, bundle_config_file) 297 298 # Create .apks file 299 apex_info = ctx.attr.mainline_module[0][ApexInfo] 300 package_name = apex_info.package_name 301 302 if ctx.attr.dev_sign_bundle and ctx.attr.dev_keystore and (package_name.startswith("com.google.android") or package_name.startswith("com.google.mainline")): 303 signed_files = _sign_bundle(ctx, apex_toolchain.aapt2, apex_toolchain.avbtool, module_name, bundle_file, apex_info) 304 return [ 305 DefaultInfo(files = depset([bundle_file] + signed_files)), 306 OutputGroupInfo(apex_files = depset(prefixed_apex_files), signed_files = signed_files), 307 ] 308 309 return [ 310 DefaultInfo(files = depset([bundle_file])), 311 OutputGroupInfo(apex_files = depset(prefixed_apex_files)), 312 ] 313 314# apex_aab rule creates multi-arch outputs of a Mainline module, such as the 315# Android Apk Bundle (.aab) file of the APEX specified in mainline_module. 316# There is no equivalent Soong module, and it is currently done in shell script 317# by invoking Soong multiple times. 318_apex_aab = rule( 319 implementation = _apex_aab_impl, 320 toolchains = [ 321 # The apex toolchain is not mandatory so that we don't get toolchain resolution errors 322 # even when the aab is not compatible with the current target (via target_compatible_with). 323 config_common.toolchain_type("//build/bazel/rules/apex:apex_toolchain_type", mandatory = False), 324 "@bazel_tools//tools/python:toolchain_type", 325 ], 326 attrs = { 327 "dev_keystore": attr.label( 328 cfg = "exec", 329 executable = False, 330 ), 331 "dev_sign_bundle": attr.label( 332 cfg = "exec", 333 executable = True, 334 ), 335 "mainline_module": attr.label( 336 mandatory = True, 337 cfg = arch_transition, 338 providers = [ApexInfo], 339 doc = "The label of a mainline module target", 340 ), 341 "_allowlist_function_transition": attr.label( 342 default = "@bazel_tools//tools/allowlists/function_transition_allowlist", 343 doc = "Allow transition.", 344 ), 345 "_blkid": attr.label( 346 cfg = "exec", 347 executable = True, 348 default = "//external/e2fsprogs/misc:blkid", 349 ), 350 "_bundletool": attr.label( 351 cfg = "exec", 352 executable = True, 353 default = "//prebuilts/bundletool", 354 ), 355 "_bundletool_lib": attr.label( 356 cfg = "exec", 357 executable = False, 358 default = "//prebuilts/bundletool:bundletool-lib", 359 ), 360 "_deapexer": attr.label( 361 cfg = "exec", 362 executable = True, 363 default = "//system/apex/tools:deapexer", 364 ), 365 "_debugfs": attr.label( 366 cfg = "exec", 367 executable = True, 368 default = "//external/e2fsprogs/debugfs:debugfs_static", 369 ), 370 "_fsck_erofs": attr.label( 371 cfg = "exec", 372 executable = True, 373 default = "//external/erofs-utils:fsck.erofs", 374 ), 375 "_java_runtime": attr.label( 376 default = Label("@bazel_tools//tools/jdk:current_java_runtime"), 377 cfg = "exec", 378 providers = [java_common.JavaRuntimeInfo], 379 ), 380 "_libconscrypt_openjdk_jni": attr.label( 381 cfg = "exec", 382 executable = False, 383 default = "//external/conscrypt:libconscrypt_openjdk_jni", 384 ), 385 "_merge_zips": attr.label( 386 allow_single_file = True, 387 cfg = "exec", 388 executable = True, 389 default = "//prebuilts/build-tools:linux-x86/bin/merge_zips", 390 ), 391 "_openssl": attr.label( 392 allow_single_file = True, 393 cfg = "exec", 394 executable = True, 395 default = "//prebuilts/build-tools:linux-x86/bin/openssl", 396 ), 397 "_sign_apex": attr.label( 398 cfg = "exec", 399 executable = True, 400 default = "//build/make/tools/releasetools:sign_apex", 401 ), 402 "_signapk_jar": attr.label( 403 cfg = "exec", 404 executable = False, 405 default = "//build/bazel/rules/apex:signapk_deploy_jar", 406 ), 407 "_zip2zip": attr.label( 408 allow_single_file = True, 409 cfg = "exec", 410 executable = True, 411 default = "//build/soong/cmd/zip2zip:zip2zip", 412 ), 413 "_zipper": attr.label( 414 cfg = "exec", 415 executable = True, 416 default = "@bazel_tools//tools/zip:zipper", 417 ), 418 }, 419) 420 421def apex_aab(name, mainline_module, dev_sign_bundle = None, dev_keystore = None, target_compatible_with = [], **kwargs): 422 target_compatible_with = select({ 423 "//build/bazel/platforms/os:android": [], 424 "//conditions:default": ["@platforms//:incompatible"], 425 }) + target_compatible_with 426 427 _apex_aab( 428 name = name, 429 mainline_module = mainline_module, 430 dev_sign_bundle = dev_sign_bundle, 431 dev_keystore = dev_keystore, 432 target_compatible_with = target_compatible_with, 433 **kwargs 434 ) 435