export_proguard_spec for libs deps

Add a property to export proguard flags files for libs dependencies.
Currently only proguard flags files from static deps are propagated up
to reverse dependencies, but it is necessary sometimes to have flags
from libs dependencies also be propagated.

Bug: 289087274
Test: go test ./java
Change-Id: Ic0aa22b086792bf322041aa5780db6c4f4eb2770
This commit is contained in:
Sam Delmerico
2023-08-02 18:00:35 -04:00
parent 34a1c57b05
commit 95d709402a
6 changed files with 327 additions and 44 deletions

View File

@@ -29,7 +29,6 @@ import (
) )
type AndroidLibraryDependency interface { type AndroidLibraryDependency interface {
LibraryDependency
ExportPackage() android.Path ExportPackage() android.Path
ResourcesNodeDepSet() *android.DepSet[*resourcesNode] ResourcesNodeDepSet() *android.DepSet[*resourcesNode]
RRODirsDepSet() *android.DepSet[rroDir] RRODirsDepSet() *android.DepSet[rroDir]
@@ -777,17 +776,9 @@ func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext)
ctx.CheckbuildFile(a.aarFile) ctx.CheckbuildFile(a.aarFile)
} }
a.exportedProguardFlagFiles = append(a.exportedProguardFlagFiles, proguardSpecInfo := a.collectProguardSpecInfo(ctx)
android.PathsForModuleSrc(ctx, a.dexProperties.Optimize.Proguard_flags_files)...) ctx.SetProvider(ProguardSpecInfoProvider, proguardSpecInfo)
a.exportedProguardFlagFiles = proguardSpecInfo.ProguardFlagsFiles.ToList()
ctx.VisitDirectDeps(func(m android.Module) {
if ctx.OtherModuleDependencyTag(m) == staticLibTag {
if lib, ok := m.(LibraryDependency); ok {
a.exportedProguardFlagFiles = append(a.exportedProguardFlagFiles, lib.ExportedProguardFlagFiles()...)
}
}
})
a.exportedProguardFlagFiles = android.FirstUniquePaths(a.exportedProguardFlagFiles)
prebuiltJniPackages := android.Paths{} prebuiltJniPackages := android.Paths{}
ctx.VisitDirectDeps(func(module android.Module) { ctx.VisitDirectDeps(func(module android.Module) {
@@ -938,10 +929,6 @@ var _ AndroidLibraryDependency = (*AARImport)(nil)
func (a *AARImport) ExportPackage() android.Path { func (a *AARImport) ExportPackage() android.Path {
return a.exportPackage return a.exportPackage
} }
func (a *AARImport) ExportedProguardFlagFiles() android.Paths {
return android.Paths{a.proguardFlags}
}
func (a *AARImport) ResourcesNodeDepSet() *android.DepSet[*resourcesNode] { func (a *AARImport) ResourcesNodeDepSet() *android.DepSet[*resourcesNode] {
return a.resourcesNodesDepSet return a.resourcesNodesDepSet
} }
@@ -1045,10 +1032,17 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
extractedAARDir := android.PathForModuleOut(ctx, "aar") extractedAARDir := android.PathForModuleOut(ctx, "aar")
a.classpathFile = extractedAARDir.Join(ctx, "classes-combined.jar") a.classpathFile = extractedAARDir.Join(ctx, "classes-combined.jar")
a.proguardFlags = extractedAARDir.Join(ctx, "proguard.txt")
a.manifest = extractedAARDir.Join(ctx, "AndroidManifest.xml") a.manifest = extractedAARDir.Join(ctx, "AndroidManifest.xml")
aarRTxt := extractedAARDir.Join(ctx, "R.txt") aarRTxt := extractedAARDir.Join(ctx, "R.txt")
a.assetsPackage = android.PathForModuleOut(ctx, "assets.zip") a.assetsPackage = android.PathForModuleOut(ctx, "assets.zip")
a.proguardFlags = extractedAARDir.Join(ctx, "proguard.txt")
ctx.SetProvider(ProguardSpecInfoProvider, ProguardSpecInfo{
ProguardFlagsFiles: android.NewDepSet[android.Path](
android.POSTORDER,
android.Paths{a.proguardFlags},
nil,
),
})
ctx.Build(pctx, android.BuildParams{ ctx.Build(pctx, android.BuildParams{
Rule: unzipAAR, Rule: unzipAAR,

View File

@@ -200,10 +200,6 @@ func (a *AndroidApp) IsInstallable() bool {
return Bool(a.properties.Installable) return Bool(a.properties.Installable)
} }
func (a *AndroidApp) ExportedProguardFlagFiles() android.Paths {
return nil
}
func (a *AndroidApp) ResourcesNodeDepSet() *android.DepSet[*resourcesNode] { func (a *AndroidApp) ResourcesNodeDepSet() *android.DepSet[*resourcesNode] {
return a.aapt.resourcesNodesDepSet return a.aapt.resourcesNodesDepSet
} }
@@ -482,8 +478,10 @@ func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) {
func (a *AndroidApp) proguardBuildActions(ctx android.ModuleContext) { func (a *AndroidApp) proguardBuildActions(ctx android.ModuleContext) {
var staticLibProguardFlagFiles android.Paths var staticLibProguardFlagFiles android.Paths
ctx.VisitDirectDeps(func(m android.Module) { ctx.VisitDirectDeps(func(m android.Module) {
if lib, ok := m.(LibraryDependency); ok && ctx.OtherModuleDependencyTag(m) == staticLibTag { depProguardInfo := ctx.OtherModuleProvider(m, ProguardSpecInfoProvider).(ProguardSpecInfo)
staticLibProguardFlagFiles = append(staticLibProguardFlagFiles, lib.ExportedProguardFlagFiles()...) staticLibProguardFlagFiles = append(staticLibProguardFlagFiles, depProguardInfo.UnconditionallyExportedProguardFlags.ToList()...)
if ctx.OtherModuleDependencyTag(m) == staticLibTag {
staticLibProguardFlagFiles = append(staticLibProguardFlagFiles, depProguardInfo.ProguardFlagsFiles.ToList()...)
} }
}) })

View File

@@ -1670,6 +1670,49 @@ func (j *Module) useCompose() bool {
return android.InList("androidx.compose.runtime_runtime", j.properties.Static_libs) return android.InList("androidx.compose.runtime_runtime", j.properties.Static_libs)
} }
func (j *Module) collectProguardSpecInfo(ctx android.ModuleContext) ProguardSpecInfo {
transitiveUnconditionalExportedFlags := []*android.DepSet[android.Path]{}
transitiveProguardFlags := []*android.DepSet[android.Path]{}
ctx.VisitDirectDeps(func(m android.Module) {
depProguardInfo := ctx.OtherModuleProvider(m, ProguardSpecInfoProvider).(ProguardSpecInfo)
depTag := ctx.OtherModuleDependencyTag(m)
if depProguardInfo.UnconditionallyExportedProguardFlags != nil {
transitiveUnconditionalExportedFlags = append(transitiveUnconditionalExportedFlags, depProguardInfo.UnconditionallyExportedProguardFlags)
transitiveProguardFlags = append(transitiveProguardFlags, depProguardInfo.UnconditionallyExportedProguardFlags)
}
if depTag == staticLibTag && depProguardInfo.ProguardFlagsFiles != nil {
transitiveProguardFlags = append(transitiveProguardFlags, depProguardInfo.ProguardFlagsFiles)
}
})
directUnconditionalExportedFlags := android.Paths{}
proguardFlagsForThisModule := android.PathsForModuleSrc(ctx, j.dexProperties.Optimize.Proguard_flags_files)
exportUnconditionally := proptools.Bool(j.dexProperties.Optimize.Export_proguard_flags_files)
if exportUnconditionally {
// if we explicitly export, then our unconditional exports are the same as our transitive flags
transitiveUnconditionalExportedFlags = transitiveProguardFlags
directUnconditionalExportedFlags = proguardFlagsForThisModule
}
return ProguardSpecInfo{
Export_proguard_flags_files: exportUnconditionally,
ProguardFlagsFiles: android.NewDepSet[android.Path](
android.POSTORDER,
proguardFlagsForThisModule,
transitiveProguardFlags,
),
UnconditionallyExportedProguardFlags: android.NewDepSet[android.Path](
android.POSTORDER,
directUnconditionalExportedFlags,
transitiveUnconditionalExportedFlags,
),
}
}
// Returns a copy of the supplied flags, but with all the errorprone-related // Returns a copy of the supplied flags, but with all the errorprone-related
// fields copied to the regular build's fields. // fields copied to the regular build's fields.
func enableErrorproneFlags(flags javaBuilderFlags) javaBuilderFlags { func enableErrorproneFlags(flags javaBuilderFlags) javaBuilderFlags {

View File

@@ -71,6 +71,10 @@ type DexProperties struct {
// Specifies the locations of files containing proguard flags. // Specifies the locations of files containing proguard flags.
Proguard_flags_files []string `android:"path"` 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, // Keep the data uncompressed. We always need uncompressed dex for execution,

View File

@@ -15,6 +15,7 @@
package java package java
import ( import (
"fmt"
"testing" "testing"
"android/soong/android" "android/soong/android"
@@ -327,7 +328,7 @@ func TestD8(t *testing.T) {
fooD8.Args["d8Flags"], staticLibHeader.String()) fooD8.Args["d8Flags"], staticLibHeader.String())
} }
func TestProguardFlagsInheritance(t *testing.T) { func TestProguardFlagsInheritanceStatic(t *testing.T) {
result := PrepareForTestWithJavaDefaultModules.RunTestWithBp(t, ` result := PrepareForTestWithJavaDefaultModules.RunTestWithBp(t, `
android_app { android_app {
name: "app", name: "app",
@@ -380,3 +381,246 @@ func TestProguardFlagsInheritance(t *testing.T) {
android.AssertStringDoesContain(t, "expected tertiary_lib's proguard flags from inherited dep", android.AssertStringDoesContain(t, "expected tertiary_lib's proguard flags from inherited dep",
appR8.Args["r8Flags"], "tertiary.flags") appR8.Args["r8Flags"], "tertiary.flags")
} }
func TestProguardFlagsInheritance(t *testing.T) {
directDepFlagsFileName := "direct_dep.flags"
transitiveDepFlagsFileName := "transitive_dep.flags"
bp := `
android_app {
name: "app",
static_libs: ["androidlib"], // this must be static_libs to initate dexing
platform_apis: true,
}
android_library {
name: "androidlib",
static_libs: ["app_dep"],
}
java_library {
name: "app_dep",
%s: ["dep"],
}
java_library {
name: "dep",
%s: ["transitive_dep"],
optimize: {
proguard_flags_files: ["direct_dep.flags"],
export_proguard_flags_files: %v,
},
}
java_library {
name: "transitive_dep",
optimize: {
proguard_flags_files: ["transitive_dep.flags"],
export_proguard_flags_files: %v,
},
}
`
testcases := []struct {
name string
depType string
depExportsFlagsFiles bool
transitiveDepType string
transitiveDepExportsFlagsFiles bool
expectedFlagsFiles []string
}{
{
name: "libs_export_libs_export",
depType: "libs",
depExportsFlagsFiles: true,
transitiveDepType: "libs",
transitiveDepExportsFlagsFiles: true,
expectedFlagsFiles: []string{directDepFlagsFileName, transitiveDepFlagsFileName},
},
{
name: "static_export_libs_export",
depType: "static_libs",
depExportsFlagsFiles: true,
transitiveDepType: "libs",
transitiveDepExportsFlagsFiles: true,
expectedFlagsFiles: []string{directDepFlagsFileName, transitiveDepFlagsFileName},
},
{
name: "libs_no-export_static_export",
depType: "libs",
depExportsFlagsFiles: false,
transitiveDepType: "static_libs",
transitiveDepExportsFlagsFiles: true,
expectedFlagsFiles: []string{transitiveDepFlagsFileName},
},
{
name: "static_no-export_static_export",
depType: "static_libs",
depExportsFlagsFiles: false,
transitiveDepType: "static_libs",
transitiveDepExportsFlagsFiles: true,
expectedFlagsFiles: []string{directDepFlagsFileName, transitiveDepFlagsFileName},
},
{
name: "libs_export_libs_no-export",
depType: "libs",
depExportsFlagsFiles: true,
transitiveDepType: "libs",
transitiveDepExportsFlagsFiles: false,
expectedFlagsFiles: []string{directDepFlagsFileName},
},
{
name: "static_export_libs_no-export",
depType: "static_libs",
depExportsFlagsFiles: true,
transitiveDepType: "libs",
transitiveDepExportsFlagsFiles: false,
expectedFlagsFiles: []string{directDepFlagsFileName},
},
{
name: "libs_no-export_static_no-export",
depType: "libs",
depExportsFlagsFiles: false,
transitiveDepType: "static_libs",
transitiveDepExportsFlagsFiles: false,
expectedFlagsFiles: []string{},
},
{
name: "static_no-export_static_no-export",
depType: "static_libs",
depExportsFlagsFiles: false,
transitiveDepType: "static_libs",
transitiveDepExportsFlagsFiles: false,
expectedFlagsFiles: []string{directDepFlagsFileName, transitiveDepFlagsFileName},
},
{
name: "libs_no-export_libs_export",
depType: "libs",
depExportsFlagsFiles: false,
transitiveDepType: "libs",
transitiveDepExportsFlagsFiles: true,
expectedFlagsFiles: []string{transitiveDepFlagsFileName},
},
{
name: "static_no-export_libs_export",
depType: "static_libs",
depExportsFlagsFiles: false,
transitiveDepType: "libs",
transitiveDepExportsFlagsFiles: true,
expectedFlagsFiles: []string{directDepFlagsFileName, transitiveDepFlagsFileName},
},
{
name: "libs_export_static_export",
depType: "libs",
depExportsFlagsFiles: true,
transitiveDepType: "static_libs",
transitiveDepExportsFlagsFiles: true,
expectedFlagsFiles: []string{directDepFlagsFileName, transitiveDepFlagsFileName},
},
{
name: "static_export_static_export",
depType: "static_libs",
depExportsFlagsFiles: true,
transitiveDepType: "static_libs",
transitiveDepExportsFlagsFiles: true,
expectedFlagsFiles: []string{directDepFlagsFileName, transitiveDepFlagsFileName},
},
{
name: "libs_no-export_libs_no-export",
depType: "libs",
depExportsFlagsFiles: false,
transitiveDepType: "libs",
transitiveDepExportsFlagsFiles: false,
expectedFlagsFiles: []string{},
},
{
name: "static_no-export_libs_no-export",
depType: "static_libs",
depExportsFlagsFiles: false,
transitiveDepType: "libs",
transitiveDepExportsFlagsFiles: false,
expectedFlagsFiles: []string{directDepFlagsFileName},
},
{
name: "libs_export_static_no-export",
depType: "libs",
depExportsFlagsFiles: true,
transitiveDepType: "static_libs",
transitiveDepExportsFlagsFiles: false,
expectedFlagsFiles: []string{directDepFlagsFileName, transitiveDepFlagsFileName},
},
{
name: "static_export_static_no-export",
depType: "static_libs",
depExportsFlagsFiles: true,
transitiveDepType: "static_libs",
transitiveDepExportsFlagsFiles: false,
expectedFlagsFiles: []string{directDepFlagsFileName, transitiveDepFlagsFileName},
},
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
result := android.GroupFixturePreparers(
PrepareForTestWithJavaDefaultModules,
android.FixtureMergeMockFs(android.MockFS{
directDepFlagsFileName: nil,
transitiveDepFlagsFileName: nil,
}),
).RunTestWithBp(t,
fmt.Sprintf(
bp,
tc.depType,
tc.transitiveDepType,
tc.depExportsFlagsFiles,
tc.transitiveDepExportsFlagsFiles,
),
)
appR8 := result.ModuleForTests("app", "android_common").Rule("r8")
shouldHaveDepFlags := android.InList(directDepFlagsFileName, tc.expectedFlagsFiles)
if shouldHaveDepFlags {
android.AssertStringDoesContain(t, "expected deps's proguard flags",
appR8.Args["r8Flags"], directDepFlagsFileName)
} else {
android.AssertStringDoesNotContain(t, "app did not expect deps's proguard flags",
appR8.Args["r8Flags"], directDepFlagsFileName)
}
shouldHaveTransitiveDepFlags := android.InList(transitiveDepFlagsFileName, tc.expectedFlagsFiles)
if shouldHaveTransitiveDepFlags {
android.AssertStringDoesContain(t, "expected transitive deps's proguard flags",
appR8.Args["r8Flags"], transitiveDepFlagsFileName)
} else {
android.AssertStringDoesNotContain(t, "app did not expect transitive deps's proguard flags",
appR8.Args["r8Flags"], transitiveDepFlagsFileName)
}
})
}
}
func TestProguardFlagsInheritanceAppImport(t *testing.T) {
bp := `
android_app {
name: "app",
static_libs: ["aarimport"], // this must be static_libs to initate dexing
platform_apis: true,
}
android_library {
name: "androidlib",
static_libs: ["aarimport"],
}
android_library_import {
name: "aarimport",
aars: ["import.aar"],
}
`
result := android.GroupFixturePreparers(
PrepareForTestWithJavaDefaultModules,
).RunTestWithBp(t, bp)
appR8 := result.ModuleForTests("app", "android_common").Rule("r8")
android.AssertStringDoesContain(t, "expected aarimports's proguard flags",
appR8.Args["r8Flags"], "proguard.txt")
}

View File

@@ -225,6 +225,23 @@ var (
}, "jar_name", "partition", "main_class") }, "jar_name", "partition", "main_class")
) )
type ProguardSpecInfo struct {
// If true, proguard flags files will be exported to reverse dependencies across libs edges
// If false, proguard flags files will only be exported to reverse dependencies across
// static_libs edges.
Export_proguard_flags_files bool
// TransitiveDepsProguardSpecFiles is a depset of paths to proguard flags files that are exported from
// all transitive deps. This list includes all proguard flags files from transitive static dependencies,
// and all proguard flags files from transitive libs dependencies which set `export_proguard_spec: true`.
ProguardFlagsFiles *android.DepSet[android.Path]
// implementation detail to store transitive proguard flags files from exporting shared deps
UnconditionallyExportedProguardFlags *android.DepSet[android.Path]
}
var ProguardSpecInfoProvider = blueprint.NewProvider(ProguardSpecInfo{})
// JavaInfo contains information about a java module for use by modules that depend on it. // JavaInfo contains information about a java module for use by modules that depend on it.
type JavaInfo struct { type JavaInfo struct {
// HeaderJars is a list of jars that can be passed as the javac classpath in order to link // HeaderJars is a list of jars that can be passed as the javac classpath in order to link
@@ -310,11 +327,6 @@ type UsesLibraryDependency interface {
ClassLoaderContexts() dexpreopt.ClassLoaderContextMap ClassLoaderContexts() dexpreopt.ClassLoaderContextMap
} }
// Provides transitive Proguard flag files to downstream DEX jars.
type LibraryDependency interface {
ExportedProguardFlagFiles() android.Paths
}
// TODO(jungjw): Move this to kythe.go once it's created. // TODO(jungjw): Move this to kythe.go once it's created.
type xref interface { type xref interface {
XrefJavaFiles() android.Paths XrefJavaFiles() android.Paths
@@ -626,12 +638,6 @@ type Library struct {
InstallMixin func(ctx android.ModuleContext, installPath android.Path) (extraInstallDeps android.Paths) InstallMixin func(ctx android.ModuleContext, installPath android.Path) (extraInstallDeps android.Paths)
} }
var _ LibraryDependency = (*Library)(nil)
func (j *Library) ExportedProguardFlagFiles() android.Paths {
return j.exportedProguardFlagFiles
}
var _ android.ApexModule = (*Library)(nil) var _ android.ApexModule = (*Library)(nil)
// Provides access to the list of permitted packages from apex boot jars. // Provides access to the list of permitted packages from apex boot jars.
@@ -730,15 +736,9 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) {
j.installFile = ctx.InstallFile(installDir, j.Stem()+".jar", j.outputFile, extraInstallDeps...) j.installFile = ctx.InstallFile(installDir, j.Stem()+".jar", j.outputFile, extraInstallDeps...)
} }
j.exportedProguardFlagFiles = append(j.exportedProguardFlagFiles, proguardSpecInfo := j.collectProguardSpecInfo(ctx)
android.PathsForModuleSrc(ctx, j.dexProperties.Optimize.Proguard_flags_files)...) ctx.SetProvider(ProguardSpecInfoProvider, proguardSpecInfo)
ctx.VisitDirectDeps(func(m android.Module) { j.exportedProguardFlagFiles = proguardSpecInfo.ProguardFlagsFiles.ToList()
if lib, ok := m.(LibraryDependency); ok && ctx.OtherModuleDependencyTag(m) == staticLibTag {
j.exportedProguardFlagFiles = append(j.exportedProguardFlagFiles, lib.ExportedProguardFlagFiles()...)
}
})
j.exportedProguardFlagFiles = android.FirstUniquePaths(j.exportedProguardFlagFiles)
} }
func (j *Library) DepsMutator(ctx android.BottomUpMutatorContext) { func (j *Library) DepsMutator(ctx android.BottomUpMutatorContext) {