• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (C) 2018 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
15package aidl
16
17import (
18	"android/soong/android"
19	"android/soong/bazel"
20	"android/soong/cc"
21	"android/soong/java"
22	"android/soong/phony"
23	"android/soong/rust"
24
25	"fmt"
26	"path/filepath"
27	"regexp"
28	"sort"
29	"strconv"
30	"strings"
31
32	"github.com/google/blueprint"
33	"github.com/google/blueprint/proptools"
34)
35
36const (
37	aidlInterfaceSuffix       = "_interface"
38	aidlMetadataSingletonName = "aidl_metadata_json"
39	aidlApiDir                = "aidl_api"
40	aidlApiSuffix             = "-api"
41	langCpp                   = "cpp"
42	langJava                  = "java"
43	langNdk                   = "ndk"
44	langRust                  = "rust"
45	langCppAnalyzer           = "cpp-analyzer"
46	// TODO(b/161456198) remove the NDK platform backend as the 'platform' variant of the NDK
47	// backend serves the same purpose.
48	langNdkPlatform = "ndk_platform"
49
50	currentVersion = "current"
51)
52
53var pctx = android.NewPackageContext("android/aidl")
54
55func init() {
56	pctx.Import("android/soong/android")
57	pctx.HostBinToolVariable("aidlCmd", "aidl")
58	pctx.HostBinToolVariable("aidlHashGen", "aidl_hash_gen")
59	pctx.SourcePathVariable("aidlToJniCmd", "system/tools/aidl/build/aidl_to_jni.py")
60	pctx.SourcePathVariable("aidlRustGlueCmd", "system/tools/aidl/build/aidl_rust_glue.py")
61	android.RegisterModuleType("aidl_interface", AidlInterfaceFactory)
62	android.PreArchMutators(registerPreArchMutators)
63	android.PreArchBp2BuildMutators(registerPreArchMutators)
64	android.PostDepsMutators(registerPostDepsMutators)
65}
66
67func registerPreArchMutators(ctx android.RegisterMutatorsContext) {
68	ctx.BottomUp("addInterfaceDeps", addInterfaceDeps).Parallel()
69	ctx.BottomUp("checkImports", checkImports).Parallel()
70	ctx.TopDown("createAidlInterface", createAidlInterfaceMutator).Parallel()
71}
72
73func registerPostDepsMutators(ctx android.RegisterMutatorsContext) {
74	ctx.BottomUp("checkAidlGeneratedModules", checkAidlGeneratedModules).Parallel()
75}
76
77func createAidlInterfaceMutator(mctx android.TopDownMutatorContext) {
78	if g, ok := mctx.Module().(*aidlImplementationGenerator); ok {
79		g.GenerateImplementation(mctx)
80	}
81}
82
83// A marker struct for AIDL-generated library modules
84type AidlGeneratedModuleProperties struct{}
85
86func wrapLibraryFactory(factory func() android.Module) func() android.Module {
87	return func() android.Module {
88		m := factory()
89		// put a marker struct for AIDL-generated modules
90		m.AddProperties(&AidlGeneratedModuleProperties{})
91		return m
92	}
93}
94
95func isAidlGeneratedModule(module android.Module) bool {
96	for _, props := range module.GetProperties() {
97		// check if there's a marker struct
98		if _, ok := props.(*AidlGeneratedModuleProperties); ok {
99			return true
100		}
101	}
102	return false
103}
104
105// AidlVersionInfo keeps the *-source module for each (aidl_interface & lang) and the list of
106// not-frozen versions (which shouldn't be used by other modules)
107type AidlVersionInfo struct {
108	notFrozen            []string
109	requireFrozenReasons []string
110	sourceMap            map[string]string
111}
112
113var AidlVersionInfoProvider = blueprint.NewMutatorProvider(AidlVersionInfo{}, "checkAidlGeneratedModules")
114
115// Merges `other` version info into this one.
116// Returns the pair of mismatching versions when there's conflict. Otherwise returns nil.
117// For example, when a module depends on 'foo-V2-ndk', the map contains an entry of (foo, foo-V2-ndk-source).
118// Merging (foo, foo-V1-ndk-source) and (foo, foo-V2-ndk-source) will fail and returns
119// {foo-V1-ndk-source, foo-V2-ndk-source}.
120func (info *AidlVersionInfo) merge(other AidlVersionInfo) []string {
121	info.notFrozen = append(info.notFrozen, other.notFrozen...)
122	info.requireFrozenReasons = append(info.requireFrozenReasons, other.requireFrozenReasons...)
123
124	if other.sourceMap == nil {
125		return nil
126	}
127	if info.sourceMap == nil {
128		info.sourceMap = make(map[string]string)
129	}
130	for ifaceName, otherSourceName := range other.sourceMap {
131		if sourceName, ok := info.sourceMap[ifaceName]; ok {
132			if sourceName != otherSourceName {
133				return []string{sourceName, otherSourceName}
134			}
135		} else {
136			info.sourceMap[ifaceName] = otherSourceName
137		}
138	}
139	return nil
140}
141
142func reportUsingNotFrozenError(ctx android.BaseModuleContext, notFrozen []string, requireFrozenReason []string) {
143	// TODO(b/154066686): Replace it with a common method instead of listing up module types.
144	// Test libraries are exempted.
145	if android.InList(ctx.ModuleType(), []string{"cc_test_library", "android_test", "cc_benchmark", "cc_test"}) {
146		return
147	}
148	for i, name := range notFrozen {
149		reason := requireFrozenReason[i]
150		ctx.ModuleErrorf("%v is an unfrozen development version, and it can't be used because %q", name, reason)
151	}
152}
153
154func reportMultipleVersionError(ctx android.BaseModuleContext, violators []string) {
155	sort.Strings(violators)
156	ctx.ModuleErrorf("depends on multiple versions of the same aidl_interface: %s", strings.Join(violators, ", "))
157	ctx.WalkDeps(func(child android.Module, parent android.Module) bool {
158		if android.InList(child.Name(), violators) {
159			ctx.ModuleErrorf("Dependency path: %s", ctx.GetPathString(true))
160			return false
161		}
162		return true
163	})
164}
165
166func checkAidlGeneratedModules(mctx android.BottomUpMutatorContext) {
167	switch mctx.Module().(type) {
168	case *java.Library:
169	case *cc.Module:
170	case *rust.Module:
171	case *aidlGenRule:
172	default:
173		return
174	}
175	if gen, ok := mctx.Module().(*aidlGenRule); ok {
176		var notFrozen []string
177		var requireFrozenReasons []string
178		if gen.properties.NotFrozen {
179			notFrozen = []string{strings.TrimSuffix(mctx.ModuleName(), "-source")}
180			requireFrozenReasons = []string{gen.properties.RequireFrozenReason}
181		}
182		mctx.SetProvider(AidlVersionInfoProvider, AidlVersionInfo{
183			notFrozen:            notFrozen,
184			requireFrozenReasons: requireFrozenReasons,
185			sourceMap: map[string]string{
186				gen.properties.BaseName + "-" + gen.properties.Lang: gen.Name(),
187			},
188		})
189		return
190	}
191	// Collect/merge AidlVersionInfos from direct dependencies
192	var info AidlVersionInfo
193	mctx.VisitDirectDeps(func(dep android.Module) {
194		if mctx.OtherModuleHasProvider(dep, AidlVersionInfoProvider) {
195			otherInfo := mctx.OtherModuleProvider(dep, AidlVersionInfoProvider).(AidlVersionInfo)
196			if violators := info.merge(otherInfo); violators != nil {
197				reportMultipleVersionError(mctx, violators)
198			}
199		}
200	})
201	if !isAidlGeneratedModule(mctx.Module()) && len(info.notFrozen) > 0 {
202		reportUsingNotFrozenError(mctx, info.notFrozen, info.requireFrozenReasons)
203	}
204	if mctx.Failed() {
205		return
206	}
207	if info.sourceMap != nil || len(info.notFrozen) > 0 {
208		mctx.SetProvider(AidlVersionInfoProvider, info)
209	}
210}
211
212func getPaths(ctx android.ModuleContext, rawSrcs []string, root string) (srcs android.Paths, imports []string) {
213	// TODO(b/189288369): move this to android.PathsForModuleSrcSubDir(ctx, srcs, subdir)
214	for _, src := range rawSrcs {
215		if m, _ := android.SrcIsModuleWithTag(src); m != "" {
216			srcs = append(srcs, android.PathsForModuleSrc(ctx, []string{src})...)
217		} else {
218			srcs = append(srcs, android.PathsWithModuleSrcSubDir(ctx, android.PathsForModuleSrc(ctx, []string{src}), root)...)
219		}
220	}
221
222	if len(srcs) == 0 {
223		ctx.PropertyErrorf("srcs", "No sources provided in %v", root)
224	}
225
226	// gather base directories from input .aidl files
227	for _, src := range srcs {
228		if src.Ext() != ".aidl" {
229			// Silently ignore non-aidl files as some filegroups have both java and aidl files together
230			continue
231		}
232		baseDir := strings.TrimSuffix(src.String(), src.Rel())
233		baseDir = strings.TrimSuffix(baseDir, "/")
234		if baseDir != "" && !android.InList(baseDir, imports) {
235			imports = append(imports, baseDir)
236		}
237	}
238
239	return srcs, imports
240}
241
242func isRelativePath(path string) bool {
243	if path == "" {
244		return true
245	}
246	return filepath.Clean(path) == path && path != ".." &&
247		!strings.HasPrefix(path, "../") && !strings.HasPrefix(path, "/")
248}
249
250type CommonBackendProperties struct {
251	// Whether to generate code in the corresponding backend.
252	// Default:
253	//   - for Java/NDK/CPP backends - True
254	//   - for Rust backend - False
255	Enabled        *bool
256	Apex_available []string
257
258	// The minimum version of the sdk that the compiled artifacts will run against
259	// For native modules, the property needs to be set when a module is a part of mainline modules(APEX).
260	// Forwarded to generated java/native module.
261	Min_sdk_version *string
262
263	// Whether tracing should be added to the interface.
264	Gen_trace *bool
265}
266
267type CommonNativeBackendProperties struct {
268	CommonBackendProperties
269
270	// Must be NDK libraries, for stable types.
271	Additional_shared_libraries []string
272
273	// cflags to forward to native compilation. This is expected to be
274	// used more for AIDL compiler developers than being actually
275	// practical.
276	Cflags []string
277
278	// Whether to generate additional code for gathering information
279	// about the transactions.
280	// Default: false
281	Gen_log *bool
282
283	// VNDK properties for correspdoning backend.
284	cc.VndkProperties
285}
286
287type DumpApiProperties struct {
288	// Dumps without license header (assuming it is the first comment in .aidl file). Default: false
289	No_license *bool
290}
291
292type aidlInterfaceProperties struct {
293	// Vndk properties for C++/NDK libraries only (preferred to use backend-specific settings)
294	cc.VndkProperties
295
296	// How to interpret VNDK options. We only want one library in the VNDK (not multiple
297	// versions, since this would be a waste of space/unclear, and ultimately we want all
298	// code in a given release to be updated to use a specific version). By default, this
299	// puts either the latest stable version of the library or, if there is no stable
300	// version, the unstable version of the library in the VNDK. When using this field,
301	// explicitly set it to one of the values in the 'versions' field to put that version
302	// in the VNDK or set it to the next version (1 higher than this) to mean the version
303	// that will be frozen in the next update.
304	Vndk_use_version *string
305
306	// Whether the library can be installed on the vendor image.
307	Vendor_available *bool
308
309	// Whether the library can be installed on the odm image.
310	Odm_available *bool
311
312	// Whether the library can be installed on the product image.
313	Product_available *bool
314
315	// Whether the library can be installed on the recovery image.
316	Recovery_available *bool
317
318	// Whether the library can be loaded multiple times into the same process
319	Double_loadable *bool
320
321	// Whether the library can be used on host
322	Host_supported *bool
323
324	// Whether tracing should be added to the interface.
325	Gen_trace *bool
326
327	// Top level directories for includes.
328	// TODO(b/128940869): remove it if aidl_interface can depend on framework.aidl
329	Include_dirs []string
330	// Relative path for includes. By default assumes AIDL path is relative to current directory.
331	Local_include_dir string
332
333	// List of .aidl files which compose this interface.
334	Srcs []string `android:"path"`
335
336	// List of aidl_interface modules that this uses. If one of your AIDL interfaces uses an
337	// interface or parcelable from another aidl_interface, you should put its name here.
338	// It could be an aidl_interface solely or with version(such as -V1)
339	Imports []string
340
341	// Stability promise. Currently only supports "vintf".
342	// If this is unset, this corresponds to an interface with stability within
343	// this compilation context (so an interface loaded here can only be used
344	// with things compiled together, e.g. on the system.img).
345	// If this is set to "vintf", this corresponds to a stability promise: the
346	// interface must be kept stable as long as it is used.
347	Stability *string
348
349	// If true, this interface is frozen and does not have any changes since the last
350	// frozen version.
351	// If false, there are changes to this interface between the last frozen version (N) and
352	// the current version (N + 1).
353	Frozen *bool
354
355	// Deprecated: Use `versions_with_info` instead. Don't use `versions` property directly.
356	Versions []string
357
358	// Previous API versions that are now frozen. The version that is last in
359	// the list is considered as the most recent version.
360	// The struct contains both version and imports information per a version.
361	// Until versions property is removed, don't use `versions_with_info` directly.
362	Versions_with_info []struct {
363		Version string
364		Imports []string
365	}
366
367	// Use aidlInterface.getVersions()
368	VersionsInternal []string `blueprint:"mutated"`
369
370	// The minimum version of the sdk that the compiled artifacts will run against
371	// For native modules, the property needs to be set when a module is a part of mainline modules(APEX).
372	// Forwarded to generated java/native module. This can be overridden by
373	// backend.<name>.min_sdk_version.
374	Min_sdk_version *string
375
376	Backend struct {
377		// Backend of the compiler generating code for Java clients.
378		// When enabled, this creates a target called "<name>-java".
379		Java struct {
380			CommonBackendProperties
381			// Set to the version of the sdk to compile against
382			// Default: system_current
383			Sdk_version *string
384			// Whether to compile against platform APIs instead of
385			// an SDK.
386			Platform_apis *bool
387			// Whether RPC features are enabled (requires API level 32)
388			// TODO(b/175819535): enable this automatically?
389			Gen_rpc *bool
390			// Lint properties for generated java module
391			java.LintProperties
392		}
393		// Backend of the compiler generating code for C++ clients using
394		// libbinder (unstable C++ interface)
395		// When enabled, this creates a target called "<name>-cpp".
396		Cpp struct {
397			CommonNativeBackendProperties
398		}
399		// Backend of the compiler generating code for C++ clients using libbinder_ndk
400		// (stable C interface to system's libbinder) When enabled, this creates a target
401		// called "<name>-V<ver>-ndk" (for both apps and platform) and
402		// "<name>-V<ver>-ndk_platform" (for platform only).
403		// TODO(b/161456198): remove the ndk_platform backend as the ndk backend can serve
404		// the same purpose.
405		Ndk struct {
406			CommonNativeBackendProperties
407
408			// Set to the version of the sdk to compile against, for the NDK
409			// variant.
410			// Default: current
411			Sdk_version *string
412
413			// If set to false, the ndk backend is exclusive to platform and is not
414			// available to applications. Default is true (i.e. available to both
415			// applications and platform).
416			Apps_enabled *bool
417		}
418		// Backend of the compiler generating code for Rust clients.
419		// When enabled, this creates a target called "<name>-rust".
420		Rust struct {
421			CommonBackendProperties
422		}
423	}
424
425	// Marks that this interface does not need to be stable. When set to true, the build system
426	// doesn't create the API dump and require it to be updated. Default is false.
427	Unstable *bool
428
429	// Optional flags to be passed to the AIDL compiler. e.g. "-Weverything"
430	Flags []string
431
432	// --dumpapi options
433	Dumpapi DumpApiProperties
434
435	// List of aidl_interface_headers modules that provide include dependencies
436	// for the AIDL tool.
437	Headers []string
438}
439
440type aidlInterface struct {
441	android.ModuleBase
442	android.BazelModuleBase
443	android.DefaultableModuleBase
444
445	properties aidlInterfaceProperties
446
447	computedTypes []string
448
449	// list of module names that are created for this interface
450	internalModuleNames []string
451
452	// map for version to preprocessed.aidl file.
453	// There's two additional alias for versions:
454	// - ""(empty) is for ToT
455	// - "latest" is for i.latestVersion()
456	preprocessed map[string]android.WritablePath
457}
458
459func (i *aidlInterface) shouldGenerateJavaBackend() bool {
460	// explicitly true if not specified to give early warning to devs
461	return proptools.BoolDefault(i.properties.Backend.Java.Enabled, true)
462}
463
464func (i *aidlInterface) shouldGenerateCppBackend() bool {
465	// explicitly true if not specified to give early warning to devs
466	return proptools.BoolDefault(i.properties.Backend.Cpp.Enabled, true)
467}
468
469func (i *aidlInterface) shouldGenerateNdkBackend() bool {
470	// explicitly true if not specified to give early warning to devs
471	return proptools.BoolDefault(i.properties.Backend.Ndk.Enabled, true)
472}
473
474// Returns whether the ndk backend supports applications or not. Default is `true`. `false` is
475// returned when `apps_enabled` is explicitly set to false or the interface is exclusive to vendor
476// (i.e. `vendor: true`). Note that the ndk_platform backend (which will be removed in the future)
477// is not affected by this. In other words, it is always exclusive for the platform, as its name
478// clearly shows.
479func (i *aidlInterface) shouldGenerateAppNdkBackend() bool {
480	return i.shouldGenerateNdkBackend() &&
481		proptools.BoolDefault(i.properties.Backend.Ndk.Apps_enabled, true) &&
482		!i.SocSpecific()
483}
484
485func (i *aidlInterface) shouldGenerateRustBackend() bool {
486	return i.properties.Backend.Rust.Enabled != nil && *i.properties.Backend.Rust.Enabled
487}
488
489func (i *aidlInterface) minSdkVersion(lang string) *string {
490	var ver *string
491	switch lang {
492	case langCpp:
493		ver = i.properties.Backend.Cpp.Min_sdk_version
494	case langJava:
495		ver = i.properties.Backend.Java.Min_sdk_version
496	case langNdk, langNdkPlatform:
497		ver = i.properties.Backend.Ndk.Min_sdk_version
498	case langRust:
499		ver = i.properties.Backend.Rust.Min_sdk_version
500	default:
501		panic(fmt.Errorf("unsupported language backend %q\n", lang))
502	}
503	if ver == nil {
504		return i.properties.Min_sdk_version
505	}
506	return ver
507}
508
509func (i *aidlInterface) genTrace(lang string) bool {
510	var ver *bool
511	switch lang {
512	case langCpp:
513		ver = i.properties.Backend.Cpp.Gen_trace
514		if ver == nil {
515			// Enable tracing for all cpp backends by default
516			ver = proptools.BoolPtr(true)
517		}
518	case langJava:
519		ver = i.properties.Backend.Java.Gen_trace
520		if ver == nil && proptools.Bool(i.properties.Backend.Java.Platform_apis) {
521			// Enable tracing for all Java backends using platform APIs
522			// TODO(161393989) Once we generate ATRACE_TAG_APP instead of ATRACE_TAG_AIDL,
523			// this can be removed and we can start generating traces in all apps.
524			ver = proptools.BoolPtr(true)
525		}
526	case langNdk, langNdkPlatform:
527		ver = i.properties.Backend.Ndk.Gen_trace
528	case langRust: // unsupported b/236880829
529		ver = i.properties.Backend.Rust.Gen_trace
530	case langCppAnalyzer:
531		*ver = false
532	default:
533		panic(fmt.Errorf("unsupported language backend %q\n", lang))
534	}
535	if ver == nil {
536		ver = i.properties.Gen_trace
537	}
538	return proptools.Bool(ver)
539}
540
541// Dep to *-api module(aidlApi)
542type apiDepTag struct {
543	blueprint.BaseDependencyTag
544	name string
545}
546
547type importInterfaceDepTag struct {
548	blueprint.BaseDependencyTag
549	anImport string
550}
551
552type interfaceDepTag struct {
553	blueprint.BaseDependencyTag
554}
555
556type interfaceHeadersDepTag struct {
557	blueprint.BaseDependencyTag
558}
559
560var (
561	// Dep from *-source (aidlGenRule) to *-api (aidlApi)
562	apiDep = apiDepTag{name: "api"}
563	// Dep from *-api (aidlApi) to *-api (aidlApi), representing imported interfaces
564	importApiDep = apiDepTag{name: "imported-api"}
565	// Dep to original *-interface (aidlInterface)
566	interfaceDep = interfaceDepTag{}
567	// Dep for a header interface
568	interfaceHeadersDep = interfaceHeadersDepTag{}
569)
570
571func addImportedInterfaceDeps(ctx android.BottomUpMutatorContext, imports []string) {
572	for _, anImport := range imports {
573		name, _ := parseModuleWithVersion(anImport)
574		ctx.AddDependency(ctx.Module(), importInterfaceDepTag{anImport: anImport}, name+aidlInterfaceSuffix)
575	}
576}
577
578// Run custom "Deps" mutator between AIDL modules created at LoadHook stage.
579// We can't use the "DepsMutator" for these dependencies because
580// - We need to create library modules (cc/java/...) before "arch" mutator. Note that cc_library
581//
582//	should be mutated by os/image/arch mutators as well.
583//
584// - When creating library modules, we need to access the original interface and its imported
585//
586//	interfaces to determine which version to use. See aidlInterface.getImportWithVersion.
587func addInterfaceDeps(mctx android.BottomUpMutatorContext) {
588	switch i := mctx.Module().(type) {
589	case *aidlInterface:
590		// In fact this isn't necessary because soong checks dependencies on undefined modules.
591		// But since aidl_interface overrides its name internally, this provides better error message.
592		for _, anImportWithVersion := range i.properties.Imports {
593			anImport, _ := parseModuleWithVersion(anImportWithVersion)
594			if !mctx.OtherModuleExists(anImport + aidlInterfaceSuffix) {
595				if !mctx.Config().AllowMissingDependencies() {
596					mctx.PropertyErrorf("imports", "Import does not exist: "+anImport)
597				}
598			}
599		}
600		if mctx.Failed() {
601			return
602		}
603		addImportedInterfaceDeps(mctx, i.properties.Imports)
604
605		for _, header := range i.properties.Headers {
606			mctx.AddDependency(i, interfaceHeadersDep, header)
607		}
608	case *aidlImplementationGenerator:
609		mctx.AddDependency(i, interfaceDep, i.properties.AidlInterfaceName+aidlInterfaceSuffix)
610		addImportedInterfaceDeps(mctx, i.properties.Imports)
611	case *rust.Module:
612		for _, props := range i.GetProperties() {
613			if sp, ok := props.(*aidlRustSourceProviderProperties); ok {
614				mctx.AddDependency(i, interfaceDep, sp.AidlInterfaceName+aidlInterfaceSuffix)
615				addImportedInterfaceDeps(mctx, sp.Imports)
616				break
617			}
618		}
619	case *aidlApi:
620		mctx.AddDependency(i, interfaceDep, i.properties.BaseName+aidlInterfaceSuffix)
621		addImportedInterfaceDeps(mctx, i.properties.Imports)
622		for _, anImport := range i.properties.Imports {
623			name, _ := parseModuleWithVersion(anImport)
624			mctx.AddDependency(i, importApiDep, name+aidlApiSuffix)
625		}
626		for _, header := range i.properties.Headers {
627			mctx.AddDependency(i, interfaceHeadersDep, header)
628		}
629	case *aidlGenRule:
630		mctx.AddDependency(i, interfaceDep, i.properties.BaseName+aidlInterfaceSuffix)
631		addImportedInterfaceDeps(mctx, i.properties.Imports)
632		if !proptools.Bool(i.properties.Unstable) {
633			// for checkapi timestamps
634			mctx.AddDependency(i, apiDep, i.properties.BaseName+aidlApiSuffix)
635		}
636		for _, header := range i.properties.Headers {
637			mctx.AddDependency(i, interfaceHeadersDep, header)
638		}
639	}
640}
641
642// checkImports checks if "import:" property is valid.
643// In fact, this isn't necessary because Soong can check/report when we add a dependency to
644// undefined/unknown module. But module names are very implementation specific and may not be easy
645// to understand. For example, when foo (with java enabled) depends on bar (with java disabled), the
646// error message would look like "foo-V2-java depends on unknown module `bar-V3-java`", which isn't
647// clear that backend.java.enabled should be turned on.
648func checkImports(mctx android.BottomUpMutatorContext) {
649	if i, ok := mctx.Module().(*aidlInterface); ok {
650		mctx.VisitDirectDeps(func(dep android.Module) {
651			tag, ok := mctx.OtherModuleDependencyTag(dep).(importInterfaceDepTag)
652			if !ok {
653				return
654			}
655			other := dep.(*aidlInterface)
656			anImport := other.ModuleBase.Name()
657			anImportWithVersion := tag.anImport
658			_, version := parseModuleWithVersion(tag.anImport)
659
660			candidateVersions := other.getVersions()
661			if !proptools.Bool(other.properties.Frozen) {
662				candidateVersions = concat(candidateVersions, []string{other.nextVersion()})
663			}
664
665			if version == "" {
666				if !proptools.Bool(other.properties.Unstable) {
667					mctx.PropertyErrorf("imports", "%q depends on %q but does not specify a version (must be one of %q)", i.ModuleBase.Name(), anImport, candidateVersions)
668				}
669			} else {
670				if !android.InList(version, candidateVersions) {
671					mctx.PropertyErrorf("imports", "%q depends on %q version %q(%q), which doesn't exist. The version must be one of %q", i.ModuleBase.Name(), anImport, version, anImportWithVersion, candidateVersions)
672				}
673			}
674			if i.shouldGenerateJavaBackend() && !other.shouldGenerateJavaBackend() {
675				mctx.PropertyErrorf("backend.java.enabled",
676					"Java backend not enabled in the imported AIDL interface %q", anImport)
677			}
678
679			if i.shouldGenerateCppBackend() && !other.shouldGenerateCppBackend() {
680				mctx.PropertyErrorf("backend.cpp.enabled",
681					"C++ backend not enabled in the imported AIDL interface %q", anImport)
682			}
683
684			if i.shouldGenerateNdkBackend() && !other.shouldGenerateNdkBackend() {
685				mctx.PropertyErrorf("backend.ndk.enabled",
686					"NDK backend not enabled in the imported AIDL interface %q", anImport)
687			}
688
689			if i.shouldGenerateRustBackend() && !other.shouldGenerateRustBackend() {
690				mctx.PropertyErrorf("backend.rust.enabled",
691					"Rust backend not enabled in the imported AIDL interface %q", anImport)
692			}
693
694			if i.isFrozen() && other.isExplicitlyUnFrozen() && version == "" {
695				mctx.PropertyErrorf("frozen",
696					"%q imports %q which is not frozen. Either %q must set 'frozen: false' or must explicitly import %q where * is one of %q",
697					i.ModuleBase.Name(), anImport, i.ModuleBase.Name(), anImport+"-V*", candidateVersions)
698			}
699			if i.Owner() == "" && other.Owner() != "" {
700				mctx.PropertyErrorf("imports",
701					"%q imports %q which is an interface owned by %q. This is not allowed because the owned interface will not be frozen at the same time.",
702					i.ModuleBase.Name(), anImport, other.Owner())
703			}
704		})
705	}
706}
707
708func (i *aidlInterface) checkGenTrace(mctx android.DefaultableHookContext) {
709	if !proptools.Bool(i.properties.Gen_trace) {
710		return
711	}
712	if i.shouldGenerateJavaBackend() && !proptools.Bool(i.properties.Backend.Java.Platform_apis) {
713		mctx.PropertyErrorf("gen_trace", "must be false when Java backend is enabled and platform_apis is false")
714	}
715}
716
717func (i *aidlInterface) checkStability(mctx android.DefaultableHookContext) {
718	if i.properties.Stability == nil {
719		return
720	}
721
722	if proptools.Bool(i.properties.Unstable) {
723		mctx.PropertyErrorf("stability", "must be empty when \"unstable\" is true")
724	}
725
726	// TODO(b/136027762): should we allow more types of stability (e.g. for APEX) or
727	// should we switch this flag to be something like "vintf { enabled: true }"
728	isVintf := "vintf" == proptools.String(i.properties.Stability)
729	if !isVintf {
730		mctx.PropertyErrorf("stability", "must be empty or \"vintf\"")
731	}
732}
733func (i *aidlInterface) checkVersions(mctx android.DefaultableHookContext) {
734	if len(i.properties.Versions) > 0 && len(i.properties.Versions_with_info) > 0 {
735		mctx.ModuleErrorf("versions:%q and versions_with_info:%q cannot be used at the same time. Use versions_with_info instead of versions.", i.properties.Versions, i.properties.Versions_with_info)
736	}
737
738	if len(i.properties.Versions) > 0 {
739		i.properties.VersionsInternal = make([]string, len(i.properties.Versions))
740		copy(i.properties.VersionsInternal, i.properties.Versions)
741	} else if len(i.properties.Versions_with_info) > 0 {
742		i.properties.VersionsInternal = make([]string, len(i.properties.Versions_with_info))
743		for idx, value := range i.properties.Versions_with_info {
744			i.properties.VersionsInternal[idx] = value.Version
745			for _, im := range value.Imports {
746				if !hasVersionSuffix(im) {
747					mctx.ModuleErrorf("imports in versions_with_info must specify its version, but %s. Add a version suffix(such as %s-V1).", im, im)
748					return
749				}
750			}
751		}
752	}
753
754	versions := make(map[string]bool)
755	intVersions := make([]int, 0, len(i.getVersions()))
756	for _, ver := range i.getVersions() {
757		if _, dup := versions[ver]; dup {
758			mctx.PropertyErrorf("versions", "duplicate found", ver)
759			continue
760		}
761		versions[ver] = true
762		n, err := strconv.Atoi(ver)
763		if err != nil {
764			mctx.PropertyErrorf("versions", "%q is not an integer", ver)
765			continue
766		}
767		if n <= 0 {
768			mctx.PropertyErrorf("versions", "should be > 0, but is %v", ver)
769			continue
770		}
771		intVersions = append(intVersions, n)
772
773	}
774	if !mctx.Failed() && !sort.IntsAreSorted(intVersions) {
775		mctx.PropertyErrorf("versions", "should be sorted, but is %v", i.getVersions())
776	}
777}
778func (i *aidlInterface) checkVndkUseVersion(mctx android.DefaultableHookContext) {
779	if i.properties.Vndk_use_version == nil {
780		return
781	}
782	if *i.properties.Vndk_use_version == i.nextVersion() {
783		return
784	}
785	for _, ver := range i.getVersions() {
786		if *i.properties.Vndk_use_version == ver {
787			return
788		}
789	}
790	mctx.PropertyErrorf("vndk_use_version", "Specified version %q does not exist", *i.properties.Vndk_use_version)
791}
792
793func (i *aidlInterface) nextVersion() string {
794	if proptools.Bool(i.properties.Unstable) {
795		return ""
796	}
797	return nextVersion(i.getVersions())
798}
799
800func nextVersion(versions []string) string {
801	if len(versions) == 0 {
802		return "1"
803	}
804	ver := versions[len(versions)-1]
805	i, err := strconv.Atoi(ver)
806	if err != nil {
807		panic(err)
808	}
809	return strconv.Itoa(i + 1)
810}
811
812func (i *aidlInterface) latestVersion() string {
813	if !i.hasVersion() {
814		return "0"
815	}
816	return i.getVersions()[len(i.getVersions())-1]
817}
818
819func (i *aidlInterface) hasVersion() bool {
820	return len(i.getVersions()) > 0
821}
822
823func (i *aidlInterface) getVersions() []string {
824	return i.properties.VersionsInternal
825}
826
827func (i *aidlInterface) isFrozen() bool {
828	return proptools.Bool(i.properties.Frozen)
829}
830
831// in order to keep original behavior for certain operations, we may want to
832// check if frozen is set.
833func (i *aidlInterface) isExplicitlyUnFrozen() bool {
834	return i.properties.Frozen != nil && !proptools.Bool(i.properties.Frozen)
835}
836
837func hasVersionSuffix(moduleName string) bool {
838	hasVersionSuffix, _ := regexp.MatchString("-V\\d+$", moduleName)
839	return hasVersionSuffix
840}
841
842func parseModuleWithVersion(moduleName string) (string, string) {
843	if hasVersionSuffix(moduleName) {
844		versionIdx := strings.LastIndex(moduleName, "-V")
845		if versionIdx == -1 {
846			panic("-V must exist in this context")
847		}
848		return moduleName[:versionIdx], moduleName[versionIdx+len("-V"):]
849	}
850	return moduleName, ""
851}
852
853func trimVersionSuffixInList(moduleNames []string) []string {
854	return wrapFunc("", moduleNames, "", func(moduleName string) string {
855		moduleNameWithoutVersion, _ := parseModuleWithVersion(moduleName)
856		return moduleNameWithoutVersion
857	})
858}
859
860func (i *aidlInterface) checkRequireFrozenAndReason(mctx android.EarlyModuleContext) (bool, string) {
861	if proptools.Bool(i.properties.Unstable) {
862		return false, "it's an unstable interface"
863	}
864
865	if proptools.Bool(i.properties.Frozen) {
866		return true, "it's explicitly marked as `frozen: true`"
867	}
868
869	if i.Owner() == "" {
870		if !mctx.Config().DefaultAppTargetSdk(mctx).IsPreview() {
871			return true, "this is a release branch - freeze it or set 'owners:'"
872		} else if mctx.Config().IsEnvTrue("AIDL_FROZEN_REL") {
873			return true, "this is a release branch (simulated by setting AIDL_FROZEN_REL) - freeze it or set 'owners:'"
874		}
875	} else {
876		// has an OWNER
877		// REL branches don't enforce downstream interfaces or owned interfaces
878		// to be frozen. Instead, these interfaces are verified by other tests
879		// like vts_treble_vintf_vendor_test
880		if android.InList(i.Owner(), strings.Fields(mctx.Config().Getenv("AIDL_FROZEN_OWNERS"))) {
881			return true, "the owner field is in environment variable AIDL_FROZEN_OWNERS"
882		}
883	}
884
885	return false, "by default, we don't require the interface to be frozen"
886}
887
888func aidlInterfaceHook(mctx android.DefaultableHookContext, i *aidlInterface) {
889	if hasVersionSuffix(i.ModuleBase.Name()) {
890		mctx.PropertyErrorf("name", "aidl_interface should not have '-V<number> suffix")
891	}
892	if !isRelativePath(i.properties.Local_include_dir) {
893		mctx.PropertyErrorf("local_include_dir", "must be relative path: "+i.properties.Local_include_dir)
894	}
895
896	i.checkStability(mctx)
897	i.checkVersions(mctx)
898	i.checkVndkUseVersion(mctx)
899	i.checkGenTrace(mctx)
900
901	if mctx.Failed() {
902		return
903	}
904
905	var libs []string
906
907	unstable := proptools.Bool(i.properties.Unstable)
908
909	if unstable {
910		if i.hasVersion() {
911			mctx.PropertyErrorf("versions", "cannot have versions for an unstable interface")
912			return
913		}
914		if i.properties.Stability != nil {
915			mctx.ModuleErrorf("unstable:true and stability:%q cannot happen at the same time", i.properties.Stability)
916			return
917		}
918	}
919
920	if i.isFrozen() {
921		if !i.hasVersion() {
922			mctx.PropertyErrorf("frozen", "cannot be frozen without versions")
923			return
924		}
925	}
926
927	if !unstable && mctx.Namespace().Path != "." && i.Owner() == "" {
928		mctx.PropertyErrorf("owner", "aidl_interface in a soong_namespace must have the 'owner' property set.")
929	}
930
931	requireFrozenVersion, requireFrozenReason := i.checkRequireFrozenAndReason(mctx)
932
933	// surface error early, main check is via checkUnstableModuleMutator
934	if requireFrozenVersion && !i.hasVersion() {
935		mctx.PropertyErrorf("versions", "must be set (need to be frozen) because: %q", requireFrozenReason)
936	}
937
938	vndkEnabled := proptools.Bool(i.properties.VndkProperties.Vndk.Enabled) ||
939		proptools.Bool(i.properties.Backend.Cpp.CommonNativeBackendProperties.VndkProperties.Vndk.Enabled) ||
940		proptools.Bool(i.properties.Backend.Ndk.CommonNativeBackendProperties.VndkProperties.Vndk.Enabled)
941
942	if vndkEnabled && !proptools.Bool(i.properties.Unstable) {
943		if i.properties.Frozen == nil {
944			mctx.PropertyErrorf("frozen", "true or false must be specified when the VNDK is enabled on a versioned interface (not `unstable: true`)")
945		}
946		if !proptools.Bool(i.properties.Frozen) && i.properties.Vndk_use_version == nil {
947			mctx.PropertyErrorf("vndk_use_version", "must be specified if interface is unfrozen (or specify 'frozen: false')")
948		}
949	}
950
951	versions := i.getVersions()
952	nextVersion := i.nextVersion()
953	shouldGenerateLangBackendMap := map[string]bool{
954		langCpp:  i.shouldGenerateCppBackend(),
955		langNdk:  i.shouldGenerateNdkBackend(),
956		langJava: i.shouldGenerateJavaBackend(),
957		langRust: i.shouldGenerateRustBackend()}
958
959	// The ndk_platform backend is generated only when explicitly requested. This will
960	// eventually be completely removed the devices in the long tail are gone.
961	if mctx.DeviceConfig().GenerateAidlNdkPlatformBackend() {
962		shouldGenerateLangBackendMap[langNdkPlatform] = i.shouldGenerateNdkBackend()
963	}
964
965	for lang, shouldGenerate := range shouldGenerateLangBackendMap {
966		if !shouldGenerate {
967			continue
968		}
969		libs = append(libs, addLibrary(mctx, i, nextVersion, lang, requireFrozenVersion, requireFrozenReason))
970		for _, version := range versions {
971			libs = append(libs, addLibrary(mctx, i, version, lang, false, "this is a known frozen version"))
972		}
973	}
974
975	// In the future, we may want to force the -cpp backend to be on host,
976	// and limit its visibility, even if it's not created normally
977	if i.shouldGenerateCppBackend() && len(i.properties.Imports) == 0 {
978		libs = append(libs, addLibrary(mctx, i, nextVersion, langCppAnalyzer, false, "analysis always uses latest version even if frozen"))
979	}
980
981	if unstable {
982		apiDirRoot := filepath.Join(aidlApiDir, i.ModuleBase.Name())
983		aidlDumps, _ := mctx.GlobWithDeps(filepath.Join(mctx.ModuleDir(), apiDirRoot, "**/*.aidl"), nil)
984		if len(aidlDumps) != 0 {
985			mctx.PropertyErrorf("unstable", "The interface is configured as unstable, "+
986				"but API dumps exist under %q. Unstable interface cannot have dumps.", apiDirRoot)
987		}
988	} else {
989		addApiModule(mctx, i)
990	}
991
992	// Reserve this module name for future use
993	mctx.CreateModule(phony.PhonyFactory, &phonyProperties{
994		Name: proptools.StringPtr(i.ModuleBase.Name()),
995	})
996
997	i.internalModuleNames = libs
998}
999
1000func (i *aidlInterface) commonBackendProperties(lang string) CommonBackendProperties {
1001	switch lang {
1002	case langCpp:
1003		return i.properties.Backend.Cpp.CommonBackendProperties
1004	case langJava:
1005		return i.properties.Backend.Java.CommonBackendProperties
1006	case langNdk, langNdkPlatform:
1007		return i.properties.Backend.Ndk.CommonBackendProperties
1008	case langRust:
1009		return i.properties.Backend.Rust.CommonBackendProperties
1010	default:
1011		panic(fmt.Errorf("unsupported language backend %q\n", lang))
1012	}
1013}
1014
1015func (i *aidlInterface) Name() string {
1016	return i.ModuleBase.Name() + aidlInterfaceSuffix
1017}
1018
1019func (i *aidlInterface) GenerateAndroidBuildActions(ctx android.ModuleContext) {
1020	srcs, _ := getPaths(ctx, i.properties.Srcs, i.properties.Local_include_dir)
1021	for _, src := range srcs {
1022		computedType := strings.TrimSuffix(strings.ReplaceAll(src.Rel(), "/", "."), ".aidl")
1023		i.computedTypes = append(i.computedTypes, computedType)
1024	}
1025
1026	i.preprocessed = make(map[string]android.WritablePath)
1027	// generate (len(versions) + 1) preprocessed.aidl files
1028	for _, version := range concat(i.getVersions(), []string{i.nextVersion()}) {
1029		i.preprocessed[version] = i.buildPreprocessed(ctx, version)
1030	}
1031	// helpful aliases
1032	if !proptools.Bool(i.properties.Unstable) {
1033		if i.hasVersion() {
1034			i.preprocessed["latest"] = i.preprocessed[i.latestVersion()]
1035		} else {
1036			// when we have no frozen versions yet, use "next version" as latest
1037			i.preprocessed["latest"] = i.preprocessed[i.nextVersion()]
1038		}
1039		i.preprocessed[""] = i.preprocessed[i.nextVersion()]
1040	}
1041}
1042
1043func (i *aidlInterface) getImportsForVersion(version string) []string {
1044	// `Imports` is used when version == i.nextVersion() or`versions` is defined instead of `versions_with_info`
1045	importsSrc := i.properties.Imports
1046	for _, v := range i.properties.Versions_with_info {
1047		if v.Version == version {
1048			importsSrc = v.Imports
1049			break
1050		}
1051	}
1052	imports := make([]string, len(importsSrc))
1053	copy(imports, importsSrc)
1054
1055	return imports
1056}
1057
1058func (i *aidlInterface) getImports(version string) map[string]string {
1059	imports := make(map[string]string)
1060	imports_src := i.getImportsForVersion(version)
1061
1062	useLatestStable := !proptools.Bool(i.properties.Unstable) && version != "" && version != i.nextVersion()
1063	for _, importString := range imports_src {
1064		name, targetVersion := parseModuleWithVersion(importString)
1065		if targetVersion == "" && useLatestStable {
1066			targetVersion = "latest"
1067		}
1068		imports[name] = targetVersion
1069	}
1070	return imports
1071}
1072
1073// generate preprocessed.aidl which contains only types with evaluated constants.
1074// "imports" will use preprocessed.aidl with -p flag to avoid parsing the entire transitive list
1075// of dependencies.
1076func (i *aidlInterface) buildPreprocessed(ctx android.ModuleContext, version string) android.WritablePath {
1077	deps := getDeps(ctx, i.getImports(version))
1078
1079	preprocessed := android.PathForModuleOut(ctx, version, "preprocessed.aidl")
1080	rb := android.NewRuleBuilder(pctx, ctx)
1081	srcs, root_dir := i.srcsForVersion(ctx, version)
1082
1083	if len(srcs) == 0 {
1084		ctx.PropertyErrorf("srcs", "No sources for a previous version in %v. Was a version manually added to .bp file? This is added automatically by <module>-freeze-api.", root_dir)
1085	}
1086
1087	paths, imports := getPaths(ctx, srcs, root_dir)
1088	imports = append(imports, deps.imports...)
1089	imports = append(imports, i.properties.Include_dirs...)
1090
1091	preprocessCommand := rb.Command().BuiltTool("aidl").
1092		FlagWithOutput("--preprocess ", preprocessed).
1093		Flag("--structured")
1094	if i.properties.Stability != nil {
1095		preprocessCommand.FlagWithArg("--stability ", *i.properties.Stability)
1096	}
1097	preprocessCommand.FlagForEachInput("-p", deps.preprocessed)
1098	preprocessCommand.FlagForEachArg("-I", imports)
1099	preprocessCommand.Inputs(paths)
1100	name := i.BaseModuleName()
1101	if version != "" {
1102		name += "/" + version
1103	}
1104	rb.Build("export_"+name, "export types for "+name)
1105	return preprocessed
1106}
1107
1108func (i *aidlInterface) DepsMutator(ctx android.BottomUpMutatorContext) {
1109	ctx.AddReverseDependency(ctx.Module(), nil, aidlMetadataSingletonName)
1110}
1111
1112func AidlInterfaceFactory() android.Module {
1113	i := &aidlInterface{}
1114	i.AddProperties(&i.properties)
1115	android.InitAndroidModule(i)
1116	android.InitBazelModule(i)
1117	android.InitDefaultableModule(i)
1118	i.SetDefaultableHook(func(ctx android.DefaultableHookContext) { aidlInterfaceHook(ctx, i) })
1119	return i
1120}
1121
1122type aidlInterfaceAttributes struct {
1123	aidlLibraryAttributes
1124	Stability          *string
1125	Versions_with_info []versionWithInfoAttribute
1126	Java_config        *javaConfigAttributes
1127	Cpp_config         *cppConfigAttributes
1128	Ndk_config         *ndkConfigAttributes
1129	// Backend_Configs    backendConfigAttributes
1130	Unstable *bool
1131	Frozen   *bool
1132}
1133
1134type javaConfigAttributes struct {
1135	commonBackendAttributes
1136}
1137type cppConfigAttributes struct {
1138	commonNativeBackendAttributes
1139}
1140type ndkConfigAttributes struct {
1141	commonNativeBackendAttributes
1142}
1143
1144type commonBackendAttributes struct {
1145	Enabled         bool
1146	Min_sdk_version *string
1147	Tags            []string
1148}
1149
1150type commonNativeBackendAttributes struct {
1151	commonBackendAttributes
1152}
1153
1154type versionWithInfoAttribute struct {
1155	Version string
1156	// Versions_with_info.Deps in Bazel is analogous to Versions_with_info.Imports in Soong.
1157	// Deps is chosen to be consistent with other Bazel rules/macros for AIDL
1158	Deps bazel.LabelListAttribute
1159}
1160
1161type aidlLibraryAttributes struct {
1162	Srcs                bazel.LabelListAttribute
1163	Hdrs                bazel.LabelListAttribute
1164	Deps                bazel.LabelListAttribute
1165	Strip_import_prefix *string
1166	Flags               []string
1167}
1168
1169// getBazelLabelListForImports returns a bazel label list converted from
1170// aidl_interface.imports or aidl_interface.versions_with_info.imports prop
1171func getBazelLabelListForImports(ctx android.BazelConversionPathContext, imports []string) bazel.LabelList {
1172	type nameAndVersion struct {
1173		name    string
1174		version string
1175	}
1176	// An aidl_interface with a version designation doesn't correspond to a specific
1177	// module, but rather just imforms Soong on which collection of sources to provide
1178	// from a particular interface module.
1179	// However in Bazel, we will be creating an aidl_library for each version, so we can
1180	// depend directly on a "versioned" module. But, we must look up the "unversioned"
1181	// module name in BazelLabelForModuleDeps and then re-attach the version information.
1182	namesAndVersions := make([]nameAndVersion, len(imports))
1183	names := make([]string, len(imports))
1184	for i, dep := range imports {
1185		// Split dep into two parts
1186		name, version := parseModuleWithVersion(dep)
1187		if version == "" {
1188			version = "-latest"
1189		} else {
1190			version = "-V" + version
1191		}
1192		namesAndVersions[i] = nameAndVersion{
1193			name:    name,
1194			version: version,
1195		}
1196		names[i] = name
1197	}
1198	// Look up bazel label by name without version
1199	bazelLabels := android.BazelLabelForModuleDeps(ctx, names)
1200	for i := range bazelLabels.Includes {
1201		// Re-attach the version to the name
1202		bazelLabels.Includes[i].Label = bazelLabels.Includes[i].Label + namesAndVersions[i].version
1203	}
1204	return bazelLabels
1205}
1206
1207func (i *aidlInterface) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
1208	var javaConfig *javaConfigAttributes
1209	var cppConfig *cppConfigAttributes
1210	var ndkConfig *ndkConfigAttributes
1211	if i.shouldGenerateJavaBackend() {
1212		javaConfig = &javaConfigAttributes{}
1213		javaConfig.Enabled = true
1214		javaConfig.Min_sdk_version = i.minSdkVersion(langJava)
1215		javaConfig.Tags = android.ConvertApexAvailableToTags(i.properties.Backend.Java.Apex_available)
1216	}
1217	if i.shouldGenerateCppBackend() {
1218		cppConfig = &cppConfigAttributes{}
1219		cppConfig.Enabled = true
1220		cppConfig.Min_sdk_version = i.minSdkVersion(langCpp)
1221		cppConfig.Tags = android.ConvertApexAvailableToTags(i.properties.Backend.Cpp.Apex_available)
1222	}
1223	if i.shouldGenerateNdkBackend() {
1224		ndkConfig = &ndkConfigAttributes{}
1225		ndkConfig.Enabled = true
1226		ndkConfig.Min_sdk_version = i.minSdkVersion(langNdk)
1227		ndkConfig.Tags = android.ConvertApexAvailableToTags(i.properties.Backend.Ndk.Apex_available)
1228	}
1229
1230	imports := getBazelLabelListForImports(ctx, i.properties.Imports)
1231
1232	var versionsWithInfos []versionWithInfoAttribute
1233
1234	if len(i.properties.Versions_with_info) > 0 {
1235		for _, versionWithInfo := range i.properties.Versions_with_info {
1236			versionedImports := getBazelLabelListForImports(ctx, versionWithInfo.Imports)
1237			if !versionedImports.IsEmpty() {
1238				versionsWithInfos = append(
1239					versionsWithInfos,
1240					versionWithInfoAttribute{
1241						Version: versionWithInfo.Version,
1242						Deps:    bazel.MakeLabelListAttribute(versionedImports),
1243					},
1244				)
1245			} else {
1246				versionsWithInfos = append(
1247					versionsWithInfos,
1248					versionWithInfoAttribute{
1249						Version: versionWithInfo.Version,
1250					},
1251				)
1252			}
1253		}
1254	} else if len(i.properties.Versions) > 0 {
1255		for _, version := range i.properties.Versions {
1256			if !imports.IsEmpty() {
1257				versionsWithInfos = append(
1258					versionsWithInfos,
1259					versionWithInfoAttribute{
1260						Version: version,
1261						Deps:    bazel.MakeLabelListAttribute(imports),
1262					},
1263				)
1264			} else {
1265				versionsWithInfos = append(
1266					versionsWithInfos,
1267					versionWithInfoAttribute{
1268						Version: version,
1269					},
1270				)
1271			}
1272		}
1273	}
1274
1275	var deps bazel.LabelListAttribute
1276
1277	if len(i.properties.Srcs) > 0 && !imports.IsEmpty() {
1278		// imports is only needed for (non-frozen) srcs
1279		// frozen verions use imports in versions_with_info
1280		deps = bazel.MakeLabelListAttribute(imports)
1281	}
1282
1283	deps.Append(
1284		bazel.MakeLabelListAttribute(
1285			android.BazelLabelForModuleDeps(
1286				ctx,
1287				i.properties.Headers,
1288			),
1289		),
1290	)
1291
1292	srcsAttr := bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, i.properties.Srcs))
1293	var stripImportPrefixAttr *string = nil
1294	if i.properties.Local_include_dir != "" && !srcsAttr.IsEmpty() {
1295		stripImportPrefixAttr = &i.properties.Local_include_dir
1296	}
1297
1298	attrs := &aidlInterfaceAttributes{
1299		aidlLibraryAttributes: aidlLibraryAttributes{
1300			Srcs:                srcsAttr,
1301			Flags:               i.properties.Flags,
1302			Deps:                deps,
1303			Strip_import_prefix: stripImportPrefixAttr,
1304		},
1305		Stability:          i.properties.Stability,
1306		Versions_with_info: versionsWithInfos,
1307		Java_config:        javaConfig,
1308		Cpp_config:         cppConfig,
1309		Ndk_config:         ndkConfig,
1310		Unstable:           i.properties.Unstable,
1311		Frozen:             i.properties.Frozen,
1312	}
1313
1314	interfaceName := strings.TrimSuffix(i.Name(), "_interface")
1315
1316	ctx.CreateBazelTargetModule(
1317		bazel.BazelTargetModuleProperties{
1318			Rule_class:        "aidl_interface",
1319			Bzl_load_location: "//build/bazel/rules/aidl:aidl_interface.bzl",
1320		},
1321		android.CommonAttributes{Name: interfaceName},
1322		attrs,
1323	)
1324}
1325