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