Move class loader context definitions to a separate file.
Test: lunch aosp_cf_x86_phone-userdebug && m
Bug: 132357300
Change-Id: I1e7e9db1654d0b835276be1cfa6a8eeffc5e96ee
diff --git a/dexpreopt/Android.bp b/dexpreopt/Android.bp
index b8f7ea6..94c0361 100644
--- a/dexpreopt/Android.bp
+++ b/dexpreopt/Android.bp
@@ -2,6 +2,7 @@
name: "soong-dexpreopt",
pkgPath: "android/soong/dexpreopt",
srcs: [
+ "class_loader_context.go",
"config.go",
"dexpreopt.go",
"testing.go",
diff --git a/dexpreopt/class_loader_context.go b/dexpreopt/class_loader_context.go
new file mode 100644
index 0000000..48269e6
--- /dev/null
+++ b/dexpreopt/class_loader_context.go
@@ -0,0 +1,377 @@
+// Copyright 2020 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package dexpreopt
+
+import (
+ "fmt"
+ "path/filepath"
+ "strings"
+
+ "android/soong/android"
+)
+
+// These libs are added as <uses-library> dependencies for apps if the targetSdkVersion in the
+// app manifest is less than the specified version. This is needed because these libraries haven't
+// existed prior to certain SDK version, but classes in them were in bootclasspath jars, etc.
+// Some of the compatibility libraries are optional (their <uses-library> tag has "required=false"),
+// so that if this library is missing this in not a build or run-time error.
+var OrgApacheHttpLegacy = "org.apache.http.legacy"
+var AndroidTestBase = "android.test.base"
+var AndroidTestMock = "android.test.mock"
+var AndroidHidlBase = "android.hidl.base-V1.0-java"
+var AndroidHidlManager = "android.hidl.manager-V1.0-java"
+
+var OptionalCompatUsesLibs28 = []string{
+ OrgApacheHttpLegacy,
+}
+var OptionalCompatUsesLibs30 = []string{
+ AndroidTestBase,
+ AndroidTestMock,
+}
+var CompatUsesLibs29 = []string{
+ AndroidHidlBase,
+ AndroidHidlManager,
+}
+var OptionalCompatUsesLibs = append(android.CopyOf(OptionalCompatUsesLibs28), OptionalCompatUsesLibs30...)
+var CompatUsesLibs = android.CopyOf(CompatUsesLibs29)
+
+const UnknownInstallLibraryPath = "error"
+
+const AnySdkVersion int = 9999 // should go last in class loader context
+
+// LibraryPath contains paths to the library DEX jar on host and on device.
+type LibraryPath struct {
+ Host android.Path
+ Device string
+}
+
+// LibraryPaths is a map from library name to on-host and on-device paths to its DEX jar.
+type LibraryPaths map[string]*LibraryPath
+
+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.ModuleContext, lib string,
+ hostPath, installPath android.Path, strict bool) {
+
+ // 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
+ // possible to construct class loader context without on-host and on-device library paths.
+ strict = strict && !ctx.Config().AllowMissingDependencies()
+
+ if hostPath == nil && strict {
+ android.ReportPathErrorf(ctx, "unknown build path to <uses-library> '%s'", lib)
+ }
+
+ 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 {
+ android.ReportPathErrorf(ctx, "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))
+ } 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
+ }
+ libPaths[lib] = &LibraryPath{hostPath, devicePath}
+ }
+}
+
+// Add a new library path to the map. Enforce checks that the library paths exist.
+func (libPaths LibraryPaths) AddLibraryPath(ctx android.ModuleContext, lib string, hostPath, installPath android.Path) {
+ libPaths.addLibraryPath(ctx, lib, hostPath, installPath, true)
+}
+
+// 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.ModuleContext, lib *string, hostPath, installPath android.Path) {
+ if lib != nil {
+ libPaths.addLibraryPath(ctx, *lib, hostPath, installPath, false)
+ }
+}
+
+// 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
+ }
+ }
+}
+
+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 {
+ 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.
+ android.ReportPathErrorf(ctx, "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
+ }
+ }
+ return true
+}
+
+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"))
+ }
+}
+
+func (m classLoaderContextMap) usesLibs() []string {
+ if clc, ok := m[AnySdkVersion]; ok {
+ return clc.Names
+ }
+ 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 {
+ 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 !classLoaderContexts.addLibs(ctx, AnySdkVersion, module, usesLibs...) {
+ return nil
+ }
+
+ // Conditional class loader context for API version < 28.
+ const httpLegacy = "org.apache.http.legacy"
+ if !classLoaderContexts.addLibs(ctx, 28, module, httpLegacy) {
+ return nil
+ }
+
+ // Conditional class loader context for API version < 29.
+ usesLibs29 := []string{
+ "android.hidl.base-V1.0-java",
+ "android.hidl.manager-V1.0-java",
+ }
+ if !classLoaderContexts.addLibs(ctx, 29, module, usesLibs29...) {
+ return nil
+ }
+
+ // Conditional class loader context for API version < 30.
+ if !classLoaderContexts.addLibs(ctx, 30, module, OptionalCompatUsesLibs30...) {
+ return nil
+ }
+
+ } 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
+}
+
+// Find build and install paths to "android.hidl.base". The library must be present in conditional
+// class loader context for SDK version 29, because it's one of the compatibility libraries.
+func findHidlBasePaths(ctx android.PathContext, clcMap classLoaderContextMap) (android.Path, string) {
+ var hostPath android.Path
+ targetPath := UnknownInstallLibraryPath
+
+ if clc, ok := clcMap[29]; ok {
+ for i, lib := range clc.Names {
+ if lib == AndroidHidlBase {
+ hostPath = clc.Host[i]
+ targetPath = clc.Target[i]
+ break
+ }
+ }
+ }
+
+ // Fail if the library paths were not found. This may happen if the function is called at the
+ // wrong time (either before the compatibility libraries were added to context, or after they
+ // have been removed for some reason).
+ if hostPath == nil {
+ android.ReportPathErrorf(ctx, "dexpreopt cannot find build path to '%s'", AndroidHidlBase)
+ } else if targetPath == UnknownInstallLibraryPath {
+ android.ReportPathErrorf(ctx, "dexpreopt cannot find install path to '%s'", AndroidHidlBase)
+ }
+
+ return hostPath, targetPath
+}
+
+// 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):
+// - move handling of android.hidl.manager -> android.hidl.base dependency here
+// - remove android.hidl.manager and android.hidl.base unless the app is a system app.
+//
+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 if lib == 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])
+ }
+ }
+ }
+}
+
+// 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) {
+ hidlBaseHostPath, hidlBaseTargetPath := findHidlBasePaths(ctx, clcMap)
+
+ 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")
+ }
+
+ 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] + "]"
+
+ // Add dependency of android.hidl.manager on android.hidl.base (it is not tracked as
+ // a regular dependency by the build system, so it needs special handling).
+ if clc.Names[i] == AndroidHidlManager {
+ hostStr += "{PCL[" + hidlBaseHostPath.String() + "]}"
+ targetStr += "{PCL[" + hidlBaseTargetPath + "]}"
+ hostPaths = append(hostPaths, hidlBaseHostPath)
+ }
+
+ hostClc = append(hostClc, hostStr)
+ targetClc = append(targetClc, targetStr)
+ hostPaths = append(hostPaths, clc.Host[i])
+ }
+
+ 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...)
+ }
+ }
+
+ return clcStr, paths
+}
+
+type jsonLibraryPath struct {
+ Host string
+ Device string
+}
+
+type jsonLibraryPaths 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,
+ }
+ }
+ return m
+}
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index 2052847..03accc8 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -100,104 +100,6 @@
ConstructContext android.Path
}
-// These libs are added as <uses-library> dependencies for apps if the targetSdkVersion in the
-// app manifest is less than the specified version. This is needed because these libraries haven't
-// existed prior to certain SDK version, but classes in them were in bootclasspath jars, etc.
-// Some of the compatibility libraries are optional (their <uses-library> tag has "required=false"),
-// so that if this library is missing this in not a build or run-time error.
-var OrgApacheHttpLegacy = "org.apache.http.legacy"
-var AndroidTestBase = "android.test.base"
-var AndroidTestMock = "android.test.mock"
-var AndroidHidlBase = "android.hidl.base-V1.0-java"
-var AndroidHidlManager = "android.hidl.manager-V1.0-java"
-
-var OptionalCompatUsesLibs28 = []string{
- OrgApacheHttpLegacy,
-}
-var OptionalCompatUsesLibs30 = []string{
- AndroidTestBase,
- AndroidTestMock,
-}
-var CompatUsesLibs29 = []string{
- AndroidHidlBase,
- AndroidHidlManager,
-}
-var OptionalCompatUsesLibs = append(android.CopyOf(OptionalCompatUsesLibs28), OptionalCompatUsesLibs30...)
-var CompatUsesLibs = android.CopyOf(CompatUsesLibs29)
-
-const UnknownInstallLibraryPath = "error"
-
-// LibraryPath contains paths to the library DEX jar on host and on device.
-type LibraryPath struct {
- Host android.Path
- Device string
-}
-
-// LibraryPaths is a map from library name to on-host and on-device paths to its DEX jar.
-type LibraryPaths map[string]*LibraryPath
-
-// 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.ModuleContext, lib string,
- hostPath, installPath android.Path, strict bool) {
-
- // 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
- // possible to construct class loader context without on-host and on-device library paths.
- strict = strict && !ctx.Config().AllowMissingDependencies()
-
- if hostPath == nil && strict {
- android.ReportPathErrorf(ctx, "unknown build path to <uses-library> '%s'", lib)
- }
-
- 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 {
- android.ReportPathErrorf(ctx, "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))
- } 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
- }
- libPaths[lib] = &LibraryPath{hostPath, devicePath}
- }
-}
-
-// Add a new library path to the map. Enforce checks that the library paths exist.
-func (libPaths LibraryPaths) AddLibraryPath(ctx android.ModuleContext, lib string, hostPath, installPath android.Path) {
- libPaths.addLibraryPath(ctx, lib, hostPath, installPath, true)
-}
-
-// 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.ModuleContext, lib *string, hostPath, installPath android.Path) {
- if lib != nil {
- libPaths.addLibraryPath(ctx, *lib, hostPath, installPath, false)
- }
-}
-
-// 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
- }
- }
-}
-
type ModuleConfig struct {
Name string
DexLocation string // dex location on device
@@ -354,13 +256,6 @@
// from Make to read the module dexpreopt.config written in the Make config
// stage.
func ParseModuleConfig(ctx android.PathContext, data []byte) (*ModuleConfig, error) {
- type jsonLibraryPath struct {
- Host string
- Device string
- }
-
- type jsonLibraryPaths map[string]jsonLibraryPath
-
type ModuleJSONConfig struct {
*ModuleConfig
@@ -376,18 +271,6 @@
PreoptBootClassPathDexFiles []string
}
- // convert JSON map of library paths to LibraryPaths
- constructLibraryPaths := func(ctx android.PathContext, paths jsonLibraryPaths) LibraryPaths {
- m := LibraryPaths{}
- for lib, path := range paths {
- m[lib] = &LibraryPath{
- constructPath(ctx, path.Host),
- path.Device,
- }
- }
- return m
- }
-
config := ModuleJSONConfig{}
err := json.Unmarshal(data, &config)
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index 66e765f..51d1157 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -194,243 +194,6 @@
return profilePath
}
-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
-
-const AnySdkVersion int = 9999 // should go last in class loader context
-
-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 {
- 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.
- android.ReportPathErrorf(ctx, "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
- }
- }
- 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.addLib(lib, SystemServerDexJarHostPath(ctx, lib), filepath.Join("/system/framework", lib+".jar"))
- }
-}
-
-// 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 {
- 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 !classLoaderContexts.addLibs(ctx, AnySdkVersion, module, usesLibs...) {
- return nil
- }
-
- // Conditional class loader context for API version < 28.
- const httpLegacy = "org.apache.http.legacy"
- if !classLoaderContexts.addLibs(ctx, 28, module, httpLegacy) {
- return nil
- }
-
- // Conditional class loader context for API version < 29.
- usesLibs29 := []string{
- "android.hidl.base-V1.0-java",
- "android.hidl.manager-V1.0-java",
- }
- if !classLoaderContexts.addLibs(ctx, 29, module, usesLibs29...) {
- return nil
- }
-
- // Conditional class loader context for API version < 30.
- if !classLoaderContexts.addLibs(ctx, 30, module, OptionalCompatUsesLibs30...) {
- return nil
- }
-
- } 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
-}
-
-// Find build and install paths to "android.hidl.base". The library must be present in conditional
-// class loader context for SDK version 29, because it's one of the compatibility libraries.
-func findHidlBasePaths(ctx android.PathContext, clcMap classLoaderContextMap) (android.Path, string) {
- var hostPath android.Path
- targetPath := UnknownInstallLibraryPath
-
- if clc, ok := clcMap[29]; ok {
- for i, lib := range clc.Names {
- if lib == AndroidHidlBase {
- hostPath = clc.Host[i]
- targetPath = clc.Target[i]
- break
- }
- }
- }
-
- // Fail if the library paths were not found. This may happen if the function is called at the
- // wrong time (either before the compatibility libraries were added to context, or after they
- // have been removed for some reason).
- if hostPath == nil {
- android.ReportPathErrorf(ctx, "dexpreopt cannot find build path to '%s'", AndroidHidlBase)
- } else if targetPath == UnknownInstallLibraryPath {
- android.ReportPathErrorf(ctx, "dexpreopt cannot find install path to '%s'", AndroidHidlBase)
- }
-
- return hostPath, targetPath
-}
-
-// 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):
-// - move handling of android.hidl.manager -> android.hidl.base dependency here
-// - remove android.hidl.manager and android.hidl.base unless the app is a system app.
-//
-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 if lib == 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])
- }
- }
- }
-}
-
-// 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) {
- hidlBaseHostPath, hidlBaseTargetPath := findHidlBasePaths(ctx, clcMap)
-
- 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")
- }
-
- 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] + "]"
-
- // Add dependency of android.hidl.manager on android.hidl.base (it is not tracked as
- // a regular dependency by the build system, so it needs special handling).
- if clc.Names[i] == AndroidHidlManager {
- hostStr += "{PCL[" + hidlBaseHostPath.String() + "]}"
- targetStr += "{PCL[" + hidlBaseTargetPath + "]}"
- hostPaths = append(hostPaths, hidlBaseHostPath)
- }
-
- hostClc = append(hostClc, hostStr)
- targetClc = append(targetClc, targetStr)
- hostPaths = append(hostPaths, clc.Host[i])
- }
-
- 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...)
- }
- }
-
- return clcStr, paths
-}
-
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) {