diff options
Diffstat (limited to 'java/dex.go')
-rw-r--r-- | java/dex.go | 251 |
1 files changed, 192 insertions, 59 deletions
diff --git a/java/dex.go b/java/dex.go index 7b99549d4..ed2df2103 100644 --- a/java/dex.go +++ b/java/dex.go @@ -49,10 +49,28 @@ type DexProperties struct { // Whether to continue building even if warnings are emitted. Defaults to true. Ignore_warnings *bool + // Whether runtime invisible annotations should be kept by R8. Defaults to false. + // This is equivalent to: + // -keepattributes RuntimeInvisibleAnnotations, + // RuntimeInvisibleParameterAnnotations, + // RuntimeInvisibleTypeAnnotations + // This is only applicable when RELEASE_R8_ONLY_RUNTIME_VISIBLE_ANNOTATIONS is + // enabled and will be used to migrate away from keeping runtime invisible + // annotations (b/387958004). + Keep_runtime_invisible_annotations *bool + // If true, runs R8 in Proguard compatibility mode, otherwise runs R8 in full mode. // Defaults to false for apps and tests, true for libraries. Proguard_compatibility *bool + // If true, R8 will not add public or protected members (fields or methods) to + // the API surface of the compilation unit, i.e., classes that are kept or + // have kept subclasses will not expose any members added by R8 for internal + // use. That includes renamed members if obfuscation is enabled. + // This should only be used for building targets that go on the bootclasspath. + // Defaults to false. + Protect_api_surface *bool + // If true, optimize for size by removing unused code. Defaults to true for apps, // false for libraries and tests. Shrink *bool @@ -160,6 +178,71 @@ var d8, d8RE = pctx.MultiCommandRemoteStaticRules("d8", }, }, []string{"outDir", "d8Flags", "zipFlags", "mergeZipsFlags"}, nil) +// Include all of the args for d8r8, so that we can generate the partialcompileclean target's build using the same list. +var d8r8Clean = pctx.AndroidStaticRule("d8r8-partialcompileclean", + blueprint.RuleParams{ + Command: `rm -rf "${outDir}" "${outDict}" "${outConfig}" "${outUsage}" "${outUsageZip}" "${outUsageDir}" ` + + `"${resourcesOutput}" "${outR8ArtProfile}" ${builtOut}`, + }, "outDir", "outDict", "outConfig", "outUsage", "outUsageZip", "outUsageDir", "builtOut", + "d8Flags", "r8Flags", "zipFlags", "mergeZipsFlags", "resourcesOutput", "outR8ArtProfile", "implicits", +) + +var d8r8, d8r8RE = pctx.MultiCommandRemoteStaticRules("d8r8", + blueprint.RuleParams{ + Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` + + `rm -f "$outDict" && rm -f "$outConfig" && rm -rf "${outUsageDir}" && ` + + `mkdir -p $$(dirname ${outUsage}) && ` + + `if [ -n "$${SOONG_USE_PARTIAL_COMPILE}" ]; then ` + + ` for f in "${outConfig}" "${outDict}" "${outUsage}" "${resourcesOutput}"; do ` + + ` test -n "$${f}" && test ! -f "$${f}" && mkdir -p "$$(dirname "$${f}")" && touch "$${f}" || true; ` + + ` done && ` + + ` $d8Template${config.D8Cmd} ${config.D8Flags} $d8Flags --output $outDir --no-dex-input-jar $in; ` + + `else ` + + ` $r8Template${config.R8Cmd} ${config.R8Flags} $r8Flags -injars $in --output $outDir ` + + ` --no-data-resources ` + + ` -printmapping ${outDict} ` + + ` -printconfiguration ${outConfig} ` + + ` -printusage ${outUsage} ` + + ` --deps-file ${out}.d && ` + + ` touch "${outDict}" "${outConfig}" "${outUsage}"; ` + + `fi && ` + + `${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 && ` + + `rm -f "$outDir"/classes*.dex "$outDir/classes.dex.jar" `, + CommandDeps: []string{ + "${config.D8Cmd}", + "${config.R8Cmd}", + "${config.SoongZipCmd}", + "${config.MergeZipsCmd}", + }, + }, map[string]*remoteexec.REParams{ + "$d8Template": &remoteexec.REParams{ + Labels: map[string]string{"type": "compile", "compiler": "d8"}, + Inputs: []string{"${config.D8Jar}"}, + ExecStrategy: "${config.RED8ExecStrategy}", + ToolchainInputs: []string{"${config.JavaCmd}"}, + Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, + }, + "$r8Template": &remoteexec.REParams{ + Labels: map[string]string{"type": "compile", "compiler": "r8"}, + Inputs: []string{"$implicits", "${config.R8Jar}"}, + OutputFiles: []string{"${outUsage}", "${outConfig}", "${outDict}", "${resourcesOutput}", "${outR8ArtProfile}"}, + ExecStrategy: "${config.RER8ExecStrategy}", + ToolchainInputs: []string{"${config.JavaCmd}"}, + Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, + }, + "$zipTemplate": &remoteexec.REParams{ + Labels: map[string]string{"type": "tool", "name": "soong_zip"}, + Inputs: []string{"${config.SoongZipCmd}", "$outDir"}, + OutputFiles: []string{"$outDir/classes.dex.jar"}, + ExecStrategy: "${config.RED8ExecStrategy}", + Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, + }, + }, []string{"outDir", "outDict", "outConfig", "outUsage", "outUsageZip", "outUsageDir", + "d8Flags", "r8Flags", "zipFlags", "mergeZipsFlags", "resourcesOutput", "outR8ArtProfile"}, []string{"implicits"}) + var r8, r8RE = pctx.MultiCommandRemoteStaticRules("r8", blueprint.RuleParams{ Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` + @@ -224,21 +307,29 @@ func (d *dexer) dexCommonFlags(ctx android.ModuleContext, deps = append(deps, f) } - var requestReleaseMode bool + var requestReleaseMode, requestDebugMode bool requestReleaseMode, flags = android.RemoveFromList("--release", flags) + requestDebugMode, flags = android.RemoveFromList("--debug", flags) if ctx.Config().Getenv("NO_OPTIMIZE_DX") != "" || ctx.Config().Getenv("GENERATE_DEX_DEBUG") != "" { - flags = append(flags, "--debug") + requestDebugMode = true requestReleaseMode = false } // Don't strip out debug information for eng builds, unless the target // explicitly provided the `--release` build flag. This allows certain // test targets to remain optimized as part of eng test_suites builds. - if requestReleaseMode { + if requestDebugMode { + flags = append(flags, "--debug") + } else if requestReleaseMode { flags = append(flags, "--release") } else if ctx.Config().Eng() { flags = append(flags, "--debug") + } else if !d.effectiveOptimizeEnabled() && d.dexProperties.Optimize.EnabledByDefault { + // D8 uses --debug by default, whereas R8 uses --release by default. + // For targets that default to R8 usage (e.g., apps), but override this default, we still + // want D8 to run in release mode, preserving semantics as much as possible between the two. + flags = append(flags, "--release") } // Supplying the platform build flag disables various features like API modeling and desugaring. @@ -310,7 +401,7 @@ func (d *dexer) r8Flags(ctx android.ModuleContext, dexParams *compileDexParams, // TODO(b/360905238): Remove SdkSystemServer exception after resolving missing class references. if !dexParams.sdkVersion.Stable() || dexParams.sdkVersion.Kind == android.SdkSystemServer { var proguardRaiseDeps classpath - ctx.VisitDirectDepsWithTag(proguardRaiseTag, func(m android.Module) { + ctx.VisitDirectDepsProxyWithTag(proguardRaiseTag, func(m android.ModuleProxy) { if dep, ok := android.OtherModuleProvider(ctx, m, JavaInfoProvider); ok { proguardRaiseDeps = append(proguardRaiseDeps, dep.RepackagedHeaderJars...) } @@ -344,6 +435,11 @@ func (d *dexer) r8Flags(ctx android.ModuleContext, dexParams *compileDexParams, android.PathForSource(ctx, "build/make/core/proguard.flags"), } + if ctx.Config().UseR8GlobalCheckNotNullFlags() { + flagFiles = append(flagFiles, android.PathForSource(ctx, + "build/make/core/proguard/checknotnull.flags")) + } + flagFiles = append(flagFiles, d.extraProguardFlagsFiles...) // TODO(ccross): static android library proguard files @@ -364,10 +460,18 @@ func (d *dexer) r8Flags(ctx android.ModuleContext, dexParams *compileDexParams, r8Flags = append(r8Flags, "--ignore-library-extends-program") } - if BoolDefault(opt.Proguard_compatibility, true) { + if BoolDefault(opt.Keep_runtime_invisible_annotations, false) { + r8Flags = append(r8Flags, "--keep-runtime-invisible-annotations") + } + + if BoolDefault(opt.Proguard_compatibility, !ctx.Config().UseR8FullModeByDefault()) { r8Flags = append(r8Flags, "--force-proguard-compatibility") } + if BoolDefault(opt.Protect_api_surface, false) { + r8Flags = append(r8Flags, "--protect-api-surface") + } + // Avoid unnecessary stack frame noise by only injecting source map ids for non-debug // optimized or obfuscated targets. if (Bool(opt.Optimize) || Bool(opt.Obfuscate)) && !debugMode { @@ -460,6 +564,7 @@ func (d *dexer) compileDex(ctx android.ModuleContext, dexParams *compileDexParam // Compile classes.jar into classes.dex and then javalib.jar javalibJar := android.PathForModuleOut(ctx, "dex", dexParams.jarName).OutputPath + cleanPhonyPath := android.PathForModuleOut(ctx, "dex", dexParams.jarName+"-partialcompileclean").OutputPath outDir := android.PathForModuleOut(ctx, "dex") zipFlags := "--ignore_missing_files" @@ -476,7 +581,19 @@ func (d *dexer) compileDex(ctx android.ModuleContext, dexParams *compileDexParam } useR8 := d.effectiveOptimizeEnabled() + useD8 := !useR8 || ctx.Config().PartialCompileFlags().Use_d8 + rbeR8 := ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_R8") + rbeD8 := ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_D8") + var rule blueprint.Rule + var description string var artProfileOutputPath *android.OutputPath + var implicitOutputs android.WritablePaths + var deps android.Paths + args := map[string]string{ + "zipFlags": zipFlags, + "outDir": outDir.String(), + "mergeZipsFlags": mergeZipsFlags, + } if useR8 { proguardDictionary := android.PathForModuleOut(ctx, "proguard_dictionary") d.proguardDictionary = android.OptionalPathForPath(proguardDictionary) @@ -489,83 +606,89 @@ 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) - implicitOutputs := android.WritablePaths{ + implicitOutputs = append(implicitOutputs, android.WritablePaths{ proguardDictionary, proguardUsageZip, proguardConfiguration, - } + }...) + description = "r8" debugMode := android.InList("--debug", commonFlags) r8Flags, r8Deps, r8ArtProfileOutputPath := d.r8Flags(ctx, dexParams, debugMode) - rule := r8 - args := map[string]string{ - "r8Flags": strings.Join(append(commonFlags, r8Flags...), " "), - "zipFlags": zipFlags, - "outDict": proguardDictionary.String(), - "outConfig": proguardConfiguration.String(), - "outUsageDir": proguardUsageDir.String(), - "outUsage": proguardUsage.String(), - "outUsageZip": proguardUsageZip.String(), - "outDir": outDir.String(), - "mergeZipsFlags": mergeZipsFlags, - } + deps = append(deps, r8Deps...) + args["r8Flags"] = strings.Join(append(commonFlags, r8Flags...), " ") 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(), ",") + args["outR8ArtProfile"] = r8ArtProfileOutputPath.String() } + args["outDict"] = proguardDictionary.String() + args["outConfig"] = proguardConfiguration.String() + args["outUsageDir"] = proguardUsageDir.String() + args["outUsage"] = proguardUsage.String() + args["outUsageZip"] = proguardUsageZip.String() if d.resourcesInput.Valid() { implicitOutputs = append(implicitOutputs, resourcesOutput) args["resourcesOutput"] = resourcesOutput.String() } - ctx.Build(pctx, android.BuildParams{ - Rule: rule, - Description: "r8", - Output: javalibJar, - ImplicitOutputs: implicitOutputs, - Input: dexParams.classesJar, - Implicits: r8Deps, - Args: args, - }) - } else { - implicitOutputs := android.WritablePaths{} + + rule = r8 + if rbeR8 { + rule = r8RE + args["implicits"] = strings.Join(deps.Strings(), ",") + } + } + if useD8 { + description = "d8" d8Flags, d8Deps, d8ArtProfileOutputPath := d.d8Flags(ctx, dexParams) + deps = append(deps, d8Deps...) + deps = append(deps, commonDeps...) + args["d8Flags"] = strings.Join(append(commonFlags, d8Flags...), " ") if d8ArtProfileOutputPath != nil { artProfileOutputPath = d8ArtProfileOutputPath - implicitOutputs = append( - implicitOutputs, - artProfileOutputPath, - ) } - d8Deps = append(d8Deps, commonDeps...) - rule := d8 - if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_D8") { + // If we are generating both d8 and r8, only use RBE when both are enabled. + switch { + case useR8 && rule == r8: + rule = d8r8 + description = "d8r8" + case useR8 && rule == r8RE && rbeD8: + rule = d8r8RE + description = "d8r8" + case rbeD8: rule = d8RE + default: + rule = d8 } + } + if artProfileOutputPath != nil { + implicitOutputs = append( + implicitOutputs, + artProfileOutputPath, + ) + } + ctx.Build(pctx, android.BuildParams{ + Rule: rule, + Description: description, + Output: javalibJar, + ImplicitOutputs: implicitOutputs, + Input: dexParams.classesJar, + Implicits: deps, + Args: args, + }) + if useR8 && useD8 { + // Generate the rule for partial compile clean. + args["builtOut"] = javalibJar.String() ctx.Build(pctx, android.BuildParams{ - 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(), - "mergeZipsFlags": mergeZipsFlags, - }, + Rule: d8r8Clean, + Description: "d8r8Clean", + Output: cleanPhonyPath, + Args: args, + PhonyOutput: true, }) + ctx.Phony("partialcompileclean", cleanPhonyPath) } + if proptools.Bool(d.dexProperties.Uncompress_dex) { alignedJavalibJar := android.PathForModuleOut(ctx, "aligned", dexParams.jarName).OutputPath TransformZipAlign(ctx, alignedJavalibJar, javalibJar, nil) @@ -574,3 +697,13 @@ func (d *dexer) compileDex(ctx android.ModuleContext, dexParams *compileDexParam return javalibJar, artProfileOutputPath } + +type ProguardInfo struct { + ModuleName string + Class string + ProguardDictionary android.Path + ProguardUsageZip android.Path + ClassesJar android.Path +} + +var ProguardProvider = blueprint.NewProvider[ProguardInfo]() |