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