diff options
Diffstat (limited to 'java/dex.go')
| -rw-r--r-- | java/dex.go | 222 |
1 files changed, 165 insertions, 57 deletions
diff --git a/java/dex.go b/java/dex.go index 4d6aa3456..7bb69257c 100644 --- a/java/dex.go +++ b/java/dex.go @@ -45,8 +45,8 @@ type DexProperties struct { // Whether to continue building even if warnings are emitted. Defaults to true. Ignore_warnings *bool - // If true, runs R8 in Proguard compatibility mode (default). - // Otherwise, runs R8 in full mode. + // If true, runs R8 in Proguard compatibility mode, otherwise runs R8 in full mode. + // Defaults to false for apps, true for libraries and tests. Proguard_compatibility *bool // If true, optimize for size by removing unused code. Defaults to true for apps, @@ -66,11 +66,21 @@ type DexProperties struct { // If true, optimize for size by removing unused resources. Defaults to false. Shrink_resources *bool + // If true, use optimized resource shrinking in R8, overriding the + // Shrink_resources setting. Defaults to false. + // Optimized shrinking means that R8 will trace and treeshake resources together with code + // and apply additional optimizations. This implies non final fields in the R classes. + Optimized_shrink_resources *bool + // Flags to pass to proguard. Proguard_flags []string // Specifies the locations of files containing proguard flags. Proguard_flags_files []string `android:"path"` + + // If true, transitive reverse dependencies of this module will have this + // module's proguard spec appended to their optimization action + Export_proguard_flags_files *bool } // Keep the data uncompressed. We always need uncompressed dex for execution, @@ -81,16 +91,22 @@ type DexProperties struct { // Exclude kotlinc generate files: *.kotlin_module, *.kotlin_builtins. Defaults to false. Exclude_kotlinc_generated_files *bool + + // Disable dex container (also known as "multi-dex"). + // This may be necessary as a temporary workaround to mask toolchain bugs (see b/341652226). + No_dex_container *bool } type dexer struct { dexProperties DexProperties // list of extra proguard flag files - extraProguardFlagFiles android.Paths - proguardDictionary android.OptionalPath - proguardConfiguration android.OptionalPath - proguardUsageZip android.OptionalPath + extraProguardFlagsFiles android.Paths + proguardDictionary android.OptionalPath + proguardConfiguration android.OptionalPath + proguardUsageZip android.OptionalPath + resourcesInput android.OptionalPath + resourcesOutput android.OptionalPath providesTransitiveHeaderJars } @@ -99,17 +115,27 @@ func (d *dexer) effectiveOptimizeEnabled() bool { return BoolDefault(d.dexProperties.Optimize.Enabled, d.dexProperties.Optimize.EnabledByDefault) } +func (d *DexProperties) resourceShrinkingEnabled(ctx android.ModuleContext) bool { + return !ctx.Config().Eng() && BoolDefault(d.Optimize.Optimized_shrink_resources, Bool(d.Optimize.Shrink_resources)) +} + +func (d *DexProperties) optimizedResourceShrinkingEnabled(ctx android.ModuleContext) bool { + return d.resourceShrinkingEnabled(ctx) && Bool(d.Optimize.Optimized_shrink_resources) +} + +func (d *dexer) optimizeOrObfuscateEnabled() bool { + return d.effectiveOptimizeEnabled() && (proptools.Bool(d.dexProperties.Optimize.Optimize) || proptools.Bool(d.dexProperties.Optimize.Obfuscate)) +} + var d8, d8RE = pctx.MultiCommandRemoteStaticRules("d8", blueprint.RuleParams{ Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` + - `mkdir -p $$(dirname $tmpJar) && ` + - `${config.Zip2ZipCmd} -i $in -o $tmpJar -x '**/*.dex' && ` + - `$d8Template${config.D8Cmd} ${config.D8Flags} --output $outDir $d8Flags $tmpJar && ` + + `$d8Template${config.D8Cmd} ${config.D8Flags} $d8Flags --output $outDir --no-dex-input-jar $in && ` + `$zipTemplate${config.SoongZipCmd} $zipFlags -o $outDir/classes.dex.jar -C $outDir -f "$outDir/classes*.dex" && ` + - `${config.MergeZipsCmd} -D -stripFile "**/*.class" $mergeZipsFlags $out $outDir/classes.dex.jar $in`, + `${config.MergeZipsCmd} -D -stripFile "**/*.class" $mergeZipsFlags $out $outDir/classes.dex.jar $in && ` + + `rm -f "$outDir/classes*.dex" "$outDir/classes.dex.jar"`, CommandDeps: []string{ "${config.D8Cmd}", - "${config.Zip2ZipCmd}", "${config.SoongZipCmd}", "${config.MergeZipsCmd}", }, @@ -128,32 +154,29 @@ var d8, d8RE = pctx.MultiCommandRemoteStaticRules("d8", ExecStrategy: "${config.RED8ExecStrategy}", Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, }, - }, []string{"outDir", "d8Flags", "zipFlags", "tmpJar", "mergeZipsFlags"}, nil) + }, []string{"outDir", "d8Flags", "zipFlags", "mergeZipsFlags"}, nil) var r8, r8RE = pctx.MultiCommandRemoteStaticRules("r8", blueprint.RuleParams{ Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` + `rm -f "$outDict" && rm -f "$outConfig" && rm -rf "${outUsageDir}" && ` + `mkdir -p $$(dirname ${outUsage}) && ` + - `mkdir -p $$(dirname $tmpJar) && ` + - `${config.Zip2ZipCmd} -i $in -o $tmpJar -x '**/*.dex' && ` + - `$r8Template${config.R8Cmd} ${config.R8Flags} -injars $tmpJar --output $outDir ` + + `$r8Template${config.R8Cmd} ${config.R8Flags} $r8Flags -injars $in --output $outDir ` + `--no-data-resources ` + `-printmapping ${outDict} ` + - `--pg-conf-output ${outConfig} ` + + `-printconfiguration ${outConfig} ` + `-printusage ${outUsage} ` + - `--deps-file ${out}.d ` + - `$r8Flags && ` + + `--deps-file ${out}.d && ` + `touch "${outDict}" "${outConfig}" "${outUsage}" && ` + `${config.SoongZipCmd} -o ${outUsageZip} -C ${outUsageDir} -f ${outUsage} && ` + `rm -rf ${outUsageDir} && ` + `$zipTemplate${config.SoongZipCmd} $zipFlags -o $outDir/classes.dex.jar -C $outDir -f "$outDir/classes*.dex" && ` + - `${config.MergeZipsCmd} -D -stripFile "**/*.class" $mergeZipsFlags $out $outDir/classes.dex.jar $in`, + `${config.MergeZipsCmd} -D -stripFile "**/*.class" $mergeZipsFlags $out $outDir/classes.dex.jar $in && ` + + `rm -f "$outDir/classes*.dex" "$outDir/classes.dex.jar"`, Depfile: "${out}.d", Deps: blueprint.DepsGCC, CommandDeps: []string{ "${config.R8Cmd}", - "${config.Zip2ZipCmd}", "${config.SoongZipCmd}", "${config.MergeZipsCmd}", }, @@ -161,7 +184,7 @@ var r8, r8RE = pctx.MultiCommandRemoteStaticRules("r8", "$r8Template": &remoteexec.REParams{ Labels: map[string]string{"type": "compile", "compiler": "r8"}, Inputs: []string{"$implicits", "${config.R8Jar}"}, - OutputFiles: []string{"${outUsage}"}, + OutputFiles: []string{"${outUsage}", "${outConfig}", "${outDict}", "${resourcesOutput}", "${outR8ArtProfile}"}, ExecStrategy: "${config.RER8ExecStrategy}", ToolchainInputs: []string{"${config.JavaCmd}"}, Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, @@ -181,7 +204,7 @@ var r8, r8RE = pctx.MultiCommandRemoteStaticRules("r8", Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, }, }, []string{"outDir", "outDict", "outConfig", "outUsage", "outUsageZip", "outUsageDir", - "r8Flags", "zipFlags", "tmpJar", "mergeZipsFlags"}, []string{"implicits"}) + "r8Flags", "zipFlags", "mergeZipsFlags", "resourcesOutput", "outR8ArtProfile"}, []string{"implicits"}) func (d *dexer) dexCommonFlags(ctx android.ModuleContext, dexParams *compileDexParams) (flags []string, deps android.Paths) { @@ -213,8 +236,9 @@ func (d *dexer) dexCommonFlags(ctx android.ModuleContext, // Note: Targets with a min SDK kind of core_platform (e.g., framework.jar) or unspecified (e.g., // services.jar), are not classified as stable, which is WAI. // TODO(b/232073181): Expand to additional min SDK cases after validation. + var addAndroidPlatformBuildFlag = false if !dexParams.sdkVersion.Stable() { - flags = append(flags, "--android-platform-build") + addAndroidPlatformBuildFlag = true } effectiveVersion, err := dexParams.minSdkVersion.EffectiveVersion(ctx) @@ -222,21 +246,40 @@ func (d *dexer) dexCommonFlags(ctx android.ModuleContext, ctx.PropertyErrorf("min_sdk_version", "%s", err) } - flags = append(flags, "--min-api "+strconv.Itoa(effectiveVersion.FinalOrFutureInt())) + // If the specified SDK level is 10000, then configure the compiler to use the + // current platform SDK level and to compile the build as a platform build. + var minApiFlagValue = effectiveVersion.FinalOrFutureInt() + if minApiFlagValue == 10000 { + minApiFlagValue = ctx.Config().PlatformSdkVersion().FinalInt() + addAndroidPlatformBuildFlag = true + } + flags = append(flags, "--min-api "+strconv.Itoa(minApiFlagValue)) + + if addAndroidPlatformBuildFlag { + flags = append(flags, "--android-platform-build") + } 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 + } + + return d8Flags, d8Deps, artProfileOutput } -func (d *dexer) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8Flags []string, r8Deps android.Paths) { +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 @@ -248,8 +291,8 @@ func (d *dexer) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8Fl // See b/20667396 var proguardRaiseDeps classpath ctx.VisitDirectDepsWithTag(proguardRaiseTag, func(m android.Module) { - dep := ctx.OtherModuleProvider(m, JavaInfoProvider).(JavaInfo) - proguardRaiseDeps = append(proguardRaiseDeps, dep.HeaderJars...) + dep, _ := android.OtherModuleProvider(ctx, m, JavaInfoProvider) + proguardRaiseDeps = append(proguardRaiseDeps, dep.RepackagedHeaderJars...) }) r8Flags = append(r8Flags, proguardRaiseDeps.FormJavaClassPath("-libraryjars")) @@ -283,11 +326,13 @@ func (d *dexer) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8Fl android.PathForSource(ctx, "build/make/core/proguard.flags"), } - flagFiles = append(flagFiles, d.extraProguardFlagFiles...) + flagFiles = append(flagFiles, d.extraProguardFlagsFiles...) // TODO(ccross): static android library proguard files flagFiles = append(flagFiles, android.PathsForModuleSrc(ctx, opt.Proguard_flags_files)...) + flagFiles = android.FirstUniquePaths(flagFiles) + r8Flags = append(r8Flags, android.JoinWithPrefix(flagFiles.Strings(), "-include ")) r8Deps = append(r8Deps, flagFiles...) @@ -299,15 +344,14 @@ func (d *dexer) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8Fl if BoolDefault(opt.Proguard_compatibility, true) { r8Flags = append(r8Flags, "--force-proguard-compatibility") - } else { + } + + if Bool(opt.Optimize) || Bool(opt.Obfuscate) { // TODO(b/213833843): Allow configuration of the prefix via a build variable. var sourceFilePrefix = "go/retraceme " var sourceFileTemplate = "\"" + sourceFilePrefix + "%MAP_ID\"" - // TODO(b/200967150): Also tag the source file in compat builds. - if Bool(opt.Optimize) || Bool(opt.Obfuscate) { - r8Flags = append(r8Flags, "--map-id-template", "%MAP_HASH") - r8Flags = append(r8Flags, "--source-file-template", sourceFileTemplate) - } + r8Flags = append(r8Flags, "--map-id-template", "%MAP_HASH") + r8Flags = append(r8Flags, "--source-file-template", sourceFileTemplate) } // TODO(ccross): Don't shrink app instrumentation tests by default. @@ -337,23 +381,58 @@ func (d *dexer) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8Fl r8Flags = append(r8Flags, "-ignorewarnings") } - return r8Flags, r8Deps + // resourcesInput is empty when we don't use resource shrinking, if on, pass these to R8 + if d.resourcesInput.Valid() { + r8Flags = append(r8Flags, "--resource-input", d.resourcesInput.Path().String()) + r8Deps = append(r8Deps, d.resourcesInput.Path()) + r8Flags = append(r8Flags, "--resource-output", d.resourcesOutput.Path().String()) + if Bool(opt.Optimized_shrink_resources) { + r8Flags = append(r8Flags, "--optimized-resource-shrinking") + } + } + + 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 { - flags javaBuilderFlags - sdkVersion android.SdkSpec - minSdkVersion android.ApiLevel - classesJar android.Path - jarName string + flags javaBuilderFlags + sdkVersion android.SdkSpec + minSdkVersion android.ApiLevel + classesJar android.Path + jarName string + artProfileInput *string } -func (d *dexer) compileDex(ctx android.ModuleContext, dexParams *compileDexParams) android.OutputPath { +// 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 + +} + +// 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 outDir := android.PathForModuleOut(ctx, "dex") - tmpJar := android.PathForModuleOut(ctx, "withres-withoutdex", dexParams.jarName) zipFlags := "--ignore_missing_files" if proptools.Bool(d.dexProperties.Uncompress_dex) { @@ -369,6 +448,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) @@ -379,8 +459,14 @@ func (d *dexer) compileDex(ctx android.ModuleContext, dexParams *compileDexParam android.ModuleNameWithPossibleOverride(ctx), "unused.txt") proguardUsageZip := android.PathForModuleOut(ctx, "proguard_usage.zip") d.proguardUsageZip = android.OptionalPathForPath(proguardUsageZip) - r8Flags, r8Deps := d.r8Flags(ctx, dexParams.flags) - r8Deps = append(r8Deps, commonDeps...) + resourcesOutput := android.PathForModuleOut(ctx, "package-res-shrunken.apk") + d.resourcesOutput = android.OptionalPathForPath(resourcesOutput) + implicitOutputs := android.WritablePaths{ + proguardDictionary, + proguardUsageZip, + proguardConfiguration, + } + r8Flags, r8Deps, r8ArtProfileOutputPath := d.r8Flags(ctx, dexParams) rule := r8 args := map[string]string{ "r8Flags": strings.Join(append(commonFlags, r8Flags...), " "), @@ -391,49 +477,71 @@ func (d *dexer) compileDex(ctx android.ModuleContext, dexParams *compileDexParam "outUsage": proguardUsage.String(), "outUsageZip": proguardUsageZip.String(), "outDir": outDir.String(), - "tmpJar": tmpJar.String(), "mergeZipsFlags": mergeZipsFlags, } + if r8ArtProfileOutputPath != nil { + artProfileOutputPath = r8ArtProfileOutputPath + implicitOutputs = append( + implicitOutputs, + artProfileOutputPath, + ) + // Add the implicit r8 Art profile output to args so that r8RE knows + // about this implicit output + args["outR8ArtProfile"] = artProfileOutputPath.String() + } + if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_R8") { rule = r8RE args["implicits"] = strings.Join(r8Deps.Strings(), ",") } + if d.resourcesInput.Valid() { + implicitOutputs = append(implicitOutputs, resourcesOutput) + args["resourcesOutput"] = resourcesOutput.String() + } ctx.Build(pctx, android.BuildParams{ Rule: rule, Description: "r8", Output: javalibJar, - ImplicitOutputs: android.WritablePaths{proguardDictionary, proguardUsageZip}, + ImplicitOutputs: implicitOutputs, Input: dexParams.classesJar, Implicits: r8Deps, 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") { rule = d8RE } ctx.Build(pctx, android.BuildParams{ - Rule: rule, - Description: "d8", - Output: javalibJar, - Input: dexParams.classesJar, - Implicits: d8Deps, + Rule: rule, + Description: "d8", + Output: javalibJar, + Input: dexParams.classesJar, + ImplicitOutputs: implicitOutputs, + Implicits: d8Deps, Args: map[string]string{ "d8Flags": strings.Join(append(commonFlags, d8Flags...), " "), "zipFlags": zipFlags, "outDir": outDir.String(), - "tmpJar": tmpJar.String(), "mergeZipsFlags": mergeZipsFlags, }, }) } if proptools.Bool(d.dexProperties.Uncompress_dex) { alignedJavalibJar := android.PathForModuleOut(ctx, "aligned", dexParams.jarName).OutputPath - TransformZipAlign(ctx, alignedJavalibJar, javalibJar) + TransformZipAlign(ctx, alignedJavalibJar, javalibJar, nil) javalibJar = alignedJavalibJar } - return javalibJar + return javalibJar, artProfileOutputPath } |