Merge "Add tidy_timeout_srcs property"
diff --git a/android/bazel.go b/android/bazel.go
index 4a96918..f4fc038 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -540,6 +540,31 @@
 		"libadb_pairing_connection",
 		"libadb_pairing_connection_static",
 		"libadb_pairing_server", "libadb_pairing_server_static",
+
+		// TODO(b/204811222) support suffix in cc_binary
+		"acvp_modulewrapper",
+		"android.hardware.media.c2@1.0-service-v4l2",
+		"app_process",
+		"bar_test",
+		"bench_cxa_atexit",
+		"bench_noop",
+		"bench_noop_nostl",
+		"bench_noop_static",
+		"boringssl_self_test",
+		"boringssl_self_test_vendor",
+		"bssl",
+		"cavp",
+		"crash_dump",
+		"crasher",
+		"libcxx_test_template",
+		"linker",
+		"memory_replay",
+		"native_bridge_guest_linker",
+		"native_bridge_stub_library_defaults",
+		"noop",
+		"simpleperf_ndk",
+		"toybox-static",
+		"zlib_bench",
 	}
 
 	// Used for quicker lookups
diff --git a/android/util.go b/android/util.go
index 0ee253e..47c4583 100644
--- a/android/util.go
+++ b/android/util.go
@@ -65,21 +65,55 @@
 	return buf.String()
 }
 
-// SorterStringKeys returns the keys of the given string-keyed map in the ascending order
+// SorterStringKeys returns the keys of the given string-keyed map in the ascending order.
 func SortedStringKeys(m interface{}) []string {
 	v := reflect.ValueOf(m)
 	if v.Kind() != reflect.Map {
 		panic(fmt.Sprintf("%#v is not a map", m))
 	}
-	keys := v.MapKeys()
-	s := make([]string, 0, len(keys))
-	for _, key := range keys {
-		s = append(s, key.String())
+	if v.Len() == 0 {
+		return nil
+	}
+	iter := v.MapRange()
+	s := make([]string, 0, v.Len())
+	for iter.Next() {
+		s = append(s, iter.Key().String())
 	}
 	sort.Strings(s)
 	return s
 }
 
+// stringValues returns the values of the given string-valued map in randomized map order.
+func stringValues(m interface{}) []string {
+	v := reflect.ValueOf(m)
+	if v.Kind() != reflect.Map {
+		panic(fmt.Sprintf("%#v is not a map", m))
+	}
+	if v.Len() == 0 {
+		return nil
+	}
+	iter := v.MapRange()
+	s := make([]string, 0, v.Len())
+	for iter.Next() {
+		s = append(s, iter.Value().String())
+	}
+	return s
+}
+
+// SortedStringValues returns the values of the given string-valued map in the ascending order.
+func SortedStringValues(m interface{}) []string {
+	s := stringValues(m)
+	sort.Strings(s)
+	return s
+}
+
+// SortedUniqueStringValues returns the values of the given string-valued map in the ascending order
+// with duplicates removed.
+func SortedUniqueStringValues(m interface{}) []string {
+	s := stringValues(m)
+	return SortedUniqueStrings(s)
+}
+
 // IndexList returns the index of the first occurrence of the given string in the list or -1
 func IndexList(s string, list []string) int {
 	for i, l := range list {
diff --git a/android/util_test.go b/android/util_test.go
index 09bec01..9b9253b 100644
--- a/android/util_test.go
+++ b/android/util_test.go
@@ -640,3 +640,117 @@
 		})
 	}
 }
+
+func TestSortedStringKeys(t *testing.T) {
+	testCases := []struct {
+		name     string
+		in       interface{}
+		expected []string
+	}{
+		{
+			name:     "nil",
+			in:       map[string]string(nil),
+			expected: nil,
+		},
+		{
+			name:     "empty",
+			in:       map[string]string{},
+			expected: nil,
+		},
+		{
+			name:     "simple",
+			in:       map[string]string{"a": "foo", "b": "bar"},
+			expected: []string{"a", "b"},
+		},
+		{
+			name:     "interface values",
+			in:       map[string]interface{}{"a": nil, "b": nil},
+			expected: []string{"a", "b"},
+		},
+	}
+
+	for _, tt := range testCases {
+		t.Run(tt.name, func(t *testing.T) {
+			got := SortedStringKeys(tt.in)
+			if g, w := got, tt.expected; !reflect.DeepEqual(g, w) {
+				t.Errorf("wanted %q, got %q", w, g)
+			}
+		})
+	}
+}
+
+func TestSortedStringValues(t *testing.T) {
+	testCases := []struct {
+		name     string
+		in       interface{}
+		expected []string
+	}{
+		{
+			name:     "nil",
+			in:       map[string]string(nil),
+			expected: nil,
+		},
+		{
+			name:     "empty",
+			in:       map[string]string{},
+			expected: nil,
+		},
+		{
+			name:     "simple",
+			in:       map[string]string{"foo": "a", "bar": "b"},
+			expected: []string{"a", "b"},
+		},
+		{
+			name:     "duplicates",
+			in:       map[string]string{"foo": "a", "bar": "b", "baz": "b"},
+			expected: []string{"a", "b", "b"},
+		},
+	}
+
+	for _, tt := range testCases {
+		t.Run(tt.name, func(t *testing.T) {
+			got := SortedStringValues(tt.in)
+			if g, w := got, tt.expected; !reflect.DeepEqual(g, w) {
+				t.Errorf("wanted %q, got %q", w, g)
+			}
+		})
+	}
+}
+
+func TestSortedUniqueStringValues(t *testing.T) {
+	testCases := []struct {
+		name     string
+		in       interface{}
+		expected []string
+	}{
+		{
+			name:     "nil",
+			in:       map[string]string(nil),
+			expected: nil,
+		},
+		{
+			name:     "empty",
+			in:       map[string]string{},
+			expected: nil,
+		},
+		{
+			name:     "simple",
+			in:       map[string]string{"foo": "a", "bar": "b"},
+			expected: []string{"a", "b"},
+		},
+		{
+			name:     "duplicates",
+			in:       map[string]string{"foo": "a", "bar": "b", "baz": "b"},
+			expected: []string{"a", "b"},
+		},
+	}
+
+	for _, tt := range testCases {
+		t.Run(tt.name, func(t *testing.T) {
+			got := SortedUniqueStringValues(tt.in)
+			if g, w := got, tt.expected; !reflect.DeepEqual(g, w) {
+				t.Errorf("wanted %q, got %q", w, g)
+			}
+		})
+	}
+}
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 7154905..9290272 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -399,6 +399,9 @@
 		}
 
 		entries.SetBoolIfTrue("LOCAL_COMPATIBILITY_PER_TESTCASE_DIRECTORY", Bool(test.Properties.Per_testcase_directory))
+		if len(test.Properties.Data_bins) > 0 {
+			entries.AddStrings("LOCAL_TEST_DATA_BINS", test.Properties.Data_bins...)
+		}
 	})
 
 	AndroidMkWriteTestData(test.data, entries)
diff --git a/cc/binary.go b/cc/binary.go
index 54fd339..6c7d581 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -70,6 +70,7 @@
 // cc_binary produces a binary that is runnable on a device.
 func BinaryFactory() android.Module {
 	module, _ := newBinary(android.HostAndDeviceSupported, true)
+	module.bazelHandler = &ccBinaryBazelHandler{module: module}
 	return module.Init()
 }
 
@@ -556,6 +557,28 @@
 	})
 }
 
+type ccBinaryBazelHandler struct {
+	android.BazelHandler
+
+	module *Module
+}
+
+func (handler *ccBinaryBazelHandler) GenerateBazelBuildActions(ctx android.ModuleContext, label string) bool {
+	bazelCtx := ctx.Config().BazelContext
+	filePaths, ok := bazelCtx.GetOutputFiles(label, android.GetConfigKey(ctx))
+	if ok {
+		if len(filePaths) != 1 {
+			ctx.ModuleErrorf("expected exactly one output file for '%s', but got %s", label, filePaths)
+			return false
+		}
+		outputFilePath := android.PathForBazelOut(ctx, filePaths[0])
+		handler.module.outputFile = android.OptionalPathForPath(outputFilePath)
+		// TODO(b/220164721): We need to decide if we should return the stripped as the unstripped.
+		handler.module.linker.(*binaryDecorator).unstrippedOutputFile = outputFilePath
+	}
+	return ok
+}
+
 func binaryBp2build(ctx android.TopDownMutatorContext, m *Module, typ string) {
 	baseAttrs := bp2BuildParseBaseProps(ctx, m)
 	binaryLinkerAttrs := bp2buildBinaryLinkerProps(ctx, m)
diff --git a/cc/binary_test.go b/cc/binary_test.go
new file mode 100644
index 0000000..8ec3871
--- /dev/null
+++ b/cc/binary_test.go
@@ -0,0 +1,51 @@
+// Copyright 2022 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cc
+
+import (
+	"testing"
+
+	"android/soong/android"
+)
+
+func TestCcBinaryWithBazel(t *testing.T) {
+	bp := `
+cc_binary {
+	name: "foo",
+	srcs: ["foo.cc"],
+	bazel_module: { label: "//foo/bar:bar" },
+}`
+	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
+	config.BazelContext = android.MockBazelContext{
+		OutputBaseDir: "outputbase",
+		LabelToOutputFiles: map[string][]string{
+			"//foo/bar:bar": []string{"foo"},
+		},
+	}
+	ctx := testCcWithConfig(t, config)
+
+	binMod := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Module()
+	producer := binMod.(android.OutputFileProducer)
+	outputFiles, err := producer.OutputFiles("")
+	if err != nil {
+		t.Errorf("Unexpected error getting cc_binary outputfiles %s", err)
+	}
+	expectedOutputFiles := []string{"outputbase/execroot/__main__/foo"}
+	android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings())
+
+	unStrippedFilePath := binMod.(*Module).UnstrippedOutputFile()
+	expectedUnStrippedFile := "outputbase/execroot/__main__/foo"
+	android.AssertStringEquals(t, "Unstripped output file", expectedUnStrippedFile, unStrippedFilePath.String())
+}
diff --git a/cc/makevars.go b/cc/makevars.go
index 1ad71ec..6752f8c 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -255,14 +255,43 @@
 	}, " "))
 
 	if target.Os.Class == android.Device {
-		ctx.Strict(secondPrefix+"ADDRESS_SANITIZER_RUNTIME_LIBRARY", strings.TrimSuffix(config.AddressSanitizerRuntimeLibrary(toolchain), ".so"))
-		ctx.Strict(secondPrefix+"HWADDRESS_SANITIZER_RUNTIME_LIBRARY", strings.TrimSuffix(config.HWAddressSanitizerRuntimeLibrary(toolchain), ".so"))
-		ctx.Strict(secondPrefix+"HWADDRESS_SANITIZER_STATIC_LIBRARY", strings.TrimSuffix(config.HWAddressSanitizerStaticLibrary(toolchain), ".a"))
-		ctx.Strict(secondPrefix+"UBSAN_RUNTIME_LIBRARY", strings.TrimSuffix(config.UndefinedBehaviorSanitizerRuntimeLibrary(toolchain), ".so"))
-		ctx.Strict(secondPrefix+"UBSAN_MINIMAL_RUNTIME_LIBRARY", strings.TrimSuffix(config.UndefinedBehaviorSanitizerMinimalRuntimeLibrary(toolchain), ".a"))
-		ctx.Strict(secondPrefix+"TSAN_RUNTIME_LIBRARY", strings.TrimSuffix(config.ThreadSanitizerRuntimeLibrary(toolchain), ".so"))
-		ctx.Strict(secondPrefix+"SCUDO_RUNTIME_LIBRARY", strings.TrimSuffix(config.ScudoRuntimeLibrary(toolchain), ".so"))
-		ctx.Strict(secondPrefix+"SCUDO_MINIMAL_RUNTIME_LIBRARY", strings.TrimSuffix(config.ScudoMinimalRuntimeLibrary(toolchain), ".so"))
+		sanitizerVariables := map[string]string{
+			"ADDRESS_SANITIZER_RUNTIME_LIBRARY":   config.AddressSanitizerRuntimeLibrary(toolchain),
+			"HWADDRESS_SANITIZER_RUNTIME_LIBRARY": config.HWAddressSanitizerRuntimeLibrary(toolchain),
+			"HWADDRESS_SANITIZER_STATIC_LIBRARY":  config.HWAddressSanitizerStaticLibrary(toolchain),
+			"UBSAN_RUNTIME_LIBRARY":               config.UndefinedBehaviorSanitizerRuntimeLibrary(toolchain),
+			"UBSAN_MINIMAL_RUNTIME_LIBRARY":       config.UndefinedBehaviorSanitizerMinimalRuntimeLibrary(toolchain),
+			"TSAN_RUNTIME_LIBRARY":                config.ThreadSanitizerRuntimeLibrary(toolchain),
+			"SCUDO_RUNTIME_LIBRARY":               config.ScudoRuntimeLibrary(toolchain),
+			"SCUDO_MINIMAL_RUNTIME_LIBRARY":       config.ScudoMinimalRuntimeLibrary(toolchain),
+		}
+
+		for variable, value := range sanitizerVariables {
+			ctx.Strict(secondPrefix+variable, value)
+		}
+
+		sanitizerLibs := android.SortedStringValues(sanitizerVariables)
+		var sanitizerLibStems []string
+		ctx.VisitAllModules(func(m android.Module) {
+			if !m.Enabled() {
+				return
+			}
+
+			ccModule, _ := m.(*Module)
+			if ccModule == nil || ccModule.library == nil || !ccModule.library.shared() {
+				return
+			}
+
+			if android.InList(strings.TrimPrefix(ctx.ModuleName(m), "prebuilt_"), sanitizerLibs) &&
+				m.Target().Os == target.Os && m.Target().Arch.ArchType == target.Arch.ArchType {
+				outputFile := ccModule.outputFile
+				if outputFile.Valid() {
+					sanitizerLibStems = append(sanitizerLibStems, outputFile.Path().Base())
+				}
+			}
+		})
+		sanitizerLibStems = android.SortedUniqueStrings(sanitizerLibStems)
+		ctx.Strict(secondPrefix+"SANITIZER_STEMS", strings.Join(sanitizerLibStems, " "))
 	}
 
 	// This is used by external/gentoo/...
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 1db2219..f8661a6 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -42,6 +42,7 @@
 		"-fno-omit-frame-pointer",
 		"-Wno-frame-larger-than=",
 		"-fsanitize-hwaddress-abi=platform",
+		"-mllvm", "-hwasan-use-after-scope=1",
 	}
 
 	// ThinLTO performs codegen during link time, thus these flags need to
diff --git a/rust/androidmk.go b/rust/androidmk.go
index 4e58632..2361e03 100644
--- a/rust/androidmk.go
+++ b/rust/androidmk.go
@@ -106,6 +106,9 @@
 			}
 			entries.SetBoolIfTrue("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", !BoolDefault(test.Properties.Auto_gen_config, true))
 			entries.SetBoolIfTrue("LOCAL_IS_UNIT_TEST", Bool(test.Properties.Test_options.Unit_test))
+			if test.Properties.Data_bins != nil {
+				entries.AddStrings("LOCAL_TEST_DATA_BINS", test.Properties.Data_bins...)
+			}
 		})
 
 	cc.AndroidMkWriteTestData(test.data, ret)
diff --git a/sh/sh_binary.go b/sh/sh_binary.go
index 2ab784d..4190e84 100644
--- a/sh/sh_binary.go
+++ b/sh/sh_binary.go
@@ -458,6 +458,9 @@
 					dir := strings.TrimSuffix(s.dataModules[relPath].String(), relPath)
 					entries.AddStrings("LOCAL_TEST_DATA", dir+":"+relPath)
 				}
+				if s.testProperties.Data_bins != nil {
+					entries.AddStrings("LOCAL_TEST_DATA_BINS", s.testProperties.Data_bins...)
+				}
 				if Bool(s.testProperties.Test_options.Unit_test) {
 					entries.SetBool("LOCAL_IS_UNIT_TEST", true)
 				}