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