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/genrule"
21	"android/soong/java"
22	"android/soong/phony"
23
24	"fmt"
25	"io"
26	"path/filepath"
27	"strconv"
28	"strings"
29	"sync"
30
31	"github.com/google/blueprint"
32	"github.com/google/blueprint/pathtools"
33	"github.com/google/blueprint/proptools"
34)
35
36const (
37	aidlInterfaceSuffix       = "_interface"
38	aidlMetadataSingletonName = "aidl_metadata_json"
39	aidlApiDir                = "aidl_api"
40	aidlApiSuffix             = "-api"
41	langCpp                   = "cpp"
42	langJava                  = "java"
43	langNdk                   = "ndk"
44	langNdkPlatform           = "ndk_platform"
45
46	currentVersion = "current"
47)
48
49var (
50	pctx = android.NewPackageContext("android/aidl")
51
52	aidlDirPrepareRule = pctx.StaticRule("aidlDirPrepareRule", blueprint.RuleParams{
53		Command: `rm -rf "${outDir}" && mkdir -p "${outDir}" && ` +
54			`touch ${out} # ${in}`,
55		Description: "create ${out}",
56	}, "outDir")
57
58	aidlCppRule = pctx.StaticRule("aidlCppRule", blueprint.RuleParams{
59		Command: `mkdir -p "${headerDir}" && ` +
60			`${aidlCmd} --lang=${lang} ${optionalFlags} --structured --ninja -d ${out}.d ` +
61			`-h ${headerDir} -o ${outDir} ${imports} ${in}`,
62		Depfile:     "${out}.d",
63		Deps:        blueprint.DepsGCC,
64		CommandDeps: []string{"${aidlCmd}"},
65		Description: "AIDL ${lang} ${in}",
66	}, "imports", "lang", "headerDir", "outDir", "optionalFlags")
67
68	aidlJavaRule = pctx.StaticRule("aidlJavaRule", blueprint.RuleParams{
69		Command: `${aidlCmd} --lang=java ${optionalFlags} --structured --ninja -d ${out}.d ` +
70			`-o ${outDir} ${imports} ${in}`,
71		Depfile:     "${out}.d",
72		Deps:        blueprint.DepsGCC,
73		CommandDeps: []string{"${aidlCmd}"},
74		Description: "AIDL Java ${in}",
75	}, "imports", "outDir", "optionalFlags")
76
77	aidlDumpApiRule = pctx.StaticRule("aidlDumpApiRule", blueprint.RuleParams{
78		Command: `rm -rf "${outDir}" && mkdir -p "${outDir}" && ` +
79			`${aidlCmd} --dumpapi --structured ${imports} ${optionalFlags} --out ${outDir} ${in} && ` +
80			`(cd ${outDir} && find ./ -name "*.aidl" -print0 | LC_ALL=C sort -z | xargs -0 sha1sum && echo ${latestVersion}) | sha1sum | cut -d " " -f 1 > ${hashFile} `,
81		CommandDeps: []string{"${aidlCmd}"},
82	}, "optionalFlags", "imports", "outDir", "hashFile", "latestVersion")
83
84	aidlMetadataRule = pctx.StaticRule("aidlMetadataRule", blueprint.RuleParams{
85		Command: `rm -f ${out} && { ` +
86			`echo '{' && ` +
87			`echo "\"name\": \"${name}\"," && ` +
88			`echo "\"stability\": \"${stability}\"," && ` +
89			`echo "\"types\": [${types}]," && ` +
90			`echo "\"hashes\": [${hashes}]" && ` +
91			`echo '}' ` +
92			`;} >> ${out}`,
93		Description: "AIDL metadata: ${out}",
94	}, "name", "stability", "types", "hashes")
95
96	aidlDumpMappingsRule = pctx.StaticRule("aidlDumpMappingsRule", blueprint.RuleParams{
97		Command: `rm -rf "${outDir}" && mkdir -p "${outDir}" && ` +
98			`${aidlCmd} --apimapping ${outDir}/intermediate.txt ${in} ${imports} && ` +
99			`${aidlToJniCmd} ${outDir}/intermediate.txt ${out}`,
100		CommandDeps: []string{"${aidlCmd}"},
101	}, "imports", "outDir")
102
103	aidlCheckApiRule = pctx.StaticRule("aidlCheckApiRule", blueprint.RuleParams{
104		Command: `(${aidlCmd} ${optionalFlags} --checkapi ${old} ${new} && touch ${out}) || ` +
105			`(cat ${messageFile} && exit 1)`,
106		CommandDeps: []string{"${aidlCmd}"},
107		Description: "AIDL CHECK API: ${new} against ${old}",
108	}, "optionalFlags", "old", "new", "messageFile")
109
110	aidlDiffApiRule = pctx.StaticRule("aidlDiffApiRule", blueprint.RuleParams{
111		Command: `if diff -r -B -I '//.*' -x '${hashFile}' '${old}' '${new}'; then touch '${out}'; else ` +
112			`cat '${messageFile}' && exit 1; fi`,
113		Description: "Check equality of ${new} and ${old}",
114	}, "old", "new", "hashFile", "messageFile")
115
116	aidlVerifyHashRule = pctx.StaticRule("aidlVerifyHashRule", blueprint.RuleParams{
117		Command: `if [ $$(cd '${apiDir}' && { find ./ -name "*.aidl" -print0 | LC_ALL=C sort -z | xargs -0 sha1sum && echo ${version}; } | sha1sum | cut -d " " -f 1) = $$(read -r <'${hashFile}' hash extra; printf %s $$hash) ]; then ` +
118			`touch ${out}; else cat '${messageFile}' && exit 1; fi`,
119		Description: "Verify ${apiDir} files have not been modified",
120	}, "apiDir", "version", "messageFile", "hashFile")
121
122	joinJsonObjectsToArrayRule = pctx.StaticRule("joinJsonObjectsToArrayRule", blueprint.RuleParams{
123		Rspfile:        "$out.rsp",
124		RspfileContent: "$files",
125		Command: "rm -rf ${out} && " +
126			// Start the output array with an opening bracket.
127			"echo '[' >> ${out} && " +
128			// Append each input file and a comma to the output.
129			"for file in $$(cat ${out}.rsp); do " +
130			"cat $$file >> ${out}; echo ',' >> ${out}; " +
131			"done && " +
132			// Remove the last comma, replacing it with the closing bracket.
133			"sed -i '$$d' ${out} && echo ']' >> ${out}",
134		Description: "Joining JSON objects into array ${out}",
135	}, "files")
136)
137
138func init() {
139	pctx.HostBinToolVariable("aidlCmd", "aidl")
140	pctx.SourcePathVariable("aidlToJniCmd", "system/tools/aidl/build/aidl_to_jni.py")
141	android.RegisterModuleType("aidl_interface", aidlInterfaceFactory)
142	android.RegisterModuleType("aidl_mapping", aidlMappingFactory)
143	android.RegisterMakeVarsProvider(pctx, allAidlInterfacesMakeVars)
144	android.RegisterModuleType("aidl_interfaces_metadata", aidlInterfacesMetadataSingletonFactory)
145	android.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
146		ctx.BottomUp("checkUnstableModule", checkUnstableModuleMutator).Parallel()
147		ctx.BottomUp("checkDuplicatedVersions", checkDuplicatedVersions).Parallel()
148	})
149}
150
151func checkUnstableModuleMutator(mctx android.BottomUpMutatorContext) {
152	mctx.VisitDirectDepsIf(func(m android.Module) bool {
153		return android.InList(m.Name(), *unstableModules(mctx.Config()))
154	}, func(m android.Module) {
155		if mctx.ModuleName() == m.Name() {
156			return
157		}
158		// TODO(b/154066686): Replace it with a common method instead of listing up module types.
159		// Test libraries are exempted.
160		if android.InList(mctx.ModuleType(), []string{"cc_test_library", "android_test", "cc_benchmark", "cc_test"}) {
161			return
162		}
163
164		mctx.ModuleErrorf(m.Name() + " is disallowed in release version because it is unstable, and its \"owner\" property is missing.")
165	})
166}
167
168func checkDuplicatedVersions(mctx android.BottomUpMutatorContext) {
169	switch mctx.Module().(type) {
170	case *java.Library:
171	case *cc.Module:
172	default:
173		return
174	}
175
176	// First, gather all the AIDL interfaces modules that are directly or indirectly
177	// depended on by this module
178	myAidlDeps := make(map[DepInfo]bool)
179	mctx.VisitDirectDeps(func(dep android.Module) {
180		switch dep.(type) {
181		case *java.Library:
182		case *cc.Module:
183		default:
184			return
185		}
186		depName := mctx.OtherModuleName(dep)
187		// If this module dgpends on one of the aidl interface module, record it
188		for _, i := range *aidlInterfaces(mctx.Config()) {
189			if android.InList(depName, i.internalModuleNames) {
190				ifaceName := i.ModuleBase.Name()
191				verLang := depName[len(ifaceName):]
192				myAidlDeps[DepInfo{ifaceName, verLang}] = true
193				return
194			}
195		}
196		// If dep is in aidlDeps, that means dep has direct or indirect dependencies to AIDL interfaces
197		// That becomes this module's aidlDeps as well
198		aidlDepsMutex.RLock()
199		if depsOfDep, ok := aidlDeps(mctx.Config())[dep]; ok {
200			for _, d := range depsOfDep {
201				myAidlDeps[d] = true
202			}
203		}
204		aidlDepsMutex.RUnlock()
205	})
206
207	if len(myAidlDeps) == 0 {
208		// This should be usual case.
209		return
210	}
211
212	// Then, record the aidl deps of this module to the global map so that it can be used by
213	// next runs of this mutator for the modules that depend on this module.
214	var list []DepInfo
215	for d := range myAidlDeps {
216		list = append(list, d)
217	}
218	aidlDepsMutex.Lock()
219	aidlDeps(mctx.Config())[mctx.Module()] = list
220	aidlDepsMutex.Unlock()
221
222	// Lastly, report an error if there is any duplicated versions of the same interface * lang
223	for _, lang := range []string{langJava, langCpp, langNdk, langNdkPlatform} {
224		// interfaceName -> list of module names for the interface
225		versionsOf := make(map[string][]string)
226		for dep := range myAidlDeps {
227			if !strings.HasSuffix(dep.verLang, lang) {
228				continue
229			}
230			versions := versionsOf[dep.ifaceName]
231			versions = append(versions, dep.ifaceName+dep.verLang)
232			if len(versions) >= 2 {
233				mctx.ModuleErrorf("multiple versions of aidl_interface %s (backend:%s) are used: %v",
234					dep.ifaceName, lang, versions)
235			}
236			versionsOf[dep.ifaceName] = versions
237		}
238	}
239}
240
241// wrap(p, a, s) = [p + v + s for v in a]
242func wrap(prefix string, strs []string, suffix string) []string {
243	ret := make([]string, len(strs))
244	for i, v := range strs {
245		ret[i] = prefix + v + suffix
246	}
247	return ret
248}
249
250// concat(a...) = sum((i for i in a), [])
251func concat(sstrs ...[]string) []string {
252	var ret []string
253	for _, v := range sstrs {
254		ret = append(ret, v...)
255	}
256	return ret
257}
258
259func getPaths(ctx android.ModuleContext, rawSrcs []string) (paths android.Paths, imports []string) {
260	srcs := android.PathsForModuleSrc(ctx, rawSrcs)
261
262	if len(srcs) == 0 {
263		ctx.PropertyErrorf("srcs", "No sources provided.")
264	}
265
266	for _, src := range srcs {
267		if src.Ext() != ".aidl" {
268			// Silently ignore non-aidl files as some filegroups have both java and aidl files together
269			continue
270		}
271		baseDir := strings.TrimSuffix(src.String(), src.Rel())
272		if baseDir != "" && !android.InList(baseDir, imports) {
273			imports = append(imports, baseDir)
274		}
275	}
276
277	return srcs, imports
278}
279
280func isRelativePath(path string) bool {
281	if path == "" {
282		return true
283	}
284	return filepath.Clean(path) == path && path != ".." &&
285		!strings.HasPrefix(path, "../") && !strings.HasPrefix(path, "/")
286}
287
288type aidlGenProperties struct {
289	Srcs      []string `android:"path"`
290	AidlRoot  string   // base directory for the input aidl file
291	Imports   []string
292	Stability *string
293	Lang      string // target language [java|cpp|ndk]
294	BaseName  string
295	GenLog    bool
296	Version   string
297	GenTrace  bool
298	Unstable  *bool
299}
300
301type aidlGenRule struct {
302	android.ModuleBase
303
304	properties aidlGenProperties
305
306	implicitInputs android.Paths
307	importFlags    string
308
309	// TODO(b/149952131): always have a hash file
310	hashFile android.Path
311
312	genOutDir     android.ModuleGenPath
313	genHeaderDir  android.ModuleGenPath
314	genHeaderDeps android.Paths
315	genOutputs    android.WritablePaths
316}
317
318var _ android.SourceFileProducer = (*aidlGenRule)(nil)
319var _ genrule.SourceFileGenerator = (*aidlGenRule)(nil)
320
321func (g *aidlGenRule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
322	srcs, imports := getPaths(ctx, g.properties.Srcs)
323
324	if ctx.Failed() {
325		return
326	}
327
328	genDirTimestamp := android.PathForModuleGen(ctx, "timestamp")
329	g.implicitInputs = append(g.implicitInputs, genDirTimestamp)
330
331	var importPaths []string
332	importPaths = append(importPaths, imports...)
333	ctx.VisitDirectDeps(func(dep android.Module) {
334		if importedAidl, ok := dep.(*aidlInterface); ok {
335			importPaths = append(importPaths, importedAidl.properties.Full_import_paths...)
336		} else if api, ok := dep.(*aidlApi); ok {
337			// When compiling an AIDL interface, also make sure that each
338			// version of the interface is compatible with its previous version
339			for _, path := range api.checkApiTimestamps {
340				g.implicitInputs = append(g.implicitInputs, path)
341			}
342			for _, path := range api.checkHashTimestamps {
343				g.implicitInputs = append(g.implicitInputs, path)
344			}
345		}
346	})
347	g.importFlags = strings.Join(wrap("-I", importPaths, ""), " ")
348
349	g.genOutDir = android.PathForModuleGen(ctx)
350	g.genHeaderDir = android.PathForModuleGen(ctx, "include")
351	for _, src := range srcs {
352		outFile, headers := g.generateBuildActionsForSingleAidl(ctx, src)
353		g.genOutputs = append(g.genOutputs, outFile)
354		g.genHeaderDeps = append(g.genHeaderDeps, headers...)
355	}
356
357	// This is to clean genOutDir before generating any file
358	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
359		Rule:   aidlDirPrepareRule,
360		Inputs: srcs,
361		Output: genDirTimestamp,
362		Args: map[string]string{
363			"outDir": g.genOutDir.String(),
364		},
365	})
366}
367
368// baseDir is the directory where the package name starts. e.g. For an AIDL fil
369// mymodule/aidl_src/com/android/IFoo.aidl, baseDir is mymodule/aidl_src given that the package name is
370// com.android. The build system however don't know the package name without actually reading the AIDL file.
371// Therefore, we rely on the user to correctly set the base directory via following two methods:
372// 1) via the 'path' property of filegroup or
373// 2) via `local_include_dir' of the aidl_interface module.
374func getBaseDir(ctx android.ModuleContext, src android.Path, aidlRoot android.Path) string {
375	// By default, we try to get 1) by reading Rel() of the input path.
376	baseDir := strings.TrimSuffix(src.String(), src.Rel())
377	// However, if 2) is set and it's more specific (i.e. deeper) than 1), we use 2).
378	if strings.HasPrefix(aidlRoot.String(), baseDir) {
379		baseDir = aidlRoot.String()
380	}
381	return baseDir
382}
383
384func (g *aidlGenRule) generateBuildActionsForSingleAidl(ctx android.ModuleContext, src android.Path) (android.WritablePath, android.Paths) {
385	baseDir := getBaseDir(ctx, src, android.PathForModuleSrc(ctx, g.properties.AidlRoot))
386
387	var ext string
388	if g.properties.Lang == langJava {
389		ext = "java"
390	} else {
391		ext = "cpp"
392	}
393	relPath, _ := filepath.Rel(baseDir, src.String())
394	outFile := android.PathForModuleGen(ctx, pathtools.ReplaceExtension(relPath, ext))
395	implicits := g.implicitInputs
396
397	var optionalFlags []string
398	if g.properties.Version != "" {
399		optionalFlags = append(optionalFlags, "--version "+g.properties.Version)
400
401		hash := "notfrozen"
402		if !strings.HasPrefix(baseDir, ctx.Config().BuildDir()) {
403			hashFile := android.ExistentPathForSource(ctx, baseDir, ".hash")
404			if hashFile.Valid() {
405				hash = "$$(read -r <" + hashFile.Path().String() + " hash extra; printf '%s' \"$$hash\")"
406				implicits = append(implicits, hashFile.Path())
407
408				g.hashFile = hashFile.Path()
409			}
410		}
411		optionalFlags = append(optionalFlags, "--hash "+hash)
412	}
413	if g.properties.GenTrace {
414		optionalFlags = append(optionalFlags, "-t")
415	}
416	if g.properties.Stability != nil {
417		optionalFlags = append(optionalFlags, "--stability", *g.properties.Stability)
418	}
419
420	var headers android.WritablePaths
421	if g.properties.Lang == langJava {
422		ctx.ModuleBuild(pctx, android.ModuleBuildParams{
423			Rule:      aidlJavaRule,
424			Input:     src,
425			Implicits: implicits,
426			Output:    outFile,
427			Args: map[string]string{
428				"imports":       g.importFlags,
429				"outDir":        g.genOutDir.String(),
430				"optionalFlags": strings.Join(optionalFlags, " "),
431			},
432		})
433	} else {
434		typeName := strings.TrimSuffix(filepath.Base(relPath), ".aidl")
435		packagePath := filepath.Dir(relPath)
436		baseName := typeName
437		// TODO(b/111362593): aidl_to_cpp_common.cpp uses heuristics to figure out if
438		//   an interface name has a leading I. Those same heuristics have been
439		//   moved here.
440		if len(baseName) >= 2 && baseName[0] == 'I' &&
441			strings.ToUpper(baseName)[1] == baseName[1] {
442			baseName = strings.TrimPrefix(typeName, "I")
443		}
444
445		prefix := ""
446		if g.properties.Lang == langNdk || g.properties.Lang == langNdkPlatform {
447			prefix = "aidl"
448		}
449
450		headers = append(headers, g.genHeaderDir.Join(ctx, prefix, packagePath,
451			typeName+".h"))
452		headers = append(headers, g.genHeaderDir.Join(ctx, prefix, packagePath,
453			"Bp"+baseName+".h"))
454		headers = append(headers, g.genHeaderDir.Join(ctx, prefix, packagePath,
455			"Bn"+baseName+".h"))
456
457		if g.properties.GenLog {
458			optionalFlags = append(optionalFlags, "--log")
459		}
460
461		aidlLang := g.properties.Lang
462		if aidlLang == langNdkPlatform {
463			aidlLang = "ndk"
464		}
465
466		ctx.ModuleBuild(pctx, android.ModuleBuildParams{
467			Rule:            aidlCppRule,
468			Input:           src,
469			Implicits:       implicits,
470			Output:          outFile,
471			ImplicitOutputs: headers,
472			Args: map[string]string{
473				"imports":       g.importFlags,
474				"lang":          aidlLang,
475				"headerDir":     g.genHeaderDir.String(),
476				"outDir":        g.genOutDir.String(),
477				"optionalFlags": strings.Join(optionalFlags, " "),
478			},
479		})
480	}
481
482	return outFile, headers.Paths()
483}
484
485func (g *aidlGenRule) GeneratedSourceFiles() android.Paths {
486	return g.genOutputs.Paths()
487}
488
489func (g *aidlGenRule) Srcs() android.Paths {
490	return g.genOutputs.Paths()
491}
492
493func (g *aidlGenRule) GeneratedDeps() android.Paths {
494	return g.genHeaderDeps
495}
496
497func (g *aidlGenRule) GeneratedHeaderDirs() android.Paths {
498	return android.Paths{g.genHeaderDir}
499}
500
501func (g *aidlGenRule) DepsMutator(ctx android.BottomUpMutatorContext) {
502	ctx.AddDependency(ctx.Module(), nil, wrap("", g.properties.Imports, aidlInterfaceSuffix)...)
503	if !proptools.Bool(g.properties.Unstable) {
504		ctx.AddDependency(ctx.Module(), nil, g.properties.BaseName+aidlApiSuffix)
505	}
506
507	ctx.AddReverseDependency(ctx.Module(), nil, aidlMetadataSingletonName)
508}
509
510func aidlGenFactory() android.Module {
511	g := &aidlGenRule{}
512	g.AddProperties(&g.properties)
513	android.InitAndroidModule(g)
514	return g
515}
516
517type aidlApiProperties struct {
518	BaseName  string
519	Srcs      []string `android:"path"`
520	AidlRoot  string   // base directory for the input aidl file
521	Stability *string
522	Imports   []string
523	Versions  []string
524}
525
526type aidlApi struct {
527	android.ModuleBase
528
529	properties aidlApiProperties
530
531	// for triggering api check for version X against version X-1
532	checkApiTimestamps android.WritablePaths
533
534	// for triggering updating current API
535	updateApiTimestamp android.WritablePath
536
537	// for triggering check that files have not been modified
538	checkHashTimestamps android.WritablePaths
539
540	// for triggering freezing API as the new version
541	freezeApiTimestamp android.WritablePath
542}
543
544func (m *aidlApi) apiDir() string {
545	return filepath.Join(aidlApiDir, m.properties.BaseName)
546}
547
548// `m <iface>-freeze-api` will freeze ToT as this version
549func (m *aidlApi) nextVersion(ctx android.ModuleContext) string {
550	if len(m.properties.Versions) == 0 {
551		return "1"
552	} else {
553		latestVersion := m.properties.Versions[len(m.properties.Versions)-1]
554
555		i, err := strconv.Atoi(latestVersion)
556		if err != nil {
557			panic(err)
558		}
559
560		return strconv.Itoa(i + 1)
561	}
562}
563
564type apiDump struct {
565	dir      android.Path
566	files    android.Paths
567	hashFile android.OptionalPath
568}
569
570func (m *aidlApi) createApiDumpFromSource(ctx android.ModuleContext) apiDump {
571	srcs, imports := getPaths(ctx, m.properties.Srcs)
572
573	if ctx.Failed() {
574		return apiDump{}
575	}
576
577	var importPaths []string
578	importPaths = append(importPaths, imports...)
579	ctx.VisitDirectDeps(func(dep android.Module) {
580		if importedAidl, ok := dep.(*aidlInterface); ok {
581			importPaths = append(importPaths, importedAidl.properties.Full_import_paths...)
582		}
583	})
584
585	var apiDir android.WritablePath
586	var apiFiles android.WritablePaths
587	var hashFile android.WritablePath
588
589	apiDir = android.PathForModuleOut(ctx, "dump")
590	aidlRoot := android.PathForModuleSrc(ctx, m.properties.AidlRoot)
591	for _, src := range srcs {
592		baseDir := getBaseDir(ctx, src, aidlRoot)
593		relPath, _ := filepath.Rel(baseDir, src.String())
594		outFile := android.PathForModuleOut(ctx, "dump", relPath)
595		apiFiles = append(apiFiles, outFile)
596	}
597	hashFile = android.PathForModuleOut(ctx, "dump", ".hash")
598	latestVersion := "latest-version"
599	if len(m.properties.Versions) >= 1 {
600		latestVersion = m.properties.Versions[len(m.properties.Versions)-1]
601	}
602
603	var optionalFlags []string
604	if m.properties.Stability != nil {
605		optionalFlags = append(optionalFlags, "--stability", *m.properties.Stability)
606	}
607
608	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
609		Rule:    aidlDumpApiRule,
610		Outputs: append(apiFiles, hashFile),
611		Inputs:  srcs,
612		Args: map[string]string{
613			"optionalFlags": strings.Join(optionalFlags, " "),
614			"imports":       strings.Join(wrap("-I", importPaths, ""), " "),
615			"outDir":        apiDir.String(),
616			"hashFile":      hashFile.String(),
617			"latestVersion": latestVersion,
618		},
619	})
620	return apiDump{apiDir, apiFiles.Paths(), android.OptionalPathForPath(hashFile)}
621}
622
623func (m *aidlApi) makeApiDumpAsVersion(ctx android.ModuleContext, dump apiDump, version string) android.WritablePath {
624	timestampFile := android.PathForModuleOut(ctx, "updateapi_"+version+".timestamp")
625
626	modulePath := android.PathForModuleSrc(ctx).String()
627
628	targetDir := filepath.Join(modulePath, m.apiDir(), version)
629	rb := android.NewRuleBuilder()
630	// Wipe the target directory and then copy the API dump into the directory
631	rb.Command().Text("mkdir -p " + targetDir)
632	rb.Command().Text("rm -rf " + targetDir + "/*")
633	if version != currentVersion {
634		rb.Command().Text("cp -rf " + dump.dir.String() + "/. " + targetDir).Implicits(dump.files)
635		// If this is making a new frozen (i.e. non-current) version of the interface,
636		// modify Android.bp file to add the new version to the 'versions' property.
637		rb.Command().BuiltTool(ctx, "bpmodify").
638			Text("-w -m " + m.properties.BaseName).
639			Text("-parameter versions -a " + version).
640			Text(android.PathForModuleSrc(ctx, "Android.bp").String())
641	} else {
642		// In this case (unfrozen interface), don't copy .hash
643		rb.Command().Text("cp -rf " + dump.dir.String() + "/* " + targetDir).Implicits(dump.files)
644	}
645	rb.Command().Text("touch").Output(timestampFile)
646
647	rb.Build(pctx, ctx, "dump_aidl_api"+m.properties.BaseName+"_"+version,
648		"Making AIDL API of "+m.properties.BaseName+" as version "+version)
649	return timestampFile
650}
651
652func (m *aidlApi) checkCompatibility(ctx android.ModuleContext, oldDump apiDump, newDump apiDump) android.WritablePath {
653	newVersion := newDump.dir.Base()
654	timestampFile := android.PathForModuleOut(ctx, "checkapi_"+newVersion+".timestamp")
655	messageFile := android.PathForSource(ctx, "system/tools/aidl/build/message_check_compatibility.txt")
656
657	var optionalFlags []string
658	if m.properties.Stability != nil {
659		optionalFlags = append(optionalFlags, "--stability", *m.properties.Stability)
660	}
661
662	var implicits android.Paths
663	implicits = append(implicits, oldDump.files...)
664	implicits = append(implicits, newDump.files...)
665	implicits = append(implicits, messageFile)
666	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
667		Rule:      aidlCheckApiRule,
668		Implicits: implicits,
669		Output:    timestampFile,
670		Args: map[string]string{
671			"optionalFlags": strings.Join(optionalFlags, " "),
672			"old":           oldDump.dir.String(),
673			"new":           newDump.dir.String(),
674			"messageFile":   messageFile.String(),
675		},
676	})
677	return timestampFile
678}
679
680func (m *aidlApi) checkEquality(ctx android.ModuleContext, oldDump apiDump, newDump apiDump) android.WritablePath {
681	newVersion := newDump.dir.Base()
682	timestampFile := android.PathForModuleOut(ctx, "checkapi_"+newVersion+".timestamp")
683
684	// Use different messages depending on whether platform SDK is finalized or not.
685	// In case when it is finalized, we should never allow updating the already frozen API.
686	// If it's not finalized, we let users to update the current version by invoking
687	// `m <name>-update-api`.
688	messageFile := android.PathForSource(ctx, "system/tools/aidl/build/message_check_equality.txt")
689	sdkIsFinal := ctx.Config().DefaultAppTargetSdkInt() != android.FutureApiLevel
690	if sdkIsFinal {
691		messageFile = android.PathForSource(ctx, "system/tools/aidl/build/message_check_equality_release.txt")
692	}
693	formattedMessageFile := android.PathForModuleOut(ctx, "message_check_equality.txt")
694	rb := android.NewRuleBuilder()
695	rb.Command().Text("sed").Flag(" s/%s/" + m.properties.BaseName + "/g ").Input(messageFile).Text(" > ").Output(formattedMessageFile)
696	rb.Build(pctx, ctx, "format_message_"+m.properties.BaseName, "")
697
698	var implicits android.Paths
699	implicits = append(implicits, oldDump.files...)
700	implicits = append(implicits, newDump.files...)
701	implicits = append(implicits, formattedMessageFile)
702	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
703		Rule:      aidlDiffApiRule,
704		Implicits: implicits,
705		Output:    timestampFile,
706		Args: map[string]string{
707			"old":         oldDump.dir.String(),
708			"new":         newDump.dir.String(),
709			"hashFile":    newDump.hashFile.Path().Base(),
710			"messageFile": formattedMessageFile.String(),
711		},
712	})
713	return timestampFile
714}
715
716func (m *aidlApi) checkIntegrity(ctx android.ModuleContext, dump apiDump) android.WritablePath {
717	version := dump.dir.Base()
718	timestampFile := android.PathForModuleOut(ctx, "checkhash_"+version+".timestamp")
719	messageFile := android.PathForSource(ctx, "system/tools/aidl/build/message_check_integrity.txt")
720
721	i, _ := strconv.Atoi(version)
722	if i == 1 {
723		version = "latest-version"
724	} else {
725		version = strconv.Itoa(i - 1)
726	}
727
728	var implicits android.Paths
729	implicits = append(implicits, dump.files...)
730	implicits = append(implicits, dump.hashFile.Path())
731	implicits = append(implicits, messageFile)
732	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
733		Rule:      aidlVerifyHashRule,
734		Implicits: implicits,
735		Output:    timestampFile,
736		Args: map[string]string{
737			"apiDir":      dump.dir.String(),
738			"version":     version,
739			"hashFile":    dump.hashFile.Path().String(),
740			"messageFile": messageFile.String(),
741		},
742	})
743	return timestampFile
744}
745
746func (m *aidlApi) GenerateAndroidBuildActions(ctx android.ModuleContext) {
747	// An API dump is created from source and it is compared against the API dump of the
748	// 'current' (yet-to-be-finalized) version. By checking this we enforce that any change in
749	// the AIDL interface is gated by the AIDL API review even before the interface is frozen as
750	// a new version.
751	totApiDump := m.createApiDumpFromSource(ctx)
752	currentApiDir := android.ExistentPathForSource(ctx, ctx.ModuleDir(), m.apiDir(), currentVersion)
753	var currentApiDump apiDump
754	if currentApiDir.Valid() {
755		currentApiDump = apiDump{
756			dir:      currentApiDir.Path(),
757			files:    ctx.Glob(filepath.Join(currentApiDir.Path().String(), "**/*.aidl"), nil),
758			hashFile: android.ExistentPathForSource(ctx, ctx.ModuleDir(), m.apiDir(), currentVersion, ".hash"),
759		}
760		checked := m.checkEquality(ctx, currentApiDump, totApiDump)
761		m.checkApiTimestamps = append(m.checkApiTimestamps, checked)
762	} else {
763		// The "current" directory might not exist, in case when the interface is first created.
764		// Instruct user to create one by executing `m <name>-update-api`.
765		rb := android.NewRuleBuilder()
766		ifaceName := m.properties.BaseName
767		rb.Command().Text(fmt.Sprintf(`echo "API dump for the current version of AIDL interface %s does not exist."`, ifaceName))
768		rb.Command().Text(fmt.Sprintf(`echo Run "m %s-update-api", or add "unstable: true" to the build rule `+
769			`for the interface if it does not need to be versioned`, ifaceName))
770		// This file will never be created. Otherwise, the build will pass simply by running 'm; m'.
771		alwaysChecked := android.PathForModuleOut(ctx, "checkapi_current.timestamp")
772		rb.Command().Text("false").ImplicitOutput(alwaysChecked)
773		rb.Build(pctx, ctx, "check_current_aidl_api", "")
774		m.checkApiTimestamps = append(m.checkApiTimestamps, alwaysChecked)
775	}
776
777	// Also check that version X is backwards compatible with version X-1.
778	// "current" is checked against the latest version.
779	var dumps []apiDump
780	for _, ver := range m.properties.Versions {
781		apiDir := filepath.Join(ctx.ModuleDir(), m.apiDir(), ver)
782		apiDirPath := android.ExistentPathForSource(ctx, apiDir)
783		if apiDirPath.Valid() {
784			dumps = append(dumps, apiDump{
785				dir:      apiDirPath.Path(),
786				files:    ctx.Glob(filepath.Join(apiDirPath.String(), "**/*.aidl"), nil),
787				hashFile: android.ExistentPathForSource(ctx, ctx.ModuleDir(), m.apiDir(), ver, ".hash"),
788			})
789		} else if ctx.Config().AllowMissingDependencies() {
790			ctx.AddMissingDependencies([]string{apiDir})
791		} else {
792			ctx.ModuleErrorf("API version %s path %s does not exist", ver, apiDir)
793		}
794	}
795	if currentApiDir.Valid() {
796		dumps = append(dumps, currentApiDump)
797	}
798	for i, _ := range dumps {
799		if dumps[i].hashFile.Valid() {
800			checkHashTimestamp := m.checkIntegrity(ctx, dumps[i])
801			m.checkHashTimestamps = append(m.checkHashTimestamps, checkHashTimestamp)
802		}
803
804		if i == 0 {
805			continue
806		}
807		checked := m.checkCompatibility(ctx, dumps[i-1], dumps[i])
808		m.checkApiTimestamps = append(m.checkApiTimestamps, checked)
809	}
810
811	// API dump from source is updated to the 'current' version. Triggered by `m <name>-update-api`
812	m.updateApiTimestamp = m.makeApiDumpAsVersion(ctx, totApiDump, currentVersion)
813
814	// API dump from source is frozen as the next stable version. Triggered by `m <name>-freeze-api`
815	nextVersion := m.nextVersion(ctx)
816	m.freezeApiTimestamp = m.makeApiDumpAsVersion(ctx, totApiDump, nextVersion)
817}
818
819func (m *aidlApi) AndroidMk() android.AndroidMkData {
820	return android.AndroidMkData{
821		Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
822			android.WriteAndroidMkData(w, data)
823			targetName := m.properties.BaseName + "-freeze-api"
824			fmt.Fprintln(w, ".PHONY:", targetName)
825			fmt.Fprintln(w, targetName+":", m.freezeApiTimestamp.String())
826
827			targetName = m.properties.BaseName + "-update-api"
828			fmt.Fprintln(w, ".PHONY:", targetName)
829			fmt.Fprintln(w, targetName+":", m.updateApiTimestamp.String())
830		},
831	}
832}
833
834func (m *aidlApi) DepsMutator(ctx android.BottomUpMutatorContext) {
835	ctx.AddDependency(ctx.Module(), nil, wrap("", m.properties.Imports, aidlInterfaceSuffix)...)
836}
837
838func aidlApiFactory() android.Module {
839	m := &aidlApi{}
840	m.AddProperties(&m.properties)
841	android.InitAndroidModule(m)
842	return m
843}
844
845type CommonBackendProperties struct {
846	// Whether to generate code in the corresponding backend.
847	// Default: true
848	Enabled        *bool
849	Apex_available []string
850
851	// The minimum version of the sdk that the compiled artifacts will run against
852	// For native modules, the property needs to be set when a module is a part of mainline modules(APEX).
853	// Forwarded to generated java/native module.
854	Min_sdk_version *string
855}
856
857type CommonNativeBackendProperties struct {
858	CommonBackendProperties
859	// Whether to generate additional code for gathering information
860	// about the transactions.
861	// Default: false
862	Gen_log *bool
863
864	// VNDK properties for correspdoning backend.
865	cc.VndkProperties
866}
867
868type aidlInterfaceProperties struct {
869	// Vndk properties for C++/NDK libraries only (preferred to use backend-specific settings)
870	cc.VndkProperties
871
872	// Whether the library can be installed on the vendor image.
873	Vendor_available *bool
874
875	// Whether the library can be used on host
876	Host_supported *bool
877
878	// Whether tracing should be added to the interface.
879	Gen_trace *bool
880
881	// Top level directories for includes.
882	// TODO(b/128940869): remove it if aidl_interface can depend on framework.aidl
883	Include_dirs []string
884	// Relative path for includes. By default assumes AIDL path is relative to current directory.
885	Local_include_dir string
886
887	// List of .aidl files which compose this interface.
888	Srcs []string `android:"path"`
889
890	// List of aidl_interface modules that this uses. If one of your AIDL interfaces uses an
891	// interface or parcelable from another aidl_interface, you should put its name here.
892	Imports []string
893
894	// Used by gen dependency to fill out aidl include path
895	Full_import_paths []string `blueprint:"mutated"`
896
897	// Stability promise. Currently only supports "vintf".
898	// If this is unset, this corresponds to an interface with stability within
899	// this compilation context (so an interface loaded here can only be used
900	// with things compiled together, e.g. on the system.img).
901	// If this is set to "vintf", this corresponds to a stability promise: the
902	// interface must be kept stable as long as it is used.
903	Stability *string
904
905	// Previous API versions that are now frozen. The version that is last in
906	// the list is considered as the most recent version.
907	Versions []string
908
909	Backend struct {
910		// Backend of the compiler generating code for Java clients.
911		// When enabled, this creates a target called "<name>-java".
912		Java struct {
913			CommonBackendProperties
914			// Set to the version of the sdk to compile against
915			// Default: system_current
916			Sdk_version *string
917			// Whether to compile against platform APIs instead of
918			// an SDK.
919			Platform_apis *bool
920		}
921		// Backend of the compiler generating code for C++ clients using
922		// libbinder (unstable C++ interface)
923		// When enabled, this creates a target called "<name>-cpp".
924		Cpp struct {
925			CommonNativeBackendProperties
926		}
927		// Backend of the compiler generating code for C++ clients using
928		// libbinder_ndk (stable C interface to system's libbinder)
929		// When enabled, this creates a target called "<name>-ndk"
930		// (for apps) and "<name>-ndk_platform" (for platform usage).
931		Ndk struct {
932			CommonNativeBackendProperties
933		}
934	}
935
936	// Marks that this interface does not need to be stable. When set to true, the build system
937	// doesn't create the API dump and require it to be updated. Default is false.
938	Unstable *bool
939}
940
941type aidlInterface struct {
942	android.ModuleBase
943
944	properties aidlInterfaceProperties
945
946	computedTypes []string
947
948	// list of module names that are created for this interface
949	internalModuleNames []string
950}
951
952func (i *aidlInterface) shouldGenerateJavaBackend() bool {
953	// explicitly true if not specified to give early warning to devs
954	return i.properties.Backend.Java.Enabled == nil || *i.properties.Backend.Java.Enabled
955}
956
957func (i *aidlInterface) shouldGenerateCppBackend() bool {
958	// explicitly true if not specified to give early warning to devs
959	return i.properties.Backend.Cpp.Enabled == nil || *i.properties.Backend.Cpp.Enabled
960}
961
962func (i *aidlInterface) shouldGenerateNdkBackend() bool {
963	// explicitly true if not specified to give early warning to devs
964	return i.properties.Backend.Ndk.Enabled == nil || *i.properties.Backend.Ndk.Enabled
965}
966
967func (i *aidlInterface) gatherInterface(mctx android.LoadHookContext) {
968	aidlInterfaces := aidlInterfaces(mctx.Config())
969	aidlInterfaceMutex.Lock()
970	defer aidlInterfaceMutex.Unlock()
971	*aidlInterfaces = append(*aidlInterfaces, i)
972}
973
974func addUnstableModule(mctx android.LoadHookContext, moduleName string) {
975	unstableModules := unstableModules(mctx.Config())
976	unstableModuleMutex.Lock()
977	defer unstableModuleMutex.Unlock()
978	*unstableModules = append(*unstableModules, moduleName)
979}
980
981func (i *aidlInterface) checkImports(mctx android.BaseModuleContext) {
982	for _, anImport := range i.properties.Imports {
983		other := lookupInterface(anImport, mctx.Config())
984
985		if other == nil {
986			mctx.PropertyErrorf("imports", "Import does not exist: "+anImport)
987		}
988
989		if i.shouldGenerateJavaBackend() && !other.shouldGenerateJavaBackend() {
990			mctx.PropertyErrorf("backend.java.enabled",
991				"Java backend not enabled in the imported AIDL interface %q", anImport)
992		}
993
994		if i.shouldGenerateCppBackend() && !other.shouldGenerateCppBackend() {
995			mctx.PropertyErrorf("backend.cpp.enabled",
996				"C++ backend not enabled in the imported AIDL interface %q", anImport)
997		}
998
999		if i.shouldGenerateNdkBackend() && !other.shouldGenerateNdkBackend() {
1000			mctx.PropertyErrorf("backend.ndk.enabled",
1001				"NDK backend not enabled in the imported AIDL interface %q", anImport)
1002		}
1003	}
1004}
1005
1006func (i *aidlInterface) checkGenTrace(mctx android.LoadHookContext) {
1007	if !proptools.Bool(i.properties.Gen_trace) {
1008		return
1009	}
1010	if i.shouldGenerateJavaBackend() && !proptools.Bool(i.properties.Backend.Java.Platform_apis) {
1011		mctx.PropertyErrorf("gen_trace", "must be false when Java backend is enabled and platform_apis is false")
1012	}
1013}
1014
1015func (i *aidlInterface) checkStability(mctx android.LoadHookContext) {
1016	if i.properties.Stability == nil {
1017		return
1018	}
1019
1020	if proptools.Bool(i.properties.Unstable) {
1021		mctx.PropertyErrorf("stability", "must be empty when \"unstable\" is true")
1022	}
1023
1024	// TODO(b/136027762): should we allow more types of stability (e.g. for APEX) or
1025	// should we switch this flag to be something like "vintf { enabled: true }"
1026	isVintf := "vintf" == proptools.String(i.properties.Stability)
1027	if !isVintf {
1028		mctx.PropertyErrorf("stability", "must be empty or \"vintf\"")
1029	}
1030}
1031func (i *aidlInterface) checkVersions(mctx android.LoadHookContext) {
1032	for _, ver := range i.properties.Versions {
1033		_, err := strconv.Atoi(ver)
1034		if err != nil {
1035			mctx.PropertyErrorf("versions", "%q is not an integer", ver)
1036			continue
1037		}
1038	}
1039}
1040
1041func (i *aidlInterface) currentVersion(ctx android.LoadHookContext) string {
1042	if !i.hasVersion() {
1043		return ""
1044	} else {
1045		ver := i.latestVersion()
1046		i, err := strconv.Atoi(ver)
1047		if err != nil {
1048			panic(err)
1049		}
1050
1051		return strconv.Itoa(i + 1)
1052	}
1053}
1054
1055func (i *aidlInterface) latestVersion() string {
1056	if !i.hasVersion() {
1057		return "0"
1058	}
1059	return i.properties.Versions[len(i.properties.Versions)-1]
1060}
1061func (i *aidlInterface) isLatestVersion(version string) bool {
1062	if !i.hasVersion() {
1063		return true
1064	}
1065	return version == i.latestVersion()
1066}
1067func (i *aidlInterface) hasVersion() bool {
1068	return len(i.properties.Versions) > 0
1069}
1070
1071// This function returns module name with version. Assume that there is foo of which latest version is 2
1072// Version -> Module name
1073// "1"->foo-V1
1074// "2"->foo-V2
1075// "3"(unfrozen)->foo-unstable
1076// ""-> foo
1077func (i *aidlInterface) versionedName(ctx android.LoadHookContext, version string) string {
1078	name := i.ModuleBase.Name()
1079	if version == "" {
1080		return name
1081	}
1082	if version == i.currentVersion(ctx) {
1083		return name + "-unstable"
1084	}
1085	return name + "-V" + version
1086}
1087
1088// This function returns C++ artifact's name. Mostly, it returns same as versionedName(),
1089// But, it returns different value only if it is the case below.
1090// Assume that there is foo of which latest version is 2
1091// foo-unstable -> foo-V3
1092// foo -> foo-V2 (latest frozen version)
1093// Assume that there is bar of which version hasn't been defined yet.
1094// bar -> bar-V1
1095func (i *aidlInterface) cppOutputName(version string) string {
1096	name := i.ModuleBase.Name()
1097	// Even if the module doesn't have version, it returns with version(-V1)
1098	if !i.hasVersion() {
1099		// latestVersion() always returns "0"
1100		i, err := strconv.Atoi(i.latestVersion())
1101		if err != nil {
1102			panic(err)
1103		}
1104		return name + "-V" + strconv.Itoa(i+1)
1105	}
1106	if version == "" {
1107		version = i.latestVersion()
1108	}
1109	return name + "-V" + version
1110}
1111
1112func (i *aidlInterface) srcsForVersion(mctx android.LoadHookContext, version string) (srcs []string, aidlRoot string) {
1113	if version == i.currentVersion(mctx) {
1114		return i.properties.Srcs, i.properties.Local_include_dir
1115	} else {
1116		aidlRoot = filepath.Join(aidlApiDir, i.ModuleBase.Name(), version)
1117		full_paths, err := mctx.GlobWithDeps(filepath.Join(mctx.ModuleDir(), aidlRoot, "**/*.aidl"), nil)
1118		if err != nil {
1119			panic(err)
1120		}
1121		for _, path := range full_paths {
1122			// Here, we need path local to the module
1123			srcs = append(srcs, strings.TrimPrefix(path, mctx.ModuleDir()+"/"))
1124		}
1125		return srcs, aidlRoot
1126	}
1127}
1128
1129func aidlInterfaceHook(mctx android.LoadHookContext, i *aidlInterface) {
1130	if !isRelativePath(i.properties.Local_include_dir) {
1131		mctx.PropertyErrorf("local_include_dir", "must be relative path: "+i.properties.Local_include_dir)
1132	}
1133	var importPaths []string
1134	importPaths = append(importPaths, filepath.Join(mctx.ModuleDir(), i.properties.Local_include_dir))
1135	importPaths = append(importPaths, i.properties.Include_dirs...)
1136
1137	i.properties.Full_import_paths = importPaths
1138
1139	i.gatherInterface(mctx)
1140	i.checkStability(mctx)
1141	i.checkVersions(mctx)
1142	i.checkGenTrace(mctx)
1143
1144	if mctx.Failed() {
1145		return
1146	}
1147
1148	var libs []string
1149
1150	currentVersion := i.currentVersion(mctx)
1151
1152	versionsForCpp := make([]string, len(i.properties.Versions))
1153
1154	sdkIsFinal := mctx.Config().DefaultAppTargetSdkInt() != android.FutureApiLevel
1155
1156	needToCheckUnstableVersion := sdkIsFinal && i.hasVersion() && i.Owner() == ""
1157	copy(versionsForCpp, i.properties.Versions)
1158	if i.hasVersion() {
1159		// In C++ library, AIDL doesn't create the module of which name is with latest version,
1160		// instead of it, there is a module without version.
1161		versionsForCpp[len(i.properties.Versions)-1] = ""
1162	}
1163	if i.shouldGenerateCppBackend() {
1164		unstableLib := addCppLibrary(mctx, i, currentVersion, langCpp)
1165		if needToCheckUnstableVersion {
1166			addUnstableModule(mctx, unstableLib)
1167		}
1168		libs = append(libs, unstableLib)
1169		for _, version := range versionsForCpp {
1170			libs = append(libs, addCppLibrary(mctx, i, version, langCpp))
1171		}
1172	}
1173
1174	if i.shouldGenerateNdkBackend() {
1175		if !proptools.Bool(i.properties.Vendor_available) {
1176			unstableLib := addCppLibrary(mctx, i, currentVersion, langNdk)
1177			if needToCheckUnstableVersion {
1178				addUnstableModule(mctx, unstableLib)
1179			}
1180			libs = append(libs, unstableLib)
1181			for _, version := range versionsForCpp {
1182				libs = append(libs, addCppLibrary(mctx, i, version, langNdk))
1183			}
1184		}
1185		// TODO(b/121157555): combine with '-ndk' variant
1186		unstableLib := addCppLibrary(mctx, i, currentVersion, langNdkPlatform)
1187		if needToCheckUnstableVersion {
1188			addUnstableModule(mctx, unstableLib)
1189		}
1190		libs = append(libs, unstableLib)
1191		for _, version := range versionsForCpp {
1192			libs = append(libs, addCppLibrary(mctx, i, version, langNdkPlatform))
1193		}
1194	}
1195	versionsForJava := i.properties.Versions
1196	if i.hasVersion() {
1197		versionsForJava = append(i.properties.Versions, "")
1198	}
1199	if i.shouldGenerateJavaBackend() {
1200		unstableLib := addJavaLibrary(mctx, i, currentVersion)
1201		if needToCheckUnstableVersion {
1202			addUnstableModule(mctx, unstableLib)
1203		}
1204		libs = append(libs, unstableLib)
1205		for _, version := range versionsForJava {
1206			libs = append(libs, addJavaLibrary(mctx, i, version))
1207		}
1208	}
1209
1210	if proptools.Bool(i.properties.Unstable) {
1211		if i.hasVersion() {
1212			mctx.PropertyErrorf("versions", "cannot have versions for an unstable interface")
1213		}
1214		apiDirRoot := filepath.Join(aidlApiDir, i.ModuleBase.Name())
1215		aidlDumps, _ := mctx.GlobWithDeps(filepath.Join(mctx.ModuleDir(), apiDirRoot, "**/*.aidl"), nil)
1216		if len(aidlDumps) != 0 {
1217			mctx.PropertyErrorf("unstable", "The interface is configured as unstable, "+
1218				"but API dumps exist under %q. Unstable interface cannot have dumps.", apiDirRoot)
1219		}
1220		if i.properties.Stability != nil {
1221			mctx.ModuleErrorf("unstable:true and stability:%q cannot happen at the same time", i.properties.Stability)
1222		}
1223	} else {
1224		sdkIsFinal := mctx.Config().DefaultAppTargetSdkInt() != android.FutureApiLevel
1225		if sdkIsFinal && !i.hasVersion() && i.Owner() == "" {
1226			mctx.PropertyErrorf("versions", "must be set (need to be frozen) when \"unstable\" is false, PLATFORM_VERSION_CODENAME is REL, and \"owner\" property is missing.")
1227		}
1228		addApiModule(mctx, i)
1229	}
1230
1231	// Reserve this module name for future use
1232	mctx.CreateModule(phony.PhonyFactory, &phonyProperties{
1233		Name:     proptools.StringPtr(i.ModuleBase.Name()),
1234		Required: libs,
1235	})
1236
1237	i.internalModuleNames = libs
1238}
1239
1240func addCppLibrary(mctx android.LoadHookContext, i *aidlInterface, version string, lang string) string {
1241	cppSourceGen := i.versionedName(mctx, version) + "-" + lang + "-source"
1242	cppModuleGen := i.versionedName(mctx, version) + "-" + lang
1243	cppOutputGen := i.cppOutputName(version) + "-" + lang
1244	if i.hasVersion() && version == "" {
1245		version = i.latestVersion()
1246	}
1247	srcs, aidlRoot := i.srcsForVersion(mctx, version)
1248	if len(srcs) == 0 {
1249		// This can happen when the version is about to be frozen; the version
1250		// directory is created but API dump hasn't been copied there.
1251		// Don't create a library for the yet-to-be-frozen version.
1252		return ""
1253	}
1254
1255	// For an interface with no versions, this is the ToT interface.
1256	// For an interface w/ versions, this is that latest version.
1257	isLatest := !i.hasVersion() || version == i.latestVersion()
1258
1259	var overrideVndkProperties cc.VndkProperties
1260	if !isLatest {
1261		// We only want the VNDK to include the latest interface. For interfaces in
1262		// development, they will be frozen, so we put their latest version in the
1263		// VNDK. For interfaces which are already frozen, we put their latest version
1264		// in the VNDK, and when that version is frozen, the version in the VNDK can
1265		// be updated. Otherwise, we remove this library from the VNDK, to avoid adding
1266		// multiple versions of the same library to the VNDK.
1267		overrideVndkProperties.Vndk.Enabled = proptools.BoolPtr(false)
1268		overrideVndkProperties.Vndk.Support_system_process = proptools.BoolPtr(false)
1269	}
1270
1271	var commonProperties *CommonNativeBackendProperties
1272	if lang == langCpp {
1273		commonProperties = &i.properties.Backend.Cpp.CommonNativeBackendProperties
1274	} else if lang == langNdk || lang == langNdkPlatform {
1275		commonProperties = &i.properties.Backend.Ndk.CommonNativeBackendProperties
1276	}
1277
1278	genLog := proptools.Bool(commonProperties.Gen_log)
1279	genTrace := proptools.Bool(i.properties.Gen_trace)
1280
1281	mctx.CreateModule(aidlGenFactory, &nameProperties{
1282		Name: proptools.StringPtr(cppSourceGen),
1283	}, &aidlGenProperties{
1284		Srcs:      srcs,
1285		AidlRoot:  aidlRoot,
1286		Imports:   concat(i.properties.Imports, []string{i.ModuleBase.Name()}),
1287		Stability: i.properties.Stability,
1288		Lang:      lang,
1289		BaseName:  i.ModuleBase.Name(),
1290		GenLog:    genLog,
1291		Version:   version,
1292		GenTrace:  genTrace,
1293		Unstable:  i.properties.Unstable,
1294	})
1295
1296	importExportDependencies := wrap("", i.properties.Imports, "-"+lang)
1297	var sharedLibDependency []string
1298	var libJSONCppDependency []string
1299	var staticLibDependency []string
1300	var headerLibs []string
1301	var sdkVersion *string
1302	var minSdkVersion *string
1303	var stl *string
1304	var cpp_std *string
1305	var hostSupported *bool
1306	var addCflags []string
1307
1308	if lang == langCpp {
1309		importExportDependencies = append(importExportDependencies, "libbinder", "libutils")
1310		if genLog {
1311			libJSONCppDependency = []string{"libjsoncpp"}
1312		}
1313		if genTrace {
1314			sharedLibDependency = append(sharedLibDependency, "libcutils")
1315		}
1316		hostSupported = i.properties.Host_supported
1317		minSdkVersion = i.properties.Backend.Cpp.Min_sdk_version
1318	} else if lang == langNdk {
1319		importExportDependencies = append(importExportDependencies, "libbinder_ndk")
1320		if genLog {
1321			staticLibDependency = []string{"libjsoncpp_ndk"}
1322		}
1323		if genTrace {
1324			sharedLibDependency = append(sharedLibDependency, "libandroid")
1325		}
1326		sdkVersion = proptools.StringPtr("current")
1327		stl = proptools.StringPtr("c++_shared")
1328		minSdkVersion = i.properties.Backend.Ndk.Min_sdk_version
1329	} else if lang == langNdkPlatform {
1330		importExportDependencies = append(importExportDependencies, "libbinder_ndk")
1331		if genLog {
1332			libJSONCppDependency = []string{"libjsoncpp"}
1333		}
1334		if genTrace {
1335			headerLibs = append(headerLibs, "libandroid_aidltrace")
1336			sharedLibDependency = append(sharedLibDependency, "libcutils")
1337		}
1338		hostSupported = i.properties.Host_supported
1339		addCflags = append(addCflags, "-DBINDER_STABILITY_SUPPORT")
1340		minSdkVersion = i.properties.Backend.Ndk.Min_sdk_version
1341	} else {
1342		panic("Unrecognized language: " + lang)
1343	}
1344
1345	vendorAvailable := i.properties.Vendor_available
1346	if lang == langCpp && "vintf" == proptools.String(i.properties.Stability) {
1347		// Vendors cannot use the libbinder (cpp) backend of AIDL in a way that is stable.
1348		// So, in order to prevent accidental usage of these library by vendor, forcibly
1349		// disabling this version of the library.
1350		//
1351		// It may be the case in the future that we will want to enable this (if some generic
1352		// helper should be used by both libbinder vendor things using /dev/vndbinder as well
1353		// as those things using /dev/binder + libbinder_ndk to talk to stable interfaces).
1354		vendorAvailable = proptools.BoolPtr(false)
1355	}
1356
1357	mctx.CreateModule(cc.LibraryFactory, &ccProperties{
1358		Name:                      proptools.StringPtr(cppModuleGen),
1359		Vendor_available:          vendorAvailable,
1360		Host_supported:            hostSupported,
1361		Defaults:                  []string{"aidl-cpp-module-defaults"},
1362		Generated_sources:         []string{cppSourceGen},
1363		Generated_headers:         []string{cppSourceGen},
1364		Export_generated_headers:  []string{cppSourceGen},
1365		Static:                    staticLib{Whole_static_libs: libJSONCppDependency},
1366		Shared:                    sharedLib{Shared_libs: libJSONCppDependency, Export_shared_lib_headers: libJSONCppDependency},
1367		Static_libs:               staticLibDependency,
1368		Shared_libs:               append(importExportDependencies, sharedLibDependency...),
1369		Header_libs:               headerLibs,
1370		Export_shared_lib_headers: importExportDependencies,
1371		Sdk_version:               sdkVersion,
1372		Stl:                       stl,
1373		Cpp_std:                   cpp_std,
1374		Cflags:                    append(addCflags, "-Wextra", "-Wall", "-Werror"),
1375		Stem:                      proptools.StringPtr(cppOutputGen),
1376		Apex_available:            commonProperties.Apex_available,
1377		Min_sdk_version:           minSdkVersion,
1378	}, &i.properties.VndkProperties, &commonProperties.VndkProperties, &overrideVndkProperties)
1379
1380	return cppModuleGen
1381}
1382
1383func addJavaLibrary(mctx android.LoadHookContext, i *aidlInterface, version string) string {
1384	javaSourceGen := i.versionedName(mctx, version) + "-java-source"
1385	javaModuleGen := i.versionedName(mctx, version) + "-java"
1386	if i.hasVersion() && version == "" {
1387		version = i.latestVersion()
1388	}
1389	srcs, aidlRoot := i.srcsForVersion(mctx, version)
1390	if len(srcs) == 0 {
1391		// This can happen when the version is about to be frozen; the version
1392		// directory is created but API dump hasn't been copied there.
1393		// Don't create a library for the yet-to-be-frozen version.
1394		return ""
1395	}
1396
1397	sdkVersion := i.properties.Backend.Java.Sdk_version
1398	if !proptools.Bool(i.properties.Backend.Java.Platform_apis) && sdkVersion == nil {
1399		// platform apis requires no default
1400		sdkVersion = proptools.StringPtr("system_current")
1401	}
1402
1403	mctx.CreateModule(aidlGenFactory, &nameProperties{
1404		Name: proptools.StringPtr(javaSourceGen),
1405	}, &aidlGenProperties{
1406		Srcs:      srcs,
1407		AidlRoot:  aidlRoot,
1408		Imports:   concat(i.properties.Imports, []string{i.ModuleBase.Name()}),
1409		Stability: i.properties.Stability,
1410		Lang:      langJava,
1411		BaseName:  i.ModuleBase.Name(),
1412		Version:   version,
1413		GenTrace:  proptools.Bool(i.properties.Gen_trace),
1414		Unstable:  i.properties.Unstable,
1415	})
1416
1417	mctx.CreateModule(java.LibraryFactory, &javaProperties{
1418		Name:            proptools.StringPtr(javaModuleGen),
1419		Installable:     proptools.BoolPtr(true),
1420		Defaults:        []string{"aidl-java-module-defaults"},
1421		Sdk_version:     sdkVersion,
1422		Platform_apis:   i.properties.Backend.Java.Platform_apis,
1423		Static_libs:     wrap("", i.properties.Imports, "-java"),
1424		Srcs:            []string{":" + javaSourceGen},
1425		Apex_available:  i.properties.Backend.Java.Apex_available,
1426		Min_sdk_version: i.properties.Backend.Java.Min_sdk_version,
1427	})
1428
1429	return javaModuleGen
1430}
1431
1432func addApiModule(mctx android.LoadHookContext, i *aidlInterface) string {
1433	apiModule := i.ModuleBase.Name() + aidlApiSuffix
1434	srcs, aidlRoot := i.srcsForVersion(mctx, i.currentVersion(mctx))
1435	mctx.CreateModule(aidlApiFactory, &nameProperties{
1436		Name: proptools.StringPtr(apiModule),
1437	}, &aidlApiProperties{
1438		BaseName:  i.ModuleBase.Name(),
1439		Srcs:      srcs,
1440		AidlRoot:  aidlRoot,
1441		Stability: i.properties.Stability,
1442		Imports:   concat(i.properties.Imports, []string{i.ModuleBase.Name()}),
1443		Versions:  i.properties.Versions,
1444	})
1445	return apiModule
1446}
1447
1448func (i *aidlInterface) Name() string {
1449	return i.ModuleBase.Name() + aidlInterfaceSuffix
1450}
1451func (i *aidlInterface) GenerateAndroidBuildActions(ctx android.ModuleContext) {
1452	aidlRoot := android.PathForModuleSrc(ctx, i.properties.Local_include_dir)
1453	for _, src := range android.PathsForModuleSrc(ctx, i.properties.Srcs) {
1454		baseDir := getBaseDir(ctx, src, aidlRoot)
1455		relPath, _ := filepath.Rel(baseDir, src.String())
1456		computedType := strings.TrimSuffix(strings.ReplaceAll(relPath, "/", "."), ".aidl")
1457		i.computedTypes = append(i.computedTypes, computedType)
1458	}
1459}
1460func (i *aidlInterface) DepsMutator(ctx android.BottomUpMutatorContext) {
1461	i.checkImports(ctx)
1462
1463	ctx.AddReverseDependency(ctx.Module(), nil, aidlMetadataSingletonName)
1464}
1465
1466var (
1467	aidlInterfacesKey   = android.NewOnceKey("aidlInterfaces")
1468	unstableModulesKey  = android.NewOnceKey("unstableModules")
1469	aidlDepsKey         = android.NewOnceKey("aidlDeps")
1470	aidlInterfaceMutex  sync.Mutex
1471	unstableModuleMutex sync.Mutex
1472	aidlDepsMutex       sync.RWMutex
1473)
1474
1475func aidlInterfaces(config android.Config) *[]*aidlInterface {
1476	return config.Once(aidlInterfacesKey, func() interface{} {
1477		return &[]*aidlInterface{}
1478	}).(*[]*aidlInterface)
1479}
1480
1481func unstableModules(config android.Config) *[]string {
1482	return config.Once(unstableModulesKey, func() interface{} {
1483		return &[]string{}
1484	}).(*[]string)
1485}
1486
1487type DepInfo struct {
1488	ifaceName string
1489	verLang   string
1490}
1491
1492func aidlDeps(config android.Config) map[android.Module][]DepInfo {
1493	return config.Once(aidlDepsKey, func() interface{} {
1494		return make(map[android.Module][]DepInfo)
1495	}).(map[android.Module][]DepInfo)
1496}
1497
1498func aidlInterfaceFactory() android.Module {
1499	i := &aidlInterface{}
1500	i.AddProperties(&i.properties)
1501	android.InitAndroidModule(i)
1502	android.AddLoadHook(i, func(ctx android.LoadHookContext) { aidlInterfaceHook(ctx, i) })
1503	return i
1504}
1505
1506func lookupInterface(name string, config android.Config) *aidlInterface {
1507	for _, i := range *aidlInterfaces(config) {
1508		if i.ModuleBase.Name() == name {
1509			return i
1510		}
1511	}
1512	return nil
1513}
1514
1515func aidlInterfacesMetadataSingletonFactory() android.Module {
1516	i := &aidlInterfacesMetadataSingleton{}
1517	android.InitAndroidModule(i)
1518	return i
1519}
1520
1521type aidlInterfacesMetadataSingleton struct {
1522	android.ModuleBase
1523
1524	metadataPath android.OutputPath
1525}
1526
1527var _ android.OutputFileProducer = (*aidlInterfacesMetadataSingleton)(nil)
1528
1529func (m *aidlInterfacesMetadataSingleton) GenerateAndroidBuildActions(ctx android.ModuleContext) {
1530	if m.Name() != aidlMetadataSingletonName {
1531		ctx.PropertyErrorf("name", "must be %s", aidlMetadataSingletonName)
1532		return
1533	}
1534
1535	type ModuleInfo struct {
1536		Stability     string
1537		ComputedTypes []string
1538		HashFiles     []string
1539	}
1540
1541	// name -> ModuleInfo
1542	moduleInfos := map[string]ModuleInfo{}
1543	ctx.VisitDirectDeps(func(m android.Module) {
1544		if !m.ExportedToMake() {
1545			return
1546		}
1547
1548		switch t := m.(type) {
1549		case *aidlInterface:
1550			info := moduleInfos[t.ModuleBase.Name()]
1551			info.Stability = proptools.StringDefault(t.properties.Stability, "")
1552			info.ComputedTypes = t.computedTypes
1553			moduleInfos[t.ModuleBase.Name()] = info
1554		case *aidlGenRule:
1555			info := moduleInfos[t.properties.BaseName]
1556			if t.hashFile != nil {
1557				info.HashFiles = append(info.HashFiles, t.hashFile.String())
1558			}
1559			moduleInfos[t.properties.BaseName] = info
1560		default:
1561			panic(fmt.Sprintf("Unrecognized module type: %v", t))
1562		}
1563
1564	})
1565
1566	var metadataOutputs android.Paths
1567	for name, info := range moduleInfos {
1568		metadataPath := android.PathForModuleOut(ctx, "metadata_"+name)
1569		metadataOutputs = append(metadataOutputs, metadataPath)
1570
1571		// There is one aidlGenRule per-version per-backend. If we had
1572		// objects per version and sub-objects per backend, we could
1573		// avoid needing to filter out duplicates.
1574		info.HashFiles = android.FirstUniqueStrings(info.HashFiles)
1575
1576		implicits := android.PathsForSource(ctx, info.HashFiles)
1577
1578		ctx.Build(pctx, android.BuildParams{
1579			Rule:      aidlMetadataRule,
1580			Implicits: implicits,
1581			Output:    metadataPath,
1582			Args: map[string]string{
1583				"name":      name,
1584				"stability": info.Stability,
1585				"types":     strings.Join(wrap(`\"`, info.ComputedTypes, `\"`), ", "),
1586				"hashes": strings.Join(
1587					wrap(`\"$$(read -r < `,
1588						info.HashFiles,
1589						` hash extra; printf '%s' $$hash)\"`), ", "),
1590			},
1591		})
1592	}
1593
1594	m.metadataPath = android.PathForModuleOut(ctx, "aidl_metadata.json").OutputPath
1595
1596	ctx.Build(pctx, android.BuildParams{
1597		Rule:   joinJsonObjectsToArrayRule,
1598		Inputs: metadataOutputs,
1599		Output: m.metadataPath,
1600		Args: map[string]string{
1601			"files": strings.Join(metadataOutputs.Strings(), " "),
1602		},
1603	})
1604}
1605
1606func (m *aidlInterfacesMetadataSingleton) OutputFiles(tag string) (android.Paths, error) {
1607	if tag != "" {
1608		return nil, fmt.Errorf("unsupported tag %q", tag)
1609	}
1610
1611	return android.Paths{m.metadataPath}, nil
1612}
1613
1614type aidlMappingProperties struct {
1615	// Source file of this prebuilt.
1616	Srcs   []string `android:"path"`
1617	Output string
1618}
1619
1620type aidlMapping struct {
1621	android.ModuleBase
1622	properties     aidlMappingProperties
1623	outputFilePath android.WritablePath
1624}
1625
1626func (s *aidlMapping) DepsMutator(ctx android.BottomUpMutatorContext) {
1627}
1628
1629func (s *aidlMapping) GenerateAndroidBuildActions(ctx android.ModuleContext) {
1630	srcs, imports := getPaths(ctx, s.properties.Srcs)
1631
1632	s.outputFilePath = android.PathForModuleOut(ctx, s.properties.Output)
1633	outDir := android.PathForModuleGen(ctx)
1634	ctx.Build(pctx, android.BuildParams{
1635		Rule:   aidlDumpMappingsRule,
1636		Inputs: srcs,
1637		Output: s.outputFilePath,
1638		Args: map[string]string{
1639			"imports": android.JoinWithPrefix(imports, " -I"),
1640			"outDir":  outDir.String(),
1641		},
1642	})
1643}
1644
1645func InitAidlMappingModule(s *aidlMapping) {
1646	s.AddProperties(&s.properties)
1647}
1648
1649func aidlMappingFactory() android.Module {
1650	module := &aidlMapping{}
1651	InitAidlMappingModule(module)
1652	android.InitAndroidModule(module)
1653	return module
1654}
1655
1656func (m *aidlMapping) AndroidMk() android.AndroidMkData {
1657	return android.AndroidMkData{
1658		Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
1659			android.WriteAndroidMkData(w, data)
1660			targetName := m.Name()
1661			fmt.Fprintln(w, ".PHONY:", targetName)
1662			fmt.Fprintln(w, targetName+":", m.outputFilePath.String())
1663		},
1664	}
1665}
1666
1667func allAidlInterfacesMakeVars(ctx android.MakeVarsContext) {
1668	names := []string{}
1669	ctx.VisitAllModules(func(module android.Module) {
1670		if ai, ok := module.(*aidlInterface); ok {
1671			names = append(names, ai.BaseModuleName())
1672		}
1673	})
1674	ctx.Strict("ALL_AIDL_INTERFACES", strings.Join(names, " "))
1675}
1676