diff --git a/java/Android.bp b/java/Android.bp index cf968713c..9f42771a0 100644 --- a/java/Android.bp +++ b/java/Android.bp @@ -67,7 +67,6 @@ bootstrap_go_package { "plugin.go", "prebuilt_apis.go", "proto.go", - "resourceshrinker.go", "robolectric.go", "rro.go", "sdk.go", @@ -107,7 +106,6 @@ bootstrap_go_package { "plugin_test.go", "prebuilt_apis_test.go", "proto_test.go", - "resourceshrinker_test.go", "rro_test.go", "sdk_test.go", "sdk_library_test.go", diff --git a/java/app.go b/java/app.go index 6d7411d47..6ec6bb273 100755 --- a/java/app.go +++ b/java/app.go @@ -544,7 +544,7 @@ func (a *AndroidApp) installPath(ctx android.ModuleContext) android.InstallPath 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.isApp = true if a.dexProperties.Uncompress_dex == nil { @@ -557,7 +557,15 @@ func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) android.Path { a.dexpreopter.manifestFile = a.mergedManifestFile a.dexpreopter.preventInstall = a.appProperties.PreventInstall + var packageResources = a.exportPackage + 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 extraClasspathJars android.Paths var extraCombinedJars android.Paths @@ -575,9 +583,14 @@ func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) android.Path { } 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 { @@ -762,7 +775,6 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { // Process all building blocks, from AAPT to certificates. a.aaptBuildActions(ctx) - // The decision to enforce checks is made before adding implicit SDK libraries. a.usesLibrary.freezeEnforceUsesLibraries() @@ -788,7 +800,7 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { a.linter.resources = a.aapt.resourceFiles 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)) jniJarFile := a.jniBuildActions(jniLibs, prebuiltJniPackages, ctx) @@ -812,7 +824,7 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { } 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 if v4SigningRequested { a.extraOutputFiles = append(a.extraOutputFiles, v4SignatureFile) @@ -841,7 +853,7 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { if v4SigningRequested { 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) if v4SigningRequested { a.extraOutputFiles = append(a.extraOutputFiles, v4SignatureFile) diff --git a/java/app_builder.go b/java/app_builder.go index d397ff7f5..943ce317b 100644 --- a/java/app_builder.go +++ b/java/app_builder.go @@ -52,7 +52,7 @@ var combineApk = pctx.AndroidStaticRule("combineApk", }) 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" unsignedApk := android.PathForModuleOut(ctx, unsignedApkName) @@ -71,12 +71,6 @@ func CreateAndSignAppPackage(ctx android.ModuleContext, outputFile android.Writa Output: unsignedApk, 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) } diff --git a/java/dex.go b/java/dex.go index 8af06d530..5d8f5163f 100644 --- a/java/dex.go +++ b/java/dex.go @@ -95,6 +95,8 @@ type dexer struct { proguardDictionary android.OptionalPath proguardConfiguration android.OptionalPath proguardUsageZip android.OptionalPath + resourcesInput android.OptionalPath + resourcesOutput android.OptionalPath providesTransitiveHeaderJars } @@ -160,7 +162,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}", "${outConfig}", "${outDict}"}, + OutputFiles: []string{"${outUsage}", "${outConfig}", "${outDict}", "${resourcesOutput}"}, ExecStrategy: "${config.RER8ExecStrategy}", ToolchainInputs: []string{"${config.JavaCmd}"}, Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, @@ -180,7 +182,7 @@ var r8, r8RE = pctx.MultiCommandRemoteStaticRules("r8", Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, }, }, []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, dexParams *compileDexParams) (flags []string, deps android.Paths) { @@ -354,6 +356,12 @@ func (d *dexer) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8Fl 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 } @@ -395,6 +403,8 @@ 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) + resourcesOutput := android.PathForModuleOut(ctx, "package-res-shrunken.apk") + d.resourcesOutput = android.OptionalPathForPath(resourcesOutput) r8Flags, r8Deps := d.r8Flags(ctx, dexParams.flags) r8Deps = append(r8Deps, commonDeps...) rule := r8 @@ -413,17 +423,22 @@ 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() + } ctx.Build(pctx, android.BuildParams{ - Rule: rule, - Description: "r8", - Output: javalibJar, - ImplicitOutputs: android.WritablePaths{ - proguardDictionary, - proguardUsageZip, - proguardConfiguration}, - Input: dexParams.classesJar, - Implicits: r8Deps, - Args: args, + Rule: rule, + Description: "r8", + Output: javalibJar, + ImplicitOutputs: implicitOutputs, + Input: dexParams.classesJar, + Implicits: r8Deps, + Args: args, }) } else { d8Flags, d8Deps := d8Flags(dexParams.flags) diff --git a/java/resourceshrinker.go b/java/resourceshrinker.go deleted file mode 100644 index af13aa3cb..000000000 --- a/java/resourceshrinker.go +++ /dev/null @@ -1,45 +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: `RESOURCESHRINKER_OPTS=-Dcom.android.tools.r8.dexContainerExperiment ` + - `${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") -} diff --git a/java/resourceshrinker_test.go b/java/resourceshrinker_test.go deleted file mode 100644 index 3bbf11670..000000000 --- a/java/resourceshrinker_test.go +++ /dev/null @@ -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") - } -}