Merge "Add rust_grpcio module type."
diff --git a/android/config.go b/android/config.go
index a499057..e87a4ac 100644
--- a/android/config.go
+++ b/android/config.go
@@ -974,13 +974,21 @@
 	return c.productVariables.ModulesLoadedByPrivilegedModules
 }
 
-func (c *config) DexpreoptGlobalConfig(ctx PathContext) ([]byte, error) {
+func (c *config) DexpreoptGlobalConfigPath(ctx PathContext) OptionalPath {
 	if c.productVariables.DexpreoptGlobalConfig == nil {
+		return OptionalPathForPath(nil)
+	}
+	return OptionalPathForPath(
+		pathForBuildToolDep(ctx, *c.productVariables.DexpreoptGlobalConfig))
+}
+
+func (c *config) DexpreoptGlobalConfig(ctx PathContext) ([]byte, error) {
+	path := c.DexpreoptGlobalConfigPath(ctx)
+	if !path.Valid() {
 		return nil, nil
 	}
-	path := absolutePath(*c.productVariables.DexpreoptGlobalConfig)
-	ctx.AddNinjaFileDeps(path)
-	return ioutil.ReadFile(path)
+	ctx.AddNinjaFileDeps(path.String())
+	return ioutil.ReadFile(absolutePath(path.String()))
 }
 
 func (c *config) FrameworksBaseDirExists(ctx PathContext) bool {
diff --git a/android/writedocs.go b/android/writedocs.go
index 4eb15e6..91c2318 100644
--- a/android/writedocs.go
+++ b/android/writedocs.go
@@ -48,6 +48,13 @@
 	deps = append(deps, pathForBuildToolDep(ctx, ctx.Config().moduleListFile))
 	deps = append(deps, pathForBuildToolDep(ctx, ctx.Config().ProductVariablesFileName))
 
+	// The dexpreopt configuration may not exist, but if it does, it's a dependency
+	// of soong_build.
+	dexpreoptConfigPath := ctx.Config().DexpreoptGlobalConfigPath(ctx)
+	if dexpreoptConfigPath.Valid() {
+		deps = append(deps, dexpreoptConfigPath.Path())
+	}
+
 	// Generate build system docs for the primary builder.  Generating docs reads the source
 	// files used to build the primary builder, but that dependency will be picked up through
 	// the dependency on the primary builder itself.  There are no dependencies on the
diff --git a/apex/allowed_deps.txt b/apex/allowed_deps.txt
index 3fa3a10..8c70a56 100644
--- a/apex/allowed_deps.txt
+++ b/apex/allowed_deps.txt
@@ -17,12 +17,14 @@
 android.hardware.cas.native@1.0(minSdkVersion:29)
 android.hardware.cas@1.0(minSdkVersion:29)
 android.hardware.common-ndk_platform(minSdkVersion:29)
+android.hardware.common-unstable-ndk_platform(minSdkVersion:29)
 android.hardware.graphics.allocator@2.0(minSdkVersion:29)
 android.hardware.graphics.allocator@3.0(minSdkVersion:29)
 android.hardware.graphics.allocator@4.0(minSdkVersion:29)
 android.hardware.graphics.bufferqueue@1.0(minSdkVersion:29)
 android.hardware.graphics.bufferqueue@2.0(minSdkVersion:29)
 android.hardware.graphics.common-ndk_platform(minSdkVersion:29)
+android.hardware.graphics.common-unstable-ndk_platform(minSdkVersion:29)
 android.hardware.graphics.common@1.0(minSdkVersion:29)
 android.hardware.graphics.common@1.1(minSdkVersion:29)
 android.hardware.graphics.common@1.2(minSdkVersion:29)
@@ -233,6 +235,7 @@
 libc_headers(minSdkVersion:apex_inherit)
 libc_headers_arch(minSdkVersion:apex_inherit)
 libcap(minSdkVersion:29)
+libclang_rt.hwasan-aarch64-android.llndk(minSdkVersion:(no version))
 libcodec2(minSdkVersion:29)
 libcodec2_headers(minSdkVersion:29)
 libcodec2_hidl@1.0(minSdkVersion:29)
@@ -423,15 +426,23 @@
 ndk_libc++abi(minSdkVersion:(no version))
 ndk_libc++abi(minSdkVersion:16)
 ndk_libunwind(minSdkVersion:16)
+net-utils-device-common(minSdkVersion:29)
 net-utils-framework-common(minSdkVersion:current)
 netd_aidl_interface-unstable-java(minSdkVersion:29)
 netd_event_listener_interface-ndk_platform(minSdkVersion:29)
+netd_event_listener_interface-unstable-ndk_platform(minSdkVersion:29)
 netlink-client(minSdkVersion:29)
 networkstack-aidl-interfaces-unstable-java(minSdkVersion:29)
 networkstack-client(minSdkVersion:29)
 NetworkStackApiStableDependencies(minSdkVersion:29)
 NetworkStackApiStableLib(minSdkVersion:29)
 networkstackprotos(minSdkVersion:29)
+neuralnetworks_types(minSdkVersion:30)
+neuralnetworks_utils_hal_1_0(minSdkVersion:30)
+neuralnetworks_utils_hal_1_1(minSdkVersion:30)
+neuralnetworks_utils_hal_1_2(minSdkVersion:30)
+neuralnetworks_utils_hal_1_3(minSdkVersion:30)
+neuralnetworks_utils_hal_common(minSdkVersion:30)
 PermissionController(minSdkVersion:28)
 permissioncontroller-statsd(minSdkVersion:current)
 philox_random(minSdkVersion:(no version))
diff --git a/apex/apex.go b/apex/apex.go
index b02711e..fdc105e 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -276,8 +276,6 @@
 		"libc_malloc_debug_backtrace",
 		"libcamera_client",
 		"libcamera_metadata",
-		"libdexfile_external_headers",
-		"libdexfile_support",
 		"libdvr_headers",
 		"libexpat",
 		"libfifo",
@@ -304,10 +302,6 @@
 		"libmp4extractor",
 		"libmpeg2extractor",
 		"libnativebase_headers",
-		"libnativebridge-headers",
-		"libnativebridge_lazy",
-		"libnativeloader-headers",
-		"libnativeloader_lazy",
 		"libnativewindow_headers",
 		"libnblog",
 		"liboggextractor",
@@ -431,7 +425,6 @@
 		"libcodec2_soft_vp9dec",
 		"libcodec2_soft_vp9enc",
 		"libcodec2_vndk",
-		"libdexfile_support",
 		"libdvr_headers",
 		"libfmq",
 		"libfmq",
@@ -454,8 +447,6 @@
 		"libmedia_headers",
 		"libmpeg2dec",
 		"libnativebase_headers",
-		"libnativebridge_lazy",
-		"libnativeloader_lazy",
 		"libnativewindow_headers",
 		"libpdx_headers",
 		"libscudo_wrapper",
@@ -563,8 +554,6 @@
 		"libdebuggerd_common_headers",
 		"libdebuggerd_handler_core",
 		"libdebuggerd_handler_fallback",
-		"libdexfile_external_headers",
-		"libdexfile_support",
 		"libdl_static",
 		"libjemalloc5",
 		"liblinker_main",
diff --git a/apex/apex_singleton.go b/apex/apex_singleton.go
index 803e0c5..ee9fc81 100644
--- a/apex/apex_singleton.go
+++ b/apex/apex_singleton.go
@@ -100,6 +100,8 @@
 			"new_allowed_deps": newAllowedDeps.String(),
 		},
 	})
+
+	ctx.Phony("apex-allowed-deps-check", s.allowedApexDepsInfoCheckResult)
 }
 
 func (s *apexDepsInfoSingleton) MakeVars(ctx android.MakeVarsContext) {
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 7e83070..8b1f40d 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -825,7 +825,7 @@
 	ensureNotContains(t, mylib2Cflags, "-include ")
 
 	// Ensure that genstub is invoked with --apex
-	ensureContains(t, "--apex", ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_static_3").Rule("genStubSrc").Args["flags"])
+	ensureContains(t, "--apex", ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_shared_3").Rule("genStubSrc").Args["flags"])
 
 	ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
 		"lib64/mylib.so",
@@ -920,11 +920,11 @@
 	ensureNotContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_29/mylib3.so")
 
 	// Ensure that stubs libs are built without -include flags
-	mylib2Cflags := ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"]
+	mylib2Cflags := ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_shared_29").Rule("cc").Args["cFlags"]
 	ensureNotContains(t, mylib2Cflags, "-include ")
 
 	// Ensure that genstub is invoked with --apex
-	ensureContains(t, "--apex", ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_static_29").Rule("genStubSrc").Args["flags"])
+	ensureContains(t, "--apex", ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_shared_29").Rule("genStubSrc").Args["flags"])
 
 	ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
 		"lib64/mylib.so",
diff --git a/cc/cc.go b/cc/cc.go
index 3b01fb2..3297e41 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -377,8 +377,6 @@
 	isForPlatform() bool
 	apexVariationName() string
 	apexSdkVersion() android.ApiLevel
-	hasStubsVariants() bool
-	isStubs() bool
 	bootstrap() bool
 	mustUseVendorVariant() bool
 	nativeCoverage() bool
@@ -623,6 +621,8 @@
 	lto       *lto
 	pgo       *pgo
 
+	library libraryInterface
+
 	outputFile android.OptionalPath
 
 	cachedToolchain config.Toolchain
@@ -731,13 +731,6 @@
 	return c.Properties.AlwaysSdk || Bool(c.Properties.Sdk_variant_only)
 }
 
-func (c *Module) StubsVersions(ctx android.BaseMutatorContext) []string {
-	if versioned, ok := c.linker.(versionedInterface); ok {
-		return versioned.stubsVersions(ctx)
-	}
-	panic(fmt.Errorf("StubsVersions called on non-library module: %q", c.BaseModuleName()))
-}
-
 func (c *Module) CcLibrary() bool {
 	if c.linker != nil {
 		if _, ok := c.linker.(*libraryDecorator); ok {
@@ -761,53 +754,6 @@
 	return false
 }
 
-func (c *Module) SetBuildStubs() {
-	if versioned, ok := c.linker.(versionedInterface); ok {
-		versioned.setBuildStubs()
-		c.Properties.HideFromMake = true
-		c.sanitize = nil
-		c.stl = nil
-		c.Properties.PreventInstall = true
-		return
-	}
-	panic(fmt.Errorf("SetBuildStubs called on non-library module: %q", c.BaseModuleName()))
-}
-
-func (c *Module) BuildStubs() bool {
-	if versioned, ok := c.linker.(versionedInterface); ok {
-		return versioned.buildStubs()
-	}
-	panic(fmt.Errorf("BuildStubs called on non-library module: %q", c.BaseModuleName()))
-}
-
-func (c *Module) SetAllStubsVersions(versions []string) {
-	if versioned, ok := c.linker.(versionedInterface); ok {
-		versioned.setAllStubsVersions(versions)
-	}
-}
-
-func (c *Module) AllStubsVersions() []string {
-	if versioned, ok := c.linker.(versionedInterface); ok {
-		return versioned.allStubsVersions()
-	}
-	return nil
-}
-
-func (c *Module) SetStubsVersion(version string) {
-	if versioned, ok := c.linker.(versionedInterface); ok {
-		versioned.setStubsVersion(version)
-		return
-	}
-	panic(fmt.Errorf("SetStubsVersion called on non-library module: %q", c.BaseModuleName()))
-}
-
-func (c *Module) StubsVersion() string {
-	if versioned, ok := c.linker.(versionedInterface); ok {
-		return versioned.stubsVersion()
-	}
-	panic(fmt.Errorf("StubsVersion called on non-library module: %q", c.BaseModuleName()))
-}
-
 func (c *Module) SetStatic() {
 	if c.linker != nil {
 		if library, ok := c.linker.(libraryInterface); ok {
@@ -1041,15 +987,15 @@
 }
 
 func (c *Module) IsStubs() bool {
-	if versioned, ok := c.linker.(versionedInterface); ok {
-		return versioned.buildStubs()
+	if lib := c.library; lib != nil {
+		return lib.buildStubs()
 	}
 	return false
 }
 
 func (c *Module) HasStubsVariants() bool {
-	if versioned, ok := c.linker.(versionedInterface); ok {
-		return versioned.hasStubsVariants()
+	if lib := c.library; lib != nil {
+		return lib.hasStubsVariants()
 	}
 	return false
 }
@@ -1240,10 +1186,15 @@
 		// Host modules do not need ABI dumps.
 		return false
 	}
-	if ctx.isStubs() || ctx.isNDKStubLibrary() {
+	if ctx.isNDKStubLibrary() {
 		// Stubs do not need ABI dumps.
 		return false
 	}
+	if lib := ctx.mod.library; lib != nil && lib.buildStubs() {
+		// Stubs do not need ABI dumps.
+		return false
+	}
+
 	return true
 }
 
@@ -1278,14 +1229,6 @@
 	return ctx.mod.apexSdkVersion
 }
 
-func (ctx *moduleContextImpl) hasStubsVariants() bool {
-	return ctx.mod.HasStubsVariants()
-}
-
-func (ctx *moduleContextImpl) isStubs() bool {
-	return ctx.mod.IsStubs()
-}
-
 func (ctx *moduleContextImpl) bootstrap() bool {
 	return ctx.mod.bootstrap()
 }
@@ -2078,18 +2021,20 @@
 		// Recovery code is not NDK
 		return
 	}
-	if to.ToolchainLibrary() {
-		// These are always allowed
-		return
-	}
-	if to.NdkPrebuiltStl() {
-		// These are allowed, but they don't set sdk_version
-		return
-	}
-	if to.StubDecorator() {
-		// These aren't real libraries, but are the stub shared libraries that are included in
-		// the NDK.
-		return
+	if c, ok := to.(*Module); ok {
+		if c.ToolchainLibrary() {
+			// These are always allowed
+			return
+		}
+		if c.NdkPrebuiltStl() {
+			// These are allowed, but they don't set sdk_version
+			return
+		}
+		if c.StubDecorator() {
+			// These aren't real libraries, but are the stub shared libraries that are included in
+			// the NDK.
+			return
+		}
 	}
 
 	if strings.HasPrefix(ctx.ModuleName(), "libclang_rt.") && to.Module().Name() == "libc++" {
@@ -2337,12 +2282,17 @@
 		}
 
 		if depTag == reuseObjTag {
-			// reusing objects only make sense for cc.Modules.
-			staticAnalogue := ctx.OtherModuleProvider(dep, StaticLibraryInfoProvider).(StaticLibraryInfo)
-			objs := staticAnalogue.ReuseObjects
-			depPaths.Objs = depPaths.Objs.Append(objs)
-			depExporterInfo := ctx.OtherModuleProvider(dep, FlagExporterInfoProvider).(FlagExporterInfo)
-			reexportExporter(depExporterInfo)
+			// Skip reused objects for stub libraries, they use their own stub object file instead.
+			// The reuseObjTag dependency still exists because the LinkageMutator runs before the
+			// version mutator, so the stubs variant is created from the shared variant that
+			// already has the reuseObjTag dependency on the static variant.
+			if !c.library.buildStubs() {
+				staticAnalogue := ctx.OtherModuleProvider(dep, StaticLibraryInfoProvider).(StaticLibraryInfo)
+				objs := staticAnalogue.ReuseObjects
+				depPaths.Objs = depPaths.Objs.Append(objs)
+				depExporterInfo := ctx.OtherModuleProvider(dep, FlagExporterInfoProvider).(FlagExporterInfo)
+				reexportExporter(depExporterInfo)
+			}
 			return
 		}
 
@@ -2378,7 +2328,8 @@
 
 				if !libDepTag.explicitlyVersioned && len(sharedLibraryStubsInfo.SharedLibraryStubsInfos) > 0 {
 					useStubs := false
-					if m, ok := ccDep.(*Module); ok && m.IsStubs() && c.UseVndk() { // LLNDK
+
+					if lib := moduleLibraryInterface(dep); lib.buildStubs() && c.UseVndk() { // LLNDK
 						if !apexInfo.IsForPlatform() {
 							// For platform libraries, use current version of LLNDK
 							// If this is for use_vendor apex we will apply the same rules
@@ -2547,8 +2498,8 @@
 				c.Properties.AndroidMkHeaderLibs = append(
 					c.Properties.AndroidMkHeaderLibs, makeLibName)
 			case libDepTag.shared():
-				if ccDep.CcLibrary() {
-					if ccDep.BuildStubs() && dep.(android.ApexModule).InAnyApex() {
+				if lib := moduleLibraryInterface(dep); lib != nil {
+					if lib.buildStubs() && dep.(android.ApexModule).InAnyApex() {
 						// Add the dependency to the APEX(es) providing the library so that
 						// m <module> can trigger building the APEXes as well.
 						depApexInfo := ctx.OtherModuleProvider(dep, android.ApexInfoProvider).(android.ApexInfo)
@@ -2850,12 +2801,10 @@
 // Overrides ApexModule.IsInstallabeToApex()
 // Only shared/runtime libraries and "test_per_src" tests are installable to APEX.
 func (c *Module) IsInstallableToApex() bool {
-	if shared, ok := c.linker.(interface {
-		shared() bool
-	}); ok {
+	if lib := c.library; lib != nil {
 		// Stub libs and prebuilt libs in a versioned SDK are not
 		// installable to APEX even though they are shared libs.
-		return shared.shared() && !c.IsStubs() && c.ContainingSdk().Unversioned()
+		return lib.shared() && !lib.buildStubs() && c.ContainingSdk().Unversioned()
 	} else if _, ok := c.linker.(testPerSrc); ok {
 		return true
 	}
diff --git a/cc/config/global.go b/cc/config/global.go
index a170652..e5cb7ee 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -46,6 +46,7 @@
 
 		"-O2",
 		"-g",
+		"-fdebug-info-for-profiling",
 
 		"-fno-strict-aliasing",
 
diff --git a/cc/fuzz.go b/cc/fuzz.go
index 681e3bc..fe3c12b 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -174,12 +174,25 @@
 	// TODO(b/144090547): We should be parsing these modules using
 	// ModuleDependencyTag instead of the current brute-force checking.
 
-	if linkable, ok := dependency.(LinkableInterface); !ok || // Discard non-linkables.
-		!linkable.CcLibraryInterface() || !linkable.Shared() || // Discard static libs.
-		linkable.UseVndk() || // Discard vendor linked libraries.
+	linkable, ok := dependency.(LinkableInterface)
+	if !ok || !linkable.CcLibraryInterface() {
+		// Discard non-linkables.
+		return false
+	}
+
+	if !linkable.Shared() {
+		// Discard static libs.
+		return false
+	}
+
+	if linkable.UseVndk() {
+		// Discard vendor linked libraries.
+		return false
+	}
+
+	if lib := moduleLibraryInterface(dependency); lib != nil && lib.buildStubs() && linkable.CcLibrary() {
 		// Discard stubs libs (only CCLibrary variants). Prebuilt libraries should not
 		// be excluded on the basis of they're not CCLibrary()'s.
-		(linkable.CcLibrary() && linkable.BuildStubs()) {
 		return false
 	}
 
diff --git a/cc/library.go b/cc/library.go
index 910fc31..d946629 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -587,7 +587,7 @@
 			}
 		}
 	}
-	if Bool(enabled) || ctx.hasStubsVariants() {
+	if Bool(enabled) || library.hasStubsVariants() {
 		return "PLATFORM"
 	}
 	return ""
@@ -598,7 +598,7 @@
 		return false
 	}
 	if !ctx.isForPlatform() {
-		if !ctx.hasStubsVariants() {
+		if !library.hasStubsVariants() {
 			// Skip ABI checks if this library is for APEX but isn't exported.
 			return false
 		}
@@ -1060,7 +1060,7 @@
 			stubInfo := ctx.OtherModuleProvider(stub, SharedLibraryInfoProvider).(SharedLibraryInfo)
 			flagInfo := ctx.OtherModuleProvider(stub, FlagExporterInfoProvider).(FlagExporterInfo)
 			stubsInfo = append(stubsInfo, SharedLibraryStubsInfo{
-				Version:           stub.(*Module).StubsVersion(),
+				Version:           moduleLibraryInterface(stub).stubsVersion(),
 				SharedLibraryInfo: stubInfo,
 				FlagExporterInfo:  flagInfo,
 			})
@@ -1384,7 +1384,7 @@
 	if library.Properties.Header_abi_checker.Symbol_file != nil {
 		return library.Properties.Header_abi_checker.Symbol_file
 	}
-	if ctx.hasStubsVariants() && library.Properties.Stubs.Symbol_file != nil {
+	if library.hasStubsVariants() && library.Properties.Stubs.Symbol_file != nil {
 		return library.Properties.Stubs.Symbol_file
 	}
 	return nil
@@ -1483,6 +1483,7 @@
 	module.compiler = library
 	module.linker = library
 	module.installer = library
+	module.library = library
 
 	return module, library
 }
@@ -1620,8 +1621,14 @@
 	modules := mctx.CreateLocalVariations(variants...)
 	for i, m := range modules {
 		if variants[i] != "" {
-			m.(LinkableInterface).SetBuildStubs()
-			m.(LinkableInterface).SetStubsVersion(variants[i])
+			c := m.(*Module)
+			c.Properties.HideFromMake = true
+			c.sanitize = nil
+			c.stl = nil
+			c.Properties.PreventInstall = true
+			lib := moduleLibraryInterface(m)
+			lib.setBuildStubs()
+			lib.setStubsVersion(variants[i])
 			// The implementation depends on the stubs
 			mctx.AddInterVariantDependency(stubImplDepTag, modules[len(modules)-1], modules[i])
 		}
@@ -1665,18 +1672,24 @@
 	InRecovery() bool
 	CcLibraryInterface() bool
 	Shared() bool
-	Static() bool
 }) bool {
 	return CanBeOrLinkAgainstVersionVariants(module) &&
-		module.CcLibraryInterface() && (module.Shared() || module.Static())
+		module.CcLibraryInterface() && module.Shared()
+}
+
+func moduleLibraryInterface(module android.Module) libraryInterface {
+	if m, ok := module.(*Module); ok {
+		return m.library
+	}
+	return nil
 }
 
 // versionSelector normalizes the versions in the Stubs.Versions property into MutatedProperties.AllStubsVersions,
 // and propagates the value from implementation libraries to llndk libraries with the same name.
 func versionSelectorMutator(mctx android.BottomUpMutatorContext) {
-	if library, ok := mctx.Module().(LinkableInterface); ok && CanBeVersionVariant(library) {
-		if library.CcLibraryInterface() && library.BuildSharedVariant() {
-			versions := library.StubsVersions(mctx)
+	if library := moduleLibraryInterface(mctx.Module()); library != nil && CanBeVersionVariant(mctx.Module().(*Module)) {
+		if library.buildShared() {
+			versions := library.stubsVersions(mctx)
 			if len(versions) > 0 {
 				normalizeVersions(mctx, versions)
 				if mctx.Failed() {
@@ -1684,7 +1697,7 @@
 				}
 				// Set the versions on the pre-mutated module so they can be read by any llndk modules that
 				// depend on the implementation library and haven't been mutated yet.
-				library.SetAllStubsVersions(versions)
+				library.setAllStubsVersions(versions)
 				return
 			}
 		}
@@ -1694,8 +1707,8 @@
 // versionMutator splits a module into the mandatory non-stubs variant
 // (which is unnamed) and zero or more stubs variants.
 func versionMutator(mctx android.BottomUpMutatorContext) {
-	if library, ok := mctx.Module().(LinkableInterface); ok && CanBeVersionVariant(library) {
-		createVersionVariations(mctx, library.AllStubsVersions())
+	if library := moduleLibraryInterface(mctx.Module()); library != nil && CanBeVersionVariant(mctx.Module().(*Module)) {
+		createVersionVariations(mctx, library.allStubsVersions())
 		return
 	}
 
diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go
index fa6b326..106b2eb 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -86,10 +86,6 @@
 			if mctx.Device() {
 				variations = append(variations,
 					blueprint.Variation{Mutator: "image", Variation: android.CoreVariation})
-				if mt.linkTypes != nil {
-					variations = append(variations,
-						blueprint.Variation{Mutator: "version", Variation: version})
-				}
 			}
 			if mt.linkTypes == nil {
 				mctx.AddFarVariationDependencies(variations, dependencyTag, name)
@@ -97,6 +93,10 @@
 				for _, linkType := range mt.linkTypes {
 					libVariations := append(variations,
 						blueprint.Variation{Mutator: "link", Variation: linkType})
+					if mctx.Device() && linkType == "shared" {
+						libVariations = append(libVariations,
+							blueprint.Variation{Mutator: "version", Variation: version})
+					}
 					mctx.AddFarVariationDependencies(libVariations, dependencyTag, name)
 				}
 			}
@@ -428,22 +428,22 @@
 		specifiedDeps := specifiedDeps{}
 		specifiedDeps = ccModule.linker.linkerSpecifiedDeps(specifiedDeps)
 
-		if !ccModule.HasStubsVariants() {
-			// Propagate dynamic dependencies for implementation libs, but not stubs.
-			p.SharedLibs = specifiedDeps.sharedLibs
+		if lib := ccModule.library; lib != nil {
+			if !lib.hasStubsVariants() {
+				// Propagate dynamic dependencies for implementation libs, but not stubs.
+				p.SharedLibs = specifiedDeps.sharedLibs
+			} else {
+				// TODO(b/169373910): 1. Only output the specific version (from
+				// ccModule.StubsVersion()) if the module is versioned. 2. Ensure that all
+				// the versioned stub libs are retained in the prebuilt tree; currently only
+				// the stub corresponding to ccModule.StubsVersion() is.
+				p.StubsVersions = lib.allStubsVersions()
+			}
 		}
 		p.SystemSharedLibs = specifiedDeps.systemSharedLibs
 	}
 	p.exportedGeneratedHeaders = exportedInfo.GeneratedHeaders
 
-	if ccModule.HasStubsVariants() {
-		// TODO(b/169373910): 1. Only output the specific version (from
-		// ccModule.StubsVersion()) if the module is versioned. 2. Ensure that all
-		// the versioned stub libs are retained in the prebuilt tree; currently only
-		// the stub corresponding to ccModule.StubsVersion() is.
-		p.StubsVersions = ccModule.AllStubsVersions()
-	}
-
 	if !p.memberType.noOutputFiles && addOutputFile {
 		p.outputFile = getRequiredMemberOutputFile(ctx, ccModule)
 	}
diff --git a/cc/linkable.go b/cc/linkable.go
index 177e0c4..60ab6df 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -16,16 +16,7 @@
 
 	NonCcVariants() bool
 
-	StubsVersions(android.BaseMutatorContext) []string
-	BuildStubs() bool
-	SetBuildStubs()
-	SetStubsVersion(string)
-	StubsVersion() string
-	SetAllStubsVersions([]string)
-	AllStubsVersions() []string
-	HasStubsVariants() bool
 	SelectedStl() string
-	ApiLevel() string
 
 	BuildStaticVariant() bool
 	BuildSharedVariant() bool
@@ -56,10 +47,6 @@
 	AlwaysSdk() bool
 	IsSdkVariant() bool
 
-	ToolchainLibrary() bool
-	NdkPrebuiltStl() bool
-	StubDecorator() bool
-
 	SplitPerApiLevel() bool
 }
 
diff --git a/cc/llndk_library.go b/cc/llndk_library.go
index 9f4444d..3b1d2f4 100644
--- a/cc/llndk_library.go
+++ b/cc/llndk_library.go
@@ -185,7 +185,7 @@
 	if len(impls) > 1 {
 		panic(fmt.Errorf("Expected single implmenetation library, got %d", len(impls)))
 	} else if len(impls) == 1 {
-		return impls[0].(*Module).AllStubsVersions()
+		return moduleLibraryInterface(impls[0]).allStubsVersions()
 	}
 	return nil
 }
@@ -204,6 +204,7 @@
 	module.compiler = stub
 	module.linker = stub
 	module.installer = nil
+	module.library = stub
 
 	module.AddProperties(
 		&module.Properties,
@@ -251,6 +252,7 @@
 	module.compiler = nil
 	module.linker = decorator
 	module.installer = nil
+	module.library = decorator
 
 	module.AddProperties(
 		&module.Properties,
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index 02b38a6..9097e7b 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -333,6 +333,7 @@
 	module.compiler = stub
 	module.linker = stub
 	module.installer = stub
+	module.library = stub
 
 	module.Properties.AlwaysSdk = true
 	module.Properties.Sdk_version = StringPtr("current")
diff --git a/cc/ndk_sysroot.go b/cc/ndk_sysroot.go
index b6733c2..70b15c1 100644
--- a/cc/ndk_sysroot.go
+++ b/cc/ndk_sysroot.go
@@ -131,7 +131,7 @@
 		}
 
 		if m, ok := module.(*Module); ok {
-			if installer, ok := m.installer.(*stubDecorator); ok && m.BuildStubs() {
+			if installer, ok := m.installer.(*stubDecorator); ok && m.library.buildStubs() {
 				if ctx.Config().ExcludeDraftNdkApis() &&
 					installer.properties.Draft {
 					return
diff --git a/cc/pgo.go b/cc/pgo.go
index 439d2f7..3cf550a 100644
--- a/cc/pgo.go
+++ b/cc/pgo.go
@@ -41,7 +41,6 @@
 var pgoProfileProjectsConfigKey = android.NewOnceKey("PgoProfileProjects")
 
 const profileInstrumentFlag = "-fprofile-generate=/data/local/tmp"
-const profileSamplingFlag = "-gmlt -fdebug-info-for-profiling"
 const profileUseInstrumentFormat = "-fprofile-use=%s"
 const profileUseSamplingFormat = "-fprofile-sample-accurate -fprofile-sample-use=%s"
 
@@ -100,9 +99,6 @@
 }
 func (props *PgoProperties) addSamplingProfileGatherFlags(ctx ModuleContext, flags Flags) Flags {
 	flags.Local.CFlags = append(flags.Local.CFlags, props.Pgo.Cflags...)
-
-	flags.Local.CFlags = append(flags.Local.CFlags, profileSamplingFlag)
-	flags.Local.LdFlags = append(flags.Local.LdFlags, profileSamplingFlag)
 	return flags
 }
 
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index 45d3eb1..8873883 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -228,6 +228,7 @@
 		libraryDecorator: library,
 	}
 	module.linker = prebuilt
+	module.library = prebuilt
 
 	module.AddProperties(&prebuilt.properties)
 
diff --git a/cc/toolchain_library.go b/cc/toolchain_library.go
index 8c546c5..0c934ad 100644
--- a/cc/toolchain_library.go
+++ b/cc/toolchain_library.go
@@ -66,6 +66,7 @@
 	module.stl = nil
 	module.sanitize = nil
 	module.installer = nil
+	module.library = toolchainLibrary
 	module.Properties.Sdk_version = StringPtr("current")
 	return module.Init()
 }
diff --git a/cc/vndk.go b/cc/vndk.go
index 7d8777c..b2614c5 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -313,7 +313,7 @@
 		panic(err)
 	}
 
-	if m.HasStubsVariants() && name != "libz" {
+	if lib := m.library; lib != nil && lib.hasStubsVariants() && name != "libz" {
 		// b/155456180 libz is the ONLY exception here. We don't want to make
 		// libz an LLNDK library because we in general can't guarantee that
 		// libz will behave consistently especially about the compression.
diff --git a/cmd/multiproduct_kati/main.go b/cmd/multiproduct_kati/main.go
index 7329aee..0a9b156 100644
--- a/cmd/multiproduct_kati/main.go
+++ b/cmd/multiproduct_kati/main.go
@@ -412,7 +412,9 @@
 	ctx.Status.AddOutput(terminal.NewStatusOutput(ctx.Writer, "", false,
 		build.OsEnvironment().IsEnvTrue("ANDROID_QUIET_BUILD")))
 
-	config := build.NewConfig(ctx, flag.Args()...)
+	args := append([]string(nil), flag.Args()...)
+	args = append(args, "--skip-soong-tests")
+	config := build.NewConfig(ctx, args...)
 	config.Environment().Set("OUT_DIR", outDir)
 	if !*keepArtifacts {
 		config.Environment().Set("EMPTY_NINJA_FILE", "true")
diff --git a/genrule/genrule.go b/genrule/genrule.go
index b09c195..53b9dbe 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -561,13 +561,12 @@
 
 func (g *Module) AndroidMk() android.AndroidMkData {
 	return android.AndroidMkData{
-		Include:    "$(BUILD_PHONY_PACKAGE)",
-		Class:      "FAKE",
+		Class:      "ETC",
 		OutputFile: android.OptionalPathForPath(g.outputFiles[0]),
 		SubName:    g.subName,
 		Extra: []android.AndroidMkExtraFunc{
 			func(w io.Writer, outputFile android.Path) {
-				fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES :=", strings.Join(g.outputDeps.Strings(), " "))
+				fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
 			},
 		},
 		Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
diff --git a/java/java.go b/java/java.go
index 3167512..9f09051 100644
--- a/java/java.go
+++ b/java/java.go
@@ -1246,7 +1246,8 @@
 	return flags
 }
 
-func (j *Module) collectJavacFlags(ctx android.ModuleContext, flags javaBuilderFlags) javaBuilderFlags {
+func (j *Module) collectJavacFlags(
+	ctx android.ModuleContext, flags javaBuilderFlags, srcFiles android.Paths) javaBuilderFlags {
 	// javac flags.
 	javacFlags := j.properties.Javacflags
 
@@ -1262,14 +1263,48 @@
 
 		if j.properties.Patch_module != nil {
 			// Manually specify build directory in case it is not under the repo root.
-			// (javac doesn't seem to expand into symbolc links when searching for patch-module targets, so
+			// (javac doesn't seem to expand into symbolic links when searching for patch-module targets, so
 			// just adding a symlink under the root doesn't help.)
-			patchPaths := ".:" + ctx.Config().BuildDir()
+			patchPaths := []string{".", ctx.Config().BuildDir()}
+
+			// b/150878007
+			//
+			// Workaround to support *Bazel-executed* JDK9 javac in Bazel's
+			// execution root for --patch-module. If this javac command line is
+			// invoked within Bazel's execution root working directory, the top
+			// level directories (e.g. libcore/, tools/, frameworks/) are all
+			// symlinks. JDK9 javac does not traverse into symlinks, which causes
+			// --patch-module to fail source file lookups when invoked in the
+			// execution root.
+			//
+			// Short of patching javac or enumerating *all* directories as possible
+			// input dirs, manually add the top level dir of the source files to be
+			// compiled.
+			topLevelDirs := map[string]bool{}
+			for _, srcFilePath := range srcFiles {
+				srcFileParts := strings.Split(srcFilePath.String(), "/")
+				// Ignore source files that are already in the top level directory
+				// as well as generated files in the out directory. The out
+				// directory may be an absolute path, which means srcFileParts[0] is the
+				// empty string, so check that as well. Note that "out" in Bazel's execution
+				// root is *not* a symlink, which doesn't cause problems for --patch-modules
+				// anyway, so it's fine to not apply this workaround for generated
+				// source files.
+				if len(srcFileParts) > 1 &&
+					srcFileParts[0] != "" &&
+					srcFileParts[0] != "out" {
+					topLevelDirs[srcFileParts[0]] = true
+				}
+			}
+			patchPaths = append(patchPaths, android.SortedStringKeys(topLevelDirs)...)
+
 			classPath := flags.classpath.FormJavaClassPath("")
 			if classPath != "" {
-				patchPaths += ":" + classPath
+				patchPaths = append(patchPaths, classPath)
 			}
-			javacFlags = append(javacFlags, "--patch-module="+String(j.properties.Patch_module)+"="+patchPaths)
+			javacFlags = append(
+				javacFlags,
+				"--patch-module="+String(j.properties.Patch_module)+"="+strings.Join(patchPaths, ":"))
 		}
 	}
 
@@ -1303,7 +1338,9 @@
 
 	srcFiles = j.genSources(ctx, srcFiles, flags)
 
-	flags = j.collectJavacFlags(ctx, flags)
+	// Collect javac flags only after computing the full set of srcFiles to
+	// ensure that the --patch-module lookup paths are complete.
+	flags = j.collectJavacFlags(ctx, flags, srcFiles)
 
 	srcJars := srcFiles.FilterByExt(".srcjar")
 	srcJars = append(srcJars, deps.srcJars...)
diff --git a/java/java_test.go b/java/java_test.go
index cdb4375..6c0a908 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -2046,7 +2046,14 @@
 
 			java_library {
 				name: "baz",
-				srcs: ["c.java"],
+				srcs: [
+					"c.java",
+					// Tests for b/150878007
+					"dir/d.java",
+					"dir2/e.java",
+					"dir2/f.java",
+					"nested/dir/g.java"
+				],
 				patch_module: "java.base",
 			}
 		`
@@ -2055,7 +2062,8 @@
 		checkPatchModuleFlag(t, ctx, "foo", "")
 		expected := "java.base=.:" + buildDir
 		checkPatchModuleFlag(t, ctx, "bar", expected)
-		expected = "java.base=" + strings.Join([]string{".", buildDir, moduleToPath("ext"), moduleToPath("framework")}, ":")
+		expected = "java.base=" + strings.Join([]string{
+			".", buildDir, "dir", "dir2", "nested", moduleToPath("ext"), moduleToPath("framework")}, ":")
 		checkPatchModuleFlag(t, ctx, "baz", expected)
 	})
 }
diff --git a/rust/rust.go b/rust/rust.go
index 77d9a90..e65b90e 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -133,14 +133,6 @@
 func (c *Module) SetImageVariation(ctx android.BaseModuleContext, variant string, module android.Module) {
 }
 
-func (mod *Module) BuildStubs() bool {
-	return false
-}
-
-func (mod *Module) HasStubsVariants() bool {
-	return false
-}
-
 func (mod *Module) SelectedStl() string {
 	return ""
 }
@@ -154,10 +146,6 @@
 	panic(fmt.Errorf("NonCcVariants called on non-library module: %q", mod.BaseModuleName()))
 }
 
-func (mod *Module) ApiLevel() string {
-	panic(fmt.Errorf("Called ApiLevel on Rust module %q; stubs libraries are not yet supported.", mod.BaseModuleName()))
-}
-
 func (mod *Module) Static() bool {
 	if mod.compiler != nil {
 		if library, ok := mod.compiler.(libraryInterface); ok {
@@ -233,18 +221,6 @@
 	return false
 }
 
-func (mod *Module) ToolchainLibrary() bool {
-	return false
-}
-
-func (mod *Module) NdkPrebuiltStl() bool {
-	return false
-}
-
-func (mod *Module) StubDecorator() bool {
-	return false
-}
-
 type Deps struct {
 	Dylibs     []string
 	Rlibs      []string
@@ -466,26 +442,6 @@
 	panic(fmt.Errorf("SetShared called on non-library module: %q", mod.BaseModuleName()))
 }
 
-func (mod *Module) SetBuildStubs() {
-	panic("SetBuildStubs not yet implemented for rust modules")
-}
-
-func (mod *Module) SetStubsVersion(string) {
-	panic("SetStubsVersion not yet implemented for rust modules")
-}
-
-func (mod *Module) StubsVersion() string {
-	panic("StubsVersion not yet implemented for rust modules")
-}
-
-func (mod *Module) SetAllStubsVersions([]string) {
-	panic("SetAllStubsVersions not yet implemented for rust modules")
-}
-
-func (mod *Module) AllStubsVersions() []string {
-	return nil
-}
-
 func (mod *Module) BuildStaticVariant() bool {
 	if mod.compiler != nil {
 		if library, ok := mod.compiler.(libraryInterface); ok {
@@ -508,16 +464,6 @@
 	return mod
 }
 
-func (mod *Module) StubsVersions(ctx android.BaseMutatorContext) []string {
-	// For now, Rust has no stubs versions.
-	if mod.compiler != nil {
-		if _, ok := mod.compiler.(libraryInterface); ok {
-			return []string{}
-		}
-	}
-	panic(fmt.Errorf("StubsVersions called on non-library module: %q", mod.BaseModuleName()))
-}
-
 func (mod *Module) OutputFile() android.OptionalPath {
 	return mod.outputFile
 }
diff --git a/scripts/conv_linker_config.py b/scripts/conv_linker_config.py
index 86f788d..81425fb 100644
--- a/scripts/conv_linker_config.py
+++ b/scripts/conv_linker_config.py
@@ -25,8 +25,12 @@
 
 
 def Proto(args):
+  json_content = ''
   with open(args.source) as f:
-    obj = json.load(f, object_pairs_hook=collections.OrderedDict)
+    for line in f:
+      if not line.lstrip().startswith('//'):
+        json_content += line
+  obj = json.loads(json_content, object_pairs_hook=collections.OrderedDict)
   pb = ParseDict(obj, linker_config_pb2.LinkerConfig())
   with open(args.output, 'wb') as f:
     f.write(pb.SerializeToString())
diff --git a/ui/build/bazel.go b/ui/build/bazel.go
index c5702c0..978553d 100644
--- a/ui/build/bazel.go
+++ b/ui/build/bazel.go
@@ -15,6 +15,8 @@
 package build
 
 import (
+	"io/ioutil"
+	"os"
 	"path/filepath"
 	"strings"
 )
@@ -32,12 +34,6 @@
 	bazelExecutable := filepath.Join("tools", "bazel")
 	args := []string{
 		"build",
-		"--verbose_failures",
-		"--show_progress_rate_limit=0.05",
-		"--color=yes",
-		"--curses=yes",
-		"--show_timestamps",
-		"--announce_rc",
 		"--output_groups=" + outputGroups,
 		"//:" + config.TargetProduct() + "-" + config.TargetBuildVariant(),
 	}
@@ -51,4 +47,57 @@
 	cmd.Dir = filepath.Join(config.OutDir(), "..")
 	ctx.Status.Status("Starting Bazel..")
 	cmd.RunAndStreamOrFatal()
+
+	// Obtain the Bazel output directory for ninja_build.
+	infoArgs := []string{
+		"info",
+		"output_path",
+	}
+
+	infoCmd := Command(ctx, config, "bazel", bazelExecutable, infoArgs...)
+
+	infoCmd.Environment.Set("DIST_DIR", config.DistDir())
+	infoCmd.Environment.Set("SHELL", "/bin/bash")
+	infoCmd.Dir = filepath.Join(config.OutDir(), "..")
+	ctx.Status.Status("Getting Bazel Info..")
+	outputBasePath := string(infoCmd.OutputOrFatal())
+	// TODO: Don't hardcode out/ as the bazel output directory. This is
+	// currently hardcoded as ninja_build.output_root.
+	bazelNinjaBuildOutputRoot := filepath.Join(outputBasePath, "..", "out")
+
+	symlinkOutdir(ctx, config, bazelNinjaBuildOutputRoot, ".")
+}
+
+// For all files F recursively under rootPath/relativePath, creates symlinks
+// such that OutDir/F resolves to rootPath/F via symlinks.
+func symlinkOutdir(ctx Context, config Config, rootPath string, relativePath string) {
+	destDir := filepath.Join(rootPath, relativePath)
+	os.MkdirAll(destDir, 0755)
+	files, err := ioutil.ReadDir(destDir)
+	if err != nil {
+		ctx.Fatal(err)
+	}
+	for _, f := range files {
+		destPath := filepath.Join(destDir, f.Name())
+		srcPath := filepath.Join(config.OutDir(), relativePath, f.Name())
+		if statResult, err := os.Stat(srcPath); err == nil {
+			if statResult.Mode().IsDir() && f.IsDir() {
+				// Directory under OutDir already exists, so recurse on its contents.
+				symlinkOutdir(ctx, config, rootPath, filepath.Join(relativePath, f.Name()))
+			} else if !statResult.Mode().IsDir() && !f.IsDir() {
+				// File exists both in source and destination, and it's not a directory
+				// in either location. Do nothing.
+				// This can arise for files which are generated under OutDir outside of
+				// soong_build, such as .bootstrap files.
+			} else {
+				// File is a directory in one location but not the other. Raise an error.
+				ctx.Fatalf("Could not link %s to %s due to conflict", srcPath, destPath)
+			}
+		} else if os.IsNotExist(err) {
+			// Create symlink srcPath -> fullDestPath.
+			os.Symlink(destPath, srcPath)
+		} else {
+			ctx.Fatalf("Unable to stat %s: %s", srcPath, err)
+		}
+	}
 }
diff --git a/ui/build/config.go b/ui/build/config.go
index 82df8a0..e57c730 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -41,12 +41,13 @@
 	buildDateTime string
 
 	// From the arguments
-	parallel   int
-	keepGoing  int
-	verbose    bool
-	checkbuild bool
-	dist       bool
-	skipMake   bool
+	parallel       int
+	keepGoing      int
+	verbose        bool
+	checkbuild     bool
+	dist           bool
+	skipMake       bool
+	skipSoongTests bool
 
 	// From the product config
 	katiArgs        []string
@@ -526,6 +527,8 @@
 			c.verbose = true
 		} else if arg == "--skip-make" {
 			c.skipMake = true
+		} else if arg == "--skip-soong-tests" {
+			c.skipSoongTests = true
 		} else if len(arg) > 0 && arg[0] == '-' {
 			parseArgNum := func(def int) int {
 				if len(arg) > 2 {
diff --git a/ui/build/exec.go b/ui/build/exec.go
index 053bbae..8f92269 100644
--- a/ui/build/exec.go
+++ b/ui/build/exec.go
@@ -66,8 +66,11 @@
 }
 
 func (c *Cmd) report() {
-	if c.Cmd.ProcessState != nil {
-		rusage := c.Cmd.ProcessState.SysUsage().(*syscall.Rusage)
+	if state := c.Cmd.ProcessState; state != nil {
+		if c.ctx.Metrics != nil {
+			c.ctx.Metrics.EventTracer.AddProcResInfo(c.name, state)
+		}
+		rusage := state.SysUsage().(*syscall.Rusage)
 		c.ctx.Verbosef("%q finished with exit code %d (%s real, %s user, %s system, %dMB maxrss)",
 			c.name, c.Cmd.ProcessState.ExitCode(),
 			time.Since(c.started).Round(time.Millisecond),
diff --git a/ui/build/soong.go b/ui/build/soong.go
index fb21430..b20237c 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -38,7 +38,12 @@
 		ctx.BeginTrace(metrics.RunSoong, "blueprint bootstrap")
 		defer ctx.EndTrace()
 
-		cmd := Command(ctx, config, "blueprint bootstrap", "build/blueprint/bootstrap.bash", "-t", "-n")
+		args := []string{"-n"}
+		if !config.skipSoongTests {
+			args = append(args, "-t")
+		}
+
+		cmd := Command(ctx, config, "blueprint bootstrap", "build/blueprint/bootstrap.bash", args...)
 		cmd.Environment.Set("BLUEPRINTDIR", "./build/blueprint")
 		cmd.Environment.Set("BOOTSTRAP", "./build/blueprint/bootstrap.bash")
 		cmd.Environment.Set("BUILDDIR", config.SoongOutDir())
diff --git a/ui/build/test_build.go b/ui/build/test_build.go
index 83b3807..3164680 100644
--- a/ui/build/test_build.go
+++ b/ui/build/test_build.go
@@ -68,6 +68,12 @@
 	miniBootstrapDir := filepath.Join(outDir, "soong", ".minibootstrap")
 	modulePathsDir := filepath.Join(outDir, ".module_paths")
 	variablesFilePath := filepath.Join(outDir, "soong", "soong.variables")
+	// dexpreopt.config is an input to the soong_docs action, which runs the
+	// soong_build primary builder. However, this file is created from $(shell)
+	// invocation at Kati parse time, so it's not an explicit output of any
+	// Ninja action, but it is present during the build itself and can be
+	// treated as an source file.
+	dexpreoptConfigFilePath := filepath.Join(outDir, "soong", "dexpreopt.config")
 
 	danglingRules := make(map[string]bool)
 
@@ -81,7 +87,8 @@
 		if strings.HasPrefix(line, bootstrapDir) ||
 			strings.HasPrefix(line, miniBootstrapDir) ||
 			strings.HasPrefix(line, modulePathsDir) ||
-			line == variablesFilePath {
+			line == variablesFilePath ||
+			line == dexpreoptConfigFilePath {
 			// Leaf node is in one of Soong's bootstrap directories, which do not have
 			// full build rules in the primary build.ninja file.
 			continue
diff --git a/ui/metrics/event.go b/ui/metrics/event.go
index 5a62847..6becfd1 100644
--- a/ui/metrics/event.go
+++ b/ui/metrics/event.go
@@ -15,6 +15,8 @@
 package metrics
 
 import (
+	"os"
+	"syscall"
 	"time"
 
 	"android/soong/ui/metrics/metrics_proto"
@@ -31,11 +33,15 @@
 
 	// the time that the event started to occur.
 	start time.Time
+
+	// The list of process resource information that was executed
+	procResInfo []*soong_metrics_proto.ProcessResourceInfo
 }
 
 type EventTracer interface {
 	Begin(name, desc string, thread tracer.Thread)
 	End(thread tracer.Thread) soong_metrics_proto.PerfInfo
+	AddProcResInfo(string, *os.ProcessState)
 }
 
 type eventTracerImpl struct {
@@ -48,6 +54,34 @@
 	return time.Now()
 }
 
+// AddProcResInfo adds information on an executed process such as max resident set memory
+// and the number of voluntary context switches.
+func (t *eventTracerImpl) AddProcResInfo(name string, state *os.ProcessState) {
+	if len(t.activeEvents) < 1 {
+		return
+	}
+
+	rusage := state.SysUsage().(*syscall.Rusage)
+	// The implementation of the metrics system is a stacked based system. The steps of the
+	// build system in the UI layer is sequential so the Begin function is invoked when a
+	// function (or scoped code) is invoked. That is translated to a new event which is added
+	// at the end of the activeEvents array. When the invoking function is completed, End is
+	// invoked which is a pop operation from activeEvents.
+	curEvent := &t.activeEvents[len(t.activeEvents)-1]
+	curEvent.procResInfo = append(curEvent.procResInfo, &soong_metrics_proto.ProcessResourceInfo{
+		Name:             proto.String(name),
+		UserTimeMicros:   proto.Uint64(uint64(rusage.Utime.Usec)),
+		SystemTimeMicros: proto.Uint64(uint64(rusage.Stime.Usec)),
+		MinorPageFaults:  proto.Uint64(uint64(rusage.Minflt)),
+		MajorPageFaults:  proto.Uint64(uint64(rusage.Majflt)),
+		// ru_inblock and ru_oublock are measured in blocks of 512 bytes.
+		IoInputKb:                  proto.Uint64(uint64(rusage.Inblock / 2)),
+		IoOutputKb:                 proto.Uint64(uint64(rusage.Oublock / 2)),
+		VoluntaryContextSwitches:   proto.Uint64(uint64(rusage.Nvcsw)),
+		InvoluntaryContextSwitches: proto.Uint64(uint64(rusage.Nivcsw)),
+	})
+}
+
 func (t *eventTracerImpl) Begin(name, desc string, _ tracer.Thread) {
 	t.activeEvents = append(t.activeEvents, event{name: name, desc: desc, start: _now()})
 }
@@ -61,9 +95,10 @@
 	realTime := uint64(_now().Sub(lastEvent.start).Nanoseconds())
 
 	return soong_metrics_proto.PerfInfo{
-		Desc:      proto.String(lastEvent.desc),
-		Name:      proto.String(lastEvent.name),
-		StartTime: proto.Uint64(uint64(lastEvent.start.UnixNano())),
-		RealTime:  proto.Uint64(realTime),
+		Desc:                  proto.String(lastEvent.desc),
+		Name:                  proto.String(lastEvent.name),
+		StartTime:             proto.Uint64(uint64(lastEvent.start.UnixNano())),
+		RealTime:              proto.Uint64(realTime),
+		ProcessesResourceInfo: lastEvent.procResInfo,
 	}
 }