1*7594170eSAndroid Build Coastguard Worker# Copyright (C) 2022 The Android Open Source Project 2*7594170eSAndroid Build Coastguard Worker# 3*7594170eSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 4*7594170eSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 5*7594170eSAndroid Build Coastguard Worker# You may obtain a copy of the License at 6*7594170eSAndroid Build Coastguard Worker# 7*7594170eSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 8*7594170eSAndroid Build Coastguard Worker# 9*7594170eSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 10*7594170eSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 11*7594170eSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*7594170eSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 13*7594170eSAndroid Build Coastguard Worker# limitations under the License. 14*7594170eSAndroid Build Coastguard Worker 15*7594170eSAndroid Build Coastguard Workerload("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo") 16*7594170eSAndroid Build Coastguard Workerload("//build/bazel/rules:common.bzl", "get_dep_targets", "strip_bp2build_label_suffix") 17*7594170eSAndroid Build Coastguard Workerload("//build/bazel/rules/android:android_app_certificate.bzl", "AndroidAppCertificateInfo") 18*7594170eSAndroid Build Coastguard Workerload(":apex_available.bzl", "ApexAvailableInfo") 19*7594170eSAndroid Build Coastguard Workerload(":apex_info.bzl", "ApexInfo") 20*7594170eSAndroid Build Coastguard Workerload(":apex_key.bzl", "ApexKeyInfo") 21*7594170eSAndroid Build Coastguard Workerload(":cc.bzl", "get_min_sdk_version") 22*7594170eSAndroid Build Coastguard Worker 23*7594170eSAndroid Build Coastguard WorkerApexDepsInfo = provider( 24*7594170eSAndroid Build Coastguard Worker "ApexDepsInfo collects transitive deps for dependency validation.", 25*7594170eSAndroid Build Coastguard Worker fields = { 26*7594170eSAndroid Build Coastguard Worker "transitive_deps": "Labels of targets that are depended on by this APEX.", 27*7594170eSAndroid Build Coastguard Worker }, 28*7594170eSAndroid Build Coastguard Worker) 29*7594170eSAndroid Build Coastguard Worker 30*7594170eSAndroid Build Coastguard WorkerApexDepInfo = provider( 31*7594170eSAndroid Build Coastguard Worker "ApexDepInfo collects metadata about dependencies of APEXs.", 32*7594170eSAndroid Build Coastguard Worker fields = { 33*7594170eSAndroid Build Coastguard Worker "is_external": "True if this target is an external dep to the APEX.", 34*7594170eSAndroid Build Coastguard Worker "label": "Label of target", 35*7594170eSAndroid Build Coastguard Worker "min_sdk_version": "min_sdk_version of target", 36*7594170eSAndroid Build Coastguard Worker }, 37*7594170eSAndroid Build Coastguard Worker) 38*7594170eSAndroid Build Coastguard Worker 39*7594170eSAndroid Build Coastguard Worker_IGNORED_PACKAGES = [ 40*7594170eSAndroid Build Coastguard Worker "build/bazel/platforms", 41*7594170eSAndroid Build Coastguard Worker] 42*7594170eSAndroid Build Coastguard Worker_IGNORED_REPOSITORIES = [ 43*7594170eSAndroid Build Coastguard Worker "bazel_tools", 44*7594170eSAndroid Build Coastguard Worker] 45*7594170eSAndroid Build Coastguard Worker_IGNORED_RULE_KINDS = [ 46*7594170eSAndroid Build Coastguard Worker # No validation for language-agnostic targets. In general language 47*7594170eSAndroid Build Coastguard Worker # agnostic rules to support AIDL, HIDL, Sysprop do not have an analogous 48*7594170eSAndroid Build Coastguard Worker # module type in Soong and do not have an apex_available property, often 49*7594170eSAndroid Build Coastguard Worker # relying on language-specific apex_available properties. Because a 50*7594170eSAndroid Build Coastguard Worker # language-specific rule is required for a language-agnostic rule to be 51*7594170eSAndroid Build Coastguard Worker # within the transitive deps of an apex and impact the apex contents, this 52*7594170eSAndroid Build Coastguard Worker # is safe. 53*7594170eSAndroid Build Coastguard Worker "aidl_library", 54*7594170eSAndroid Build Coastguard Worker "hidl_library", 55*7594170eSAndroid Build Coastguard Worker "sysprop_library", 56*7594170eSAndroid Build Coastguard Worker 57*7594170eSAndroid Build Coastguard Worker # Build settings, these have no built artifact and thus will not be 58*7594170eSAndroid Build Coastguard Worker # included in an apex. 59*7594170eSAndroid Build Coastguard Worker "string_list_setting", 60*7594170eSAndroid Build Coastguard Worker "string_setting", 61*7594170eSAndroid Build Coastguard Worker 62*7594170eSAndroid Build Coastguard Worker # These rule kinds cannot be skipped by checking providers because most 63*7594170eSAndroid Build Coastguard Worker # targets have a License provider 64*7594170eSAndroid Build Coastguard Worker "_license", 65*7594170eSAndroid Build Coastguard Worker "_license_kind", 66*7594170eSAndroid Build Coastguard Worker] 67*7594170eSAndroid Build Coastguard Worker_IGNORED_PROVIDERS = [ 68*7594170eSAndroid Build Coastguard Worker AndroidAppCertificateInfo, 69*7594170eSAndroid Build Coastguard Worker ApexKeyInfo, 70*7594170eSAndroid Build Coastguard Worker ProtoInfo, 71*7594170eSAndroid Build Coastguard Worker] 72*7594170eSAndroid Build Coastguard Worker_IGNORED_ATTRS = [ 73*7594170eSAndroid Build Coastguard Worker "androidmk_static_deps", 74*7594170eSAndroid Build Coastguard Worker "androidmk_whole_archive_deps", 75*7594170eSAndroid Build Coastguard Worker "androidmk_dynamic_deps", 76*7594170eSAndroid Build Coastguard Worker "androidmk_deps", 77*7594170eSAndroid Build Coastguard Worker] 78*7594170eSAndroid Build Coastguard Worker_IGNORED_TARGETS = [ 79*7594170eSAndroid Build Coastguard Worker "default_metadata_file", 80*7594170eSAndroid Build Coastguard Worker] 81*7594170eSAndroid Build Coastguard Worker 82*7594170eSAndroid Build Coastguard Workerdef _should_skip_apex_dep(target, ctx): 83*7594170eSAndroid Build Coastguard Worker # Ignore Bazel-specific targets like platform/os/arch constraints, 84*7594170eSAndroid Build Coastguard Worker # anything from @bazel_tools, and rule types that we dont care about 85*7594170eSAndroid Build Coastguard Worker # for dependency validation like licenses, certificates, etc. 86*7594170eSAndroid Build Coastguard Worker #TODO(b/261715581) update allowed_deps.txt to include Bazel-specific targets 87*7594170eSAndroid Build Coastguard Worker return ( 88*7594170eSAndroid Build Coastguard Worker ctx.label.workspace_name in _IGNORED_REPOSITORIES or 89*7594170eSAndroid Build Coastguard Worker ctx.label.package in _IGNORED_PACKAGES or 90*7594170eSAndroid Build Coastguard Worker ctx.rule.kind in _IGNORED_RULE_KINDS or 91*7594170eSAndroid Build Coastguard Worker True in [p in target for p in _IGNORED_PROVIDERS] or 92*7594170eSAndroid Build Coastguard Worker target.label.name in _IGNORED_TARGETS 93*7594170eSAndroid Build Coastguard Worker ) 94*7594170eSAndroid Build Coastguard Worker 95*7594170eSAndroid Build Coastguard Workerdef _apex_dep_validation_aspect_impl(target, ctx): 96*7594170eSAndroid Build Coastguard Worker transitive_deps = [] 97*7594170eSAndroid Build Coastguard Worker for attr, attr_deps in get_dep_targets(ctx.rule.attr, predicate = lambda target: ApexDepsInfo in target).items(): 98*7594170eSAndroid Build Coastguard Worker if attr in _IGNORED_ATTRS: 99*7594170eSAndroid Build Coastguard Worker continue 100*7594170eSAndroid Build Coastguard Worker for dep in attr_deps: 101*7594170eSAndroid Build Coastguard Worker transitive_deps.append(dep[ApexDepsInfo].transitive_deps) 102*7594170eSAndroid Build Coastguard Worker 103*7594170eSAndroid Build Coastguard Worker if _should_skip_apex_dep(target, ctx): 104*7594170eSAndroid Build Coastguard Worker return ApexDepsInfo( 105*7594170eSAndroid Build Coastguard Worker transitive_deps = depset( 106*7594170eSAndroid Build Coastguard Worker transitive = transitive_deps, 107*7594170eSAndroid Build Coastguard Worker ), 108*7594170eSAndroid Build Coastguard Worker ) 109*7594170eSAndroid Build Coastguard Worker 110*7594170eSAndroid Build Coastguard Worker is_external = False 111*7594170eSAndroid Build Coastguard Worker include_self_in_transitive_deps = True 112*7594170eSAndroid Build Coastguard Worker 113*7594170eSAndroid Build Coastguard Worker if "manual" in ctx.rule.attr.tags and "apex_available_checked_manual_for_testing" not in ctx.rule.attr.tags: 114*7594170eSAndroid Build Coastguard Worker include_self_in_transitive_deps = False 115*7594170eSAndroid Build Coastguard Worker else: 116*7594170eSAndroid Build Coastguard Worker apex_available_names = target[ApexAvailableInfo].apex_available_names 117*7594170eSAndroid Build Coastguard Worker apex_name = ctx.attr._apex_name[BuildSettingInfo].value 118*7594170eSAndroid Build Coastguard Worker base_apex_name = ctx.attr._base_apex_name[BuildSettingInfo].value 119*7594170eSAndroid Build Coastguard Worker if not ( 120*7594170eSAndroid Build Coastguard Worker "//apex_available:anyapex" in apex_available_names or 121*7594170eSAndroid Build Coastguard Worker base_apex_name in apex_available_names or 122*7594170eSAndroid Build Coastguard Worker apex_name in apex_available_names 123*7594170eSAndroid Build Coastguard Worker ): 124*7594170eSAndroid Build Coastguard Worker # APEX deps validation stops when the dependency graph crosses the APEX boundary 125*7594170eSAndroid Build Coastguard Worker # Record that this is a boundary target, so that we exclude can it later from validation 126*7594170eSAndroid Build Coastguard Worker is_external = True 127*7594170eSAndroid Build Coastguard Worker transitive_deps = [] 128*7594170eSAndroid Build Coastguard Worker 129*7594170eSAndroid Build Coastguard Worker if not target[ApexAvailableInfo].platform_available: 130*7594170eSAndroid Build Coastguard Worker # Skip dependencies that are only available to APEXes; they are 131*7594170eSAndroid Build Coastguard Worker # developed with updatability in mind and don't need manual approval. 132*7594170eSAndroid Build Coastguard Worker include_self_in_transitive_deps = False 133*7594170eSAndroid Build Coastguard Worker 134*7594170eSAndroid Build Coastguard Worker if ApexInfo in target: 135*7594170eSAndroid Build Coastguard Worker include_self_in_transitive_deps = False 136*7594170eSAndroid Build Coastguard Worker 137*7594170eSAndroid Build Coastguard Worker direct_deps = [] 138*7594170eSAndroid Build Coastguard Worker if include_self_in_transitive_deps: 139*7594170eSAndroid Build Coastguard Worker direct_deps = [ 140*7594170eSAndroid Build Coastguard Worker ApexDepInfo( 141*7594170eSAndroid Build Coastguard Worker label = ctx.label, 142*7594170eSAndroid Build Coastguard Worker is_external = is_external, 143*7594170eSAndroid Build Coastguard Worker min_sdk_version = get_min_sdk_version(ctx), 144*7594170eSAndroid Build Coastguard Worker ), 145*7594170eSAndroid Build Coastguard Worker ] 146*7594170eSAndroid Build Coastguard Worker 147*7594170eSAndroid Build Coastguard Worker return ApexDepsInfo( 148*7594170eSAndroid Build Coastguard Worker transitive_deps = depset( 149*7594170eSAndroid Build Coastguard Worker direct = direct_deps, 150*7594170eSAndroid Build Coastguard Worker transitive = transitive_deps, 151*7594170eSAndroid Build Coastguard Worker ), 152*7594170eSAndroid Build Coastguard Worker ) 153*7594170eSAndroid Build Coastguard Worker 154*7594170eSAndroid Build Coastguard Workerapex_deps_validation_aspect = aspect( 155*7594170eSAndroid Build Coastguard Worker doc = "apex_deps_validation_aspect walks the deps of an APEX and records" + 156*7594170eSAndroid Build Coastguard Worker " its transitive dependencies so that they can be validated against" + 157*7594170eSAndroid Build Coastguard Worker " allowed_deps.txt.", 158*7594170eSAndroid Build Coastguard Worker implementation = _apex_dep_validation_aspect_impl, 159*7594170eSAndroid Build Coastguard Worker attr_aspects = ["*"], 160*7594170eSAndroid Build Coastguard Worker apply_to_generating_rules = True, 161*7594170eSAndroid Build Coastguard Worker attrs = { 162*7594170eSAndroid Build Coastguard Worker "_apex_name": attr.label(default = "//build/bazel/rules/apex:apex_name"), 163*7594170eSAndroid Build Coastguard Worker "_base_apex_name": attr.label(default = "//build/bazel/rules/apex:base_apex_name"), 164*7594170eSAndroid Build Coastguard Worker "_direct_deps": attr.label(default = "//build/bazel/rules/apex:apex_direct_deps"), 165*7594170eSAndroid Build Coastguard Worker }, 166*7594170eSAndroid Build Coastguard Worker required_aspect_providers = [ApexAvailableInfo], 167*7594170eSAndroid Build Coastguard Worker provides = [ApexDepsInfo], 168*7594170eSAndroid Build Coastguard Worker) 169*7594170eSAndroid Build Coastguard Worker 170*7594170eSAndroid Build Coastguard Workerdef _min_sdk_version_string(version): 171*7594170eSAndroid Build Coastguard Worker if version.apex_inherit: 172*7594170eSAndroid Build Coastguard Worker return "apex_inherit" 173*7594170eSAndroid Build Coastguard Worker elif version.min_sdk_version == None: 174*7594170eSAndroid Build Coastguard Worker return "(no version)" 175*7594170eSAndroid Build Coastguard Worker return version.min_sdk_version 176*7594170eSAndroid Build Coastguard Worker 177*7594170eSAndroid Build Coastguard Workerdef _apex_dep_to_string(apex_dep_info): 178*7594170eSAndroid Build Coastguard Worker return "{name}(minSdkVersion:{min_sdk_version})".format( 179*7594170eSAndroid Build Coastguard Worker name = strip_bp2build_label_suffix(apex_dep_info.label.name), 180*7594170eSAndroid Build Coastguard Worker min_sdk_version = _min_sdk_version_string(apex_dep_info.min_sdk_version), 181*7594170eSAndroid Build Coastguard Worker ) 182*7594170eSAndroid Build Coastguard Worker 183*7594170eSAndroid Build Coastguard Workerdef apex_dep_infos_to_allowlist_strings(apex_dep_infos): 184*7594170eSAndroid Build Coastguard Worker """apex_dep_infos_to_allowlist_strings converts outputs a string that can be compared against allowed_deps.txt 185*7594170eSAndroid Build Coastguard Worker 186*7594170eSAndroid Build Coastguard Worker Args: 187*7594170eSAndroid Build Coastguard Worker apex_dep_infos (list[ApexDepInfo]): list of deps to convert 188*7594170eSAndroid Build Coastguard Worker Returns: 189*7594170eSAndroid Build Coastguard Worker a list of strings conforming to the format of allowed_deps.txt 190*7594170eSAndroid Build Coastguard Worker """ 191*7594170eSAndroid Build Coastguard Worker return [ 192*7594170eSAndroid Build Coastguard Worker _apex_dep_to_string(d) 193*7594170eSAndroid Build Coastguard Worker for d in apex_dep_infos 194*7594170eSAndroid Build Coastguard Worker if not d.is_external 195*7594170eSAndroid Build Coastguard Worker ] 196*7594170eSAndroid Build Coastguard Worker 197*7594170eSAndroid Build Coastguard Workerdef validate_apex_deps(ctx, transitive_deps, allowed_deps_manifest): 198*7594170eSAndroid Build Coastguard Worker """validate_apex_deps generates actions to validate that all deps in transitive_deps exist in the allowed_deps file 199*7594170eSAndroid Build Coastguard Worker 200*7594170eSAndroid Build Coastguard Worker Args: 201*7594170eSAndroid Build Coastguard Worker ctx (rule context): a rule context 202*7594170eSAndroid Build Coastguard Worker transitive_deps (depset[ApexDepsInfo]): list of transitive dependencies 203*7594170eSAndroid Build Coastguard Worker of an APEX. This is most likely generated by collecting the output 204*7594170eSAndroid Build Coastguard Worker of apex_deps_validation_aspect 205*7594170eSAndroid Build Coastguard Worker allowed_deps_manifest (File): a file containing an allowlist of modules 206*7594170eSAndroid Build Coastguard Worker that can be included in an APEX. This is expected to be in the format 207*7594170eSAndroid Build Coastguard Worker of //packages/modules/common/build/allowed_deps.txt 208*7594170eSAndroid Build Coastguard Worker Returns: 209*7594170eSAndroid Build Coastguard Worker validation_marker (File): an empty file created if validation succeeds 210*7594170eSAndroid Build Coastguard Worker """ 211*7594170eSAndroid Build Coastguard Worker apex_deps_file = ctx.actions.declare_file(ctx.label.name + ".current_deps") 212*7594170eSAndroid Build Coastguard Worker ctx.actions.write( 213*7594170eSAndroid Build Coastguard Worker apex_deps_file, 214*7594170eSAndroid Build Coastguard Worker "\n".join(apex_dep_infos_to_allowlist_strings(transitive_deps.to_list())), 215*7594170eSAndroid Build Coastguard Worker ) 216*7594170eSAndroid Build Coastguard Worker validation_marker = ctx.actions.declare_file(ctx.label.name + ".allowed_deps") 217*7594170eSAndroid Build Coastguard Worker shell_command = """ 218*7594170eSAndroid Build Coastguard Worker export module_diff=$( 219*7594170eSAndroid Build Coastguard Worker cat {allowed_deps_manifest} | 220*7594170eSAndroid Build Coastguard Worker sed -e 's/^prebuilt_//g' | 221*7594170eSAndroid Build Coastguard Worker sort | 222*7594170eSAndroid Build Coastguard Worker comm -23 <(sort -u {apex_deps_file}) - 223*7594170eSAndroid Build Coastguard Worker ); 224*7594170eSAndroid Build Coastguard Worker export diff_size=$(echo "$module_diff" | wc -w); 225*7594170eSAndroid Build Coastguard Worker if [[ $diff_size -eq 0 ]]; then 226*7594170eSAndroid Build Coastguard Worker touch {validation_marker}; 227*7594170eSAndroid Build Coastguard Worker else 228*7594170eSAndroid Build Coastguard Worker echo -e "\n******************************"; 229*7594170eSAndroid Build Coastguard Worker echo "ERROR: go/apex-allowed-deps-error contains more information"; 230*7594170eSAndroid Build Coastguard Worker echo "******************************"; 231*7594170eSAndroid Build Coastguard Worker echo "Detected changes to allowed dependencies in updatable modules."; 232*7594170eSAndroid Build Coastguard Worker echo "There are $diff_size dependencies of APEX {target_label} on modules not in {allowed_deps_manifest}:"; 233*7594170eSAndroid Build Coastguard Worker echo "$module_diff"; 234*7594170eSAndroid Build Coastguard Worker echo "To fix and update packages/modules/common/build/allowed_deps.txt, please run:"; 235*7594170eSAndroid Build Coastguard Worker echo -e "$ (croot && packages/modules/common/build/update-apex-allowed-deps.sh)\n"; 236*7594170eSAndroid Build Coastguard Worker echo "When submitting the generated CL, you must include the following information"; 237*7594170eSAndroid Build Coastguard Worker echo "in the commit message if you are adding a new dependency:"; 238*7594170eSAndroid Build Coastguard Worker echo "Apex-Size-Increase: Expected binary size increase for affected APEXes (or the size of the .jar / .so file of the new library)"; 239*7594170eSAndroid Build Coastguard Worker echo "Previous-Platform-Support: Are the maintainers of the new dependency committed to supporting previous platform releases?"; 240*7594170eSAndroid Build Coastguard Worker echo "Aosp-First: Is the new dependency being developed AOSP-first or internal?"; 241*7594170eSAndroid Build Coastguard Worker echo "Test-Info: What’s the testing strategy for the new dependency? Does it have its own tests, and are you adding integration tests? How/when are the tests run?"; 242*7594170eSAndroid Build Coastguard Worker echo "You do not need OWNERS approval to submit the change, but mainline-modularization@"; 243*7594170eSAndroid Build Coastguard Worker echo "will periodically review additions and may require changes."; 244*7594170eSAndroid Build Coastguard Worker echo -e "******************************\n"; 245*7594170eSAndroid Build Coastguard Worker exit 1; 246*7594170eSAndroid Build Coastguard Worker fi; 247*7594170eSAndroid Build Coastguard Worker """.format( 248*7594170eSAndroid Build Coastguard Worker allowed_deps_manifest = allowed_deps_manifest.path, 249*7594170eSAndroid Build Coastguard Worker apex_deps_file = apex_deps_file.path, 250*7594170eSAndroid Build Coastguard Worker validation_marker = validation_marker.path, 251*7594170eSAndroid Build Coastguard Worker target_label = ctx.label, 252*7594170eSAndroid Build Coastguard Worker ) 253*7594170eSAndroid Build Coastguard Worker ctx.actions.run_shell( 254*7594170eSAndroid Build Coastguard Worker inputs = [allowed_deps_manifest, apex_deps_file], 255*7594170eSAndroid Build Coastguard Worker outputs = [validation_marker], 256*7594170eSAndroid Build Coastguard Worker command = shell_command, 257*7594170eSAndroid Build Coastguard Worker mnemonic = "ApexDepValidation", 258*7594170eSAndroid Build Coastguard Worker progress_message = "Validating APEX dependencies", 259*7594170eSAndroid Build Coastguard Worker ) 260*7594170eSAndroid Build Coastguard Worker 261*7594170eSAndroid Build Coastguard Worker return validation_marker 262