blob: 3810d20e7ce5854f87fc6fefec72b9d384081991 [file] [log] [blame]
Jeongik Chada36d5a2021-01-20 00:43:34 +09001// 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
20 "fmt"
21 "io"
22 "path/filepath"
23 "strconv"
24 "strings"
25
26 "github.com/google/blueprint"
27 "github.com/google/blueprint/proptools"
28)
29
30var (
31 aidlDumpApiRule = pctx.StaticRule("aidlDumpApiRule", blueprint.RuleParams{
32 Command: `rm -rf "${outDir}" && mkdir -p "${outDir}" && ` +
33 `${aidlCmd} --dumpapi --structured ${imports} ${optionalFlags} --out ${outDir} ${in} && ` +
Jeongik Cha6cc16f32021-05-18 11:23:55 +090034 `${aidlHashGen} ${outDir} ${latestVersion} ${hashFile}`,
35 CommandDeps: []string{"${aidlCmd}", "${aidlHashGen}"},
Jeongik Chada36d5a2021-01-20 00:43:34 +090036 }, "optionalFlags", "imports", "outDir", "hashFile", "latestVersion")
37
38 aidlCheckApiRule = pctx.StaticRule("aidlCheckApiRule", blueprint.RuleParams{
Jooyung Han8e3b72c2021-05-22 02:54:37 +090039 Command: `(${aidlCmd} ${optionalFlags} --checkapi=${checkApiLevel} ${imports} ${old} ${new} && touch ${out}) || ` +
Jeongik Chada36d5a2021-01-20 00:43:34 +090040 `(cat ${messageFile} && exit 1)`,
41 CommandDeps: []string{"${aidlCmd}"},
42 Description: "AIDL CHECK API: ${new} against ${old}",
Jooyung Han8e3b72c2021-05-22 02:54:37 +090043 }, "optionalFlags", "imports", "old", "new", "messageFile", "checkApiLevel")
Jeongik Chada36d5a2021-01-20 00:43:34 +090044
45 aidlVerifyHashRule = pctx.StaticRule("aidlVerifyHashRule", blueprint.RuleParams{
46 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 ` +
47 `touch ${out}; else cat '${messageFile}' && exit 1; fi`,
48 Description: "Verify ${apiDir} files have not been modified",
49 }, "apiDir", "version", "messageFile", "hashFile")
50)
51
52type aidlApiProperties struct {
Jeongik Chaa01447d2021-03-17 17:43:12 +090053 BaseName string
54 Srcs []string `android:"path"`
55 AidlRoot string // base directory for the input aidl file
56 Stability *string
57 ImportsWithoutVersion []string
58 Versions []string
59 Dumpapi DumpApiProperties
Jeongik Chada36d5a2021-01-20 00:43:34 +090060}
61
62type aidlApi struct {
63 android.ModuleBase
64
65 properties aidlApiProperties
66
67 // for triggering api check for version X against version X-1
68 checkApiTimestamps android.WritablePaths
69
70 // for triggering updating current API
71 updateApiTimestamp android.WritablePath
72
73 // for triggering check that files have not been modified
74 checkHashTimestamps android.WritablePaths
75
76 // for triggering freezing API as the new version
77 freezeApiTimestamp android.WritablePath
78}
79
80func (m *aidlApi) apiDir() string {
81 return filepath.Join(aidlApiDir, m.properties.BaseName)
82}
83
84// `m <iface>-freeze-api` will freeze ToT as this version
85func (m *aidlApi) nextVersion() string {
Jeongik Cha52e98022021-01-20 18:37:20 +090086 return nextVersion(m.properties.Versions)
Jeongik Chada36d5a2021-01-20 00:43:34 +090087}
88
89type apiDump struct {
90 dir android.Path
91 files android.Paths
92 hashFile android.OptionalPath
93}
94
95func (m *aidlApi) createApiDumpFromSource(ctx android.ModuleContext) apiDump {
Jooyung Han60699b52021-05-26 22:20:42 +090096 srcs, imports := getPaths(ctx, m.properties.Srcs, m.properties.AidlRoot)
Jeongik Chada36d5a2021-01-20 00:43:34 +090097
98 if ctx.Failed() {
99 return apiDump{}
100 }
101
Jooyung Han60699b52021-05-26 22:20:42 +0900102 importPaths, _ := getImportsFromDeps(ctx, true)
103 imports = append(imports, importPaths...)
Jeongik Chada36d5a2021-01-20 00:43:34 +0900104
105 var apiDir android.WritablePath
106 var apiFiles android.WritablePaths
107 var hashFile android.WritablePath
108
109 apiDir = android.PathForModuleOut(ctx, "dump")
110 aidlRoot := android.PathForModuleSrc(ctx, m.properties.AidlRoot)
111 for _, src := range srcs {
112 baseDir := getBaseDir(ctx, src, aidlRoot)
113 relPath, _ := filepath.Rel(baseDir, src.String())
114 outFile := android.PathForModuleOut(ctx, "dump", relPath)
115 apiFiles = append(apiFiles, outFile)
116 }
117 hashFile = android.PathForModuleOut(ctx, "dump", ".hash")
Jeongik Chada36d5a2021-01-20 00:43:34 +0900118
119 var optionalFlags []string
120 if m.properties.Stability != nil {
121 optionalFlags = append(optionalFlags, "--stability", *m.properties.Stability)
122 }
Jooyung Han252657e2021-02-27 02:51:39 +0900123 if proptools.Bool(m.properties.Dumpapi.No_license) {
124 optionalFlags = append(optionalFlags, "--no_license")
125 }
Jeongik Chada36d5a2021-01-20 00:43:34 +0900126
127 ctx.Build(pctx, android.BuildParams{
128 Rule: aidlDumpApiRule,
129 Outputs: append(apiFiles, hashFile),
130 Inputs: srcs,
131 Args: map[string]string{
132 "optionalFlags": strings.Join(optionalFlags, " "),
Jooyung Han60699b52021-05-26 22:20:42 +0900133 "imports": strings.Join(wrap("-I", imports, ""), " "),
Jeongik Chada36d5a2021-01-20 00:43:34 +0900134 "outDir": apiDir.String(),
135 "hashFile": hashFile.String(),
Jeongik Cha6cc16f32021-05-18 11:23:55 +0900136 "latestVersion": versionForHashGen(nextVersion(m.properties.Versions)),
Jeongik Chada36d5a2021-01-20 00:43:34 +0900137 },
138 })
139 return apiDump{apiDir, apiFiles.Paths(), android.OptionalPathForPath(hashFile)}
140}
141
Jiyong Park72e08932021-05-21 00:18:20 +0900142func (m *aidlApi) makeApiDumpAsVersion(ctx android.ModuleContext, dump apiDump, version string, latestVersionDump *apiDump) android.WritablePath {
143 creatingNewVersion := version != currentVersion
144 moduleDir := android.PathForModuleSrc(ctx).String()
145 targetDir := filepath.Join(moduleDir, m.apiDir(), version)
Jeongik Chada36d5a2021-01-20 00:43:34 +0900146 rb := android.NewRuleBuilder(pctx, ctx)
Jiyong Park72e08932021-05-21 00:18:20 +0900147
148 if creatingNewVersion {
149 // We are asked to create a new version. But before doing that, check if the given
150 // dump is the same as the latest version. If so, don't create a new version,
151 // otherwise we will be unnecessarily creating many versions. `newVersionNeededFile`
152 // is created when the equality check fails.
153 newVersionNeededFile := android.PathForModuleOut(ctx, "updateapi_"+version+".needed")
154 rb.Command().Text("rm -f " + newVersionNeededFile.String())
155
156 if latestVersionDump != nil {
157 equalityCheckCommand := rb.Command()
158 equalityCheckCommand.BuiltTool("aidl").
159 FlagWithArg("--checkapi=", "equal")
160 if m.properties.Stability != nil {
161 equalityCheckCommand.FlagWithArg("--stability ", *m.properties.Stability)
162 }
Jooyung Han60699b52021-05-26 22:20:42 +0900163 importPaths, implicits := getImportsFromDeps(ctx, false)
Jooyung Han8e3b72c2021-05-22 02:54:37 +0900164 equalityCheckCommand.FlagForEachArg("-I", importPaths).Implicits(implicits)
Jiyong Park72e08932021-05-21 00:18:20 +0900165 equalityCheckCommand.
166 Text(latestVersionDump.dir.String()).Implicits(latestVersionDump.files).
167 Text(dump.dir.String()).Implicits(dump.files).
168 Text("&> /dev/null")
169 equalityCheckCommand.
170 Text("|| touch").
171 Text(newVersionNeededFile.String())
172 } else {
173 // If there is no latest version (i.e. we are creating the initial version)
174 // create the new version unconditionally
175 rb.Command().Text("touch").Text(newVersionNeededFile.String())
176 }
177
178 // Copy the given dump to the target directory only when the equality check failed
179 // (i.e. `newVersionNeededFile` exists).
180 rb.Command().
181 Text("if [ -f " + newVersionNeededFile.String() + " ]; then").
182 Text("cp -rf " + dump.dir.String() + "/. " + targetDir).Implicits(dump.files).
183 Text("; fi")
184
185 // Also modify Android.bp file to add the new version to the 'versions' property.
186 rb.Command().
187 Text("if [ -f " + newVersionNeededFile.String() + " ]; then").
188 BuiltTool("bpmodify").
Jeongik Chada36d5a2021-01-20 00:43:34 +0900189 Text("-w -m " + m.properties.BaseName).
190 Text("-parameter versions -a " + version).
Jiyong Park72e08932021-05-21 00:18:20 +0900191 Text(android.PathForModuleSrc(ctx, "Android.bp").String()).
192 Text("; fi")
193
Jeongik Chada36d5a2021-01-20 00:43:34 +0900194 } else {
Jiyong Park72e08932021-05-21 00:18:20 +0900195 // We are updating the current version. Don't copy .hash to the current dump
196 rb.Command().Text("mkdir -p " + targetDir)
197 rb.Command().Text("rm -rf " + targetDir + "/*")
Jeongik Chada36d5a2021-01-20 00:43:34 +0900198 rb.Command().Text("cp -rf " + dump.dir.String() + "/* " + targetDir).Implicits(dump.files)
199 }
Jiyong Park72e08932021-05-21 00:18:20 +0900200
201 timestampFile := android.PathForModuleOut(ctx, "updateapi_"+version+".timestamp")
Jeongik Chada36d5a2021-01-20 00:43:34 +0900202 rb.Command().Text("touch").Output(timestampFile)
203
204 rb.Build("dump_aidl_api"+m.properties.BaseName+"_"+version,
205 "Making AIDL API of "+m.properties.BaseName+" as version "+version)
206 return timestampFile
207}
208
Jooyung Han60699b52021-05-26 22:20:42 +0900209// calculates import flags(-I) from deps.
210// When the target is ToT, use ToT of imported interfaces. If not, we use "current" snapshot of
211// imported interfaces.
212func getImportsFromDeps(ctx android.ModuleContext, targetIsToT bool) (importPaths []string, implicits android.Paths) {
Jooyung Han8e3b72c2021-05-22 02:54:37 +0900213 ctx.VisitDirectDeps(func(dep android.Module) {
Jooyung Han60699b52021-05-26 22:20:42 +0900214 switch ctx.OtherModuleDependencyTag(dep) {
215 case importInterfaceDep:
216 iface := dep.(*aidlInterface)
217 if proptools.Bool(iface.properties.Unstable) || targetIsToT {
218 importPaths = append(importPaths, iface.properties.Full_import_paths...)
219 } else {
220 // use "current" snapshot from stable "imported" modules
221 currentDir := filepath.Join(ctx.OtherModuleDir(dep), aidlApiDir, iface.BaseModuleName(), currentVersion)
222 importPaths = append(importPaths, currentDir)
223 // TODO(b/189288369) this should be transitive
224 importPaths = append(importPaths, iface.properties.Include_dirs...)
Jooyung Han8e3b72c2021-05-22 02:54:37 +0900225 }
Jooyung Han60699b52021-05-26 22:20:42 +0900226 case interfaceDep:
227 iface := dep.(*aidlInterface)
228 importPaths = append(importPaths, iface.properties.Include_dirs...)
229 case importApiDep, apiDep:
230 api := dep.(*aidlApi)
Jooyung Han8e3b72c2021-05-22 02:54:37 +0900231 // add imported module's checkapiTimestamps as implicits to make sure that imported apiDump is up-to-date
Jooyung Han60699b52021-05-26 22:20:42 +0900232 implicits = append(implicits, api.checkApiTimestamps.Paths()...)
233 implicits = append(implicits, api.checkHashTimestamps.Paths()...)
Jooyung Han8e3b72c2021-05-22 02:54:37 +0900234 }
235 })
236 return
237}
238
Jooyung Hanb8a97772021-01-19 01:27:38 +0900239func (m *aidlApi) checkApi(ctx android.ModuleContext, oldDump, newDump apiDump, checkApiLevel string, messageFile android.Path) android.WritablePath {
Jeongik Chada36d5a2021-01-20 00:43:34 +0900240 newVersion := newDump.dir.Base()
241 timestampFile := android.PathForModuleOut(ctx, "checkapi_"+newVersion+".timestamp")
Jeongik Chada36d5a2021-01-20 00:43:34 +0900242
243 var optionalFlags []string
244 if m.properties.Stability != nil {
245 optionalFlags = append(optionalFlags, "--stability", *m.properties.Stability)
246 }
247
Jooyung Han60699b52021-05-26 22:20:42 +0900248 importPaths, implicits := getImportsFromDeps(ctx, false)
Jeongik Chada36d5a2021-01-20 00:43:34 +0900249 implicits = append(implicits, oldDump.files...)
250 implicits = append(implicits, newDump.files...)
251 implicits = append(implicits, messageFile)
Jooyung Han8e3b72c2021-05-22 02:54:37 +0900252
Jeongik Chada36d5a2021-01-20 00:43:34 +0900253 ctx.Build(pctx, android.BuildParams{
254 Rule: aidlCheckApiRule,
255 Implicits: implicits,
256 Output: timestampFile,
257 Args: map[string]string{
258 "optionalFlags": strings.Join(optionalFlags, " "),
Jooyung Han8e3b72c2021-05-22 02:54:37 +0900259 "imports": strings.Join(wrap("-I", importPaths, ""), " "),
Jeongik Chada36d5a2021-01-20 00:43:34 +0900260 "old": oldDump.dir.String(),
261 "new": newDump.dir.String(),
262 "messageFile": messageFile.String(),
Jooyung Hanb8a97772021-01-19 01:27:38 +0900263 "checkApiLevel": checkApiLevel,
Jeongik Chada36d5a2021-01-20 00:43:34 +0900264 },
265 })
266 return timestampFile
267}
268
Jooyung Hanb8a97772021-01-19 01:27:38 +0900269func (m *aidlApi) checkCompatibility(ctx android.ModuleContext, oldDump, newDump apiDump) android.WritablePath {
270 messageFile := android.PathForSource(ctx, "system/tools/aidl/build/message_check_compatibility.txt")
271 return m.checkApi(ctx, oldDump, newDump, "compatible", messageFile)
272}
Jeongik Chada36d5a2021-01-20 00:43:34 +0900273
Jooyung Hanb8a97772021-01-19 01:27:38 +0900274func (m *aidlApi) checkEquality(ctx android.ModuleContext, oldDump apiDump, newDump apiDump) android.WritablePath {
Jeongik Chada36d5a2021-01-20 00:43:34 +0900275 // Use different messages depending on whether platform SDK is finalized or not.
276 // In case when it is finalized, we should never allow updating the already frozen API.
277 // If it's not finalized, we let users to update the current version by invoking
278 // `m <name>-update-api`.
279 messageFile := android.PathForSource(ctx, "system/tools/aidl/build/message_check_equality.txt")
280 sdkIsFinal := !ctx.Config().DefaultAppTargetSdk(ctx).IsPreview()
281 if sdkIsFinal {
282 messageFile = android.PathForSource(ctx, "system/tools/aidl/build/message_check_equality_release.txt")
283 }
284 formattedMessageFile := android.PathForModuleOut(ctx, "message_check_equality.txt")
285 rb := android.NewRuleBuilder(pctx, ctx)
286 rb.Command().Text("sed").Flag(" s/%s/" + m.properties.BaseName + "/g ").Input(messageFile).Text(" > ").Output(formattedMessageFile)
287 rb.Build("format_message_"+m.properties.BaseName, "")
288
Jooyung Hanb8a97772021-01-19 01:27:38 +0900289 return m.checkApi(ctx, oldDump, newDump, "equal", formattedMessageFile)
Jeongik Chada36d5a2021-01-20 00:43:34 +0900290}
291
292func (m *aidlApi) checkIntegrity(ctx android.ModuleContext, dump apiDump) android.WritablePath {
293 version := dump.dir.Base()
294 timestampFile := android.PathForModuleOut(ctx, "checkhash_"+version+".timestamp")
295 messageFile := android.PathForSource(ctx, "system/tools/aidl/build/message_check_integrity.txt")
296
Jeongik Chada36d5a2021-01-20 00:43:34 +0900297 var implicits android.Paths
298 implicits = append(implicits, dump.files...)
299 implicits = append(implicits, dump.hashFile.Path())
300 implicits = append(implicits, messageFile)
301 ctx.Build(pctx, android.BuildParams{
302 Rule: aidlVerifyHashRule,
303 Implicits: implicits,
304 Output: timestampFile,
305 Args: map[string]string{
306 "apiDir": dump.dir.String(),
Jeongik Cha6cc16f32021-05-18 11:23:55 +0900307 "version": versionForHashGen(version),
Jeongik Chada36d5a2021-01-20 00:43:34 +0900308 "hashFile": dump.hashFile.Path().String(),
309 "messageFile": messageFile.String(),
310 },
311 })
312 return timestampFile
313}
314
315func (m *aidlApi) GenerateAndroidBuildActions(ctx android.ModuleContext) {
316 // An API dump is created from source and it is compared against the API dump of the
317 // 'current' (yet-to-be-finalized) version. By checking this we enforce that any change in
318 // the AIDL interface is gated by the AIDL API review even before the interface is frozen as
319 // a new version.
320 totApiDump := m.createApiDumpFromSource(ctx)
321 currentApiDir := android.ExistentPathForSource(ctx, ctx.ModuleDir(), m.apiDir(), currentVersion)
322 var currentApiDump apiDump
323 if currentApiDir.Valid() {
324 currentApiDump = apiDump{
325 dir: currentApiDir.Path(),
326 files: ctx.Glob(filepath.Join(currentApiDir.Path().String(), "**/*.aidl"), nil),
327 hashFile: android.ExistentPathForSource(ctx, ctx.ModuleDir(), m.apiDir(), currentVersion, ".hash"),
328 }
329 checked := m.checkEquality(ctx, currentApiDump, totApiDump)
330 m.checkApiTimestamps = append(m.checkApiTimestamps, checked)
331 } else {
332 // The "current" directory might not exist, in case when the interface is first created.
333 // Instruct user to create one by executing `m <name>-update-api`.
334 rb := android.NewRuleBuilder(pctx, ctx)
335 ifaceName := m.properties.BaseName
336 rb.Command().Text(fmt.Sprintf(`echo "API dump for the current version of AIDL interface %s does not exist."`, ifaceName))
337 rb.Command().Text(fmt.Sprintf(`echo Run "m %s-update-api", or add "unstable: true" to the build rule `+
338 `for the interface if it does not need to be versioned`, ifaceName))
339 // This file will never be created. Otherwise, the build will pass simply by running 'm; m'.
340 alwaysChecked := android.PathForModuleOut(ctx, "checkapi_current.timestamp")
341 rb.Command().Text("false").ImplicitOutput(alwaysChecked)
342 rb.Build("check_current_aidl_api", "")
343 m.checkApiTimestamps = append(m.checkApiTimestamps, alwaysChecked)
344 }
345
346 // Also check that version X is backwards compatible with version X-1.
347 // "current" is checked against the latest version.
348 var dumps []apiDump
349 for _, ver := range m.properties.Versions {
350 apiDir := filepath.Join(ctx.ModuleDir(), m.apiDir(), ver)
351 apiDirPath := android.ExistentPathForSource(ctx, apiDir)
352 if apiDirPath.Valid() {
Jeongik Cha6cc16f32021-05-18 11:23:55 +0900353 hashFilePath := filepath.Join(apiDir, ".hash")
354 dump := apiDump{
Jeongik Chada36d5a2021-01-20 00:43:34 +0900355 dir: apiDirPath.Path(),
356 files: ctx.Glob(filepath.Join(apiDirPath.String(), "**/*.aidl"), nil),
Jeongik Cha6cc16f32021-05-18 11:23:55 +0900357 hashFile: android.ExistentPathForSource(ctx, hashFilePath),
358 }
359 if !dump.hashFile.Valid() {
Jeongik Chac6442172021-05-25 10:46:56 +0900360 // We should show the source path of hash_gen because aidl_hash_gen cannot be built due to build error.
361 cmd := fmt.Sprintf(`(croot && system/tools/aidl/build/hash_gen.sh %s %s %s)`, apiDir, versionForHashGen(ver), hashFilePath)
Jeongik Cha6cc16f32021-05-18 11:23:55 +0900362 ctx.ModuleErrorf("A frozen aidl_interface must have '.hash' file, but %s-V%s doesn't have it. Use the command below to generate hash.\n%s\n",
363 m.properties.BaseName, ver, cmd)
364 }
365 dumps = append(dumps, dump)
Jeongik Chada36d5a2021-01-20 00:43:34 +0900366 } else if ctx.Config().AllowMissingDependencies() {
367 ctx.AddMissingDependencies([]string{apiDir})
368 } else {
369 ctx.ModuleErrorf("API version %s path %s does not exist", ver, apiDir)
370 }
371 }
Jiyong Park72e08932021-05-21 00:18:20 +0900372 var latestVersionDump *apiDump
373 if len(dumps) >= 1 {
374 latestVersionDump = &dumps[len(dumps)-1]
375 }
Jeongik Chada36d5a2021-01-20 00:43:34 +0900376 if currentApiDir.Valid() {
377 dumps = append(dumps, currentApiDump)
378 }
379 for i, _ := range dumps {
380 if dumps[i].hashFile.Valid() {
381 checkHashTimestamp := m.checkIntegrity(ctx, dumps[i])
382 m.checkHashTimestamps = append(m.checkHashTimestamps, checkHashTimestamp)
383 }
384
385 if i == 0 {
386 continue
387 }
388 checked := m.checkCompatibility(ctx, dumps[i-1], dumps[i])
389 m.checkApiTimestamps = append(m.checkApiTimestamps, checked)
390 }
391
392 // API dump from source is updated to the 'current' version. Triggered by `m <name>-update-api`
Jiyong Park72e08932021-05-21 00:18:20 +0900393 m.updateApiTimestamp = m.makeApiDumpAsVersion(ctx, totApiDump, currentVersion, nil)
Jeongik Chada36d5a2021-01-20 00:43:34 +0900394
395 // API dump from source is frozen as the next stable version. Triggered by `m <name>-freeze-api`
396 nextVersion := m.nextVersion()
Jiyong Park72e08932021-05-21 00:18:20 +0900397 m.freezeApiTimestamp = m.makeApiDumpAsVersion(ctx, totApiDump, nextVersion, latestVersionDump)
Jeongik Chada36d5a2021-01-20 00:43:34 +0900398}
399
400func (m *aidlApi) AndroidMk() android.AndroidMkData {
401 return android.AndroidMkData{
402 Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
403 android.WriteAndroidMkData(w, data)
404 targetName := m.properties.BaseName + "-freeze-api"
405 fmt.Fprintln(w, ".PHONY:", targetName)
406 fmt.Fprintln(w, targetName+":", m.freezeApiTimestamp.String())
407
408 targetName = m.properties.BaseName + "-update-api"
409 fmt.Fprintln(w, ".PHONY:", targetName)
410 fmt.Fprintln(w, targetName+":", m.updateApiTimestamp.String())
411 },
412 }
413}
414
Jooyung Han8e3b72c2021-05-22 02:54:37 +0900415type depTag struct {
416 blueprint.BaseDependencyTag
417 name string
418}
419
420var (
Jooyung Han60699b52021-05-26 22:20:42 +0900421 apiDep = depTag{name: "api"}
Jooyung Han8e3b72c2021-05-22 02:54:37 +0900422 interfaceDep = depTag{name: "interface"}
Jooyung Han60699b52021-05-26 22:20:42 +0900423
424 importApiDep = depTag{name: "imported-api"}
425 importInterfaceDep = depTag{name: "imported-interface"}
Jooyung Han8e3b72c2021-05-22 02:54:37 +0900426)
427
Jeongik Chada36d5a2021-01-20 00:43:34 +0900428func (m *aidlApi) DepsMutator(ctx android.BottomUpMutatorContext) {
Jooyung Han8e3b72c2021-05-22 02:54:37 +0900429 ctx.AddDependency(ctx.Module(), importApiDep, wrap("", m.properties.ImportsWithoutVersion, aidlApiSuffix)...)
Jooyung Han60699b52021-05-26 22:20:42 +0900430 ctx.AddDependency(ctx.Module(), importInterfaceDep, wrap("", m.properties.ImportsWithoutVersion, aidlInterfaceSuffix)...)
Jooyung Han8e3b72c2021-05-22 02:54:37 +0900431 ctx.AddDependency(ctx.Module(), interfaceDep, m.properties.BaseName+aidlInterfaceSuffix)
Jeongik Chada36d5a2021-01-20 00:43:34 +0900432}
433
434func aidlApiFactory() android.Module {
435 m := &aidlApi{}
436 m.AddProperties(&m.properties)
437 android.InitAndroidModule(m)
438 return m
439}
440
441func addApiModule(mctx android.LoadHookContext, i *aidlInterface) string {
442 apiModule := i.ModuleBase.Name() + aidlApiSuffix
Jeongik Cha52e98022021-01-20 18:37:20 +0900443 srcs, aidlRoot := i.srcsForVersion(mctx, i.nextVersion())
Jeongik Chada36d5a2021-01-20 00:43:34 +0900444 mctx.CreateModule(aidlApiFactory, &nameProperties{
445 Name: proptools.StringPtr(apiModule),
446 }, &aidlApiProperties{
Jeongik Chaa01447d2021-03-17 17:43:12 +0900447 BaseName: i.ModuleBase.Name(),
448 Srcs: srcs,
449 AidlRoot: aidlRoot,
450 Stability: i.properties.Stability,
Jooyung Han8e3b72c2021-05-22 02:54:37 +0900451 ImportsWithoutVersion: i.properties.ImportsWithoutVersion,
Jeongik Chaa01447d2021-03-17 17:43:12 +0900452 Versions: i.properties.Versions,
453 Dumpapi: i.properties.Dumpapi,
Jeongik Chada36d5a2021-01-20 00:43:34 +0900454 })
455 return apiModule
456}
Jeongik Cha6cc16f32021-05-18 11:23:55 +0900457
458func versionForHashGen(ver string) string {
459 // aidlHashGen uses the version before current version. If it has never been frozen, return 'latest-version'.
460 verInt, _ := strconv.Atoi(ver)
461 if verInt > 1 {
462 return strconv.Itoa(verInt - 1)
463 }
464 return "latest-version"
465}
Jiyong Parke38dab42021-05-20 14:25:34 +0900466
467func init() {
468 android.RegisterSingletonType("aidl-freeze-api", freezeApiSingletonFactory)
469}
470
471func freezeApiSingletonFactory() android.Singleton {
472 return &freezeApiSingleton{}
473}
474
475type freezeApiSingleton struct{}
476
477func (f *freezeApiSingleton) GenerateBuildActions(ctx android.SingletonContext) {
478 var files android.Paths
479 ctx.VisitAllModules(func(module android.Module) {
480 if !module.Enabled() {
481 return
482 }
483 if m, ok := module.(*aidlApi); ok {
484 files = append(files, m.freezeApiTimestamp)
485 }
486 })
487 ctx.Phony("aidl-freeze-api", files...)
488}