Merge "Use R8 for resource shrinking" into main

This commit is contained in:
Rico Wind 2023-11-03 07:29:45 +00:00 committed by Gerrit Code Review
commit 4ea88503e4
6 changed files with 46 additions and 124 deletions

View file

@ -66,7 +66,6 @@ bootstrap_go_package {
"plugin.go", "plugin.go",
"prebuilt_apis.go", "prebuilt_apis.go",
"proto.go", "proto.go",
"resourceshrinker.go",
"robolectric.go", "robolectric.go",
"rro.go", "rro.go",
"sdk.go", "sdk.go",
@ -106,7 +105,6 @@ bootstrap_go_package {
"plugin_test.go", "plugin_test.go",
"prebuilt_apis_test.go", "prebuilt_apis_test.go",
"proto_test.go", "proto_test.go",
"resourceshrinker_test.go",
"rro_test.go", "rro_test.go",
"sdk_test.go", "sdk_test.go",
"sdk_library_test.go", "sdk_library_test.go",

View file

@ -532,7 +532,7 @@ func (a *AndroidApp) installPath(ctx android.ModuleContext) android.InstallPath
return android.PathForModuleInstall(ctx, installDir, a.installApkName+".apk") return android.PathForModuleInstall(ctx, installDir, a.installApkName+".apk")
} }
func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) android.Path { func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) (android.Path, android.Path) {
a.dexpreopter.installPath = a.installPath(ctx) a.dexpreopter.installPath = a.installPath(ctx)
a.dexpreopter.isApp = true a.dexpreopter.isApp = true
if a.dexProperties.Uncompress_dex == nil { if a.dexProperties.Uncompress_dex == nil {
@ -545,7 +545,15 @@ func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) android.Path {
a.dexpreopter.manifestFile = a.mergedManifestFile a.dexpreopter.manifestFile = a.mergedManifestFile
a.dexpreopter.preventInstall = a.appProperties.PreventInstall a.dexpreopter.preventInstall = a.appProperties.PreventInstall
var packageResources = a.exportPackage
if ctx.ModuleName() != "framework-res" { if ctx.ModuleName() != "framework-res" {
if Bool(a.dexProperties.Optimize.Shrink_resources) {
protoFile := android.PathForModuleOut(ctx, packageResources.Base()+".proto.apk")
aapt2Convert(ctx, protoFile, packageResources, "proto")
a.dexer.resourcesInput = android.OptionalPathForPath(protoFile)
}
var extraSrcJars android.Paths var extraSrcJars android.Paths
var extraClasspathJars android.Paths var extraClasspathJars android.Paths
var extraCombinedJars android.Paths var extraCombinedJars android.Paths
@ -563,9 +571,14 @@ func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) android.Path {
} }
a.Module.compile(ctx, extraSrcJars, extraClasspathJars, extraCombinedJars) a.Module.compile(ctx, extraSrcJars, extraClasspathJars, extraCombinedJars)
if Bool(a.dexProperties.Optimize.Shrink_resources) {
binaryResources := android.PathForModuleOut(ctx, packageResources.Base()+".binary.out.apk")
aapt2Convert(ctx, binaryResources, a.dexer.resourcesOutput.Path(), "binary")
packageResources = binaryResources
}
} }
return a.dexJarFile.PathOrNil() return a.dexJarFile.PathOrNil(), packageResources
} }
func (a *AndroidApp) jniBuildActions(jniLibs []jniLib, prebuiltJniPackages android.Paths, ctx android.ModuleContext) android.WritablePath { func (a *AndroidApp) jniBuildActions(jniLibs []jniLib, prebuiltJniPackages android.Paths, ctx android.ModuleContext) android.WritablePath {
@ -750,7 +763,6 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) {
// Process all building blocks, from AAPT to certificates. // Process all building blocks, from AAPT to certificates.
a.aaptBuildActions(ctx) a.aaptBuildActions(ctx)
// The decision to enforce <uses-library> checks is made before adding implicit SDK libraries. // The decision to enforce <uses-library> checks is made before adding implicit SDK libraries.
a.usesLibrary.freezeEnforceUsesLibraries() a.usesLibrary.freezeEnforceUsesLibraries()
@ -776,7 +788,7 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) {
a.linter.resources = a.aapt.resourceFiles a.linter.resources = a.aapt.resourceFiles
a.linter.buildModuleReportZip = ctx.Config().UnbundledBuildApps() a.linter.buildModuleReportZip = ctx.Config().UnbundledBuildApps()
dexJarFile := a.dexBuildActions(ctx) dexJarFile, packageResources := a.dexBuildActions(ctx)
jniLibs, prebuiltJniPackages, certificates := collectAppDeps(ctx, a, a.shouldEmbedJnis(ctx), !Bool(a.appProperties.Jni_uses_platform_apis)) jniLibs, prebuiltJniPackages, certificates := collectAppDeps(ctx, a, a.shouldEmbedJnis(ctx), !Bool(a.appProperties.Jni_uses_platform_apis))
jniJarFile := a.jniBuildActions(jniLibs, prebuiltJniPackages, ctx) jniJarFile := a.jniBuildActions(jniLibs, prebuiltJniPackages, ctx)
@ -800,7 +812,7 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) {
} }
rotationMinSdkVersion := String(a.overridableAppProperties.RotationMinSdkVersion) rotationMinSdkVersion := String(a.overridableAppProperties.RotationMinSdkVersion)
CreateAndSignAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, dexJarFile, certificates, apkDeps, v4SignatureFile, lineageFile, rotationMinSdkVersion, Bool(a.dexProperties.Optimize.Shrink_resources)) CreateAndSignAppPackage(ctx, packageFile, packageResources, jniJarFile, dexJarFile, certificates, apkDeps, v4SignatureFile, lineageFile, rotationMinSdkVersion)
a.outputFile = packageFile a.outputFile = packageFile
if v4SigningRequested { if v4SigningRequested {
a.extraOutputFiles = append(a.extraOutputFiles, v4SignatureFile) a.extraOutputFiles = append(a.extraOutputFiles, v4SignatureFile)
@ -829,7 +841,7 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) {
if v4SigningRequested { if v4SigningRequested {
v4SignatureFile = android.PathForModuleOut(ctx, a.installApkName+"_"+split.suffix+".apk.idsig") v4SignatureFile = android.PathForModuleOut(ctx, a.installApkName+"_"+split.suffix+".apk.idsig")
} }
CreateAndSignAppPackage(ctx, packageFile, split.path, nil, nil, certificates, apkDeps, v4SignatureFile, lineageFile, rotationMinSdkVersion, false) CreateAndSignAppPackage(ctx, packageFile, split.path, nil, nil, certificates, apkDeps, v4SignatureFile, lineageFile, rotationMinSdkVersion)
a.extraOutputFiles = append(a.extraOutputFiles, packageFile) a.extraOutputFiles = append(a.extraOutputFiles, packageFile)
if v4SigningRequested { if v4SigningRequested {
a.extraOutputFiles = append(a.extraOutputFiles, v4SignatureFile) a.extraOutputFiles = append(a.extraOutputFiles, v4SignatureFile)

View file

@ -52,7 +52,7 @@ var combineApk = pctx.AndroidStaticRule("combineApk",
}) })
func CreateAndSignAppPackage(ctx android.ModuleContext, outputFile android.WritablePath, func CreateAndSignAppPackage(ctx android.ModuleContext, outputFile android.WritablePath,
packageFile, jniJarFile, dexJarFile android.Path, certificates []Certificate, deps android.Paths, v4SignatureFile android.WritablePath, lineageFile android.Path, rotationMinSdkVersion string, shrinkResources bool) { packageFile, jniJarFile, dexJarFile android.Path, certificates []Certificate, deps android.Paths, v4SignatureFile android.WritablePath, lineageFile android.Path, rotationMinSdkVersion string) {
unsignedApkName := strings.TrimSuffix(outputFile.Base(), ".apk") + "-unsigned.apk" unsignedApkName := strings.TrimSuffix(outputFile.Base(), ".apk") + "-unsigned.apk"
unsignedApk := android.PathForModuleOut(ctx, unsignedApkName) unsignedApk := android.PathForModuleOut(ctx, unsignedApkName)
@ -71,12 +71,6 @@ func CreateAndSignAppPackage(ctx android.ModuleContext, outputFile android.Writa
Output: unsignedApk, Output: unsignedApk,
Implicits: deps, Implicits: deps,
}) })
if shrinkResources {
shrunkenApk := android.PathForModuleOut(ctx, "resource-shrunken", unsignedApk.Base())
ShrinkResources(ctx, unsignedApk, shrunkenApk)
unsignedApk = shrunkenApk
}
SignAppPackage(ctx, outputFile, unsignedApk, certificates, v4SignatureFile, lineageFile, rotationMinSdkVersion) SignAppPackage(ctx, outputFile, unsignedApk, certificates, v4SignatureFile, lineageFile, rotationMinSdkVersion)
} }

View file

@ -95,6 +95,8 @@ type dexer struct {
proguardDictionary android.OptionalPath proguardDictionary android.OptionalPath
proguardConfiguration android.OptionalPath proguardConfiguration android.OptionalPath
proguardUsageZip android.OptionalPath proguardUsageZip android.OptionalPath
resourcesInput android.OptionalPath
resourcesOutput android.OptionalPath
providesTransitiveHeaderJars providesTransitiveHeaderJars
} }
@ -161,7 +163,7 @@ var r8, r8RE = pctx.MultiCommandRemoteStaticRules("r8",
"$r8Template": &remoteexec.REParams{ "$r8Template": &remoteexec.REParams{
Labels: map[string]string{"type": "compile", "compiler": "r8"}, Labels: map[string]string{"type": "compile", "compiler": "r8"},
Inputs: []string{"$implicits", "${config.R8Jar}"}, Inputs: []string{"$implicits", "${config.R8Jar}"},
OutputFiles: []string{"${outUsage}", "${outConfig}", "${outDict}"}, OutputFiles: []string{"${outUsage}", "${outConfig}", "${outDict}", "${resourcesOutput}"},
ExecStrategy: "${config.RER8ExecStrategy}", ExecStrategy: "${config.RER8ExecStrategy}",
ToolchainInputs: []string{"${config.JavaCmd}"}, ToolchainInputs: []string{"${config.JavaCmd}"},
Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
@ -181,7 +183,7 @@ var r8, r8RE = pctx.MultiCommandRemoteStaticRules("r8",
Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
}, },
}, []string{"outDir", "outDict", "outConfig", "outUsage", "outUsageZip", "outUsageDir", }, []string{"outDir", "outDict", "outConfig", "outUsage", "outUsageZip", "outUsageDir",
"r8Flags", "zipFlags", "mergeZipsFlags"}, []string{"implicits"}) "r8Flags", "zipFlags", "mergeZipsFlags", "resourcesOutput"}, []string{"implicits"})
func (d *dexer) dexCommonFlags(ctx android.ModuleContext, func (d *dexer) dexCommonFlags(ctx android.ModuleContext,
dexParams *compileDexParams) (flags []string, deps android.Paths) { dexParams *compileDexParams) (flags []string, deps android.Paths) {
@ -350,6 +352,12 @@ func (d *dexer) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8Fl
r8Flags = append(r8Flags, "-ignorewarnings") r8Flags = append(r8Flags, "-ignorewarnings")
} }
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())
}
return r8Flags, r8Deps return r8Flags, r8Deps
} }
@ -391,6 +399,8 @@ func (d *dexer) compileDex(ctx android.ModuleContext, dexParams *compileDexParam
android.ModuleNameWithPossibleOverride(ctx), "unused.txt") android.ModuleNameWithPossibleOverride(ctx), "unused.txt")
proguardUsageZip := android.PathForModuleOut(ctx, "proguard_usage.zip") proguardUsageZip := android.PathForModuleOut(ctx, "proguard_usage.zip")
d.proguardUsageZip = android.OptionalPathForPath(proguardUsageZip) 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) r8Flags, r8Deps := d.r8Flags(ctx, dexParams.flags)
r8Deps = append(r8Deps, commonDeps...) r8Deps = append(r8Deps, commonDeps...)
rule := r8 rule := r8
@ -409,17 +419,22 @@ func (d *dexer) compileDex(ctx android.ModuleContext, dexParams *compileDexParam
rule = r8RE rule = r8RE
args["implicits"] = strings.Join(r8Deps.Strings(), ",") args["implicits"] = strings.Join(r8Deps.Strings(), ",")
} }
implicitOutputs := android.WritablePaths{
proguardDictionary,
proguardUsageZip,
proguardConfiguration}
if d.resourcesInput.Valid() {
implicitOutputs = append(implicitOutputs, resourcesOutput)
args["resourcesOutput"] = resourcesOutput.String()
}
ctx.Build(pctx, android.BuildParams{ ctx.Build(pctx, android.BuildParams{
Rule: rule, Rule: rule,
Description: "r8", Description: "r8",
Output: javalibJar, Output: javalibJar,
ImplicitOutputs: android.WritablePaths{ ImplicitOutputs: implicitOutputs,
proguardDictionary, Input: dexParams.classesJar,
proguardUsageZip, Implicits: r8Deps,
proguardConfiguration}, Args: args,
Input: dexParams.classesJar,
Implicits: r8Deps,
Args: args,
}) })
} else { } else {
d8Flags, d8Deps := d8Flags(dexParams.flags) d8Flags, d8Deps := d8Flags(dexParams.flags)

View file

@ -1,44 +0,0 @@
// Copyright 2022 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package java
import (
"android/soong/android"
"github.com/google/blueprint"
)
var shrinkResources = pctx.AndroidStaticRule("shrinkResources",
blueprint.RuleParams{
// Note that we suppress stdout to avoid successful log confirmations.
Command: `${config.ResourceShrinkerCmd} --output $out --input $in --raw_resources $raw_resources >/dev/null`,
CommandDeps: []string{"${config.ResourceShrinkerCmd}"},
}, "raw_resources")
func ShrinkResources(ctx android.ModuleContext, apk android.Path, outputFile android.WritablePath) {
protoFile := android.PathForModuleOut(ctx, apk.Base()+".proto.apk")
aapt2Convert(ctx, protoFile, apk, "proto")
strictModeFile := android.PathForSource(ctx, "prebuilts/cmdline-tools/shrinker.xml")
protoOut := android.PathForModuleOut(ctx, apk.Base()+".proto.out.apk")
ctx.Build(pctx, android.BuildParams{
Rule: shrinkResources,
Input: protoFile,
Output: protoOut,
Args: map[string]string{
"raw_resources": strictModeFile.String(),
},
})
aapt2Convert(ctx, outputFile, protoOut, "binary")
}

View file

@ -1,53 +0,0 @@
// Copyright 2022 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package java
import (
"testing"
"android/soong/android"
)
func TestShrinkResourcesArgs(t *testing.T) {
result := android.GroupFixturePreparers(
PrepareForTestWithJavaDefaultModules,
).RunTestWithBp(t, `
android_app {
name: "app_shrink",
platform_apis: true,
optimize: {
shrink_resources: true,
}
}
android_app {
name: "app_no_shrink",
platform_apis: true,
optimize: {
shrink_resources: false,
}
}
`)
appShrink := result.ModuleForTests("app_shrink", "android_common")
appShrinkResources := appShrink.Rule("shrinkResources")
android.AssertStringDoesContain(t, "expected shrinker.xml in app_shrink resource shrinker flags",
appShrinkResources.Args["raw_resources"], "shrinker.xml")
appNoShrink := result.ModuleForTests("app_no_shrink", "android_common")
if appNoShrink.MaybeRule("shrinkResources").Rule != nil {
t.Errorf("unexpected shrinkResources rule for app_no_shrink")
}
}