Merge "Add cert_validator to allowed rust paths"
diff --git a/android/bazel.go b/android/bazel.go
index d5fdfd7..3046edb 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -449,6 +449,9 @@
 
 		"apex_manifest_proto_java", // b/215230097, we don't handle .proto files in java_library srcs attribute
 
+		"libc_musl_sysroot_bionic_arch_headers", // b/218405924, depends on soong_zip
+		"libc_musl_sysroot_bionic_headers",      // b/218405924, depends on soong_zip and generates duplicate srcs
+
 		// python protos
 		"libprotobuf-python",                           // contains .proto sources
 		"conv_linker_config",                           // depends on linker_config_proto, a python lib with proto sources
@@ -716,6 +719,7 @@
 	if err != nil {
 		return "", err
 	}
+	defer file.Close()
 	scanner := bufio.NewScanner(file)
 	for scanner.Scan() {
 		line := scanner.Text()
diff --git a/android/licenses.go b/android/licenses.go
index e9e271b..b82d8d7 100644
--- a/android/licenses.go
+++ b/android/licenses.go
@@ -316,4 +316,7 @@
 func licensesMakeVarsProvider(ctx MakeVarsContext) {
 	ctx.Strict("BUILD_LICENSE_METADATA",
 		ctx.Config().HostToolPath(ctx, "build_license_metadata").String())
+	ctx.Strict("HTMLNOTICE", ctx.Config().HostToolPath(ctx, "htmlnotice").String())
+	ctx.Strict("XMLNOTICE", ctx.Config().HostToolPath(ctx, "xmlnotice").String())
+	ctx.Strict("TEXTNOTICE", ctx.Config().HostToolPath(ctx, "textnotice").String())
 }
diff --git a/android/soong_config_modules.go b/android/soong_config_modules.go
index 91bbce6..bd73645 100644
--- a/android/soong_config_modules.go
+++ b/android/soong_config_modules.go
@@ -378,6 +378,7 @@
 			ctx.PropertyErrorf("from", "failed to open %q: %s", from, err)
 			return (map[string]blueprint.ModuleFactory)(nil)
 		}
+		defer r.Close()
 
 		mtDef, errs := soongconfig.Parse(r, from)
 		if ctx.Config().runningAsBp2Build {
diff --git a/apex/apex.go b/apex/apex.go
index 0ac6eaa..d12a786 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -888,9 +888,18 @@
 	// APEX, but shared across APEXes via the VNDK APEX.
 	useVndk := a.SocSpecific() || a.DeviceSpecific() || (a.ProductSpecific() && mctx.Config().EnforceProductPartitionInterface())
 	excludeVndkLibs := useVndk && proptools.Bool(a.properties.Use_vndk_as_stable)
-	if !useVndk && proptools.Bool(a.properties.Use_vndk_as_stable) {
-		mctx.PropertyErrorf("use_vndk_as_stable", "not supported for system/system_ext APEXes")
-		return
+	if proptools.Bool(a.properties.Use_vndk_as_stable) {
+		if !useVndk {
+			mctx.PropertyErrorf("use_vndk_as_stable", "not supported for system/system_ext APEXes")
+		}
+		mctx.VisitDirectDepsWithTag(sharedLibTag, func(dep android.Module) {
+			if c, ok := dep.(*cc.Module); ok && c.IsVndk() {
+				mctx.PropertyErrorf("use_vndk_as_stable", "Trying to include a VNDK library(%s) while use_vndk_as_stable is true.", dep.Name())
+			}
+		})
+		if mctx.Failed() {
+			return
+		}
 	}
 
 	continueApexDepsWalk := func(child, parent android.Module) bool {
diff --git a/apex/apex_test.go b/apex/apex_test.go
index c546fa1..6d77b06 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -2713,7 +2713,33 @@
 	ensureListNotContains(t, requireNativeLibs, ":vndk")
 }
 
+func TestVendorApex_use_vndk_as_stable_TryingToIncludeVNDKLib(t *testing.T) {
+	testApexError(t, `Trying to include a VNDK library`, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			native_shared_libs: ["libc++"], // libc++ is a VNDK lib
+			vendor: true,
+			use_vndk_as_stable: true,
+			updatable: false,
+		}
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}`)
+}
+
 func TestVendorApex_use_vndk_as_stable(t *testing.T) {
+	//   myapex                  myapex2
+	//    |                       |
+	//  mybin ------.           mybin2
+	//   \           \          /  |
+	// (stable)   .---\--------`   |
+	//     \     /     \           |
+	//      \   /       \         /
+	//      libvndk       libvendor
+	//      (vndk)
 	ctx := testApex(t, `
 		apex {
 			name: "myapex",
@@ -2744,28 +2770,95 @@
 		cc_library {
 			name: "libvendor",
 			vendor: true,
+			stl: "none",
+		}
+		apex {
+			name: "myapex2",
+			key: "myapex.key",
+			binaries: ["mybin2"],
+			vendor: true,
+			use_vndk_as_stable: false,
+			updatable: false,
+		}
+		cc_binary {
+			name: "mybin2",
+			vendor: true,
+			shared_libs: ["libvndk", "libvendor"],
 		}
 	`)
 
 	vendorVariant := "android_vendor.29_arm64_armv8-a"
 
-	ldRule := ctx.ModuleForTests("mybin", vendorVariant+"_apex10000").Rule("ld")
-	libs := names(ldRule.Args["libFlags"])
-	// VNDK libs(libvndk/libc++) as they are
-	ensureListContains(t, libs, "out/soong/.intermediates/libvndk/"+vendorVariant+"_shared/libvndk.so")
-	ensureListContains(t, libs, "out/soong/.intermediates/"+cc.DefaultCcCommonTestModulesDir+"libc++/"+vendorVariant+"_shared/libc++.so")
-	// non-stable Vendor libs as APEX variants
-	ensureListContains(t, libs, "out/soong/.intermediates/libvendor/"+vendorVariant+"_shared_apex10000/libvendor.so")
+	for _, tc := range []struct {
+		name                 string
+		apexName             string
+		moduleName           string
+		moduleVariant        string
+		libs                 []string
+		contents             []string
+		requireVndkNamespace bool
+	}{
+		{
+			name:          "use_vndk_as_stable",
+			apexName:      "myapex",
+			moduleName:    "mybin",
+			moduleVariant: vendorVariant + "_apex10000",
+			libs: []string{
+				// should link with vendor variants of VNDK libs(libvndk/libc++)
+				"out/soong/.intermediates/libvndk/" + vendorVariant + "_shared/libvndk.so",
+				"out/soong/.intermediates/" + cc.DefaultCcCommonTestModulesDir + "libc++/" + vendorVariant + "_shared/libc++.so",
+				// unstable Vendor libs as APEX variant
+				"out/soong/.intermediates/libvendor/" + vendorVariant + "_shared_apex10000/libvendor.so",
+			},
+			contents: []string{
+				"bin/mybin",
+				"lib64/libvendor.so",
+				// VNDK libs (libvndk/libc++) are not included
+			},
+			requireVndkNamespace: true,
+		},
+		{
+			name:          "!use_vndk_as_stable",
+			apexName:      "myapex2",
+			moduleName:    "mybin2",
+			moduleVariant: vendorVariant + "_myapex2",
+			libs: []string{
+				// should link with "unique" APEX(myapex2) variant of VNDK libs(libvndk/libc++)
+				"out/soong/.intermediates/libvndk/" + vendorVariant + "_shared_myapex2/libvndk.so",
+				"out/soong/.intermediates/" + cc.DefaultCcCommonTestModulesDir + "libc++/" + vendorVariant + "_shared_myapex2/libc++.so",
+				// unstable vendor libs have "merged" APEX variants
+				"out/soong/.intermediates/libvendor/" + vendorVariant + "_shared_apex10000/libvendor.so",
+			},
+			contents: []string{
+				"bin/mybin2",
+				"lib64/libvendor.so",
+				// VNDK libs are included as well
+				"lib64/libvndk.so",
+				"lib64/libc++.so",
+			},
+			requireVndkNamespace: false,
+		},
+	} {
+		t.Run(tc.name, func(t *testing.T) {
+			// Check linked libs
+			ldRule := ctx.ModuleForTests(tc.moduleName, tc.moduleVariant).Rule("ld")
+			libs := names(ldRule.Args["libFlags"])
+			for _, lib := range tc.libs {
+				ensureListContains(t, libs, lib)
+			}
+			// Check apex contents
+			ensureExactContents(t, ctx, tc.apexName, "android_common_"+tc.apexName+"_image", tc.contents)
 
-	// VNDK libs are not included when use_vndk_as_stable: true
-	ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
-		"bin/mybin",
-		"lib64/libvendor.so",
-	})
-
-	apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule")
-	requireNativeLibs := names(apexManifestRule.Args["requireNativeLibs"])
-	ensureListContains(t, requireNativeLibs, ":vndk")
+			// Check "requireNativeLibs"
+			apexManifestRule := ctx.ModuleForTests(tc.apexName, "android_common_"+tc.apexName+"_image").Rule("apexManifestRule")
+			requireNativeLibs := names(apexManifestRule.Args["requireNativeLibs"])
+			if tc.requireVndkNamespace {
+				ensureListContains(t, requireNativeLibs, ":vndk")
+			} else {
+				ensureListNotContains(t, requireNativeLibs, ":vndk")
+			}
+		})
+	}
 }
 
 func TestProductVariant(t *testing.T) {
@@ -2796,7 +2889,7 @@
 	)
 
 	cflags := strings.Fields(
-		ctx.ModuleForTests("foo", "android_product.29_arm64_armv8-a_apex10000").Rule("cc").Args["cFlags"])
+		ctx.ModuleForTests("foo", "android_product.29_arm64_armv8-a_myapex").Rule("cc").Args["cFlags"])
 	ensureListContains(t, cflags, "-D__ANDROID_VNDK__")
 	ensureListContains(t, cflags, "-D__ANDROID_APEX__")
 	ensureListContains(t, cflags, "-D__ANDROID_PRODUCT__")
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index ee19783..4c4953d 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -1287,6 +1287,7 @@
 		"strip":                    true,
 		"stubs_symbol_file":        true,
 		"stubs_versions":           true,
+		"inject_bssl_hash":         true,
 	}
 	sharedAttrs := attrNameToString{}
 	staticAttrs := attrNameToString{}
@@ -1822,6 +1823,33 @@
 	)
 }
 
+func TestLibcryptoHashInjection(t *testing.T) {
+	runCcLibraryTestCase(t, bp2buildTestCase{
+		description:                "cc_library - libcrypto hash injection",
+		moduleTypeUnderTest:        "cc_library",
+		moduleTypeUnderTestFactory: cc.LibraryFactory,
+		filesystem:                 map[string]string{},
+		blueprint: soongCcLibraryPreamble + `
+cc_library {
+    name: "libcrypto",
+    target: {
+        android: {
+            inject_bssl_hash: true,
+        },
+    },
+    include_build_directory: false,
+}
+`,
+		expectedBazelTargets: makeCcLibraryTargets("libcrypto", attrNameToString{
+			"inject_bssl_hash": `select({
+        "//build/bazel/platforms/os:android": True,
+        "//conditions:default": None,
+    })`,
+		}),
+	},
+	)
+}
+
 func TestCcLibraryCppStdWithGnuExtensions_ConvertsToFeatureAttr(t *testing.T) {
 	type testCase struct {
 		cpp_std        string
diff --git a/cc/cc.go b/cc/cc.go
index 46e3b91..2a84f55 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -3465,6 +3465,14 @@
 	return c.IsStubs() || c.Target().NativeBridge == android.NativeBridgeEnabled
 }
 
+// Overrides android.ApexModuleBase.UniqueApexVariations
+func (c *Module) UniqueApexVariations() bool {
+	// When a vendor APEX needs a VNDK lib in it (use_vndk_as_stable: false), it should be a unique
+	// APEX variation. Otherwise, another vendor APEX with use_vndk_as_stable:true may use a wrong
+	// variation of the VNDK lib because APEX variations are merged/grouped.
+	return c.UseVndk() && c.IsVndk()
+}
+
 var _ snapshot.RelativeInstallPath = (*Module)(nil)
 
 type moduleType int
diff --git a/cc/config/tidy.go b/cc/config/tidy.go
index fdc246c..ba1043b 100644
--- a/cc/config/tidy.go
+++ b/cc/config/tidy.go
@@ -62,8 +62,9 @@
 		}, ",")
 		// clang-analyzer-* checks are too slow to be in the default for WITH_TIDY=1.
 		// nightly builds add CLANG_ANALYZER_CHECKS=1 to run those checks.
+		// The insecureAPI.DeprecatedOrUnsafeBufferHandling warning does not apply to Android.
 		if ctx.Config().IsEnvTrue("CLANG_ANALYZER_CHECKS") {
-			checks += ",clang-analyzer-*"
+			checks += ",clang-analyzer-*,-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling"
 		}
 		return checks
 	})
diff --git a/cc/library.go b/cc/library.go
index de5d46f..5d40820 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -386,6 +386,21 @@
 		Stubs_versions:    compilerAttrs.stubsVersions,
 	}
 
+	for axis, configToProps := range m.GetArchVariantProperties(ctx, &LibraryProperties{}) {
+		for config, props := range configToProps {
+			if props, ok := props.(*LibraryProperties); ok {
+				if props.Inject_bssl_hash != nil {
+					// This is an edge case applies only to libcrypto
+					if m.Name() == "libcrypto" {
+						sharedTargetAttrs.Inject_bssl_hash.SetSelectValue(axis, config, props.Inject_bssl_hash)
+					} else {
+						ctx.PropertyErrorf("inject_bssl_hash", "only applies to libcrypto")
+					}
+				}
+			}
+		}
+	}
+
 	staticProps := bazel.BazelTargetModuleProperties{
 		Rule_class:        "cc_library_static",
 		Bzl_load_location: "//build/bazel/rules:cc_library_static.bzl",
@@ -2602,4 +2617,5 @@
 
 	Stubs_symbol_file *string
 	Stubs_versions    bazel.StringListAttribute
+	Inject_bssl_hash  bazel.BoolAttribute
 }
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index 13b20f4..d80051c 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -23,6 +23,7 @@
 	"path/filepath"
 	"strconv"
 	"strings"
+	"syscall"
 	"time"
 
 	"android/soong/shared"
@@ -205,6 +206,15 @@
 		config.Parallel(), config.RemoteParallel(), config.HighmemParallel())
 
 	{
+		var limits syscall.Rlimit
+		err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limits)
+		if err != nil {
+			buildCtx.Verbosef("Failed to get file limit:", err)
+		}
+		buildCtx.Verbosef("Current file limits: %d soft, %d hard", limits.Cur, limits.Max)
+	}
+
+	{
 		// The order of the function calls is important. The last defer function call
 		// is the first one that is executed to save the rbe metrics to a protobuf
 		// file. The soong metrics file is then next. Bazel profiles are written
diff --git a/finder/finder.go b/finder/finder.go
index 5413fa6..b4834b1 100644
--- a/finder/finder.go
+++ b/finder/finder.go
@@ -847,6 +847,7 @@
 	if err != nil {
 		return errors.New("No data to load from database\n")
 	}
+	defer reader.Close()
 	bufferedReader := bufio.NewReader(reader)
 	if !f.validateCacheHeader(bufferedReader) {
 		return errors.New("Cache header does not match")
diff --git a/finder/fs/test.go b/finder/fs/test.go
index cb2140e..ed981fd 100644
--- a/finder/fs/test.go
+++ b/finder/fs/test.go
@@ -74,6 +74,7 @@
 	if err != nil {
 		t.Fatalf(err.Error())
 	}
+	defer reader.Close()
 	bytes, err := ioutil.ReadAll(reader)
 	if err != nil {
 		t.Fatal(err.Error())
diff --git a/mk2rbc/cmd/mk2rbc.go b/mk2rbc/cmd/mk2rbc.go
index d9b4e86..e84eacd 100644
--- a/mk2rbc/cmd/mk2rbc.go
+++ b/mk2rbc/cmd/mk2rbc.go
@@ -40,7 +40,6 @@
 )
 
 var (
-	rootDir = flag.String("root", ".", "the value of // for load paths")
 	// TODO(asmundak): remove this option once there is a consensus on suffix
 	suffix   = flag.String("suffix", ".rbc", "generated files' suffix")
 	dryRun   = flag.Bool("dry_run", false, "dry run")
@@ -57,6 +56,7 @@
 	cpuProfile            = flag.String("cpu_profile", "", "write cpu profile to file")
 	traceCalls            = flag.Bool("trace_calls", false, "trace function calls")
 	inputVariables        = flag.String("input_variables", "", "starlark file containing product config and global variables")
+	makefileList          = flag.String("makefile_list", "", "path to a list of all makefiles in the source tree, generated by soong's finder. If not provided, mk2rbc will find the makefiles itself (more slowly than if this flag was provided)")
 )
 
 func init() {
@@ -70,7 +70,6 @@
 		quit("cannot alias unknown flag " + target)
 	}
 	flagAlias("suffix", "s")
-	flagAlias("root", "d")
 	flagAlias("dry_run", "n")
 	flagAlias("convert_dependents", "r")
 	flagAlias("error_stat", "e")
@@ -79,7 +78,7 @@
 var backupSuffix string
 var tracedVariables []string
 var errorLogger = errorSink{data: make(map[string]datum)}
-var makefileFinder = &LinuxMakefileFinder{}
+var makefileFinder mk2rbc.MakefileFinder
 
 func main() {
 	flag.Usage = func() {
@@ -90,6 +89,10 @@
 	}
 	flag.Parse()
 
+	if _, err := os.Stat("build/soong/mk2rbc"); err != nil {
+		quit("Must be run from the root of the android tree. (build/soong/mk2rbc does not exist)")
+	}
+
 	// Delouse
 	if *suffix == ".mk" {
 		quit("cannot use .mk as generated file suffix")
@@ -133,6 +136,16 @@
 		pprof.StartCPUProfile(f)
 		defer pprof.StopCPUProfile()
 	}
+
+	if *makefileList != "" {
+		makefileFinder = &FileListMakefileFinder{
+			cachedMakefiles: nil,
+			filePath:        *makefileList,
+		}
+	} else {
+		makefileFinder = &FindCommandMakefileFinder{}
+	}
+
 	// Find out global variables
 	getConfigVariables()
 	getSoongVariables()
@@ -217,17 +230,16 @@
 	const androidProductsMk = "AndroidProducts.mk"
 	// Build the list of AndroidProducts.mk files: it's
 	// build/make/target/product/AndroidProducts.mk + device/**/AndroidProducts.mk plus + vendor/**/AndroidProducts.mk
-	targetAndroidProductsFile := filepath.Join(*rootDir, "build", "make", "target", "product", androidProductsMk)
+	targetAndroidProductsFile := filepath.Join("build", "make", "target", "product", androidProductsMk)
 	if _, err := os.Stat(targetAndroidProductsFile); err != nil {
-		fmt.Fprintf(os.Stderr, "%s: %s\n(hint: %s is not a source tree root)\n",
-			targetAndroidProductsFile, err, *rootDir)
+		fmt.Fprintf(os.Stderr, "%s: %s\n", targetAndroidProductsFile, err)
 	}
 	productConfigMap := make(map[string]string)
 	if err := mk2rbc.UpdateProductConfigMap(productConfigMap, targetAndroidProductsFile); err != nil {
 		fmt.Fprintf(os.Stderr, "%s: %s\n", targetAndroidProductsFile, err)
 	}
 	for _, t := range []string{"device", "vendor"} {
-		_ = filepath.WalkDir(filepath.Join(*rootDir, t),
+		_ = filepath.WalkDir(t,
 			func(path string, d os.DirEntry, err error) error {
 				if err != nil || d.IsDir() || filepath.Base(path) != androidProductsMk {
 					return nil
@@ -243,10 +255,9 @@
 }
 
 func getConfigVariables() {
-	path := filepath.Join(*rootDir, "build", "make", "core", "product.mk")
+	path := filepath.Join("build", "make", "core", "product.mk")
 	if err := mk2rbc.FindConfigVariables(path, mk2rbc.KnownVariables); err != nil {
-		quit(fmt.Errorf("%s\n(check --root[=%s], it should point to the source root)",
-			err, *rootDir))
+		quit(err)
 	}
 }
 
@@ -259,11 +270,11 @@
 	if name != "BUILD_SYSTEM" {
 		return fmt.Sprintf("$(%s)", name)
 	}
-	return filepath.Join(*rootDir, "build", "make", "core")
+	return filepath.Join("build", "make", "core")
 }
 
 func getSoongVariables() {
-	path := filepath.Join(*rootDir, "build", "make", "core", "soong_config.mk")
+	path := filepath.Join("build", "make", "core", "soong_config.mk")
 	err := mk2rbc.FindSoongVariables(path, fileNameScope{}, mk2rbc.KnownVariables)
 	if err != nil {
 		quit(err)
@@ -314,12 +325,11 @@
 	mk2starRequest := mk2rbc.Request{
 		MkFile:          mkFile,
 		Reader:          nil,
-		RootDir:         *rootDir,
 		OutputDir:       *outputTop,
 		OutputSuffix:    *suffix,
 		TracedVariables: tracedVariables,
 		TraceCalls:      *traceCalls,
-		SourceFS:        os.DirFS(*rootDir),
+		SourceFS:        os.DirFS("."),
 		MakefileFinder:  makefileFinder,
 		ErrorLogger:     errorLogger,
 	}
@@ -519,17 +529,17 @@
 	return res, len(sorted)
 }
 
-type LinuxMakefileFinder struct {
+// FindCommandMakefileFinder is an implementation of mk2rbc.MakefileFinder that
+// runs the unix find command to find all the makefiles in the source tree.
+type FindCommandMakefileFinder struct {
 	cachedRoot      string
 	cachedMakefiles []string
 }
 
-func (l *LinuxMakefileFinder) Find(root string) []string {
+func (l *FindCommandMakefileFinder) Find(root string) []string {
 	if l.cachedMakefiles != nil && l.cachedRoot == root {
 		return l.cachedMakefiles
 	}
-	l.cachedRoot = root
-	l.cachedMakefiles = make([]string, 0)
 
 	// Return all *.mk files but not in hidden directories.
 
@@ -548,9 +558,60 @@
 		panic(fmt.Errorf("cannot get the output from %s: %s", cmd, err))
 	}
 	scanner := bufio.NewScanner(stdout)
+	result := make([]string, 0)
 	for scanner.Scan() {
-		l.cachedMakefiles = append(l.cachedMakefiles, strings.TrimPrefix(scanner.Text(), "./"))
+		result = append(result, strings.TrimPrefix(scanner.Text(), "./"))
 	}
 	stdout.Close()
+	err = scanner.Err()
+	if err != nil {
+		panic(fmt.Errorf("cannot get the output from %s: %s", cmd, err))
+	}
+	l.cachedRoot = root
+	l.cachedMakefiles = result
+	return l.cachedMakefiles
+}
+
+// FileListMakefileFinder is an implementation of mk2rbc.MakefileFinder that
+// reads a file containing the list of makefiles in the android source tree.
+// This file is generated by soong's finder, so that it can be computed while
+// soong is already walking the source tree looking for other files. If the root
+// to find makefiles under is not the root of the android source tree, it will
+// fall back to using FindCommandMakefileFinder.
+type FileListMakefileFinder struct {
+	FindCommandMakefileFinder
+	cachedMakefiles []string
+	filePath        string
+}
+
+func (l *FileListMakefileFinder) Find(root string) []string {
+	root, err1 := filepath.Abs(root)
+	wd, err2 := os.Getwd()
+	if root != wd || err1 != nil || err2 != nil {
+		return l.FindCommandMakefileFinder.Find(root)
+	}
+	if l.cachedMakefiles != nil {
+		return l.cachedMakefiles
+	}
+
+	file, err := os.Open(l.filePath)
+	if err != nil {
+		panic(fmt.Errorf("Cannot read makefile list: %s\n", err))
+	}
+	defer file.Close()
+
+	result := make([]string, 0)
+	scanner := bufio.NewScanner(file)
+	for scanner.Scan() {
+		line := scanner.Text()
+		if len(line) > 0 {
+			result = append(result, line)
+		}
+	}
+
+	if err = scanner.Err(); err != nil {
+		panic(fmt.Errorf("Cannot read makefile list: %s\n", err))
+	}
+	l.cachedMakefiles = result
 	return l.cachedMakefiles
 }
diff --git a/mk2rbc/mk2rbc.go b/mk2rbc/mk2rbc.go
index 03cf21e..b8fe162 100644
--- a/mk2rbc/mk2rbc.go
+++ b/mk2rbc/mk2rbc.go
@@ -142,7 +142,6 @@
 type Request struct {
 	MkFile          string    // file to convert
 	Reader          io.Reader // if set, read input from this stream instead
-	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     ErrorLogger
@@ -378,7 +377,6 @@
 	nodes          []starlarkNode
 	inherited      []*moduleInfo
 	hasErrors      bool
-	topDir         string
 	traceCalls     bool // print enter/exit each init function
 	sourceFS       fs.FS
 	makefileFinder MakefileFinder
@@ -414,11 +412,10 @@
 }
 
 func newParseContext(ss *StarlarkScript, nodes []mkparser.Node) *parseContext {
-	topdir, _ := filepath.Split(filepath.Join(ss.topDir, "foo"))
 	predefined := []struct{ name, value string }{
 		{"SRC_TARGET_DIR", filepath.Join("build", "make", "target")},
 		{"LOCAL_PATH", filepath.Dir(ss.mkFile)},
-		{"TOPDIR", topdir},
+		{"TOPDIR", ""}, // TOPDIR is just set to an empty string in cleanbuild.mk and core.mk
 		// TODO(asmundak): maybe read it from build/make/core/envsetup.mk?
 		{"TARGET_COPY_OUT_SYSTEM", "system"},
 		{"TARGET_COPY_OUT_SYSTEM_OTHER", "system_other"},
@@ -827,7 +824,7 @@
 }
 
 func (ctx *parseContext) findMatchingPaths(pattern []string) []string {
-	files := ctx.script.makefileFinder.Find(ctx.script.topDir)
+	files := ctx.script.makefileFinder.Find(".")
 	if len(pattern) == 0 {
 		return files
 	}
@@ -1864,7 +1861,6 @@
 	starScript := &StarlarkScript{
 		moduleName:     moduleNameForFile(req.MkFile),
 		mkFile:         req.MkFile,
-		topDir:         req.RootDir,
 		traceCalls:     req.TraceCalls,
 		sourceFS:       req.SourceFS,
 		makefileFinder: req.MakefileFinder,
diff --git a/mk2rbc/mk2rbc_test.go b/mk2rbc/mk2rbc_test.go
index c499398..2083121 100644
--- a/mk2rbc/mk2rbc_test.go
+++ b/mk2rbc/mk2rbc_test.go
@@ -1387,7 +1387,6 @@
 				ss, err := Convert(Request{
 					MkFile:         test.mkname,
 					Reader:         bytes.NewBufferString(test.in),
-					RootDir:        ".",
 					OutputSuffix:   ".star",
 					SourceFS:       fs,
 					MakefileFinder: &testMakefileFinder{fs: fs},
diff --git a/scripts/rbc-run b/scripts/rbc-run
index 7243421..b8a6c0c 100755
--- a/scripts/rbc-run
+++ b/scripts/rbc-run
@@ -9,9 +9,10 @@
 declare -r runner="${output_root}/soong/rbcrun"
 declare -r converter="${output_root}/soong/mk2rbc"
 declare -r launcher="${output_root}/rbc/launcher.rbc"
+declare -r makefile_list="${output_root}/.module_paths/configuration.list"
 declare -r makefile="$1"
 declare -r input_variables="$2"
 shift 2
-"${converter}" -mode=write -r --outdir "${output_root}/rbc" --input_variables "${input_variables}" --launcher="${launcher}" "${makefile}"
+"${converter}" -mode=write -r --outdir "${output_root}/rbc" --input_variables "${input_variables}" --launcher="${launcher}" --makefile_list="${makefile_list}" "${makefile}"
 "${runner}" RBC_OUT="make,global" RBC_DEBUG="${RBC_DEBUG:-}" $@ "${launcher}"
 
diff --git a/ui/build/finder.go b/ui/build/finder.go
index 8f74969..68efe21 100644
--- a/ui/build/finder.go
+++ b/ui/build/finder.go
@@ -87,8 +87,8 @@
 			// Bazel top-level file to mark a directory as a Bazel workspace.
 			"WORKSPACE",
 		},
-		// Bazel Starlark configuration files.
-		IncludeSuffixes: []string{".bzl"},
+		// Bazel Starlark configuration files and all .mk files for product/board configuration.
+		IncludeSuffixes: []string{".bzl", ".mk"},
 	}
 	dumpDir := config.FileListDir()
 	f, err = finder.New(cacheParams, filesystem, logger.New(ioutil.Discard),
@@ -110,6 +110,19 @@
 	return entries.DirNames, matches
 }
 
+func findProductAndBoardConfigFiles(entries finder.DirEntries) (dirNames []string, fileNames []string) {
+	matches := []string{}
+	for _, foundName := range entries.FileNames {
+		if foundName != "Android.mk" &&
+			foundName != "AndroidProducts.mk" &&
+			foundName != "CleanSpec.mk" &&
+			strings.HasSuffix(foundName, ".mk") {
+			matches = append(matches, foundName)
+		}
+	}
+	return entries.DirNames, matches
+}
+
 // FindSources searches for source files known to <f> and writes them to the filesystem for
 // use later.
 func FindSources(ctx Context, config Config, f *finder.Finder) {
@@ -172,6 +185,13 @@
 		ctx.Fatalf("Could not find modules: %v", err)
 	}
 
+	// Recursively look for all product/board config files.
+	configurationFiles := f.FindMatching(".", findProductAndBoardConfigFiles)
+	err = dumpListToFile(ctx, config, configurationFiles, filepath.Join(dumpDir, "configuration.list"))
+	if err != nil {
+		ctx.Fatalf("Could not export product/board configuration list: %v", err)
+	}
+
 	if config.Dist() {
 		f.WaitForDbDump()
 		// Dist the files.db plain text database.