Merge "rust: Support new rust_stdlib_prebuilt_host type"
diff --git a/android/bazel.go b/android/bazel.go
index 3bc104d..26d70e4 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -188,6 +188,7 @@
"packages/apps/QuickSearchBox":/* recursive = */ true,
"packages/apps/WallpaperPicker":/* recursive = */ false,
+ "prebuilts/gcc":/* recursive = */ true,
"prebuilts/sdk":/* recursive = */ false,
"prebuilts/sdk/current/extras/app-toolkit":/* recursive = */ false,
"prebuilts/sdk/current/support":/* recursive = */ false,
@@ -250,6 +251,8 @@
// Per-module denylist to always opt modules out of both bp2build and mixed builds.
bp2buildModuleDoNotConvertList = []string{
+ "libprotobuf-cpp-full", "libprotobuf-cpp-lite", // Unsupported product&vendor suffix. b/204811222 and b/204810610.
+
"libc_malloc_debug", // depends on libunwindstack, which depends on unsupported module art_cc_library_statics
"libbase_ndk", // http://b/186826477, fails to link libctscamera2_jni for device (required for CtsCameraTestCases)
@@ -270,14 +273,8 @@
"platform_tools_properties",
"build_tools_source_properties",
- // //external/libcap/...
- "cap_names.h", // http://b/196105070 host toolchain misconfigurations for mixed builds
- "libcap", // http://b/196105070 host toolchain misconfigurations for mixed builds
-
- "libminijail", // depends on unconverted modules: libcap
- "getcap", // depends on unconverted modules: libcap
- "setcap", // depends on unconverted modules: libcap
- "minijail0", // depends on unconverted modules: libcap, libminijail
+ "libminijail", // b/202491296: Uses unsupported c_std property.
+ "minijail0", // depends on unconverted modules: libminijail
"drop_privs", // depends on unconverted modules: libminijail
// Tests. Handle later.
@@ -381,7 +378,11 @@
// MixedBuildsEnabled checks that a module is ready to be replaced by a
// converted or handcrafted Bazel target.
-func (b *BazelModuleBase) MixedBuildsEnabled(ctx BazelConversionPathContext) bool {
+func (b *BazelModuleBase) MixedBuildsEnabled(ctx ModuleContext) bool {
+ if ctx.Os() == Windows {
+ // Windows toolchains are not currently supported.
+ return false
+ }
if !ctx.Config().BazelContext.BazelEnabled() {
return false
}
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 3c6212e..0052551 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -602,8 +602,6 @@
platform_name = build_options(target)["//command_line_option:platforms"][0].name
if platform_name == "host":
return "HOST"
- elif platform_name.startswith("linux_glibc_"):
- return platform_name[len("linux_glibc_"):] + "|" + platform_name[:len("linux_glibc_")-1]
elif platform_name.startswith("android_"):
return platform_name[len("android_"):] + "|" + platform_name[:len("android_")-1]
elif platform_name.startswith("linux_"):
@@ -865,7 +863,7 @@
arch = "x86_64"
}
os := key.configKey.osType.Name
- if len(os) == 0 || os == "common_os" {
+ if len(os) == 0 || os == "common_os" || os == "linux_glibc" {
// Use host OS, which is currently hardcoded to be linux.
os = "linux"
}
diff --git a/android/makevars.go b/android/makevars.go
index 8825d1a..665d576 100644
--- a/android/makevars.go
+++ b/android/makevars.go
@@ -422,6 +422,7 @@
fmt.Fprintln(buf)
for _, dist := range dists {
+ fmt.Fprintf(buf, ".PHONY: %s\n", strings.Join(dist.goals, " "))
fmt.Fprintf(buf, "$(call dist-for-goals,%s,%s)\n",
strings.Join(dist.goals, " "), strings.Join(dist.paths, " "))
}
diff --git a/cc/cc.go b/cc/cc.go
index 8915d6f..113620c 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -1717,7 +1717,7 @@
bazelActionsUsed := false
// Mixed builds mode is disabled for modules outside of device OS.
// TODO(b/200841190): Support non-device OS in mixed builds.
- if c.MixedBuildsEnabled(actx) && c.bazelHandler != nil && actx.Os().Class == android.Device {
+ if c.MixedBuildsEnabled(actx) && c.bazelHandler != nil {
bazelActionsUsed = c.bazelHandler.GenerateBazelBuildActions(actx, bazelModuleLabel)
}
return bazelActionsUsed
diff --git a/cc/sanitize.go b/cc/sanitize.go
index c7e8411..93d4b4c 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -88,7 +88,7 @@
intOverflow
scs
Fuzzer
- memtag_heap
+ Memtag_heap
cfi // cfi is last to prevent it running before incompatible mutators
)
@@ -99,7 +99,7 @@
intOverflow,
scs,
Fuzzer,
- memtag_heap,
+ Memtag_heap,
cfi, // cfi is last to prevent it running before incompatible mutators
}
@@ -118,7 +118,7 @@
return "cfi"
case scs:
return "scs"
- case memtag_heap:
+ case Memtag_heap:
return "memtag_heap"
case Fuzzer:
return "fuzzer"
@@ -134,7 +134,7 @@
return "address"
case Hwasan:
return "hwaddress"
- case memtag_heap:
+ case Memtag_heap:
return "memtag_heap"
case tsan:
return "thread"
@@ -156,7 +156,7 @@
case Asan, Hwasan, Fuzzer, scs, tsan, cfi:
ctx.TopDown(t.variationName()+"_deps", sanitizerDepsMutator(t))
ctx.BottomUp(t.variationName(), sanitizerMutator(t))
- case memtag_heap, intOverflow:
+ case Memtag_heap, intOverflow:
// do nothing
default:
panic(fmt.Errorf("unknown SanitizerType %d", t))
@@ -179,6 +179,8 @@
return true
case Fuzzer:
return true
+ case Memtag_heap:
+ return true
default:
return false
}
@@ -467,7 +469,7 @@
s.Scs = nil
}
- // memtag_heap is only implemented on AArch64.
+ // Memtag_heap is only implemented on AArch64.
if ctx.Arch().ArchType != android.Arm64 {
s.Memtag_heap = nil
}
@@ -813,7 +815,7 @@
return sanitize.Properties.Sanitize.Cfi
case scs:
return sanitize.Properties.Sanitize.Scs
- case memtag_heap:
+ case Memtag_heap:
return sanitize.Properties.Sanitize.Memtag_heap
case Fuzzer:
return sanitize.Properties.Sanitize.Fuzzer
@@ -829,7 +831,7 @@
!sanitize.isSanitizerEnabled(tsan) &&
!sanitize.isSanitizerEnabled(cfi) &&
!sanitize.isSanitizerEnabled(scs) &&
- !sanitize.isSanitizerEnabled(memtag_heap) &&
+ !sanitize.isSanitizerEnabled(Memtag_heap) &&
!sanitize.isSanitizerEnabled(Fuzzer)
}
@@ -859,7 +861,7 @@
sanitize.Properties.Sanitize.Cfi = bPtr
case scs:
sanitize.Properties.Sanitize.Scs = bPtr
- case memtag_heap:
+ case Memtag_heap:
sanitize.Properties.Sanitize.Memtag_heap = bPtr
case Fuzzer:
sanitize.Properties.Sanitize.Fuzzer = bPtr
@@ -1148,7 +1150,7 @@
if lib, ok := snapshot.StaticLibs[noteDep]; ok {
noteDep = lib
}
- depTag := libraryDependencyTag{Kind: staticLibraryDependency, wholeStatic: true}
+ depTag := StaticDepTag(true)
variations := append(mctx.Target().Variations(),
blueprint.Variation{Mutator: "link", Variation: "static"})
if c.Device() {
@@ -1318,6 +1320,10 @@
func sanitizerMutator(t SanitizerType) func(android.BottomUpMutatorContext) {
return func(mctx android.BottomUpMutatorContext) {
if c, ok := mctx.Module().(PlatformSanitizeable); ok && c.SanitizePropDefined() {
+
+ // Make sure we're not setting CFI to any value if it's not supported.
+ cfiSupported := mctx.Module().(PlatformSanitizeable).SanitizerSupported(cfi)
+
if c.Binary() && c.IsSanitizerEnabled(t) {
modules := mctx.CreateVariations(t.variationName())
modules[0].(PlatformSanitizeable).SetSanitizer(t, true)
@@ -1338,7 +1344,6 @@
// is redirected to the sanitized variant of the dependent module.
defaultVariation := t.variationName()
// Not all PlatformSanitizeable modules support the CFI sanitizer
- cfiSupported := mctx.Module().(PlatformSanitizeable).SanitizerSupported(cfi)
mctx.SetDefaultDependencyVariation(&defaultVariation)
modules := mctx.CreateVariations("", t.variationName())
@@ -1385,7 +1390,7 @@
modules[0].(PlatformSanitizeable).SetInSanitizerDir()
}
- if mctx.Device() && t.incompatibleWithCfi() {
+ if mctx.Device() && t.incompatibleWithCfi() && cfiSupported {
// TODO: Make sure that cfi mutator runs "after" any of the sanitizers that
// are incompatible with cfi
modules[0].(PlatformSanitizeable).SetSanitizer(cfi, false)
diff --git a/mk2rbc/cmd/mk2rbc.go b/mk2rbc/cmd/mk2rbc.go
index 0f030d3..7bb0246 100644
--- a/mk2rbc/cmd/mk2rbc.go
+++ b/mk2rbc/cmd/mk2rbc.go
@@ -81,7 +81,7 @@
var backupSuffix string
var tracedVariables []string
-var errorLogger = errorsByType{data: make(map[string]datum)}
+var errorLogger = errorSink{data: make(map[string]datum)}
var makefileFinder = &LinuxMakefileFinder{}
var versionDefaultsMk = filepath.Join("build", "make", "core", "version_defaults.mk")
@@ -339,9 +339,7 @@
WarnPartialSuccess: !*noWarn,
SourceFS: os.DirFS(*rootDir),
MakefileFinder: makefileFinder,
- }
- if *errstat {
- mk2starRequest.ErrorLogger = errorLogger
+ ErrorLogger: errorLogger,
}
ss, err := mk2rbc.Convert(mk2starRequest)
if err != nil {
@@ -456,10 +454,8 @@
}
}
}
- if *verbose {
- fmt.Fprintf(os.Stderr, "%-16s%5d\n", "Succeeded:", nOk)
- fmt.Fprintf(os.Stderr, "%-16s%5d\n", "Partial:", nPartial)
- fmt.Fprintf(os.Stderr, "%-16s%5d\n", "Failed:", nFailed)
+ if *verbose && (nPartial > 0 || nFailed > 0) {
+ fmt.Fprintln(os.Stderr, "Succeeded: ", nOk, " Partial: ", nPartial, " Failed: ", nFailed)
}
}
@@ -468,11 +464,18 @@
formattingArgs []string
}
-type errorsByType struct {
+type errorSink struct {
data map[string]datum
}
-func (ebt errorsByType) NewError(message string, node parser.Node, args ...interface{}) {
+func (ebt errorSink) NewError(sourceFile string, sourceLine int, node parser.Node, message string, args ...interface{}) {
+ fmt.Fprintf(os.Stderr, "%s:%d ", sourceFile, sourceLine)
+ fmt.Fprintf(os.Stderr, message, args...)
+ fmt.Fprintln(os.Stderr)
+ if !*errstat {
+ return
+ }
+
v, exists := ebt.data[message]
if exists {
v.count++
@@ -497,7 +500,7 @@
ebt.data[message] = v
}
-func (ebt errorsByType) printStatistics() {
+func (ebt errorSink) printStatistics() {
if len(ebt.data) > 0 {
fmt.Fprintln(os.Stderr, "Error counts:")
}
diff --git a/mk2rbc/mk2rbc.go b/mk2rbc/mk2rbc.go
index 0e39c32..7ce1834 100644
--- a/mk2rbc/mk2rbc.go
+++ b/mk2rbc/mk2rbc.go
@@ -161,7 +161,7 @@
RootDir string // root directory path used to resolve included files
OutputSuffix string // generated Starlark files suffix
OutputDir string // if set, root of the output hierarchy
- ErrorLogger ErrorMonitorCB
+ ErrorLogger ErrorLogger
TracedVariables []string // trace assignment to these variables
TraceCalls bool
WarnPartialSuccess bool
@@ -169,10 +169,10 @@
MakefileFinder MakefileFinder
}
-// An error sink allowing to gather error statistics.
-// NewError is called on every error encountered during processing.
-type ErrorMonitorCB interface {
- NewError(s string, node mkparser.Node, args ...interface{})
+// ErrorLogger prints errors and gathers error statistics.
+// Its NewError function is called on every error encountered during the conversion.
+type ErrorLogger interface {
+ NewError(sourceFile string, sourceLine int, node mkparser.Node, text string, args ...interface{})
}
// Derives module name for a given file. It is base name
@@ -381,6 +381,7 @@
warnPartialSuccess bool
sourceFS fs.FS
makefileFinder MakefileFinder
+ nodeLocator func(pos mkparser.Pos) int
}
func (ss *StarlarkScript) newNode(node starlarkNode) {
@@ -406,7 +407,7 @@
fatalError error
builtinMakeVars map[string]starlarkExpr
outputSuffix string
- errorLogger ErrorMonitorCB
+ errorLogger ErrorLogger
tracedVariables map[string]bool // variables to be traced in the generated script
variables map[string]variable
varAssignments *varAssignmentScope
@@ -973,25 +974,16 @@
ctx.pushReceiver(&block)
for ctx.hasNodes() {
node := ctx.getNode()
- if ctx.handleSimpleStatement(node) {
- continue
- }
- switch d := node.(type) {
- case *mkparser.Directive:
+ if d, ok := node.(*mkparser.Directive); ok {
switch d.Name {
case "else", "elifdef", "elifndef", "elifeq", "elifneq", "endif":
ctx.popReceiver()
ctx.receiver.newNode(&block)
ctx.backNode()
return
- case "ifdef", "ifndef", "ifeq", "ifneq":
- ctx.handleIfBlock(d)
- default:
- ctx.errorf(d, "unexpected directive %s", d.Name)
}
- default:
- ctx.errorf(node, "unexpected statement")
}
+ ctx.handleSimpleStatement(node)
}
ctx.fatalError = fmt.Errorf("no matching endif for %s", check.Dump())
ctx.popReceiver()
@@ -1031,7 +1023,7 @@
func (ctx *parseContext) newBadExpr(node mkparser.Node, text string, args ...interface{}) starlarkExpr {
message := fmt.Sprintf(text, args...)
if ctx.errorLogger != nil {
- ctx.errorLogger.NewError(text, node, args)
+ ctx.errorLogger.NewError(ctx.script.mkFile, ctx.script.nodeLocator(node.Pos()), node, text, args...)
}
ctx.script.hasErrors = true
return &badExpr{node, message}
@@ -1493,9 +1485,7 @@
// Handles the statements whose treatment is the same in all contexts: comment,
// assignment, variable (which is a macro call in reality) and all constructs that
// do not handle in any context ('define directive and any unrecognized stuff).
-// Return true if we handled it.
-func (ctx *parseContext) handleSimpleStatement(node mkparser.Node) bool {
- handled := true
+func (ctx *parseContext) handleSimpleStatement(node mkparser.Node) {
switch x := node.(type) {
case *mkparser.Comment:
ctx.maybeHandleAnnotation(x)
@@ -1510,13 +1500,14 @@
ctx.handleDefine(x)
case "include", "-include":
ctx.handleInclude(node, ctx.parseMakeString(node, x.Args), x.Name[0] != '-')
+ case "ifeq", "ifneq", "ifdef", "ifndef":
+ ctx.handleIfBlock(x)
default:
- handled = false
+ ctx.errorf(x, "unexpected directive %s", x.Name)
}
default:
ctx.errorf(x, "unsupported line %s", strings.ReplaceAll(x.Dump(), "\n", "\n#"))
}
- return handled
}
// Processes annotation. An annotation is a comment that starts with #RBC# and provides
@@ -1554,11 +1545,12 @@
// records that the given node failed to be converted and includes an explanatory message
func (ctx *parseContext) errorf(failedNode mkparser.Node, message string, args ...interface{}) {
if ctx.errorLogger != nil {
- ctx.errorLogger.NewError(message, failedNode, args...)
+ ctx.errorLogger.NewError(ctx.script.mkFile, ctx.script.nodeLocator(failedNode.Pos()), failedNode, message, args...)
}
message = fmt.Sprintf(message, args...)
ctx.insertComment(fmt.Sprintf("# MK2RBC TRANSLATION ERROR: %s", message))
ctx.carryAsComment(failedNode)
+
ctx.script.hasErrors = true
}
@@ -1675,6 +1667,7 @@
warnPartialSuccess: req.WarnPartialSuccess,
sourceFS: req.SourceFS,
makefileFinder: req.MakefileFinder,
+ nodeLocator: func(pos mkparser.Pos) int { return parser.Unpack(pos).Line },
}
ctx := newParseContext(starScript, nodes)
ctx.outputSuffix = req.OutputSuffix
@@ -1688,21 +1681,7 @@
}
ctx.pushReceiver(starScript)
for ctx.hasNodes() && ctx.fatalError == nil {
- node := ctx.getNode()
- if ctx.handleSimpleStatement(node) {
- continue
- }
- switch x := node.(type) {
- case *mkparser.Directive:
- switch x.Name {
- case "ifeq", "ifneq", "ifdef", "ifndef":
- ctx.handleIfBlock(x)
- default:
- ctx.errorf(x, "unexpected directive %s", x.Name)
- }
- default:
- ctx.errorf(x, "unsupported line")
- }
+ ctx.handleSimpleStatement(ctx.getNode())
}
if ctx.fatalError != nil {
return nil, ctx.fatalError
diff --git a/rust/Android.bp b/rust/Android.bp
index 0ee673d..cda2dbc 100644
--- a/rust/Android.bp
+++ b/rust/Android.bp
@@ -54,6 +54,7 @@
"project_json_test.go",
"protobuf_test.go",
"rust_test.go",
+ "sanitize_test.go",
"source_provider_test.go",
"test_test.go",
"vendor_snapshot_test.go",
diff --git a/rust/binary.go b/rust/binary.go
index cba2f72..db91ccb 100644
--- a/rust/binary.go
+++ b/rust/binary.go
@@ -34,6 +34,7 @@
type binaryInterface interface {
binary() bool
staticallyLinked() bool
+ testBinary() bool
}
type binaryDecorator struct {
@@ -172,3 +173,7 @@
func (binary *binaryDecorator) staticallyLinked() bool {
return Bool(binary.Properties.Static_executable)
}
+
+func (binary *binaryDecorator) testBinary() bool {
+ return false
+}
diff --git a/rust/config/allowed_list.go b/rust/config/allowed_list.go
index d66db14..9b88b6d 100644
--- a/rust/config/allowed_list.go
+++ b/rust/config/allowed_list.go
@@ -17,6 +17,7 @@
"external/vm_tools/p9",
"frameworks/native/libs/binder/rust",
"frameworks/proto_logging/stats",
+ "hardware/interfaces/security",
"packages/modules/Bluetooth",
"packages/modules/DnsResolver",
"packages/modules/Uwb",
diff --git a/rust/fuzz.go b/rust/fuzz.go
index c52f5f9..55921ba 100644
--- a/rust/fuzz.go
+++ b/rust/fuzz.go
@@ -36,7 +36,7 @@
fuzzPackagedModule fuzz.FuzzPackagedModule
}
-var _ compiler = (*binaryDecorator)(nil)
+var _ compiler = (*fuzzDecorator)(nil)
// rust_binary produces a binary that is runnable on a device.
func RustFuzzFactory() android.Module {
diff --git a/rust/rust_test.go b/rust/rust_test.go
index 9b518c8..b99b1e6 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -442,3 +442,10 @@
m.Output("unstripped/libwaldo.dylib.so.bloaty.csv")
m.Output("libwaldo.dylib.so.bloaty.csv")
}
+
+func assertString(t *testing.T, got, expected string) {
+ t.Helper()
+ if got != expected {
+ t.Errorf("expected %q got %q", expected, got)
+ }
+}
diff --git a/rust/sanitize.go b/rust/sanitize.go
index baa383d..fdb342d 100644
--- a/rust/sanitize.go
+++ b/rust/sanitize.go
@@ -15,20 +15,39 @@
package rust
import (
+ "fmt"
+ "strings"
+
+ "github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
+
"android/soong/android"
"android/soong/cc"
"android/soong/rust/config"
- "fmt"
- "github.com/google/blueprint"
)
+// TODO: When Rust has sanitizer-parity with CC, deduplicate this struct
type SanitizeProperties struct {
// enable AddressSanitizer, HWAddressSanitizer, and others.
Sanitize struct {
Address *bool `android:"arch_variant"`
Hwaddress *bool `android:"arch_variant"`
- Fuzzer *bool `android:"arch_variant"`
- Never *bool `android:"arch_variant"`
+
+ // Memory-tagging, only available on arm64
+ // if diag.memtag unset or false, enables async memory tagging
+ Memtag_heap *bool `android:"arch_variant"`
+ Fuzzer *bool `android:"arch_variant"`
+ Never *bool `android:"arch_variant"`
+
+ // Sanitizers to run in the diagnostic mode (as opposed to the release mode).
+ // Replaces abort() on error with a human-readable error message.
+ // Address and Thread sanitizers always run in diagnostic mode.
+ Diag struct {
+ // Memory-tagging, only available on arm64
+ // requires sanitizer.memtag: true
+ // if set, enables sync memory tagging
+ Memtag_heap *bool `android:"arch_variant"`
+ }
}
SanitizerEnabled bool `blueprint:"mutated"`
SanitizeDep bool `blueprint:"mutated"`
@@ -59,9 +78,18 @@
"-Z sanitizer=address",
}
+// See cc/sanitize.go's hwasanGlobalOptions for global hwasan options.
var hwasanFlags = []string{
"-Z sanitizer=hwaddress",
"-C target-feature=+tagged-globals",
+
+ // Flags from cc/sanitize.go hwasanFlags
+ "-C llvm-args=--aarch64-enable-global-isel-at-O=-1",
+ "-C llvm-args=-fast-isel=false",
+ "-C llvm-args=-instcombine-lower-dbg-declare=0",
+
+ // Additional flags for HWASAN-ified Rust/C interop
+ "-C llvm-args=--hwasan-with-ifunc",
}
func boolPtr(v bool) *bool {
@@ -79,7 +107,85 @@
}
func (sanitize *sanitize) begin(ctx BaseModuleContext) {
- s := sanitize.Properties.Sanitize
+ s := &sanitize.Properties.Sanitize
+
+ // Never always wins.
+ if Bool(s.Never) {
+ return
+ }
+
+ // rust_test targets default to SYNC MemTag unless explicitly set to ASYNC (via diag: {Memtag_heap}).
+ if binary, ok := ctx.RustModule().compiler.(binaryInterface); ok && binary.testBinary() {
+ if s.Memtag_heap == nil {
+ s.Memtag_heap = proptools.BoolPtr(true)
+ }
+ if s.Diag.Memtag_heap == nil {
+ s.Diag.Memtag_heap = proptools.BoolPtr(true)
+ }
+ }
+
+ var globalSanitizers []string
+ var globalSanitizersDiag []string
+
+ if ctx.Host() {
+ if !ctx.Windows() {
+ globalSanitizers = ctx.Config().SanitizeHost()
+ }
+ } else {
+ arches := ctx.Config().SanitizeDeviceArch()
+ if len(arches) == 0 || android.InList(ctx.Arch().ArchType.Name, arches) {
+ globalSanitizers = ctx.Config().SanitizeDevice()
+ globalSanitizersDiag = ctx.Config().SanitizeDeviceDiag()
+ }
+ }
+
+ if len(globalSanitizers) > 0 {
+ var found bool
+
+ // Global Sanitizers
+ if found, globalSanitizers = android.RemoveFromList("hwaddress", globalSanitizers); found && s.Hwaddress == nil {
+ // TODO(b/180495975): HWASan for static Rust binaries isn't supported yet.
+ if !ctx.RustModule().StaticExecutable() {
+ s.Hwaddress = proptools.BoolPtr(true)
+ }
+ }
+
+ if found, globalSanitizers = android.RemoveFromList("memtag_heap", globalSanitizers); found && s.Memtag_heap == nil {
+ if !ctx.Config().MemtagHeapDisabledForPath(ctx.ModuleDir()) {
+ s.Memtag_heap = proptools.BoolPtr(true)
+ }
+ }
+
+ if found, globalSanitizers = android.RemoveFromList("address", globalSanitizers); found && s.Address == nil {
+ s.Address = proptools.BoolPtr(true)
+ }
+
+ if found, globalSanitizers = android.RemoveFromList("fuzzer", globalSanitizers); found && s.Fuzzer == nil {
+ s.Fuzzer = proptools.BoolPtr(true)
+ }
+
+ // Global Diag Sanitizers
+ if found, globalSanitizersDiag = android.RemoveFromList("memtag_heap", globalSanitizersDiag); found &&
+ s.Diag.Memtag_heap == nil && Bool(s.Memtag_heap) {
+ s.Diag.Memtag_heap = proptools.BoolPtr(true)
+ }
+ }
+
+ // Enable Memtag for all components in the include paths (for Aarch64 only)
+ if ctx.Arch().ArchType == android.Arm64 {
+ if ctx.Config().MemtagHeapSyncEnabledForPath(ctx.ModuleDir()) {
+ if s.Memtag_heap == nil {
+ s.Memtag_heap = proptools.BoolPtr(true)
+ }
+ if s.Diag.Memtag_heap == nil {
+ s.Diag.Memtag_heap = proptools.BoolPtr(true)
+ }
+ } else if ctx.Config().MemtagHeapAsyncEnabledForPath(ctx.ModuleDir()) {
+ if s.Memtag_heap == nil {
+ s.Memtag_heap = proptools.BoolPtr(true)
+ }
+ }
+ }
// TODO:(b/178369775)
// For now sanitizing is only supported on devices
@@ -96,7 +202,22 @@
s.Hwaddress = nil
}
- if ctx.Os() == android.Android && Bool(s.Hwaddress) {
+ // HWASan ramdisk (which is built from recovery) goes over some bootloader limit.
+ // Keep libc instrumented so that ramdisk / vendor_ramdisk / recovery can run hwasan-instrumented code if necessary.
+ if (ctx.RustModule().InRamdisk() || ctx.RustModule().InVendorRamdisk() || ctx.RustModule().InRecovery()) && !strings.HasPrefix(ctx.ModuleDir(), "bionic/libc") {
+ s.Hwaddress = nil
+ }
+
+ if Bool(s.Hwaddress) {
+ s.Address = nil
+ }
+
+ // Memtag_heap is only implemented on AArch64.
+ if ctx.Arch().ArchType != android.Arm64 {
+ s.Memtag_heap = nil
+ }
+
+ if ctx.Os() == android.Android && (Bool(s.Hwaddress) || Bool(s.Address) || Bool(s.Memtag_heap)) {
sanitize.Properties.SanitizerEnabled = true
}
}
@@ -136,6 +257,26 @@
return
}
+ if Bool(mod.sanitize.Properties.Sanitize.Memtag_heap) && mod.Binary() {
+ noteDep := "note_memtag_heap_async"
+ if Bool(mod.sanitize.Properties.Sanitize.Diag.Memtag_heap) {
+ noteDep = "note_memtag_heap_sync"
+ }
+ // If we're using snapshots, redirect to snapshot whenever possible
+ // TODO(b/178470649): clean manual snapshot redirections
+ snapshot := mctx.Provider(cc.SnapshotInfoProvider).(cc.SnapshotInfo)
+ if lib, ok := snapshot.StaticLibs[noteDep]; ok {
+ noteDep = lib
+ }
+ depTag := cc.StaticDepTag(true)
+ variations := append(mctx.Target().Variations(),
+ blueprint.Variation{Mutator: "link", Variation: "static"})
+ if mod.Device() {
+ variations = append(variations, mod.ImageVariation())
+ }
+ mctx.AddFarVariationDependencies(variations, depTag, noteDep)
+ }
+
variations := mctx.Target().Variations()
var depTag blueprint.DependencyTag
var deps []string
@@ -149,26 +290,23 @@
} 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) {
+ if binary, ok := mod.compiler.(binaryInterface); ok {
+ if binary.staticallyLinked() {
mctx.ModuleErrorf("HWASan is not supported for static Rust executables yet.")
}
}
- if mod.StaticallyLinked() {
- variations = append(variations,
- blueprint.Variation{Mutator: "link", Variation: "static"})
- depTag = cc.StaticDepTag(false)
- deps = []string{config.LibclangRuntimeLibrary(mod.toolchain(mctx), "hwasan_static")}
- } else {
- variations = append(variations,
- blueprint.Variation{Mutator: "link", Variation: "shared"})
- depTag = cc.SharedDepTag()
- deps = []string{config.LibclangRuntimeLibrary(mod.toolchain(mctx), "hwasan")}
- }
+ // Always link against the shared library -- static binaries will pull in the static
+ // library during final link if necessary
+ variations = append(variations,
+ blueprint.Variation{Mutator: "link", Variation: "shared"})
+ depTag = cc.SharedDepTag()
+ deps = []string{config.LibclangRuntimeLibrary(mod.toolchain(mctx), "hwasan")}
}
- mctx.AddFarVariationDependencies(variations, depTag, deps...)
+ if len(deps) > 0 {
+ mctx.AddFarVariationDependencies(variations, depTag, deps...)
+ }
}
}
@@ -184,6 +322,9 @@
case cc.Hwasan:
sanitize.Properties.Sanitize.Hwaddress = boolPtr(b)
sanitizerSet = true
+ case cc.Memtag_heap:
+ sanitize.Properties.Sanitize.Memtag_heap = boolPtr(b)
+ sanitizerSet = true
default:
panic(fmt.Errorf("setting unsupported sanitizerType %d", t))
}
@@ -243,6 +384,8 @@
return sanitize.Properties.Sanitize.Address
case cc.Hwasan:
return sanitize.Properties.Sanitize.Hwaddress
+ case cc.Memtag_heap:
+ return sanitize.Properties.Sanitize.Memtag_heap
default:
return nil
}
@@ -268,6 +411,12 @@
case cc.Asan:
return true
case cc.Hwasan:
+ // TODO(b/180495975): HWASan for static Rust binaries isn't supported yet.
+ if mod.StaticExecutable() {
+ return false
+ }
+ return true
+ case cc.Memtag_heap:
return true
default:
return false
diff --git a/rust/sanitize_test.go b/rust/sanitize_test.go
new file mode 100644
index 0000000..d6a14b2
--- /dev/null
+++ b/rust/sanitize_test.go
@@ -0,0 +1,365 @@
+package rust
+
+import (
+ "fmt"
+ "strings"
+ "testing"
+
+ "android/soong/android"
+)
+
+type MemtagNoteType int
+
+const (
+ None MemtagNoteType = iota + 1
+ Sync
+ Async
+)
+
+func (t MemtagNoteType) str() string {
+ switch t {
+ case None:
+ return "none"
+ case Sync:
+ return "sync"
+ case Async:
+ return "async"
+ default:
+ panic("type_note_invalid")
+ }
+}
+
+func checkHasMemtagNote(t *testing.T, m android.TestingModule, expected MemtagNoteType) {
+ t.Helper()
+ note_async := "note_memtag_heap_async"
+ note_sync := "note_memtag_heap_sync"
+
+ found := None
+ implicits := m.Rule("rustc").Implicits
+ for _, lib := range implicits {
+ if strings.Contains(lib.Rel(), note_async) {
+ found = Async
+ break
+ } else if strings.Contains(lib.Rel(), note_sync) {
+ found = Sync
+ break
+ }
+ }
+
+ if found != expected {
+ t.Errorf("Wrong Memtag note in target %q: found %q, expected %q", m.Module().(*Module).Name(), found.str(), expected.str())
+ }
+}
+
+var prepareForTestWithMemtagHeap = android.GroupFixturePreparers(
+ android.FixtureModifyMockFS(func(fs android.MockFS) {
+ templateBp := `
+ rust_test {
+ name: "unset_test_%[1]s",
+ srcs: ["foo.rs"],
+ }
+
+ rust_test {
+ name: "no_memtag_test_%[1]s",
+ srcs: ["foo.rs"],
+ sanitize: { memtag_heap: false },
+ }
+
+ rust_test {
+ name: "set_memtag_test_%[1]s",
+ srcs: ["foo.rs"],
+ sanitize: { memtag_heap: true },
+ }
+
+ rust_test {
+ name: "set_memtag_set_async_test_%[1]s",
+ srcs: ["foo.rs"],
+ sanitize: { memtag_heap: true, diag: { memtag_heap: false } },
+ }
+
+ rust_test {
+ name: "set_memtag_set_sync_test_%[1]s",
+ srcs: ["foo.rs"],
+ sanitize: { memtag_heap: true, diag: { memtag_heap: true } },
+ }
+
+ rust_test {
+ name: "unset_memtag_set_sync_test_%[1]s",
+ srcs: ["foo.rs"],
+ sanitize: { diag: { memtag_heap: true } },
+ }
+
+ rust_binary {
+ name: "unset_binary_%[1]s",
+ srcs: ["foo.rs"],
+ }
+
+ rust_binary {
+ name: "no_memtag_binary_%[1]s",
+ srcs: ["foo.rs"],
+ sanitize: { memtag_heap: false },
+ }
+
+ rust_binary {
+ name: "set_memtag_binary_%[1]s",
+ srcs: ["foo.rs"],
+ sanitize: { memtag_heap: true },
+ }
+
+ rust_binary {
+ name: "set_memtag_set_async_binary_%[1]s",
+ srcs: ["foo.rs"],
+ sanitize: { memtag_heap: true, diag: { memtag_heap: false } },
+ }
+
+ rust_binary {
+ name: "set_memtag_set_sync_binary_%[1]s",
+ srcs: ["foo.rs"],
+ sanitize: { memtag_heap: true, diag: { memtag_heap: true } },
+ }
+
+ rust_binary {
+ name: "unset_memtag_set_sync_binary_%[1]s",
+ srcs: ["foo.rs"],
+ sanitize: { diag: { memtag_heap: true } },
+ }
+ `
+ subdirNoOverrideBp := fmt.Sprintf(templateBp, "no_override")
+ subdirOverrideDefaultDisableBp := fmt.Sprintf(templateBp, "override_default_disable")
+ subdirSyncBp := fmt.Sprintf(templateBp, "override_default_sync")
+ subdirAsyncBp := fmt.Sprintf(templateBp, "override_default_async")
+
+ fs.Merge(android.MockFS{
+ "subdir_no_override/Android.bp": []byte(subdirNoOverrideBp),
+ "subdir_override_default_disable/Android.bp": []byte(subdirOverrideDefaultDisableBp),
+ "subdir_sync/Android.bp": []byte(subdirSyncBp),
+ "subdir_async/Android.bp": []byte(subdirAsyncBp),
+ })
+ }),
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.MemtagHeapExcludePaths = []string{"subdir_override_default_disable"}
+ // "subdir_override_default_disable" is covered by both include and override_default_disable paths. override_default_disable wins.
+ variables.MemtagHeapSyncIncludePaths = []string{"subdir_sync", "subdir_override_default_disable"}
+ variables.MemtagHeapAsyncIncludePaths = []string{"subdir_async", "subdir_override_default_disable"}
+ }),
+)
+
+func TestSanitizeMemtagHeap(t *testing.T) {
+ variant := "android_arm64_armv8-a"
+
+ result := android.GroupFixturePreparers(
+ prepareForRustTest,
+ prepareForTestWithMemtagHeap,
+ ).RunTest(t)
+ ctx := result.TestContext
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_no_override", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_async", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_disable", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_sync", variant), None)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_no_override", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_async", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_disable", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_sync", variant), None)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_no_override", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_async", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_disable", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_no_override", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_async", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_disable", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_sync", variant), Async)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_no_override", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_async", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_disable", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_sync", variant), Async)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_no_override", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_disable", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_no_override", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_async", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_disable", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_sync", variant), Sync)
+}
+
+func TestSanitizeMemtagHeapWithSanitizeDevice(t *testing.T) {
+ variant := "android_arm64_armv8-a"
+
+ result := android.GroupFixturePreparers(
+ prepareForRustTest,
+ prepareForTestWithMemtagHeap,
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.SanitizeDevice = []string{"memtag_heap"}
+ }),
+ ).RunTest(t)
+ ctx := result.TestContext
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_no_override", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_async", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_disable", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_sync", variant), None)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_no_override", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_async", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_disable", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_sync", variant), None)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_no_override", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_async", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_disable", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_no_override", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_async", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_disable", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_sync", variant), Async)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_no_override", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_async", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_disable", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_sync", variant), Async)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_sync", variant), Sync)
+
+ // should sanitize: { diag: { memtag: true } } result in Sync instead of None here?
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_async", variant), Sync)
+ // should sanitize: { diag: { memtag: true } } result in Sync instead of None here?
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_disable", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_no_override", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_async", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_disable", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_sync", variant), Sync)
+}
+
+func TestSanitizeMemtagHeapWithSanitizeDeviceDiag(t *testing.T) {
+ variant := "android_arm64_armv8-a"
+
+ result := android.GroupFixturePreparers(
+ prepareForRustTest,
+ prepareForTestWithMemtagHeap,
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.SanitizeDevice = []string{"memtag_heap"}
+ variables.SanitizeDeviceDiag = []string{"memtag_heap"}
+ }),
+ ).RunTest(t)
+ ctx := result.TestContext
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_no_override", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_async", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_disable", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_sync", variant), None)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_no_override", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_async", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_disable", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_sync", variant), None)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_no_override", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_async", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_disable", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_sync", variant), Async)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_no_override", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_async", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_disable", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_sync", variant), Async)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_async", variant), Sync)
+ // should sanitize: { diag: { memtag: true } } result in Sync instead of None here?
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_disable", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_disable", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_sync", variant), Sync)
+}
diff --git a/rust/test.go b/rust/test.go
index 56da509..bb877a9 100644
--- a/rust/test.go
+++ b/rust/test.go
@@ -196,3 +196,7 @@
return deps
}
+
+func (test *testDecorator) testBinary() bool {
+ return true
+}
diff --git a/rust/testing.go b/rust/testing.go
index dac04d6..9f8ed54 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -91,7 +91,12 @@
no_libcrt: true,
nocrt: true,
system_shared_libs: [],
- export_include_dirs: ["libprotobuf-cpp-full-includes"],
+ }
+ cc_library {
+ name: "libclang_rt.hwasan_static-aarch64-android",
+ no_libcrt: true,
+ nocrt: true,
+ system_shared_libs: [],
}
rust_library {
name: "libstd",
@@ -186,5 +191,8 @@
ctx.BottomUp("rust_begin", BeginMutator).Parallel()
})
ctx.RegisterSingletonType("rust_project_generator", rustProjectGeneratorSingleton)
+ ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.BottomUp("rust_sanitizers", rustSanitizerRuntimeMutator).Parallel()
+ })
registerRustSnapshotModules(ctx)
}
diff --git a/rust/vendor_snapshot_test.go b/rust/vendor_snapshot_test.go
index 60ddb65..bfa6f36 100644
--- a/rust/vendor_snapshot_test.go
+++ b/rust/vendor_snapshot_test.go
@@ -562,6 +562,7 @@
"libvendor",
"libvndk",
"libclang_rt.builtins-aarch64-android",
+ "note_memtag_heap_sync",
],
shared_libs: [
"libvendor_available",
@@ -853,6 +854,20 @@
},
}
+ // Test sanitizers use the snapshot libraries
+ rust_binary {
+ name: "memtag_binary",
+ srcs: ["vendor/bin.rs"],
+ vendor: true,
+ compile_multilib: "64",
+ sanitize: {
+ memtag_heap: true,
+ diag: {
+ memtag_heap: true,
+ }
+ },
+ }
+
// old snapshot module which has to be ignored
vendor_snapshot_binary {
name: "bin",
@@ -880,11 +895,25 @@
},
},
}
+
+ vendor_snapshot_static {
+ name: "note_memtag_heap_sync",
+ vendor: true,
+ target_arch: "arm64",
+ version: "30",
+ arch: {
+ arm64: {
+ src: "note_memtag_heap_sync.a",
+ },
+ },
+ }
+
`
mockFS := android.MockFS{
"framework/Android.bp": []byte(frameworkBp),
"framework/bin.rs": nil,
+ "note_memtag_heap_sync.a": nil,
"vendor/Android.bp": []byte(vendorProprietaryBp),
"vendor/bin": nil,
"vendor/bin32": nil,
@@ -993,4 +1022,9 @@
if android.InList(binaryVariant, binVariants) {
t.Errorf("bin must not have variant %#v, but it does", sharedVariant)
}
+
+ memtagStaticLibs := ctx.ModuleForTests("memtag_binary", "android_vendor.30_arm64_armv8-a").Module().(*Module).Properties.AndroidMkStaticLibs
+ if g, w := memtagStaticLibs, []string{"libclang_rt.builtins-aarch64-android.vendor", "note_memtag_heap_sync.vendor"}; !reflect.DeepEqual(g, w) {
+ t.Errorf("wanted memtag_binary AndroidMkStaticLibs %q, got %q", w, g)
+ }
}
diff --git a/scripts/Android.bp b/scripts/Android.bp
index 635be10..730d756 100644
--- a/scripts/Android.bp
+++ b/scripts/Android.bp
@@ -1,5 +1,6 @@
package {
default_applicable_licenses: ["Android-Apache-2.0"],
+ default_visibility: ["//build/soong:__subpackages__"],
}
python_binary_host {
@@ -8,14 +9,6 @@
srcs: [
"check_boot_jars/check_boot_jars.py",
],
- version: {
- py2: {
- enabled: true,
- },
- py3: {
- enabled: false,
- },
- },
}
python_binary_host {
@@ -24,14 +17,6 @@
srcs: [
"manifest_fixer.py",
],
- version: {
- py2: {
- enabled: true,
- },
- py3: {
- enabled: false,
- },
- },
libs: [
"manifest_utils",
],
@@ -45,11 +30,8 @@
"manifest_fixer.py",
],
version: {
- py2: {
- enabled: true,
- },
py3: {
- enabled: false,
+ embedded_launcher: true,
},
},
libs: [
@@ -67,12 +49,14 @@
],
version: {
py2: {
+ // TODO(b/203436762) Remove when system/apex/apexer/apexer.py is converted
enabled: true,
},
py3: {
- enabled: false,
+ enabled: true,
},
},
+ visibility: ["//system/apex/apexer:__pkg__"],
}
python_binary_host {
@@ -81,14 +65,6 @@
srcs: [
"manifest_check.py",
],
- version: {
- py2: {
- enabled: true,
- },
- py3: {
- enabled: false,
- },
- },
libs: [
"manifest_utils",
],
@@ -101,14 +77,6 @@
"manifest_check_test.py",
"manifest_check.py",
],
- version: {
- py2: {
- enabled: true,
- },
- py3: {
- enabled: false,
- },
- },
libs: [
"manifest_utils",
],
@@ -123,14 +91,6 @@
srcs: [
"jsonmodify.py",
],
- version: {
- py2: {
- enabled: true,
- },
- py3: {
- enabled: false,
- },
- },
}
python_binary_host {
@@ -139,14 +99,6 @@
srcs: [
"test_config_fixer.py",
],
- version: {
- py2: {
- enabled: true,
- },
- py3: {
- enabled: false,
- },
- },
libs: [
"manifest_utils",
],
@@ -159,14 +111,6 @@
"test_config_fixer_test.py",
"test_config_fixer.py",
],
- version: {
- py2: {
- enabled: true,
- },
- py3: {
- enabled: false,
- },
- },
libs: [
"manifest_utils",
],
@@ -179,14 +123,6 @@
srcs: [
"construct_context.py",
],
- version: {
- py2: {
- enabled: true,
- },
- py3: {
- enabled: false,
- },
- },
libs: [
"manifest_utils",
],
@@ -199,14 +135,6 @@
"construct_context_test.py",
"construct_context.py",
],
- version: {
- py2: {
- enabled: true,
- },
- py3: {
- enabled: false,
- },
- },
libs: [
"manifest_utils",
],
@@ -253,11 +181,7 @@
"conv_linker_config.py",
],
version: {
- py2: {
- enabled: false,
- },
py3: {
- enabled: true,
embedded_launcher: true,
},
},
@@ -272,12 +196,4 @@
srcs: [
"get_clang_version.py",
],
- version: {
- py2: {
- enabled: false,
- },
- py3: {
- enabled: true,
- },
- },
}
diff --git a/scripts/manifest.py b/scripts/manifest.py
index 04f7405..81f9c61 100755
--- a/scripts/manifest.py
+++ b/scripts/manifest.py
@@ -123,4 +123,4 @@
def write_xml(f, doc):
f.write('<?xml version="1.0" encoding="utf-8"?>\n')
for node in doc.childNodes:
- f.write(node.toxml(encoding='utf-8') + '\n')
+ f.write(node.toxml() + '\n')
diff --git a/scripts/manifest_check.py b/scripts/manifest_check.py
index 8bed52a..c8d4f76 100755
--- a/scripts/manifest_check.py
+++ b/scripts/manifest_check.py
@@ -335,7 +335,7 @@
if is_apk:
aapt = args.aapt if args.aapt is not None else 'aapt'
manifest = subprocess.check_output(
- [aapt, 'dump', 'badging', args.input])
+ [aapt, 'dump', 'badging', args.input]).decode('utf-8')
else:
manifest = minidom.parse(args.input)
@@ -381,7 +381,7 @@
if is_apk:
raise RuntimeError('cannot save APK manifest as XML')
- with open(args.output, 'wb') as f:
+ with open(args.output, 'w') as f:
write_xml(f, manifest)
# pylint: disable=broad-except
diff --git a/scripts/manifest_fixer.py b/scripts/manifest_fixer.py
index 55d0fd1..d80a617 100755
--- a/scripts/manifest_fixer.py
+++ b/scripts/manifest_fixer.py
@@ -352,7 +352,7 @@
if args.extract_native_libs is not None:
add_extract_native_libs(doc, args.extract_native_libs)
- with open(args.output, 'wb') as f:
+ with open(args.output, 'w') as f:
write_xml(f, doc)
# pylint: disable=broad-except
diff --git a/scripts/manifest_fixer_test.py b/scripts/manifest_fixer_test.py
index 3a0a25d..f6fcaaf 100755
--- a/scripts/manifest_fixer_test.py
+++ b/scripts/manifest_fixer_test.py
@@ -16,16 +16,16 @@
#
"""Unit tests for manifest_fixer.py."""
-import StringIO
+import io
import sys
import unittest
from xml.dom import minidom
+import xml.etree.ElementTree as ET
import manifest_fixer
sys.dont_write_bytecode = True
-
class CompareVersionGtTest(unittest.TestCase):
"""Unit tests for compare_version_gt function."""
@@ -59,7 +59,7 @@
doc = minidom.parseString(input_manifest)
manifest_fixer.raise_min_sdk_version(doc, min_sdk_version,
target_sdk_version, library)
- output = StringIO.StringIO()
+ output = io.StringIO()
manifest_fixer.write_xml(output, doc)
return output.getvalue()
@@ -80,13 +80,16 @@
attrs += ' ' + extra
return ' <uses-sdk%s/>\n' % (attrs)
+ def assert_xml_equal(self, output, expected):
+ self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected))
+
def test_no_uses_sdk(self):
"""Tests inserting a uses-sdk element into a manifest."""
manifest_input = self.manifest_tmpl % ''
expected = self.manifest_tmpl % self.uses_sdk(min='28', target='28')
output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_no_min(self):
"""Tests inserting a minSdkVersion attribute into a uses-sdk element."""
@@ -95,7 +98,7 @@
expected = self.manifest_tmpl % self.uses_sdk(min='28', target='28',
extra='extra="foo"')
output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_raise_min(self):
"""Tests inserting a minSdkVersion attribute into a uses-sdk element."""
@@ -103,7 +106,7 @@
manifest_input = self.manifest_tmpl % self.uses_sdk(min='27')
expected = self.manifest_tmpl % self.uses_sdk(min='28', target='28')
output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_raise(self):
"""Tests raising a minSdkVersion attribute."""
@@ -111,7 +114,7 @@
manifest_input = self.manifest_tmpl % self.uses_sdk(min='27')
expected = self.manifest_tmpl % self.uses_sdk(min='28', target='28')
output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_no_raise_min(self):
"""Tests a minSdkVersion that doesn't need raising."""
@@ -119,7 +122,7 @@
manifest_input = self.manifest_tmpl % self.uses_sdk(min='28')
expected = self.manifest_tmpl % self.uses_sdk(min='28', target='27')
output = self.raise_min_sdk_version_test(manifest_input, '27', '27', False)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_raise_codename(self):
"""Tests raising a minSdkVersion attribute to a codename."""
@@ -127,7 +130,7 @@
manifest_input = self.manifest_tmpl % self.uses_sdk(min='28')
expected = self.manifest_tmpl % self.uses_sdk(min='P', target='P')
output = self.raise_min_sdk_version_test(manifest_input, 'P', 'P', False)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_no_raise_codename(self):
"""Tests a minSdkVersion codename that doesn't need raising."""
@@ -135,7 +138,7 @@
manifest_input = self.manifest_tmpl % self.uses_sdk(min='P')
expected = self.manifest_tmpl % self.uses_sdk(min='P', target='28')
output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_target(self):
"""Tests an existing targetSdkVersion is preserved."""
@@ -143,7 +146,7 @@
manifest_input = self.manifest_tmpl % self.uses_sdk(min='26', target='27')
expected = self.manifest_tmpl % self.uses_sdk(min='28', target='27')
output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_no_target(self):
"""Tests inserting targetSdkVersion when minSdkVersion exists."""
@@ -151,7 +154,7 @@
manifest_input = self.manifest_tmpl % self.uses_sdk(min='27')
expected = self.manifest_tmpl % self.uses_sdk(min='28', target='29')
output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_target_no_min(self):
""""Tests inserting targetSdkVersion when minSdkVersion exists."""
@@ -159,7 +162,7 @@
manifest_input = self.manifest_tmpl % self.uses_sdk(target='27')
expected = self.manifest_tmpl % self.uses_sdk(min='28', target='27')
output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_no_target_no_min(self):
"""Tests inserting targetSdkVersion when minSdkVersion does not exist."""
@@ -167,7 +170,7 @@
manifest_input = self.manifest_tmpl % ''
expected = self.manifest_tmpl % self.uses_sdk(min='28', target='29')
output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_library_no_target(self):
"""Tests inserting targetSdkVersion when minSdkVersion exists."""
@@ -175,7 +178,7 @@
manifest_input = self.manifest_tmpl % self.uses_sdk(min='27')
expected = self.manifest_tmpl % self.uses_sdk(min='28', target='16')
output = self.raise_min_sdk_version_test(manifest_input, '28', '29', True)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_library_target_no_min(self):
"""Tests inserting targetSdkVersion when minSdkVersion exists."""
@@ -183,7 +186,7 @@
manifest_input = self.manifest_tmpl % self.uses_sdk(target='27')
expected = self.manifest_tmpl % self.uses_sdk(min='28', target='27')
output = self.raise_min_sdk_version_test(manifest_input, '28', '29', True)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_library_no_target_no_min(self):
"""Tests inserting targetSdkVersion when minSdkVersion does not exist."""
@@ -191,7 +194,7 @@
manifest_input = self.manifest_tmpl % ''
expected = self.manifest_tmpl % self.uses_sdk(min='28', target='16')
output = self.raise_min_sdk_version_test(manifest_input, '28', '29', True)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_extra(self):
"""Tests that extra attributes and elements are maintained."""
@@ -204,12 +207,12 @@
# pylint: disable=line-too-long
expected = self.manifest_tmpl % (
' <!-- comment -->\n'
- ' <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="29" extra="foo"/>\n'
+ ' <uses-sdk android:minSdkVersion="28" extra="foo" android:targetSdkVersion="29"/>\n'
' <application/>\n')
output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_indent(self):
"""Tests that an inserted element copies the existing indentation."""
@@ -223,17 +226,20 @@
output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
class AddLoggingParentTest(unittest.TestCase):
"""Unit tests for add_logging_parent function."""
+ def assert_xml_equal(self, output, expected):
+ self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected))
+
def add_logging_parent_test(self, input_manifest, logging_parent=None):
doc = minidom.parseString(input_manifest)
if logging_parent:
manifest_fixer.add_logging_parent(doc, logging_parent)
- output = StringIO.StringIO()
+ output = io.StringIO()
manifest_fixer.write_xml(output, doc)
return output.getvalue()
@@ -257,23 +263,26 @@
manifest_input = self.manifest_tmpl % ''
expected = self.manifest_tmpl % self.uses_logging_parent()
output = self.add_logging_parent_test(manifest_input)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_logging_parent(self):
"""Tests manifest_fixer with no logging_parent."""
manifest_input = self.manifest_tmpl % ''
expected = self.manifest_tmpl % self.uses_logging_parent('FOO')
output = self.add_logging_parent_test(manifest_input, 'FOO')
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
class AddUsesLibrariesTest(unittest.TestCase):
"""Unit tests for add_uses_libraries function."""
+ def assert_xml_equal(self, output, expected):
+ self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected))
+
def run_test(self, input_manifest, new_uses_libraries):
doc = minidom.parseString(input_manifest)
manifest_fixer.add_uses_libraries(doc, new_uses_libraries, True)
- output = StringIO.StringIO()
+ output = io.StringIO()
manifest_fixer.write_xml(output, doc)
return output.getvalue()
@@ -301,7 +310,7 @@
('bar', 'false')])
expected = manifest_input
output = self.run_test(manifest_input, [])
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_not_overwrite(self):
"""new_uses_libraries must not overwrite existing tags."""
@@ -310,7 +319,7 @@
('bar', 'false')])
expected = manifest_input
output = self.run_test(manifest_input, ['foo', 'bar'])
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_add(self):
"""New names are added with 'required:true'."""
@@ -323,7 +332,7 @@
('baz', 'true'),
('qux', 'true')])
output = self.run_test(manifest_input, ['bar', 'baz', 'qux'])
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_no_application(self):
"""When there is no <application> tag, the tag is added."""
@@ -336,7 +345,7 @@
('foo', 'true'),
('bar', 'true')])
output = self.run_test(manifest_input, ['foo', 'bar'])
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_empty_application(self):
"""Even when here is an empty <application/> tag, the libs are added."""
@@ -350,16 +359,19 @@
('foo', 'true'),
('bar', 'true')])
output = self.run_test(manifest_input, ['foo', 'bar'])
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
class AddUsesNonSdkApiTest(unittest.TestCase):
"""Unit tests for add_uses_libraries function."""
+ def assert_xml_equal(self, output, expected):
+ self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected))
+
def run_test(self, input_manifest):
doc = minidom.parseString(input_manifest)
manifest_fixer.add_uses_non_sdk_api(doc)
- output = StringIO.StringIO()
+ output = io.StringIO()
manifest_fixer.write_xml(output, doc)
return output.getvalue()
@@ -377,23 +389,26 @@
manifest_input = self.manifest_tmpl % self.uses_non_sdk_api(False)
expected = self.manifest_tmpl % self.uses_non_sdk_api(True)
output = self.run_test(manifest_input)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_already_set(self):
"""new_uses_libraries must not overwrite existing tags."""
manifest_input = self.manifest_tmpl % self.uses_non_sdk_api(True)
expected = manifest_input
output = self.run_test(manifest_input)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
class UseEmbeddedDexTest(unittest.TestCase):
"""Unit tests for add_use_embedded_dex function."""
+ def assert_xml_equal(self, output, expected):
+ self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected))
+
def run_test(self, input_manifest):
doc = minidom.parseString(input_manifest)
manifest_fixer.add_use_embedded_dex(doc)
- output = StringIO.StringIO()
+ output = io.StringIO()
manifest_fixer.write_xml(output, doc)
return output.getvalue()
@@ -410,13 +425,13 @@
manifest_input = self.manifest_tmpl % ''
expected = self.manifest_tmpl % self.use_embedded_dex('true')
output = self.run_test(manifest_input)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_manifest_with_use_embedded_dex(self):
manifest_input = self.manifest_tmpl % self.use_embedded_dex('true')
expected = manifest_input
output = self.run_test(manifest_input)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_manifest_with_not_use_embedded_dex(self):
manifest_input = self.manifest_tmpl % self.use_embedded_dex('false')
@@ -426,10 +441,13 @@
class AddExtractNativeLibsTest(unittest.TestCase):
"""Unit tests for add_extract_native_libs function."""
+ def assert_xml_equal(self, output, expected):
+ self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected))
+
def run_test(self, input_manifest, value):
doc = minidom.parseString(input_manifest)
manifest_fixer.add_extract_native_libs(doc, value)
- output = StringIO.StringIO()
+ output = io.StringIO()
manifest_fixer.write_xml(output, doc)
return output.getvalue()
@@ -446,19 +464,19 @@
manifest_input = self.manifest_tmpl % ''
expected = self.manifest_tmpl % self.extract_native_libs('true')
output = self.run_test(manifest_input, True)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_set_false(self):
manifest_input = self.manifest_tmpl % ''
expected = self.manifest_tmpl % self.extract_native_libs('false')
output = self.run_test(manifest_input, False)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_match(self):
manifest_input = self.manifest_tmpl % self.extract_native_libs('true')
expected = manifest_input
output = self.run_test(manifest_input, True)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_conflict(self):
manifest_input = self.manifest_tmpl % self.extract_native_libs('true')
@@ -468,10 +486,13 @@
class AddNoCodeApplicationTest(unittest.TestCase):
"""Unit tests for set_has_code_to_false function."""
+ def assert_xml_equal(self, output, expected):
+ self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected))
+
def run_test(self, input_manifest):
doc = minidom.parseString(input_manifest)
manifest_fixer.set_has_code_to_false(doc)
- output = StringIO.StringIO()
+ output = io.StringIO()
manifest_fixer.write_xml(output, doc)
return output.getvalue()
@@ -485,26 +506,26 @@
manifest_input = self.manifest_tmpl % ''
expected = self.manifest_tmpl % ' <application android:hasCode="false"/>\n'
output = self.run_test(manifest_input)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_has_application_no_has_code(self):
manifest_input = self.manifest_tmpl % ' <application/>\n'
expected = self.manifest_tmpl % ' <application android:hasCode="false"/>\n'
output = self.run_test(manifest_input)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_has_application_has_code_false(self):
""" Do nothing if there's already an application elemeent. """
manifest_input = self.manifest_tmpl % ' <application android:hasCode="false"/>\n'
output = self.run_test(manifest_input)
- self.assertEqual(output, manifest_input)
+ self.assert_xml_equal(output, manifest_input)
def test_has_application_has_code_true(self):
""" Do nothing if there's already an application elemeent even if its
hasCode attribute is true. """
manifest_input = self.manifest_tmpl % ' <application android:hasCode="true"/>\n'
output = self.run_test(manifest_input)
- self.assertEqual(output, manifest_input)
+ self.assert_xml_equal(output, manifest_input)
if __name__ == '__main__':
diff --git a/scripts/test_config_fixer.py b/scripts/test_config_fixer.py
index 32d5b17..c150e8c 100644
--- a/scripts/test_config_fixer.py
+++ b/scripts/test_config_fixer.py
@@ -86,7 +86,7 @@
if args.test_file_name:
overwrite_test_file_name(doc, args.test_file_name)
- with open(args.output, 'wb') as f:
+ with open(args.output, 'w') as f:
write_xml(f, doc)
# pylint: disable=broad-except
diff --git a/scripts/test_config_fixer_test.py b/scripts/test_config_fixer_test.py
index 1272c6b..d00a593 100644
--- a/scripts/test_config_fixer_test.py
+++ b/scripts/test_config_fixer_test.py
@@ -16,7 +16,7 @@
#
"""Unit tests for test_config_fixer.py."""
-import StringIO
+import io
import sys
import unittest
from xml.dom import minidom
@@ -59,7 +59,7 @@
manifest = minidom.parseString(self.manifest)
test_config_fixer.overwrite_package_name(doc, manifest, "com.soong.foo")
- output = StringIO.StringIO()
+ output = io.StringIO()
test_config_fixer.write_xml(output, doc)
# Only the matching package name in a test node should be updated.
@@ -86,7 +86,7 @@
doc = minidom.parseString(self.test_config % ("foo.apk"))
test_config_fixer.overwrite_test_file_name(doc, "bar.apk")
- output = StringIO.StringIO()
+ output = io.StringIO()
test_config_fixer.write_xml(output, doc)
# Only the matching package name in a test node should be updated.