Merge "Update stub definition docs."
diff --git a/android/Android.bp b/android/Android.bp
index a32e8f2..f5e5606 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -78,9 +78,6 @@
"variable.go",
"visibility.go",
"writedocs.go",
-
- // Lock down environment access last
- "env.go",
],
testSrcs: [
"android_test.go",
diff --git a/android/arch.go b/android/arch.go
index 6826f3b..e40b6f5 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -618,7 +618,7 @@
}
// only the primary arch in the ramdisk / vendor_ramdisk / recovery partition
- if os == Android && (module.InstallInRecovery() || module.InstallInRamdisk() || module.InstallInVendorRamdisk()) {
+ if os == Android && (module.InstallInRecovery() || module.InstallInRamdisk() || module.InstallInVendorRamdisk() || module.InstallInDebugRamdisk()) {
osTargets = []Target{osTargets[0]}
}
diff --git a/android/bazel.go b/android/bazel.go
index b54ae64..9468891 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -129,54 +129,45 @@
// Configure modules in these directories to enable bp2build_available: true or false by default.
bp2buildDefaultConfig = Bp2BuildConfig{
"bionic": Bp2BuildDefaultTrueRecursively,
+ "external/gwp_asan": Bp2BuildDefaultTrueRecursively,
"system/core/libcutils": Bp2BuildDefaultTrueRecursively,
"system/logging/liblog": Bp2BuildDefaultTrueRecursively,
}
// Per-module denylist to always opt modules out.
bp2buildModuleDoNotConvertList = []string{
- "libBionicBenchmarksUtils", // ruperts@, cc_library_static
+ "libBionicBenchmarksUtils", // ruperts@, cc_library_static, 'map' file not found
"libbionic_spawn_benchmark", // ruperts@, cc_library_static, depends on //system/libbase
"libc_jemalloc_wrapper", // ruperts@, cc_library_static, depends on //external/jemalloc_new
- "libc_bootstrap", // ruperts@, cc_library_static
- "libc_init_static", // ruperts@, cc_library_static
- "libc_init_dynamic", // ruperts@, cc_library_static
- "libc_tzcode", // ruperts@, cc_library_static
- "libc_freebsd", // ruperts@, cc_library_static
- "libc_freebsd_large_stack", // ruperts@, cc_library_static
- "libc_netbsd", // ruperts@, cc_library_static
- "libc_openbsd_ndk", // ruperts@, cc_library_static
- "libc_openbsd_large_stack", // ruperts@, cc_library_static
- "libc_openbsd", // ruperts@, cc_library_static
- "libc_gdtoa", // ruperts@, cc_library_static
- "libc_fortify", // ruperts@, cc_library_static
- "libc_bionic", // ruperts@, cc_library_static
+ "libc_bootstrap", // ruperts@, cc_library_static, 'private/bionic_auxv.h' file not found
+ "libc_init_static", // ruperts@, cc_library_static, 'private/bionic_elf_tls.h' file not found
+ "libc_init_dynamic", // ruperts@, cc_library_static, 'private/bionic_defs.h' file not found
+ "libc_tzcode", // ruperts@, cc_library_static, error: expected expression
+ "libc_netbsd", // ruperts@, cc_library_static, 'engine.c' file not found
+ "libc_openbsd_large_stack", // ruperts@, cc_library_static, 'android/log.h' file not found
+ "libc_openbsd", // ruperts@, cc_library_static, 'android/log.h' file not found
+ "libc_fortify", // ruperts@, cc_library_static, 'private/bionic_fortify.h' file not found
+ "libc_bionic", // ruperts@, cc_library_static, 'private/bionic_asm.h' file not found
"libc_bionic_ndk", // ruperts@, cc_library_static, depends on //bionic/libc/system_properties
- "libc_bionic_systrace", // ruperts@, cc_library_static
- "libc_pthread", // ruperts@, cc_library_static
- "libc_syscalls", // ruperts@, cc_library_static
- "libc_aeabi", // ruperts@, cc_library_static
+ "libc_bionic_systrace", // ruperts@, cc_library_static, 'private/bionic_systrace.h' file not found
+ "libc_pthread", // ruperts@, cc_library_static, 'private/bionic_defs.h' file not found
+ "libc_syscalls", // ruperts@, cc_library_static, mutator panic cannot get direct dep syscalls-arm64.S of libc_syscalls
"libc_ndk", // ruperts@, cc_library_static, depends on //bionic/libm:libm
"libc_nopthread", // ruperts@, cc_library_static, depends on //external/arm-optimized-routines
"libc_common", // ruperts@, cc_library_static, depends on //bionic/libc:libc_nopthread
- "libc_static_dispatch", // ruperts@, cc_library_static
- "libc_dynamic_dispatch", // ruperts@, cc_library_static
"libc_common_static", // ruperts@, cc_library_static, depends on //bionic/libc:libc_common
"libc_common_shared", // ruperts@, cc_library_static, depends on //bionic/libc:libc_common
- "libc_unwind_static", // ruperts@, cc_library_static
+ "libc_unwind_static", // ruperts@, cc_library_static, 'private/bionic_elf_tls.h' file not found
"libc_nomalloc", // ruperts@, cc_library_static, depends on //bionic/libc:libc_common
- "libasync_safe", // ruperts@, cc_library_static
+ "libasync_safe", // ruperts@, cc_library_static, 'private/CachedProperty.h' file not found
"libc_malloc_debug_backtrace", // ruperts@, cc_library_static, depends on //system/libbase
"libsystemproperties", // ruperts@, cc_library_static, depends on //system/core/property_service/libpropertyinfoparser
- "libdl_static", // ruperts@, cc_library_static
+ "libdl_static", // ruperts@, cc_library_static, 'private/CFIShadow.h' file not found
"liblinker_main", // ruperts@, cc_library_static, depends on //system/libbase
"liblinker_malloc", // ruperts@, cc_library_static, depends on //system/logging/liblog:liblog
"liblinker_debuggerd_stub", // ruperts@, cc_library_static, depends on //system/libbase
- "libbionic_tests_headers_posix", // ruperts@, cc_library_static
- "libc_dns", // ruperts@, cc_library_static
-
- "note_memtag_heap_async", // jingwen@, b/185079815, features.h includes not found
- "note_memtag_heap_sync", // jingwen@, b/185079815, features.h includes not found
+ "libbionic_tests_headers_posix", // ruperts@, cc_library_static, 'complex.h' file not found
+ "libc_dns", // ruperts@, cc_library_static, 'android/log.h' file not found
// List of all full_cc_libraries in //bionic, with their immediate failures
"libc", // jingwen@, cc_library, depends on //external/gwp_asan
@@ -186,6 +177,11 @@
"libm", // jingwen@, cc_library, fatal error: 'freebsd-compat.h' file not found
"libseccomp_policy", // jingwen@, cc_library, fatal error: 'seccomp_policy.h' file not found
"libstdc++", // jingwen@, cc_library, depends on //external/gwp_asan
+
+ // For mixed builds specifically
+ "note_memtag_heap_async", // jingwen@, cc_library_static, OK for bp2build but features.h includes not found for mixed builds (b/185079815)
+ "note_memtag_heap_sync", // jingwen@, cc_library_static, OK for bp2build but features.h includes not found for mixed builds (b/185079815)
+ "libc_gdtoa", // ruperts@, cc_library_static, OK for bp2build but undefined symbol: __strtorQ for mixed builds
}
// Used for quicker lookups
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 97eec30..8d561d2 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -67,11 +67,7 @@
// TODO(cparsons): Other cquery-related methods should be added here.
// Returns the results of GetOutputFiles and GetCcObjectFiles in a single query (in that order).
- GetOutputFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool)
-
- // GetPrebuiltCcStaticLibraryFiles returns paths to prebuilt cc static libraries, and whether the
- // results were available
- GetPrebuiltCcStaticLibraryFiles(label string, archType ArchType) ([]string, bool)
+ GetCcInfo(label string, archType ArchType) (cquery.CcInfo, bool, error)
// ** End cquery methods
@@ -89,16 +85,24 @@
BuildStatementsToRegister() []bazel.BuildStatement
}
-// A context object which tracks queued requests that need to be made to Bazel,
-// and their results after the requests have been made.
-type bazelContext struct {
+type bazelRunner interface {
+ issueBazelCommand(paths *bazelPaths, runName bazel.RunName, command bazelCommand, extraFlags ...string) (string, string, error)
+}
+
+type bazelPaths struct {
homeDir string
bazelPath string
outputBase string
workspaceDir string
buildDir string
metricsDir string
+}
+// A context object which tracks queued requests that need to be made to Bazel,
+// and their results after the requests have been made.
+type bazelContext struct {
+ bazelRunner
+ paths *bazelPaths
requests map[cqueryKey]bool // cquery requests that have not yet been issued to Bazel
requestMutex sync.Mutex // requests can be written in parallel
@@ -119,9 +123,8 @@
type MockBazelContext struct {
OutputBaseDir string
- LabelToOutputFiles map[string][]string
- LabelToOutputFilesAndCcObjectFiles map[string]cquery.GetOutputFilesAndCcObjectFiles_Result
- LabelToCcStaticLibraryFiles map[string][]string
+ LabelToOutputFiles map[string][]string
+ LabelToCcInfo map[string]cquery.CcInfo
}
func (m MockBazelContext) GetOutputFiles(label string, archType ArchType) ([]string, bool) {
@@ -129,14 +132,9 @@
return result, ok
}
-func (m MockBazelContext) GetOutputFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) {
- result, ok := m.LabelToOutputFilesAndCcObjectFiles[label]
- return result.OutputFiles, result.CcObjectFiles, ok
-}
-
-func (m MockBazelContext) GetPrebuiltCcStaticLibraryFiles(label string, archType ArchType) ([]string, bool) {
- result, ok := m.LabelToCcStaticLibraryFiles[label]
- return result, ok
+func (m MockBazelContext) GetCcInfo(label string, archType ArchType) (cquery.CcInfo, bool, error) {
+ result, ok := m.LabelToCcInfo[label]
+ return result, ok, nil
}
func (m MockBazelContext) InvokeBazel() error {
@@ -165,39 +163,22 @@
return ret, ok
}
-func (bazelCtx *bazelContext) GetOutputFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) {
- var outputFiles []string
- var ccObjects []string
-
- result, ok := bazelCtx.cquery(label, cquery.GetOutputFilesAndCcObjectFiles, archType)
- if ok {
- bazelOutput := strings.TrimSpace(result)
- returnResult := cquery.GetOutputFilesAndCcObjectFiles.ParseResult(bazelOutput)
- outputFiles = returnResult.OutputFiles
- ccObjects = returnResult.CcObjectFiles
- }
-
- return outputFiles, ccObjects, ok
-}
-
-// GetPrebuiltCcStaticLibraryFiles returns a slice of prebuilt static libraries for the given
-// label/archType if there are query results; otherwise, it enqueues the query and returns false.
-func (bazelCtx *bazelContext) GetPrebuiltCcStaticLibraryFiles(label string, archType ArchType) ([]string, bool) {
- result, ok := bazelCtx.cquery(label, cquery.GetPrebuiltCcStaticLibraryFiles, archType)
+func (bazelCtx *bazelContext) GetCcInfo(label string, archType ArchType) (cquery.CcInfo, bool, error) {
+ result, ok := bazelCtx.cquery(label, cquery.GetCcInfo, archType)
if !ok {
- return nil, false
+ return cquery.CcInfo{}, ok, nil
}
bazelOutput := strings.TrimSpace(result)
- ret := cquery.GetPrebuiltCcStaticLibraryFiles.ParseResult(bazelOutput)
- return ret, ok
+ ret, err := cquery.GetCcInfo.ParseResult(bazelOutput)
+ return ret, ok, err
}
func (n noopBazelContext) GetOutputFiles(label string, archType ArchType) ([]string, bool) {
panic("unimplemented")
}
-func (n noopBazelContext) GetOutputFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) {
+func (n noopBazelContext) GetCcInfo(label string, archType ArchType) (cquery.CcInfo, bool, error) {
panic("unimplemented")
}
@@ -228,42 +209,56 @@
return noopBazelContext{}, nil
}
- bazelCtx := bazelContext{buildDir: c.buildDir, requests: make(map[cqueryKey]bool)}
+ p, err := bazelPathsFromConfig(c)
+ if err != nil {
+ return nil, err
+ }
+ return &bazelContext{
+ bazelRunner: &builtinBazelRunner{},
+ paths: p,
+ requests: make(map[cqueryKey]bool),
+ }, nil
+}
+
+func bazelPathsFromConfig(c *config) (*bazelPaths, error) {
+ p := bazelPaths{
+ buildDir: c.buildDir,
+ }
missingEnvVars := []string{}
if len(c.Getenv("BAZEL_HOME")) > 1 {
- bazelCtx.homeDir = c.Getenv("BAZEL_HOME")
+ p.homeDir = c.Getenv("BAZEL_HOME")
} else {
missingEnvVars = append(missingEnvVars, "BAZEL_HOME")
}
if len(c.Getenv("BAZEL_PATH")) > 1 {
- bazelCtx.bazelPath = c.Getenv("BAZEL_PATH")
+ p.bazelPath = c.Getenv("BAZEL_PATH")
} else {
missingEnvVars = append(missingEnvVars, "BAZEL_PATH")
}
if len(c.Getenv("BAZEL_OUTPUT_BASE")) > 1 {
- bazelCtx.outputBase = c.Getenv("BAZEL_OUTPUT_BASE")
+ p.outputBase = c.Getenv("BAZEL_OUTPUT_BASE")
} else {
missingEnvVars = append(missingEnvVars, "BAZEL_OUTPUT_BASE")
}
if len(c.Getenv("BAZEL_WORKSPACE")) > 1 {
- bazelCtx.workspaceDir = c.Getenv("BAZEL_WORKSPACE")
+ p.workspaceDir = c.Getenv("BAZEL_WORKSPACE")
} else {
missingEnvVars = append(missingEnvVars, "BAZEL_WORKSPACE")
}
if len(c.Getenv("BAZEL_METRICS_DIR")) > 1 {
- bazelCtx.metricsDir = c.Getenv("BAZEL_METRICS_DIR")
+ p.metricsDir = c.Getenv("BAZEL_METRICS_DIR")
} else {
missingEnvVars = append(missingEnvVars, "BAZEL_METRICS_DIR")
}
if len(missingEnvVars) > 0 {
return nil, errors.New(fmt.Sprintf("missing required env vars to use bazel: %s", missingEnvVars))
} else {
- return &bazelCtx, nil
+ return &p, nil
}
}
-func (context *bazelContext) BazelMetricsDir() string {
- return context.metricsDir
+func (p *bazelPaths) BazelMetricsDir() string {
+ return p.metricsDir
}
func (context *bazelContext) BazelEnabled() bool {
@@ -296,17 +291,40 @@
return ""
}
+type bazelCommand struct {
+ command string
+ // query or label
+ expression string
+}
+
+type mockBazelRunner struct {
+ bazelCommandResults map[bazelCommand]string
+ commands []bazelCommand
+}
+
+func (r *mockBazelRunner) issueBazelCommand(paths *bazelPaths,
+ runName bazel.RunName,
+ command bazelCommand,
+ extraFlags ...string) (string, string, error) {
+ r.commands = append(r.commands, command)
+ if ret, ok := r.bazelCommandResults[command]; ok {
+ return ret, "", nil
+ }
+ return "", "", nil
+}
+
+type builtinBazelRunner struct{}
+
// Issues the given bazel command with given build label and additional flags.
// Returns (stdout, stderr, error). The first and second return values are strings
// containing the stdout and stderr of the run command, and an error is returned if
// the invocation returned an error code.
-func (context *bazelContext) issueBazelCommand(runName bazel.RunName, command string, labels []string,
+func (r *builtinBazelRunner) issueBazelCommand(paths *bazelPaths, runName bazel.RunName, command bazelCommand,
extraFlags ...string) (string, string, error) {
-
- cmdFlags := []string{"--output_base=" + context.outputBase, command}
- cmdFlags = append(cmdFlags, labels...)
- cmdFlags = append(cmdFlags, "--package_path=%workspace%/"+context.intermediatesDir())
- cmdFlags = append(cmdFlags, "--profile="+shared.BazelMetricsFilename(context, runName))
+ cmdFlags := []string{"--output_base=" + paths.outputBase, command.command}
+ cmdFlags = append(cmdFlags, command.expression)
+ cmdFlags = append(cmdFlags, "--package_path=%workspace%/"+paths.intermediatesDir())
+ cmdFlags = append(cmdFlags, "--profile="+shared.BazelMetricsFilename(paths, runName))
// Set default platforms to canonicalized values for mixed builds requests.
// If these are set in the bazelrc, they will have values that are
@@ -328,9 +346,9 @@
cmdFlags = append(cmdFlags, "--experimental_repository_disable_download")
cmdFlags = append(cmdFlags, extraFlags...)
- bazelCmd := exec.Command(context.bazelPath, cmdFlags...)
- bazelCmd.Dir = context.workspaceDir
- bazelCmd.Env = append(os.Environ(), "HOME="+context.homeDir, pwdPrefix(),
+ bazelCmd := exec.Command(paths.bazelPath, cmdFlags...)
+ bazelCmd.Dir = paths.workspaceDir
+ bazelCmd.Env = append(os.Environ(), "HOME="+paths.homeDir, pwdPrefix(),
// Disables local host detection of gcc; toolchain information is defined
// explicitly in BUILD files.
"BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1")
@@ -367,7 +385,7 @@
path = "%[1]s/build/bazel/bazel_skylib",
)
`
- return []byte(fmt.Sprintf(formatString, context.workspaceDir))
+ return []byte(fmt.Sprintf(formatString, context.paths.workspaceDir))
}
func (context *bazelContext) mainBzlFileContents() []byte {
@@ -577,8 +595,8 @@
// Returns a workspace-relative path containing build-related metadata required
// for interfacing with Bazel. Example: out/soong/bazel.
-func (context *bazelContext) intermediatesDir() string {
- return filepath.Join(context.buildDir, "bazel")
+func (p *bazelPaths) intermediatesDir() string {
+ return filepath.Join(p.buildDir, "bazel")
}
// Issues commands to Bazel to receive results for all cquery requests
@@ -590,7 +608,7 @@
var cqueryErr string
var err error
- intermediatesDirPath := absolutePath(context.intermediatesDir())
+ intermediatesDirPath := absolutePath(context.paths.intermediatesDir())
if _, err := os.Stat(intermediatesDirPath); os.IsNotExist(err) {
err = os.Mkdir(intermediatesDirPath, 0777)
}
@@ -599,38 +617,38 @@
return err
}
err = ioutil.WriteFile(
- absolutePath(filepath.Join(context.intermediatesDir(), "main.bzl")),
+ filepath.Join(intermediatesDirPath, "main.bzl"),
context.mainBzlFileContents(), 0666)
if err != nil {
return err
}
err = ioutil.WriteFile(
- absolutePath(filepath.Join(context.intermediatesDir(), "BUILD.bazel")),
+ filepath.Join(intermediatesDirPath, "BUILD.bazel"),
context.mainBuildFileContents(), 0666)
if err != nil {
return err
}
- cqueryFileRelpath := filepath.Join(context.intermediatesDir(), "buildroot.cquery")
+ cqueryFileRelpath := filepath.Join(context.paths.intermediatesDir(), "buildroot.cquery")
err = ioutil.WriteFile(
absolutePath(cqueryFileRelpath),
context.cqueryStarlarkFileContents(), 0666)
if err != nil {
return err
}
- workspaceFileRelpath := filepath.Join(context.intermediatesDir(), "WORKSPACE.bazel")
err = ioutil.WriteFile(
- absolutePath(workspaceFileRelpath),
+ filepath.Join(intermediatesDirPath, "WORKSPACE.bazel"),
context.workspaceFileContents(), 0666)
if err != nil {
return err
}
buildrootLabel := "//:buildroot"
- cqueryOutput, cqueryErr, err = context.issueBazelCommand(bazel.CqueryBuildRootRunName, "cquery",
- []string{fmt.Sprintf("kind(rule, deps(%s))", buildrootLabel)},
+ cqueryOutput, cqueryErr, err = context.issueBazelCommand(
+ context.paths,
+ bazel.CqueryBuildRootRunName,
+ bazelCommand{"cquery", fmt.Sprintf("kind(rule, deps(%s))", buildrootLabel)},
"--output=starlark",
"--starlark:file="+cqueryFileRelpath)
- err = ioutil.WriteFile(
- absolutePath(filepath.Join(context.intermediatesDir(), "cquery.out")),
+ err = ioutil.WriteFile(filepath.Join(intermediatesDirPath, "cquery.out"),
[]byte(cqueryOutput), 0666)
if err != nil {
return err
@@ -661,11 +679,13 @@
//
// TODO(cparsons): Use --target_pattern_file to avoid command line limits.
var aqueryOutput string
- aqueryOutput, _, err = context.issueBazelCommand(bazel.AqueryBuildRootRunName, "aquery",
- []string{fmt.Sprintf("deps(%s)", buildrootLabel),
- // Use jsonproto instead of proto; actual proto parsing would require a dependency on Bazel's
- // proto sources, which would add a number of unnecessary dependencies.
- "--output=jsonproto"})
+ aqueryOutput, _, err = context.issueBazelCommand(
+ context.paths,
+ bazel.AqueryBuildRootRunName,
+ bazelCommand{"aquery", fmt.Sprintf("deps(%s)", buildrootLabel)},
+ // Use jsonproto instead of proto; actual proto parsing would require a dependency on Bazel's
+ // proto sources, which would add a number of unnecessary dependencies.
+ "--output=jsonproto")
if err != nil {
return err
@@ -679,8 +699,10 @@
// Issue a build command of the phony root to generate symlink forests for dependencies of the
// Bazel build. This is necessary because aquery invocations do not generate this symlink forest,
// but some of symlinks may be required to resolve source dependencies of the build.
- _, _, err = context.issueBazelCommand(bazel.BazelBuildPhonyRootRunName, "build",
- []string{"//:phonyroot"})
+ _, _, err = context.issueBazelCommand(
+ context.paths,
+ bazel.BazelBuildPhonyRootRunName,
+ bazelCommand{"build", "//:phonyroot"})
if err != nil {
return err
@@ -696,7 +718,7 @@
}
func (context *bazelContext) OutputBase() string {
- return context.outputBase
+ return context.paths.outputBase
}
// Singleton used for registering BUILD file ninja dependencies (needed
@@ -715,7 +737,7 @@
// Add ninja file dependencies for files which all bazel invocations require.
bazelBuildList := absolutePath(filepath.Join(
- filepath.Dir(bootstrap.CmdlineModuleListFile()), "bazel.list"))
+ filepath.Dir(bootstrap.CmdlineArgs.ModuleListFile), "bazel.list"))
ctx.AddNinjaFileDeps(bazelBuildList)
data, err := ioutil.ReadFile(bazelBuildList)
diff --git a/android/bazel_handler_test.go b/android/bazel_handler_test.go
new file mode 100644
index 0000000..85f701f
--- /dev/null
+++ b/android/bazel_handler_test.go
@@ -0,0 +1,118 @@
+package android
+
+import (
+ "os"
+ "path/filepath"
+ "reflect"
+ "testing"
+)
+
+func TestRequestResultsAfterInvokeBazel(t *testing.T) {
+ label := "//foo:bar"
+ arch := Arm64
+ bazelContext, _ := testBazelContext(t, map[bazelCommand]string{
+ bazelCommand{command: "cquery", expression: "kind(rule, deps(//:buildroot))"}: `@sourceroot//foo:bar|arm64>>out/foo/bar.txt`,
+ })
+ g, ok := bazelContext.GetOutputFiles(label, arch)
+ if ok {
+ t.Errorf("Did not expect cquery results prior to running InvokeBazel(), but got %s", g)
+ }
+ err := bazelContext.InvokeBazel()
+ if err != nil {
+ t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
+ }
+ g, ok = bazelContext.GetOutputFiles(label, arch)
+ if !ok {
+ t.Errorf("Expected cquery results after running InvokeBazel(), but got none")
+ } else if w := []string{"out/foo/bar.txt"}; !reflect.DeepEqual(w, g) {
+ t.Errorf("Expected output %s, got %s", w, g)
+ }
+}
+
+func TestInvokeBazelWritesBazelFiles(t *testing.T) {
+ bazelContext, baseDir := testBazelContext(t, map[bazelCommand]string{})
+ err := bazelContext.InvokeBazel()
+ if err != nil {
+ t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
+ }
+ if _, err := os.Stat(filepath.Join(baseDir, "bazel", "main.bzl")); os.IsNotExist(err) {
+ t.Errorf("Expected main.bzl to exist, but it does not")
+ } else if err != nil {
+ t.Errorf("Unexpected error stating main.bzl %s", err)
+ }
+
+ if _, err := os.Stat(filepath.Join(baseDir, "bazel", "BUILD.bazel")); os.IsNotExist(err) {
+ t.Errorf("Expected BUILD.bazel to exist, but it does not")
+ } else if err != nil {
+ t.Errorf("Unexpected error stating BUILD.bazel %s", err)
+ }
+
+ if _, err := os.Stat(filepath.Join(baseDir, "bazel", "WORKSPACE.bazel")); os.IsNotExist(err) {
+ t.Errorf("Expected WORKSPACE.bazel to exist, but it does not")
+ } else if err != nil {
+ t.Errorf("Unexpected error stating WORKSPACE.bazel %s", err)
+ }
+}
+
+func TestInvokeBazelPopulatesBuildStatements(t *testing.T) {
+ bazelContext, _ := testBazelContext(t, map[bazelCommand]string{
+ bazelCommand{command: "aquery", expression: "deps(//:buildroot)"}: `
+{
+ "artifacts": [{
+ "id": 1,
+ "pathFragmentId": 1
+ }, {
+ "id": 2,
+ "pathFragmentId": 2
+ }],
+ "actions": [{
+ "targetId": 1,
+ "actionKey": "x",
+ "mnemonic": "x",
+ "arguments": ["touch", "foo"],
+ "inputDepSetIds": [1],
+ "outputIds": [1],
+ "primaryOutputId": 1
+ }],
+ "depSetOfFiles": [{
+ "id": 1,
+ "directArtifactIds": [1, 2]
+ }],
+ "pathFragments": [{
+ "id": 1,
+ "label": "one"
+ }, {
+ "id": 2,
+ "label": "two"
+ }]
+}`,
+ })
+ err := bazelContext.InvokeBazel()
+ if err != nil {
+ t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
+ }
+
+ got := bazelContext.BuildStatementsToRegister()
+ if want := 1; len(got) != want {
+ t.Errorf("Expected %d registered build statements, got %#v", want, got)
+ }
+}
+
+func testBazelContext(t *testing.T, bazelCommandResults map[bazelCommand]string) (*bazelContext, string) {
+ t.Helper()
+ p := bazelPaths{
+ buildDir: t.TempDir(),
+ outputBase: "outputbase",
+ workspaceDir: "workspace_dir",
+ }
+ aqueryCommand := bazelCommand{command: "aquery", expression: "deps(//:buildroot)"}
+ if _, exists := bazelCommandResults[aqueryCommand]; !exists {
+ bazelCommandResults[aqueryCommand] = "{}\n"
+ }
+ runner := &mockBazelRunner{bazelCommandResults: bazelCommandResults}
+ return &bazelContext{
+ bazelRunner: runner,
+ paths: &p,
+ requests: map[cqueryKey]bool{},
+ }, p.buildDir
+}
diff --git a/android/config.go b/android/config.go
index 80651bb..c170f1e 100644
--- a/android/config.go
+++ b/android/config.go
@@ -345,7 +345,7 @@
// multiple runs in the same program execution is carried over (such as Bazel
// context or environment deps).
func ConfigForAdditionalRun(c Config) (Config, error) {
- newConfig, err := NewConfig(c.srcDir, c.buildDir, c.moduleListFile)
+ newConfig, err := NewConfig(c.srcDir, c.buildDir, c.moduleListFile, c.env)
if err != nil {
return Config{}, err
}
@@ -356,12 +356,12 @@
// NewConfig creates a new Config object. The srcDir argument specifies the path
// to the root source directory. It also loads the config file, if found.
-func NewConfig(srcDir, buildDir string, moduleListFile string) (Config, error) {
+func NewConfig(srcDir, buildDir string, moduleListFile string, availableEnv map[string]string) (Config, error) {
// Make a config with default options.
config := &config{
ProductVariablesFileName: filepath.Join(buildDir, productVariablesFileName),
- env: originalEnv,
+ env: availableEnv,
srcDir: srcDir,
buildDir: buildDir,
@@ -1259,7 +1259,7 @@
if len(c.productVariables.CFIIncludePaths) == 0 {
return false
}
- return HasAnyPrefix(path, c.productVariables.CFIIncludePaths)
+ return HasAnyPrefix(path, c.productVariables.CFIIncludePaths) && !c.CFIDisabledForPath(path)
}
func (c *config) MemtagHeapDisabledForPath(path string) bool {
@@ -1273,14 +1273,14 @@
if len(c.productVariables.MemtagHeapAsyncIncludePaths) == 0 {
return false
}
- return HasAnyPrefix(path, c.productVariables.MemtagHeapAsyncIncludePaths)
+ return HasAnyPrefix(path, c.productVariables.MemtagHeapAsyncIncludePaths) && !c.MemtagHeapDisabledForPath(path)
}
func (c *config) MemtagHeapSyncEnabledForPath(path string) bool {
if len(c.productVariables.MemtagHeapSyncIncludePaths) == 0 {
return false
}
- return HasAnyPrefix(path, c.productVariables.MemtagHeapSyncIncludePaths)
+ return HasAnyPrefix(path, c.productVariables.MemtagHeapSyncIncludePaths) && !c.MemtagHeapDisabledForPath(path)
}
func (c *config) VendorConfig(name string) VendorConfig {
diff --git a/android/env.go b/android/env.go
deleted file mode 100644
index 725a145..0000000
--- a/android/env.go
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2015 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 android
-
-import (
- "android/soong/shared"
-)
-
-// This file supports dependencies on environment variables. During build
-// manifest generation, any dependency on an environment variable is added to a
-// list. At the end of the build, a JSON file called soong.environment.used is
-// written containing the current value of all used environment variables. The
-// next time the top-level build script is run, soong_ui parses the compare the
-// contents of the used environment variables, then, if they changed, deletes
-// soong.environment.used to cause a rebuild.
-//
-// The dependency of build.ninja on soong.environment.used is declared in
-// build.ninja.d
-
-var originalEnv map[string]string
-
-func InitEnvironment(envFile string) {
- var err error
- originalEnv, err = shared.EnvFromFile(envFile)
- if err != nil {
- panic(err)
- }
-}
diff --git a/android/image.go b/android/image.go
index 1a1a423..bdb9be0 100644
--- a/android/image.go
+++ b/android/image.go
@@ -30,6 +30,11 @@
// vendor ramdisk partition).
VendorRamdiskVariantNeeded(ctx BaseModuleContext) bool
+ // DebugRamdiskVariantNeeded should return true if the module needs a debug ramdisk variant (installed on the
+ // debug ramdisk partition: $(PRODUCT_OUT)/debug_ramdisk/first_stage_ramdisk if BOARD_USES_RECOVERY_AS_ROOT is
+ // true, $(PRODUCT_OUT)/debug_ramdisk otherise).
+ DebugRamdiskVariantNeeded(ctx BaseModuleContext) bool
+
// RecoveryVariantNeeded should return true if the module needs a recovery variant (installed on the
// recovery partition).
RecoveryVariantNeeded(ctx BaseModuleContext) bool
@@ -60,6 +65,9 @@
// VendorRamdiskVariation means a module to be installed to vendor ramdisk image.
VendorRamdiskVariation string = "vendor_ramdisk"
+
+ // DebugRamdiskVariation means a module to be installed to debug ramdisk image.
+ DebugRamdiskVariation string = "debug_ramdisk"
)
// imageMutator creates variants for modules that implement the ImageInterface that
@@ -83,6 +91,9 @@
if m.VendorRamdiskVariantNeeded(ctx) {
variations = append(variations, VendorRamdiskVariation)
}
+ if m.DebugRamdiskVariantNeeded(ctx) {
+ variations = append(variations, DebugRamdiskVariation)
+ }
if m.RecoveryVariantNeeded(ctx) {
variations = append(variations, RecoveryVariation)
}
diff --git a/android/module.go b/android/module.go
index 9f923e2..942e071 100644
--- a/android/module.go
+++ b/android/module.go
@@ -393,6 +393,7 @@
InstallInSanitizerDir() bool
InstallInRamdisk() bool
InstallInVendorRamdisk() bool
+ InstallInDebugRamdisk() bool
InstallInRecovery() bool
InstallInRoot() bool
InstallBypassMake() bool
@@ -450,6 +451,7 @@
InstallInSanitizerDir() bool
InstallInRamdisk() bool
InstallInVendorRamdisk() bool
+ InstallInDebugRamdisk() bool
InstallInRecovery() bool
InstallInRoot() bool
InstallBypassMake() bool
@@ -753,6 +755,9 @@
// Whether this module is installed to vendor ramdisk
Vendor_ramdisk *bool
+ // Whether this module is installed to debug ramdisk
+ Debug_ramdisk *bool
+
// Whether this module is built for non-native architectures (also known as native bridge binary)
Native_bridge_supported *bool `android:"arch_variant"`
@@ -1540,6 +1545,10 @@
return Bool(m.commonProperties.Vendor_ramdisk)
}
+func (m *ModuleBase) InstallInDebugRamdisk() bool {
+ return Bool(m.commonProperties.Debug_ramdisk)
+}
+
func (m *ModuleBase) InstallInRecovery() bool {
return Bool(m.commonProperties.Recovery)
}
@@ -1593,6 +1602,10 @@
return m.base().commonProperties.ImageVariation == VendorRamdiskVariation
}
+func (m *ModuleBase) InDebugRamdisk() bool {
+ return m.base().commonProperties.ImageVariation == DebugRamdiskVariation
+}
+
func (m *ModuleBase) InRecovery() bool {
return m.base().commonProperties.ImageVariation == RecoveryVariation
}
@@ -2548,6 +2561,10 @@
return m.module.InstallInVendorRamdisk()
}
+func (m *moduleContext) InstallInDebugRamdisk() bool {
+ return m.module.InstallInDebugRamdisk()
+}
+
func (m *moduleContext) InstallInRecovery() bool {
return m.module.InstallInRecovery()
}
diff --git a/android/paths.go b/android/paths.go
index 37b04dd..c303c38 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -107,6 +107,7 @@
InstallInSanitizerDir() bool
InstallInRamdisk() bool
InstallInVendorRamdisk() bool
+ InstallInDebugRamdisk() bool
InstallInRecovery() bool
InstallInRoot() bool
InstallBypassMake() bool
@@ -416,6 +417,93 @@
return labels
}
+// Returns true if a prefix + components[:i] + /Android.bp exists
+// TODO(b/185358476) Could check for BUILD file instead of checking for Android.bp file, or ensure BUILD is always generated?
+func directoryHasBlueprint(fs pathtools.FileSystem, prefix string, components []string, componentIndex int) bool {
+ blueprintPath := prefix
+ if blueprintPath != "" {
+ blueprintPath = blueprintPath + "/"
+ }
+ blueprintPath = blueprintPath + strings.Join(components[:componentIndex+1], "/")
+ blueprintPath = blueprintPath + "/Android.bp"
+ if exists, _, _ := fs.Exists(blueprintPath); exists {
+ return true
+ } else {
+ return false
+ }
+}
+
+// Transform a path (if necessary) to acknowledge package boundaries
+//
+// e.g. something like
+// async_safe/include/async_safe/CHECK.h
+// might become
+// //bionic/libc/async_safe:include/async_safe/CHECK.h
+// if the "async_safe" directory is actually a package and not just a directory.
+//
+// In particular, paths that extend into packages are transformed into absolute labels beginning with //.
+func transformSubpackagePath(ctx BazelConversionPathContext, path bazel.Label) bazel.Label {
+ var newPath bazel.Label
+
+ // Don't transform Bp_text
+ newPath.Bp_text = path.Bp_text
+
+ if strings.HasPrefix(path.Label, "//") {
+ // Assume absolute labels are already correct (e.g. //path/to/some/package:foo.h)
+ newPath.Label = path.Label
+ return newPath
+ }
+
+ newLabel := ""
+ pathComponents := strings.Split(path.Label, "/")
+ foundBlueprint := false
+ // Check the deepest subdirectory first and work upwards
+ for i := len(pathComponents) - 1; i >= 0; i-- {
+ pathComponent := pathComponents[i]
+ var sep string
+ if !foundBlueprint && directoryHasBlueprint(ctx.Config().fs, ctx.ModuleDir(), pathComponents, i) {
+ sep = ":"
+ foundBlueprint = true
+ } else {
+ sep = "/"
+ }
+ if newLabel == "" {
+ newLabel = pathComponent
+ } else {
+ newLabel = pathComponent + sep + newLabel
+ }
+ }
+ if foundBlueprint {
+ // Ensure paths end up looking like //bionic/... instead of //./bionic/...
+ moduleDir := ctx.ModuleDir()
+ if strings.HasPrefix(moduleDir, ".") {
+ moduleDir = moduleDir[1:]
+ }
+ // Make the path into an absolute label (e.g. //bionic/libc/foo:bar.h instead of just foo:bar.h)
+ if moduleDir == "" {
+ newLabel = "//" + newLabel
+ } else {
+ newLabel = "//" + moduleDir + "/" + newLabel
+ }
+ }
+ newPath.Label = newLabel
+
+ return newPath
+}
+
+// Transform paths to acknowledge package boundaries
+// See transformSubpackagePath() for more information
+func transformSubpackagePaths(ctx BazelConversionPathContext, paths bazel.LabelList) bazel.LabelList {
+ var newPaths bazel.LabelList
+ for _, include := range paths.Includes {
+ newPaths.Includes = append(newPaths.Includes, transformSubpackagePath(ctx, include))
+ }
+ for _, exclude := range paths.Excludes {
+ newPaths.Excludes = append(newPaths.Excludes, transformSubpackagePath(ctx, exclude))
+ }
+ return newPaths
+}
+
// BazelLabelForModuleSrc returns bazel.LabelList with paths rooted from the module's local source
// directory. It expands globs, and resolves references to modules using the ":name" syntax to
// bazel-compatible labels. Properties passed as the paths or excludes argument must have been
@@ -445,6 +533,7 @@
}
labels := expandSrcsForBazel(ctx, paths, excluded)
labels.Excludes = excludeLabels.Includes
+ labels = transformSubpackagePaths(ctx, labels)
return labels
}
@@ -1101,11 +1190,12 @@
// a single file.
files, err = gctx.GlobWithDeps(path.String(), nil)
} else {
- var deps []string
+ var result pathtools.GlobResult
// We cannot add build statements in this context, so we fall back to
// AddNinjaFileDeps
- files, deps, err = ctx.Config().fs.Glob(path.String(), nil, pathtools.FollowSymlinks)
- ctx.AddNinjaFileDeps(deps...)
+ result, err = ctx.Config().fs.Glob(path.String(), nil, pathtools.FollowSymlinks)
+ ctx.AddNinjaFileDeps(result.Deps...)
+ files = result.Matches
}
if err != nil {
@@ -1848,6 +1938,16 @@
if !ctx.InstallInRoot() {
partition += "/system"
}
+ } else if ctx.InstallInDebugRamdisk() {
+ // The module is only available after switching root into
+ // /first_stage_ramdisk. To expose the module before switching root
+ // on a device without a dedicated recovery partition, install the
+ // recovery variant.
+ if ctx.DeviceConfig().BoardUsesRecoveryAsBoot() {
+ partition = "debug_ramdisk/first_stage_ramdisk"
+ } else {
+ partition = "debug_ramdisk"
+ }
} else if ctx.InstallInRecovery() {
if ctx.InstallInRoot() {
partition = "recovery/root"
@@ -2018,6 +2118,7 @@
inSanitizerDir bool
inRamdisk bool
inVendorRamdisk bool
+ inDebugRamdisk bool
inRecovery bool
inRoot bool
forceOS *OsType
@@ -2050,6 +2151,10 @@
return m.inVendorRamdisk
}
+func (m testModuleInstallPathContext) InstallInDebugRamdisk() bool {
+ return m.inDebugRamdisk
+}
+
func (m testModuleInstallPathContext) InstallInRecovery() bool {
return m.inRecovery
}
diff --git a/android/paths_test.go b/android/paths_test.go
index 465ea3b..cb9138b 100644
--- a/android/paths_test.go
+++ b/android/paths_test.go
@@ -21,6 +21,8 @@
"strconv"
"strings"
"testing"
+
+ "github.com/google/blueprint/proptools"
)
type strsTestCase struct {
@@ -339,6 +341,73 @@
},
{
+ name: "ramdisk binary",
+ ctx: &testModuleInstallPathContext{
+ baseModuleContext: baseModuleContext{
+ os: deviceTarget.Os,
+ target: deviceTarget,
+ },
+ inRamdisk: true,
+ },
+ in: []string{"my_test"},
+ out: "target/product/test_device/ramdisk/system/my_test",
+ partitionDir: "target/product/test_device/ramdisk/system",
+ },
+ {
+ name: "ramdisk root binary",
+ ctx: &testModuleInstallPathContext{
+ baseModuleContext: baseModuleContext{
+ os: deviceTarget.Os,
+ target: deviceTarget,
+ },
+ inRamdisk: true,
+ inRoot: true,
+ },
+ in: []string{"my_test"},
+ out: "target/product/test_device/ramdisk/my_test",
+ partitionDir: "target/product/test_device/ramdisk",
+ },
+ {
+ name: "vendor_ramdisk binary",
+ ctx: &testModuleInstallPathContext{
+ baseModuleContext: baseModuleContext{
+ os: deviceTarget.Os,
+ target: deviceTarget,
+ },
+ inVendorRamdisk: true,
+ },
+ in: []string{"my_test"},
+ out: "target/product/test_device/vendor_ramdisk/system/my_test",
+ partitionDir: "target/product/test_device/vendor_ramdisk/system",
+ },
+ {
+ name: "vendor_ramdisk root binary",
+ ctx: &testModuleInstallPathContext{
+ baseModuleContext: baseModuleContext{
+ os: deviceTarget.Os,
+ target: deviceTarget,
+ },
+ inVendorRamdisk: true,
+ inRoot: true,
+ },
+ in: []string{"my_test"},
+ out: "target/product/test_device/vendor_ramdisk/my_test",
+ partitionDir: "target/product/test_device/vendor_ramdisk",
+ },
+ {
+ name: "debug_ramdisk binary",
+ ctx: &testModuleInstallPathContext{
+ baseModuleContext: baseModuleContext{
+ os: deviceTarget.Os,
+ target: deviceTarget,
+ },
+ inDebugRamdisk: true,
+ },
+ in: []string{"my_test"},
+ out: "target/product/test_device/debug_ramdisk/my_test",
+ partitionDir: "target/product/test_device/debug_ramdisk",
+ },
+ {
name: "system native test binary",
ctx: &testModuleInstallPathContext{
baseModuleContext: baseModuleContext{
@@ -635,6 +704,80 @@
}
}
+func TestPathForModuleInstallRecoveryAsBoot(t *testing.T) {
+ testConfig := pathTestConfig("")
+ testConfig.TestProductVariables.BoardUsesRecoveryAsBoot = proptools.BoolPtr(true)
+ testConfig.TestProductVariables.BoardMoveRecoveryResourcesToVendorBoot = proptools.BoolPtr(true)
+ deviceTarget := Target{Os: Android, Arch: Arch{ArchType: Arm64}}
+
+ testCases := []struct {
+ name string
+ ctx *testModuleInstallPathContext
+ in []string
+ out string
+ partitionDir string
+ }{
+ {
+ name: "ramdisk binary",
+ ctx: &testModuleInstallPathContext{
+ baseModuleContext: baseModuleContext{
+ os: deviceTarget.Os,
+ target: deviceTarget,
+ },
+ inRamdisk: true,
+ inRoot: true,
+ },
+ in: []string{"my_test"},
+ out: "target/product/test_device/recovery/root/first_stage_ramdisk/my_test",
+ partitionDir: "target/product/test_device/recovery/root/first_stage_ramdisk",
+ },
+
+ {
+ name: "vendor_ramdisk binary",
+ ctx: &testModuleInstallPathContext{
+ baseModuleContext: baseModuleContext{
+ os: deviceTarget.Os,
+ target: deviceTarget,
+ },
+ inVendorRamdisk: true,
+ inRoot: true,
+ },
+ in: []string{"my_test"},
+ out: "target/product/test_device/vendor_ramdisk/first_stage_ramdisk/my_test",
+ partitionDir: "target/product/test_device/vendor_ramdisk/first_stage_ramdisk",
+ },
+ {
+ name: "debug_ramdisk binary",
+ ctx: &testModuleInstallPathContext{
+ baseModuleContext: baseModuleContext{
+ os: deviceTarget.Os,
+ target: deviceTarget,
+ },
+ inDebugRamdisk: true,
+ },
+ in: []string{"my_test"},
+ out: "target/product/test_device/debug_ramdisk/first_stage_ramdisk/my_test",
+ partitionDir: "target/product/test_device/debug_ramdisk/first_stage_ramdisk",
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ tc.ctx.baseModuleContext.config = testConfig
+ output := PathForModuleInstall(tc.ctx, tc.in...)
+ if output.basePath.path != tc.out {
+ t.Errorf("unexpected path:\n got: %q\nwant: %q\n",
+ output.basePath.path,
+ tc.out)
+ }
+ if output.partitionDir != tc.partitionDir {
+ t.Errorf("unexpected partitionDir:\n got: %q\nwant: %q\n",
+ output.partitionDir, tc.partitionDir)
+ }
+ })
+ }
+}
+
func TestBaseDirForInstallPath(t *testing.T) {
testConfig := pathTestConfig("")
deviceTarget := Target{Os: Android, Arch: Arch{ArchType: Arm64}}
diff --git a/android/prebuilt.go b/android/prebuilt.go
index 2fc4782..40bcdfd 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -339,6 +339,13 @@
return false
}
+ // Skip prebuilt modules under unexported namespaces so that we won't
+ // end up shadowing non-prebuilt module when prebuilt module under same
+ // name happens to have a `Prefer` property set to true.
+ if ctx.Config().KatiEnabled() && !prebuilt.ExportedToMake() {
+ return false
+ }
+
// TODO: use p.Properties.Name and ctx.ModuleDir to override preference
if Bool(p.properties.Prefer) {
return true
diff --git a/android/sdk_version.go b/android/sdk_version.go
index 5fdaa91..98db824 100644
--- a/android/sdk_version.go
+++ b/android/sdk_version.go
@@ -22,15 +22,15 @@
type SdkContext interface {
// SdkVersion returns SdkSpec that corresponds to the sdk_version property of the current module
- SdkVersion() SdkSpec
+ SdkVersion(ctx EarlyModuleContext) SdkSpec
// SystemModules returns the system_modules property of the current module, or an empty string if it is not set.
SystemModules() string
// MinSdkVersion returns SdkSpec that corresponds to the min_sdk_version property of the current module,
// or from sdk_version if it is not set.
- MinSdkVersion() SdkSpec
+ MinSdkVersion(ctx EarlyModuleContext) SdkSpec
// TargetSdkVersion returns the SdkSpec that corresponds to the target_sdk_version property of the current module,
// or from sdk_version if it is not set.
- TargetSdkVersion() SdkSpec
+ TargetSdkVersion(ctx EarlyModuleContext) SdkSpec
}
// SdkKind represents a particular category of an SDK spec like public, system, test, etc.
@@ -201,15 +201,23 @@
return ctx.Config().DefaultAppTargetSdk(ctx).String(), nil
}
-func SdkSpecFrom(str string) SdkSpec {
+var (
+ SdkSpecNone = SdkSpec{SdkNone, NoneApiLevel, "(no version)"}
+ // TODO(b/175678607) ApiLevel of SdkSpecPrivate should be FutureApiLevel
+ SdkSpecPrivate = SdkSpec{SdkPrivate, NoneApiLevel, ""}
+ // TODO(b/175678607) ApiLevel of SdkSpecCorePlatform should be FutureApiLevel
+ SdkSpecCorePlatform = SdkSpec{SdkCorePlatform, NoneApiLevel, "core_platform"}
+)
+
+func SdkSpecFrom(ctx EarlyModuleContext, str string) SdkSpec {
switch str {
// special cases first
case "":
- return SdkSpec{SdkPrivate, NoneApiLevel, str}
+ return SdkSpecPrivate
case "none":
- return SdkSpec{SdkNone, NoneApiLevel, str}
+ return SdkSpecNone
case "core_platform":
- return SdkSpec{SdkCorePlatform, NoneApiLevel, str}
+ return SdkSpecCorePlatform
default:
// the syntax is [kind_]version
sep := strings.LastIndex(str, "_")
@@ -242,15 +250,10 @@
return SdkSpec{SdkInvalid, NoneApiLevel, str}
}
- var apiLevel ApiLevel
- if versionString == "current" {
- apiLevel = FutureApiLevel
- } else if i, err := strconv.Atoi(versionString); err == nil {
- apiLevel = uncheckedFinalApiLevel(i)
- } else {
+ apiLevel, err := ApiLevelFromUser(ctx, versionString)
+ if err != nil {
return SdkSpec{SdkInvalid, apiLevel, str}
}
-
return SdkSpec{kind, apiLevel, str}
}
}
diff --git a/apex/apex.go b/apex/apex.go
index 880028f..0eacf6d 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -2272,8 +2272,10 @@
tag := ctx.OtherModuleDependencyTag(module)
switch tag {
case javaLibTag, androidAppTag:
- if m, ok := module.(interface{ CheckStableSdkVersion() error }); ok {
- if err := m.CheckStableSdkVersion(); err != nil {
+ if m, ok := module.(interface {
+ CheckStableSdkVersion(ctx android.BaseModuleContext) error
+ }); ok {
+ if err := m.CheckStableSdkVersion(ctx); err != nil {
ctx.ModuleErrorf("cannot depend on \"%v\": %v", ctx.OtherModuleName(module), err)
}
}
diff --git a/apex/apex_test.go b/apex/apex_test.go
index ee4255e..977a954 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -4375,9 +4375,7 @@
// These tests verify that the prebuilt_apex/deapexer to java_import wiring allows for the
// propagation of paths to dex implementation jars from the former to the latter.
func TestPrebuiltExportDexImplementationJars(t *testing.T) {
- transform := func(config *dexpreopt.GlobalConfig) {
- // Empty transformation.
- }
+ transform := android.NullFixturePreparer
checkDexJarBuildPath := func(t *testing.T, ctx *android.TestContext, name string) {
// Make sure the import has been given the correct path to the dex jar.
@@ -4547,9 +4545,7 @@
}
func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) {
- transform := func(config *dexpreopt.GlobalConfig) {
- config.BootJars = android.CreateTestConfiguredJarList([]string{"myapex:libfoo", "myapex:libbar"})
- }
+ preparer := java.FixtureConfigureBootJars("myapex:libfoo", "myapex:libbar")
checkBootDexJarPath := func(t *testing.T, ctx *android.TestContext, stem string, bootDexJarPath string) {
t.Helper()
@@ -4570,8 +4566,8 @@
checkHiddenAPIIndexInputs := func(t *testing.T, ctx *android.TestContext, expectedInputs string) {
t.Helper()
- hiddenAPIIndex := ctx.SingletonForTests("hiddenapi_index")
- indexRule := hiddenAPIIndex.Rule("singleton-merged-hiddenapi-index")
+ platformBootclasspath := ctx.ModuleForTests("platform-bootclasspath", "android_common")
+ indexRule := platformBootclasspath.Rule("platform-bootclasspath-monolithic-hiddenapi-index")
java.CheckHiddenAPIRuleInputs(t, expectedInputs, indexRule)
}
@@ -4605,7 +4601,7 @@
}
`
- ctx := testDexpreoptWithApexes(t, bp, "", transform)
+ ctx := testDexpreoptWithApexes(t, bp, "", preparer)
checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libbar.jar")
@@ -4639,7 +4635,7 @@
}
`
- ctx := testDexpreoptWithApexes(t, bp, "", transform)
+ ctx := testDexpreoptWithApexes(t, bp, "", preparer)
checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libbar.jar")
@@ -4698,7 +4694,7 @@
// prebuilt_apex module always depends on the prebuilt, and so it doesn't
// find the dex boot jar in it. We either need to disable the source libfoo
// or make the prebuilt libfoo preferred.
- testDexpreoptWithApexes(t, bp, "failed to find a dex jar path for module 'libfoo'", transform)
+ testDexpreoptWithApexes(t, bp, "failed to find a dex jar path for module 'libfoo'", preparer)
})
t.Run("prebuilt library preferred with source", func(t *testing.T) {
@@ -4746,7 +4742,7 @@
}
`
- ctx := testDexpreoptWithApexes(t, bp, "", transform)
+ ctx := testDexpreoptWithApexes(t, bp, "", preparer)
checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libbar.jar")
@@ -4813,7 +4809,7 @@
}
`
- ctx := testDexpreoptWithApexes(t, bp, "", transform)
+ ctx := testDexpreoptWithApexes(t, bp, "", preparer)
checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/libfoo/android_common_apex10000/hiddenapi/libfoo.jar")
checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/libbar/android_common_myapex/hiddenapi/libbar.jar")
@@ -4830,7 +4826,7 @@
name: "myapex",
enabled: false,
key: "myapex.key",
- java_libs: ["libfoo"],
+ java_libs: ["libfoo", "libbar"],
}
apex_key {
@@ -4882,14 +4878,14 @@
}
`
- ctx := testDexpreoptWithApexes(t, bp, "", transform)
+ ctx := testDexpreoptWithApexes(t, bp, "", preparer)
checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libbar.jar")
// Make sure that the dex file from the prebuilt_apex contributes to the hiddenapi index file.
checkHiddenAPIIndexInputs(t, ctx, `
-.intermediates/prebuilt_libbar/android_common_prebuilt_myapex/hiddenapi/index.csv
-.intermediates/prebuilt_libfoo/android_common_prebuilt_myapex/hiddenapi/index.csv
+.intermediates/prebuilt_libbar/android_common_myapex/hiddenapi/index.csv
+.intermediates/prebuilt_libfoo/android_common_myapex/hiddenapi/index.csv
`)
})
}
@@ -6440,7 +6436,7 @@
android.AssertStringEquals(t, "myapex input", extractorOutput, copiedApex.Input.String())
}
-func testNoUpdatableJarsInBootImage(t *testing.T, errmsg string, transformDexpreoptConfig func(*dexpreopt.GlobalConfig)) {
+func testNoUpdatableJarsInBootImage(t *testing.T, errmsg string, preparer android.FixturePreparer) {
t.Helper()
bp := `
@@ -6528,10 +6524,10 @@
}
`
- testDexpreoptWithApexes(t, bp, errmsg, transformDexpreoptConfig)
+ testDexpreoptWithApexes(t, bp, errmsg, preparer)
}
-func testDexpreoptWithApexes(t *testing.T, bp, errmsg string, transformDexpreoptConfig func(*dexpreopt.GlobalConfig)) *android.TestContext {
+func testDexpreoptWithApexes(t *testing.T, bp, errmsg string, preparer android.FixturePreparer) *android.TestContext {
t.Helper()
fs := android.MockFS{
@@ -6557,18 +6553,13 @@
java.PrepareForTestWithJavaDefaultModules,
java.PrepareForTestWithJavaSdkLibraryFiles,
PrepareForTestWithApexBuildComponents,
- android.FixtureModifyConfig(func(config android.Config) {
- pathCtx := android.PathContextForTesting(config)
- dexpreoptConfig := dexpreopt.GlobalConfigForTests(pathCtx)
- transformDexpreoptConfig(dexpreoptConfig)
- dexpreopt.SetTestGlobalConfig(config, dexpreoptConfig)
-
- // Make sure that any changes to these dexpreopt properties are mirrored in the corresponding
- // product variables.
- config.TestProductVariables.BootJars = dexpreoptConfig.BootJars
- config.TestProductVariables.UpdatableBootJars = dexpreoptConfig.UpdatableBootJars
- }),
+ preparer,
fs.AddToFixture(),
+ android.FixtureAddTextFile("frameworks/base/boot/Android.bp", `
+ platform_bootclasspath {
+ name: "platform-bootclasspath",
+ }
+ `),
).
ExtendWithErrorHandler(errorHandler).
RunTestWithBp(t, bp)
@@ -6608,92 +6599,95 @@
}
func TestNoUpdatableJarsInBootImage(t *testing.T) {
- var err string
- var transform func(*dexpreopt.GlobalConfig)
+ // Set the BootJars in dexpreopt.GlobalConfig and productVariables to the same value. This can
+ // result in an invalid configuration as it does not set the ArtApexJars and allows art apex
+ // modules to be included in the BootJars.
+ prepareSetBootJars := func(bootJars ...string) android.FixturePreparer {
+ return android.GroupFixturePreparers(
+ dexpreopt.FixtureSetBootJars(bootJars...),
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.BootJars = android.CreateTestConfiguredJarList(bootJars)
+ }),
+ )
+ }
+
+ // Set the ArtApexJars and BootJars in dexpreopt.GlobalConfig and productVariables all to the
+ // same value. This can result in an invalid configuration as it allows non art apex jars to be
+ // specified in the ArtApexJars configuration.
+ prepareSetArtJars := func(bootJars ...string) android.FixturePreparer {
+ return android.GroupFixturePreparers(
+ dexpreopt.FixtureSetArtBootJars(bootJars...),
+ dexpreopt.FixtureSetBootJars(bootJars...),
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.BootJars = android.CreateTestConfiguredJarList(bootJars)
+ }),
+ )
+ }
t.Run("updatable jar from ART apex in the ART boot image => ok", func(t *testing.T) {
- transform = func(config *dexpreopt.GlobalConfig) {
- config.ArtApexJars = android.CreateTestConfiguredJarList([]string{"com.android.art.debug:some-art-lib"})
- }
- testNoUpdatableJarsInBootImage(t, "", transform)
+ preparer := java.FixtureConfigureBootJars("com.android.art.debug:some-art-lib")
+ testNoUpdatableJarsInBootImage(t, "", preparer)
})
t.Run("updatable jar from ART apex in the framework boot image => error", func(t *testing.T) {
- err = `module "some-art-lib" from updatable apexes \["com.android.art.debug"\] is not allowed in the framework boot image`
- transform = func(config *dexpreopt.GlobalConfig) {
- config.BootJars = android.CreateTestConfiguredJarList([]string{"com.android.art.debug:some-art-lib"})
- }
- testNoUpdatableJarsInBootImage(t, err, transform)
+ err := `module "some-art-lib" from updatable apexes \["com.android.art.debug"\] is not allowed in the framework boot image`
+ // Update the dexpreopt BootJars directly.
+ preparer := prepareSetBootJars("com.android.art.debug:some-art-lib")
+ testNoUpdatableJarsInBootImage(t, err, preparer)
})
t.Run("updatable jar from some other apex in the ART boot image => error", func(t *testing.T) {
- err = `module "some-updatable-apex-lib" from updatable apexes \["some-updatable-apex"\] is not allowed in the ART boot image`
- transform = func(config *dexpreopt.GlobalConfig) {
- config.ArtApexJars = android.CreateTestConfiguredJarList([]string{"some-updatable-apex:some-updatable-apex-lib"})
- }
- testNoUpdatableJarsInBootImage(t, err, transform)
+ err := `module "some-updatable-apex-lib" from updatable apexes \["some-updatable-apex"\] is not allowed in the ART boot image`
+ // Update the dexpreopt ArtApexJars directly.
+ preparer := prepareSetArtJars("some-updatable-apex:some-updatable-apex-lib")
+ testNoUpdatableJarsInBootImage(t, err, preparer)
})
t.Run("non-updatable jar from some other apex in the ART boot image => error", func(t *testing.T) {
- err = `module "some-non-updatable-apex-lib" is not allowed in the ART boot image`
- transform = func(config *dexpreopt.GlobalConfig) {
- config.ArtApexJars = android.CreateTestConfiguredJarList([]string{"some-non-updatable-apex:some-non-updatable-apex-lib"})
- }
- testNoUpdatableJarsInBootImage(t, err, transform)
+ err := `module "some-non-updatable-apex-lib" is not allowed in the ART boot image`
+ // Update the dexpreopt ArtApexJars directly.
+ preparer := prepareSetArtJars("some-non-updatable-apex:some-non-updatable-apex-lib")
+ testNoUpdatableJarsInBootImage(t, err, preparer)
})
t.Run("updatable jar from some other apex in the framework boot image => error", func(t *testing.T) {
- err = `module "some-updatable-apex-lib" from updatable apexes \["some-updatable-apex"\] is not allowed in the framework boot image`
- transform = func(config *dexpreopt.GlobalConfig) {
- config.BootJars = android.CreateTestConfiguredJarList([]string{"some-updatable-apex:some-updatable-apex-lib"})
- }
- testNoUpdatableJarsInBootImage(t, err, transform)
+ err := `module "some-updatable-apex-lib" from updatable apexes \["some-updatable-apex"\] is not allowed in the framework boot image`
+ preparer := java.FixtureConfigureBootJars("some-updatable-apex:some-updatable-apex-lib")
+ testNoUpdatableJarsInBootImage(t, err, preparer)
})
t.Run("non-updatable jar from some other apex in the framework boot image => ok", func(t *testing.T) {
- transform = func(config *dexpreopt.GlobalConfig) {
- config.BootJars = android.CreateTestConfiguredJarList([]string{"some-non-updatable-apex:some-non-updatable-apex-lib"})
- }
- testNoUpdatableJarsInBootImage(t, "", transform)
+ preparer := java.FixtureConfigureBootJars("some-non-updatable-apex:some-non-updatable-apex-lib")
+ testNoUpdatableJarsInBootImage(t, "", preparer)
})
t.Run("nonexistent jar in the ART boot image => error", func(t *testing.T) {
- err = "failed to find a dex jar path for module 'nonexistent'"
- transform = func(config *dexpreopt.GlobalConfig) {
- config.ArtApexJars = android.CreateTestConfiguredJarList([]string{"platform:nonexistent"})
- }
- testNoUpdatableJarsInBootImage(t, err, transform)
+ err := `"platform-bootclasspath" depends on undefined module "nonexistent"`
+ preparer := java.FixtureConfigureBootJars("platform:nonexistent")
+ testNoUpdatableJarsInBootImage(t, err, preparer)
})
t.Run("nonexistent jar in the framework boot image => error", func(t *testing.T) {
- err = "failed to find a dex jar path for module 'nonexistent'"
- transform = func(config *dexpreopt.GlobalConfig) {
- config.BootJars = android.CreateTestConfiguredJarList([]string{"platform:nonexistent"})
- }
- testNoUpdatableJarsInBootImage(t, err, transform)
+ err := `"platform-bootclasspath" depends on undefined module "nonexistent"`
+ preparer := java.FixtureConfigureBootJars("platform:nonexistent")
+ testNoUpdatableJarsInBootImage(t, err, preparer)
})
t.Run("platform jar in the ART boot image => error", func(t *testing.T) {
- err = `module "some-platform-lib" is not allowed in the ART boot image`
- transform = func(config *dexpreopt.GlobalConfig) {
- config.ArtApexJars = android.CreateTestConfiguredJarList([]string{"platform:some-platform-lib"})
- }
- testNoUpdatableJarsInBootImage(t, err, transform)
+ err := `module "some-platform-lib" is not allowed in the ART boot image`
+ // Update the dexpreopt ArtApexJars directly.
+ preparer := prepareSetArtJars("platform:some-platform-lib")
+ testNoUpdatableJarsInBootImage(t, err, preparer)
})
t.Run("platform jar in the framework boot image => ok", func(t *testing.T) {
- transform = func(config *dexpreopt.GlobalConfig) {
- config.BootJars = android.CreateTestConfiguredJarList([]string{"platform:some-platform-lib"})
- }
- testNoUpdatableJarsInBootImage(t, "", transform)
+ preparer := java.FixtureConfigureBootJars("platform:some-platform-lib")
+ testNoUpdatableJarsInBootImage(t, "", preparer)
})
-
}
func TestDexpreoptAccessDexFilesFromPrebuiltApex(t *testing.T) {
- transform := func(config *dexpreopt.GlobalConfig) {
- config.BootJars = android.CreateTestConfiguredJarList([]string{"myapex:libfoo"})
- }
+ preparer := java.FixtureConfigureBootJars("myapex:libfoo")
t.Run("prebuilt no source", func(t *testing.T) {
testDexpreoptWithApexes(t, `
prebuilt_apex {
@@ -6713,7 +6707,7 @@
name: "libfoo",
jars: ["libfoo.jar"],
}
-`, "", transform)
+`, "", preparer)
})
t.Run("prebuilt no source", func(t *testing.T) {
@@ -6735,7 +6729,7 @@
name: "libfoo",
jars: ["libfoo.jar"],
}
-`, "", transform)
+`, "", preparer)
})
}
diff --git a/apex/boot_image_test.go b/apex/boot_image_test.go
index aa0d9c4..d447d70 100644
--- a/apex/boot_image_test.go
+++ b/apex/boot_image_test.go
@@ -19,7 +19,6 @@
"testing"
"android/soong/android"
- "android/soong/dexpreopt"
"android/soong/java"
)
@@ -42,8 +41,7 @@
result := android.GroupFixturePreparers(
prepareForTestWithBootImage,
// Configure some libraries in the art and framework boot images.
- dexpreopt.FixtureSetArtBootJars("com.android.art:baz", "com.android.art:quuz"),
- dexpreopt.FixtureSetBootJars("platform:foo", "platform:bar"),
+ java.FixtureConfigureBootJars("com.android.art:baz", "com.android.art:quuz", "platform:foo", "platform:bar"),
prepareForTestWithArtApex,
java.PrepareForTestWithJavaSdkLibraryFiles,
@@ -169,7 +167,7 @@
prepareForTestWithArtApex,
// Configure some libraries in the art boot image.
- dexpreopt.FixtureSetArtBootJars("com.android.art:foo", "com.android.art:bar"),
+ java.FixtureConfigureBootJars("com.android.art:foo", "com.android.art:bar"),
).RunTestWithBp(t, `
apex {
name: "com.android.art",
@@ -264,7 +262,7 @@
}),
// Configure some libraries in the art boot image.
- dexpreopt.FixtureSetArtBootJars("com.android.art:foo", "com.android.art:bar"),
+ java.FixtureConfigureBootJars("com.android.art:foo", "com.android.art:bar"),
).RunTestWithBp(t, `
prebuilt_apex {
name: "com.android.art",
diff --git a/apex/builder.go b/apex/builder.go
index 2df380b..e59dc96 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -517,6 +517,9 @@
outHostBinDir := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "bin").String()
prebuiltSdkToolsBinDir := filepath.Join("prebuilts", "sdk", "tools", runtime.GOOS, "bin")
+ // Figure out if need to compress apex.
+ compressionEnabled := ctx.Config().CompressedApex() && proptools.BoolDefault(a.properties.Compressible, false) && !a.testApex
+
if apexType == imageApex {
////////////////////////////////////////////////////////////////////////////////////
// Step 2: create canned_fs_config which encodes filemode,uid,gid of each files
@@ -631,7 +634,7 @@
ctx.PropertyErrorf("test_only_no_hashtree", "not available")
return
}
- if moduleMinSdkVersion.GreaterThan(android.SdkVersion_Android10) || a.testOnlyShouldSkipHashtreeGeneration() {
+ if (moduleMinSdkVersion.GreaterThan(android.SdkVersion_Android10) || a.testOnlyShouldSkipHashtreeGeneration()) && !compressionEnabled {
// Apexes which are supposed to be installed in builtin dirs(/system, etc)
// don't need hashtree for activation. Therefore, by removing hashtree from
// apex bundle (filesystem image in it, to be specific), we can save storage.
@@ -780,12 +783,11 @@
})
a.outputFile = signedOutputFile
- // Process APEX compression if enabled or forced
if ctx.ModuleDir() != "system/apex/apexd/apexd_testdata" && a.testOnlyShouldForceCompression() {
ctx.PropertyErrorf("test_only_force_compression", "not available")
return
}
- compressionEnabled := ctx.Config().CompressedApex() && proptools.BoolDefault(a.properties.Compressible, false)
+
if apexType == imageApex && (compressionEnabled || a.testOnlyShouldForceCompression()) {
a.isCompressed = true
unsignedCompressedOutputFile := android.PathForModuleOut(ctx, a.Name()+".capex.unsigned")
@@ -946,16 +948,19 @@
depInfos[to.Name()] = info
} else {
toMinSdkVersion := "(no version)"
- if m, ok := to.(interface{ MinSdkVersion() string }); ok {
+ if m, ok := to.(interface {
+ MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec
+ }); ok {
+ if v := m.MinSdkVersion(ctx); !v.ApiLevel.IsNone() {
+ toMinSdkVersion = v.ApiLevel.String()
+ }
+ } else if m, ok := to.(interface{ MinSdkVersion() string }); ok {
+ // TODO(b/175678607) eliminate the use of MinSdkVersion returning
+ // string
if v := m.MinSdkVersion(); v != "" {
toMinSdkVersion = v
}
- } else if m, ok := to.(interface{ MinSdkVersionString() string }); ok {
- if v := m.MinSdkVersionString(); v != "" {
- toMinSdkVersion = v
- }
}
-
depInfos[to.Name()] = android.ApexModuleDepInfo{
To: to.Name(),
From: []string{from.Name()},
diff --git a/apex/platform_bootclasspath_test.go b/apex/platform_bootclasspath_test.go
index 2ea6401..74830d3 100644
--- a/apex/platform_bootclasspath_test.go
+++ b/apex/platform_bootclasspath_test.go
@@ -18,7 +18,6 @@
"testing"
"android/soong/android"
- "android/soong/dexpreopt"
"android/soong/java"
"github.com/google/blueprint"
)
@@ -37,9 +36,8 @@
prepareForTestWithArtApex,
prepareForTestWithMyapex,
// Configure some libraries in the art and framework boot images.
- dexpreopt.FixtureSetArtBootJars("com.android.art:baz", "com.android.art:quuz"),
- dexpreopt.FixtureSetBootJars("platform:foo"),
- dexpreopt.FixtureSetUpdatableBootJars("myapex:bar"),
+ java.FixtureConfigureBootJars("com.android.art:baz", "com.android.art:quuz", "platform:foo"),
+ java.FixtureConfigureUpdatableBootJars("myapex:bar"),
java.PrepareForTestWithJavaSdkLibraryFiles,
java.FixtureWithLastReleaseApis("foo"),
).RunTestWithBp(t, `
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index 10a70a3..a9d24a7 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -172,7 +172,7 @@
// Create an ApexInfo for the prebuilt_apex.
apexInfo := android.ApexInfo{
- ApexVariationName: mctx.ModuleName(),
+ ApexVariationName: android.RemoveOptionalPrebuiltPrefix(mctx.ModuleName()),
InApexes: []string{mctx.ModuleName()},
ApexContents: []*android.ApexContents{apexContents},
ForPrebuiltApex: true,
diff --git a/bazel/cquery/request_type.go b/bazel/cquery/request_type.go
index b88da2f..8049108 100644
--- a/bazel/cquery/request_type.go
+++ b/bazel/cquery/request_type.go
@@ -1,18 +1,19 @@
package cquery
import (
+ "fmt"
"strings"
)
var (
- GetOutputFiles = &getOutputFilesRequestType{}
- GetOutputFilesAndCcObjectFiles = &getOutputFilesAndCcObjectFilesType{}
- GetPrebuiltCcStaticLibraryFiles = &getPrebuiltCcStaticLibraryFiles{}
+ GetOutputFiles = &getOutputFilesRequestType{}
+ GetCcInfo = &getCcInfoType{}
)
-type GetOutputFilesAndCcObjectFiles_Result struct {
- OutputFiles []string
- CcObjectFiles []string
+type CcInfo struct {
+ OutputFiles []string
+ CcObjectFiles []string
+ CcStaticLibraryFiles []string
}
type getOutputFilesRequestType struct{}
@@ -39,15 +40,15 @@
// The given rawString must correspond to the string output which was created by evaluating the
// Starlark given in StarlarkFunctionBody.
func (g getOutputFilesRequestType) ParseResult(rawString string) []string {
- return strings.Split(rawString, ", ")
+ return splitOrEmpty(rawString, ", ")
}
-type getOutputFilesAndCcObjectFilesType struct{}
+type getCcInfoType struct{}
// Name returns a string name for this request type. Such request type names must be unique,
// and must only consist of alphanumeric characters.
-func (g getOutputFilesAndCcObjectFilesType) Name() string {
- return "getOutputFilesAndCcObjectFiles"
+func (g getCcInfoType) Name() string {
+ return "getCcInfo"
}
// StarlarkFunctionBody returns a starlark function body to process this request type.
@@ -58,61 +59,52 @@
// - `target` is the only parameter to this function (a configured target).
// - The return value must be a string.
// - The function body should not be indented outside of its own scope.
-func (g getOutputFilesAndCcObjectFilesType) StarlarkFunctionBody() string {
+func (g getCcInfoType) StarlarkFunctionBody() string {
return `
outputFiles = [f.path for f in target.files.to_list()]
ccObjectFiles = []
+staticLibraries = []
linker_inputs = providers(target)["CcInfo"].linking_context.linker_inputs.to_list()
for linker_input in linker_inputs:
for library in linker_input.libraries:
for object in library.objects:
ccObjectFiles += [object.path]
-return ', '.join(outputFiles) + "|" + ', '.join(ccObjectFiles)`
+ if library.static_library:
+ staticLibraries.append(library.static_library.path)
+
+returns = [
+ outputFiles,
+ staticLibraries,
+ ccObjectFiles,
+]
+
+return "|".join([", ".join(r) for r in returns])`
}
// ParseResult returns a value obtained by parsing the result of the request's Starlark function.
// The given rawString must correspond to the string output which was created by evaluating the
// Starlark given in StarlarkFunctionBody.
-func (g getOutputFilesAndCcObjectFilesType) ParseResult(rawString string) GetOutputFilesAndCcObjectFiles_Result {
+func (g getCcInfoType) ParseResult(rawString string) (CcInfo, error) {
var outputFiles []string
var ccObjects []string
splitString := strings.Split(rawString, "|")
+ if expectedLen := 3; len(splitString) != expectedLen {
+ return CcInfo{}, fmt.Errorf("Expected %d items, got %q", expectedLen, splitString)
+ }
outputFilesString := splitString[0]
- ccObjectsString := splitString[1]
+ ccStaticLibrariesString := splitString[1]
+ ccObjectsString := splitString[2]
outputFiles = splitOrEmpty(outputFilesString, ", ")
+ ccStaticLibraries := splitOrEmpty(ccStaticLibrariesString, ", ")
ccObjects = splitOrEmpty(ccObjectsString, ", ")
- return GetOutputFilesAndCcObjectFiles_Result{outputFiles, ccObjects}
-}
-
-type getPrebuiltCcStaticLibraryFiles struct{}
-
-// Name returns the name of the starlark function to get prebuilt cc static library files
-func (g getPrebuiltCcStaticLibraryFiles) Name() string {
- return "getPrebuiltCcStaticLibraryFiles"
-}
-
-// StarlarkFunctionBody returns the unindented body of a starlark function for extracting the static
-// library paths from a cc_import module.
-func (g getPrebuiltCcStaticLibraryFiles) StarlarkFunctionBody() string {
- return `
-linker_inputs = providers(target)["CcInfo"].linking_context.linker_inputs.to_list()
-
-static_libraries = []
-for linker_input in linker_inputs:
- for library in linker_input.libraries:
- static_libraries.append(library.static_library.path)
-
-return ', '.join(static_libraries)`
-}
-
-// ParseResult returns a slice of bazel output paths to static libraries if any exist for the given
-// rawString corresponding to the string output which was created by evaluating the
-// StarlarkFunctionBody.
-func (g getPrebuiltCcStaticLibraryFiles) ParseResult(rawString string) []string {
- return strings.Split(rawString, ", ")
+ return CcInfo{
+ OutputFiles: outputFiles,
+ CcObjectFiles: ccObjects,
+ CcStaticLibraryFiles: ccStaticLibraries,
+ }, nil
}
// splitOrEmpty is a modification of strings.Split() that returns an empty list
diff --git a/bazel/cquery/request_type_test.go b/bazel/cquery/request_type_test.go
new file mode 100644
index 0000000..48edb90
--- /dev/null
+++ b/bazel/cquery/request_type_test.go
@@ -0,0 +1,95 @@
+package cquery
+
+import (
+ "fmt"
+ "reflect"
+ "testing"
+)
+
+func TestGetOutputFilesParseResults(t *testing.T) {
+ testCases := []struct {
+ description string
+ input string
+ expectedOutput []string
+ }{
+ {
+ description: "no result",
+ input: "",
+ expectedOutput: []string{},
+ },
+ {
+ description: "one result",
+ input: "test",
+ expectedOutput: []string{"test"},
+ },
+ {
+ description: "splits on comma with space",
+ input: "foo, bar",
+ expectedOutput: []string{"foo", "bar"},
+ },
+ }
+ for _, tc := range testCases {
+ actualOutput := GetOutputFiles.ParseResult(tc.input)
+ if !reflect.DeepEqual(tc.expectedOutput, actualOutput) {
+ t.Errorf("%q: expected %#v != actual %#v", tc.description, tc.expectedOutput, actualOutput)
+ }
+ }
+}
+
+func TestGetCcInfoParseResults(t *testing.T) {
+ testCases := []struct {
+ description string
+ input string
+ expectedOutput CcInfo
+ expectedErrorMessage string
+ }{
+ {
+ description: "no result",
+ input: "||",
+ expectedOutput: CcInfo{
+ OutputFiles: []string{},
+ CcObjectFiles: []string{},
+ CcStaticLibraryFiles: []string{},
+ },
+ },
+ {
+ description: "only output",
+ input: "test||",
+ expectedOutput: CcInfo{
+ OutputFiles: []string{"test"},
+ CcObjectFiles: []string{},
+ CcStaticLibraryFiles: []string{},
+ },
+ },
+ {
+ description: "all items set",
+ input: "out1, out2|static_lib1, static_lib2|object1, object2",
+ expectedOutput: CcInfo{
+ OutputFiles: []string{"out1", "out2"},
+ CcObjectFiles: []string{"object1", "object2"},
+ CcStaticLibraryFiles: []string{"static_lib1", "static_lib2"},
+ },
+ },
+ {
+ description: "too few result splits",
+ input: "|",
+ expectedOutput: CcInfo{},
+ expectedErrorMessage: fmt.Sprintf("Expected %d items, got %q", 3, []string{"", ""}),
+ },
+ {
+ description: "too many result splits",
+ input: "|||",
+ expectedOutput: CcInfo{},
+ expectedErrorMessage: fmt.Sprintf("Expected %d items, got %q", 3, []string{"", "", "", ""}),
+ },
+ }
+ for _, tc := range testCases {
+ actualOutput, err := GetCcInfo.ParseResult(tc.input)
+ if (err == nil && tc.expectedErrorMessage != "") ||
+ (err != nil && err.Error() != tc.expectedErrorMessage) {
+ t.Errorf("%q: expected Error %s, got %s", tc.description, tc.expectedErrorMessage, err)
+ } else if err == nil && !reflect.DeepEqual(tc.expectedOutput, actualOutput) {
+ t.Errorf("%q: expected %#v != actual %#v", tc.description, tc.expectedOutput, actualOutput)
+ }
+ }
+}
diff --git a/bloaty/Android.bp b/bloaty/Android.bp
index 96cc1a5..7e722a7 100644
--- a/bloaty/Android.bp
+++ b/bloaty/Android.bp
@@ -11,6 +11,7 @@
],
srcs: [
"bloaty.go",
+ "testing.go",
],
pluginFor: ["soong_build"],
}
diff --git a/bloaty/bloaty.go b/bloaty/bloaty.go
index 764cded..50f241f 100644
--- a/bloaty/bloaty.go
+++ b/bloaty/bloaty.go
@@ -52,12 +52,28 @@
pctx.SourcePathVariable("bloaty", "prebuilts/build-tools/${hostPrebuiltTag}/bin/bloaty")
pctx.HostBinToolVariable("bloatyMerger", "bloaty_merger")
android.RegisterSingletonType("file_metrics", fileSizesSingleton)
- fileSizeMeasurerKey = blueprint.NewProvider(android.ModuleOutPath{})
+ fileSizeMeasurerKey = blueprint.NewProvider(measuredFiles{})
}
-// MeasureSizeForPath should be called by binary producers (e.g. in builder.go).
-func MeasureSizeForPath(ctx android.ModuleContext, filePath android.WritablePath) {
- ctx.SetProvider(fileSizeMeasurerKey, filePath)
+// measuredFiles contains the paths of the files measured by a module.
+type measuredFiles struct {
+ paths []android.WritablePath
+}
+
+// MeasureSizeForPaths should be called by binary producers to measure the
+// sizes of artifacts. It must only be called once per module; it will panic
+// otherwise.
+func MeasureSizeForPaths(ctx android.ModuleContext, paths ...android.OptionalPath) {
+ mf := measuredFiles{}
+ for _, p := range paths {
+ if !p.Valid() {
+ continue
+ }
+ if p, ok := p.Path().(android.WritablePath); ok {
+ mf.paths = append(mf.paths, p)
+ }
+ }
+ ctx.SetProvider(fileSizeMeasurerKey, mf)
}
type sizesSingleton struct{}
@@ -68,21 +84,22 @@
func (singleton *sizesSingleton) GenerateBuildActions(ctx android.SingletonContext) {
var deps android.Paths
- // Visit all modules. If the size provider give us a binary path to measure,
- // create the rule to measure it.
ctx.VisitAllModules(func(m android.Module) {
if !ctx.ModuleHasProvider(m, fileSizeMeasurerKey) {
return
}
- filePath := ctx.ModuleProvider(m, fileSizeMeasurerKey).(android.ModuleOutPath)
- sizeFile := filePath.InSameDir(ctx, filePath.Base()+bloatyDescriptorExt)
- ctx.Build(pctx, android.BuildParams{
- Rule: bloaty,
- Description: "bloaty " + filePath.Rel(),
- Input: filePath,
- Output: sizeFile,
- })
- deps = append(deps, sizeFile)
+ filePaths := ctx.ModuleProvider(m, fileSizeMeasurerKey).(measuredFiles)
+ for _, path := range filePaths.paths {
+ filePath := path.(android.ModuleOutPath)
+ sizeFile := filePath.InSameDir(ctx, filePath.Base()+bloatyDescriptorExt)
+ ctx.Build(pctx, android.BuildParams{
+ Rule: bloaty,
+ Description: "bloaty " + filePath.Rel(),
+ Input: filePath,
+ Output: sizeFile,
+ })
+ deps = append(deps, sizeFile)
+ }
})
ctx.Build(pctx, android.BuildParams{
diff --git a/bloaty/testing.go b/bloaty/testing.go
new file mode 100644
index 0000000..5f5ec84
--- /dev/null
+++ b/bloaty/testing.go
@@ -0,0 +1,25 @@
+// Copyright 2021 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 bloaty
+
+import (
+ "android/soong/android"
+)
+
+// Preparer that will define the default bloaty singleton.
+var PrepareForTestWithBloatyDefaultModules = android.GroupFixturePreparers(
+ android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
+ ctx.RegisterSingletonType("file_metrics", fileSizesSingleton)
+ }))
diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go
index 427aed3..7e72a8b 100644
--- a/bp2build/cc_library_static_conversion_test.go
+++ b/bp2build/cc_library_static_conversion_test.go
@@ -279,6 +279,53 @@
],
)`},
},
+ {
+ description: "cc_library_static subpackage test",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ filesystem: map[string]string{
+ // subpackage with subdirectory
+ "subpackage/Android.bp": "",
+ "subpackage/subpackage_header.h": "",
+ "subpackage/subdirectory/subdirectory_header.h": "",
+ // subsubpackage with subdirectory
+ "subpackage/subsubpackage/Android.bp": "",
+ "subpackage/subsubpackage/subsubpackage_header.h": "",
+ "subpackage/subsubpackage/subdirectory/subdirectory_header.h": "",
+ // subsubsubpackage with subdirectory
+ "subpackage/subsubpackage/subsubsubpackage/Android.bp": "",
+ "subpackage/subsubpackage/subsubsubpackage/subsubsubpackage_header.h": "",
+ "subpackage/subsubpackage/subsubsubpackage/subdirectory/subdirectory_header.h": "",
+ },
+ bp: soongCcLibraryStaticPreamble + `
+cc_library_static {
+ name: "foo_static",
+ srcs: [
+ ],
+ include_dirs: [
+ "subpackage",
+ ],
+
+ bazel_module: { bp2build_available: true },
+}`,
+ expectedBazelTargets: []string{`cc_library_static(
+ name = "foo_static",
+ includes = [
+ "subpackage",
+ ".",
+ ],
+ linkstatic = True,
+ srcs = [
+ "//subpackage:subpackage_header.h",
+ "//subpackage:subdirectory/subdirectory_header.h",
+ "//subpackage/subsubpackage:subsubpackage_header.h",
+ "//subpackage/subsubpackage:subdirectory/subdirectory_header.h",
+ "//subpackage/subsubpackage/subsubsubpackage:subsubsubpackage_header.h",
+ "//subpackage/subsubpackage/subsubsubpackage:subdirectory/subdirectory_header.h",
+ ],
+)`},
+ },
}
dir := "."
diff --git a/cc/cc.go b/cc/cc.go
index 9176bc3..bef49b8 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -1113,16 +1113,33 @@
return inList(c.BaseModuleName(), *getNDKKnownLibs(config))
}
-// isLLndk returns true for both LLNDK (public) and LLNDK-private libs.
func (c *Module) IsLlndk() bool {
return c.VendorProperties.IsLLNDK
}
-// IsLlndkPublic returns true only for LLNDK (public) libs.
func (c *Module) IsLlndkPublic() bool {
return c.VendorProperties.IsLLNDK && !c.VendorProperties.IsVNDKPrivate
}
+func (c *Module) IsLlndkHeaders() bool {
+ if _, ok := c.linker.(*llndkHeadersDecorator); ok {
+ return true
+ }
+ return false
+}
+
+func (c *Module) IsLlndkLibrary() bool {
+ if _, ok := c.linker.(*llndkStubDecorator); ok {
+ return true
+ }
+ return false
+}
+
+func (m *Module) HasLlndkStubs() bool {
+ lib := moduleLibraryInterface(m)
+ return lib != nil && lib.hasLLNDKStubs()
+}
+
// isImplementationForLLNDKPublic returns true for any variant of a cc_library that has LLNDK stubs
// and does not set llndk.vendor_available: false.
func (c *Module) isImplementationForLLNDKPublic() bool {
@@ -1186,6 +1203,10 @@
return false
}
+func (c *Module) SubName() string {
+ return c.Properties.SubName
+}
+
func (c *Module) MustUseVendorVariant() bool {
return c.isVndkSp() || c.Properties.MustUseVendorVariant
}
@@ -1246,7 +1267,7 @@
return c.linker != nil && c.linker.nativeCoverage()
}
-func (c *Module) isSnapshotPrebuilt() bool {
+func (c *Module) IsSnapshotPrebuilt() bool {
if p, ok := c.linker.(snapshotInterface); ok {
return p.isSnapshotPrebuilt()
}
@@ -2289,12 +2310,7 @@
if ccFrom.vndkdep != nil {
ccFrom.vndkdep.vndkCheckLinkType(ctx, ccTo, tag)
}
- } else if linkableMod, ok := to.(LinkableInterface); ok {
- // Static libraries from other languages can be linked
- if !linkableMod.Static() {
- ctx.ModuleErrorf("Attempting to link VNDK cc.Module with unsupported module type")
- }
- } else {
+ } else if _, ok := to.(LinkableInterface); !ok {
ctx.ModuleErrorf("Attempting to link VNDK cc.Module with unsupported module type")
}
return
@@ -2807,7 +2823,7 @@
c.sabi.Properties.ReexportedIncludes, depExporterInfo.IncludeDirs.Strings()...)
}
- makeLibName := c.makeLibName(ctx, ccDep, depName) + libDepTag.makeSuffix
+ makeLibName := MakeLibName(ctx, c, ccDep, depName) + libDepTag.makeSuffix
switch {
case libDepTag.header():
c.Properties.AndroidMkHeaderLibs = append(
@@ -2846,7 +2862,7 @@
switch depTag {
case runtimeDepTag:
c.Properties.AndroidMkRuntimeLibs = append(
- c.Properties.AndroidMkRuntimeLibs, c.makeLibName(ctx, ccDep, depName)+libDepTag.makeSuffix)
+ c.Properties.AndroidMkRuntimeLibs, MakeLibName(ctx, c, ccDep, depName)+libDepTag.makeSuffix)
// Record baseLibName for snapshots.
c.Properties.SnapshotRuntimeLibs = append(c.Properties.SnapshotRuntimeLibs, baseLibName(depName))
case objDepTag:
@@ -2924,7 +2940,8 @@
return libName
}
-func (c *Module) makeLibName(ctx android.ModuleContext, ccDep LinkableInterface, depName string) string {
+func MakeLibName(ctx android.ModuleContext, c LinkableInterface, ccDep LinkableInterface, depName string) string {
+
vendorPublicLibraries := vendorPublicLibraries(ctx.Config())
libName := baseLibName(depName)
@@ -2934,6 +2951,7 @@
nonSystemVariantsExist := ccDep.HasNonSystemVariants() || isLLndk
if ccDepModule != nil {
+ // TODO(ivanlozano) Support snapshots for Rust-produced C library variants.
// Use base module name for snapshots when exporting to Makefile.
if snapshotPrebuilt, ok := ccDepModule.linker.(snapshotInterface); ok {
baseName := ccDepModule.BaseModuleName()
@@ -2947,10 +2965,10 @@
// The vendor module is a no-vendor-variant VNDK library. Depend on the
// core module instead.
return libName
- } else if ccDep.UseVndk() && nonSystemVariantsExist && ccDepModule != nil {
+ } else if ccDep.UseVndk() && nonSystemVariantsExist {
// The vendor and product modules in Make will have been renamed to not conflict with the
// core module, so update the dependency name here accordingly.
- return libName + ccDepModule.Properties.SubName
+ return libName + ccDep.SubName()
} else if (ctx.Platform() || ctx.ProductSpecific()) && isVendorPublicLib {
return libName + vendorPublicLibrarySuffix
} else if ccDep.InRamdisk() && !ccDep.OnlyInRamdisk() {
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 465283d..07dcc95 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -244,6 +244,120 @@
}
}
+func checkInstallPartition(t *testing.T, ctx *android.TestContext, name, variant, expected string) {
+ mod := ctx.ModuleForTests(name, variant).Module().(*Module)
+ partitionDefined := false
+ checkPartition := func(specific bool, partition string) {
+ if specific {
+ if expected != partition && !partitionDefined {
+ // The variant is installed to the 'partition'
+ t.Errorf("%s variant of %q must not be installed to %s partition", variant, name, partition)
+ }
+ partitionDefined = true
+ } else {
+ // The variant is not installed to the 'partition'
+ if expected == partition {
+ t.Errorf("%s variant of %q must be installed to %s partition", variant, name, partition)
+ }
+ }
+ }
+ socSpecific := func(m *Module) bool {
+ return m.SocSpecific() || m.socSpecificModuleContext()
+ }
+ deviceSpecific := func(m *Module) bool {
+ return m.DeviceSpecific() || m.deviceSpecificModuleContext()
+ }
+ productSpecific := func(m *Module) bool {
+ return m.ProductSpecific() || m.productSpecificModuleContext()
+ }
+ systemExtSpecific := func(m *Module) bool {
+ return m.SystemExtSpecific()
+ }
+ checkPartition(socSpecific(mod), "vendor")
+ checkPartition(deviceSpecific(mod), "odm")
+ checkPartition(productSpecific(mod), "product")
+ checkPartition(systemExtSpecific(mod), "system_ext")
+ if !partitionDefined && expected != "system" {
+ t.Errorf("%s variant of %q is expected to be installed to %s partition,"+
+ " but installed to system partition", variant, name, expected)
+ }
+}
+
+func TestInstallPartition(t *testing.T) {
+ t.Helper()
+ ctx := prepareForCcTest.RunTestWithBp(t, `
+ cc_library {
+ name: "libsystem",
+ }
+ cc_library {
+ name: "libsystem_ext",
+ system_ext_specific: true,
+ }
+ cc_library {
+ name: "libproduct",
+ product_specific: true,
+ }
+ cc_library {
+ name: "libvendor",
+ vendor: true,
+ }
+ cc_library {
+ name: "libodm",
+ device_specific: true,
+ }
+ cc_library {
+ name: "liball_available",
+ vendor_available: true,
+ product_available: true,
+ }
+ cc_library {
+ name: "libsystem_ext_all_available",
+ system_ext_specific: true,
+ vendor_available: true,
+ product_available: true,
+ }
+ cc_library {
+ name: "liball_available_odm",
+ odm_available: true,
+ product_available: true,
+ }
+ cc_library {
+ name: "libproduct_vendoravailable",
+ product_specific: true,
+ vendor_available: true,
+ }
+ cc_library {
+ name: "libproduct_odmavailable",
+ product_specific: true,
+ odm_available: true,
+ }
+ `).TestContext
+
+ checkInstallPartition(t, ctx, "libsystem", coreVariant, "system")
+ checkInstallPartition(t, ctx, "libsystem_ext", coreVariant, "system_ext")
+ checkInstallPartition(t, ctx, "libproduct", productVariant, "product")
+ checkInstallPartition(t, ctx, "libvendor", vendorVariant, "vendor")
+ checkInstallPartition(t, ctx, "libodm", vendorVariant, "odm")
+
+ checkInstallPartition(t, ctx, "liball_available", coreVariant, "system")
+ checkInstallPartition(t, ctx, "liball_available", productVariant, "product")
+ checkInstallPartition(t, ctx, "liball_available", vendorVariant, "vendor")
+
+ checkInstallPartition(t, ctx, "libsystem_ext_all_available", coreVariant, "system_ext")
+ checkInstallPartition(t, ctx, "libsystem_ext_all_available", productVariant, "product")
+ checkInstallPartition(t, ctx, "libsystem_ext_all_available", vendorVariant, "vendor")
+
+ checkInstallPartition(t, ctx, "liball_available_odm", coreVariant, "system")
+ checkInstallPartition(t, ctx, "liball_available_odm", productVariant, "product")
+ checkInstallPartition(t, ctx, "liball_available_odm", vendorVariant, "odm")
+
+ checkInstallPartition(t, ctx, "libproduct_vendoravailable", productVariant, "product")
+ checkInstallPartition(t, ctx, "libproduct_vendoravailable", vendorVariant, "vendor")
+
+ checkInstallPartition(t, ctx, "libproduct_odmavailable", productVariant, "product")
+ checkInstallPartition(t, ctx, "libproduct_odmavailable", vendorVariant, "odm")
+}
+
func checkVndkModule(t *testing.T, ctx *android.TestContext, name, subDir string,
isVndkSp bool, extends string, variant string) {
@@ -3807,8 +3921,9 @@
}),
android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
variables.MemtagHeapExcludePaths = []string{"subdir_exclude"}
- variables.MemtagHeapSyncIncludePaths = []string{"subdir_sync"}
- variables.MemtagHeapAsyncIncludePaths = []string{"subdir_async"}
+ // "subdir_exclude" is covered by both include and exclude paths. Exclude wins.
+ variables.MemtagHeapSyncIncludePaths = []string{"subdir_sync", "subdir_exclude"}
+ variables.MemtagHeapAsyncIncludePaths = []string{"subdir_async", "subdir_exclude"}
}),
)
diff --git a/cc/gen.go b/cc/gen.go
index 83c019c..b152e02 100644
--- a/cc/gen.go
+++ b/cc/gen.go
@@ -111,9 +111,7 @@
return ret
}
-func genAidl(ctx android.ModuleContext, rule *android.RuleBuilder, aidlFile android.Path,
- outFile, depFile android.ModuleGenPath, aidlFlags string) android.Paths {
-
+func genAidl(ctx android.ModuleContext, rule *android.RuleBuilder, aidlFile android.Path, aidlFlags string) (cppFile android.OutputPath, headerFiles android.Paths) {
aidlPackage := strings.TrimSuffix(aidlFile.Rel(), aidlFile.Base())
baseName := strings.TrimSuffix(aidlFile.Base(), aidlFile.Ext())
shortName := baseName
@@ -126,6 +124,8 @@
}
outDir := android.PathForModuleGen(ctx, "aidl")
+ cppFile = outDir.Join(ctx, aidlPackage, baseName+".cpp")
+ depFile := outDir.Join(ctx, aidlPackage, baseName+".cpp.d")
headerI := outDir.Join(ctx, aidlPackage, baseName+".h")
headerBn := outDir.Join(ctx, aidlPackage, "Bn"+shortName+".h")
headerBp := outDir.Join(ctx, aidlPackage, "Bp"+shortName+".h")
@@ -142,14 +142,14 @@
Flag(aidlFlags).
Input(aidlFile).
OutputDir().
- Output(outFile).
+ Output(cppFile).
ImplicitOutputs(android.WritablePaths{
headerI,
headerBn,
headerBp,
})
- return android.Paths{
+ return cppFile, android.Paths{
headerI,
headerBn,
headerBp,
@@ -293,10 +293,9 @@
aidlRule = android.NewRuleBuilder(pctx, ctx).Sbox(android.PathForModuleGen(ctx, "aidl"),
android.PathForModuleGen(ctx, "aidl.sbox.textproto"))
}
- cppFile := android.GenPathWithExt(ctx, "aidl", srcFile, "cpp")
- depFile := android.GenPathWithExt(ctx, "aidl", srcFile, "cpp.d")
+ cppFile, aidlHeaders := genAidl(ctx, aidlRule, srcFile, buildFlags.aidlFlags)
srcFiles[i] = cppFile
- aidlHeaders := genAidl(ctx, aidlRule, srcFile, cppFile, depFile, buildFlags.aidlFlags)
+
info.aidlHeaders = append(info.aidlHeaders, aidlHeaders...)
// Use the generated headers as order only deps to ensure that they are up to date when
// needed.
diff --git a/cc/genrule.go b/cc/genrule.go
index ca4fda7..82d7205 100644
--- a/cc/genrule.go
+++ b/cc/genrule.go
@@ -75,6 +75,10 @@
return Bool(g.Vendor_ramdisk_available)
}
+func (g *GenruleExtraProperties) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+ return false
+}
+
func (g *GenruleExtraProperties) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
// If the build is using a snapshot, the recovery variant under AOSP directories
// is not needed.
diff --git a/cc/image.go b/cc/image.go
index afe6a0e..bf662c6 100644
--- a/cc/image.go
+++ b/cc/image.go
@@ -49,21 +49,15 @@
)
func (ctx *moduleContext) ProductSpecific() bool {
- // Additionally check if this module is inProduct() that means it is a "product" variant of a
- // module. As well as product specific modules, product variants must be installed to /product.
- return ctx.ModuleContext.ProductSpecific() || ctx.mod.InProduct()
+ return ctx.ModuleContext.ProductSpecific() || ctx.mod.productSpecificModuleContext()
}
func (ctx *moduleContext) SocSpecific() bool {
- // Additionally check if this module is inVendor() that means it is a "vendor" variant of a
- // module. As well as SoC specific modules, vendor variants must be installed to /vendor
- // unless they have "odm_available: true".
- return ctx.ModuleContext.SocSpecific() || (ctx.mod.InVendor() && !ctx.mod.VendorVariantToOdm())
+ return ctx.ModuleContext.SocSpecific() || ctx.mod.socSpecificModuleContext()
}
func (ctx *moduleContext) DeviceSpecific() bool {
- // Some vendor variants want to be installed to /odm by setting "odm_available: true".
- return ctx.ModuleContext.DeviceSpecific() || (ctx.mod.InVendor() && ctx.mod.VendorVariantToOdm())
+ return ctx.ModuleContext.DeviceSpecific() || ctx.mod.deviceSpecificModuleContext()
}
func (ctx *moduleContextImpl) inProduct() bool {
@@ -86,6 +80,24 @@
return ctx.mod.InRecovery()
}
+func (c *Module) productSpecificModuleContext() bool {
+ // Additionally check if this module is inProduct() that means it is a "product" variant of a
+ // module. As well as product specific modules, product variants must be installed to /product.
+ return c.InProduct()
+}
+
+func (c *Module) socSpecificModuleContext() bool {
+ // Additionally check if this module is inVendor() that means it is a "vendor" variant of a
+ // module. As well as SoC specific modules, vendor variants must be installed to /vendor
+ // unless they have "odm_available: true".
+ return c.HasVendorVariant() && c.InVendor() && !c.VendorVariantToOdm()
+}
+
+func (c *Module) deviceSpecificModuleContext() bool {
+ // Some vendor variants want to be installed to /odm by setting "odm_available: true".
+ return c.InVendor() && c.VendorVariantToOdm()
+}
+
// Returns true when this module is configured to have core and vendor variants.
func (c *Module) HasVendorVariant() bool {
return Bool(c.VendorProperties.Vendor_available) || Bool(c.VendorProperties.Odm_available)
@@ -187,40 +199,73 @@
return true
}
+// ImageMutatableModule provides a common image mutation interface for LinkableInterface modules.
+type ImageMutatableModule interface {
+ android.Module
+ LinkableInterface
+
+ // AndroidModuleBase returns the android.ModuleBase for this module
+ AndroidModuleBase() *android.ModuleBase
+
+ // VendorAvailable returns true if this module is available on the vendor image.
+ VendorAvailable() bool
+
+ // OdmAvailable returns true if this module is available on the odm image.
+ OdmAvailable() bool
+
+ // ProductAvailable returns true if this module is available on the product image.
+ ProductAvailable() bool
+
+ // RamdiskAvailable returns true if this module is available on the ramdisk image.
+ RamdiskAvailable() bool
+
+ // RecoveryAvailable returns true if this module is available on the recovery image.
+ RecoveryAvailable() bool
+
+ // VendorRamdiskAvailable returns true if this module is available on the vendor ramdisk image.
+ VendorRamdiskAvailable() bool
+
+ // IsSnapshotPrebuilt returns true if this module is a snapshot prebuilt.
+ IsSnapshotPrebuilt() bool
+
+ // SnapshotVersion returns the snapshot version for this module.
+ SnapshotVersion(mctx android.BaseModuleContext) string
+
+ // SdkVersion returns the SDK version for this module.
+ SdkVersion() string
+
+ // ExtraVariants returns the list of extra variants this module requires.
+ ExtraVariants() []string
+
+ // AppendExtraVariant returns an extra variant to the list of extra variants this module requires.
+ AppendExtraVariant(extraVariant string)
+
+ // SetRamdiskVariantNeeded sets whether the Ramdisk Variant is needed.
+ SetRamdiskVariantNeeded(b bool)
+
+ // SetVendorRamdiskVariantNeeded sets whether the Vendor Ramdisk Variant is needed.
+ SetVendorRamdiskVariantNeeded(b bool)
+
+ // SetRecoveryVariantNeeded sets whether the Recovery Variant is needed.
+ SetRecoveryVariantNeeded(b bool)
+
+ // SetCoreVariantNeeded sets whether the Core Variant is needed.
+ SetCoreVariantNeeded(b bool)
+}
+
+var _ ImageMutatableModule = (*Module)(nil)
+
func (m *Module) ImageMutatorBegin(mctx android.BaseModuleContext) {
- // Validation check
+ m.CheckVndkProperties(mctx)
+ MutateImage(mctx, m)
+}
+
+// CheckVndkProperties checks whether the VNDK-related properties are set correctly.
+// If properties are not set correctly, results in a module context property error.
+func (m *Module) CheckVndkProperties(mctx android.BaseModuleContext) {
vendorSpecific := mctx.SocSpecific() || mctx.DeviceSpecific()
productSpecific := mctx.ProductSpecific()
- if Bool(m.VendorProperties.Vendor_available) {
- if vendorSpecific {
- mctx.PropertyErrorf("vendor_available",
- "doesn't make sense at the same time as `vendor: true`, `proprietary: true`, or `device_specific: true`")
- }
- if Bool(m.VendorProperties.Odm_available) {
- mctx.PropertyErrorf("vendor_available",
- "doesn't make sense at the same time as `odm_available: true`")
- }
- }
-
- if Bool(m.VendorProperties.Odm_available) {
- if vendorSpecific {
- mctx.PropertyErrorf("odm_available",
- "doesn't make sense at the same time as `vendor: true`, `proprietary: true`, or `device_specific: true`")
- }
- }
-
- if Bool(m.VendorProperties.Product_available) {
- if productSpecific {
- mctx.PropertyErrorf("product_available",
- "doesn't make sense at the same time as `product_specific: true`")
- }
- if vendorSpecific {
- mctx.PropertyErrorf("product_available",
- "cannot provide product variant from a vendor module. Please use `product_specific: true` with `vendor_available: true`")
- }
- }
-
if vndkdep := m.vndkdep; vndkdep != nil {
if vndkdep.isVndk() {
if vendorSpecific || productSpecific {
@@ -265,6 +310,111 @@
}
}
}
+}
+
+func (m *Module) VendorAvailable() bool {
+ return Bool(m.VendorProperties.Vendor_available)
+}
+
+func (m *Module) OdmAvailable() bool {
+ return Bool(m.VendorProperties.Odm_available)
+}
+
+func (m *Module) ProductAvailable() bool {
+ return Bool(m.VendorProperties.Product_available)
+}
+
+func (m *Module) RamdiskAvailable() bool {
+ return Bool(m.Properties.Ramdisk_available)
+}
+
+func (m *Module) VendorRamdiskAvailable() bool {
+ return Bool(m.Properties.Vendor_ramdisk_available)
+}
+
+func (m *Module) AndroidModuleBase() *android.ModuleBase {
+ return &m.ModuleBase
+}
+
+func (m *Module) RecoveryAvailable() bool {
+ return Bool(m.Properties.Recovery_available)
+}
+
+func (m *Module) ExtraVariants() []string {
+ return m.Properties.ExtraVariants
+}
+
+func (m *Module) AppendExtraVariant(extraVariant string) {
+ m.Properties.ExtraVariants = append(m.Properties.ExtraVariants, extraVariant)
+}
+
+func (m *Module) SetRamdiskVariantNeeded(b bool) {
+ m.Properties.RamdiskVariantNeeded = b
+}
+
+func (m *Module) SetVendorRamdiskVariantNeeded(b bool) {
+ m.Properties.VendorRamdiskVariantNeeded = b
+}
+
+func (m *Module) SetRecoveryVariantNeeded(b bool) {
+ m.Properties.RecoveryVariantNeeded = b
+}
+
+func (m *Module) SetCoreVariantNeeded(b bool) {
+ m.Properties.CoreVariantNeeded = b
+}
+
+func (m *Module) SnapshotVersion(mctx android.BaseModuleContext) string {
+ if snapshot, ok := m.linker.(snapshotInterface); ok {
+ return snapshot.version()
+ } else {
+ mctx.ModuleErrorf("version is unknown for snapshot prebuilt")
+ // Should we be panicking here instead?
+ return ""
+ }
+}
+
+func (m *Module) KernelHeadersDecorator() bool {
+ if _, ok := m.linker.(*kernelHeadersDecorator); ok {
+ return true
+ }
+ return false
+}
+
+// MutateImage handles common image mutations for ImageMutatableModule interfaces.
+func MutateImage(mctx android.BaseModuleContext, m ImageMutatableModule) {
+ // Validation check
+ vendorSpecific := mctx.SocSpecific() || mctx.DeviceSpecific()
+ productSpecific := mctx.ProductSpecific()
+
+ if m.VendorAvailable() {
+ if vendorSpecific {
+ mctx.PropertyErrorf("vendor_available",
+ "doesn't make sense at the same time as `vendor: true`, `proprietary: true`, or `device_specific: true`")
+ }
+ if m.OdmAvailable() {
+ mctx.PropertyErrorf("vendor_available",
+ "doesn't make sense at the same time as `odm_available: true`")
+ }
+ }
+
+ if m.OdmAvailable() {
+ if vendorSpecific {
+ mctx.PropertyErrorf("odm_available",
+ "doesn't make sense at the same time as `vendor: true`, `proprietary: true`, or `device_specific: true`")
+ }
+ }
+
+ if m.ProductAvailable() {
+ if productSpecific {
+ mctx.PropertyErrorf("product_available",
+ "doesn't make sense at the same time as `product_specific: true`")
+ }
+ if vendorSpecific {
+ mctx.PropertyErrorf("product_available",
+ "cannot provide product variant from a vendor module. Please use `product_specific: true` with `vendor_available: true`")
+ }
+ }
var coreVariantNeeded bool = false
var ramdiskVariantNeeded bool = false
@@ -287,18 +437,13 @@
productVndkVersion = platformVndkVersion
}
- _, isLLNDKLibrary := m.linker.(*llndkStubDecorator)
- _, isLLNDKHeaders := m.linker.(*llndkHeadersDecorator)
- lib := moduleLibraryInterface(m)
- hasLLNDKStubs := lib != nil && lib.hasLLNDKStubs()
-
- if isLLNDKLibrary || isLLNDKHeaders || hasLLNDKStubs {
+ if m.IsLlndkLibrary() || m.IsLlndkHeaders() || m.HasLlndkStubs() {
// This is an LLNDK library. The implementation of the library will be on /system,
// and vendor and product variants will be created with LLNDK stubs.
// The LLNDK libraries need vendor variants even if there is no VNDK.
// The obsolete llndk_library and llndk_headers modules also need the vendor variants
// so the cc_library LLNDK stubs can depend on them.
- if hasLLNDKStubs {
+ if m.HasLlndkStubs() {
coreVariantNeeded = true
}
if platformVndkVersion != "" {
@@ -315,17 +460,13 @@
// If the device isn't compiling against the VNDK, we always
// use the core mode.
coreVariantNeeded = true
- } else if m.isSnapshotPrebuilt() {
+ } else if m.IsSnapshotPrebuilt() {
// Make vendor variants only for the versions in BOARD_VNDK_VERSION and
// PRODUCT_EXTRA_VNDK_VERSIONS.
- if snapshot, ok := m.linker.(snapshotInterface); ok {
- if m.InstallInRecovery() {
- recoveryVariantNeeded = true
- } else {
- vendorVariants = append(vendorVariants, snapshot.version())
- }
+ if m.InstallInRecovery() {
+ recoveryVariantNeeded = true
} else {
- mctx.ModuleErrorf("version is unknown for snapshot prebuilt")
+ vendorVariants = append(vendorVariants, m.SnapshotVersion(mctx))
}
} else if m.HasNonSystemVariants() && !m.IsVndkExt() {
// This will be available to /system unless it is product_specific
@@ -351,7 +492,7 @@
productVariants = append(productVariants, productVndkVersion)
}
}
- } else if vendorSpecific && String(m.Properties.Sdk_version) == "" {
+ } else if vendorSpecific && m.SdkVersion() == "" {
// This will be available in /vendor (or /odm) only
// kernel_headers is a special module type whose exported headers
@@ -360,7 +501,7 @@
// For other modules, we assume that modules under proprietary
// paths are compatible for BOARD_VNDK_VERSION. The other modules
// are regarded as AOSP, which is PLATFORM_VNDK_VERSION.
- if _, ok := m.linker.(*kernelHeadersDecorator); ok {
+ if m.KernelHeadersDecorator() {
vendorVariants = append(vendorVariants,
platformVndkVersion,
boardVndkVersion,
@@ -378,7 +519,7 @@
}
if boardVndkVersion != "" && productVndkVersion != "" {
- if coreVariantNeeded && productSpecific && String(m.Properties.Sdk_version) == "" {
+ if coreVariantNeeded && productSpecific && m.SdkVersion() == "" {
// The module has "product_specific: true" that does not create core variant.
coreVariantNeeded = false
productVariants = append(productVariants, productVndkVersion)
@@ -390,60 +531,60 @@
productVariants = []string{}
}
- if Bool(m.Properties.Ramdisk_available) {
+ if m.RamdiskAvailable() {
ramdiskVariantNeeded = true
}
- if m.ModuleBase.InstallInRamdisk() {
+ if m.AndroidModuleBase().InstallInRamdisk() {
ramdiskVariantNeeded = true
coreVariantNeeded = false
}
- if Bool(m.Properties.Vendor_ramdisk_available) {
+ if m.VendorRamdiskAvailable() {
vendorRamdiskVariantNeeded = true
}
- if m.ModuleBase.InstallInVendorRamdisk() {
+ if m.AndroidModuleBase().InstallInVendorRamdisk() {
vendorRamdiskVariantNeeded = true
coreVariantNeeded = false
}
- if Bool(m.Properties.Recovery_available) {
+ if m.RecoveryAvailable() {
recoveryVariantNeeded = true
}
- if m.ModuleBase.InstallInRecovery() {
+ if m.AndroidModuleBase().InstallInRecovery() {
recoveryVariantNeeded = true
coreVariantNeeded = false
}
// If using a snapshot, the recovery variant under AOSP directories is not needed,
// except for kernel headers, which needs all variants.
- if _, ok := m.linker.(*kernelHeadersDecorator); !ok &&
- !m.isSnapshotPrebuilt() &&
+ if m.KernelHeadersDecorator() &&
+ !m.IsSnapshotPrebuilt() &&
usingRecoverySnapshot &&
!isRecoveryProprietaryModule(mctx) {
recoveryVariantNeeded = false
}
for _, variant := range android.FirstUniqueStrings(vendorVariants) {
- m.Properties.ExtraVariants = append(m.Properties.ExtraVariants, VendorVariationPrefix+variant)
+ m.AppendExtraVariant(VendorVariationPrefix + variant)
}
for _, variant := range android.FirstUniqueStrings(productVariants) {
- m.Properties.ExtraVariants = append(m.Properties.ExtraVariants, ProductVariationPrefix+variant)
+ m.AppendExtraVariant(ProductVariationPrefix + variant)
}
- m.Properties.RamdiskVariantNeeded = ramdiskVariantNeeded
- m.Properties.VendorRamdiskVariantNeeded = vendorRamdiskVariantNeeded
- m.Properties.RecoveryVariantNeeded = recoveryVariantNeeded
- m.Properties.CoreVariantNeeded = coreVariantNeeded
+ m.SetRamdiskVariantNeeded(ramdiskVariantNeeded)
+ m.SetVendorRamdiskVariantNeeded(vendorRamdiskVariantNeeded)
+ m.SetRecoveryVariantNeeded(recoveryVariantNeeded)
+ m.SetCoreVariantNeeded(coreVariantNeeded)
// Disable the module if no variants are needed.
if !ramdiskVariantNeeded &&
!recoveryVariantNeeded &&
!coreVariantNeeded &&
- len(m.Properties.ExtraVariants) == 0 {
+ len(m.ExtraVariants()) == 0 {
m.Disable()
}
}
@@ -460,6 +601,10 @@
return c.Properties.VendorRamdiskVariantNeeded
}
+func (c *Module) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+ return false
+}
+
func (c *Module) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
return c.Properties.RecoveryVariantNeeded
}
diff --git a/cc/library.go b/cc/library.go
index 738b45f..53be3a5 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -483,10 +483,16 @@
func (handler *staticLibraryBazelHandler) generateBazelBuildActions(ctx android.ModuleContext, label string) bool {
bazelCtx := ctx.Config().BazelContext
- outputPaths, objPaths, ok := bazelCtx.GetOutputFilesAndCcObjectFiles(label, ctx.Arch().ArchType)
+ ccInfo, ok, err := bazelCtx.GetCcInfo(label, ctx.Arch().ArchType)
+ if err != nil {
+ ctx.ModuleErrorf("Error getting Bazel CcInfo: %s", err)
+ return false
+ }
if !ok {
return ok
}
+ outputPaths := ccInfo.OutputFiles
+ objPaths := ccInfo.CcObjectFiles
if len(outputPaths) > 1 {
// TODO(cparsons): This is actually expected behavior for static libraries with no srcs.
// We should support this.
diff --git a/cc/linkable.go b/cc/linkable.go
index 6aa238b..571a3bb 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -98,10 +98,24 @@
InVendor() bool
UseSdk() bool
+
+ // IsLlndk returns true for both LLNDK (public) and LLNDK-private libs.
+ IsLlndk() bool
+
+ // IsLlndkPublic returns true only for LLNDK (public) libs.
+ IsLlndkPublic() bool
+
+ // IsLlndkHeaders returns true if this module is an LLNDK headers module.
+ IsLlndkHeaders() bool
+
+ // IsLlndkLibrary returns true if this module is an LLNDK library module.
+ IsLlndkLibrary() bool
+
+ // HasLlndkStubs returns true if this module has LLNDK stubs.
+ HasLlndkStubs() bool
+
UseVndk() bool
MustUseVendorVariant() bool
- IsLlndk() bool
- IsLlndkPublic() bool
IsVndk() bool
IsVndkExt() bool
IsVndkPrivate() bool
@@ -110,6 +124,9 @@
HasNonSystemVariants() bool
InProduct() bool
+ // SubName returns the modules SubName, used for image and NDK/SDK variations.
+ SubName() string
+
SdkVersion() string
MinSdkVersion() string
AlwaysSdk() bool
@@ -121,6 +138,10 @@
SetPreventInstall()
// SetHideFromMake sets the HideFromMake property to 'true' for this module.
SetHideFromMake()
+
+ // KernelHeadersDecorator returns true if this is a kernel headers decorator module.
+ // This is specific to cc and should always return false for all other packages.
+ KernelHeadersDecorator() bool
}
var (
@@ -152,6 +173,15 @@
}
}
+// DepTagMakeSuffix returns the makeSuffix value of a particular library dependency tag.
+// Returns an empty string if not a library dependency tag.
+func DepTagMakeSuffix(depTag blueprint.DependencyTag) string {
+ if libDepTag, ok := depTag.(libraryDependencyTag); ok {
+ return libDepTag.makeSuffix
+ }
+ return ""
+}
+
// SharedDepTag returns the dependency tag for any C++ shared libraries.
func SharedDepTag() blueprint.DependencyTag {
return libraryDependencyTag{Kind: sharedLibraryDependency}
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index 3829b1e..c19b1ff 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -329,10 +329,14 @@
func (h *prebuiltStaticLibraryBazelHandler) generateBazelBuildActions(ctx android.ModuleContext, label string) bool {
bazelCtx := ctx.Config().BazelContext
- staticLibs, ok := bazelCtx.GetPrebuiltCcStaticLibraryFiles(label, ctx.Arch().ArchType)
+ ccInfo, ok, err := bazelCtx.GetCcInfo(label, ctx.Arch().ArchType)
+ if err != nil {
+ ctx.ModuleErrorf("Error getting Bazel CcInfo: %s", err)
+ }
if !ok {
return false
}
+ staticLibs := ccInfo.CcStaticLibraryFiles
if len(staticLibs) > 1 {
ctx.ModuleErrorf("expected 1 static library from bazel target %q, got %s", label, staticLibs)
return false
diff --git a/cc/sabi.go b/cc/sabi.go
index 4a1ba3c..c0eb57c 100644
--- a/cc/sabi.go
+++ b/cc/sabi.go
@@ -141,7 +141,7 @@
}
// Don't create ABI dump for prebuilts.
- if m.Prebuilt() != nil || m.isSnapshotPrebuilt() {
+ if m.Prebuilt() != nil || m.IsSnapshotPrebuilt() {
return false
}
diff --git a/cc/snapshot_prebuilt.go b/cc/snapshot_prebuilt.go
index af05102..6d48aed 100644
--- a/cc/snapshot_prebuilt.go
+++ b/cc/snapshot_prebuilt.go
@@ -308,6 +308,10 @@
return false
}
+func (s *snapshot) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+ return false
+}
+
func (s *snapshot) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
return false
}
@@ -559,10 +563,18 @@
return nil
}
+ // Flags specified directly to this module.
p.libraryDecorator.reexportDirs(android.PathsForModuleSrc(ctx, p.properties.Export_include_dirs)...)
p.libraryDecorator.reexportSystemDirs(android.PathsForModuleSrc(ctx, p.properties.Export_system_include_dirs)...)
p.libraryDecorator.reexportFlags(p.properties.Export_flags...)
+ // Flags reexported from dependencies. (e.g. vndk_prebuilt_shared)
+ p.libraryDecorator.reexportDirs(deps.ReexportedDirs...)
+ p.libraryDecorator.reexportSystemDirs(deps.ReexportedSystemDirs...)
+ p.libraryDecorator.reexportFlags(deps.ReexportedFlags...)
+ p.libraryDecorator.reexportDeps(deps.ReexportedDeps...)
+ p.libraryDecorator.addExportedGeneratedHeaders(deps.ReexportedGeneratedHeaders...)
+
in := android.PathForModuleSrc(ctx, *p.properties.Src)
p.unstrippedOutputFile = in
diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go
index 3437d77..2f68cca 100644
--- a/cc/vendor_snapshot.go
+++ b/cc/vendor_snapshot.go
@@ -173,7 +173,7 @@
return false
}
// the module must be installed in target image
- if !apexInfo.IsForPlatform() || m.isSnapshotPrebuilt() || !image.inImage(m)() {
+ if !apexInfo.IsForPlatform() || m.IsSnapshotPrebuilt() || !image.inImage(m)() {
return false
}
// skip kernel_headers which always depend on vendor
diff --git a/cc/vendor_snapshot_test.go b/cc/vendor_snapshot_test.go
index 1c3f1b4..66396f7 100644
--- a/cc/vendor_snapshot_test.go
+++ b/cc/vendor_snapshot_test.go
@@ -424,6 +424,20 @@
srcs: ["client.cpp"],
}
+ cc_library_shared {
+ name: "libclient_cfi",
+ vendor: true,
+ nocrt: true,
+ no_libcrt: true,
+ stl: "none",
+ system_shared_libs: [],
+ static_libs: ["libvendor"],
+ sanitize: {
+ cfi: true,
+ },
+ srcs: ["client.cpp"],
+ }
+
cc_binary {
name: "bin_without_snapshot",
vendor: true,
@@ -492,13 +506,13 @@
arch: {
arm64: {
src: "libvndk.a",
- export_include_dirs: ["include/libvndk"],
},
arm: {
src: "libvndk.a",
- export_include_dirs: ["include/libvndk"],
},
},
+ shared_libs: ["libvndk"],
+ export_shared_lib_headers: ["libvndk"],
}
vendor_snapshot_shared {
@@ -584,10 +598,18 @@
vendor: true,
arch: {
arm64: {
+ cfi: {
+ src: "libvendor.cfi.a",
+ export_include_dirs: ["include/libvendor_cfi"],
+ },
src: "libvendor.a",
export_include_dirs: ["include/libvendor"],
},
arm: {
+ cfi: {
+ src: "libvendor.cfi.a",
+ export_include_dirs: ["include/libvendor_cfi"],
+ },
src: "libvendor.a",
export_include_dirs: ["include/libvendor"],
},
@@ -726,29 +748,31 @@
depsBp := GatherRequiredDepsForTest(android.Android)
mockFS := map[string][]byte{
- "deps/Android.bp": []byte(depsBp),
- "framework/Android.bp": []byte(frameworkBp),
- "framework/symbol.txt": nil,
- "vendor/Android.bp": []byte(vendorProprietaryBp),
- "vendor/bin": nil,
- "vendor/bin32": nil,
- "vendor/bin.cpp": nil,
- "vendor/client.cpp": nil,
- "vendor/include/libvndk/a.h": nil,
- "vendor/include/libvendor/b.h": nil,
- "vendor/libc++_static.a": nil,
- "vendor/libc++demangle.a": nil,
- "vendor/libgcc_striped.a": nil,
- "vendor/libvndk.a": nil,
- "vendor/libvendor.a": nil,
- "vendor/libvendor.so": nil,
- "vendor/lib32.a": nil,
- "vendor/lib32.so": nil,
- "vendor/lib64.a": nil,
- "vendor/lib64.so": nil,
- "vndk/Android.bp": []byte(vndkBp),
- "vndk/include/libvndk/a.h": nil,
- "vndk/libvndk.so": nil,
+ "deps/Android.bp": []byte(depsBp),
+ "framework/Android.bp": []byte(frameworkBp),
+ "framework/symbol.txt": nil,
+ "vendor/Android.bp": []byte(vendorProprietaryBp),
+ "vendor/bin": nil,
+ "vendor/bin32": nil,
+ "vendor/bin.cpp": nil,
+ "vendor/client.cpp": nil,
+ "vendor/include/libvndk/a.h": nil,
+ "vendor/include/libvendor/b.h": nil,
+ "vendor/include/libvendor_cfi/c.h": nil,
+ "vendor/libc++_static.a": nil,
+ "vendor/libc++demangle.a": nil,
+ "vendor/libgcc_striped.a": nil,
+ "vendor/libvndk.a": nil,
+ "vendor/libvendor.a": nil,
+ "vendor/libvendor.cfi.a": nil,
+ "vendor/libvendor.so": nil,
+ "vendor/lib32.a": nil,
+ "vendor/lib32.so": nil,
+ "vendor/lib64.a": nil,
+ "vendor/lib64.so": nil,
+ "vndk/Android.bp": []byte(vndkBp),
+ "vndk/include/libvndk/a.h": nil,
+ "vndk/libvndk.so": nil,
}
config := TestConfig(t.TempDir(), android.Android, nil, "", mockFS)
@@ -766,6 +790,9 @@
staticVariant := "android_vendor.30_arm64_armv8-a_static"
binaryVariant := "android_vendor.30_arm64_armv8-a"
+ sharedCfiVariant := "android_vendor.30_arm64_armv8-a_shared_cfi"
+ staticCfiVariant := "android_vendor.30_arm64_armv8-a_static_cfi"
+
shared32Variant := "android_vendor.30_arm_armv7-a-neon_shared"
binary32Variant := "android_vendor.30_arm_armv7-a-neon"
@@ -808,9 +835,22 @@
t.Errorf("wanted libclient32 AndroidMkSharedLibs %q, got %q", w, g)
}
- // bin_without_snapshot uses libvndk.vendor_static.30.arm64
+ // libclient_cfi uses libvendor.vendor_static.30.arm64's cfi variant
+ libclientCfiCcFlags := ctx.ModuleForTests("libclient_cfi", sharedCfiVariant).Rule("cc").Args["cFlags"]
+ if !strings.Contains(libclientCfiCcFlags, "-Ivendor/include/libvendor_cfi") {
+ t.Errorf("flags for libclient_cfi must contain %#v, but was %#v.",
+ "-Ivendor/include/libvendor_cfi", libclientCfiCcFlags)
+ }
+
+ libclientCfiLdFlags := ctx.ModuleForTests("libclient_cfi", sharedCfiVariant).Rule("ld").Args["libFlags"]
+ libvendorCfiOutputPaths := getOutputPaths(ctx, staticCfiVariant, []string{"libvendor.vendor_static.30.arm64"})
+ if !strings.Contains(libclientCfiLdFlags, libvendorCfiOutputPaths[0].String()) {
+ t.Errorf("libflags for libclientCfi must contain %#v, but was %#v", libvendorCfiOutputPaths[0], libclientCfiLdFlags)
+ }
+
+ // bin_without_snapshot uses libvndk.vendor_static.30.arm64 (which reexports vndk's exported headers)
binWithoutSnapshotCcFlags := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("cc").Args["cFlags"]
- if !strings.Contains(binWithoutSnapshotCcFlags, "-Ivendor/include/libvndk") {
+ if !strings.Contains(binWithoutSnapshotCcFlags, "-Ivndk/include/libvndk") {
t.Errorf("flags for bin_without_snapshot must contain %#v, but was %#v.",
"-Ivendor/include/libvndk", binWithoutSnapshotCcFlags)
}
diff --git a/cc/vndk.go b/cc/vndk.go
index b7047e9..1a8a454 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -609,8 +609,8 @@
}
// !inVendor: There's product/vendor variants for VNDK libs. We only care about vendor variants.
// !installable: Snapshot only cares about "installable" modules.
- // isSnapshotPrebuilt: Snapshotting a snapshot doesn't make sense.
- if !m.InVendor() || !m.installable(apexInfo) || m.isSnapshotPrebuilt() {
+ // IsSnapshotPrebuilt: Snapshotting a snapshot doesn't make sense.
+ if !m.InVendor() || !m.installable(apexInfo) || m.IsSnapshotPrebuilt() {
return nil, "", false
}
l, ok := m.linker.(snapshotLibraryInterface)
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 1863ece..1e796ec 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -23,29 +23,43 @@
"strings"
"time"
+ "android/soong/bp2build"
"android/soong/shared"
"github.com/google/blueprint/bootstrap"
+ "github.com/google/blueprint/deptools"
"android/soong/android"
- "android/soong/bp2build"
)
var (
- topDir string
- outDir string
+ topDir string
+ outDir string
+ availableEnvFile string
+ usedEnvFile string
+
+ delveListen string
+ delvePath string
+
docFile string
bazelQueryViewDir string
- delveListen string
- delvePath string
+ bp2buildMarker string
)
func init() {
+ // Flags that make sense in every mode
flag.StringVar(&topDir, "top", "", "Top directory of the Android source tree")
flag.StringVar(&outDir, "out", "", "Soong output directory (usually $TOP/out/soong)")
+ flag.StringVar(&availableEnvFile, "available_env", "", "File containing available environment variables")
+ flag.StringVar(&usedEnvFile, "used_env", "", "File containing used environment variables")
+
+ // Debug flags
flag.StringVar(&delveListen, "delve_listen", "", "Delve port to listen on for debugging")
flag.StringVar(&delvePath, "delve_path", "", "Path to Delve. Only used if --delve_listen is set")
+
+ // Flags representing various modes soong_build can run in
flag.StringVar(&docFile, "soong_docs", "", "build documentation file to output")
flag.StringVar(&bazelQueryViewDir, "bazel_queryview_dir", "", "path to the bazel queryview directory relative to --top")
+ flag.StringVar(&bp2buildMarker, "bp2build_marker", "", "If set, run bp2build, touch the specified marker file then exit")
}
func newNameResolver(config android.Config) *android.NameResolver {
@@ -75,8 +89,8 @@
return ctx
}
-func newConfig(srcDir string) android.Config {
- configuration, err := android.NewConfig(srcDir, bootstrap.CmdlineBuildDir(), bootstrap.CmdlineModuleListFile())
+func newConfig(srcDir, outDir string, availableEnv map[string]string) android.Config {
+ configuration, err := android.NewConfig(srcDir, outDir, bootstrap.CmdlineArgs.ModuleListFile, availableEnv)
if err != nil {
fmt.Fprintf(os.Stderr, "%s", err)
os.Exit(1)
@@ -90,21 +104,31 @@
// TODO(cparsons): Don't output any ninja file, as the second pass will overwrite
// the incorrect results from the first pass, and file I/O is expensive.
func runMixedModeBuild(configuration android.Config, firstCtx *android.Context, extraNinjaDeps []string) {
+ var firstArgs, secondArgs bootstrap.Args
+
+ firstArgs = bootstrap.CmdlineArgs
configuration.SetStopBefore(bootstrap.StopBeforeWriteNinja)
- bootstrap.Main(firstCtx.Context, configuration, false, extraNinjaDeps...)
+ bootstrap.RunBlueprint(firstArgs, firstCtx.Context, configuration, extraNinjaDeps...)
+
// Invoke bazel commands and save results for second pass.
if err := configuration.BazelContext.InvokeBazel(); err != nil {
fmt.Fprintf(os.Stderr, "%s", err)
os.Exit(1)
}
// Second pass: Full analysis, using the bazel command results. Output ninja file.
- secondPassConfig, err := android.ConfigForAdditionalRun(configuration)
+ secondConfig, err := android.ConfigForAdditionalRun(configuration)
if err != nil {
fmt.Fprintf(os.Stderr, "%s", err)
os.Exit(1)
}
- secondCtx := newContext(secondPassConfig, true)
- bootstrap.Main(secondCtx.Context, secondPassConfig, false, extraNinjaDeps...)
+ secondCtx := newContext(secondConfig, true)
+ secondArgs = bootstrap.CmdlineArgs
+ ninjaDeps := bootstrap.RunBlueprint(secondArgs, secondCtx.Context, secondConfig, extraNinjaDeps...)
+ err = deptools.WriteDepFile(shared.JoinPath(topDir, secondArgs.DepFile), secondArgs.OutFile, ninjaDeps)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Error writing depfile '%s': %s\n", secondArgs.DepFile, err)
+ os.Exit(1)
+ }
}
// Run the code-generation phase to convert BazelTargetModules to BUILD files.
@@ -119,7 +143,8 @@
func runSoongDocs(configuration android.Config, extraNinjaDeps []string) {
ctx := newContext(configuration, false)
- bootstrap.Main(ctx.Context, configuration, false, extraNinjaDeps...)
+ soongDocsArgs := bootstrap.CmdlineArgs
+ bootstrap.RunBlueprint(soongDocsArgs, ctx.Context, configuration, extraNinjaDeps...)
if err := writeDocs(ctx, configuration, docFile); err != nil {
fmt.Fprintf(os.Stderr, "%s", err)
os.Exit(1)
@@ -127,7 +152,7 @@
}
func writeMetrics(configuration android.Config) {
- metricsFile := filepath.Join(bootstrap.CmdlineBuildDir(), "soong_build_metrics.pb")
+ metricsFile := filepath.Join(configuration.BuildDir(), "soong_build_metrics.pb")
err := android.WriteMetrics(configuration, metricsFile)
if err != nil {
fmt.Fprintf(os.Stderr, "error writing soong_build metrics %s: %s", metricsFile, err)
@@ -147,40 +172,78 @@
writeFakeNinjaFile(extraNinjaDeps, configuration.BuildDir())
}
-func doChosenActivity(configuration android.Config, extraNinjaDeps []string) {
- bazelConversionRequested := configuration.IsEnvTrue("GENERATE_BAZEL_FILES")
+func doChosenActivity(configuration android.Config, extraNinjaDeps []string) string {
+ bazelConversionRequested := configuration.IsEnvTrue("GENERATE_BAZEL_FILES") || bp2buildMarker != ""
mixedModeBuild := configuration.BazelContext.BazelEnabled()
generateQueryView := bazelQueryViewDir != ""
jsonModuleFile := configuration.Getenv("SOONG_DUMP_JSON_MODULE_GRAPH")
+ blueprintArgs := bootstrap.CmdlineArgs
prepareBuildActions := !generateQueryView && jsonModuleFile == ""
-
if bazelConversionRequested {
// Run the alternate pipeline of bp2build mutators and singleton to convert
// Blueprint to BUILD files before everything else.
runBp2Build(configuration, extraNinjaDeps)
- return
+ if bp2buildMarker != "" {
+ return bp2buildMarker
+ } else {
+ return bootstrap.CmdlineArgs.OutFile
+ }
}
ctx := newContext(configuration, prepareBuildActions)
if mixedModeBuild {
runMixedModeBuild(configuration, ctx, extraNinjaDeps)
} else {
- bootstrap.Main(ctx.Context, configuration, false, extraNinjaDeps...)
+ ninjaDeps := bootstrap.RunBlueprint(blueprintArgs, ctx.Context, configuration, extraNinjaDeps...)
+ err := deptools.WriteDepFile(shared.JoinPath(topDir, blueprintArgs.DepFile), blueprintArgs.OutFile, ninjaDeps)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Error writing depfile '%s': %s\n", blueprintArgs.DepFile, err)
+ os.Exit(1)
+ }
}
// Convert the Soong module graph into Bazel BUILD files.
if generateQueryView {
runQueryView(configuration, ctx)
- return
+ return bootstrap.CmdlineArgs.OutFile // TODO: This is a lie
}
if jsonModuleFile != "" {
writeJsonModuleGraph(configuration, ctx, jsonModuleFile, extraNinjaDeps)
- return
+ return bootstrap.CmdlineArgs.OutFile // TODO: This is a lie
}
writeMetrics(configuration)
+ return bootstrap.CmdlineArgs.OutFile
+}
+
+// soong_ui dumps the available environment variables to
+// soong.environment.available . Then soong_build itself is run with an empty
+// environment so that the only way environment variables can be accessed is
+// using Config, which tracks access to them.
+
+// At the end of the build, a file called soong.environment.used is written
+// containing the current value of all used environment variables. The next
+// time soong_ui is run, it checks whether any environment variables that was
+// used had changed and if so, it deletes soong.environment.used to cause a
+// rebuild.
+//
+// The dependency of build.ninja on soong.environment.used is declared in
+// build.ninja.d
+func parseAvailableEnv() map[string]string {
+ if availableEnvFile == "" {
+ fmt.Fprintf(os.Stderr, "--available_env not set\n")
+ os.Exit(1)
+ }
+
+ result, err := shared.EnvFromFile(shared.JoinPath(topDir, availableEnvFile))
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "error reading available environment file '%s': %s\n", availableEnvFile, err)
+ os.Exit(1)
+ }
+
+ return result
}
func main() {
@@ -188,25 +251,21 @@
shared.ReexecWithDelveMaybe(delveListen, delvePath)
android.InitSandbox(topDir)
- android.InitEnvironment(shared.JoinPath(topDir, outDir, "soong.environment.available"))
- usedVariablesFile := shared.JoinPath(outDir, "soong.environment.used")
+ availableEnv := parseAvailableEnv()
+
// The top-level Blueprints file is passed as the first argument.
srcDir := filepath.Dir(flag.Arg(0))
- configuration := newConfig(srcDir)
+ configuration := newConfig(srcDir, outDir, availableEnv)
extraNinjaDeps := []string{
configuration.ProductVariablesFileName,
- shared.JoinPath(outDir, "soong.environment.used"),
+ usedEnvFile,
}
if configuration.Getenv("ALLOW_MISSING_DEPENDENCIES") == "true" {
configuration.SetAllowMissingDependencies()
}
- // These two are here so that we restart a non-debugged soong_build when the
- // user sets SOONG_DELVE the first time.
- configuration.Getenv("SOONG_DELVE")
- configuration.Getenv("SOONG_DELVE_PATH")
if shared.IsDebugging() {
// Add a non-existent file to the dependencies so that soong_build will rerun when the debugger is
// enabled even if it completed successfully.
@@ -218,37 +277,37 @@
// because that is done from within the actual builds as a Ninja action and
// thus it would overwrite the actual used variables file so this is
// special-cased.
+ // TODO: Fix this by not passing --used_env to the soong_docs invocation
runSoongDocs(configuration, extraNinjaDeps)
return
}
- doChosenActivity(configuration, extraNinjaDeps)
- writeUsedVariablesFile(shared.JoinPath(topDir, usedVariablesFile), configuration)
+ finalOutputFile := doChosenActivity(configuration, extraNinjaDeps)
+ writeUsedEnvironmentFile(configuration, finalOutputFile)
}
-func writeUsedVariablesFile(path string, configuration android.Config) {
+func writeUsedEnvironmentFile(configuration android.Config, finalOutputFile string) {
+ if usedEnvFile == "" {
+ return
+ }
+
+ path := shared.JoinPath(topDir, usedEnvFile)
data, err := shared.EnvFileContents(configuration.EnvDeps())
if err != nil {
- fmt.Fprintf(os.Stderr, "error writing used variables file %s: %s\n", path, err)
+ fmt.Fprintf(os.Stderr, "error writing used environment file '%s': %s\n", usedEnvFile, err)
os.Exit(1)
}
err = ioutil.WriteFile(path, data, 0666)
if err != nil {
- fmt.Fprintf(os.Stderr, "error writing used variables file %s: %s\n", path, err)
+ fmt.Fprintf(os.Stderr, "error writing used environment file '%s': %s\n", usedEnvFile, err)
os.Exit(1)
}
- // Touch the output Ninja file so that it's not older than the file we just
+ // Touch the output file so that it's not older than the file we just
// wrote. We can't write the environment file earlier because one an access
// new environment variables while writing it.
- outputNinjaFile := shared.JoinPath(topDir, bootstrap.CmdlineOutFile())
- currentTime := time.Now().Local()
- err = os.Chtimes(outputNinjaFile, currentTime, currentTime)
- if err != nil {
- fmt.Fprintf(os.Stderr, "error touching output file %s: %s\n", outputNinjaFile, err)
- os.Exit(1)
- }
+ touch(shared.JoinPath(topDir, finalOutputFile))
}
// Workarounds to support running bp2build in a clean AOSP checkout with no
@@ -274,6 +333,27 @@
0666)
}
+func touch(path string) {
+ f, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Error touching '%s': %s\n", path, err)
+ os.Exit(1)
+ }
+
+ err = f.Close()
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Error touching '%s': %s\n", path, err)
+ os.Exit(1)
+ }
+
+ currentTime := time.Now().Local()
+ err = os.Chtimes(path, currentTime, currentTime)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "error touching '%s': %s\n", path, err)
+ os.Exit(1)
+ }
+}
+
// Run Soong in the bp2build mode. This creates a standalone context that registers
// an alternate pipeline of mutators and singletons specifically for generating
// Bazel BUILD files instead of Ninja files.
@@ -281,17 +361,18 @@
// Register an alternate set of singletons and mutators for bazel
// conversion for Bazel conversion.
bp2buildCtx := android.NewContext(configuration)
- bp2buildCtx.RegisterForBazelConversion()
- // No need to generate Ninja build rules/statements from Modules and Singletons.
- configuration.SetStopBefore(bootstrap.StopBeforePrepareBuildActions)
+ // Propagate "allow misssing dependencies" bit. This is normally set in
+ // newContext(), but we create bp2buildCtx without calling that method.
+ bp2buildCtx.SetAllowMissingDependencies(configuration.AllowMissingDependencies())
bp2buildCtx.SetNameInterface(newNameResolver(configuration))
+ bp2buildCtx.RegisterForBazelConversion()
// The bp2build process is a purely functional process that only depends on
// Android.bp files. It must not depend on the values of per-build product
// configurations or variables, since those will generate different BUILD
// files based on how the user has configured their tree.
- bp2buildCtx.SetModuleListFile(bootstrap.CmdlineModuleListFile())
+ bp2buildCtx.SetModuleListFile(bootstrap.CmdlineArgs.ModuleListFile)
modulePaths, err := bp2buildCtx.ListModulePaths(configuration.SrcDir())
if err != nil {
panic(err)
@@ -299,10 +380,25 @@
extraNinjaDeps = append(extraNinjaDeps, modulePaths...)
+ // No need to generate Ninja build rules/statements from Modules and Singletons.
+ configuration.SetStopBefore(bootstrap.StopBeforePrepareBuildActions)
+
// Run the loading and analysis pipeline to prepare the graph of regular
// Modules parsed from Android.bp files, and the BazelTargetModules mapped
// from the regular Modules.
- bootstrap.Main(bp2buildCtx.Context, configuration, false, extraNinjaDeps...)
+ blueprintArgs := bootstrap.CmdlineArgs
+ ninjaDeps := bootstrap.RunBlueprint(blueprintArgs, bp2buildCtx.Context, configuration, extraNinjaDeps...)
+
+ for _, globPath := range bp2buildCtx.Globs() {
+ ninjaDeps = append(ninjaDeps, globPath.FileListFile(configuration.BuildDir()))
+ }
+
+ depFile := bp2buildMarker + ".d"
+ err = deptools.WriteDepFile(shared.JoinPath(topDir, depFile), bp2buildMarker, ninjaDeps)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Cannot write depfile '%s': %s\n", depFile, err)
+ os.Exit(1)
+ }
// Run the code-generation phase to convert BazelTargetModules to BUILD files
// and print conversion metrics to the user.
@@ -315,5 +411,9 @@
metrics.Print()
extraNinjaDeps = append(extraNinjaDeps, codegenContext.AdditionalNinjaDeps()...)
- writeFakeNinjaFile(extraNinjaDeps, codegenContext.Config().BuildDir())
+ if bp2buildMarker != "" {
+ touch(shared.JoinPath(topDir, bp2buildMarker))
+ } else {
+ writeFakeNinjaFile(extraNinjaDeps, codegenContext.Config().BuildDir())
+ }
}
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index 6291325..3204e70 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -29,6 +29,7 @@
import (
"fmt"
+ "strings"
"github.com/google/blueprint/proptools"
@@ -47,6 +48,7 @@
func RegisterPrebuiltEtcBuildComponents(ctx android.RegistrationContext) {
ctx.RegisterModuleType("prebuilt_etc", PrebuiltEtcFactory)
ctx.RegisterModuleType("prebuilt_etc_host", PrebuiltEtcHostFactory)
+ ctx.RegisterModuleType("prebuilt_root", PrebuiltRootFactory)
ctx.RegisterModuleType("prebuilt_usr_share", PrebuiltUserShareFactory)
ctx.RegisterModuleType("prebuilt_usr_share_host", PrebuiltUserShareHostFactory)
ctx.RegisterModuleType("prebuilt_font", PrebuiltFontFactory)
@@ -60,14 +62,6 @@
// Source file of this prebuilt. Can reference a genrule type module with the ":module" syntax.
Src *string `android:"path,arch_variant"`
- // Optional subdirectory under which this file is installed into, cannot be specified with
- // relative_install_path, prefer relative_install_path.
- Sub_dir *string `android:"arch_variant"`
-
- // Optional subdirectory under which this file is installed into, cannot be specified with
- // sub_dir.
- Relative_install_path *string `android:"arch_variant"`
-
// Optional name for the installed file. If unspecified, name of the module is used as the file
// name.
Filename *string `android:"arch_variant"`
@@ -90,6 +84,13 @@
// the recovery variant instead.
Vendor_ramdisk_available *bool
+ // Make this module available when building for debug ramdisk.
+ // On device without a dedicated recovery partition, the module is only
+ // available after switching root into
+ // /first_stage_ramdisk. To expose the module before switching root, install
+ // the recovery variant instead.
+ Debug_ramdisk_available *bool
+
// Make this module available when building for recovery.
Recovery_available *bool
@@ -100,6 +101,16 @@
Symlinks []string `android:"arch_variant"`
}
+type prebuiltSubdirProperties struct {
+ // Optional subdirectory under which this file is installed into, cannot be specified with
+ // relative_install_path, prefer relative_install_path.
+ Sub_dir *string `android:"arch_variant"`
+
+ // Optional subdirectory under which this file is installed into, cannot be specified with
+ // sub_dir.
+ Relative_install_path *string `android:"arch_variant"`
+}
+
type PrebuiltEtcModule interface {
android.Module
@@ -117,7 +128,8 @@
type PrebuiltEtc struct {
android.ModuleBase
- properties prebuiltEtcProperties
+ properties prebuiltEtcProperties
+ subdirProperties prebuiltSubdirProperties
sourceFilePath android.Path
outputFilePath android.OutputPath
@@ -154,6 +166,18 @@
return p.inVendorRamdisk()
}
+func (p *PrebuiltEtc) inDebugRamdisk() bool {
+ return p.ModuleBase.InDebugRamdisk() || p.ModuleBase.InstallInDebugRamdisk()
+}
+
+func (p *PrebuiltEtc) onlyInDebugRamdisk() bool {
+ return p.ModuleBase.InstallInDebugRamdisk()
+}
+
+func (p *PrebuiltEtc) InstallInDebugRamdisk() bool {
+ return p.inDebugRamdisk()
+}
+
func (p *PrebuiltEtc) inRecovery() bool {
return p.ModuleBase.InRecovery() || p.ModuleBase.InstallInRecovery()
}
@@ -172,7 +196,7 @@
func (p *PrebuiltEtc) CoreVariantNeeded(ctx android.BaseModuleContext) bool {
return !p.ModuleBase.InstallInRecovery() && !p.ModuleBase.InstallInRamdisk() &&
- !p.ModuleBase.InstallInVendorRamdisk()
+ !p.ModuleBase.InstallInVendorRamdisk() && !p.ModuleBase.InstallInDebugRamdisk()
}
func (p *PrebuiltEtc) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
@@ -183,6 +207,10 @@
return proptools.Bool(p.properties.Vendor_ramdisk_available) || p.ModuleBase.InstallInVendorRamdisk()
}
+func (p *PrebuiltEtc) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+ return proptools.Bool(p.properties.Debug_ramdisk_available) || p.ModuleBase.InstallInDebugRamdisk()
+}
+
func (p *PrebuiltEtc) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
return proptools.Bool(p.properties.Recovery_available) || p.ModuleBase.InstallInRecovery()
}
@@ -224,10 +252,10 @@
}
func (p *PrebuiltEtc) SubDir() string {
- if subDir := proptools.String(p.properties.Sub_dir); subDir != "" {
+ if subDir := proptools.String(p.subdirProperties.Sub_dir); subDir != "" {
return subDir
}
- return proptools.String(p.properties.Relative_install_path)
+ return proptools.String(p.subdirProperties.Relative_install_path)
}
func (p *PrebuiltEtc) BaseDir() string {
@@ -263,8 +291,13 @@
}
p.outputFilePath = android.PathForModuleOut(ctx, filename).OutputPath
+ if strings.Contains(filename, "/") {
+ ctx.PropertyErrorf("filename", "filename cannot contain separator '/'")
+ return
+ }
+
// Check that `sub_dir` and `relative_install_path` are not set at the same time.
- if p.properties.Sub_dir != nil && p.properties.Relative_install_path != nil {
+ if p.subdirProperties.Sub_dir != nil && p.subdirProperties.Relative_install_path != nil {
ctx.PropertyErrorf("sub_dir", "relative_install_path is set. Cannot set sub_dir")
}
@@ -303,6 +336,9 @@
if p.inVendorRamdisk() && !p.onlyInVendorRamdisk() {
nameSuffix = ".vendor_ramdisk"
}
+ if p.inDebugRamdisk() && !p.onlyInDebugRamdisk() {
+ nameSuffix = ".debug_ramdisk"
+ }
if p.inRecovery() && !p.onlyInRecovery() {
nameSuffix = ".recovery"
}
@@ -330,6 +366,12 @@
func InitPrebuiltEtcModule(p *PrebuiltEtc, dirBase string) {
p.installDirBase = dirBase
p.AddProperties(&p.properties)
+ p.AddProperties(&p.subdirProperties)
+}
+
+func InitPrebuiltRootModule(p *PrebuiltEtc) {
+ p.installDirBase = "."
+ p.AddProperties(&p.properties)
}
// prebuilt_etc is for a prebuilt artifact that is installed in
@@ -352,6 +394,16 @@
return module
}
+// prebuilt_root is for a prebuilt artifact that is installed in
+// <partition>/ directory. Can't have any sub directories.
+func PrebuiltRootFactory() android.Module {
+ module := &PrebuiltEtc{}
+ InitPrebuiltRootModule(module)
+ // This module is device-only
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
+ return module
+}
+
// prebuilt_usr_share is for a prebuilt artifact that is installed in
// <partition>/usr/share/<sub_dir> directory.
func PrebuiltUserShareFactory() android.Module {
diff --git a/etc/prebuilt_etc_test.go b/etc/prebuilt_etc_test.go
index 9c3db3b..fdb5648 100644
--- a/etc/prebuilt_etc_test.go
+++ b/etc/prebuilt_etc_test.go
@@ -179,6 +179,30 @@
}
}
+func TestPrebuiltRootInstallDirPath(t *testing.T) {
+ result := prepareForPrebuiltEtcTest.RunTestWithBp(t, `
+ prebuilt_root {
+ name: "foo.conf",
+ src: "foo.conf",
+ filename: "foo.conf",
+ }
+ `)
+
+ p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc)
+ expected := "out/soong/target/product/test_device/system"
+ android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPath)
+}
+
+func TestPrebuiltRootInstallDirPathValidate(t *testing.T) {
+ prepareForPrebuiltEtcTest.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern("filename cannot contain separator")).RunTestWithBp(t, `
+ prebuilt_root {
+ name: "foo.conf",
+ src: "foo.conf",
+ filename: "foo/bar.conf",
+ }
+ `)
+}
+
func TestPrebuiltUserShareInstallDirPath(t *testing.T) {
result := prepareForPrebuiltEtcTest.RunTestWithBp(t, `
prebuilt_usr_share {
diff --git a/filesystem/bootimg.go b/filesystem/bootimg.go
index 3dcc416..29a8a39 100644
--- a/filesystem/bootimg.go
+++ b/filesystem/bootimg.go
@@ -61,7 +61,7 @@
Vendor_boot *bool
// Optional kernel commandline
- Cmdline *string
+ Cmdline *string `android:"arch_variant"`
// File that contains bootconfig parameters. This can be set only when `vendor_boot` is true
// and `header_version` is greater than or equal to 4.
diff --git a/filesystem/vbmeta.go b/filesystem/vbmeta.go
index f823387..3f16c0d 100644
--- a/filesystem/vbmeta.go
+++ b/filesystem/vbmeta.go
@@ -110,6 +110,9 @@
return proptools.StringDefault(v.properties.Partition_name, v.BaseModuleName())
}
+// See external/avb/libavb/avb_slot_verify.c#VBMETA_MAX_SIZE
+const vbmetaMaxSize = 64 * 1024
+
func (v *vbmeta) GenerateAndroidBuildActions(ctx android.ModuleContext) {
extractedPublicKeys := v.extractPublicKeys(ctx)
@@ -172,6 +175,13 @@
}
cmd.FlagWithOutput("--output ", v.output)
+
+ // libavb expects to be able to read the maximum vbmeta size, so we must provide a partition
+ // which matches this or the read will fail.
+ builder.Command().Text("truncate").
+ FlagWithArg("-s ", strconv.Itoa(vbmetaMaxSize)).
+ Output(v.output)
+
builder.Build("vbmeta", fmt.Sprintf("vbmeta %s", ctx.ModuleName()))
v.installDir = android.PathForModuleInstall(ctx, "etc")
diff --git a/genrule/genrule.go b/genrule/genrule.go
index d07b002..e6a5ab9 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -626,6 +626,7 @@
func (x noopImageInterface) CoreVariantNeeded(android.BaseModuleContext) bool { return false }
func (x noopImageInterface) RamdiskVariantNeeded(android.BaseModuleContext) bool { return false }
func (x noopImageInterface) VendorRamdiskVariantNeeded(android.BaseModuleContext) bool { return false }
+func (x noopImageInterface) DebugRamdiskVariantNeeded(android.BaseModuleContext) bool { return false }
func (x noopImageInterface) RecoveryVariantNeeded(android.BaseModuleContext) bool { return false }
func (x noopImageInterface) ExtraImageVariations(ctx android.BaseModuleContext) []string { return nil }
func (x noopImageInterface) SetImageVariation(ctx android.BaseModuleContext, variation string, module android.Module) {
diff --git a/java/Android.bp b/java/Android.bp
index f8ba1b6..2a4b596 100644
--- a/java/Android.bp
+++ b/java/Android.bp
@@ -32,6 +32,7 @@
"boot_image.go",
"boot_jars.go",
"builder.go",
+ "classpath_fragment.go",
"device_host_converter.go",
"dex.go",
"dexpreopt.go",
diff --git a/java/aar.go b/java/aar.go
index a122a94..04727e4 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -218,7 +218,7 @@
linkDeps = append(linkDeps, assetDeps...)
// SDK version flags
- minSdkVersion, err := sdkContext.MinSdkVersion().EffectiveVersionString(ctx)
+ minSdkVersion, err := sdkContext.MinSdkVersion(ctx).EffectiveVersionString(ctx)
if err != nil {
ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
}
@@ -609,6 +609,9 @@
hideApexVariantFromMake bool
aarPath android.Path
+
+ sdkVersion android.SdkSpec
+ minSdkVersion android.SdkSpec
}
var _ android.OutputFileProducer = (*AARImport)(nil)
@@ -625,23 +628,23 @@
}
}
-func (a *AARImport) SdkVersion() android.SdkSpec {
- return android.SdkSpecFrom(String(a.properties.Sdk_version))
+func (a *AARImport) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
+ return android.SdkSpecFrom(ctx, String(a.properties.Sdk_version))
}
func (a *AARImport) SystemModules() string {
return ""
}
-func (a *AARImport) MinSdkVersion() android.SdkSpec {
+func (a *AARImport) MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
if a.properties.Min_sdk_version != nil {
- return android.SdkSpecFrom(*a.properties.Min_sdk_version)
+ return android.SdkSpecFrom(ctx, *a.properties.Min_sdk_version)
}
- return a.SdkVersion()
+ return a.SdkVersion(ctx)
}
-func (a *AARImport) TargetSdkVersion() android.SdkSpec {
- return a.SdkVersion()
+func (a *AARImport) TargetSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
+ return a.SdkVersion(ctx)
}
func (a *AARImport) javaVersion() string {
@@ -727,6 +730,9 @@
return
}
+ a.sdkVersion = a.SdkVersion(ctx)
+ a.minSdkVersion = a.MinSdkVersion(ctx)
+
a.hideApexVariantFromMake = !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform()
aarName := ctx.ModuleName() + ".aar"
diff --git a/java/android_manifest.go b/java/android_manifest.go
index 8510f30..331f941 100644
--- a/java/android_manifest.go
+++ b/java/android_manifest.go
@@ -51,7 +51,7 @@
if isLibrary {
args = append(args, "--library")
} else {
- minSdkVersion, err := sdkContext.MinSdkVersion().EffectiveVersion(ctx)
+ minSdkVersion, err := sdkContext.MinSdkVersion(ctx).EffectiveVersion(ctx)
if err != nil {
ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
}
@@ -87,7 +87,7 @@
args = append(args, "--logging-parent", loggingParent)
}
var deps android.Paths
- targetSdkVersion, err := sdkContext.TargetSdkVersion().EffectiveVersionString(ctx)
+ targetSdkVersion, err := sdkContext.TargetSdkVersion(ctx).EffectiveVersionString(ctx)
if err != nil {
ctx.ModuleErrorf("invalid targetSdkVersion: %s", err)
}
@@ -96,7 +96,7 @@
deps = append(deps, ApiFingerprintPath(ctx))
}
- minSdkVersion, err := sdkContext.MinSdkVersion().EffectiveVersionString(ctx)
+ minSdkVersion, err := sdkContext.MinSdkVersion(ctx).EffectiveVersionString(ctx)
if err != nil {
ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
}
diff --git a/java/androidmk.go b/java/androidmk.go
index 75661a7..4e594a2 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -106,7 +106,7 @@
if len(library.dexpreopter.builtInstalled) > 0 {
entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", library.dexpreopter.builtInstalled)
}
- entries.SetString("LOCAL_SDK_VERSION", library.SdkVersion().Raw)
+ entries.SetString("LOCAL_SDK_VERSION", library.sdkVersion.String())
entries.SetPath("LOCAL_SOONG_CLASSES_JAR", library.implementationAndResourcesJar)
entries.SetPath("LOCAL_SOONG_HEADER_JAR", library.headerJarFile)
@@ -205,7 +205,7 @@
}
entries.SetPath("LOCAL_SOONG_HEADER_JAR", prebuilt.combinedClasspathFile)
entries.SetPath("LOCAL_SOONG_CLASSES_JAR", prebuilt.combinedClasspathFile)
- entries.SetString("LOCAL_SDK_VERSION", prebuilt.makeSdkVersion())
+ entries.SetString("LOCAL_SDK_VERSION", prebuilt.sdkVersion.String())
entries.SetString("LOCAL_MODULE_STEM", prebuilt.Stem())
},
},
@@ -255,7 +255,7 @@
entries.SetPath("LOCAL_SOONG_EXPORT_PROGUARD_FLAGS", prebuilt.proguardFlags)
entries.SetPath("LOCAL_SOONG_STATIC_LIBRARY_EXTRA_PACKAGES", prebuilt.extraAaptPackagesFile)
entries.SetPath("LOCAL_FULL_MANIFEST_FILE", prebuilt.manifest)
- entries.SetString("LOCAL_SDK_VERSION", prebuilt.SdkVersion().Raw)
+ entries.SetString("LOCAL_SDK_VERSION", prebuilt.sdkVersion.String())
},
},
}}
diff --git a/java/app.go b/java/app.go
index 04406e7..5695022 100755
--- a/java/app.go
+++ b/java/app.go
@@ -213,7 +213,7 @@
func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) {
a.Module.deps(ctx)
- if String(a.appProperties.Stl) == "c++_shared" && !a.SdkVersion().Specified() {
+ if String(a.appProperties.Stl) == "c++_shared" && !a.SdkVersion(ctx).Specified() {
ctx.PropertyErrorf("stl", "sdk_version must be set in order to use c++_shared")
}
@@ -222,7 +222,7 @@
a.aapt.deps(ctx, sdkDep)
}
- usesSDK := a.SdkVersion().Specified() && a.SdkVersion().Kind != android.SdkCorePlatform
+ usesSDK := a.SdkVersion(ctx).Specified() && a.SdkVersion(ctx).Kind != android.SdkCorePlatform
if usesSDK && Bool(a.appProperties.Jni_uses_sdk_apis) {
ctx.PropertyErrorf("jni_uses_sdk_apis",
@@ -279,14 +279,14 @@
func (a *AndroidApp) checkAppSdkVersions(ctx android.ModuleContext) {
if a.Updatable() {
- if !a.SdkVersion().Stable() {
- ctx.PropertyErrorf("sdk_version", "Updatable apps must use stable SDKs, found %v", a.SdkVersion())
+ if !a.SdkVersion(ctx).Stable() {
+ ctx.PropertyErrorf("sdk_version", "Updatable apps must use stable SDKs, found %v", a.SdkVersion(ctx))
}
if String(a.deviceProperties.Min_sdk_version) == "" {
ctx.PropertyErrorf("updatable", "updatable apps must set min_sdk_version.")
}
- if minSdkVersion, err := a.MinSdkVersion().EffectiveVersion(ctx); err == nil {
+ if minSdkVersion, err := a.MinSdkVersion(ctx).EffectiveVersion(ctx); err == nil {
a.checkJniLibsSdkVersion(ctx, minSdkVersion)
android.CheckMinSdkVersion(a, ctx, minSdkVersion)
} else {
@@ -314,7 +314,7 @@
// The domain of cc.sdk_version is "current" and <number>
// We can rely on android.SdkSpec to convert it to <number> so that "current" is
// handled properly regardless of sdk finalization.
- jniSdkVersion, err := android.SdkSpecFrom(dep.SdkVersion()).EffectiveVersion(ctx)
+ jniSdkVersion, err := android.SdkSpecFrom(ctx, dep.SdkVersion()).EffectiveVersion(ctx)
if err != nil || minSdkVersion.LessThan(jniSdkVersion) {
ctx.OtherModuleErrorf(dep, "sdk_version(%v) is higher than min_sdk_version(%v) of the containing android_app(%v)",
dep.SdkVersion(), minSdkVersion, ctx.ModuleName())
@@ -327,9 +327,9 @@
// Returns true if the native libraries should be stored in the APK uncompressed and the
// extractNativeLibs application flag should be set to false in the manifest.
func (a *AndroidApp) useEmbeddedNativeLibs(ctx android.ModuleContext) bool {
- minSdkVersion, err := a.MinSdkVersion().EffectiveVersion(ctx)
+ minSdkVersion, err := a.MinSdkVersion(ctx).EffectiveVersion(ctx)
if err != nil {
- ctx.PropertyErrorf("min_sdk_version", "invalid value %q: %s", a.MinSdkVersion(), err)
+ ctx.PropertyErrorf("min_sdk_version", "invalid value %q: %s", a.MinSdkVersion(ctx), err)
}
apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
@@ -381,7 +381,7 @@
func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) {
usePlatformAPI := proptools.Bool(a.Module.deviceProperties.Platform_apis)
- if ctx.Module().(android.SdkContext).SdkVersion().Kind == android.SdkModule {
+ if ctx.Module().(android.SdkContext).SdkVersion(ctx).Kind == android.SdkModule {
usePlatformAPI = true
}
a.aapt.usesNonSdkApis = usePlatformAPI
@@ -724,8 +724,8 @@
}
type appDepsInterface interface {
- SdkVersion() android.SdkSpec
- MinSdkVersion() android.SdkSpec
+ SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec
+ MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec
RequiresStableAPIs(ctx android.BaseModuleContext) bool
}
@@ -738,8 +738,8 @@
seenModulePaths := make(map[string]bool)
if checkNativeSdkVersion {
- checkNativeSdkVersion = app.SdkVersion().Specified() &&
- app.SdkVersion().Kind != android.SdkCorePlatform && !app.RequiresStableAPIs(ctx)
+ checkNativeSdkVersion = app.SdkVersion(ctx).Specified() &&
+ app.SdkVersion(ctx).Kind != android.SdkCorePlatform && !app.RequiresStableAPIs(ctx)
}
ctx.WalkDeps(func(module android.Module, parent android.Module) bool {
@@ -829,12 +829,16 @@
depsInfo[depName] = info
} else {
toMinSdkVersion := "(no version)"
- if m, ok := to.(interface{ MinSdkVersion() string }); ok {
- if v := m.MinSdkVersion(); v != "" {
- toMinSdkVersion = v
+ if m, ok := to.(interface {
+ MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec
+ }); ok {
+ if v := m.MinSdkVersion(ctx); !v.ApiLevel.IsNone() {
+ toMinSdkVersion = v.ApiLevel.String()
}
- } else if m, ok := to.(interface{ MinSdkVersionString() string }); ok {
- if v := m.MinSdkVersionString(); v != "" {
+ } else if m, ok := to.(interface{ MinSdkVersion() string }); ok {
+ // TODO(b/175678607) eliminate the use of MinSdkVersion returning
+ // string
+ if v := m.MinSdkVersion(); v != "" {
toMinSdkVersion = v
}
}
@@ -848,7 +852,7 @@
return true
})
- a.ApexBundleDepsInfo.BuildDepsInfoLists(ctx, a.MinSdkVersionString(), depsInfo)
+ a.ApexBundleDepsInfo.BuildDepsInfoLists(ctx, a.MinSdkVersion(ctx).String(), depsInfo)
}
func (a *AndroidApp) Updatable() bool {
diff --git a/java/app_import.go b/java/app_import.go
index 32cec23..839051e 100644
--- a/java/app_import.go
+++ b/java/app_import.go
@@ -394,12 +394,12 @@
return false
}
-func (a *AndroidAppImport) SdkVersion() android.SdkSpec {
- return android.SdkSpecFrom("")
+func (a *AndroidAppImport) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
+ return android.SdkSpecPrivate
}
-func (a *AndroidAppImport) MinSdkVersion() android.SdkSpec {
- return android.SdkSpecFrom("")
+func (a *AndroidAppImport) MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
+ return android.SdkSpecPrivate
}
var _ android.ApexModule = (*AndroidAppImport)(nil)
diff --git a/java/base.go b/java/base.go
index 9bc0738..19c85cd 100644
--- a/java/base.go
+++ b/java/base.go
@@ -370,10 +370,13 @@
modulePaths []string
hideApexVariantFromMake bool
+
+ sdkVersion android.SdkSpec
+ minSdkVersion android.SdkSpec
}
-func (j *Module) CheckStableSdkVersion() error {
- sdkVersion := j.SdkVersion()
+func (j *Module) CheckStableSdkVersion(ctx android.BaseModuleContext) error {
+ sdkVersion := j.SdkVersion(ctx)
if sdkVersion.Stable() {
return nil
}
@@ -393,7 +396,7 @@
func (j *Module) checkSdkVersions(ctx android.ModuleContext) {
if j.RequiresStableAPIs(ctx) {
if sc, ok := ctx.Module().(android.SdkContext); ok {
- if !sc.SdkVersion().Specified() {
+ if !sc.SdkVersion(ctx).Specified() {
ctx.PropertyErrorf("sdk_version",
"sdk_version must have a value when the module is located at vendor or product(only if PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE is set).")
}
@@ -418,7 +421,7 @@
func (j *Module) checkPlatformAPI(ctx android.ModuleContext) {
if sc, ok := ctx.Module().(android.SdkContext); ok {
usePlatformAPI := proptools.Bool(j.deviceProperties.Platform_apis)
- sdkVersionSpecified := sc.SdkVersion().Specified()
+ sdkVersionSpecified := sc.SdkVersion(ctx).Specified()
if usePlatformAPI && sdkVersionSpecified {
ctx.PropertyErrorf("platform_apis", "platform_apis must be false when sdk_version is not empty.")
} else if !usePlatformAPI && !sdkVersionSpecified {
@@ -512,30 +515,30 @@
return false
}
-func (j *Module) SdkVersion() android.SdkSpec {
- return android.SdkSpecFrom(String(j.deviceProperties.Sdk_version))
+func (j *Module) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
+ return android.SdkSpecFrom(ctx, String(j.deviceProperties.Sdk_version))
}
func (j *Module) SystemModules() string {
return proptools.String(j.deviceProperties.System_modules)
}
-func (j *Module) MinSdkVersion() android.SdkSpec {
+func (j *Module) MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
if j.deviceProperties.Min_sdk_version != nil {
- return android.SdkSpecFrom(*j.deviceProperties.Min_sdk_version)
+ return android.SdkSpecFrom(ctx, *j.deviceProperties.Min_sdk_version)
}
- return j.SdkVersion()
-}
-
-func (j *Module) TargetSdkVersion() android.SdkSpec {
- if j.deviceProperties.Target_sdk_version != nil {
- return android.SdkSpecFrom(*j.deviceProperties.Target_sdk_version)
- }
- return j.SdkVersion()
+ return j.SdkVersion(ctx)
}
func (j *Module) MinSdkVersionString() string {
- return j.MinSdkVersion().ApiLevel.String()
+ return j.minSdkVersion.Raw
+}
+
+func (j *Module) TargetSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
+ if j.deviceProperties.Target_sdk_version != nil {
+ return android.SdkSpecFrom(ctx, *j.deviceProperties.Target_sdk_version)
+ }
+ return j.SdkVersion(ctx)
}
func (j *Module) AvailableFor(what string) bool {
@@ -1209,7 +1212,7 @@
}
// Dex compilation
var dexOutputFile android.OutputPath
- dexOutputFile = j.dexer.compileDex(ctx, flags, j.MinSdkVersion(), outputFile, jarName)
+ dexOutputFile = j.dexer.compileDex(ctx, flags, j.MinSdkVersion(ctx), outputFile, jarName)
if ctx.Failed() {
return
}
@@ -1267,9 +1270,9 @@
j.linter.srcJars = srcJars
j.linter.classpath = append(append(android.Paths(nil), flags.bootClasspath...), flags.classpath...)
j.linter.classes = j.implementationJarFile
- j.linter.minSdkVersion = lintSDKVersionString(j.MinSdkVersion())
- j.linter.targetSdkVersion = lintSDKVersionString(j.TargetSdkVersion())
- j.linter.compileSdkVersion = lintSDKVersionString(j.SdkVersion())
+ j.linter.minSdkVersion = lintSDKVersionString(j.MinSdkVersion(ctx))
+ j.linter.targetSdkVersion = lintSDKVersionString(j.TargetSdkVersion(ctx))
+ j.linter.compileSdkVersion = lintSDKVersionString(j.SdkVersion(ctx))
j.linter.javaLanguageLevel = flags.javaVersion.String()
j.linter.kotlinLanguageLevel = "1.3"
if !apexInfo.IsForPlatform() && ctx.Config().UnbundledBuildApps() {
@@ -1471,7 +1474,7 @@
// Implements android.ApexModule
func (j *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext,
sdkVersion android.ApiLevel) error {
- sdkSpec := j.MinSdkVersion()
+ sdkSpec := j.MinSdkVersion(ctx)
if !sdkSpec.Specified() {
return fmt.Errorf("min_sdk_version is not specified")
}
@@ -1551,10 +1554,10 @@
type moduleWithSdkDep interface {
android.Module
- getSdkLinkType(name string) (ret sdkLinkType, stubs bool)
+ getSdkLinkType(ctx android.BaseModuleContext, name string) (ret sdkLinkType, stubs bool)
}
-func (m *Module) getSdkLinkType(name string) (ret sdkLinkType, stubs bool) {
+func (m *Module) getSdkLinkType(ctx android.BaseModuleContext, name string) (ret sdkLinkType, stubs bool) {
switch name {
case "core.current.stubs", "legacy.core.platform.api.stubs", "stable.core.platform.api.stubs",
"stub-annotations", "private-stub-annotations-jar",
@@ -1576,7 +1579,7 @@
return linkType, true
}
- ver := m.SdkVersion()
+ ver := m.SdkVersion(ctx)
switch ver.Kind {
case android.SdkCore:
return javaCore, false
@@ -1606,11 +1609,11 @@
return
}
- myLinkType, stubs := j.getSdkLinkType(ctx.ModuleName())
+ myLinkType, stubs := j.getSdkLinkType(ctx, ctx.ModuleName())
if stubs {
return
}
- depLinkType, _ := dep.getSdkLinkType(ctx.OtherModuleName(dep))
+ depLinkType, _ := dep.getSdkLinkType(ctx, ctx.OtherModuleName(dep))
if myLinkType.rank() < depLinkType.rank() {
ctx.ModuleErrorf("compiles against %v, but dependency %q is compiling against %v. "+
@@ -1638,7 +1641,7 @@
}
}
- sdkLinkType, _ := j.getSdkLinkType(ctx.ModuleName())
+ sdkLinkType, _ := j.getSdkLinkType(ctx, ctx.ModuleName())
ctx.VisitDirectDeps(func(module android.Module) {
otherName := ctx.OtherModuleName(module)
@@ -1656,7 +1659,7 @@
if dep, ok := module.(SdkLibraryDependency); ok {
switch tag {
case libTag:
- deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.SdkVersion())...)
+ deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.SdkVersion(ctx))...)
case staticLibTag:
ctx.ModuleErrorf("dependency on java_sdk_library %q can only be in libs", otherName)
}
diff --git a/java/classpath_fragment.go b/java/classpath_fragment.go
new file mode 100644
index 0000000..d497460
--- /dev/null
+++ b/java/classpath_fragment.go
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * 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 java
+
+import (
+ "fmt"
+ "strings"
+
+ "android/soong/android"
+)
+
+// Build rules and utilities to generate individual packages/modules/SdkExtensions/proto/classpaths.proto
+// config files based on build configuration to embed into /system and /apex on a device.
+//
+// See `derive_classpath` service that reads the configs at runtime and defines *CLASSPATH variables
+// on the device.
+
+type classpathType int
+
+const (
+ // Matches definition in packages/modules/SdkExtensions/proto/classpaths.proto
+ BOOTCLASSPATH classpathType = iota
+ DEX2OATBOOTCLASSPATH
+ SYSTEMSERVERCLASSPATH
+)
+
+func (c classpathType) String() string {
+ return [...]string{"BOOTCLASSPATH", "DEX2OATBOOTCLASSPATH", "SYSTEMSERVERCLASSPATH"}[c]
+}
+
+type classpathFragmentProperties struct {
+}
+
+// classpathFragment interface is implemented by a module that contributes jars to a *CLASSPATH
+// variables at runtime.
+type classpathFragment interface {
+ android.Module
+
+ classpathFragmentBase() *ClasspathFragmentBase
+}
+
+// ClasspathFragmentBase is meant to be embedded in any module types that implement classpathFragment;
+// such modules are expected to call initClasspathFragment().
+type ClasspathFragmentBase struct {
+ properties classpathFragmentProperties
+
+ outputFilepath android.OutputPath
+ installDirPath android.InstallPath
+}
+
+func (c *ClasspathFragmentBase) classpathFragmentBase() *ClasspathFragmentBase {
+ return c
+}
+
+// Initializes ClasspathFragmentBase struct. Must be called by all modules that include ClasspathFragmentBase.
+func initClasspathFragment(c classpathFragment) {
+ base := c.classpathFragmentBase()
+ c.AddProperties(&base.properties)
+}
+
+// Matches definition of Jar in packages/modules/SdkExtensions/proto/classpaths.proto
+type classpathJar struct {
+ path string
+ classpath classpathType
+ // TODO(satayev): propagate min/max sdk versions for the jars
+ minSdkVersion int32
+ maxSdkVersion int32
+}
+
+func (c *ClasspathFragmentBase) generateAndroidBuildActions(ctx android.ModuleContext) {
+ outputFilename := ctx.ModuleName() + ".pb"
+ c.outputFilepath = android.PathForModuleOut(ctx, outputFilename).OutputPath
+ c.installDirPath = android.PathForModuleInstall(ctx, "etc", "classpaths")
+
+ var jars []classpathJar
+ jars = appendClasspathJar(jars, BOOTCLASSPATH, defaultBootclasspath(ctx)...)
+ jars = appendClasspathJar(jars, DEX2OATBOOTCLASSPATH, defaultBootImageConfig(ctx).getAnyAndroidVariant().dexLocationsDeps...)
+ jars = appendClasspathJar(jars, SYSTEMSERVERCLASSPATH, systemServerClasspath(ctx)...)
+
+ generatedJson := android.PathForModuleOut(ctx, outputFilename+".json")
+ writeClasspathsJson(ctx, generatedJson, jars)
+
+ rule := android.NewRuleBuilder(pctx, ctx)
+ rule.Command().
+ BuiltTool("conv_classpaths_proto").
+ Flag("encode").
+ Flag("--format=json").
+ FlagWithInput("--input=", generatedJson).
+ FlagWithOutput("--output=", c.outputFilepath)
+
+ rule.Build("classpath_fragment", "Compiling "+c.outputFilepath.String())
+}
+
+func writeClasspathsJson(ctx android.ModuleContext, output android.WritablePath, jars []classpathJar) {
+ var content strings.Builder
+ fmt.Fprintf(&content, "{\n")
+ fmt.Fprintf(&content, "\"jars\": [\n")
+ for idx, jar := range jars {
+ fmt.Fprintf(&content, "{\n")
+
+ fmt.Fprintf(&content, "\"relativePath\": \"%s\",\n", jar.path)
+ fmt.Fprintf(&content, "\"classpath\": \"%s\"\n", jar.classpath)
+
+ if idx < len(jars)-1 {
+ fmt.Fprintf(&content, "},\n")
+ } else {
+ fmt.Fprintf(&content, "}\n")
+ }
+ }
+ fmt.Fprintf(&content, "]\n")
+ fmt.Fprintf(&content, "}\n")
+ android.WriteFileRule(ctx, output, content.String())
+}
+
+func appendClasspathJar(slice []classpathJar, classpathType classpathType, paths ...string) (result []classpathJar) {
+ result = append(result, slice...)
+ for _, path := range paths {
+ result = append(result, classpathJar{
+ path: path,
+ classpath: classpathType,
+ })
+ }
+ return
+}
+
+func (c *ClasspathFragmentBase) getAndroidMkEntries() []android.AndroidMkEntries {
+ return []android.AndroidMkEntries{android.AndroidMkEntries{
+ Class: "ETC",
+ OutputFile: android.OptionalPathForPath(c.outputFilepath),
+ ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+ func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+ entries.SetString("LOCAL_MODULE_PATH", c.installDirPath.ToMakePath().String())
+ entries.SetString("LOCAL_INSTALLED_MODULE_STEM", c.outputFilepath.Base())
+ },
+ },
+ }}
+}
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 7137f33..e57c3e9 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -484,7 +484,7 @@
// Now match the apex part of the boot image configuration.
requiredApex := bootjars.Apex(index)
- if requiredApex == "platform" {
+ if requiredApex == "platform" || requiredApex == "system_ext" {
if len(apexInfo.InApexes) != 0 {
// A platform variant is required but this is for an apex so ignore it.
return -1, nil, nil
diff --git a/java/dexpreopt_bootjars_test.go b/java/dexpreopt_bootjars_test.go
index d78651d..73f21d1 100644
--- a/java/dexpreopt_bootjars_test.go
+++ b/java/dexpreopt_bootjars_test.go
@@ -35,6 +35,7 @@
name: "bar",
srcs: ["b.java"],
installable: true,
+ system_ext_specific: true,
}
dex_import {
@@ -47,7 +48,7 @@
prepareForJavaTest,
PrepareForTestWithJavaSdkLibraryFiles,
FixtureWithLastReleaseApis("foo"),
- dexpreopt.FixtureSetBootJars("platform:foo", "platform:bar", "platform:baz"),
+ dexpreopt.FixtureSetBootJars("platform:foo", "system_ext:bar", "platform:baz"),
).RunTestWithBp(t, bp)
dexpreoptBootJars := result.SingletonForTests("dex_bootjars")
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index 64b2656..656f5ef 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -26,7 +26,7 @@
// systemServerClasspath returns the on-device locations of the modules in the system server classpath. It is computed
// once the first time it is called for any ctx.Config(), and returns the same slice for all future calls with the same
// ctx.Config().
-func systemServerClasspath(ctx android.MakeVarsContext) []string {
+func systemServerClasspath(ctx android.PathContext) []string {
return ctx.Config().OnceStringSlice(systemServerClasspathKey, func() []string {
global := dexpreopt.GetGlobalConfig(ctx)
var systemServerClasspathLocations []string
diff --git a/java/droiddoc.go b/java/droiddoc.go
index e527d59..01c0f16 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -261,20 +261,20 @@
var _ android.OutputFileProducer = (*Javadoc)(nil)
-func (j *Javadoc) SdkVersion() android.SdkSpec {
- return android.SdkSpecFrom(String(j.properties.Sdk_version))
+func (j *Javadoc) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
+ return android.SdkSpecFrom(ctx, String(j.properties.Sdk_version))
}
func (j *Javadoc) SystemModules() string {
return proptools.String(j.properties.System_modules)
}
-func (j *Javadoc) MinSdkVersion() android.SdkSpec {
- return j.SdkVersion()
+func (j *Javadoc) MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
+ return j.SdkVersion(ctx)
}
-func (j *Javadoc) TargetSdkVersion() android.SdkSpec {
- return j.SdkVersion()
+func (j *Javadoc) TargetSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
+ return j.SdkVersion(ctx)
}
func (j *Javadoc) addDeps(ctx android.BottomUpMutatorContext) {
@@ -386,7 +386,7 @@
}
case libTag:
if dep, ok := module.(SdkLibraryDependency); ok {
- deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.SdkVersion())...)
+ deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.SdkVersion(ctx))...)
} else if ctx.OtherModuleHasProvider(module, JavaInfoProvider) {
dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo)
deps.classpath = append(deps.classpath, dep.HeaderJars...)
diff --git a/java/hiddenapi.go b/java/hiddenapi.go
index 208ced7..3ecb977 100644
--- a/java/hiddenapi.go
+++ b/java/hiddenapi.go
@@ -111,6 +111,13 @@
var _ hiddenAPIIntf = (*hiddenAPI)(nil)
+// hiddenAPISupportingModule is the interface that is implemented by any module that supports
+// contributing to the hidden API processing.
+type hiddenAPISupportingModule interface {
+ android.Module
+ hiddenAPIIntf
+}
+
// Initialize the hiddenapi structure
func (h *hiddenAPI) initHiddenAPI(ctx android.BaseModuleContext, configurationName string) {
// If hiddenapi processing is disabled treat this as inactive.
diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go
index bed11fe..7cf082b 100644
--- a/java/hiddenapi_modular.go
+++ b/java/hiddenapi_modular.go
@@ -20,9 +20,9 @@
// Contains support for processing hiddenAPI in a modular fashion.
-// HiddenAPIAugmentationProperties contains paths to the files that can be used to augment the information
-// obtained from annotations within the source code in order to create the complete set of flags
-// that should be applied to the dex implementation jars on the bootclasspath.
+// HiddenAPIFlagFileProperties contains paths to the flag files that can be used to augment the
+// information obtained from annotations within the source code in order to create the complete set
+// of flags that should be applied to the dex implementation jars on the bootclasspath.
//
// Each property contains a list of paths. With the exception of the Unsupported_packages the paths
// of each property reference a plain text file that contains a java signature per line. The flags
@@ -31,7 +31,7 @@
// The Unsupported_packages property contains a list of paths, each of which is a plain text file
// with one Java package per line. All members of all classes within that package (but not nested
// packages) will be updated in a property specific way.
-type HiddenAPIAugmentationProperties struct {
+type HiddenAPIFlagFileProperties struct {
// Marks each signature in the referenced files as being unsupported.
Unsupported []string `android:"path"`
@@ -60,45 +60,116 @@
Unsupported_packages []string `android:"path"`
}
-func (p *HiddenAPIAugmentationProperties) hiddenAPIAugmentationInfo(ctx android.ModuleContext) hiddenAPIAugmentationInfo {
- paths := func(paths []string) android.Paths { return android.PathsForModuleSrc(ctx, paths) }
- return hiddenAPIAugmentationInfo{
- Unsupported: paths(p.Unsupported),
- Removed: paths(p.Removed),
- Max_target_r_low_priority: paths(p.Max_target_r_low_priority),
- Max_target_q: paths(p.Max_target_q),
- Max_target_p: paths(p.Max_target_p),
- Max_target_o_low_priority: paths(p.Max_target_o_low_priority),
- Blocked: paths(p.Blocked),
- Unsupported_packages: paths(p.Unsupported_packages),
+func (p *HiddenAPIFlagFileProperties) hiddenAPIFlagFileInfo(ctx android.ModuleContext) hiddenAPIFlagFileInfo {
+ info := hiddenAPIFlagFileInfo{categoryToPaths: map[*hiddenAPIFlagFileCategory]android.Paths{}}
+ for _, category := range hiddenAPIFlagFileCategories {
+ paths := android.PathsForModuleSrc(ctx, category.propertyAccessor(p))
+ info.categoryToPaths[category] = paths
}
+ return info
}
-// hiddenAPIAugmentationInfo contains paths resolved from HiddenAPIAugmentationProperties
-type hiddenAPIAugmentationInfo struct {
- // See HiddenAPIAugmentationProperties.Unsupported
- Unsupported android.Paths
+type hiddenAPIFlagFileCategory struct {
+ // propertyName is the name of the property for this category.
+ propertyName string
- // See HiddenAPIAugmentationProperties.Removed
- Removed android.Paths
+ // propertyAccessor retrieves the value of the property for this category from the set of
+ // properties.
+ propertyAccessor func(properties *HiddenAPIFlagFileProperties) []string
- // See HiddenAPIAugmentationProperties.Max_target_r_low_priority
- Max_target_r_low_priority android.Paths
+ // commandMutator adds the appropriate command line options for this category to the supplied
+ // command
+ commandMutator func(command *android.RuleBuilderCommand, path android.Path)
+}
- // See HiddenAPIAugmentationProperties.Max_target_q
- Max_target_q android.Paths
+var hiddenAPIFlagFileCategories = []*hiddenAPIFlagFileCategory{
+ // See HiddenAPIFlagFileProperties.Unsupported
+ {
+ propertyName: "unsupported",
+ propertyAccessor: func(properties *HiddenAPIFlagFileProperties) []string {
+ return properties.Unsupported
+ },
+ commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
+ command.FlagWithInput("--unsupported ", path)
+ },
+ },
+ // See HiddenAPIFlagFileProperties.Removed
+ {
+ propertyName: "removed",
+ propertyAccessor: func(properties *HiddenAPIFlagFileProperties) []string {
+ return properties.Removed
+ },
+ commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
+ command.FlagWithInput("--unsupported ", path).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "removed")
+ },
+ },
+ // See HiddenAPIFlagFileProperties.Max_target_r_low_priority
+ {
+ propertyName: "max_target_r_low_priority",
+ propertyAccessor: func(properties *HiddenAPIFlagFileProperties) []string {
+ return properties.Max_target_r_low_priority
+ },
+ commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
+ command.FlagWithInput("--max-target-r ", path).FlagWithArg("--tag ", "lo-prio")
+ },
+ },
+ // See HiddenAPIFlagFileProperties.Max_target_q
+ {
+ propertyName: "max_target_q",
+ propertyAccessor: func(properties *HiddenAPIFlagFileProperties) []string {
+ return properties.Max_target_q
+ },
+ commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
+ command.FlagWithInput("--max-target-q ", path)
+ },
+ },
+ // See HiddenAPIFlagFileProperties.Max_target_p
+ {
+ propertyName: "max_target_p",
+ propertyAccessor: func(properties *HiddenAPIFlagFileProperties) []string {
+ return properties.Max_target_p
+ },
+ commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
+ command.FlagWithInput("--max-target-p ", path)
+ },
+ },
+ // See HiddenAPIFlagFileProperties.Max_target_o_low_priority
+ {
+ propertyName: "max_target_o_low_priority",
+ propertyAccessor: func(properties *HiddenAPIFlagFileProperties) []string {
+ return properties.Max_target_o_low_priority
+ },
+ commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
+ command.FlagWithInput("--max-target-o ", path).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "lo-prio")
+ },
+ },
+ // See HiddenAPIFlagFileProperties.Blocked
+ {
+ propertyName: "blocked",
+ propertyAccessor: func(properties *HiddenAPIFlagFileProperties) []string {
+ return properties.Blocked
+ },
+ commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
+ command.FlagWithInput("--blocked ", path)
+ },
+ },
+ // See HiddenAPIFlagFileProperties.Unsupported_packages
+ {
+ propertyName: "unsupported_packages",
+ propertyAccessor: func(properties *HiddenAPIFlagFileProperties) []string {
+ return properties.Unsupported_packages
+ },
+ commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
+ command.FlagWithInput("--unsupported ", path).Flag("--packages ")
+ },
+ },
+}
- // See HiddenAPIAugmentationProperties.Max_target_p
- Max_target_p android.Paths
-
- // See HiddenAPIAugmentationProperties.Max_target_o_low_priority
- Max_target_o_low_priority android.Paths
-
- // See HiddenAPIAugmentationProperties.Blocked
- Blocked android.Paths
-
- // See HiddenAPIAugmentationProperties.Unsupported_packages
- Unsupported_packages android.Paths
+// hiddenAPIFlagFileInfo contains paths resolved from HiddenAPIFlagFileProperties
+type hiddenAPIFlagFileInfo struct {
+ // categoryToPaths maps from the flag file category to the paths containing information for that
+ // category.
+ categoryToPaths map[*hiddenAPIFlagFileCategory]android.Paths
}
// ruleToGenerateHiddenApiFlags creates a rule to create the monolithic hidden API flags from the
@@ -125,7 +196,7 @@
//
// augmentationInfo is a struct containing paths to files that augment the information provided by
// the moduleSpecificFlagsPaths.
-func ruleToGenerateHiddenApiFlags(ctx android.BuilderContext, outputPath android.WritablePath, baseFlagsPath android.Path, moduleSpecificFlagsPaths android.Paths, augmentationInfo hiddenAPIAugmentationInfo) {
+func ruleToGenerateHiddenApiFlags(ctx android.BuilderContext, outputPath android.WritablePath, baseFlagsPath android.Path, moduleSpecificFlagsPaths android.Paths, augmentationInfo hiddenAPIFlagFileInfo) {
tempPath := android.PathForOutput(ctx, outputPath.Rel()+".tmp")
rule := android.NewRuleBuilder(pctx, ctx)
command := rule.Command().
@@ -134,36 +205,12 @@
Inputs(moduleSpecificFlagsPaths).
FlagWithOutput("--output ", tempPath)
- for _, path := range augmentationInfo.Unsupported {
- command.FlagWithInput("--unsupported ", path)
- }
-
- for _, path := range augmentationInfo.Removed {
- command.FlagWithInput("--unsupported ", path).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "removed")
- }
-
- for _, path := range augmentationInfo.Max_target_r_low_priority {
- command.FlagWithInput("--max-target-r ", path).FlagWithArg("--tag ", "lo-prio")
- }
-
- for _, path := range augmentationInfo.Max_target_q {
- command.FlagWithInput("--max-target-q ", path)
- }
-
- for _, path := range augmentationInfo.Max_target_p {
- command.FlagWithInput("--max-target-p ", path)
- }
-
- for _, path := range augmentationInfo.Max_target_o_low_priority {
- command.FlagWithInput("--max-target-o ", path).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "lo-prio")
- }
-
- for _, path := range augmentationInfo.Blocked {
- command.FlagWithInput("--blocked ", path)
- }
-
- for _, path := range augmentationInfo.Unsupported_packages {
- command.FlagWithInput("--unsupported ", path).Flag("--packages ")
+ // Add the options for the different categories of flag files.
+ for _, category := range hiddenAPIFlagFileCategories {
+ paths := augmentationInfo.categoryToPaths[category]
+ for _, path := range paths {
+ category.commandMutator(command, path)
+ }
}
commitChangeForRestat(rule, tempPath, outputPath)
diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go
index 641e19f..ed0b722 100644
--- a/java/hiddenapi_singleton.go
+++ b/java/hiddenapi_singleton.go
@@ -15,8 +15,6 @@
package java
import (
- "fmt"
-
"android/soong/android"
)
@@ -26,8 +24,6 @@
func RegisterHiddenApiSingletonComponents(ctx android.RegistrationContext) {
ctx.RegisterSingletonType("hiddenapi", hiddenAPISingletonFactory)
- ctx.RegisterSingletonType("hiddenapi_index", hiddenAPIIndexSingletonFactory)
- ctx.RegisterModuleType("hiddenapi_flags", hiddenAPIFlagsFactory)
}
var PrepareForTestWithHiddenApiBuildComponents = android.FixtureRegisterWithContext(RegisterHiddenApiSingletonComponents)
@@ -101,11 +97,15 @@
// yet been created.
func hiddenAPISingletonPaths(ctx android.PathContext) hiddenAPISingletonPathsStruct {
return ctx.Config().Once(hiddenAPISingletonPathsKey, func() interface{} {
+ // Make the paths relative to the out/soong/hiddenapi directory instead of to the out/soong/
+ // directory. This ensures that if they are used as java_resources they do not end up in a
+ // hiddenapi directory in the resulting APK.
+ hiddenapiDir := android.PathForOutput(ctx, "hiddenapi")
return hiddenAPISingletonPathsStruct{
- flags: android.PathForOutput(ctx, "hiddenapi", "hiddenapi-flags.csv"),
- index: android.PathForOutput(ctx, "hiddenapi", "hiddenapi-index.csv"),
- metadata: android.PathForOutput(ctx, "hiddenapi", "hiddenapi-unsupported.csv"),
- stubFlags: android.PathForOutput(ctx, "hiddenapi", "hiddenapi-stub-flags.txt"),
+ flags: hiddenapiDir.Join(ctx, "hiddenapi-flags.csv"),
+ index: hiddenapiDir.Join(ctx, "hiddenapi-index.csv"),
+ metadata: hiddenapiDir.Join(ctx, "hiddenapi-unsupported.csv"),
+ stubFlags: hiddenapiDir.Join(ctx, "hiddenapi-stub-flags.txt"),
}
}).(hiddenAPISingletonPathsStruct)
}
@@ -115,7 +115,7 @@
}
type hiddenAPISingleton struct {
- flags, metadata android.Path
+ flags android.Path
}
// hiddenAPI singleton rules
@@ -137,30 +137,25 @@
if ctx.Config().PrebuiltHiddenApiDir(ctx) != "" {
h.flags = prebuiltFlagsRule(ctx)
+ prebuiltIndexRule(ctx)
return
}
// These rules depend on files located in frameworks/base, skip them if running in a tree that doesn't have them.
if ctx.Config().FrameworksBaseDirExists(ctx) {
h.flags = flagsRule(ctx)
- h.metadata = metadataRule(ctx)
} else {
h.flags = emptyFlagsRule(ctx)
}
}
// Export paths to Make. INTERNAL_PLATFORM_HIDDENAPI_FLAGS is used by Make rules in art/ and cts/.
-// Both paths are used to call dist-for-goals.
func (h *hiddenAPISingleton) MakeVars(ctx android.MakeVarsContext) {
if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
return
}
ctx.Strict("INTERNAL_PLATFORM_HIDDENAPI_FLAGS", h.flags.String())
-
- if h.metadata != nil {
- ctx.Strict("INTERNAL_PLATFORM_HIDDENAPI_GREYLIST_METADATA", h.metadata.String())
- }
}
// stubFlagsRule creates the rule to build hiddenapi-stub-flags.txt out of dex jars from stub modules and boot image
@@ -320,6 +315,17 @@
return outputPath
}
+func prebuiltIndexRule(ctx android.SingletonContext) {
+ outputPath := hiddenAPISingletonPaths(ctx).index
+ inputPath := android.PathForSource(ctx, ctx.Config().PrebuiltHiddenApiDir(ctx), "hiddenapi-index.csv")
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cp,
+ Output: outputPath,
+ Input: inputPath,
+ })
+}
+
// flagsRule is a placeholder that simply returns the location of the file, the generation of the
// ninja rules is done in generateHiddenAPIBuildActions.
func flagsRule(ctx android.SingletonContext) android.Path {
@@ -342,34 +348,6 @@
return outputPath
}
-// metadataRule creates a rule to build hiddenapi-unsupported.csv out of the metadata.csv files generated for boot image
-// modules.
-func metadataRule(ctx android.SingletonContext) android.Path {
- var metadataCSV android.Paths
-
- ctx.VisitAllModules(func(module android.Module) {
- if h, ok := module.(hiddenAPIIntf); ok {
- if csv := h.metadataCSV(); csv != nil {
- metadataCSV = append(metadataCSV, csv)
- }
- }
- })
-
- rule := android.NewRuleBuilder(pctx, ctx)
-
- outputPath := hiddenAPISingletonPaths(ctx).metadata
-
- rule.Command().
- BuiltTool("merge_csv").
- Flag("--key_field signature").
- FlagWithOutput("--output=", outputPath).
- Inputs(metadataCSV)
-
- rule.Build("hiddenAPIGreylistMetadataFile", "hiddenapi greylist metadata")
-
- return outputPath
-}
-
// commitChangeForRestat adds a command to a rule that updates outputPath from tempPath if they are different. It
// also marks the rule as restat and marks the tempPath as a temporary file that should not be considered an output of
// the rule.
@@ -387,105 +365,3 @@
Text("fi").
Text(")")
}
-
-type hiddenAPIFlagsProperties struct {
- // name of the file into which the flags will be copied.
- Filename *string
-}
-
-type hiddenAPIFlags struct {
- android.ModuleBase
-
- properties hiddenAPIFlagsProperties
-
- outputFilePath android.OutputPath
-}
-
-func (h *hiddenAPIFlags) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- filename := String(h.properties.Filename)
-
- inputPath := hiddenAPISingletonPaths(ctx).flags
- h.outputFilePath = android.PathForModuleOut(ctx, filename).OutputPath
-
- // This ensures that outputFilePath has the correct name for others to
- // use, as the source file may have a different name.
- ctx.Build(pctx, android.BuildParams{
- Rule: android.Cp,
- Output: h.outputFilePath,
- Input: inputPath,
- })
-}
-
-func (h *hiddenAPIFlags) OutputFiles(tag string) (android.Paths, error) {
- switch tag {
- case "":
- return android.Paths{h.outputFilePath}, nil
- default:
- return nil, fmt.Errorf("unsupported module reference tag %q", tag)
- }
-}
-
-// hiddenapi-flags provides access to the hiddenapi-flags.csv file generated during the build.
-func hiddenAPIFlagsFactory() android.Module {
- module := &hiddenAPIFlags{}
- module.AddProperties(&module.properties)
- android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
- return module
-}
-
-func hiddenAPIIndexSingletonFactory() android.Singleton {
- return &hiddenAPIIndexSingleton{}
-}
-
-type hiddenAPIIndexSingleton struct {
- index android.Path
-}
-
-func (h *hiddenAPIIndexSingleton) GenerateBuildActions(ctx android.SingletonContext) {
- // Don't run any hiddenapi rules if UNSAFE_DISABLE_HIDDENAPI_FLAGS=true
- if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
- return
- }
-
- if ctx.Config().PrebuiltHiddenApiDir(ctx) != "" {
- outputPath := hiddenAPISingletonPaths(ctx).index
- inputPath := android.PathForSource(ctx, ctx.Config().PrebuiltHiddenApiDir(ctx), "hiddenapi-index.csv")
-
- ctx.Build(pctx, android.BuildParams{
- Rule: android.Cp,
- Output: outputPath,
- Input: inputPath,
- })
-
- h.index = outputPath
- return
- }
-
- indexes := android.Paths{}
- ctx.VisitAllModules(func(module android.Module) {
- if h, ok := module.(hiddenAPIIntf); ok {
- if h.indexCSV() != nil {
- indexes = append(indexes, h.indexCSV())
- }
- }
- })
-
- rule := android.NewRuleBuilder(pctx, ctx)
- rule.Command().
- BuiltTool("merge_csv").
- Flag("--key_field signature").
- FlagWithArg("--header=", "signature,file,startline,startcol,endline,endcol,properties").
- FlagWithOutput("--output=", hiddenAPISingletonPaths(ctx).index).
- Inputs(indexes)
- rule.Build("singleton-merged-hiddenapi-index", "Singleton merged Hidden API index")
-
- h.index = hiddenAPISingletonPaths(ctx).index
-}
-
-func (h *hiddenAPIIndexSingleton) MakeVars(ctx android.MakeVarsContext) {
- if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
- return
- }
-
- ctx.Strict("INTERNAL_PLATFORM_HIDDENAPI_INDEX", h.index.String())
-}
diff --git a/java/hiddenapi_singleton_test.go b/java/hiddenapi_singleton_test.go
index 5c449e5..5ea9a5b 100644
--- a/java/hiddenapi_singleton_test.go
+++ b/java/hiddenapi_singleton_test.go
@@ -23,12 +23,6 @@
"github.com/google/blueprint/proptools"
)
-func fixtureSetBootJarsProductVariable(bootJars ...string) android.FixturePreparer {
- return android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
- variables.BootJars = android.CreateTestConfiguredJarList(bootJars)
- })
-}
-
func fixtureSetPrebuiltHiddenApiDirProductVariable(prebuiltHiddenApiDir *string) android.FixturePreparer {
return android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
variables.PrebuiltHiddenApiDir = prebuiltHiddenApiDir
@@ -41,7 +35,7 @@
func TestHiddenAPISingleton(t *testing.T) {
result := android.GroupFixturePreparers(
hiddenApiFixtureFactory,
- fixtureSetBootJarsProductVariable("platform:foo"),
+ FixtureConfigureBootJars("platform:foo"),
).RunTestWithBp(t, `
java_library {
name: "foo",
@@ -56,61 +50,6 @@
android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, want)
}
-func TestHiddenAPIIndexSingleton(t *testing.T) {
- result := android.GroupFixturePreparers(
- hiddenApiFixtureFactory,
- PrepareForTestWithJavaSdkLibraryFiles,
- FixtureWithLastReleaseApis("bar"),
- fixtureSetBootJarsProductVariable("platform:foo", "platform:bar"),
- ).RunTestWithBp(t, `
- java_library {
- name: "foo",
- srcs: ["a.java"],
- compile_dex: true,
-
- hiddenapi_additional_annotations: [
- "foo-hiddenapi-annotations",
- ],
- }
-
- java_library {
- name: "foo-hiddenapi-annotations",
- srcs: ["a.java"],
- compile_dex: true,
- }
-
- java_import {
- name: "foo",
- jars: ["a.jar"],
- compile_dex: true,
- prefer: false,
- }
-
- java_sdk_library {
- name: "bar",
- srcs: ["a.java"],
- compile_dex: true,
- }
- `)
-
- hiddenAPIIndex := result.SingletonForTests("hiddenapi_index")
- indexRule := hiddenAPIIndex.Rule("singleton-merged-hiddenapi-index")
- CheckHiddenAPIRuleInputs(t, `
-.intermediates/bar/android_common/hiddenapi/index.csv
-.intermediates/foo/android_common/hiddenapi/index.csv
-`,
- indexRule)
-
- // Make sure that the foo-hiddenapi-annotations.jar is included in the inputs to the rules that
- // creates the index.csv file.
- foo := result.ModuleForTests("foo", "android_common")
- indexParams := foo.Output("hiddenapi/index.csv")
- CheckHiddenAPIRuleInputs(t, `
-.intermediates/foo-hiddenapi-annotations/android_common/javac/foo-hiddenapi-annotations.jar
-.intermediates/foo/android_common/javac/foo.jar
-`, indexParams)
-}
-
func TestHiddenAPISingletonWithSourceAndPrebuiltPreferredButNoDex(t *testing.T) {
expectedErrorMessage :=
"hiddenapi has determined that the source module \"foo\" should be ignored as it has been" +
@@ -119,7 +58,7 @@
android.GroupFixturePreparers(
hiddenApiFixtureFactory,
- fixtureSetBootJarsProductVariable("platform:foo"),
+ FixtureConfigureBootJars("platform:foo"),
).ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(expectedErrorMessage)).
RunTestWithBp(t, `
java_library {
@@ -139,7 +78,7 @@
func TestHiddenAPISingletonWithPrebuilt(t *testing.T) {
result := android.GroupFixturePreparers(
hiddenApiFixtureFactory,
- fixtureSetBootJarsProductVariable("platform:foo"),
+ FixtureConfigureBootJars("platform:foo"),
).RunTestWithBp(t, `
java_import {
name: "foo",
@@ -157,7 +96,7 @@
func TestHiddenAPISingletonWithPrebuiltUseSource(t *testing.T) {
result := android.GroupFixturePreparers(
hiddenApiFixtureFactory,
- fixtureSetBootJarsProductVariable("platform:foo"),
+ FixtureConfigureBootJars("platform:foo"),
).RunTestWithBp(t, `
java_library {
name: "foo",
@@ -185,7 +124,7 @@
func TestHiddenAPISingletonWithPrebuiltOverrideSource(t *testing.T) {
result := android.GroupFixturePreparers(
hiddenApiFixtureFactory,
- fixtureSetBootJarsProductVariable("platform:foo"),
+ FixtureConfigureBootJars("platform:foo"),
).RunTestWithBp(t, `
java_library {
name: "foo",
@@ -295,7 +234,7 @@
result := android.GroupFixturePreparers(
hiddenApiFixtureFactory,
- fixtureSetBootJarsProductVariable("platform:foo"),
+ FixtureConfigureBootJars("platform:foo"),
fixtureSetPrebuiltHiddenApiDirProductVariable(&prebuiltHiddenApiDir),
).RunTestWithBp(t, `
java_import {
diff --git a/java/java.go b/java/java.go
index fa7c96e..ee4f2eb 100644
--- a/java/java.go
+++ b/java/java.go
@@ -356,7 +356,7 @@
if javaVersion != "" {
return normalizeJavaVersion(ctx, javaVersion)
} else if ctx.Device() {
- return defaultJavaLanguageVersion(ctx, sdkContext.SdkVersion())
+ return defaultJavaLanguageVersion(ctx, sdkContext.SdkVersion(ctx))
} else {
return JAVA_VERSION_9
}
@@ -463,6 +463,9 @@
// would the <x> library if <x> was configured as a boot jar.
j.initHiddenAPI(ctx, j.ConfigurationName())
+ j.sdkVersion = j.SdkVersion(ctx)
+ j.minSdkVersion = j.MinSdkVersion(ctx)
+
apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
if !apexInfo.IsForPlatform() {
j.hideApexVariantFromMake = true
@@ -1130,33 +1133,28 @@
exportAidlIncludeDirs android.Paths
hideApexVariantFromMake bool
+
+ sdkVersion android.SdkSpec
+ minSdkVersion android.SdkSpec
}
-func (j *Import) SdkVersion() android.SdkSpec {
- return android.SdkSpecFrom(String(j.properties.Sdk_version))
-}
-
-func (j *Import) makeSdkVersion() string {
- return j.SdkVersion().Raw
+func (j *Import) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
+ return android.SdkSpecFrom(ctx, String(j.properties.Sdk_version))
}
func (j *Import) SystemModules() string {
return "none"
}
-func (j *Import) MinSdkVersion() android.SdkSpec {
+func (j *Import) MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
if j.properties.Min_sdk_version != nil {
- return android.SdkSpecFrom(*j.properties.Min_sdk_version)
+ return android.SdkSpecFrom(ctx, *j.properties.Min_sdk_version)
}
- return j.SdkVersion()
+ return j.SdkVersion(ctx)
}
-func (j *Import) TargetSdkVersion() android.SdkSpec {
- return j.SdkVersion()
-}
-
-func (j *Import) MinSdkVersionString() string {
- return j.MinSdkVersion().ApiLevel.String()
+func (j *Import) TargetSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
+ return j.SdkVersion(ctx)
}
func (j *Import) Prebuilt() *android.Prebuilt {
@@ -1192,6 +1190,9 @@
}
func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ j.sdkVersion = j.SdkVersion(ctx)
+ j.minSdkVersion = j.MinSdkVersion(ctx)
+
// Initialize the hiddenapi structure.
j.initHiddenAPI(ctx, j.BaseModuleName())
@@ -1230,7 +1231,7 @@
} else if dep, ok := module.(SdkLibraryDependency); ok {
switch tag {
case libTag:
- flags.classpath = append(flags.classpath, dep.SdkHeaderJars(ctx, j.SdkVersion())...)
+ flags.classpath = append(flags.classpath, dep.SdkHeaderJars(ctx, j.SdkVersion(ctx))...)
}
}
@@ -1291,7 +1292,7 @@
j.dexpreopter.uncompressedDex = *j.dexProperties.Uncompress_dex
var dexOutputFile android.OutputPath
- dexOutputFile = j.dexer.compileDex(ctx, flags, j.MinSdkVersion(), outputFile, jarName)
+ dexOutputFile = j.dexer.compileDex(ctx, flags, j.MinSdkVersion(ctx), outputFile, jarName)
if ctx.Failed() {
return
}
@@ -1359,7 +1360,7 @@
// Implements android.ApexModule
func (j *Import) ShouldSupportSdkVersion(ctx android.BaseModuleContext,
sdkVersion android.ApiLevel) error {
- sdkSpec := j.MinSdkVersion()
+ sdkSpec := j.MinSdkVersion(ctx)
if !sdkSpec.Specified() {
return fmt.Errorf("min_sdk_version is not specified")
}
diff --git a/java/java_test.go b/java/java_test.go
index fdf7579..0523458 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -1261,6 +1261,14 @@
if !strings.Contains(*sboxProto.Commands[0].Command, "--baseline mybaseline.xml") {
t.Error("did not use the correct file for baseline")
}
+
+ if !strings.Contains(*sboxProto.Commands[0].Command, "--error_check NewApi") {
+ t.Error("should check NewApi errors")
+ }
+
+ if !strings.Contains(*sboxProto.Commands[0].Command, "--error_check SomeCheck") {
+ t.Error("should combine NewApi errors with SomeCheck errors")
+ }
}
func TestGeneratedSources(t *testing.T) {
diff --git a/java/lint.go b/java/lint.go
index 30843dc..aa308e6 100644
--- a/java/lint.go
+++ b/java/lint.go
@@ -57,24 +57,25 @@
}
type linter struct {
- name string
- manifest android.Path
- mergedManifest android.Path
- srcs android.Paths
- srcJars android.Paths
- resources android.Paths
- classpath android.Paths
- classes android.Path
- extraLintCheckJars android.Paths
- test bool
- library bool
- minSdkVersion string
- targetSdkVersion string
- compileSdkVersion string
- javaLanguageLevel string
- kotlinLanguageLevel string
- outputs lintOutputs
- properties LintProperties
+ name string
+ manifest android.Path
+ mergedManifest android.Path
+ srcs android.Paths
+ srcJars android.Paths
+ resources android.Paths
+ classpath android.Paths
+ classes android.Path
+ extraLintCheckJars android.Paths
+ test bool
+ library bool
+ minSdkVersion string
+ targetSdkVersion string
+ compileSdkVersion string
+ javaLanguageLevel string
+ kotlinLanguageLevel string
+ outputs lintOutputs
+ properties LintProperties
+ extraMainlineLintErrors []string
reports android.Paths
@@ -246,6 +247,7 @@
cmd.FlagWithInput("@",
android.PathForSource(ctx, "build/soong/java/lint_defaults.txt"))
+ cmd.FlagForEachArg("--error_check ", l.extraMainlineLintErrors)
cmd.FlagForEachArg("--disable_check ", l.properties.Lint.Disabled_checks)
cmd.FlagForEachArg("--warning_check ", l.properties.Lint.Warning_checks)
cmd.FlagForEachArg("--error_check ", l.properties.Lint.Error_checks)
@@ -282,6 +284,10 @@
return
}
+ if l.minSdkVersion != l.compileSdkVersion {
+ l.extraMainlineLintErrors = append(l.extraMainlineLintErrors, "NewApi")
+ }
+
extraLintCheckModules := ctx.GetDirectDepsWithTag(extraLintCheckTag)
for _, extraLintCheckModule := range extraLintCheckModules {
if ctx.OtherModuleHasProvider(extraLintCheckModule, JavaInfoProvider) {
diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go
index e292d80..cb8ad68 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -15,6 +15,8 @@
package java
import (
+ "fmt"
+
"android/soong/android"
"android/soong/dexpreopt"
"github.com/google/blueprint"
@@ -57,6 +59,7 @@
type platformBootclasspathModule struct {
android.ModuleBase
+ ClasspathFragmentBase
properties platformBootclasspathProperties
@@ -69,6 +72,15 @@
//
// Currently only for testing.
fragments []android.Module
+
+ // Path to the monolithic hiddenapi-flags.csv file.
+ hiddenAPIFlagsCSV android.OutputPath
+
+ // Path to the monolithic hiddenapi-index.csv file.
+ hiddenAPIIndexCSV android.OutputPath
+
+ // Path to the monolithic hiddenapi-unsupported.csv file.
+ hiddenAPIMetadataCSV android.OutputPath
}
// ApexVariantReference specifies a particular apex variant of a module.
@@ -88,16 +100,45 @@
// platform_bootclasspath.
Fragments []ApexVariantReference
- Hidden_api HiddenAPIAugmentationProperties
+ Hidden_api HiddenAPIFlagFileProperties
}
func platformBootclasspathFactory() android.Module {
m := &platformBootclasspathModule{}
m.AddProperties(&m.properties)
+ // TODO(satayev): split systemserver and apex jars into separate configs.
+ initClasspathFragment(m)
android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon)
return m
}
+var _ android.OutputFileProducer = (*platformBootclasspathModule)(nil)
+
+func (b *platformBootclasspathModule) AndroidMkEntries() (entries []android.AndroidMkEntries) {
+ entries = append(entries, android.AndroidMkEntries{
+ Class: "FAKE",
+ // Need at least one output file in order for this to take effect.
+ OutputFile: android.OptionalPathForPath(b.hiddenAPIFlagsCSV),
+ Include: "$(BUILD_PHONY_PACKAGE)",
+ })
+ entries = append(entries, b.classpathFragmentBase().getAndroidMkEntries()...)
+ return
+}
+
+// Make the hidden API files available from the platform-bootclasspath module.
+func (b *platformBootclasspathModule) OutputFiles(tag string) (android.Paths, error) {
+ switch tag {
+ case "hiddenapi-flags.csv":
+ return android.Paths{b.hiddenAPIFlagsCSV}, nil
+ case "hiddenapi-index.csv":
+ return android.Paths{b.hiddenAPIIndexCSV}, nil
+ case "hiddenapi-metadata.csv":
+ return android.Paths{b.hiddenAPIMetadataCSV}, nil
+ }
+
+ return nil, fmt.Errorf("unknown tag %s", tag)
+}
+
func (b *platformBootclasspathModule) DepsMutator(ctx android.BottomUpMutatorContext) {
if SkipDexpreoptBootJars(ctx) {
return
@@ -169,7 +210,30 @@
// error, unless missing dependencies are allowed. The simplest way to handle that is to add a
// dependency that will not be satisfied and the default behavior will handle it.
if !addedDep {
- ctx.AddFarVariationDependencies(variations, tag, name)
+ // Add dependency on the unprefixed (i.e. source or renamed prebuilt) module which we know does
+ // not exist. The resulting error message will contain useful information about the available
+ // variants.
+ reportMissingVariationDependency(ctx, variations, name)
+
+ // Add dependency on the missing prefixed prebuilt variant too if a module with that name exists
+ // so that information about its available variants will be reported too.
+ if ctx.OtherModuleExists(prebuiltName) {
+ reportMissingVariationDependency(ctx, variations, prebuiltName)
+ }
+ }
+}
+
+// reportMissingVariationDependency intentionally adds a dependency on a missing variation in order
+// to generate an appropriate error message with information about the available variations.
+func reportMissingVariationDependency(ctx android.BottomUpMutatorContext, variations []blueprint.Variation, name string) {
+ modules := ctx.AddFarVariationDependencies(variations, nil, name)
+ if len(modules) != 1 {
+ panic(fmt.Errorf("Internal Error: expected one module, found %d", len(modules)))
+ return
+ }
+ if modules[0] != nil {
+ panic(fmt.Errorf("Internal Error: expected module to be missing but was found: %q", modules[0]))
+ return
}
}
@@ -183,6 +247,8 @@
}
func (b *platformBootclasspathModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ b.classpathFragmentBase().generateAndroidBuildActions(ctx)
+
ctx.VisitDirectDepsIf(isActiveModule, func(module android.Module) {
tag := ctx.OtherModuleDependencyTag(module)
if tag == platformBootclasspathModuleDepTag {
@@ -222,20 +288,97 @@
// generateHiddenAPIBuildActions generates all the hidden API related build rules.
func (b *platformBootclasspathModule) generateHiddenAPIBuildActions(ctx android.ModuleContext, modules []android.Module) {
- moduleSpecificFlagsPaths := android.Paths{}
+ // Save the paths to the monolithic files for retrieval via OutputFiles().
+ b.hiddenAPIFlagsCSV = hiddenAPISingletonPaths(ctx).flags
+ b.hiddenAPIIndexCSV = hiddenAPISingletonPaths(ctx).index
+ b.hiddenAPIMetadataCSV = hiddenAPISingletonPaths(ctx).metadata
+
+ // Don't run any hiddenapi rules if UNSAFE_DISABLE_HIDDENAPI_FLAGS=true. This is a performance
+ // optimization that can be used to reduce the incremental build time but as its name suggests it
+ // can be unsafe to use, e.g. when the changes affect anything that goes on the bootclasspath.
+ if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
+ paths := android.OutputPaths{b.hiddenAPIFlagsCSV, b.hiddenAPIIndexCSV, b.hiddenAPIMetadataCSV}
+ for _, path := range paths {
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Touch,
+ Output: path,
+ })
+ }
+ return
+ }
+
+ hiddenAPISupportingModules := []hiddenAPISupportingModule{}
for _, module := range modules {
- if h, ok := module.(hiddenAPIIntf); ok {
- if csv := h.flagsCSV(); csv != nil {
- moduleSpecificFlagsPaths = append(moduleSpecificFlagsPaths, csv)
+ if h, ok := module.(hiddenAPISupportingModule); ok {
+ if h.bootDexJar() == nil {
+ ctx.ModuleErrorf("module %s does not provide a bootDexJar file", module)
}
+ if h.flagsCSV() == nil {
+ ctx.ModuleErrorf("module %s does not provide a flagsCSV file", module)
+ }
+ if h.indexCSV() == nil {
+ ctx.ModuleErrorf("module %s does not provide an indexCSV file", module)
+ }
+ if h.metadataCSV() == nil {
+ ctx.ModuleErrorf("module %s does not provide a metadataCSV file", module)
+ }
+
+ if ctx.Failed() {
+ continue
+ }
+
+ hiddenAPISupportingModules = append(hiddenAPISupportingModules, h)
} else {
- ctx.ModuleErrorf("module %s of type %s does not implement hiddenAPIIntf", module, ctx.OtherModuleType(module))
+ ctx.ModuleErrorf("module %s of type %s does not support hidden API processing", module, ctx.OtherModuleType(module))
}
}
- augmentationInfo := b.properties.Hidden_api.hiddenAPIAugmentationInfo(ctx)
+ moduleSpecificFlagsPaths := android.Paths{}
+ for _, module := range hiddenAPISupportingModules {
+ moduleSpecificFlagsPaths = append(moduleSpecificFlagsPaths, module.flagsCSV())
+ }
+
+ augmentationInfo := b.properties.Hidden_api.hiddenAPIFlagFileInfo(ctx)
outputPath := hiddenAPISingletonPaths(ctx).flags
baseFlagsPath := hiddenAPISingletonPaths(ctx).stubFlags
ruleToGenerateHiddenApiFlags(ctx, outputPath, baseFlagsPath, moduleSpecificFlagsPaths, augmentationInfo)
+
+ b.generateHiddenAPIIndexRules(ctx, hiddenAPISupportingModules)
+ b.generatedHiddenAPIMetadataRules(ctx, hiddenAPISupportingModules)
+}
+
+func (b *platformBootclasspathModule) generateHiddenAPIIndexRules(ctx android.ModuleContext, modules []hiddenAPISupportingModule) {
+ indexes := android.Paths{}
+ for _, module := range modules {
+ indexes = append(indexes, module.indexCSV())
+ }
+
+ rule := android.NewRuleBuilder(pctx, ctx)
+ rule.Command().
+ BuiltTool("merge_csv").
+ Flag("--key_field signature").
+ FlagWithArg("--header=", "signature,file,startline,startcol,endline,endcol,properties").
+ FlagWithOutput("--output=", hiddenAPISingletonPaths(ctx).index).
+ Inputs(indexes)
+ rule.Build("platform-bootclasspath-monolithic-hiddenapi-index", "monolithic hidden API index")
+}
+
+func (b *platformBootclasspathModule) generatedHiddenAPIMetadataRules(ctx android.ModuleContext, modules []hiddenAPISupportingModule) {
+ metadataCSVFiles := android.Paths{}
+ for _, module := range modules {
+ metadataCSVFiles = append(metadataCSVFiles, module.metadataCSV())
+ }
+
+ rule := android.NewRuleBuilder(pctx, ctx)
+
+ outputPath := hiddenAPISingletonPaths(ctx).metadata
+
+ rule.Command().
+ BuiltTool("merge_csv").
+ Flag("--key_field signature").
+ FlagWithOutput("--output=", outputPath).
+ Inputs(metadataCSVFiles)
+
+ rule.Build("platform-bootclasspath-monolithic-hiddenapi-metadata", "monolithic hidden API metadata")
}
diff --git a/java/platform_bootclasspath_test.go b/java/platform_bootclasspath_test.go
index ebbe3a5..e51b049 100644
--- a/java/platform_bootclasspath_test.go
+++ b/java/platform_bootclasspath_test.go
@@ -31,7 +31,7 @@
func TestPlatformBootclasspath(t *testing.T) {
preparer := android.GroupFixturePreparers(
prepareForTestWithPlatformBootclasspath,
- dexpreopt.FixtureSetBootJars("platform:foo", "platform:bar"),
+ FixtureConfigureBootJars("platform:foo", "platform:bar"),
android.FixtureWithRootAndroidBp(`
platform_bootclasspath {
name: "platform-bootclasspath",
@@ -131,3 +131,186 @@
})
})
}
+
+func TestPlatformBootclasspathVariant(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForTestWithPlatformBootclasspath,
+ android.FixtureWithRootAndroidBp(`
+ platform_bootclasspath {
+ name: "platform-bootclasspath",
+ }
+ `),
+ ).RunTest(t)
+
+ variants := result.ModuleVariantsForTests("platform-bootclasspath")
+ android.AssertIntEquals(t, "expect 1 variant", 1, len(variants))
+}
+
+func TestPlatformBootclasspath_ClasspathFragmentPaths(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForTestWithPlatformBootclasspath,
+ android.FixtureWithRootAndroidBp(`
+ platform_bootclasspath {
+ name: "platform-bootclasspath",
+ }
+ `),
+ ).RunTest(t)
+
+ p := result.Module("platform-bootclasspath", "android_common").(*platformBootclasspathModule)
+ android.AssertStringEquals(t, "output filepath", p.Name()+".pb", p.ClasspathFragmentBase.outputFilepath.Base())
+ android.AssertPathRelativeToTopEquals(t, "install filepath", "out/soong/target/product/test_device/system/etc/classpaths", p.ClasspathFragmentBase.installDirPath)
+}
+
+func TestPlatformBootclasspathModule_AndroidMkEntries(t *testing.T) {
+ preparer := android.GroupFixturePreparers(
+ prepareForTestWithPlatformBootclasspath,
+ android.FixtureWithRootAndroidBp(`
+ platform_bootclasspath {
+ name: "platform-bootclasspath",
+ }
+ `),
+ )
+
+ t.Run("AndroidMkEntries", func(t *testing.T) {
+ result := preparer.RunTest(t)
+
+ p := result.Module("platform-bootclasspath", "android_common").(*platformBootclasspathModule)
+
+ entries := android.AndroidMkEntriesForTest(t, result.TestContext, p)
+ android.AssertIntEquals(t, "AndroidMkEntries count", 2, len(entries))
+ })
+
+ t.Run("hiddenapi-flags-entry", func(t *testing.T) {
+ result := preparer.RunTest(t)
+
+ p := result.Module("platform-bootclasspath", "android_common").(*platformBootclasspathModule)
+
+ entries := android.AndroidMkEntriesForTest(t, result.TestContext, p)
+ got := entries[0].OutputFile
+ android.AssertBoolEquals(t, "valid output path", true, got.Valid())
+ android.AssertSame(t, "output filepath", p.hiddenAPIFlagsCSV, got.Path())
+ })
+
+ t.Run("classpath-fragment-entry", func(t *testing.T) {
+ result := preparer.RunTest(t)
+
+ want := map[string][]string{
+ "LOCAL_MODULE": {"platform-bootclasspath"},
+ "LOCAL_MODULE_CLASS": {"ETC"},
+ "LOCAL_INSTALLED_MODULE_STEM": {"platform-bootclasspath.pb"},
+ // Output and Install paths are tested separately in TestPlatformBootclasspath_ClasspathFragmentPaths
+ }
+
+ p := result.Module("platform-bootclasspath", "android_common").(*platformBootclasspathModule)
+
+ entries := android.AndroidMkEntriesForTest(t, result.TestContext, p)
+ got := entries[1]
+ for k, expectedValue := range want {
+ if value, ok := got.EntryMap[k]; ok {
+ android.AssertDeepEquals(t, k, expectedValue, value)
+ } else {
+ t.Errorf("No %s defined, saw %q", k, got.EntryMap)
+ }
+ }
+ })
+}
+
+func TestPlatformBootclasspath_Dist(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForTestWithPlatformBootclasspath,
+ FixtureConfigureBootJars("platform:foo", "platform:bar"),
+ android.PrepareForTestWithAndroidMk,
+ android.FixtureWithRootAndroidBp(`
+ platform_bootclasspath {
+ name: "platform-bootclasspath",
+ dists: [
+ {
+ targets: ["droidcore"],
+ tag: "hiddenapi-flags.csv",
+ },
+ ],
+ }
+
+ java_library {
+ name: "bar",
+ srcs: ["a.java"],
+ system_modules: "none",
+ sdk_version: "none",
+ compile_dex: true,
+ }
+
+ java_library {
+ name: "foo",
+ srcs: ["a.java"],
+ system_modules: "none",
+ sdk_version: "none",
+ compile_dex: true,
+ }
+ `),
+ ).RunTest(t)
+
+ platformBootclasspath := result.Module("platform-bootclasspath", "android_common").(*platformBootclasspathModule)
+ entries := android.AndroidMkEntriesForTest(t, result.TestContext, platformBootclasspath)
+ goals := entries[0].GetDistForGoals(platformBootclasspath)
+ android.AssertStringEquals(t, "platform dist goals phony", ".PHONY: droidcore\n", goals[0])
+ android.AssertStringEquals(t, "platform dist goals call", "$(call dist-for-goals,droidcore,out/soong/hiddenapi/hiddenapi-flags.csv:hiddenapi-flags.csv)\n", android.StringRelativeToTop(result.Config, goals[1]))
+}
+
+func TestPlatformBootclasspath_HiddenAPIMonolithicFiles(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ hiddenApiFixtureFactory,
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithLastReleaseApis("bar"),
+ FixtureConfigureBootJars("platform:foo", "platform:bar"),
+ ).RunTestWithBp(t, `
+ java_library {
+ name: "foo",
+ srcs: ["a.java"],
+ compile_dex: true,
+
+ hiddenapi_additional_annotations: [
+ "foo-hiddenapi-annotations",
+ ],
+ }
+
+ java_library {
+ name: "foo-hiddenapi-annotations",
+ srcs: ["a.java"],
+ compile_dex: true,
+ }
+
+ java_import {
+ name: "foo",
+ jars: ["a.jar"],
+ compile_dex: true,
+ prefer: false,
+ }
+
+ java_sdk_library {
+ name: "bar",
+ srcs: ["a.java"],
+ compile_dex: true,
+ }
+
+ platform_bootclasspath {
+ name: "myplatform-bootclasspath",
+ }
+ `)
+
+ platformBootclasspath := result.ModuleForTests("myplatform-bootclasspath", "android_common")
+ indexRule := platformBootclasspath.Rule("platform-bootclasspath-monolithic-hiddenapi-index")
+ CheckHiddenAPIRuleInputs(t, `
+.intermediates/bar/android_common/hiddenapi/index.csv
+.intermediates/foo/android_common/hiddenapi/index.csv
+`,
+ indexRule)
+
+ // Make sure that the foo-hiddenapi-annotations.jar is included in the inputs to the rules that
+ // creates the index.csv file.
+ foo := result.ModuleForTests("foo", "android_common")
+ indexParams := foo.Output("hiddenapi/index.csv")
+ CheckHiddenAPIRuleInputs(t, `
+.intermediates/foo-hiddenapi-annotations/android_common/javac/foo-hiddenapi-annotations.jar
+.intermediates/foo/android_common/javac/foo.jar
+`, indexParams)
+}
diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go
index 8a442b5..c33e6c2 100644
--- a/java/prebuilt_apis.go
+++ b/java/prebuilt_apis.go
@@ -253,14 +253,8 @@
files := getPrebuiltFilesInSubdir(mctx, nextApiDir, "api/*incompatibilities.txt")
for _, f := range files {
localPath := strings.TrimPrefix(f, mydir)
- module, _, scope := parseApiFilePath(mctx, localPath)
-
- // Figure out which module is referenced by this file. Special case for "android".
- referencedModule := strings.TrimSuffix(module, "incompatibilities")
- referencedModule = strings.TrimSuffix(referencedModule, "-")
- if referencedModule == "" {
- referencedModule = "android"
- }
+ filename, _, scope := parseApiFilePath(mctx, localPath)
+ referencedModule := strings.TrimSuffix(filename, "-incompatibilities")
createApiModule(mctx, apiModuleName(referencedModule+"-incompatibilities", scope, "latest"), localPath)
diff --git a/java/rro.go b/java/rro.go
index 4ae0014..2e58c04 100644
--- a/java/rro.go
+++ b/java/rro.go
@@ -141,23 +141,23 @@
ctx.InstallFile(r.installDir, r.outputFile.Base(), r.outputFile)
}
-func (r *RuntimeResourceOverlay) SdkVersion() android.SdkSpec {
- return android.SdkSpecFrom(String(r.properties.Sdk_version))
+func (r *RuntimeResourceOverlay) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
+ return android.SdkSpecFrom(ctx, String(r.properties.Sdk_version))
}
func (r *RuntimeResourceOverlay) SystemModules() string {
return ""
}
-func (r *RuntimeResourceOverlay) MinSdkVersion() android.SdkSpec {
+func (r *RuntimeResourceOverlay) MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
if r.properties.Min_sdk_version != nil {
- return android.SdkSpecFrom(*r.properties.Min_sdk_version)
+ return android.SdkSpecFrom(ctx, *r.properties.Min_sdk_version)
}
- return r.SdkVersion()
+ return r.SdkVersion(ctx)
}
-func (r *RuntimeResourceOverlay) TargetSdkVersion() android.SdkSpec {
- return r.SdkVersion()
+func (r *RuntimeResourceOverlay) TargetSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
+ return r.SdkVersion(ctx)
}
func (r *RuntimeResourceOverlay) Certificate() Certificate {
diff --git a/java/sdk.go b/java/sdk.go
index f324b76..d6e20a7 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -61,7 +61,7 @@
}
func decodeSdkDep(ctx android.EarlyModuleContext, sdkContext android.SdkContext) sdkDep {
- sdkVersion := sdkContext.SdkVersion()
+ sdkVersion := sdkContext.SdkVersion(ctx)
if !sdkVersion.Valid() {
ctx.PropertyErrorf("sdk_version", "invalid version %q", sdkVersion.Raw)
return sdkDep{}
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 96135c3..e5ee397 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -1512,7 +1512,7 @@
// force override sdk_version to module_current so that the closest possible API
// surface could be found in selectHeaderJarsForSdkVersion
if module.defaultsToStubs() && !sdkVersion.Specified() {
- sdkVersion = android.SdkSpecFrom("module_current")
+ sdkVersion = android.SdkSpecFrom(ctx, "module_current")
}
// Only provide access to the implementation library if it is actually built.
diff --git a/java/testing.go b/java/testing.go
index 6ebc747..aee0710 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -178,6 +178,43 @@
return fs
}
+// FixtureConfigureBootJars configures the boot jars in both the dexpreopt.GlobalConfig and
+// Config.productVariables structs. As a side effect that enables dexpreopt.
+func FixtureConfigureBootJars(bootJars ...string) android.FixturePreparer {
+ artBootJars := []string{}
+ for _, j := range bootJars {
+ artApex := false
+ for _, artApexName := range artApexNames {
+ if strings.HasPrefix(j, artApexName+":") {
+ artApex = true
+ break
+ }
+ }
+ if artApex {
+ artBootJars = append(artBootJars, j)
+ }
+ }
+ return android.GroupFixturePreparers(
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.BootJars = android.CreateTestConfiguredJarList(bootJars)
+ }),
+ dexpreopt.FixtureSetBootJars(bootJars...),
+ dexpreopt.FixtureSetArtBootJars(artBootJars...),
+ )
+}
+
+// FixtureConfigureUpdatableBootJars configures the updatable boot jars in both the
+// dexpreopt.GlobalConfig and Config.productVariables structs. As a side effect that enables
+// dexpreopt.
+func FixtureConfigureUpdatableBootJars(bootJars ...string) android.FixturePreparer {
+ return android.GroupFixturePreparers(
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.UpdatableBootJars = android.CreateTestConfiguredJarList(bootJars)
+ }),
+ dexpreopt.FixtureSetUpdatableBootJars(bootJars...),
+ )
+}
+
// registerRequiredBuildComponentsForTest registers the build components used by
// PrepareForTestWithJavaDefaultModules.
//
diff --git a/linkerconfig/linkerconfig.go b/linkerconfig/linkerconfig.go
index da80a47..241cac6 100644
--- a/linkerconfig/linkerconfig.go
+++ b/linkerconfig/linkerconfig.go
@@ -17,6 +17,7 @@
import (
"android/soong/android"
"android/soong/etc"
+ "fmt"
"github.com/google/blueprint/proptools"
)
@@ -68,6 +69,17 @@
return l.outputFilePath
}
+var _ android.OutputFileProducer = (*linkerConfig)(nil)
+
+func (l *linkerConfig) OutputFiles(tag string) (android.Paths, error) {
+ switch tag {
+ case "":
+ return android.Paths{l.outputFilePath}, nil
+ default:
+ return nil, fmt.Errorf("unsupported module reference tag %q", tag)
+ }
+}
+
func (l *linkerConfig) GenerateAndroidBuildActions(ctx android.ModuleContext) {
inputFile := android.PathForModuleSrc(ctx, android.String(l.properties.Src))
l.outputFilePath = android.PathForModuleOut(ctx, "linker.config.pb").OutputPath
@@ -81,9 +93,10 @@
linkerConfigRule.Build("conv_linker_config",
"Generate linker config protobuf "+l.outputFilePath.String())
- if proptools.BoolDefault(l.properties.Installable, true) {
- ctx.InstallFile(l.installDirPath, l.outputFilePath.Base(), l.outputFilePath)
+ if !proptools.BoolDefault(l.properties.Installable, true) {
+ l.SkipInstall()
}
+ ctx.InstallFile(l.installDirPath, l.outputFilePath.Base(), l.outputFilePath)
}
// linker_config generates protobuf file from json file. This protobuf file will be used from
diff --git a/rust/Android.bp b/rust/Android.bp
index a29c474..a6c4e07 100644
--- a/rust/Android.bp
+++ b/rust/Android.bp
@@ -14,6 +14,7 @@
],
srcs: [
"androidmk.go",
+ "benchmark.go",
"binary.go",
"bindgen.go",
"builder.go",
@@ -35,6 +36,7 @@
"testing.go",
],
testSrcs: [
+ "benchmark_test.go",
"binary_test.go",
"bindgen_test.go",
"builder_test.go",
diff --git a/rust/androidmk.go b/rust/androidmk.go
index dea32a3..5f89d73 100644
--- a/rust/androidmk.go
+++ b/rust/androidmk.go
@@ -60,6 +60,10 @@
entries.AddStrings("LOCAL_SHARED_LIBRARIES", mod.Properties.AndroidMkSharedLibs...)
entries.AddStrings("LOCAL_STATIC_LIBRARIES", mod.Properties.AndroidMkStaticLibs...)
entries.AddStrings("LOCAL_SOONG_LINK_TYPE", mod.makeLinkType)
+ if mod.UseVndk() {
+ entries.SetBool("LOCAL_USE_VNDK", true)
+ }
+
},
},
}
@@ -75,6 +79,7 @@
mod.SubAndroidMk(&ret, mod.sanitize)
}
+ ret.SubName += mod.Properties.RustSubName
ret.SubName += mod.Properties.SubName
return []android.AndroidMkEntries{ret}
@@ -107,6 +112,20 @@
cc.AndroidMkWriteTestData(test.data, ret)
}
+func (benchmark *benchmarkDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkEntries) {
+ benchmark.binaryDecorator.AndroidMk(ctx, ret)
+ ret.Class = "NATIVE_TESTS"
+ ret.ExtraEntries = append(ret.ExtraEntries,
+ func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+ entries.AddCompatibilityTestSuites(benchmark.Properties.Test_suites...)
+ if benchmark.testConfig != nil {
+ entries.SetString("LOCAL_FULL_TEST_CONFIG", benchmark.testConfig.String())
+ }
+ entries.SetBool("LOCAL_NATIVE_BENCHMARK", true)
+ entries.SetBoolIfTrue("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", !BoolDefault(benchmark.Properties.Auto_gen_config, true))
+ })
+}
+
func (library *libraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkEntries) {
ctx.SubAndroidMk(ret, library.baseCompiler)
diff --git a/rust/benchmark.go b/rust/benchmark.go
new file mode 100644
index 0000000..b89f5cd
--- /dev/null
+++ b/rust/benchmark.go
@@ -0,0 +1,129 @@
+// Copyright 2020 The Android Open Source Project
+//
+// 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 rust
+
+import (
+ "android/soong/android"
+ "android/soong/tradefed"
+)
+
+type BenchmarkProperties struct {
+ // Disables the creation of a test-specific directory when used with
+ // relative_install_path. Useful if several tests need to be in the same
+ // directory, but test_per_src doesn't work.
+ No_named_install_directory *bool
+
+ // the name of the test configuration (for example "AndroidBenchmark.xml") that should be
+ // installed with the module.
+ Test_config *string `android:"path,arch_variant"`
+
+ // the name of the test configuration template (for example "AndroidBenchmarkTemplate.xml") that
+ // should be installed with the module.
+ Test_config_template *string `android:"path,arch_variant"`
+
+ // list of compatibility suites (for example "cts", "vts") that the module should be
+ // installed into.
+ Test_suites []string `android:"arch_variant"`
+
+ // Flag to indicate whether or not to create test config automatically. If AndroidTest.xml
+ // doesn't exist next to the Android.bp, this attribute doesn't need to be set to true
+ // explicitly.
+ Auto_gen_config *bool
+}
+
+type benchmarkDecorator struct {
+ *binaryDecorator
+ Properties BenchmarkProperties
+ testConfig android.Path
+}
+
+func NewRustBenchmark(hod android.HostOrDeviceSupported) (*Module, *benchmarkDecorator) {
+ // Build both 32 and 64 targets for device benchmarks.
+ // Cannot build both for host benchmarks yet if the benchmark depends on
+ // something like proc-macro2 that cannot be built for both.
+ multilib := android.MultilibBoth
+ if hod != android.DeviceSupported && hod != android.HostAndDeviceSupported {
+ multilib = android.MultilibFirst
+ }
+ module := newModule(hod, multilib)
+
+ benchmark := &benchmarkDecorator{
+ binaryDecorator: &binaryDecorator{
+ baseCompiler: NewBaseCompiler("nativebench", "nativebench64", InstallInData),
+ },
+ }
+
+ module.compiler = benchmark
+ module.AddProperties(&benchmark.Properties)
+ return module, benchmark
+}
+
+func init() {
+ android.RegisterModuleType("rust_benchmark", RustBenchmarkFactory)
+ android.RegisterModuleType("rust_benchmark_host", RustBenchmarkHostFactory)
+}
+
+func RustBenchmarkFactory() android.Module {
+ module, _ := NewRustBenchmark(android.HostAndDeviceSupported)
+ return module.Init()
+}
+
+func RustBenchmarkHostFactory() android.Module {
+ module, _ := NewRustBenchmark(android.HostSupported)
+ return module.Init()
+}
+
+func (benchmark *benchmarkDecorator) autoDep(ctx android.BottomUpMutatorContext) autoDep {
+ return rlibAutoDep
+}
+
+func (benchmark *benchmarkDecorator) stdLinkage(ctx *depsContext) RustLinkage {
+ return RlibLinkage
+}
+
+func (benchmark *benchmarkDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags {
+ flags = benchmark.binaryDecorator.compilerFlags(ctx, flags)
+ return flags
+}
+
+func (benchmark *benchmarkDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps {
+ deps = benchmark.binaryDecorator.compilerDeps(ctx, deps)
+
+ deps.Rustlibs = append(deps.Rustlibs, "libcriterion")
+
+ return deps
+}
+
+func (benchmark *benchmarkDecorator) compilerProps() []interface{} {
+ return append(benchmark.binaryDecorator.compilerProps(), &benchmark.Properties)
+}
+
+func (benchmark *benchmarkDecorator) install(ctx ModuleContext) {
+ benchmark.testConfig = tradefed.AutoGenRustBenchmarkConfig(ctx,
+ benchmark.Properties.Test_config,
+ benchmark.Properties.Test_config_template,
+ benchmark.Properties.Test_suites,
+ nil,
+ benchmark.Properties.Auto_gen_config)
+
+ // default relative install path is module name
+ if !Bool(benchmark.Properties.No_named_install_directory) {
+ benchmark.baseCompiler.relative = ctx.ModuleName()
+ } else if String(benchmark.baseCompiler.Properties.Relative_install_path) == "" {
+ ctx.PropertyErrorf("no_named_install_directory", "Module install directory may only be disabled if relative_install_path is set")
+ }
+
+ benchmark.binaryDecorator.install(ctx)
+}
diff --git a/rust/benchmark_test.go b/rust/benchmark_test.go
new file mode 100644
index 0000000..734dda7
--- /dev/null
+++ b/rust/benchmark_test.go
@@ -0,0 +1,54 @@
+// Copyright 2021 The Android Open Source Project
+//
+// 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 rust
+
+import (
+ "strings"
+ "testing"
+
+ "android/soong/android"
+)
+
+func TestRustBenchmark(t *testing.T) {
+ ctx := testRust(t, `
+ rust_benchmark_host {
+ name: "my_bench",
+ srcs: ["foo.rs"],
+ }`)
+
+ testingModule := ctx.ModuleForTests("my_bench", "linux_glibc_x86_64")
+ expectedOut := "my_bench/linux_glibc_x86_64/my_bench"
+ outPath := testingModule.Output("my_bench").Output.String()
+ if !strings.Contains(outPath, expectedOut) {
+ t.Errorf("wrong output path: %v; expected: %v", outPath, expectedOut)
+ }
+}
+
+func TestRustBenchmarkLinkage(t *testing.T) {
+ ctx := testRust(t, `
+ rust_benchmark {
+ name: "my_bench",
+ srcs: ["foo.rs"],
+ }`)
+
+ testingModule := ctx.ModuleForTests("my_bench", "android_arm64_armv8-a").Module().(*Module)
+
+ if !android.InList("libcriterion.rlib-std", testingModule.Properties.AndroidMkRlibs) {
+ t.Errorf("rlib-std variant for libcriterion not detected as a rustlib-defined rlib dependency for device rust_benchmark module")
+ }
+ if !android.InList("libstd", testingModule.Properties.AndroidMkRlibs) {
+ t.Errorf("Device rust_benchmark module 'my_bench' does not link libstd as an rlib")
+ }
+}
diff --git a/rust/builder.go b/rust/builder.go
index 197c703..208b734 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -21,7 +21,6 @@
"github.com/google/blueprint"
"android/soong/android"
- "android/soong/bloaty"
"android/soong/rust/config"
)
@@ -254,8 +253,6 @@
implicits = append(implicits, clippyFile)
}
- bloaty.MeasureSizeForPath(ctx, outputFile)
-
ctx.Build(pctx, android.BuildParams{
Rule: rustc,
Description: "rustc " + main.Rel(),
diff --git a/rust/compiler.go b/rust/compiler.go
index aaa1924..bc034d7 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -303,7 +303,6 @@
if ctx.Target().Os == android.BuildOs {
stdlib = stdlib + "_" + ctx.toolchain().RustTriple()
}
-
deps.Stdlibs = append(deps.Stdlibs, stdlib)
}
}
@@ -344,6 +343,10 @@
if !ctx.Host() && ctx.Config().HasMultilibConflict(ctx.Arch().ArchType) {
dir = filepath.Join(dir, ctx.Arch().ArchType.String())
}
+
+ if compiler.location == InstallInData && ctx.RustModule().UseVndk() {
+ dir = filepath.Join(dir, "vendor")
+ }
return android.PathForModuleInstall(ctx, dir, compiler.subDir,
compiler.relativeInstallPath(), compiler.relative)
}
diff --git a/rust/fuzz.go b/rust/fuzz.go
index 6035e68..d699971 100644
--- a/rust/fuzz.go
+++ b/rust/fuzz.go
@@ -70,10 +70,9 @@
}
func (fuzzer *fuzzDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps {
- deps.StaticLibs = append(deps.StaticLibs,
- config.LibFuzzerRuntimeLibrary(ctx.toolchain()))
- deps.SharedLibs = append(deps.SharedLibs,
- config.LibclangRuntimeLibrary(ctx.toolchain(), "asan"))
+ if libFuzzerRuntimeLibrary := config.LibFuzzerRuntimeLibrary(ctx.toolchain()); libFuzzerRuntimeLibrary != "" {
+ deps.StaticLibs = append(deps.StaticLibs, libFuzzerRuntimeLibrary)
+ }
deps.SharedLibs = append(deps.SharedLibs, "libc++")
deps.Rlibs = append(deps.Rlibs, "liblibfuzzer_sys")
diff --git a/rust/fuzz_test.go b/rust/fuzz_test.go
index f93ccc7..2524f91 100644
--- a/rust/fuzz_test.go
+++ b/rust/fuzz_test.go
@@ -37,9 +37,6 @@
// Check that appropriate dependencies are added and that the rustlib linkage is correct.
fuzz_libtest_mod := ctx.ModuleForTests("fuzz_libtest", "android_arm64_armv8-a_fuzzer").Module().(*Module)
- if !android.InList("libclang_rt.asan-aarch64-android", fuzz_libtest_mod.Properties.AndroidMkSharedLibs) {
- t.Errorf("libclang_rt.asan-aarch64-android shared library dependency missing for rust_fuzz module.")
- }
if !android.InList("liblibfuzzer_sys.rlib-std", fuzz_libtest_mod.Properties.AndroidMkRlibs) {
t.Errorf("liblibfuzzer_sys rlib library dependency missing for rust_fuzz module. %#v", fuzz_libtest_mod.Properties.AndroidMkRlibs)
}
@@ -49,18 +46,18 @@
// Check that compiler flags are set appropriately .
fuzz_libtest := ctx.ModuleForTests("fuzz_libtest", "android_arm64_armv8-a_fuzzer").Output("fuzz_libtest")
- if !strings.Contains(fuzz_libtest.Args["rustcFlags"], "-Z sanitizer=address") ||
+ if !strings.Contains(fuzz_libtest.Args["rustcFlags"], "-Z sanitizer=hwaddress") ||
!strings.Contains(fuzz_libtest.Args["rustcFlags"], "-C passes='sancov'") ||
!strings.Contains(fuzz_libtest.Args["rustcFlags"], "--cfg fuzzing") {
- t.Errorf("rust_fuzz module does not contain the expected flags (sancov, cfg fuzzing, address sanitizer).")
+ t.Errorf("rust_fuzz module does not contain the expected flags (sancov, cfg fuzzing, hwaddress sanitizer).")
}
// Check that dependencies have 'fuzzer' variants produced for them as well.
libtest_fuzzer := ctx.ModuleForTests("libtest_fuzzing", "android_arm64_armv8-a_rlib_rlib-std_fuzzer").Output("libtest_fuzzing.rlib")
- if !strings.Contains(libtest_fuzzer.Args["rustcFlags"], "-Z sanitizer=address") ||
+ if !strings.Contains(libtest_fuzzer.Args["rustcFlags"], "-Z sanitizer=hwaddress") ||
!strings.Contains(libtest_fuzzer.Args["rustcFlags"], "-C passes='sancov'") ||
!strings.Contains(libtest_fuzzer.Args["rustcFlags"], "--cfg fuzzing") {
- t.Errorf("rust_fuzz dependent library does not contain the expected flags (sancov, cfg fuzzing, address sanitizer).")
+ t.Errorf("rust_fuzz dependent library does not contain the expected flags (sancov, cfg fuzzing, hwaddress sanitizer).")
}
}
diff --git a/rust/image.go b/rust/image.go
index 628aca3..900842e 100644
--- a/rust/image.go
+++ b/rust/image.go
@@ -23,6 +23,68 @@
var _ android.ImageInterface = (*Module)(nil)
+var _ cc.ImageMutatableModule = (*Module)(nil)
+
+func (mod *Module) VendorAvailable() bool {
+ return Bool(mod.VendorProperties.Vendor_available)
+}
+
+func (mod *Module) OdmAvailable() bool {
+ return Bool(mod.VendorProperties.Odm_available)
+}
+
+func (mod *Module) ProductAvailable() bool {
+ return false
+}
+
+func (mod *Module) RamdiskAvailable() bool {
+ return false
+}
+
+func (mod *Module) VendorRamdiskAvailable() bool {
+ return Bool(mod.Properties.Vendor_ramdisk_available)
+}
+
+func (mod *Module) AndroidModuleBase() *android.ModuleBase {
+ return &mod.ModuleBase
+}
+
+func (mod *Module) RecoveryAvailable() bool {
+ return false
+}
+
+func (mod *Module) ExtraVariants() []string {
+ return mod.Properties.ExtraVariants
+}
+
+func (mod *Module) AppendExtraVariant(extraVariant string) {
+ mod.Properties.ExtraVariants = append(mod.Properties.ExtraVariants, extraVariant)
+}
+
+func (mod *Module) SetRamdiskVariantNeeded(b bool) {
+ if b {
+ panic("Setting ramdisk variant needed for Rust module is unsupported: " + mod.BaseModuleName())
+ }
+}
+
+func (mod *Module) SetVendorRamdiskVariantNeeded(b bool) {
+ mod.Properties.VendorRamdiskVariantNeeded = b
+}
+
+func (mod *Module) SetRecoveryVariantNeeded(b bool) {
+ if b {
+ panic("Setting recovery variant needed for Rust module is unsupported: " + mod.BaseModuleName())
+ }
+}
+
+func (mod *Module) SetCoreVariantNeeded(b bool) {
+ mod.Properties.CoreVariantNeeded = b
+}
+
+func (mod *Module) SnapshotVersion(mctx android.BaseModuleContext) string {
+ panic("Rust modules do not support snapshotting: " + mod.BaseModuleName())
+}
+
func (mod *Module) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
return mod.Properties.VendorRamdiskVariantNeeded
}
@@ -35,6 +97,10 @@
return mod.InRamdisk()
}
+func (mod *Module) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+ return false
+}
+
func (mod *Module) RecoveryVariantNeeded(android.BaseModuleContext) bool {
return mod.InRecovery()
}
@@ -43,6 +109,29 @@
return mod.Properties.ExtraVariants
}
+func (mod *Module) IsSnapshotPrebuilt() bool {
+ // Rust does not support prebuilts in its snapshots
+ return false
+}
+
+func (ctx *moduleContext) SocSpecific() bool {
+ // Additionally check if this module is inVendor() that means it is a "vendor" variant of a
+ // module. As well as SoC specific modules, vendor variants must be installed to /vendor
+ // unless they have "odm_available: true".
+ return ctx.ModuleContext.SocSpecific() || (ctx.RustModule().InVendor() && !ctx.RustModule().VendorVariantToOdm())
+}
+
+func (ctx *moduleContext) DeviceSpecific() bool {
+ // Some vendor variants want to be installed to /odm by setting "odm_available: true".
+ return ctx.ModuleContext.DeviceSpecific() || (ctx.RustModule().InVendor() && ctx.RustModule().VendorVariantToOdm())
+}
+
+// Returns true when this module creates a vendor variant and wants to install the vendor variant
+// to the odm partition.
+func (c *Module) VendorVariantToOdm() bool {
+ return Bool(c.VendorProperties.Odm_available)
+}
+
func (ctx *moduleContext) ProductSpecific() bool {
return false
}
@@ -84,10 +173,15 @@
return mod.HasVendorVariant() || mod.HasProductVariant()
}
-func (c *Module) InProduct() bool {
+func (mod *Module) InProduct() bool {
return false
}
+// Returns true if the module is "vendor" variant. Usually these modules are installed in /vendor
+func (mod *Module) InVendor() bool {
+ return mod.Properties.ImageVariationPrefix == cc.VendorVariationPrefix
+}
+
func (mod *Module) SetImageVariation(ctx android.BaseModuleContext, variant string, module android.Module) {
m := module.(*Module)
if variant == android.VendorRamdiskVariation {
@@ -107,9 +201,6 @@
}
func (mod *Module) ImageMutatorBegin(mctx android.BaseModuleContext) {
- vendorSpecific := mctx.SocSpecific() || mctx.DeviceSpecific()
- platformVndkVersion := mctx.DeviceConfig().PlatformVndkVersion()
-
// Rust does not support installing to the product image yet.
if Bool(mod.VendorProperties.Product_available) {
mctx.PropertyErrorf("product_available",
@@ -121,60 +212,19 @@
mctx.PropertyErrorf("double_loadable",
"Rust modules do not yet support double loading")
}
-
- coreVariantNeeded := true
- vendorRamdiskVariantNeeded := false
-
- var vendorVariants []string
-
- if mod.HasVendorVariant() {
- prop := "vendor_available"
- if Bool(mod.VendorProperties.Odm_available) {
- prop = "odm_available"
- }
-
- if vendorSpecific {
- mctx.PropertyErrorf(prop,
- "doesn't make sense at the same time as `vendor: true`, `proprietary: true`, or `device_specific: true`")
- }
-
- if lib, ok := mod.compiler.(libraryInterface); ok {
- // Explicitly disallow rust_ffi variants which produce shared libraries from setting vendor_available.
- // Vendor variants do not produce an error for dylibs, rlibs with dylib-std linkage are disabled in the respective library
- // mutators until support is added.
- //
- // We can't check shared() here because image mutator is called before the library mutator, so we need to
- // check buildShared()
- if lib.buildShared() {
- mctx.PropertyErrorf(prop, "cannot be set for rust_ffi or rust_ffi_shared modules.")
- } else {
- vendorVariants = append(vendorVariants, platformVndkVersion)
- }
- }
- }
-
if Bool(mod.Properties.Vendor_ramdisk_available) {
if lib, ok := mod.compiler.(libraryInterface); !ok || (ok && lib.buildShared()) {
mctx.PropertyErrorf("vendor_ramdisk_available", "cannot be set for rust_ffi or rust_ffi_shared modules.")
- } else {
- vendorRamdiskVariantNeeded = true
}
}
- if vendorSpecific {
- if lib, ok := mod.compiler.(libraryInterface); !ok || (ok && (lib.buildShared() || lib.buildDylib() || lib.buildRlib())) {
- mctx.ModuleErrorf("Rust vendor specific modules are currently only supported for rust_ffi_static modules.")
- } else {
- coreVariantNeeded = false
- vendorVariants = append(vendorVariants, platformVndkVersion)
+ cc.MutateImage(mctx, mod)
+
+ if !mod.Properties.CoreVariantNeeded || mod.HasNonSystemVariants() {
+
+ if _, ok := mod.compiler.(*prebuiltLibraryDecorator); ok {
+ // Rust does not support prebuilt libraries on non-System images.
+ mctx.ModuleErrorf("Rust prebuilt modules not supported for non-system images.")
}
}
-
- mod.Properties.CoreVariantNeeded = coreVariantNeeded
- mod.Properties.VendorRamdiskVariantNeeded = vendorRamdiskVariantNeeded
-
- for _, variant := range android.FirstUniqueStrings(vendorVariants) {
- mod.Properties.ExtraVariants = append(mod.Properties.ExtraVariants, cc.VendorVariationPrefix+variant)
- }
-
}
diff --git a/rust/image_test.go b/rust/image_test.go
index 7677cce..95e788f 100644
--- a/rust/image_test.go
+++ b/rust/image_test.go
@@ -40,8 +40,8 @@
vendorBinary := ctx.ModuleForTests("fizz_vendor", "android_vendor.29_arm64_armv8-a").Module().(*cc.Module)
- if !android.InList("libfoo_vendor", vendorBinary.Properties.AndroidMkStaticLibs) {
- t.Errorf("vendorBinary should have a dependency on libfoo_vendor")
+ if !android.InList("libfoo_vendor.vendor", vendorBinary.Properties.AndroidMkStaticLibs) {
+ t.Errorf("vendorBinary should have a dependency on libfoo_vendor: %#v", vendorBinary.Properties.AndroidMkStaticLibs)
}
}
@@ -87,47 +87,19 @@
}
}
-// Test that shared libraries cannot be made vendor available until proper support is added.
+// Test that prebuilt libraries cannot be made vendor available.
func TestForbiddenVendorLinkage(t *testing.T) {
- testRustError(t, "cannot be set for rust_ffi or rust_ffi_shared modules.", `
- rust_ffi_shared {
- name: "libfoo_vendor",
- crate_name: "foo",
- srcs: ["foo.rs"],
- vendor_available: true,
- }
- `)
- testRustError(t, "cannot be set for rust_ffi or rust_ffi_shared modules.", `
- rust_ffi_shared {
- name: "libfoo_vendor",
- crate_name: "foo",
- srcs: ["foo.rs"],
- vendor_ramdisk_available: true,
- }
- `)
- testRustError(t, "Rust vendor specific modules are currently only supported for rust_ffi_static modules.", `
- rust_ffi {
- name: "libfoo_vendor",
- crate_name: "foo",
- srcs: ["foo.rs"],
+ testRustVndkError(t, "Rust prebuilt modules not supported for non-system images.", `
+ rust_prebuilt_library {
+ name: "librust_prebuilt",
+ crate_name: "rust_prebuilt",
+ rlib: {
+ srcs: ["libtest.rlib"],
+ },
+ dylib: {
+ srcs: ["libtest.so"],
+ },
vendor: true,
}
- `)
- testRustError(t, "Rust vendor specific modules are currently only supported for rust_ffi_static modules.", `
- rust_library {
- name: "libfoo_vendor",
- crate_name: "foo",
- srcs: ["foo.rs"],
- vendor: true,
- }
- `)
- testRustError(t, "Rust vendor specific modules are currently only supported for rust_ffi_static modules.", `
- rust_binary {
- name: "foo_vendor",
- crate_name: "foo",
- srcs: ["foo.rs"],
- vendor: true,
- }
- `)
-
+ `)
}
diff --git a/rust/library.go b/rust/library.go
index 71fe1f5..26c104c 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -475,7 +475,7 @@
TransformSrctoShared(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
}
- if !library.rlib() && library.stripper.NeedsStrip(ctx) {
+ if !library.rlib() && !library.static() && library.stripper.NeedsStrip(ctx) {
strippedOutputFile := android.PathForModuleOut(ctx, "stripped", fileName)
library.stripper.StripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile)
library.strippedOutputFile = android.OptionalPathForPath(strippedOutputFile)
@@ -596,9 +596,9 @@
v.(*Module).compiler.(libraryInterface).setRlib()
case dylibVariation:
v.(*Module).compiler.(libraryInterface).setDylib()
- if v.(*Module).ModuleBase.ImageVariation().Variation != android.CoreVariation {
+ if v.(*Module).ModuleBase.ImageVariation().Variation == android.VendorRamdiskVariation {
// TODO(b/165791368)
- // Disable dylib non-core variations until we support these.
+ // Disable dylib Vendor Ramdisk variations until we support these.
v.(*Module).Disable()
}
case "source":
@@ -637,14 +637,14 @@
dylib := modules[1].(*Module)
rlib.compiler.(libraryInterface).setRlibStd()
dylib.compiler.(libraryInterface).setDylibStd()
- if dylib.ModuleBase.ImageVariation().Variation != android.CoreVariation {
+ if dylib.ModuleBase.ImageVariation().Variation == android.VendorRamdiskVariation {
// TODO(b/165791368)
- // Disable rlibs that link against dylib-std on non-core variations until non-core dylib
+ // Disable rlibs that link against dylib-std on vendor ramdisk variations until those dylib
// variants are properly supported.
dylib.Disable()
}
- rlib.Properties.SubName += RlibStdlibSuffix
- dylib.Properties.SubName += DylibStdlibSuffix
+ rlib.Properties.RustSubName += RlibStdlibSuffix
+ dylib.Properties.RustSubName += DylibStdlibSuffix
}
}
}
diff --git a/rust/rust.go b/rust/rust.go
index 34e197a..9738b46 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -22,6 +22,7 @@
"github.com/google/blueprint/proptools"
"android/soong/android"
+ "android/soong/bloaty"
"android/soong/cc"
cc_config "android/soong/cc/config"
"android/soong/rust/config"
@@ -73,6 +74,11 @@
VndkVersion string `blueprint:"mutated"`
SubName string `blueprint:"mutated"`
+ // SubName is used by CC for tracking image variants / SDK versions. RustSubName is used for Rust-specific
+ // subnaming which shouldn't be visible to CC modules (such as the rlib stdlinkage subname). This should be
+ // appended before SubName.
+ RustSubName string `blueprint:"mutated"`
+
// Set by imageMutator
CoreVariantNeeded bool `blueprint:"mutated"`
VendorRamdiskVariantNeeded bool `blueprint:"mutated"`
@@ -131,11 +137,6 @@
mod.Properties.PreventInstall = true
}
-// Returns true if the module is "vendor" variant. Usually these modules are installed in /vendor
-func (mod *Module) InVendor() bool {
- return mod.Properties.ImageVariationPrefix == cc.VendorVariationPrefix
-}
-
func (mod *Module) SetHideFromMake() {
mod.Properties.HideFromMake = true
}
@@ -231,7 +232,11 @@
}
func (mod *Module) MustUseVendorVariant() bool {
- return false
+ return true
+}
+
+func (mod *Module) SubName() string {
+ return mod.Properties.SubName
}
func (mod *Module) IsVndk() bool {
@@ -255,6 +260,22 @@
return false
}
+func (m *Module) IsLlndkHeaders() bool {
+ return false
+}
+
+func (m *Module) IsLlndkLibrary() bool {
+ return false
+}
+
+func (mod *Module) KernelHeadersDecorator() bool {
+ return false
+}
+
+func (m *Module) HasLlndkStubs() bool {
+ return false
+}
+
func (mod *Module) SdkVersion() string {
return ""
}
@@ -434,6 +455,7 @@
module.AddProperties(
&BaseProperties{},
&cc.VendorProperties{},
+ &BenchmarkProperties{},
&BindgenProperties{},
&BaseCompilerProperties{},
&BinaryCompilerProperties{},
@@ -730,8 +752,8 @@
if mod.compiler != nil && !mod.compiler.Disabled() {
mod.compiler.initialize(ctx)
unstrippedOutputFile := mod.compiler.compile(ctx, flags, deps)
-
mod.unstrippedOutputFile = android.OptionalPathForPath(unstrippedOutputFile)
+ bloaty.MeasureSizeForPaths(ctx, mod.compiler.strippedOutputFilePath(), mod.unstrippedOutputFile)
apexInfo := actx.Provider(android.ApexInfoProvider).(android.ApexInfo)
if mod.installable(apexInfo) {
@@ -842,8 +864,10 @@
ctx.VisitDirectDeps(func(dep android.Module) {
depName := ctx.OtherModuleName(dep)
depTag := ctx.OtherModuleDependencyTag(dep)
+
if rustDep, ok := dep.(*Module); ok && !rustDep.CcLibraryInterface() {
//Handle Rust Modules
+ makeLibName := cc.MakeLibName(ctx, mod, rustDep, depName+rustDep.Properties.RustSubName)
switch depTag {
case dylibDepTag:
@@ -853,19 +877,19 @@
return
}
directDylibDeps = append(directDylibDeps, rustDep)
- mod.Properties.AndroidMkDylibs = append(mod.Properties.AndroidMkDylibs, depName)
+ mod.Properties.AndroidMkDylibs = append(mod.Properties.AndroidMkDylibs, makeLibName)
case rlibDepTag:
rlib, ok := rustDep.compiler.(libraryInterface)
if !ok || !rlib.rlib() {
- ctx.ModuleErrorf("mod %q not an rlib library", depName+rustDep.Properties.SubName)
+ ctx.ModuleErrorf("mod %q not an rlib library", makeLibName)
return
}
directRlibDeps = append(directRlibDeps, rustDep)
- mod.Properties.AndroidMkRlibs = append(mod.Properties.AndroidMkRlibs, depName+rustDep.Properties.SubName)
+ mod.Properties.AndroidMkRlibs = append(mod.Properties.AndroidMkRlibs, makeLibName)
case procMacroDepTag:
directProcMacroDeps = append(directProcMacroDeps, rustDep)
- mod.Properties.AndroidMkProcMacroLibs = append(mod.Properties.AndroidMkProcMacroLibs, depName)
+ mod.Properties.AndroidMkProcMacroLibs = append(mod.Properties.AndroidMkProcMacroLibs, makeLibName)
case android.SourceDepTag:
// Since these deps are added in path_properties.go via AddDependencies, we need to ensure the correct
// OS/Arch variant is used.
@@ -909,6 +933,7 @@
} else if ccDep, ok := dep.(cc.LinkableInterface); ok {
//Handle C dependencies
+ makeLibName := cc.MakeLibName(ctx, mod, ccDep, depName)
if _, ok := ccDep.(*Module); !ok {
if ccDep.Module().Target().Os != ctx.Os() {
ctx.ModuleErrorf("OS mismatch between %q and %q", ctx.ModuleName(), depName)
@@ -950,7 +975,7 @@
depPaths.depClangFlags = append(depPaths.depClangFlags, exportedInfo.Flags...)
depPaths.depGeneratedHeaders = append(depPaths.depGeneratedHeaders, exportedInfo.GeneratedHeaders...)
directStaticLibDeps = append(directStaticLibDeps, ccDep)
- mod.Properties.AndroidMkStaticLibs = append(mod.Properties.AndroidMkStaticLibs, depName)
+ mod.Properties.AndroidMkStaticLibs = append(mod.Properties.AndroidMkStaticLibs, makeLibName)
case cc.IsSharedDepTag(depTag):
depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
depPaths.linkObjects = append(depPaths.linkObjects, linkObject.String())
@@ -960,7 +985,7 @@
depPaths.depClangFlags = append(depPaths.depClangFlags, exportedInfo.Flags...)
depPaths.depGeneratedHeaders = append(depPaths.depGeneratedHeaders, exportedInfo.GeneratedHeaders...)
directSharedLibDeps = append(directSharedLibDeps, ccDep)
- mod.Properties.AndroidMkSharedLibs = append(mod.Properties.AndroidMkSharedLibs, depName)
+ mod.Properties.AndroidMkSharedLibs = append(mod.Properties.AndroidMkSharedLibs, makeLibName)
exportDep = true
case cc.IsHeaderDepTag(depTag):
exportedInfo := ctx.OtherModuleProvider(dep, cc.FlagExporterInfoProvider).(cc.FlagExporterInfo)
diff --git a/rust/rust_test.go b/rust/rust_test.go
index 890fb26..6ae05d9 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -113,6 +113,24 @@
RunTestWithBp(t, bp)
}
+// testRustVndkError is similar to testRustError, but can be used to test VNDK-related errors.
+func testRustVndkError(t *testing.T, pattern string, bp string) {
+ skipTestIfOsNotSupported(t)
+ android.GroupFixturePreparers(
+ prepareForRustTest,
+ rustMockedFiles.AddToFixture(),
+ android.FixtureModifyProductVariables(
+ func(variables android.FixtureProductVariables) {
+ variables.DeviceVndkVersion = StringPtr("current")
+ variables.ProductVndkVersion = StringPtr("current")
+ variables.Platform_vndk_version = StringPtr("VER")
+ },
+ ),
+ ).
+ ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(pattern)).
+ RunTestWithBp(t, bp)
+}
+
// testRustCtx is used to build a particular test environment. Unless your
// tests requires a specific setup, prefer the wrapping functions: testRust,
// testRustCov or testRustError.
@@ -384,3 +402,17 @@
_ = ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib_dylib-std")
_ = ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_rlib_dylib-std")
}
+
+// Test that library size measurements are generated.
+func TestLibrarySizes(t *testing.T) {
+ ctx := testRust(t, `
+ rust_library_dylib {
+ name: "libwaldo",
+ srcs: ["foo.rs"],
+ crate_name: "waldo",
+ }`)
+
+ m := ctx.SingletonForTests("file_metrics")
+ m.Output("libwaldo.dylib.so.bloaty.csv")
+ m.Output("stripped/libwaldo.dylib.so.bloaty.csv")
+}
diff --git a/rust/sanitize.go b/rust/sanitize.go
index ae3eff0..0a53f98 100644
--- a/rust/sanitize.go
+++ b/rust/sanitize.go
@@ -46,7 +46,6 @@
"-C llvm-args=-sanitizer-coverage-inline-8bit-counters",
"-C llvm-args=-sanitizer-coverage-trace-geps",
"-C llvm-args=-sanitizer-coverage-prune-blocks=0",
- "-Z sanitizer=address",
// Sancov breaks with lto
// TODO: Remove when https://bugs.llvm.org/show_bug.cgi?id=41734 is resolved and sancov works with LTO
@@ -109,6 +108,11 @@
}
if Bool(sanitize.Properties.Sanitize.Fuzzer) {
flags.RustFlags = append(flags.RustFlags, fuzzerFlags...)
+ if ctx.Arch().ArchType == android.Arm64 {
+ flags.RustFlags = append(flags.RustFlags, hwasanFlags...)
+ } else {
+ flags.RustFlags = append(flags.RustFlags, asanFlags...)
+ }
}
if Bool(sanitize.Properties.Sanitize.Address) {
flags.RustFlags = append(flags.RustFlags, asanFlags...)
@@ -133,12 +137,14 @@
var depTag blueprint.DependencyTag
var deps []string
- if Bool(mod.sanitize.Properties.Sanitize.Fuzzer) || Bool(mod.sanitize.Properties.Sanitize.Address) {
+ if mod.IsSanitizerEnabled(cc.Asan) ||
+ (mod.IsSanitizerEnabled(cc.Fuzzer) && mctx.Arch().ArchType != android.Arm64) {
variations = append(variations,
blueprint.Variation{Mutator: "link", Variation: "shared"})
depTag = cc.SharedDepTag()
deps = []string{config.LibclangRuntimeLibrary(mod.toolchain(mctx), "asan")}
- } else if mod.IsSanitizerEnabled(cc.Hwasan) {
+ } else if mod.IsSanitizerEnabled(cc.Hwasan) ||
+ (mod.IsSanitizerEnabled(cc.Fuzzer) && mctx.Arch().ArchType == android.Arm64) {
// TODO(b/180495975): HWASan for static Rust binaries isn't supported yet.
if binary, ok := mod.compiler.(*binaryDecorator); ok {
if Bool(binary.Properties.Static_executable) {
@@ -285,11 +291,9 @@
func (mod *Module) StaticallyLinked() bool {
if lib, ok := mod.compiler.(libraryInterface); ok {
- if lib.rlib() || lib.static() {
- return true
- }
- } else if Bool(mod.compiler.(*binaryDecorator).Properties.Static_executable) {
- return true
+ return lib.rlib() || lib.static()
+ } else if binary, ok := mod.compiler.(*binaryDecorator); ok {
+ return Bool(binary.Properties.Static_executable)
}
return false
}
diff --git a/rust/testing.go b/rust/testing.go
index 75adcfc..a0f86b2 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -16,6 +16,7 @@
import (
"android/soong/android"
+ "android/soong/bloaty"
"android/soong/cc"
)
@@ -34,6 +35,7 @@
// Preparer that will define default rust modules, e.g. standard prebuilt modules.
var PrepareForTestWithRustDefaultModules = android.GroupFixturePreparers(
cc.PrepareForTestWithCcDefaultModules,
+ bloaty.PrepareForTestWithBloatyDefaultModules,
PrepareForTestWithRustBuildComponents,
android.FixtureAddTextFile(rustDefaultsDir+"Android.bp", GatherRequiredDepsForTest()),
)
@@ -127,6 +129,7 @@
system_shared_libs: [],
apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
min_sdk_version: "29",
+ vendor_available: true,
}
cc_library {
name: "libprotobuf-cpp-full",
@@ -150,7 +153,7 @@
host_supported: true,
vendor_available: true,
vendor_ramdisk_available: true,
- native_coverage: false,
+ native_coverage: false,
sysroot: true,
apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
min_sdk_version: "29",
@@ -163,7 +166,7 @@
host_supported: true,
vendor_available: true,
vendor_ramdisk_available: true,
- native_coverage: false,
+ native_coverage: false,
sysroot: true,
apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
min_sdk_version: "29",
@@ -192,11 +195,19 @@
srcs:["foo.rs"],
host_supported: true,
}
+ rust_library {
+ name: "libcriterion",
+ crate_name: "criterion",
+ srcs:["foo.rs"],
+ host_supported: true,
+ }
`
return bp
}
func registerRequiredBuildComponentsForTest(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("rust_benchmark", RustBenchmarkFactory)
+ ctx.RegisterModuleType("rust_benchmark_host", RustBenchmarkHostFactory)
ctx.RegisterModuleType("rust_binary", RustBinaryFactory)
ctx.RegisterModuleType("rust_binary_host", RustBinaryHostFactory)
ctx.RegisterModuleType("rust_bindgen", RustBindgenFactory)
diff --git a/scripts/conv_linker_config.py b/scripts/conv_linker_config.py
index 22fe9f6..92f79da 100644
--- a/scripts/conv_linker_config.py
+++ b/scripts/conv_linker_config.py
@@ -78,6 +78,14 @@
with open(args.output, 'wb') as f:
f.write(pb.SerializeToString())
+def Merge(args):
+ pb = linker_config_pb2.LinkerConfig()
+ for other in args.input:
+ with open(other, 'rb') as f:
+ pb.MergeFromString(f.read())
+
+ with open(args.out, 'wb') as f:
+ f.write(pb.SerializeToString())
def GetArgParser():
parser = argparse.ArgumentParser()
@@ -161,6 +169,22 @@
help='Values of the libraries to append. If there are more than one it should be separated by empty space')
append.set_defaults(func=Append)
+ append = subparsers.add_parser(
+ 'merge', help='Merge configurations')
+ append.add_argument(
+ '-o',
+ '--out',
+ required=True,
+ type=str,
+ help='Ouptut linker configuration file to write in protobuf.')
+ append.add_argument(
+ '-i',
+ '--input',
+ nargs='+',
+ type=str,
+ help='Linker configuration files to merge.')
+ append.set_defaults(func=Merge)
+
return parser
diff --git a/sh/sh_binary.go b/sh/sh_binary.go
index 6623381..42d5680 100644
--- a/sh/sh_binary.go
+++ b/sh/sh_binary.go
@@ -210,6 +210,10 @@
return proptools.Bool(s.properties.Vendor_ramdisk_available) || s.ModuleBase.InstallInVendorRamdisk()
}
+func (s *ShBinary) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+ return false
+}
+
func (s *ShBinary) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
return proptools.Bool(s.properties.Recovery_available) || s.ModuleBase.InstallInRecovery()
}
diff --git a/tests/bootstrap_test.sh b/tests/bootstrap_test.sh
index b2f7b2b..a483370 100755
--- a/tests/bootstrap_test.sh
+++ b/tests/bootstrap_test.sh
@@ -114,7 +114,61 @@
rm a/Android.bp
run_soong
- grep -q "^# Module:.*my_little_binary_host$" out/soong/build.ninja && fail "Old module in output"
+ if grep -q "^# Module:.*my_little_binary_host$" out/soong/build.ninja; then
+ fail "Old module in output"
+ fi
+}
+
+# Test that an incremental build with a glob doesn't rerun soong_build, and
+# only regenerates the globs on the first but not the second incremental build.
+function test_glob_noop_incremental() {
+ setup
+
+ mkdir -p a
+ cat > a/Android.bp <<'EOF'
+python_binary_host {
+ name: "my_little_binary_host",
+ srcs: ["*.py"],
+}
+EOF
+ touch a/my_little_binary_host.py
+ run_soong
+ local ninja_mtime1=$(stat -c "%y" out/soong/build.ninja)
+
+ local glob_deps_file=out/soong/.glob/a/__py.glob.d
+
+ if [ -e "$glob_deps_file" ]; then
+ fail "Glob deps file unexpectedly written on first build"
+ fi
+
+ run_soong
+ local ninja_mtime2=$(stat -c "%y" out/soong/build.ninja)
+
+ # There is an ineffiencency in glob that requires bpglob to rerun once for each glob to update
+ # the entry in the .ninja_log. It doesn't update the output file, but we can detect the rerun
+ # by checking if the deps file was created.
+ if [ ! -e "$glob_deps_file" ]; then
+ fail "Glob deps file missing after second build"
+ fi
+
+ local glob_deps_mtime2=$(stat -c "%y" "$glob_deps_file")
+
+ if [[ "$ninja_mtime1" != "$ninja_mtime2" ]]; then
+ fail "Ninja file rewritten on null incremental build"
+ fi
+
+ run_soong
+ local ninja_mtime3=$(stat -c "%y" out/soong/build.ninja)
+ local glob_deps_mtime3=$(stat -c "%y" "$glob_deps_file")
+
+ if [[ "$ninja_mtime2" != "$ninja_mtime3" ]]; then
+ fail "Ninja file rewritten on null incremental build"
+ fi
+
+ # The bpglob commands should not rerun after the first incremental build.
+ if [[ "$glob_deps_mtime2" != "$glob_deps_mtime3" ]]; then
+ fail "Glob deps file rewritten on second null incremental build"
+ fi
}
function test_add_file_to_glob() {
@@ -295,6 +349,120 @@
grep -q "Make it so" out/soong/build.ninja || fail "New action not present"
}
+# Tests a glob in a build= statement in an Android.bp file, which is interpreted
+# during bootstrapping.
+function test_glob_during_bootstrapping() {
+ setup
+
+ mkdir -p a
+ cat > a/Android.bp <<'EOF'
+build=["foo*.bp"]
+EOF
+ cat > a/fooa.bp <<'EOF'
+bootstrap_go_package {
+ name: "picard-soong-rules",
+ pkgPath: "android/soong/picard",
+ deps: [
+ "blueprint",
+ "soong",
+ "soong-android",
+ ],
+ srcs: [
+ "picard.go",
+ ],
+ pluginFor: ["soong_build"],
+}
+EOF
+
+ cat > a/picard.go <<'EOF'
+package picard
+
+import (
+ "android/soong/android"
+ "github.com/google/blueprint"
+)
+
+var (
+ pctx = android.NewPackageContext("picard")
+)
+
+func init() {
+ android.RegisterSingletonType("picard", PicardSingleton)
+}
+
+func PicardSingleton() android.Singleton {
+ return &picardSingleton{}
+}
+
+type picardSingleton struct{}
+
+var Message = "Make it so."
+
+func (p *picardSingleton) GenerateBuildActions(ctx android.SingletonContext) {
+ picardRule := ctx.Rule(pctx, "picard",
+ blueprint.RuleParams{
+ Command: "echo " + Message + " > ${out}",
+ CommandDeps: []string{},
+ Description: "Something quotable",
+ })
+
+ outputFile := android.PathForOutput(ctx, "picard", "picard.txt")
+ var deps android.Paths
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: picardRule,
+ Output: outputFile,
+ Inputs: deps,
+ })
+}
+
+EOF
+
+ run_soong
+ local mtime1=$(stat -c "%y" out/soong/build.ninja)
+
+ grep -q "Make it so" out/soong/build.ninja || fail "Original action not present"
+
+ cat > a/foob.bp <<'EOF'
+bootstrap_go_package {
+ name: "worf-soong-rules",
+ pkgPath: "android/soong/worf",
+ deps: [
+ "blueprint",
+ "soong",
+ "soong-android",
+ "picard-soong-rules",
+ ],
+ srcs: [
+ "worf.go",
+ ],
+ pluginFor: ["soong_build"],
+}
+EOF
+
+ cat > a/worf.go <<'EOF'
+package worf
+
+import "android/soong/picard"
+
+func init() {
+ picard.Message = "Engage."
+}
+EOF
+
+ run_soong
+ local mtime2=$(stat -c "%y" out/soong/build.ninja)
+ if [[ "$mtime1" == "$mtime2" ]]; then
+ fail "Output Ninja file did not change"
+ fi
+
+ grep -q "Engage" out/soong/build.ninja || fail "New action not present"
+
+ if grep -q "Make it so" out/soong/build.ninja; then
+ fail "Original action still present"
+ fi
+}
+
function test_null_build_after_docs {
setup
run_soong
@@ -309,6 +477,83 @@
fi
}
+function test_integrated_bp2build_smoke {
+ setup
+ INTEGRATED_BP2BUILD=1 run_soong
+ if [[ ! -e out/soong/.bootstrap/bp2build_workspace_marker ]]; then
+ fail "bp2build marker file not created"
+ fi
+}
+
+function test_integrated_bp2build_add_android_bp {
+ setup
+
+ mkdir -p a
+ touch a/a.txt
+ cat > a/Android.bp <<'EOF'
+filegroup {
+ name: "a",
+ srcs: ["a.txt"],
+ bazel_module: { bp2build_available: true },
+}
+EOF
+
+ INTEGRATED_BP2BUILD=1 run_soong
+ if [[ ! -e out/soong/bp2build/a/BUILD ]]; then
+ fail "a/BUILD not created";
+ fi
+
+ mkdir -p b
+ touch b/b.txt
+ cat > b/Android.bp <<'EOF'
+filegroup {
+ name: "b",
+ srcs: ["b.txt"],
+ bazel_module: { bp2build_available: true },
+}
+EOF
+
+ INTEGRATED_BP2BUILD=1 run_soong
+ if [[ ! -e out/soong/bp2build/b/BUILD ]]; then
+ fail "b/BUILD not created";
+ fi
+}
+
+function test_integrated_bp2build_null_build {
+ setup
+
+ INTEGRATED_BP2BUILD=1 run_soong
+ local mtime1=$(stat -c "%y" out/soong/build.ninja)
+
+ INTEGRATED_BP2BUILD=1 run_soong
+ local mtime2=$(stat -c "%y" out/soong/build.ninja)
+
+ if [[ "$mtime1" != "$mtime2" ]]; then
+ fail "Output Ninja file changed on null build"
+ fi
+}
+
+function test_integrated_bp2build_add_to_glob {
+ setup
+
+ mkdir -p a
+ touch a/a1.txt
+ cat > a/Android.bp <<'EOF'
+filegroup {
+ name: "a",
+ srcs: ["*.txt"],
+ bazel_module: { bp2build_available: true },
+}
+EOF
+
+ INTEGRATED_BP2BUILD=1 run_soong
+ grep -q a1.txt out/soong/bp2build/a/BUILD || fail "a1.txt not in BUILD file"
+
+ touch a/a2.txt
+ INTEGRATED_BP2BUILD=1 run_soong
+ grep -q a2.txt out/soong/bp2build/a/BUILD || fail "a2.txt not in BUILD file"
+}
+
function test_dump_json_module_graph() {
setup
SOONG_DUMP_JSON_MODULE_GRAPH="$MOCK_TOP/modules.json" run_soong
@@ -321,10 +566,15 @@
test_null_build
test_null_build_after_docs
test_soong_build_rebuilt_if_blueprint_changes
+test_glob_noop_incremental
test_add_file_to_glob
test_add_android_bp
test_change_android_bp
test_delete_android_bp
test_add_file_to_soong_build
+test_glob_during_bootstrapping
test_soong_build_rerun_iff_environment_changes
test_dump_json_module_graph
+test_integrated_bp2build_smoke
+test_integrated_bp2build_null_build
+test_integrated_bp2build_add_to_glob
diff --git a/tests/lib.sh b/tests/lib.sh
index 3c97e14..1478e37 100644
--- a/tests/lib.sh
+++ b/tests/lib.sh
@@ -6,8 +6,39 @@
REAL_TOP="$(readlink -f "$(dirname "$0")"/../../..)"
+if [[ ! -z "$HARDWIRED_MOCK_TOP" ]]; then
+ MOCK_TOP="$HARDWIRED_MOCK_TOP"
+else
+ MOCK_TOP=$(mktemp -t -d st.XXXXX)
+ trap cleanup_mock_top EXIT
+fi
+
+WARMED_UP_MOCK_TOP=$(mktemp -t soong_integration_tests_warmup.XXXXXX.tar.gz)
+trap 'rm -f "$WARMED_UP_MOCK_TOP"' EXIT
+
+function warmup_mock_top {
+ info "Warming up mock top ..."
+ info "Mock top warmup archive: $WARMED_UP_MOCK_TOP"
+ cleanup_mock_top
+ mkdir -p "$MOCK_TOP"
+ cd "$MOCK_TOP"
+
+ create_mock_soong
+ run_soong
+ tar czf "$WARMED_UP_MOCK_TOP" *
+}
+
+function cleanup_mock_top {
+ cd /
+ rm -fr "$MOCK_TOP"
+}
+
+function info {
+ echo -e "\e[92;1m[TEST HARNESS INFO]\e[0m" $*
+}
+
function fail {
- echo ERROR: $1
+ echo -e "\e[91;1mFAILED:\e[0m" $*
exit 1
}
@@ -47,19 +78,7 @@
done
}
-function setup() {
- if [[ ! -z "$HARDWIRED_MOCK_TOP" ]]; then
- MOCK_TOP="$HARDWIRED_MOCK_TOP"
- rm -fr "$MOCK_TOP"
- mkdir -p "$MOCK_TOP"
- else
- MOCK_TOP=$(mktemp -t -d st.XXXXX)
- trap 'echo cd / && echo rm -fr "$MOCK_TOP"' EXIT
- fi
-
- echo "Test case: ${FUNCNAME[1]}, mock top path: $MOCK_TOP"
- cd "$MOCK_TOP"
-
+function create_mock_soong {
copy_directory build/blueprint
copy_directory build/soong
@@ -68,12 +87,27 @@
symlink_directory external/golang-protobuf
touch "$MOCK_TOP/Android.bp"
+}
- export ALLOW_MISSING_DEPENDENCIES=true
+function setup() {
+ cleanup_mock_top
+ mkdir -p "$MOCK_TOP"
- mkdir -p out/soong
+ echo
+ echo ----------------------------------------------------------------------------
+ info "Running test case ${FUNCNAME[1]}"
+ cd "$MOCK_TOP"
+
+ tar xzf "$WARMED_UP_MOCK_TOP"
}
function run_soong() {
build/soong/soong_ui.bash --make-mode --skip-ninja --skip-make --skip-soong-tests
}
+
+info "Starting Soong integration test suite $(basename $0)"
+info "Mock top: $MOCK_TOP"
+
+
+export ALLOW_MISSING_DEPENDENCIES=true
+warmup_mock_top
diff --git a/tests/mixed_mode_test.sh b/tests/mixed_mode_test.sh
index 54f0689..7dbafea 100755
--- a/tests/mixed_mode_test.sh
+++ b/tests/mixed_mode_test.sh
@@ -8,7 +8,7 @@
source "$(dirname "$0")/lib.sh"
-function setup_bazel() {
+function create_mock_bazel() {
copy_directory build/bazel
symlink_directory prebuilts/bazel
@@ -20,7 +20,7 @@
function test_bazel_smoke {
setup
- setup_bazel
+ create_mock_bazel
tools/bazel info
}
diff --git a/tradefed/autogen.go b/tradefed/autogen.go
index 27d71e8..3d96c84 100644
--- a/tradefed/autogen.go
+++ b/tradefed/autogen.go
@@ -245,6 +245,25 @@
return path
}
+func AutoGenRustBenchmarkConfig(ctx android.ModuleContext, testConfigProp *string,
+ testConfigTemplateProp *string, testSuites []string, config []Config, autoGenConfig *bool) android.Path {
+ path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp)
+ if autogenPath != nil {
+ templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
+ if templatePath.Valid() {
+ autogenTemplate(ctx, autogenPath, templatePath.String(), config, "")
+ } else {
+ if ctx.Device() {
+ autogenTemplate(ctx, autogenPath, "${RustDeviceBenchmarkConfigTemplate}", config, "")
+ } else {
+ autogenTemplate(ctx, autogenPath, "${RustHostBenchmarkConfigTemplate}", config, "")
+ }
+ }
+ return autogenPath
+ }
+ return path
+}
+
func AutoGenRobolectricTestConfig(ctx android.ModuleContext, testConfigProp *string, testConfigTemplateProp *string,
testSuites []string, autoGenConfig *bool) android.Path {
path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp)
diff --git a/tradefed/config.go b/tradefed/config.go
index f3566a8..999424c 100644
--- a/tradefed/config.go
+++ b/tradefed/config.go
@@ -34,6 +34,8 @@
pctx.SourcePathVariable("PythonBinaryHostTestConfigTemplate", "build/make/core/python_binary_host_test_config_template.xml")
pctx.SourcePathVariable("RustDeviceTestConfigTemplate", "build/make/core/rust_device_test_config_template.xml")
pctx.SourcePathVariable("RustHostTestConfigTemplate", "build/make/core/rust_host_test_config_template.xml")
+ pctx.SourcePathVariable("RustDeviceBenchmarkConfigTemplate", "build/make/core/rust_device_benchmark_config_template.xml")
+ pctx.SourcePathVariable("RustHostBenchmarkConfigTemplate", "build/make/core/rust_host_benchmark_config_template.xml")
pctx.SourcePathVariable("RobolectricTestConfigTemplate", "build/make/core/robolectric_test_config_template.xml")
pctx.SourcePathVariable("ShellTestConfigTemplate", "build/make/core/shell_test_config_template.xml")
diff --git a/tradefed/makevars.go b/tradefed/makevars.go
index f9682e4..9b5a20f 100644
--- a/tradefed/makevars.go
+++ b/tradefed/makevars.go
@@ -33,6 +33,8 @@
ctx.Strict("PYTHON_BINARY_HOST_TEST_CONFIG_TEMPLATE", "${PythonBinaryHostTestConfigTemplate}")
ctx.Strict("RUST_DEVICE_TEST_CONFIG_TEMPLATE", "${RustDeviceTestConfigTemplate}")
ctx.Strict("RUST_HOST_TEST_CONFIG_TEMPLATE", "${RustHostTestConfigTemplate}")
+ ctx.Strict("RUST_DEVICE_BENCHMARK_CONFIG_TEMPLATE", "${RustDeviceBenchmarkConfigTemplate}")
+ ctx.Strict("RUST_HOST_BENCHMARK_CONFIG_TEMPLATE", "${RustHostBenchmarkConfigTemplate}")
ctx.Strict("SHELL_TEST_CONFIG_TEMPLATE", "${ShellTestConfigTemplate}")
ctx.Strict("EMPTY_TEST_CONFIG", "${EmptyTestConfig}")
diff --git a/ui/build/soong.go b/ui/build/soong.go
index 9afcb88..7e94b25 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -21,6 +21,7 @@
"strconv"
"android/soong/shared"
+ "github.com/google/blueprint/deptools"
soong_metrics_proto "android/soong/ui/metrics/metrics_proto"
"github.com/google/blueprint"
@@ -33,6 +34,11 @@
"android/soong/ui/status"
)
+const (
+ availableEnvFile = "soong.environment.available"
+ usedEnvFile = "soong.environment.used"
+)
+
func writeEnvironmentFile(ctx Context, envFile string, envDeps map[string]string) error {
data, err := shared.EnvFileContents(envDeps)
if err != nil {
@@ -87,12 +93,23 @@
return c.debugCompilation
}
-func bootstrapBlueprint(ctx Context, config Config) {
+func environmentArgs(config Config, suffix string) []string {
+ return []string{
+ "--available_env", shared.JoinPath(config.SoongOutDir(), availableEnvFile),
+ "--used_env", shared.JoinPath(config.SoongOutDir(), usedEnvFile+suffix),
+ }
+}
+func bootstrapBlueprint(ctx Context, config Config, integratedBp2Build bool) {
ctx.BeginTrace(metrics.RunSoong, "blueprint bootstrap")
defer ctx.EndTrace()
var args bootstrap.Args
+ mainNinjaFile := shared.JoinPath(config.SoongOutDir(), "build.ninja")
+ globFile := shared.JoinPath(config.SoongOutDir(), ".bootstrap/soong-build-globs.ninja")
+ bootstrapGlobFile := shared.JoinPath(config.SoongOutDir(), ".bootstrap/build-globs.ninja")
+ bootstrapDepFile := shared.JoinPath(config.SoongOutDir(), ".bootstrap/build.ninja.d")
+
args.RunGoTests = !config.skipSoongTests
args.UseValidations = true // Use validations to depend on tests
args.BuildDir = config.SoongOutDir()
@@ -100,10 +117,52 @@
args.TopFile = "Android.bp"
args.ModuleListFile = filepath.Join(config.FileListDir(), "Android.bp.list")
args.OutFile = shared.JoinPath(config.SoongOutDir(), ".bootstrap/build.ninja")
- args.DepFile = shared.JoinPath(config.SoongOutDir(), ".bootstrap/build.ninja.d")
- args.GlobFile = shared.JoinPath(config.SoongOutDir(), ".bootstrap/soong-build-globs.ninja")
+ args.GlobFile = globFile
args.GeneratingPrimaryBuilder = true
+ args.DelveListen = os.Getenv("SOONG_DELVE")
+ if args.DelveListen != "" {
+ args.DelvePath = shared.ResolveDelveBinary()
+ }
+
+ commonArgs := bootstrap.PrimaryBuilderExtraFlags(args, bootstrapGlobFile, mainNinjaFile)
+ bp2BuildMarkerFile := shared.JoinPath(config.SoongOutDir(), ".bootstrap/bp2build_workspace_marker")
+ mainSoongBuildInputs := []string{"Android.bp"}
+
+ if integratedBp2Build {
+ mainSoongBuildInputs = append(mainSoongBuildInputs, bp2BuildMarkerFile)
+ }
+
+ soongBuildArgs := make([]string, 0)
+ soongBuildArgs = append(soongBuildArgs, commonArgs...)
+ soongBuildArgs = append(soongBuildArgs, environmentArgs(config, "")...)
+ soongBuildArgs = append(soongBuildArgs, "Android.bp")
+
+ mainSoongBuildInvocation := bootstrap.PrimaryBuilderInvocation{
+ Inputs: mainSoongBuildInputs,
+ Outputs: []string{mainNinjaFile},
+ Args: soongBuildArgs,
+ }
+
+ if integratedBp2Build {
+ bp2buildArgs := []string{"--bp2build_marker", bp2BuildMarkerFile}
+ bp2buildArgs = append(bp2buildArgs, commonArgs...)
+ bp2buildArgs = append(bp2buildArgs, environmentArgs(config, ".bp2build")...)
+ bp2buildArgs = append(bp2buildArgs, "Android.bp")
+
+ bp2buildInvocation := bootstrap.PrimaryBuilderInvocation{
+ Inputs: []string{"Android.bp"},
+ Outputs: []string{bp2BuildMarkerFile},
+ Args: bp2buildArgs,
+ }
+ args.PrimaryBuilderInvocations = []bootstrap.PrimaryBuilderInvocation{
+ bp2buildInvocation,
+ mainSoongBuildInvocation,
+ }
+ } else {
+ args.PrimaryBuilderInvocations = []bootstrap.PrimaryBuilderInvocation{mainSoongBuildInvocation}
+ }
+
blueprintCtx := blueprint.NewContext()
blueprintCtx.SetIgnoreUnknownModuleTypes(true)
blueprintConfig := BlueprintConfig{
@@ -113,7 +172,21 @@
debugCompilation: os.Getenv("SOONG_DELVE") != "",
}
- bootstrap.RunBlueprint(args, blueprintCtx, blueprintConfig)
+ bootstrapDeps := bootstrap.RunBlueprint(args, blueprintCtx, blueprintConfig)
+ err := deptools.WriteDepFile(bootstrapDepFile, args.OutFile, bootstrapDeps)
+ if err != nil {
+ ctx.Fatalf("Error writing depfile '%s': %s", bootstrapDepFile, err)
+ }
+}
+
+func checkEnvironmentFile(currentEnv *Environment, envFile string) {
+ getenv := func(k string) string {
+ v, _ := currentEnv.Get(k)
+ return v
+ }
+ if stale, _ := shared.StaleEnvFile(envFile, getenv); stale {
+ os.Remove(envFile)
+ }
}
func runSoong(ctx Context, config Config) {
@@ -124,7 +197,7 @@
// .used with the ones that were actually used. The latter is used to
// determine whether Soong needs to be re-run since why re-run it if only
// unused variables were changed?
- envFile := filepath.Join(config.SoongOutDir(), "soong.environment.available")
+ envFile := filepath.Join(config.SoongOutDir(), availableEnvFile)
for _, n := range []string{".bootstrap", ".minibootstrap"} {
dir := filepath.Join(config.SoongOutDir(), n)
@@ -133,16 +206,13 @@
}
}
+ integratedBp2Build := config.Environment().IsEnvTrue("INTEGRATED_BP2BUILD")
+
// This is done unconditionally, but does not take a measurable amount of time
- bootstrapBlueprint(ctx, config)
+ bootstrapBlueprint(ctx, config, integratedBp2Build)
soongBuildEnv := config.Environment().Copy()
soongBuildEnv.Set("TOP", os.Getenv("TOP"))
- // These two dependencies are read from bootstrap.go, but also need to be here
- // so that soong_build can declare a dependency on them
- soongBuildEnv.Set("SOONG_DELVE", os.Getenv("SOONG_DELVE"))
- soongBuildEnv.Set("SOONG_DELVE_PATH", os.Getenv("SOONG_DELVE_PATH"))
- soongBuildEnv.Set("SOONG_OUTDIR", config.SoongOutDir())
// For Bazel mixed builds.
soongBuildEnv.Set("BAZEL_PATH", "./tools/bazel")
soongBuildEnv.Set("BAZEL_HOME", filepath.Join(config.BazelOutDir(), "bazelhome"))
@@ -164,13 +234,12 @@
ctx.BeginTrace(metrics.RunSoong, "environment check")
defer ctx.EndTrace()
- envFile := filepath.Join(config.SoongOutDir(), "soong.environment.used")
- getenv := func(k string) string {
- v, _ := soongBuildEnv.Get(k)
- return v
- }
- if stale, _ := shared.StaleEnvFile(envFile, getenv); stale {
- os.Remove(envFile)
+ soongBuildEnvFile := filepath.Join(config.SoongOutDir(), usedEnvFile)
+ checkEnvironmentFile(soongBuildEnv, soongBuildEnvFile)
+
+ if integratedBp2Build {
+ bp2buildEnvFile := filepath.Join(config.SoongOutDir(), usedEnvFile+".bp2build")
+ checkEnvironmentFile(soongBuildEnv, bp2buildEnvFile)
}
}()
@@ -215,13 +284,6 @@
// This is currently how the command line to invoke soong_build finds the
// root of the source tree and the output root
ninjaEnv.Set("TOP", os.Getenv("TOP"))
- ninjaEnv.Set("SOONG_OUTDIR", config.SoongOutDir())
-
- // For debugging
- if os.Getenv("SOONG_DELVE") != "" {
- ninjaEnv.Set("SOONG_DELVE", os.Getenv("SOONG_DELVE"))
- ninjaEnv.Set("SOONG_DELVE_PATH", shared.ResolveDelveBinary())
- }
cmd.Environment = &ninjaEnv
cmd.Sandbox = soongSandbox
diff --git a/zip/zip.go b/zip/zip.go
index a6490d4..84e974b 100644
--- a/zip/zip.go
+++ b/zip/zip.go
@@ -292,11 +292,11 @@
continue
}
- globbed, _, err := z.fs.Glob(s, nil, followSymlinks)
+ result, err := z.fs.Glob(s, nil, followSymlinks)
if err != nil {
return err
}
- if len(globbed) == 0 {
+ if len(result.Matches) == 0 {
err := &os.PathError{
Op: "lstat",
Path: s,
@@ -308,7 +308,7 @@
return err
}
}
- srcs = append(srcs, globbed...)
+ srcs = append(srcs, result.Matches...)
}
if fa.GlobDir != "" {
if exists, isDir, err := z.fs.Exists(fa.GlobDir); err != nil {
@@ -336,11 +336,11 @@
return err
}
}
- globbed, _, err := z.fs.Glob(filepath.Join(fa.GlobDir, "**/*"), nil, followSymlinks)
+ result, err := z.fs.Glob(filepath.Join(fa.GlobDir, "**/*"), nil, followSymlinks)
if err != nil {
return err
}
- srcs = append(srcs, globbed...)
+ srcs = append(srcs, result.Matches...)
}
for _, src := range srcs {
err := fillPathPairs(fa, src, &pathMappings, args.NonDeflatedFiles, noCompression)