• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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//rules:common_settings.bzl", "BuildSettingInfo")
16load("//build/bazel/product_config:product_variables_providing_rule.bzl", "ProductVariablesInfo")
17load("//build/bazel/rules:metadata.bzl", "MetadataFileInfo")
18load("//build/bazel/rules/cc:cc_library_common.bzl", "parse_apex_sdk_version")
19load("//build/bazel/rules/cc:cc_library_shared.bzl", "CcSharedLibraryOutputInfo", "CcStubLibrariesInfo")
20load("//build/bazel/rules/cc:cc_stub_library.bzl", "CcStubLibrarySharedInfo")
21load("//build/bazel/rules/cc:stripped_cc_common.bzl", "CcUnstrippedInfo")
22load("//build/bazel/rules/license:license_aspect.bzl", "license_aspect")
23
24ApexCcInfo = provider(
25    "Info needed to use CC targets in APEXes",
26    fields = {
27        "provides_native_libs": "Labels of native shared libs that this apex provides.",
28        "requires_native_libs": "Labels of native shared libs that this apex requires.",
29        "transitive_shared_libs": "File references to transitive .so libs produced by the CC targets and should be included in the APEX.",
30    },
31)
32
33ApexCcMkInfo = provider(
34    "AndroidMk data about CC targets in APEXes",
35    fields = {
36        "make_modules_to_install": "List of module names that should be installed into the system, along with this APEX",
37    },
38)
39
40# Special libraries that are installed to the bootstrap subdirectory. Bionic
41# libraries are assumed to be provided by the system, and installed automatically
42# as a symlink to the runtime APEX.
43#
44# This list is from https://cs.android.com/android/platform/superproject/+/master:build/soong/cc/cc.go;l=1439-1452;drc=9c667416ded33b93a44c5f1894ea23cae6699a17
45#
46# NOTE: Keep this list in sync with the Soong list.
47#
48# See cc/binary.go#install for more information.
49def _installed_to_bootstrap(label):
50    label = str(label)
51
52    # hwasan
53    if label == "@//prebuilts/clang/host/linux-x86:libclang_rt.hwasan":
54        return True
55
56    # bionic libs
57    if label in [
58        "@//bionic/libc:libc",
59        "@//bionic/libc:libc_hwasan",  # For completeness, but no one should be depending on this.
60        "@//bionic/libm:libm",
61        "@//bionic/libdl:libdl",
62        "@//bionic/libdl_android:libdl_android",
63        "@//bionic/linker:linker",
64    ]:
65        return True
66
67    return False
68
69def has_cc_stubs(target):
70    """
71    Return True if this target provides stubs.
72
73    There is no need to check versions of stubs any more, see aosp/1609533.
74
75    These stable ABI libraries are intentionally omitted from APEXes as they are
76    provided from another APEX or the platform.  By omitting them from APEXes, we
77    ensure that there are no multiple copies of such libraries on a device.
78
79    Args:
80      target: The target to check for stubs on.
81    Returns:
82      If the target has cc stubs
83    """
84    if CcStubLibrarySharedInfo in target:
85        # This is a stub lib (direct or transitive).
86        return True
87
88    if CcStubLibrariesInfo in target and target[CcStubLibrariesInfo].has_stubs:
89        # Direct deps of the apex. The apex would depend on the source lib, not stub lib,
90        # so check for CcStubLibrariesInfo.has_stubs.
91        return True
92
93    return False
94
95# Check if this target is specified as a direct dependency of the APEX,
96# as opposed to a transitive dependency, as the transitivity impacts
97# the files that go into an APEX.
98def is_apex_direct_dep(label, ctx):
99    apex_direct_deps = ctx.attr._apex_direct_deps[BuildSettingInfo].value
100    return str(label) in apex_direct_deps
101
102MinSdkVersionInfo = provider(
103    "MinSdkVersionInfo provides metadata about the min_sdk_version attribute of a target",
104    fields = {
105        "apex_inherit": "true if min_sdk_version: \"apex_inherit\" is present on the module",
106        "min_sdk_version": "value of min_sdk_version",
107    },
108)
109
110def get_min_sdk_version(ctx):
111    """get_min_sdk_version returns the min_sdk_version for the existing target
112
113    Args:
114        ctx (rule context): a rule context
115    Returns:
116        MinSdkVersionInfo
117    """
118    min_sdk_version = None
119    apex_inherit = False
120    if hasattr(ctx.rule.attr, "min_sdk_version"):
121        if ctx.rule.attr.min_sdk_version == "apex_inherit":
122            apex_inherit = True
123        elif ctx.rule.attr.min_sdk_version:
124            min_sdk_version = parse_apex_sdk_version(ctx.rule.attr.min_sdk_version)
125    else:
126        # min_sdk_version in cc targets are represented as features
127        for f in ctx.rule.attr.features:
128            if f.startswith("sdk_version_"):
129                # e.g. sdk_version_29 or sdk_version_10000 or sdk_version_apex_inherit
130                sdk_version = f.removeprefix("sdk_version_")
131                if sdk_version == "apex_inherit":
132                    apex_inherit = True
133                elif min_sdk_version == None:
134                    min_sdk_version = int(sdk_version)
135                else:
136                    fail(
137                        "found more than one sdk_version feature on {target}; features = {features}",
138                        target = ctx.label,
139                        features = ctx.rule.attr.features,
140                    )
141    return MinSdkVersionInfo(
142        min_sdk_version = min_sdk_version,
143        apex_inherit = apex_inherit,
144    )
145
146def _validate_min_sdk_version(ctx):
147    dep_min_version = get_min_sdk_version(ctx).min_sdk_version
148    apex_min_version = parse_apex_sdk_version(ctx.attr._min_sdk_version[BuildSettingInfo].value)
149    if dep_min_version and apex_min_version < dep_min_version:
150        fail("The apex %s's min_sdk_version %s cannot be lower than the dep's min_sdk_version %s" %
151             (ctx.attr._apex_name[BuildSettingInfo].value, apex_min_version, dep_min_version))
152
153def _apex_cc_aspect_impl(target, ctx):
154    # Ensure that dependencies are compatible with this apex's min_sdk_level
155    if not ctx.attr.testonly:
156        _validate_min_sdk_version(ctx)
157
158    # Whether this dep is a direct dep of an APEX or makes a difference in dependency
159    # traversal, and aggregation of libs that are required from the platform/other APEXes,
160    # and libs that this APEX will provide to others.
161    is_direct_dep = is_apex_direct_dep(target.label, ctx)
162
163    provides = []
164    requires = []
165    make_modules_to_install = []
166
167    # The APEX manifest records the stub-providing libs (ABI-stable) in its
168    # direct and transitive deps.
169    #
170    # If a stub-providing lib is in the direct deps of an apex, then the apex
171    # provides the symbols.
172    #
173    # If a stub-providing lib is in the transitive deps of an apex, then the
174    # apex requires the symbols from the platform or other apexes.
175    if has_cc_stubs(target):
176        if is_direct_dep:
177            # Mark this target as "stub-providing" exports of this APEX,
178            # which the system and other APEXes can depend on, and propagate
179            # this list.
180            provides.append(target.label)
181        else:
182            # If this is not a direct dep and the build is in not unbundled mode,
183            # and stubs are available, don't propagate the libraries.
184
185            # Mark this target as required from the system either via
186            # the system partition, or another APEX, and propagate this list.
187            source_library_label = target[CcStubLibrarySharedInfo].source_library_label
188
189            # If a stub library is in the "provides" of the apex, it doesn't need to be in the "requires"
190            if not is_apex_direct_dep(source_library_label, ctx):
191                requires.append(source_library_label)
192                if not ctx.attr._product_variables[ProductVariablesInfo].Unbundled_build and not _installed_to_bootstrap(source_library_label):
193                    # It's sufficient to pass the make module name, not the fully qualified bazel label.
194                    make_modules_to_install.append(source_library_label.name)
195
196            return [
197                ApexCcInfo(
198                    transitive_shared_libs = depset(),
199                    requires_native_libs = depset(direct = requires),
200                    provides_native_libs = depset(direct = provides),
201                ),
202                ApexCcMkInfo(
203                    make_modules_to_install = depset(direct = make_modules_to_install),
204                ),
205            ]
206
207    shared_object_files = []
208
209    # Transitive deps containing shared libraries to be propagated the apex.
210    transitive_deps = []
211    rules_propagate_src = [
212        "_bssl_hash_injection",
213        "stripped_shared_library",
214        "versioned_shared_library",
215        "stripped_binary",
216        "versioned_binary",
217    ]
218
219    # Exclude the stripped and unstripped so files
220    if ctx.rule.kind == "_cc_library_shared_proxy":
221        shared_object_files.append(struct(
222            stripped = target[CcSharedLibraryOutputInfo].output_file,
223            unstripped = target[CcUnstrippedInfo].unstripped,
224            metadata_file = target[MetadataFileInfo].metadata_file,
225        ))
226        if hasattr(ctx.rule.attr, "shared"):
227            transitive_deps.append(ctx.rule.attr.shared[0])
228    elif ctx.rule.kind in ["cc_shared_library", "cc_binary"]:
229        # Propagate along the dynamic_deps and deps edges for binaries and shared libs
230        if hasattr(ctx.rule.attr, "dynamic_deps"):
231            for dep in ctx.rule.attr.dynamic_deps:
232                transitive_deps.append(dep)
233        if hasattr(ctx.rule.attr, "deps"):
234            for dep in ctx.rule.attr.deps:
235                transitive_deps.append(dep)
236    elif ctx.rule.kind in rules_propagate_src and hasattr(ctx.rule.attr, "src"):
237        # Propagate along the src edge
238        if ctx.rule.kind == "stripped_binary":
239            transitive_deps.append(ctx.rule.attr.src[0])
240        else:
241            transitive_deps.append(ctx.rule.attr.src)
242
243    if ctx.rule.kind in ["stripped_binary", "_cc_library_shared_proxy", "_cc_library_combiner"] and hasattr(ctx.rule.attr, "runtime_deps"):
244        for dep in ctx.rule.attr.runtime_deps:
245            unstripped = None
246            if CcUnstrippedInfo in dep:
247                unstripped = dep[CcUnstrippedInfo].unstripped
248            for output_file in dep[DefaultInfo].files.to_list():
249                if output_file.extension == "so":
250                    shared_object_files.append(struct(
251                        stripped = output_file,
252                        unstripped = unstripped,
253                        metadata_file = dep[MetadataFileInfo].metadata_file,
254                    ))
255            transitive_deps.append(dep)
256
257    return [
258        ApexCcInfo(
259            transitive_shared_libs = depset(
260                shared_object_files,
261                transitive = [info[ApexCcInfo].transitive_shared_libs for info in transitive_deps],
262            ),
263            requires_native_libs = depset(
264                [],
265                transitive = [info[ApexCcInfo].requires_native_libs for info in transitive_deps],
266            ),
267            provides_native_libs = depset(
268                provides,
269                transitive = [info[ApexCcInfo].provides_native_libs for info in transitive_deps],
270            ),
271        ),
272        ApexCcMkInfo(
273            make_modules_to_install = depset(
274                [],
275                transitive = [info[ApexCcMkInfo].make_modules_to_install for info in transitive_deps],
276            ),
277        ),
278    ]
279
280# The list of attributes in a cc dep graph where this aspect will traverse on.
281CC_ATTR_ASPECTS = [
282    "dynamic_deps",
283    "deps",
284    "shared",
285    "src",
286    "runtime_deps",
287    "static_deps",
288    "whole_archive_deps",
289]
290
291# This aspect is intended to be applied on a apex.native_shared_libs attribute
292apex_cc_aspect = aspect(
293    implementation = _apex_cc_aspect_impl,
294    provides = [ApexCcInfo, ApexCcMkInfo],
295    attrs = {
296        # This is propagated from the apex
297        "testonly": attr.bool(default = False),
298        "_apex_direct_deps": attr.label(default = "//build/bazel/rules/apex:apex_direct_deps"),
299        "_apex_name": attr.label(default = "//build/bazel/rules/apex:apex_name"),
300        "_min_sdk_version": attr.label(default = "//build/bazel/rules/apex:min_sdk_version"),
301        "_product_variables": attr.label(default = "//build/bazel/product_config:product_vars"),
302    },
303    attr_aspects = CC_ATTR_ASPECTS,
304    requires = [license_aspect],
305    # TODO: Have this aspect also propagate along attributes of native_shared_libs?
306)
307