• 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/phony"
22	"android/soong/rust"
23
24	"fmt"
25	"path/filepath"
26	"regexp"
27	"sort"
28	"strconv"
29	"strings"
30	"sync"
31
32	"github.com/google/blueprint/proptools"
33)
34
35const (
36	aidlInterfaceSuffix       = "_interface"
37	aidlMetadataSingletonName = "aidl_metadata_json"
38	aidlApiDir                = "aidl_api"
39	aidlApiSuffix             = "-api"
40	langCpp                   = "cpp"
41	langJava                  = "java"
42	langNdk                   = "ndk"
43	langNdkPlatform           = "ndk_platform"
44	langRust                  = "rust"
45
46	currentVersion = "current"
47)
48
49var (
50	pctx = android.NewPackageContext("android/aidl")
51)
52
53func init() {
54	pctx.Import("android/soong/android")
55	pctx.HostBinToolVariable("aidlCmd", "aidl")
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(registerPreDepsMutators)
60	android.PreArchBp2BuildMutators(registerPreDepsMutators)
61	android.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
62		ctx.BottomUp("checkUnstableModule", checkUnstableModuleMutator).Parallel()
63		ctx.BottomUp("recordVersions", recordVersions).Parallel()
64		ctx.BottomUp("checkDuplicatedVersions", checkDuplicatedVersions).Parallel()
65	})
66}
67
68func registerPreDepsMutators(ctx android.RegisterMutatorsContext) {
69	ctx.BottomUp("checkImports", checkImports).Parallel()
70	ctx.TopDown("createAidlInterface", createAidlInterfaceMutator).Parallel()
71}
72
73func createAidlInterfaceMutator(mctx android.TopDownMutatorContext) {
74	if g, ok := mctx.Module().(*aidlImplementationGenerator); ok {
75		g.GenerateImplementation(mctx)
76	}
77}
78
79func checkUnstableModuleMutator(mctx android.BottomUpMutatorContext) {
80	// If it is an aidl interface, we don't need to check its dependencies.
81	if isAidlModule(mctx.ModuleName(), mctx.Config()) {
82		return
83	}
84	mctx.VisitDirectDepsIf(func(m android.Module) bool {
85		return android.InList(m.Name(), *unstableModules(mctx.Config()))
86	}, func(m android.Module) {
87		if mctx.ModuleName() == m.Name() {
88			return
89		}
90		// TODO(b/154066686): Replace it with a common method instead of listing up module types.
91		// Test libraries are exempted.
92		if android.InList(mctx.ModuleType(), []string{"cc_test_library", "android_test", "cc_benchmark", "cc_test"}) {
93			return
94		}
95
96		mctx.ModuleErrorf(m.Name() + " is disallowed in release version because it is unstable, and its \"owner\" property is missing.")
97	})
98}
99
100func isAidlModule(moduleName string, config android.Config) bool {
101	for _, i := range *aidlInterfaces(config) {
102		if android.InList(moduleName, i.internalModuleNames) {
103			return true
104		}
105	}
106	return false
107}
108
109func recordVersions(mctx android.BottomUpMutatorContext) {
110	switch mctx.Module().(type) {
111	case *java.Library:
112	case *cc.Module:
113	case *rust.Module:
114	case *aidlGenRule:
115	default:
116		return
117	}
118
119	isAidlModule := isAidlModule(mctx.ModuleName(), mctx.Config())
120
121	// First, gather all the AIDL interfaces modules that are directly or indirectly
122	// depended on by this module
123	myAidlDeps := make(map[DepInfo]bool)
124	mctx.VisitDirectDeps(func(dep android.Module) {
125		switch dep.(type) {
126		case *java.Library:
127		case *cc.Module:
128		case *rust.Module:
129		case *aidlGenRule:
130			// Dependencies to the source module is tracked only when it's from a client
131			// module, i.e. not from an AIDL-generated stub library
132			if isAidlModule {
133				return
134			}
135		default:
136			return
137		}
138		depName := mctx.OtherModuleName(dep)
139		isSource := strings.HasSuffix(depName, "-source")
140		depName = strings.TrimSuffix(depName, "-source")
141		// If this module depends on one of the aidl interface module, record it
142		for _, i := range *aidlInterfaces(mctx.Config()) {
143			if android.InList(depName, i.internalModuleNames) {
144				ifaceName := i.ModuleBase.Name()
145				verLang := depName[len(ifaceName):]
146				myAidlDeps[DepInfo{ifaceName, verLang, isSource}] = true
147				break
148			}
149		}
150		// If dep is in aidlDeps, that means dep has direct or indirect dependencies to AIDL interfaces
151		// That becomes this module's aidlDeps as well
152		aidlDepsMutex.RLock()
153		if depsOfDep, ok := aidlDeps(mctx.Config())[dep]; ok {
154			for _, d := range depsOfDep {
155				myAidlDeps[d] = true
156			}
157		}
158		aidlDepsMutex.RUnlock()
159	})
160
161	if len(myAidlDeps) == 0 {
162		// This should be usual case.
163		return
164	}
165
166	// Then, record the aidl deps of this module to the global map so that it can be used by
167	// next runs of this mutator for the modules that depend on this module.
168	var list []DepInfo
169	for d := range myAidlDeps {
170		list = append(list, d)
171	}
172	aidlDepsMutex.Lock()
173	aidlDeps(mctx.Config())[mctx.Module()] = list
174	aidlDepsMutex.Unlock()
175}
176
177func checkDuplicatedVersions(mctx android.BottomUpMutatorContext) {
178	switch mctx.Module().(type) {
179	case *java.Library:
180	case *cc.Module:
181	case *rust.Module:
182	case *aidlGenRule:
183	default:
184		return
185	}
186
187	aidlDepsMutex.RLock()
188	myAidlDeps := aidlDeps(mctx.Config())[mctx.Module()]
189	aidlDepsMutex.RUnlock()
190	if myAidlDeps == nil || len(myAidlDeps) == 0 {
191		return // This should be the usual case
192	}
193
194	// Lastly, report an error if there is any duplicated versions of the same interface * lang
195	for _, lang := range []string{langJava, langCpp, langNdk, langNdkPlatform} {
196		// interfaceName -> verLang -> list of module names
197		versionsOf := make(map[string]map[string][]string)
198		for _, dep := range myAidlDeps {
199			if !strings.HasSuffix(dep.verLang, lang) {
200				continue
201			}
202			versions := versionsOf[dep.ifaceName]
203			if versions == nil {
204				versions = make(map[string][]string)
205				versionsOf[dep.ifaceName] = versions
206			}
207			versions[dep.verLang] = append(versions[dep.verLang], dep.moduleName())
208		}
209
210		for _, versions := range versionsOf {
211			if len(versions) >= 2 {
212				var violators []string
213				for _, modules := range versions {
214					violators = append(violators, modules...)
215				}
216				violators = android.SortedUniqueStrings(violators)
217				mctx.ModuleErrorf("depends on multiple versions of the same aidl_interface: %s", strings.Join(violators, ", "))
218				mctx.WalkDeps(func(child android.Module, parent android.Module) bool {
219					if android.InList(child.Name(), violators) {
220						mctx.ModuleErrorf("Dependency path: %s", mctx.GetPathString(true))
221						return false
222					}
223					return true
224				})
225			}
226		}
227	}
228}
229
230func getPaths(ctx android.ModuleContext, rawSrcs []string, root string) (srcs android.Paths, imports []string) {
231	// TODO(b/189288369): move this to android.PathsForModuleSrcSubDir(ctx, srcs, subdir)
232	for _, src := range rawSrcs {
233		if m, _ := android.SrcIsModuleWithTag(src); m != "" {
234			srcs = append(srcs, android.PathsForModuleSrc(ctx, []string{src})...)
235		} else {
236			srcs = append(srcs, android.PathsWithModuleSrcSubDir(ctx, android.PathsForModuleSrc(ctx, []string{src}), root)...)
237		}
238	}
239
240	if len(srcs) == 0 {
241		ctx.PropertyErrorf("srcs", "No sources provided.")
242	}
243
244	// gather base directories from input .aidl files
245	for _, src := range srcs {
246		if src.Ext() != ".aidl" {
247			// Silently ignore non-aidl files as some filegroups have both java and aidl files together
248			continue
249		}
250		baseDir := strings.TrimSuffix(src.String(), src.Rel())
251		baseDir = strings.TrimSuffix(baseDir, "/")
252		if baseDir != "" && !android.InList(baseDir, imports) {
253			imports = append(imports, baseDir)
254		}
255	}
256
257	return srcs, imports
258}
259
260func isRelativePath(path string) bool {
261	if path == "" {
262		return true
263	}
264	return filepath.Clean(path) == path && path != ".." &&
265		!strings.HasPrefix(path, "../") && !strings.HasPrefix(path, "/")
266}
267
268type CommonBackendProperties struct {
269	// Whether to generate code in the corresponding backend.
270	// Default: true
271	Enabled        *bool
272	Apex_available []string
273
274	// The minimum version of the sdk that the compiled artifacts will run against
275	// For native modules, the property needs to be set when a module is a part of mainline modules(APEX).
276	// Forwarded to generated java/native module.
277	Min_sdk_version *string
278
279	// Determines whether the generated source files are available or not. When set to true,
280	// the source files can be added to `srcs` property via `:<ifacename>-<backend>-source`,
281	// e.g., ":myaidl-java-source"
282	Srcs_available *bool
283}
284
285type CommonNativeBackendProperties struct {
286	CommonBackendProperties
287	// Whether to generate additional code for gathering information
288	// about the transactions.
289	// Default: false
290	Gen_log *bool
291
292	// VNDK properties for correspdoning backend.
293	cc.VndkProperties
294}
295
296type DumpApiProperties struct {
297	// Dumps without license header (assuming it is the first comment in .aidl file). Default: false
298	No_license *bool
299}
300
301type aidlInterfaceProperties struct {
302	// Vndk properties for C++/NDK libraries only (preferred to use backend-specific settings)
303	cc.VndkProperties
304
305	// How to interpret VNDK options. We only want one library in the VNDK (not multiple
306	// versions, since this would be a waste of space/unclear, and ultimately we want all
307	// code in a given release to be updated to use a specific version). By default, this
308	// puts either the latest stable version of the library or, if there is no stable
309	// version, the unstable version of the library in the VNDK. When using this field,
310	// explicitly set it to one of the values in the 'versions' field to put that version
311	// in the VNDK or set it to the next version (1 higher than this) to mean the version
312	// that will be frozen in the next update.
313	Vndk_use_version *string
314
315	// Whether the library can be installed on the vendor image.
316	Vendor_available *bool
317
318	// Whether the library can be installed on the odm image.
319	Odm_available *bool
320
321	// Whether the library can be installed on the product image.
322	Product_available *bool
323
324	// Whether the library can be loaded multiple times into the same process
325	Double_loadable *bool
326
327	// Whether the library can be used on host
328	Host_supported *bool
329
330	// Whether tracing should be added to the interface.
331	Gen_trace *bool
332
333	// Top level directories for includes.
334	// TODO(b/128940869): remove it if aidl_interface can depend on framework.aidl
335	Include_dirs []string
336	// Relative path for includes. By default assumes AIDL path is relative to current directory.
337	Local_include_dir string
338
339	// List of .aidl files which compose this interface.
340	Srcs []string `android:"path"`
341
342	// List of aidl_interface modules that this uses. If one of your AIDL interfaces uses an
343	// interface or parcelable from another aidl_interface, you should put its name here.
344	// It could be an aidl_interface solely or with version(such as -V1)
345	Imports []string
346
347	// List of aidl_interface modules that this uses. It trims version suffix in 'Imports' field.
348	ImportsWithoutVersion []string `blueprint:"mutated"`
349
350	// Used by gen dependency to fill out aidl include path
351	Full_import_paths []string `blueprint:"mutated"`
352
353	// Stability promise. Currently only supports "vintf".
354	// If this is unset, this corresponds to an interface with stability within
355	// this compilation context (so an interface loaded here can only be used
356	// with things compiled together, e.g. on the system.img).
357	// If this is set to "vintf", this corresponds to a stability promise: the
358	// interface must be kept stable as long as it is used.
359	Stability *string
360
361	// Previous API versions that are now frozen. The version that is last in
362	// the list is considered as the most recent version.
363	Versions []string
364
365	Backend struct {
366		// Backend of the compiler generating code for Java clients.
367		// When enabled, this creates a target called "<name>-java".
368		Java struct {
369			CommonBackendProperties
370			// Set to the version of the sdk to compile against
371			// Default: system_current
372			Sdk_version *string
373			// Whether to compile against platform APIs instead of
374			// an SDK.
375			Platform_apis *bool
376		}
377		// Backend of the compiler generating code for C++ clients using
378		// libbinder (unstable C++ interface)
379		// When enabled, this creates a target called "<name>-cpp".
380		Cpp struct {
381			CommonNativeBackendProperties
382		}
383		// Backend of the compiler generating code for C++ clients using
384		// libbinder_ndk (stable C interface to system's libbinder)
385		// When enabled, this creates a target called "<name>-ndk"
386		// (for apps) and "<name>-ndk_platform" (for platform usage).
387		Ndk struct {
388			CommonNativeBackendProperties
389
390			// Currently, all ndk-supported interfaces generate two variants:
391			// - ndk - for apps to use, against an NDK
392			// - ndk_platform - for the platform to use
393			//
394			// This adds an option to disable the 'ndk' variant in cases where APIs
395			// only available in the platform version work.
396			Apps_enabled *bool
397		}
398		// Backend of the compiler generating code for Rust clients.
399		// When enabled, this creates a target called "<name>-rust".
400		Rust struct {
401			CommonBackendProperties
402		}
403	}
404
405	// Marks that this interface does not need to be stable. When set to true, the build system
406	// doesn't create the API dump and require it to be updated. Default is false.
407	Unstable *bool
408
409	// Optional flags to be passed to the AIDL compiler. e.g. "-Weverything"
410	Flags []string
411
412	// --dumpapi options
413	Dumpapi DumpApiProperties
414}
415
416type aidlInterface struct {
417	android.ModuleBase
418
419	properties aidlInterfaceProperties
420
421	computedTypes []string
422
423	// list of module names that are created for this interface
424	internalModuleNames []string
425}
426
427func (i *aidlInterface) shouldGenerateJavaBackend() bool {
428	// explicitly true if not specified to give early warning to devs
429	return i.properties.Backend.Java.Enabled == nil || *i.properties.Backend.Java.Enabled
430}
431
432func (i *aidlInterface) shouldGenerateCppBackend() bool {
433	// explicitly true if not specified to give early warning to devs
434	return i.properties.Backend.Cpp.Enabled == nil || *i.properties.Backend.Cpp.Enabled
435}
436
437func (i *aidlInterface) shouldGenerateNdkBackend() bool {
438	// explicitly true if not specified to give early warning to devs
439	return i.properties.Backend.Ndk.Enabled == nil || *i.properties.Backend.Ndk.Enabled
440}
441
442func (i *aidlInterface) shouldGenerateAppNdkBackend() bool {
443	if !i.shouldGenerateNdkBackend() {
444		return false
445	}
446	// explicitly true if not specified to give early warning to devs
447	return i.properties.Backend.Ndk.Apps_enabled == nil || *i.properties.Backend.Ndk.Apps_enabled
448}
449
450func (i *aidlInterface) shouldGenerateRustBackend() bool {
451	return i.properties.Backend.Rust.Enabled != nil && *i.properties.Backend.Rust.Enabled
452}
453
454func (i *aidlInterface) gatherInterface(mctx android.LoadHookContext) {
455	aidlInterfaces := aidlInterfaces(mctx.Config())
456	aidlInterfaceMutex.Lock()
457	defer aidlInterfaceMutex.Unlock()
458	*aidlInterfaces = append(*aidlInterfaces, i)
459}
460
461func addUnstableModule(mctx android.LoadHookContext, moduleName string) {
462	unstableModules := unstableModules(mctx.Config())
463	unstableModuleMutex.Lock()
464	defer unstableModuleMutex.Unlock()
465	*unstableModules = append(*unstableModules, moduleName)
466}
467
468func checkImports(mctx android.BottomUpMutatorContext) {
469	if i, ok := mctx.Module().(*aidlInterface); ok {
470		for _, anImportWithVersion := range i.properties.Imports {
471			anImport, version := parseModuleWithVersion(anImportWithVersion)
472			other := lookupInterface(anImport, mctx.Config())
473
474			if other == nil {
475				if mctx.Config().AllowMissingDependencies() {
476					continue
477				}
478				mctx.PropertyErrorf("imports", "Import does not exist: "+anImport)
479			}
480			if version != "" {
481				candidateVersions := concat(other.properties.Versions, []string{other.nextVersion()})
482				if !android.InList(version, candidateVersions) {
483					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)
484				}
485			}
486			if i.shouldGenerateJavaBackend() && !other.shouldGenerateJavaBackend() {
487				mctx.PropertyErrorf("backend.java.enabled",
488					"Java backend not enabled in the imported AIDL interface %q", anImport)
489			}
490
491			if i.shouldGenerateCppBackend() && !other.shouldGenerateCppBackend() {
492				mctx.PropertyErrorf("backend.cpp.enabled",
493					"C++ backend not enabled in the imported AIDL interface %q", anImport)
494			}
495
496			if i.shouldGenerateNdkBackend() && !other.shouldGenerateNdkBackend() {
497				mctx.PropertyErrorf("backend.ndk.enabled",
498					"NDK backend not enabled in the imported AIDL interface %q", anImport)
499			}
500
501			if i.shouldGenerateRustBackend() && !other.shouldGenerateRustBackend() {
502				mctx.PropertyErrorf("backend.rust.enabled",
503					"Rust backend not enabled in the imported AIDL interface %q", anImport)
504			}
505		}
506	}
507}
508
509func (i *aidlInterface) checkGenTrace(mctx android.LoadHookContext) {
510	if !proptools.Bool(i.properties.Gen_trace) {
511		return
512	}
513	if i.shouldGenerateJavaBackend() && !proptools.Bool(i.properties.Backend.Java.Platform_apis) {
514		mctx.PropertyErrorf("gen_trace", "must be false when Java backend is enabled and platform_apis is false")
515	}
516}
517
518func (i *aidlInterface) checkStability(mctx android.LoadHookContext) {
519	if i.properties.Stability == nil {
520		return
521	}
522
523	if proptools.Bool(i.properties.Unstable) {
524		mctx.PropertyErrorf("stability", "must be empty when \"unstable\" is true")
525	}
526
527	// TODO(b/136027762): should we allow more types of stability (e.g. for APEX) or
528	// should we switch this flag to be something like "vintf { enabled: true }"
529	isVintf := "vintf" == proptools.String(i.properties.Stability)
530	if !isVintf {
531		mctx.PropertyErrorf("stability", "must be empty or \"vintf\"")
532	}
533}
534func (i *aidlInterface) checkVersions(mctx android.LoadHookContext) {
535	versions := make(map[string]bool)
536	intVersions := make([]int, 0, len(i.properties.Versions))
537	for _, ver := range i.properties.Versions {
538		if _, dup := versions[ver]; dup {
539			mctx.PropertyErrorf("versions", "duplicate found", ver)
540			continue
541		}
542		versions[ver] = true
543		n, err := strconv.Atoi(ver)
544		if err != nil {
545			mctx.PropertyErrorf("versions", "%q is not an integer", ver)
546			continue
547		}
548		if n <= 0 {
549			mctx.PropertyErrorf("versions", "should be > 0, but is %v", ver)
550			continue
551		}
552		intVersions = append(intVersions, n)
553
554	}
555	if !mctx.Failed() && !sort.IntsAreSorted(intVersions) {
556		mctx.PropertyErrorf("versions", "should be sorted, but is %v", i.properties.Versions)
557	}
558}
559func (i *aidlInterface) checkVndkUseVersion(mctx android.LoadHookContext) {
560	if i.properties.Vndk_use_version == nil {
561		return
562	}
563	if !i.hasVersion() {
564		mctx.PropertyErrorf("vndk_use_version", "This does not make sense when no 'versions' are specified.")
565
566	}
567	if *i.properties.Vndk_use_version == i.nextVersion() {
568		return
569	}
570	for _, ver := range i.properties.Versions {
571		if *i.properties.Vndk_use_version == ver {
572			return
573		}
574	}
575	mctx.PropertyErrorf("vndk_use_version", "Specified version %q does not exist", *i.properties.Vndk_use_version)
576}
577
578func (i *aidlInterface) nextVersion() string {
579	if proptools.Bool(i.properties.Unstable) {
580		return ""
581	}
582	return nextVersion(i.properties.Versions)
583}
584
585func nextVersion(versions []string) string {
586	if len(versions) == 0 {
587		return "1"
588	}
589	ver := versions[len(versions)-1]
590	i, err := strconv.Atoi(ver)
591	if err != nil {
592		panic(err)
593	}
594	return strconv.Itoa(i + 1)
595}
596
597func (i *aidlInterface) latestVersion() string {
598	if !i.hasVersion() {
599		return "0"
600	}
601	return i.properties.Versions[len(i.properties.Versions)-1]
602}
603
604func (i *aidlInterface) hasVersion() bool {
605	return len(i.properties.Versions) > 0
606}
607
608func hasVersionSuffix(moduleName string) bool {
609	hasVersionSuffix, _ := regexp.MatchString("-V\\d+$", moduleName)
610	return hasVersionSuffix
611}
612
613func parseModuleWithVersion(moduleName string) (string, string) {
614	if hasVersionSuffix(moduleName) {
615		versionIdx := strings.LastIndex(moduleName, "-V")
616		if versionIdx == -1 {
617			panic("-V must exist in this context")
618		}
619		return moduleName[:versionIdx], moduleName[versionIdx+len("-V"):]
620	}
621	return moduleName, ""
622}
623
624func trimVersionSuffixInList(moduleNames []string) []string {
625	return wrapFunc("", moduleNames, "", func(moduleName string) string {
626		moduleNameWithoutVersion, _ := parseModuleWithVersion(moduleName)
627		return moduleNameWithoutVersion
628	})
629}
630
631func aidlInterfaceHook(mctx android.LoadHookContext, i *aidlInterface) {
632	if hasVersionSuffix(i.ModuleBase.Name()) {
633		mctx.PropertyErrorf("name", "aidl_interface should not have '-V<number> suffix")
634	}
635	i.properties.ImportsWithoutVersion = trimVersionSuffixInList(i.properties.Imports)
636	if !isRelativePath(i.properties.Local_include_dir) {
637		mctx.PropertyErrorf("local_include_dir", "must be relative path: "+i.properties.Local_include_dir)
638	}
639	var importPaths []string
640	importPaths = append(importPaths, filepath.Join(mctx.ModuleDir(), i.properties.Local_include_dir))
641	importPaths = append(importPaths, i.properties.Include_dirs...)
642
643	i.properties.Full_import_paths = importPaths
644
645	i.gatherInterface(mctx)
646	i.checkStability(mctx)
647	i.checkVersions(mctx)
648	i.checkVndkUseVersion(mctx)
649	i.checkGenTrace(mctx)
650
651	if mctx.Failed() {
652		return
653	}
654
655	var libs []string
656	sdkIsFinal := !mctx.Config().DefaultAppTargetSdk(mctx).IsPreview()
657
658	unstable := proptools.Bool(i.properties.Unstable)
659
660	if unstable {
661		if i.hasVersion() {
662			mctx.PropertyErrorf("versions", "cannot have versions for an unstable interface")
663			return
664		}
665		if i.properties.Stability != nil {
666			mctx.ModuleErrorf("unstable:true and stability:%q cannot happen at the same time", i.properties.Stability)
667			return
668		}
669	}
670
671	// Two different types of 'unstable' here
672	// - 'unstable: true' meaning the module is never stable
673	// - current unfrozen ToT version
674	//
675	// OEM branches may remove 'i.Owner()' here to apply the check to all interfaces, in
676	// addition to core platform interfaces. Otherwise, we rely on vts_treble_vintf_vendor_test.
677	requireFrozenVersion := !unstable && sdkIsFinal && i.Owner() == ""
678
679	// surface error early, main check is via checkUnstableModuleMutator
680	if requireFrozenVersion && !i.hasVersion() {
681		mctx.PropertyErrorf("versions", "must be set (need to be frozen) when \"unstable\" is false, PLATFORM_VERSION_CODENAME is REL, and \"owner\" property is missing.")
682	}
683
684	versions := i.properties.Versions
685	nextVersion := i.nextVersion()
686	shouldGenerateLangBackendMap := map[string]bool{
687		langCpp:         i.shouldGenerateCppBackend(),
688		langNdk:         i.shouldGenerateAppNdkBackend(),
689		langNdkPlatform: i.shouldGenerateNdkBackend(),
690		langJava:        i.shouldGenerateJavaBackend(),
691		langRust:        i.shouldGenerateRustBackend()}
692	for lang, shouldGenerate := range shouldGenerateLangBackendMap {
693		if !shouldGenerate {
694			continue
695		}
696		libs = append(libs, addLibrary(mctx, i, nextVersion, lang))
697		if requireFrozenVersion {
698			addUnstableModule(mctx, libs[len(libs)-1])
699		}
700		for _, version := range versions {
701			libs = append(libs, addLibrary(mctx, i, version, lang))
702		}
703	}
704
705	if unstable {
706		apiDirRoot := filepath.Join(aidlApiDir, i.ModuleBase.Name())
707		aidlDumps, _ := mctx.GlobWithDeps(filepath.Join(mctx.ModuleDir(), apiDirRoot, "**/*.aidl"), nil)
708		if len(aidlDumps) != 0 {
709			mctx.PropertyErrorf("unstable", "The interface is configured as unstable, "+
710				"but API dumps exist under %q. Unstable interface cannot have dumps.", apiDirRoot)
711		}
712	} else {
713		addApiModule(mctx, i)
714	}
715
716	if proptools.Bool(i.properties.VndkProperties.Vndk.Enabled) {
717		if "vintf" != proptools.String(i.properties.Stability) {
718			mctx.PropertyErrorf("stability", "must be \"vintf\" if the module is for VNDK.")
719		}
720	}
721
722	// Reserve this module name for future use
723	mctx.CreateModule(phony.PhonyFactory, &phonyProperties{
724		Name: proptools.StringPtr(i.ModuleBase.Name()),
725	})
726
727	i.internalModuleNames = libs
728}
729
730func (i *aidlInterface) commonBackendProperties(lang string) CommonBackendProperties {
731	switch lang {
732	case langCpp:
733		return i.properties.Backend.Cpp.CommonBackendProperties
734	case langJava:
735		return i.properties.Backend.Java.CommonBackendProperties
736	case langNdk, langNdkPlatform:
737		return i.properties.Backend.Ndk.CommonBackendProperties
738	case langRust:
739		return i.properties.Backend.Rust.CommonBackendProperties
740	default:
741		panic(fmt.Errorf("unsupported language backend %q\n", lang))
742	}
743}
744
745// srcsVisibility gives the value for the `visibility` property of the source gen module for the
746// language backend `lang`. By default, the source gen module is not visible to the clients of
747// aidl_interface (because it's an impl detail), but when `backend.<backend>.srcs_available` is set
748// to true, the source gen module follows the visibility of the aidl_interface module.
749func srcsVisibility(mctx android.LoadHookContext, lang string) []string {
750	if a, ok := mctx.Module().(*aidlInterface); !ok {
751		panic(fmt.Errorf("%q is not aidl_interface", mctx.Module().String()))
752	} else {
753		if proptools.Bool(a.commonBackendProperties(lang).Srcs_available) {
754			// Returning nil so that the visibility of the source module defaults to the
755			// the package-level default visibility. This way, the source module gets
756			// the same visibility as the library modules.
757			return nil
758		}
759	}
760	return []string{
761		"//" + mctx.ModuleDir(),
762		// system/tools/aidl/build is always added because aidl_metadata_json in the
763		// directory has dependencies to all aidl_interface modules.
764		"//system/tools/aidl/build",
765	}
766}
767
768func (i *aidlInterface) Name() string {
769	return i.ModuleBase.Name() + aidlInterfaceSuffix
770}
771func (i *aidlInterface) GenerateAndroidBuildActions(ctx android.ModuleContext) {
772	aidlRoot := android.PathForModuleSrc(ctx, i.properties.Local_include_dir)
773	for _, src := range android.PathsForModuleSrc(ctx, i.properties.Srcs) {
774		baseDir := getBaseDir(ctx, src, aidlRoot)
775		relPath, _ := filepath.Rel(baseDir, src.String())
776		computedType := strings.TrimSuffix(strings.ReplaceAll(relPath, "/", "."), ".aidl")
777		i.computedTypes = append(i.computedTypes, computedType)
778	}
779}
780func (i *aidlInterface) DepsMutator(ctx android.BottomUpMutatorContext) {
781	ctx.AddReverseDependency(ctx.Module(), nil, aidlMetadataSingletonName)
782}
783
784var (
785	aidlInterfacesKey   = android.NewOnceKey("aidlInterfaces")
786	unstableModulesKey  = android.NewOnceKey("unstableModules")
787	aidlDepsKey         = android.NewOnceKey("aidlDeps")
788	aidlInterfaceMutex  sync.Mutex
789	unstableModuleMutex sync.Mutex
790	aidlDepsMutex       sync.RWMutex
791)
792
793func aidlInterfaces(config android.Config) *[]*aidlInterface {
794	return config.Once(aidlInterfacesKey, func() interface{} {
795		return &[]*aidlInterface{}
796	}).(*[]*aidlInterface)
797}
798
799func unstableModules(config android.Config) *[]string {
800	return config.Once(unstableModulesKey, func() interface{} {
801		return &[]string{}
802	}).(*[]string)
803}
804
805type DepInfo struct {
806	ifaceName string
807	verLang   string
808	isSource  bool
809}
810
811func (d DepInfo) moduleName() string {
812	name := d.ifaceName + d.verLang
813	if d.isSource {
814		name += "-source"
815	}
816	return name
817}
818
819func aidlDeps(config android.Config) map[android.Module][]DepInfo {
820	return config.Once(aidlDepsKey, func() interface{} {
821		return make(map[android.Module][]DepInfo)
822	}).(map[android.Module][]DepInfo)
823}
824
825func aidlInterfaceFactory() android.Module {
826	i := &aidlInterface{}
827	i.AddProperties(&i.properties)
828	android.InitAndroidModule(i)
829	android.AddLoadHook(i, func(ctx android.LoadHookContext) { aidlInterfaceHook(ctx, i) })
830	return i
831}
832
833func lookupInterface(name string, config android.Config) *aidlInterface {
834	for _, i := range *aidlInterfaces(config) {
835		if i.ModuleBase.Name() == name {
836			return i
837		}
838	}
839	return nil
840}
841