1// Copyright 2018 Google Inc. All rights reserved. 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 java 16 17import ( 18 "crypto/sha256" 19 "fmt" 20 "path/filepath" 21 "slices" 22 "strings" 23 24 "android/soong/android" 25 "android/soong/dexpreopt" 26 27 "github.com/google/blueprint" 28 "github.com/google/blueprint/depset" 29 "github.com/google/blueprint/proptools" 30) 31 32type AndroidLibraryDependency interface { 33 ExportPackage() android.Path 34 ResourcesNodeDepSet() depset.DepSet[*resourcesNode] 35 RRODirsDepSet() depset.DepSet[rroDir] 36 ManifestsDepSet() depset.DepSet[android.Path] 37 SetRROEnforcedForDependent(enforce bool) 38 IsRROEnforced(ctx android.BaseModuleContext) bool 39} 40 41func init() { 42 RegisterAARBuildComponents(android.InitRegistrationContext) 43} 44 45func RegisterAARBuildComponents(ctx android.RegistrationContext) { 46 ctx.RegisterModuleType("android_library_import", AARImportFactory) 47 ctx.RegisterModuleType("android_library", AndroidLibraryFactory) 48 ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) { 49 ctx.Transition("propagate_rro_enforcement", &propagateRROEnforcementTransitionMutator{}) 50 }) 51} 52 53// 54// AAR (android library) 55// 56 57type androidLibraryProperties struct { 58 BuildAAR bool `blueprint:"mutated"` 59} 60 61type aaptProperties struct { 62 // flags passed to aapt when creating the apk 63 Aaptflags []string 64 65 // include all resource configurations, not just the product-configured 66 // ones. 67 Aapt_include_all_resources *bool 68 69 // list of files to use as assets. 70 Assets []string `android:"path"` 71 72 // list of directories relative to the Blueprints file containing assets. 73 // Defaults to ["assets"] if a directory called assets exists. Set to [] 74 // to disable the default. 75 Asset_dirs []string 76 77 // list of directories relative to the Blueprints file containing 78 // Android resources. Defaults to ["res"] if a directory called res exists. 79 // Set to [] to disable the default. 80 Resource_dirs proptools.Configurable[[]string] `android:"path"` 81 82 // list of zip files containing Android resources. 83 Resource_zips []string `android:"path"` 84 85 // path to AndroidManifest.xml. If unset, defaults to "AndroidManifest.xml". 86 Manifest *string `android:"path"` 87 88 // paths to additional manifest files to merge with main manifest. 89 Additional_manifests []string `android:"path"` 90 91 // do not include AndroidManifest from dependent libraries 92 Dont_merge_manifests *bool 93 94 // If use_resource_processor is set, use Bazel's resource processor instead of aapt2 to generate R.class files. 95 // The resource processor produces more optimal R.class files that only list resources in the package of the 96 // library that provided them, as opposed to aapt2 which produces R.java files for every package containing 97 // every resource. Using the resource processor can provide significant build time speedups, but requires 98 // fixing the module to use the correct package to reference each resource, and to avoid having any other 99 // libraries in the tree that use the same package name. Defaults to false, but will default to true in the 100 // future. 101 Use_resource_processor *bool 102 103 // true if RRO is enforced for any of the dependent modules 104 RROEnforcedForDependent bool `blueprint:"mutated"` 105 106 // Filter only specified product and ignore other products 107 Filter_product *string `blueprint:"mutated"` 108 109 // Names of aconfig_declarations modules that specify aconfig flags that the module depends on. 110 Flags_packages []string 111} 112 113type aapt struct { 114 aaptSrcJar android.Path 115 transitiveAaptRJars android.Paths 116 transitiveAaptResourcePackagesFile android.Path 117 exportPackage android.Path 118 manifestPath android.Path 119 proguardOptionsFile android.Path 120 rTxt android.Path 121 rJar android.Path 122 extraAaptPackagesFile android.Path 123 mergedManifestFile android.Path 124 noticeFile android.OptionalPath 125 assetPackage android.OptionalPath 126 isLibrary bool 127 defaultManifestVersion string 128 useEmbeddedNativeLibs bool 129 useEmbeddedDex bool 130 usesNonSdkApis bool 131 hasNoCode bool 132 LoggingParent string 133 resourceFiles android.Paths 134 135 splitNames []string 136 splits []split 137 138 aaptProperties aaptProperties 139 140 resourcesNodesDepSet depset.DepSet[*resourcesNode] 141 rroDirsDepSet depset.DepSet[rroDir] 142 manifestsDepSet depset.DepSet[android.Path] 143 144 manifestValues struct { 145 applicationId string 146 } 147} 148 149type split struct { 150 name string 151 suffix string 152 path android.Path 153} 154 155// Propagate RRO enforcement flag to static lib dependencies transitively. If EnforceRROGlobally is set then 156// all modules will use the "" variant. If specific modules have RRO enforced, then modules (usually apps) with 157// RRO enabled will use the "" variation for themselves, but use the "rro" variant of direct and transitive static 158// android_library dependencies. 159type propagateRROEnforcementTransitionMutator struct{} 160 161func (p propagateRROEnforcementTransitionMutator) Split(ctx android.BaseModuleContext) []string { 162 // Never split modules, apps with or without RRO enabled use the "" variant, static android_library dependencies 163 // will use create the "rro" variant from incoming tranisitons. 164 return []string{""} 165} 166 167func (p propagateRROEnforcementTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string { 168 // Non-static dependencies are not involved in RRO and always use the empty variant. 169 if ctx.DepTag() != staticLibTag { 170 return "" 171 } 172 173 m := ctx.Module() 174 if _, ok := m.(AndroidLibraryDependency); ok { 175 // If RRO is enforced globally don't bother using "rro" variants, the empty variant will have RRO enabled. 176 if ctx.Config().EnforceRROGlobally() { 177 return "" 178 } 179 180 // If RRO is enabled for this module use the "rro" variants of static dependencies. IncomingTransition will 181 // rewrite this back to "" if the dependency is not an android_library. 182 if ctx.Config().EnforceRROForModule(ctx.Module().Name()) { 183 return "rro" 184 } 185 } 186 187 return sourceVariation 188} 189 190func (p propagateRROEnforcementTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string { 191 // Propagate the "rro" variant to android_library modules, but use the empty variant for everything else. 192 if incomingVariation == "rro" { 193 m := ctx.Module() 194 if _, ok := m.(AndroidLibraryDependency); ok { 195 return "rro" 196 } 197 return "" 198 } 199 200 return "" 201} 202 203func (p propagateRROEnforcementTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) { 204 m := ctx.Module() 205 if d, ok := m.(AndroidLibraryDependency); ok { 206 if variation == "rro" { 207 // This is the "rro" variant of a module that has both variants, mark this one as RRO enabled and 208 // hide it from make to avoid collisions with the non-RRO empty variant. 209 d.SetRROEnforcedForDependent(true) 210 m.HideFromMake() 211 } else if ctx.Config().EnforceRROGlobally() { 212 // RRO is enabled globally, mark it enabled for this module, but there is only one variant so no 213 // need to hide it from make. 214 d.SetRROEnforcedForDependent(true) 215 } 216 } 217} 218 219func (a *aapt) useResourceProcessorBusyBox(ctx android.BaseModuleContext) bool { 220 return BoolDefault(a.aaptProperties.Use_resource_processor, ctx.Config().UseResourceProcessorByDefault()) && 221 // TODO(b/331641946): remove this when ResourceProcessorBusyBox supports generating shared libraries. 222 !slices.Contains(a.aaptProperties.Aaptflags, "--shared-lib") && 223 // Use the legacy resource processor in kythe builds. 224 // The legacy resource processor creates an R.srcjar, which kythe can use for generating crossrefs. 225 // TODO(b/354854007): Re-enable BusyBox in kythe builds 226 !ctx.Config().EmitXrefRules() 227} 228 229func (a *aapt) filterProduct() string { 230 return String(a.aaptProperties.Filter_product) 231} 232 233func (a *aapt) ExportPackage() android.Path { 234 return a.exportPackage 235} 236func (a *aapt) ResourcesNodeDepSet() depset.DepSet[*resourcesNode] { 237 return a.resourcesNodesDepSet 238} 239 240func (a *aapt) RRODirsDepSet() depset.DepSet[rroDir] { 241 return a.rroDirsDepSet 242} 243 244func (a *aapt) ManifestsDepSet() depset.DepSet[android.Path] { 245 return a.manifestsDepSet 246} 247 248func (a *aapt) SetRROEnforcedForDependent(enforce bool) { 249 a.aaptProperties.RROEnforcedForDependent = enforce 250} 251 252func (a *aapt) IsRROEnforced(ctx android.BaseModuleContext) bool { 253 // True if RRO is enforced for this module or... 254 return ctx.Config().EnforceRROForModule(ctx.ModuleName()) || 255 // if RRO is enforced for any of its dependents. 256 a.aaptProperties.RROEnforcedForDependent 257} 258 259func (a *aapt) aapt2Flags(ctx android.ModuleContext, sdkContext android.SdkContext, 260 manifestPath android.Path, doNotIncludeAssetDirImplicitly bool) (compileFlags, linkFlags []string, linkDeps android.Paths, 261 resDirs, overlayDirs []globbedResourceDir, rroDirs []rroDir, resZips android.Paths) { 262 263 hasVersionCode := android.PrefixInList(a.aaptProperties.Aaptflags, "--version-code") 264 hasVersionName := android.PrefixInList(a.aaptProperties.Aaptflags, "--version-name") 265 266 // Flags specified in Android.bp 267 linkFlags = append(linkFlags, a.aaptProperties.Aaptflags...) 268 269 linkFlags = append(linkFlags, "--enable-compact-entries") 270 271 // Find implicit or explicit asset and resource dirs 272 assets := android.PathsRelativeToModuleSourceDir(android.SourceInput{ 273 Context: ctx, 274 Paths: a.aaptProperties.Assets, 275 IncludeDirs: false, 276 }) 277 var assetDirs android.Paths 278 if doNotIncludeAssetDirImplicitly { 279 assetDirs = android.PathsForModuleSrc(ctx, a.aaptProperties.Asset_dirs) 280 } else { 281 assetDirs = android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Asset_dirs, "assets") 282 } 283 resourceDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Resource_dirs.GetOrDefault(ctx, nil), "res") 284 resourceZips := android.PathsForModuleSrc(ctx, a.aaptProperties.Resource_zips) 285 286 // Glob directories into lists of paths 287 for _, dir := range resourceDirs { 288 resDirs = append(resDirs, globbedResourceDir{ 289 dir: dir, 290 files: androidResourceGlob(ctx, dir), 291 }) 292 resOverlayDirs, resRRODirs := overlayResourceGlob(ctx, a, dir) 293 overlayDirs = append(overlayDirs, resOverlayDirs...) 294 rroDirs = append(rroDirs, resRRODirs...) 295 } 296 297 assetDirsHasher := sha256.New() 298 var assetDeps android.Paths 299 for _, dir := range assetDirs { 300 // Add a dependency on every file in the asset directory. This ensures the aapt2 301 // rule will be rerun if one of the files in the asset directory is modified. 302 dirContents := androidResourceGlob(ctx, dir) 303 assetDeps = append(assetDeps, dirContents...) 304 305 // Add a hash of all the files in the asset directory to the command line. 306 // This ensures the aapt2 rule will be run if a file is removed from the asset directory, 307 // or a file is added whose timestamp is older than the output of aapt2. 308 for _, path := range dirContents.Strings() { 309 assetDirsHasher.Write([]byte(path)) 310 } 311 } 312 313 assetDirStrings := assetDirs.Strings() 314 if a.noticeFile.Valid() { 315 assetDirStrings = append(assetDirStrings, filepath.Dir(a.noticeFile.Path().String())) 316 assetDeps = append(assetDeps, a.noticeFile.Path()) 317 } 318 if len(assets) > 0 { 319 // aapt2 doesn't support adding individual asset files. Create a temp directory to hold asset 320 // files and pass it to aapt2. 321 tmpAssetDir := android.PathForModuleOut(ctx, "tmp_asset_dir") 322 323 rule := android.NewRuleBuilder(pctx, ctx) 324 rule.Command(). 325 Text("rm -rf").Text(tmpAssetDir.String()). 326 Text("&&"). 327 Text("mkdir -p").Text(tmpAssetDir.String()) 328 329 for _, asset := range assets { 330 output := tmpAssetDir.Join(ctx, asset.Rel()) 331 assetDeps = append(assetDeps, output) 332 rule.Command().Text("mkdir -p").Text(filepath.Dir(output.String())) 333 rule.Command().Text("cp").Input(asset).Output(output) 334 } 335 336 rule.Build("tmp_asset_dir", "tmp_asset_dir") 337 338 assetDirStrings = append(assetDirStrings, tmpAssetDir.String()) 339 } 340 341 linkFlags = append(linkFlags, "--manifest "+manifestPath.String()) 342 linkDeps = append(linkDeps, manifestPath) 343 344 linkFlags = append(linkFlags, android.JoinWithPrefix(assetDirStrings, "-A ")) 345 linkFlags = append(linkFlags, fmt.Sprintf("$$(: %x)", assetDirsHasher.Sum(nil))) 346 linkDeps = append(linkDeps, assetDeps...) 347 348 // Returns the effective version for {min|target}_sdk_version 349 effectiveVersionString := func(sdkVersion android.SdkSpec, minSdkVersion android.ApiLevel) string { 350 // If {min|target}_sdk_version is current, use sdk_version to determine the effective level 351 // This is necessary for vendor modules. 352 // The effective version does not _only_ depend on {min|target}_sdk_version(level), 353 // but also on the sdk_version (kind+level) 354 if minSdkVersion.IsCurrent() { 355 ret, err := sdkVersion.EffectiveVersionString(ctx) 356 if err != nil { 357 ctx.ModuleErrorf("invalid sdk_version: %s", err) 358 } 359 return ret 360 } 361 ret, err := minSdkVersion.EffectiveVersionString(ctx) 362 if err != nil { 363 ctx.ModuleErrorf("invalid min_sdk_version: %s", err) 364 } 365 return ret 366 } 367 // SDK version flags 368 sdkVersion := sdkContext.SdkVersion(ctx) 369 minSdkVersion := effectiveVersionString(sdkVersion, sdkContext.MinSdkVersion(ctx)) 370 371 linkFlags = append(linkFlags, "--min-sdk-version "+minSdkVersion) 372 // Use minSdkVersion for target-sdk-version, even if `target_sdk_version` is set 373 // This behavior has been copied from Make. 374 linkFlags = append(linkFlags, "--target-sdk-version "+minSdkVersion) 375 376 // Version code 377 if !hasVersionCode { 378 linkFlags = append(linkFlags, "--version-code", ctx.Config().PlatformSdkVersion().String()) 379 } 380 381 if !hasVersionName { 382 var versionName string 383 if ctx.ModuleName() == "framework-res" { 384 // Some builds set AppsDefaultVersionName() to include the build number ("O-123456"). aapt2 copies the 385 // version name of framework-res into app manifests as compileSdkVersionCodename, which confuses things 386 // if it contains the build number. Use the PlatformVersionName instead. 387 versionName = ctx.Config().PlatformVersionName() 388 } else { 389 versionName = ctx.Config().AppsDefaultVersionName() 390 } 391 versionName = proptools.NinjaEscape(versionName) 392 linkFlags = append(linkFlags, "--version-name ", versionName) 393 } 394 395 linkFlags, compileFlags = android.FilterList(linkFlags, []string{"--legacy"}) 396 397 // Always set --pseudo-localize, it will be stripped out later for release 398 // builds that don't want it. 399 compileFlags = append(compileFlags, "--pseudo-localize") 400 401 return compileFlags, linkFlags, linkDeps, resDirs, overlayDirs, rroDirs, resourceZips 402} 403 404func (a *aapt) deps(ctx android.BottomUpMutatorContext, sdkDep sdkDep) { 405 if sdkDep.frameworkResModule != "" { 406 ctx.AddVariationDependencies(nil, frameworkResTag, sdkDep.frameworkResModule) 407 } 408} 409 410var extractAssetsRule = pctx.AndroidStaticRule("extractAssets", 411 blueprint.RuleParams{ 412 Command: `${config.Zip2ZipCmd} -i ${in} -o ${out} "assets/**/*"`, 413 CommandDeps: []string{"${config.Zip2ZipCmd}"}, 414 }) 415 416type aaptBuildActionOptions struct { 417 sdkContext android.SdkContext 418 classLoaderContexts dexpreopt.ClassLoaderContextMap 419 excludedLibs []string 420 enforceDefaultTargetSdkVersion bool 421 forceNonFinalResourceIDs bool 422 extraLinkFlags []string 423 aconfigTextFiles android.Paths 424 usesLibrary *usesLibrary 425 // If rroDirs is provided, it will be used to generate package-res.apk 426 rroDirs *android.Paths 427 // If manifestForAapt is not nil, it will be used for aapt instead of the default source manifest. 428 manifestForAapt android.Path 429} 430 431func filterRRO(rroDirsDepSet depset.DepSet[rroDir], filter overlayType) android.Paths { 432 var paths android.Paths 433 seen := make(map[android.Path]bool) 434 for _, d := range rroDirsDepSet.ToList() { 435 if d.overlayType == filter { 436 if seen[d.path] { 437 continue 438 } 439 seen[d.path] = true 440 paths = append(paths, d.path) 441 } 442 } 443 return paths 444} 445 446func (a *aapt) buildActions(ctx android.ModuleContext, opts aaptBuildActionOptions) { 447 448 staticResourcesNodesDepSet, sharedResourcesNodesDepSet, staticRRODirsDepSet, staticManifestsDepSet, sharedExportPackages, libFlags := 449 aaptLibs(ctx, opts.sdkContext, opts.classLoaderContexts, opts.usesLibrary) 450 451 // Exclude any libraries from the supplied list. 452 opts.classLoaderContexts = opts.classLoaderContexts.ExcludeLibs(opts.excludedLibs) 453 454 // App manifest file 455 var manifestFilePath android.Path 456 if opts.manifestForAapt != nil { 457 manifestFilePath = opts.manifestForAapt 458 } else { 459 manifestFile := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml") 460 manifestFilePath = android.PathForModuleSrc(ctx, manifestFile) 461 } 462 463 manifestPath := ManifestFixer(ctx, manifestFilePath, ManifestFixerParams{ 464 SdkContext: opts.sdkContext, 465 ClassLoaderContexts: opts.classLoaderContexts, 466 IsLibrary: a.isLibrary, 467 DefaultManifestVersion: a.defaultManifestVersion, 468 UseEmbeddedNativeLibs: a.useEmbeddedNativeLibs, 469 UsesNonSdkApis: a.usesNonSdkApis, 470 UseEmbeddedDex: a.useEmbeddedDex, 471 HasNoCode: a.hasNoCode, 472 LoggingParent: a.LoggingParent, 473 EnforceDefaultTargetSdkVersion: opts.enforceDefaultTargetSdkVersion, 474 }) 475 476 staticDeps := transitiveAarDeps(staticResourcesNodesDepSet.ToList()) 477 sharedDeps := transitiveAarDeps(sharedResourcesNodesDepSet.ToList()) 478 479 // Add additional manifest files to transitive manifests. 480 additionalManifests := android.PathsForModuleSrc(ctx, a.aaptProperties.Additional_manifests) 481 transitiveManifestPaths := append(android.Paths{manifestPath}, additionalManifests...) 482 transitiveManifestPaths = append(transitiveManifestPaths, staticManifestsDepSet.ToList()...) 483 484 if len(transitiveManifestPaths) > 1 && !Bool(a.aaptProperties.Dont_merge_manifests) { 485 manifestMergerParams := ManifestMergerParams{ 486 staticLibManifests: transitiveManifestPaths[1:], 487 isLibrary: a.isLibrary, 488 packageName: a.manifestValues.applicationId, 489 } 490 a.mergedManifestFile = manifestMerger(ctx, transitiveManifestPaths[0], manifestMergerParams) 491 ctx.CheckbuildFile(a.mergedManifestFile) 492 if !a.isLibrary { 493 // Only use the merged manifest for applications. For libraries, the transitive closure of manifests 494 // will be propagated to the final application and merged there. The merged manifest for libraries is 495 // only passed to Make, which can't handle transitive dependencies. 496 manifestPath = a.mergedManifestFile 497 } 498 } else { 499 a.mergedManifestFile = manifestPath 500 } 501 502 // do not include assets in autogenerated RRO. 503 compileFlags, linkFlags, linkDeps, resDirs, overlayDirs, rroDirs, resZips := a.aapt2Flags(ctx, opts.sdkContext, manifestPath, opts.rroDirs != nil) 504 505 a.rroDirsDepSet = depset.NewBuilder[rroDir](depset.TOPOLOGICAL). 506 Direct(rroDirs...). 507 Transitive(staticRRODirsDepSet).Build() 508 509 linkFlags = append(linkFlags, libFlags...) 510 linkDeps = append(linkDeps, sharedExportPackages...) 511 linkDeps = append(linkDeps, staticDeps.resPackages()...) 512 linkFlags = append(linkFlags, opts.extraLinkFlags...) 513 if a.isLibrary { 514 linkFlags = append(linkFlags, "--static-lib") 515 } 516 if opts.forceNonFinalResourceIDs { 517 linkFlags = append(linkFlags, "--non-final-ids") 518 } 519 520 linkFlags = append(linkFlags, "--no-static-lib-packages") 521 if a.isLibrary { 522 // Pass --merge-only to skip resource references validation until the final 523 // app link step when when all static libraries are present. 524 linkFlags = append(linkFlags, "--merge-only") 525 } 526 527 packageRes := android.PathForModuleOut(ctx, "package-res.apk") 528 proguardOptionsFile := android.PathForModuleGen(ctx, "proguard.options") 529 rTxt := android.PathForModuleOut(ctx, "R.txt") 530 // This file isn't used by Soong, but is generated for exporting 531 extraPackages := android.PathForModuleOut(ctx, "extra_packages") 532 var transitiveRJars android.Paths 533 var srcJar android.WritablePath 534 535 var compiledResDirs []android.Paths 536 for _, dir := range resDirs { 537 a.resourceFiles = append(a.resourceFiles, dir.files...) 538 compiledResDirs = append(compiledResDirs, aapt2Compile(ctx, dir.dir, dir.files, 539 compileFlags, a.filterProduct(), opts.aconfigTextFiles).Paths()) 540 } 541 542 for i, zip := range resZips { 543 flata := android.PathForModuleOut(ctx, fmt.Sprintf("reszip.%d.flata", i)) 544 aapt2CompileZip(ctx, flata, zip, "", compileFlags) 545 compiledResDirs = append(compiledResDirs, android.Paths{flata}) 546 } 547 548 var compiledRes, compiledOverlay android.Paths 549 550 // AAPT2 overlays are in lowest to highest priority order, reverse the topological order 551 // of transitiveStaticLibs. 552 transitiveStaticLibs := android.ReversePaths(staticDeps.resPackages()) 553 554 if a.isLibrary && a.useResourceProcessorBusyBox(ctx) { 555 // When building an android_library with ResourceProcessorBusyBox enabled treat static library dependencies 556 // as imports. The resources from dependencies will not be merged into this module's package-res.apk, and 557 // instead modules depending on this module will reference package-res.apk from all transitive static 558 // dependencies. 559 for _, sharedDep := range sharedDeps { 560 if sharedDep.usedResourceProcessor { 561 transitiveRJars = append(transitiveRJars, sharedDep.rJar) 562 } 563 } 564 for _, staticDep := range staticDeps { 565 linkDeps = append(linkDeps, staticDep.resPackage) 566 linkFlags = append(linkFlags, "-I "+staticDep.resPackage.String()) 567 if staticDep.usedResourceProcessor { 568 transitiveRJars = append(transitiveRJars, staticDep.rJar) 569 } 570 } 571 } else { 572 // When building an app or building a library without ResourceProcessorBusyBox enabled all static 573 // dependencies are compiled into this module's package-res.apk as overlays. 574 compiledOverlay = append(compiledOverlay, transitiveStaticLibs...) 575 } 576 577 if len(transitiveStaticLibs) > 0 { 578 // If we are using static android libraries, every source file becomes an overlay. 579 // This is to emulate old AAPT behavior which simulated library support. 580 for _, compiledResDir := range compiledResDirs { 581 compiledOverlay = append(compiledOverlay, compiledResDir...) 582 } 583 } else if a.isLibrary { 584 // Otherwise, for a static library we treat all the resources equally with no overlay. 585 for _, compiledResDir := range compiledResDirs { 586 compiledRes = append(compiledRes, compiledResDir...) 587 } 588 } else if len(compiledResDirs) > 0 { 589 // Without static libraries, the first directory is our directory, which can then be 590 // overlaid by the rest. 591 compiledRes = append(compiledRes, compiledResDirs[0]...) 592 for _, compiledResDir := range compiledResDirs[1:] { 593 compiledOverlay = append(compiledOverlay, compiledResDir...) 594 } 595 } 596 597 var compiledRro, compiledRroOverlay android.Paths 598 if opts.rroDirs != nil { 599 compiledRro, compiledRroOverlay = a.compileResInDir(ctx, *opts.rroDirs, compileFlags, opts.aconfigTextFiles) 600 } else { 601 // RRO enforcement is done based on module name. Compile the overlayDirs only if rroDirs is nil. 602 // This ensures that the autogenerated RROs do not compile the overlay dirs twice. 603 for _, dir := range overlayDirs { 604 compiledOverlay = append(compiledOverlay, aapt2Compile(ctx, dir.dir, dir.files, 605 compileFlags, a.filterProduct(), opts.aconfigTextFiles).Paths()...) 606 } 607 } 608 609 var splitPackages android.WritablePaths 610 var splits []split 611 612 for _, s := range a.splitNames { 613 suffix := strings.Replace(s, ",", "_", -1) 614 path := android.PathForModuleOut(ctx, "package_"+suffix+".apk") 615 linkFlags = append(linkFlags, "--split", path.String()+":"+s) 616 splitPackages = append(splitPackages, path) 617 splits = append(splits, split{ 618 name: s, 619 suffix: suffix, 620 path: path, 621 }) 622 } 623 624 if !a.useResourceProcessorBusyBox(ctx) { 625 // the subdir "android" is required to be filtered by package names 626 srcJar = android.PathForModuleGen(ctx, "android", "R.srcjar") 627 } 628 629 // No need to specify assets from dependencies to aapt2Link for libraries, all transitive assets will be 630 // provided to the final app aapt2Link step. 631 var transitiveAssets android.Paths 632 if !a.isLibrary { 633 transitiveAssets = android.ReverseSliceInPlace(staticDeps.assets()) 634 } 635 if opts.rroDirs == nil { // link resources and overlay 636 aapt2Link(ctx, packageRes, srcJar, proguardOptionsFile, rTxt, 637 linkFlags, linkDeps, compiledRes, compiledOverlay, transitiveAssets, splitPackages, 638 opts.aconfigTextFiles) 639 ctx.CheckbuildFile(packageRes) 640 } else { // link autogenerated rro 641 if len(compiledRro) == 0 { 642 return 643 } 644 aapt2Link(ctx, packageRes, srcJar, proguardOptionsFile, rTxt, 645 linkFlags, linkDeps, compiledRro, compiledRroOverlay, nil, nil, 646 opts.aconfigTextFiles) 647 ctx.CheckbuildFile(packageRes) 648 } 649 650 // Extract assets from the resource package output so that they can be used later in aapt2link 651 // for modules that depend on this one. 652 if android.PrefixInList(linkFlags, "-A ") { 653 assets := android.PathForModuleOut(ctx, "assets.zip") 654 ctx.Build(pctx, android.BuildParams{ 655 Rule: extractAssetsRule, 656 Input: packageRes, 657 Output: assets, 658 Description: "extract assets from built resource file", 659 }) 660 a.assetPackage = android.OptionalPathForPath(assets) 661 } 662 663 if a.useResourceProcessorBusyBox(ctx) { 664 rJar := android.PathForModuleOut(ctx, "busybox/R.jar") 665 resourceProcessorBusyBoxGenerateBinaryR(ctx, rTxt, a.mergedManifestFile, rJar, staticDeps, a.isLibrary, a.aaptProperties.Aaptflags, 666 opts.forceNonFinalResourceIDs) 667 aapt2ExtractExtraPackages(ctx, extraPackages, rJar) 668 transitiveRJars = append(transitiveRJars, rJar) 669 a.rJar = rJar 670 } else { 671 aapt2ExtractExtraPackages(ctx, extraPackages, srcJar) 672 } 673 674 transitiveAaptResourcePackages := staticDeps.resPackages().Strings() 675 transitiveAaptResourcePackages = slices.DeleteFunc(transitiveAaptResourcePackages, func(p string) bool { 676 return p == packageRes.String() 677 }) 678 transitiveAaptResourcePackagesFile := android.PathForModuleOut(ctx, "transitive-res-packages") 679 android.WriteFileRule(ctx, transitiveAaptResourcePackagesFile, strings.Join(transitiveAaptResourcePackages, "\n")) 680 681 // Reverse the list of R.jar files so that the current module comes first, and direct dependencies come before 682 // transitive dependencies. 683 transitiveRJars = android.ReversePaths(transitiveRJars) 684 685 a.aaptSrcJar = srcJar 686 a.transitiveAaptRJars = transitiveRJars 687 a.transitiveAaptResourcePackagesFile = transitiveAaptResourcePackagesFile 688 a.exportPackage = packageRes 689 a.manifestPath = manifestPath 690 a.proguardOptionsFile = proguardOptionsFile 691 a.extraAaptPackagesFile = extraPackages 692 a.rTxt = rTxt 693 a.splits = splits 694 a.resourcesNodesDepSet = depset.NewBuilder[*resourcesNode](depset.TOPOLOGICAL). 695 Direct(&resourcesNode{ 696 resPackage: a.exportPackage, 697 manifest: a.manifestPath, 698 additionalManifests: additionalManifests, 699 rTxt: a.rTxt, 700 rJar: a.rJar, 701 assets: a.assetPackage, 702 703 usedResourceProcessor: a.useResourceProcessorBusyBox(ctx), 704 }). 705 Transitive(staticResourcesNodesDepSet).Build() 706 a.manifestsDepSet = depset.NewBuilder[android.Path](depset.TOPOLOGICAL). 707 Direct(a.manifestPath). 708 DirectSlice(additionalManifests). 709 Transitive(staticManifestsDepSet).Build() 710} 711 712// comileResInDir finds the resource files in dirs by globbing and then compiles them using aapt2 713// returns the file paths of compiled resources 714// dirs[0] is used as compileRes 715// dirs[1:] is used as compileOverlay 716func (a *aapt) compileResInDir(ctx android.ModuleContext, dirs android.Paths, compileFlags []string, aconfig android.Paths) (android.Paths, android.Paths) { 717 filesInDir := func(dir android.Path) android.Paths { 718 files, err := ctx.GlobWithDeps(filepath.Join(dir.String(), "**/*"), androidResourceIgnoreFilenames) 719 if err != nil { 720 ctx.ModuleErrorf("failed to glob overlay resource dir %q: %s", dir, err.Error()) 721 return nil 722 } 723 var filePaths android.Paths 724 for _, file := range files { 725 if strings.HasSuffix(file, "/") { 726 continue // ignore directories 727 } 728 filePaths = append(filePaths, android.PathForSource(ctx, file)) 729 } 730 return filePaths 731 } 732 733 var compiledRes, compiledOverlay android.Paths 734 if len(dirs) == 0 { 735 return nil, nil 736 } 737 compiledRes = append(compiledRes, aapt2Compile(ctx, dirs[0], filesInDir(dirs[0]), compileFlags, a.filterProduct(), aconfig).Paths()...) 738 if len(dirs) > 0 { 739 for _, dir := range dirs[1:] { 740 compiledOverlay = append(compiledOverlay, aapt2Compile(ctx, dir, filesInDir(dir), compileFlags, a.filterProduct(), aconfig).Paths()...) 741 } 742 } 743 return compiledRes, compiledOverlay 744} 745 746var resourceProcessorBusyBox = pctx.AndroidStaticRule("resourceProcessorBusyBox", 747 blueprint.RuleParams{ 748 Command: "${config.JavaCmd} -cp ${config.ResourceProcessorBusyBox} " + 749 "com.google.devtools.build.android.ResourceProcessorBusyBox --tool=GENERATE_BINARY_R -- @${out}.args && " + 750 "if cmp -s ${out}.tmp ${out} ; then rm ${out}.tmp ; else mv ${out}.tmp ${out}; fi", 751 CommandDeps: []string{"${config.ResourceProcessorBusyBox}"}, 752 Rspfile: "${out}.args", 753 RspfileContent: "--primaryRTxt ${rTxt} --primaryManifest ${manifest} --classJarOutput ${out}.tmp ${args}", 754 Restat: true, 755 }, "rTxt", "manifest", "args") 756 757// resourceProcessorBusyBoxGenerateBinaryR converts the R.txt file produced by aapt2 into R.class files 758// using Bazel's ResourceProcessorBusyBox tool, which is faster than compiling the R.java files and 759// supports producing classes for static dependencies that only include resources from that dependency. 760func resourceProcessorBusyBoxGenerateBinaryR(ctx android.ModuleContext, rTxt, manifest android.Path, 761 rJar android.WritablePath, transitiveDeps transitiveAarDeps, isLibrary bool, aaptFlags []string, 762 forceNonFinalIds bool) { 763 764 var args []string 765 var deps android.Paths 766 767 if !isLibrary { 768 // When compiling an app, pass all R.txt and AndroidManifest.xml from transitive static library dependencies 769 // to ResourceProcessorBusyBox so that it can regenerate R.class files with the final resource IDs for each 770 // package. 771 args, deps = transitiveDeps.resourceProcessorDeps() 772 if forceNonFinalIds { 773 args = append(args, "--finalFields=false") 774 } 775 } else { 776 // When compiling a library don't pass any dependencies as it only needs to generate an R.class file for this 777 // library. Pass --finalFields=false so that the R.class file contains non-final fields so they don't get 778 // inlined into the library before the final IDs are assigned during app compilation. 779 args = append(args, "--finalFields=false") 780 } 781 782 for i, arg := range aaptFlags { 783 const AAPT_CUSTOM_PACKAGE = "--custom-package" 784 if strings.HasPrefix(arg, AAPT_CUSTOM_PACKAGE) { 785 pkg := strings.TrimSpace(strings.TrimPrefix(arg, AAPT_CUSTOM_PACKAGE)) 786 if pkg == "" && i+1 < len(aaptFlags) { 787 pkg = aaptFlags[i+1] 788 } 789 args = append(args, "--packageForR "+pkg) 790 } 791 } 792 793 deps = append(deps, rTxt, manifest) 794 795 ctx.Build(pctx, android.BuildParams{ 796 Rule: resourceProcessorBusyBox, 797 Output: rJar, 798 Implicits: deps, 799 Description: "ResourceProcessorBusyBox", 800 Args: map[string]string{ 801 "rTxt": rTxt.String(), 802 "manifest": manifest.String(), 803 "args": strings.Join(args, " "), 804 }, 805 }) 806} 807 808type resourcesNode struct { 809 resPackage android.Path 810 manifest android.Path 811 additionalManifests android.Paths 812 rTxt android.Path 813 rJar android.Path 814 assets android.OptionalPath 815 816 usedResourceProcessor bool 817} 818 819type transitiveAarDeps []*resourcesNode 820 821func (t transitiveAarDeps) resPackages() android.Paths { 822 paths := make(android.Paths, 0, len(t)) 823 for _, dep := range t { 824 paths = append(paths, dep.resPackage) 825 } 826 return paths 827} 828 829func (t transitiveAarDeps) manifests() android.Paths { 830 paths := make(android.Paths, 0, len(t)) 831 for _, dep := range t { 832 paths = append(paths, dep.manifest) 833 paths = append(paths, dep.additionalManifests...) 834 } 835 return paths 836} 837 838func (t transitiveAarDeps) resourceProcessorDeps() (args []string, deps android.Paths) { 839 for _, dep := range t { 840 args = append(args, "--library="+dep.rTxt.String()+","+dep.manifest.String()) 841 deps = append(deps, dep.rTxt, dep.manifest) 842 } 843 return args, deps 844} 845 846func (t transitiveAarDeps) assets() android.Paths { 847 paths := make(android.Paths, 0, len(t)) 848 for _, dep := range t { 849 if dep.assets.Valid() { 850 paths = append(paths, dep.assets.Path()) 851 } 852 } 853 return paths 854} 855 856// aaptLibs collects libraries from dependencies and sdk_version and converts them into paths 857func aaptLibs(ctx android.ModuleContext, sdkContext android.SdkContext, 858 classLoaderContexts dexpreopt.ClassLoaderContextMap, usesLibrary *usesLibrary) ( 859 staticResourcesNodes, sharedResourcesNodes depset.DepSet[*resourcesNode], staticRRODirs depset.DepSet[rroDir], 860 staticManifests depset.DepSet[android.Path], sharedLibs android.Paths, flags []string) { 861 862 if classLoaderContexts == nil { 863 // Not all callers need to compute class loader context, those who don't just pass nil. 864 // Create a temporary class loader context here (it will be computed, but not used). 865 classLoaderContexts = make(dexpreopt.ClassLoaderContextMap) 866 } 867 868 sdkDep := decodeSdkDep(ctx, sdkContext) 869 if sdkDep.useFiles { 870 sharedLibs = append(sharedLibs, sdkDep.jars...) 871 } 872 873 var staticResourcesNodeDepSets []depset.DepSet[*resourcesNode] 874 var sharedResourcesNodeDepSets []depset.DepSet[*resourcesNode] 875 rroDirsDepSetBuilder := depset.NewBuilder[rroDir](depset.TOPOLOGICAL) 876 manifestsDepSetBuilder := depset.NewBuilder[android.Path](depset.TOPOLOGICAL) 877 878 ctx.VisitDirectDeps(func(module android.Module) { 879 depTag := ctx.OtherModuleDependencyTag(module) 880 881 var exportPackage android.Path 882 aarDep, _ := module.(AndroidLibraryDependency) 883 if aarDep != nil { 884 exportPackage = aarDep.ExportPackage() 885 } 886 887 switch depTag { 888 case instrumentationForTag: 889 // Nothing, instrumentationForTag is treated as libTag for javac but not for aapt2. 890 case sdkLibTag, libTag, rroDepTag: 891 if exportPackage != nil { 892 sharedResourcesNodeDepSets = append(sharedResourcesNodeDepSets, aarDep.ResourcesNodeDepSet()) 893 sharedLibs = append(sharedLibs, exportPackage) 894 } 895 case frameworkResTag: 896 if exportPackage != nil { 897 sharedLibs = append(sharedLibs, exportPackage) 898 } 899 case staticLibTag: 900 if exportPackage != nil { 901 staticResourcesNodeDepSets = append(staticResourcesNodeDepSets, aarDep.ResourcesNodeDepSet()) 902 rroDirsDepSetBuilder.Transitive(aarDep.RRODirsDepSet()) 903 manifestsDepSetBuilder.Transitive(aarDep.ManifestsDepSet()) 904 } 905 } 906 907 addCLCFromDep(ctx, module, classLoaderContexts) 908 if usesLibrary != nil { 909 addMissingOptionalUsesLibsFromDep(ctx, module, usesLibrary) 910 } 911 }) 912 913 // AAPT2 overlays are in lowest to highest priority order, the topological order will be reversed later. 914 // Reverse the dependency order now going into the depset so that it comes out in order after the second 915 // reverse later. 916 // NOTE: this is legacy and probably incorrect behavior, for most other cases (e.g. conflicting classes in 917 // dependencies) the highest priority dependency is listed first, but for resources the highest priority 918 // dependency has to be listed last. This is also inconsistent with the way manifests from the same 919 // transitive dependencies are merged. 920 staticResourcesNodes = depset.New(depset.TOPOLOGICAL, nil, 921 android.ReverseSliceInPlace(staticResourcesNodeDepSets)) 922 sharedResourcesNodes = depset.New(depset.TOPOLOGICAL, nil, 923 android.ReverseSliceInPlace(sharedResourcesNodeDepSets)) 924 925 staticRRODirs = rroDirsDepSetBuilder.Build() 926 staticManifests = manifestsDepSetBuilder.Build() 927 928 if len(staticResourcesNodes.ToList()) > 0 { 929 flags = append(flags, "--auto-add-overlay") 930 } 931 932 for _, sharedLib := range sharedLibs { 933 flags = append(flags, "-I "+sharedLib.String()) 934 } 935 936 return staticResourcesNodes, sharedResourcesNodes, staticRRODirs, staticManifests, sharedLibs, flags 937} 938 939type AndroidLibrary struct { 940 Library 941 aapt 942 943 androidLibraryProperties androidLibraryProperties 944 945 aarFile android.WritablePath 946} 947 948var _ AndroidLibraryDependency = (*AndroidLibrary)(nil) 949 950func (a *AndroidLibrary) DepsMutator(ctx android.BottomUpMutatorContext) { 951 a.usesLibrary.deps(ctx, false) 952 a.Module.deps(ctx) 953 sdkDep := decodeSdkDep(ctx, android.SdkContext(a)) 954 if sdkDep.hasFrameworkLibs() { 955 a.aapt.deps(ctx, sdkDep) 956 } 957 958 for _, aconfig_declaration := range a.aaptProperties.Flags_packages { 959 ctx.AddDependency(ctx.Module(), aconfigDeclarationTag, aconfig_declaration) 960 } 961} 962 963func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { 964 a.aapt.isLibrary = true 965 a.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx) 966 if a.usesLibrary.shouldDisableDexpreopt { 967 a.dexpreopter.disableDexpreopt() 968 } 969 aconfigTextFilePaths := getAconfigFilePaths(ctx) 970 a.aapt.buildActions(ctx, 971 aaptBuildActionOptions{ 972 sdkContext: android.SdkContext(a), 973 classLoaderContexts: a.classLoaderContexts, 974 enforceDefaultTargetSdkVersion: false, 975 aconfigTextFiles: aconfigTextFilePaths, 976 usesLibrary: &a.usesLibrary, 977 }, 978 ) 979 980 apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider) 981 a.hideApexVariantFromMake = !apexInfo.IsForPlatform() 982 983 a.stem = proptools.StringDefault(a.overridableProperties.Stem, ctx.ModuleName()) 984 985 ctx.CheckbuildFile(a.aapt.proguardOptionsFile) 986 ctx.CheckbuildFile(a.aapt.exportPackage) 987 if a.useResourceProcessorBusyBox(ctx) { 988 ctx.CheckbuildFile(a.aapt.rJar) 989 } else { 990 ctx.CheckbuildFile(a.aapt.aaptSrcJar) 991 } 992 993 // apps manifests are handled by aapt, don't let Module see them 994 a.properties.Manifest = nil 995 996 a.linter.mergedManifest = a.aapt.mergedManifestFile 997 a.linter.manifest = a.aapt.manifestPath 998 a.linter.resources = a.aapt.resourceFiles 999 1000 proguardSpecInfo := a.collectProguardSpecInfo(ctx) 1001 android.SetProvider(ctx, ProguardSpecInfoProvider, proguardSpecInfo) 1002 exportedProguardFlagsFiles := proguardSpecInfo.ProguardFlagsFiles.ToList() 1003 a.extraProguardFlagsFiles = append(a.extraProguardFlagsFiles, exportedProguardFlagsFiles...) 1004 a.extraProguardFlagsFiles = append(a.extraProguardFlagsFiles, a.proguardOptionsFile) 1005 1006 combinedExportedProguardFlagFile := android.PathForModuleOut(ctx, "export_proguard_flags") 1007 writeCombinedProguardFlagsFile(ctx, combinedExportedProguardFlagFile, exportedProguardFlagsFiles) 1008 a.combinedExportedProguardFlagsFile = combinedExportedProguardFlagFile 1009 1010 var extraSrcJars android.Paths 1011 var extraCombinedJars android.Paths 1012 var extraClasspathJars android.Paths 1013 if a.useResourceProcessorBusyBox(ctx) { 1014 // When building a library with ResourceProcessorBusyBox enabled ResourceProcessorBusyBox for this 1015 // library and each of the transitive static android_library dependencies has already created an 1016 // R.class file for the appropriate package. Add all of those R.class files to the classpath. 1017 extraClasspathJars = a.transitiveAaptRJars 1018 } else { 1019 // When building a library without ResourceProcessorBusyBox the aapt2 rule creates R.srcjar containing 1020 // R.java files for the library's package and the packages from all transitive static android_library 1021 // dependencies. Compile the srcjar alongside the rest of the sources. 1022 extraSrcJars = android.Paths{a.aapt.aaptSrcJar} 1023 } 1024 1025 a.Module.compile(ctx, extraSrcJars, extraClasspathJars, extraCombinedJars, nil) 1026 1027 a.aarFile = android.PathForModuleOut(ctx, ctx.ModuleName()+".aar") 1028 var res android.Paths 1029 if a.androidLibraryProperties.BuildAAR { 1030 BuildAAR(ctx, a.aarFile, a.outputFile, a.manifestPath, a.rTxt, res) 1031 } 1032 1033 prebuiltJniPackages := android.Paths{} 1034 ctx.VisitDirectDeps(func(module android.Module) { 1035 if info, ok := android.OtherModuleProvider(ctx, module, JniPackageProvider); ok { 1036 prebuiltJniPackages = append(prebuiltJniPackages, info.JniPackages...) 1037 } 1038 }) 1039 if len(prebuiltJniPackages) > 0 { 1040 android.SetProvider(ctx, JniPackageProvider, JniPackageInfo{ 1041 JniPackages: prebuiltJniPackages, 1042 }) 1043 } 1044 1045 android.SetProvider(ctx, FlagsPackagesProvider, FlagsPackages{ 1046 AconfigTextFiles: aconfigTextFilePaths, 1047 }) 1048 1049 a.setOutputFiles(ctx) 1050} 1051 1052func (a *AndroidLibrary) setOutputFiles(ctx android.ModuleContext) { 1053 ctx.SetOutputFiles([]android.Path{a.aarFile}, ".aar") 1054 setOutputFiles(ctx, a.Library.Module) 1055} 1056 1057func (a *AndroidLibrary) IDEInfo(ctx android.BaseModuleContext, dpInfo *android.IdeInfo) { 1058 a.Library.IDEInfo(ctx, dpInfo) 1059 a.aapt.IDEInfo(ctx, dpInfo) 1060} 1061 1062func (a *aapt) IDEInfo(ctx android.BaseModuleContext, dpInfo *android.IdeInfo) { 1063 if a.rJar != nil { 1064 dpInfo.Jars = append(dpInfo.Jars, a.rJar.String()) 1065 } 1066} 1067 1068// android_library builds and links sources into a `.jar` file for the device along with Android resources. 1069// 1070// An android_library has a single variant that produces a `.jar` file containing `.class` files that were 1071// compiled against the device bootclasspath, along with a `package-res.apk` file containing Android resources compiled 1072// with aapt2. This module is not suitable for installing on a device, but can be used as a `static_libs` dependency of 1073// an android_app module. 1074func AndroidLibraryFactory() android.Module { 1075 module := &AndroidLibrary{} 1076 1077 module.Module.addHostAndDeviceProperties() 1078 module.AddProperties( 1079 &module.aaptProperties, 1080 &module.androidLibraryProperties, 1081 &module.sourceProperties) 1082 1083 module.androidLibraryProperties.BuildAAR = true 1084 module.Module.linter.library = true 1085 1086 android.InitApexModule(module) 1087 InitJavaModule(module, android.DeviceSupported) 1088 return module 1089} 1090 1091// 1092// AAR (android library) prebuilts 1093// 1094 1095// Properties for android_library_import 1096type AARImportProperties struct { 1097 // ARR (android library prebuilt) filepath. Exactly one ARR is required. 1098 Aars []string `android:"path"` 1099 // If not blank, set to the version of the sdk to compile against. 1100 // Defaults to private. 1101 // Values are of one of the following forms: 1102 // 1) numerical API level, "current", "none", or "core_platform" 1103 // 2) An SDK kind with an API level: "<sdk kind>_<API level>" 1104 // See build/soong/android/sdk_version.go for the complete and up to date list of SDK kinds. 1105 // If the SDK kind is empty, it will be set to public 1106 Sdk_version *string 1107 // If not blank, set the minimum version of the sdk that the compiled artifacts will run against. 1108 // Defaults to sdk_version if not set. See sdk_version for possible values. 1109 Min_sdk_version *string 1110 // List of java static libraries that the included ARR (android library prebuilts) has dependencies to. 1111 Static_libs proptools.Configurable[[]string] 1112 // List of java libraries that the included ARR (android library prebuilts) has dependencies to. 1113 Libs []string 1114 // If set to true, run Jetifier against .aar file. Defaults to false. 1115 Jetifier *bool 1116 // If true, extract JNI libs from AAR archive. These libs will be accessible to android_app modules and 1117 // will be passed transitively through android_libraries to an android_app. 1118 //TODO(b/241138093) evaluate whether we can have this flag default to true for Bazel conversion 1119 Extract_jni *bool 1120 1121 // If set, overrides the manifest extracted from the AAR with the provided path. 1122 Manifest *string `android:"path"` 1123} 1124 1125type AARImport struct { 1126 android.ModuleBase 1127 android.DefaultableModuleBase 1128 android.ApexModuleBase 1129 prebuilt android.Prebuilt 1130 1131 // Functionality common to Module and Import. 1132 embeddableInModuleAndImport 1133 1134 providesTransitiveHeaderJarsForR8 1135 1136 properties AARImportProperties 1137 1138 headerJarFile android.Path 1139 implementationJarFile android.Path 1140 implementationAndResourcesJarFile android.Path 1141 proguardFlags android.Path 1142 exportPackage android.Path 1143 transitiveAaptResourcePackagesFile android.Path 1144 extraAaptPackagesFile android.Path 1145 manifest android.Path 1146 assetsPackage android.Path 1147 rTxt android.Path 1148 rJar android.Path 1149 1150 resourcesNodesDepSet depset.DepSet[*resourcesNode] 1151 manifestsDepSet depset.DepSet[android.Path] 1152 1153 hideApexVariantFromMake bool 1154 1155 aarPath android.Path 1156 jniPackages android.Paths 1157 1158 sdkVersion android.SdkSpec 1159 minSdkVersion android.ApiLevel 1160 1161 usesLibrary 1162 classLoaderContexts dexpreopt.ClassLoaderContextMap 1163} 1164 1165func (a *AARImport) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { 1166 return android.SdkSpecFrom(ctx, String(a.properties.Sdk_version)) 1167} 1168 1169func (a *AARImport) SystemModules() string { 1170 return "" 1171} 1172 1173func (a *AARImport) MinSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel { 1174 if a.properties.Min_sdk_version != nil { 1175 return android.ApiLevelFrom(ctx, *a.properties.Min_sdk_version) 1176 } 1177 return a.SdkVersion(ctx).ApiLevel 1178} 1179 1180func (a *AARImport) ReplaceMaxSdkVersionPlaceholder(ctx android.EarlyModuleContext) android.ApiLevel { 1181 return android.SdkSpecFrom(ctx, "").ApiLevel 1182} 1183 1184func (a *AARImport) TargetSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel { 1185 return a.SdkVersion(ctx).ApiLevel 1186} 1187 1188func (a *AARImport) javaVersion() string { 1189 return "" 1190} 1191 1192var _ AndroidLibraryDependency = (*AARImport)(nil) 1193 1194func (a *AARImport) ExportPackage() android.Path { 1195 return a.exportPackage 1196} 1197func (a *AARImport) ResourcesNodeDepSet() depset.DepSet[*resourcesNode] { 1198 return a.resourcesNodesDepSet 1199} 1200 1201func (a *AARImport) RRODirsDepSet() depset.DepSet[rroDir] { 1202 return depset.New[rroDir](depset.TOPOLOGICAL, nil, nil) 1203} 1204 1205func (a *AARImport) ManifestsDepSet() depset.DepSet[android.Path] { 1206 return a.manifestsDepSet 1207} 1208 1209// RRO enforcement is not available on aar_import since its RRO dirs are not 1210// exported. 1211func (a *AARImport) SetRROEnforcedForDependent(enforce bool) { 1212} 1213 1214// RRO enforcement is not available on aar_import since its RRO dirs are not 1215// exported. 1216func (a *AARImport) IsRROEnforced(ctx android.BaseModuleContext) bool { 1217 return false 1218} 1219 1220func (a *AARImport) Prebuilt() *android.Prebuilt { 1221 return &a.prebuilt 1222} 1223 1224func (a *AARImport) Name() string { 1225 return a.prebuilt.Name(a.ModuleBase.Name()) 1226} 1227 1228func (a *AARImport) JacocoReportClassesFile() android.Path { 1229 return nil 1230} 1231 1232func (a *AARImport) DepsMutator(ctx android.BottomUpMutatorContext) { 1233 if !ctx.Config().AlwaysUsePrebuiltSdks() { 1234 sdkDep := decodeSdkDep(ctx, android.SdkContext(a)) 1235 if sdkDep.useModule && sdkDep.frameworkResModule != "" { 1236 ctx.AddVariationDependencies(nil, frameworkResTag, sdkDep.frameworkResModule) 1237 } 1238 } 1239 1240 ctx.AddVariationDependencies(nil, libTag, a.properties.Libs...) 1241 ctx.AddVariationDependencies(nil, staticLibTag, a.properties.Static_libs.GetOrDefault(ctx, nil)...) 1242 1243 a.usesLibrary.deps(ctx, false) 1244} 1245 1246type JniPackageInfo struct { 1247 // List of zip files containing JNI libraries 1248 // Zip files should have directory structure jni/<arch>/*.so 1249 JniPackages android.Paths 1250} 1251 1252var JniPackageProvider = blueprint.NewProvider[JniPackageInfo]() 1253 1254// Unzip an AAR and extract the JNI libs for $archString. 1255var extractJNI = pctx.AndroidStaticRule("extractJNI", 1256 blueprint.RuleParams{ 1257 Command: `rm -rf $out $outDir && touch $out && ` + 1258 `unzip -qoDD -d $outDir $in "jni/${archString}/*" && ` + 1259 `jni_files=$$(find $outDir/jni -type f) && ` + 1260 // print error message if there are no JNI libs for this arch 1261 `[ -n "$$jni_files" ] || (echo "ERROR: no JNI libs found for arch ${archString}" && exit 1) && ` + 1262 `${config.SoongZipCmd} -o $out -L 0 -P 'lib/${archString}' ` + 1263 `-C $outDir/jni/${archString} $$(echo $$jni_files | xargs -n1 printf " -f %s")`, 1264 CommandDeps: []string{"${config.SoongZipCmd}"}, 1265 }, 1266 "outDir", "archString") 1267 1268// Unzip an AAR into its constituent files and directories. Any files in Outputs that don't exist in the AAR will be 1269// touched to create an empty file. The res directory is not extracted, as it will be extracted in its own rule. 1270var unzipAAR = pctx.AndroidStaticRule("unzipAAR", 1271 blueprint.RuleParams{ 1272 Command: `rm -rf $outDir && mkdir -p $outDir && ` + 1273 `unzip -qoDD -d $outDir $in && rm -rf $outDir/res && touch $out && ` + 1274 `${config.Zip2ZipCmd} -i $in -o $assetsPackage 'assets/**/*' && ` + 1275 `${config.MergeZipsCmd} $combinedClassesJar $$(ls $outDir/classes.jar 2> /dev/null) $$(ls $outDir/libs/*.jar 2> /dev/null)`, 1276 CommandDeps: []string{"${config.MergeZipsCmd}", "${config.Zip2ZipCmd}"}, 1277 }, 1278 "outDir", "combinedClassesJar", "assetsPackage") 1279 1280func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { 1281 if len(a.properties.Aars) != 1 { 1282 ctx.PropertyErrorf("aars", "exactly one aar is required") 1283 return 1284 } 1285 1286 a.sdkVersion = a.SdkVersion(ctx) 1287 a.minSdkVersion = a.MinSdkVersion(ctx) 1288 1289 apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider) 1290 a.hideApexVariantFromMake = !apexInfo.IsForPlatform() 1291 1292 aarName := ctx.ModuleName() + ".aar" 1293 a.aarPath = android.PathForModuleSrc(ctx, a.properties.Aars[0]) 1294 1295 if Bool(a.properties.Jetifier) { 1296 inputFile := a.aarPath 1297 jetifierPath := android.PathForModuleOut(ctx, "jetifier", aarName) 1298 TransformJetifier(ctx, jetifierPath, inputFile) 1299 a.aarPath = jetifierPath 1300 } 1301 1302 jarName := ctx.ModuleName() + ".jar" 1303 extractedAARDir := android.PathForModuleOut(ctx, "aar") 1304 classpathFile := extractedAARDir.Join(ctx, jarName) 1305 1306 extractedManifest := extractedAARDir.Join(ctx, "AndroidManifest.xml") 1307 providedManifest := android.OptionalPathForModuleSrc(ctx, a.properties.Manifest) 1308 if providedManifest.Valid() { 1309 a.manifest = providedManifest.Path() 1310 } else { 1311 a.manifest = extractedManifest 1312 } 1313 1314 rTxt := extractedAARDir.Join(ctx, "R.txt") 1315 assetsPackage := android.PathForModuleOut(ctx, "assets.zip") 1316 proguardFlags := extractedAARDir.Join(ctx, "proguard.txt") 1317 transitiveProguardFlags, transitiveUnconditionalExportedFlags := collectDepProguardSpecInfo(ctx) 1318 android.SetProvider(ctx, ProguardSpecInfoProvider, ProguardSpecInfo{ 1319 ProguardFlagsFiles: depset.New[android.Path]( 1320 depset.POSTORDER, 1321 android.Paths{proguardFlags}, 1322 transitiveProguardFlags, 1323 ), 1324 UnconditionallyExportedProguardFlags: depset.New[android.Path]( 1325 depset.POSTORDER, 1326 nil, 1327 transitiveUnconditionalExportedFlags, 1328 ), 1329 }) 1330 1331 ctx.Build(pctx, android.BuildParams{ 1332 Rule: unzipAAR, 1333 Input: a.aarPath, 1334 Outputs: android.WritablePaths{classpathFile, proguardFlags, extractedManifest, assetsPackage, rTxt}, 1335 Description: "unzip AAR", 1336 Args: map[string]string{ 1337 "outDir": extractedAARDir.String(), 1338 "combinedClassesJar": classpathFile.String(), 1339 "assetsPackage": assetsPackage.String(), 1340 }, 1341 }) 1342 1343 a.proguardFlags = proguardFlags 1344 a.assetsPackage = assetsPackage 1345 a.rTxt = rTxt 1346 1347 // Always set --pseudo-localize, it will be stripped out later for release 1348 // builds that don't want it. 1349 compileFlags := []string{"--pseudo-localize"} 1350 compiledResDir := android.PathForModuleOut(ctx, "flat-res") 1351 flata := compiledResDir.Join(ctx, "gen_res.flata") 1352 aapt2CompileZip(ctx, flata, a.aarPath, "res", compileFlags) 1353 1354 exportPackage := android.PathForModuleOut(ctx, "package-res.apk") 1355 proguardOptionsFile := android.PathForModuleGen(ctx, "proguard.options") 1356 aaptRTxt := android.PathForModuleOut(ctx, "R.txt") 1357 extraAaptPackagesFile := android.PathForModuleOut(ctx, "extra_packages") 1358 1359 var linkDeps android.Paths 1360 1361 linkFlags := []string{ 1362 "--static-lib", 1363 "--merge-only", 1364 "--auto-add-overlay", 1365 "--no-static-lib-packages", 1366 } 1367 1368 linkFlags = append(linkFlags, "--manifest "+a.manifest.String()) 1369 linkDeps = append(linkDeps, a.manifest) 1370 1371 staticResourcesNodesDepSet, sharedResourcesNodesDepSet, staticRRODirsDepSet, staticManifestsDepSet, sharedLibs, libFlags := 1372 aaptLibs(ctx, android.SdkContext(a), nil, nil) 1373 1374 _ = sharedResourcesNodesDepSet 1375 _ = staticRRODirsDepSet 1376 1377 staticDeps := transitiveAarDeps(staticResourcesNodesDepSet.ToList()) 1378 1379 linkDeps = append(linkDeps, sharedLibs...) 1380 linkDeps = append(linkDeps, staticDeps.resPackages()...) 1381 linkFlags = append(linkFlags, libFlags...) 1382 1383 overlayRes := android.Paths{flata} 1384 1385 // Treat static library dependencies of static libraries as imports. 1386 transitiveStaticLibs := staticDeps.resPackages() 1387 linkDeps = append(linkDeps, transitiveStaticLibs...) 1388 for _, staticLib := range transitiveStaticLibs { 1389 linkFlags = append(linkFlags, "-I "+staticLib.String()) 1390 } 1391 1392 transitiveAssets := android.ReverseSliceInPlace(staticDeps.assets()) 1393 aapt2Link(ctx, exportPackage, nil, proguardOptionsFile, aaptRTxt, 1394 linkFlags, linkDeps, nil, overlayRes, transitiveAssets, nil, nil) 1395 ctx.CheckbuildFile(exportPackage) 1396 a.exportPackage = exportPackage 1397 1398 rJar := android.PathForModuleOut(ctx, "busybox/R.jar") 1399 resourceProcessorBusyBoxGenerateBinaryR(ctx, a.rTxt, a.manifest, rJar, nil, true, nil, false) 1400 ctx.CheckbuildFile(rJar) 1401 a.rJar = rJar 1402 1403 aapt2ExtractExtraPackages(ctx, extraAaptPackagesFile, a.rJar) 1404 a.extraAaptPackagesFile = extraAaptPackagesFile 1405 1406 resourcesNodesDepSetBuilder := depset.NewBuilder[*resourcesNode](depset.TOPOLOGICAL) 1407 resourcesNodesDepSetBuilder.Direct(&resourcesNode{ 1408 resPackage: a.exportPackage, 1409 manifest: a.manifest, 1410 rTxt: a.rTxt, 1411 rJar: a.rJar, 1412 assets: android.OptionalPathForPath(a.assetsPackage), 1413 1414 usedResourceProcessor: true, 1415 }) 1416 resourcesNodesDepSetBuilder.Transitive(staticResourcesNodesDepSet) 1417 a.resourcesNodesDepSet = resourcesNodesDepSetBuilder.Build() 1418 1419 manifestDepSetBuilder := depset.NewBuilder[android.Path](depset.TOPOLOGICAL).Direct(a.manifest) 1420 manifestDepSetBuilder.Transitive(staticManifestsDepSet) 1421 a.manifestsDepSet = manifestDepSetBuilder.Build() 1422 1423 transitiveAaptResourcePackages := staticDeps.resPackages().Strings() 1424 transitiveAaptResourcePackages = slices.DeleteFunc(transitiveAaptResourcePackages, func(p string) bool { 1425 return p == a.exportPackage.String() 1426 }) 1427 transitiveAaptResourcePackagesFile := android.PathForModuleOut(ctx, "transitive-res-packages") 1428 android.WriteFileRule(ctx, transitiveAaptResourcePackagesFile, strings.Join(transitiveAaptResourcePackages, "\n")) 1429 a.transitiveAaptResourcePackagesFile = transitiveAaptResourcePackagesFile 1430 1431 a.collectTransitiveHeaderJarsForR8(ctx) 1432 1433 a.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx) 1434 1435 var staticJars android.Paths 1436 var staticHeaderJars android.Paths 1437 var staticResourceJars android.Paths 1438 var transitiveStaticLibsHeaderJars []depset.DepSet[android.Path] 1439 var transitiveStaticLibsImplementationJars []depset.DepSet[android.Path] 1440 var transitiveStaticLibsResourceJars []depset.DepSet[android.Path] 1441 1442 ctx.VisitDirectDeps(func(module android.Module) { 1443 if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok { 1444 tag := ctx.OtherModuleDependencyTag(module) 1445 switch tag { 1446 case staticLibTag: 1447 staticJars = append(staticJars, dep.ImplementationJars...) 1448 staticHeaderJars = append(staticHeaderJars, dep.HeaderJars...) 1449 staticResourceJars = append(staticResourceJars, dep.ResourceJars...) 1450 transitiveStaticLibsHeaderJars = append(transitiveStaticLibsHeaderJars, dep.TransitiveStaticLibsHeaderJars) 1451 transitiveStaticLibsImplementationJars = append(transitiveStaticLibsImplementationJars, dep.TransitiveStaticLibsImplementationJars) 1452 transitiveStaticLibsResourceJars = append(transitiveStaticLibsResourceJars, dep.TransitiveStaticLibsResourceJars) 1453 } 1454 } 1455 addCLCFromDep(ctx, module, a.classLoaderContexts) 1456 addMissingOptionalUsesLibsFromDep(ctx, module, &a.usesLibrary) 1457 }) 1458 1459 completeStaticLibsHeaderJars := depset.New(depset.PREORDER, android.Paths{classpathFile}, transitiveStaticLibsHeaderJars) 1460 completeStaticLibsImplementationJars := depset.New(depset.PREORDER, android.Paths{classpathFile}, transitiveStaticLibsImplementationJars) 1461 completeStaticLibsResourceJars := depset.New(depset.PREORDER, nil, transitiveStaticLibsResourceJars) 1462 1463 var implementationJarFile android.Path 1464 var combineJars android.Paths 1465 if ctx.Config().UseTransitiveJarsInClasspath() { 1466 combineJars = completeStaticLibsImplementationJars.ToList() 1467 } else { 1468 combineJars = append(android.Paths{classpathFile}, staticJars...) 1469 } 1470 1471 if len(combineJars) > 1 { 1472 implementationJarOutputPath := android.PathForModuleOut(ctx, "combined", jarName) 1473 TransformJarsToJar(ctx, implementationJarOutputPath, "combine", combineJars, android.OptionalPath{}, false, nil, nil) 1474 implementationJarFile = implementationJarOutputPath 1475 } else { 1476 implementationJarFile = classpathFile 1477 } 1478 1479 var resourceJarFile android.Path 1480 var resourceJars android.Paths 1481 if ctx.Config().UseTransitiveJarsInClasspath() { 1482 resourceJars = completeStaticLibsResourceJars.ToList() 1483 } else { 1484 resourceJars = staticResourceJars 1485 } 1486 if len(resourceJars) > 1 { 1487 combinedJar := android.PathForModuleOut(ctx, "res-combined", jarName) 1488 TransformJarsToJar(ctx, combinedJar, "for resources", resourceJars, android.OptionalPath{}, 1489 false, nil, nil) 1490 resourceJarFile = combinedJar 1491 } else if len(resourceJars) == 1 { 1492 resourceJarFile = resourceJars[0] 1493 } 1494 1495 // merge implementation jar with resources if necessary 1496 var implementationAndResourcesJars android.Paths 1497 if ctx.Config().UseTransitiveJarsInClasspath() { 1498 implementationAndResourcesJars = append(slices.Clone(resourceJars), combineJars...) 1499 } else { 1500 implementationAndResourcesJars = android.PathsIfNonNil(resourceJarFile, implementationJarFile) 1501 } 1502 var implementationAndResourcesJar android.Path 1503 if len(implementationAndResourcesJars) > 1 { 1504 combinedJar := android.PathForModuleOut(ctx, "withres", jarName) 1505 TransformJarsToJar(ctx, combinedJar, "for resources", implementationAndResourcesJars, android.OptionalPath{}, 1506 false, nil, nil) 1507 implementationAndResourcesJar = combinedJar 1508 } else { 1509 implementationAndResourcesJar = implementationAndResourcesJars[0] 1510 } 1511 1512 a.implementationJarFile = implementationJarFile 1513 // Save the output file with no relative path so that it doesn't end up in a subdirectory when used as a resource 1514 a.implementationAndResourcesJarFile = implementationAndResourcesJar.WithoutRel() 1515 1516 var headerJars android.Paths 1517 if ctx.Config().UseTransitiveJarsInClasspath() { 1518 headerJars = completeStaticLibsHeaderJars.ToList() 1519 } else { 1520 headerJars = append(android.Paths{classpathFile}, staticHeaderJars...) 1521 } 1522 if len(headerJars) > 1 { 1523 headerJarFile := android.PathForModuleOut(ctx, "turbine-combined", jarName) 1524 TransformJarsToJar(ctx, headerJarFile, "combine header jars", headerJars, android.OptionalPath{}, false, nil, nil) 1525 a.headerJarFile = headerJarFile 1526 } else { 1527 a.headerJarFile = headerJars[0] 1528 } 1529 1530 if ctx.Config().UseTransitiveJarsInClasspath() { 1531 ctx.CheckbuildFile(classpathFile) 1532 } else { 1533 ctx.CheckbuildFile(a.headerJarFile) 1534 ctx.CheckbuildFile(a.implementationJarFile) 1535 } 1536 1537 android.SetProvider(ctx, JavaInfoProvider, &JavaInfo{ 1538 HeaderJars: android.PathsIfNonNil(a.headerJarFile), 1539 LocalHeaderJars: android.PathsIfNonNil(classpathFile), 1540 TransitiveStaticLibsHeaderJars: completeStaticLibsHeaderJars, 1541 TransitiveStaticLibsImplementationJars: completeStaticLibsImplementationJars, 1542 TransitiveStaticLibsResourceJars: completeStaticLibsResourceJars, 1543 ResourceJars: android.PathsIfNonNil(resourceJarFile), 1544 TransitiveLibsHeaderJarsForR8: a.transitiveLibsHeaderJarsForR8, 1545 TransitiveStaticLibsHeaderJarsForR8: a.transitiveStaticLibsHeaderJarsForR8, 1546 ImplementationAndResourcesJars: android.PathsIfNonNil(a.implementationAndResourcesJarFile), 1547 ImplementationJars: android.PathsIfNonNil(a.implementationJarFile), 1548 StubsLinkType: Implementation, 1549 // TransitiveAconfigFiles: // TODO(b/289117800): LOCAL_ACONFIG_FILES for prebuilts 1550 }) 1551 1552 if proptools.Bool(a.properties.Extract_jni) { 1553 for _, t := range ctx.MultiTargets() { 1554 arch := t.Arch.Abi[0] 1555 path := android.PathForModuleOut(ctx, arch+"_jni.zip") 1556 a.jniPackages = append(a.jniPackages, path) 1557 1558 outDir := android.PathForModuleOut(ctx, "aarForJni") 1559 aarPath := android.PathForModuleSrc(ctx, a.properties.Aars[0]) 1560 ctx.Build(pctx, android.BuildParams{ 1561 Rule: extractJNI, 1562 Input: aarPath, 1563 Outputs: android.WritablePaths{path}, 1564 Description: "extract JNI from AAR", 1565 Args: map[string]string{ 1566 "outDir": outDir.String(), 1567 "archString": arch, 1568 }, 1569 }) 1570 } 1571 } 1572 1573 android.SetProvider(ctx, JniPackageProvider, JniPackageInfo{ 1574 JniPackages: a.jniPackages, 1575 }) 1576 1577 ctx.SetOutputFiles([]android.Path{a.implementationAndResourcesJarFile}, "") 1578 ctx.SetOutputFiles([]android.Path{a.aarPath}, ".aar") 1579} 1580 1581func (a *AARImport) HeaderJars() android.Paths { 1582 return android.Paths{a.headerJarFile} 1583} 1584 1585func (a *AARImport) ImplementationAndResourcesJars() android.Paths { 1586 return android.Paths{a.implementationAndResourcesJarFile} 1587} 1588 1589func (a *AARImport) DexJarBuildPath(ctx android.ModuleErrorfContext) OptionalDexJarPath { 1590 return OptionalDexJarPath{} 1591} 1592 1593func (a *AARImport) DexJarInstallPath() android.Path { 1594 return nil 1595} 1596 1597func (a *AARImport) ClassLoaderContexts() dexpreopt.ClassLoaderContextMap { 1598 return a.classLoaderContexts 1599} 1600 1601var _ UsesLibraryDependency = (*AARImport)(nil) 1602 1603var _ android.ApexModule = (*AARImport)(nil) 1604 1605// Implements android.ApexModule 1606func (a *AARImport) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool { 1607 return a.depIsInSameApex(ctx, dep) 1608} 1609 1610// Implements android.ApexModule 1611func (a *AARImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext, 1612 sdkVersion android.ApiLevel) error { 1613 return nil 1614} 1615 1616var _ android.PrebuiltInterface = (*AARImport)(nil) 1617 1618func (a *AARImport) UsesLibrary() *usesLibrary { 1619 return &a.usesLibrary 1620} 1621 1622var _ ModuleWithUsesLibrary = (*AARImport)(nil) 1623 1624// android_library_import imports an `.aar` file into the build graph as if it was built with android_library. 1625// 1626// This module is not suitable for installing on a device, but can be used as a `static_libs` dependency of 1627// an android_app module. 1628func AARImportFactory() android.Module { 1629 module := &AARImport{} 1630 1631 module.AddProperties( 1632 &module.properties, 1633 &module.usesLibrary.usesLibraryProperties, 1634 ) 1635 1636 android.InitPrebuiltModule(module, &module.properties.Aars) 1637 android.InitApexModule(module) 1638 InitJavaModuleMultiTargets(module, android.DeviceSupported) 1639 return module 1640} 1641 1642func (a *AARImport) IDEInfo(ctx android.BaseModuleContext, dpInfo *android.IdeInfo) { 1643 dpInfo.Jars = append(dpInfo.Jars, a.headerJarFile.String(), a.rJar.String()) 1644} 1645