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