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