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 "strconv" 21 "strings" 22 23 "android/soong/android" 24 "android/soong/bazel" 25 "android/soong/dexpreopt" 26 27 "github.com/google/blueprint" 28 "github.com/google/blueprint/proptools" 29) 30 31type AndroidLibraryDependency interface { 32 LibraryDependency 33 ExportPackage() android.Path 34 ExportedRRODirs() []rroDir 35 ExportedStaticPackages() android.Paths 36 ExportedManifests() android.Paths 37 ExportedAssets() android.OptionalPath 38 SetRROEnforcedForDependent(enforce bool) 39 IsRROEnforced(ctx android.BaseModuleContext) bool 40} 41 42func init() { 43 RegisterAARBuildComponents(android.InitRegistrationContext) 44} 45 46func RegisterAARBuildComponents(ctx android.RegistrationContext) { 47 ctx.RegisterModuleType("android_library_import", AARImportFactory) 48 ctx.RegisterModuleType("android_library", AndroidLibraryFactory) 49 ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) { 50 ctx.TopDown("propagate_rro_enforcement", propagateRROEnforcementMutator).Parallel() 51 }) 52} 53 54// 55// AAR (android library) 56// 57 58type androidLibraryProperties struct { 59 BuildAAR bool `blueprint:"mutated"` 60} 61 62type aaptProperties struct { 63 // flags passed to aapt when creating the apk 64 Aaptflags []string 65 66 // include all resource configurations, not just the product-configured 67 // ones. 68 Aapt_include_all_resources *bool 69 70 // list of directories relative to the Blueprints file containing assets. 71 // Defaults to ["assets"] if a directory called assets exists. Set to [] 72 // to disable the default. 73 Asset_dirs []string 74 75 // list of directories relative to the Blueprints file containing 76 // Android resources. Defaults to ["res"] if a directory called res exists. 77 // Set to [] to disable the default. 78 Resource_dirs []string 79 80 // list of zip files containing Android resources. 81 Resource_zips []string `android:"path"` 82 83 // path to AndroidManifest.xml. If unset, defaults to "AndroidManifest.xml". 84 Manifest *string `android:"path"` 85 86 // paths to additional manifest files to merge with main manifest. 87 Additional_manifests []string `android:"path"` 88 89 // do not include AndroidManifest from dependent libraries 90 Dont_merge_manifests *bool 91 92 // true if RRO is enforced for any of the dependent modules 93 RROEnforcedForDependent bool `blueprint:"mutated"` 94} 95 96type aapt struct { 97 aaptSrcJar android.Path 98 exportPackage android.Path 99 manifestPath android.Path 100 transitiveManifestPaths android.Paths 101 proguardOptionsFile android.Path 102 rroDirs []rroDir 103 rTxt android.Path 104 extraAaptPackagesFile android.Path 105 mergedManifestFile android.Path 106 noticeFile android.OptionalPath 107 assetPackage android.OptionalPath 108 isLibrary bool 109 defaultManifestVersion string 110 useEmbeddedNativeLibs bool 111 useEmbeddedDex bool 112 usesNonSdkApis bool 113 hasNoCode bool 114 LoggingParent string 115 resourceFiles android.Paths 116 117 splitNames []string 118 splits []split 119 120 aaptProperties aaptProperties 121} 122 123type split struct { 124 name string 125 suffix string 126 path android.Path 127} 128 129// Propagate RRO enforcement flag to static lib dependencies transitively. 130func propagateRROEnforcementMutator(ctx android.TopDownMutatorContext) { 131 m := ctx.Module() 132 if d, ok := m.(AndroidLibraryDependency); ok && d.IsRROEnforced(ctx) { 133 ctx.VisitDirectDepsWithTag(staticLibTag, func(d android.Module) { 134 if a, ok := d.(AndroidLibraryDependency); ok { 135 a.SetRROEnforcedForDependent(true) 136 } 137 }) 138 } 139} 140 141func (a *aapt) ExportPackage() android.Path { 142 return a.exportPackage 143} 144 145func (a *aapt) ExportedRRODirs() []rroDir { 146 return a.rroDirs 147} 148 149func (a *aapt) ExportedManifests() android.Paths { 150 return a.transitiveManifestPaths 151} 152 153func (a *aapt) ExportedAssets() android.OptionalPath { 154 return a.assetPackage 155} 156 157func (a *aapt) SetRROEnforcedForDependent(enforce bool) { 158 a.aaptProperties.RROEnforcedForDependent = enforce 159} 160 161func (a *aapt) IsRROEnforced(ctx android.BaseModuleContext) bool { 162 // True if RRO is enforced for this module or... 163 return ctx.Config().EnforceRROForModule(ctx.ModuleName()) || 164 // if RRO is enforced for any of its dependents. 165 a.aaptProperties.RROEnforcedForDependent 166} 167 168func (a *aapt) aapt2Flags(ctx android.ModuleContext, sdkContext android.SdkContext, 169 manifestPath android.Path) (compileFlags, linkFlags []string, linkDeps android.Paths, 170 resDirs, overlayDirs []globbedResourceDir, rroDirs []rroDir, resZips android.Paths) { 171 172 hasVersionCode := android.PrefixInList(a.aaptProperties.Aaptflags, "--version-code") 173 hasVersionName := android.PrefixInList(a.aaptProperties.Aaptflags, "--version-name") 174 175 // Flags specified in Android.bp 176 linkFlags = append(linkFlags, a.aaptProperties.Aaptflags...) 177 178 linkFlags = append(linkFlags, "--no-static-lib-packages") 179 180 // Find implicit or explicit asset and resource dirs 181 assetDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Asset_dirs, "assets") 182 resourceDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Resource_dirs, "res") 183 resourceZips := android.PathsForModuleSrc(ctx, a.aaptProperties.Resource_zips) 184 185 // Glob directories into lists of paths 186 for _, dir := range resourceDirs { 187 resDirs = append(resDirs, globbedResourceDir{ 188 dir: dir, 189 files: androidResourceGlob(ctx, dir), 190 }) 191 resOverlayDirs, resRRODirs := overlayResourceGlob(ctx, a, dir) 192 overlayDirs = append(overlayDirs, resOverlayDirs...) 193 rroDirs = append(rroDirs, resRRODirs...) 194 } 195 196 var assetDeps android.Paths 197 for i, dir := range assetDirs { 198 // Add a dependency on every file in the asset directory. This ensures the aapt2 199 // rule will be rerun if one of the files in the asset directory is modified. 200 assetDeps = append(assetDeps, androidResourceGlob(ctx, dir)...) 201 202 // Add a dependency on a file that contains a list of all the files in the asset directory. 203 // This ensures the aapt2 rule will be run if a file is removed from the asset directory, 204 // or a file is added whose timestamp is older than the output of aapt2. 205 assetFileListFile := android.PathForModuleOut(ctx, "asset_dir_globs", strconv.Itoa(i)+".glob") 206 androidResourceGlobList(ctx, dir, assetFileListFile) 207 assetDeps = append(assetDeps, assetFileListFile) 208 } 209 210 assetDirStrings := assetDirs.Strings() 211 if a.noticeFile.Valid() { 212 assetDirStrings = append(assetDirStrings, filepath.Dir(a.noticeFile.Path().String())) 213 assetDeps = append(assetDeps, a.noticeFile.Path()) 214 } 215 216 linkFlags = append(linkFlags, "--manifest "+manifestPath.String()) 217 linkDeps = append(linkDeps, manifestPath) 218 219 linkFlags = append(linkFlags, android.JoinWithPrefix(assetDirStrings, "-A ")) 220 linkDeps = append(linkDeps, assetDeps...) 221 222 // Returns the effective version for {min|target}_sdk_version 223 effectiveVersionString := func(sdkVersion android.SdkSpec, minSdkVersion android.ApiLevel) string { 224 // If {min|target}_sdk_version is current, use sdk_version to determine the effective level 225 // This is necessary for vendor modules. 226 // The effective version does not _only_ depend on {min|target}_sdk_version(level), 227 // but also on the sdk_version (kind+level) 228 if minSdkVersion.IsCurrent() { 229 ret, err := sdkVersion.EffectiveVersionString(ctx) 230 if err != nil { 231 ctx.ModuleErrorf("invalid sdk_version: %s", err) 232 } 233 return ret 234 } 235 ret, err := minSdkVersion.EffectiveVersionString(ctx) 236 if err != nil { 237 ctx.ModuleErrorf("invalid min_sdk_version: %s", err) 238 } 239 return ret 240 } 241 // SDK version flags 242 sdkVersion := sdkContext.SdkVersion(ctx) 243 minSdkVersion := effectiveVersionString(sdkVersion, sdkContext.MinSdkVersion(ctx)) 244 245 linkFlags = append(linkFlags, "--min-sdk-version "+minSdkVersion) 246 // Use minSdkVersion for target-sdk-version, even if `target_sdk_version` is set 247 // This behavior has been copied from Make. 248 linkFlags = append(linkFlags, "--target-sdk-version "+minSdkVersion) 249 250 // Version code 251 if !hasVersionCode { 252 linkFlags = append(linkFlags, "--version-code", ctx.Config().PlatformSdkVersion().String()) 253 } 254 255 if !hasVersionName { 256 var versionName string 257 if ctx.ModuleName() == "framework-res" { 258 // Some builds set AppsDefaultVersionName() to include the build number ("O-123456"). aapt2 copies the 259 // version name of framework-res into app manifests as compileSdkVersionCodename, which confuses things 260 // if it contains the build number. Use the PlatformVersionName instead. 261 versionName = ctx.Config().PlatformVersionName() 262 } else { 263 versionName = ctx.Config().AppsDefaultVersionName() 264 } 265 versionName = proptools.NinjaEscape(versionName) 266 linkFlags = append(linkFlags, "--version-name ", versionName) 267 } 268 269 linkFlags, compileFlags = android.FilterList(linkFlags, []string{"--legacy"}) 270 271 // Always set --pseudo-localize, it will be stripped out later for release 272 // builds that don't want it. 273 compileFlags = append(compileFlags, "--pseudo-localize") 274 275 return compileFlags, linkFlags, linkDeps, resDirs, overlayDirs, rroDirs, resourceZips 276} 277 278func (a *aapt) deps(ctx android.BottomUpMutatorContext, sdkDep sdkDep) { 279 if sdkDep.frameworkResModule != "" { 280 ctx.AddVariationDependencies(nil, frameworkResTag, sdkDep.frameworkResModule) 281 } 282} 283 284var extractAssetsRule = pctx.AndroidStaticRule("extractAssets", 285 blueprint.RuleParams{ 286 Command: `${config.Zip2ZipCmd} -i ${in} -o ${out} "assets/**/*"`, 287 CommandDeps: []string{"${config.Zip2ZipCmd}"}, 288 }) 289 290func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext android.SdkContext, 291 classLoaderContexts dexpreopt.ClassLoaderContextMap, excludedLibs []string, 292 enforceDefaultTargetSdkVersion bool, extraLinkFlags ...string) { 293 294 transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, assetPackages, libDeps, libFlags := 295 aaptLibs(ctx, sdkContext, classLoaderContexts) 296 297 // Exclude any libraries from the supplied list. 298 classLoaderContexts = classLoaderContexts.ExcludeLibs(excludedLibs) 299 300 // App manifest file 301 manifestFile := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml") 302 manifestSrcPath := android.PathForModuleSrc(ctx, manifestFile) 303 304 manifestPath := ManifestFixer(ctx, manifestSrcPath, ManifestFixerParams{ 305 SdkContext: sdkContext, 306 ClassLoaderContexts: classLoaderContexts, 307 IsLibrary: a.isLibrary, 308 DefaultManifestVersion: a.defaultManifestVersion, 309 UseEmbeddedNativeLibs: a.useEmbeddedNativeLibs, 310 UsesNonSdkApis: a.usesNonSdkApis, 311 UseEmbeddedDex: a.useEmbeddedDex, 312 HasNoCode: a.hasNoCode, 313 LoggingParent: a.LoggingParent, 314 EnforceDefaultTargetSdkVersion: enforceDefaultTargetSdkVersion, 315 }) 316 317 // Add additional manifest files to transitive manifests. 318 additionalManifests := android.PathsForModuleSrc(ctx, a.aaptProperties.Additional_manifests) 319 a.transitiveManifestPaths = append(android.Paths{manifestPath}, additionalManifests...) 320 a.transitiveManifestPaths = append(a.transitiveManifestPaths, transitiveStaticLibManifests...) 321 322 if len(a.transitiveManifestPaths) > 1 && !Bool(a.aaptProperties.Dont_merge_manifests) { 323 a.mergedManifestFile = manifestMerger(ctx, a.transitiveManifestPaths[0], a.transitiveManifestPaths[1:], a.isLibrary) 324 if !a.isLibrary { 325 // Only use the merged manifest for applications. For libraries, the transitive closure of manifests 326 // will be propagated to the final application and merged there. The merged manifest for libraries is 327 // only passed to Make, which can't handle transitive dependencies. 328 manifestPath = a.mergedManifestFile 329 } 330 } else { 331 a.mergedManifestFile = manifestPath 332 } 333 334 compileFlags, linkFlags, linkDeps, resDirs, overlayDirs, rroDirs, resZips := a.aapt2Flags(ctx, sdkContext, manifestPath) 335 336 rroDirs = append(rroDirs, staticRRODirs...) 337 linkFlags = append(linkFlags, libFlags...) 338 linkDeps = append(linkDeps, libDeps...) 339 linkFlags = append(linkFlags, extraLinkFlags...) 340 if a.isLibrary { 341 linkFlags = append(linkFlags, "--static-lib") 342 } 343 344 packageRes := android.PathForModuleOut(ctx, "package-res.apk") 345 // the subdir "android" is required to be filtered by package names 346 srcJar := android.PathForModuleGen(ctx, "android", "R.srcjar") 347 proguardOptionsFile := android.PathForModuleGen(ctx, "proguard.options") 348 rTxt := android.PathForModuleOut(ctx, "R.txt") 349 // This file isn't used by Soong, but is generated for exporting 350 extraPackages := android.PathForModuleOut(ctx, "extra_packages") 351 352 var compiledResDirs []android.Paths 353 for _, dir := range resDirs { 354 a.resourceFiles = append(a.resourceFiles, dir.files...) 355 compiledResDirs = append(compiledResDirs, aapt2Compile(ctx, dir.dir, dir.files, compileFlags).Paths()) 356 } 357 358 for i, zip := range resZips { 359 flata := android.PathForModuleOut(ctx, fmt.Sprintf("reszip.%d.flata", i)) 360 aapt2CompileZip(ctx, flata, zip, "", compileFlags) 361 compiledResDirs = append(compiledResDirs, android.Paths{flata}) 362 } 363 364 var compiledRes, compiledOverlay android.Paths 365 366 compiledOverlay = append(compiledOverlay, transitiveStaticLibs...) 367 368 if len(transitiveStaticLibs) > 0 { 369 // If we are using static android libraries, every source file becomes an overlay. 370 // This is to emulate old AAPT behavior which simulated library support. 371 for _, compiledResDir := range compiledResDirs { 372 compiledOverlay = append(compiledOverlay, compiledResDir...) 373 } 374 } else if a.isLibrary { 375 // Otherwise, for a static library we treat all the resources equally with no overlay. 376 for _, compiledResDir := range compiledResDirs { 377 compiledRes = append(compiledRes, compiledResDir...) 378 } 379 } else if len(compiledResDirs) > 0 { 380 // Without static libraries, the first directory is our directory, which can then be 381 // overlaid by the rest. 382 compiledRes = append(compiledRes, compiledResDirs[0]...) 383 for _, compiledResDir := range compiledResDirs[1:] { 384 compiledOverlay = append(compiledOverlay, compiledResDir...) 385 } 386 } 387 388 for _, dir := range overlayDirs { 389 compiledOverlay = append(compiledOverlay, aapt2Compile(ctx, dir.dir, dir.files, compileFlags).Paths()...) 390 } 391 392 var splitPackages android.WritablePaths 393 var splits []split 394 395 for _, s := range a.splitNames { 396 suffix := strings.Replace(s, ",", "_", -1) 397 path := android.PathForModuleOut(ctx, "package_"+suffix+".apk") 398 linkFlags = append(linkFlags, "--split", path.String()+":"+s) 399 splitPackages = append(splitPackages, path) 400 splits = append(splits, split{ 401 name: s, 402 suffix: suffix, 403 path: path, 404 }) 405 } 406 407 aapt2Link(ctx, packageRes, srcJar, proguardOptionsFile, rTxt, extraPackages, 408 linkFlags, linkDeps, compiledRes, compiledOverlay, assetPackages, splitPackages) 409 410 // Extract assets from the resource package output so that they can be used later in aapt2link 411 // for modules that depend on this one. 412 if android.PrefixInList(linkFlags, "-A ") || len(assetPackages) > 0 { 413 assets := android.PathForModuleOut(ctx, "assets.zip") 414 ctx.Build(pctx, android.BuildParams{ 415 Rule: extractAssetsRule, 416 Input: packageRes, 417 Output: assets, 418 Description: "extract assets from built resource file", 419 }) 420 a.assetPackage = android.OptionalPathForPath(assets) 421 } 422 423 a.aaptSrcJar = srcJar 424 a.exportPackage = packageRes 425 a.manifestPath = manifestPath 426 a.proguardOptionsFile = proguardOptionsFile 427 a.rroDirs = rroDirs 428 a.extraAaptPackagesFile = extraPackages 429 a.rTxt = rTxt 430 a.splits = splits 431} 432 433// aaptLibs collects libraries from dependencies and sdk_version and converts them into paths 434func aaptLibs(ctx android.ModuleContext, sdkContext android.SdkContext, classLoaderContexts dexpreopt.ClassLoaderContextMap) ( 435 transitiveStaticLibs, transitiveStaticLibManifests android.Paths, staticRRODirs []rroDir, assets, deps android.Paths, flags []string) { 436 437 var sharedLibs android.Paths 438 439 if classLoaderContexts == nil { 440 // Not all callers need to compute class loader context, those who don't just pass nil. 441 // Create a temporary class loader context here (it will be computed, but not used). 442 classLoaderContexts = make(dexpreopt.ClassLoaderContextMap) 443 } 444 445 sdkDep := decodeSdkDep(ctx, sdkContext) 446 if sdkDep.useFiles { 447 sharedLibs = append(sharedLibs, sdkDep.jars...) 448 } 449 450 ctx.VisitDirectDeps(func(module android.Module) { 451 depTag := ctx.OtherModuleDependencyTag(module) 452 453 var exportPackage android.Path 454 aarDep, _ := module.(AndroidLibraryDependency) 455 if aarDep != nil { 456 exportPackage = aarDep.ExportPackage() 457 } 458 459 switch depTag { 460 case instrumentationForTag: 461 // Nothing, instrumentationForTag is treated as libTag for javac but not for aapt2. 462 case sdkLibTag, libTag: 463 if exportPackage != nil { 464 sharedLibs = append(sharedLibs, exportPackage) 465 } 466 case frameworkResTag: 467 if exportPackage != nil { 468 sharedLibs = append(sharedLibs, exportPackage) 469 } 470 case staticLibTag: 471 if exportPackage != nil { 472 transitiveStaticLibs = append(transitiveStaticLibs, aarDep.ExportedStaticPackages()...) 473 transitiveStaticLibs = append(transitiveStaticLibs, exportPackage) 474 transitiveStaticLibManifests = append(transitiveStaticLibManifests, aarDep.ExportedManifests()...) 475 if aarDep.ExportedAssets().Valid() { 476 assets = append(assets, aarDep.ExportedAssets().Path()) 477 } 478 479 outer: 480 for _, d := range aarDep.ExportedRRODirs() { 481 for _, e := range staticRRODirs { 482 if d.path == e.path { 483 continue outer 484 } 485 } 486 staticRRODirs = append(staticRRODirs, d) 487 } 488 } 489 } 490 491 addCLCFromDep(ctx, module, classLoaderContexts) 492 }) 493 494 deps = append(deps, sharedLibs...) 495 deps = append(deps, transitiveStaticLibs...) 496 497 if len(transitiveStaticLibs) > 0 { 498 flags = append(flags, "--auto-add-overlay") 499 } 500 501 for _, sharedLib := range sharedLibs { 502 flags = append(flags, "-I "+sharedLib.String()) 503 } 504 505 transitiveStaticLibs = android.FirstUniquePaths(transitiveStaticLibs) 506 transitiveStaticLibManifests = android.FirstUniquePaths(transitiveStaticLibManifests) 507 508 return transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, assets, deps, flags 509} 510 511type AndroidLibrary struct { 512 Library 513 aapt 514 android.BazelModuleBase 515 516 androidLibraryProperties androidLibraryProperties 517 518 aarFile android.WritablePath 519 520 exportedStaticPackages android.Paths 521} 522 523var _ android.OutputFileProducer = (*AndroidLibrary)(nil) 524 525// For OutputFileProducer interface 526func (a *AndroidLibrary) OutputFiles(tag string) (android.Paths, error) { 527 switch tag { 528 case ".aar": 529 return []android.Path{a.aarFile}, nil 530 default: 531 return a.Library.OutputFiles(tag) 532 } 533} 534 535func (a *AndroidLibrary) ExportedStaticPackages() android.Paths { 536 return a.exportedStaticPackages 537} 538 539var _ AndroidLibraryDependency = (*AndroidLibrary)(nil) 540 541func (a *AndroidLibrary) DepsMutator(ctx android.BottomUpMutatorContext) { 542 a.Module.deps(ctx) 543 sdkDep := decodeSdkDep(ctx, android.SdkContext(a)) 544 if sdkDep.hasFrameworkLibs() { 545 a.aapt.deps(ctx, sdkDep) 546 } 547 a.usesLibrary.deps(ctx, false) 548} 549 550func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { 551 a.aapt.isLibrary = true 552 a.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx) 553 a.aapt.buildActions(ctx, android.SdkContext(a), a.classLoaderContexts, nil, false) 554 555 a.hideApexVariantFromMake = !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform() 556 557 ctx.CheckbuildFile(a.proguardOptionsFile) 558 ctx.CheckbuildFile(a.exportPackage) 559 ctx.CheckbuildFile(a.aaptSrcJar) 560 561 // apps manifests are handled by aapt, don't let Module see them 562 a.properties.Manifest = nil 563 564 a.linter.mergedManifest = a.aapt.mergedManifestFile 565 a.linter.manifest = a.aapt.manifestPath 566 a.linter.resources = a.aapt.resourceFiles 567 568 a.Module.extraProguardFlagFiles = append(a.Module.extraProguardFlagFiles, 569 a.proguardOptionsFile) 570 571 a.Module.compile(ctx, a.aaptSrcJar) 572 573 a.aarFile = android.PathForModuleOut(ctx, ctx.ModuleName()+".aar") 574 var res android.Paths 575 if a.androidLibraryProperties.BuildAAR { 576 BuildAAR(ctx, a.aarFile, a.outputFile, a.manifestPath, a.rTxt, res) 577 ctx.CheckbuildFile(a.aarFile) 578 } 579 580 a.exportedProguardFlagFiles = append(a.exportedProguardFlagFiles, 581 android.PathsForModuleSrc(ctx, a.dexProperties.Optimize.Proguard_flags_files)...) 582 ctx.VisitDirectDeps(func(m android.Module) { 583 if ctx.OtherModuleDependencyTag(m) == staticLibTag { 584 if lib, ok := m.(LibraryDependency); ok { 585 a.exportedProguardFlagFiles = append(a.exportedProguardFlagFiles, lib.ExportedProguardFlagFiles()...) 586 } 587 if alib, ok := m.(AndroidLibraryDependency); ok { 588 a.exportedStaticPackages = append(a.exportedStaticPackages, alib.ExportPackage()) 589 a.exportedStaticPackages = append(a.exportedStaticPackages, alib.ExportedStaticPackages()...) 590 } 591 } 592 }) 593 a.exportedProguardFlagFiles = android.FirstUniquePaths(a.exportedProguardFlagFiles) 594 a.exportedStaticPackages = android.FirstUniquePaths(a.exportedStaticPackages) 595 596 prebuiltJniPackages := android.Paths{} 597 ctx.VisitDirectDeps(func(module android.Module) { 598 if info, ok := ctx.OtherModuleProvider(module, JniPackageProvider).(JniPackageInfo); ok { 599 prebuiltJniPackages = append(prebuiltJniPackages, info.JniPackages...) 600 } 601 }) 602 if len(prebuiltJniPackages) > 0 { 603 ctx.SetProvider(JniPackageProvider, JniPackageInfo{ 604 JniPackages: prebuiltJniPackages, 605 }) 606 } 607} 608 609// android_library builds and links sources into a `.jar` file for the device along with Android resources. 610// 611// An android_library has a single variant that produces a `.jar` file containing `.class` files that were 612// compiled against the device bootclasspath, along with a `package-res.apk` file containing Android resources compiled 613// with aapt2. This module is not suitable for installing on a device, but can be used as a `static_libs` dependency of 614// an android_app module. 615func AndroidLibraryFactory() android.Module { 616 module := &AndroidLibrary{} 617 618 module.Module.addHostAndDeviceProperties() 619 module.AddProperties( 620 &module.aaptProperties, 621 &module.androidLibraryProperties) 622 623 module.androidLibraryProperties.BuildAAR = true 624 module.Module.linter.library = true 625 626 android.InitApexModule(module) 627 InitJavaModule(module, android.DeviceSupported) 628 android.InitBazelModule(module) 629 return module 630} 631 632// 633// AAR (android library) prebuilts 634// 635 636// Properties for android_library_import 637type AARImportProperties struct { 638 // ARR (android library prebuilt) filepath. Exactly one ARR is required. 639 Aars []string `android:"path"` 640 // If not blank, set to the version of the sdk to compile against. 641 // Defaults to private. 642 // Values are of one of the following forms: 643 // 1) numerical API level, "current", "none", or "core_platform" 644 // 2) An SDK kind with an API level: "<sdk kind>_<API level>" 645 // See build/soong/android/sdk_version.go for the complete and up to date list of SDK kinds. 646 // If the SDK kind is empty, it will be set to public 647 Sdk_version *string 648 // If not blank, set the minimum version of the sdk that the compiled artifacts will run against. 649 // Defaults to sdk_version if not set. See sdk_version for possible values. 650 Min_sdk_version *string 651 // List of java static libraries that the included ARR (android library prebuilts) has dependencies to. 652 Static_libs []string 653 // List of java libraries that the included ARR (android library prebuilts) has dependencies to. 654 Libs []string 655 // If set to true, run Jetifier against .aar file. Defaults to false. 656 Jetifier *bool 657 // If true, extract JNI libs from AAR archive. These libs will be accessible to android_app modules and 658 // will be passed transitively through android_libraries to an android_app. 659 //TODO(b/241138093) evaluate whether we can have this flag default to true for Bazel conversion 660 Extract_jni *bool 661} 662 663type AARImport struct { 664 android.ModuleBase 665 android.DefaultableModuleBase 666 android.ApexModuleBase 667 android.BazelModuleBase 668 prebuilt android.Prebuilt 669 670 // Functionality common to Module and Import. 671 embeddableInModuleAndImport 672 673 providesTransitiveHeaderJars 674 675 properties AARImportProperties 676 677 classpathFile android.WritablePath 678 proguardFlags android.WritablePath 679 exportPackage android.WritablePath 680 extraAaptPackagesFile android.WritablePath 681 manifest android.WritablePath 682 assetsPackage android.WritablePath 683 684 exportedStaticPackages android.Paths 685 686 hideApexVariantFromMake bool 687 688 aarPath android.Path 689 jniPackages android.Paths 690 691 sdkVersion android.SdkSpec 692 minSdkVersion android.ApiLevel 693} 694 695var _ android.OutputFileProducer = (*AARImport)(nil) 696 697// For OutputFileProducer interface 698func (a *AARImport) OutputFiles(tag string) (android.Paths, error) { 699 switch tag { 700 case ".aar": 701 return []android.Path{a.aarPath}, nil 702 case "": 703 return []android.Path{a.classpathFile}, nil 704 default: 705 return nil, fmt.Errorf("unsupported module reference tag %q", tag) 706 } 707} 708 709func (a *AARImport) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { 710 return android.SdkSpecFrom(ctx, String(a.properties.Sdk_version)) 711} 712 713func (a *AARImport) SystemModules() string { 714 return "" 715} 716 717func (a *AARImport) MinSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel { 718 if a.properties.Min_sdk_version != nil { 719 return android.ApiLevelFrom(ctx, *a.properties.Min_sdk_version) 720 } 721 return a.SdkVersion(ctx).ApiLevel 722} 723 724func (a *AARImport) ReplaceMaxSdkVersionPlaceholder(ctx android.EarlyModuleContext) android.ApiLevel { 725 return android.SdkSpecFrom(ctx, "").ApiLevel 726} 727 728func (a *AARImport) TargetSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel { 729 return a.SdkVersion(ctx).ApiLevel 730} 731 732func (a *AARImport) javaVersion() string { 733 return "" 734} 735 736var _ AndroidLibraryDependency = (*AARImport)(nil) 737 738func (a *AARImport) ExportPackage() android.Path { 739 return a.exportPackage 740} 741 742func (a *AARImport) ExportedProguardFlagFiles() android.Paths { 743 return android.Paths{a.proguardFlags} 744} 745 746func (a *AARImport) ExportedRRODirs() []rroDir { 747 return nil 748} 749 750func (a *AARImport) ExportedStaticPackages() android.Paths { 751 return a.exportedStaticPackages 752} 753 754func (a *AARImport) ExportedManifests() android.Paths { 755 return android.Paths{a.manifest} 756} 757 758func (a *AARImport) ExportedAssets() android.OptionalPath { 759 return android.OptionalPathForPath(a.assetsPackage) 760} 761 762// RRO enforcement is not available on aar_import since its RRO dirs are not 763// exported. 764func (a *AARImport) SetRROEnforcedForDependent(enforce bool) { 765} 766 767// RRO enforcement is not available on aar_import since its RRO dirs are not 768// exported. 769func (a *AARImport) IsRROEnforced(ctx android.BaseModuleContext) bool { 770 return false 771} 772 773func (a *AARImport) Prebuilt() *android.Prebuilt { 774 return &a.prebuilt 775} 776 777func (a *AARImport) Name() string { 778 return a.prebuilt.Name(a.ModuleBase.Name()) 779} 780 781func (a *AARImport) JacocoReportClassesFile() android.Path { 782 return nil 783} 784 785func (a *AARImport) DepsMutator(ctx android.BottomUpMutatorContext) { 786 if !ctx.Config().AlwaysUsePrebuiltSdks() { 787 sdkDep := decodeSdkDep(ctx, android.SdkContext(a)) 788 if sdkDep.useModule && sdkDep.frameworkResModule != "" { 789 ctx.AddVariationDependencies(nil, frameworkResTag, sdkDep.frameworkResModule) 790 } 791 } 792 793 ctx.AddVariationDependencies(nil, libTag, a.properties.Libs...) 794 ctx.AddVariationDependencies(nil, staticLibTag, a.properties.Static_libs...) 795} 796 797type JniPackageInfo struct { 798 // List of zip files containing JNI libraries 799 // Zip files should have directory structure jni/<arch>/*.so 800 JniPackages android.Paths 801} 802 803var JniPackageProvider = blueprint.NewProvider(JniPackageInfo{}) 804 805// Unzip an AAR and extract the JNI libs for $archString. 806var extractJNI = pctx.AndroidStaticRule("extractJNI", 807 blueprint.RuleParams{ 808 Command: `rm -rf $out $outDir && touch $out && ` + 809 `unzip -qoDD -d $outDir $in "jni/${archString}/*" && ` + 810 `jni_files=$$(find $outDir/jni -type f) && ` + 811 // print error message if there are no JNI libs for this arch 812 `[ -n "$$jni_files" ] || (echo "ERROR: no JNI libs found for arch ${archString}" && exit 1) && ` + 813 `${config.SoongZipCmd} -o $out -P 'lib/${archString}' ` + 814 `-C $outDir/jni/${archString} $$(echo $$jni_files | xargs -n1 printf " -f %s")`, 815 CommandDeps: []string{"${config.SoongZipCmd}"}, 816 }, 817 "outDir", "archString") 818 819// Unzip an AAR into its constituent files and directories. Any files in Outputs that don't exist in the AAR will be 820// touched to create an empty file. The res directory is not extracted, as it will be extracted in its own rule. 821var unzipAAR = pctx.AndroidStaticRule("unzipAAR", 822 blueprint.RuleParams{ 823 Command: `rm -rf $outDir && mkdir -p $outDir && ` + 824 `unzip -qoDD -d $outDir $in && rm -rf $outDir/res && touch $out && ` + 825 `${config.Zip2ZipCmd} -i $in -o $assetsPackage 'assets/**/*' && ` + 826 `${config.MergeZipsCmd} $combinedClassesJar $$(ls $outDir/classes.jar 2> /dev/null) $$(ls $outDir/libs/*.jar 2> /dev/null)`, 827 CommandDeps: []string{"${config.MergeZipsCmd}", "${config.Zip2ZipCmd}"}, 828 }, 829 "outDir", "combinedClassesJar", "assetsPackage") 830 831func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { 832 if len(a.properties.Aars) != 1 { 833 ctx.PropertyErrorf("aars", "exactly one aar is required") 834 return 835 } 836 837 a.sdkVersion = a.SdkVersion(ctx) 838 a.minSdkVersion = a.MinSdkVersion(ctx) 839 840 a.hideApexVariantFromMake = !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform() 841 842 aarName := ctx.ModuleName() + ".aar" 843 a.aarPath = android.PathForModuleSrc(ctx, a.properties.Aars[0]) 844 845 if Bool(a.properties.Jetifier) { 846 inputFile := a.aarPath 847 a.aarPath = android.PathForModuleOut(ctx, "jetifier", aarName) 848 TransformJetifier(ctx, a.aarPath.(android.WritablePath), inputFile) 849 } 850 851 extractedAARDir := android.PathForModuleOut(ctx, "aar") 852 a.classpathFile = extractedAARDir.Join(ctx, "classes-combined.jar") 853 a.proguardFlags = extractedAARDir.Join(ctx, "proguard.txt") 854 a.manifest = extractedAARDir.Join(ctx, "AndroidManifest.xml") 855 a.assetsPackage = android.PathForModuleOut(ctx, "assets.zip") 856 857 ctx.Build(pctx, android.BuildParams{ 858 Rule: unzipAAR, 859 Input: a.aarPath, 860 Outputs: android.WritablePaths{a.classpathFile, a.proguardFlags, a.manifest, a.assetsPackage}, 861 Description: "unzip AAR", 862 Args: map[string]string{ 863 "outDir": extractedAARDir.String(), 864 "combinedClassesJar": a.classpathFile.String(), 865 "assetsPackage": a.assetsPackage.String(), 866 }, 867 }) 868 869 // Always set --pseudo-localize, it will be stripped out later for release 870 // builds that don't want it. 871 compileFlags := []string{"--pseudo-localize"} 872 compiledResDir := android.PathForModuleOut(ctx, "flat-res") 873 flata := compiledResDir.Join(ctx, "gen_res.flata") 874 aapt2CompileZip(ctx, flata, a.aarPath, "res", compileFlags) 875 876 a.exportPackage = android.PathForModuleOut(ctx, "package-res.apk") 877 // the subdir "android" is required to be filtered by package names 878 srcJar := android.PathForModuleGen(ctx, "android", "R.srcjar") 879 proguardOptionsFile := android.PathForModuleGen(ctx, "proguard.options") 880 rTxt := android.PathForModuleOut(ctx, "R.txt") 881 a.extraAaptPackagesFile = android.PathForModuleOut(ctx, "extra_packages") 882 883 var linkDeps android.Paths 884 885 linkFlags := []string{ 886 "--static-lib", 887 "--no-static-lib-packages", 888 "--auto-add-overlay", 889 } 890 891 linkFlags = append(linkFlags, "--manifest "+a.manifest.String()) 892 linkDeps = append(linkDeps, a.manifest) 893 894 transitiveStaticLibs, staticLibManifests, staticRRODirs, transitiveAssets, libDeps, libFlags := 895 aaptLibs(ctx, android.SdkContext(a), nil) 896 897 _ = staticLibManifests 898 _ = staticRRODirs 899 900 linkDeps = append(linkDeps, libDeps...) 901 linkFlags = append(linkFlags, libFlags...) 902 903 overlayRes := append(android.Paths{flata}, transitiveStaticLibs...) 904 905 aapt2Link(ctx, a.exportPackage, srcJar, proguardOptionsFile, rTxt, a.extraAaptPackagesFile, 906 linkFlags, linkDeps, nil, overlayRes, transitiveAssets, nil) 907 908 // Merge this import's assets with its dependencies' assets (if there are any). 909 if len(transitiveAssets) > 0 { 910 mergedAssets := android.PathForModuleOut(ctx, "merged-assets.zip") 911 inputZips := append(android.Paths{a.assetsPackage}, transitiveAssets...) 912 ctx.Build(pctx, android.BuildParams{ 913 Rule: mergeAssetsRule, 914 Inputs: inputZips, 915 Output: mergedAssets, 916 Description: "merge assets from dependencies and self", 917 }) 918 a.assetsPackage = mergedAssets 919 } 920 921 a.collectTransitiveHeaderJars(ctx) 922 ctx.SetProvider(JavaInfoProvider, JavaInfo{ 923 HeaderJars: android.PathsIfNonNil(a.classpathFile), 924 TransitiveLibsHeaderJars: a.transitiveLibsHeaderJars, 925 TransitiveStaticLibsHeaderJars: a.transitiveStaticLibsHeaderJars, 926 ImplementationAndResourcesJars: android.PathsIfNonNil(a.classpathFile), 927 ImplementationJars: android.PathsIfNonNil(a.classpathFile), 928 }) 929 930 if proptools.Bool(a.properties.Extract_jni) { 931 for _, t := range ctx.MultiTargets() { 932 arch := t.Arch.Abi[0] 933 path := android.PathForModuleOut(ctx, arch+"_jni.zip") 934 a.jniPackages = append(a.jniPackages, path) 935 936 outDir := android.PathForModuleOut(ctx, "aarForJni") 937 aarPath := android.PathForModuleSrc(ctx, a.properties.Aars[0]) 938 ctx.Build(pctx, android.BuildParams{ 939 Rule: extractJNI, 940 Input: aarPath, 941 Outputs: android.WritablePaths{path}, 942 Description: "extract JNI from AAR", 943 Args: map[string]string{ 944 "outDir": outDir.String(), 945 "archString": arch, 946 }, 947 }) 948 } 949 950 ctx.SetProvider(JniPackageProvider, JniPackageInfo{ 951 JniPackages: a.jniPackages, 952 }) 953 } 954} 955 956func (a *AARImport) HeaderJars() android.Paths { 957 return android.Paths{a.classpathFile} 958} 959 960func (a *AARImport) ImplementationAndResourcesJars() android.Paths { 961 return android.Paths{a.classpathFile} 962} 963 964func (a *AARImport) DexJarBuildPath() android.Path { 965 return nil 966} 967 968func (a *AARImport) DexJarInstallPath() android.Path { 969 return nil 970} 971 972func (a *AARImport) ClassLoaderContexts() dexpreopt.ClassLoaderContextMap { 973 return nil 974} 975 976var _ android.ApexModule = (*AARImport)(nil) 977 978// Implements android.ApexModule 979func (a *AARImport) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool { 980 return a.depIsInSameApex(ctx, dep) 981} 982 983// Implements android.ApexModule 984func (g *AARImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext, 985 sdkVersion android.ApiLevel) error { 986 return nil 987} 988 989var _ android.PrebuiltInterface = (*AARImport)(nil) 990 991// android_library_import imports an `.aar` file into the build graph as if it was built with android_library. 992// 993// This module is not suitable for installing on a device, but can be used as a `static_libs` dependency of 994// an android_app module. 995func AARImportFactory() android.Module { 996 module := &AARImport{} 997 998 module.AddProperties(&module.properties) 999 1000 android.InitPrebuiltModule(module, &module.properties.Aars) 1001 android.InitApexModule(module) 1002 InitJavaModuleMultiTargets(module, android.DeviceSupported) 1003 android.InitBazelModule(module) 1004 return module 1005} 1006 1007type bazelAapt struct { 1008 Manifest bazel.Label 1009 Resource_files bazel.LabelListAttribute 1010} 1011 1012type bazelAndroidLibrary struct { 1013 *javaLibraryAttributes 1014 *bazelAapt 1015} 1016 1017type bazelAndroidLibraryImport struct { 1018 Aar bazel.Label 1019 Deps bazel.LabelListAttribute 1020 Exports bazel.LabelListAttribute 1021 Sdk_version bazel.StringAttribute 1022} 1023 1024func (a *aapt) convertAaptAttrsWithBp2Build(ctx android.TopDownMutatorContext) *bazelAapt { 1025 manifest := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml") 1026 1027 resourceFiles := bazel.LabelList{ 1028 Includes: []bazel.Label{}, 1029 } 1030 for _, dir := range android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Resource_dirs, "res") { 1031 files := android.RootToModuleRelativePaths(ctx, androidResourceGlob(ctx, dir)) 1032 resourceFiles.Includes = append(resourceFiles.Includes, files...) 1033 } 1034 return &bazelAapt{ 1035 android.BazelLabelForModuleSrcSingle(ctx, manifest), 1036 bazel.MakeLabelListAttribute(resourceFiles), 1037 } 1038} 1039 1040func (a *AARImport) ConvertWithBp2build(ctx android.TopDownMutatorContext) { 1041 aars := android.BazelLabelForModuleSrcExcludes(ctx, a.properties.Aars, []string{}) 1042 exportableStaticLibs := []string{} 1043 // TODO(b/240716882): investigate and handle static_libs deps that are not imports. They are not supported for export by Bazel. 1044 for _, depName := range a.properties.Static_libs { 1045 if dep, ok := ctx.ModuleFromName(depName); ok { 1046 switch dep.(type) { 1047 case *AARImport, *Import: 1048 exportableStaticLibs = append(exportableStaticLibs, depName) 1049 } 1050 } 1051 } 1052 name := android.RemoveOptionalPrebuiltPrefix(a.Name()) 1053 deps := android.BazelLabelForModuleDeps(ctx, android.LastUniqueStrings(android.CopyOf(append(a.properties.Static_libs, a.properties.Libs...)))) 1054 exports := android.BazelLabelForModuleDeps(ctx, android.LastUniqueStrings(exportableStaticLibs)) 1055 1056 ctx.CreateBazelTargetModule( 1057 bazel.BazelTargetModuleProperties{ 1058 Rule_class: "aar_import", 1059 Bzl_load_location: "//build/bazel/rules/android:rules.bzl", 1060 }, 1061 android.CommonAttributes{Name: name}, 1062 &bazelAndroidLibraryImport{ 1063 Aar: aars.Includes[0], 1064 Deps: bazel.MakeLabelListAttribute(deps), 1065 Exports: bazel.MakeLabelListAttribute(exports), 1066 Sdk_version: bazel.StringAttribute{Value: a.properties.Sdk_version}, 1067 }, 1068 ) 1069 1070 neverlink := true 1071 ctx.CreateBazelTargetModule( 1072 AndroidLibraryBazelTargetModuleProperties(), 1073 android.CommonAttributes{Name: name + "-neverlink"}, 1074 &bazelAndroidLibrary{ 1075 javaLibraryAttributes: &javaLibraryAttributes{ 1076 Neverlink: bazel.BoolAttribute{Value: &neverlink}, 1077 Exports: bazel.MakeSingleLabelListAttribute(bazel.Label{Label: ":" + name}), 1078 javaCommonAttributes: &javaCommonAttributes{ 1079 Sdk_version: bazel.StringAttribute{Value: a.properties.Sdk_version}, 1080 }, 1081 }, 1082 }, 1083 ) 1084 1085} 1086func AndroidLibraryBazelTargetModuleProperties() bazel.BazelTargetModuleProperties { 1087 return bazel.BazelTargetModuleProperties{ 1088 Rule_class: "android_library", 1089 Bzl_load_location: "//build/bazel/rules/android:rules.bzl", 1090 } 1091} 1092 1093func (a *AndroidLibrary) ConvertWithBp2build(ctx android.TopDownMutatorContext) { 1094 commonAttrs, bp2buildInfo := a.convertLibraryAttrsBp2Build(ctx) 1095 depLabels := bp2buildInfo.DepLabels 1096 1097 deps := depLabels.Deps 1098 if !commonAttrs.Srcs.IsEmpty() { 1099 deps.Append(depLabels.StaticDeps) // we should only append these if there are sources to use them 1100 } else if !depLabels.Deps.IsEmpty() { 1101 ctx.ModuleErrorf("Module has direct dependencies but no sources. Bazel will not allow this.") 1102 } 1103 name := a.Name() 1104 props := AndroidLibraryBazelTargetModuleProperties() 1105 1106 ctx.CreateBazelTargetModule( 1107 props, 1108 android.CommonAttributes{Name: name}, 1109 &bazelAndroidLibrary{ 1110 &javaLibraryAttributes{ 1111 javaCommonAttributes: commonAttrs, 1112 Deps: deps, 1113 Exports: depLabels.StaticDeps, 1114 }, 1115 a.convertAaptAttrsWithBp2Build(ctx), 1116 }, 1117 ) 1118 1119 neverlink := true 1120 ctx.CreateBazelTargetModule( 1121 props, 1122 android.CommonAttributes{Name: name + "-neverlink"}, 1123 &bazelAndroidLibrary{ 1124 javaLibraryAttributes: &javaLibraryAttributes{ 1125 Neverlink: bazel.BoolAttribute{Value: &neverlink}, 1126 Exports: bazel.MakeSingleLabelListAttribute(bazel.Label{Label: ":" + name}), 1127 javaCommonAttributes: &javaCommonAttributes{ 1128 Sdk_version: bazel.StringAttribute{Value: a.deviceProperties.Sdk_version}, 1129 Java_version: bazel.StringAttribute{Value: a.properties.Java_version}, 1130 }, 1131 }, 1132 }, 1133 ) 1134} 1135