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