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

Commit 8723705f authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Use r8/d8 optimized profile for dexpreopt" into main

parents f820c3be 3dbda18e
Loading
Loading
Loading
Loading
+13 −1
Original line number Diff line number Diff line
@@ -1650,11 +1650,23 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath
				classesJar:    implementationAndResourcesJar,
				jarName:       jarName,
			}
			dexOutputFile = j.dexer.compileDex(ctx, params)
			if j.EnableProfileRewriting() {
				profile := j.GetProfile()
				if profile == "" || !j.GetProfileGuided() {
					ctx.PropertyErrorf("enable_profile_rewriting", "Profile and Profile_guided must be set when enable_profile_rewriting is true")
				}
				params.artProfileInput = &profile
			}
			dexOutputFile, dexArtProfileOutput := j.dexer.compileDex(ctx, params)
			if ctx.Failed() {
				return
			}

			// If r8/d8 provides a profile that matches the optimized dex, use that for dexpreopt.
			if dexArtProfileOutput != nil {
				j.dexpreopter.SetRewrittenProfile(*dexArtProfileOutput)
			}

			// merge dex jar with resources if necessary
			if j.resourceJar != nil {
				jars := android.Paths{dexOutputFile, j.resourceJar}
+74 −23
Original line number Diff line number Diff line
@@ -253,17 +253,25 @@ func (d *dexer) dexCommonFlags(ctx android.ModuleContext,
	return flags, deps
}

func d8Flags(flags javaBuilderFlags) (d8Flags []string, d8Deps android.Paths) {
func (d *dexer) d8Flags(ctx android.ModuleContext, dexParams *compileDexParams) (d8Flags []string, d8Deps android.Paths, artProfileOutput *android.OutputPath) {
	flags := dexParams.flags
	d8Flags = append(d8Flags, flags.bootClasspath.FormRepeatedClassPath("--lib ")...)
	d8Flags = append(d8Flags, flags.dexClasspath.FormRepeatedClassPath("--lib ")...)

	d8Deps = append(d8Deps, flags.bootClasspath...)
	d8Deps = append(d8Deps, flags.dexClasspath...)

	return d8Flags, d8Deps
	if flags, deps, profileOutput := d.addArtProfile(ctx, dexParams); profileOutput != nil {
		d8Flags = append(d8Flags, flags...)
		d8Deps = append(d8Deps, deps...)
		artProfileOutput = profileOutput
	}

func (d *dexer) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8Flags []string, r8Deps android.Paths) {
	return d8Flags, d8Deps, artProfileOutput
}

func (d *dexer) r8Flags(ctx android.ModuleContext, dexParams *compileDexParams) (r8Flags []string, r8Deps android.Paths, artProfileOutput *android.OutputPath) {
	flags := dexParams.flags
	opt := d.dexProperties.Optimize

	// When an app contains references to APIs that are not in the SDK specified by
@@ -375,7 +383,13 @@ func (d *dexer) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8Fl
		}
	}

	return r8Flags, r8Deps
	if flags, deps, profileOutput := d.addArtProfile(ctx, dexParams); profileOutput != nil {
		r8Flags = append(r8Flags, flags...)
		r8Deps = append(r8Deps, deps...)
		artProfileOutput = profileOutput
	}

	return r8Flags, r8Deps, artProfileOutput
}

type compileDexParams struct {
@@ -384,9 +398,29 @@ type compileDexParams struct {
	minSdkVersion   android.ApiLevel
	classesJar      android.Path
	jarName         string
	artProfileInput *string
}

// Adds --art-profile to r8/d8 command.
// r8/d8 will output a generated profile file to match the optimized dex code.
func (d *dexer) addArtProfile(ctx android.ModuleContext, dexParams *compileDexParams) (flags []string, deps android.Paths, artProfileOutputPath *android.OutputPath) {
	if dexParams.artProfileInput != nil {
		artProfileInputPath := android.PathForModuleSrc(ctx, *dexParams.artProfileInput)
		artProfileOutputPathValue := android.PathForModuleOut(ctx, "profile.prof.txt").OutputPath
		artProfileOutputPath = &artProfileOutputPathValue
		flags = []string{
			"--art-profile",
			artProfileInputPath.String(),
			artProfileOutputPath.String(),
		}
		deps = append(deps, artProfileInputPath)
	}
	return flags, deps, artProfileOutputPath

func (d *dexer) compileDex(ctx android.ModuleContext, dexParams *compileDexParams) android.OutputPath {
}

// Return the compiled dex jar and (optional) profile _after_ r8 optimization
func (d *dexer) compileDex(ctx android.ModuleContext, dexParams *compileDexParams) (android.OutputPath, *android.OutputPath) {

	// Compile classes.jar into classes.dex and then javalib.jar
	javalibJar := android.PathForModuleOut(ctx, "dex", dexParams.jarName).OutputPath
@@ -406,6 +440,7 @@ func (d *dexer) compileDex(ctx android.ModuleContext, dexParams *compileDexParam
	}

	useR8 := d.effectiveOptimizeEnabled()
	var artProfileOutputPath *android.OutputPath
	if useR8 {
		proguardDictionary := android.PathForModuleOut(ctx, "proguard_dictionary")
		d.proguardDictionary = android.OptionalPathForPath(proguardDictionary)
@@ -418,8 +453,19 @@ func (d *dexer) compileDex(ctx android.ModuleContext, dexParams *compileDexParam
		d.proguardUsageZip = android.OptionalPathForPath(proguardUsageZip)
		resourcesOutput := android.PathForModuleOut(ctx, "package-res-shrunken.apk")
		d.resourcesOutput = android.OptionalPathForPath(resourcesOutput)
		r8Flags, r8Deps := d.r8Flags(ctx, dexParams.flags)
		r8Deps = append(r8Deps, commonDeps...)
		implicitOutputs := android.WritablePaths{
			proguardDictionary,
			proguardUsageZip,
			proguardConfiguration,
		}
		r8Flags, r8Deps, r8ArtProfileOutputPath := d.r8Flags(ctx, dexParams)
		if r8ArtProfileOutputPath != nil {
			artProfileOutputPath = r8ArtProfileOutputPath
			implicitOutputs = append(
				implicitOutputs,
				artProfileOutputPath,
			)
		}
		rule := r8
		args := map[string]string{
			"r8Flags":        strings.Join(append(commonFlags, r8Flags...), " "),
@@ -436,10 +482,6 @@ func (d *dexer) compileDex(ctx android.ModuleContext, dexParams *compileDexParam
			rule = r8RE
			args["implicits"] = strings.Join(r8Deps.Strings(), ",")
		}
		implicitOutputs := android.WritablePaths{
			proguardDictionary,
			proguardUsageZip,
			proguardConfiguration}
		if d.resourcesInput.Valid() {
			implicitOutputs = append(implicitOutputs, resourcesOutput)
			args["resourcesOutput"] = resourcesOutput.String()
@@ -454,7 +496,15 @@ func (d *dexer) compileDex(ctx android.ModuleContext, dexParams *compileDexParam
			Args:            args,
		})
	} else {
		d8Flags, d8Deps := d8Flags(dexParams.flags)
		implicitOutputs := android.WritablePaths{}
		d8Flags, d8Deps, d8ArtProfileOutputPath := d.d8Flags(ctx, dexParams)
		if d8ArtProfileOutputPath != nil {
			artProfileOutputPath = d8ArtProfileOutputPath
			implicitOutputs = append(
				implicitOutputs,
				artProfileOutputPath,
			)
		}
		d8Deps = append(d8Deps, commonDeps...)
		rule := d8
		if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_D8") {
@@ -465,6 +515,7 @@ func (d *dexer) compileDex(ctx android.ModuleContext, dexParams *compileDexParam
			Description:     "d8",
			Output:          javalibJar,
			Input:           dexParams.classesJar,
			ImplicitOutputs: implicitOutputs,
			Implicits:       d8Deps,
			Args: map[string]string{
				"d8Flags":        strings.Join(append(commonFlags, d8Flags...), " "),
@@ -480,5 +531,5 @@ func (d *dexer) compileDex(ctx android.ModuleContext, dexParams *compileDexParam
		javalibJar = alignedJavalibJar
	}

	return javalibJar
	return javalibJar, artProfileOutputPath
}
+27 −0
Original line number Diff line number Diff line
@@ -662,3 +662,30 @@ func TestProguardFlagsInheritanceAppImport(t *testing.T) {
	android.AssertStringDoesContain(t, "expected aarimports's proguard flags",
		appR8.Args["r8Flags"], "proguard.txt")
}

func TestR8FlagsArtProfile(t *testing.T) {
	result := PrepareForTestWithJavaDefaultModules.RunTestWithBp(t, `
		android_app {
			name: "app",
			srcs: ["foo.java"],
			platform_apis: true,
			dex_preopt: {
				profile_guided: true,
				profile: "profile.txt.prof",
				enable_profile_rewriting: true,
			},
		}
	`)

	app := result.ModuleForTests("app", "android_common")
	appR8 := app.Rule("r8")
	android.AssertStringDoesContain(t, "expected --art-profile in app r8 flags",
		appR8.Args["r8Flags"], "--art-profile")

	appDexpreopt := app.Rule("dexpreopt")
	android.AssertStringDoesContain(t,
		"expected --art-profile output to be used to create .prof binary",
		appDexpreopt.RuleParams.Command,
		"--create-profile-from=out/soong/.intermediates/app/android_common/profile.prof.txt --output-profile-type=app",
	)
}
+40 −5
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@ import (
	"sort"
	"strings"

	"github.com/google/blueprint/proptools"

	"android/soong/android"
	"android/soong/dexpreopt"
)
@@ -139,6 +141,10 @@ type dexpreopter struct {
	// The path to the profile that dexpreopter accepts. It must be in the binary format. If this is
	// set, it overrides the profile settings in `dexpreoptProperties`.
	inputProfilePathOnHost android.Path

	// The path to the profile that matches the dex optimized by r8/d8. It is in text format. If this is
	// set, it will be converted to a binary profile which will be subsequently used for dexpreopt.
	rewrittenProfile android.Path
}

type DexpreoptProperties struct {
@@ -158,6 +164,11 @@ type DexpreoptProperties struct {
		// defaults to searching for a file that matches the name of this module in the default
		// profile location set by PRODUCT_DEX_PREOPT_PROFILE_DIR, or empty if not found.
		Profile *string `android:"path"`

		// If set to true, r8/d8 will use `profile` as input to generate a new profile that matches
		// the optimized dex.
		// The new profile will be subsequently used as the profile to dexpreopt the dex file.
		Enable_profile_rewriting *bool
	}

	Dex_preopt_result struct {
@@ -421,13 +432,17 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, libName string, dexJa
	if d.inputProfilePathOnHost != nil {
		profileClassListing = android.OptionalPathForPath(d.inputProfilePathOnHost)
	} else if BoolDefault(d.dexpreoptProperties.Dex_preopt.Profile_guided, true) && !forPrebuiltApex(ctx) {
		// If enable_profile_rewriting is set, use the rewritten profile instead of the checked-in profile
		if d.EnableProfileRewriting() {
			profileClassListing = android.OptionalPathForPath(d.GetRewrittenProfile())
			profileIsTextListing = true
		} else if profile := d.GetProfile(); profile != "" {
			// If dex_preopt.profile_guided is not set, default it based on the existence of the
			// dexprepot.profile option or the profile class listing.
		if String(d.dexpreoptProperties.Dex_preopt.Profile) != "" {
			profileClassListing = android.OptionalPathForPath(
				android.PathForModuleSrc(ctx, String(d.dexpreoptProperties.Dex_preopt.Profile)))
				android.PathForModuleSrc(ctx, profile))
			profileBootListing = android.ExistentPathForSource(ctx,
				ctx.ModuleDir(), String(d.dexpreoptProperties.Dex_preopt.Profile)+"-boot")
				ctx.ModuleDir(), profile+"-boot")
			profileIsTextListing = true
		} else if global.ProfileDir != "" {
			profileClassListing = android.ExistentPathForSource(ctx,
@@ -588,3 +603,23 @@ func (d *dexpreopter) OutputProfilePathOnHost() android.Path {
func (d *dexpreopter) disableDexpreopt() {
	d.shouldDisableDexpreopt = true
}

func (d *dexpreopter) EnableProfileRewriting() bool {
	return proptools.Bool(d.dexpreoptProperties.Dex_preopt.Enable_profile_rewriting)
}

func (d *dexpreopter) GetProfile() string {
	return proptools.String(d.dexpreoptProperties.Dex_preopt.Profile)
}

func (d *dexpreopter) GetProfileGuided() bool {
	return proptools.Bool(d.dexpreoptProperties.Dex_preopt.Profile_guided)
}

func (d *dexpreopter) GetRewrittenProfile() android.Path {
	return d.rewrittenProfile
}

func (d *dexpreopter) SetRewrittenProfile(p android.Path) {
	d.rewrittenProfile = p
}
+2 −2
Original line number Diff line number Diff line
@@ -2339,7 +2339,7 @@ func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
		classesJar:    al.stubsJar,
		jarName:       ctx.ModuleName() + ".jar",
	}
	dexOutputFile := al.dexer.compileDex(ctx, dexParams)
	dexOutputFile, _ := al.dexer.compileDex(ctx, dexParams)
	uncompressed := true
	al.initHiddenAPI(ctx, makeDexJarPathFromPath(dexOutputFile), al.stubsJar, &uncompressed)
	dexOutputFile = al.hiddenAPIEncodeDex(ctx, dexOutputFile)
@@ -2723,7 +2723,7 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) {
				jarName:       jarName,
			}

			dexOutputFile = j.dexer.compileDex(ctx, dexParams)
			dexOutputFile, _ = j.dexer.compileDex(ctx, dexParams)
			if ctx.Failed() {
				return
			}