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