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