xref: /aosp_15_r20/build/bazel/rules/android/android_binary_aosp_internal/impl.bzl (revision 7594170e27e0732bc44b93d1440d87a54b6ffe7c)
1"""
2Copyright (C) 2023 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"""
16
17load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo")
18load("@rules_android//rules:java.bzl", "java")
19load(
20    "@rules_android//rules:processing_pipeline.bzl",
21    "ProviderInfo",
22    "processing_pipeline",
23)
24load("@rules_android//rules:resources.bzl", _resources = "resources")
25load("@rules_android//rules:utils.bzl", "utils")
26load("@rules_android//rules/android_binary_internal:impl.bzl", "finalize", _BASE_PROCESSORS = "PROCESSORS")
27load("//build/bazel/rules/android:manifest_fixer.bzl", "manifest_fixer")
28load("//build/bazel/rules/cc:cc_stub_library.bzl", "CcStubInfo")
29load("//build/bazel/rules/common:api.bzl", "api")
30load("//build/bazel/rules/common:config.bzl", "has_unbundled_build_apps")
31load("//build/bazel/rules/common:sdk_version.bzl", "sdk_version")
32
33CollectedCcStubsInfo = provider(
34    "Tracks cc stub libraries to exclude from APK packaging.",
35    fields = {
36        "stubs": "A depset of Cc stub library files",
37    },
38)
39
40_ATTR_ASPECTS = ["deps", "dynamic_deps", "implementation_dynamic_deps", "system_dynamic_deps", "src", "shared_debuginfo", "shared"]
41
42def _collect_cc_stubs_aspect_impl(_target, ctx):
43    """An aspect that traverses the dep tree along _ATTR_ASPECTS and collects all deps with cc stubs.
44
45    For all discovered deps with cc stubs, add its linker_input and all dynamic_deps' linker_inputs to the returned list.
46
47    Args:
48        _target: Unused
49        ctx: The current aspect context.
50
51    Returns:
52        A list of CollectedCcStubsInfos which point to linker_inputs of discovered cc stubs.
53    """
54    stubs = []
55    extra_infos = []
56    for attr in _ATTR_ASPECTS:
57        if hasattr(ctx.rule.attr, attr):
58            gotten_attr = getattr(ctx.rule.attr, attr)
59            attr_as_list = gotten_attr
60            if type(getattr(ctx.rule.attr, attr)) == "Target":
61                attr_as_list = [gotten_attr]
62            for dep in attr_as_list:
63                if CcStubInfo in dep:
64                    stubs.append(dep[CcSharedLibraryInfo].linker_input)
65            extra_infos.extend(utils.collect_providers(CollectedCcStubsInfo, attr_as_list))
66
67    for info in extra_infos:
68        stubs.extend(info.stubs.to_list())
69    return [CollectedCcStubsInfo(stubs = depset(stubs))]
70
71collect_cc_stubs_aspect = aspect(
72    implementation = _collect_cc_stubs_aspect_impl,
73    attr_aspects = _ATTR_ASPECTS,
74)
75
76def _get_lib_name_from_ctx(ctx):
77    # Use the device ABI for the arch name when naming subdirectories within the APK's lib/ dir
78    # Note that the value from _product_config_abi[BuildSettingInfo].value is a list of strings
79    # where only the first element matters.
80    return ctx.attr._product_config_device_abi[BuildSettingInfo].value[0]
81
82def _process_native_deps_aosp(ctx, **_unused_ctxs):
83    """AOSP-specific native dep processof for android_binary.
84
85    Bypasses any C++ toolchains or compiling or linking, as AOSP's JNI dependencies are all
86    built via the cc_library_shared() macro, which already handles compilation and linking.
87
88    Args:
89        ctx: The build context
90        **_unused_ctxs: Unused
91
92    Returns:
93        An AndroidBinaryNativeLibsInfo provider that informs downstream native.android_binary of the native libs.
94    """
95
96    # determine where in the APK to put the .so files
97    lib_dir_name = _get_lib_name_from_ctx(ctx)
98
99    # determine list of stub cc libraries
100    stubs_to_ignore = []
101    for dep in ctx.attr.deps:
102        if CollectedCcStubsInfo in dep:
103            stubs_to_ignore = dep[CollectedCcStubsInfo].stubs.to_list()
104
105    # get all CcSharedLibraryInfo linker_inputs
106    shared_libs = []
107    for dep in ctx.attr.deps:
108        if CcSharedLibraryInfo in dep:
109            shared_libs.append(dep[CcSharedLibraryInfo].linker_input)
110
111            for dyndep in dep[CcSharedLibraryInfo].dynamic_deps.to_list():
112                if dyndep.linker_input not in stubs_to_ignore:
113                    shared_libs.append(dyndep.linker_input)
114
115    shared_lib_files = [lib.libraries[0].dynamic_library for lib in shared_libs]
116
117    libs = dict()
118    libs[lib_dir_name] = depset(shared_lib_files)
119
120    return struct(
121        name = "native_libs_ctx",
122        value = struct(providers = [
123            AndroidBinaryNativeLibsInfo(
124                libs,
125                None,
126                None,
127            ),
128        ]),
129    )
130
131# Starlark implementation of AndroidApp.MinSdkVersion from build/soong/java/app.go
132def _maybe_override_min_sdk_version(ctx):
133    min_sdk_version = sdk_version.api_level_string_with_fallback(
134        ctx.attr.manifest_values.get("minSdkVersion"),
135        ctx.attr.sdk_version,
136    )
137    override_apex_manifest_default_version = ctx.attr._override_apex_manifest_default_version[BuildSettingInfo].value
138    if (ctx.attr.updatable and
139        override_apex_manifest_default_version and
140        (api.parse_api_level_from_version(override_apex_manifest_default_version) >
141         api.parse_api_level_from_version(min_sdk_version))):
142        return override_apex_manifest_default_version
143    return min_sdk_version
144
145def _maybe_override_manifest_values(ctx):
146    min_sdk_version = api.effective_version_string(_maybe_override_min_sdk_version(ctx))
147
148    # TODO: b/300916281 - When Api fingerprinting is used, it should be appended to the target SDK version here.
149    target_sdk_version = manifest_fixer.target_sdk_version_for_manifest_fixer(
150        target_sdk_version = sdk_version.api_level_string_with_fallback(
151            ctx.attr.manifest_values.get("targetSdkVersion"),
152            ctx.attr.sdk_version,
153        ),
154        platform_sdk_final = ctx.attr._platform_sdk_final[BuildSettingInfo].value,
155        has_unbundled_build_apps = has_unbundled_build_apps(ctx.attr._unbundled_build_apps),
156    )
157    return struct(
158        min_sdk_version = min_sdk_version,
159        target_sdk_version = target_sdk_version,
160    )
161
162def _process_manifest_aosp(ctx, **_unused_ctxs):
163    maybe_overriden_values = _maybe_override_manifest_values(ctx)
164    out_manifest = ctx.actions.declare_file("fixed_manifest/" + ctx.label.name + "/" + "AndroidManifest.xml")
165    manifest_fixer.fix(
166        ctx,
167        manifest_fixer = ctx.executable._manifest_fixer,
168        in_manifest = ctx.file.manifest,
169        out_manifest = out_manifest,
170        min_sdk_version = maybe_overriden_values.min_sdk_version,
171        target_sdk_version = maybe_overriden_values.target_sdk_version,
172    )
173
174    updated_manifest_values = {
175        key: ctx.attr.manifest_values[key]
176        for key in ctx.attr.manifest_values.keys()
177        if key not in ("minSdkVersion", "targetSdkVersion")
178    }
179
180    return ProviderInfo(
181        name = "manifest_ctx",
182        value = _resources.ManifestContextInfo(
183            processed_manifest = out_manifest,
184            processed_manifest_values = updated_manifest_values,
185        ),
186    )
187
188# TODO: b/303862657 - Populate with any needed validation
189def _validate_manifest_aosp(
190        ctx,  # @unused
191        **_unused_ctxs):
192    return
193
194# (b/274150785)  validation processor does not allow min_sdk that are a string
195PROCESSORS = processing_pipeline.replace(
196    _BASE_PROCESSORS,
197    ManifestProcessor = _process_manifest_aosp,
198    ValidateManifestProcessor = _validate_manifest_aosp,
199    NativeLibsProcessor = _process_native_deps_aosp,
200)
201
202_PROCESSING_PIPELINE = processing_pipeline.make_processing_pipeline(
203    processors = PROCESSORS,
204    finalize = finalize,
205)
206
207def impl(ctx):
208    """The rule implementation.
209
210    Args:
211      ctx: The context.
212
213    Returns:
214      A list of providers.
215    """
216    java_package = java.resolve_package_from_label(ctx.label, ctx.attr.custom_package)
217    return processing_pipeline.run(ctx, java_package, _PROCESSING_PIPELINE)
218