1""" 2Copyright (C) 2022 The Android Open Source Project 3 4Licensed under the Apache License, Version 2.0 (the "License"); 5you may not use this file except in compliance with the License. 6You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10Unless required by applicable law or agreed to in writing, software 11distributed under the License is distributed on an "AS IS" BASIS, 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13See the License for the specific language governing permissions and 14limitations under the License. 15""" 16load("//build/bazel/rules:apex.bzl", "ApexInfo") 17 18def _arch_transition_impl(settings, attr): 19 """Implementation of arch_transition. 20 Four archs are included for mainline modules: x86, x86_64, arm and arm64. 21 """ 22 return { 23 "x86": { 24 "//command_line_option:platforms": "//build/bazel/platforms:android_x86", 25 }, 26 "x86_64": { 27 "//command_line_option:platforms": "//build/bazel/platforms:android_x86_64", 28 }, 29 "arm": { 30 "//command_line_option:platforms": "//build/bazel/platforms:android_arm", 31 }, 32 "arm64": { 33 "//command_line_option:platforms": "//build/bazel/platforms:android_arm64", 34 }, 35 } 36 37# Multi-arch transition. 38arch_transition = transition( 39 implementation = _arch_transition_impl, 40 inputs = [], 41 outputs = [ 42 "//command_line_option:platforms", 43 ], 44) 45 46# Arch to ABI map 47_arch_abi_map = { 48 "arm64": "arm64-v8a", 49 "arm": "armeabi-v7a", 50 "x86_64": "x86_64", 51 "x86": "x86", 52} 53 54def _apex_proto_convert(ctx, arch, module_name, apex_file): 55 """Run 'aapt2 convert' to convert resource files to protobuf format.""" 56 # Inputs 57 inputs = [ 58 apex_file, 59 ctx.executable._aapt2, 60 ] 61 62 # Outputs 63 filename = apex_file.basename 64 pos_dot = filename.rindex(".") 65 proto_convert_file = ctx.actions.declare_file("/".join([ 66 module_name, 67 arch, 68 filename[:pos_dot] + ".pb" + filename[pos_dot:]])) 69 outputs = [proto_convert_file] 70 71 # Arguments 72 args = ctx.actions.args() 73 args.add_all(["convert"]) 74 args.add_all(["--output-format", "proto"]) 75 args.add_all([apex_file]) 76 args.add_all(["-o", proto_convert_file.path]) 77 78 ctx.actions.run( 79 inputs = inputs, 80 outputs = outputs, 81 executable = ctx.executable._aapt2, 82 arguments = [args], 83 mnemonic = "ApexProtoConvert", 84 ) 85 return proto_convert_file 86 87def _apex_base_file(ctx, arch, module_name, apex_proto_file): 88 """Run zip2zip to transform the apex file the expected directory structure 89 with all files that will be included in the base module of aab file.""" 90 91 # Inputs 92 inputs = [ 93 apex_proto_file, 94 ctx.executable._zip2zip, 95 ] 96 97 # Outputs 98 base_file = ctx.actions.declare_file("/".join([module_name, arch, module_name + ".base"])) 99 outputs = [base_file] 100 101 # Arguments 102 args = ctx.actions.args() 103 args.add_all(["-i", apex_proto_file]) 104 args.add_all(["-o", base_file]) 105 abi = _arch_abi_map[arch] 106 args.add_all([ 107 "apex_payload.img:apex/%s.img" % abi, 108 "apex_build_info.pb:apex/%s.build_info.pb" % abi, 109 "apex_manifest.json:root/apex_manifest.json", 110 "apex_manifest.pb:root/apex_manifest.pb", 111 "AndroidManifest.xml:manifest/AndroidManifest.xml", 112 "assets/NOTICE.html.gz:assets/NOTICE.html.gz", 113 ]) 114 115 ctx.actions.run( 116 inputs = inputs, 117 outputs = outputs, 118 executable = ctx.executable._zip2zip, 119 arguments = [args], 120 mnemonic = "ApexBaseFile", 121 ) 122 return base_file 123 124def _build_bundle_config(ctx, arch, module_name): 125 """Create bundle_config.json as configuration for running bundletool.""" 126 file_content = { 127 "compression": { 128 "uncompressed_glob": [ 129 "apex_payload.img", 130 "apex_manifest.*", 131 ], 132 }, 133 "apex_config": {}, 134 } 135 bundle_config_file = ctx.actions.declare_file("/".join([module_name, "bundle_config.json"])) 136 ctx.actions.write(bundle_config_file, json.encode(file_content)) 137 138 return bundle_config_file 139 140def _merge_base_files(ctx, module_name, base_files): 141 """Run merge_zips to merge all files created for each arch by _apex_base_file.""" 142 143 # Inputs 144 inputs = base_files + [ctx.executable._merge_zips] 145 146 # Outputs 147 merged_base_file = ctx.actions.declare_file(module_name + "/" + module_name + ".zip") 148 outputs = [merged_base_file] 149 150 # Arguments 151 args = ctx.actions.args() 152 args.add_all(["--ignore-duplicates"]) 153 args.add_all([merged_base_file]) 154 args.add_all(base_files) 155 156 ctx.actions.run( 157 inputs = inputs, 158 outputs = outputs, 159 executable = ctx.executable._merge_zips, 160 arguments = [args], 161 mnemonic = "ApexMergeBaseFiles", 162 ) 163 return merged_base_file 164 165def _apex_bundle(ctx, module_name, merged_base_file, bundle_config_file): 166 """Run bundletool to create the aab file.""" 167 168 # Inputs 169 inputs = [ 170 bundle_config_file, 171 merged_base_file, 172 ctx.executable._bundletool, 173 ] 174 175 # Outputs 176 bundle_file = ctx.actions.declare_file(module_name + "/" + module_name + ".aab") 177 outputs = [bundle_file] 178 179 # Arguments 180 args = ctx.actions.args() 181 args.add_all(["build-bundle"]) 182 args.add_all(["--config", bundle_config_file]) 183 args.add_all(["--modules", merged_base_file]) 184 args.add_all(["--output", bundle_file]) 185 186 ctx.actions.run( 187 inputs = inputs, 188 outputs = outputs, 189 executable = ctx.executable._bundletool, 190 arguments = [args], 191 mnemonic = "ApexBundleFile", 192 ) 193 return bundle_file 194 195def _apex_aab_impl(ctx): 196 """Implementation of apex_aab rule, which drives the process of creating aab 197 file from apex files created for each arch.""" 198 apex_base_files = [] 199 bundle_config_file = None 200 module_name = ctx.attr.mainline_module[0].label.name 201 for arch in ctx.split_attr.mainline_module: 202 apex_file = ctx.split_attr.mainline_module[arch].files.to_list()[0] 203 proto_convert_file = _apex_proto_convert(ctx, arch, module_name, apex_file) 204 base_file = _apex_base_file(ctx, arch, module_name, proto_convert_file) 205 apex_base_files.append(base_file) 206 # It is assumed that the bundle config is the same for all products. 207 if bundle_config_file == None: 208 bundle_config_file = _build_bundle_config(ctx, arch, module_name) 209 210 merged_base_file = _merge_base_files(ctx, module_name, apex_base_files) 211 bundle_file = _apex_bundle(ctx, module_name, merged_base_file, bundle_config_file) 212 213 return [DefaultInfo(files = depset([bundle_file]))] 214 215# apex_aab rule creates Android Apk Bundle (.aab) file of the APEX specified in mainline_module. 216# There is no equivalent Soong module, and it is currently done in shell script by 217# invoking Soong multiple times. 218apex_aab = rule( 219 implementation = _apex_aab_impl, 220 attrs = { 221 "mainline_module": attr.label( 222 mandatory = True, 223 cfg = arch_transition, 224 providers = [ApexInfo], 225 doc = "The label of a mainline module target", 226 ), 227 "_allowlist_function_transition": attr.label( 228 default = "@bazel_tools//tools/allowlists/function_transition_allowlist", 229 doc = "Allow transition.", 230 ), 231 "_zipper": attr.label( 232 cfg = "host", 233 executable = True, 234 default = "@bazel_tools//tools/zip:zipper", 235 ), 236 "_aapt2": attr.label( 237 allow_single_file = True, 238 cfg = "host", 239 executable = True, 240 default = "//prebuilts/sdk/tools:linux/bin/aapt2", 241 ), 242 "_merge_zips": attr.label( 243 allow_single_file = True, 244 cfg = "host", 245 executable = True, 246 default = "//prebuilts/build-tools:linux-x86/bin/merge_zips", 247 ), 248 "_zip2zip": attr.label( 249 allow_single_file = True, 250 cfg = "host", 251 executable = True, 252 default = "//prebuilts/build-tools:linux-x86/bin/zip2zip", 253 ), 254 "_bundletool": attr.label( 255 cfg = "host", 256 executable = True, 257 default = "//prebuilts/bundletool", 258 ), 259 }, 260) 261