• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (C) 2021 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/genrule"
20
21	"path/filepath"
22	"strings"
23
24	"github.com/google/blueprint"
25	"github.com/google/blueprint/pathtools"
26	"github.com/google/blueprint/proptools"
27)
28
29var (
30	aidlDirPrepareRule = pctx.StaticRule("aidlDirPrepareRule", blueprint.RuleParams{
31		Command: `rm -rf "${outDir}" && mkdir -p "${outDir}" && ` +
32			`touch ${out} # ${in}`,
33		Description: "create ${out}",
34	}, "outDir")
35
36	aidlCppRule = pctx.StaticRule("aidlCppRule", blueprint.RuleParams{
37		Command: `mkdir -p "${headerDir}" && ` +
38			`${aidlCmd} --lang=${lang} ${optionalFlags} --structured --ninja -d ${out}.d ` +
39			`-h ${headerDir} -o ${outDir} ${imports} ${in}`,
40		Depfile:     "${out}.d",
41		Deps:        blueprint.DepsGCC,
42		CommandDeps: []string{"${aidlCmd}"},
43		Description: "AIDL ${lang} ${in}",
44	}, "imports", "lang", "headerDir", "outDir", "optionalFlags")
45
46	aidlJavaRule = pctx.StaticRule("aidlJavaRule", blueprint.RuleParams{
47		Command: `${aidlCmd} --lang=java ${optionalFlags} --structured --ninja -d ${out}.d ` +
48			`-o ${outDir} ${imports} ${in}`,
49		Depfile:     "${out}.d",
50		Deps:        blueprint.DepsGCC,
51		CommandDeps: []string{"${aidlCmd}"},
52		Description: "AIDL Java ${in}",
53	}, "imports", "outDir", "optionalFlags")
54
55	aidlRustRule = pctx.StaticRule("aidlRustRule", blueprint.RuleParams{
56		Command: `${aidlCmd} --lang=rust ${optionalFlags} --structured --ninja -d ${out}.d ` +
57			`-o ${outDir} ${imports} ${in}`,
58		Depfile:     "${out}.d",
59		Deps:        blueprint.DepsGCC,
60		CommandDeps: []string{"${aidlCmd}"},
61		Description: "AIDL Rust ${in}",
62	}, "imports", "outDir", "optionalFlags")
63)
64
65type aidlGenProperties struct {
66	Srcs            []string `android:"path"`
67	AidlRoot        string   // base directory for the input aidl file
68	Imports         []string
69	Stability       *string
70	Min_sdk_version *string
71	Platform_apis   bool
72	Lang            string // target language [java|cpp|ndk|rust]
73	BaseName        string
74	GenLog          bool
75	Version         string
76	GenRpc          bool
77	GenTrace        bool
78	Unstable        *bool
79	NotFrozen       bool
80	Visibility      []string
81	Flags           []string
82}
83
84type aidlGenRule struct {
85	android.ModuleBase
86
87	properties aidlGenProperties
88
89	deps           deps
90	implicitInputs android.Paths
91	importFlags    string
92
93	// A frozen aidl_interface always have a hash file
94	hashFile android.Path
95
96	genOutDir     android.ModuleGenPath
97	genHeaderDir  android.ModuleGenPath
98	genHeaderDeps android.Paths
99	genOutputs    android.WritablePaths
100}
101
102var _ android.SourceFileProducer = (*aidlGenRule)(nil)
103var _ genrule.SourceFileGenerator = (*aidlGenRule)(nil)
104
105func (g *aidlGenRule) aidlInterface(ctx android.BaseModuleContext) *aidlInterface {
106	return ctx.GetDirectDepWithTag(g.properties.BaseName, interfaceDep).(*aidlInterface)
107}
108
109func (g *aidlGenRule) getImports(ctx android.ModuleContext) map[string]string {
110	iface := g.aidlInterface(ctx)
111	return iface.getImports(g.properties.Version)
112}
113
114func (g *aidlGenRule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
115	srcs, imports := getPaths(ctx, g.properties.Srcs, g.properties.AidlRoot)
116
117	if ctx.Failed() {
118		return
119	}
120
121	g.deps = getDeps(ctx, g.getImports(ctx))
122
123	genDirTimestamp := android.PathForModuleGen(ctx, "timestamp") // $out/gen/timestamp
124	g.implicitInputs = append(g.implicitInputs, genDirTimestamp)
125	g.implicitInputs = append(g.implicitInputs, g.deps.implicits...)
126	g.implicitInputs = append(g.implicitInputs, g.deps.preprocessed...)
127
128	imports = append(imports, g.deps.imports...)
129	g.importFlags = strings.Join(wrap("-I", imports, ""), " ")
130
131	g.genOutDir = android.PathForModuleGen(ctx)
132	g.genHeaderDir = android.PathForModuleGen(ctx, "include")
133	for _, src := range srcs {
134		outFile, headers := g.generateBuildActionsForSingleAidl(ctx, src)
135		g.genOutputs = append(g.genOutputs, outFile)
136		g.genHeaderDeps = append(g.genHeaderDeps, headers...)
137	}
138
139	// This is to clean genOutDir before generating any file
140	ctx.Build(pctx, android.BuildParams{
141		Rule:   aidlDirPrepareRule,
142		Inputs: srcs,
143		Output: genDirTimestamp,
144		Args: map[string]string{
145			"outDir": g.genOutDir.String(),
146		},
147	})
148
149	// This is to trigger genrule alone
150	ctx.Build(pctx, android.BuildParams{
151		Rule:   android.Phony,
152		Output: android.PathForModuleOut(ctx, "timestamp"), // $out/timestamp
153		Inputs: g.genOutputs.Paths(),
154	})
155}
156
157func (g *aidlGenRule) generateBuildActionsForSingleAidl(ctx android.ModuleContext, src android.Path) (android.WritablePath, android.Paths) {
158	relPath := src.Rel()
159	baseDir := strings.TrimSuffix(strings.TrimSuffix(src.String(), relPath), "/")
160
161	var ext string
162	if g.properties.Lang == langJava {
163		ext = "java"
164	} else if g.properties.Lang == langRust {
165		ext = "rs"
166	} else {
167		ext = "cpp"
168	}
169	outFile := android.PathForModuleGen(ctx, pathtools.ReplaceExtension(relPath, ext))
170	implicits := g.implicitInputs
171
172	optionalFlags := append([]string{}, g.properties.Flags...)
173	if g.properties.Version != "" {
174		optionalFlags = append(optionalFlags, "--version "+g.properties.Version)
175
176		hash := "notfrozen"
177		if !strings.HasPrefix(baseDir, ctx.Config().SoongOutDir()) {
178			hashFile := android.ExistentPathForSource(ctx, baseDir, ".hash")
179			if hashFile.Valid() {
180				hash = "$$(tail -1 '" + hashFile.Path().String() + "')"
181				implicits = append(implicits, hashFile.Path())
182
183				g.hashFile = hashFile.Path()
184			}
185		}
186		optionalFlags = append(optionalFlags, "--hash "+hash)
187	}
188	if g.properties.GenRpc {
189		optionalFlags = append(optionalFlags, "--rpc")
190	}
191	if g.properties.GenTrace {
192		optionalFlags = append(optionalFlags, "-t")
193	}
194	if g.properties.Stability != nil {
195		optionalFlags = append(optionalFlags, "--stability", *g.properties.Stability)
196	}
197	if g.properties.Platform_apis {
198		optionalFlags = append(optionalFlags, "--min_sdk_version platform_apis")
199	} else {
200		minSdkVer := proptools.StringDefault(g.properties.Min_sdk_version, "current")
201		optionalFlags = append(optionalFlags, "--min_sdk_version "+minSdkVer)
202	}
203	optionalFlags = append(optionalFlags, wrap("-p", g.deps.preprocessed.Strings(), "")...)
204
205	var headers android.WritablePaths
206	if g.properties.Lang == langJava {
207		ctx.Build(pctx, android.BuildParams{
208			Rule:      aidlJavaRule,
209			Input:     src,
210			Implicits: implicits,
211			Output:    outFile,
212			Args: map[string]string{
213				"imports":       g.importFlags,
214				"outDir":        g.genOutDir.String(),
215				"optionalFlags": strings.Join(optionalFlags, " "),
216			},
217		})
218	} else if g.properties.Lang == langRust {
219		ctx.Build(pctx, android.BuildParams{
220			Rule:      aidlRustRule,
221			Input:     src,
222			Implicits: implicits,
223			Output:    outFile,
224			Args: map[string]string{
225				"imports":       g.importFlags,
226				"outDir":        g.genOutDir.String(),
227				"optionalFlags": strings.Join(optionalFlags, " "),
228			},
229		})
230	} else {
231		typeName := strings.TrimSuffix(filepath.Base(relPath), ".aidl")
232		packagePath := filepath.Dir(relPath)
233		baseName := typeName
234		// TODO(b/111362593): aidl_to_cpp_common.cpp uses heuristics to figure out if
235		//   an interface name has a leading I. Those same heuristics have been
236		//   moved here.
237		if len(baseName) >= 2 && baseName[0] == 'I' &&
238			strings.ToUpper(baseName)[1] == baseName[1] {
239			baseName = strings.TrimPrefix(typeName, "I")
240		}
241
242		prefix := ""
243		if g.properties.Lang == langNdk || g.properties.Lang == langNdkPlatform {
244			prefix = "aidl"
245		}
246
247		headers = append(headers, g.genHeaderDir.Join(ctx, prefix, packagePath,
248			typeName+".h"))
249		headers = append(headers, g.genHeaderDir.Join(ctx, prefix, packagePath,
250			"Bp"+baseName+".h"))
251		headers = append(headers, g.genHeaderDir.Join(ctx, prefix, packagePath,
252			"Bn"+baseName+".h"))
253
254		if g.properties.GenLog {
255			optionalFlags = append(optionalFlags, "--log")
256		}
257
258		aidlLang := g.properties.Lang
259		if aidlLang == langNdkPlatform {
260			aidlLang = "ndk"
261		}
262
263		ctx.Build(pctx, android.BuildParams{
264			Rule:            aidlCppRule,
265			Input:           src,
266			Implicits:       implicits,
267			Output:          outFile,
268			ImplicitOutputs: headers,
269			Args: map[string]string{
270				"imports":       g.importFlags,
271				"lang":          aidlLang,
272				"headerDir":     g.genHeaderDir.String(),
273				"outDir":        g.genOutDir.String(),
274				"optionalFlags": strings.Join(optionalFlags, " "),
275			},
276		})
277	}
278
279	return outFile, headers.Paths()
280}
281
282func (g *aidlGenRule) GeneratedSourceFiles() android.Paths {
283	return g.genOutputs.Paths()
284}
285
286func (g *aidlGenRule) Srcs() android.Paths {
287	return g.genOutputs.Paths()
288}
289
290func (g *aidlGenRule) GeneratedDeps() android.Paths {
291	return g.genHeaderDeps
292}
293
294func (g *aidlGenRule) GeneratedHeaderDirs() android.Paths {
295	return android.Paths{g.genHeaderDir}
296}
297
298func (g *aidlGenRule) DepsMutator(ctx android.BottomUpMutatorContext) {
299	ctx.AddReverseDependency(ctx.Module(), nil, aidlMetadataSingletonName)
300}
301
302func aidlGenFactory() android.Module {
303	g := &aidlGenRule{}
304	g.AddProperties(&g.properties)
305	android.InitAndroidModule(g)
306	return g
307}
308