Unify handling of compat and normal libs in class loader contexts.
Also, add tests for compatibility libraries in class loader context. This CL separates special-case handling of compatibility libraries into a "fixup" step that is done after class loader context is constructed by Soong. This allows to handle compatibility libraries and normal libraries uniformly, which should enable further simplification of class loader context representation (in subsequent CLs). Currently the only "fixup" step is removal of libraries from conditional class loader context if they already are in unconditional context. This check cannot be done at the time when the libraries are added to conditional context, because the full uncoditional context is not yet known at that time. Previously construction of unconditional context was delayed, now it is no longer delayed and handled in the same way as unconditional context, and the "fixup" does the filtering. Test: lunch aosp_cf_x86_phone-userdebug && m Bug: 132357300 Change-Id: Ie71e9fb2d3d529b5317cd84e09ab3c853017c349
This commit is contained in:
@@ -195,6 +195,9 @@ func bootProfileCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig,
|
||||
}
|
||||
|
||||
type classLoaderContext struct {
|
||||
// Library names
|
||||
Names []string
|
||||
|
||||
// The class loader context using paths in the build.
|
||||
Host android.Paths
|
||||
|
||||
@@ -209,7 +212,7 @@ type classLoaderContext struct {
|
||||
// targetSdkVersion in the manifest or APK is less than that API version.
|
||||
type classLoaderContextMap map[int]*classLoaderContext
|
||||
|
||||
const anySdkVersion int = 9999 // should go last in class loader context
|
||||
const AnySdkVersion int = 9999 // should go last in class loader context
|
||||
|
||||
func (m classLoaderContextMap) getValue(sdkVer int) *classLoaderContext {
|
||||
if _, ok := m[sdkVer]; !ok {
|
||||
@@ -218,14 +221,19 @@ func (m classLoaderContextMap) getValue(sdkVer int) *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 {
|
||||
clc := m.getValue(sdkVer)
|
||||
for _, lib := range libs {
|
||||
if p, ok := module.LibraryPaths[lib]; ok && p.Host != nil && p.Device != UnknownInstallLibraryPath {
|
||||
clc.Host = append(clc.Host, p.Host)
|
||||
clc.Target = append(clc.Target, p.Device)
|
||||
clc.addLib(lib, p.Host, p.Device)
|
||||
} else {
|
||||
if sdkVer == anySdkVersion {
|
||||
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.
|
||||
android.ReportPathErrorf(ctx, "dexpreopt cannot find path for <uses-library> '%s'", lib)
|
||||
@@ -239,11 +247,17 @@ func (m classLoaderContextMap) addLibs(ctx android.PathContext, sdkVer int, modu
|
||||
return true
|
||||
}
|
||||
|
||||
func (m classLoaderContextMap) usesLibs() []string {
|
||||
if clc, ok := m[AnySdkVersion]; ok {
|
||||
return clc.Names
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m classLoaderContextMap) addSystemServerLibs(sdkVer int, ctx android.PathContext, module *ModuleConfig, libs ...string) {
|
||||
clc := m.getValue(sdkVer)
|
||||
for _, lib := range libs {
|
||||
clc.Host = append(clc.Host, SystemServerDexJarHostPath(ctx, lib))
|
||||
clc.Target = append(clc.Target, filepath.Join("/system/framework", lib+".jar"))
|
||||
clc.addLib(lib, SystemServerDexJarHostPath(ctx, lib), filepath.Join("/system/framework", lib+".jar"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -261,7 +275,7 @@ func (m classLoaderContextMap) addSystemServerLibs(sdkVer int, ctx android.PathC
|
||||
// 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.
|
||||
//
|
||||
// 2. All other library jars or APKs for which the exact <uses-library> list is unknown. They use
|
||||
// 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.
|
||||
@@ -273,21 +287,19 @@ func genClassLoaderContext(ctx android.PathContext, global *GlobalConfig, module
|
||||
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]...)
|
||||
classLoaderContexts.addSystemServerLibs(AnySdkVersion, ctx, module, systemServerJars[:jarIndex]...)
|
||||
|
||||
} else if module.EnforceUsesLibraries {
|
||||
// Unconditional class loader context.
|
||||
usesLibs := append(copyOf(module.UsesLibraries), module.OptionalUsesLibraries...)
|
||||
if !classLoaderContexts.addLibs(ctx, anySdkVersion, module, usesLibs...) {
|
||||
if !classLoaderContexts.addLibs(ctx, AnySdkVersion, module, usesLibs...) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Conditional class loader context for API version < 28.
|
||||
const httpLegacy = "org.apache.http.legacy"
|
||||
if !contains(usesLibs, httpLegacy) {
|
||||
if !classLoaderContexts.addLibs(ctx, 28, module, httpLegacy) {
|
||||
return nil
|
||||
}
|
||||
if !classLoaderContexts.addLibs(ctx, 28, module, httpLegacy) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Conditional class loader context for API version < 29.
|
||||
@@ -301,10 +313,8 @@ func genClassLoaderContext(ctx android.PathContext, global *GlobalConfig, module
|
||||
|
||||
// Conditional class loader context for API version < 30.
|
||||
const testBase = "android.test.base"
|
||||
if !contains(usesLibs, testBase) {
|
||||
if !classLoaderContexts.addLibs(ctx, 30, module, testBase) {
|
||||
return nil
|
||||
}
|
||||
if !classLoaderContexts.addLibs(ctx, 30, module, testBase) {
|
||||
return nil
|
||||
}
|
||||
|
||||
} else {
|
||||
@@ -314,9 +324,32 @@ func genClassLoaderContext(ctx android.PathContext, global *GlobalConfig, module
|
||||
// to the &.
|
||||
}
|
||||
|
||||
fixConditionalClassLoaderContext(classLoaderContexts)
|
||||
|
||||
return &classLoaderContexts
|
||||
}
|
||||
|
||||
// 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.
|
||||
func fixConditionalClassLoaderContext(clcMap classLoaderContextMap) {
|
||||
usesLibs := clcMap.usesLibs()
|
||||
|
||||
for sdkVer, clc := range clcMap {
|
||||
if sdkVer == AnySdkVersion {
|
||||
continue
|
||||
}
|
||||
clcMap[sdkVer] = &classLoaderContext{}
|
||||
for i, lib := range clc.Names {
|
||||
if android.InList(lib, usesLibs) {
|
||||
// skip compatibility libraries that are already included in unconditional context
|
||||
} else {
|
||||
clcMap[sdkVer].addLib(lib, clc.Host[i], clc.Target[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -363,7 +396,7 @@ func dexpreoptCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, g
|
||||
|
||||
checkSystemServerOrder(ctx, jarIndex)
|
||||
|
||||
clc := classLoaderContexts[anySdkVersion]
|
||||
clc := classLoaderContexts[AnySdkVersion]
|
||||
rule.Command().
|
||||
Text("class_loader_context_arg=--class-loader-context=PCL[" + strings.Join(clc.Host.Strings(), ":") + "]").
|
||||
Implicits(clc.Host).
|
||||
@@ -391,14 +424,15 @@ func dexpreoptCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, g
|
||||
Text(`eval "$(`).Tool(globalSoong.ConstructContext).
|
||||
Text(` --target-sdk-version ${target_sdk_version}`)
|
||||
for _, ver := range android.SortedIntKeys(classLoaderContexts) {
|
||||
clc := classLoaderContexts.getValue(ver)
|
||||
verString := fmt.Sprintf("%d", ver)
|
||||
if ver == anySdkVersion {
|
||||
verString = "any" // a special keyword that means any SDK version
|
||||
if clc := classLoaderContexts.getValue(ver); len(clc.Host) > 0 {
|
||||
verString := fmt.Sprintf("%d", ver)
|
||||
if ver == AnySdkVersion {
|
||||
verString = "any" // a special keyword that means any SDK version
|
||||
}
|
||||
cmd.Textf(`--host-classpath-for-sdk %s %s`, verString, strings.Join(clc.Host.Strings(), ":")).
|
||||
Implicits(clc.Host).
|
||||
Textf(`--target-classpath-for-sdk %s %s`, verString, strings.Join(clc.Target, ":"))
|
||||
}
|
||||
cmd.Textf(`--host-classpath-for-sdk %s %s`, verString, strings.Join(clc.Host.Strings(), ":")).
|
||||
Implicits(clc.Host).
|
||||
Textf(`--target-classpath-for-sdk %s %s`, verString, strings.Join(clc.Target, ":"))
|
||||
}
|
||||
cmd.Text(`)"`)
|
||||
} else {
|
||||
|
Reference in New Issue
Block a user