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