Merge "Automatically propagate jarjar rules for aconfig libraries" into main
This commit is contained in:
commit
4f0b9b4289
6 changed files with 270 additions and 7 deletions
|
@ -102,6 +102,13 @@ func (callbacks *JavaAconfigDeclarationsLibraryCallbacks) GenerateSourceJarBuild
|
|||
},
|
||||
})
|
||||
|
||||
// Mark our generated code as possibly needing jarjar repackaging
|
||||
// TODO: Maybe control this with a property?
|
||||
module.AddJarJarRenameRule(declarations.Package+".Flags", "")
|
||||
module.AddJarJarRenameRule(declarations.Package+".FeatureFlags", "")
|
||||
module.AddJarJarRenameRule(declarations.Package+".FeatureFlagsImpl", "")
|
||||
module.AddJarJarRenameRule(declarations.Package+".FakeFeatureFlagsImpl", "")
|
||||
|
||||
return srcJarPath
|
||||
}
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ import (
|
|||
var (
|
||||
DeviceSharedLibrary = "shared_library"
|
||||
DeviceStaticLibrary = "static_library"
|
||||
jarJarPrefixHandler func(ctx ModuleContext)
|
||||
)
|
||||
|
||||
type Module interface {
|
||||
|
@ -1772,6 +1773,13 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext)
|
|||
return
|
||||
}
|
||||
|
||||
if jarJarPrefixHandler != nil {
|
||||
jarJarPrefixHandler(ctx)
|
||||
if ctx.Failed() {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
m.module.GenerateAndroidBuildActions(ctx)
|
||||
if ctx.Failed() {
|
||||
return
|
||||
|
@ -1865,6 +1873,13 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext)
|
|||
m.variables = ctx.variables
|
||||
}
|
||||
|
||||
func SetJarJarPrefixHandler(handler func(ModuleContext)) {
|
||||
if jarJarPrefixHandler != nil {
|
||||
panic("jarJarPrefixHandler already set")
|
||||
}
|
||||
jarJarPrefixHandler = handler
|
||||
}
|
||||
|
||||
func (m *ModuleBase) moduleInfoRegisterName(ctx ModuleContext, subName string) string {
|
||||
name := m.BaseModuleName()
|
||||
|
||||
|
|
246
java/base.go
246
java/base.go
|
@ -17,6 +17,8 @@ package java
|
|||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
|
@ -89,6 +91,9 @@ type CommonProperties struct {
|
|||
// if not blank, run jarjar using the specified rules file
|
||||
Jarjar_rules *string `android:"path,arch_variant"`
|
||||
|
||||
// if not blank, used as prefix to generate repackage rule
|
||||
Jarjar_prefix *string
|
||||
|
||||
// If not blank, set the java version passed to javac as -source and -target
|
||||
Java_version *string
|
||||
|
||||
|
@ -425,6 +430,8 @@ type Module struct {
|
|||
// inserting into the bootclasspath/classpath of another compile
|
||||
headerJarFile android.Path
|
||||
|
||||
repackagedHeaderJarFile android.Path
|
||||
|
||||
// jar file containing implementation classes including static library dependencies but no
|
||||
// resources
|
||||
implementationJarFile android.Path
|
||||
|
@ -489,6 +496,9 @@ type Module struct {
|
|||
// expanded Jarjar_rules
|
||||
expandJarjarRules android.Path
|
||||
|
||||
// jarjar rule for inherited jarjar rules
|
||||
repackageJarjarRules android.Path
|
||||
|
||||
// Extra files generated by the module type to be added as java resources.
|
||||
extraResources android.Paths
|
||||
|
||||
|
@ -518,6 +528,10 @@ type Module struct {
|
|||
|
||||
// Single aconfig "cache file" merged from this module and all dependencies.
|
||||
mergedAconfigFiles map[string]android.Paths
|
||||
|
||||
// Values that will be set in the JarJarProvider data for jarjar repackaging,
|
||||
// and merged with our dependencies' rules.
|
||||
jarjarRenameRules map[string]string
|
||||
}
|
||||
|
||||
func (j *Module) CheckStableSdkVersion(ctx android.BaseModuleContext) error {
|
||||
|
@ -1072,6 +1086,19 @@ func (j *Module) addGeneratedSrcJars(path android.Path) {
|
|||
}
|
||||
|
||||
func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspathJars, extraCombinedJars android.Paths) {
|
||||
|
||||
// Auto-propagating jarjar rules
|
||||
jarjarProviderData := j.collectJarJarRules(ctx)
|
||||
if jarjarProviderData != nil {
|
||||
android.SetProvider(ctx, JarJarProvider, *jarjarProviderData)
|
||||
text := getJarJarRuleText(jarjarProviderData)
|
||||
if text != "" {
|
||||
ruleTextFile := android.PathForModuleOut(ctx, "repackaged-jarjar", "repackaging.txt")
|
||||
android.WriteFileRule(ctx, ruleTextFile, text)
|
||||
j.repackageJarjarRules = ruleTextFile
|
||||
}
|
||||
}
|
||||
|
||||
j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.deviceProperties.Aidl.Export_include_dirs)
|
||||
|
||||
deps := j.collectDeps(ctx)
|
||||
|
@ -1170,7 +1197,7 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath
|
|||
ctx.ModuleErrorf("headers_only is enabled but Turbine is disabled.")
|
||||
}
|
||||
|
||||
_, j.headerJarFile =
|
||||
_, j.headerJarFile, _ =
|
||||
j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName,
|
||||
extraCombinedJars)
|
||||
if ctx.Failed() {
|
||||
|
@ -1285,7 +1312,7 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath
|
|||
// with sharding enabled. See: b/77284273.
|
||||
}
|
||||
extraJars := append(android.CopyOf(extraCombinedJars), kotlinHeaderJars...)
|
||||
headerJarFileWithoutDepsOrJarjar, j.headerJarFile =
|
||||
headerJarFileWithoutDepsOrJarjar, j.headerJarFile, j.repackagedHeaderJarFile =
|
||||
j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName, extraJars)
|
||||
if ctx.Failed() {
|
||||
return
|
||||
|
@ -1509,6 +1536,16 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath
|
|||
}
|
||||
}
|
||||
|
||||
// Automatic jarjar rules propagation
|
||||
if j.repackageJarjarRules != nil {
|
||||
repackagedJarjarFile := android.PathForModuleOut(ctx, "repackaged-jarjar", jarName).OutputPath
|
||||
TransformJarJar(ctx, repackagedJarjarFile, outputFile, j.repackageJarjarRules)
|
||||
outputFile = repackagedJarjarFile
|
||||
if ctx.Failed() {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Check package restrictions if necessary.
|
||||
if len(j.properties.Permitted_packages) > 0 {
|
||||
// Time stamp file created by the package check rule.
|
||||
|
@ -1678,6 +1715,7 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath
|
|||
|
||||
android.SetProvider(ctx, JavaInfoProvider, JavaInfo{
|
||||
HeaderJars: android.PathsIfNonNil(j.headerJarFile),
|
||||
RepackagedHeaderJars: android.PathsIfNonNil(j.repackagedHeaderJarFile),
|
||||
TransitiveLibsHeaderJars: j.transitiveLibsHeaderJars,
|
||||
TransitiveStaticLibsHeaderJars: j.transitiveStaticLibsHeaderJars,
|
||||
ImplementationAndResourcesJars: android.PathsIfNonNil(j.implementationAndResourcesJar),
|
||||
|
@ -1813,7 +1851,7 @@ func CheckKotlincFlags(ctx android.ModuleContext, flags []string) {
|
|||
|
||||
func (j *Module) compileJavaHeader(ctx android.ModuleContext, srcFiles, srcJars android.Paths,
|
||||
deps deps, flags javaBuilderFlags, jarName string,
|
||||
extraJars android.Paths) (headerJar, jarjarAndDepsHeaderJar android.Path) {
|
||||
extraJars android.Paths) (headerJar, jarjarAndDepsHeaderJar, jarjarAndDepsRepackagedHeaderJar android.Path) {
|
||||
|
||||
var jars android.Paths
|
||||
if len(srcFiles) > 0 || len(srcJars) > 0 {
|
||||
|
@ -1821,7 +1859,7 @@ func (j *Module) compileJavaHeader(ctx android.ModuleContext, srcFiles, srcJars
|
|||
turbineJar := android.PathForModuleOut(ctx, "turbine", jarName)
|
||||
TransformJavaToHeaderClasses(ctx, turbineJar, srcFiles, srcJars, flags)
|
||||
if ctx.Failed() {
|
||||
return nil, nil
|
||||
return nil, nil, nil
|
||||
}
|
||||
jars = append(jars, turbineJar)
|
||||
headerJar = turbineJar
|
||||
|
@ -1846,11 +1884,22 @@ func (j *Module) compileJavaHeader(ctx android.ModuleContext, srcFiles, srcJars
|
|||
TransformJarJar(ctx, jarjarFile, jarjarAndDepsHeaderJar, j.expandJarjarRules)
|
||||
jarjarAndDepsHeaderJar = jarjarFile
|
||||
if ctx.Failed() {
|
||||
return nil, nil
|
||||
return nil, nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
return headerJar, jarjarAndDepsHeaderJar
|
||||
if j.repackageJarjarRules != nil {
|
||||
repackagedJarjarFile := android.PathForModuleOut(ctx, "repackaged-turbine-jarjar", jarName)
|
||||
TransformJarJar(ctx, repackagedJarjarFile, jarjarAndDepsHeaderJar, j.repackageJarjarRules)
|
||||
jarjarAndDepsRepackagedHeaderJar = repackagedJarjarFile
|
||||
if ctx.Failed() {
|
||||
return nil, nil, nil
|
||||
}
|
||||
} else {
|
||||
jarjarAndDepsRepackagedHeaderJar = jarjarAndDepsHeaderJar
|
||||
}
|
||||
|
||||
return headerJar, jarjarAndDepsHeaderJar, jarjarAndDepsRepackagedHeaderJar
|
||||
}
|
||||
|
||||
func (j *Module) instrument(ctx android.ModuleContext, flags javaBuilderFlags,
|
||||
|
@ -2207,6 +2256,10 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps {
|
|||
}
|
||||
deps.classpath = append(deps.classpath, dep.HeaderJars...)
|
||||
deps.dexClasspath = append(deps.dexClasspath, dep.HeaderJars...)
|
||||
if len(dep.RepackagedHeaderJars) == 1 && !slices.Contains(dep.HeaderJars, dep.RepackagedHeaderJars[0]) {
|
||||
deps.classpath = append(deps.classpath, dep.RepackagedHeaderJars...)
|
||||
deps.dexClasspath = append(deps.dexClasspath, dep.RepackagedHeaderJars...)
|
||||
}
|
||||
deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs...)
|
||||
addPlugins(&deps, dep.ExportedPlugins, dep.ExportedPluginClasses...)
|
||||
deps.disableTurbine = deps.disableTurbine || dep.ExportedPluginDisableTurbine
|
||||
|
@ -2311,6 +2364,187 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps {
|
|||
return deps
|
||||
}
|
||||
|
||||
// Provider for jarjar renaming rules.
|
||||
//
|
||||
// Modules can set their jarjar renaming rules with addJarJarRenameRule, and those renamings will be
|
||||
// passed to all rdeps. The typical way that these renamings will NOT be inherited is when a module
|
||||
// links against stubs -- these are not passed through stubs. The classes will remain unrenamed on
|
||||
// classes until a module with jarjar_prefix is reached, and all as yet unrenamed classes will then
|
||||
// be renamed from that module.
|
||||
// TODO: Add another property to suppress the forwarding of
|
||||
type JarJarProviderData struct {
|
||||
// Mapping of class names: original --> renamed. If the value is "", the class will be
|
||||
// renamed by the next rdep that has the jarjar_prefix attribute (or this module if it has
|
||||
// attribute). Rdeps of that module will inherit the renaming.
|
||||
Rename map[string]string
|
||||
}
|
||||
|
||||
func (this JarJarProviderData) GetDebugString() string {
|
||||
result := ""
|
||||
for k, v := range this.Rename {
|
||||
if strings.Contains(k, "android.companion.virtual.flags.FakeFeatureFlagsImpl") {
|
||||
result += k + "-->" + v + ";"
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
var JarJarProvider = blueprint.NewProvider[JarJarProviderData]()
|
||||
|
||||
var overridableJarJarPrefix = "com.android.internal.hidden_from_bootclasspath"
|
||||
|
||||
func init() {
|
||||
android.SetJarJarPrefixHandler(mergeJarJarPrefixes)
|
||||
}
|
||||
|
||||
// BaseJarJarProviderData contains information that will propagate across dependencies regardless of
|
||||
// whether they are java modules or not.
|
||||
type BaseJarJarProviderData struct {
|
||||
JarJarProviderData JarJarProviderData
|
||||
}
|
||||
|
||||
func (this BaseJarJarProviderData) GetDebugString() string {
|
||||
return this.JarJarProviderData.GetDebugString()
|
||||
}
|
||||
|
||||
var BaseJarJarProvider = blueprint.NewProvider[BaseJarJarProviderData]()
|
||||
|
||||
// mergeJarJarPrefixes is called immediately before module.GenerateAndroidBuildActions is called.
|
||||
// Since there won't be a JarJarProvider, we create the BaseJarJarProvider if any of our deps have
|
||||
// either JarJarProvider or BaseJarJarProvider.
|
||||
func mergeJarJarPrefixes(ctx android.ModuleContext) {
|
||||
mod := ctx.Module()
|
||||
// Explicitly avoid propagating into some module types.
|
||||
switch reflect.TypeOf(mod).String() {
|
||||
case "*java.Droidstubs":
|
||||
return
|
||||
}
|
||||
jarJarData := collectDirectDepsProviders(ctx)
|
||||
if jarJarData != nil {
|
||||
providerData := BaseJarJarProviderData{
|
||||
JarJarProviderData: *jarJarData,
|
||||
}
|
||||
android.SetProvider(ctx, BaseJarJarProvider, providerData)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Add a jarjar renaming rule to this module, to be inherited to all dependent modules.
|
||||
func (module *Module) addJarJarRenameRule(original string, renamed string) {
|
||||
if module.jarjarRenameRules == nil {
|
||||
module.jarjarRenameRules = make(map[string]string)
|
||||
}
|
||||
module.jarjarRenameRules[original] = renamed
|
||||
}
|
||||
|
||||
func collectDirectDepsProviders(ctx android.ModuleContext) (result *JarJarProviderData) {
|
||||
// Gather repackage information from deps
|
||||
// If the dep jas a JarJarProvider, it is used. Otherwise, any BaseJarJarProvider is used.
|
||||
ctx.VisitDirectDepsIgnoreBlueprint(func(m android.Module) {
|
||||
merge := func(theirs *JarJarProviderData) {
|
||||
for orig, renamed := range theirs.Rename {
|
||||
if result == nil {
|
||||
result = &JarJarProviderData{
|
||||
Rename: make(map[string]string),
|
||||
}
|
||||
}
|
||||
if preexisting, exists := (*result).Rename[orig]; !exists || preexisting == "" {
|
||||
result.Rename[orig] = renamed
|
||||
} else if preexisting != "" && renamed != "" && preexisting != renamed {
|
||||
if strings.HasPrefix(preexisting, overridableJarJarPrefix) {
|
||||
result.Rename[orig] = renamed
|
||||
} else if !strings.HasPrefix(renamed, overridableJarJarPrefix) {
|
||||
ctx.ModuleErrorf("1. Conflicting jarjar rules inherited for class: %s (%s and %s)", orig, renamed, preexisting, ctx.ModuleName(), m.Name())
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if theirs, ok := android.OtherModuleProvider(ctx, m, JarJarProvider); ok {
|
||||
merge(&theirs)
|
||||
} else if theirs, ok := android.OtherModuleProvider(ctx, m, BaseJarJarProvider); ok {
|
||||
// TODO: if every java.Module should have a JarJarProvider, and we find only the
|
||||
// BaseJarJarProvider, then there is a bug. Consider seeing if m can be cast
|
||||
// to java.Module.
|
||||
merge(&theirs.JarJarProviderData)
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func (this Module) GetDebugString() string {
|
||||
return "sdk_version=" + proptools.String(this.deviceProperties.Sdk_version)
|
||||
}
|
||||
|
||||
// Merge the jarjar rules we inherit from our dependencies, any that have been added directly to
|
||||
// us, and if it's been set, apply the jarjar_prefix property to rename them.
|
||||
func (module *Module) collectJarJarRules(ctx android.ModuleContext) *JarJarProviderData {
|
||||
// Gather repackage information from deps
|
||||
result := collectDirectDepsProviders(ctx)
|
||||
|
||||
// Update that with entries we've stored for ourself
|
||||
for orig, renamed := range module.jarjarRenameRules {
|
||||
if result == nil {
|
||||
result = &JarJarProviderData{
|
||||
Rename: make(map[string]string),
|
||||
}
|
||||
}
|
||||
if renamed != "" {
|
||||
if preexisting, exists := (*result).Rename[orig]; exists && preexisting != renamed {
|
||||
ctx.ModuleErrorf("Conflicting jarjar rules inherited for class: %s (%s and %s)", orig, renamed, preexisting)
|
||||
continue
|
||||
}
|
||||
}
|
||||
(*result).Rename[orig] = renamed
|
||||
}
|
||||
|
||||
// If there are no renamings, then jarjar_prefix does nothing, so skip the extra work.
|
||||
if result == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// If they've given us a jarjar_prefix property, then we will use that to rename any classes
|
||||
// that have not yet been renamed.
|
||||
prefix := proptools.String(module.properties.Jarjar_prefix)
|
||||
if prefix != "" {
|
||||
if prefix[0] == '.' {
|
||||
ctx.PropertyErrorf("jarjar_prefix", "jarjar_prefix can not start with '.'")
|
||||
return nil
|
||||
}
|
||||
if prefix[len(prefix)-1] == '.' {
|
||||
ctx.PropertyErrorf("jarjar_prefix", "jarjar_prefix can not end with '.'")
|
||||
return nil
|
||||
}
|
||||
|
||||
var updated map[string]string
|
||||
for orig, renamed := range (*result).Rename {
|
||||
if renamed == "" {
|
||||
if updated == nil {
|
||||
updated = make(map[string]string)
|
||||
}
|
||||
updated[orig] = prefix + "." + orig
|
||||
}
|
||||
}
|
||||
for orig, renamed := range updated {
|
||||
(*result).Rename[orig] = renamed
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Get the jarjar rule text for a given provider for the fully resolved rules. Classes that map
|
||||
// to "" won't be in this list because they shouldn't be renamed yet.
|
||||
func getJarJarRuleText(provider *JarJarProviderData) string {
|
||||
result := ""
|
||||
for orig, renamed := range provider.Rename {
|
||||
if renamed != "" {
|
||||
result += "rule " + orig + " " + renamed + "\n"
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func addPlugins(deps *deps, pluginJars android.Paths, pluginClasses ...string) {
|
||||
deps.processorPath = append(deps.processorPath, pluginJars...)
|
||||
deps.processorClasses = append(deps.processorClasses, pluginClasses...)
|
||||
|
|
|
@ -262,7 +262,7 @@ func (d *dexer) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8Fl
|
|||
var proguardRaiseDeps classpath
|
||||
ctx.VisitDirectDepsWithTag(proguardRaiseTag, func(m android.Module) {
|
||||
dep, _ := android.OtherModuleProvider(ctx, m, JavaInfoProvider)
|
||||
proguardRaiseDeps = append(proguardRaiseDeps, dep.HeaderJars...)
|
||||
proguardRaiseDeps = append(proguardRaiseDeps, dep.RepackagedHeaderJars...)
|
||||
})
|
||||
|
||||
r8Flags = append(r8Flags, proguardRaiseDeps.FormJavaClassPath("-libraryjars"))
|
||||
|
|
|
@ -107,3 +107,8 @@ func (module *GeneratedJavaLibraryModule) GenerateAndroidBuildActions(ctx androi
|
|||
module.Library.properties.Generated_srcjars = append(module.Library.properties.Generated_srcjars, srcJarPath)
|
||||
module.Library.GenerateAndroidBuildActions(ctx)
|
||||
}
|
||||
|
||||
// Add a rule to the jarjar renaming rules. See RepackageProviderData.
|
||||
func (module *GeneratedJavaLibraryModule) AddJarJarRenameRule(original string, renamed string) {
|
||||
module.addJarJarRenameRule(original, renamed)
|
||||
}
|
||||
|
|
|
@ -248,6 +248,8 @@ type JavaInfo struct {
|
|||
// against this module. If empty, ImplementationJars should be used instead.
|
||||
HeaderJars android.Paths
|
||||
|
||||
RepackagedHeaderJars android.Paths
|
||||
|
||||
// set of header jars for all transitive libs deps
|
||||
TransitiveLibsHeaderJars *android.DepSet[android.Path]
|
||||
|
||||
|
|
Loading…
Reference in a new issue