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 "fmt" 24 "io" 25 "path/filepath" 26 "strconv" 27 "strings" 28 "sync" 29 30 "github.com/google/blueprint" 31 "github.com/google/blueprint/pathtools" 32 "github.com/google/blueprint/proptools" 33) 34 35var ( 36 aidlInterfaceSuffix = "_interface" 37 aidlApiSuffix = "-api" 38 langCpp = "cpp" 39 langJava = "java" 40 langNdk = "ndk" 41 langNdkPlatform = "ndk_platform" 42 futureVersion = "10000" 43 44 pctx = android.NewPackageContext("android/aidl") 45 46 aidlDirPrepareRule = pctx.StaticRule("aidlDirPrepareRule", blueprint.RuleParams{ 47 Command: `rm -rf "${outDir}" && mkdir -p "${outDir}" && ` + 48 `touch ${out}`, 49 Description: "create ${out}", 50 }, "outDir") 51 52 aidlCppRule = pctx.StaticRule("aidlCppRule", blueprint.RuleParams{ 53 Command: `mkdir -p "${headerDir}" && ` + 54 `${aidlCmd} --lang=${lang} ${optionalFlags} --structured --ninja -d ${out}.d ` + 55 `-h ${headerDir} -o ${outDir} ${imports} ${in}`, 56 Depfile: "${out}.d", 57 Deps: blueprint.DepsGCC, 58 CommandDeps: []string{"${aidlCmd}"}, 59 Description: "AIDL ${lang} ${in}", 60 }, "imports", "lang", "headerDir", "outDir", "optionalFlags") 61 62 aidlJavaRule = pctx.StaticRule("aidlJavaRule", blueprint.RuleParams{ 63 Command: `${aidlCmd} --lang=java ${optionalFlags} --structured --ninja -d ${out}.d ` + 64 `-o ${outDir} ${imports} ${in}`, 65 Depfile: "${out}.d", 66 Deps: blueprint.DepsGCC, 67 CommandDeps: []string{"${aidlCmd}"}, 68 Description: "AIDL Java ${in}", 69 }, "imports", "outDir", "optionalFlags") 70 71 aidlDumpApiRule = pctx.StaticRule("aidlDumpApiRule", blueprint.RuleParams{ 72 Command: `rm -rf "${out}" && mkdir -p "${out}" && ` + 73 `${aidlCmd} --dumpapi --structured ${imports} --out ${out} ${in}`, 74 CommandDeps: []string{"${aidlCmd}"}, 75 }, "imports") 76 77 aidlDumpMappingsRule = pctx.StaticRule("aidlDumpMappingsRule", blueprint.RuleParams{ 78 Command: `rm -rf "${outDir}" && mkdir -p "${outDir}" && ` + 79 `${aidlCmd} --apimapping ${outDir}/intermediate.txt ${in} ${imports} && ` + 80 `${aidlToJniCmd} ${outDir}/intermediate.txt ${out}`, 81 CommandDeps: []string{"${aidlCmd}"}, 82 }, "imports", "outDir") 83 84 aidlFreezeApiRule = pctx.AndroidStaticRule("aidlFreezeApiRule", 85 blueprint.RuleParams{ 86 Command: `mkdir -p ${to} && rm -rf ${to}/* && ` + 87 `${bpmodifyCmd} -w -m ${name} -parameter versions -a ${version} ${bp} && ` + 88 `cp -rf ${in}/* ${to} && ` + 89 `find ${to} -type f -exec bash -c ` + 90 `"cat ${apiPreamble} {} > {}.temp; mv {}.temp {}" \; && ` + 91 `touch ${out}`, 92 CommandDeps: []string{"${bpmodifyCmd}"}, 93 }, "to", "name", "version", "bp", "apiPreamble") 94 95 aidlCheckApiRule = pctx.StaticRule("aidlCheckApiRule", blueprint.RuleParams{ 96 Command: `(${aidlCmd} --checkapi ${old} ${new} && touch ${out}) || ` + 97 `(cat ${messageFile} && exit 1)`, 98 CommandDeps: []string{"${aidlCmd}"}, 99 Description: "AIDL CHECK API: ${new} against ${old}", 100 }, "old", "new", "messageFile") 101 102 aidlDiffApiRule = pctx.StaticRule("aidlDiffApiRule", blueprint.RuleParams{ 103 Command: `(diff -r -B -I '//.*' ${old} ${new} && touch ${out}) || ` + 104 `(cat ${messageFile} && exit 1)`, 105 Description: "Check equality of ${new} and ${old}", 106 }, "old", "new", "messageFile") 107) 108 109func init() { 110 pctx.HostBinToolVariable("aidlCmd", "aidl") 111 pctx.HostBinToolVariable("bpmodifyCmd", "bpmodify") 112 pctx.SourcePathVariable("aidlToJniCmd", "system/tools/aidl/build/aidl_to_jni.py") 113 android.RegisterModuleType("aidl_interface", aidlInterfaceFactory) 114 android.RegisterModuleType("aidl_mapping", aidlMappingFactory) 115} 116 117// wrap(p, a, s) = [p + v + s for v in a] 118func wrap(prefix string, strs []string, suffix string) []string { 119 ret := make([]string, len(strs)) 120 for i, v := range strs { 121 ret[i] = prefix + v + suffix 122 } 123 return ret 124} 125 126// concat(a...) = sum((i for i in a), []) 127func concat(sstrs ...[]string) []string { 128 var ret []string 129 for _, v := range sstrs { 130 ret = append(ret, v...) 131 } 132 return ret 133} 134 135func isRelativePath(path string) bool { 136 if path == "" { 137 return true 138 } 139 return filepath.Clean(path) == path && path != ".." && 140 !strings.HasPrefix(path, "../") && !strings.HasPrefix(path, "/") 141} 142 143type aidlGenProperties struct { 144 Srcs []string 145 AidlRoot string // base directory for the input aidl file 146 Imports []string 147 Lang string // target language [java|cpp|ndk] 148 BaseName string 149 GenLog bool 150 Version string 151} 152 153type aidlGenRule struct { 154 android.ModuleBase 155 156 properties aidlGenProperties 157 158 implicitInputs android.Paths 159 importFlags string 160 161 genOutDir android.ModuleGenPath 162 genHeaderDir android.ModuleGenPath 163 genOutputs android.WritablePaths 164} 165 166var _ android.SourceFileProducer = (*aidlGenRule)(nil) 167var _ genrule.SourceFileGenerator = (*aidlGenRule)(nil) 168 169func (g *aidlGenRule) GenerateAndroidBuildActions(ctx android.ModuleContext) { 170 genDirTimestamp := android.PathForModuleGen(ctx, "timestamp") 171 g.implicitInputs = append(g.implicitInputs, genDirTimestamp) 172 173 var importPaths []string 174 ctx.VisitDirectDeps(func(dep android.Module) { 175 if importedAidl, ok := dep.(*aidlInterface); ok { 176 importPaths = append(importPaths, importedAidl.properties.Full_import_paths...) 177 } else if api, ok := dep.(*aidlApi); ok { 178 // When compiling an AIDL interface, also make sure that each 179 // version of the interface is compatible with its previous version 180 for _, path := range api.checkApiTimestamps { 181 g.implicitInputs = append(g.implicitInputs, path) 182 } 183 } 184 }) 185 g.importFlags = strings.Join(wrap("-I", importPaths, ""), " ") 186 187 srcs := android.PathsWithModuleSrcSubDir(ctx, android.PathsForModuleSrc(ctx, g.properties.Srcs), g.properties.AidlRoot) 188 189 g.genOutDir = android.PathForModuleGen(ctx) 190 g.genHeaderDir = android.PathForModuleGen(ctx, "include") 191 for _, src := range srcs { 192 g.genOutputs = append(g.genOutputs, g.generateBuildActionsForSingleAidl(ctx, src)) 193 } 194 195 // This is to clean genOutDir before generating any file 196 ctx.ModuleBuild(pctx, android.ModuleBuildParams{ 197 Rule: aidlDirPrepareRule, 198 Implicits: srcs, 199 Output: genDirTimestamp, 200 Args: map[string]string{ 201 "outDir": g.genOutDir.String(), 202 }, 203 }) 204} 205 206func (g *aidlGenRule) generateBuildActionsForSingleAidl(ctx android.ModuleContext, src android.Path) android.WritablePath { 207 var outFile android.WritablePath 208 if g.properties.Lang == langJava { 209 outFile = android.PathForModuleGen(ctx, pathtools.ReplaceExtension(src.Rel(), "java")) 210 } else { 211 outFile = android.PathForModuleGen(ctx, pathtools.ReplaceExtension(src.Rel(), "cpp")) 212 } 213 214 var optionalFlags []string 215 if g.properties.Version != "" { 216 optionalFlags = append(optionalFlags, "--version "+g.properties.Version) 217 } 218 219 if g.properties.Lang == langJava { 220 ctx.ModuleBuild(pctx, android.ModuleBuildParams{ 221 Rule: aidlJavaRule, 222 Input: src, 223 Implicits: g.implicitInputs, 224 Output: outFile, 225 Args: map[string]string{ 226 "imports": g.importFlags, 227 "outDir": g.genOutDir.String(), 228 "optionalFlags": strings.Join(optionalFlags, " "), 229 }, 230 }) 231 } else { 232 typeName := strings.TrimSuffix(filepath.Base(src.Rel()), ".aidl") 233 packagePath := filepath.Dir(src.Rel()) 234 baseName := typeName 235 // TODO(b/111362593): aidl_to_cpp_common.cpp uses heuristics to figure out if 236 // an interface name has a leading I. Those same heuristics have been 237 // moved here. 238 if len(baseName) >= 2 && baseName[0] == 'I' && 239 strings.ToUpper(baseName)[1] == baseName[1] { 240 baseName = strings.TrimPrefix(typeName, "I") 241 } 242 243 prefix := "" 244 if g.properties.Lang == langNdk || g.properties.Lang == langNdkPlatform { 245 prefix = "aidl" 246 } 247 248 var headers android.WritablePaths 249 headers = append(headers, g.genHeaderDir.Join(ctx, prefix, packagePath, 250 typeName+".h")) 251 headers = append(headers, g.genHeaderDir.Join(ctx, prefix, packagePath, 252 "Bp"+baseName+".h")) 253 headers = append(headers, g.genHeaderDir.Join(ctx, prefix, packagePath, 254 "Bn"+baseName+".h")) 255 256 if g.properties.GenLog { 257 optionalFlags = append(optionalFlags, "--log") 258 } 259 260 aidlLang := g.properties.Lang 261 if aidlLang == langNdkPlatform { 262 aidlLang = "ndk" 263 } 264 265 ctx.ModuleBuild(pctx, android.ModuleBuildParams{ 266 Rule: aidlCppRule, 267 Input: src, 268 Implicits: g.implicitInputs, 269 Output: outFile, 270 ImplicitOutputs: headers, 271 Args: map[string]string{ 272 "imports": g.importFlags, 273 "lang": aidlLang, 274 "headerDir": g.genHeaderDir.String(), 275 "outDir": g.genOutDir.String(), 276 "optionalFlags": strings.Join(optionalFlags, " "), 277 }, 278 }) 279 } 280 281 return outFile 282} 283 284func (g *aidlGenRule) GeneratedSourceFiles() android.Paths { 285 return g.genOutputs.Paths() 286} 287 288func (g *aidlGenRule) Srcs() android.Paths { 289 return g.genOutputs.Paths() 290} 291 292func (g *aidlGenRule) GeneratedDeps() android.Paths { 293 return g.genOutputs.Paths() 294} 295 296func (g *aidlGenRule) GeneratedHeaderDirs() android.Paths { 297 return android.Paths{g.genHeaderDir} 298} 299 300func (g *aidlGenRule) DepsMutator(ctx android.BottomUpMutatorContext) { 301 ctx.AddDependency(ctx.Module(), nil, wrap("", g.properties.Imports, aidlInterfaceSuffix)...) 302 ctx.AddDependency(ctx.Module(), nil, g.properties.BaseName+aidlApiSuffix) 303} 304 305func aidlGenFactory() android.Module { 306 g := &aidlGenRule{} 307 g.AddProperties(&g.properties) 308 android.InitAndroidModule(g) 309 return g 310} 311 312type aidlApiProperties struct { 313 BaseName string 314 Inputs []string 315 Imports []string 316 Api_dir *string 317 Versions []string 318 AidlRoot string // base directory for the input aidl file 319} 320 321type aidlApi struct { 322 android.ModuleBase 323 324 properties aidlApiProperties 325 326 // for triggering api check for version X against version X-1 327 checkApiTimestamps android.WritablePaths 328 329 // for triggering freezing API as the new version 330 freezeApiTimestamp android.WritablePath 331} 332 333func (m *aidlApi) apiDir() string { 334 if m.properties.Api_dir != nil { 335 return *(m.properties.Api_dir) 336 } else { 337 return "api" 338 } 339} 340 341// Version of the interface at ToT if it is frozen 342func (m *aidlApi) validateCurrentVersion(ctx android.ModuleContext) string { 343 if len(m.properties.Versions) == 0 { 344 return "1" 345 } else { 346 latestVersion := m.properties.Versions[len(m.properties.Versions)-1] 347 348 i, err := strconv.ParseInt(latestVersion, 10, 64) 349 if err != nil { 350 ctx.PropertyErrorf("versions", "must be integers") 351 return "" 352 } 353 354 return strconv.FormatInt(i+1, 10) 355 } 356} 357 358func (m *aidlApi) createApiDumpFromSource(ctx android.ModuleContext) (apiDir android.WritablePath, apiFiles android.WritablePaths) { 359 var importPaths []string 360 ctx.VisitDirectDeps(func(dep android.Module) { 361 if importedAidl, ok := dep.(*aidlInterface); ok { 362 importPaths = append(importPaths, importedAidl.properties.Full_import_paths...) 363 } 364 }) 365 366 var srcs android.Paths 367 for _, input := range m.properties.Inputs { 368 path := android.PathForModuleSrc(ctx, input) 369 path = android.PathWithModuleSrcSubDir(ctx, path, m.properties.AidlRoot) 370 srcs = append(srcs, path) 371 } 372 373 apiDir = android.PathForModuleOut(ctx, "dump") 374 for _, src := range srcs { 375 apiFiles = append(apiFiles, android.PathForModuleOut(ctx, "dump", src.Rel())) 376 } 377 imports := strings.Join(wrap("-I", importPaths, ""), " ") 378 ctx.ModuleBuild(pctx, android.ModuleBuildParams{ 379 Rule: aidlDumpApiRule, 380 Inputs: srcs, 381 Output: apiDir, 382 ImplicitOutputs: apiFiles, 383 Args: map[string]string{ 384 "imports": imports, 385 }, 386 }) 387 return apiDir, apiFiles 388} 389 390func (m *aidlApi) freezeApiDumpAsVersion(ctx android.ModuleContext, apiDumpDir android.Path, apiFiles android.Paths, version string) android.WritablePath { 391 timestampFile := android.PathForModuleOut(ctx, "freezeapi_"+version+".timestamp") 392 393 modulePath := android.PathForModuleSrc(ctx).String() 394 395 var implicits android.Paths 396 implicits = append(implicits, apiFiles...) 397 398 apiPreamble := android.PathForSource(ctx, "system/tools/aidl/build/api_preamble.txt") 399 implicits = append(implicits, apiPreamble) 400 401 ctx.ModuleBuild(pctx, android.ModuleBuildParams{ 402 Rule: aidlFreezeApiRule, 403 Description: "Freezing AIDL API of " + m.properties.BaseName + " as version " + version, 404 Implicits: implicits, 405 Output: timestampFile, 406 Args: map[string]string{ 407 "to": filepath.Join(modulePath, m.apiDir(), version), 408 "name": m.properties.BaseName, 409 "version": version, 410 "bp": android.PathForModuleSrc(ctx, "Android.bp").String(), 411 "apiPreamble": apiPreamble.String(), 412 }, 413 }) 414 return timestampFile 415} 416 417func (m *aidlApi) checkCompatibility(ctx android.ModuleContext, oldApiDir android.Path, oldApiFiles android.Paths, newApiDir android.Path, newApiFiles android.Paths) android.WritablePath { 418 newVersion := newApiDir.Base() 419 timestampFile := android.PathForModuleOut(ctx, "checkapi_"+newVersion+".timestamp") 420 messageFile := android.PathForSource(ctx, "system/tools/aidl/build/message_check_compatibility.txt") 421 var implicits android.Paths 422 implicits = append(implicits, oldApiFiles...) 423 implicits = append(implicits, newApiFiles...) 424 implicits = append(implicits, messageFile) 425 ctx.ModuleBuild(pctx, android.ModuleBuildParams{ 426 Rule: aidlCheckApiRule, 427 Implicits: implicits, 428 Output: timestampFile, 429 Args: map[string]string{ 430 "old": oldApiDir.String(), 431 "new": newApiDir.String(), 432 "messageFile": messageFile.String(), 433 }, 434 }) 435 return timestampFile 436} 437 438func (m *aidlApi) checkEquality(ctx android.ModuleContext, oldApiDir android.Path, oldApiFiles android.Paths, newApiDir android.Path, newApiFiles android.Paths) android.WritablePath { 439 newVersion := newApiDir.Base() 440 timestampFile := android.PathForModuleOut(ctx, "checkapi_"+newVersion+".timestamp") 441 messageFile := android.PathForSource(ctx, "system/tools/aidl/build/message_check_equality.txt") 442 var implicits android.Paths 443 implicits = append(implicits, oldApiFiles...) 444 implicits = append(implicits, newApiFiles...) 445 implicits = append(implicits, messageFile) 446 ctx.ModuleBuild(pctx, android.ModuleBuildParams{ 447 Rule: aidlDiffApiRule, 448 Implicits: implicits, 449 Output: timestampFile, 450 Args: map[string]string{ 451 "old": oldApiDir.String(), 452 "new": newApiDir.String(), 453 "messageFile": messageFile.String(), 454 }, 455 }) 456 return timestampFile 457} 458 459func (m *aidlApi) GenerateAndroidBuildActions(ctx android.ModuleContext) { 460 currentVersion := m.validateCurrentVersion(ctx) 461 462 if ctx.Failed() { 463 return 464 } 465 466 currentDumpDir, currentApiFiles := m.createApiDumpFromSource(ctx) 467 m.freezeApiTimestamp = m.freezeApiDumpAsVersion(ctx, currentDumpDir, currentApiFiles.Paths(), currentVersion) 468 469 apiDirs := make(map[string]android.Path) 470 apiFiles := make(map[string]android.Paths) 471 for _, ver := range m.properties.Versions { 472 apiDir := android.PathForModuleSrc(ctx, m.apiDir(), ver) 473 apiDirs[ver] = apiDir 474 apiFiles[ver] = ctx.Glob(filepath.Join(apiDir.String(), "**/*.aidl"), nil) 475 } 476 apiDirs[currentVersion] = currentDumpDir 477 apiFiles[currentVersion] = currentApiFiles.Paths() 478 479 // Check that version X is backward compatible with version X-1 480 for i, newVersion := range m.properties.Versions { 481 if i != 0 { 482 oldVersion := m.properties.Versions[i-1] 483 checkApiTimestamp := m.checkCompatibility(ctx, apiDirs[oldVersion], apiFiles[oldVersion], apiDirs[newVersion], apiFiles[newVersion]) 484 m.checkApiTimestamps = append(m.checkApiTimestamps, checkApiTimestamp) 485 } 486 } 487 488 // ... and that the currentVersion (ToT) is backwards compatible with or 489 // equal to the latest frozen version 490 if len(m.properties.Versions) >= 1 { 491 latestVersion := m.properties.Versions[len(m.properties.Versions)-1] 492 var checkApiTimestamp android.WritablePath 493 if ctx.Config().DefaultAppTargetSdkInt() != android.FutureApiLevel { 494 // If API is frozen, don't allow any change to the API 495 checkApiTimestamp = m.checkEquality(ctx, apiDirs[latestVersion], apiFiles[latestVersion], apiDirs[currentVersion], apiFiles[currentVersion]) 496 } else { 497 // If not, allow backwards compatible changes to the API 498 checkApiTimestamp = m.checkCompatibility(ctx, apiDirs[latestVersion], apiFiles[latestVersion], apiDirs[currentVersion], apiFiles[currentVersion]) 499 } 500 m.checkApiTimestamps = append(m.checkApiTimestamps, checkApiTimestamp) 501 } 502} 503 504func (m *aidlApi) AndroidMk() android.AndroidMkData { 505 return android.AndroidMkData{ 506 Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) { 507 android.WriteAndroidMkData(w, data) 508 targetName := m.properties.BaseName + "-freeze-api" 509 fmt.Fprintln(w, ".PHONY:", targetName) 510 fmt.Fprintln(w, targetName+":", m.freezeApiTimestamp.String()) 511 }, 512 } 513} 514 515func (m *aidlApi) DepsMutator(ctx android.BottomUpMutatorContext) { 516 ctx.AddDependency(ctx.Module(), nil, wrap("", m.properties.Imports, aidlInterfaceSuffix)...) 517} 518 519func aidlApiFactory() android.Module { 520 m := &aidlApi{} 521 m.AddProperties(&m.properties) 522 android.InitAndroidModule(m) 523 return m 524} 525 526type aidlInterfaceProperties struct { 527 // Vndk properties for interface library only. 528 cc.VndkProperties 529 530 // Whether the library can be installed on the vendor image. 531 Vendor_available *bool 532 // Top level directories for includes. 533 // TODO(b/128940869): remove it if aidl_interface can depend on framework.aidl 534 Include_dirs []string 535 // Relative path for includes. By default assumes AIDL path is relative to current directory. 536 // TODO(b/111117220): automatically compute by letting AIDL parse multiple files simultaneously 537 Local_include_dir string 538 539 // The owner of the module 540 Owner *string 541 542 // List of .aidl files which compose this interface. These may be globbed. 543 Srcs []string 544 545 Imports []string 546 547 // Used by gen dependency to fill out aidl include path 548 Full_import_paths []string `blueprint:"mutated"` 549 550 // Directory where API dumps are. Default is "api". 551 Api_dir *string 552 553 // Previous API versions that are now frozen. The version that is last in 554 // the list is considered as the most recent version. 555 Versions []string 556 557 Backend struct { 558 Java struct { 559 // Whether to generate Java code using Java binder APIs 560 // Default: true 561 Enabled *bool 562 // Set to the version of the sdk to compile against 563 // Default: system_current 564 Sdk_version *string 565 } 566 Cpp struct { 567 // Whether to generate C++ code using C++ binder APIs 568 // Default: true 569 Enabled *bool 570 // Whether to generate additional code for gathering information 571 // about the transactions 572 // Default: false 573 Gen_log *bool 574 } 575 Ndk struct { 576 // Whether to generate C++ code using NDK binder APIs 577 // Default: true 578 Enabled *bool 579 // Whether to generate additional code for gathering information 580 // about the transactions 581 // Default: false 582 Gen_log *bool 583 } 584 } 585} 586 587type aidlInterface struct { 588 android.ModuleBase 589 590 properties aidlInterfaceProperties 591 592 // Unglobbed sources 593 rawSrcs []string 594} 595 596func (i *aidlInterface) shouldGenerateJavaBackend() bool { 597 // explicitly true if not specified to give early warning to devs 598 return i.properties.Backend.Java.Enabled == nil || *i.properties.Backend.Java.Enabled 599} 600 601func (i *aidlInterface) shouldGenerateCppBackend() bool { 602 // explicitly true if not specified to give early warning to devs 603 return i.properties.Backend.Cpp.Enabled == nil || *i.properties.Backend.Cpp.Enabled 604} 605 606func (i *aidlInterface) shouldGenerateNdkBackend() bool { 607 // explicitly true if not specified to give early warning to devs 608 return i.properties.Backend.Ndk.Enabled == nil || *i.properties.Backend.Ndk.Enabled 609} 610 611func (i *aidlInterface) checkAndUpdateSources(mctx android.LoadHookContext) { 612 prefix := mctx.ModuleDir() 613 for _, source := range i.properties.Srcs { 614 if pathtools.IsGlob(source) { 615 globbedSrcFiles, err := mctx.GlobWithDeps(filepath.Join(prefix, source), nil) 616 if err != nil { 617 mctx.ModuleErrorf("glob: %s", err.Error()) 618 } 619 for _, globbedSrc := range globbedSrcFiles { 620 relativeGlobbedSrc, err := filepath.Rel(prefix, globbedSrc) 621 if err != nil { 622 panic(err) 623 } 624 625 i.rawSrcs = append(i.rawSrcs, relativeGlobbedSrc) 626 } 627 } else { 628 i.rawSrcs = append(i.rawSrcs, source) 629 } 630 } 631 632 if len(i.rawSrcs) == 0 { 633 mctx.PropertyErrorf("srcs", "No sources provided.") 634 } 635 636 for _, source := range i.rawSrcs { 637 if !strings.HasSuffix(source, ".aidl") { 638 mctx.PropertyErrorf("srcs", "Source must be a .aidl file: "+source) 639 continue 640 } 641 642 relativePath, err := filepath.Rel(i.properties.Local_include_dir, source) 643 if err != nil || !isRelativePath(relativePath) { 644 mctx.PropertyErrorf("srcs", "Source is not in local_include_dir: "+source) 645 } 646 } 647} 648 649func (i *aidlInterface) checkImports(mctx android.LoadHookContext) { 650 for _, anImport := range i.properties.Imports { 651 other := lookupInterface(anImport) 652 653 if other == nil { 654 mctx.PropertyErrorf("imports", "Import does not exist: "+anImport) 655 } 656 657 if i.shouldGenerateCppBackend() && !other.shouldGenerateCppBackend() { 658 mctx.PropertyErrorf("backend.cpp.enabled", 659 "C++ backend not enabled in the imported AIDL interface %q", anImport) 660 } 661 662 if i.shouldGenerateNdkBackend() && !other.shouldGenerateNdkBackend() { 663 mctx.PropertyErrorf("backend.ndk.enabled", 664 "NDK backend not enabled in the imported AIDL interface %q", anImport) 665 } 666 } 667} 668 669func (i *aidlInterface) versionedName(version string) string { 670 name := i.ModuleBase.Name() 671 if version != futureVersion && version != "" { 672 name = name + "-V" + version 673 } 674 return name 675} 676 677func (i *aidlInterface) srcsForVersion(mctx android.LoadHookContext, version string) (srcs []string, base string) { 678 if version == futureVersion || version == "" { 679 return i.rawSrcs, i.properties.Local_include_dir 680 } else { 681 var apiDir string 682 if i.properties.Api_dir != nil { 683 apiDir = *(i.properties.Api_dir) 684 } else { 685 apiDir = "api" 686 } 687 base = filepath.Join(apiDir, version) 688 full_paths, err := mctx.GlobWithDeps(filepath.Join(mctx.ModuleDir(), base, "**/*.aidl"), nil) 689 if err != nil { 690 panic(err) 691 } 692 for _, path := range full_paths { 693 // Here, we need path local to the module 694 srcs = append(srcs, strings.TrimPrefix(path, mctx.ModuleDir()+"/")) 695 } 696 return srcs, base 697 } 698} 699 700func aidlInterfaceHook(mctx android.LoadHookContext, i *aidlInterface) { 701 if !isRelativePath(i.properties.Local_include_dir) { 702 mctx.PropertyErrorf("local_include_dir", "must be relative path: "+i.properties.Local_include_dir) 703 } 704 var importPaths []string 705 importPaths = append(importPaths, filepath.Join(mctx.ModuleDir(), i.properties.Local_include_dir)) 706 importPaths = append(importPaths, i.properties.Include_dirs...) 707 708 i.properties.Full_import_paths = importPaths 709 710 i.checkAndUpdateSources(mctx) 711 i.checkImports(mctx) 712 713 if mctx.Failed() { 714 return 715 } 716 717 var libs []string 718 719 currentVersion := "" 720 if len(i.properties.Versions) > 0 { 721 currentVersion = futureVersion 722 } 723 724 if i.shouldGenerateCppBackend() { 725 libs = append(libs, addCppLibrary(mctx, i, currentVersion, langCpp)) 726 for _, version := range i.properties.Versions { 727 addCppLibrary(mctx, i, version, langCpp) 728 } 729 } 730 731 if i.shouldGenerateNdkBackend() { 732 // TODO(b/119771576): inherit properties and export 'is vendor' computation from cc.go 733 if !proptools.Bool(i.properties.Vendor_available) { 734 libs = append(libs, addCppLibrary(mctx, i, currentVersion, langNdk)) 735 for _, version := range i.properties.Versions { 736 addCppLibrary(mctx, i, version, langNdk) 737 } 738 } 739 // TODO(b/121157555): combine with '-ndk' variant 740 libs = append(libs, addCppLibrary(mctx, i, currentVersion, langNdkPlatform)) 741 for _, version := range i.properties.Versions { 742 addCppLibrary(mctx, i, version, langNdkPlatform) 743 } 744 } 745 746 libs = append(libs, addJavaLibrary(mctx, i, currentVersion)) 747 for _, version := range i.properties.Versions { 748 addJavaLibrary(mctx, i, version) 749 } 750 751 addApiModule(mctx, i) 752 753 // Reserve this module name for future use 754 mctx.CreateModule(android.ModuleFactoryAdaptor(phony.PhonyFactory), &phonyProperties{ 755 Name: proptools.StringPtr(i.ModuleBase.Name()), 756 Required: libs, 757 }) 758} 759 760func addCppLibrary(mctx android.LoadHookContext, i *aidlInterface, version string, lang string) string { 761 cppSourceGen := i.versionedName(version) + "-" + lang + "-source" 762 cppModuleGen := i.versionedName(version) + "-" + lang 763 764 srcs, base := i.srcsForVersion(mctx, version) 765 if len(srcs) == 0 { 766 // This can happen when the version is about to be frozen; the version 767 // directory is created but API dump hasn't been copied there. 768 // Don't create a library for the yet-to-be-frozen version. 769 return "" 770 } 771 772 genLog := false 773 if lang == langCpp { 774 genLog = proptools.Bool(i.properties.Backend.Cpp.Gen_log) 775 } else if lang == langNdk || lang == langNdkPlatform { 776 genLog = proptools.Bool(i.properties.Backend.Ndk.Gen_log) 777 } 778 779 mctx.CreateModule(android.ModuleFactoryAdaptor(aidlGenFactory), &nameProperties{ 780 Name: proptools.StringPtr(cppSourceGen), 781 }, &aidlGenProperties{ 782 Srcs: srcs, 783 AidlRoot: base, 784 Imports: concat(i.properties.Imports, []string{i.ModuleBase.Name()}), 785 Lang: lang, 786 BaseName: i.ModuleBase.Name(), 787 GenLog: genLog, 788 Version: version, 789 }) 790 791 importExportDependencies := wrap("", i.properties.Imports, "-"+lang) 792 var libJSONCppDependency []string 793 var staticLibDependency []string 794 var sdkVersion *string 795 var stl *string 796 var cpp_std *string 797 if lang == langCpp { 798 importExportDependencies = append(importExportDependencies, "libbinder", "libutils") 799 if genLog { 800 libJSONCppDependency = []string{"libjsoncpp"} 801 } 802 sdkVersion = nil 803 stl = nil 804 cpp_std = nil 805 } else if lang == langNdk { 806 importExportDependencies = append(importExportDependencies, "libbinder_ndk") 807 if genLog { 808 staticLibDependency = []string{"libjsoncpp_ndk"} 809 } 810 sdkVersion = proptools.StringPtr("current") 811 stl = proptools.StringPtr("c++_shared") 812 } else if lang == langNdkPlatform { 813 importExportDependencies = append(importExportDependencies, "libbinder_ndk") 814 if genLog { 815 libJSONCppDependency = []string{"libjsoncpp"} 816 } 817 } else { 818 panic("Unrecognized language: " + lang) 819 } 820 821 mctx.CreateModule(android.ModuleFactoryAdaptor(cc.LibraryFactory), &ccProperties{ 822 Name: proptools.StringPtr(cppModuleGen), 823 Owner: i.properties.Owner, 824 Vendor_available: i.properties.Vendor_available, 825 Defaults: []string{"aidl-cpp-module-defaults"}, 826 Generated_sources: []string{cppSourceGen}, 827 Generated_headers: []string{cppSourceGen}, 828 Export_generated_headers: []string{cppSourceGen}, 829 Static: staticLib{Whole_static_libs: libJSONCppDependency}, 830 Shared: sharedLib{Shared_libs: libJSONCppDependency, Export_shared_lib_headers: libJSONCppDependency}, 831 Static_libs: staticLibDependency, 832 Shared_libs: importExportDependencies, 833 Export_shared_lib_headers: importExportDependencies, 834 Sdk_version: sdkVersion, 835 Stl: stl, 836 Cpp_std: cpp_std, 837 Cflags: []string{"-Wextra", "-Wall", "-Werror"}, 838 }, &i.properties.VndkProperties) 839 840 return cppModuleGen 841} 842 843func addJavaLibrary(mctx android.LoadHookContext, i *aidlInterface, version string) string { 844 javaSourceGen := i.versionedName(version) + "-java-source" 845 javaModuleGen := i.versionedName(version) + "-java" 846 847 srcs, base := i.srcsForVersion(mctx, version) 848 if len(srcs) == 0 { 849 // This can happen when the version is about to be frozen; the version 850 // directory is created but API dump hasn't been copied there. 851 // Don't create a library for the yet-to-be-frozen version. 852 return "" 853 } 854 855 sdkVersion := proptools.StringDefault(i.properties.Backend.Java.Sdk_version, "system_current") 856 857 mctx.CreateModule(android.ModuleFactoryAdaptor(aidlGenFactory), &nameProperties{ 858 Name: proptools.StringPtr(javaSourceGen), 859 }, &aidlGenProperties{ 860 Srcs: srcs, 861 AidlRoot: base, 862 Imports: concat(i.properties.Imports, []string{i.ModuleBase.Name()}), 863 Lang: langJava, 864 BaseName: i.ModuleBase.Name(), 865 Version: version, 866 }) 867 868 mctx.CreateModule(android.ModuleFactoryAdaptor(java.LibraryFactory), &javaProperties{ 869 Name: proptools.StringPtr(javaModuleGen), 870 Owner: i.properties.Owner, 871 Installable: proptools.BoolPtr(true), 872 Defaults: []string{"aidl-java-module-defaults"}, 873 No_framework_libs: proptools.BoolPtr(true), 874 Sdk_version: proptools.StringPtr(sdkVersion), 875 Static_libs: wrap("", i.properties.Imports, "-java"), 876 Srcs: []string{":" + javaSourceGen}, 877 }) 878 879 return javaModuleGen 880} 881 882func addApiModule(mctx android.LoadHookContext, i *aidlInterface) string { 883 apiModule := i.ModuleBase.Name() + aidlApiSuffix 884 mctx.CreateModule(android.ModuleFactoryAdaptor(aidlApiFactory), &nameProperties{ 885 Name: proptools.StringPtr(apiModule), 886 }, &aidlApiProperties{ 887 BaseName: i.ModuleBase.Name(), 888 Inputs: i.rawSrcs, 889 Imports: concat(i.properties.Imports, []string{i.ModuleBase.Name()}), 890 Api_dir: i.properties.Api_dir, 891 AidlRoot: i.properties.Local_include_dir, 892 Versions: i.properties.Versions, 893 }) 894 return apiModule 895} 896 897func (i *aidlInterface) Name() string { 898 return i.ModuleBase.Name() + aidlInterfaceSuffix 899} 900func (i *aidlInterface) GenerateAndroidBuildActions(ctx android.ModuleContext) { 901} 902func (i *aidlInterface) DepsMutator(ctx android.BottomUpMutatorContext) { 903} 904 905var aidlInterfaceMutex sync.Mutex 906var aidlInterfaces []*aidlInterface 907 908func aidlInterfaceFactory() android.Module { 909 i := &aidlInterface{} 910 i.AddProperties(&i.properties) 911 android.InitAndroidModule(i) 912 android.AddLoadHook(i, func(ctx android.LoadHookContext) { aidlInterfaceHook(ctx, i) }) 913 914 aidlInterfaceMutex.Lock() 915 aidlInterfaces = append(aidlInterfaces, i) 916 aidlInterfaceMutex.Unlock() 917 918 return i 919} 920 921func lookupInterface(name string) *aidlInterface { 922 for _, i := range aidlInterfaces { 923 if i.ModuleBase.Name() == name { 924 return i 925 } 926 } 927 return nil 928} 929 930type aidlMappingProperties struct { 931 // Source file of this prebuilt. 932 Srcs []string `android:"arch_variant"` 933 Output string 934} 935 936type aidlMapping struct { 937 android.ModuleBase 938 properties aidlMappingProperties 939 outputFilePath android.WritablePath 940} 941 942func (s *aidlMapping) DepsMutator(ctx android.BottomUpMutatorContext) { 943 android.ExtractSourcesDeps(ctx, s.properties.Srcs) 944} 945 946func addItemsToMap(dest map[string]bool, src []string) { 947 for _, item := range src { 948 dest[item] = true 949 } 950} 951 952func (s *aidlMapping) GenerateAndroidBuildActions(ctx android.ModuleContext) { 953 var srcs android.Paths 954 var all_import_dirs map[string]bool = make(map[string]bool) 955 956 ctx.VisitDirectDeps(func(module android.Module) { 957 for _, property := range module.GetProperties() { 958 if jproperty, ok := property.(*java.CompilerProperties); ok { 959 for _, src := range jproperty.Srcs { 960 if strings.HasSuffix(src, ".aidl") { 961 full_path := android.PathForModuleSrc(ctx, src) 962 srcs = append(srcs, full_path) 963 all_import_dirs[filepath.Dir(full_path.String())] = true 964 } else if pathtools.IsGlob(src) { 965 globbedSrcFiles, err := ctx.GlobWithDeps(src, nil) 966 if err == nil { 967 for _, globbedSrc := range globbedSrcFiles { 968 full_path := android.PathForModuleSrc(ctx, globbedSrc) 969 all_import_dirs[full_path.String()] = true 970 } 971 } 972 } 973 } 974 } else if jproperty, ok := property.(*java.CompilerDeviceProperties); ok { 975 addItemsToMap(all_import_dirs, jproperty.Aidl.Include_dirs) 976 for _, include_dir := range jproperty.Aidl.Export_include_dirs { 977 var full_path = filepath.Join(ctx.ModuleDir(), include_dir) 978 all_import_dirs[full_path] = true 979 } 980 for _, include_dir := range jproperty.Aidl.Local_include_dirs { 981 var full_path = filepath.Join(ctx.ModuleSubDir(), include_dir) 982 all_import_dirs[full_path] = true 983 } 984 } 985 } 986 }) 987 988 var import_dirs []string 989 for dir := range all_import_dirs { 990 import_dirs = append(import_dirs, dir) 991 } 992 imports := strings.Join(wrap("-I", import_dirs, ""), " ") 993 s.outputFilePath = android.PathForModuleOut(ctx, s.properties.Output) 994 outDir := android.PathForModuleGen(ctx) 995 ctx.Build(pctx, android.BuildParams{ 996 Rule: aidlDumpMappingsRule, 997 Inputs: srcs, 998 Output: s.outputFilePath, 999 Args: map[string]string{ 1000 "imports": imports, 1001 "outDir": outDir.String(), 1002 }, 1003 }) 1004} 1005 1006func InitAidlMappingModule(s *aidlMapping) { 1007 s.AddProperties(&s.properties) 1008} 1009 1010func aidlMappingFactory() android.Module { 1011 module := &aidlMapping{} 1012 InitAidlMappingModule(module) 1013 android.InitAndroidModule(module) 1014 return module 1015} 1016 1017func (m *aidlMapping) AndroidMk() android.AndroidMkData { 1018 return android.AndroidMkData{ 1019 Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) { 1020 android.WriteAndroidMkData(w, data) 1021 targetName := m.Name() 1022 fmt.Fprintln(w, ".PHONY:", targetName) 1023 fmt.Fprintln(w, targetName+":", m.outputFilePath.String()) 1024 }, 1025 } 1026} 1027