Merge "export_proguard_spec for libs deps" into main

This commit is contained in:
Treehugger Robot 2023-08-18 18:17:19 +00:00 committed by Gerrit Code Review
commit b4cd93ccc0
6 changed files with 327 additions and 44 deletions

View file

@ -30,7 +30,6 @@ import (
)
type AndroidLibraryDependency interface {
LibraryDependency
ExportPackage() android.Path
ResourcesNodeDepSet() *android.DepSet[*resourcesNode]
RRODirsDepSet() *android.DepSet[rroDir]
@ -778,17 +777,9 @@ func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext)
ctx.CheckbuildFile(a.aarFile)
}
a.exportedProguardFlagFiles = append(a.exportedProguardFlagFiles,
android.PathsForModuleSrc(ctx, a.dexProperties.Optimize.Proguard_flags_files)...)
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)
proguardSpecInfo := a.collectProguardSpecInfo(ctx)
ctx.SetProvider(ProguardSpecInfoProvider, proguardSpecInfo)
a.exportedProguardFlagFiles = proguardSpecInfo.ProguardFlagsFiles.ToList()
prebuiltJniPackages := android.Paths{}
ctx.VisitDirectDeps(func(module android.Module) {
@ -939,10 +930,6 @@ var _ AndroidLibraryDependency = (*AARImport)(nil)
func (a *AARImport) ExportPackage() android.Path {
return a.exportPackage
}
func (a *AARImport) ExportedProguardFlagFiles() android.Paths {
return android.Paths{a.proguardFlags}
}
func (a *AARImport) ResourcesNodeDepSet() *android.DepSet[*resourcesNode] {
return a.resourcesNodesDepSet
}
@ -1046,10 +1033,17 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
extractedAARDir := android.PathForModuleOut(ctx, "aar")
a.classpathFile = extractedAARDir.Join(ctx, "classes-combined.jar")
a.proguardFlags = extractedAARDir.Join(ctx, "proguard.txt")
a.manifest = extractedAARDir.Join(ctx, "AndroidManifest.xml")
aarRTxt := extractedAARDir.Join(ctx, "R.txt")
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{
Rule: unzipAAR,

View file

@ -200,10 +200,6 @@ func (a *AndroidApp) IsInstallable() bool {
return Bool(a.properties.Installable)
}
func (a *AndroidApp) ExportedProguardFlagFiles() android.Paths {
return nil
}
func (a *AndroidApp) ResourcesNodeDepSet() *android.DepSet[*resourcesNode] {
return a.aapt.resourcesNodesDepSet
}
@ -482,8 +478,10 @@ func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) {
func (a *AndroidApp) proguardBuildActions(ctx android.ModuleContext) {
var staticLibProguardFlagFiles android.Paths
ctx.VisitDirectDeps(func(m android.Module) {
if lib, ok := m.(LibraryDependency); ok && ctx.OtherModuleDependencyTag(m) == staticLibTag {
staticLibProguardFlagFiles = append(staticLibProguardFlagFiles, lib.ExportedProguardFlagFiles()...)
depProguardInfo := ctx.OtherModuleProvider(m, ProguardSpecInfoProvider).(ProguardSpecInfo)
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)
}
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
// fields copied to the regular build's fields.
func enableErrorproneFlags(flags javaBuilderFlags) javaBuilderFlags {

View file

@ -71,6 +71,10 @@ type DexProperties struct {
// 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,

View file

@ -15,6 +15,7 @@
package java
import (
"fmt"
"testing"
"android/soong/android"
@ -327,7 +328,7 @@ func TestD8(t *testing.T) {
fooD8.Args["d8Flags"], staticLibHeader.String())
}
func TestProguardFlagsInheritance(t *testing.T) {
func TestProguardFlagsInheritanceStatic(t *testing.T) {
result := PrepareForTestWithJavaDefaultModules.RunTestWithBp(t, `
android_app {
name: "app",
@ -380,3 +381,246 @@ func TestProguardFlagsInheritance(t *testing.T) {
android.AssertStringDoesContain(t, "expected tertiary_lib's proguard flags from inherited dep",
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")
)
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.
type JavaInfo struct {
// 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
}
// 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.
type xref interface {
XrefJavaFiles() android.Paths
@ -626,12 +638,6 @@ type Library struct {
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)
// 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.exportedProguardFlagFiles = append(j.exportedProguardFlagFiles,
android.PathsForModuleSrc(ctx, j.dexProperties.Optimize.Proguard_flags_files)...)
ctx.VisitDirectDeps(func(m android.Module) {
if lib, ok := m.(LibraryDependency); ok && ctx.OtherModuleDependencyTag(m) == staticLibTag {
j.exportedProguardFlagFiles = append(j.exportedProguardFlagFiles, lib.ExportedProguardFlagFiles()...)
}
})
j.exportedProguardFlagFiles = android.FirstUniquePaths(j.exportedProguardFlagFiles)
proguardSpecInfo := j.collectProguardSpecInfo(ctx)
ctx.SetProvider(ProguardSpecInfoProvider, proguardSpecInfo)
j.exportedProguardFlagFiles = proguardSpecInfo.ProguardFlagsFiles.ToList()
}
func (j *Library) DepsMutator(ctx android.BottomUpMutatorContext) {