Merge "Rework class loader context implementation."

This commit is contained in:
Ulyana Trafimovich 2020-11-16 14:50:11 +00:00 committed by Gerrit Code Review
commit af335a4694
14 changed files with 351 additions and 361 deletions

View File

@ -16,7 +16,7 @@ package dexpreopt
import (
"fmt"
"path/filepath"
"strconv"
"strings"
"android/soong/android"
@ -49,39 +49,39 @@ var CompatUsesLibs = android.CopyOf(CompatUsesLibs29)
const UnknownInstallLibraryPath = "error"
const AnySdkVersion int = 9999 // should go last in class loader context
// AnySdkVersion means that the class loader context is needed regardless of the targetSdkVersion
// of the app. The numeric value affects the key order in the map and, as a result, the order of
// arguments passed to construct_context.py (high value means that the unconditional context goes
// last). We use the converntional "current" SDK level (10000), but any big number would do as well.
const AnySdkVersion int = android.FutureApiLevelInt
// LibraryPath contains paths to the library DEX jar on host and on device.
type LibraryPath struct {
Host android.Path
// ClassLoaderContext is a tree of libraries used by the dexpreopted module with their dependencies.
// The context is used by dex2oat to compile the module and recorded in the AOT-compiled files, so
// that it can be checked agains the run-time class loader context on device. If there is a mismatch
// at runtime, AOT-compiled code is rejected.
type ClassLoaderContext struct {
// The name of the library (same as the name of the module that contains it).
Name string
// On-host build path to the library dex file (used in dex2oat argument --class-loader-context).
Host android.Path
// On-device install path (used in dex2oat argument --stored-class-loader-context).
Device string
// Nested class loader subcontexts for dependencies.
Subcontexts []*ClassLoaderContext
}
// LibraryPaths is a map from library name to on-host and on-device paths to its DEX jar.
type LibraryPaths map[string]*LibraryPath
// ClassLoaderContextMap is a map from SDK version to a class loader context.
// There is a special entry with key AnySdkVersion that stores unconditional class loader context.
// Other entries store conditional contexts that should be added for some apps that have
// targetSdkVersion in the manifest lower than the key SDK version.
type ClassLoaderContextMap map[int][]*ClassLoaderContext
type classLoaderContext struct {
// Library names
Names []string
// The class loader context using paths in the build.
Host android.Paths
// The class loader context using paths as they will be on the device.
Target []string
}
// A map of class loader contexts for each SDK version.
// A map entry for "any" version contains libraries that are unconditionally added to class loader
// context. Map entries for existing versions contains libraries that were in the default classpath
// until that API version, and should be added to class loader context if and only if the
// targetSdkVersion in the manifest or APK is less than that API version.
type classLoaderContextMap map[int]*classLoaderContext
// Add a new library path to the map, unless a path for this library already exists.
// If necessary, check that the build and install paths exist.
func (libPaths LibraryPaths) addLibraryPath(ctx android.ModuleInstallPathContext, lib string,
hostPath, installPath android.Path, strict bool) error {
// Add class loader context for the given library to the map entry for the given SDK version.
func (clcMap ClassLoaderContextMap) addContext(ctx android.ModuleInstallPathContext, sdkVer int, lib string,
hostPath, installPath android.Path, strict bool, nestedClcMap ClassLoaderContextMap) error {
// If missing dependencies are allowed, the build shouldn't fail when a <uses-library> is
// not found. However, this is likely to result is disabling dexpreopt, as it won't be
@ -89,263 +89,254 @@ func (libPaths LibraryPaths) addLibraryPath(ctx android.ModuleInstallPathContext
strict = strict && !ctx.Config().AllowMissingDependencies()
if hostPath == nil && strict {
return fmt.Errorf("unknown build path to <uses-library> '%s'", lib)
return fmt.Errorf("unknown build path to <uses-library> \"%s\"", lib)
}
devicePath := UnknownInstallLibraryPath
if installPath == nil {
if android.InList(lib, CompatUsesLibs) || android.InList(lib, OptionalCompatUsesLibs) {
// Assume that compatibility libraries are installed in /system/framework.
installPath = android.PathForModuleInstall(ctx, "framework", lib+".jar")
} else if strict {
return fmt.Errorf("unknown install path to <uses-library> '%s'", lib)
}
}
// Add a library only if the build and install path to it is known.
if _, present := libPaths[lib]; !present {
var devicePath string
if installPath != nil {
devicePath = android.InstallPathToOnDevicePath(ctx, installPath.(android.InstallPath))
return fmt.Errorf("unknown install path to <uses-library> \"%s\"", lib)
} else {
// For some stub libraries the only known thing is the name of their implementation
// library, but the library itself is unavailable (missing or part of a prebuilt). In
// such cases we still need to add the library to <uses-library> tags in the manifest,
// but we cannot use if for dexpreopt.
devicePath = UnknownInstallLibraryPath
// but we cannot use it for dexpreopt.
}
libPaths[lib] = &LibraryPath{hostPath, devicePath}
}
if installPath != nil {
devicePath = android.InstallPathToOnDevicePath(ctx, installPath.(android.InstallPath))
}
subcontexts := nestedClcMap[AnySdkVersion]
// If the library with this name is already present as one of the unconditional top-level
// components, do not re-add it.
for _, clc := range clcMap[sdkVer] {
if clc.Name == lib {
return nil
}
}
clcMap[sdkVer] = append(clcMap[sdkVer], &ClassLoaderContext{
Name: lib,
Host: hostPath,
Device: devicePath,
Subcontexts: subcontexts,
})
return nil
}
// Wrapper around addLibraryPath that does error reporting.
func (libPaths LibraryPaths) addLibraryPathOrReportError(ctx android.ModuleInstallPathContext, lib string,
hostPath, installPath android.Path, strict bool) {
// Wrapper around addContext that reports errors.
func (clcMap ClassLoaderContextMap) addContextOrReportError(ctx android.ModuleInstallPathContext, sdkVer int, lib string,
hostPath, installPath android.Path, strict bool, nestedClcMap ClassLoaderContextMap) {
err := libPaths.addLibraryPath(ctx, lib, hostPath, installPath, strict)
err := clcMap.addContext(ctx, sdkVer, lib, hostPath, installPath, strict, nestedClcMap)
if err != nil {
ctx.ModuleErrorf(err.Error())
android.ReportPathErrorf(ctx, err.Error())
}
}
// Add a new library path to the map. Enforce checks that the library paths exist.
func (libPaths LibraryPaths) AddLibraryPath(ctx android.ModuleInstallPathContext, lib string, hostPath, installPath android.Path) {
libPaths.addLibraryPathOrReportError(ctx, lib, hostPath, installPath, true)
// Add class loader context. Fail on unknown build/install paths.
func (clcMap ClassLoaderContextMap) AddContext(ctx android.ModuleInstallPathContext, lib string,
hostPath, installPath android.Path) {
clcMap.addContextOrReportError(ctx, AnySdkVersion, lib, hostPath, installPath, true, nil)
}
// Add a new library path to the map, if the library exists (name is not nil).
// Don't enforce checks that the library paths exist. Some libraries may be missing from the build,
// but their names still need to be added to <uses-library> tags in the manifest.
func (libPaths LibraryPaths) MaybeAddLibraryPath(ctx android.ModuleInstallPathContext, lib *string, hostPath, installPath android.Path) {
// Add class loader context if the library exists. Don't fail on unknown build/install paths.
func (clcMap ClassLoaderContextMap) MaybeAddContext(ctx android.ModuleInstallPathContext, lib *string,
hostPath, installPath android.Path) {
if lib != nil {
libPaths.addLibraryPathOrReportError(ctx, *lib, hostPath, installPath, false)
clcMap.addContextOrReportError(ctx, AnySdkVersion, *lib, hostPath, installPath, false, nil)
}
}
// Add library paths from the second map to the first map (do not override existing entries).
func (libPaths LibraryPaths) AddLibraryPaths(otherPaths LibraryPaths) {
for lib, path := range otherPaths {
if _, present := libPaths[lib]; !present {
libPaths[lib] = path
}
}
// Add class loader context for the given SDK version. Fail on unknown build/install paths.
func (clcMap ClassLoaderContextMap) AddContextForSdk(ctx android.ModuleInstallPathContext, sdkVer int,
lib string, hostPath, installPath android.Path, nestedClcMap ClassLoaderContextMap) {
clcMap.addContextOrReportError(ctx, sdkVer, lib, hostPath, installPath, true, nestedClcMap)
}
func (m classLoaderContextMap) getValue(sdkVer int) *classLoaderContext {
if _, ok := m[sdkVer]; !ok {
m[sdkVer] = &classLoaderContext{}
}
return m[sdkVer]
}
func (clc *classLoaderContext) addLib(lib string, hostPath android.Path, targetPath string) {
clc.Names = append(clc.Names, lib)
clc.Host = append(clc.Host, hostPath)
clc.Target = append(clc.Target, targetPath)
}
func (m classLoaderContextMap) addLibs(ctx android.PathContext, sdkVer int, module *ModuleConfig,
libs ...string) (bool, error) {
clc := m.getValue(sdkVer)
for _, lib := range libs {
if p, ok := module.LibraryPaths[lib]; ok && p.Host != nil && p.Device != UnknownInstallLibraryPath {
clc.addLib(lib, p.Host, p.Device)
} else {
if sdkVer == AnySdkVersion {
// Fail the build if dexpreopt doesn't know paths to one of the <uses-library>
// dependencies. In the future we may need to relax this and just disable dexpreopt.
return false, fmt.Errorf("dexpreopt cannot find path for <uses-library> '%s'", lib)
} else {
// No error for compatibility libraries, as Soong doesn't know if they are needed
// (this depends on the targetSdkVersion in the manifest).
return false, nil
// Merge the other class loader context map into this one, do not override existing entries.
func (clcMap ClassLoaderContextMap) AddContextMap(otherClcMap ClassLoaderContextMap) {
for sdkVer, otherClcs := range otherClcMap {
for _, otherClc := range otherClcs {
alreadyHave := false
for _, clc := range clcMap[sdkVer] {
if clc.Name == otherClc.Name {
alreadyHave = true
break
}
}
if !alreadyHave {
clcMap[sdkVer] = append(clcMap[sdkVer], otherClc)
}
}
}
return true, nil
}
func (m classLoaderContextMap) addSystemServerLibs(sdkVer int, ctx android.PathContext, module *ModuleConfig, libs ...string) {
clc := m.getValue(sdkVer)
for _, lib := range libs {
clc.addLib(lib, SystemServerDexJarHostPath(ctx, lib), filepath.Join("/system/framework", lib+".jar"))
// List of libraries in the unconditional class loader context, excluding dependencies of shared libraries.
func (clcMap ClassLoaderContextMap) UsesLibs() (ulibs []string) {
if clcMap != nil {
// compatibility libraries (those in conditional context) are not added to <uses-library> tags
ulibs = usesLibsRec(clcMap[AnySdkVersion])
ulibs = android.FirstUniqueStrings(ulibs)
}
return ulibs
}
func (m classLoaderContextMap) usesLibs() []string {
if clc, ok := m[AnySdkVersion]; ok {
return clc.Names
func usesLibsRec(clcs []*ClassLoaderContext) (ulibs []string) {
for _, clc := range clcs {
ulibs = append(ulibs, clc.Name)
ulibs = append(ulibs, usesLibsRec(clc.Subcontexts)...)
}
return nil
}
// genClassLoaderContext generates host and target class loader context to be passed to the dex2oat
// command for the dexpreopted module. There are three possible cases:
//
// 1. System server jars. They have a special class loader context that includes other system
// server jars.
//
// 2. Library jars or APKs which have precise list of their <uses-library> libs. Their class loader
// context includes build and on-device paths to these libs. In some cases it may happen that
// the path to a <uses-library> is unknown (e.g. the dexpreopted module may depend on stubs
// library, whose implementation library is missing from the build altogether). In such case
// dexpreopting with the <uses-library> is impossible, and dexpreopting without it is pointless,
// as the runtime classpath won't match and the dexpreopted code will be discarded. Therefore in
// such cases the function returns nil, which disables dexpreopt.
//
// 3. All other library jars or APKs for which the exact <uses-library> list is unknown. They use
// the unsafe &-classpath workaround that means empty class loader context and absence of runtime
// check that the class loader context provided by the PackageManager agrees with the stored
// class loader context recorded in the .odex file.
//
func genClassLoaderContext(ctx android.PathContext, global *GlobalConfig, module *ModuleConfig) (*classLoaderContextMap, error) {
classLoaderContexts := make(classLoaderContextMap)
systemServerJars := NonUpdatableSystemServerJars(ctx, global)
if jarIndex := android.IndexList(module.Name, systemServerJars); jarIndex >= 0 {
// System server jars should be dexpreopted together: class loader context of each jar
// should include all preceding jars on the system server classpath.
classLoaderContexts.addSystemServerLibs(AnySdkVersion, ctx, module, systemServerJars[:jarIndex]...)
} else if module.EnforceUsesLibraries {
// Unconditional class loader context.
usesLibs := append(copyOf(module.UsesLibraries), module.OptionalUsesLibraries...)
if ok, err := classLoaderContexts.addLibs(ctx, AnySdkVersion, module, usesLibs...); !ok {
return nil, err
}
// Conditional class loader context for API version < 28.
const httpLegacy = "org.apache.http.legacy"
if ok, err := classLoaderContexts.addLibs(ctx, 28, module, httpLegacy); !ok {
return nil, err
}
// Conditional class loader context for API version < 29.
usesLibs29 := []string{
"android.hidl.base-V1.0-java",
"android.hidl.manager-V1.0-java",
}
if ok, err := classLoaderContexts.addLibs(ctx, 29, module, usesLibs29...); !ok {
return nil, err
}
// Conditional class loader context for API version < 30.
if ok, err := classLoaderContexts.addLibs(ctx, 30, module, OptionalCompatUsesLibs30...); !ok {
return nil, err
}
} else {
// Pass special class loader context to skip the classpath and collision check.
// This will get removed once LOCAL_USES_LIBRARIES is enforced.
// Right now LOCAL_USES_LIBRARIES is opt in, for the case where it's not specified we still default
// to the &.
}
fixConditionalClassLoaderContext(classLoaderContexts)
return &classLoaderContexts, nil
return ulibs
}
// Now that the full unconditional context is known, reconstruct conditional context.
// Apply filters for individual libraries, mirroring what the PackageManager does when it
// constructs class loader context on device.
//
// TODO(b/132357300):
// - remove android.hidl.manager and android.hidl.base unless the app is a system app.
// TODO(b/132357300): remove "android.hidl.manager" and "android.hidl.base" for non-system apps.
//
func fixConditionalClassLoaderContext(clcMap classLoaderContextMap) {
usesLibs := clcMap.usesLibs()
func fixClassLoaderContext(clcMap ClassLoaderContextMap) {
usesLibs := clcMap.UsesLibs()
for sdkVer, clc := range clcMap {
for sdkVer, clcs := range clcMap {
if sdkVer == AnySdkVersion {
continue
}
clcMap[sdkVer] = &classLoaderContext{}
for i, lib := range clc.Names {
if android.InList(lib, usesLibs) {
fixedClcs := []*ClassLoaderContext{}
for _, clc := range clcs {
if android.InList(clc.Name, usesLibs) {
// skip compatibility libraries that are already included in unconditional context
} else if lib == AndroidTestMock && !android.InList("android.test.runner", usesLibs) {
} else if clc.Name == AndroidTestMock && !android.InList("android.test.runner", usesLibs) {
// android.test.mock is only needed as a compatibility library (in conditional class
// loader context) if android.test.runner is used, otherwise skip it
} else {
clcMap[sdkVer].addLib(lib, clc.Host[i], clc.Target[i])
fixedClcs = append(fixedClcs, clc)
}
clcMap[sdkVer] = fixedClcs
}
}
}
// Return the class loader context as a string and a slice of build paths for all dependencies.
func computeClassLoaderContext(ctx android.PathContext, clcMap classLoaderContextMap) (clcStr string, paths android.Paths) {
for _, ver := range android.SortedIntKeys(clcMap) {
clc := clcMap.getValue(ver)
clcLen := len(clc.Names)
if clcLen != len(clc.Host) || clcLen != len(clc.Target) {
android.ReportPathErrorf(ctx, "ill-formed class loader context")
// Return true if all build/install library paths are valid (including recursive subcontexts),
// otherwise return false. A build path is valid if it's not nil. An install path is valid if it's
// not equal to a special "error" value.
func validateClassLoaderContext(clcMap ClassLoaderContextMap) (bool, error) {
for sdkVer, clcs := range clcMap {
if valid, err := validateClassLoaderContextRec(sdkVer, clcs); !valid || err != nil {
return valid, err
}
}
return true, nil
}
var hostClc, targetClc []string
var hostPaths android.Paths
for i := 0; i < clcLen; i++ {
hostStr := "PCL[" + clc.Host[i].String() + "]"
targetStr := "PCL[" + clc.Target[i] + "]"
hostClc = append(hostClc, hostStr)
targetClc = append(targetClc, targetStr)
hostPaths = append(hostPaths, clc.Host[i])
func validateClassLoaderContextRec(sdkVer int, clcs []*ClassLoaderContext) (bool, error) {
for _, clc := range clcs {
if clc.Host == nil || clc.Device == UnknownInstallLibraryPath {
if sdkVer == AnySdkVersion {
// Return error if dexpreopt doesn't know paths to one of the <uses-library>
// dependencies. In the future we may need to relax this and just disable dexpreopt.
return false, fmt.Errorf("invalid path for <uses-library> \"%s\"", clc.Name)
} else {
// No error for compatibility libraries, as Soong doesn't know if they are needed
// (this depends on the targetSdkVersion in the manifest), but the CLC is invalid.
return false, nil
}
}
if valid, err := validateClassLoaderContextRec(sdkVer, clc.Subcontexts); !valid || err != nil {
return valid, err
}
}
return true, nil
}
// Return the class loader context as a string, and a slice of build paths for all dependencies.
// Perform a depth-first preorder traversal of the class loader context tree for each SDK version.
// Return the resulting string and a slice of on-host build paths to all library dependencies.
func ComputeClassLoaderContext(clcMap ClassLoaderContextMap) (clcStr string, paths android.Paths) {
for _, sdkVer := range android.SortedIntKeys(clcMap) { // determinisitc traversal order
sdkVerStr := fmt.Sprintf("%d", sdkVer)
if sdkVer == AnySdkVersion {
sdkVerStr = "any" // a special keyword that means any SDK version
}
hostClc, targetClc, hostPaths := computeClassLoaderContextRec(clcMap[sdkVer])
if hostPaths != nil {
sdkVerStr := fmt.Sprintf("%d", ver)
if ver == AnySdkVersion {
sdkVerStr = "any" // a special keyword that means any SDK version
}
clcStr += fmt.Sprintf(" --host-context-for-sdk %s %s", sdkVerStr, strings.Join(hostClc, "#"))
clcStr += fmt.Sprintf(" --target-context-for-sdk %s %s", sdkVerStr, strings.Join(targetClc, "#"))
paths = append(paths, hostPaths...)
clcStr += fmt.Sprintf(" --host-context-for-sdk %s %s", sdkVerStr, hostClc)
clcStr += fmt.Sprintf(" --target-context-for-sdk %s %s", sdkVerStr, targetClc)
}
paths = append(paths, hostPaths...)
}
return clcStr, paths
return clcStr, android.FirstUniquePaths(paths)
}
func computeClassLoaderContextRec(clcs []*ClassLoaderContext) (string, string, android.Paths) {
var paths android.Paths
var clcsHost, clcsTarget []string
for _, clc := range clcs {
subClcHost, subClcTarget, subPaths := computeClassLoaderContextRec(clc.Subcontexts)
if subPaths != nil {
subClcHost = "{" + subClcHost + "}"
subClcTarget = "{" + subClcTarget + "}"
}
clcsHost = append(clcsHost, "PCL["+clc.Host.String()+"]"+subClcHost)
clcsTarget = append(clcsTarget, "PCL["+clc.Device+"]"+subClcTarget)
paths = append(paths, clc.Host)
paths = append(paths, subPaths...)
}
clcHost := strings.Join(clcsHost, "#")
clcTarget := strings.Join(clcsTarget, "#")
return clcHost, clcTarget, paths
}
// Paths to a <uses-library> on host and on device.
type jsonLibraryPath struct {
Host string
Device string
}
type jsonLibraryPaths map[string]jsonLibraryPath
// Class loader contexts that come from Make (via JSON dexpreopt.config) files have simpler
// structure than Soong class loader contexts: they are flat maps from a <uses-library> name to its
// on-host and on-device paths. There are no nested subcontexts. It is a limitation of the current
// Make implementation.
type jsonClassLoaderContext map[string]jsonLibraryPath
// convert JSON map of library paths to LibraryPaths
func constructLibraryPaths(ctx android.PathContext, paths jsonLibraryPaths) LibraryPaths {
m := LibraryPaths{}
for lib, path := range paths {
m[lib] = &LibraryPath{
constructPath(ctx, path.Host),
path.Device,
// A map from SDK version (represented with a JSON string) to JSON class loader context.
type jsonClassLoaderContextMap map[string]jsonClassLoaderContext
// Convert JSON class loader context map to ClassLoaderContextMap.
func fromJsonClassLoaderContext(ctx android.PathContext, jClcMap jsonClassLoaderContextMap) ClassLoaderContextMap {
clcMap := make(ClassLoaderContextMap)
for sdkVerStr, clc := range jClcMap {
sdkVer, ok := strconv.Atoi(sdkVerStr)
if ok != nil {
if sdkVerStr == "any" {
sdkVer = AnySdkVersion
} else {
android.ReportPathErrorf(ctx, "failed to parse SDK version in dexpreopt.config: '%s'", sdkVerStr)
}
}
for lib, path := range clc {
clcMap[sdkVer] = append(clcMap[sdkVer], &ClassLoaderContext{
Name: lib,
Host: constructPath(ctx, path.Host),
Device: path.Device,
Subcontexts: nil,
})
}
}
return m
return clcMap
}

View File

@ -37,91 +37,74 @@ func TestCLC(t *testing.T) {
// ├── b
// ├── c
// ├── d
// ├── a2
// ├── b2
// ── c2
// ├── a1
// ── b1
// │   ├── a2
// │   ├── b2
// │   └── c2
// │   ├── a1
// │   └── b1
// ├── f
// ├── a3
// └── b3
//
ctx := testContext()
lp := make(LibraryPaths)
m := make(ClassLoaderContextMap)
lp.AddLibraryPath(ctx, "a", buildPath(ctx, "a"), installPath(ctx, "a"))
lp.AddLibraryPath(ctx, "b", buildPath(ctx, "b"), installPath(ctx, "b"))
m.AddContext(ctx, "a", buildPath(ctx, "a"), installPath(ctx, "a"))
m.AddContext(ctx, "b", buildPath(ctx, "b"), installPath(ctx, "b"))
// "Maybe" variant in the good case: add as usual.
c := "c"
lp.MaybeAddLibraryPath(ctx, &c, buildPath(ctx, "c"), installPath(ctx, "c"))
m.MaybeAddContext(ctx, &c, buildPath(ctx, "c"), installPath(ctx, "c"))
// "Maybe" variant in the bad case: don't add library with unknown name, keep going.
lp.MaybeAddLibraryPath(ctx, nil, nil, nil)
m.MaybeAddContext(ctx, nil, nil, nil)
// Add some libraries with nested subcontexts.
lp1 := make(LibraryPaths)
lp1.AddLibraryPath(ctx, "a1", buildPath(ctx, "a1"), installPath(ctx, "a1"))
lp1.AddLibraryPath(ctx, "b1", buildPath(ctx, "b1"), installPath(ctx, "b1"))
m1 := make(ClassLoaderContextMap)
m1.AddContext(ctx, "a1", buildPath(ctx, "a1"), installPath(ctx, "a1"))
m1.AddContext(ctx, "b1", buildPath(ctx, "b1"), installPath(ctx, "b1"))
lp2 := make(LibraryPaths)
lp2.AddLibraryPath(ctx, "a2", buildPath(ctx, "a2"), installPath(ctx, "a2"))
lp2.AddLibraryPath(ctx, "b2", buildPath(ctx, "b2"), installPath(ctx, "b2"))
lp2.AddLibraryPath(ctx, "c2", buildPath(ctx, "c2"), installPath(ctx, "c2"))
lp2.AddLibraryPaths(lp1)
m2 := make(ClassLoaderContextMap)
m2.AddContext(ctx, "a2", buildPath(ctx, "a2"), installPath(ctx, "a2"))
m2.AddContext(ctx, "b2", buildPath(ctx, "b2"), installPath(ctx, "b2"))
m2.AddContextForSdk(ctx, AnySdkVersion, "c2", buildPath(ctx, "c2"), installPath(ctx, "c2"), m1)
lp.AddLibraryPath(ctx, "d", buildPath(ctx, "d"), installPath(ctx, "d"))
lp.AddLibraryPaths(lp2)
m3 := make(ClassLoaderContextMap)
m3.AddContext(ctx, "a3", buildPath(ctx, "a3"), installPath(ctx, "a3"))
m3.AddContext(ctx, "b3", buildPath(ctx, "b3"), installPath(ctx, "b3"))
lp3 := make(LibraryPaths)
lp3.AddLibraryPath(ctx, "f", buildPath(ctx, "f"), installPath(ctx, "f"))
lp3.AddLibraryPath(ctx, "a3", buildPath(ctx, "a3"), installPath(ctx, "a3"))
lp3.AddLibraryPath(ctx, "b3", buildPath(ctx, "b3"), installPath(ctx, "b3"))
lp.AddLibraryPaths(lp3)
m.AddContextForSdk(ctx, AnySdkVersion, "d", buildPath(ctx, "d"), installPath(ctx, "d"), m2)
// When the same library is both in conditional and unconditional context, it should be removed
// from conditional context.
m.AddContextForSdk(ctx, 42, "f", buildPath(ctx, "f"), installPath(ctx, "f"), nil)
m.AddContextForSdk(ctx, AnySdkVersion, "f", buildPath(ctx, "f"), installPath(ctx, "f"), nil)
m.AddContextMap(m3)
// Compatibility libraries with unknown install paths get default paths.
lp.AddLibraryPath(ctx, AndroidHidlBase, buildPath(ctx, AndroidHidlBase), nil)
lp.AddLibraryPath(ctx, AndroidHidlManager, buildPath(ctx, AndroidHidlManager), nil)
lp.AddLibraryPath(ctx, AndroidTestMock, buildPath(ctx, AndroidTestMock), nil)
module := testSystemModuleConfig(ctx, "test")
module.LibraryPaths = lp
m := make(classLoaderContextMap)
valid := true
ok, err := m.addLibs(ctx, AnySdkVersion, module, "a", "b", "c", "d", "a2", "b2", "c2", "a1", "b1", "f", "a3", "b3")
valid = valid && ok && err == nil
// Add compatibility libraries to conditional CLC for SDK level 29.
ok, err = m.addLibs(ctx, 29, module, AndroidHidlManager, AndroidHidlBase)
valid = valid && ok && err == nil
m.AddContextForSdk(ctx, 29, AndroidHidlManager, buildPath(ctx, AndroidHidlManager), nil, nil)
m.AddContextForSdk(ctx, 29, AndroidHidlBase, buildPath(ctx, AndroidHidlBase), nil, nil)
// Add "android.test.mock" to conditional CLC, observe that is gets removed because it is only
// needed as a compatibility library if "android.test.runner" is in CLC as well.
ok, err = m.addLibs(ctx, 30, module, AndroidTestMock)
valid = valid && ok && err == nil
m.AddContextForSdk(ctx, 30, AndroidTestMock, buildPath(ctx, AndroidTestMock), nil, nil)
// When the same library is both in conditional and unconditional context, it should be removed
// from conditional context.
ok, err = m.addLibs(ctx, 42, module, "f")
valid = valid && ok && err == nil
valid, validationError := validateClassLoaderContext(m)
fixConditionalClassLoaderContext(m)
fixClassLoaderContext(m)
var haveStr string
var havePaths android.Paths
var haveUsesLibs []string
if valid {
haveStr, havePaths = computeClassLoaderContext(ctx, m)
haveUsesLibs = m.usesLibs()
if valid && validationError == nil {
haveStr, havePaths = ComputeClassLoaderContext(m)
haveUsesLibs = m.UsesLibs()
}
// Test that validation is successful (all paths are known).
t.Run("validate", func(t *testing.T) {
if !valid {
if !(valid && validationError == nil) {
t.Errorf("invalid class loader context")
}
})
@ -135,14 +118,14 @@ func TestCLC(t *testing.T) {
"PCL[/system/framework/" + AndroidHidlManager + ".jar]#" +
"PCL[/system/framework/" + AndroidHidlBase + ".jar]" +
" --host-context-for-sdk any " +
"PCL[out/a.jar]#PCL[out/b.jar]#PCL[out/c.jar]#PCL[out/d.jar]#" +
"PCL[out/a2.jar]#PCL[out/b2.jar]#PCL[out/c2.jar]#" +
"PCL[out/a1.jar]#PCL[out/b1.jar]#" +
"PCL[out/a.jar]#PCL[out/b.jar]#PCL[out/c.jar]#PCL[out/d.jar]" +
"{PCL[out/a2.jar]#PCL[out/b2.jar]#PCL[out/c2.jar]" +
"{PCL[out/a1.jar]#PCL[out/b1.jar]}}#" +
"PCL[out/f.jar]#PCL[out/a3.jar]#PCL[out/b3.jar]" +
" --target-context-for-sdk any " +
"PCL[/system/a.jar]#PCL[/system/b.jar]#PCL[/system/c.jar]#PCL[/system/d.jar]#" +
"PCL[/system/a2.jar]#PCL[/system/b2.jar]#PCL[/system/c2.jar]#" +
"PCL[/system/a1.jar]#PCL[/system/b1.jar]#" +
"PCL[/system/a.jar]#PCL[/system/b.jar]#PCL[/system/c.jar]#PCL[/system/d.jar]" +
"{PCL[/system/a2.jar]#PCL[/system/b2.jar]#PCL[/system/c2.jar]" +
"{PCL[/system/a1.jar]#PCL[/system/b1.jar]}}#" +
"PCL[/system/f.jar]#PCL[/system/a3.jar]#PCL[/system/b3.jar]"
if wantStr != haveStr {
t.Errorf("\nwant class loader context: %s\nhave class loader context: %s", wantStr, haveStr)
@ -175,32 +158,40 @@ func TestCLC(t *testing.T) {
// Test that an unexpected unknown build path causes immediate error.
func TestCLCUnknownBuildPath(t *testing.T) {
ctx := testContext()
lp := make(LibraryPaths)
err := lp.addLibraryPath(ctx, "a", nil, nil, true)
checkError(t, err, "unknown build path to <uses-library> 'a'")
m := make(ClassLoaderContextMap)
err := m.addContext(ctx, AnySdkVersion, "a", nil, nil, true, nil)
checkError(t, err, "unknown build path to <uses-library> \"a\"")
}
// Test that an unexpected unknown install path causes immediate error.
func TestCLCUnknownInstallPath(t *testing.T) {
ctx := testContext()
lp := make(LibraryPaths)
err := lp.addLibraryPath(ctx, "a", buildPath(ctx, "a"), nil, true)
checkError(t, err, "unknown install path to <uses-library> 'a'")
m := make(ClassLoaderContextMap)
err := m.addContext(ctx, AnySdkVersion, "a", buildPath(ctx, "a"), nil, true, nil)
checkError(t, err, "unknown install path to <uses-library> \"a\"")
}
func TestCLCMaybeAdd(t *testing.T) {
ctx := testContext()
lp := make(LibraryPaths)
m := make(ClassLoaderContextMap)
a := "a"
lp.MaybeAddLibraryPath(ctx, &a, nil, nil)
m.MaybeAddContext(ctx, &a, nil, nil)
module := testSystemModuleConfig(ctx, "test")
module.LibraryPaths = lp
// The library should be added to <uses-library> tags by the manifest_fixer.
t.Run("maybe add", func(t *testing.T) {
haveUsesLibs := m.UsesLibs()
wantUsesLibs := []string{"a"}
if !reflect.DeepEqual(wantUsesLibs, haveUsesLibs) {
t.Errorf("\nwant uses libs: %s\nhave uses libs: %s", wantUsesLibs, haveUsesLibs)
}
})
m := make(classLoaderContextMap)
_, err := m.addLibs(ctx, AnySdkVersion, module, "a")
checkError(t, err, "dexpreopt cannot find path for <uses-library> 'a'")
// But class loader context in such cases should raise an error on validation.
t.Run("validate", func(t *testing.T) {
_, err := validateClassLoaderContext(m)
checkError(t, err, "invalid path for <uses-library> \"a\"")
})
}
func checkError(t *testing.T, have error, want string) {

View File

@ -114,10 +114,8 @@ type ModuleConfig struct {
ProfileIsTextListing bool
ProfileBootListing android.OptionalPath
EnforceUsesLibraries bool
OptionalUsesLibraries []string
UsesLibraries []string
LibraryPaths LibraryPaths
EnforceUsesLibraries bool
ClassLoaderContexts ClassLoaderContextMap
Archs []android.ArchType
DexPreoptImages []android.Path
@ -265,7 +263,7 @@ func ParseModuleConfig(ctx android.PathContext, data []byte) (*ModuleConfig, err
DexPath string
ManifestPath string
ProfileClassListing string
LibraryPaths jsonLibraryPaths
ClassLoaderContexts jsonClassLoaderContextMap
DexPreoptImages []string
DexPreoptImageLocations []string
PreoptBootClassPathDexFiles []string
@ -283,7 +281,7 @@ func ParseModuleConfig(ctx android.PathContext, data []byte) (*ModuleConfig, err
config.ModuleConfig.DexPath = constructPath(ctx, config.DexPath)
config.ModuleConfig.ManifestPath = constructPath(ctx, config.ManifestPath)
config.ModuleConfig.ProfileClassListing = android.OptionalPathForPath(constructPath(ctx, config.ProfileClassListing))
config.ModuleConfig.LibraryPaths = constructLibraryPaths(ctx, config.LibraryPaths)
config.ModuleConfig.ClassLoaderContexts = fromJsonClassLoaderContext(ctx, config.ClassLoaderContexts)
config.ModuleConfig.DexPreoptImages = constructPaths(ctx, config.DexPreoptImages)
config.ModuleConfig.DexPreoptImageLocations = config.DexPreoptImageLocations
config.ModuleConfig.PreoptBootClassPathDexFiles = constructPaths(ctx, config.PreoptBootClassPathDexFiles)

View File

@ -81,16 +81,18 @@ func GenerateDexpreoptRule(ctx android.PathContext, globalSoong *GlobalSoongConf
}
if !dexpreoptDisabled(ctx, global, module) {
if clc, err := genClassLoaderContext(ctx, global, module); err != nil {
if valid, err := validateClassLoaderContext(module.ClassLoaderContexts); err != nil {
android.ReportPathErrorf(ctx, err.Error())
} else if clc != nil {
} else if valid {
fixClassLoaderContext(module.ClassLoaderContexts)
appImage := (generateProfile || module.ForceCreateAppImage || global.DefaultAppImages) &&
!module.NoCreateAppImage
generateDM := shouldGenerateDM(module, global)
for archIdx, _ := range module.Archs {
dexpreoptCommand(ctx, globalSoong, global, module, rule, archIdx, *clc, profile, appImage, generateDM)
dexpreoptCommand(ctx, globalSoong, global, module, rule, archIdx, profile, appImage, generateDM)
}
}
}
@ -197,8 +199,8 @@ func bootProfileCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig,
}
func dexpreoptCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, global *GlobalConfig,
module *ModuleConfig, rule *android.RuleBuilder, archIdx int, classLoaderContexts classLoaderContextMap,
profile android.WritablePath, appImage bool, generateDM bool) {
module *ModuleConfig, rule *android.RuleBuilder, archIdx int, profile android.WritablePath,
appImage bool, generateDM bool) {
arch := module.Archs[archIdx]
@ -235,6 +237,16 @@ func dexpreoptCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, g
rule.Command().FlagWithOutput("rm -f ", odexPath)
if jarIndex := android.IndexList(module.Name, systemServerJars); jarIndex >= 0 {
// System server jars should be dexpreopted together: class loader context of each jar
// should include all preceding jars on the system server classpath.
var clcHost android.Paths
var clcTarget []string
for _, lib := range systemServerJars[:jarIndex] {
clcHost = append(clcHost, SystemServerDexJarHostPath(ctx, lib))
clcTarget = append(clcTarget, filepath.Join("/system/framework", lib+".jar"))
}
// Copy the system server jar to a predefined location where dex2oat will find it.
dexPathHost := SystemServerDexJarHostPath(ctx, module.Name)
rule.Command().Text("mkdir -p").Flag(filepath.Dir(dexPathHost.String()))
@ -242,11 +254,11 @@ func dexpreoptCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, g
checkSystemServerOrder(ctx, jarIndex)
clc := classLoaderContexts[AnySdkVersion]
rule.Command().
Text("class_loader_context_arg=--class-loader-context=PCL[" + strings.Join(clc.Host.Strings(), ":") + "]").
Implicits(clc.Host).
Text("stored_class_loader_context_arg=--stored-class-loader-context=PCL[" + strings.Join(clc.Target, ":") + "]")
Text("class_loader_context_arg=--class-loader-context=PCL[" + strings.Join(clcHost.Strings(), ":") + "]").
Implicits(clcHost).
Text("stored_class_loader_context_arg=--stored-class-loader-context=PCL[" + strings.Join(clcTarget, ":") + "]")
} else if module.EnforceUsesLibraries {
// Generate command that saves target SDK version in a shell variable.
if module.ManifestPath != nil {
@ -266,13 +278,15 @@ func dexpreoptCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, g
}
// Generate command that saves host and target class loader context in shell variables.
clc, paths := computeClassLoaderContext(ctx, classLoaderContexts)
clc, paths := ComputeClassLoaderContext(module.ClassLoaderContexts)
cmd := rule.Command().
Text(`eval "$(`).Tool(globalSoong.ConstructContext).
Text(` --target-sdk-version ${target_sdk_version}`).
Text(clc).Implicits(paths)
cmd.Text(`)"`)
} else {
// Other libraries or APKs for which the exact <uses-library> list is unknown.
// Pass special class loader context to skip the classpath and collision check.
// This will get removed once LOCAL_USES_LIBRARIES is enforced.
// Right now LOCAL_USES_LIBRARIES is opt in, for the case where it's not specified we still default

View File

@ -44,9 +44,7 @@ func testModuleConfig(ctx android.PathContext, name, partition string) *ModuleCo
ProfileClassListing: android.OptionalPath{},
ProfileIsTextListing: false,
EnforceUsesLibraries: false,
OptionalUsesLibraries: nil,
UsesLibraries: nil,
LibraryPaths: nil,
ClassLoaderContexts: nil,
Archs: []android.ArchType{android.Arm},
DexPreoptImages: android.Paths{android.PathForTesting("system/framework/arm/boot.art")},
DexPreoptImagesDeps: []android.OutputPaths{android.OutputPaths{}},

View File

@ -109,7 +109,7 @@ type aapt struct {
useEmbeddedNativeLibs bool
useEmbeddedDex bool
usesNonSdkApis bool
sdkLibraries dexpreopt.LibraryPaths
sdkLibraries dexpreopt.ClassLoaderContextMap
hasNoCode bool
LoggingParent string
resourceFiles android.Paths
@ -392,7 +392,7 @@ func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext sdkContext, ex
// aaptLibs collects libraries from dependencies and sdk_version and converts them into paths
func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStaticLibs, transitiveStaticLibManifests android.Paths,
staticRRODirs []rroDir, assets, deps android.Paths, flags []string, sdkLibraries dexpreopt.LibraryPaths) {
staticRRODirs []rroDir, assets, deps android.Paths, flags []string, sdkLibraries dexpreopt.ClassLoaderContextMap) {
var sharedLibs android.Paths
@ -401,7 +401,7 @@ func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStati
sharedLibs = append(sharedLibs, sdkDep.jars...)
}
sdkLibraries = make(dexpreopt.LibraryPaths)
sdkLibraries = make(dexpreopt.ClassLoaderContextMap)
ctx.VisitDirectDeps(func(module android.Module) {
var exportPackage android.Path
@ -411,7 +411,7 @@ func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStati
}
if dep, ok := module.(Dependency); ok {
sdkLibraries.AddLibraryPaths(dep.ExportedSdkLibs())
sdkLibraries.AddContextMap(dep.ExportedSdkLibs())
}
switch ctx.OtherModuleDependencyTag(module) {
@ -426,7 +426,7 @@ func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStati
// (including the java_sdk_library) itself then append any implicit sdk library
// names to the list of sdk libraries to be added to the manifest.
if component, ok := module.(SdkLibraryComponentDependency); ok {
sdkLibraries.MaybeAddLibraryPath(ctx, component.OptionalImplicitSdkLibrary(),
sdkLibraries.MaybeAddContext(ctx, component.OptionalImplicitSdkLibrary(),
component.DexJarBuildPath(), component.DexJarInstallPath())
}
@ -439,7 +439,7 @@ func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStati
transitiveStaticLibs = append(transitiveStaticLibs, aarDep.ExportedStaticPackages()...)
transitiveStaticLibs = append(transitiveStaticLibs, exportPackage)
transitiveStaticLibManifests = append(transitiveStaticLibManifests, aarDep.ExportedManifests()...)
sdkLibraries.AddLibraryPaths(aarDep.ExportedSdkLibs())
sdkLibraries.AddContextMap(aarDep.ExportedSdkLibs())
if aarDep.ExportedAssets().Valid() {
assets = append(assets, aarDep.ExportedAssets().Path())
}
@ -827,7 +827,7 @@ func (a *AARImport) AidlIncludeDirs() android.Paths {
return nil
}
func (a *AARImport) ExportedSdkLibs() dexpreopt.LibraryPaths {
func (a *AARImport) ExportedSdkLibs() dexpreopt.ClassLoaderContextMap {
return nil
}

View File

@ -43,8 +43,9 @@ var manifestMergerRule = pctx.AndroidStaticRule("manifestMerger",
"args", "libs")
// Uses manifest_fixer.py to inject minSdkVersion, etc. into an AndroidManifest.xml
func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext sdkContext, sdkLibraries dexpreopt.LibraryPaths,
isLibrary, useEmbeddedNativeLibs, usesNonSdkApis, useEmbeddedDex, hasNoCode bool, loggingParent string) android.Path {
func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext sdkContext,
sdkLibraries dexpreopt.ClassLoaderContextMap, isLibrary, useEmbeddedNativeLibs, usesNonSdkApis,
useEmbeddedDex, hasNoCode bool, loggingParent string) android.Path {
var args []string
if isLibrary {
@ -70,7 +71,7 @@ func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext
args = append(args, "--use-embedded-dex")
}
for _, usesLib := range android.SortedStringKeys(sdkLibraries) {
for _, usesLib := range sdkLibraries.UsesLibs() {
if inList(usesLib, dexpreopt.OptionalCompatUsesLibs) {
args = append(args, "--optional-uses-library", usesLib)
} else {

View File

@ -115,7 +115,7 @@ func (library *Library) AndroidMkEntries() []android.AndroidMkEntries {
entries.SetPath("LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR", library.jacocoReportClassesFile)
}
entries.AddStrings("LOCAL_EXPORT_SDK_LIBRARIES", android.SortedStringKeys(library.exportedSdkLibs)...)
entries.AddStrings("LOCAL_EXPORT_SDK_LIBRARIES", library.exportedSdkLibs.UsesLibs()...)
if len(library.additionalCheckedModules) != 0 {
entries.AddStrings("LOCAL_ADDITIONAL_CHECKED_MODULE", library.additionalCheckedModules.Strings()...)

View File

@ -601,7 +601,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, sdkLibs dexpreopt.LibraryPaths) android.Path {
func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext, sdkLibs dexpreopt.ClassLoaderContextMap) android.Path {
a.dexpreopter.installPath = a.installPath(ctx)
if a.dexProperties.Uncompress_dex == nil {
// If the value was not force-set by the user, use reasonable default based on the module.
@ -609,12 +609,10 @@ func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext, sdkLibs dexpreop
}
a.dexpreopter.uncompressedDex = *a.dexProperties.Uncompress_dex
a.dexpreopter.enforceUsesLibs = a.usesLibrary.enforceUsesLibraries()
a.dexpreopter.usesLibs = a.usesLibrary.usesLibraryProperties.Uses_libs
a.dexpreopter.optionalUsesLibs = a.usesLibrary.presentOptionalUsesLibs(ctx)
a.dexpreopter.libraryPaths = a.usesLibrary.usesLibraryPaths(ctx)
a.dexpreopter.libraryPaths.AddLibraryPaths(sdkLibs)
a.dexpreopter.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
a.dexpreopter.classLoaderContexts.AddContextMap(sdkLibs)
a.dexpreopter.manifestFile = a.mergedManifestFile
a.exportedSdkLibs = make(dexpreopt.LibraryPaths)
a.exportedSdkLibs = make(dexpreopt.ClassLoaderContextMap)
if ctx.ModuleName() != "framework-res" {
a.Module.compile(ctx, a.aaptSrcJar)
@ -791,7 +789,7 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) {
a.usesLibrary.freezeEnforceUsesLibraries()
// Add implicit SDK libraries to <uses-library> list.
for _, usesLib := range android.SortedStringKeys(a.aapt.sdkLibraries) {
for _, usesLib := range a.aapt.sdkLibraries.UsesLibs() {
a.usesLibrary.addLib(usesLib, inList(usesLib, dexpreopt.OptionalCompatUsesLibs))
}
@ -1540,9 +1538,7 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext
a.dexpreopter.uncompressedDex = a.shouldUncompressDex(ctx)
a.dexpreopter.enforceUsesLibs = a.usesLibrary.enforceUsesLibraries()
a.dexpreopter.usesLibs = a.usesLibrary.usesLibraryProperties.Uses_libs
a.dexpreopter.optionalUsesLibs = a.usesLibrary.presentOptionalUsesLibs(ctx)
a.dexpreopter.libraryPaths = a.usesLibrary.usesLibraryPaths(ctx)
a.dexpreopter.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
dexOutput := a.dexpreopter.dexpreopt(ctx, jnisUncompressed)
if a.dexpreopter.uncompressedDex {
@ -1976,17 +1972,18 @@ func (u *usesLibrary) presentOptionalUsesLibs(ctx android.BaseModuleContext) []s
return optionalUsesLibs
}
// usesLibraryPaths returns a map of module names of shared library dependencies to the paths
// Returns a map of module names of shared library dependencies to the paths
// to their dex jars on host and on device.
func (u *usesLibrary) usesLibraryPaths(ctx android.ModuleContext) dexpreopt.LibraryPaths {
usesLibPaths := make(dexpreopt.LibraryPaths)
func (u *usesLibrary) classLoaderContextForUsesLibDeps(ctx android.ModuleContext) dexpreopt.ClassLoaderContextMap {
clcMap := make(dexpreopt.ClassLoaderContextMap)
if !ctx.Config().UnbundledBuild() {
ctx.VisitDirectDeps(func(m android.Module) {
if _, ok := ctx.OtherModuleDependencyTag(m).(usesLibraryDependencyTag); ok {
if tag, ok := ctx.OtherModuleDependencyTag(m).(usesLibraryDependencyTag); ok {
dep := ctx.OtherModuleName(m)
if lib, ok := m.(Dependency); ok {
usesLibPaths.AddLibraryPath(ctx, dep, lib.DexJarBuildPath(), lib.DexJarInstallPath())
clcMap.AddContextForSdk(ctx, tag.sdkVersion, dep,
lib.DexJarBuildPath(), lib.DexJarInstallPath(), lib.ExportedSdkLibs())
} else if ctx.Config().AllowMissingDependencies() {
ctx.AddMissingDependencies([]string{dep})
} else {
@ -1996,7 +1993,7 @@ func (u *usesLibrary) usesLibraryPaths(ctx android.ModuleContext) dexpreopt.Libr
})
}
return usesLibPaths
return clcMap
}
// enforceUsesLibraries returns true of <uses-library> tags should be checked against uses_libs and optional_uses_libs

View File

@ -2815,11 +2815,11 @@ func TestUsesLibraries(t *testing.T) {
// Test that all present libraries are preopted, including implicit SDK dependencies, possibly stubs
cmd = app.Rule("dexpreopt").RuleParams.Command
w := `--target-context-for-sdk any ` +
`PCL[/system/framework/foo.jar]#` +
`PCL[/system/framework/quuz.jar]#` +
`PCL[/system/framework/qux.jar]#` +
`PCL[/system/framework/runtime-library.jar]#` +
`PCL[/system/framework/bar.jar]`
`PCL[/system/framework/quuz.jar]#` +
`PCL[/system/framework/foo.jar]#` +
`PCL[/system/framework/bar.jar]#` +
`PCL[/system/framework/runtime-library.jar]`
if !strings.Contains(cmd, w) {
t.Errorf("wanted %q in %q", w, cmd)
}

View File

@ -163,7 +163,7 @@ func (d *DeviceHostConverter) AidlIncludeDirs() android.Paths {
return nil
}
func (d *DeviceHostConverter) ExportedSdkLibs() dexpreopt.LibraryPaths {
func (d *DeviceHostConverter) ExportedSdkLibs() dexpreopt.ClassLoaderContextMap {
return nil
}

View File

@ -33,11 +33,9 @@ type dexpreopter struct {
isTest bool
isPresignedPrebuilt bool
manifestFile android.Path
usesLibs []string
optionalUsesLibs []string
enforceUsesLibs bool
libraryPaths dexpreopt.LibraryPaths
manifestFile android.Path
enforceUsesLibs bool
classLoaderContexts dexpreopt.ClassLoaderContextMap
builtInstalled string
}
@ -193,10 +191,8 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Mo
ProfileIsTextListing: profileIsTextListing,
ProfileBootListing: profileBootListing,
EnforceUsesLibraries: d.enforceUsesLibs,
OptionalUsesLibraries: d.optionalUsesLibs,
UsesLibraries: d.usesLibs,
LibraryPaths: d.libraryPaths,
EnforceUsesLibraries: d.enforceUsesLibs,
ClassLoaderContexts: d.classLoaderContexts,
Archs: archs,
DexPreoptImages: images,

View File

@ -416,8 +416,8 @@ type Module struct {
// manifest file to use instead of properties.Manifest
overrideManifest android.OptionalPath
// map of SDK libs exported by this java module to their build and install paths
exportedSdkLibs dexpreopt.LibraryPaths
// map of SDK version to class loader context
exportedSdkLibs dexpreopt.ClassLoaderContextMap
// list of plugins that this java module is exporting
exportedPluginJars android.Paths
@ -509,7 +509,7 @@ type Dependency interface {
ImplementationJars() android.Paths
ResourceJars() android.Paths
AidlIncludeDirs() android.Paths
ExportedSdkLibs() dexpreopt.LibraryPaths
ExportedSdkLibs() dexpreopt.ClassLoaderContextMap
ExportedPlugins() (android.Paths, []string)
SrcJarArgs() ([]string, android.Paths)
BaseModuleName() string
@ -1027,7 +1027,8 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps {
case libTag:
deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.sdkVersion())...)
// names of sdk libs that are directly depended are exported
j.exportedSdkLibs.MaybeAddLibraryPath(ctx, dep.OptionalImplicitSdkLibrary(), dep.DexJarBuildPath(), dep.DexJarInstallPath())
j.exportedSdkLibs.MaybeAddContext(ctx, dep.OptionalImplicitSdkLibrary(),
dep.DexJarBuildPath(), dep.DexJarInstallPath())
case staticLibTag:
ctx.ModuleErrorf("dependency on java_sdk_library %q can only be in libs", otherName)
}
@ -1038,7 +1039,7 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps {
case libTag, instrumentationForTag:
deps.classpath = append(deps.classpath, dep.HeaderJars()...)
// sdk lib names from dependencies are re-exported
j.exportedSdkLibs.AddLibraryPaths(dep.ExportedSdkLibs())
j.exportedSdkLibs.AddContextMap(dep.ExportedSdkLibs())
deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...)
pluginJars, pluginClasses := dep.ExportedPlugins()
addPlugins(&deps, pluginJars, pluginClasses...)
@ -1050,7 +1051,7 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps {
deps.staticHeaderJars = append(deps.staticHeaderJars, dep.HeaderJars()...)
deps.staticResourceJars = append(deps.staticResourceJars, dep.ResourceJars()...)
// sdk lib names from dependencies are re-exported
j.exportedSdkLibs.AddLibraryPaths(dep.ExportedSdkLibs())
j.exportedSdkLibs.AddContextMap(dep.ExportedSdkLibs())
deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...)
pluginJars, pluginClasses := dep.ExportedPlugins()
addPlugins(&deps, pluginJars, pluginClasses...)
@ -1902,7 +1903,7 @@ func (j *Module) AidlIncludeDirs() android.Paths {
return j.exportAidlIncludeDirs
}
func (j *Module) ExportedSdkLibs() dexpreopt.LibraryPaths {
func (j *Module) ExportedSdkLibs() dexpreopt.ClassLoaderContextMap {
return j.exportedSdkLibs
}
@ -2041,7 +2042,7 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) {
j.dexProperties.Uncompress_dex = proptools.BoolPtr(shouldUncompressDex(ctx, &j.dexpreopter))
}
j.dexpreopter.uncompressedDex = *j.dexProperties.Uncompress_dex
j.exportedSdkLibs = make(dexpreopt.LibraryPaths)
j.exportedSdkLibs = make(dexpreopt.ClassLoaderContextMap)
j.compile(ctx, nil)
// Collect the module directory for IDE info in java/jdeps.go.
@ -2061,11 +2062,12 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) {
// add the name of that java_sdk_library to the exported sdk libs to make sure
// that, if necessary, a <uses-library> element for that java_sdk_library is
// added to the Android manifest.
j.exportedSdkLibs.MaybeAddLibraryPath(ctx, j.OptionalImplicitSdkLibrary(), j.DexJarBuildPath(), j.DexJarInstallPath())
j.exportedSdkLibs.MaybeAddContext(ctx, j.OptionalImplicitSdkLibrary(),
j.DexJarBuildPath(), j.DexJarInstallPath())
// A non-SDK library may provide a <uses-library> (the name may be different from the module name).
if lib := proptools.String(j.usesLibraryProperties.Provides_uses_lib); lib != "" {
j.exportedSdkLibs.AddLibraryPath(ctx, lib, j.DexJarBuildPath(), j.DexJarInstallPath())
j.exportedSdkLibs.AddContext(ctx, lib, j.DexJarBuildPath(), j.DexJarInstallPath())
}
j.distFiles = j.GenerateTaggedDistFiles(ctx)
@ -2644,7 +2646,7 @@ type Import struct {
dexJarFile android.Path
combinedClasspathFile android.Path
exportedSdkLibs dexpreopt.LibraryPaths
exportedSdkLibs dexpreopt.ClassLoaderContextMap
exportAidlIncludeDirs android.Paths
hideApexVariantFromMake bool
@ -2719,7 +2721,7 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) {
TransformJetifier(ctx, outputFile, inputFile)
}
j.combinedClasspathFile = outputFile
j.exportedSdkLibs = make(dexpreopt.LibraryPaths)
j.exportedSdkLibs = make(dexpreopt.ClassLoaderContextMap)
var flags javaBuilderFlags
@ -2733,7 +2735,7 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) {
case libTag, staticLibTag:
flags.classpath = append(flags.classpath, dep.HeaderJars()...)
// sdk lib names from dependencies are re-exported
j.exportedSdkLibs.AddLibraryPaths(dep.ExportedSdkLibs())
j.exportedSdkLibs.AddContextMap(dep.ExportedSdkLibs())
case bootClasspathTag:
flags.bootClasspath = append(flags.bootClasspath, dep.HeaderJars()...)
}
@ -2742,7 +2744,8 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) {
case libTag:
flags.classpath = append(flags.classpath, dep.SdkHeaderJars(ctx, j.sdkVersion())...)
// names of sdk libs that are directly depended are exported
j.exportedSdkLibs.AddLibraryPath(ctx, otherName, dep.DexJarBuildPath(), dep.DexJarInstallPath())
j.exportedSdkLibs.AddContext(ctx, otherName,
dep.DexJarBuildPath(), dep.DexJarInstallPath())
}
}
})
@ -2757,7 +2760,8 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) {
// add the name of that java_sdk_library to the exported sdk libs to make sure
// that, if necessary, a <uses-library> element for that java_sdk_library is
// added to the Android manifest.
j.exportedSdkLibs.MaybeAddLibraryPath(ctx, j.OptionalImplicitSdkLibrary(), outputFile, installFile)
j.exportedSdkLibs.MaybeAddContext(ctx, j.OptionalImplicitSdkLibrary(),
outputFile, installFile)
j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.properties.Aidl.Export_include_dirs)
@ -2839,7 +2843,7 @@ func (j *Import) AidlIncludeDirs() android.Paths {
return j.exportAidlIncludeDirs
}
func (j *Import) ExportedSdkLibs() dexpreopt.LibraryPaths {
func (j *Import) ExportedSdkLibs() dexpreopt.ClassLoaderContextMap {
return j.exportedSdkLibs
}

View File

@ -1593,8 +1593,8 @@ func TestJavaSdkLibrary(t *testing.T) {
// test if baz has exported SDK lib names foo and bar to qux
qux := ctx.ModuleForTests("qux", "android_common")
if quxLib, ok := qux.Module().(*Library); ok {
sdkLibs := android.SortedStringKeys(quxLib.ExportedSdkLibs())
if w := []string{"bar", "foo", "fred", "quuz"}; !reflect.DeepEqual(w, sdkLibs) {
sdkLibs := quxLib.ExportedSdkLibs().UsesLibs()
if w := []string{"foo", "bar", "fred", "quuz"}; !reflect.DeepEqual(w, sdkLibs) {
t.Errorf("qux should export %q but exports %q", w, sdkLibs)
}
}