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/dexpreopt" 25 26 "github.com/google/blueprint" 27 "github.com/google/blueprint/proptools" 28) 29 30type AndroidLibraryDependency interface { 31 ExportPackage() android.Path 32 ExportedProguardFlagFiles() android.Paths 33 ExportedRRODirs() []rroDir 34 ExportedStaticPackages() android.Paths 35 ExportedManifests() android.Paths 36 ExportedAssets() android.OptionalPath 37 SetRROEnforcedForDependent(enforce bool) 38 IsRROEnforced(ctx android.BaseModuleContext) bool 39} 40 41func init() { 42 RegisterAARBuildComponents(android.InitRegistrationContext) 43} 44 45func RegisterAARBuildComponents(ctx android.RegistrationContext) { 46 ctx.RegisterModuleType("android_library_import", AARImportFactory) 47 ctx.RegisterModuleType("android_library", AndroidLibraryFactory) 48 ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) { 49 ctx.TopDown("propagate_rro_enforcement", propagateRROEnforcementMutator).Parallel() 50 }) 51} 52 53// 54// AAR (android library) 55// 56 57type androidLibraryProperties struct { 58 BuildAAR bool `blueprint:"mutated"` 59} 60 61type aaptProperties struct { 62 // flags passed to aapt when creating the apk 63 Aaptflags []string 64 65 // include all resource configurations, not just the product-configured 66 // ones. 67 Aapt_include_all_resources *bool 68 69 // list of directories relative to the Blueprints file containing assets. 70 // Defaults to ["assets"] if a directory called assets exists. Set to [] 71 // to disable the default. 72 Asset_dirs []string 73 74 // list of directories relative to the Blueprints file containing 75 // Android resources. Defaults to ["res"] if a directory called res exists. 76 // Set to [] to disable the default. 77 Resource_dirs []string 78 79 // list of zip files containing Android resources. 80 Resource_zips []string `android:"path"` 81 82 // path to AndroidManifest.xml. If unset, defaults to "AndroidManifest.xml". 83 Manifest *string `android:"path"` 84 85 // paths to additional manifest files to merge with main manifest. 86 Additional_manifests []string `android:"path"` 87 88 // do not include AndroidManifest from dependent libraries 89 Dont_merge_manifests *bool 90 91 // true if RRO is enforced for any of the dependent modules 92 RROEnforcedForDependent bool `blueprint:"mutated"` 93} 94 95type aapt struct { 96 aaptSrcJar android.Path 97 exportPackage android.Path 98 manifestPath android.Path 99 transitiveManifestPaths android.Paths 100 proguardOptionsFile android.Path 101 rroDirs []rroDir 102 rTxt android.Path 103 extraAaptPackagesFile android.Path 104 mergedManifestFile android.Path 105 noticeFile android.OptionalPath 106 assetPackage android.OptionalPath 107 isLibrary bool 108 useEmbeddedNativeLibs bool 109 useEmbeddedDex bool 110 usesNonSdkApis bool 111 hasNoCode bool 112 LoggingParent string 113 resourceFiles android.Paths 114 115 splitNames []string 116 splits []split 117 118 aaptProperties aaptProperties 119} 120 121type split struct { 122 name string 123 suffix string 124 path android.Path 125} 126 127// Propagate RRO enforcement flag to static lib dependencies transitively. 128func propagateRROEnforcementMutator(ctx android.TopDownMutatorContext) { 129 m := ctx.Module() 130 if d, ok := m.(AndroidLibraryDependency); ok && d.IsRROEnforced(ctx) { 131 ctx.VisitDirectDepsWithTag(staticLibTag, func(d android.Module) { 132 if a, ok := d.(AndroidLibraryDependency); ok { 133 a.SetRROEnforcedForDependent(true) 134 } 135 }) 136 } 137} 138 139func (a *aapt) ExportPackage() android.Path { 140 return a.exportPackage 141} 142 143func (a *aapt) ExportedRRODirs() []rroDir { 144 return a.rroDirs 145} 146 147func (a *aapt) ExportedManifests() android.Paths { 148 return a.transitiveManifestPaths 149} 150 151func (a *aapt) ExportedAssets() android.OptionalPath { 152 return a.assetPackage 153} 154 155func (a *aapt) SetRROEnforcedForDependent(enforce bool) { 156 a.aaptProperties.RROEnforcedForDependent = enforce 157} 158 159func (a *aapt) IsRROEnforced(ctx android.BaseModuleContext) bool { 160 // True if RRO is enforced for this module or... 161 return ctx.Config().EnforceRROForModule(ctx.ModuleName()) || 162 // if RRO is enforced for any of its dependents. 163 a.aaptProperties.RROEnforcedForDependent 164} 165 166func (a *aapt) aapt2Flags(ctx android.ModuleContext, sdkContext android.SdkContext, 167 manifestPath android.Path) (compileFlags, linkFlags []string, linkDeps android.Paths, 168 resDirs, overlayDirs []globbedResourceDir, rroDirs []rroDir, resZips android.Paths) { 169 170 hasVersionCode := android.PrefixInList(a.aaptProperties.Aaptflags, "--version-code") 171 hasVersionName := android.PrefixInList(a.aaptProperties.Aaptflags, "--version-name") 172 173 // Flags specified in Android.bp 174 linkFlags = append(linkFlags, a.aaptProperties.Aaptflags...) 175 176 linkFlags = append(linkFlags, "--no-static-lib-packages") 177 178 // Find implicit or explicit asset and resource dirs 179 assetDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Asset_dirs, "assets") 180 resourceDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Resource_dirs, "res") 181 resourceZips := android.PathsForModuleSrc(ctx, a.aaptProperties.Resource_zips) 182 183 // Glob directories into lists of paths 184 for _, dir := range resourceDirs { 185 resDirs = append(resDirs, globbedResourceDir{ 186 dir: dir, 187 files: androidResourceGlob(ctx, dir), 188 }) 189 resOverlayDirs, resRRODirs := overlayResourceGlob(ctx, a, dir) 190 overlayDirs = append(overlayDirs, resOverlayDirs...) 191 rroDirs = append(rroDirs, resRRODirs...) 192 } 193 194 var assetDeps android.Paths 195 for i, dir := range assetDirs { 196 // Add a dependency on every file in the asset directory. This ensures the aapt2 197 // rule will be rerun if one of the files in the asset directory is modified. 198 assetDeps = append(assetDeps, androidResourceGlob(ctx, dir)...) 199 200 // Add a dependency on a file that contains a list of all the files in the asset directory. 201 // This ensures the aapt2 rule will be run if a file is removed from the asset directory, 202 // or a file is added whose timestamp is older than the output of aapt2. 203 assetFileListFile := android.PathForModuleOut(ctx, "asset_dir_globs", strconv.Itoa(i)+".glob") 204 androidResourceGlobList(ctx, dir, assetFileListFile) 205 assetDeps = append(assetDeps, assetFileListFile) 206 } 207 208 assetDirStrings := assetDirs.Strings() 209 if a.noticeFile.Valid() { 210 assetDirStrings = append(assetDirStrings, filepath.Dir(a.noticeFile.Path().String())) 211 assetDeps = append(assetDeps, a.noticeFile.Path()) 212 } 213 214 linkFlags = append(linkFlags, "--manifest "+manifestPath.String()) 215 linkDeps = append(linkDeps, manifestPath) 216 217 linkFlags = append(linkFlags, android.JoinWithPrefix(assetDirStrings, "-A ")) 218 linkDeps = append(linkDeps, assetDeps...) 219 220 // SDK version flags 221 minSdkVersion, err := sdkContext.MinSdkVersion(ctx).EffectiveVersionString(ctx) 222 if err != nil { 223 ctx.ModuleErrorf("invalid minSdkVersion: %s", err) 224 } 225 226 linkFlags = append(linkFlags, "--min-sdk-version "+minSdkVersion) 227 linkFlags = append(linkFlags, "--target-sdk-version "+minSdkVersion) 228 229 // Version code 230 if !hasVersionCode { 231 linkFlags = append(linkFlags, "--version-code", ctx.Config().PlatformSdkVersion().String()) 232 } 233 234 if !hasVersionName { 235 var versionName string 236 if ctx.ModuleName() == "framework-res" { 237 // Some builds set AppsDefaultVersionName() to include the build number ("O-123456"). aapt2 copies the 238 // version name of framework-res into app manifests as compileSdkVersionCodename, which confuses things 239 // if it contains the build number. Use the PlatformVersionName instead. 240 versionName = ctx.Config().PlatformVersionName() 241 } else { 242 versionName = ctx.Config().AppsDefaultVersionName() 243 } 244 versionName = proptools.NinjaEscape(versionName) 245 linkFlags = append(linkFlags, "--version-name ", versionName) 246 } 247 248 linkFlags, compileFlags = android.FilterList(linkFlags, []string{"--legacy"}) 249 250 // Always set --pseudo-localize, it will be stripped out later for release 251 // builds that don't want it. 252 compileFlags = append(compileFlags, "--pseudo-localize") 253 254 return compileFlags, linkFlags, linkDeps, resDirs, overlayDirs, rroDirs, resourceZips 255} 256 257func (a *aapt) deps(ctx android.BottomUpMutatorContext, sdkDep sdkDep) { 258 if sdkDep.frameworkResModule != "" { 259 ctx.AddVariationDependencies(nil, frameworkResTag, sdkDep.frameworkResModule) 260 } 261} 262 263var extractAssetsRule = pctx.AndroidStaticRule("extractAssets", 264 blueprint.RuleParams{ 265 Command: `${config.Zip2ZipCmd} -i ${in} -o ${out} "assets/**/*"`, 266 CommandDeps: []string{"${config.Zip2ZipCmd}"}, 267 }) 268 269func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext android.SdkContext, 270 classLoaderContexts dexpreopt.ClassLoaderContextMap, extraLinkFlags ...string) { 271 272 transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, assetPackages, libDeps, libFlags := 273 aaptLibs(ctx, sdkContext, classLoaderContexts) 274 275 // App manifest file 276 manifestFile := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml") 277 manifestSrcPath := android.PathForModuleSrc(ctx, manifestFile) 278 279 manifestPath := manifestFixer(ctx, manifestSrcPath, sdkContext, classLoaderContexts, 280 a.isLibrary, a.useEmbeddedNativeLibs, a.usesNonSdkApis, a.useEmbeddedDex, a.hasNoCode, 281 a.LoggingParent) 282 283 // Add additional manifest files to transitive manifests. 284 additionalManifests := android.PathsForModuleSrc(ctx, a.aaptProperties.Additional_manifests) 285 a.transitiveManifestPaths = append(android.Paths{manifestPath}, additionalManifests...) 286 a.transitiveManifestPaths = append(a.transitiveManifestPaths, transitiveStaticLibManifests...) 287 288 if len(a.transitiveManifestPaths) > 1 && !Bool(a.aaptProperties.Dont_merge_manifests) { 289 a.mergedManifestFile = manifestMerger(ctx, a.transitiveManifestPaths[0], a.transitiveManifestPaths[1:], a.isLibrary) 290 if !a.isLibrary { 291 // Only use the merged manifest for applications. For libraries, the transitive closure of manifests 292 // will be propagated to the final application and merged there. The merged manifest for libraries is 293 // only passed to Make, which can't handle transitive dependencies. 294 manifestPath = a.mergedManifestFile 295 } 296 } else { 297 a.mergedManifestFile = manifestPath 298 } 299 300 compileFlags, linkFlags, linkDeps, resDirs, overlayDirs, rroDirs, resZips := a.aapt2Flags(ctx, sdkContext, manifestPath) 301 302 rroDirs = append(rroDirs, staticRRODirs...) 303 linkFlags = append(linkFlags, libFlags...) 304 linkDeps = append(linkDeps, libDeps...) 305 linkFlags = append(linkFlags, extraLinkFlags...) 306 if a.isLibrary { 307 linkFlags = append(linkFlags, "--static-lib") 308 } 309 310 packageRes := android.PathForModuleOut(ctx, "package-res.apk") 311 // the subdir "android" is required to be filtered by package names 312 srcJar := android.PathForModuleGen(ctx, "android", "R.srcjar") 313 proguardOptionsFile := android.PathForModuleGen(ctx, "proguard.options") 314 rTxt := android.PathForModuleOut(ctx, "R.txt") 315 // This file isn't used by Soong, but is generated for exporting 316 extraPackages := android.PathForModuleOut(ctx, "extra_packages") 317 318 var compiledResDirs []android.Paths 319 for _, dir := range resDirs { 320 a.resourceFiles = append(a.resourceFiles, dir.files...) 321 compiledResDirs = append(compiledResDirs, aapt2Compile(ctx, dir.dir, dir.files, compileFlags).Paths()) 322 } 323 324 for i, zip := range resZips { 325 flata := android.PathForModuleOut(ctx, fmt.Sprintf("reszip.%d.flata", i)) 326 aapt2CompileZip(ctx, flata, zip, "", compileFlags) 327 compiledResDirs = append(compiledResDirs, android.Paths{flata}) 328 } 329 330 var compiledRes, compiledOverlay android.Paths 331 332 compiledOverlay = append(compiledOverlay, transitiveStaticLibs...) 333 334 if len(transitiveStaticLibs) > 0 { 335 // If we are using static android libraries, every source file becomes an overlay. 336 // This is to emulate old AAPT behavior which simulated library support. 337 for _, compiledResDir := range compiledResDirs { 338 compiledOverlay = append(compiledOverlay, compiledResDir...) 339 } 340 } else if a.isLibrary { 341 // Otherwise, for a static library we treat all the resources equally with no overlay. 342 for _, compiledResDir := range compiledResDirs { 343 compiledRes = append(compiledRes, compiledResDir...) 344 } 345 } else if len(compiledResDirs) > 0 { 346 // Without static libraries, the first directory is our directory, which can then be 347 // overlaid by the rest. 348 compiledRes = append(compiledRes, compiledResDirs[0]...) 349 for _, compiledResDir := range compiledResDirs[1:] { 350 compiledOverlay = append(compiledOverlay, compiledResDir...) 351 } 352 } 353 354 for _, dir := range overlayDirs { 355 compiledOverlay = append(compiledOverlay, aapt2Compile(ctx, dir.dir, dir.files, compileFlags).Paths()...) 356 } 357 358 var splitPackages android.WritablePaths 359 var splits []split 360 361 for _, s := range a.splitNames { 362 suffix := strings.Replace(s, ",", "_", -1) 363 path := android.PathForModuleOut(ctx, "package_"+suffix+".apk") 364 linkFlags = append(linkFlags, "--split", path.String()+":"+s) 365 splitPackages = append(splitPackages, path) 366 splits = append(splits, split{ 367 name: s, 368 suffix: suffix, 369 path: path, 370 }) 371 } 372 373 aapt2Link(ctx, packageRes, srcJar, proguardOptionsFile, rTxt, extraPackages, 374 linkFlags, linkDeps, compiledRes, compiledOverlay, assetPackages, splitPackages) 375 376 // Extract assets from the resource package output so that they can be used later in aapt2link 377 // for modules that depend on this one. 378 if android.PrefixInList(linkFlags, "-A ") || len(assetPackages) > 0 { 379 assets := android.PathForModuleOut(ctx, "assets.zip") 380 ctx.Build(pctx, android.BuildParams{ 381 Rule: extractAssetsRule, 382 Input: packageRes, 383 Output: assets, 384 Description: "extract assets from built resource file", 385 }) 386 a.assetPackage = android.OptionalPathForPath(assets) 387 } 388 389 a.aaptSrcJar = srcJar 390 a.exportPackage = packageRes 391 a.manifestPath = manifestPath 392 a.proguardOptionsFile = proguardOptionsFile 393 a.rroDirs = rroDirs 394 a.extraAaptPackagesFile = extraPackages 395 a.rTxt = rTxt 396 a.splits = splits 397} 398 399// aaptLibs collects libraries from dependencies and sdk_version and converts them into paths 400func aaptLibs(ctx android.ModuleContext, sdkContext android.SdkContext, classLoaderContexts dexpreopt.ClassLoaderContextMap) ( 401 transitiveStaticLibs, transitiveStaticLibManifests android.Paths, staticRRODirs []rroDir, assets, deps android.Paths, flags []string) { 402 403 var sharedLibs android.Paths 404 405 if classLoaderContexts == nil { 406 // Not all callers need to compute class loader context, those who don't just pass nil. 407 // Create a temporary class loader context here (it will be computed, but not used). 408 classLoaderContexts = make(dexpreopt.ClassLoaderContextMap) 409 } 410 411 sdkDep := decodeSdkDep(ctx, sdkContext) 412 if sdkDep.useFiles { 413 sharedLibs = append(sharedLibs, sdkDep.jars...) 414 } 415 416 ctx.VisitDirectDeps(func(module android.Module) { 417 depTag := ctx.OtherModuleDependencyTag(module) 418 419 var exportPackage android.Path 420 aarDep, _ := module.(AndroidLibraryDependency) 421 if aarDep != nil { 422 exportPackage = aarDep.ExportPackage() 423 } 424 425 switch depTag { 426 case instrumentationForTag: 427 // Nothing, instrumentationForTag is treated as libTag for javac but not for aapt2. 428 case libTag: 429 if exportPackage != nil { 430 sharedLibs = append(sharedLibs, exportPackage) 431 } 432 case frameworkResTag: 433 if exportPackage != nil { 434 sharedLibs = append(sharedLibs, exportPackage) 435 } 436 case staticLibTag: 437 if exportPackage != nil { 438 transitiveStaticLibs = append(transitiveStaticLibs, aarDep.ExportedStaticPackages()...) 439 transitiveStaticLibs = append(transitiveStaticLibs, exportPackage) 440 transitiveStaticLibManifests = append(transitiveStaticLibManifests, aarDep.ExportedManifests()...) 441 if aarDep.ExportedAssets().Valid() { 442 assets = append(assets, aarDep.ExportedAssets().Path()) 443 } 444 445 outer: 446 for _, d := range aarDep.ExportedRRODirs() { 447 for _, e := range staticRRODirs { 448 if d.path == e.path { 449 continue outer 450 } 451 } 452 staticRRODirs = append(staticRRODirs, d) 453 } 454 } 455 } 456 457 addCLCFromDep(ctx, module, classLoaderContexts) 458 }) 459 460 deps = append(deps, sharedLibs...) 461 deps = append(deps, transitiveStaticLibs...) 462 463 if len(transitiveStaticLibs) > 0 { 464 flags = append(flags, "--auto-add-overlay") 465 } 466 467 for _, sharedLib := range sharedLibs { 468 flags = append(flags, "-I "+sharedLib.String()) 469 } 470 471 transitiveStaticLibs = android.FirstUniquePaths(transitiveStaticLibs) 472 transitiveStaticLibManifests = android.FirstUniquePaths(transitiveStaticLibManifests) 473 474 return transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, assets, deps, flags 475} 476 477type AndroidLibrary struct { 478 Library 479 aapt 480 481 androidLibraryProperties androidLibraryProperties 482 483 aarFile android.WritablePath 484 485 exportedProguardFlagFiles android.Paths 486 exportedStaticPackages android.Paths 487} 488 489var _ android.OutputFileProducer = (*AndroidLibrary)(nil) 490 491// For OutputFileProducer interface 492func (a *AndroidLibrary) OutputFiles(tag string) (android.Paths, error) { 493 switch tag { 494 case ".aar": 495 return []android.Path{a.aarFile}, nil 496 default: 497 return a.Library.OutputFiles(tag) 498 } 499} 500 501func (a *AndroidLibrary) ExportedProguardFlagFiles() android.Paths { 502 return a.exportedProguardFlagFiles 503} 504 505func (a *AndroidLibrary) ExportedStaticPackages() android.Paths { 506 return a.exportedStaticPackages 507} 508 509var _ AndroidLibraryDependency = (*AndroidLibrary)(nil) 510 511func (a *AndroidLibrary) DepsMutator(ctx android.BottomUpMutatorContext) { 512 a.Module.deps(ctx) 513 sdkDep := decodeSdkDep(ctx, android.SdkContext(a)) 514 if sdkDep.hasFrameworkLibs() { 515 a.aapt.deps(ctx, sdkDep) 516 } 517} 518 519func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { 520 a.aapt.isLibrary = true 521 a.classLoaderContexts = make(dexpreopt.ClassLoaderContextMap) 522 a.aapt.buildActions(ctx, android.SdkContext(a), a.classLoaderContexts) 523 524 a.hideApexVariantFromMake = !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform() 525 526 ctx.CheckbuildFile(a.proguardOptionsFile) 527 ctx.CheckbuildFile(a.exportPackage) 528 ctx.CheckbuildFile(a.aaptSrcJar) 529 530 // apps manifests are handled by aapt, don't let Module see them 531 a.properties.Manifest = nil 532 533 a.linter.mergedManifest = a.aapt.mergedManifestFile 534 a.linter.manifest = a.aapt.manifestPath 535 a.linter.resources = a.aapt.resourceFiles 536 537 a.Module.extraProguardFlagFiles = append(a.Module.extraProguardFlagFiles, 538 a.proguardOptionsFile) 539 540 a.Module.compile(ctx, a.aaptSrcJar) 541 542 a.aarFile = android.PathForModuleOut(ctx, ctx.ModuleName()+".aar") 543 var res android.Paths 544 if a.androidLibraryProperties.BuildAAR { 545 BuildAAR(ctx, a.aarFile, a.outputFile, a.manifestPath, a.rTxt, res) 546 ctx.CheckbuildFile(a.aarFile) 547 } 548 549 a.exportedProguardFlagFiles = append(a.exportedProguardFlagFiles, 550 android.PathsForModuleSrc(ctx, a.dexProperties.Optimize.Proguard_flags_files)...) 551 ctx.VisitDirectDeps(func(m android.Module) { 552 if lib, ok := m.(AndroidLibraryDependency); ok && ctx.OtherModuleDependencyTag(m) == staticLibTag { 553 a.exportedProguardFlagFiles = append(a.exportedProguardFlagFiles, lib.ExportedProguardFlagFiles()...) 554 a.exportedStaticPackages = append(a.exportedStaticPackages, lib.ExportPackage()) 555 a.exportedStaticPackages = append(a.exportedStaticPackages, lib.ExportedStaticPackages()...) 556 } 557 }) 558 559 a.exportedProguardFlagFiles = android.FirstUniquePaths(a.exportedProguardFlagFiles) 560 a.exportedStaticPackages = android.FirstUniquePaths(a.exportedStaticPackages) 561} 562 563// android_library builds and links sources into a `.jar` file for the device along with Android resources. 564// 565// An android_library has a single variant that produces a `.jar` file containing `.class` files that were 566// compiled against the device bootclasspath, along with a `package-res.apk` file containing Android resources compiled 567// with aapt2. This module is not suitable for installing on a device, but can be used as a `static_libs` dependency of 568// an android_app module. 569func AndroidLibraryFactory() android.Module { 570 module := &AndroidLibrary{} 571 572 module.Module.addHostAndDeviceProperties() 573 module.AddProperties( 574 &module.aaptProperties, 575 &module.androidLibraryProperties) 576 577 module.androidLibraryProperties.BuildAAR = true 578 module.Module.linter.library = true 579 580 android.InitApexModule(module) 581 InitJavaModule(module, android.DeviceSupported) 582 return module 583} 584 585// 586// AAR (android library) prebuilts 587// 588 589type AARImportProperties struct { 590 Aars []string `android:"path"` 591 592 Sdk_version *string 593 Min_sdk_version *string 594 595 Static_libs []string 596 Libs []string 597 598 // if set to true, run Jetifier against .aar file. Defaults to false. 599 Jetifier *bool 600} 601 602type AARImport struct { 603 android.ModuleBase 604 android.DefaultableModuleBase 605 android.ApexModuleBase 606 prebuilt android.Prebuilt 607 608 // Functionality common to Module and Import. 609 embeddableInModuleAndImport 610 611 properties AARImportProperties 612 613 classpathFile android.WritablePath 614 proguardFlags android.WritablePath 615 exportPackage android.WritablePath 616 extraAaptPackagesFile android.WritablePath 617 manifest android.WritablePath 618 619 exportedStaticPackages android.Paths 620 621 hideApexVariantFromMake bool 622 623 aarPath android.Path 624 625 sdkVersion android.SdkSpec 626 minSdkVersion android.SdkSpec 627} 628 629var _ android.OutputFileProducer = (*AARImport)(nil) 630 631// For OutputFileProducer interface 632func (a *AARImport) OutputFiles(tag string) (android.Paths, error) { 633 switch tag { 634 case ".aar": 635 return []android.Path{a.aarPath}, nil 636 case "": 637 return []android.Path{a.classpathFile}, nil 638 default: 639 return nil, fmt.Errorf("unsupported module reference tag %q", tag) 640 } 641} 642 643func (a *AARImport) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { 644 return android.SdkSpecFrom(ctx, String(a.properties.Sdk_version)) 645} 646 647func (a *AARImport) SystemModules() string { 648 return "" 649} 650 651func (a *AARImport) MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { 652 if a.properties.Min_sdk_version != nil { 653 return android.SdkSpecFrom(ctx, *a.properties.Min_sdk_version) 654 } 655 return a.SdkVersion(ctx) 656} 657 658func (a *AARImport) TargetSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { 659 return a.SdkVersion(ctx) 660} 661 662func (a *AARImport) javaVersion() string { 663 return "" 664} 665 666var _ AndroidLibraryDependency = (*AARImport)(nil) 667 668func (a *AARImport) ExportPackage() android.Path { 669 return a.exportPackage 670} 671 672func (a *AARImport) ExportedProguardFlagFiles() android.Paths { 673 return android.Paths{a.proguardFlags} 674} 675 676func (a *AARImport) ExportedRRODirs() []rroDir { 677 return nil 678} 679 680func (a *AARImport) ExportedStaticPackages() android.Paths { 681 return a.exportedStaticPackages 682} 683 684func (a *AARImport) ExportedManifests() android.Paths { 685 return android.Paths{a.manifest} 686} 687 688// TODO(jungjw): Decide whether we want to implement this. 689func (a *AARImport) ExportedAssets() android.OptionalPath { 690 return android.OptionalPath{} 691} 692 693// RRO enforcement is not available on aar_import since its RRO dirs are not 694// exported. 695func (a *AARImport) SetRROEnforcedForDependent(enforce bool) { 696} 697 698// RRO enforcement is not available on aar_import since its RRO dirs are not 699// exported. 700func (a *AARImport) IsRROEnforced(ctx android.BaseModuleContext) bool { 701 return false 702} 703 704func (a *AARImport) Prebuilt() *android.Prebuilt { 705 return &a.prebuilt 706} 707 708func (a *AARImport) Name() string { 709 return a.prebuilt.Name(a.ModuleBase.Name()) 710} 711 712func (a *AARImport) JacocoReportClassesFile() android.Path { 713 return nil 714} 715 716func (a *AARImport) DepsMutator(ctx android.BottomUpMutatorContext) { 717 if !ctx.Config().AlwaysUsePrebuiltSdks() { 718 sdkDep := decodeSdkDep(ctx, android.SdkContext(a)) 719 if sdkDep.useModule && sdkDep.frameworkResModule != "" { 720 ctx.AddVariationDependencies(nil, frameworkResTag, sdkDep.frameworkResModule) 721 } 722 } 723 724 ctx.AddVariationDependencies(nil, libTag, a.properties.Libs...) 725 ctx.AddVariationDependencies(nil, staticLibTag, a.properties.Static_libs...) 726} 727 728// Unzip an AAR into its constituent files and directories. Any files in Outputs that don't exist in the AAR will be 729// touched to create an empty file. The res directory is not extracted, as it will be extracted in its own rule. 730var unzipAAR = pctx.AndroidStaticRule("unzipAAR", 731 blueprint.RuleParams{ 732 Command: `rm -rf $outDir && mkdir -p $outDir && ` + 733 `unzip -qoDD -d $outDir $in && rm -rf $outDir/res && touch $out && ` + 734 `${config.MergeZipsCmd} $combinedClassesJar $$(ls $outDir/classes.jar 2> /dev/null) $$(ls $outDir/libs/*.jar 2> /dev/null)`, 735 CommandDeps: []string{"${config.MergeZipsCmd}"}, 736 }, 737 "outDir", "combinedClassesJar") 738 739func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { 740 if len(a.properties.Aars) != 1 { 741 ctx.PropertyErrorf("aars", "exactly one aar is required") 742 return 743 } 744 745 a.sdkVersion = a.SdkVersion(ctx) 746 a.minSdkVersion = a.MinSdkVersion(ctx) 747 748 a.hideApexVariantFromMake = !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform() 749 750 aarName := ctx.ModuleName() + ".aar" 751 a.aarPath = android.PathForModuleSrc(ctx, a.properties.Aars[0]) 752 753 if Bool(a.properties.Jetifier) { 754 inputFile := a.aarPath 755 a.aarPath = android.PathForModuleOut(ctx, "jetifier", aarName) 756 TransformJetifier(ctx, a.aarPath.(android.WritablePath), inputFile) 757 } 758 759 extractedAARDir := android.PathForModuleOut(ctx, "aar") 760 a.classpathFile = extractedAARDir.Join(ctx, "classes-combined.jar") 761 a.proguardFlags = extractedAARDir.Join(ctx, "proguard.txt") 762 a.manifest = extractedAARDir.Join(ctx, "AndroidManifest.xml") 763 764 ctx.Build(pctx, android.BuildParams{ 765 Rule: unzipAAR, 766 Input: a.aarPath, 767 Outputs: android.WritablePaths{a.classpathFile, a.proguardFlags, a.manifest}, 768 Description: "unzip AAR", 769 Args: map[string]string{ 770 "outDir": extractedAARDir.String(), 771 "combinedClassesJar": a.classpathFile.String(), 772 }, 773 }) 774 775 // Always set --pseudo-localize, it will be stripped out later for release 776 // builds that don't want it. 777 compileFlags := []string{"--pseudo-localize"} 778 compiledResDir := android.PathForModuleOut(ctx, "flat-res") 779 flata := compiledResDir.Join(ctx, "gen_res.flata") 780 aapt2CompileZip(ctx, flata, a.aarPath, "res", compileFlags) 781 782 a.exportPackage = android.PathForModuleOut(ctx, "package-res.apk") 783 // the subdir "android" is required to be filtered by package names 784 srcJar := android.PathForModuleGen(ctx, "android", "R.srcjar") 785 proguardOptionsFile := android.PathForModuleGen(ctx, "proguard.options") 786 rTxt := android.PathForModuleOut(ctx, "R.txt") 787 a.extraAaptPackagesFile = android.PathForModuleOut(ctx, "extra_packages") 788 789 var linkDeps android.Paths 790 791 linkFlags := []string{ 792 "--static-lib", 793 "--no-static-lib-packages", 794 "--auto-add-overlay", 795 } 796 797 linkFlags = append(linkFlags, "--manifest "+a.manifest.String()) 798 linkDeps = append(linkDeps, a.manifest) 799 800 transitiveStaticLibs, staticLibManifests, staticRRODirs, transitiveAssets, libDeps, libFlags := 801 aaptLibs(ctx, android.SdkContext(a), nil) 802 803 _ = staticLibManifests 804 _ = staticRRODirs 805 806 linkDeps = append(linkDeps, libDeps...) 807 linkFlags = append(linkFlags, libFlags...) 808 809 overlayRes := append(android.Paths{flata}, transitiveStaticLibs...) 810 811 aapt2Link(ctx, a.exportPackage, srcJar, proguardOptionsFile, rTxt, a.extraAaptPackagesFile, 812 linkFlags, linkDeps, nil, overlayRes, transitiveAssets, nil) 813 814 ctx.SetProvider(JavaInfoProvider, JavaInfo{ 815 HeaderJars: android.PathsIfNonNil(a.classpathFile), 816 ImplementationAndResourcesJars: android.PathsIfNonNil(a.classpathFile), 817 ImplementationJars: android.PathsIfNonNil(a.classpathFile), 818 }) 819} 820 821func (a *AARImport) HeaderJars() android.Paths { 822 return android.Paths{a.classpathFile} 823} 824 825func (a *AARImport) ImplementationAndResourcesJars() android.Paths { 826 return android.Paths{a.classpathFile} 827} 828 829func (a *AARImport) DexJarBuildPath() android.Path { 830 return nil 831} 832 833func (a *AARImport) DexJarInstallPath() android.Path { 834 return nil 835} 836 837func (a *AARImport) ClassLoaderContexts() dexpreopt.ClassLoaderContextMap { 838 return nil 839} 840 841var _ android.ApexModule = (*AARImport)(nil) 842 843// Implements android.ApexModule 844func (a *AARImport) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool { 845 return a.depIsInSameApex(ctx, dep) 846} 847 848// Implements android.ApexModule 849func (g *AARImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext, 850 sdkVersion android.ApiLevel) error { 851 return nil 852} 853 854var _ android.PrebuiltInterface = (*Import)(nil) 855 856// android_library_import imports an `.aar` file into the build graph as if it was built with android_library. 857// 858// This module is not suitable for installing on a device, but can be used as a `static_libs` dependency of 859// an android_app module. 860func AARImportFactory() android.Module { 861 module := &AARImport{} 862 863 module.AddProperties(&module.properties) 864 865 android.InitPrebuiltModule(module, &module.properties.Aars) 866 android.InitApexModule(module) 867 InitJavaModule(module, android.DeviceSupported) 868 return module 869} 870