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