Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 245482e0 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Move android_library resource handling to Bazel's ResourceProcessorBusyBox" into main

parents 5ad5c918 4eae06dc
Loading
Loading
Loading
Loading
+195 −45
Original line number Diff line number Diff line
@@ -88,16 +88,28 @@ type aaptProperties struct {
	// do not include AndroidManifest from dependent libraries
	Dont_merge_manifests *bool

	// If use_resource_processor is set, use Bazel's resource processor instead of aapt2 to generate R.class files.
	// The resource processor produces more optimal R.class files that only list resources in the package of the
	// library that provided them, as opposed to aapt2 which produces R.java files for every package containing
	// every resource.  Using the resource processor can provide significant build time speedups, but requires
	// fixing the module to use the correct package to reference each resource, and to avoid having any other
	// libraries in the tree that use the same package name.  Defaults to false, but will default to true in the
	// future.
	Use_resource_processor *bool

	// true if RRO is enforced for any of the dependent modules
	RROEnforcedForDependent bool `blueprint:"mutated"`
}

type aapt struct {
	aaptSrcJar                     android.Path
	transitiveAaptRJars            android.Paths
	transitiveAaptResourcePackages android.Paths
	exportPackage                  android.Path
	manifestPath                   android.Path
	proguardOptionsFile            android.Path
	rTxt                           android.Path
	rJar                           android.Path
	extraAaptPackagesFile          android.Path
	mergedManifestFile             android.Path
	noticeFile                     android.OptionalPath
@@ -139,6 +151,10 @@ func propagateRROEnforcementMutator(ctx android.TopDownMutatorContext) {
	}
}

func (a *aapt) useResourceProcessorBusyBox() bool {
	return BoolDefault(a.aaptProperties.Use_resource_processor, false)
}

func (a *aapt) ExportPackage() android.Path {
	return a.exportPackage
}
@@ -175,8 +191,6 @@ func (a *aapt) aapt2Flags(ctx android.ModuleContext, sdkContext android.SdkConte
	// Flags specified in Android.bp
	linkFlags = append(linkFlags, a.aaptProperties.Aaptflags...)

	linkFlags = append(linkFlags, "--no-static-lib-packages")

	// Find implicit or explicit asset and resource dirs
	assetDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Asset_dirs, "assets")
	resourceDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Resource_dirs, "res")
@@ -348,6 +362,19 @@ func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext android.SdkCon
		linkFlags = append(linkFlags, "--static-lib")
	}

	if a.isLibrary && a.useResourceProcessorBusyBox() {
		// When building an android_library using ResourceProcessorBusyBox the resources are merged into
		// package-res.apk with --merge-only, but --no-static-lib-packages is not used so that R.txt only
		// contains resources from this library.
		linkFlags = append(linkFlags, "--merge-only")
	} else {
		// When building and app or when building an android_library without ResourceProcessorBusyBox
		// --no-static-lib-packages is used to put all the resources into the app.  If ResourceProcessorBusyBox
		// is used then the app's R.txt will be post-processed along with the R.txt files from dependencies to
		// sort resources into the right packages in R.class.
		linkFlags = append(linkFlags, "--no-static-lib-packages")
	}

	packageRes := android.PathForModuleOut(ctx, "package-res.apk")
	// the subdir "android" is required to be filtered by package names
	srcJar := android.PathForModuleGen(ctx, "android", "R.srcjar")
@@ -355,6 +382,7 @@ func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext android.SdkCon
	rTxt := android.PathForModuleOut(ctx, "R.txt")
	// This file isn't used by Soong, but is generated for exporting
	extraPackages := android.PathForModuleOut(ctx, "extra_packages")
	var transitiveRJars android.Paths

	var compiledResDirs []android.Paths
	for _, dir := range resDirs {
@@ -374,7 +402,23 @@ func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext android.SdkCon
	// of transitiveStaticLibs.
	transitiveStaticLibs := android.ReversePaths(staticDeps.resPackages())

	if a.isLibrary && a.useResourceProcessorBusyBox() {
		// When building an android_library with ResourceProcessorBusyBox enabled treat static library dependencies
		// as imports.  The resources from dependencies will not be merged into this module's package-res.apk, and
		// instead modules depending on this module will reference package-res.apk from all transitive static
		// dependencies.
		for _, staticDep := range staticDeps {
			linkDeps = append(linkDeps, staticDep.resPackage)
			linkFlags = append(linkFlags, "-I "+staticDep.resPackage.String())
			if staticDep.usedResourceProcessor {
				transitiveRJars = append(transitiveRJars, staticDep.rJar)
			}
		}
	} else {
		// When building an app or building a library without ResourceProcessorBusyBox enabled all static
		// dependencies are compiled into this module's package-res.apk as overlays.
		compiledOverlay = append(compiledOverlay, transitiveStaticLibs...)
	}

	if len(transitiveStaticLibs) > 0 {
		// If we are using static android libraries, every source file becomes an overlay.
@@ -437,7 +481,16 @@ func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext android.SdkCon
		a.assetPackage = android.OptionalPathForPath(assets)
	}

	if a.useResourceProcessorBusyBox() {
		rJar := android.PathForModuleOut(ctx, "busybox/R.jar")
		resourceProcessorBusyBoxGenerateBinaryR(ctx, rTxt, a.mergedManifestFile, rJar, staticDeps, a.isLibrary)
		transitiveRJars = append(transitiveRJars, rJar)
		a.rJar = rJar
	}

	a.aaptSrcJar = srcJar
	a.transitiveAaptRJars = transitiveRJars
	a.transitiveAaptResourcePackages = staticDeps.resPackages()
	a.exportPackage = packageRes
	a.manifestPath = manifestPath
	a.proguardOptionsFile = proguardOptionsFile
@@ -449,7 +502,11 @@ func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext android.SdkCon
			resPackage:          a.exportPackage,
			manifest:            a.manifestPath,
			additionalManifests: additionalManifests,
			rTxt:                a.rTxt,
			rJar:                a.rJar,
			assets:              a.assetPackage,

			usedResourceProcessor: a.useResourceProcessorBusyBox(),
		}).
		Transitive(staticResourcesNodesDepSet).Build()
	a.rroDirsDepSet = android.NewDepSetBuilder[rroDir](android.TOPOLOGICAL).
@@ -461,34 +518,93 @@ func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext android.SdkCon
		Transitive(staticManifestsDepSet).Build()
}

var resourceProcessorBusyBox = pctx.AndroidStaticRule("resourceProcessorBusyBox",
	blueprint.RuleParams{
		Command: "${config.JavaCmd} -cp ${config.ResourceProcessorBusyBox} " +
			"com.google.devtools.build.android.ResourceProcessorBusyBox --tool=GENERATE_BINARY_R -- @${out}.args && " +
			"if cmp -s ${out}.tmp ${out} ; then rm ${out}.tmp ; else mv ${out}.tmp ${out}; fi",
		CommandDeps:    []string{"${config.ResourceProcessorBusyBox}"},
		Rspfile:        "${out}.args",
		RspfileContent: "--primaryRTxt ${rTxt} --primaryManifest ${manifest} --classJarOutput ${out}.tmp ${args}",
		Restat:         true,
	}, "rTxt", "manifest", "args")

// resourceProcessorBusyBoxGenerateBinaryR converts the R.txt file produced by aapt2 into R.class files
// using Bazel's ResourceProcessorBusyBox tool, which is faster than compiling the R.java files and
// supports producing classes for static dependencies that only include resources from that dependency.
func resourceProcessorBusyBoxGenerateBinaryR(ctx android.ModuleContext, rTxt, manifest android.Path,
	rJar android.WritablePath, transitiveDeps transitiveAarDeps, isLibrary bool) {

	var args []string
	var deps android.Paths

	if !isLibrary {
		// When compiling an app, pass all R.txt and AndroidManifest.xml from transitive static library dependencies
		// to ResourceProcessorBusyBox so that it can regenerate R.class files with the final resource IDs for each
		// package.
		args, deps = transitiveDeps.resourceProcessorDeps()
	} else {
		// When compiling a library don't pass any dependencies as it only needs to generate an R.class file for this
		// library.  Pass --finalFields=false so that the R.class file contains non-final fields so they don't get
		// inlined into the library before the final IDs are assigned during app compilation.
		args = append(args, "--finalFields=false")
	}

	deps = append(deps, rTxt, manifest)

	ctx.Build(pctx, android.BuildParams{
		Rule:        resourceProcessorBusyBox,
		Output:      rJar,
		Implicits:   deps,
		Description: "ResourceProcessorBusyBox",
		Args: map[string]string{
			"rTxt":     rTxt.String(),
			"manifest": manifest.String(),
			"args":     strings.Join(args, " "),
		},
	})
}

type resourcesNode struct {
	resPackage          android.Path
	manifest            android.Path
	additionalManifests android.Paths
	rTxt                android.Path
	rJar                android.Path
	assets              android.OptionalPath

	usedResourceProcessor bool
}

type transitiveAarDeps []*resourcesNode

func (t transitiveAarDeps) resPackages() android.Paths {
	var paths android.Paths
	paths := make(android.Paths, 0, len(t))
	for _, dep := range t {
		paths = append(paths, dep.resPackage)
	}
	return android.FirstUniquePaths(paths)
	return paths
}

func (t transitiveAarDeps) manifests() android.Paths {
	var paths android.Paths
	paths := make(android.Paths, 0, len(t))
	for _, dep := range t {
		paths = append(paths, dep.manifest)
		paths = append(paths, dep.additionalManifests...)
	}
	return android.FirstUniquePaths(paths)
	return paths
}

func (t transitiveAarDeps) resourceProcessorDeps() (args []string, deps android.Paths) {
	for _, dep := range t {
		args = append(args, "--library="+dep.rTxt.String()+","+dep.manifest.String())
		deps = append(deps, dep.rTxt, dep.manifest)
	}
	return args, deps
}

func (t transitiveAarDeps) assets() android.Paths {
	var paths android.Paths
	paths := make(android.Paths, 0, len(t))
	for _, dep := range t {
		if dep.assets.Valid() {
			paths = append(paths, dep.assets.Path())
@@ -613,9 +729,12 @@ func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext)

	a.stem = proptools.StringDefault(a.overridableDeviceProperties.Stem, ctx.ModuleName())

	ctx.CheckbuildFile(a.proguardOptionsFile)
	ctx.CheckbuildFile(a.exportPackage)
	ctx.CheckbuildFile(a.aaptSrcJar)
	ctx.CheckbuildFile(a.aapt.proguardOptionsFile)
	ctx.CheckbuildFile(a.aapt.exportPackage)
	ctx.CheckbuildFile(a.aapt.aaptSrcJar)
	if a.useResourceProcessorBusyBox() {
		ctx.CheckbuildFile(a.aapt.rJar)
	}

	// apps manifests are handled by aapt, don't let Module see them
	a.properties.Manifest = nil
@@ -627,7 +746,22 @@ func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext)
	a.Module.extraProguardFlagFiles = append(a.Module.extraProguardFlagFiles,
		a.proguardOptionsFile)

	a.Module.compile(ctx, a.aaptSrcJar)
	var extraSrcJars android.Paths
	var extraCombinedJars android.Paths
	var extraClasspathJars android.Paths
	if a.useResourceProcessorBusyBox() {
		// When building a library with ResourceProcessorBusyBox enabled ResourceProcessorBusyBox for this
		// library and each of the transitive static android_library dependencies has already created an
		// R.class file for the appropriate package.  Add all of those R.class files to the classpath.
		extraClasspathJars = a.transitiveAaptRJars
	} else {
		// When building a library without ResourceProcessorBusyBox the aapt2 rule creates R.srcjar containing
		// R.java files for the library's package and the packages from all transitive static android_library
		// dependencies.  Compile the srcjar alongside the rest of the sources.
		extraSrcJars = android.Paths{a.aapt.aaptSrcJar}
	}

	a.Module.compile(ctx, extraSrcJars, extraClasspathJars, extraCombinedJars)

	a.aarFile = android.PathForModuleOut(ctx, ctx.ModuleName()+".aar")
	var res android.Paths
@@ -732,9 +866,12 @@ type AARImport struct {
	classpathFile                  android.WritablePath
	proguardFlags                  android.WritablePath
	exportPackage                  android.WritablePath
	transitiveAaptResourcePackages android.Paths
	extraAaptPackagesFile          android.WritablePath
	manifest                       android.WritablePath
	assetsPackage                  android.WritablePath
	rTxt                           android.WritablePath
	rJar                           android.WritablePath

	resourcesNodesDepSet *android.DepSet[*resourcesNode]
	manifestsDepSet      *android.DepSet[android.Path]
@@ -903,12 +1040,13 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
	a.classpathFile = extractedAARDir.Join(ctx, "classes-combined.jar")
	a.proguardFlags = extractedAARDir.Join(ctx, "proguard.txt")
	a.manifest = extractedAARDir.Join(ctx, "AndroidManifest.xml")
	aarRTxt := extractedAARDir.Join(ctx, "R.txt")
	a.assetsPackage = android.PathForModuleOut(ctx, "assets.zip")

	ctx.Build(pctx, android.BuildParams{
		Rule:        unzipAAR,
		Input:       a.aarPath,
		Outputs:     android.WritablePaths{a.classpathFile, a.proguardFlags, a.manifest, a.assetsPackage},
		Outputs:     android.WritablePaths{a.classpathFile, a.proguardFlags, a.manifest, a.assetsPackage, aarRTxt},
		Description: "unzip AAR",
		Args: map[string]string{
			"outDir":             extractedAARDir.String(),
@@ -928,14 +1066,14 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
	// the subdir "android" is required to be filtered by package names
	srcJar := android.PathForModuleGen(ctx, "android", "R.srcjar")
	proguardOptionsFile := android.PathForModuleGen(ctx, "proguard.options")
	rTxt := android.PathForModuleOut(ctx, "R.txt")
	a.rTxt = android.PathForModuleOut(ctx, "R.txt")
	a.extraAaptPackagesFile = android.PathForModuleOut(ctx, "extra_packages")

	var linkDeps android.Paths

	linkFlags := []string{
		"--static-lib",
		"--no-static-lib-packages",
		"--merge-only",
		"--auto-add-overlay",
	}

@@ -948,25 +1086,35 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
	_ = staticRRODirsDepSet
	staticDeps := transitiveAarDeps(staticResourcesNodesDepSet.ToList())

	// AAPT2 overlays are in lowest to highest priority order, reverse the topological order
	// of transitiveStaticLibs.
	transitiveStaticLibs := android.ReversePaths(staticDeps.resPackages())

	linkDeps = append(linkDeps, sharedLibs...)
	linkDeps = append(linkDeps, transitiveStaticLibs...)
	linkDeps = append(linkDeps, staticDeps.resPackages()...)
	linkFlags = append(linkFlags, libFlags...)

	overlayRes := append(android.Paths{flata}, transitiveStaticLibs...)
	overlayRes := android.Paths{flata}

	// Treat static library dependencies of static libraries as imports.
	transitiveStaticLibs := staticDeps.resPackages()
	linkDeps = append(linkDeps, transitiveStaticLibs...)
	for _, staticLib := range transitiveStaticLibs {
		linkFlags = append(linkFlags, "-I "+staticLib.String())
	}

	transitiveAssets := android.ReverseSliceInPlace(staticDeps.assets())
	aapt2Link(ctx, a.exportPackage, srcJar, proguardOptionsFile, rTxt, a.extraAaptPackagesFile,
	aapt2Link(ctx, a.exportPackage, srcJar, proguardOptionsFile, a.rTxt, a.extraAaptPackagesFile,
		linkFlags, linkDeps, nil, overlayRes, transitiveAssets, nil)

	a.rJar = android.PathForModuleOut(ctx, "busybox/R.jar")
	resourceProcessorBusyBoxGenerateBinaryR(ctx, a.rTxt, a.manifest, a.rJar, nil, true)

	resourcesNodesDepSetBuilder := android.NewDepSetBuilder[*resourcesNode](android.TOPOLOGICAL)
	resourcesNodesDepSetBuilder.Direct(&resourcesNode{
		resPackage: a.exportPackage,
		manifest:   a.manifest,
		rTxt:       a.rTxt,
		rJar:       a.rJar,
		assets:     android.OptionalPathForPath(a.assetsPackage),

		usedResourceProcessor: true,
	})
	resourcesNodesDepSetBuilder.Transitive(staticResourcesNodesDepSet)
	a.resourcesNodesDepSet = resourcesNodesDepSetBuilder.Build()
@@ -981,6 +1129,8 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
	_ = staticManifestsDepSet
	a.manifestsDepSet = manifestDepSetBuilder.Build()

	a.transitiveAaptResourcePackages = staticDeps.resPackages()

	a.collectTransitiveHeaderJars(ctx)
	ctx.SetProvider(JavaInfoProvider, JavaInfo{
		HeaderJars:                     android.PathsIfNonNil(a.classpathFile),
+2 −0
Original line number Diff line number Diff line
@@ -269,6 +269,7 @@ func (prebuilt *AARImport) AndroidMkEntries() []android.AndroidMkEntries {
				entries.SetPath("LOCAL_SOONG_HEADER_JAR", prebuilt.classpathFile)
				entries.SetPath("LOCAL_SOONG_CLASSES_JAR", prebuilt.classpathFile)
				entries.SetPath("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE", prebuilt.exportPackage)
				entries.SetPaths("LOCAL_SOONG_TRANSITIVE_RES_PACKAGES", prebuilt.transitiveAaptResourcePackages)
				entries.SetPath("LOCAL_SOONG_EXPORT_PROGUARD_FLAGS", prebuilt.proguardFlags)
				entries.SetPath("LOCAL_SOONG_STATIC_LIBRARY_EXTRA_PACKAGES", prebuilt.extraAaptPackagesFile)
				entries.SetPath("LOCAL_FULL_MANIFEST_FILE", prebuilt.manifest)
@@ -521,6 +522,7 @@ func (a *AndroidLibrary) AndroidMkEntries() []android.AndroidMkEntries {
		}

		entries.SetPath("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE", a.exportPackage)
		entries.SetPaths("LOCAL_SOONG_TRANSITIVE_RES_PACKAGES", a.transitiveAaptResourcePackages)
		entries.SetPath("LOCAL_SOONG_STATIC_LIBRARY_EXTRA_PACKAGES", a.extraAaptPackagesFile)
		entries.SetPath("LOCAL_FULL_MANIFEST_FILE", a.mergedManifestFile)
		entries.AddStrings("LOCAL_SOONG_EXPORT_PROGUARD_FLAGS", a.exportedProguardFlagFiles.Strings()...)
+17 −1
Original line number Diff line number Diff line
@@ -521,7 +521,23 @@ func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) android.Path {
	a.dexpreopter.preventInstall = a.appProperties.PreventInstall

	if ctx.ModuleName() != "framework-res" {
		a.Module.compile(ctx, a.aaptSrcJar)
		var extraSrcJars android.Paths
		var extraClasspathJars android.Paths
		var extraCombinedJars android.Paths
		if a.useResourceProcessorBusyBox() {
			// When building an app with ResourceProcessorBusyBox enabled ResourceProcessorBusyBox has already
			// created R.class files that provide IDs for resources in busybox/R.jar.  Pass that file in the
			// classpath when compiling everything else, and add it to the final classes jar.
			extraClasspathJars = android.Paths{a.aapt.rJar}
			extraCombinedJars = android.Paths{a.aapt.rJar}
		} else {
			// When building an app without ResourceProcessorBusyBox the aapt2 rule creates R.srcjar containing
			// R.java files for the app's package and the packages from all transitive static android_library
			// dependencies.  Compile the srcjar alongside the rest of the sources.
			extraSrcJars = android.Paths{a.aapt.aaptSrcJar}
		}

		a.Module.compile(ctx, extraSrcJars, extraClasspathJars, extraCombinedJars)
	}

	return a.dexJarFile.PathOrNil()
+258 −11

File changed.

Preview size limit exceeded, changes collapsed.

+11 −5
Original line number Diff line number Diff line
@@ -1065,7 +1065,7 @@ func (module *Module) addGeneratedSrcJars(path android.Path) {
	module.properties.Generated_srcjars = append(module.properties.Generated_srcjars, path)
}

func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {
func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspathJars, extraCombinedJars android.Paths) {
	j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.deviceProperties.Aidl.Export_include_dirs)

	deps := j.collectDeps(ctx)
@@ -1103,9 +1103,7 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {

	srcJars := srcFiles.FilterByExt(".srcjar")
	srcJars = append(srcJars, deps.srcJars...)
	if aaptSrcJar != nil {
		srcJars = append(srcJars, aaptSrcJar)
	}
	srcJars = append(srcJars, extraSrcJars...)
	srcJars = append(srcJars, j.properties.Generated_srcjars...)
	srcFiles = srcFiles.FilterOutByExt(".srcjar")

@@ -1148,6 +1146,11 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {
	var kotlinJars android.Paths
	var kotlinHeaderJars android.Paths

	// Prepend extraClasspathJars to classpath so that the resource processor R.jar comes before
	// any dependencies so that it can override any non-final R classes from dependencies with the
	// final R classes from the app.
	flags.classpath = append(android.CopyOf(extraClasspathJars), flags.classpath...)

	if srcFiles.HasExt(".kt") {
		// When using kotlin sources turbine is used to generate annotation processor sources,
		// including for annotation processors that generate API, so we can use turbine for
@@ -1241,8 +1244,9 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {
			// allow for the use of annotation processors that do function correctly
			// with sharding enabled. See: b/77284273.
		}
		extraJars := append(android.CopyOf(extraCombinedJars), kotlinHeaderJars...)
		headerJarFileWithoutDepsOrJarjar, j.headerJarFile =
			j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName, kotlinHeaderJars)
			j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName, extraJars)
		if ctx.Failed() {
			return
		}
@@ -1393,6 +1397,8 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {
		jars = append(jars, servicesJar)
	}

	jars = append(android.CopyOf(extraCombinedJars), jars...)

	// Combine the classes built from sources, any manifests, and any static libraries into
	// classes.jar. If there is only one input jar this step will be skipped.
	var outputFile android.OutputPath
Loading