1# Copyright (C) 2022 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("@soong_injection//apex_toolchain:constants.bzl", "apex_available_baseline") 17load("//build/bazel/rules:common.bzl", "get_dep_targets", "strip_bp2build_label_suffix") 18load("//build/bazel/rules:prebuilt_file.bzl", "PrebuiltFileInfo") 19load("//build/bazel/rules/apex:cc.bzl", "CC_ATTR_ASPECTS") 20load("//build/bazel/rules/cc:cc_library_static.bzl", "CcStaticLibraryInfo") 21load("//build/bazel/rules/cc:cc_stub_library.bzl", "CcStubLibrarySharedInfo") 22 23ApexAvailableInfo = provider( 24 "ApexAvailableInfo collects APEX availability metadata.", 25 fields = { 26 "apex_available_names": "names of APEXs that this target is available to", 27 "platform_available": "whether this target is available for the platform", 28 "transitive_invalid_targets": "list of targets that had an invalid apex_available attribute", 29 "transitive_unvalidated_targets": "list of targets that were skipped in the apex_available_validation function", 30 }, 31) 32 33# Validates if a target is made available as a transitive dependency of an APEX. The return 34# value is tri-state: True, False, string. Strings are used when a target is _not checked_ 35# and the string itself contains the reason. 36def _validate_apex_available(target, ctx, *, apex_available_tags, apex_name, base_apex_name): 37 # testonly apexes aren't checked. 38 if ctx.attr.testonly: 39 return "testonly" 40 41 # Macro-internal manual targets aren't checked. 42 if "manual" in ctx.rule.attr.tags and "apex_available_checked_manual_for_testing" not in ctx.rule.attr.tags: 43 return "manual" 44 45 # prebuilt_file targets don't specify apex_available, and aren't checked. 46 if PrebuiltFileInfo in target: 47 return "prebuilt" 48 49 # stubs are APIs, and don't specify apex_available, and aren't checked. 50 if CcStubLibrarySharedInfo in target: 51 return "stubs" 52 53 if "//apex_available:anyapex" in apex_available_tags: 54 return "//apex_available:anyapex" 55 56 # https://cs.android.com/android/platform/superproject/+/master:build/soong/apex/apex.go;l=2910;drc=862c0d68fff500d7fe59bc2fcfc9c7d75596e5b5 57 # Bp2build-generated cc_library_static target from stubs-providing lib 58 # doesn't have apex_available tag. 59 # If its shared variant is directly in the apex, skip validation 60 # Otherwise, it will be invalidated. 61 direct_deps = ctx.attr._direct_deps[BuildSettingInfo].value 62 if CcStaticLibraryInfo in target and str(target.label).removesuffix("_bp2build_cc_library_static") in direct_deps: 63 return "has shared variant directly included" 64 65 if base_apex_name in apex_available_tags or apex_name in apex_available_tags: 66 return True 67 68 target_name = strip_bp2build_label_suffix(target.label.name) 69 baselines = [ 70 apex_available_baseline.get(base_apex_name, []), 71 apex_available_baseline.get(apex_name, []), 72 apex_available_baseline.get("//apex_available:anyapex", []), 73 ] 74 if any([target_name in b for b in baselines]): 75 return True 76 77 return False 78 79_IGNORED_ATTRS = [ 80 "certificate", 81 "key", 82 "android_manifest", 83 "applicable_licenses", 84 "androidmk_static_deps", 85 "androidmk_whole_archive_deps", 86 "androidmk_dynamic_deps", 87 "androidmk_deps", 88] 89 90def _apex_available_aspect_impl(target, ctx): 91 apex_available_tags = [ 92 t.removeprefix("apex_available=") 93 for t in ctx.rule.attr.tags 94 if t.startswith("apex_available=") 95 ] 96 platform_available = ( 97 "//apex_available:platform" in apex_available_tags or 98 len(apex_available_tags) == 0 99 ) 100 apex_name = ctx.attr._apex_name[BuildSettingInfo].value 101 102 dep_targets = get_dep_targets( 103 ctx.rule.attr, 104 predicate = lambda target: ApexAvailableInfo in target, 105 ) 106 transitive_unvalidated_targets = [] 107 transitive_invalid_targets = [] 108 for attr, attr_targets in dep_targets.items(): 109 for t in attr_targets: 110 info = t[ApexAvailableInfo] 111 transitive_unvalidated_targets.append(info.transitive_unvalidated_targets) 112 if attr in CC_ATTR_ASPECTS: 113 transitive_invalid_targets.append(info.transitive_invalid_targets) 114 if attr not in _IGNORED_ATTRS: 115 if info.platform_available != None: 116 platform_available = platform_available and info.platform_available 117 118 if "manual" in ctx.rule.attr.tags and "apex_available_checked_manual_for_testing" not in ctx.rule.attr.tags: 119 platform_available = None 120 121 if CcStubLibrarySharedInfo in target: 122 # stub libraries libraries are always available to platform 123 # https://cs.android.com/android/platform/superproject/+/master:build/soong/cc/cc.go;l=3670;drc=89ff729d1d65fb0ce2945ec6b8c4777a9d78dcab 124 platform_available = True 125 126 skipped_reason = _validate_apex_available( 127 target, 128 ctx, 129 apex_available_tags = apex_available_tags, 130 apex_name = apex_name, 131 base_apex_name = ctx.attr._base_apex_name[BuildSettingInfo].value, 132 ) 133 134 return [ 135 ApexAvailableInfo( 136 platform_available = platform_available, 137 apex_available_names = apex_available_tags, 138 transitive_unvalidated_targets = depset( 139 direct = [(ctx.label, skipped_reason)] if type(skipped_reason) == type("") else None, 140 transitive = transitive_unvalidated_targets, 141 ), 142 transitive_invalid_targets = depset( 143 direct = [(target, tuple(apex_available_tags))] if skipped_reason == False else None, 144 transitive = transitive_invalid_targets, 145 ), 146 ), 147 ] 148 149apex_available_aspect = aspect( 150 implementation = _apex_available_aspect_impl, 151 provides = [ApexAvailableInfo], 152 apply_to_generating_rules = True, 153 attr_aspects = ["*"], 154 attrs = { 155 "testonly": attr.bool(default = False), # propagated from the apex 156 "_apex_name": attr.label(default = "//build/bazel/rules/apex:apex_name"), 157 "_base_apex_name": attr.label(default = "//build/bazel/rules/apex:base_apex_name"), 158 "_direct_deps": attr.label(default = "//build/bazel/rules/apex:apex_direct_deps"), 159 }, 160) 161