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