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//lib:paths.bzl", "paths") 16*7594170eSAndroid Build Coastguard Worker 17*7594170eSAndroid Build Coastguard WorkerAidlGenInfo = provider( 18*7594170eSAndroid Build Coastguard Worker fields = [ 19*7594170eSAndroid Build Coastguard Worker "srcs", 20*7594170eSAndroid Build Coastguard Worker "hdrs", 21*7594170eSAndroid Build Coastguard Worker "hash_file", 22*7594170eSAndroid Build Coastguard Worker "transitive_srcs", 23*7594170eSAndroid Build Coastguard Worker "transitive_include_dirs", 24*7594170eSAndroid Build Coastguard Worker "flags", 25*7594170eSAndroid Build Coastguard Worker ], 26*7594170eSAndroid Build Coastguard Worker) 27*7594170eSAndroid Build Coastguard Worker 28*7594170eSAndroid Build Coastguard Workerdef _symlink_aidl_srcs(ctx, srcs, strip_import_prefix): 29*7594170eSAndroid Build Coastguard Worker virtual_imports = paths.join("_virtual_imports", ctx.label.name) 30*7594170eSAndroid Build Coastguard Worker include_path = paths.join(ctx.genfiles_dir.path, ctx.label.package, virtual_imports) 31*7594170eSAndroid Build Coastguard Worker workspace_root_strip_import_prefix = paths.join(ctx.label.package, strip_import_prefix) 32*7594170eSAndroid Build Coastguard Worker 33*7594170eSAndroid Build Coastguard Worker direct_srcs = [] 34*7594170eSAndroid Build Coastguard Worker for src in srcs: 35*7594170eSAndroid Build Coastguard Worker src_path = src.short_path 36*7594170eSAndroid Build Coastguard Worker 37*7594170eSAndroid Build Coastguard Worker if not paths.normalize(src_path).startswith(paths.normalize(workspace_root_strip_import_prefix)): 38*7594170eSAndroid Build Coastguard Worker fail(".aidl file '%s' is not under the specified strip prefix '%s'" % 39*7594170eSAndroid Build Coastguard Worker (src_path, workspace_root_strip_import_prefix)) 40*7594170eSAndroid Build Coastguard Worker 41*7594170eSAndroid Build Coastguard Worker import_path = paths.relativize(src_path, workspace_root_strip_import_prefix) 42*7594170eSAndroid Build Coastguard Worker virtual_src = ctx.actions.declare_file(paths.join(virtual_imports, import_path)) 43*7594170eSAndroid Build Coastguard Worker ctx.actions.symlink( 44*7594170eSAndroid Build Coastguard Worker output = virtual_src, 45*7594170eSAndroid Build Coastguard Worker target_file = src, 46*7594170eSAndroid Build Coastguard Worker progress_message = "Symlinking virtual .aidl sources for %{label}", 47*7594170eSAndroid Build Coastguard Worker ) 48*7594170eSAndroid Build Coastguard Worker direct_srcs.append(virtual_src) 49*7594170eSAndroid Build Coastguard Worker return include_path, direct_srcs 50*7594170eSAndroid Build Coastguard Worker 51*7594170eSAndroid Build Coastguard Worker# https://cs.android.com/android/platform/system/tools/aidl/+/master:build/aidl_api.go;l=718-724;drc=87bcb923b4ed9cf6e6837f4cc02d954f211c0b12 52*7594170eSAndroid Build Coastguard Workerdef _version_for_hash_gen(version): 53*7594170eSAndroid Build Coastguard Worker if int(version) > 1: 54*7594170eSAndroid Build Coastguard Worker return int(version) - 1 55*7594170eSAndroid Build Coastguard Worker return "latest-version" 56*7594170eSAndroid Build Coastguard Worker 57*7594170eSAndroid Build Coastguard Workerdef _get_aidl_interface_name(versioned_name): 58*7594170eSAndroid Build Coastguard Worker parts = versioned_name.split("-V") 59*7594170eSAndroid Build Coastguard Worker if len(parts) == 1 or not parts[-1].isdigit(): 60*7594170eSAndroid Build Coastguard Worker fail("{}'s version is not parsable", versioned_name) 61*7594170eSAndroid Build Coastguard Worker 62*7594170eSAndroid Build Coastguard Worker return parts[0] 63*7594170eSAndroid Build Coastguard Worker 64*7594170eSAndroid Build Coastguard Workerdef _verify_hash_file(ctx): 65*7594170eSAndroid Build Coastguard Worker timestamp = ctx.actions.declare_file(ctx.label.name + "_checkhash_" + ctx.attr.version + ".timestamp") 66*7594170eSAndroid Build Coastguard Worker 67*7594170eSAndroid Build Coastguard Worker api_dir = "{package_dir}/aidl_api/{aidl_interface_name}/{version}".format( 68*7594170eSAndroid Build Coastguard Worker package_dir = paths.dirname(ctx.build_file_path), 69*7594170eSAndroid Build Coastguard Worker aidl_interface_name = _get_aidl_interface_name(ctx.label.name), 70*7594170eSAndroid Build Coastguard Worker version = ctx.attr.version, 71*7594170eSAndroid Build Coastguard Worker ) 72*7594170eSAndroid Build Coastguard Worker 73*7594170eSAndroid Build Coastguard Worker shell_command = """ 74*7594170eSAndroid Build Coastguard Worker cd {api_dir} 75*7594170eSAndroid Build Coastguard Worker aidl_files_checksums=$(find ./ -name "*.aidl" -print0 | LC_ALL=C sort -z | xargs -0 sha1sum && echo {version}) 76*7594170eSAndroid Build Coastguard Worker cd - 77*7594170eSAndroid Build Coastguard Worker 78*7594170eSAndroid Build Coastguard Worker if [[ $(echo "$aidl_files_checksums" | sha1sum | cut -d " " -f 1) = $(tail -1 {hash_file}) ]]; then 79*7594170eSAndroid Build Coastguard Worker touch {timestamp}; 80*7594170eSAndroid Build Coastguard Worker else 81*7594170eSAndroid Build Coastguard Worker cat "{message_check_equality}" 82*7594170eSAndroid Build Coastguard Worker exit 1; 83*7594170eSAndroid Build Coastguard Worker fi; 84*7594170eSAndroid Build Coastguard Worker """.format( 85*7594170eSAndroid Build Coastguard Worker api_dir = api_dir, 86*7594170eSAndroid Build Coastguard Worker aidl_files = " ".join([src.path for src in ctx.files.srcs]), 87*7594170eSAndroid Build Coastguard Worker version = _version_for_hash_gen(ctx.attr.version), 88*7594170eSAndroid Build Coastguard Worker hash_file = ctx.file.hash_file.path, 89*7594170eSAndroid Build Coastguard Worker timestamp = timestamp.path, 90*7594170eSAndroid Build Coastguard Worker message_check_equality = ctx.file._message_check_equality.path, 91*7594170eSAndroid Build Coastguard Worker ) 92*7594170eSAndroid Build Coastguard Worker 93*7594170eSAndroid Build Coastguard Worker ctx.actions.run_shell( 94*7594170eSAndroid Build Coastguard Worker inputs = ctx.files.srcs + [ctx.file.hash_file, ctx.file._message_check_equality], 95*7594170eSAndroid Build Coastguard Worker outputs = [timestamp], 96*7594170eSAndroid Build Coastguard Worker command = shell_command, 97*7594170eSAndroid Build Coastguard Worker mnemonic = "AidlHashValidation", 98*7594170eSAndroid Build Coastguard Worker progress_message = "Validating AIDL .hash file", 99*7594170eSAndroid Build Coastguard Worker ) 100*7594170eSAndroid Build Coastguard Worker 101*7594170eSAndroid Build Coastguard Worker return timestamp 102*7594170eSAndroid Build Coastguard Worker 103*7594170eSAndroid Build Coastguard Workerdef _aidl_library_rule_impl(ctx): 104*7594170eSAndroid Build Coastguard Worker transitive_srcs = [] 105*7594170eSAndroid Build Coastguard Worker transitive_include_dirs = [] 106*7594170eSAndroid Build Coastguard Worker 107*7594170eSAndroid Build Coastguard Worker validation_output = [] 108*7594170eSAndroid Build Coastguard Worker 109*7594170eSAndroid Build Coastguard Worker if ctx.attr.hash_file and ctx.attr.version: 110*7594170eSAndroid Build Coastguard Worker # if the aidl_library represents an aidl_interface frozen version, 111*7594170eSAndroid Build Coastguard Worker # hash_file and version attributes are set 112*7594170eSAndroid Build Coastguard Worker validation_output.append(_verify_hash_file(ctx)) 113*7594170eSAndroid Build Coastguard Worker 114*7594170eSAndroid Build Coastguard Worker aidl_import_infos = [d[AidlGenInfo] for d in ctx.attr.deps] 115*7594170eSAndroid Build Coastguard Worker for info in aidl_import_infos: 116*7594170eSAndroid Build Coastguard Worker transitive_srcs.append(info.transitive_srcs) 117*7594170eSAndroid Build Coastguard Worker transitive_include_dirs.append(info.transitive_include_dirs) 118*7594170eSAndroid Build Coastguard Worker 119*7594170eSAndroid Build Coastguard Worker include_path, srcs = _symlink_aidl_srcs(ctx, ctx.files.srcs, ctx.attr.strip_import_prefix) 120*7594170eSAndroid Build Coastguard Worker _, hdrs = _symlink_aidl_srcs(ctx, ctx.files.hdrs, ctx.attr.strip_import_prefix) 121*7594170eSAndroid Build Coastguard Worker 122*7594170eSAndroid Build Coastguard Worker return [ 123*7594170eSAndroid Build Coastguard Worker DefaultInfo(files = depset(ctx.files.srcs)), 124*7594170eSAndroid Build Coastguard Worker OutputGroupInfo( 125*7594170eSAndroid Build Coastguard Worker _validation = depset(direct = validation_output), 126*7594170eSAndroid Build Coastguard Worker ), 127*7594170eSAndroid Build Coastguard Worker AidlGenInfo( 128*7594170eSAndroid Build Coastguard Worker srcs = depset(srcs), 129*7594170eSAndroid Build Coastguard Worker hdrs = depset(hdrs), 130*7594170eSAndroid Build Coastguard Worker hash_file = ctx.file.hash_file, 131*7594170eSAndroid Build Coastguard Worker transitive_srcs = depset( 132*7594170eSAndroid Build Coastguard Worker direct = srcs + hdrs, 133*7594170eSAndroid Build Coastguard Worker transitive = transitive_srcs, 134*7594170eSAndroid Build Coastguard Worker ), 135*7594170eSAndroid Build Coastguard Worker transitive_include_dirs = depset( 136*7594170eSAndroid Build Coastguard Worker direct = [include_path], 137*7594170eSAndroid Build Coastguard Worker transitive = transitive_include_dirs, 138*7594170eSAndroid Build Coastguard Worker # build with preorder so that transitive_include_dirs.to_list() 139*7594170eSAndroid Build Coastguard Worker # return direct include path in the first element 140*7594170eSAndroid Build Coastguard Worker order = "preorder", 141*7594170eSAndroid Build Coastguard Worker ), 142*7594170eSAndroid Build Coastguard Worker flags = ctx.attr.flags, 143*7594170eSAndroid Build Coastguard Worker ), 144*7594170eSAndroid Build Coastguard Worker ] 145*7594170eSAndroid Build Coastguard Worker 146*7594170eSAndroid Build Coastguard Workeraidl_library = rule( 147*7594170eSAndroid Build Coastguard Worker implementation = _aidl_library_rule_impl, 148*7594170eSAndroid Build Coastguard Worker attrs = { 149*7594170eSAndroid Build Coastguard Worker "srcs": attr.label_list( 150*7594170eSAndroid Build Coastguard Worker allow_files = [".aidl"], 151*7594170eSAndroid Build Coastguard Worker doc = "AIDL source files that contain StructuredParcelable" + 152*7594170eSAndroid Build Coastguard Worker " AIDL defintions. These files can be compiled to language" + 153*7594170eSAndroid Build Coastguard Worker " bindings.", 154*7594170eSAndroid Build Coastguard Worker ), 155*7594170eSAndroid Build Coastguard Worker "hdrs": attr.label_list( 156*7594170eSAndroid Build Coastguard Worker allow_files = [".aidl"], 157*7594170eSAndroid Build Coastguard Worker doc = "AIDL source files that contain UnstructuredParcelable" + 158*7594170eSAndroid Build Coastguard Worker " AIDL defintions. These files cannot be compiled to language" + 159*7594170eSAndroid Build Coastguard Worker " bindings, but can be referenced by other AIDL sources.", 160*7594170eSAndroid Build Coastguard Worker ), 161*7594170eSAndroid Build Coastguard Worker "version": attr.string( 162*7594170eSAndroid Build Coastguard Worker doc = "The version of the upstream aidl_interface that" + 163*7594170eSAndroid Build Coastguard Worker " the aidl_library is created for", 164*7594170eSAndroid Build Coastguard Worker ), 165*7594170eSAndroid Build Coastguard Worker "hash_file": attr.label( 166*7594170eSAndroid Build Coastguard Worker doc = "The .hash file in the api directory of an aidl_interface frozen version", 167*7594170eSAndroid Build Coastguard Worker allow_single_file = [".hash"], 168*7594170eSAndroid Build Coastguard Worker ), 169*7594170eSAndroid Build Coastguard Worker "_message_check_equality": attr.label( 170*7594170eSAndroid Build Coastguard Worker allow_single_file = [".txt"], 171*7594170eSAndroid Build Coastguard Worker default = "//system/tools/aidl/build:message_check_equality.txt", 172*7594170eSAndroid Build Coastguard Worker ), 173*7594170eSAndroid Build Coastguard Worker "deps": attr.label_list( 174*7594170eSAndroid Build Coastguard Worker providers = [AidlGenInfo], 175*7594170eSAndroid Build Coastguard Worker doc = "Targets listed here provide AIDL sources referenced" + 176*7594170eSAndroid Build Coastguard Worker "by this library.", 177*7594170eSAndroid Build Coastguard Worker ), 178*7594170eSAndroid Build Coastguard Worker "strip_import_prefix": attr.string( 179*7594170eSAndroid Build Coastguard Worker doc = "The prefix to strip from the paths of the .aidl files in " + 180*7594170eSAndroid Build Coastguard Worker "this rule. When set, aidl source files in the srcs " + 181*7594170eSAndroid Build Coastguard Worker "attribute of this rule are accessible at their path with " + 182*7594170eSAndroid Build Coastguard Worker "this prefix cut off.", 183*7594170eSAndroid Build Coastguard Worker ), 184*7594170eSAndroid Build Coastguard Worker "flags": attr.string_list( 185*7594170eSAndroid Build Coastguard Worker doc = "Flags to pass to AIDL tool", 186*7594170eSAndroid Build Coastguard Worker ), 187*7594170eSAndroid Build Coastguard Worker }, 188*7594170eSAndroid Build Coastguard Worker provides = [AidlGenInfo], 189*7594170eSAndroid Build Coastguard Worker) 190*7594170eSAndroid Build Coastguard Worker 191*7594170eSAndroid Build Coastguard Workerdef _generate_aidl_bindings(ctx, lang, aidl_info): 192*7594170eSAndroid Build Coastguard Worker """ Utility function for creating AIDL bindings from aidl_libraries. 193*7594170eSAndroid Build Coastguard Worker 194*7594170eSAndroid Build Coastguard Worker Args: 195*7594170eSAndroid Build Coastguard Worker ctx: context, used for declaring actions and new files and providing _aidl_tool 196*7594170eSAndroid Build Coastguard Worker lang: string, defines the language of the generated binding code 197*7594170eSAndroid Build Coastguard Worker aidl_src_infos: AidlGenInfo, list of sources to provide to AIDL compiler 198*7594170eSAndroid Build Coastguard Worker 199*7594170eSAndroid Build Coastguard Worker Returns: 200*7594170eSAndroid Build Coastguard Worker list of output files 201*7594170eSAndroid Build Coastguard Worker """ 202*7594170eSAndroid Build Coastguard Worker 203*7594170eSAndroid Build Coastguard Worker #TODO(b/235113507) support C++ AIDL binding 204*7594170eSAndroid Build Coastguard Worker ext = "" 205*7594170eSAndroid Build Coastguard Worker if lang == "java": 206*7594170eSAndroid Build Coastguard Worker ext = ".java" 207*7594170eSAndroid Build Coastguard Worker else: 208*7594170eSAndroid Build Coastguard Worker fail("Cannot generate AIDL language bindings for `{}`.".format(lang)) 209*7594170eSAndroid Build Coastguard Worker 210*7594170eSAndroid Build Coastguard Worker out_files = [] 211*7594170eSAndroid Build Coastguard Worker for aidl_file in aidl_info.srcs.to_list(): 212*7594170eSAndroid Build Coastguard Worker out_filename = paths.replace_extension(aidl_file.basename, ext) 213*7594170eSAndroid Build Coastguard Worker out_file = ctx.actions.declare_file(out_filename, sibling = aidl_file) 214*7594170eSAndroid Build Coastguard Worker out_files.append(out_file) 215*7594170eSAndroid Build Coastguard Worker 216*7594170eSAndroid Build Coastguard Worker args = ctx.actions.args() 217*7594170eSAndroid Build Coastguard Worker args.add_all(aidl_info.flags) 218*7594170eSAndroid Build Coastguard Worker 219*7594170eSAndroid Build Coastguard Worker #TODO(b/241139797) allow this flag to be controlled by an attribute 220*7594170eSAndroid Build Coastguard Worker args.add("--structured") 221*7594170eSAndroid Build Coastguard Worker 222*7594170eSAndroid Build Coastguard Worker args.add_all([ 223*7594170eSAndroid Build Coastguard Worker "-I {}".format(i) 224*7594170eSAndroid Build Coastguard Worker for i in aidl_info.transitive_include_dirs.to_list() 225*7594170eSAndroid Build Coastguard Worker ]) 226*7594170eSAndroid Build Coastguard Worker args.add(aidl_file.path) 227*7594170eSAndroid Build Coastguard Worker args.add(out_file) 228*7594170eSAndroid Build Coastguard Worker 229*7594170eSAndroid Build Coastguard Worker ctx.actions.run( 230*7594170eSAndroid Build Coastguard Worker inputs = aidl_info.transitive_srcs, 231*7594170eSAndroid Build Coastguard Worker outputs = [out_file], 232*7594170eSAndroid Build Coastguard Worker arguments = [args], 233*7594170eSAndroid Build Coastguard Worker progress_message = "Generating {} AIDL binding from {}".format(lang, aidl_file.short_path), 234*7594170eSAndroid Build Coastguard Worker executable = ctx.executable._aidl_tool, 235*7594170eSAndroid Build Coastguard Worker ) 236*7594170eSAndroid Build Coastguard Worker 237*7594170eSAndroid Build Coastguard Worker return out_files 238*7594170eSAndroid Build Coastguard Worker 239*7594170eSAndroid Build Coastguard Workeraidl_file_utils = struct( 240*7594170eSAndroid Build Coastguard Worker generate_aidl_bindings = _generate_aidl_bindings, 241*7594170eSAndroid Build Coastguard Worker) 242