• 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
31	"github.com/google/blueprint"
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	langRust                  = "rust"
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 (
52	pctx = android.NewPackageContext("android/aidl")
53)
54
55func init() {
56	pctx.Import("android/soong/android")
57	pctx.HostBinToolVariable("aidlCmd", "aidl")
58	pctx.HostBinToolVariable("aidlHashGen", "aidl_hash_gen")
59	pctx.SourcePathVariable("aidlToJniCmd", "system/tools/aidl/build/aidl_to_jni.py")
60	pctx.SourcePathVariable("aidlRustGlueCmd", "system/tools/aidl/build/aidl_rust_glue.py")
61	android.RegisterModuleType("aidl_interface", aidlInterfaceFactory)
62	android.PreArchMutators(registerPreArchMutators)
63	android.PreArchBp2BuildMutators(registerPreArchMutators)
64	android.PostDepsMutators(registerPostDepsMutators)
65}
66
67func registerPreArchMutators(ctx android.RegisterMutatorsContext) {
68	ctx.BottomUp("addInterfaceDeps", addInterfaceDeps).Parallel()
69	ctx.BottomUp("checkImports", checkImports).Parallel()
70	ctx.TopDown("createAidlInterface", createAidlInterfaceMutator).Parallel()
71}
72
73func registerPostDepsMutators(ctx android.RegisterMutatorsContext) {
74	ctx.BottomUp("checkAidlGeneratedModules", checkAidlGeneratedModules).Parallel()
75}
76
77func createAidlInterfaceMutator(mctx android.TopDownMutatorContext) {
78	if g, ok := mctx.Module().(*aidlImplementationGenerator); ok {
79		g.GenerateImplementation(mctx)
80	}
81}
82
83// A marker struct for AIDL-generated library modules
84type AidlGeneratedModuleProperties struct{}
85
86func wrapLibraryFactory(factory func() android.Module) func() android.Module {
87	return func() android.Module {
88		m := factory()
89		// put a marker struct for AIDL-generated modules
90		m.AddProperties(&AidlGeneratedModuleProperties{})
91		return m
92	}
93}
94
95func isAidlGeneratedModule(module android.Module) bool {
96	for _, props := range module.GetProperties() {
97		// check if there's a marker struct
98		if _, ok := props.(*AidlGeneratedModuleProperties); ok {
99			return true
100		}
101	}
102	return false
103}
104
105// AildVersionInfo keeps the *-source module for each (aidl_interface & lang) and the list of
106// not-frozen versions (which shouldn't be used by other modules)
107type AildVersionInfo struct {
108	notFrozen []string
109	sourceMap map[string]string
110}
111
112var AidlVersionInfoProvider = blueprint.NewMutatorProvider(AildVersionInfo{}, "checkAidlGeneratedModules")
113
114// Merges `other` version info into this one.
115// Returns the pair of mismatching versions when there's conflict. Otherwise returns nil.
116// For example, when a module depends on 'foo-V2-ndk', the map contains an entry of (foo, foo-V2-ndk-source).
117// Merging (foo, foo-V1-ndk-source) and (foo, foo-V2-ndk-source) will fail and returns
118// {foo-V1-ndk-source, foo-V2-ndk-source}.
119func (info *AildVersionInfo) merge(other AildVersionInfo) []string {
120	info.notFrozen = append(info.notFrozen, other.notFrozen...)
121
122	if other.sourceMap == nil {
123		return nil
124	}
125	if info.sourceMap == nil {
126		info.sourceMap = make(map[string]string)
127	}
128	for ifaceName, otherSourceName := range other.sourceMap {
129		if sourceName, ok := info.sourceMap[ifaceName]; ok {
130			if sourceName != otherSourceName {
131				return []string{sourceName, otherSourceName}
132			}
133		} else {
134			info.sourceMap[ifaceName] = otherSourceName
135		}
136	}
137	return nil
138}
139
140func reportUsingNotFrozenError(ctx android.BaseModuleContext, notFrozen []string) {
141	// TODO(b/154066686): Replace it with a common method instead of listing up module types.
142	// Test libraries are exempted.
143	if android.InList(ctx.ModuleType(), []string{"cc_test_library", "android_test", "cc_benchmark", "cc_test"}) {
144		return
145	}
146	for _, name := range notFrozen {
147		ctx.ModuleErrorf("%v is disallowed in release version because it is unstable, and its \"owner\" property is missing.",
148			name)
149	}
150}
151
152func reportMultipleVersionError(ctx android.BaseModuleContext, violators []string) {
153	sort.Strings(violators)
154	ctx.ModuleErrorf("depends on multiple versions of the same aidl_interface: %s", strings.Join(violators, ", "))
155	ctx.WalkDeps(func(child android.Module, parent android.Module) bool {
156		if android.InList(child.Name(), violators) {
157			ctx.ModuleErrorf("Dependency path: %s", ctx.GetPathString(true))
158			return false
159		}
160		return true
161	})
162}
163
164func checkAidlGeneratedModules(mctx android.BottomUpMutatorContext) {
165	switch mctx.Module().(type) {
166	case *java.Library:
167	case *cc.Module:
168	case *rust.Module:
169	case *aidlGenRule:
170	default:
171		return
172	}
173	if gen, ok := mctx.Module().(*aidlGenRule); ok {
174		var notFrozen []string
175		if gen.properties.NotFrozen {
176			notFrozen = []string{strings.TrimSuffix(mctx.ModuleName(), "-source")}
177		}
178		mctx.SetProvider(AidlVersionInfoProvider, AildVersionInfo{
179			notFrozen: notFrozen,
180			sourceMap: map[string]string{
181				gen.properties.BaseName + "-" + gen.properties.Lang: gen.Name(),
182			},
183		})
184		return
185	}
186	// Collect/merge AildVersionInfos from direct dependencies
187	var info AildVersionInfo
188	mctx.VisitDirectDeps(func(dep android.Module) {
189		if mctx.OtherModuleHasProvider(dep, AidlVersionInfoProvider) {
190			otherInfo := mctx.OtherModuleProvider(dep, AidlVersionInfoProvider).(AildVersionInfo)
191			if violators := info.merge(otherInfo); violators != nil {
192				reportMultipleVersionError(mctx, violators)
193			}
194		}
195	})
196	if !isAidlGeneratedModule(mctx.Module()) && len(info.notFrozen) > 0 {
197		reportUsingNotFrozenError(mctx, info.notFrozen)
198	}
199	if mctx.Failed() {
200		return
201	}
202	if info.sourceMap != nil || len(info.notFrozen) > 0 {
203		mctx.SetProvider(AidlVersionInfoProvider, info)
204	}
205}
206
207func getPaths(ctx android.ModuleContext, rawSrcs []string, root string) (srcs android.Paths, imports []string) {
208	// TODO(b/189288369): move this to android.PathsForModuleSrcSubDir(ctx, srcs, subdir)
209	for _, src := range rawSrcs {
210		if m, _ := android.SrcIsModuleWithTag(src); m != "" {
211			srcs = append(srcs, android.PathsForModuleSrc(ctx, []string{src})...)
212		} else {
213			srcs = append(srcs, android.PathsWithModuleSrcSubDir(ctx, android.PathsForModuleSrc(ctx, []string{src}), root)...)
214		}
215	}
216
217	if len(srcs) == 0 {
218		ctx.PropertyErrorf("srcs", "No sources provided in %v", root)
219	}
220
221	// gather base directories from input .aidl files
222	for _, src := range srcs {
223		if src.Ext() != ".aidl" {
224			// Silently ignore non-aidl files as some filegroups have both java and aidl files together
225			continue
226		}
227		baseDir := strings.TrimSuffix(src.String(), src.Rel())
228		baseDir = strings.TrimSuffix(baseDir, "/")
229		if baseDir != "" && !android.InList(baseDir, imports) {
230			imports = append(imports, baseDir)
231		}
232	}
233
234	return srcs, imports
235}
236
237func isRelativePath(path string) bool {
238	if path == "" {
239		return true
240	}
241	return filepath.Clean(path) == path && path != ".." &&
242		!strings.HasPrefix(path, "../") && !strings.HasPrefix(path, "/")
243}
244
245type CommonBackendProperties struct {
246	// Whether to generate code in the corresponding backend.
247	// Default: true
248	Enabled        *bool
249	Apex_available []string
250
251	// The minimum version of the sdk that the compiled artifacts will run against
252	// For native modules, the property needs to be set when a module is a part of mainline modules(APEX).
253	// Forwarded to generated java/native module.
254	Min_sdk_version *string
255}
256
257type CommonNativeBackendProperties struct {
258	CommonBackendProperties
259	// Whether to generate additional code for gathering information
260	// about the transactions.
261	// Default: false
262	Gen_log *bool
263
264	// VNDK properties for correspdoning backend.
265	cc.VndkProperties
266}
267
268type DumpApiProperties struct {
269	// Dumps without license header (assuming it is the first comment in .aidl file). Default: false
270	No_license *bool
271}
272
273type aidlInterfaceProperties struct {
274	// Vndk properties for C++/NDK libraries only (preferred to use backend-specific settings)
275	cc.VndkProperties
276
277	// How to interpret VNDK options. We only want one library in the VNDK (not multiple
278	// versions, since this would be a waste of space/unclear, and ultimately we want all
279	// code in a given release to be updated to use a specific version). By default, this
280	// puts either the latest stable version of the library or, if there is no stable
281	// version, the unstable version of the library in the VNDK. When using this field,
282	// explicitly set it to one of the values in the 'versions' field to put that version
283	// in the VNDK or set it to the next version (1 higher than this) to mean the version
284	// that will be frozen in the next update.
285	Vndk_use_version *string
286
287	// Whether the library can be installed on the vendor image.
288	Vendor_available *bool
289
290	// Whether the library can be installed on the odm image.
291	Odm_available *bool
292
293	// Whether the library can be installed on the product image.
294	Product_available *bool
295
296	// Whether the library can be installed on the recovery image.
297	Recovery_available *bool
298
299	// Whether the library can be loaded multiple times into the same process
300	Double_loadable *bool
301
302	// Whether the library can be used on host
303	Host_supported *bool
304
305	// Whether tracing should be added to the interface.
306	Gen_trace *bool
307
308	// Top level directories for includes.
309	// TODO(b/128940869): remove it if aidl_interface can depend on framework.aidl
310	Include_dirs []string
311	// Relative path for includes. By default assumes AIDL path is relative to current directory.
312	Local_include_dir string
313
314	// List of .aidl files which compose this interface.
315	Srcs []string `android:"path"`
316
317	// List of aidl_interface modules that this uses. If one of your AIDL interfaces uses an
318	// interface or parcelable from another aidl_interface, you should put its name here.
319	// It could be an aidl_interface solely or with version(such as -V1)
320	Imports []string
321
322	// Stability promise. Currently only supports "vintf".
323	// If this is unset, this corresponds to an interface with stability within
324	// this compilation context (so an interface loaded here can only be used
325	// with things compiled together, e.g. on the system.img).
326	// If this is set to "vintf", this corresponds to a stability promise: the
327	// interface must be kept stable as long as it is used.
328	Stability *string
329
330	// Deprecated: Use `versions_with_info` instead. Don't use `versions` property directly.
331	Versions []string
332
333	// Previous API versions that are now frozen. The version that is last in
334	// the list is considered as the most recent version.
335	// The struct contains both version and imports information per a version.
336	// Until versions property is removed, don't use `versions_with_info` directly.
337	Versions_with_info []struct {
338		Version string
339		Imports []string
340	}
341
342	// Use aidlInterface.getVersions()
343	VersionsInternal []string `blueprint:"mutated"`
344
345	// The minimum version of the sdk that the compiled artifacts will run against
346	// For native modules, the property needs to be set when a module is a part of mainline modules(APEX).
347	// Forwarded to generated java/native module. This can be overridden by
348	// backend.<name>.min_sdk_version.
349	Min_sdk_version *string
350
351	Backend struct {
352		// Backend of the compiler generating code for Java clients.
353		// When enabled, this creates a target called "<name>-java".
354		Java struct {
355			CommonBackendProperties
356			// Set to the version of the sdk to compile against
357			// Default: system_current
358			Sdk_version *string
359			// Whether to compile against platform APIs instead of
360			// an SDK.
361			Platform_apis *bool
362			// Whether RPC features are enabled (requires API level 32)
363			// TODO(b/175819535): enable this automatically?
364			Gen_rpc *bool
365			// Lint properties for generated java module
366			java.LintProperties
367		}
368		// Backend of the compiler generating code for C++ clients using
369		// libbinder (unstable C++ interface)
370		// When enabled, this creates a target called "<name>-cpp".
371		Cpp struct {
372			CommonNativeBackendProperties
373		}
374		// Backend of the compiler generating code for C++ clients using libbinder_ndk
375		// (stable C interface to system's libbinder) When enabled, this creates a target
376		// called "<name>-V<ver>-ndk" (for both apps and platform) and
377		// "<name>-V<ver>-ndk_platform" (for platform only).
378		// TODO(b/161456198): remove the ndk_platform backend as the ndk backend can serve
379		// the same purpose.
380		Ndk struct {
381			CommonNativeBackendProperties
382
383			// Set to the version of the sdk to compile against, for the NDK
384			// variant.
385			// Default: current
386			Sdk_version *string
387
388			// If set to false, the ndk backend is exclusive to platform and is not
389			// available to applications. Default is true (i.e. available to both
390			// applications and platform).
391			Apps_enabled *bool
392		}
393		// Backend of the compiler generating code for Rust clients.
394		// When enabled, this creates a target called "<name>-rust".
395		Rust struct {
396			CommonBackendProperties
397		}
398	}
399
400	// Marks that this interface does not need to be stable. When set to true, the build system
401	// doesn't create the API dump and require it to be updated. Default is false.
402	Unstable *bool
403
404	// Optional flags to be passed to the AIDL compiler. e.g. "-Weverything"
405	Flags []string
406
407	// --dumpapi options
408	Dumpapi DumpApiProperties
409}
410
411type aidlInterface struct {
412	android.ModuleBase
413
414	properties aidlInterfaceProperties
415
416	computedTypes []string
417
418	// list of module names that are created for this interface
419	internalModuleNames []string
420
421	// map for version to preprocessed.aidl file.
422	// There's two additional alias for versions:
423	// - ""(empty) is for ToT
424	// - "latest" is for i.latestVersion()
425	preprocessed map[string]android.WritablePath
426}
427
428func (i *aidlInterface) shouldGenerateJavaBackend() bool {
429	// explicitly true if not specified to give early warning to devs
430	return proptools.BoolDefault(i.properties.Backend.Java.Enabled, true)
431}
432
433func (i *aidlInterface) shouldGenerateCppBackend() bool {
434	// explicitly true if not specified to give early warning to devs
435	return proptools.BoolDefault(i.properties.Backend.Cpp.Enabled, true)
436}
437
438func (i *aidlInterface) shouldGenerateNdkBackend() bool {
439	// explicitly true if not specified to give early warning to devs
440	return proptools.BoolDefault(i.properties.Backend.Ndk.Enabled, true)
441}
442
443// Returns whether the ndk backend supports applications or not. Default is `true`. `false` is
444// returned when `apps_enabled` is explicitly set to false or the interface is exclusive to vendor
445// (i.e. `vendor: true`). Note that the ndk_platform backend (which will be removed in the future)
446// is not affected by this. In other words, it is always exclusive for the platform, as its name
447// clearly shows.
448func (i *aidlInterface) shouldGenerateAppNdkBackend() bool {
449	return i.shouldGenerateNdkBackend() &&
450		proptools.BoolDefault(i.properties.Backend.Ndk.Apps_enabled, true) &&
451		!i.SocSpecific()
452}
453
454func (i *aidlInterface) shouldGenerateRustBackend() bool {
455	return i.properties.Backend.Rust.Enabled != nil && *i.properties.Backend.Rust.Enabled
456}
457
458func (i *aidlInterface) minSdkVersion(lang string) *string {
459	var ver *string
460	switch lang {
461	case langCpp:
462		ver = i.properties.Backend.Cpp.Min_sdk_version
463	case langJava:
464		ver = i.properties.Backend.Java.Min_sdk_version
465	case langNdk, langNdkPlatform:
466		ver = i.properties.Backend.Ndk.Min_sdk_version
467	case langRust:
468		ver = i.properties.Backend.Rust.Min_sdk_version
469	default:
470		panic(fmt.Errorf("unsupported language backend %q\n", lang))
471	}
472	if ver == nil {
473		return i.properties.Min_sdk_version
474	}
475	return ver
476}
477
478// Dep to *-api module(aidlApi)
479type apiDepTag struct {
480	blueprint.BaseDependencyTag
481	name string
482}
483
484type importInterfaceDepTag struct {
485	blueprint.BaseDependencyTag
486	anImport string
487}
488
489type interfaceDepTag struct {
490	blueprint.BaseDependencyTag
491}
492
493var (
494	// Dep from *-source (aidlGenRule) to *-api (aidlApi)
495	apiDep = apiDepTag{name: "api"}
496	// Dep from *-api (aidlApi) to *-api (aidlApi), representing imported interfaces
497	importApiDep = apiDepTag{name: "imported-api"}
498	// Dep to original *-interface (aidlInterface)
499	interfaceDep = interfaceDepTag{}
500)
501
502func addImportedInterfaceDeps(ctx android.BottomUpMutatorContext, imports []string) {
503	for _, anImport := range imports {
504		name, _ := parseModuleWithVersion(anImport)
505		ctx.AddDependency(ctx.Module(), importInterfaceDepTag{anImport: anImport}, name+aidlInterfaceSuffix)
506	}
507}
508
509// Run custom "Deps" mutator between AIDL modules created at LoadHook stage.
510// We can't use the "DepsMutator" for these dependencies because
511// - We need to create library modules (cc/java/...) before "arch" mutator. Note that cc_library
512//   should be mutated by os/image/arch mutators as well.
513// - When creating library modules, we need to access the original interface and its imported
514//   interfaces to determine which version to use. See aidlInterface.getImportWithVersion.
515func addInterfaceDeps(mctx android.BottomUpMutatorContext) {
516	switch i := mctx.Module().(type) {
517	case *aidlInterface:
518		// In fact this isn't necessary because soong checks dependencies on undefined modules.
519		// But since aidl_interface overrides its name internally, this provides better error message.
520		for _, anImportWithVersion := range i.properties.Imports {
521			anImport, _ := parseModuleWithVersion(anImportWithVersion)
522			if !mctx.OtherModuleExists(anImport + aidlInterfaceSuffix) {
523				if !mctx.Config().AllowMissingDependencies() {
524					mctx.PropertyErrorf("imports", "Import does not exist: "+anImport)
525				}
526			}
527		}
528		if mctx.Failed() {
529			return
530		}
531		addImportedInterfaceDeps(mctx, i.properties.Imports)
532	case *aidlImplementationGenerator:
533		mctx.AddDependency(i, interfaceDep, i.properties.AidlInterfaceName+aidlInterfaceSuffix)
534		addImportedInterfaceDeps(mctx, i.properties.Imports)
535	case *rust.Module:
536		for _, props := range i.GetProperties() {
537			if sp, ok := props.(*aidlRustSourceProviderProperties); ok {
538				mctx.AddDependency(i, interfaceDep, sp.AidlInterfaceName+aidlInterfaceSuffix)
539				addImportedInterfaceDeps(mctx, sp.Imports)
540				break
541			}
542		}
543	case *aidlApi:
544		mctx.AddDependency(i, interfaceDep, i.properties.BaseName+aidlInterfaceSuffix)
545		addImportedInterfaceDeps(mctx, i.properties.Imports)
546		for _, anImport := range i.properties.Imports {
547			name, _ := parseModuleWithVersion(anImport)
548			mctx.AddDependency(i, importApiDep, name+aidlApiSuffix)
549		}
550	case *aidlGenRule:
551		mctx.AddDependency(i, interfaceDep, i.properties.BaseName+aidlInterfaceSuffix)
552		addImportedInterfaceDeps(mctx, i.properties.Imports)
553		if !proptools.Bool(i.properties.Unstable) {
554			// for checkapi timestamps
555			mctx.AddDependency(i, apiDep, i.properties.BaseName+aidlApiSuffix)
556		}
557	}
558}
559
560// checkImports checks if "import:" property is valid.
561// In fact, this isn't necessary because Soong can check/report when we add a dependency to
562// undefined/unknown module. But module names are very implementation specific and may not be easy
563// to understand. For example, when foo (with java enabled) depends on bar (with java disabled), the
564// error message would look like "foo-V2-java depends on unknown module `bar-V3-java`", which isn't
565// clear that backend.java.enabled should be turned on.
566func checkImports(mctx android.BottomUpMutatorContext) {
567	if i, ok := mctx.Module().(*aidlInterface); ok {
568		mctx.VisitDirectDeps(func(dep android.Module) {
569			tag, ok := mctx.OtherModuleDependencyTag(dep).(importInterfaceDepTag)
570			if !ok {
571				return
572			}
573			other := dep.(*aidlInterface)
574			anImport := other.ModuleBase.Name()
575			anImportWithVersion := tag.anImport
576			_, version := parseModuleWithVersion(tag.anImport)
577			if version != "" {
578				candidateVersions := concat(other.getVersions(), []string{other.nextVersion()})
579				if !android.InList(version, candidateVersions) {
580					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)
581				}
582			}
583			if i.shouldGenerateJavaBackend() && !other.shouldGenerateJavaBackend() {
584				mctx.PropertyErrorf("backend.java.enabled",
585					"Java backend not enabled in the imported AIDL interface %q", anImport)
586			}
587
588			if i.shouldGenerateCppBackend() && !other.shouldGenerateCppBackend() {
589				mctx.PropertyErrorf("backend.cpp.enabled",
590					"C++ backend not enabled in the imported AIDL interface %q", anImport)
591			}
592
593			if i.shouldGenerateNdkBackend() && !other.shouldGenerateNdkBackend() {
594				mctx.PropertyErrorf("backend.ndk.enabled",
595					"NDK backend not enabled in the imported AIDL interface %q", anImport)
596			}
597
598			if i.shouldGenerateRustBackend() && !other.shouldGenerateRustBackend() {
599				mctx.PropertyErrorf("backend.rust.enabled",
600					"Rust backend not enabled in the imported AIDL interface %q", anImport)
601			}
602		})
603	}
604}
605
606func (i *aidlInterface) checkGenTrace(mctx android.LoadHookContext) {
607	if !proptools.Bool(i.properties.Gen_trace) {
608		return
609	}
610	if i.shouldGenerateJavaBackend() && !proptools.Bool(i.properties.Backend.Java.Platform_apis) {
611		mctx.PropertyErrorf("gen_trace", "must be false when Java backend is enabled and platform_apis is false")
612	}
613}
614
615func (i *aidlInterface) checkStability(mctx android.LoadHookContext) {
616	if i.properties.Stability == nil {
617		return
618	}
619
620	if proptools.Bool(i.properties.Unstable) {
621		mctx.PropertyErrorf("stability", "must be empty when \"unstable\" is true")
622	}
623
624	// TODO(b/136027762): should we allow more types of stability (e.g. for APEX) or
625	// should we switch this flag to be something like "vintf { enabled: true }"
626	isVintf := "vintf" == proptools.String(i.properties.Stability)
627	if !isVintf {
628		mctx.PropertyErrorf("stability", "must be empty or \"vintf\"")
629	}
630}
631func (i *aidlInterface) checkVersions(mctx android.LoadHookContext) {
632	if len(i.properties.Versions) > 0 && len(i.properties.Versions_with_info) > 0 {
633		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)
634	}
635
636	if len(i.properties.Versions) > 0 {
637		i.properties.VersionsInternal = make([]string, len(i.properties.Versions))
638		copy(i.properties.VersionsInternal, i.properties.Versions)
639	} else if len(i.properties.Versions_with_info) > 0 {
640		i.properties.VersionsInternal = make([]string, len(i.properties.Versions_with_info))
641		for idx, value := range i.properties.Versions_with_info {
642			i.properties.VersionsInternal[idx] = value.Version
643			for _, im := range value.Imports {
644				if !hasVersionSuffix(im) {
645					mctx.ModuleErrorf("imports in versions_with_info must specify its version, but %s. Add a version suffix(such as %s-V1).", im, im)
646					return
647				}
648			}
649		}
650	}
651
652	versions := make(map[string]bool)
653	intVersions := make([]int, 0, len(i.getVersions()))
654	for _, ver := range i.getVersions() {
655		if _, dup := versions[ver]; dup {
656			mctx.PropertyErrorf("versions", "duplicate found", ver)
657			continue
658		}
659		versions[ver] = true
660		n, err := strconv.Atoi(ver)
661		if err != nil {
662			mctx.PropertyErrorf("versions", "%q is not an integer", ver)
663			continue
664		}
665		if n <= 0 {
666			mctx.PropertyErrorf("versions", "should be > 0, but is %v", ver)
667			continue
668		}
669		intVersions = append(intVersions, n)
670
671	}
672	if !mctx.Failed() && !sort.IntsAreSorted(intVersions) {
673		mctx.PropertyErrorf("versions", "should be sorted, but is %v", i.getVersions())
674	}
675}
676func (i *aidlInterface) checkVndkUseVersion(mctx android.LoadHookContext) {
677	if i.properties.Vndk_use_version == nil {
678		return
679	}
680	if !i.hasVersion() {
681		mctx.PropertyErrorf("vndk_use_version", "This does not make sense when no 'versions' are specified.")
682
683	}
684	if *i.properties.Vndk_use_version == i.nextVersion() {
685		return
686	}
687	for _, ver := range i.getVersions() {
688		if *i.properties.Vndk_use_version == ver {
689			return
690		}
691	}
692	mctx.PropertyErrorf("vndk_use_version", "Specified version %q does not exist", *i.properties.Vndk_use_version)
693}
694
695func (i *aidlInterface) nextVersion() string {
696	if proptools.Bool(i.properties.Unstable) {
697		return ""
698	}
699	return nextVersion(i.getVersions())
700}
701
702func nextVersion(versions []string) string {
703	if len(versions) == 0 {
704		return "1"
705	}
706	ver := versions[len(versions)-1]
707	i, err := strconv.Atoi(ver)
708	if err != nil {
709		panic(err)
710	}
711	return strconv.Itoa(i + 1)
712}
713
714func (i *aidlInterface) latestVersion() string {
715	if !i.hasVersion() {
716		return "0"
717	}
718	return i.getVersions()[len(i.getVersions())-1]
719}
720
721func (i *aidlInterface) hasVersion() bool {
722	return len(i.getVersions()) > 0
723}
724
725func (i *aidlInterface) getVersions() []string {
726	return i.properties.VersionsInternal
727}
728
729func hasVersionSuffix(moduleName string) bool {
730	hasVersionSuffix, _ := regexp.MatchString("-V\\d+$", moduleName)
731	return hasVersionSuffix
732}
733
734func parseModuleWithVersion(moduleName string) (string, string) {
735	if hasVersionSuffix(moduleName) {
736		versionIdx := strings.LastIndex(moduleName, "-V")
737		if versionIdx == -1 {
738			panic("-V must exist in this context")
739		}
740		return moduleName[:versionIdx], moduleName[versionIdx+len("-V"):]
741	}
742	return moduleName, ""
743}
744
745func trimVersionSuffixInList(moduleNames []string) []string {
746	return wrapFunc("", moduleNames, "", func(moduleName string) string {
747		moduleNameWithoutVersion, _ := parseModuleWithVersion(moduleName)
748		return moduleNameWithoutVersion
749	})
750}
751
752func aidlInterfaceHook(mctx android.LoadHookContext, i *aidlInterface) {
753	if hasVersionSuffix(i.ModuleBase.Name()) {
754		mctx.PropertyErrorf("name", "aidl_interface should not have '-V<number> suffix")
755	}
756	if !isRelativePath(i.properties.Local_include_dir) {
757		mctx.PropertyErrorf("local_include_dir", "must be relative path: "+i.properties.Local_include_dir)
758	}
759
760	i.checkStability(mctx)
761	i.checkVersions(mctx)
762	i.checkVndkUseVersion(mctx)
763	i.checkGenTrace(mctx)
764
765	if mctx.Failed() {
766		return
767	}
768
769	var libs []string
770
771	unstable := proptools.Bool(i.properties.Unstable)
772
773	if unstable {
774		if i.hasVersion() {
775			mctx.PropertyErrorf("versions", "cannot have versions for an unstable interface")
776			return
777		}
778		if i.properties.Stability != nil {
779			mctx.ModuleErrorf("unstable:true and stability:%q cannot happen at the same time", i.properties.Stability)
780			return
781		}
782	}
783
784	sdkIsFinal := !mctx.Config().DefaultAppTargetSdk(mctx).IsPreview()
785	requireFrozenNoOwner := i.Owner() == "" && (sdkIsFinal || mctx.Config().IsEnvTrue("AIDL_FROZEN_REL"))
786	requireFrozenWithOwner := i.Owner() != "" && android.InList(i.Owner(), strings.Fields(mctx.Config().Getenv("AIDL_FROZEN_OWNERS")))
787	requireFrozenByOwner := requireFrozenNoOwner || requireFrozenWithOwner
788
789	// Two different types of 'unstable' here
790	// - 'unstable: true' meaning the module is never stable
791	// - current unfrozen ToT version
792	//
793	// OEM branches may remove 'i.Owner()' here to apply the check to all interfaces, in
794	// addition to core platform interfaces. Otherwise, we rely on vts_treble_vintf_vendor_test.
795	requireFrozenVersion := !unstable && requireFrozenByOwner
796
797	// surface error early, main check is via checkUnstableModuleMutator
798	if requireFrozenVersion && !i.hasVersion() {
799		mctx.PropertyErrorf("versions", "must be set (need to be frozen) when \"unstable\" is false, PLATFORM_VERSION_CODENAME is REL, and \"owner\" property is missing.")
800	}
801
802	versions := i.getVersions()
803	nextVersion := i.nextVersion()
804	shouldGenerateLangBackendMap := map[string]bool{
805		langCpp:  i.shouldGenerateCppBackend(),
806		langNdk:  i.shouldGenerateNdkBackend(),
807		langJava: i.shouldGenerateJavaBackend(),
808		langRust: i.shouldGenerateRustBackend()}
809
810	// The ndk_platform backend is generated only when explicitly requested. This will
811	// eventually be completely removed the devices in the long tail are gone.
812	if mctx.DeviceConfig().GenerateAidlNdkPlatformBackend() {
813		shouldGenerateLangBackendMap[langNdkPlatform] = i.shouldGenerateNdkBackend()
814	}
815
816	for lang, shouldGenerate := range shouldGenerateLangBackendMap {
817		if !shouldGenerate {
818			continue
819		}
820		libs = append(libs, addLibrary(mctx, i, nextVersion, lang, requireFrozenVersion))
821		for _, version := range versions {
822			libs = append(libs, addLibrary(mctx, i, version, lang, false))
823		}
824	}
825
826	if unstable {
827		apiDirRoot := filepath.Join(aidlApiDir, i.ModuleBase.Name())
828		aidlDumps, _ := mctx.GlobWithDeps(filepath.Join(mctx.ModuleDir(), apiDirRoot, "**/*.aidl"), nil)
829		if len(aidlDumps) != 0 {
830			mctx.PropertyErrorf("unstable", "The interface is configured as unstable, "+
831				"but API dumps exist under %q. Unstable interface cannot have dumps.", apiDirRoot)
832		}
833	} else {
834		addApiModule(mctx, i)
835	}
836
837	if proptools.Bool(i.properties.VndkProperties.Vndk.Enabled) {
838		if "vintf" != proptools.String(i.properties.Stability) {
839			mctx.PropertyErrorf("stability", "must be \"vintf\" if the module is for VNDK.")
840		}
841	}
842
843	// Reserve this module name for future use
844	mctx.CreateModule(phony.PhonyFactory, &phonyProperties{
845		Name: proptools.StringPtr(i.ModuleBase.Name()),
846	})
847
848	i.internalModuleNames = libs
849}
850
851func (i *aidlInterface) commonBackendProperties(lang string) CommonBackendProperties {
852	switch lang {
853	case langCpp:
854		return i.properties.Backend.Cpp.CommonBackendProperties
855	case langJava:
856		return i.properties.Backend.Java.CommonBackendProperties
857	case langNdk, langNdkPlatform:
858		return i.properties.Backend.Ndk.CommonBackendProperties
859	case langRust:
860		return i.properties.Backend.Rust.CommonBackendProperties
861	default:
862		panic(fmt.Errorf("unsupported language backend %q\n", lang))
863	}
864}
865
866func (i *aidlInterface) Name() string {
867	return i.ModuleBase.Name() + aidlInterfaceSuffix
868}
869
870func (i *aidlInterface) GenerateAndroidBuildActions(ctx android.ModuleContext) {
871	srcs, _ := getPaths(ctx, i.properties.Srcs, i.properties.Local_include_dir)
872	for _, src := range srcs {
873		computedType := strings.TrimSuffix(strings.ReplaceAll(src.Rel(), "/", "."), ".aidl")
874		i.computedTypes = append(i.computedTypes, computedType)
875	}
876
877	i.preprocessed = make(map[string]android.WritablePath)
878	// generate (len(versions) + 1) preprocessed.aidl files
879	for _, version := range concat(i.getVersions(), []string{i.nextVersion()}) {
880		i.preprocessed[version] = i.buildPreprocessed(ctx, version)
881	}
882	// helpful aliases
883	if !proptools.Bool(i.properties.Unstable) {
884		if i.hasVersion() {
885			i.preprocessed["latest"] = i.preprocessed[i.latestVersion()]
886		} else {
887			// when we have no frozen versions yet, use "next version" as latest
888			i.preprocessed["latest"] = i.preprocessed[i.nextVersion()]
889		}
890		i.preprocessed[""] = i.preprocessed[i.nextVersion()]
891	}
892}
893
894func (i *aidlInterface) getImportsForVersion(version string) []string {
895	// `Imports` is used when version == i.nextVersion() or`versions` is defined instead of `versions_with_info`
896	importsSrc := i.properties.Imports
897	for _, v := range i.properties.Versions_with_info {
898		if v.Version == version {
899			importsSrc = v.Imports
900			break
901		}
902	}
903	imports := make([]string, len(importsSrc))
904	copy(imports, importsSrc)
905
906	return imports
907}
908
909func (i *aidlInterface) getImports(version string) map[string]string {
910	imports := make(map[string]string)
911	imports_src := i.getImportsForVersion(version)
912
913	useLatestStable := !proptools.Bool(i.properties.Unstable) && version != "" && version != i.nextVersion()
914	for _, importString := range imports_src {
915		name, targetVersion := parseModuleWithVersion(importString)
916		if targetVersion == "" && useLatestStable {
917			targetVersion = "latest"
918		}
919		imports[name] = targetVersion
920	}
921	return imports
922}
923
924// generate preprocessed.aidl which contains only types with evaluated constants.
925// "imports" will use preprocessed.aidl with -p flag to avoid parsing the entire transitive list
926// of dependencies.
927func (i *aidlInterface) buildPreprocessed(ctx android.ModuleContext, version string) android.WritablePath {
928	deps := getDeps(ctx, i.getImports(version))
929
930	preprocessed := android.PathForModuleOut(ctx, version, "preprocessed.aidl")
931	rb := android.NewRuleBuilder(pctx, ctx)
932	srcs, root_dir := i.srcsForVersion(ctx, version)
933
934	if len(srcs) == 0 {
935		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)
936	}
937
938	paths, imports := getPaths(ctx, srcs, root_dir)
939
940	preprocessCommand := rb.Command().BuiltTool("aidl").
941		FlagWithOutput("--preprocess ", preprocessed).
942		Flag("--structured")
943	if i.properties.Stability != nil {
944		preprocessCommand.FlagWithArg("--stability ", *i.properties.Stability)
945	}
946	preprocessCommand.FlagForEachInput("-p", deps.preprocessed)
947	preprocessCommand.FlagForEachArg("-I", concat(imports, i.properties.Include_dirs))
948	preprocessCommand.Inputs(paths)
949	name := i.BaseModuleName()
950	if version != "" {
951		name += "/" + version
952	}
953	rb.Build("export_"+name, "export types for "+name)
954	return preprocessed
955}
956
957func (i *aidlInterface) DepsMutator(ctx android.BottomUpMutatorContext) {
958	ctx.AddReverseDependency(ctx.Module(), nil, aidlMetadataSingletonName)
959}
960
961func aidlInterfaceFactory() android.Module {
962	i := &aidlInterface{}
963	i.AddProperties(&i.properties)
964	android.InitAndroidModule(i)
965	android.AddLoadHook(i, func(ctx android.LoadHookContext) { aidlInterfaceHook(ctx, i) })
966	return i
967}
968