Merge "Allowlist gcloud to be run during the build" into main
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 7e67c0f..d3959ec 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -1455,6 +1455,7 @@
name: "libc",
no_libcrt: true,
nocrt: true,
+ no_crt_pad_segment: true,
stl: "none",
system_shared_libs: [],
stubs: { versions: ["1"] },
@@ -1469,6 +1470,7 @@
name: "libclang_rt.hwasan",
no_libcrt: true,
nocrt: true,
+ no_crt_pad_segment: true,
stl: "none",
system_shared_libs: [],
srcs: [""],
@@ -1511,6 +1513,7 @@
name: "libc",
no_libcrt: true,
nocrt: true,
+ no_crt_pad_segment: true,
stl: "none",
system_shared_libs: [],
stubs: { versions: ["1"] },
@@ -1521,6 +1524,7 @@
name: "libclang_rt.hwasan",
no_libcrt: true,
nocrt: true,
+ no_crt_pad_segment: true,
stl: "none",
system_shared_libs: [],
srcs: [""],
@@ -3768,13 +3772,6 @@
"lib64/libvndk.so",
"lib64/libvndksp.so"),
},
- {
- vndkVersion: "",
- expectedFiles: append(commonFiles,
- // Legacy VNDK APEX contains only VNDK-SP files (of core variant)
- "lib/libvndksp.so",
- "lib64/libvndksp.so"),
- },
}
for _, tc := range testCases {
t.Run("VNDK.current with DeviceVndkVersion="+tc.vndkVersion, func(t *testing.T) {
diff --git a/apex/dexpreopt_bootjars_test.go b/apex/dexpreopt_bootjars_test.go
index d9ab8fa..7a17f50 100644
--- a/apex/dexpreopt_bootjars_test.go
+++ b/apex/dexpreopt_bootjars_test.go
@@ -164,6 +164,7 @@
"out/soong/dexpreopt_arm64/dex_bootjars_input/baz.jar",
"out/soong/.intermediates/art-bootclasspath-fragment/android_common_apex10000/art-bootclasspath-fragment/boot.prof",
"out/soong/.intermediates/default/java/dex_bootjars/android_common/boot/boot.prof",
+ "out/soong/dexpreopt/uffd_gc_flag.txt",
}
expectedOutputs := []string{
@@ -201,6 +202,7 @@
"out/soong/dexpreopt_arm64/dex_bootjars_input/baz.jar",
"out/soong/.intermediates/prebuilt_com.android.art.deapexer/android_common/deapexer/etc/boot-image.prof",
"out/soong/.intermediates/default/java/dex_bootjars/android_common/boot/boot.prof",
+ "out/soong/dexpreopt/uffd_gc_flag.txt",
}
expectedOutputs := []string{
diff --git a/apex/vndk_test.go b/apex/vndk_test.go
index e2aee96..894aece 100644
--- a/apex/vndk_test.go
+++ b/apex/vndk_test.go
@@ -8,66 +8,6 @@
"android/soong/android"
)
-func TestVndkApexForVndkLite(t *testing.T) {
- ctx := testApex(t, `
- apex_vndk {
- name: "com.android.vndk.current",
- key: "com.android.vndk.current.key",
- updatable: false,
- }
-
- apex_key {
- name: "com.android.vndk.current.key",
- public_key: "testkey.avbpubkey",
- private_key: "testkey.pem",
- }
-
- cc_library {
- name: "libvndk",
- srcs: ["mylib.cpp"],
- vendor_available: true,
- product_available: true,
- vndk: {
- enabled: true,
- },
- system_shared_libs: [],
- stl: "none",
- apex_available: [ "com.android.vndk.current" ],
- }
-
- cc_library {
- name: "libvndksp",
- srcs: ["mylib.cpp"],
- vendor_available: true,
- product_available: true,
- vndk: {
- enabled: true,
- support_system_process: true,
- },
- system_shared_libs: [],
- stl: "none",
- apex_available: [ "com.android.vndk.current" ],
- }
- `+vndkLibrariesTxtFiles("current"),
- android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
- variables.DeviceVndkVersion = proptools.StringPtr("")
- variables.KeepVndk = proptools.BoolPtr(true)
- }),
- )
- // VNDK-Lite contains only core variants of VNDK-Sp libraries
- ensureExactContents(t, ctx, "com.android.vndk.current", "android_common", []string{
- "lib/libvndksp.so",
- "lib/libc++.so",
- "lib64/libvndksp.so",
- "lib64/libc++.so",
- "etc/llndk.libraries.29.txt",
- "etc/vndkcore.libraries.29.txt",
- "etc/vndksp.libraries.29.txt",
- "etc/vndkprivate.libraries.29.txt",
- "etc/vndkproduct.libraries.29.txt",
- })
-}
-
func TestVndkApexUsesVendorVariant(t *testing.T) {
bp := `
apex_vndk {
diff --git a/bin/soongdbg b/bin/soongdbg
new file mode 100755
index 0000000..132a0f0
--- /dev/null
+++ b/bin/soongdbg
@@ -0,0 +1,313 @@
+#!/usr/bin/env python3
+
+import argparse
+import fnmatch
+import json
+import os
+import pathlib
+import types
+import sys
+
+
+class Graph:
+ def __init__(self, modules):
+ def get_or_make_node(dictionary, id, module):
+ node = dictionary.get(id)
+ if node:
+ if module and not node.module:
+ node.module = module
+ return node
+ node = Node(id, module)
+ dictionary[id] = node
+ return node
+ self.nodes = dict()
+ for module in modules.values():
+ node = get_or_make_node(self.nodes, module.id, module)
+ for d in module.deps:
+ dep = get_or_make_node(self.nodes, d.id, None)
+ node.deps.add(dep)
+ dep.rdeps.add(node)
+
+ def find_paths(self, id1, id2):
+ # Throws KeyError if one of the names isn't found
+ def recurse(node1, node2, visited):
+ result = set()
+ for dep in node1.rdeps:
+ if dep == node2:
+ result.add(node2)
+ if dep not in visited:
+ visited.add(dep)
+ found = recurse(dep, node2, visited)
+ if found:
+ result |= found
+ result.add(dep)
+ return result
+ node1 = self.nodes[id1]
+ node2 = self.nodes[id2]
+ # Take either direction
+ p = recurse(node1, node2, set())
+ if p:
+ p.add(node1)
+ return p
+ p = recurse(node2, node1, set())
+ p.add(node2)
+ return p
+
+
+class Node:
+ def __init__(self, id, module):
+ self.id = id
+ self.module = module
+ self.deps = set()
+ self.rdeps = set()
+
+
+PROVIDERS = [
+ "android/soong/java.JarJarProviderData",
+ "android/soong/java.BaseJarJarProviderData",
+]
+
+
+def format_node_label(node):
+ if not node.module:
+ return node.id
+ if node.module.debug:
+ module_debug = f"<tr><td>{node.module.debug}</td></tr>"
+ else:
+ module_debug = ""
+
+ result = (f"<<table border=\"0\" cellborder=\"0\" cellspacing=\"0\" cellpadding=\"0\">"
+ + f"<tr><td><b>{node.module.name}</b></td></tr>"
+ + module_debug
+ + f"<tr><td>{node.module.type}</td></tr>")
+ for p in node.module.providers:
+ if p.type in PROVIDERS:
+ result += "<tr><td><font color=\"#666666\">" + format_provider(p) + "</font></td></tr>"
+ result += "</table>>"
+ return result
+
+
+def format_source_pos(file, lineno):
+ result = file
+ if lineno:
+ result += f":{lineno}"
+ return result
+
+
+STRIP_TYPE_PREFIXES = [
+ "android/soong/",
+ "github.com/google/",
+]
+
+
+def format_provider(provider):
+ result = ""
+ for prefix in STRIP_TYPE_PREFIXES:
+ if provider.type.startswith(prefix):
+ result = provider.type[len(prefix):]
+ break
+ if not result:
+ result = provider.type
+ if True and provider.debug:
+ result += " (" + provider.debug + ")"
+ return result
+
+
+def load_soong_debug():
+ # Read the json
+ try:
+ with open(SOONG_DEBUG_DATA_FILENAME) as f:
+ info = json.load(f, object_hook=lambda d: types.SimpleNamespace(**d))
+ except IOError:
+ sys.stderr.write(f"error: Unable to open {SOONG_DEBUG_DATA_FILENAME}. Make sure you have"
+ + " built with GENERATE_SOONG_DEBUG.\n")
+ sys.exit(1)
+
+ # Construct IDs, which are name + variant if the
+ name_counts = dict()
+ for m in info.modules:
+ name_counts[m.name] = name_counts.get(m.name, 0) + 1
+ def get_id(m):
+ result = m.name
+ if name_counts[m.name] > 1 and m.variant:
+ result += "@@" + m.variant
+ return result
+ for m in info.modules:
+ m.id = get_id(m)
+ for dep in m.deps:
+ dep.id = get_id(dep)
+
+ return info
+
+
+def load_modules():
+ info = load_soong_debug()
+
+ # Filter out unnamed modules
+ modules = dict()
+ for m in info.modules:
+ if not m.name:
+ continue
+ modules[m.id] = m
+
+ return modules
+
+
+def load_graph():
+ modules=load_modules()
+ return Graph(modules)
+
+
+def module_selection_args(parser):
+ parser.add_argument("modules", nargs="*",
+ help="Modules to match. Can be glob-style wildcards.")
+ parser.add_argument("--provider", nargs="+",
+ help="Match the given providers.")
+ parser.add_argument("--dep", nargs="+",
+ help="Match the given providers.")
+
+
+def load_and_filter_modules(args):
+ # Which modules are printed
+ matchers = []
+ if args.modules:
+ matchers.append(lambda m: [True for pattern in args.modules
+ if fnmatch.fnmatchcase(m.name, pattern)])
+ if args.provider:
+ matchers.append(lambda m: [True for pattern in args.provider
+ if [True for p in m.providers if p.type.endswith(pattern)]])
+ if args.dep:
+ matchers.append(lambda m: [True for pattern in args.dep
+ if [True for d in m.deps if d.id == pattern]])
+
+ if not matchers:
+ sys.stderr.write("error: At least one module matcher must be supplied\n")
+ sys.exit(1)
+
+ info = load_soong_debug()
+ for m in sorted(info.modules, key=lambda m: (m.name, m.variant)):
+ if len([matcher for matcher in matchers if matcher(m)]) == len(matchers):
+ yield m
+
+
+def print_nodes(nodes):
+ print("digraph {")
+ for node in nodes:
+ print(f"\"{node.id}\"[label={format_node_label(node)}];")
+ for dep in node.deps:
+ if dep in nodes:
+ print(f"\"{node.id}\" -> \"{dep.id}\";")
+ print("}")
+
+
+def get_deps(nodes, root):
+ if root in nodes:
+ return
+ nodes.add(root)
+ for dep in root.deps:
+ get_deps(nodes, dep)
+
+
+class BetweenCommand:
+ help = "Print the module graph between two nodes."
+
+ def args(self, parser):
+ parser.add_argument("module", nargs=2,
+ help="The two modules")
+
+ def run(self, args):
+ graph = load_graph()
+ print_nodes(graph.find_paths(args.module[0], args.module[1]))
+
+
+class DepsCommand:
+ help = "Print the module graph of dependencies of one or more modules"
+
+ def args(self, parser):
+ parser.add_argument("module", nargs="+",
+ help="Module to print dependencies of")
+
+ def run(self, args):
+ graph = load_graph()
+ nodes = set()
+ err = False
+ for id in sys.argv[3:]:
+ root = graph.nodes.get(id)
+ if not root:
+ sys.stderr.write(f"error: Can't find root: {id}\n")
+ err = True
+ continue
+ get_deps(nodes, root)
+ if err:
+ sys.exit(1)
+ print_nodes(nodes)
+
+
+class IdCommand:
+ help = "Print the id (name + variant) of matching modules"
+
+ def args(self, parser):
+ module_selection_args(parser)
+
+ def run(self, args):
+ for m in load_and_filter_modules(args):
+ print(m.id)
+
+
+class QueryCommand:
+ help = "Query details about modules"
+
+ def args(self, parser):
+ module_selection_args(parser)
+
+ def run(self, args):
+ for m in load_and_filter_modules(args):
+ print(m.id)
+ print(f" type: {m.type}")
+ print(f" location: {format_source_pos(m.source_file, m.source_line)}")
+ for p in m.providers:
+ print(f" provider: {format_provider(p)}")
+ for d in m.deps:
+ print(f" dep: {d.id}")
+
+
+COMMANDS = {
+ "between": BetweenCommand(),
+ "deps": DepsCommand(),
+ "id": IdCommand(),
+ "query": QueryCommand(),
+}
+
+
+def assert_env(name):
+ val = os.getenv(name)
+ if not val:
+ sys.stderr.write(f"{name} not set. please make sure you've run lunch.")
+ return val
+
+ANDROID_BUILD_TOP = assert_env("ANDROID_BUILD_TOP")
+
+TARGET_PRODUCT = assert_env("TARGET_PRODUCT")
+OUT_DIR = os.getenv("OUT_DIR")
+if not OUT_DIR:
+ OUT_DIR = "out"
+if OUT_DIR[0] != "/":
+ OUT_DIR = pathlib.Path(ANDROID_BUILD_TOP).joinpath(OUT_DIR)
+SOONG_DEBUG_DATA_FILENAME = pathlib.Path(OUT_DIR).joinpath("soong/soong-debug-info.json")
+
+
+def main():
+ parser = argparse.ArgumentParser()
+ subparsers = parser.add_subparsers(required=True, dest="command")
+ for name in sorted(COMMANDS.keys()):
+ command = COMMANDS[name]
+ subparser = subparsers.add_parser(name, help=command.help)
+ command.args(subparser)
+ args = parser.parse_args()
+ COMMANDS[args.command].run(args)
+ sys.exit(0)
+
+
+if __name__ == "__main__":
+ main()
+
diff --git a/cc/compiler.go b/cc/compiler.go
index c57b72c..de1ae71 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -116,6 +116,10 @@
// if set to false, use -std=c++* instead of -std=gnu++*
Gnu_extensions *bool
+ // cc Build rules targeting BPF must set this to true. The correct fix is to
+ // ban targeting bpf in cc rules instead use bpf_rules. (b/323415017)
+ Bpf_target *bool
+
Yacc *YaccProperties
Lex *LexProperties
@@ -483,6 +487,11 @@
}
}
+ // bpf targets don't need the default target triple. b/308826679
+ if proptools.Bool(compiler.Properties.Bpf_target) {
+ target = "--target=bpf"
+ }
+
flags.Global.CFlags = append(flags.Global.CFlags, target)
flags.Global.AsFlags = append(flags.Global.AsFlags, target)
flags.Global.LdFlags = append(flags.Global.LdFlags, target)
@@ -498,8 +507,12 @@
flags.Global.AsFlags = append(flags.Global.AsFlags, tc.Asflags())
flags.Global.CppFlags = append([]string{"${config.CommonGlobalCppflags}"}, flags.Global.CppFlags...)
+
+ // bpf targets don't need the target specific toolchain cflags. b/308826679
+ if !proptools.Bool(compiler.Properties.Bpf_target) {
+ flags.Global.CommonFlags = append(flags.Global.CommonFlags, tc.Cflags())
+ }
flags.Global.CommonFlags = append(flags.Global.CommonFlags,
- tc.Cflags(),
"${config.CommonGlobalCflags}",
fmt.Sprintf("${config.%sGlobalCflags}", hod))
@@ -521,7 +534,11 @@
flags.Global.YasmFlags = append(flags.Global.YasmFlags, tc.YasmFlags())
- flags.Global.CommonFlags = append(flags.Global.CommonFlags, tc.ToolchainCflags())
+ // bpf targets don't need the target specific toolchain cflags. b/308826679
+ if !proptools.Bool(compiler.Properties.Bpf_target) {
+ flags.Global.CommonFlags = append(flags.Global.CommonFlags, tc.ToolchainCflags())
+ }
+
cStd := parseCStd(compiler.Properties.C_std)
cppStd := parseCppStd(compiler.Properties.Cpp_std)
diff --git a/cc/config/bionic.go b/cc/config/bionic.go
index a1e3851..ed724f5 100644
--- a/cc/config/bionic.go
+++ b/cc/config/bionic.go
@@ -24,6 +24,7 @@
bionicCrtBeginStaticBinary, bionicCrtEndStaticBinary = []string{"crtbegin_static"}, []string{"crtend_android"}
bionicCrtBeginSharedBinary, bionicCrtEndSharedBinary = []string{"crtbegin_dynamic"}, []string{"crtend_android"}
bionicCrtBeginSharedLibrary, bionicCrtEndSharedLibrary = []string{"crtbegin_so"}, []string{"crtend_so"}
+ bionicCrtPadSegmentSharedLibrary = []string{"crt_pad_segment"}
)
func (toolchainBionic) Bionic() bool { return true }
@@ -36,9 +37,10 @@
func (toolchainBionic) AvailableLibraries() []string { return nil }
-func (toolchainBionic) CrtBeginStaticBinary() []string { return bionicCrtBeginStaticBinary }
-func (toolchainBionic) CrtBeginSharedBinary() []string { return bionicCrtBeginSharedBinary }
-func (toolchainBionic) CrtBeginSharedLibrary() []string { return bionicCrtBeginSharedLibrary }
-func (toolchainBionic) CrtEndStaticBinary() []string { return bionicCrtEndStaticBinary }
-func (toolchainBionic) CrtEndSharedBinary() []string { return bionicCrtEndSharedBinary }
-func (toolchainBionic) CrtEndSharedLibrary() []string { return bionicCrtEndSharedLibrary }
+func (toolchainBionic) CrtBeginStaticBinary() []string { return bionicCrtBeginStaticBinary }
+func (toolchainBionic) CrtBeginSharedBinary() []string { return bionicCrtBeginSharedBinary }
+func (toolchainBionic) CrtBeginSharedLibrary() []string { return bionicCrtBeginSharedLibrary }
+func (toolchainBionic) CrtEndStaticBinary() []string { return bionicCrtEndStaticBinary }
+func (toolchainBionic) CrtEndSharedBinary() []string { return bionicCrtEndSharedBinary }
+func (toolchainBionic) CrtEndSharedLibrary() []string { return bionicCrtEndSharedLibrary }
+func (toolchainBionic) CrtPadSegmentSharedLibrary() []string { return bionicCrtPadSegmentSharedLibrary }
diff --git a/cc/config/global.go b/cc/config/global.go
index 5fed7f1..c562614 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -253,6 +253,14 @@
// http://b/161386391 for -Wno-pointer-to-int-cast
"-Wno-pointer-to-int-cast",
"-Werror=fortify-source",
+ // http://b/315246135 temporarily disabled
+ "-Wno-error=unused-variable",
+ // http://b/315250603 temporarily disabled
+ "-Wno-error=format",
+ // Disabled because it produces many false positives. http://b/323050926
+ "-Wno-missing-field-initializers",
+ // http://b/323050889
+ "-Wno-packed-non-pod",
"-Werror=address-of-temporary",
"-Werror=incompatible-function-pointer-types",
@@ -351,11 +359,16 @@
// enabling since it's a cosmetic issue.
"-Wno-bitwise-instead-of-logical",
- "-Wno-unused-but-set-variable",
+ "-Wno-unused",
+ "-Wno-unused-parameter",
"-Wno-unused-but-set-parameter",
"-Wno-unqualified-std-cast-call",
"-Wno-array-parameter",
"-Wno-gnu-offsetof-extensions",
+ // TODO: Enable this warning http://b/315245071
+ "-Wno-fortify-source",
+ "-Wno-tautological-negation-compare",
+ "-Wno-tautological-undefined-compare",
}
llvmNextExtraCommonGlobalCflags = []string{
@@ -375,8 +388,8 @@
// prebuilts/clang default settings.
ClangDefaultBase = "prebuilts/clang/host"
- ClangDefaultVersion = "clang-r498229b"
- ClangDefaultShortVersion = "17"
+ ClangDefaultVersion = "clang-r510928"
+ ClangDefaultShortVersion = "18"
// Directories with warnings from Android.bp files.
WarningAllowedProjects = []string{
diff --git a/cc/config/toolchain.go b/cc/config/toolchain.go
index 62f75d1..71e98fe 100644
--- a/cc/config/toolchain.go
+++ b/cc/config/toolchain.go
@@ -100,6 +100,7 @@
CrtEndStaticBinary() []string
CrtEndSharedBinary() []string
CrtEndSharedLibrary() []string
+ CrtPadSegmentSharedLibrary() []string
// DefaultSharedLibraries returns the list of shared libraries that will be added to all
// targets unless they explicitly specify system_shared_libs.
@@ -155,12 +156,13 @@
type toolchainNoCrt struct{}
-func (toolchainNoCrt) CrtBeginStaticBinary() []string { return nil }
-func (toolchainNoCrt) CrtBeginSharedBinary() []string { return nil }
-func (toolchainNoCrt) CrtBeginSharedLibrary() []string { return nil }
-func (toolchainNoCrt) CrtEndStaticBinary() []string { return nil }
-func (toolchainNoCrt) CrtEndSharedBinary() []string { return nil }
-func (toolchainNoCrt) CrtEndSharedLibrary() []string { return nil }
+func (toolchainNoCrt) CrtBeginStaticBinary() []string { return nil }
+func (toolchainNoCrt) CrtBeginSharedBinary() []string { return nil }
+func (toolchainNoCrt) CrtBeginSharedLibrary() []string { return nil }
+func (toolchainNoCrt) CrtEndStaticBinary() []string { return nil }
+func (toolchainNoCrt) CrtEndSharedBinary() []string { return nil }
+func (toolchainNoCrt) CrtEndSharedLibrary() []string { return nil }
+func (toolchainNoCrt) CrtPadSegmentSharedLibrary() []string { return nil }
func (toolchainBase) DefaultSharedLibraries() []string {
return nil
diff --git a/cc/config/x86_linux_host.go b/cc/config/x86_linux_host.go
index f95da0b..f497bf9 100644
--- a/cc/config/x86_linux_host.go
+++ b/cc/config/x86_linux_host.go
@@ -328,12 +328,13 @@
func (toolchainMusl) Musl() bool { return true }
-func (toolchainMusl) CrtBeginStaticBinary() []string { return muslCrtBeginStaticBinary }
-func (toolchainMusl) CrtBeginSharedBinary() []string { return muslCrtBeginSharedBinary }
-func (toolchainMusl) CrtBeginSharedLibrary() []string { return muslCrtBeginSharedLibrary }
-func (toolchainMusl) CrtEndStaticBinary() []string { return muslCrtEndStaticBinary }
-func (toolchainMusl) CrtEndSharedBinary() []string { return muslCrtEndSharedBinary }
-func (toolchainMusl) CrtEndSharedLibrary() []string { return muslCrtEndSharedLibrary }
+func (toolchainMusl) CrtBeginStaticBinary() []string { return muslCrtBeginStaticBinary }
+func (toolchainMusl) CrtBeginSharedBinary() []string { return muslCrtBeginSharedBinary }
+func (toolchainMusl) CrtBeginSharedLibrary() []string { return muslCrtBeginSharedLibrary }
+func (toolchainMusl) CrtEndStaticBinary() []string { return muslCrtEndStaticBinary }
+func (toolchainMusl) CrtEndSharedBinary() []string { return muslCrtEndSharedBinary }
+func (toolchainMusl) CrtEndSharedLibrary() []string { return muslCrtEndSharedLibrary }
+func (toolchainMusl) CrtPadSegmentSharedLibrary() []string { return nil }
func (toolchainMusl) DefaultSharedLibraries() []string { return MuslDefaultSharedLibraries }
diff --git a/cc/library.go b/cc/library.go
index 4b6ac59..4684d32 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -974,6 +974,10 @@
if library.baseLinker.Properties.crt() {
deps.CrtBegin = append(deps.CrtBegin, ctx.toolchain().CrtBeginSharedLibrary()...)
deps.CrtEnd = append(deps.CrtEnd, ctx.toolchain().CrtEndSharedLibrary()...)
+
+ }
+ if library.baseLinker.Properties.crtPadSegment() {
+ deps.CrtEnd = append(deps.CrtEnd, ctx.toolchain().CrtPadSegmentSharedLibrary()...)
}
deps.WholeStaticLibs = append(deps.WholeStaticLibs, library.SharedProperties.Shared.Whole_static_libs...)
deps.StaticLibs = append(deps.StaticLibs, library.SharedProperties.Shared.Static_libs...)
@@ -1476,7 +1480,9 @@
headerAbiChecker.Exclude_symbol_tags,
currVersion)
- addLsdumpPath(classifySourceAbiDump(ctx) + ":" + library.sAbiOutputFile.String())
+ for _, tag := range classifySourceAbiDump(ctx) {
+ addLsdumpPath(tag + ":" + library.sAbiOutputFile.String())
+ }
dumpDir := getRefAbiDumpDir(isNdk, isLlndk)
binderBitness := ctx.DeviceConfig().BinderBitness()
diff --git a/cc/linker.go b/cc/linker.go
index 85c128e..2c50db2 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -91,6 +91,10 @@
// compiling crt or libc.
Nocrt *bool `android:"arch_variant"`
+ // don't link in crt_pad_segment. This flag is currently only used internal to
+ // soong for testing and for vndk prebuilt shared libraries.
+ No_crt_pad_segment *bool `android:"arch_variant"`
+
// deprecated and ignored because lld makes it unnecessary. See b/189475744.
Group_static_libs *bool `android:"arch_variant"`
@@ -253,6 +257,10 @@
return blp.No_libcrt == nil || !*blp.No_libcrt
}
+func (blp *BaseLinkerProperties) crtPadSegment() bool {
+ return blp.No_crt_pad_segment == nil || !*blp.No_crt_pad_segment
+}
+
func NewBaseLinker(sanitize *sanitize) *baseLinker {
return &baseLinker{sanitize: sanitize}
}
diff --git a/cc/sabi.go b/cc/sabi.go
index 9f5781f..4ca9f5c 100644
--- a/cc/sabi.go
+++ b/cc/sabi.go
@@ -97,36 +97,34 @@
return sabi != nil && sabi.Properties.ShouldCreateSourceAbiDump
}
-// Returns a string that represents the class of the ABI dump.
-// Returns an empty string if ABI check is disabled for this library.
-func classifySourceAbiDump(ctx android.BaseModuleContext) string {
+// Returns a slice of strings that represent the ABI dumps generated for this module.
+func classifySourceAbiDump(ctx android.BaseModuleContext) []string {
+ result := []string{}
m := ctx.Module().(*Module)
headerAbiChecker := m.library.getHeaderAbiCheckerProperties(ctx)
if headerAbiChecker.explicitlyDisabled() {
- return ""
+ return result
}
if !m.InProduct() && !m.InVendor() {
- // Return NDK if the library is both NDK and LLNDK.
- if m.IsNdk(ctx.Config()) {
- return "NDK"
- }
if m.isImplementationForLLNDKPublic() {
- return "LLNDK"
+ result = append(result, "LLNDK")
}
- if m.library.hasStubsVariants() {
- return "PLATFORM"
+ // Return NDK if the library is both NDK and APEX.
+ // TODO(b/309880485): Split NDK and APEX ABI.
+ if m.IsNdk(ctx.Config()) {
+ result = append(result, "NDK")
+ } else if m.library.hasStubsVariants() || headerAbiChecker.enabled() {
+ result = append(result, "PLATFORM")
}
- }
- if headerAbiChecker.enabled() {
+ } else if headerAbiChecker.enabled() {
if m.InProduct() {
- return "PRODUCT"
+ result = append(result, "PRODUCT")
}
if m.InVendor() {
- return "VENDOR"
+ result = append(result, "VENDOR")
}
- return "PLATFORM"
}
- return ""
+ return result
}
// Called from sabiDepsMutator to check whether ABI dumps should be created for this module.
@@ -195,7 +193,7 @@
return false
}
}
- return classifySourceAbiDump(ctx) != ""
+ return len(classifySourceAbiDump(ctx)) > 0
}
// Mark the direct and transitive dependencies of libraries that need ABI check, so that ABI dumps
diff --git a/cc/testing.go b/cc/testing.go
index bac41e7..9c2900c 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -77,6 +77,7 @@
no_libcrt: true,
sdk_version: "minimum",
nocrt: true,
+ no_crt_pad_segment: true,
system_shared_libs: [],
stl: "none",
check_elf_files: false,
@@ -385,6 +386,11 @@
}
cc_object {
+ name: "crt_pad_segment",
+ defaults: ["crt_defaults"],
+ }
+
+ cc_object {
name: "crtbrand",
defaults: ["crt_defaults"],
srcs: ["crtbrand.c"],
diff --git a/cc/vendor_snapshot_test.go b/cc/vendor_snapshot_test.go
index 890a533..0a55431 100644
--- a/cc/vendor_snapshot_test.go
+++ b/cc/vendor_snapshot_test.go
@@ -341,6 +341,7 @@
vendor: true,
nocrt: true,
no_libcrt: true,
+ no_crt_pad_segment: true,
stl: "none",
system_shared_libs: [],
compile_multilib: "64",
@@ -458,6 +459,7 @@
vendor: true,
nocrt: true,
no_libcrt: true,
+ no_crt_pad_segment: true,
stl: "none",
system_shared_libs: [],
}
@@ -467,6 +469,7 @@
vendor: true,
nocrt: true,
no_libcrt: true,
+ no_crt_pad_segment: true,
stl: "none",
system_shared_libs: [],
shared_libs: ["libvndk", "libvendor_available", "libllndk"],
@@ -487,6 +490,7 @@
vendor: true,
nocrt: true,
no_libcrt: true,
+ no_crt_pad_segment: true,
stl: "none",
system_shared_libs: [],
static_libs: ["libvendor"],
@@ -501,6 +505,7 @@
vendor: true,
nocrt: true,
no_libcrt: true,
+ no_crt_pad_segment: true,
stl: "none",
system_shared_libs: [],
vndk: {
@@ -597,6 +602,7 @@
target_arch: "arm64",
compile_multilib: "both",
vendor: true,
+ no_crt_pad_segment: true,
shared_libs: [
"libvendor_without_snapshot",
"libvendor_available",
@@ -620,6 +626,7 @@
target_arch: "arm64",
compile_multilib: "both",
vendor: true,
+ no_crt_pad_segment: true,
overrides: ["libvendor"],
shared_libs: [
"libvendor_without_snapshot",
@@ -657,6 +664,7 @@
target_arch: "arm64",
compile_multilib: "32",
vendor: true,
+ no_crt_pad_segment: true,
arch: {
arm: {
src: "lib32.so",
@@ -683,6 +691,7 @@
target_arch: "arm64",
compile_multilib: "64",
vendor: true,
+ no_crt_pad_segment: true,
arch: {
arm64: {
src: "lib64.so",
@@ -722,6 +731,7 @@
target_arch: "arm64",
compile_multilib: "both",
vendor: true,
+ no_crt_pad_segment: true,
arch: {
arm64: {
src: "libvendor_available.so",
diff --git a/cc/vndk.go b/cc/vndk.go
index 0e0dba9..2b2ea64 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -377,22 +377,17 @@
return false
}
- // ignore prebuilt vndk modules that are newer than or equal to the platform vndk version
- platformVndkApiLevel := android.ApiLevelOrPanic(mctx, mctx.DeviceConfig().PlatformVndkVersion())
- if platformVndkApiLevel.LessThanOrEqualTo(android.ApiLevelOrPanic(mctx, p.Version())) {
- return false
+ platformVndkVersion := mctx.DeviceConfig().PlatformVndkVersion()
+ if platformVndkVersion != "" {
+ // ignore prebuilt vndk modules that are newer than or equal to the platform vndk version
+ platformVndkApiLevel := android.ApiLevelOrPanic(mctx, platformVndkVersion)
+ if platformVndkApiLevel.LessThanOrEqualTo(android.ApiLevelOrPanic(mctx, p.Version())) {
+ return false
+ }
}
}
if lib, ok := m.linker.(libraryInterface); ok {
- // VNDK APEX for VNDK-Lite devices will have VNDK-SP libraries from core variants
- if mctx.DeviceConfig().VndkVersion() == "" {
- // b/73296261: filter out libz.so because it is considered as LLNDK for VNDK-lite devices
- if mctx.ModuleName() == "libz" {
- return false
- }
- return m.ImageVariation().Variation == android.CoreVariation && lib.shared() && m.IsVndkSp() && !m.IsVndkExt()
- }
// VNDK APEX doesn't need stub variants
if lib.buildStubs() {
return false
diff --git a/cc/vndk_prebuilt.go b/cc/vndk_prebuilt.go
index eb1790f..43030b8 100644
--- a/cc/vndk_prebuilt.go
+++ b/cc/vndk_prebuilt.go
@@ -131,11 +131,14 @@
func (p *vndkPrebuiltLibraryDecorator) link(ctx ModuleContext,
flags Flags, deps PathDeps, objs Objects) android.Path {
- platformVndkApiLevel := android.ApiLevelOrPanic(ctx, ctx.DeviceConfig().PlatformVndkVersion())
- if platformVndkApiLevel.LessThanOrEqualTo(android.ApiLevelOrPanic(ctx, p.Version())) {
- // This prebuilt VNDK module is not required for the current build
- ctx.Module().HideFromMake()
- return nil
+ platformVndkVersion := ctx.DeviceConfig().PlatformVndkVersion()
+ if platformVndkVersion != "" {
+ platformVndkApiLevel := android.ApiLevelOrPanic(ctx, platformVndkVersion)
+ if platformVndkApiLevel.LessThanOrEqualTo(android.ApiLevelOrPanic(ctx, p.Version())) {
+ // This prebuilt VNDK module is not required for the current build
+ ctx.Module().HideFromMake()
+ return nil
+ }
}
if !p.MatchesWithDevice(ctx.DeviceConfig()) {
@@ -232,6 +235,7 @@
prebuilt.properties.Check_elf_files = BoolPtr(false)
prebuilt.baseLinker.Properties.No_libcrt = BoolPtr(true)
prebuilt.baseLinker.Properties.Nocrt = BoolPtr(true)
+ prebuilt.baseLinker.Properties.No_crt_pad_segment = BoolPtr(true)
// Prevent default system libs (libc, libm, and libdl) from being linked
if prebuilt.baseLinker.Properties.System_shared_libs == nil {
@@ -246,14 +250,6 @@
&prebuilt.properties,
)
- android.AddLoadHook(module, func(ctx android.LoadHookContext) {
- // empty BOARD_VNDK_VERSION implies that the device won't support
- // system only OTA. In this case, VNDK snapshots aren't needed.
- if ctx.DeviceConfig().VndkVersion() == "" {
- ctx.Module().Disable()
- }
- })
-
return module
}
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 4727566..673f305 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -79,6 +79,7 @@
flag.BoolVar(&cmdlineArgs.MultitreeBuild, "multitree-build", false, "this is a multitree build")
flag.BoolVar(&cmdlineArgs.BuildFromSourceStub, "build-from-source-stub", false, "build Java stubs from source files instead of API text files")
flag.BoolVar(&cmdlineArgs.EnsureAllowlistIntegrity, "ensure-allowlist-integrity", false, "verify that allowlisted modules are mixed-built")
+ flag.StringVar(&cmdlineArgs.ModuleDebugFile, "soong_module_debug", "", "soong module debug info file to write")
// Flags that probably shouldn't be flags of soong_build, but we haven't found
// the time to remove them yet
flag.BoolVar(&cmdlineArgs.RunGoTests, "t", false, "build and run go tests during bootstrap")
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index 6163952..fe6317c 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -98,7 +98,9 @@
// measure, as it masks real errors and affects performance.
RelaxUsesLibraryCheck bool
- EnableUffdGc bool // preopt with the assumption that userfaultfd GC will be used on device.
+ // "true" to force preopt with CMC GC (a.k.a., UFFD GC); "false" to force preopt with CC GC;
+ // "default" to determine the GC type based on the kernel version file.
+ EnableUffdGc string
}
var allPlatformSystemServerJarsKey = android.NewOnceKey("allPlatformSystemServerJars")
@@ -154,6 +156,7 @@
Zip2zip android.Path
ManifestCheck android.Path
ConstructContext android.Path
+ UffdGcFlag android.WritablePath
}
type ModuleConfig struct {
@@ -537,6 +540,7 @@
Zip2zip: ctx.Config().HostToolPath(ctx, "zip2zip"),
ManifestCheck: ctx.Config().HostToolPath(ctx, "manifest_check"),
ConstructContext: ctx.Config().HostToolPath(ctx, "construct_context"),
+ UffdGcFlag: getUffdGcFlagPath(ctx),
}
}
@@ -588,6 +592,7 @@
Zip2zip string
ManifestCheck string
ConstructContext string
+ UffdGcFlag string
}
// ParseGlobalSoongConfig parses the given data assumed to be read from the
@@ -609,6 +614,7 @@
Zip2zip: constructPath(ctx, jc.Zip2zip),
ManifestCheck: constructPath(ctx, jc.ManifestCheck),
ConstructContext: constructPath(ctx, jc.ConstructContext),
+ UffdGcFlag: constructWritablePath(ctx, jc.UffdGcFlag),
}
return config, nil
@@ -633,12 +639,15 @@
}
func (s *globalSoongConfigSingleton) GenerateBuildActions(ctx android.SingletonContext) {
- checkBootJarsConfigConsistency(ctx, GetGlobalConfig(ctx), ctx.Config())
+ global := GetGlobalConfig(ctx)
+ checkBootJarsConfigConsistency(ctx, global, ctx.Config())
- if GetGlobalConfig(ctx).DisablePreopt {
+ if global.DisablePreopt {
return
}
+ buildUffdGcFlag(ctx, global)
+
config := GetCachedGlobalSoongConfig(ctx)
if config == nil {
// No module has enabled dexpreopting, so we assume there will be no calls
@@ -654,6 +663,7 @@
Zip2zip: config.Zip2zip.String(),
ManifestCheck: config.ManifestCheck.String(),
ConstructContext: config.ConstructContext.String(),
+ UffdGcFlag: config.UffdGcFlag.String(),
}
data, err := json.Marshal(jc)
@@ -684,9 +694,32 @@
config.Zip2zip.String(),
config.ManifestCheck.String(),
config.ConstructContext.String(),
+ config.UffdGcFlag.String(),
}, " "))
}
+func buildUffdGcFlag(ctx android.BuilderContext, global *GlobalConfig) {
+ uffdGcFlag := getUffdGcFlagPath(ctx)
+
+ if global.EnableUffdGc == "true" {
+ android.WriteFileRuleVerbatim(ctx, uffdGcFlag, "--runtime-arg -Xgc:CMC")
+ } else if global.EnableUffdGc == "false" {
+ android.WriteFileRuleVerbatim(ctx, uffdGcFlag, "")
+ } else if global.EnableUffdGc == "default" {
+ // Generated by `build/make/core/Makefile`.
+ kernelVersionFile := android.PathForOutput(ctx, "dexpreopt/kernel_version_for_uffd_gc.txt")
+ // Determine the UFFD GC flag by the kernel version file.
+ rule := android.NewRuleBuilder(pctx, ctx)
+ rule.Command().
+ Tool(ctx.Config().HostToolPath(ctx, "construct_uffd_gc_flag")).
+ Input(kernelVersionFile).
+ Output(uffdGcFlag)
+ rule.Restat().Build("dexpreopt_uffd_gc_flag", "dexpreopt_uffd_gc_flag")
+ } else {
+ panic(fmt.Sprintf("Unknown value of PRODUCT_ENABLE_UFFD_GC: %s", global.EnableUffdGc))
+ }
+}
+
func GlobalConfigForTests(ctx android.PathContext) *GlobalConfig {
return &GlobalConfig{
DisablePreopt: false,
@@ -731,7 +764,7 @@
}
}
-func globalSoongConfigForTests() *GlobalSoongConfig {
+func globalSoongConfigForTests(ctx android.BuilderContext) *GlobalSoongConfig {
return &GlobalSoongConfig{
Profman: android.PathForTesting("profman"),
Dex2oat: android.PathForTesting("dex2oat"),
@@ -740,5 +773,19 @@
Zip2zip: android.PathForTesting("zip2zip"),
ManifestCheck: android.PathForTesting("manifest_check"),
ConstructContext: android.PathForTesting("construct_context"),
+ UffdGcFlag: android.PathForOutput(ctx, "dexpreopt_test", "uffd_gc_flag.txt"),
}
}
+
+func GetDexpreoptDirName(ctx android.PathContext) string {
+ prefix := "dexpreopt_"
+ targets := ctx.Config().Targets[android.Android]
+ if len(targets) > 0 {
+ return prefix + targets[0].Arch.ArchType.String()
+ }
+ return prefix + "unknown_target"
+}
+
+func getUffdGcFlagPath(ctx android.PathContext) android.WritablePath {
+ return android.PathForOutput(ctx, "dexpreopt/uffd_gc_flag.txt")
+}
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index 94707ba..04bc61d 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -390,7 +390,8 @@
Flag("--generate-build-id").
Flag("--abort-on-hard-verifier-error").
Flag("--force-determinism").
- FlagWithArg("--no-inline-from=", "core-oj.jar")
+ FlagWithArg("--no-inline-from=", "core-oj.jar").
+ Text("$(cat").Input(globalSoong.UffdGcFlag).Text(")")
var preoptFlags []string
if len(module.PreoptFlags) > 0 {
@@ -506,10 +507,6 @@
cmd.FlagWithInput("--profile-file=", profile)
}
- if global.EnableUffdGc {
- cmd.Flag("--runtime-arg").Flag("-Xgc:CMC")
- }
-
rule.Install(odexPath, odexInstallPath)
rule.Install(vdexPath, vdexInstallPath)
}
diff --git a/dexpreopt/dexpreopt_test.go b/dexpreopt/dexpreopt_test.go
index 230fbb4..7071f3e 100644
--- a/dexpreopt/dexpreopt_test.go
+++ b/dexpreopt/dexpreopt_test.go
@@ -96,7 +96,7 @@
func TestDexPreopt(t *testing.T) {
config := android.TestConfig("out", nil, "", nil)
ctx := android.BuilderContextForTesting(config)
- globalSoong := globalSoongConfigForTests()
+ globalSoong := globalSoongConfigForTests(ctx)
global := GlobalConfigForTests(ctx)
module := testSystemModuleConfig(ctx, "test")
productPackages := android.PathForTesting("product_packages.txt")
@@ -114,12 +114,15 @@
if rule.Installs().String() != wantInstalls.String() {
t.Errorf("\nwant installs:\n %v\ngot:\n %v", wantInstalls, rule.Installs())
}
+
+ android.AssertStringListContains(t, "", rule.Inputs().RelativeToTop().Strings(),
+ "out/soong/dexpreopt_test/uffd_gc_flag.txt")
}
func TestDexPreoptSystemOther(t *testing.T) {
config := android.TestConfig("out", nil, "", nil)
ctx := android.BuilderContextForTesting(config)
- globalSoong := globalSoongConfigForTests()
+ globalSoong := globalSoongConfigForTests(ctx)
global := GlobalConfigForTests(ctx)
systemModule := testSystemModuleConfig(ctx, "Stest")
systemProductModule := testSystemProductModuleConfig(ctx, "SPtest")
@@ -180,7 +183,7 @@
func TestDexPreoptApexSystemServerJars(t *testing.T) {
config := android.TestConfig("out", nil, "", nil)
ctx := android.BuilderContextForTesting(config)
- globalSoong := globalSoongConfigForTests()
+ globalSoong := globalSoongConfigForTests(ctx)
global := GlobalConfigForTests(ctx)
module := testApexModuleConfig(ctx, "service-A", "com.android.apex1")
productPackages := android.PathForTesting("product_packages.txt")
@@ -204,7 +207,7 @@
func TestDexPreoptStandaloneSystemServerJars(t *testing.T) {
config := android.TestConfig("out", nil, "", nil)
ctx := android.BuilderContextForTesting(config)
- globalSoong := globalSoongConfigForTests()
+ globalSoong := globalSoongConfigForTests(ctx)
global := GlobalConfigForTests(ctx)
module := testPlatformSystemServerModuleConfig(ctx, "service-A")
productPackages := android.PathForTesting("product_packages.txt")
@@ -228,7 +231,7 @@
func TestDexPreoptSystemExtSystemServerJars(t *testing.T) {
config := android.TestConfig("out", nil, "", nil)
ctx := android.BuilderContextForTesting(config)
- globalSoong := globalSoongConfigForTests()
+ globalSoong := globalSoongConfigForTests(ctx)
global := GlobalConfigForTests(ctx)
module := testSystemExtSystemServerModuleConfig(ctx, "service-A")
productPackages := android.PathForTesting("product_packages.txt")
@@ -252,7 +255,7 @@
func TestDexPreoptApexStandaloneSystemServerJars(t *testing.T) {
config := android.TestConfig("out", nil, "", nil)
ctx := android.BuilderContextForTesting(config)
- globalSoong := globalSoongConfigForTests()
+ globalSoong := globalSoongConfigForTests(ctx)
global := GlobalConfigForTests(ctx)
module := testApexModuleConfig(ctx, "service-A", "com.android.apex1")
productPackages := android.PathForTesting("product_packages.txt")
@@ -276,7 +279,7 @@
func TestDexPreoptProfile(t *testing.T) {
config := android.TestConfig("out", nil, "", nil)
ctx := android.BuilderContextForTesting(config)
- globalSoong := globalSoongConfigForTests()
+ globalSoong := globalSoongConfigForTests(ctx)
global := GlobalConfigForTests(ctx)
module := testSystemModuleConfig(ctx, "test")
productPackages := android.PathForTesting("product_packages.txt")
@@ -316,3 +319,55 @@
after := fmt.Sprintf("%v", parsed)
android.AssertStringEquals(t, "The result must be the same as the original after marshalling and unmarshalling it.", before, after)
}
+
+func TestUffdGcFlagForce(t *testing.T) {
+ for _, enableUffdGc := range []string{"true", "false"} {
+ t.Run(enableUffdGc, func(t *testing.T) {
+ preparers := android.GroupFixturePreparers(
+ PrepareForTestWithFakeDex2oatd,
+ PrepareForTestWithDexpreoptConfig,
+ FixtureSetEnableUffdGc(enableUffdGc),
+ )
+
+ result := preparers.RunTest(t)
+ ctx := result.TestContext
+
+ ctx.SingletonForTests("dexpreopt-soong-config").Output("out/soong/dexpreopt/uffd_gc_flag.txt")
+ })
+ }
+}
+
+func TestUffdGcFlagDefault(t *testing.T) {
+ preparers := android.GroupFixturePreparers(
+ PrepareForTestWithFakeDex2oatd,
+ PrepareForTestWithDexpreoptConfig,
+ FixtureSetEnableUffdGc("default"),
+ )
+
+ result := preparers.RunTest(t)
+ ctx := result.TestContext
+ config := ctx.Config()
+
+ rule := ctx.SingletonForTests("dexpreopt-soong-config").Rule("dexpreopt_uffd_gc_flag")
+
+ android.AssertStringDoesContain(t, "", rule.RuleParams.Command, "construct_uffd_gc_flag")
+ android.AssertStringPathsRelativeToTopEquals(t, "", config, []string{
+ "out/soong/dexpreopt/uffd_gc_flag.txt",
+ }, rule.AllOutputs())
+ android.AssertPathsRelativeToTopEquals(t, "", []string{
+ "out/soong/dexpreopt/kernel_version_for_uffd_gc.txt",
+ }, rule.Implicits)
+}
+
+func TestUffdGcFlagBogus(t *testing.T) {
+ preparers := android.GroupFixturePreparers(
+ PrepareForTestWithFakeDex2oatd,
+ PrepareForTestWithDexpreoptConfig,
+ FixtureSetEnableUffdGc("bogus"),
+ )
+
+ preparers.
+ ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
+ "Unknown value of PRODUCT_ENABLE_UFFD_GC: bogus")).
+ RunTest(t)
+}
diff --git a/dexpreopt/testing.go b/dexpreopt/testing.go
index 147a562..b1fbef5 100644
--- a/dexpreopt/testing.go
+++ b/dexpreopt/testing.go
@@ -88,6 +88,15 @@
FixtureModifyGlobalConfig(func(android.PathContext, *GlobalConfig) {}),
)
+var PrepareForTestWithDexpreoptConfig = android.GroupFixturePreparers(
+ android.PrepareForTestWithAndroidBuildComponents,
+ android.FixtureModifyContext(func(ctx *android.TestContext) {
+ ctx.RegisterParallelSingletonType("dexpreopt-soong-config", func() android.Singleton {
+ return &globalSoongConfigSingleton{}
+ })
+ }),
+)
+
// FixtureModifyGlobalConfig enables dexpreopt (unless modified by the mutator) and modifies the
// configuration.
func FixtureModifyGlobalConfig(configModifier func(ctx android.PathContext, dexpreoptConfig *GlobalConfig)) android.FixturePreparer {
@@ -195,3 +204,10 @@
dexpreoptConfig.DisablePreopt = disable
})
}
+
+// FixtureSetEnableUffdGc sets the EnableUffdGc property in the global config.
+func FixtureSetEnableUffdGc(value string) android.FixturePreparer {
+ return FixtureModifyGlobalConfig(func(_ android.PathContext, dexpreoptConfig *GlobalConfig) {
+ dexpreoptConfig.EnableUffdGc = value
+ })
+}
diff --git a/java/androidmk.go b/java/androidmk.go
index b523594..b7df9bf 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -549,8 +549,8 @@
if BoolDefault(jd.properties.Installable, true) {
entries.SetPath("LOCAL_DROIDDOC_DOC_ZIP", jd.docZip)
}
- if jd.stubsSrcJar != nil {
- entries.SetPath("LOCAL_DROIDDOC_STUBS_SRCJAR", jd.stubsSrcJar)
+ if jd.exportableStubsSrcJar != nil {
+ entries.SetPath("LOCAL_DROIDDOC_STUBS_SRCJAR", jd.exportableStubsSrcJar)
}
},
},
@@ -596,17 +596,17 @@
Include: "$(BUILD_SYSTEM)/soong_droiddoc_prebuilt.mk",
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- if dstubs.Javadoc.stubsSrcJar != nil {
- entries.SetPath("LOCAL_DROIDDOC_STUBS_SRCJAR", dstubs.Javadoc.stubsSrcJar)
+ if dstubs.Javadoc.exportableStubsSrcJar != nil {
+ entries.SetPath("LOCAL_DROIDDOC_STUBS_SRCJAR", dstubs.Javadoc.exportableStubsSrcJar)
}
if dstubs.everythingArtifacts.apiVersionsXml != nil {
- entries.SetPath("LOCAL_DROIDDOC_API_VERSIONS_XML", dstubs.everythingArtifacts.apiVersionsXml)
+ entries.SetPath("LOCAL_DROIDDOC_API_VERSIONS_XML", dstubs.exportableArtifacts.apiVersionsXml)
}
if dstubs.everythingArtifacts.annotationsZip != nil {
- entries.SetPath("LOCAL_DROIDDOC_ANNOTATIONS_ZIP", dstubs.everythingArtifacts.annotationsZip)
+ entries.SetPath("LOCAL_DROIDDOC_ANNOTATIONS_ZIP", dstubs.exportableArtifacts.annotationsZip)
}
if dstubs.everythingArtifacts.metadataZip != nil {
- entries.SetPath("LOCAL_DROIDDOC_METADATA_ZIP", dstubs.everythingArtifacts.metadataZip)
+ entries.SetPath("LOCAL_DROIDDOC_METADATA_ZIP", dstubs.exportableArtifacts.metadataZip)
}
},
},
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index ec8b4c8..01f60d4 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -617,7 +617,8 @@
// GenerateSingletonBuildActions generates build rules for the dexpreopt config for Make.
func (d *dexpreoptBootJars) GenerateSingletonBuildActions(ctx android.SingletonContext) {
- d.dexpreoptConfigForMake = android.PathForOutput(ctx, getDexpreoptDirName(ctx), "dexpreopt.config")
+ d.dexpreoptConfigForMake =
+ android.PathForOutput(ctx, dexpreopt.GetDexpreoptDirName(ctx), "dexpreopt.config")
writeGlobalConfigForMake(ctx, d.dexpreoptConfigForMake)
}
@@ -1066,8 +1067,8 @@
cmd.FlagWithArg("--instruction-set-features=", global.InstructionSetFeatures[arch])
}
- if global.EnableUffdGc && image.target.Os == android.Android {
- cmd.Flag("--runtime-arg").Flag("-Xgc:CMC")
+ if image.target.Os == android.Android {
+ cmd.Text("$(cat").Input(globalSoong.UffdGcFlag).Text(")")
}
if global.BootFlags != "" {
@@ -1235,7 +1236,7 @@
func dumpOatRules(ctx android.ModuleContext, image *bootImageConfig) {
var allPhonies android.Paths
name := image.name
- global := dexpreopt.GetGlobalConfig(ctx)
+ globalSoong := dexpreopt.GetGlobalSoongConfig(ctx)
for _, image := range image.variants {
arch := image.target.Arch.ArchType
suffix := arch.String()
@@ -1247,6 +1248,7 @@
output := android.PathForOutput(ctx, name+"."+suffix+".oatdump.txt")
rule := android.NewRuleBuilder(pctx, ctx)
imageLocationsOnHost, _ := image.imageLocations()
+
cmd := rule.Command().
BuiltTool("oatdump").
FlagWithInputList("--runtime-arg -Xbootclasspath:", image.dexPathsDeps.Paths(), ":").
@@ -1254,8 +1256,8 @@
FlagWithArg("--image=", strings.Join(imageLocationsOnHost, ":")).Implicits(image.imagesDeps.Paths()).
FlagWithOutput("--output=", output).
FlagWithArg("--instruction-set=", arch.String())
- if global.EnableUffdGc && image.target.Os == android.Android {
- cmd.Flag("--runtime-arg").Flag("-Xgc:CMC")
+ if image.target.Os == android.Android {
+ cmd.Text("$(cat").Input(globalSoong.UffdGcFlag).Text(")")
}
rule.Build("dump-oat-"+name+"-"+suffix, "dump oat "+name+" "+arch.String())
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index 254b2c1..dc0973c 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -115,7 +115,7 @@
func genBootImageConfigs(ctx android.PathContext) map[string]*bootImageConfig {
return ctx.Config().Once(bootImageConfigKey, func() interface{} {
targets := dexpreoptTargets(ctx)
- deviceDir := android.PathForOutput(ctx, getDexpreoptDirName(ctx))
+ deviceDir := android.PathForOutput(ctx, dexpreopt.GetDexpreoptDirName(ctx))
configs := genBootImageConfigRaw(ctx)
@@ -234,12 +234,3 @@
func dexpreoptConfigMakevars(ctx android.MakeVarsContext) {
ctx.Strict("DEXPREOPT_BOOT_JARS_MODULES", strings.Join(defaultBootImageConfig(ctx).modules.CopyOfApexJarPairs(), ":"))
}
-
-func getDexpreoptDirName(ctx android.PathContext) string {
- prefix := "dexpreopt_"
- targets := ctx.Config().Targets[android.Android]
- if len(targets) > 0 {
- return prefix + targets[0].Arch.ArchType.String()
- }
- return prefix + "unknown_target"
-}
diff --git a/java/droidstubs.go b/java/droidstubs.go
index 6ef2afe..4267545 100644
--- a/java/droidstubs.go
+++ b/java/droidstubs.go
@@ -333,66 +333,89 @@
}
}
-func (d *Droidstubs) AnnotationsZip(stubsType StubsType) (android.Path, error) {
+func (d *Droidstubs) AnnotationsZip(stubsType StubsType) (ret android.Path, err error) {
switch stubsType {
case Everything:
- return d.everythingArtifacts.annotationsZip, nil
+ ret, err = d.everythingArtifacts.annotationsZip, nil
case Exportable:
- return d.exportableArtifacts.annotationsZip, nil
+ ret, err = d.exportableArtifacts.annotationsZip, nil
default:
- return nil, fmt.Errorf("annotations zip not supported for the stub type %s", stubsType.String())
+ ret, err = nil, fmt.Errorf("annotations zip not supported for the stub type %s", stubsType.String())
}
+ return ret, err
}
-func (d *Droidstubs) ApiFilePath(stubsType StubsType) (android.Path, error) {
+func (d *Droidstubs) ApiFilePath(stubsType StubsType) (ret android.Path, err error) {
switch stubsType {
case Everything:
- return d.apiFile, nil
+ ret, err = d.apiFile, nil
case Exportable:
- return d.exportableApiFile, nil
+ ret, err = d.exportableApiFile, nil
default:
- return nil, fmt.Errorf("api file path not supported for the stub type %s", stubsType.String())
+ ret, err = nil, fmt.Errorf("api file path not supported for the stub type %s", stubsType.String())
}
+ if ret == nil && err == nil {
+ err = fmt.Errorf("stubs srcjar is null for the stub type %s", stubsType.String())
+ }
+ return ret, err
}
-func (d *Droidstubs) ApiVersionsXmlFilePath(stubsType StubsType) (android.Path, error) {
+func (d *Droidstubs) ApiVersionsXmlFilePath(stubsType StubsType) (ret android.Path, err error) {
switch stubsType {
case Everything:
- return d.everythingArtifacts.apiVersionsXml, nil
- default:
- return nil, fmt.Errorf("api versions xml file path not supported for the stub type %s", stubsType.String())
- }
-}
-
-func (d *Droidstubs) DocZip(stubsType StubsType) (android.Path, error) {
- switch stubsType {
- case Everything:
- return d.docZip, nil
- default:
- return nil, fmt.Errorf("docs zip not supported for the stub type %s", stubsType.String())
- }
-}
-
-func (d *Droidstubs) RemovedApiFilePath(stubsType StubsType) (android.Path, error) {
- switch stubsType {
- case Everything:
- return d.removedApiFile, nil
+ ret, err = d.everythingArtifacts.apiVersionsXml, nil
case Exportable:
- return d.exportableRemovedApiFile, nil
+ ret, err = d.exportableArtifacts.apiVersionsXml, nil
default:
- return nil, fmt.Errorf("removed api file path not supported for the stub type %s", stubsType.String())
+ ret, err = nil, fmt.Errorf("api versions xml file path not supported for the stub type %s", stubsType.String())
}
+ if ret == nil && err == nil {
+ err = fmt.Errorf("api versions xml file is null for the stub type %s", stubsType.String())
+ }
+ return ret, err
}
-func (d *Droidstubs) StubsSrcJar(stubsType StubsType) (android.Path, error) {
+func (d *Droidstubs) DocZip(stubsType StubsType) (ret android.Path, err error) {
switch stubsType {
case Everything:
- return d.stubsSrcJar, nil
- case Exportable:
- return d.exportableStubsSrcJar, nil
+ ret, err = d.docZip, nil
default:
- return nil, fmt.Errorf("stubs srcjar not supported for the stub type %s", stubsType.String())
+ ret, err = nil, fmt.Errorf("docs zip not supported for the stub type %s", stubsType.String())
}
+ if ret == nil && err == nil {
+ err = fmt.Errorf("docs zip is null for the stub type %s", stubsType.String())
+ }
+ return ret, err
+}
+
+func (d *Droidstubs) RemovedApiFilePath(stubsType StubsType) (ret android.Path, err error) {
+ switch stubsType {
+ case Everything:
+ ret, err = d.removedApiFile, nil
+ case Exportable:
+ ret, err = d.exportableRemovedApiFile, nil
+ default:
+ ret, err = nil, fmt.Errorf("removed api file path not supported for the stub type %s", stubsType.String())
+ }
+ if ret == nil && err == nil {
+ err = fmt.Errorf("removed api file is null for the stub type %s", stubsType.String())
+ }
+ return ret, err
+}
+
+func (d *Droidstubs) StubsSrcJar(stubsType StubsType) (ret android.Path, err error) {
+ switch stubsType {
+ case Everything:
+ ret, err = d.stubsSrcJar, nil
+ case Exportable:
+ ret, err = d.exportableStubsSrcJar, nil
+ default:
+ ret, err = nil, fmt.Errorf("stubs srcjar not supported for the stub type %s", stubsType.String())
+ }
+ if ret == nil && err == nil {
+ err = fmt.Errorf("stubs srcjar is null for the stub type %s", stubsType.String())
+ }
+ return ret, err
}
func (d *Droidstubs) CurrentApiTimestamp() android.Path {
@@ -537,11 +560,17 @@
var apiVersions android.Path
if proptools.Bool(d.properties.Api_levels_annotations_enabled) {
d.apiLevelsGenerationFlags(ctx, cmd, stubsType, apiVersionsXml)
- apiVersions = d.everythingArtifacts.apiVersionsXml
+ apiVersions = apiVersionsXml
} else {
ctx.VisitDirectDepsWithTag(metalavaAPILevelsModuleTag, func(m android.Module) {
if s, ok := m.(*Droidstubs); ok {
- apiVersions = s.everythingArtifacts.apiVersionsXml
+ if stubsType == Everything {
+ apiVersions = s.everythingArtifacts.apiVersionsXml
+ } else if stubsType == Exportable {
+ apiVersions = s.exportableArtifacts.apiVersionsXml
+ } else {
+ ctx.ModuleErrorf("%s stubs type does not generate api-versions.xml file", stubsType.String())
+ }
} else {
ctx.PropertyErrorf("api_levels_module",
"module %q is not a droidstubs module", ctx.OtherModuleName(m))
@@ -976,8 +1005,11 @@
stubConfig: params,
}
- d.Javadoc.exportableStubsSrcJar = android.PathForModuleOut(ctx, params.stubsType.String(), ctx.ModuleName()+"-"+"stubs.srcjar")
- optionalCmdParams.stubsSrcJar = d.Javadoc.exportableStubsSrcJar
+ if params.generateStubs {
+ d.Javadoc.exportableStubsSrcJar = android.PathForModuleOut(ctx, params.stubsType.String(), ctx.ModuleName()+"-"+"stubs.srcjar")
+ optionalCmdParams.stubsSrcJar = d.Javadoc.exportableStubsSrcJar
+ }
+
if params.writeSdkValues {
d.exportableArtifacts.metadataZip = android.PathForModuleOut(ctx, params.stubsType.String(), ctx.ModuleName()+"-metadata.zip")
d.exportableArtifacts.metadataDir = android.PathForModuleOut(ctx, params.stubsType.String(), "metadata")
diff --git a/python/scripts/precompile_python.py b/python/scripts/precompile_python.py
index e12e7d2..80e7c76 100644
--- a/python/scripts/precompile_python.py
+++ b/python/scripts/precompile_python.py
@@ -16,6 +16,7 @@
import argparse
import py_compile
import os
+import sys
import shutil
import tempfile
import zipfile
@@ -23,22 +24,31 @@
# This file needs to support both python 2 and 3.
-def process_one_file(name, inf, outzip):
- if not name.endswith('.py'):
- outzip.writestr(name, inf.read())
+def process_one_file(info, infile, outzip):
+ if not info.filename.endswith('.py'):
+ outzip.writestr(info, infile.read())
return
# Unfortunately py_compile requires the input/output files to be written
# out to disk.
with tempfile.NamedTemporaryFile(prefix="Soong_precompile_", delete=False) as tmp:
- shutil.copyfileobj(inf, tmp)
+ shutil.copyfileobj(infile, tmp)
in_name = tmp.name
with tempfile.NamedTemporaryFile(prefix="Soong_precompile_", delete=False) as tmp:
out_name = tmp.name
try:
- py_compile.compile(in_name, out_name, name, doraise=True)
+ # Ensure deterministic pyc by using the hash rather than timestamp.
+ # This is required to improve caching in accelerated builds.
+ # Only works on Python 3.7+ (see https://docs.python.org/3/library/py_compile.html#py_compile.PycInvalidationMode)
+ # which should cover most updated branches and developer machines.
+ if sys.version_info >= (3, 7):
+ py_compile.compile(in_name, out_name, info.filename, doraise=True, invalidation_mode=py_compile.PycInvalidationMode.CHECKED_HASH)
+ else:
+ py_compile.compile(in_name, out_name, info.filename, doraise=True)
with open(out_name, 'rb') as f:
- outzip.writestr(name + 'c', f.read())
+ info.filename = info.filename + 'c'
+ # Use ZipInfo rather than str to reuse timestamps for deterministic zip files.
+ outzip.writestr(info, f.read())
finally:
os.remove(in_name)
os.remove(out_name)
@@ -52,9 +62,9 @@
with open(args.dst_zip, 'wb') as outf, open(args.src_zip, 'rb') as inf:
with zipfile.ZipFile(outf, mode='w') as outzip, zipfile.ZipFile(inf, mode='r') as inzip:
- for name in inzip.namelist():
- with inzip.open(name, mode='r') as inzipf:
- process_one_file(name, inzipf, outzip)
+ for info in inzip.infolist():
+ with inzip.open(info.filename, mode='r') as inzipf:
+ process_one_file(info, inzipf, outzip)
if __name__ == "__main__":
diff --git a/rust/bindgen.go b/rust/bindgen.go
index 77ba277..85cc220 100644
--- a/rust/bindgen.go
+++ b/rust/bindgen.go
@@ -29,7 +29,7 @@
defaultBindgenFlags = []string{""}
// bindgen should specify its own Clang revision so updating Clang isn't potentially blocked on bindgen failures.
- bindgenClangVersion = "clang-r498229b"
+ bindgenClangVersion = "clang-r510928"
_ = pctx.VariableFunc("bindgenClangVersion", func(ctx android.PackageVarContext) string {
if override := ctx.Config().Getenv("LLVM_BINDGEN_PREBUILTS_VERSION"); override != "" {
diff --git a/rust/testing.go b/rust/testing.go
index 0b34c97..d9cacdc 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -75,6 +75,7 @@
apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
min_sdk_version: "29",
vendor_available: true,
+ host_supported: true,
recovery_available: true,
llndk: {
symbol_file: "liblog.map.txt",
diff --git a/rust/vendor_snapshot_test.go b/rust/vendor_snapshot_test.go
index 4f45799..7ebe66b 100644
--- a/rust/vendor_snapshot_test.go
+++ b/rust/vendor_snapshot_test.go
@@ -553,6 +553,7 @@
vendor: true,
nocrt: true,
no_libcrt: true,
+ no_crt_pad_segment: true,
stl: "none",
system_shared_libs: [],
}
@@ -857,6 +858,7 @@
target_arch: "arm64",
compile_multilib: "32",
vendor: true,
+ no_crt_pad_segment: true,
arch: {
arm: {
src: "lib32.so",
@@ -870,6 +872,7 @@
target_arch: "arm64",
compile_multilib: "64",
vendor: true,
+ no_crt_pad_segment: true,
arch: {
arm64: {
src: "lib64.so",
@@ -882,6 +885,7 @@
target_arch: "arm64",
compile_multilib: "64",
vendor: true,
+ no_crt_pad_segment: true,
arch: {
arm64: {
src: "liblog.so",
@@ -913,6 +917,7 @@
target_arch: "arm64",
compile_multilib: "both",
vendor: true,
+ no_crt_pad_segment: true,
arch: {
arm64: {
src: "libvendor_available.so",
diff --git a/scripts/Android.bp b/scripts/Android.bp
index 7baaadb..e2fd59f 100644
--- a/scripts/Android.bp
+++ b/scripts/Android.bp
@@ -143,6 +143,39 @@
}
python_library_host {
+ name: "uffd_gc_utils",
+ srcs: [
+ "uffd_gc_utils.py",
+ ],
+ visibility: [
+ "//build/make/tools:__subpackages__",
+ ],
+}
+
+python_test_host {
+ name: "uffd_gc_utils_test",
+ main: "uffd_gc_utils_test.py",
+ srcs: [
+ "uffd_gc_utils_test.py",
+ ],
+ libs: [
+ "uffd_gc_utils",
+ ],
+ test_suites: ["general-tests"],
+}
+
+python_binary_host {
+ name: "construct_uffd_gc_flag",
+ main: "construct_uffd_gc_flag.py",
+ srcs: [
+ "construct_uffd_gc_flag.py",
+ ],
+ libs: [
+ "uffd_gc_utils",
+ ],
+}
+
+python_library_host {
name: "ninja_rsp",
srcs: ["ninja_rsp.py"],
}
diff --git a/scripts/construct_uffd_gc_flag.py b/scripts/construct_uffd_gc_flag.py
new file mode 100644
index 0000000..f437961
--- /dev/null
+++ b/scripts/construct_uffd_gc_flag.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2024 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.
+#
+"""A tool for constructing UFFD GC flag."""
+
+import argparse
+import os
+
+from uffd_gc_utils import should_enable_uffd_gc
+
+
+def parse_args():
+ parser = argparse.ArgumentParser()
+ parser.add_argument('kernel_version_file')
+ parser.add_argument('output')
+ return parser.parse_args()
+
+def main():
+ args = parse_args()
+ enable_uffd_gc = should_enable_uffd_gc(args.kernel_version_file)
+ flag = '--runtime-arg -Xgc:CMC' if enable_uffd_gc else ''
+ # Prevent the file's mtime from being changed if the contents don't change.
+ # This avoids unnecessary dexpreopt reruns.
+ if os.path.isfile(args.output):
+ with open(args.output, 'r') as f:
+ if f.read() == flag:
+ return
+ with open(args.output, 'w') as f:
+ f.write(flag)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/scripts/uffd_gc_utils.py b/scripts/uffd_gc_utils.py
new file mode 100644
index 0000000..2d35494
--- /dev/null
+++ b/scripts/uffd_gc_utils.py
@@ -0,0 +1,68 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2024 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.
+#
+"""Utils to determine whether to enable UFFD GC."""
+
+import re
+import sys
+
+
+def should_enable_uffd_gc(kernel_version_file):
+ with open(kernel_version_file, 'r') as f:
+ kernel_version = f.read().strip()
+ return should_enable_uffd_gc_impl(kernel_version)
+
+def should_enable_uffd_gc_impl(kernel_version):
+ # See https://source.android.com/docs/core/architecture/kernel/gki-versioning#determine-release
+ p = r"^(?P<w>\d+)[.](?P<x>\d+)[.](?P<y>\d+)(-android(?P<z>\d+)-(?P<k>\d+).*$)?"
+ m = re.match(p, kernel_version)
+ if m is not None:
+ if m.group('z') is not None:
+ android_release = int(m.group('z'))
+ # No need to check w, x, y because all Android 12 kernels have backports.
+ return android_release >= 12
+ else:
+ # Old kernel or non-GKI kernel.
+ version = int(m.group('w'))
+ patch_level = int(m.group('x'))
+ if version < 5:
+ # Old kernel.
+ return False
+ elif (version == 5 and patch_level >= 7) or version >= 6:
+ # New non-GKI kernel. 5.7 supports MREMAP_DONTUNMAP without the need for
+ # backports.
+ return True
+ else:
+ # Non-GKI kernel between 5 and 5.6. It may have backports.
+ raise exit_with_error(kernel_version)
+ elif kernel_version == '<unknown-kernel>':
+ # The kernel information isn't available to the build system, probably
+ # because PRODUCT_OTA_ENFORCE_VINTF_KERNEL_REQUIREMENTS is set to false. We
+ # assume that the kernel supports UFFD GC because it is the case for most of
+ # the products today and it is the future.
+ return True
+ else:
+ # Unrecognizable non-GKI kernel.
+ raise exit_with_error(kernel_version)
+
+def exit_with_error(kernel_version):
+ sys.exit(f"""
+Unable to determine UFFD GC flag for kernel version "{kernel_version}".
+You can fix this by explicitly setting PRODUCT_ENABLE_UFFD_GC to "true" or
+"false" based on the kernel version.
+1. Set PRODUCT_ENABLE_UFFD_GC to "true" if the kernel supports userfaultfd(2)
+ and MREMAP_DONTUNMAP.
+2. Set PRODUCT_ENABLE_UFFD_GC to "false" otherwise.""")
diff --git a/scripts/uffd_gc_utils_test.py b/scripts/uffd_gc_utils_test.py
new file mode 100644
index 0000000..c86ab4b
--- /dev/null
+++ b/scripts/uffd_gc_utils_test.py
@@ -0,0 +1,61 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2024 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.
+#
+"""Unit tests for uffd_gc_utils.py."""
+
+import unittest
+
+from uffd_gc_utils import should_enable_uffd_gc_impl
+
+
+class UffdGcUtilsTest(unittest.TestCase):
+ def test_should_enable_uffd_gc_impl(self):
+ # GKI kernels in new format.
+ self.assertTrue(should_enable_uffd_gc_impl(
+ "6.1.25-android14-11-g34fde9ec08a3-ab10675345"))
+ self.assertTrue(should_enable_uffd_gc_impl(
+ "5.4.42-android12-0-something"))
+ self.assertFalse(should_enable_uffd_gc_impl(
+ "5.4.42-android11-0-something"))
+ # GKI kernels in old format.
+ self.assertFalse(should_enable_uffd_gc_impl(
+ "4.19.282-g4b749a433956-ab10893502"))
+ # Non GKI kernels.
+ self.assertTrue(should_enable_uffd_gc_impl(
+ "6.1.25-foo"))
+ self.assertTrue(should_enable_uffd_gc_impl(
+ "6.1.25"))
+ self.assertTrue(should_enable_uffd_gc_impl(
+ "5.10.19-foo"))
+ self.assertTrue(should_enable_uffd_gc_impl(
+ "5.10.19"))
+ with self.assertRaises(SystemExit):
+ should_enable_uffd_gc_impl("5.4.42-foo")
+ with self.assertRaises(SystemExit):
+ should_enable_uffd_gc_impl("5.4.42")
+ self.assertFalse(should_enable_uffd_gc_impl(
+ "4.19.282-foo"))
+ self.assertFalse(should_enable_uffd_gc_impl(
+ "4.19.282"))
+ with self.assertRaises(SystemExit):
+ should_enable_uffd_gc_impl("foo")
+ # No kernel.
+ self.assertTrue(should_enable_uffd_gc_impl(
+ "<unknown-kernel>"))
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/sysprop/Android.bp b/sysprop/Android.bp
index 1d5eb31..a00a5e4 100644
--- a/sysprop/Android.bp
+++ b/sysprop/Android.bp
@@ -11,6 +11,7 @@
"soong-android",
"soong-cc",
"soong-java",
+ "soong-rust",
],
srcs: [
"sysprop_library.go",
diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go
index 766f3e7..2258232 100644
--- a/sysprop/sysprop_library.go
+++ b/sysprop/sysprop_library.go
@@ -21,6 +21,7 @@
"io"
"os"
"path"
+ "strings"
"sync"
"github.com/google/blueprint"
@@ -29,6 +30,7 @@
"android/soong/android"
"android/soong/cc"
"android/soong/java"
+ "android/soong/rust"
)
type dependencyTag struct {
@@ -51,7 +53,16 @@
genSrcjars android.Paths
}
+type syspropRustGenRule struct {
+ android.ModuleBase
+
+ properties syspropGenProperties
+
+ genSrcs android.Paths
+}
+
var _ android.OutputFileProducer = (*syspropJavaGenRule)(nil)
+var _ android.OutputFileProducer = (*syspropRustGenRule)(nil)
var (
syspropJava = pctx.AndroidStaticRule("syspropJava",
@@ -64,11 +75,20 @@
"$soongZipCmd",
},
}, "scope")
+ syspropRust = pctx.AndroidStaticRule("syspropRust",
+ blueprint.RuleParams{
+ Command: `rm -rf $out_dir && mkdir -p $out_dir && ` +
+ `$syspropRustCmd --scope $scope --rust-output-dir $out_dir $in`,
+ CommandDeps: []string{
+ "$syspropRustCmd",
+ },
+ }, "scope", "out_dir")
)
func init() {
pctx.HostBinToolVariable("soongZipCmd", "soong_zip")
pctx.HostBinToolVariable("syspropJavaCmd", "sysprop_java")
+ pctx.HostBinToolVariable("syspropRustCmd", "sysprop_rust")
}
// syspropJavaGenRule module generates srcjar containing generated java APIs.
@@ -122,6 +142,56 @@
return g
}
+// syspropRustGenRule module generates rust source files containing generated rust APIs.
+// It also depends on check api rule, so api check has to pass to use sysprop_library.
+func (g *syspropRustGenRule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ var checkApiFileTimeStamp android.WritablePath
+
+ ctx.VisitDirectDeps(func(dep android.Module) {
+ if m, ok := dep.(*syspropLibrary); ok {
+ checkApiFileTimeStamp = m.checkApiFileTimeStamp
+ }
+ })
+
+ for _, syspropFile := range android.PathsForModuleSrc(ctx, g.properties.Srcs) {
+ syspropDir := strings.TrimSuffix(syspropFile.String(), syspropFile.Ext())
+ outputDir := android.PathForModuleGen(ctx, syspropDir, "src")
+ libPath := android.PathForModuleGen(ctx, syspropDir, "src", "lib.rs")
+ parsersPath := android.PathForModuleGen(ctx, syspropDir, "src", "gen_parsers_and_formatters.rs")
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: syspropRust,
+ Description: "sysprop_rust " + syspropFile.Rel(),
+ Outputs: android.WritablePaths{libPath, parsersPath},
+ Input: syspropFile,
+ Implicit: checkApiFileTimeStamp,
+ Args: map[string]string{
+ "scope": g.properties.Scope,
+ "out_dir": outputDir.String(),
+ },
+ })
+
+ g.genSrcs = append(g.genSrcs, libPath, parsersPath)
+ }
+}
+
+func (g *syspropRustGenRule) DepsMutator(ctx android.BottomUpMutatorContext) {
+ // Add a dependency from the stubs to sysprop library so that the generator rule can depend on
+ // the check API rule of the sysprop library.
+ ctx.AddFarVariationDependencies(nil, nil, proptools.String(g.properties.Check_api))
+}
+
+func (g *syspropRustGenRule) OutputFiles(_ string) (android.Paths, error) {
+ return g.genSrcs, nil
+}
+
+func syspropRustGenFactory() android.Module {
+ g := &syspropRustGenRule{}
+ g.AddProperties(&g.properties)
+ android.InitAndroidModule(g)
+ return g
+}
+
type syspropLibrary struct {
android.ModuleBase
android.ApexModuleBase
@@ -180,6 +250,12 @@
// Forwarded to java_library.min_sdk_version
Min_sdk_version *string
}
+
+ Rust struct {
+ // Minimum sdk version that the artifact should support when it runs as part of mainline modules(APEX).
+ // Forwarded to rust_library.min_sdk_version
+ Min_sdk_version *string
+ }
}
var (
@@ -233,6 +309,21 @@
return m.BaseModuleName() + "_java_gen_public"
}
+func (m *syspropLibrary) rustGenModuleName() string {
+ return m.rustCrateName() + "_rust_gen"
+}
+
+func (m *syspropLibrary) rustGenStubName() string {
+ return "lib" + m.rustCrateName() + "_rust"
+}
+
+func (m *syspropLibrary) rustCrateName() string {
+ moduleName := strings.ToLower(m.BaseModuleName())
+ moduleName = strings.ReplaceAll(moduleName, "-", "_")
+ moduleName = strings.ReplaceAll(moduleName, ".", "_")
+ return moduleName
+}
+
func (m *syspropLibrary) BaseModuleName() string {
return m.ModuleBase.Name()
}
@@ -436,6 +527,18 @@
Min_sdk_version *string
}
+type rustLibraryProperties struct {
+ Name *string
+ Srcs []string
+ Installable *bool
+ Crate_name string
+ Rustlibs []string
+ Vendor_available *bool
+ Product_available *bool
+ Apex_available []string
+ Min_sdk_version *string
+}
+
func syspropLibraryHook(ctx android.LoadHookContext, m *syspropLibrary) {
if len(m.properties.Srcs) == 0 {
ctx.PropertyErrorf("srcs", "sysprop_library must specify srcs")
@@ -564,6 +667,28 @@
})
}
+ // Generate a Rust implementation library.
+ ctx.CreateModule(syspropRustGenFactory, &syspropGenProperties{
+ Srcs: m.properties.Srcs,
+ Scope: scope,
+ Name: proptools.StringPtr(m.rustGenModuleName()),
+ Check_api: proptools.StringPtr(ctx.ModuleName()),
+ })
+ rustProps := rustLibraryProperties{
+ Name: proptools.StringPtr(m.rustGenStubName()),
+ Srcs: []string{":" + m.rustGenModuleName()},
+ Installable: proptools.BoolPtr(false),
+ Crate_name: m.rustCrateName(),
+ Rustlibs: []string{
+ "librustutils",
+ },
+ Vendor_available: m.properties.Vendor_available,
+ Product_available: m.properties.Product_available,
+ Apex_available: m.ApexProperties.Apex_available,
+ Min_sdk_version: proptools.StringPtr("29"),
+ }
+ ctx.CreateModule(rust.RustLibraryFactory, &rustProps)
+
// syspropLibraries will be used by property_contexts to check types.
// Record absolute paths of sysprop_library to prevent soong_namespace problem.
if m.ExportedToMake() {
diff --git a/sysprop/sysprop_test.go b/sysprop/sysprop_test.go
index e5b3dea..9dd696f 100644
--- a/sysprop/sysprop_test.go
+++ b/sysprop/sysprop_test.go
@@ -22,6 +22,7 @@
"android/soong/android"
"android/soong/cc"
"android/soong/java"
+ "android/soong/rust"
"github.com/google/blueprint/proptools"
)
@@ -46,18 +47,6 @@
recovery_available: true,
}
- cc_library {
- name: "liblog",
- no_libcrt: true,
- nocrt: true,
- system_shared_libs: [],
- recovery_available: true,
- host_supported: true,
- llndk: {
- symbol_file: "liblog.map.txt",
- }
- }
-
java_library {
name: "sysprop-library-stub-platform",
sdk_version: "core_current",
@@ -74,6 +63,15 @@
product_specific: true,
sdk_version: "core_current",
}
+
+ rust_library {
+ name: "librustutils",
+ crate_name: "rustutils",
+ srcs: ["librustutils/lib.rs"],
+ product_available: true,
+ vendor_available: true,
+ min_sdk_version: "29",
+ }
`
mockFS := android.MockFS{
@@ -115,11 +113,14 @@
"android/sysprop/PlatformProperties.sysprop": nil,
"com/android/VendorProperties.sysprop": nil,
"com/android2/OdmProperties.sysprop": nil,
+
+ "librustutils/lib.rs": nil,
}
result := android.GroupFixturePreparers(
cc.PrepareForTestWithCcDefaultModules,
java.PrepareForTestWithJavaDefaultModules,
+ rust.PrepareForTestWithRustDefaultModules,
PrepareForTestWithSyspropBuildComponents,
android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
variables.DeviceSystemSdkVersions = []string{"28"}
@@ -356,6 +357,10 @@
javaModule := result.ModuleForTests("sysprop-platform", "android_common").Module().(*java.Library)
propFromJava := javaModule.ApexProperties.Apex_available
android.AssertDeepEquals(t, "apex_available forwarding to java module", expected, propFromJava)
+
+ rustModule := result.ModuleForTests("libsysprop_platform_rust", "android_arm64_armv8-a_rlib_rlib-std").Module().(*rust.Module)
+ propFromRust := rustModule.ApexProperties.Apex_available
+ android.AssertDeepEquals(t, "apex_available forwarding to rust module", expected, propFromRust)
}
func TestMinSdkVersionIsForwarded(t *testing.T) {
@@ -371,6 +376,9 @@
java: {
min_sdk_version: "30",
},
+ rust: {
+ min_sdk_version: "29",
+ }
}
`)
@@ -381,4 +389,8 @@
javaModule := result.ModuleForTests("sysprop-platform", "android_common").Module().(*java.Library)
propFromJava := javaModule.MinSdkVersionString()
android.AssertStringEquals(t, "min_sdk_version forwarding to java module", "30", propFromJava)
+
+ rustModule := result.ModuleForTests("libsysprop_platform_rust", "android_arm64_armv8-a_rlib_rlib-std").Module().(*rust.Module)
+ propFromRust := proptools.String(rustModule.Properties.Min_sdk_version)
+ android.AssertStringEquals(t, "min_sdk_version forwarding to rust module", "29", propFromRust)
}
diff --git a/ui/build/config.go b/ui/build/config.go
index 5085c68..e29d239 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -115,6 +115,11 @@
// Data source to write ninja weight list
ninjaWeightListSource NinjaWeightListSource
+
+ // This file is a detailed dump of all soong-defined modules for debugging purposes.
+ // There's quite a bit of overlap with module-info.json and soong module graph. We
+ // could consider merging them.
+ moduleDebugFile string
}
type NinjaWeightListSource uint
@@ -273,6 +278,10 @@
ret.sandboxConfig.SetSrcDirIsRO(srcDirIsWritable == "false")
}
+ if os.Getenv("GENERATE_SOONG_DEBUG") == "true" {
+ ret.moduleDebugFile, _ = filepath.Abs(shared.JoinPath(ret.SoongOutDir(), "soong-debug-info.json"))
+ }
+
ret.environ.Unset(
// We're already using it
"USE_SOONG_UI",
@@ -325,6 +334,9 @@
"ANDROID_DEV_SCRIPTS",
"ANDROID_EMULATOR_PREBUILTS",
"ANDROID_PRE_BUILD_PATHS",
+
+ // We read it here already, don't let others share in the fun
+ "GENERATE_SOONG_DEBUG",
)
if ret.UseGoma() || ret.ForceUseGoma() {
diff --git a/ui/build/soong.go b/ui/build/soong.go
index 90c3bfc..a201ac5 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -204,6 +204,11 @@
commonArgs = append(commonArgs, "--build-from-source-stub")
}
+ if pb.config.moduleDebugFile != "" {
+ commonArgs = append(commonArgs, "--soong_module_debug")
+ commonArgs = append(commonArgs, pb.config.moduleDebugFile)
+ }
+
commonArgs = append(commonArgs, "-l", filepath.Join(pb.config.FileListDir(), "Android.bp.list"))
invocationEnv := make(map[string]string)
if pb.debugPort != "" {