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