Merge "Write module dexpreopt.config for Make."

This commit is contained in:
Ulyana Trafimovich 2021-02-01 10:16:57 +00:00 committed by Gerrit Code Review
commit a4fce3b488
7 changed files with 110 additions and 5 deletions

View file

@ -534,3 +534,26 @@ func fromJsonClassLoaderContextRec(ctx android.PathContext, jClcs map[string]*js
}
return clcs
}
// Convert Soong CLC map to JSON representation for Make.
func toJsonClassLoaderContext(clcMap ClassLoaderContextMap) jsonClassLoaderContextMap {
jClcMap := make(jsonClassLoaderContextMap)
for sdkVer, clcs := range clcMap {
sdkVerStr := fmt.Sprintf("%d", sdkVer)
jClcMap[sdkVerStr] = toJsonClassLoaderContextRec(clcs)
}
return jClcMap
}
// Recursive helper for toJsonClassLoaderContext.
func toJsonClassLoaderContextRec(clcs []*ClassLoaderContext) map[string]*jsonClassLoaderContext {
jClcs := make(map[string]*jsonClassLoaderContext, len(clcs))
for _, clc := range clcs {
jClcs[clc.Name] = &jsonClassLoaderContext{
Host: clc.Host.String(),
Device: clc.Device,
Subcontexts: toJsonClassLoaderContextRec(clc.Subcontexts),
}
}
return jClcs
}

View file

@ -114,6 +114,7 @@ type ModuleConfig struct {
ProfileBootListing android.OptionalPath
EnforceUsesLibraries bool
ProvidesUsesLibrary string // the name of the <uses-library> (usually the same as its module)
ClassLoaderContexts ClassLoaderContextMap
Archs []android.ArchType
@ -290,6 +291,42 @@ func ParseModuleConfig(ctx android.PathContext, data []byte) (*ModuleConfig, err
return config.ModuleConfig, nil
}
// WriteSlimModuleConfigForMake serializes a subset of ModuleConfig into a per-module
// dexpreopt.config JSON file. It is a way to pass dexpreopt information about Soong modules to
// Make, which is needed when a Make module has a <uses-library> dependency on a Soong module.
func WriteSlimModuleConfigForMake(ctx android.ModuleContext, config *ModuleConfig, path android.WritablePath) {
if path == nil {
return
}
// JSON representation of the slim module dexpreopt.config.
type slimModuleJSONConfig struct {
Name string
DexLocation string
BuildPath string
EnforceUsesLibraries bool
ProvidesUsesLibrary string
ClassLoaderContexts jsonClassLoaderContextMap
}
jsonConfig := &slimModuleJSONConfig{
Name: config.Name,
DexLocation: config.DexLocation,
BuildPath: config.BuildPath.String(),
EnforceUsesLibraries: config.EnforceUsesLibraries,
ProvidesUsesLibrary: config.ProvidesUsesLibrary,
ClassLoaderContexts: toJsonClassLoaderContext(config.ClassLoaderContexts),
}
data, err := json.MarshalIndent(jsonConfig, "", " ")
if err != nil {
ctx.ModuleErrorf("failed to JSON marshal module dexpreopt.config: %v", err)
return
}
android.WriteFileRule(ctx, path, string(data))
}
// dex2oatModuleName returns the name of the module to use for the dex2oat host
// tool. It should be a binary module with public visibility that is compiled
// and installed for host.

View file

@ -125,6 +125,10 @@ func (library *Library) AndroidMkEntries() []android.AndroidMkEntries {
entries.SetString("LOCAL_MODULE_STEM", library.Stem())
entries.SetOptionalPaths("LOCAL_SOONG_LINT_REPORTS", library.linter.reports)
if library.dexpreopter.configPath != nil {
entries.SetPath("LOCAL_SOONG_DEXPREOPT_CONFIG", library.dexpreopter.configPath)
}
},
},
})

View file

@ -455,6 +455,7 @@ func (a *AndroidApp) installPath(ctx android.ModuleContext) android.InstallPath
func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) android.Path {
a.dexpreopter.installPath = a.installPath(ctx)
a.dexpreopter.isApp = true
if a.dexProperties.Uncompress_dex == nil {
// If the value was not force-set by the user, use reasonable default based on the module.
a.dexProperties.Uncompress_dex = proptools.BoolPtr(a.shouldUncompressDex(ctx))

View file

@ -255,6 +255,7 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext
installDir = android.PathForModuleInstall(ctx, "app", a.BaseModuleName())
}
a.dexpreopter.isApp = true
a.dexpreopter.installPath = installDir.Join(ctx, a.BaseModuleName()+".apk")
a.dexpreopter.isPresignedPrebuilt = Bool(a.properties.Presigned)
a.dexpreopter.uncompressedDex = a.shouldUncompressDex(ctx)

View file

@ -30,6 +30,7 @@ type dexpreopter struct {
installPath android.InstallPath
uncompressedDex bool
isSDKLibrary bool
isApp bool
isTest bool
isPresignedPrebuilt bool
@ -38,6 +39,11 @@ type dexpreopter struct {
classLoaderContexts dexpreopt.ClassLoaderContextMap
builtInstalled string
// A path to a dexpreopt.config file generated by Soong for libraries that may be used as a
// <uses-library> by Make modules. The path is passed to Make via LOCAL_SOONG_DEXPREOPT_CONFIG
// variable. If the path is nil, no config is generated (which is the case for apps and tests).
configPath android.WritablePath
}
type DexpreoptProperties struct {
@ -117,7 +123,40 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Mo
// the dexpreopter struct hasn't been fully initialized before we're called,
// e.g. in aar.go. This keeps the behaviour that dexpreopting is effectively
// disabled, even if installable is true.
if d.dexpreoptDisabled(ctx) || d.installPath.Base() == "." {
if d.installPath.Base() == "." {
return
}
dexLocation := android.InstallPathToOnDevicePath(ctx, d.installPath)
buildPath := android.PathForModuleOut(ctx, "dexpreopt", ctx.ModuleName()+".jar").OutputPath
providesUsesLib := ctx.ModuleName()
if ulib, ok := ctx.Module().(ProvidesUsesLib); ok {
name := ulib.ProvidesUsesLib()
if name != nil {
providesUsesLib = *name
}
}
if !d.isApp && !d.isTest {
// Slim dexpreopt config is serialized to dexpreopt.config files and used by
// dex_preopt_config_merger.py to get information about <uses-library> dependencies.
// Note that it might be needed even if dexpreopt is disabled for this module.
slimDexpreoptConfig := &dexpreopt.ModuleConfig{
Name: ctx.ModuleName(),
DexLocation: dexLocation,
BuildPath: buildPath,
EnforceUsesLibraries: d.enforceUsesLibs,
ProvidesUsesLibrary: providesUsesLib,
ClassLoaderContexts: d.classLoaderContexts,
// The rest of the fields are not needed.
}
d.configPath = android.PathForModuleOut(ctx, "dexpreopt", "dexpreopt.config")
dexpreopt.WriteSlimModuleConfigForMake(ctx, slimDexpreoptConfig, d.configPath)
}
if d.dexpreoptDisabled(ctx) {
return
}
@ -157,8 +196,6 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Mo
// The image locations for all Android variants are identical.
imageLocations := bootImage.getAnyAndroidVariant().imageLocations()
dexLocation := android.InstallPathToOnDevicePath(ctx, d.installPath)
var profileClassListing android.OptionalPath
var profileBootListing android.OptionalPath
profileIsTextListing := false
@ -177,10 +214,11 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Mo
}
}
// Full dexpreopt config, used to create dexpreopt build rules.
dexpreoptConfig := &dexpreopt.ModuleConfig{
Name: ctx.ModuleName(),
DexLocation: dexLocation,
BuildPath: android.PathForModuleOut(ctx, "dexpreopt", ctx.ModuleName()+".jar").OutputPath,
BuildPath: buildPath,
DexPath: dexJarFile,
ManifestPath: d.manifestFile,
UncompressedDex: d.uncompressedDex,
@ -192,6 +230,7 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Mo
ProfileBootListing: profileBootListing,
EnforceUsesLibraries: d.enforceUsesLibs,
ProvidesUsesLibrary: providesUsesLib,
ClassLoaderContexts: d.classLoaderContexts,
Archs: archs,

View file

@ -148,7 +148,7 @@ func TestDexpreoptEnabled(t *testing.T) {
t.Run(test.name, func(t *testing.T) {
ctx, _ := testJava(t, test.bp)
dexpreopt := ctx.ModuleForTests("foo", "android_common").MaybeDescription("dexpreopt")
dexpreopt := ctx.ModuleForTests("foo", "android_common").MaybeRule("dexpreopt")
enabled := dexpreopt.Rule != nil
if enabled != test.enabled {