Merge "Update apex/allowed_deps.txt"
diff --git a/Android.bp b/Android.bp
index 3075d67..4d69877 100644
--- a/Android.bp
+++ b/Android.bp
@@ -47,6 +47,7 @@
defaults: ["linux_bionic_supported"],
vendor_available: true,
ramdisk_available: true,
+ vendor_ramdisk_available: true,
recovery_available: true,
native_bridge_supported: true,
@@ -94,6 +95,7 @@
defaults: ["linux_bionic_supported"],
vendor_available: true,
ramdisk_available: true,
+ vendor_ramdisk_available: true,
recovery_available: true,
native_bridge_supported: true,
sdk_version: "current",
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 210d67a8..c87a945 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -29,10 +29,16 @@
"github.com/google/blueprint/bootstrap"
)
+type CqueryRequestType int
+
+const (
+ getAllFiles CqueryRequestType = iota
+)
+
// Map key to describe bazel cquery requests.
type cqueryKey struct {
- label string
- starlarkExpr string
+ label string
+ requestType CqueryRequestType
}
type BazelContext interface {
@@ -61,6 +67,7 @@
bazelPath string
outputBase string
workspaceDir string
+ buildDir string
requests map[cqueryKey]bool // cquery requests that have not yet been issued to Bazel
requestMutex sync.Mutex // requests can be written in parallel
@@ -96,8 +103,7 @@
var _ BazelContext = MockBazelContext{}
func (bazelCtx *bazelContext) GetAllFiles(label string) ([]string, bool) {
- starlarkExpr := "', '.join([f.path for f in target.files.to_list()])"
- result, ok := bazelCtx.cquery(label, starlarkExpr)
+ result, ok := bazelCtx.cquery(label, getAllFiles)
if ok {
bazelOutput := strings.TrimSpace(result)
return strings.Split(bazelOutput, ", "), true
@@ -119,11 +125,13 @@
}
func NewBazelContext(c *config) (BazelContext, error) {
- if c.Getenv("USE_BAZEL") != "1" {
+ // TODO(cparsons): Assess USE_BAZEL=1 instead once "mixed Soong/Bazel builds"
+ // are production ready.
+ if c.Getenv("USE_BAZEL_ANALYSIS") != "1" {
return noopBazelContext{}, nil
}
- bazelCtx := bazelContext{requests: make(map[cqueryKey]bool)}
+ bazelCtx := bazelContext{buildDir: c.buildDir, requests: make(map[cqueryKey]bool)}
missingEnvVars := []string{}
if len(c.Getenv("BAZEL_HOME")) > 1 {
bazelCtx.homeDir = c.Getenv("BAZEL_HOME")
@@ -161,8 +169,8 @@
// If the given request was already made (and the results are available), then
// returns (result, true). If the request is queued but no results are available,
// then returns ("", false).
-func (context *bazelContext) cquery(label string, starlarkExpr string) (string, bool) {
- key := cqueryKey{label, starlarkExpr}
+func (context *bazelContext) cquery(label string, requestType CqueryRequestType) (string, bool) {
+ key := cqueryKey{label, requestType}
if result, ok := context.results[key]; ok {
return result, true
} else {
@@ -184,7 +192,8 @@
func (context *bazelContext) issueBazelCommand(command string, labels []string,
extraFlags ...string) (string, error) {
- cmdFlags := []string{"--output_base=" + context.outputBase, command}
+ cmdFlags := []string{"--bazelrc=build/bazel/common.bazelrc",
+ "--output_base=" + context.outputBase, command}
cmdFlags = append(cmdFlags, labels...)
cmdFlags = append(cmdFlags, extraFlags...)
@@ -202,27 +211,113 @@
}
}
+func (context *bazelContext) mainBzlFileContents() []byte {
+ contents := `
+# This file is generated by soong_build. Do not edit.
+def _mixed_build_root_impl(ctx):
+ return [DefaultInfo(files = depset(ctx.files.deps))]
+
+mixed_build_root = rule(
+ implementation = _mixed_build_root_impl,
+ attrs = {"deps" : attr.label_list()},
+)
+`
+ return []byte(contents)
+}
+
+func (context *bazelContext) mainBuildFileContents() []byte {
+ formatString := `
+# This file is generated by soong_build. Do not edit.
+load(":main.bzl", "mixed_build_root")
+
+mixed_build_root(name = "buildroot",
+ deps = [%s],
+)
+`
+ var buildRootDeps []string = nil
+ for val, _ := range context.requests {
+ buildRootDeps = append(buildRootDeps, fmt.Sprintf("\"%s\"", val.label))
+ }
+ buildRootDepsString := strings.Join(buildRootDeps, ",\n ")
+
+ return []byte(fmt.Sprintf(formatString, buildRootDepsString))
+}
+
+func (context *bazelContext) cqueryStarlarkFileContents() []byte {
+ formatString := `
+# This file is generated by soong_build. Do not edit.
+getAllFilesLabels = {
+ %s
+}
+
+def format(target):
+ if str(target.label) in getAllFilesLabels:
+ return str(target.label) + ">>" + ', '.join([f.path for f in target.files.to_list()])
+ else:
+ # This target was not requested via cquery, and thus must be a dependency
+ # of a requested target.
+ return ""
+`
+ var buildRootDeps []string = nil
+ // TODO(cparsons): Sort by request type instead of assuming all requests
+ // are of GetAllFiles type.
+ for val, _ := range context.requests {
+ buildRootDeps = append(buildRootDeps, fmt.Sprintf("\"%s\" : True", val.label))
+ }
+ buildRootDepsString := strings.Join(buildRootDeps, ",\n ")
+
+ return []byte(fmt.Sprintf(formatString, buildRootDepsString))
+}
+
// Issues commands to Bazel to receive results for all cquery requests
// queued in the BazelContext.
func (context *bazelContext) InvokeBazel() error {
context.results = make(map[cqueryKey]string)
- var labels []string
var cqueryOutput string
var err error
+ err = ioutil.WriteFile(
+ absolutePath(filepath.Join(context.buildDir, "main.bzl")),
+ context.mainBzlFileContents(), 0666)
+ if err != nil {
+ return err
+ }
+ err = ioutil.WriteFile(
+ absolutePath(filepath.Join(context.buildDir, "BUILD.bazel")),
+ context.mainBuildFileContents(), 0666)
+ if err != nil {
+ return err
+ }
+ cquery_file_relpath := filepath.Join(context.buildDir, "buildroot.cquery")
+ err = ioutil.WriteFile(
+ absolutePath(cquery_file_relpath),
+ context.cqueryStarlarkFileContents(), 0666)
+ if err != nil {
+ return err
+ }
+ buildroot_label := fmt.Sprintf("//%s:buildroot", context.buildDir)
+ cqueryOutput, err = context.issueBazelCommand("cquery",
+ []string{fmt.Sprintf("deps(%s)", buildroot_label)},
+ "--output=starlark",
+ "--starlark:file="+cquery_file_relpath)
+
+ if err != nil {
+ return err
+ }
+
+ cqueryResults := map[string]string{}
+ for _, outputLine := range strings.Split(cqueryOutput, "\n") {
+ if strings.Contains(outputLine, ">>") {
+ splitLine := strings.SplitN(outputLine, ">>", 2)
+ cqueryResults[splitLine[0]] = splitLine[1]
+ }
+ }
+
for val, _ := range context.requests {
- labels = append(labels, val.label)
-
- // TODO(cparsons): Combine requests into a batch cquery request.
- // TODO(cparsons): Use --query_file to avoid command line limits.
- cqueryOutput, err = context.issueBazelCommand("cquery", []string{val.label},
- "--output=starlark",
- "--starlark:expr="+val.starlarkExpr)
-
- if err != nil {
- return err
+ if cqueryResult, ok := cqueryResults[val.label]; ok {
+ context.results[val] = string(cqueryResult)
} else {
- context.results[val] = string(cqueryOutput)
+ return fmt.Errorf("missing result for bazel target %s", val.label)
}
}
@@ -231,7 +326,7 @@
// bazel actions should either be added to the Ninja file and executed later,
// or bazel should handle execution.
// TODO(cparsons): Use --target_pattern_file to avoid command line limits.
- _, err = context.issueBazelCommand("build", labels)
+ _, err = context.issueBazelCommand("build", []string{buildroot_label})
if err != nil {
return err
diff --git a/bazel/bazelenv.sh b/bazel/bazelenv.sh
index 2ca8baf..fcf71f1 100755
--- a/bazel/bazelenv.sh
+++ b/bazel/bazelenv.sh
@@ -59,12 +59,16 @@
export BAZEL_PATH="$(which bazel)"
fi
-export USE_BAZEL=1
+# TODO(cparsons): Use USE_BAZEL=1 instead once "mixed Soong/Bazel builds" are
+# production ready.
+export USE_BAZEL_ANALYSIS=1
+# TODO(cparsons): Retrieve this information in either envsetup.sh or
+# bazel.sh.
export BAZEL_HOME="$BASE_DIR/bazelhome"
export BAZEL_OUTPUT_BASE="$BASE_DIR/output"
export BAZEL_WORKSPACE="$(gettop)"
-echo "USE_BAZEL=${USE_BAZEL}"
+echo "USE_BAZEL_ANALYSIS=${USE_BAZEL_ANALYSIS}"
echo "BAZEL_PATH=${BAZEL_PATH}"
echo "BAZEL_HOME=${BAZEL_HOME}"
echo "BAZEL_OUTPUT_BASE=${BAZEL_OUTPUT_BASE}"
diff --git a/cc/cc.go b/cc/cc.go
index c93bdeb..3b01fb2 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -3085,6 +3085,12 @@
}
}
+func squashVendorRamdiskSrcs(m *Module) {
+ if lib, ok := m.compiler.(*libraryDecorator); ok {
+ lib.baseCompiler.Properties.Exclude_srcs = append(lib.baseCompiler.Properties.Exclude_srcs, lib.baseCompiler.Properties.Target.Vendor_ramdisk.Exclude_srcs...)
+ }
+}
+
func (c *Module) IsSdkVariant() bool {
return c.Properties.IsSdkVariant || c.AlwaysSdk()
}
diff --git a/cc/compiler.go b/cc/compiler.go
index 21da2fc..e2a33d7 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -177,6 +177,15 @@
// build the recovery variant of the C/C++ module.
Exclude_generated_sources []string
}
+ Vendor_ramdisk struct {
+ // list of source files that should not be used to
+ // build the vendor ramdisk variant of the C/C++ module.
+ Exclude_srcs []string `android:"path"`
+
+ // List of additional cflags that should be used to build the vendor ramdisk
+ // variant of the C/C++ module.
+ Cflags []string
+ }
}
Proto struct {
@@ -290,6 +299,7 @@
CheckBadCompilerFlags(ctx, "asflags", compiler.Properties.Asflags)
CheckBadCompilerFlags(ctx, "vendor.cflags", compiler.Properties.Target.Vendor.Cflags)
CheckBadCompilerFlags(ctx, "recovery.cflags", compiler.Properties.Target.Recovery.Cflags)
+ CheckBadCompilerFlags(ctx, "vendor_ramdisk.cflags", compiler.Properties.Target.Vendor_ramdisk.Cflags)
esc := proptools.NinjaAndShellEscapeList
@@ -471,6 +481,10 @@
flags.Local.CFlags = append(flags.Local.CFlags, esc(compiler.Properties.Target.Recovery.Cflags)...)
}
+ if ctx.inVendorRamdisk() {
+ flags.Local.CFlags = append(flags.Local.CFlags, esc(compiler.Properties.Target.Vendor_ramdisk.Cflags)...)
+ }
+
// We can enforce some rules more strictly in the code we own. strict
// indicates if this is code that we can be stricter with. If we have
// rules that we want to apply to *our* code (but maybe can't for
diff --git a/cc/image.go b/cc/image.go
index ba091e1..7b9425f 100644
--- a/cc/image.go
+++ b/cc/image.go
@@ -353,8 +353,11 @@
func (c *Module) SetImageVariation(ctx android.BaseModuleContext, variant string, module android.Module) {
m := module.(*Module)
- if variant == android.RamdiskVariation || variant == android.VendorRamdiskVariation {
+ if variant == android.RamdiskVariation {
m.MakeAsPlatform()
+ } else if variant == android.VendorRamdiskVariation {
+ m.MakeAsPlatform()
+ squashVendorRamdiskSrcs(m)
} else if variant == android.RecoveryVariation {
m.MakeAsPlatform()
squashRecoverySrcs(m)
diff --git a/cc/library.go b/cc/library.go
index 0e0f143..910fc31 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -833,6 +833,13 @@
deps.ReexportSharedLibHeaders = removeListFromList(deps.ReexportSharedLibHeaders, library.baseLinker.Properties.Target.Ramdisk.Exclude_shared_libs)
deps.ReexportStaticLibHeaders = removeListFromList(deps.ReexportStaticLibHeaders, library.baseLinker.Properties.Target.Ramdisk.Exclude_static_libs)
}
+ if ctx.inVendorRamdisk() {
+ deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, library.baseLinker.Properties.Target.Vendor_ramdisk.Exclude_static_libs)
+ deps.SharedLibs = removeListFromList(deps.SharedLibs, library.baseLinker.Properties.Target.Vendor_ramdisk.Exclude_shared_libs)
+ deps.StaticLibs = removeListFromList(deps.StaticLibs, library.baseLinker.Properties.Target.Vendor_ramdisk.Exclude_static_libs)
+ deps.ReexportSharedLibHeaders = removeListFromList(deps.ReexportSharedLibHeaders, library.baseLinker.Properties.Target.Vendor_ramdisk.Exclude_shared_libs)
+ deps.ReexportStaticLibHeaders = removeListFromList(deps.ReexportStaticLibHeaders, library.baseLinker.Properties.Target.Vendor_ramdisk.Exclude_static_libs)
+ }
return deps
}
diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go
index fcf6069..fa6b326 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -383,12 +383,25 @@
}
func (p *nativeLibInfoProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
+ addOutputFile := true
ccModule := variant.(*Module)
- // If the library has some link types then it produces an output binary file, otherwise it
- // is header only.
- if !p.memberType.noOutputFiles {
- p.outputFile = getRequiredMemberOutputFile(ctx, ccModule)
+ if s := ccModule.sanitize; s != nil {
+ // We currently do not capture sanitizer flags for libs with sanitizers
+ // enabled, because they may vary among variants that cannot be represented
+ // in the input blueprint files. In particular, sanitizerDepsMutator enables
+ // various sanitizers on dependencies, but in many cases only on static
+ // ones, and we cannot specify sanitizer flags at the link type level (i.e.
+ // in StaticOrSharedProperties).
+ if s.isUnsanitizedVariant() {
+ // This still captures explicitly disabled sanitizers, which may be
+ // necessary to avoid cyclic dependencies.
+ p.Sanitize = s.Properties.Sanitize
+ } else {
+ // Do not add the output file to the snapshot if we don't represent it
+ // properly.
+ addOutputFile = false
+ }
}
exportedInfo := ctx.SdkModuleContext().OtherModuleProvider(variant, FlagExporterInfoProvider).(FlagExporterInfo)
@@ -431,8 +444,8 @@
p.StubsVersions = ccModule.AllStubsVersions()
}
- if ccModule.sanitize != nil {
- p.Sanitize = ccModule.sanitize.Properties.Sanitize
+ if !p.memberType.noOutputFiles && addOutputFile {
+ p.outputFile = getRequiredMemberOutputFile(ctx, ccModule)
}
}
diff --git a/cc/linker.go b/cc/linker.go
index 12c8b2c..7f13e28 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -158,6 +158,15 @@
// the ramdisk variant of the C/C++ module.
Exclude_static_libs []string
}
+ Vendor_ramdisk struct {
+ // list of shared libs that should not be used to build
+ // the recovery variant of the C/C++ module.
+ Exclude_shared_libs []string
+
+ // list of static libs that should not be used to build
+ // the vendor ramdisk variant of the C/C++ module.
+ Exclude_static_libs []string
+ }
Platform struct {
// list of shared libs that should be use to build the platform variant
// of a module that sets sdk_version. This should rarely be necessary,
@@ -259,12 +268,20 @@
}
if ctx.inRamdisk() {
- deps.SharedLibs = removeListFromList(deps.SharedLibs, linker.Properties.Target.Recovery.Exclude_shared_libs)
- deps.ReexportSharedLibHeaders = removeListFromList(deps.ReexportSharedLibHeaders, linker.Properties.Target.Recovery.Exclude_shared_libs)
- deps.StaticLibs = append(deps.StaticLibs, linker.Properties.Target.Recovery.Static_libs...)
- deps.StaticLibs = removeListFromList(deps.StaticLibs, linker.Properties.Target.Recovery.Exclude_static_libs)
- deps.ReexportStaticLibHeaders = removeListFromList(deps.ReexportStaticLibHeaders, linker.Properties.Target.Recovery.Exclude_static_libs)
- deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Target.Recovery.Exclude_static_libs)
+ deps.SharedLibs = removeListFromList(deps.SharedLibs, linker.Properties.Target.Ramdisk.Exclude_shared_libs)
+ deps.ReexportSharedLibHeaders = removeListFromList(deps.ReexportSharedLibHeaders, linker.Properties.Target.Ramdisk.Exclude_shared_libs)
+ deps.StaticLibs = append(deps.StaticLibs, linker.Properties.Target.Ramdisk.Static_libs...)
+ deps.StaticLibs = removeListFromList(deps.StaticLibs, linker.Properties.Target.Ramdisk.Exclude_static_libs)
+ deps.ReexportStaticLibHeaders = removeListFromList(deps.ReexportStaticLibHeaders, linker.Properties.Target.Ramdisk.Exclude_static_libs)
+ deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Target.Ramdisk.Exclude_static_libs)
+ }
+
+ if ctx.inVendorRamdisk() {
+ deps.SharedLibs = removeListFromList(deps.SharedLibs, linker.Properties.Target.Vendor_ramdisk.Exclude_shared_libs)
+ deps.ReexportSharedLibHeaders = removeListFromList(deps.ReexportSharedLibHeaders, linker.Properties.Target.Vendor_ramdisk.Exclude_shared_libs)
+ deps.StaticLibs = removeListFromList(deps.StaticLibs, linker.Properties.Target.Vendor_ramdisk.Exclude_static_libs)
+ deps.ReexportStaticLibHeaders = removeListFromList(deps.ReexportStaticLibHeaders, linker.Properties.Target.Vendor_ramdisk.Exclude_static_libs)
+ deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Target.Vendor_ramdisk.Exclude_static_libs)
}
if !ctx.useSdk() {
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..c8bab2f
--- /dev/null
+++ b/dexpreopt/class_loader_context.go
@@ -0,0 +1,338 @@
+// 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
+}
+
+// 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.
+//
+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) {
+ 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] + "]"
+
+ 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 7d8fbbc..03accc8 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -100,94 +100,6 @@
ConstructContext android.Path
}
-// These libs are added as optional dependencies (<uses-library> with android:required set to false).
-// This is because they haven't existed prior to certain SDK version, but classes in them were in
-// bootclasspath jars, etc. So making them hard dependencies (android:required=true) would prevent
-// apps from being installed to such legacy devices.
-var OptionalCompatUsesLibs = []string{
- "org.apache.http.legacy",
- "android.test.base",
- "android.test.mock",
-}
-
-var CompatUsesLibs = []string{
- "android.hidl.base-V1.0-java",
- "android.hidl.manager-V1.0-java",
-}
-
-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
@@ -344,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
@@ -366,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 814b75d..51d1157 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -194,129 +194,6 @@
return profilePath
}
-type classLoaderContext struct {
- // 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 (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)
- } 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.Host = append(clc.Host, SystemServerDexJarHostPath(ctx, lib))
- clc.Target = append(clc.Target, 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.
-//
-// 2. 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 !contains(usesLibs, httpLegacy) {
- 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.
- const testBase = "android.test.base"
- if !contains(usesLibs, testBase) {
- if !classLoaderContexts.addLibs(ctx, 30, module, testBase) {
- 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 &.
- }
-
- return &classLoaderContexts
-}
-
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 +240,7 @@
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).
@@ -387,19 +264,11 @@
}
// Generate command that saves host and target class loader context in shell variables.
+ clc, paths := computeClassLoaderContext(ctx, classLoaderContexts)
cmd := rule.Command().
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
- }
- 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, ":"))
- }
+ Text(` --target-sdk-version ${target_sdk_version}`).
+ Text(clc).Implicits(paths)
cmd.Text(`)"`)
} else {
// Pass special class loader context to skip the classpath and collision check.
diff --git a/java/app.go b/java/app.go
index 46ca969..c24e0c5 100755
--- a/java/app.go
+++ b/java/app.go
@@ -1962,8 +1962,9 @@
if hasFrameworkLibs {
// Dexpreopt needs paths to the dex jars of these libraries in order to construct
// class loader context for dex2oat. Add them as a dependency with a special tag.
- ctx.AddVariationDependencies(nil, usesLibTag, dexpreopt.CompatUsesLibs...)
- ctx.AddVariationDependencies(nil, usesLibTag, dexpreopt.OptionalCompatUsesLibs...)
+ ctx.AddVariationDependencies(nil, usesLibCompat29Tag, dexpreopt.CompatUsesLibs29...)
+ ctx.AddVariationDependencies(nil, usesLibCompat28Tag, dexpreopt.OptionalCompatUsesLibs28...)
+ ctx.AddVariationDependencies(nil, usesLibCompat30Tag, dexpreopt.OptionalCompatUsesLibs30...)
}
}
}
@@ -1981,14 +1982,16 @@
usesLibPaths := make(dexpreopt.LibraryPaths)
if !ctx.Config().UnbundledBuild() {
- ctx.VisitDirectDepsWithTag(usesLibTag, func(m android.Module) {
- dep := ctx.OtherModuleName(m)
- if lib, ok := m.(Dependency); ok {
- usesLibPaths.AddLibraryPath(ctx, dep, lib.DexJarBuildPath(), lib.DexJarInstallPath())
- } else if ctx.Config().AllowMissingDependencies() {
- ctx.AddMissingDependencies([]string{dep})
- } else {
- ctx.ModuleErrorf("module %q in uses_libs or optional_uses_libs must be a java library", dep)
+ ctx.VisitDirectDeps(func(m android.Module) {
+ if _, ok := ctx.OtherModuleDependencyTag(m).(usesLibraryDependencyTag); ok {
+ dep := ctx.OtherModuleName(m)
+ if lib, ok := m.(Dependency); ok {
+ usesLibPaths.AddLibraryPath(ctx, dep, lib.DexJarBuildPath(), lib.DexJarInstallPath())
+ } else if ctx.Config().AllowMissingDependencies() {
+ ctx.AddMissingDependencies([]string{dep})
+ } else {
+ ctx.ModuleErrorf("module %q in uses_libs or optional_uses_libs must be a java library", dep)
+ }
}
})
}
diff --git a/java/app_test.go b/java/app_test.go
index cec8a62..82577e3 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -2766,7 +2766,7 @@
name: "prebuilt",
apk: "prebuilts/apk/app.apk",
certificate: "platform",
- uses_libs: ["foo"],
+ uses_libs: ["foo", "android.test.runner"],
optional_uses_libs: [
"bar",
"baz",
@@ -2804,7 +2804,7 @@
cmd = prebuilt.Rule("verify_uses_libraries").RuleParams.Command
- if w := `uses_library_names="foo"`; !strings.Contains(cmd, w) {
+ if w := `uses_library_names="foo android.test.runner"`; !strings.Contains(cmd, w) {
t.Errorf("wanted %q in %q", w, cmd)
}
@@ -2814,18 +2814,49 @@
// Test that all present libraries are preopted, including implicit SDK dependencies, possibly stubs
cmd = app.Rule("dexpreopt").RuleParams.Command
- w := `--target-classpath-for-sdk any` +
- ` /system/framework/foo.jar` +
- `:/system/framework/quuz.jar` +
- `:/system/framework/qux.jar` +
- `:/system/framework/runtime-library.jar` +
- `:/system/framework/bar.jar`
+ 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]`
if !strings.Contains(cmd, w) {
t.Errorf("wanted %q in %q", w, cmd)
}
+ // Test conditional context for target SDK version 28.
+ if w := `--target-context-for-sdk 28` +
+ ` PCL[/system/framework/org.apache.http.legacy.jar] `; !strings.Contains(cmd, w) {
+ t.Errorf("wanted %q in %q", w, cmd)
+ }
+
+ // Test conditional context for target SDK version 29.
+ if w := `--target-context-for-sdk 29` +
+ ` PCL[/system/framework/android.hidl.base-V1.0-java.jar]` +
+ `#PCL[/system/framework/android.hidl.manager-V1.0-java.jar] `; !strings.Contains(cmd, w) {
+ t.Errorf("wanted %q in %q", w, cmd)
+ }
+
+ // Test conditional context for target SDK version 30.
+ // "android.test.mock" is absent because "android.test.runner" is not used.
+ if w := `--target-context-for-sdk 30` +
+ ` PCL[/system/framework/android.test.base.jar] `; !strings.Contains(cmd, w) {
+ t.Errorf("wanted %q in %q", w, cmd)
+ }
+
cmd = prebuilt.Rule("dexpreopt").RuleParams.Command
- if w := `--target-classpath-for-sdk any /system/framework/foo.jar:/system/framework/bar.jar`; !strings.Contains(cmd, w) {
+ if w := `--target-context-for-sdk any` +
+ ` PCL[/system/framework/foo.jar]` +
+ `#PCL[/system/framework/android.test.runner.jar]` +
+ `#PCL[/system/framework/bar.jar] `; !strings.Contains(cmd, w) {
+ t.Errorf("wanted %q in %q", w, cmd)
+ }
+
+ // Test conditional context for target SDK version 30.
+ // "android.test.mock" is present because "android.test.runner" is used.
+ if w := `--target-context-for-sdk 30` +
+ ` PCL[/system/framework/android.test.base.jar]` +
+ `#PCL[/system/framework/android.test.mock.jar] `; !strings.Contains(cmd, w) {
t.Errorf("wanted %q in %q", w, cmd)
}
}
diff --git a/java/java.go b/java/java.go
index a973bab..4b48a15 100644
--- a/java/java.go
+++ b/java/java.go
@@ -547,6 +547,18 @@
name string
}
+type usesLibraryDependencyTag struct {
+ dependencyTag
+ sdkVersion int // SDK version in which the library appared as a standalone library.
+}
+
+func makeUsesLibraryDependencyTag(sdkVersion int) usesLibraryDependencyTag {
+ return usesLibraryDependencyTag{
+ dependencyTag: dependencyTag{name: fmt.Sprintf("uses-library-%d", sdkVersion)},
+ sdkVersion: sdkVersion,
+ }
+}
+
func IsJniDepTag(depTag blueprint.DependencyTag) bool {
return depTag == jniLibTag
}
@@ -566,9 +578,12 @@
proguardRaiseTag = dependencyTag{name: "proguard-raise"}
certificateTag = dependencyTag{name: "certificate"}
instrumentationForTag = dependencyTag{name: "instrumentation_for"}
- usesLibTag = dependencyTag{name: "uses-library"}
extraLintCheckTag = dependencyTag{name: "extra-lint-check"}
jniLibTag = dependencyTag{name: "jnilib"}
+ usesLibTag = makeUsesLibraryDependencyTag(dexpreopt.AnySdkVersion)
+ usesLibCompat28Tag = makeUsesLibraryDependencyTag(28)
+ usesLibCompat29Tag = makeUsesLibraryDependencyTag(29)
+ usesLibCompat30Tag = makeUsesLibraryDependencyTag(30)
)
func IsLibDepTag(depTag blueprint.DependencyTag) bool {
diff --git a/java/testing.go b/java/testing.go
index 461fd3f..ab13121 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -22,6 +22,7 @@
"android/soong/android"
"android/soong/cc"
+ "android/soong/dexpreopt"
"android/soong/python"
"github.com/google/blueprint"
@@ -152,6 +153,24 @@
`, extra)
}
+ // For class loader context and <uses-library> tests.
+ dexpreoptModules := []string{"android.test.runner"}
+ dexpreoptModules = append(dexpreoptModules, dexpreopt.CompatUsesLibs...)
+ dexpreoptModules = append(dexpreoptModules, dexpreopt.OptionalCompatUsesLibs...)
+
+ for _, extra := range dexpreoptModules {
+ bp += fmt.Sprintf(`
+ java_library {
+ name: "%s",
+ srcs: ["a.java"],
+ sdk_version: "none",
+ system_modules: "stable-core-platform-api-stubs-system-modules",
+ compile_dex: true,
+ installable: true,
+ }
+ `, extra)
+ }
+
bp += `
java_library {
name: "framework",
@@ -166,48 +185,7 @@
android_app {
name: "framework-res",
sdk_version: "core_platform",
- }
-
- java_library {
- name: "android.hidl.base-V1.0-java",
- srcs: ["a.java"],
- sdk_version: "none",
- system_modules: "stable-core-platform-api-stubs-system-modules",
- installable: true,
- }
-
- java_library {
- name: "android.hidl.manager-V1.0-java",
- srcs: ["a.java"],
- sdk_version: "none",
- system_modules: "stable-core-platform-api-stubs-system-modules",
- installable: true,
- }
-
- java_library {
- name: "org.apache.http.legacy",
- srcs: ["a.java"],
- sdk_version: "none",
- system_modules: "stable-core-platform-api-stubs-system-modules",
- installable: true,
- }
-
- java_library {
- name: "android.test.base",
- srcs: ["a.java"],
- sdk_version: "none",
- system_modules: "stable-core-platform-api-stubs-system-modules",
- installable: true,
- }
-
- java_library {
- name: "android.test.mock",
- srcs: ["a.java"],
- sdk_version: "none",
- system_modules: "stable-core-platform-api-stubs-system-modules",
- installable: true,
- }
- `
+ }`
systemModules := []string{
"core-current-stubs-system-modules",
diff --git a/scripts/construct_context.py b/scripts/construct_context.py
index 8717fe3..6f9edc4 100755
--- a/scripts/construct_context.py
+++ b/scripts/construct_context.py
@@ -29,41 +29,32 @@
parser = argparse.ArgumentParser()
parser.add_argument('--target-sdk-version', default='', dest='sdk',
help='specify target SDK version (as it appears in the manifest)')
- parser.add_argument('--host-classpath-for-sdk', dest='host_classpaths',
- action='append', nargs=2, metavar=('sdk','classpath'),
- help='specify classpath on host for a given SDK version or "any" version')
- parser.add_argument('--target-classpath-for-sdk', dest='target_classpaths',
- action='append', nargs=2, metavar=('sdk','classpath'),
- help='specify classpath on target for a given SDK version or "any" version')
+ parser.add_argument('--host-context-for-sdk', dest='host_contexts',
+ action='append', nargs=2, metavar=('sdk','context'),
+ help='specify context on host for a given SDK version or "any" version')
+ parser.add_argument('--target-context-for-sdk', dest='target_contexts',
+ action='append', nargs=2, metavar=('sdk','context'),
+ help='specify context on target for a given SDK version or "any" version')
return parser.parse_args(args)
-# The hidl.manager shared library has a dependency on hidl.base. We manually
-# add that information to the class loader context if we see those libraries.
-HIDL_MANAGER = 'android.hidl.manager-V1.0-java'
-HIDL_BASE = 'android.hidl.base-V1.0-java'
-
-# Special keyword that means that the classpath should be added to class loader
+# Special keyword that means that the context should be added to class loader
# context regardless of the target SDK version.
any_sdk = 'any'
-# We assume that the order of classpath arguments passed to this script is
+# We assume that the order of context arguments passed to this script is
# correct (matches the order computed by package manager). It is possible to
# sort them here, but Soong needs to use deterministic order anyway, so it can
# as well use the correct order.
-def construct_context(versioned_classpaths, target_sdk):
+def construct_context(versioned_contexts, target_sdk):
context = []
- for [sdk, classpath] in versioned_classpaths:
+ for [sdk, ctx] in versioned_contexts:
if sdk == any_sdk or compare_version_gt(sdk, target_sdk):
- for jar in classpath.split(':'):
- pcl = 'PCL[%s]' % jar
- if HIDL_MANAGER in jar:
- pcl += '{PCL[%s]}' % jar.replace(HIDL_MANAGER, HIDL_BASE, 1)
- context.append(pcl)
+ context.append(ctx)
return context
def construct_contexts(args):
- host_context = construct_context(args.host_classpaths, args.sdk)
- target_context = construct_context(args.target_classpaths, args.sdk)
+ host_context = construct_context(args.host_contexts, args.sdk)
+ target_context = construct_context(args.target_contexts, args.sdk)
context_sep = '#'
return ('class_loader_context_arg=--class-loader-context=PCL[]{%s} ; ' % context_sep.join(host_context) +
'stored_class_loader_context_arg=--stored-class-loader-context=PCL[]{%s}' % context_sep.join(target_context))
@@ -74,10 +65,10 @@
args = parse_args(sys.argv[1:])
if not args.sdk:
raise SystemExit('target sdk version is not set')
- if not args.host_classpaths:
- raise SystemExit('host classpath is not set')
- if not args.target_classpaths:
- raise SystemExit('target classpath is not set')
+ if not args.host_contexts:
+ raise SystemExit('host context is not set')
+ if not args.target_contexts:
+ raise SystemExit('target context is not set')
print(construct_contexts(args))
diff --git a/scripts/construct_context_test.py b/scripts/construct_context_test.py
index 0b0b0a3..3b05f90 100755
--- a/scripts/construct_context_test.py
+++ b/scripts/construct_context_test.py
@@ -27,53 +27,47 @@
args = cc.parse_args(arglist)
return cc.construct_contexts(args)
-classpaths = [
- '--host-classpath-for-sdk', '28', 'out/zdir/z.jar',
- '--target-classpath-for-sdk', '28', '/system/z.jar',
- '--host-classpath-for-sdk', '29', 'out/xdir/x.jar:out/ydir/y.jar',
- '--target-classpath-for-sdk', '29', '/system/x.jar:/product/y.jar',
- '--host-classpath-for-sdk', 'any', 'out/adir/a.jar:out/android.hidl.manager-V1.0-java.jar:out/bdir/b.jar',
- '--target-classpath-for-sdk', 'any', '/system/a.jar:/system/android.hidl.manager-V1.0-java.jar:/product/b.jar',
+contexts = [
+ '--host-context-for-sdk', '28', 'PCL[out/zdir/z.jar]',
+ '--target-context-for-sdk', '28', 'PCL[/system/z.jar]',
+ '--host-context-for-sdk', '29', 'PCL[out/xdir/x.jar]#PCL[out/ydir/y.jar]',
+ '--target-context-for-sdk', '29', 'PCL[/system/x.jar]#PCL[/product/y.jar]',
+ '--host-context-for-sdk', 'any', 'PCL[out/adir/a.jar]#PCL[out/bdir/b.jar]',
+ '--target-context-for-sdk', 'any', 'PCL[/system/a.jar]#PCL[/product/b.jar]',
]
class ConstructContextTest(unittest.TestCase):
def test_construct_context_28(self):
- args = ['--target-sdk-version', '28'] + classpaths
+ args = ['--target-sdk-version', '28'] + contexts
result = construct_contexts(args)
expect = ('class_loader_context_arg=--class-loader-context=PCL[]{PCL[out/xdir/x.jar]'
'#PCL[out/ydir/y.jar]'
'#PCL[out/adir/a.jar]'
- '#PCL[out/android.hidl.manager-V1.0-java.jar]{PCL[out/android.hidl.base-V1.0-java.jar]}'
'#PCL[out/bdir/b.jar]}'
' ; '
'stored_class_loader_context_arg=--stored-class-loader-context=PCL[]{PCL[/system/x.jar]'
'#PCL[/product/y.jar]'
'#PCL[/system/a.jar]'
- '#PCL[/system/android.hidl.manager-V1.0-java.jar]{PCL[/system/android.hidl.base-V1.0-java.jar]}'
'#PCL[/product/b.jar]}')
self.assertEqual(result, expect)
def test_construct_context_29(self):
- args = ['--target-sdk-version', '29'] + classpaths
+ args = ['--target-sdk-version', '29'] + contexts
result = construct_contexts(args)
expect = ('class_loader_context_arg=--class-loader-context=PCL[]{PCL[out/adir/a.jar]'
- '#PCL[out/android.hidl.manager-V1.0-java.jar]{PCL[out/android.hidl.base-V1.0-java.jar]}'
'#PCL[out/bdir/b.jar]}'
' ; '
'stored_class_loader_context_arg=--stored-class-loader-context=PCL[]{PCL[/system/a.jar]'
- '#PCL[/system/android.hidl.manager-V1.0-java.jar]{PCL[/system/android.hidl.base-V1.0-java.jar]}'
'#PCL[/product/b.jar]}')
self.assertEqual(result, expect)
def test_construct_context_S(self):
- args = ['--target-sdk-version', 'S'] + classpaths
+ args = ['--target-sdk-version', 'S'] + contexts
result = construct_contexts(args)
expect = ('class_loader_context_arg=--class-loader-context=PCL[]{PCL[out/adir/a.jar]'
- '#PCL[out/android.hidl.manager-V1.0-java.jar]{PCL[out/android.hidl.base-V1.0-java.jar]}'
'#PCL[out/bdir/b.jar]}'
' ; '
'stored_class_loader_context_arg=--stored-class-loader-context=PCL[]{PCL[/system/a.jar]'
- '#PCL[/system/android.hidl.manager-V1.0-java.jar]{PCL[/system/android.hidl.base-V1.0-java.jar]}'
'#PCL[/product/b.jar]}')
self.assertEqual(result, expect)
diff --git a/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go
index c1813ec..84e4f28 100644
--- a/sdk/cc_sdk_test.go
+++ b/sdk/cc_sdk_test.go
@@ -464,7 +464,6 @@
arm64: {
export_system_include_dirs: ["arm64/include"],
sanitize: {
- hwaddress: true,
integer_overflow: false,
},
},
@@ -496,7 +495,6 @@
srcs: ["arm64/lib/mynativelib.so"],
export_system_include_dirs: ["arm64/include/arm64/include"],
sanitize: {
- hwaddress: true,
integer_overflow: false,
},
},
@@ -527,7 +525,6 @@
srcs: ["arm64/lib/mynativelib.so"],
export_system_include_dirs: ["arm64/include/arm64/include"],
sanitize: {
- hwaddress: true,
integer_overflow: false,
},
},
@@ -548,7 +545,7 @@
`),
checkAllCopyRules(`
include/Test.h -> include/include/Test.h
-.intermediates/mynativelib/android_arm64_armv8-a_shared_hwasan/mynativelib.so -> arm64/lib/mynativelib.so
+.intermediates/mynativelib/android_arm64_armv8-a_shared/mynativelib.so -> arm64/lib/mynativelib.so
arm64/include/Arm64Test.h -> arm64/include/arm64/include/Arm64Test.h
.intermediates/mynativelib/android_arm_armv7-a-neon_shared/mynativelib.so -> arm/lib/mynativelib.so`),
)
@@ -2727,3 +2724,75 @@
`),
)
}
+
+func TestNoSanitizerMembers(t *testing.T) {
+ result := testSdkWithCc(t, `
+ sdk {
+ name: "mysdk",
+ native_shared_libs: ["mynativelib"],
+ }
+
+ cc_library_shared {
+ name: "mynativelib",
+ srcs: ["Test.cpp"],
+ export_include_dirs: ["include"],
+ arch: {
+ arm64: {
+ export_system_include_dirs: ["arm64/include"],
+ sanitize: {
+ hwaddress: true,
+ },
+ },
+ },
+ }
+ `)
+
+ result.CheckSnapshot("mysdk", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library_shared {
+ name: "mysdk_mynativelib@current",
+ sdk_member_name: "mynativelib",
+ visibility: ["//visibility:public"],
+ installable: false,
+ compile_multilib: "both",
+ export_include_dirs: ["include/include"],
+ arch: {
+ arm64: {
+ export_system_include_dirs: ["arm64/include/arm64/include"],
+ },
+ arm: {
+ srcs: ["arm/lib/mynativelib.so"],
+ },
+ },
+}
+
+cc_prebuilt_library_shared {
+ name: "mynativelib",
+ prefer: false,
+ visibility: ["//visibility:public"],
+ compile_multilib: "both",
+ export_include_dirs: ["include/include"],
+ arch: {
+ arm64: {
+ export_system_include_dirs: ["arm64/include/arm64/include"],
+ },
+ arm: {
+ srcs: ["arm/lib/mynativelib.so"],
+ },
+ },
+}
+
+sdk_snapshot {
+ name: "mysdk@current",
+ visibility: ["//visibility:public"],
+ native_shared_libs: ["mysdk_mynativelib@current"],
+}
+`),
+ checkAllCopyRules(`
+include/Test.h -> include/include/Test.h
+arm64/include/Arm64Test.h -> arm64/include/arm64/include/Arm64Test.h
+.intermediates/mynativelib/android_arm_armv7-a-neon_shared/mynativelib.so -> arm/lib/mynativelib.so`),
+ )
+}