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