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