Merge "Add java.util.random to the allowed package list." into main
diff --git a/OWNERS b/OWNERS
index 9221d3e..c52231e 100644
--- a/OWNERS
+++ b/OWNERS
@@ -2,29 +2,29 @@
 # approving build related projects.
 
 # AMER
-agespino@google.com
+agespino@google.com  #{LAST_RESORT_SUGGESTION}
 ccross@android.com
 colefaust@google.com
-cparsons@google.com
-dacek@google.com
-delmerico@google.com
+cparsons@google.com  #{LAST_RESORT_SUGGESTION}
+dacek@google.com  #{LAST_RESORT_SUGGESTION}
+delmerico@google.com  #{LAST_RESORT_SUGGESTION}
 dwillemsen@google.com
-eakammer@google.com
+eakammer@google.com  #{LAST_RESORT_SUGGESTION}
 jihoonkang@google.com
-jobredeaux@google.com
+jobredeaux@google.com  #{LAST_RESORT_SUGGESTION}
 joeo@google.com
-juu@google.com
+juu@google.com  #{LAST_RESORT_SUGGESTION}
 lamontjones@google.com
 mrziwang@google.com
 spandandas@google.com
-tradical@google.com
-usta@google.com
-vinhdaitran@google.com
+tradical@google.com  #{LAST_RESORT_SUGGESTION}
+usta@google.com  #{LAST_RESORT_SUGGESTION}
+vinhdaitran@google.com  #{LAST_RESORT_SUGGESTION}
 weiwli@google.com
 yudiliu@google.com
 
 # APAC
-jingwen@google.com
+jingwen@google.com  #{LAST_RESORT_SUGGESTION}
 
 # EMEA
-lberki@google.com
+lberki@google.com  #{LAST_RESORT_SUGGESTION}
diff --git a/android/metrics.go b/android/metrics.go
index 63c72cd..3571272 100644
--- a/android/metrics.go
+++ b/android/metrics.go
@@ -15,9 +15,13 @@
 package android
 
 import (
+	"bytes"
 	"io/ioutil"
+	"os"
 	"runtime"
 	"sort"
+	"strconv"
+	"time"
 
 	"github.com/google/blueprint/metrics"
 	"google.golang.org/protobuf/proto"
@@ -27,18 +31,21 @@
 
 var soongMetricsOnceKey = NewOnceKey("soong metrics")
 
-type SoongMetrics struct {
-	Modules  int
-	Variants int
+type soongMetrics struct {
+	modules       int
+	variants      int
+	perfCollector perfCollector
 }
 
-func readSoongMetrics(config Config) (SoongMetrics, bool) {
-	soongMetrics, ok := config.Peek(soongMetricsOnceKey)
-	if ok {
-		return soongMetrics.(SoongMetrics), true
-	} else {
-		return SoongMetrics{}, false
-	}
+type perfCollector struct {
+	events []*soong_metrics_proto.PerfCounters
+	stop   chan<- bool
+}
+
+func getSoongMetrics(config Config) *soongMetrics {
+	return config.Once(soongMetricsOnceKey, func() interface{} {
+		return &soongMetrics{}
+	}).(*soongMetrics)
 }
 
 func init() {
@@ -50,27 +57,27 @@
 type soongMetricsSingleton struct{}
 
 func (soongMetricsSingleton) GenerateBuildActions(ctx SingletonContext) {
-	metrics := SoongMetrics{}
+	metrics := getSoongMetrics(ctx.Config())
 	ctx.VisitAllModules(func(m Module) {
 		if ctx.PrimaryModule(m) == m {
-			metrics.Modules++
+			metrics.modules++
 		}
-		metrics.Variants++
-	})
-	ctx.Config().Once(soongMetricsOnceKey, func() interface{} {
-		return metrics
+		metrics.variants++
 	})
 }
 
 func collectMetrics(config Config, eventHandler *metrics.EventHandler) *soong_metrics_proto.SoongBuildMetrics {
 	metrics := &soong_metrics_proto.SoongBuildMetrics{}
 
-	soongMetrics, ok := readSoongMetrics(config)
-	if ok {
-		metrics.Modules = proto.Uint32(uint32(soongMetrics.Modules))
-		metrics.Variants = proto.Uint32(uint32(soongMetrics.Variants))
+	soongMetrics := getSoongMetrics(config)
+	if soongMetrics.modules > 0 {
+		metrics.Modules = proto.Uint32(uint32(soongMetrics.modules))
+		metrics.Variants = proto.Uint32(uint32(soongMetrics.variants))
 	}
 
+	soongMetrics.perfCollector.stop <- true
+	metrics.PerfCounters = soongMetrics.perfCollector.events
+
 	memStats := runtime.MemStats{}
 	runtime.ReadMemStats(&memStats)
 	metrics.MaxHeapSize = proto.Uint64(memStats.HeapSys)
@@ -107,6 +114,113 @@
 	return metrics
 }
 
+func StartBackgroundMetrics(config Config) {
+	perfCollector := &getSoongMetrics(config).perfCollector
+	stop := make(chan bool)
+	perfCollector.stop = stop
+
+	previousTime := time.Now()
+	previousCpuTime := readCpuTime()
+
+	ticker := time.NewTicker(time.Second)
+
+	go func() {
+		for {
+			select {
+			case <-stop:
+				ticker.Stop()
+				return
+			case <-ticker.C:
+				// carry on
+			}
+
+			currentTime := time.Now()
+
+			var memStats runtime.MemStats
+			runtime.ReadMemStats(&memStats)
+
+			currentCpuTime := readCpuTime()
+
+			interval := currentTime.Sub(previousTime)
+			intervalCpuTime := currentCpuTime - previousCpuTime
+			intervalCpuPercent := intervalCpuTime * 100 / interval
+
+			// heapAlloc is the memory that has been allocated on the heap but not yet GC'd.  It may be referenced,
+			// or unrefenced but not yet GC'd.
+			heapAlloc := memStats.HeapAlloc
+			// heapUnused is the memory that was previously used by the heap, but is currently not used.  It does not
+			// count memory that was used and then returned to the OS.
+			heapUnused := memStats.HeapIdle - memStats.HeapReleased
+			// heapOverhead is the memory used by the allocator and GC
+			heapOverhead := memStats.MSpanSys + memStats.MCacheSys + memStats.GCSys
+			// otherMem is the memory used outside of the heap.
+			otherMem := memStats.Sys - memStats.HeapSys - heapOverhead
+
+			perfCollector.events = append(perfCollector.events, &soong_metrics_proto.PerfCounters{
+				Time: proto.Uint64(uint64(currentTime.UnixNano())),
+				Groups: []*soong_metrics_proto.PerfCounterGroup{
+					{
+						Name: proto.String("cpu"),
+						Counters: []*soong_metrics_proto.PerfCounter{
+							{Name: proto.String("cpu_percent"), Value: proto.Int64(int64(intervalCpuPercent))},
+						},
+					}, {
+						Name: proto.String("memory"),
+						Counters: []*soong_metrics_proto.PerfCounter{
+							{Name: proto.String("heap_alloc"), Value: proto.Int64(int64(heapAlloc))},
+							{Name: proto.String("heap_unused"), Value: proto.Int64(int64(heapUnused))},
+							{Name: proto.String("heap_overhead"), Value: proto.Int64(int64(heapOverhead))},
+							{Name: proto.String("other"), Value: proto.Int64(int64(otherMem))},
+						},
+					},
+				},
+			})
+
+			previousTime = currentTime
+			previousCpuTime = currentCpuTime
+		}
+	}()
+}
+
+func readCpuTime() time.Duration {
+	if runtime.GOOS != "linux" {
+		return 0
+	}
+
+	stat, err := os.ReadFile("/proc/self/stat")
+	if err != nil {
+		return 0
+	}
+
+	endOfComm := bytes.LastIndexByte(stat, ')')
+	if endOfComm < 0 || endOfComm > len(stat)-2 {
+		return 0
+	}
+
+	stat = stat[endOfComm+2:]
+
+	statFields := bytes.Split(stat, []byte{' '})
+	// This should come from sysconf(_SC_CLK_TCK), but there's no way to call that from Go.  Assume it's 100,
+	// which is the value for all platforms we support.
+	const HZ = 100
+	const MS_PER_HZ = 1e3 / HZ * time.Millisecond
+
+	const STAT_UTIME_FIELD = 14 - 2
+	const STAT_STIME_FIELD = 15 - 2
+	if len(statFields) < STAT_STIME_FIELD {
+		return 0
+	}
+	userCpuTicks, err := strconv.ParseUint(string(statFields[STAT_UTIME_FIELD]), 10, 64)
+	if err != nil {
+		return 0
+	}
+	kernelCpuTicks, _ := strconv.ParseUint(string(statFields[STAT_STIME_FIELD]), 10, 64)
+	if err != nil {
+		return 0
+	}
+	return time.Duration(userCpuTicks+kernelCpuTicks) * MS_PER_HZ
+}
+
 func WriteMetrics(config Config, eventHandler *metrics.EventHandler, metricsFile string) error {
 	metrics := collectMetrics(config, eventHandler)
 
diff --git a/android/paths.go b/android/paths.go
index 8dd1966..a6cda38 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -1915,7 +1915,9 @@
 // validatePathInternal ensures that a path does not leave its component, and
 // optionally doesn't contain Ninja variables.
 func validatePathInternal(allowNinjaVariables bool, pathComponents ...string) (string, error) {
-	for _, path := range pathComponents {
+	initialEmpty := 0
+	finalEmpty := 0
+	for i, path := range pathComponents {
 		if !allowNinjaVariables && strings.Contains(path, "$") {
 			return "", fmt.Errorf("Path contains invalid character($): %s", path)
 		}
@@ -1924,11 +1926,25 @@
 		if path == ".." || strings.HasPrefix(path, "../") || strings.HasPrefix(path, "/") {
 			return "", fmt.Errorf("Path is outside directory: %s", path)
 		}
+
+		if i == initialEmpty && pathComponents[i] == "" {
+			initialEmpty++
+		}
+		if i == finalEmpty && pathComponents[len(pathComponents)-1-i] == "" {
+			finalEmpty++
+		}
 	}
+	// Optimization: filepath.Join("foo", "") returns a newly allocated copy
+	// of "foo", while filepath.Join("foo") does not.  Strip out any empty
+	// path components.
+	if initialEmpty == len(pathComponents) {
+		return "", nil
+	}
+	nonEmptyPathComponents := pathComponents[initialEmpty : len(pathComponents)-finalEmpty]
 	// TODO: filepath.Join isn't necessarily correct with embedded ninja
 	// variables. '..' may remove the entire ninja variable, even if it
 	// will be expanded to multiple nested directories.
-	return filepath.Join(pathComponents...), nil
+	return filepath.Join(nonEmptyPathComponents...), nil
 }
 
 // validateSafePath validates a path that we trust (may contain ninja
diff --git a/android/paths_test.go b/android/paths_test.go
index 2f87977..bf46c34 100644
--- a/android/paths_test.go
+++ b/android/paths_test.go
@@ -37,6 +37,22 @@
 		out: "",
 	},
 	{
+		in:  []string{"", ""},
+		out: "",
+	},
+	{
+		in:  []string{"a", ""},
+		out: "a",
+	},
+	{
+		in:  []string{"", "a"},
+		out: "a",
+	},
+	{
+		in:  []string{"", "a", ""},
+		out: "a",
+	},
+	{
 		in:  []string{"a/b"},
 		out: "a/b",
 	},
diff --git a/android/register.go b/android/register.go
index 6182159..de31353 100644
--- a/android/register.go
+++ b/android/register.go
@@ -22,6 +22,7 @@
 	"regexp"
 
 	"android/soong/shared"
+
 	"github.com/google/blueprint"
 )
 
@@ -66,9 +67,6 @@
 var moduleTypeByFactory = map[reflect.Value]string{}
 
 type singleton struct {
-	// True if this should be registered as a pre-singleton, false otherwise.
-	pre bool
-
 	// True if this should be registered as a parallel singleton.
 	parallel bool
 
@@ -77,11 +75,7 @@
 }
 
 func newSingleton(name string, factory SingletonFactory, parallel bool) singleton {
-	return singleton{pre: false, parallel: parallel, name: name, factory: factory}
-}
-
-func newPreSingleton(name string, factory SingletonFactory) singleton {
-	return singleton{pre: true, parallel: false, name: name, factory: factory}
+	return singleton{parallel: parallel, name: name, factory: factory}
 }
 
 func (s singleton) componentName() string {
@@ -90,17 +84,12 @@
 
 func (s singleton) register(ctx *Context) {
 	adaptor := SingletonFactoryAdaptor(ctx, s.factory)
-	if s.pre {
-		ctx.RegisterPreSingletonType(s.name, adaptor)
-	} else {
-		ctx.RegisterSingletonType(s.name, adaptor, s.parallel)
-	}
+	ctx.RegisterSingletonType(s.name, adaptor, s.parallel)
 }
 
 var _ sortableComponent = singleton{}
 
 var singletons sortableComponents
-var preSingletons sortableComponents
 
 type mutator struct {
 	name              string
@@ -164,10 +153,6 @@
 	registerSingletonType(name, factory, true)
 }
 
-func RegisterPreSingletonType(name string, factory SingletonFactory) {
-	preSingletons = append(preSingletons, newPreSingleton(name, factory))
-}
-
 type Context struct {
 	*blueprint.Context
 	config Config
@@ -253,8 +238,6 @@
 // Register the pipeline of singletons, module types, and mutators for
 // generating build.ninja and other files for Kati, from Android.bp files.
 func (ctx *Context) Register() {
-	preSingletons.registerAll(ctx)
-
 	for _, t := range moduleTypes {
 		t.register(ctx)
 	}
@@ -277,17 +260,17 @@
 func collateGloballyRegisteredSingletons() sortableComponents {
 	allSingletons := append(sortableComponents(nil), singletons...)
 	allSingletons = append(allSingletons,
-		singleton{pre: false, parallel: true, name: "bazeldeps", factory: BazelSingleton},
+		singleton{parallel: true, name: "bazeldeps", factory: BazelSingleton},
 
 		// Register phony just before makevars so it can write out its phony rules as Make rules
-		singleton{pre: false, parallel: false, name: "phony", factory: phonySingletonFactory},
+		singleton{parallel: false, name: "phony", factory: phonySingletonFactory},
 
 		// Register makevars after other singletons so they can export values through makevars
-		singleton{pre: false, parallel: false, name: "makevars", factory: makeVarsSingletonFunc},
+		singleton{parallel: false, name: "makevars", factory: makeVarsSingletonFunc},
 
 		// Register env and ninjadeps last so that they can track all used environment variables and
 		// Ninja file dependencies stored in the config.
-		singleton{pre: false, parallel: false, name: "ninjadeps", factory: ninjaDepsSingletonFactory},
+		singleton{parallel: false, name: "ninjadeps", factory: ninjaDepsSingletonFactory},
 	)
 
 	return allSingletons
@@ -317,7 +300,6 @@
 	RegisterModuleType(name string, factory ModuleFactory)
 	RegisterSingletonModuleType(name string, factory SingletonModuleFactory)
 	RegisterParallelSingletonModuleType(name string, factory SingletonModuleFactory)
-	RegisterPreSingletonType(name string, factory SingletonFactory)
 	RegisterParallelSingletonType(name string, factory SingletonFactory)
 	RegisterSingletonType(name string, factory SingletonFactory)
 	PreArchMutators(f RegisterMutatorFunc)
@@ -349,9 +331,8 @@
 //	ctx := android.NewTestContext(config)
 //	RegisterBuildComponents(ctx)
 var InitRegistrationContext RegistrationContext = &initRegistrationContext{
-	moduleTypes:       make(map[string]ModuleFactory),
-	singletonTypes:    make(map[string]SingletonFactory),
-	preSingletonTypes: make(map[string]SingletonFactory),
+	moduleTypes:    make(map[string]ModuleFactory),
+	singletonTypes: make(map[string]SingletonFactory),
 }
 
 // Make sure the TestContext implements RegistrationContext.
@@ -360,7 +341,6 @@
 type initRegistrationContext struct {
 	moduleTypes        map[string]ModuleFactory
 	singletonTypes     map[string]SingletonFactory
-	preSingletonTypes  map[string]SingletonFactory
 	moduleTypesForDocs map[string]reflect.Value
 }
 
@@ -406,14 +386,6 @@
 	ctx.registerSingletonType(name, factory, true)
 }
 
-func (ctx *initRegistrationContext) RegisterPreSingletonType(name string, factory SingletonFactory) {
-	if _, present := ctx.preSingletonTypes[name]; present {
-		panic(fmt.Sprintf("pre singleton type %q is already registered", name))
-	}
-	ctx.preSingletonTypes[name] = factory
-	RegisterPreSingletonType(name, factory)
-}
-
 func (ctx *initRegistrationContext) PreArchMutators(f RegisterMutatorFunc) {
 	PreArchMutators(f)
 }
diff --git a/android/testing.go b/android/testing.go
index 32357db..da3b75a 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -186,12 +186,12 @@
 	bp2buildPreArch, bp2buildMutators     []RegisterMutatorFunc
 	NameResolver                          *NameResolver
 
-	// The list of pre-singletons and singletons registered for the test.
-	preSingletons, singletons sortableComponents
+	// The list of singletons registered for the test.
+	singletons sortableComponents
 
-	// The order in which the pre-singletons, mutators and singletons will be run in this test
+	// The order in which the mutators and singletons will be run in this test
 	// context; for debugging.
-	preSingletonOrder, mutatorOrder, singletonOrder []string
+	mutatorOrder, singletonOrder []string
 }
 
 func (ctx *TestContext) PreArchMutators(f RegisterMutatorFunc) {
@@ -397,9 +397,6 @@
 	// Used to ensure that this is only created once.
 	once sync.Once
 
-	// The order of pre-singletons
-	preSingletonOrder registeredComponentOrder
-
 	// The order of mutators
 	mutatorOrder registeredComponentOrder
 
@@ -412,9 +409,6 @@
 // Only the first call has any effect.
 func (s *registrationSorter) populate() {
 	s.once.Do(func() {
-		// Create an ordering from the globally registered pre-singletons.
-		s.preSingletonOrder = registeredComponentOrderFromExistingOrder("pre-singleton", preSingletons)
-
 		// Created an ordering from the globally registered mutators.
 		globallyRegisteredMutators := collateGloballyRegisteredMutators()
 		s.mutatorOrder = registeredComponentOrderFromExistingOrder("mutator", globallyRegisteredMutators)
@@ -441,11 +435,6 @@
 func (ctx *TestContext) Register() {
 	globalOrder := globallyRegisteredComponentsOrder()
 
-	// Ensure that the pre-singletons used in the test are in the same order as they are used at
-	// runtime.
-	globalOrder.preSingletonOrder.enforceOrdering(ctx.preSingletons)
-	ctx.preSingletons.registerAll(ctx.Context)
-
 	mutators := collateRegisteredMutators(ctx.preArch, ctx.preDeps, ctx.postDeps, ctx.finalDeps)
 	// Ensure that the mutators used in the test are in the same order as they are used at runtime.
 	globalOrder.mutatorOrder.enforceOrdering(mutators)
@@ -456,7 +445,6 @@
 	ctx.singletons.registerAll(ctx.Context)
 
 	// Save the sorted components order away to make them easy to access while debugging.
-	ctx.preSingletonOrder = componentsToNames(preSingletons)
 	ctx.mutatorOrder = componentsToNames(mutators)
 	ctx.singletonOrder = componentsToNames(singletons)
 }
@@ -503,10 +491,6 @@
 	ctx.singletons = append(ctx.singletons, newSingleton(name, factory, true))
 }
 
-func (ctx *TestContext) RegisterPreSingletonType(name string, factory SingletonFactory) {
-	ctx.preSingletons = append(ctx.preSingletons, newPreSingleton(name, factory))
-}
-
 // ModuleVariantForTests selects a specific variant of the module with the given
 // name by matching the variations map against the variations of each module
 // variant. A module variant matches the map if every variation that exists in
diff --git a/apex/androidmk.go b/apex/androidmk.go
index 2f5d8d4..6136cbd 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -260,6 +260,7 @@
 				fmt.Fprintln(w, "LOCAL_SOONG_INSTALL_PAIRS :=", a.outputFile.String()+":"+a.installedFile.String())
 				fmt.Fprintln(w, "LOCAL_SOONG_INSTALL_SYMLINKS := ", strings.Join(a.compatSymlinks.Strings(), " "))
 			}
+			fmt.Fprintln(w, "LOCAL_APEX_KEY_PATH := ", a.apexKeysPath.String())
 
 			// Because apex writes .mk with Custom(), we need to write manually some common properties
 			// which are available via data.Entries
diff --git a/apex/apex.go b/apex/apex.go
index f903373..f2e8a06 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -135,6 +135,11 @@
 	// List of filesystem images that are embedded inside this APEX bundle.
 	Filesystems []string
 
+	// List of module names which we don't want to add as transitive deps. This can be used as
+	// a workaround when the current implementation collects more than necessary. For example,
+	// Rust binaries with prefer_rlib:true add unnecessary dependencies.
+	Unwanted_transitive_deps []string
+
 	// The minimum SDK version that this APEX must support at minimum. This is usually set to
 	// the SDK version that the APEX was first introduced.
 	Min_sdk_version *string
@@ -454,6 +459,9 @@
 	// Path where this APEX was installed.
 	installedFile android.InstallPath
 
+	// fragment for this apex for apexkeys.txt
+	apexKeysPath android.WritablePath
+
 	// Installed locations of symlinks for backward compatibility.
 	compatSymlinks android.InstallPaths
 
@@ -1923,6 +1931,7 @@
 
 		a.filesInfo = append(a.filesInfo, fileInfo)
 	}
+	a.apexKeysPath = writeApexKeys(ctx, a)
 }
 
 func (a *apexBundle) setCompression(ctx android.ModuleContext) {
@@ -1999,11 +2008,21 @@
 
 	// if true, raise error on duplicate apexFile
 	checkDuplicate bool
+
+	// visitor skips these from this list of module names
+	unwantedTransitiveDeps []string
 }
 
 func (vctx *visitorContext) normalizeFileInfo(mctx android.ModuleContext) {
 	encountered := make(map[string]apexFile)
 	for _, f := range vctx.filesInfo {
+		// Skips unwanted transitive deps. This happens, for example, with Rust binaries with prefer_rlib:true.
+		// TODO(b/295593640)
+		// Needs additional verification for the resulting APEX to ensure that skipped artifacts don't make problems.
+		// For example, DT_NEEDED modules should be found within the APEX unless they are marked in `requiredNativeLibs`.
+		if f.transitiveDep && f.module != nil && android.InList(mctx.OtherModuleName(f.module), vctx.unwantedTransitiveDeps) {
+			continue
+		}
 		dest := filepath.Join(f.installDir, f.builtFile.Base())
 		if e, ok := encountered[dest]; !ok {
 			encountered[dest] = f
@@ -2367,10 +2386,6 @@
 	if a.properties.IsCoverageVariant {
 		return false
 	}
-	// TODO(b/263308515) remove this
-	if a.testApex {
-		return false
-	}
 	if ctx.DeviceConfig().DeviceArch() == "" {
 		return false
 	}
@@ -2397,8 +2412,9 @@
 	// TODO(jiyong): do this using WalkPayloadDeps
 	// TODO(jiyong): make this clean!!!
 	vctx := visitorContext{
-		handleSpecialLibs: !android.Bool(a.properties.Ignore_system_library_special_case),
-		checkDuplicate:    a.shouldCheckDuplicate(ctx),
+		handleSpecialLibs:      !android.Bool(a.properties.Ignore_system_library_special_case),
+		checkDuplicate:         a.shouldCheckDuplicate(ctx),
+		unwantedTransitiveDeps: a.properties.Unwanted_transitive_deps,
 	}
 	ctx.WalkDepsBlueprint(func(child, parent blueprint.Module) bool { return a.depVisitor(&vctx, ctx, child, parent) })
 	vctx.normalizeFileInfo(ctx)
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 2bed554..e6581cf 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -7709,6 +7709,42 @@
 		`)
 }
 
+func TestApexUnwantedTransitiveDeps(t *testing.T) {
+	bp := `
+	apex {
+		name: "myapex",
+		key: "myapex.key",
+		native_shared_libs: ["libfoo"],
+		updatable: false,
+		unwanted_transitive_deps: ["libbar"],
+	}
+
+	apex_key {
+		name: "myapex.key",
+		public_key: "testkey.avbpubkey",
+		private_key: "testkey.pem",
+	}
+
+	cc_library {
+		name: "libfoo",
+		srcs: ["foo.cpp"],
+		shared_libs: ["libbar"],
+		apex_available: ["myapex"],
+	}
+
+	cc_library {
+		name: "libbar",
+		srcs: ["bar.cpp"],
+		apex_available: ["myapex"],
+	}`
+	ctx := testApex(t, bp)
+	ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{
+		"*/libc++.so",
+		"*/libfoo.so",
+		// not libbar.so
+	})
+}
+
 func TestRejectNonInstallableJavaLibrary(t *testing.T) {
 	testApexError(t, `"myjar" is not configured to be compiled into dex`, `
 		apex {
@@ -9089,8 +9125,8 @@
 		}
 	`)
 
-	apexKeysText := ctx.SingletonForTests("apex_keys_text")
-	content := apexKeysText.MaybeDescription("apexkeys.txt").BuildParams.Args["content"]
+	myapex := ctx.ModuleForTests("myapex", "android_common_myapex")
+	content := myapex.Output("apexkeys.txt").BuildParams.Args["content"]
 	ensureContains(t, content, `name="myapex.apex" public_key="vendor/foo/devkeys/testkey.avbpubkey" private_key="vendor/foo/devkeys/testkey.pem" container_certificate="vendor/foo/devkeys/test.x509.pem" container_private_key="vendor/foo/devkeys/test.pk8" partition="system" sign_tool="sign_myapex"`)
 }
 
@@ -9130,10 +9166,10 @@
 		}
 	`)
 
-	apexKeysText := ctx.SingletonForTests("apex_keys_text")
-	content := apexKeysText.MaybeDescription("apexkeys.txt").BuildParams.Args["content"]
+	content := ctx.ModuleForTests("myapex", "android_common_myapex").Output("apexkeys.txt").BuildParams.Args["content"]
+	ensureContains(t, content, `name="myapex.apex" public_key="vendor/foo/devkeys/testkey.avbpubkey" private_key="vendor/foo/devkeys/testkey.pem" container_certificate="vendor/foo/devkeys/test.x509.pem" container_private_key="vendor/foo/devkeys/test.pk8" partition="system" sign_tool="sign_myapex"`)
+	content = ctx.ModuleForTests("myapex_set", "android_common_myapex_set").Output("apexkeys.txt").BuildParams.Args["content"]
 	ensureContains(t, content, `name="myapex_set.apex" public_key="PRESIGNED" private_key="PRESIGNED" container_certificate="PRESIGNED" container_private_key="PRESIGNED" partition="system"`)
-	ensureContains(t, content, `name="myapex.apex" public_key="PRESIGNED" private_key="PRESIGNED" container_certificate="PRESIGNED" container_private_key="PRESIGNED" partition="system"`)
 }
 
 func TestAllowedFiles(t *testing.T) {
diff --git a/apex/builder.go b/apex/builder.go
index 729917f..d75cc1d 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -948,6 +948,8 @@
 
 	// installed-files.txt is dist'ed
 	a.installedFilesFile = a.buildInstalledFilesFile(ctx, a.outputFile, imageDir)
+
+	a.apexKeysPath = writeApexKeys(ctx, a)
 }
 
 // getCertificateAndPrivateKey retrieves the cert and the private key that will be used to sign
diff --git a/apex/key.go b/apex/key.go
index fc1456b..2405e98 100644
--- a/apex/key.go
+++ b/apex/key.go
@@ -16,8 +16,6 @@
 
 import (
 	"fmt"
-	"sort"
-	"strings"
 
 	"android/soong/android"
 	"android/soong/bazel"
@@ -33,7 +31,6 @@
 
 func registerApexKeyBuildComponents(ctx android.RegistrationContext) {
 	ctx.RegisterModuleType("apex_key", ApexKeyFactory)
-	ctx.RegisterParallelSingletonType("apex_keys_text", apexKeysTextFactory)
 }
 
 type apexKey struct {
@@ -102,99 +99,65 @@
 	}
 }
 
-// //////////////////////////////////////////////////////////////////////
-// apex_keys_text
-type apexKeysText struct {
-	output android.OutputPath
+type apexKeyEntry struct {
+	name                 string
+	presigned            bool
+	publicKey            string
+	privateKey           string
+	containerCertificate string
+	containerPrivateKey  string
+	partition            string
+	signTool             string
 }
 
-func (s *apexKeysText) GenerateBuildActions(ctx android.SingletonContext) {
-	s.output = android.PathForOutput(ctx, "apexkeys.txt")
-	type apexKeyEntry struct {
-		name                 string
-		presigned            bool
-		publicKey            string
-		privateKey           string
-		containerCertificate string
-		containerPrivateKey  string
-		partition            string
-		signTool             string
+func (e apexKeyEntry) String() string {
+	signTool := ""
+	if e.signTool != "" {
+		signTool = fmt.Sprintf(" sign_tool=%q", e.signTool)
 	}
-	toString := func(e apexKeyEntry) string {
-		signTool := ""
-		if e.signTool != "" {
-			signTool = fmt.Sprintf(" sign_tool=%q", e.signTool)
-		}
-		format := "name=%q public_key=%q private_key=%q container_certificate=%q container_private_key=%q partition=%q%s\n"
-		if e.presigned {
-			return fmt.Sprintf(format, e.name, "PRESIGNED", "PRESIGNED", "PRESIGNED", "PRESIGNED", e.partition, signTool)
-		} else {
-			return fmt.Sprintf(format, e.name, e.publicKey, e.privateKey, e.containerCertificate, e.containerPrivateKey, e.partition, signTool)
-		}
+	format := "name=%q public_key=%q private_key=%q container_certificate=%q container_private_key=%q partition=%q%s\n"
+	if e.presigned {
+		return fmt.Sprintf(format, e.name, "PRESIGNED", "PRESIGNED", "PRESIGNED", "PRESIGNED", e.partition, signTool)
+	} else {
+		return fmt.Sprintf(format, e.name, e.publicKey, e.privateKey, e.containerCertificate, e.containerPrivateKey, e.partition, signTool)
 	}
-
-	apexKeyMap := make(map[string]apexKeyEntry)
-	ctx.VisitAllModules(func(module android.Module) {
-		if m, ok := module.(*apexBundle); ok && m.Enabled() && m.installable() {
-			pem, key := m.getCertificateAndPrivateKey(ctx)
-			apexKeyMap[m.Name()] = apexKeyEntry{
-				name:                 m.Name() + ".apex",
-				presigned:            false,
-				publicKey:            m.publicKeyFile.String(),
-				privateKey:           m.privateKeyFile.String(),
-				containerCertificate: pem.String(),
-				containerPrivateKey:  key.String(),
-				partition:            m.PartitionTag(ctx.DeviceConfig()),
-				signTool:             proptools.String(m.properties.Custom_sign_tool),
-			}
-		}
-	})
-
-	// Find prebuilts and let them override apexBundle if they are preferred
-	ctx.VisitAllModules(func(module android.Module) {
-		if m, ok := module.(*Prebuilt); ok && m.Enabled() && m.installable() &&
-			m.Prebuilt().UsePrebuilt() {
-			apexKeyMap[m.BaseModuleName()] = apexKeyEntry{
-				name:      m.InstallFilename(),
-				presigned: true,
-				partition: m.PartitionTag(ctx.DeviceConfig()),
-			}
-		}
-	})
-
-	// Find apex_set and let them override apexBundle or prebuilts. This is done in a separate pass
-	// so that apex_set are not overridden by prebuilts.
-	ctx.VisitAllModules(func(module android.Module) {
-		if m, ok := module.(*ApexSet); ok && m.Enabled() {
-			entry := apexKeyEntry{
-				name:      m.InstallFilename(),
-				presigned: true,
-				partition: m.PartitionTag(ctx.DeviceConfig()),
-			}
-			apexKeyMap[m.BaseModuleName()] = entry
-		}
-	})
-
-	// iterating over map does not give consistent ordering in golang
-	var moduleNames []string
-	for key, _ := range apexKeyMap {
-		moduleNames = append(moduleNames, key)
-	}
-	sort.Strings(moduleNames)
-
-	var filecontent strings.Builder
-	for _, name := range moduleNames {
-		filecontent.WriteString(toString(apexKeyMap[name]))
-	}
-	android.WriteFileRule(ctx, s.output, filecontent.String())
 }
 
-func apexKeysTextFactory() android.Singleton {
-	return &apexKeysText{}
+func apexKeyEntryFor(ctx android.ModuleContext, module android.Module) apexKeyEntry {
+	switch m := module.(type) {
+	case *apexBundle:
+		pem, key := m.getCertificateAndPrivateKey(ctx)
+		return apexKeyEntry{
+			name:                 m.Name() + ".apex",
+			presigned:            false,
+			publicKey:            m.publicKeyFile.String(),
+			privateKey:           m.privateKeyFile.String(),
+			containerCertificate: pem.String(),
+			containerPrivateKey:  key.String(),
+			partition:            m.PartitionTag(ctx.DeviceConfig()),
+			signTool:             proptools.String(m.properties.Custom_sign_tool),
+		}
+	case *Prebuilt:
+		return apexKeyEntry{
+			name:      m.InstallFilename(),
+			presigned: true,
+			partition: m.PartitionTag(ctx.DeviceConfig()),
+		}
+	case *ApexSet:
+		return apexKeyEntry{
+			name:      m.InstallFilename(),
+			presigned: true,
+			partition: m.PartitionTag(ctx.DeviceConfig()),
+		}
+	}
+	panic(fmt.Errorf("unknown type(%t) for apexKeyEntry", module))
 }
 
-func (s *apexKeysText) MakeVars(ctx android.MakeVarsContext) {
-	ctx.Strict("SOONG_APEX_KEYS_FILE", s.output.String())
+func writeApexKeys(ctx android.ModuleContext, module android.Module) android.WritablePath {
+	path := android.PathForModuleOut(ctx, "apexkeys.txt")
+	entry := apexKeyEntryFor(ctx, module)
+	android.WriteFileRuleVerbatim(ctx, path, entry.String())
+	return path
 }
 
 // For Bazel / bp2build
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index 1a90c3a..7a9d23e 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -60,6 +60,9 @@
 	installedFile   android.InstallPath
 	outputApex      android.WritablePath
 
+	// fragment for this apex for apexkeys.txt
+	apexKeysPath android.WritablePath
+
 	// A list of apexFile objects created in prebuiltCommon.initApexFilesForAndroidMk which are used
 	// to create make modules in prebuiltCommon.AndroidMkEntries.
 	apexFilesForAndroidMk []apexFile
@@ -238,6 +241,7 @@
 					entries.AddStrings("LOCAL_SOONG_INSTALL_SYMLINKS", p.compatSymlinks.Strings()...)
 					entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", !p.installable())
 					entries.AddStrings("LOCAL_OVERRIDES_MODULES", p.prebuiltCommonProperties.Overrides...)
+					entries.SetString("LOCAL_APEX_KEY_PATH", p.apexKeysPath.String())
 					p.addRequiredModules(entries)
 				},
 			},
@@ -759,6 +763,7 @@
 }
 
 func (p *Prebuilt) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	p.apexKeysPath = writeApexKeys(ctx, p)
 	// TODO(jungjw): Check the key validity.
 	p.inputApex = android.OptionalPathForModuleSrc(ctx, p.prebuiltCommonProperties.Selected_apex).Path()
 	p.installDir = android.PathForModuleInstall(ctx, "apex")
@@ -975,6 +980,7 @@
 }
 
 func (a *ApexSet) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	a.apexKeysPath = writeApexKeys(ctx, a)
 	a.installFilename = a.InstallFilename()
 	if !strings.HasSuffix(a.installFilename, imageApexSuffix) && !strings.HasSuffix(a.installFilename, imageCapexSuffix) {
 		ctx.ModuleErrorf("filename should end in %s or %s for apex_set", imageApexSuffix, imageCapexSuffix)
diff --git a/cc/builder.go b/cc/builder.go
index f5e0dcc..3f582fa 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -534,7 +534,7 @@
 		toolingCppflags += " ${config.NoOverride64GlobalCflags}"
 	}
 
-	modulePath := android.PathForModuleSrc(ctx).String()
+	modulePath := ctx.ModuleDir()
 	if android.IsThirdPartyPath(modulePath) {
 		cflags += " ${config.NoOverrideExternalGlobalCflags}"
 		toolingCflags += " ${config.NoOverrideExternalGlobalCflags}"
@@ -875,7 +875,8 @@
 // into a single .ldump sAbi dump file
 func transformDumpToLinkedDump(ctx android.ModuleContext, sAbiDumps android.Paths, soFile android.Path,
 	baseName, exportedHeaderFlags string, symbolFile android.OptionalPath,
-	excludedSymbolVersions, excludedSymbolTags []string) android.OptionalPath {
+	excludedSymbolVersions, excludedSymbolTags []string,
+	api string) android.OptionalPath {
 
 	outputFile := android.PathForModuleOut(ctx, baseName+".lsdump")
 
@@ -892,6 +893,11 @@
 	for _, tag := range excludedSymbolTags {
 		symbolFilterStr += " --exclude-symbol-tag " + tag
 	}
+	apiLevelsJson := android.GetApiLevelsJson(ctx)
+	implicits = append(implicits, apiLevelsJson)
+	symbolFilterStr += " --api-map " + apiLevelsJson.String()
+	symbolFilterStr += " --api " + api
+
 	rule := sAbiLink
 	args := map[string]string{
 		"symbolFilter":        symbolFilterStr,
diff --git a/cc/compiler.go b/cc/compiler.go
index 5bed8a7..490d3cc 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -339,7 +339,7 @@
 // per-target values, module type values, and per-module Blueprints properties
 func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps PathDeps) Flags {
 	tc := ctx.toolchain()
-	modulePath := android.PathForModuleSrc(ctx).String()
+	modulePath := ctx.ModuleDir()
 
 	compiler.srcsBeforeGen = android.PathsForModuleSrcExcludes(ctx, compiler.Properties.Srcs, compiler.Properties.Exclude_srcs)
 	compiler.srcsBeforeGen = append(compiler.srcsBeforeGen, deps.GeneratedSources...)
diff --git a/cc/library.go b/cc/library.go
index 1807bbf..d22bcec 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -1904,17 +1904,19 @@
 		}
 		exportedHeaderFlags := strings.Join(SourceAbiFlags, " ")
 		headerAbiChecker := library.getHeaderAbiCheckerProperties(ctx)
-		library.sAbiOutputFile = transformDumpToLinkedDump(ctx, objs.sAbiDumpFiles, soFile, fileName, exportedHeaderFlags,
-			android.OptionalPathForModuleSrc(ctx, library.symbolFileForAbiCheck(ctx)),
-			headerAbiChecker.Exclude_symbol_versions,
-			headerAbiChecker.Exclude_symbol_tags)
-
-		addLsdumpPath(classifySourceAbiDump(ctx) + ":" + library.sAbiOutputFile.String())
-
 		// The logic must be consistent with classifySourceAbiDump.
 		isVndk := ctx.useVndk() && ctx.isVndk()
 		isNdk := ctx.isNdk(ctx.Config())
 		isLlndk := ctx.isImplementationForLLNDKPublic()
+		currVersion := currRefAbiDumpVersion(ctx, isVndk)
+		library.sAbiOutputFile = transformDumpToLinkedDump(ctx, objs.sAbiDumpFiles, soFile, fileName, exportedHeaderFlags,
+			android.OptionalPathForModuleSrc(ctx, library.symbolFileForAbiCheck(ctx)),
+			headerAbiChecker.Exclude_symbol_versions,
+			headerAbiChecker.Exclude_symbol_tags,
+			currVersion)
+
+		addLsdumpPath(classifySourceAbiDump(ctx) + ":" + library.sAbiOutputFile.String())
+
 		dumpDir := getRefAbiDumpDir(isNdk, isVndk)
 		binderBitness := ctx.DeviceConfig().BinderBitness()
 		// If NDK or PLATFORM library, check against previous version ABI.
@@ -1930,7 +1932,6 @@
 			}
 		}
 		// Check against the current version.
-		currVersion := currRefAbiDumpVersion(ctx, isVndk)
 		currDumpDir := filepath.Join(dumpDir, currVersion, binderBitness)
 		currDumpFile := getRefAbiDumpFile(ctx, currDumpDir, fileName)
 		if currDumpFile.Valid() {
diff --git a/cc/lto.go b/cc/lto.go
index d48be14..20e4f24 100644
--- a/cc/lto.go
+++ b/cc/lto.go
@@ -147,6 +147,12 @@
 			}
 		}
 
+		// For ML training
+		if ctx.Config().IsEnvTrue("THINLTO_EMIT_INDEXES_AND_IMPORTS") {
+			ltoLdFlags = append(ltoLdFlags, "-Wl,--save-temps=import")
+			ltoLdFlags = append(ltoLdFlags, "-Wl,--thinlto-emit-index-files")
+		}
+
 		flags.Local.CFlags = append(flags.Local.CFlags, ltoCFlags...)
 		flags.Local.AsFlags = append(flags.Local.AsFlags, ltoCFlags...)
 		flags.Local.LdFlags = append(flags.Local.LdFlags, ltoCFlags...)
diff --git a/cmd/merge_zips/merge_zips.go b/cmd/merge_zips/merge_zips.go
index a70a9d1..1aa6f6f 100644
--- a/cmd/merge_zips/merge_zips.go
+++ b/cmd/merge_zips/merge_zips.go
@@ -96,7 +96,9 @@
 	if err := ze.inputZip.Open(); err != nil {
 		return err
 	}
-	return zw.CopyFrom(ze.inputZip.Entries()[ze.index], dest)
+	entry := ze.inputZip.Entries()[ze.index]
+	entry.SetModTime(jar.DefaultTime)
+	return zw.CopyFrom(entry, dest)
 }
 
 // a ZipEntryFromBuffer is a ZipEntryContents that pulls its content from a []byte
diff --git a/cmd/merge_zips/merge_zips_test.go b/cmd/merge_zips/merge_zips_test.go
index 767d4e61..64b08d0 100644
--- a/cmd/merge_zips/merge_zips_test.go
+++ b/cmd/merge_zips/merge_zips_test.go
@@ -22,40 +22,45 @@
 	"strconv"
 	"strings"
 	"testing"
+	"time"
 
 	"android/soong/jar"
 	"android/soong/third_party/zip"
 )
 
 type testZipEntry struct {
-	name   string
-	mode   os.FileMode
-	data   []byte
-	method uint16
+	name      string
+	mode      os.FileMode
+	data      []byte
+	method    uint16
+	timestamp time.Time
 }
 
 var (
-	A     = testZipEntry{"A", 0755, []byte("foo"), zip.Deflate}
-	a     = testZipEntry{"a", 0755, []byte("foo"), zip.Deflate}
-	a2    = testZipEntry{"a", 0755, []byte("FOO2"), zip.Deflate}
-	a3    = testZipEntry{"a", 0755, []byte("Foo3"), zip.Deflate}
-	bDir  = testZipEntry{"b/", os.ModeDir | 0755, nil, zip.Deflate}
-	bbDir = testZipEntry{"b/b/", os.ModeDir | 0755, nil, zip.Deflate}
-	bbb   = testZipEntry{"b/b/b", 0755, nil, zip.Deflate}
-	ba    = testZipEntry{"b/a", 0755, []byte("foo"), zip.Deflate}
-	bc    = testZipEntry{"b/c", 0755, []byte("bar"), zip.Deflate}
-	bd    = testZipEntry{"b/d", 0700, []byte("baz"), zip.Deflate}
-	be    = testZipEntry{"b/e", 0700, []byte(""), zip.Deflate}
+	A     = testZipEntry{"A", 0755, []byte("foo"), zip.Deflate, jar.DefaultTime}
+	a     = testZipEntry{"a", 0755, []byte("foo"), zip.Deflate, jar.DefaultTime}
+	a2    = testZipEntry{"a", 0755, []byte("FOO2"), zip.Deflate, jar.DefaultTime}
+	a3    = testZipEntry{"a", 0755, []byte("Foo3"), zip.Deflate, jar.DefaultTime}
+	bDir  = testZipEntry{"b/", os.ModeDir | 0755, nil, zip.Deflate, jar.DefaultTime}
+	bbDir = testZipEntry{"b/b/", os.ModeDir | 0755, nil, zip.Deflate, jar.DefaultTime}
+	bbb   = testZipEntry{"b/b/b", 0755, nil, zip.Deflate, jar.DefaultTime}
+	ba    = testZipEntry{"b/a", 0755, []byte("foo"), zip.Deflate, jar.DefaultTime}
+	bc    = testZipEntry{"b/c", 0755, []byte("bar"), zip.Deflate, jar.DefaultTime}
+	bd    = testZipEntry{"b/d", 0700, []byte("baz"), zip.Deflate, jar.DefaultTime}
+	be    = testZipEntry{"b/e", 0700, []byte(""), zip.Deflate, jar.DefaultTime}
 
-	service1a        = testZipEntry{"META-INF/services/service1", 0755, []byte("class1\nclass2\n"), zip.Store}
-	service1b        = testZipEntry{"META-INF/services/service1", 0755, []byte("class1\nclass3\n"), zip.Deflate}
-	service1combined = testZipEntry{"META-INF/services/service1", 0755, []byte("class1\nclass2\nclass3\n"), zip.Store}
-	service2         = testZipEntry{"META-INF/services/service2", 0755, []byte("class1\nclass2\n"), zip.Deflate}
+	withTimestamp    = testZipEntry{"timestamped", 0755, nil, zip.Store, jar.DefaultTime.Add(time.Hour)}
+	withoutTimestamp = testZipEntry{"timestamped", 0755, nil, zip.Store, jar.DefaultTime}
 
-	metainfDir     = testZipEntry{jar.MetaDir, os.ModeDir | 0755, nil, zip.Deflate}
-	manifestFile   = testZipEntry{jar.ManifestFile, 0755, []byte("manifest"), zip.Deflate}
-	manifestFile2  = testZipEntry{jar.ManifestFile, 0755, []byte("manifest2"), zip.Deflate}
-	moduleInfoFile = testZipEntry{jar.ModuleInfoClass, 0755, []byte("module-info"), zip.Deflate}
+	service1a        = testZipEntry{"META-INF/services/service1", 0755, []byte("class1\nclass2\n"), zip.Store, jar.DefaultTime}
+	service1b        = testZipEntry{"META-INF/services/service1", 0755, []byte("class1\nclass3\n"), zip.Deflate, jar.DefaultTime}
+	service1combined = testZipEntry{"META-INF/services/service1", 0755, []byte("class1\nclass2\nclass3\n"), zip.Store, jar.DefaultTime}
+	service2         = testZipEntry{"META-INF/services/service2", 0755, []byte("class1\nclass2\n"), zip.Deflate, jar.DefaultTime}
+
+	metainfDir     = testZipEntry{jar.MetaDir, os.ModeDir | 0755, nil, zip.Deflate, jar.DefaultTime}
+	manifestFile   = testZipEntry{jar.ManifestFile, 0755, []byte("manifest"), zip.Deflate, jar.DefaultTime}
+	manifestFile2  = testZipEntry{jar.ManifestFile, 0755, []byte("manifest2"), zip.Deflate, jar.DefaultTime}
+	moduleInfoFile = testZipEntry{jar.ModuleInfoClass, 0755, []byte("module-info"), zip.Deflate, jar.DefaultTime}
 )
 
 type testInputZip struct {
@@ -252,6 +257,14 @@
 			jar: true,
 			out: []testZipEntry{service1combined, service2},
 		},
+		{
+			name: "strip timestamps",
+			in: [][]testZipEntry{
+				{withTimestamp},
+				{a},
+			},
+			out: []testZipEntry{withoutTimestamp, a},
+		},
 	}
 
 	for _, test := range testCases {
@@ -307,6 +320,7 @@
 		}
 		fh.SetMode(e.mode)
 		fh.Method = e.method
+		fh.SetModTime(e.timestamp)
 		fh.UncompressedSize64 = uint64(len(e.data))
 		fh.CRC32 = crc32.ChecksumIEEE(e.data)
 		if fh.Method == zip.Store {
@@ -354,7 +368,7 @@
 	var ret string
 
 	for _, f := range zr.File {
-		ret += fmt.Sprintf("%v: %v %v %08x\n", f.Name, f.Mode(), f.UncompressedSize64, f.CRC32)
+		ret += fmt.Sprintf("%v: %v %v %08x %s\n", f.Name, f.Mode(), f.UncompressedSize64, f.CRC32, f.ModTime())
 	}
 
 	return ret
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index d20847b..568a6f8 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -422,6 +422,7 @@
 	metricsDir := availableEnv["LOG_DIR"]
 
 	ctx := newContext(configuration)
+	android.StartBackgroundMetrics(configuration)
 
 	var finalOutputFile string
 
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index 3b8f4f5..18cba77 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -91,14 +91,6 @@
 		config:      buildActionConfig,
 		stdio:       stdio,
 		run:         runMake,
-	}, {
-		flag:        "--finalize-bazel-metrics",
-		description: "finalize b metrics and upload",
-		config:      build.UploadOnlyConfig,
-		stdio:       stdio,
-		// Finalize-bazel-metrics mode updates metrics files and calls the metrics
-		// uploader. This marks the end of a b invocation.
-		run: finalizeBazelMetrics,
 	},
 }
 
@@ -199,7 +191,6 @@
 	soongMetricsFile := filepath.Join(logsDir, c.logsPrefix+"soong_metrics")
 	rbeMetricsFile := filepath.Join(logsDir, c.logsPrefix+"rbe_metrics.pb")
 	bp2buildMetricsFile := filepath.Join(logsDir, c.logsPrefix+"bp2build_metrics.pb")
-	bazelMetricsFile := filepath.Join(logsDir, c.logsPrefix+"bazel_metrics.pb")
 	soongBuildMetricsFile := filepath.Join(logsDir, c.logsPrefix+"soong_build_metrics.pb")
 
 	metricsFiles := []string{
@@ -207,7 +198,6 @@
 		rbeMetricsFile,           // high level metrics related to remote build execution.
 		bp2buildMetricsFile,      // high level metrics related to bp2build.
 		soongMetricsFile,         // high level metrics related to this build system.
-		bazelMetricsFile,         // high level metrics related to bazel execution
 		soongBuildMetricsFile,    // high level metrics related to soong build(except bp2build)
 		config.BazelMetricsDir(), // directory that contains a set of bazel metrics.
 	}
@@ -247,10 +237,9 @@
 	soongMetricsFile := filepath.Join(logsDir, logsPrefix+"soong_metrics")
 	bp2buildMetricsFile := filepath.Join(logsDir, logsPrefix+"bp2build_metrics.pb")
 	soongBuildMetricsFile := filepath.Join(logsDir, logsPrefix+"soong_build_metrics.pb")
-	bazelMetricsFile := filepath.Join(logsDir, logsPrefix+"bazel_metrics.pb")
 
 	//Delete the stale metrics files
-	staleFileSlice := []string{buildErrorFile, rbeMetricsFile, soongMetricsFile, bp2buildMetricsFile, soongBuildMetricsFile, bazelMetricsFile}
+	staleFileSlice := []string{buildErrorFile, rbeMetricsFile, soongMetricsFile, bp2buildMetricsFile, soongBuildMetricsFile}
 	if err := deleteStaleMetrics(staleFileSlice); err != nil {
 		log.Fatalln(err)
 	}
@@ -701,28 +690,3 @@
 		ctx.Println("Failed to increase file limit:", err)
 	}
 }
-
-func finalizeBazelMetrics(ctx build.Context, config build.Config, args []string) {
-	updateTotalRealTime(ctx, config, args)
-
-	logsDir := config.LogsDir()
-	logsPrefix := config.GetLogsPrefix()
-	bazelMetricsFile := filepath.Join(logsDir, logsPrefix+"bazel_metrics.pb")
-	bazelProfileFile := filepath.Join(logsDir, logsPrefix+"analyzed_bazel_profile.txt")
-	build.ProcessBazelMetrics(bazelProfileFile, bazelMetricsFile, ctx, config)
-}
-func updateTotalRealTime(ctx build.Context, config build.Config, args []string) {
-	soongMetricsFile := filepath.Join(config.LogsDir(), "soong_metrics")
-
-	//read file into proto
-	data, err := os.ReadFile(soongMetricsFile)
-	if err != nil {
-		ctx.Fatal(err)
-	}
-	met := ctx.ContextImpl.Metrics
-
-	err = met.UpdateTotalRealTimeAndNonZeroExit(data, config.BazelExitCode())
-	if err != nil {
-		ctx.Fatal(err)
-	}
-}
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index 685571d..275d9c3 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -65,6 +65,7 @@
 	ctx.RegisterModuleType("prebuilt_firmware", PrebuiltFirmwareFactory)
 	ctx.RegisterModuleType("prebuilt_dsp", PrebuiltDSPFactory)
 	ctx.RegisterModuleType("prebuilt_rfsa", PrebuiltRFSAFactory)
+	ctx.RegisterModuleType("prebuilt_renderscript_bitcode", PrebuiltRenderScriptBitcodeFactory)
 
 	ctx.RegisterModuleType("prebuilt_defaults", defaultsFactory)
 
@@ -149,12 +150,15 @@
 	sourceFilePath android.Path
 	outputFilePath android.OutputPath
 	// The base install location, e.g. "etc" for prebuilt_etc, "usr/share" for prebuilt_usr_share.
-	installDirBase string
+	installDirBase   string
+	installDirBase64 string
 	// The base install location when soc_specific property is set to true, e.g. "firmware" for
 	// prebuilt_firmware.
 	socInstallDirBase      string
 	installDirPath         android.InstallPath
 	additionalDependencies *android.Paths
+
+	makeClass string
 }
 
 type Defaults struct {
@@ -345,6 +349,9 @@
 	// If soc install dir was specified and SOC specific is set, set the installDirPath to the
 	// specified socInstallDirBase.
 	installBaseDir := p.installDirBase
+	if p.Target().Arch.ArchType.Multilib == "lib64" && p.installDirBase64 != "" {
+		installBaseDir = p.installDirBase64
+	}
 	if p.SocSpecific() && p.socInstallDirBase != "" {
 		installBaseDir = p.socInstallDirBase
 	}
@@ -404,8 +411,14 @@
 	if p.InRecovery() && !p.onlyInRecovery() {
 		nameSuffix = ".recovery"
 	}
+
+	class := p.makeClass
+	if class == "" {
+		class = "ETC"
+	}
+
 	return []android.AndroidMkEntries{android.AndroidMkEntries{
-		Class:      "ETC",
+		Class:      class,
 		SubName:    nameSuffix,
 		OutputFile: android.OptionalPathForPath(p.outputFilePath),
 		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
@@ -572,6 +585,18 @@
 	return module
 }
 
+// prebuilt_renderscript_bitcode installs a *.bc file into /system/lib or /system/lib64.
+func PrebuiltRenderScriptBitcodeFactory() android.Module {
+	module := &PrebuiltEtc{}
+	module.makeClass = "RENDERSCRIPT_BITCODE"
+	module.installDirBase64 = "lib64"
+	InitPrebuiltEtcModule(module, "lib")
+	// This module is device-only
+	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibBoth)
+	android.InitDefaultableModule(module)
+	return module
+}
+
 // prebuilt_rfsa installs a firmware file that will be available through Qualcomm's RFSA
 // to the <partition>/lib/rfsa directory.
 func PrebuiltRFSAFactory() android.Module {
diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go
index 023c69a..f2efd46 100644
--- a/filesystem/filesystem.go
+++ b/filesystem/filesystem.go
@@ -104,6 +104,9 @@
 	// When set, passed to mkuserimg_mke2fs --mke2fs_uuid & --mke2fs_hash_seed.
 	// Otherwise, they'll be set as random which might cause indeterministic build output.
 	Uuid *string
+
+	// Mount point for this image. Default is "/"
+	Mount_point *string
 }
 
 // android_filesystem packages a set of modules and their transitive dependencies into a filesystem
@@ -332,7 +335,7 @@
 	}
 
 	addStr("fs_type", fsTypeStr(f.fsType(ctx)))
-	addStr("mount_point", "/")
+	addStr("mount_point", proptools.StringDefault(f.properties.Mount_point, "/"))
 	addStr("use_dynamic_partition_size", "true")
 	addPath("ext_mkuserimg", ctx.Config().HostToolPath(ctx, "mkuserimg_mke2fs"))
 	// b/177813163 deps of the host tools have to be added. Remove this.
diff --git a/genrule/allowlists.go b/genrule/allowlists.go
index ea6be90..f9da61a 100644
--- a/genrule/allowlists.go
+++ b/genrule/allowlists.go
@@ -51,8 +51,6 @@
 
 	SandboxingDenyModuleList = []string{
 		// go/keep-sorted start
-		"AudioFocusControlProtoStub_cc",
-		"AudioFocusControlProtoStub_h",
 		"CompilationTestCases_package-dex-usage",
 		"ControlEnvProxyServerProto_cc",
 		"ControlEnvProxyServerProto_h",
@@ -76,12 +74,6 @@
 		"ScriptGroupTest-rscript",
 		"TracingVMProtoStub_cc",
 		"TracingVMProtoStub_h",
-		"UpdatableSystemFontTest_NotoColorEmojiV0.sig",
-		"UpdatableSystemFontTest_NotoColorEmojiV0.ttf",
-		"UpdatableSystemFontTest_NotoColorEmojiVPlus1.sig",
-		"UpdatableSystemFontTest_NotoColorEmojiVPlus1.ttf",
-		"UpdatableSystemFontTest_NotoColorEmojiVPlus2.sig",
-		"UpdatableSystemFontTest_NotoColorEmojiVPlus2.ttf",
 		"VehicleServerProtoStub_cc",
 		"VehicleServerProtoStub_cc@2.0-grpc-trout",
 		"VehicleServerProtoStub_cc@default-grpc",
@@ -104,12 +96,6 @@
 		"camera-its",
 		"checkIn-service-stub-lite",
 		"chre_atoms_log.h",
-		"com.android.apex.test.bar_stripped",
-		"com.android.apex.test.baz_stripped",
-		"com.android.apex.test.foo_stripped",
-		"com.android.apex.test.pony_stripped",
-		"com.android.apex.test.sharedlibs_generated",
-		"com.android.apex.test.sharedlibs_secondary_generated",
 		"common-profile-text-protos",
 		"core-tests-smali-dex",
 		"cronet_aml_base_android_runtime_jni_headers",
diff --git a/java/aar.go b/java/aar.go
index 479b5e0..6b89129 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -134,6 +134,10 @@
 	resourcesNodesDepSet *android.DepSet[*resourcesNode]
 	rroDirsDepSet        *android.DepSet[rroDir]
 	manifestsDepSet      *android.DepSet[android.Path]
+
+	manifestValues struct {
+		applicationId string
+	}
 }
 
 type split struct {
@@ -380,7 +384,9 @@
 	if len(transitiveManifestPaths) > 1 && !Bool(a.aaptProperties.Dont_merge_manifests) {
 		manifestMergerParams := ManifestMergerParams{
 			staticLibManifests: transitiveManifestPaths[1:],
-			isLibrary:          a.isLibrary}
+			isLibrary:          a.isLibrary,
+			packageName:        a.manifestValues.applicationId,
+		}
 		a.mergedManifestFile = manifestMerger(ctx, transitiveManifestPaths[0], manifestMergerParams)
 		if !a.isLibrary {
 			// Only use the merged manifest for applications.  For libraries, the transitive closure of manifests
@@ -805,8 +811,11 @@
 	a.linter.manifest = a.aapt.manifestPath
 	a.linter.resources = a.aapt.resourceFiles
 
-	a.Module.extraProguardFlagFiles = append(a.Module.extraProguardFlagFiles,
-		a.proguardOptionsFile)
+	proguardSpecInfo := a.collectProguardSpecInfo(ctx)
+	ctx.SetProvider(ProguardSpecInfoProvider, proguardSpecInfo)
+	a.exportedProguardFlagFiles = proguardSpecInfo.ProguardFlagsFiles.ToList()
+	a.extraProguardFlagFiles = append(a.extraProguardFlagFiles, a.exportedProguardFlagFiles...)
+	a.extraProguardFlagFiles = append(a.extraProguardFlagFiles, a.proguardOptionsFile)
 
 	var extraSrcJars android.Paths
 	var extraCombinedJars android.Paths
@@ -832,10 +841,6 @@
 		ctx.CheckbuildFile(a.aarFile)
 	}
 
-	proguardSpecInfo := a.collectProguardSpecInfo(ctx)
-	ctx.SetProvider(ProguardSpecInfoProvider, proguardSpecInfo)
-	a.exportedProguardFlagFiles = proguardSpecInfo.ProguardFlagsFiles.ToList()
-
 	prebuiltJniPackages := android.Paths{}
 	ctx.VisitDirectDeps(func(module android.Module) {
 		if info, ok := ctx.OtherModuleProvider(module, JniPackageProvider).(JniPackageInfo); ok {
diff --git a/java/android_manifest.go b/java/android_manifest.go
index a39c002..082b00e 100644
--- a/java/android_manifest.go
+++ b/java/android_manifest.go
@@ -203,15 +203,21 @@
 type ManifestMergerParams struct {
 	staticLibManifests android.Paths
 	isLibrary          bool
+	packageName        string
 }
 
 func manifestMerger(ctx android.ModuleContext, manifest android.Path,
 	params ManifestMergerParams) android.Path {
 
-	var args string
+	var args []string
 	if !params.isLibrary {
 		// Follow Gradle's behavior, only pass --remove-tools-declarations when merging app manifests.
-		args = "--remove-tools-declarations"
+		args = append(args, "--remove-tools-declarations")
+	}
+
+	packageName := params.packageName
+	if packageName != "" {
+		args = append(args, "--property PACKAGE="+packageName)
 	}
 
 	mergedManifest := android.PathForModuleOut(ctx, "manifest_merger", "AndroidManifest.xml")
@@ -223,7 +229,7 @@
 		Output:      mergedManifest,
 		Args: map[string]string{
 			"libs": android.JoinWithPrefix(params.staticLibManifests.Strings(), "--libs "),
-			"args": args,
+			"args": strings.Join(args, " "),
 		},
 	})
 
diff --git a/java/android_manifest_test.go b/java/android_manifest_test.go
index b12d778..5909b1e 100644
--- a/java/android_manifest_test.go
+++ b/java/android_manifest_test.go
@@ -15,8 +15,9 @@
 package java
 
 import (
-	"android/soong/android"
 	"testing"
+
+	"android/soong/android"
 )
 
 func TestManifestMerger(t *testing.T) {
@@ -77,10 +78,7 @@
 		}
 	`
 
-	result := android.GroupFixturePreparers(
-		PrepareForTestWithJavaDefaultModules,
-		PrepareForTestWithOverlayBuildComponents,
-	).RunTestWithBp(t, bp)
+	result := PrepareForTestWithJavaDefaultModules.RunTestWithBp(t, bp)
 
 	manifestMergerRule := result.ModuleForTests("app", "android_common").Rule("manifestMerger")
 	android.AssertPathRelativeToTopEquals(t, "main manifest",
@@ -101,3 +99,38 @@
 		},
 		manifestMergerRule.Implicits)
 }
+
+func TestManifestValuesApplicationIdSetsPackageName(t *testing.T) {
+	bp := `
+		android_test {
+			name: "test",
+			sdk_version: "current",
+			srcs: ["app/app.java"],
+			manifest: "test/AndroidManifest.xml",
+			additional_manifests: ["test/AndroidManifest2.xml"],
+			static_libs: ["direct"],
+      test_suites: ["device-tests"],
+      manifest_values:  {
+        applicationId: "new_package_name"
+      },
+		}
+
+		android_library {
+			name: "direct",
+			sdk_version: "current",
+			srcs: ["direct/direct.java"],
+			resource_dirs: ["direct/res"],
+			manifest: "direct/AndroidManifest.xml",
+			additional_manifests: ["direct/AndroidManifest2.xml"],
+		}
+
+	`
+
+	result := PrepareForTestWithJavaDefaultModules.RunTestWithBp(t, bp)
+
+	manifestMergerRule := result.ModuleForTests("test", "android_common").Rule("manifestMerger")
+	android.AssertStringMatches(t,
+		"manifest merger args",
+		manifestMergerRule.Args["args"],
+		"--property PACKAGE=new_package_name")
+}
diff --git a/java/android_resources.go b/java/android_resources.go
index 8c5908f..038a260 100644
--- a/java/android_resources.go
+++ b/java/android_resources.go
@@ -21,14 +21,6 @@
 	"android/soong/android"
 )
 
-func init() {
-	registerOverlayBuildComponents(android.InitRegistrationContext)
-}
-
-func registerOverlayBuildComponents(ctx android.RegistrationContext) {
-	ctx.RegisterPreSingletonType("overlay", OverlaySingletonFactory)
-}
-
 var androidResourceIgnoreFilenames = []string{
 	".svn",
 	".git",
@@ -84,7 +76,38 @@
 func overlayResourceGlob(ctx android.ModuleContext, a *aapt, dir android.Path) (res []globbedResourceDir,
 	rroDirs []rroDir) {
 
-	overlayData := ctx.Config().Get(overlayDataKey).([]overlayGlobResult)
+	overlayData := ctx.Config().Once(overlayDataKey, func() interface{} {
+		var overlayData []overlayGlobResult
+
+		appendOverlayData := func(overlayDirs []string, t overlayType) {
+			for i := range overlayDirs {
+				// Iterate backwards through the list of overlay directories so that the later, lower-priority
+				// directories in the list show up earlier in the command line to aapt2.
+				overlay := overlayDirs[len(overlayDirs)-1-i]
+				var result overlayGlobResult
+				result.dir = overlay
+				result.overlayType = t
+
+				files, err := ctx.GlobWithDeps(filepath.Join(overlay, "**/*"), androidResourceIgnoreFilenames)
+				if err != nil {
+					ctx.ModuleErrorf("failed to glob resource dir %q: %s", overlay, err.Error())
+					continue
+				}
+				var paths android.Paths
+				for _, f := range files {
+					if !strings.HasSuffix(f, "/") {
+						paths = append(paths, android.PathForSource(ctx, f))
+					}
+				}
+				result.paths = android.PathsToDirectorySortedPaths(paths)
+				overlayData = append(overlayData, result)
+			}
+		}
+
+		appendOverlayData(ctx.Config().DeviceResourceOverlays(), device)
+		appendOverlayData(ctx.Config().ProductResourceOverlays(), product)
+		return overlayData
+	}).([]overlayGlobResult)
 
 	// Runtime resource overlays (RRO) may be turned on by the product config for some modules
 	rroEnabled := a.IsRROEnforced(ctx)
@@ -110,44 +133,3 @@
 
 	return res, rroDirs
 }
-
-func OverlaySingletonFactory() android.Singleton {
-	return overlaySingleton{}
-}
-
-type overlaySingleton struct{}
-
-func (overlaySingleton) GenerateBuildActions(ctx android.SingletonContext) {
-	var overlayData []overlayGlobResult
-
-	appendOverlayData := func(overlayDirs []string, t overlayType) {
-		for i := range overlayDirs {
-			// Iterate backwards through the list of overlay directories so that the later, lower-priority
-			// directories in the list show up earlier in the command line to aapt2.
-			overlay := overlayDirs[len(overlayDirs)-1-i]
-			var result overlayGlobResult
-			result.dir = overlay
-			result.overlayType = t
-
-			files, err := ctx.GlobWithDeps(filepath.Join(overlay, "**/*"), androidResourceIgnoreFilenames)
-			if err != nil {
-				ctx.Errorf("failed to glob resource dir %q: %s", overlay, err.Error())
-				continue
-			}
-			var paths android.Paths
-			for _, f := range files {
-				if !strings.HasSuffix(f, "/") {
-					paths = append(paths, android.PathForSource(ctx, f))
-				}
-			}
-			result.paths = android.PathsToDirectorySortedPaths(paths)
-			overlayData = append(overlayData, result)
-		}
-	}
-
-	appendOverlayData(ctx.Config().DeviceResourceOverlays(), device)
-	appendOverlayData(ctx.Config().ProductResourceOverlays(), product)
-	ctx.Config().Once(overlayDataKey, func() interface{} {
-		return overlayData
-	})
-}
diff --git a/java/app.go b/java/app.go
index 0cb72e2..7b9e6bb 100755
--- a/java/app.go
+++ b/java/app.go
@@ -308,6 +308,13 @@
 }
 
 func (a *AndroidTestHelperApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	applicationId := a.appTestHelperAppProperties.Manifest_values.ApplicationId
+	if applicationId != nil {
+		if a.overridableAppProperties.Package_name != nil {
+			ctx.PropertyErrorf("manifest_values.applicationId", "property is not supported when property package_name is set.")
+		}
+		a.aapt.manifestValues.applicationId = *applicationId
+	}
 	a.generateAndroidBuildActions(ctx)
 }
 
@@ -1107,6 +1114,12 @@
 	return module
 }
 
+// A dictionary of values to be overridden in the manifest.
+type Manifest_values struct {
+	// Overrides the value of package_name in the manifest
+	ApplicationId *string
+}
+
 type appTestProperties struct {
 	// The name of the android_app module that the tests will run against.
 	Instrumentation_for *string
@@ -1116,6 +1129,8 @@
 
 	// If specified, the mainline module package name in the test config is overwritten by it.
 	Mainline_package_name *string
+
+	Manifest_values Manifest_values
 }
 
 type AndroidTest struct {
@@ -1160,6 +1175,13 @@
 			a.additionalAaptFlags = append(a.additionalAaptFlags, "--rename-instrumentation-target-package "+manifestPackageName)
 		}
 	}
+	applicationId := a.appTestProperties.Manifest_values.ApplicationId
+	if applicationId != nil {
+		if a.overridableAppProperties.Package_name != nil {
+			ctx.PropertyErrorf("manifest_values.applicationId", "property is not supported when property package_name is set.")
+		}
+		a.aapt.manifestValues.applicationId = *applicationId
+	}
 	a.generateAndroidBuildActions(ctx)
 
 	for _, module := range a.testProperties.Test_mainline_modules {
@@ -1264,6 +1286,8 @@
 
 	// Install the test into a folder named for the module in all test suites.
 	Per_testcase_directory *bool
+
+	Manifest_values Manifest_values
 }
 
 type AndroidTestHelperApp struct {
diff --git a/java/app_test.go b/java/app_test.go
index 4d3b2dc..5cb4a23 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -558,7 +558,6 @@
 		t.Run(testCase.name, func(t *testing.T) {
 			result := android.GroupFixturePreparers(
 				PrepareForTestWithJavaDefaultModules,
-				PrepareForTestWithOverlayBuildComponents,
 				fs.AddToFixture(),
 			).RunTestWithBp(t, fmt.Sprintf(bp, testCase.prop))
 
@@ -1283,7 +1282,6 @@
 
 			result := android.GroupFixturePreparers(
 				PrepareForTestWithJavaDefaultModules,
-				PrepareForTestWithOverlayBuildComponents,
 				fs.AddToFixture(),
 			).RunTestWithBp(t, bp)
 
@@ -1566,7 +1564,6 @@
 		t.Run(testCase.name, func(t *testing.T) {
 			result := android.GroupFixturePreparers(
 				PrepareForTestWithJavaDefaultModules,
-				PrepareForTestWithOverlayBuildComponents,
 				fs.AddToFixture(),
 				android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
 					variables.DeviceResourceOverlays = deviceResourceOverlays
diff --git a/java/base.go b/java/base.go
index e1c2386..3d7d3de 100644
--- a/java/base.go
+++ b/java/base.go
@@ -1946,19 +1946,22 @@
 		}
 
 		dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo)
-		if dep.TransitiveLibsHeaderJars != nil {
-			transitiveLibs = append(transitiveLibs, dep.TransitiveLibsHeaderJars)
-		}
-		if dep.TransitiveStaticLibsHeaderJars != nil {
-			transitiveStaticLibs = append(transitiveStaticLibs, dep.TransitiveStaticLibsHeaderJars)
-		}
-
 		tag := ctx.OtherModuleDependencyTag(module)
 		_, isUsesLibDep := tag.(usesLibraryDependencyTag)
 		if tag == libTag || tag == r8LibraryJarTag || isUsesLibDep {
 			directLibs = append(directLibs, dep.HeaderJars...)
 		} else if tag == staticLibTag {
 			directStaticLibs = append(directStaticLibs, dep.HeaderJars...)
+		} else {
+			// Don't propagate transitive libs for other kinds of dependencies.
+			return
+		}
+
+		if dep.TransitiveLibsHeaderJars != nil {
+			transitiveLibs = append(transitiveLibs, dep.TransitiveLibsHeaderJars)
+		}
+		if dep.TransitiveStaticLibsHeaderJars != nil {
+			transitiveStaticLibs = append(transitiveStaticLibs, dep.TransitiveStaticLibsHeaderJars)
 		}
 	})
 	j.transitiveLibsHeaderJars = android.NewDepSet(android.POSTORDER, directLibs, transitiveLibs)
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index d15dbc9..7d8a9f7 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -632,21 +632,6 @@
 	return output
 }
 
-// retrieveLegacyEncodedBootDexFiles attempts to retrieve the legacy encoded boot dex jar files.
-func retrieveLegacyEncodedBootDexFiles(ctx android.ModuleContext, contents []android.Module) bootDexJarByModule {
-	// If the current bootclasspath_fragment is the active module or a source module then retrieve the
-	// encoded dex files, otherwise return an empty map.
-	//
-	// An inactive (i.e. not preferred) bootclasspath_fragment needs to retrieve the encoded dex jars
-	// as they are still needed by an apex. An inactive prebuilt_bootclasspath_fragment does not need
-	// to do so and may not yet have access to dex boot jars from a prebuilt_apex/apex_set.
-	if isActiveModule(ctx.Module()) || !android.IsModulePrebuilt(ctx.Module()) {
-		return extractEncodedDexJarsFromModules(ctx, contents)
-	} else {
-		return nil
-	}
-}
-
 // createHiddenAPIFlagInput creates a HiddenAPIFlagInput struct and initializes it with information derived
 // from the properties on this module and its dependencies.
 func (b *BootclasspathFragmentModule) createHiddenAPIFlagInput(ctx android.ModuleContext, contents []android.Module, fragments []android.Module) HiddenAPIFlagInput {
diff --git a/java/config/makevars.go b/java/config/makevars.go
index 4e09195..649b6c5 100644
--- a/java/config/makevars.go
+++ b/java/config/makevars.go
@@ -34,8 +34,6 @@
 
 	ctx.Strict("ANDROID_JAVA_HOME", "${JavaHome}")
 	ctx.Strict("ANDROID_JAVA8_HOME", "prebuilts/jdk/jdk8/${hostPrebuiltTag}")
-	ctx.Strict("ANDROID_JAVA9_HOME", "prebuilts/jdk/jdk9/${hostPrebuiltTag}")
-	ctx.Strict("ANDROID_JAVA11_HOME", "prebuilts/jdk/jdk11/${hostPrebuiltTag}")
 	ctx.Strict("ANDROID_JAVA_TOOLCHAIN", "${JavaToolchain}")
 	ctx.Strict("JAVA", "${JavaCmd} ${JavaVmFlags}")
 	ctx.Strict("JAVAC", "${JavacCmd} ${JavacVmFlags}")
diff --git a/java/core-libraries/Android.bp b/java/core-libraries/Android.bp
index 8b7387a..c6ab561 100644
--- a/java/core-libraries/Android.bp
+++ b/java/core-libraries/Android.bp
@@ -207,6 +207,26 @@
     ],
 }
 
+java_api_library {
+    name: "core.module_lib.stubs.from-text",
+    api_surface: "module-lib",
+    api_contributions: [
+        "art.module.public.api.stubs.source.api.contribution",
+        "art.module.public.api.stubs.source.system.api.contribution",
+        "art.module.public.api.stubs.source.module_lib.api.contribution",
+
+        // Add the module-lib correspondence when Conscrypt or i18N module
+        // provides @SystemApi(MODULE_LIBRARIES). Currently, assume that only ART module provides
+        // @SystemApi(MODULE_LIBRARIES).
+        "conscrypt.module.public.api.stubs.source.api.contribution",
+        "i18n.module.public.api.stubs.source.api.contribution",
+    ],
+    libs: [
+        "stub-annotations",
+    ],
+    visibility: ["//visibility:private"],
+}
+
 // Produces a dist file that is used by the
 // prebuilts/sdk/update_prebuilts.py script to update the prebuilts/sdk
 // directory.
@@ -504,7 +524,3 @@
         "art-module-intra-core-api-stubs-system-modules-lib",
     ],
 }
-
-build = [
-    "TxtStubLibraries.bp",
-]
diff --git a/java/core-libraries/TxtStubLibraries.bp b/java/core-libraries/TxtStubLibraries.bp
deleted file mode 100644
index c46f8b8..0000000
--- a/java/core-libraries/TxtStubLibraries.bp
+++ /dev/null
@@ -1,140 +0,0 @@
-// Copyright (C) 2023 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// This file contains java_system_modules provided by the SDK.
-// These system modules transitively depend on core stub libraries generated from .txt files.
-
-// Same as core-public-stubs-system-modules, but the stubs are generated from .txt files
-java_system_modules {
-    name: "core-public-stubs-system-modules.from-text",
-    visibility: ["//visibility:public"],
-    libs: [
-        "core-current-stubs-for-system-modules-no-annotations.from-text",
-    ],
-}
-
-java_library {
-    name: "core-current-stubs-for-system-modules-no-annotations.from-text",
-    visibility: ["//visibility:private"],
-    defaults: [
-        "system-modules-no-annotations",
-    ],
-    static_libs: [
-        "core.current.stubs.from-text",
-        "core-lambda-stubs.from-text",
-    ],
-}
-
-// Same as core-module-lib-stubs-system-modules, but the stubs are generated from .txt files
-java_system_modules {
-    name: "core-module-lib-stubs-system-modules.from-text",
-    visibility: ["//visibility:public"],
-    libs: [
-        "core-module-lib-stubs-for-system-modules-no-annotations.from-text",
-    ],
-}
-
-java_library {
-    name: "core-module-lib-stubs-for-system-modules-no-annotations.from-text",
-    visibility: ["//visibility:private"],
-    defaults: [
-        "system-modules-no-annotations",
-    ],
-    static_libs: [
-        "core.module_lib.stubs.from-text",
-        "core-lambda-stubs.from-text",
-    ],
-}
-
-java_api_library {
-    name: "core.module_lib.stubs.from-text",
-    api_surface: "module-lib",
-    api_contributions: [
-        "art.module.public.api.stubs.source.api.contribution",
-        "art.module.public.api.stubs.source.system.api.contribution",
-        "art.module.public.api.stubs.source.module_lib.api.contribution",
-
-        // Add the module-lib correspondence when Conscrypt or i18N module
-        // provides @SystemApi(MODULE_LIBRARIES). Currently, assume that only ART module provides
-        // @SystemApi(MODULE_LIBRARIES).
-        "conscrypt.module.public.api.stubs.source.api.contribution",
-        "i18n.module.public.api.stubs.source.api.contribution",
-    ],
-    libs: [
-        "stub-annotations",
-    ],
-    visibility: ["//visibility:private"],
-}
-
-// Same as legacy-core-platform-api-stubs-system-modules, but the stubs are generated from .txt files
-java_system_modules {
-    name: "legacy-core-platform-api-stubs-system-modules.from-text",
-    visibility: core_platform_visibility,
-    libs: [
-        "legacy.core.platform.api.no.annotations.stubs.from-text",
-        "core-lambda-stubs.from-text",
-    ],
-}
-
-java_library {
-    name: "legacy.core.platform.api.no.annotations.stubs.from-text",
-    visibility: core_platform_visibility,
-    defaults: [
-        "system-modules-no-annotations",
-    ],
-    hostdex: true,
-    compile_dex: true,
-
-    static_libs: [
-        "legacy.core.platform.api.stubs.from-text",
-    ],
-    patch_module: "java.base",
-}
-
-// Same as stable-core-platform-api-stubs-system-modules, but the stubs are generated from .txt files
-java_system_modules {
-    name: "stable-core-platform-api-stubs-system-modules.from-text",
-    visibility: core_platform_visibility,
-    libs: [
-        "stable.core.platform.api.no.annotations.stubs.from-text",
-        "core-lambda-stubs.from-text",
-    ],
-}
-
-java_library {
-    name: "stable.core.platform.api.no.annotations.stubs.from-text",
-    visibility: core_platform_visibility,
-    defaults: [
-        "system-modules-no-annotations",
-    ],
-    hostdex: true,
-    compile_dex: true,
-
-    static_libs: [
-        "stable.core.platform.api.stubs.from-text",
-    ],
-    patch_module: "java.base",
-}
-
-java_api_library {
-    name: "core-lambda-stubs.from-text",
-    api_surface: "toolchain",
-    api_contributions: [
-        "art.module.toolchain.api.api.contribution",
-    ],
-    libs: [
-        // LambdaMetaFactory depends on CallSite etc. which is part of the Core API surface
-        "core.current.stubs.from-text",
-    ],
-}
diff --git a/java/dex.go b/java/dex.go
index 9ce5053..aa01783 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -300,6 +300,8 @@
 
 	flagFiles = append(flagFiles, android.PathsForModuleSrc(ctx, opt.Proguard_flags_files)...)
 
+	flagFiles = android.FirstUniquePaths(flagFiles)
+
 	r8Flags = append(r8Flags, android.JoinWithPrefix(flagFiles.Strings(), "-include "))
 	r8Deps = append(r8Deps, flagFiles...)
 
diff --git a/java/dex_test.go b/java/dex_test.go
index ec1ef15..1ecdae0 100644
--- a/java/dex_test.go
+++ b/java/dex_test.go
@@ -385,13 +385,53 @@
 func TestProguardFlagsInheritance(t *testing.T) {
 	directDepFlagsFileName := "direct_dep.flags"
 	transitiveDepFlagsFileName := "transitive_dep.flags"
-	bp := `
-		android_app {
-			name: "app",
-			static_libs: ["androidlib"], // this must be static_libs to initate dexing
-			platform_apis: true,
-		}
 
+	topLevelModules := []struct {
+		name       string
+		definition string
+	}{
+		{
+			name: "android_app",
+			definition: `
+				android_app {
+					name: "app",
+					static_libs: ["androidlib"], // this must be static_libs to initate dexing
+					platform_apis: true,
+				}
+			`,
+		},
+		{
+			name: "android_library",
+			definition: `
+				android_library {
+					name: "app",
+					static_libs: ["androidlib"], // this must be static_libs to initate dexing
+					installable: true,
+					optimize: {
+						enabled: true,
+						shrink: true,
+					},
+				}
+			`,
+		},
+		{
+			name: "java_library",
+			definition: `
+				java_library {
+					name: "app",
+					static_libs: ["androidlib"], // this must be static_libs to initate dexing
+					srcs: ["Foo.java"],
+					installable: true,
+					optimize: {
+						enabled: true,
+						shrink: true,
+					},
+				}
+			`,
+		},
+	}
+
+	bp := `
 		android_library {
 			name: "androidlib",
 			static_libs: ["app_dep"],
@@ -558,43 +598,46 @@
 		},
 	}
 
-	for _, tc := range testcases {
-		t.Run(tc.name, func(t *testing.T) {
-			result := android.GroupFixturePreparers(
-				PrepareForTestWithJavaDefaultModules,
-				android.FixtureMergeMockFs(android.MockFS{
-					directDepFlagsFileName:     nil,
-					transitiveDepFlagsFileName: nil,
-				}),
-			).RunTestWithBp(t,
-				fmt.Sprintf(
-					bp,
-					tc.depType,
-					tc.transitiveDepType,
-					tc.depExportsFlagsFiles,
-					tc.transitiveDepExportsFlagsFiles,
-				),
-			)
-			appR8 := result.ModuleForTests("app", "android_common").Rule("r8")
+	for _, topLevelModuleDef := range topLevelModules {
+		for _, tc := range testcases {
+			t.Run(topLevelModuleDef.name+"-"+tc.name, func(t *testing.T) {
+				result := android.GroupFixturePreparers(
+					PrepareForTestWithJavaDefaultModules,
+					android.FixtureMergeMockFs(android.MockFS{
+						directDepFlagsFileName:     nil,
+						transitiveDepFlagsFileName: nil,
+					}),
+				).RunTestWithBp(t,
+					topLevelModuleDef.definition+
+						fmt.Sprintf(
+							bp,
+							tc.depType,
+							tc.transitiveDepType,
+							tc.depExportsFlagsFiles,
+							tc.transitiveDepExportsFlagsFiles,
+						),
+				)
+				appR8 := result.ModuleForTests("app", "android_common").Rule("r8")
 
-			shouldHaveDepFlags := android.InList(directDepFlagsFileName, tc.expectedFlagsFiles)
-			if shouldHaveDepFlags {
-				android.AssertStringDoesContain(t, "expected deps's proguard flags",
-					appR8.Args["r8Flags"], directDepFlagsFileName)
-			} else {
-				android.AssertStringDoesNotContain(t, "app did not expect deps's proguard flags",
-					appR8.Args["r8Flags"], directDepFlagsFileName)
-			}
+				shouldHaveDepFlags := android.InList(directDepFlagsFileName, tc.expectedFlagsFiles)
+				if shouldHaveDepFlags {
+					android.AssertStringDoesContain(t, "expected deps's proguard flags",
+						appR8.Args["r8Flags"], directDepFlagsFileName)
+				} else {
+					android.AssertStringDoesNotContain(t, "app did not expect deps's proguard flags",
+						appR8.Args["r8Flags"], directDepFlagsFileName)
+				}
 
-			shouldHaveTransitiveDepFlags := android.InList(transitiveDepFlagsFileName, tc.expectedFlagsFiles)
-			if shouldHaveTransitiveDepFlags {
-				android.AssertStringDoesContain(t, "expected transitive deps's proguard flags",
-					appR8.Args["r8Flags"], transitiveDepFlagsFileName)
-			} else {
-				android.AssertStringDoesNotContain(t, "app did not expect transitive deps's proguard flags",
-					appR8.Args["r8Flags"], transitiveDepFlagsFileName)
-			}
-		})
+				shouldHaveTransitiveDepFlags := android.InList(transitiveDepFlagsFileName, tc.expectedFlagsFiles)
+				if shouldHaveTransitiveDepFlags {
+					android.AssertStringDoesContain(t, "expected transitive deps's proguard flags",
+						appR8.Args["r8Flags"], transitiveDepFlagsFileName)
+				} else {
+					android.AssertStringDoesNotContain(t, "app did not expect transitive deps's proguard flags",
+						appR8.Args["r8Flags"], transitiveDepFlagsFileName)
+				}
+			})
+		}
 	}
 }
 
@@ -606,11 +649,6 @@
 			platform_apis: true,
 		}
 
-		android_library {
-			name: "androidlib",
-			static_libs: ["aarimport"],
-		}
-
 		android_library_import {
 			name: "aarimport",
 			aars: ["import.aar"],
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 87588f3..f7d7de6 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -303,7 +303,7 @@
 	}
 
 	flags = append(flags, android.JoinWithPrefix(aidlIncludes.Strings(), "-I"))
-	flags = append(flags, "-I"+android.PathForModuleSrc(ctx).String())
+	flags = append(flags, "-I"+ctx.ModuleDir())
 	if src := android.ExistentPathForSource(ctx, ctx.ModuleDir(), "src"); src.Valid() {
 		flags = append(flags, "-I"+src.String())
 	}
diff --git a/java/droidstubs.go b/java/droidstubs.go
index a7e8eb6..180ba92 100644
--- a/java/droidstubs.go
+++ b/java/droidstubs.go
@@ -48,6 +48,7 @@
 // Droidstubs
 type Droidstubs struct {
 	Javadoc
+	embeddableInModuleAndImport
 
 	properties              DroidstubsProperties
 	apiFile                 android.Path
@@ -184,6 +185,7 @@
 
 	module.AddProperties(&module.properties,
 		&module.Javadoc.properties)
+	module.initModuleAndImport(module)
 
 	InitDroiddocModule(module, android.HostAndDeviceSupported)
 
@@ -773,6 +775,11 @@
 			`         m %s-update-current-api\n\n`+
 			`      To submit the revised current.txt to the main Android repository,\n`+
 			`      you will need approval.\n`+
+			`If your build failed due to stub validation, you can resolve the errors with\n`+
+			`either of the two choices above and try re-building the target.\n`+
+			`If the mismatch between the stubs and the current.txt is intended,\n`+
+			`you can try re-building the target by executing the following command:\n`+
+			`m DISABLE_STUB_VALIDATION=true <your build target>\n`+
 			`******************************\n`, ctx.ModuleName())
 
 		rule.Command().
@@ -930,6 +937,8 @@
 type PrebuiltStubsSources struct {
 	android.ModuleBase
 	android.DefaultableModuleBase
+	embeddableInModuleAndImport
+
 	prebuilt android.Prebuilt
 
 	properties PrebuiltStubsSourcesProperties
@@ -1008,6 +1017,7 @@
 	module := &PrebuiltStubsSources{}
 
 	module.AddProperties(&module.properties)
+	module.initModuleAndImport(module)
 
 	android.InitPrebuiltModule(module, &module.properties.Srcs)
 	InitDroiddocModule(module, android.HostAndDeviceSupported)
diff --git a/java/jacoco.go b/java/jacoco.go
index f8012b8..a820b38 100644
--- a/java/jacoco.go
+++ b/java/jacoco.go
@@ -34,13 +34,11 @@
 			`${config.Zip2ZipCmd} -i $in -o $strippedJar $stripSpec && ` +
 			`${config.JavaCmd} ${config.JavaVmFlags} -jar ${config.JacocoCLIJar} ` +
 			`  instrument --quiet --dest $tmpDir $strippedJar && ` +
-			`${config.Ziptime} $tmpJar && ` +
 			`${config.MergeZipsCmd} --ignore-duplicates -j $out $tmpJar $in`,
 		CommandDeps: []string{
 			"${config.Zip2ZipCmd}",
 			"${config.JavaCmd}",
 			"${config.JacocoCLIJar}",
-			"${config.Ziptime}",
 			"${config.MergeZipsCmd}",
 		},
 	},
diff --git a/java/java.go b/java/java.go
index bc24050..dd04188 100644
--- a/java/java.go
+++ b/java/java.go
@@ -697,6 +697,11 @@
 
 	j.stem = proptools.StringDefault(j.overridableDeviceProperties.Stem, ctx.ModuleName())
 
+	proguardSpecInfo := j.collectProguardSpecInfo(ctx)
+	ctx.SetProvider(ProguardSpecInfoProvider, proguardSpecInfo)
+	j.exportedProguardFlagFiles = proguardSpecInfo.ProguardFlagsFiles.ToList()
+	j.extraProguardFlagFiles = append(j.extraProguardFlagFiles, j.exportedProguardFlagFiles...)
+
 	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
 	if !apexInfo.IsForPlatform() {
 		j.hideApexVariantFromMake = true
@@ -741,10 +746,6 @@
 		}
 		j.installFile = ctx.InstallFile(installDir, j.Stem()+".jar", j.outputFile, extraInstallDeps...)
 	}
-
-	proguardSpecInfo := j.collectProguardSpecInfo(ctx)
-	ctx.SetProvider(ProguardSpecInfoProvider, proguardSpecInfo)
-	j.exportedProguardFlagFiles = proguardSpecInfo.ProguardFlagsFiles.ToList()
 }
 
 func (j *Library) DepsMutator(ctx android.BottomUpMutatorContext) {
@@ -1612,6 +1613,7 @@
 type JavaApiContribution struct {
 	android.ModuleBase
 	android.DefaultableModuleBase
+	embeddableInModuleAndImport
 
 	properties struct {
 		// name of the API surface
@@ -1627,6 +1629,7 @@
 	android.InitAndroidModule(module)
 	android.InitDefaultableModule(module)
 	module.AddProperties(&module.properties)
+	module.initModuleAndImport(module)
 	return module
 }
 
@@ -1655,6 +1658,7 @@
 
 	hiddenAPI
 	dexer
+	embeddableInModuleAndImport
 
 	properties JavaApiLibraryProperties
 
@@ -1713,6 +1717,7 @@
 	module := &ApiLibrary{}
 	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
 	module.AddProperties(&module.properties)
+	module.initModuleAndImport(module)
 	android.InitDefaultableModule(module)
 	return module
 }
@@ -3512,6 +3517,7 @@
 	android.InitDefaultableModule(module)
 	android.InitPrebuiltModule(module, &[]string{""})
 	module.AddProperties(&module.properties)
+	module.AddProperties(&module.sdkLibraryComponentProperties)
 	return module
 }
 
diff --git a/java/java_test.go b/java/java_test.go
index c54c0e6..81119a7 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -47,10 +47,6 @@
 	cc.PrepareForTestWithCcBuildComponents,
 	// Include all the default java modules.
 	PrepareForTestWithDexpreopt,
-	PrepareForTestWithOverlayBuildComponents,
-	android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
-		ctx.RegisterPreSingletonType("sdk_versions", sdkPreSingletonFactory)
-	}),
 )
 
 func TestMain(m *testing.M) {
diff --git a/java/rro_test.go b/java/rro_test.go
index 8067a47..c4a4d04 100644
--- a/java/rro_test.go
+++ b/java/rro_test.go
@@ -62,7 +62,6 @@
 
 	result := android.GroupFixturePreparers(
 		PrepareForTestWithJavaDefaultModules,
-		PrepareForTestWithOverlayBuildComponents,
 		android.FixtureModifyConfig(android.SetKatiEnabledForTests),
 		fs.AddToFixture(),
 	).RunTestWithBp(t, bp)
@@ -330,7 +329,6 @@
 		t.Run(testCase.name, func(t *testing.T) {
 			result := android.GroupFixturePreparers(
 				PrepareForTestWithJavaDefaultModules,
-				PrepareForTestWithOverlayBuildComponents,
 				fs.AddToFixture(),
 				android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
 					variables.ProductResourceOverlays = productResourceOverlays
diff --git a/java/sdk.go b/java/sdk.go
index ddd99bb..ad71fb2 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -17,8 +17,6 @@
 import (
 	"fmt"
 	"path/filepath"
-	"sort"
-	"strconv"
 
 	"android/soong/android"
 	"android/soong/java/config"
@@ -27,12 +25,10 @@
 )
 
 func init() {
-	android.RegisterPreSingletonType("sdk_versions", sdkPreSingletonFactory)
 	android.RegisterParallelSingletonType("sdk", sdkSingletonFactory)
 	android.RegisterMakeVarsProvider(pctx, sdkMakeVars)
 }
 
-var sdkVersionsKey = android.NewOnceKey("sdkVersionsKey")
 var sdkFrameworkAidlPathKey = android.NewOnceKey("sdkFrameworkAidlPathKey")
 var nonUpdatableFrameworkAidlPathKey = android.NewOnceKey("nonUpdatableFrameworkAidlPathKey")
 var apiFingerprintPathKey = android.NewOnceKey("apiFingerprintPathKey")
@@ -213,44 +209,6 @@
 	}
 }
 
-func sdkPreSingletonFactory() android.Singleton {
-	return sdkPreSingleton{}
-}
-
-type sdkPreSingleton struct{}
-
-func (sdkPreSingleton) GenerateBuildActions(ctx android.SingletonContext) {
-	sdkJars, err := ctx.GlobWithDeps("prebuilts/sdk/*/public/android.jar", nil)
-	if err != nil {
-		ctx.Errorf("failed to glob prebuilts/sdk/*/public/android.jar: %s", err.Error())
-	}
-
-	var sdkVersions []int
-	for _, sdkJar := range sdkJars {
-		dir := filepath.Base(filepath.Dir(filepath.Dir(sdkJar)))
-		v, err := strconv.Atoi(dir)
-		if scerr, ok := err.(*strconv.NumError); ok && scerr.Err == strconv.ErrSyntax {
-			continue
-		} else if err != nil {
-			ctx.Errorf("invalid sdk jar %q, %s, %v", sdkJar, err.Error())
-		}
-		sdkVersions = append(sdkVersions, v)
-	}
-
-	sort.Ints(sdkVersions)
-
-	ctx.Config().Once(sdkVersionsKey, func() interface{} { return sdkVersions })
-}
-
-func LatestSdkVersionInt(ctx android.EarlyModuleContext) int {
-	sdkVersions := ctx.Config().Get(sdkVersionsKey).([]int)
-	latestSdkVersion := 0
-	if len(sdkVersions) > 0 {
-		latestSdkVersion = sdkVersions[len(sdkVersions)-1]
-	}
-	return latestSdkVersion
-}
-
 func sdkSingletonFactory() android.Singleton {
 	return sdkSingleton{}
 }
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 7807889..1de8972 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -1829,7 +1829,7 @@
 		}
 	}
 
-	mctx.CreateModule(DroidstubsFactory, &props).(*Droidstubs).CallHookIfAvailable(mctx)
+	mctx.CreateModule(DroidstubsFactory, &props, module.sdkComponentPropertiesForChildLibrary()).(*Droidstubs).CallHookIfAvailable(mctx)
 }
 
 func (module *SdkLibrary) createApiLibrary(mctx android.DefaultableHookContext, apiScope *apiScope, alternativeFullApiSurfaceStub string) {
@@ -1892,7 +1892,7 @@
 	props.System_modules = module.deviceProperties.System_modules
 	props.Enable_validation = proptools.BoolPtr(true)
 
-	mctx.CreateModule(ApiLibraryFactory, &props)
+	mctx.CreateModule(ApiLibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary())
 }
 
 func (module *SdkLibrary) createTopLevelStubsLibrary(
@@ -2590,7 +2590,7 @@
 	// The stubs source is preferred if the java_sdk_library_import is preferred.
 	props.CopyUserSuppliedPropertiesFromPrebuilt(&module.prebuilt)
 
-	mctx.CreateModule(PrebuiltStubsSourcesFactory, &props)
+	mctx.CreateModule(PrebuiltStubsSourcesFactory, &props, module.sdkComponentPropertiesForChildLibrary())
 }
 
 func (module *SdkLibraryImport) createPrebuiltApiContribution(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) {
@@ -2609,7 +2609,7 @@
 	props.Api_file = api_file
 	props.Visibility = []string{"//visibility:override", "//visibility:public"}
 
-	mctx.CreateModule(ApiContributionImportFactory, &props)
+	mctx.CreateModule(ApiContributionImportFactory, &props, module.sdkComponentPropertiesForChildLibrary())
 }
 
 // Add the dependencies on the child module in the component deps mutator so that it
diff --git a/java/testing.go b/java/testing.go
index 16bdd80..e883bcb 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -118,8 +118,6 @@
 	dexpreopt.PrepareForTestByEnablingDexpreopt,
 )
 
-var PrepareForTestWithOverlayBuildComponents = android.FixtureRegisterWithContext(registerOverlayBuildComponents)
-
 // Prepare a fixture to use all java module types, mutators and singletons fully.
 //
 // This should only be used by tests that want to run with as much of the build enabled as possible.
diff --git a/remoteexec/remoteexec.go b/remoteexec/remoteexec.go
index 150d62c..690b47b 100644
--- a/remoteexec/remoteexec.go
+++ b/remoteexec/remoteexec.go
@@ -30,7 +30,7 @@
 	// DefaultImage is the default container image used for Android remote execution. The
 	// image was built with the Dockerfile at
 	// https://android.googlesource.com/platform/prebuilts/remoteexecution-client/+/refs/heads/master/docker/Dockerfile
-	DefaultImage = "docker://gcr.io/androidbuild-re-dockerimage/android-build-remoteexec-image@sha256:582efb38f0c229ea39952fff9e132ccbe183e14869b39888010dacf56b360d62"
+	DefaultImage = "docker://gcr.io/androidbuild-re-dockerimage/android-build-remoteexec-image@sha256:953fed4a6b2501256a0d17f055dc17884ff71b024e50ade773e0b348a6c303e6"
 
 	// DefaultWrapperPath is the default path to the remote execution wrapper.
 	DefaultWrapperPath = "prebuilts/remoteexecution-client/live/rewrapper"
diff --git a/rust/builder.go b/rust/builder.go
index fe2d03a..162d1aa 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -238,6 +238,10 @@
 		}
 	}
 
+	if ctx.Darwin() {
+		envVars = append(envVars, "ANDROID_RUST_DARWIN=true")
+	}
+
 	return envVars
 }
 
@@ -284,7 +288,7 @@
 	}
 
 	// Disallow experimental features
-	modulePath := android.PathForModuleSrc(ctx).String()
+	modulePath := ctx.ModuleDir()
 	if !(android.IsThirdPartyPath(modulePath) || strings.HasPrefix(modulePath, "prebuilts")) {
 		rustcFlags = append(rustcFlags, "-Zallow-features=\"\"")
 	}
@@ -346,19 +350,6 @@
 		implicits = append(implicits, outputs.Paths()...)
 	}
 
-	envVars = append(envVars, "ANDROID_RUST_VERSION="+config.GetRustVersion(ctx))
-
-	if ctx.RustModule().compiler.CargoEnvCompat() {
-		if _, ok := ctx.RustModule().compiler.(*binaryDecorator); ok {
-			envVars = append(envVars, "CARGO_BIN_NAME="+strings.TrimSuffix(outputFile.Base(), outputFile.Ext()))
-		}
-		envVars = append(envVars, "CARGO_CRATE_NAME="+ctx.RustModule().CrateName())
-		pkgVersion := ctx.RustModule().compiler.CargoPkgVersion()
-		if pkgVersion != "" {
-			envVars = append(envVars, "CARGO_PKG_VERSION="+pkgVersion)
-		}
-	}
-
 	if flags.Clippy {
 		clippyFile := android.PathForModuleOut(ctx, outputFile.Base()+".clippy")
 		ctx.Build(pctx, android.BuildParams{
@@ -445,7 +436,7 @@
 	docTimestampFile := android.PathForModuleOut(ctx, "rustdoc.timestamp")
 
 	// Silence warnings about renamed lints for third-party crates
-	modulePath := android.PathForModuleSrc(ctx).String()
+	modulePath := ctx.ModuleDir()
 	if android.IsThirdPartyPath(modulePath) {
 		rustdocFlags = append(rustdocFlags, " -A warnings")
 	}
diff --git a/rust/config/global.go b/rust/config/global.go
index 4d31121..64c9460 100644
--- a/rust/config/global.go
+++ b/rust/config/global.go
@@ -25,7 +25,7 @@
 	pctx         = android.NewPackageContext("android/soong/rust/config")
 	ExportedVars = android.NewExportedVariables(pctx)
 
-	RustDefaultVersion = "1.72.0"
+	RustDefaultVersion = "1.72.1"
 	RustDefaultBase    = "prebuilts/rust/"
 	DefaultEdition     = "2021"
 	Stdlibs            = []string{
diff --git a/ui/build/config.go b/ui/build/config.go
index e581e8f..c33312b 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -205,21 +205,6 @@
 	return nil
 }
 
-func UploadOnlyConfig(ctx Context, args ...string) Config {
-	ret := &configImpl{
-		environ:       OsEnvironment(),
-		sandboxConfig: &SandboxConfig{},
-	}
-	ret.parseArgs(ctx, args)
-	srcDir := absPath(ctx, ".")
-	bc := os.Getenv("ANDROID_BUILD_ENVIRONMENT_CONFIG")
-	if err := loadEnvConfig(ctx, ret, bc); err != nil {
-		ctx.Fatalln("Failed to parse env config files: %v", err)
-	}
-	ret.metricsUploader = GetMetricsUploader(srcDir, ret.environ)
-	return Config{ret}
-}
-
 func NewConfig(ctx Context, args ...string) Config {
 	ret := &configImpl{
 		environ:               OsEnvironment(),
@@ -397,8 +382,6 @@
 
 	// Configure Java-related variables, including adding it to $PATH
 	java8Home := filepath.Join("prebuilts/jdk/jdk8", ret.HostPrebuiltTag())
-	java9Home := filepath.Join("prebuilts/jdk/jdk9", ret.HostPrebuiltTag())
-	java11Home := filepath.Join("prebuilts/jdk/jdk11", ret.HostPrebuiltTag())
 	java17Home := filepath.Join("prebuilts/jdk/jdk17", ret.HostPrebuiltTag())
 	javaHome := func() string {
 		if override, ok := ret.environ.Get("OVERRIDE_ANDROID_JAVA_HOME"); ok {
@@ -425,8 +408,6 @@
 	ret.environ.Set("JAVA_HOME", absJavaHome)
 	ret.environ.Set("ANDROID_JAVA_HOME", javaHome)
 	ret.environ.Set("ANDROID_JAVA8_HOME", java8Home)
-	ret.environ.Set("ANDROID_JAVA9_HOME", java9Home)
-	ret.environ.Set("ANDROID_JAVA11_HOME", java11Home)
 	ret.environ.Set("PATH", strings.Join(newPath, string(filepath.ListSeparator)))
 
 	// b/286885495, https://bugzilla.redhat.com/show_bug.cgi?id=2227130: some versions of Fedora include patches
@@ -822,16 +803,6 @@
 			}
 		} else if arg == "--ensure-allowlist-integrity" {
 			c.ensureAllowlistIntegrity = true
-		} else if strings.HasPrefix(arg, "--bazel-exit-code=") {
-			bazelExitCodeStr := strings.TrimPrefix(arg, "--bazel-exit-code=")
-			val, err := strconv.Atoi(bazelExitCodeStr)
-			if err == nil {
-				c.bazelExitCode = int32(val)
-			} else {
-				ctx.Fatalf("Error parsing bazel-exit-code", err)
-			}
-		} else if strings.HasPrefix(arg, "--bes-id=") {
-			c.besId = strings.TrimPrefix(arg, "--bes-id=")
 		} else if len(arg) > 0 && arg[0] == '-' {
 			parseArgNum := func(def int) int {
 				if len(arg) > 2 {
@@ -1554,6 +1525,10 @@
 	return filepath.Join(c.SoongOutDir(), "make_vars-"+c.TargetProduct()+".mk")
 }
 
+func (c *configImpl) SoongBuildMetrics() string {
+	return filepath.Join(c.LogsDir(), "soong_build_metrics.pb")
+}
+
 func (c *configImpl) ProductOut() string {
 	return filepath.Join(c.OutDir(), "target", "product", c.TargetDevice())
 }
diff --git a/ui/build/soong.go b/ui/build/soong.go
index ac9bf3a..90f1798 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -15,6 +15,7 @@
 package build
 
 import (
+	"android/soong/ui/tracer"
 	"fmt"
 	"io/fs"
 	"os"
@@ -23,9 +24,11 @@
 	"strings"
 	"sync"
 	"sync/atomic"
+	"time"
 
 	"android/soong/bazel"
 	"android/soong/ui/metrics"
+	"android/soong/ui/metrics/metrics_proto"
 	"android/soong/ui/status"
 
 	"android/soong/shared"
@@ -33,6 +36,8 @@
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/bootstrap"
 	"github.com/google/blueprint/microfactory"
+
+	"google.golang.org/protobuf/proto"
 )
 
 const (
@@ -627,6 +632,10 @@
 
 		if config.BazelBuildEnabled() || config.Bp2Build() {
 			checkEnvironmentFile(ctx, soongBuildEnv, config.UsedEnvFile(bp2buildFilesTag))
+		} else {
+			// Remove bazel files in the event that bazel is disabled for the build.
+			// These files may have been left over from a previous bazel-enabled build.
+			cleanBazelFiles(config)
 		}
 
 		if config.JsonModuleGraph() {
@@ -717,8 +726,12 @@
 		targets = append(targets, config.SoongNinjaFile())
 	}
 
+	beforeSoongTimestamp := time.Now()
+
 	ninja(targets...)
 
+	loadSoongBuildMetrics(ctx, config, beforeSoongTimestamp)
+
 	distGzipFile(ctx, config, config.SoongNinjaFile(), "soong")
 	distFile(ctx, config, config.SoongVarsFile(), "soong")
 
@@ -732,6 +745,67 @@
 	}
 }
 
+// loadSoongBuildMetrics reads out/soong_build_metrics.pb if it was generated by soong_build and copies the
+// events stored in it into the soong_ui trace to provide introspection into how long the different phases of
+// soong_build are taking.
+func loadSoongBuildMetrics(ctx Context, config Config, oldTimestamp time.Time) {
+	soongBuildMetricsFile := config.SoongBuildMetrics()
+	if metricsStat, err := os.Stat(soongBuildMetricsFile); err != nil {
+		ctx.Verbosef("Failed to stat %s: %s", soongBuildMetricsFile, err)
+		return
+	} else if !metricsStat.ModTime().After(oldTimestamp) {
+		ctx.Verbosef("%s timestamp not later after running soong, expected %s > %s",
+			soongBuildMetricsFile, metricsStat.ModTime(), oldTimestamp)
+		return
+	}
+
+	metricsData, err := os.ReadFile(soongBuildMetricsFile)
+	if err != nil {
+		ctx.Verbosef("Failed to read %s: %s", soongBuildMetricsFile, err)
+		return
+	}
+
+	soongBuildMetrics := metrics_proto.SoongBuildMetrics{}
+	err = proto.Unmarshal(metricsData, &soongBuildMetrics)
+	if err != nil {
+		ctx.Verbosef("Failed to unmarshal %s: %s", soongBuildMetricsFile, err)
+		return
+	}
+	for _, event := range soongBuildMetrics.Events {
+		desc := event.GetDescription()
+		if dot := strings.LastIndexByte(desc, '.'); dot >= 0 {
+			desc = desc[dot+1:]
+		}
+		ctx.Tracer.Complete(desc, ctx.Thread,
+			event.GetStartTime(), event.GetStartTime()+event.GetRealTime())
+	}
+	for _, event := range soongBuildMetrics.PerfCounters {
+		timestamp := event.GetTime()
+		for _, group := range event.Groups {
+			counters := make([]tracer.Counter, 0, len(group.Counters))
+			for _, counter := range group.Counters {
+				counters = append(counters, tracer.Counter{
+					Name:  counter.GetName(),
+					Value: counter.GetValue(),
+				})
+			}
+			ctx.Tracer.CountersAtTime(group.GetName(), ctx.Thread, timestamp, counters)
+		}
+	}
+}
+
+func cleanBazelFiles(config Config) {
+	files := []string{
+		shared.JoinPath(config.SoongOutDir(), "bp2build"),
+		shared.JoinPath(config.SoongOutDir(), "workspace"),
+		shared.JoinPath(config.SoongOutDir(), bazel.SoongInjectionDirName),
+		shared.JoinPath(config.OutDir(), "bazel")}
+
+	for _, f := range files {
+		os.RemoveAll(f)
+	}
+}
+
 func runMicrofactory(ctx Context, config Config, name string, pkg string, mapping map[string]string) {
 	ctx.BeginTrace(metrics.RunSoong, name)
 	defer ctx.EndTrace()
diff --git a/ui/metrics/metrics.go b/ui/metrics/metrics.go
index d68ced8..4a275a8 100644
--- a/ui/metrics/metrics.go
+++ b/ui/metrics/metrics.go
@@ -32,7 +32,6 @@
 // of what an event is and how the metrics system is a stack based system.
 
 import (
-	"fmt"
 	"os"
 	"runtime"
 	"strings"
@@ -228,20 +227,6 @@
 	m.metrics.BuildDateTimestamp = proto.Int64(buildTimestamp.UnixNano() / int64(time.Second))
 }
 
-func (m *Metrics) UpdateTotalRealTimeAndNonZeroExit(data []byte, bazelExitCode int32) error {
-	if err := proto.Unmarshal(data, &m.metrics); err != nil {
-		return fmt.Errorf("Failed to unmarshal proto: %w", err)
-	}
-	startTime := *m.metrics.Total.StartTime
-	endTime := uint64(time.Now().UnixNano())
-
-	*m.metrics.Total.RealTime = *proto.Uint64(endTime - startTime)
-
-	bazelError := bazelExitCode != 0
-	m.metrics.NonZeroExit = proto.Bool(bazelError)
-	return nil
-}
-
 // SetBuildCommand adds the build command specified by the user to the
 // list of collected metrics.
 func (m *Metrics) SetBuildCommand(cmd []string) {
diff --git a/ui/metrics/metrics_proto/metrics.pb.go b/ui/metrics/metrics_proto/metrics.pb.go
index f3e677a..b75f572 100644
--- a/ui/metrics/metrics_proto/metrics.pb.go
+++ b/ui/metrics/metrics_proto/metrics.pb.go
@@ -279,7 +279,7 @@
 
 // Deprecated: Use ModuleTypeInfo_BuildSystem.Descriptor instead.
 func (ModuleTypeInfo_BuildSystem) EnumDescriptor() ([]byte, []int) {
-	return file_metrics_proto_rawDescGZIP(), []int{5, 0}
+	return file_metrics_proto_rawDescGZIP(), []int{8, 0}
 }
 
 type ExpConfigFetcher_ConfigStatus int32
@@ -341,7 +341,7 @@
 
 // Deprecated: Use ExpConfigFetcher_ConfigStatus.Descriptor instead.
 func (ExpConfigFetcher_ConfigStatus) EnumDescriptor() ([]byte, []int) {
-	return file_metrics_proto_rawDescGZIP(), []int{9, 0}
+	return file_metrics_proto_rawDescGZIP(), []int{12, 0}
 }
 
 type MetricsBase struct {
@@ -999,6 +999,177 @@
 	return ""
 }
 
+type PerfCounters struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// The timestamp of these counters in nanoseconds.
+	Time *uint64 `protobuf:"varint,1,opt,name=time" json:"time,omitempty"`
+	// A list of counter names and values.
+	Groups []*PerfCounterGroup `protobuf:"bytes,2,rep,name=groups" json:"groups,omitempty"`
+}
+
+func (x *PerfCounters) Reset() {
+	*x = PerfCounters{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_metrics_proto_msgTypes[4]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *PerfCounters) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PerfCounters) ProtoMessage() {}
+
+func (x *PerfCounters) ProtoReflect() protoreflect.Message {
+	mi := &file_metrics_proto_msgTypes[4]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use PerfCounters.ProtoReflect.Descriptor instead.
+func (*PerfCounters) Descriptor() ([]byte, []int) {
+	return file_metrics_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *PerfCounters) GetTime() uint64 {
+	if x != nil && x.Time != nil {
+		return *x.Time
+	}
+	return 0
+}
+
+func (x *PerfCounters) GetGroups() []*PerfCounterGroup {
+	if x != nil {
+		return x.Groups
+	}
+	return nil
+}
+
+type PerfCounterGroup struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// The name of this counter group (e.g. "cpu" or "memory")
+	Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
+	// The counters in this group
+	Counters []*PerfCounter `protobuf:"bytes,2,rep,name=counters" json:"counters,omitempty"`
+}
+
+func (x *PerfCounterGroup) Reset() {
+	*x = PerfCounterGroup{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_metrics_proto_msgTypes[5]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *PerfCounterGroup) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PerfCounterGroup) ProtoMessage() {}
+
+func (x *PerfCounterGroup) ProtoReflect() protoreflect.Message {
+	mi := &file_metrics_proto_msgTypes[5]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use PerfCounterGroup.ProtoReflect.Descriptor instead.
+func (*PerfCounterGroup) Descriptor() ([]byte, []int) {
+	return file_metrics_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *PerfCounterGroup) GetName() string {
+	if x != nil && x.Name != nil {
+		return *x.Name
+	}
+	return ""
+}
+
+func (x *PerfCounterGroup) GetCounters() []*PerfCounter {
+	if x != nil {
+		return x.Counters
+	}
+	return nil
+}
+
+type PerfCounter struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// The name of this counter.
+	Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
+	// The value of this counter.
+	Value *int64 `protobuf:"varint,2,opt,name=value" json:"value,omitempty"`
+}
+
+func (x *PerfCounter) Reset() {
+	*x = PerfCounter{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_metrics_proto_msgTypes[6]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *PerfCounter) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PerfCounter) ProtoMessage() {}
+
+func (x *PerfCounter) ProtoReflect() protoreflect.Message {
+	mi := &file_metrics_proto_msgTypes[6]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use PerfCounter.ProtoReflect.Descriptor instead.
+func (*PerfCounter) Descriptor() ([]byte, []int) {
+	return file_metrics_proto_rawDescGZIP(), []int{6}
+}
+
+func (x *PerfCounter) GetName() string {
+	if x != nil && x.Name != nil {
+		return *x.Name
+	}
+	return ""
+}
+
+func (x *PerfCounter) GetValue() int64 {
+	if x != nil && x.Value != nil {
+		return *x.Value
+	}
+	return 0
+}
+
 type ProcessResourceInfo struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
@@ -1029,7 +1200,7 @@
 func (x *ProcessResourceInfo) Reset() {
 	*x = ProcessResourceInfo{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_metrics_proto_msgTypes[4]
+		mi := &file_metrics_proto_msgTypes[7]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -1042,7 +1213,7 @@
 func (*ProcessResourceInfo) ProtoMessage() {}
 
 func (x *ProcessResourceInfo) ProtoReflect() protoreflect.Message {
-	mi := &file_metrics_proto_msgTypes[4]
+	mi := &file_metrics_proto_msgTypes[7]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1055,7 +1226,7 @@
 
 // Deprecated: Use ProcessResourceInfo.ProtoReflect.Descriptor instead.
 func (*ProcessResourceInfo) Descriptor() ([]byte, []int) {
-	return file_metrics_proto_rawDescGZIP(), []int{4}
+	return file_metrics_proto_rawDescGZIP(), []int{7}
 }
 
 func (x *ProcessResourceInfo) GetName() string {
@@ -1149,7 +1320,7 @@
 func (x *ModuleTypeInfo) Reset() {
 	*x = ModuleTypeInfo{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_metrics_proto_msgTypes[5]
+		mi := &file_metrics_proto_msgTypes[8]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -1162,7 +1333,7 @@
 func (*ModuleTypeInfo) ProtoMessage() {}
 
 func (x *ModuleTypeInfo) ProtoReflect() protoreflect.Message {
-	mi := &file_metrics_proto_msgTypes[5]
+	mi := &file_metrics_proto_msgTypes[8]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1175,7 +1346,7 @@
 
 // Deprecated: Use ModuleTypeInfo.ProtoReflect.Descriptor instead.
 func (*ModuleTypeInfo) Descriptor() ([]byte, []int) {
-	return file_metrics_proto_rawDescGZIP(), []int{5}
+	return file_metrics_proto_rawDescGZIP(), []int{8}
 }
 
 func (x *ModuleTypeInfo) GetBuildSystem() ModuleTypeInfo_BuildSystem {
@@ -1213,7 +1384,7 @@
 func (x *CriticalUserJourneyMetrics) Reset() {
 	*x = CriticalUserJourneyMetrics{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_metrics_proto_msgTypes[6]
+		mi := &file_metrics_proto_msgTypes[9]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -1226,7 +1397,7 @@
 func (*CriticalUserJourneyMetrics) ProtoMessage() {}
 
 func (x *CriticalUserJourneyMetrics) ProtoReflect() protoreflect.Message {
-	mi := &file_metrics_proto_msgTypes[6]
+	mi := &file_metrics_proto_msgTypes[9]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1239,7 +1410,7 @@
 
 // Deprecated: Use CriticalUserJourneyMetrics.ProtoReflect.Descriptor instead.
 func (*CriticalUserJourneyMetrics) Descriptor() ([]byte, []int) {
-	return file_metrics_proto_rawDescGZIP(), []int{6}
+	return file_metrics_proto_rawDescGZIP(), []int{9}
 }
 
 func (x *CriticalUserJourneyMetrics) GetName() string {
@@ -1268,7 +1439,7 @@
 func (x *CriticalUserJourneysMetrics) Reset() {
 	*x = CriticalUserJourneysMetrics{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_metrics_proto_msgTypes[7]
+		mi := &file_metrics_proto_msgTypes[10]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -1281,7 +1452,7 @@
 func (*CriticalUserJourneysMetrics) ProtoMessage() {}
 
 func (x *CriticalUserJourneysMetrics) ProtoReflect() protoreflect.Message {
-	mi := &file_metrics_proto_msgTypes[7]
+	mi := &file_metrics_proto_msgTypes[10]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1294,7 +1465,7 @@
 
 // Deprecated: Use CriticalUserJourneysMetrics.ProtoReflect.Descriptor instead.
 func (*CriticalUserJourneysMetrics) Descriptor() ([]byte, []int) {
-	return file_metrics_proto_rawDescGZIP(), []int{7}
+	return file_metrics_proto_rawDescGZIP(), []int{10}
 }
 
 func (x *CriticalUserJourneysMetrics) GetCujs() []*CriticalUserJourneyMetrics {
@@ -1323,12 +1494,14 @@
 	Events []*PerfInfo `protobuf:"bytes,6,rep,name=events" json:"events,omitempty"`
 	// Mixed Builds information
 	MixedBuildsInfo *MixedBuildsInfo `protobuf:"bytes,7,opt,name=mixed_builds_info,json=mixedBuildsInfo" json:"mixed_builds_info,omitempty"`
+	// Performance during for soong_build execution.
+	PerfCounters []*PerfCounters `protobuf:"bytes,8,rep,name=perf_counters,json=perfCounters" json:"perf_counters,omitempty"`
 }
 
 func (x *SoongBuildMetrics) Reset() {
 	*x = SoongBuildMetrics{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_metrics_proto_msgTypes[8]
+		mi := &file_metrics_proto_msgTypes[11]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -1341,7 +1514,7 @@
 func (*SoongBuildMetrics) ProtoMessage() {}
 
 func (x *SoongBuildMetrics) ProtoReflect() protoreflect.Message {
-	mi := &file_metrics_proto_msgTypes[8]
+	mi := &file_metrics_proto_msgTypes[11]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1354,7 +1527,7 @@
 
 // Deprecated: Use SoongBuildMetrics.ProtoReflect.Descriptor instead.
 func (*SoongBuildMetrics) Descriptor() ([]byte, []int) {
-	return file_metrics_proto_rawDescGZIP(), []int{8}
+	return file_metrics_proto_rawDescGZIP(), []int{11}
 }
 
 func (x *SoongBuildMetrics) GetModules() uint32 {
@@ -1406,6 +1579,13 @@
 	return nil
 }
 
+func (x *SoongBuildMetrics) GetPerfCounters() []*PerfCounters {
+	if x != nil {
+		return x.PerfCounters
+	}
+	return nil
+}
+
 type ExpConfigFetcher struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
@@ -1425,7 +1605,7 @@
 func (x *ExpConfigFetcher) Reset() {
 	*x = ExpConfigFetcher{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_metrics_proto_msgTypes[9]
+		mi := &file_metrics_proto_msgTypes[12]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -1438,7 +1618,7 @@
 func (*ExpConfigFetcher) ProtoMessage() {}
 
 func (x *ExpConfigFetcher) ProtoReflect() protoreflect.Message {
-	mi := &file_metrics_proto_msgTypes[9]
+	mi := &file_metrics_proto_msgTypes[12]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1451,7 +1631,7 @@
 
 // Deprecated: Use ExpConfigFetcher.ProtoReflect.Descriptor instead.
 func (*ExpConfigFetcher) Descriptor() ([]byte, []int) {
-	return file_metrics_proto_rawDescGZIP(), []int{9}
+	return file_metrics_proto_rawDescGZIP(), []int{12}
 }
 
 func (x *ExpConfigFetcher) GetStatus() ExpConfigFetcher_ConfigStatus {
@@ -1489,7 +1669,7 @@
 func (x *MixedBuildsInfo) Reset() {
 	*x = MixedBuildsInfo{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_metrics_proto_msgTypes[10]
+		mi := &file_metrics_proto_msgTypes[13]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -1502,7 +1682,7 @@
 func (*MixedBuildsInfo) ProtoMessage() {}
 
 func (x *MixedBuildsInfo) ProtoReflect() protoreflect.Message {
-	mi := &file_metrics_proto_msgTypes[10]
+	mi := &file_metrics_proto_msgTypes[13]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1515,7 +1695,7 @@
 
 // Deprecated: Use MixedBuildsInfo.ProtoReflect.Descriptor instead.
 func (*MixedBuildsInfo) Descriptor() ([]byte, []int) {
-	return file_metrics_proto_rawDescGZIP(), []int{10}
+	return file_metrics_proto_rawDescGZIP(), []int{13}
 }
 
 func (x *MixedBuildsInfo) GetMixedBuildEnabledModules() []string {
@@ -1552,7 +1732,7 @@
 func (x *CriticalPathInfo) Reset() {
 	*x = CriticalPathInfo{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_metrics_proto_msgTypes[11]
+		mi := &file_metrics_proto_msgTypes[14]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -1565,7 +1745,7 @@
 func (*CriticalPathInfo) ProtoMessage() {}
 
 func (x *CriticalPathInfo) ProtoReflect() protoreflect.Message {
-	mi := &file_metrics_proto_msgTypes[11]
+	mi := &file_metrics_proto_msgTypes[14]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1578,7 +1758,7 @@
 
 // Deprecated: Use CriticalPathInfo.ProtoReflect.Descriptor instead.
 func (*CriticalPathInfo) Descriptor() ([]byte, []int) {
-	return file_metrics_proto_rawDescGZIP(), []int{11}
+	return file_metrics_proto_rawDescGZIP(), []int{14}
 }
 
 func (x *CriticalPathInfo) GetElapsedTimeMicros() uint64 {
@@ -1623,7 +1803,7 @@
 func (x *JobInfo) Reset() {
 	*x = JobInfo{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_metrics_proto_msgTypes[12]
+		mi := &file_metrics_proto_msgTypes[15]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -1636,7 +1816,7 @@
 func (*JobInfo) ProtoMessage() {}
 
 func (x *JobInfo) ProtoReflect() protoreflect.Message {
-	mi := &file_metrics_proto_msgTypes[12]
+	mi := &file_metrics_proto_msgTypes[15]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1649,7 +1829,7 @@
 
 // Deprecated: Use JobInfo.ProtoReflect.Descriptor instead.
 func (*JobInfo) Descriptor() ([]byte, []int) {
-	return file_metrics_proto_rawDescGZIP(), []int{12}
+	return file_metrics_proto_rawDescGZIP(), []int{15}
 }
 
 func (x *JobInfo) GetElapsedTimeMicros() uint64 {
@@ -1856,132 +2036,153 @@
 	0x6f, 0x5f, 0x65, 0x78, 0x69, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x6e, 0x6f,
 	0x6e, 0x5a, 0x65, 0x72, 0x6f, 0x45, 0x78, 0x69, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x72, 0x72,
 	0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09,
-	0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xb9,
-	0x03, 0x0a, 0x13, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72,
-	0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01,
-	0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x10, 0x75, 0x73,
-	0x65, 0x72, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x02,
-	0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x75, 0x73, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69,
-	0x63, 0x72, 0x6f, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x74,
-	0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04,
-	0x52, 0x10, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72,
-	0x6f, 0x73, 0x12, 0x1c, 0x0a, 0x0a, 0x6d, 0x61, 0x78, 0x5f, 0x72, 0x73, 0x73, 0x5f, 0x6b, 0x62,
-	0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x52, 0x73, 0x73, 0x4b, 0x62,
-	0x12, 0x2a, 0x0a, 0x11, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x66,
-	0x61, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x6d, 0x69, 0x6e,
-	0x6f, 0x72, 0x50, 0x61, 0x67, 0x65, 0x46, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x2a, 0x0a, 0x11,
-	0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x66, 0x61, 0x75, 0x6c, 0x74,
-	0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x50, 0x61,
-	0x67, 0x65, 0x46, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x1e, 0x0a, 0x0b, 0x69, 0x6f, 0x5f, 0x69,
-	0x6e, 0x70, 0x75, 0x74, 0x5f, 0x6b, 0x62, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x69,
-	0x6f, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x4b, 0x62, 0x12, 0x20, 0x0a, 0x0c, 0x69, 0x6f, 0x5f, 0x6f,
-	0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x6b, 0x62, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a,
-	0x69, 0x6f, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x4b, 0x62, 0x12, 0x3c, 0x0a, 0x1a, 0x76, 0x6f,
-	0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x5f,
-	0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x18,
-	0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74,
-	0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x12, 0x40, 0x0a, 0x1c, 0x69, 0x6e, 0x76, 0x6f,
-	0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x5f,
-	0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x1a,
-	0x69, 0x6e, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x74, 0x65,
-	0x78, 0x74, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x22, 0xe5, 0x01, 0x0a, 0x0e, 0x4d,
-	0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x5b, 0x0a,
-	0x0c, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20,
-	0x01, 0x28, 0x0e, 0x32, 0x2f, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c,
-	0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65,
-	0x54, 0x79, 0x70, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x79,
-	0x73, 0x74, 0x65, 0x6d, 0x3a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x52, 0x0b, 0x62,
-	0x75, 0x69, 0x6c, 0x64, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x6f,
-	0x64, 0x75, 0x6c, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
-	0x0a, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x6e,
-	0x75, 0x6d, 0x5f, 0x6f, 0x66, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x03, 0x20,
-	0x01, 0x28, 0x0d, 0x52, 0x0c, 0x6e, 0x75, 0x6d, 0x4f, 0x66, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65,
-	0x73, 0x22, 0x2f, 0x0a, 0x0b, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d,
-	0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x09, 0x0a,
-	0x05, 0x53, 0x4f, 0x4f, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x4d, 0x41, 0x4b, 0x45,
-	0x10, 0x02, 0x22, 0x6c, 0x0a, 0x1a, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x55, 0x73,
+	0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x61,
+	0x0a, 0x0c, 0x50, 0x65, 0x72, 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x12, 0x12,
+	0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x74, 0x69,
+	0x6d, 0x65, 0x12, 0x3d, 0x0a, 0x06, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x18, 0x02, 0x20, 0x03,
+	0x28, 0x0b, 0x32, 0x25, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64,
+	0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x43, 0x6f, 0x75,
+	0x6e, 0x74, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x06, 0x67, 0x72, 0x6f, 0x75, 0x70,
+	0x73, 0x22, 0x64, 0x0a, 0x10, 0x50, 0x65, 0x72, 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72,
+	0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3c, 0x0a, 0x08, 0x63, 0x6f, 0x75,
+	0x6e, 0x74, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x6f,
+	0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63,
+	0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x08, 0x63,
+	0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x22, 0x37, 0x0a, 0x0b, 0x50, 0x65, 0x72, 0x66, 0x43,
+	0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61,
+	0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
+	0x22, 0xb9, 0x03, 0x0a, 0x13, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x6f,
+	0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x10,
+	0x75, 0x73, 0x65, 0x72, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73,
+	0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x75, 0x73, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65,
+	0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d,
+	0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01,
+	0x28, 0x04, 0x52, 0x10, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69,
+	0x63, 0x72, 0x6f, 0x73, 0x12, 0x1c, 0x0a, 0x0a, 0x6d, 0x61, 0x78, 0x5f, 0x72, 0x73, 0x73, 0x5f,
+	0x6b, 0x62, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x52, 0x73, 0x73,
+	0x4b, 0x62, 0x12, 0x2a, 0x0a, 0x11, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x5f, 0x70, 0x61, 0x67, 0x65,
+	0x5f, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x6d,
+	0x69, 0x6e, 0x6f, 0x72, 0x50, 0x61, 0x67, 0x65, 0x46, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x2a,
+	0x0a, 0x11, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x66, 0x61, 0x75,
+	0x6c, 0x74, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x6d, 0x61, 0x6a, 0x6f, 0x72,
+	0x50, 0x61, 0x67, 0x65, 0x46, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x1e, 0x0a, 0x0b, 0x69, 0x6f,
+	0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x6b, 0x62, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52,
+	0x09, 0x69, 0x6f, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x4b, 0x62, 0x12, 0x20, 0x0a, 0x0c, 0x69, 0x6f,
+	0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x6b, 0x62, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04,
+	0x52, 0x0a, 0x69, 0x6f, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x4b, 0x62, 0x12, 0x3c, 0x0a, 0x1a,
+	0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78,
+	0x74, 0x5f, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04,
+	0x52, 0x18, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x74, 0x65,
+	0x78, 0x74, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x12, 0x40, 0x0a, 0x1c, 0x69, 0x6e,
+	0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78,
+	0x74, 0x5f, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04,
+	0x52, 0x1a, 0x69, 0x6e, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x43, 0x6f, 0x6e,
+	0x74, 0x65, 0x78, 0x74, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x22, 0xe5, 0x01, 0x0a,
+	0x0e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12,
+	0x5b, 0x0a, 0x0c, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2f, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75,
+	0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, 0x6f, 0x64, 0x75,
+	0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64,
+	0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x3a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x52,
+	0x0b, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x1f, 0x0a, 0x0b,
+	0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x0a, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x24, 0x0a,
+	0x0e, 0x6e, 0x75, 0x6d, 0x5f, 0x6f, 0x66, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18,
+	0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x6e, 0x75, 0x6d, 0x4f, 0x66, 0x4d, 0x6f, 0x64, 0x75,
+	0x6c, 0x65, 0x73, 0x22, 0x2f, 0x0a, 0x0b, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x79, 0x73, 0x74,
+	0x65, 0x6d, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12,
+	0x09, 0x0a, 0x05, 0x53, 0x4f, 0x4f, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x4d, 0x41,
+	0x4b, 0x45, 0x10, 0x02, 0x22, 0x6c, 0x0a, 0x1a, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c,
+	0x55, 0x73, 0x65, 0x72, 0x4a, 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x79, 0x4d, 0x65, 0x74, 0x72, 0x69,
+	0x63, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3a, 0x0a, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63,
+	0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f,
+	0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, 0x65,
+	0x74, 0x72, 0x69, 0x63, 0x73, 0x42, 0x61, 0x73, 0x65, 0x52, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69,
+	0x63, 0x73, 0x22, 0x62, 0x0a, 0x1b, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x55, 0x73,
+	0x65, 0x72, 0x4a, 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x79, 0x73, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63,
+	0x73, 0x12, 0x43, 0x0a, 0x04, 0x63, 0x75, 0x6a, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
+	0x2f, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65,
+	0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x55, 0x73,
 	0x65, 0x72, 0x4a, 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x79, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
-	0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
-	0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3a, 0x0a, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x18,
-	0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75,
-	0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x72,
-	0x69, 0x63, 0x73, 0x42, 0x61, 0x73, 0x65, 0x52, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
-	0x22, 0x62, 0x0a, 0x1b, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x55, 0x73, 0x65, 0x72,
-	0x4a, 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x79, 0x73, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12,
-	0x43, 0x0a, 0x04, 0x63, 0x75, 0x6a, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e,
+	0x52, 0x04, 0x63, 0x75, 0x6a, 0x73, 0x22, 0x94, 0x03, 0x0a, 0x11, 0x53, 0x6f, 0x6f, 0x6e, 0x67,
+	0x42, 0x75, 0x69, 0x6c, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x18, 0x0a, 0x07,
+	0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x6d,
+	0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e,
+	0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e,
+	0x74, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x61, 0x6c, 0x6c, 0x6f,
+	0x63, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x74,
+	0x6f, 0x74, 0x61, 0x6c, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x28,
+	0x0a, 0x10, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x5f, 0x73, 0x69,
+	0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x41,
+	0x6c, 0x6c, 0x6f, 0x63, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x6d, 0x61, 0x78, 0x5f,
+	0x68, 0x65, 0x61, 0x70, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52,
+	0x0b, 0x6d, 0x61, 0x78, 0x48, 0x65, 0x61, 0x70, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x35, 0x0a, 0x06,
+	0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x73,
+	0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69,
+	0x63, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x65, 0x76, 0x65,
+	0x6e, 0x74, 0x73, 0x12, 0x50, 0x0a, 0x11, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69,
+	0x6c, 0x64, 0x73, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24,
+	0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74,
+	0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73,
+	0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0f, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64,
+	0x73, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x46, 0x0a, 0x0d, 0x70, 0x65, 0x72, 0x66, 0x5f, 0x63, 0x6f,
+	0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x73,
+	0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69,
+	0x63, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x52,
+	0x0c, 0x70, 0x65, 0x72, 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x22, 0xdb, 0x01,
+	0x0a, 0x10, 0x45, 0x78, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x65, 0x74, 0x63, 0x68,
+	0x65, 0x72, 0x12, 0x4a, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01,
+	0x28, 0x0e, 0x32, 0x32, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64,
+	0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x45, 0x78, 0x70, 0x43, 0x6f, 0x6e, 0x66,
+	0x69, 0x67, 0x46, 0x65, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
+	0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1a,
+	0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x69,
+	0x63, 0x72, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6d, 0x69, 0x63, 0x72,
+	0x6f, 0x73, 0x22, 0x47, 0x0a, 0x0c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x74, 0x61, 0x74,
+	0x75, 0x73, 0x12, 0x0d, 0x0a, 0x09, 0x4e, 0x4f, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10,
+	0x00, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10, 0x01, 0x12, 0x09, 0x0a,
+	0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x4d, 0x49, 0x53, 0x53,
+	0x49, 0x4e, 0x47, 0x5f, 0x47, 0x43, 0x45, 0x52, 0x54, 0x10, 0x03, 0x22, 0x91, 0x01, 0x0a, 0x0f,
+	0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x12,
+	0x3d, 0x0a, 0x1b, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x65,
+	0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01,
+	0x20, 0x03, 0x28, 0x09, 0x52, 0x18, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64,
+	0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x3f,
+	0x0a, 0x1c, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x64, 0x69,
+	0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x02,
+	0x20, 0x03, 0x28, 0x09, 0x52, 0x19, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64,
+	0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x22,
+	0x8a, 0x02, 0x0a, 0x10, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68,
+	0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2e, 0x0a, 0x13, 0x65, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64, 0x5f,
+	0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x04, 0x52, 0x11, 0x65, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69,
+	0x63, 0x72, 0x6f, 0x73, 0x12, 0x39, 0x0a, 0x19, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c,
+	0x5f, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f,
+	0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x16, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61,
+	0x6c, 0x50, 0x61, 0x74, 0x68, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12,
+	0x41, 0x0a, 0x0d, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x70, 0x61, 0x74, 0x68,
+	0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62,
+	0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4a, 0x6f, 0x62,
+	0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0c, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x50, 0x61,
+	0x74, 0x68, 0x12, 0x48, 0x0a, 0x11, 0x6c, 0x6f, 0x6e, 0x67, 0x5f, 0x72, 0x75, 0x6e, 0x6e, 0x69,
+	0x6e, 0x67, 0x5f, 0x6a, 0x6f, 0x62, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e,
 	0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72,
-	0x69, 0x63, 0x73, 0x2e, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x55, 0x73, 0x65, 0x72,
-	0x4a, 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x79, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x04,
-	0x63, 0x75, 0x6a, 0x73, 0x22, 0xcc, 0x02, 0x0a, 0x11, 0x53, 0x6f, 0x6f, 0x6e, 0x67, 0x42, 0x75,
-	0x69, 0x6c, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x6f,
-	0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x6d, 0x6f, 0x64,
-	0x75, 0x6c, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, 0x73,
-	0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, 0x73,
-	0x12, 0x2a, 0x0a, 0x11, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x5f,
-	0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x74, 0x6f, 0x74,
-	0x61, 0x6c, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x10,
-	0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x5f, 0x73, 0x69, 0x7a, 0x65,
-	0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x41, 0x6c, 0x6c,
-	0x6f, 0x63, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x6d, 0x61, 0x78, 0x5f, 0x68, 0x65,
-	0x61, 0x70, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x6d,
-	0x61, 0x78, 0x48, 0x65, 0x61, 0x70, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x35, 0x0a, 0x06, 0x65, 0x76,
-	0x65, 0x6e, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x73, 0x6f, 0x6f,
-	0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
-	0x2e, 0x50, 0x65, 0x72, 0x66, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74,
-	0x73, 0x12, 0x50, 0x0a, 0x11, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64,
-	0x73, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x73,
-	0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69,
-	0x63, 0x73, 0x2e, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x49, 0x6e,
-	0x66, 0x6f, 0x52, 0x0f, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x49,
-	0x6e, 0x66, 0x6f, 0x22, 0xdb, 0x01, 0x0a, 0x10, 0x45, 0x78, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69,
-	0x67, 0x46, 0x65, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x4a, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74,
-	0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x32, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67,
-	0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x45,
-	0x78, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x65, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2e,
-	0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74,
-	0x61, 0x74, 0x75, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65,
-	0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65,
-	0x12, 0x16, 0x0a, 0x06, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04,
-	0x52, 0x06, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x22, 0x47, 0x0a, 0x0c, 0x43, 0x6f, 0x6e, 0x66,
-	0x69, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0d, 0x0a, 0x09, 0x4e, 0x4f, 0x5f, 0x43,
-	0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x4f, 0x4e, 0x46, 0x49,
-	0x47, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x12, 0x11,
-	0x0a, 0x0d, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4e, 0x47, 0x5f, 0x47, 0x43, 0x45, 0x52, 0x54, 0x10,
-	0x03, 0x22, 0x91, 0x01, 0x0a, 0x0f, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64,
-	0x73, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x3d, 0x0a, 0x1b, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62,
-	0x75, 0x69, 0x6c, 0x64, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f, 0x6d, 0x6f, 0x64,
-	0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x18, 0x6d, 0x69, 0x78, 0x65,
-	0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x4d, 0x6f, 0x64,
-	0x75, 0x6c, 0x65, 0x73, 0x12, 0x3f, 0x0a, 0x1c, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75,
-	0x69, 0x6c, 0x64, 0x5f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f, 0x6d, 0x6f, 0x64,
-	0x75, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x19, 0x6d, 0x69, 0x78, 0x65,
-	0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x4d, 0x6f,
-	0x64, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x8a, 0x02, 0x0a, 0x10, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63,
-	0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2e, 0x0a, 0x13, 0x65, 0x6c,
-	0x61, 0x70, 0x73, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f,
-	0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x11, 0x65, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64,
-	0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x39, 0x0a, 0x19, 0x63, 0x72,
-	0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x74, 0x69, 0x6d, 0x65,
-	0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x16, 0x63,
-	0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x54, 0x69, 0x6d, 0x65, 0x4d,
-	0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x41, 0x0a, 0x0d, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61,
-	0x6c, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73,
-	0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69,
-	0x63, 0x73, 0x2e, 0x4a, 0x6f, 0x62, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0c, 0x63, 0x72, 0x69, 0x74,
-	0x69, 0x63, 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x12, 0x48, 0x0a, 0x11, 0x6c, 0x6f, 0x6e, 0x67,
-	0x5f, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x6a, 0x6f, 0x62, 0x73, 0x18, 0x05, 0x20,
-	0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c,
-	0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4a, 0x6f, 0x62, 0x49, 0x6e, 0x66,
-	0x6f, 0x52, 0x0f, 0x6c, 0x6f, 0x6e, 0x67, 0x52, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x4a, 0x6f,
-	0x62, 0x73, 0x22, 0x62, 0x0a, 0x07, 0x4a, 0x6f, 0x62, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2e, 0x0a,
-	0x13, 0x65, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69,
-	0x63, 0x72, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x11, 0x65, 0x6c, 0x61, 0x70,
-	0x73, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x27, 0x0a,
-	0x0f, 0x6a, 0x6f, 0x62, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e,
-	0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x6a, 0x6f, 0x62, 0x44, 0x65, 0x73, 0x63, 0x72,
-	0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x28, 0x5a, 0x26, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69,
-	0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x75, 0x69, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69,
-	0x63, 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x69, 0x63, 0x73, 0x2e, 0x4a, 0x6f, 0x62, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0f, 0x6c, 0x6f, 0x6e,
+	0x67, 0x52, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x4a, 0x6f, 0x62, 0x73, 0x22, 0x62, 0x0a, 0x07,
+	0x4a, 0x6f, 0x62, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2e, 0x0a, 0x13, 0x65, 0x6c, 0x61, 0x70, 0x73,
+	0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x04, 0x52, 0x11, 0x65, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64, 0x54, 0x69, 0x6d,
+	0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x6a, 0x6f, 0x62, 0x5f, 0x64,
+	0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x0e, 0x6a, 0x6f, 0x62, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e,
+	0x42, 0x28, 0x5a, 0x26, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e,
+	0x67, 0x2f, 0x75, 0x69, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x6d, 0x65, 0x74,
+	0x72, 0x69, 0x63, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
 }
 
 var (
@@ -1997,7 +2198,7 @@
 }
 
 var file_metrics_proto_enumTypes = make([]protoimpl.EnumInfo, 5)
-var file_metrics_proto_msgTypes = make([]protoimpl.MessageInfo, 13)
+var file_metrics_proto_msgTypes = make([]protoimpl.MessageInfo, 16)
 var file_metrics_proto_goTypes = []interface{}{
 	(MetricsBase_BuildVariant)(0),          // 0: soong_build_metrics.MetricsBase.BuildVariant
 	(MetricsBase_Arch)(0),                  // 1: soong_build_metrics.MetricsBase.Arch
@@ -2008,15 +2209,18 @@
 	(*BuildConfig)(nil),                    // 6: soong_build_metrics.BuildConfig
 	(*SystemResourceInfo)(nil),             // 7: soong_build_metrics.SystemResourceInfo
 	(*PerfInfo)(nil),                       // 8: soong_build_metrics.PerfInfo
-	(*ProcessResourceInfo)(nil),            // 9: soong_build_metrics.ProcessResourceInfo
-	(*ModuleTypeInfo)(nil),                 // 10: soong_build_metrics.ModuleTypeInfo
-	(*CriticalUserJourneyMetrics)(nil),     // 11: soong_build_metrics.CriticalUserJourneyMetrics
-	(*CriticalUserJourneysMetrics)(nil),    // 12: soong_build_metrics.CriticalUserJourneysMetrics
-	(*SoongBuildMetrics)(nil),              // 13: soong_build_metrics.SoongBuildMetrics
-	(*ExpConfigFetcher)(nil),               // 14: soong_build_metrics.ExpConfigFetcher
-	(*MixedBuildsInfo)(nil),                // 15: soong_build_metrics.MixedBuildsInfo
-	(*CriticalPathInfo)(nil),               // 16: soong_build_metrics.CriticalPathInfo
-	(*JobInfo)(nil),                        // 17: soong_build_metrics.JobInfo
+	(*PerfCounters)(nil),                   // 9: soong_build_metrics.PerfCounters
+	(*PerfCounterGroup)(nil),               // 10: soong_build_metrics.PerfCounterGroup
+	(*PerfCounter)(nil),                    // 11: soong_build_metrics.PerfCounter
+	(*ProcessResourceInfo)(nil),            // 12: soong_build_metrics.ProcessResourceInfo
+	(*ModuleTypeInfo)(nil),                 // 13: soong_build_metrics.ModuleTypeInfo
+	(*CriticalUserJourneyMetrics)(nil),     // 14: soong_build_metrics.CriticalUserJourneyMetrics
+	(*CriticalUserJourneysMetrics)(nil),    // 15: soong_build_metrics.CriticalUserJourneysMetrics
+	(*SoongBuildMetrics)(nil),              // 16: soong_build_metrics.SoongBuildMetrics
+	(*ExpConfigFetcher)(nil),               // 17: soong_build_metrics.ExpConfigFetcher
+	(*MixedBuildsInfo)(nil),                // 18: soong_build_metrics.MixedBuildsInfo
+	(*CriticalPathInfo)(nil),               // 19: soong_build_metrics.CriticalPathInfo
+	(*JobInfo)(nil),                        // 20: soong_build_metrics.JobInfo
 }
 var file_metrics_proto_depIdxs = []int32{
 	0,  // 0: soong_build_metrics.MetricsBase.target_build_variant:type_name -> soong_build_metrics.MetricsBase.BuildVariant
@@ -2028,27 +2232,30 @@
 	8,  // 6: soong_build_metrics.MetricsBase.soong_runs:type_name -> soong_build_metrics.PerfInfo
 	8,  // 7: soong_build_metrics.MetricsBase.ninja_runs:type_name -> soong_build_metrics.PerfInfo
 	8,  // 8: soong_build_metrics.MetricsBase.total:type_name -> soong_build_metrics.PerfInfo
-	13, // 9: soong_build_metrics.MetricsBase.soong_build_metrics:type_name -> soong_build_metrics.SoongBuildMetrics
+	16, // 9: soong_build_metrics.MetricsBase.soong_build_metrics:type_name -> soong_build_metrics.SoongBuildMetrics
 	6,  // 10: soong_build_metrics.MetricsBase.build_config:type_name -> soong_build_metrics.BuildConfig
 	7,  // 11: soong_build_metrics.MetricsBase.system_resource_info:type_name -> soong_build_metrics.SystemResourceInfo
 	8,  // 12: soong_build_metrics.MetricsBase.bazel_runs:type_name -> soong_build_metrics.PerfInfo
-	14, // 13: soong_build_metrics.MetricsBase.exp_config_fetcher:type_name -> soong_build_metrics.ExpConfigFetcher
-	16, // 14: soong_build_metrics.MetricsBase.critical_path_info:type_name -> soong_build_metrics.CriticalPathInfo
+	17, // 13: soong_build_metrics.MetricsBase.exp_config_fetcher:type_name -> soong_build_metrics.ExpConfigFetcher
+	19, // 14: soong_build_metrics.MetricsBase.critical_path_info:type_name -> soong_build_metrics.CriticalPathInfo
 	2,  // 15: soong_build_metrics.BuildConfig.ninja_weight_list_source:type_name -> soong_build_metrics.BuildConfig.NinjaWeightListSource
-	9,  // 16: soong_build_metrics.PerfInfo.processes_resource_info:type_name -> soong_build_metrics.ProcessResourceInfo
-	3,  // 17: soong_build_metrics.ModuleTypeInfo.build_system:type_name -> soong_build_metrics.ModuleTypeInfo.BuildSystem
-	5,  // 18: soong_build_metrics.CriticalUserJourneyMetrics.metrics:type_name -> soong_build_metrics.MetricsBase
-	11, // 19: soong_build_metrics.CriticalUserJourneysMetrics.cujs:type_name -> soong_build_metrics.CriticalUserJourneyMetrics
-	8,  // 20: soong_build_metrics.SoongBuildMetrics.events:type_name -> soong_build_metrics.PerfInfo
-	15, // 21: soong_build_metrics.SoongBuildMetrics.mixed_builds_info:type_name -> soong_build_metrics.MixedBuildsInfo
-	4,  // 22: soong_build_metrics.ExpConfigFetcher.status:type_name -> soong_build_metrics.ExpConfigFetcher.ConfigStatus
-	17, // 23: soong_build_metrics.CriticalPathInfo.critical_path:type_name -> soong_build_metrics.JobInfo
-	17, // 24: soong_build_metrics.CriticalPathInfo.long_running_jobs:type_name -> soong_build_metrics.JobInfo
-	25, // [25:25] is the sub-list for method output_type
-	25, // [25:25] is the sub-list for method input_type
-	25, // [25:25] is the sub-list for extension type_name
-	25, // [25:25] is the sub-list for extension extendee
-	0,  // [0:25] is the sub-list for field type_name
+	12, // 16: soong_build_metrics.PerfInfo.processes_resource_info:type_name -> soong_build_metrics.ProcessResourceInfo
+	10, // 17: soong_build_metrics.PerfCounters.groups:type_name -> soong_build_metrics.PerfCounterGroup
+	11, // 18: soong_build_metrics.PerfCounterGroup.counters:type_name -> soong_build_metrics.PerfCounter
+	3,  // 19: soong_build_metrics.ModuleTypeInfo.build_system:type_name -> soong_build_metrics.ModuleTypeInfo.BuildSystem
+	5,  // 20: soong_build_metrics.CriticalUserJourneyMetrics.metrics:type_name -> soong_build_metrics.MetricsBase
+	14, // 21: soong_build_metrics.CriticalUserJourneysMetrics.cujs:type_name -> soong_build_metrics.CriticalUserJourneyMetrics
+	8,  // 22: soong_build_metrics.SoongBuildMetrics.events:type_name -> soong_build_metrics.PerfInfo
+	18, // 23: soong_build_metrics.SoongBuildMetrics.mixed_builds_info:type_name -> soong_build_metrics.MixedBuildsInfo
+	9,  // 24: soong_build_metrics.SoongBuildMetrics.perf_counters:type_name -> soong_build_metrics.PerfCounters
+	4,  // 25: soong_build_metrics.ExpConfigFetcher.status:type_name -> soong_build_metrics.ExpConfigFetcher.ConfigStatus
+	20, // 26: soong_build_metrics.CriticalPathInfo.critical_path:type_name -> soong_build_metrics.JobInfo
+	20, // 27: soong_build_metrics.CriticalPathInfo.long_running_jobs:type_name -> soong_build_metrics.JobInfo
+	28, // [28:28] is the sub-list for method output_type
+	28, // [28:28] is the sub-list for method input_type
+	28, // [28:28] is the sub-list for extension type_name
+	28, // [28:28] is the sub-list for extension extendee
+	0,  // [0:28] is the sub-list for field type_name
 }
 
 func init() { file_metrics_proto_init() }
@@ -2106,7 +2313,7 @@
 			}
 		}
 		file_metrics_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*ProcessResourceInfo); i {
+			switch v := v.(*PerfCounters); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -2118,7 +2325,7 @@
 			}
 		}
 		file_metrics_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*ModuleTypeInfo); i {
+			switch v := v.(*PerfCounterGroup); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -2130,7 +2337,7 @@
 			}
 		}
 		file_metrics_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*CriticalUserJourneyMetrics); i {
+			switch v := v.(*PerfCounter); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -2142,7 +2349,7 @@
 			}
 		}
 		file_metrics_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*CriticalUserJourneysMetrics); i {
+			switch v := v.(*ProcessResourceInfo); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -2154,7 +2361,7 @@
 			}
 		}
 		file_metrics_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*SoongBuildMetrics); i {
+			switch v := v.(*ModuleTypeInfo); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -2166,7 +2373,7 @@
 			}
 		}
 		file_metrics_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*ExpConfigFetcher); i {
+			switch v := v.(*CriticalUserJourneyMetrics); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -2178,7 +2385,7 @@
 			}
 		}
 		file_metrics_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*MixedBuildsInfo); i {
+			switch v := v.(*CriticalUserJourneysMetrics); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -2190,7 +2397,7 @@
 			}
 		}
 		file_metrics_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*CriticalPathInfo); i {
+			switch v := v.(*SoongBuildMetrics); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -2202,6 +2409,42 @@
 			}
 		}
 		file_metrics_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ExpConfigFetcher); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_metrics_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*MixedBuildsInfo); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_metrics_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*CriticalPathInfo); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_metrics_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} {
 			switch v := v.(*JobInfo); i {
 			case 0:
 				return &v.state
@@ -2220,7 +2463,7 @@
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 			RawDescriptor: file_metrics_proto_rawDesc,
 			NumEnums:      5,
-			NumMessages:   13,
+			NumMessages:   16,
 			NumExtensions: 0,
 			NumServices:   0,
 		},
diff --git a/ui/metrics/metrics_proto/metrics.proto b/ui/metrics/metrics_proto/metrics.proto
index b437da7..11fcba7 100644
--- a/ui/metrics/metrics_proto/metrics.proto
+++ b/ui/metrics/metrics_proto/metrics.proto
@@ -213,6 +213,30 @@
   optional string error_message = 8;
 }
 
+message PerfCounters {
+  // The timestamp of these counters in nanoseconds.
+  optional uint64 time = 1;
+
+  // A list of counter names and values.
+  repeated PerfCounterGroup groups = 2;
+}
+
+message PerfCounterGroup {
+  // The name of this counter group (e.g. "cpu" or "memory")
+  optional string name = 1;
+
+  // The counters in this group
+  repeated PerfCounter counters = 2;
+}
+
+message PerfCounter {
+  // The name of this counter.
+  optional string name = 1;
+
+  // The value of this counter.
+  optional int64 value = 2;
+}
+
 message ProcessResourceInfo {
   // The name of the process for identification.
   optional string name = 1;
@@ -295,6 +319,9 @@
 
   // Mixed Builds information
   optional MixedBuildsInfo mixed_builds_info = 7;
+
+  // Performance during for soong_build execution.
+  repeated PerfCounters perf_counters = 8;
 }
 
 message ExpConfigFetcher {
diff --git a/ui/tracer/tracer.go b/ui/tracer/tracer.go
index b8fc87b..33b3d89 100644
--- a/ui/tracer/tracer.go
+++ b/ui/tracer/tracer.go
@@ -46,6 +46,8 @@
 	End(thread Thread)
 	Complete(name string, thread Thread, begin, end uint64)
 
+	CountersAtTime(name string, thread Thread, time uint64, counters []Counter)
+
 	ImportMicrofactoryLog(filename string)
 
 	StatusTracer() status.StatusOutput
@@ -247,3 +249,48 @@
 		Tid:   uint64(thread),
 	})
 }
+
+type Counter struct {
+	Name  string
+	Value int64
+}
+
+type countersMarshaller []Counter
+
+var _ json.Marshaler = countersMarshaller(nil)
+
+func (counters countersMarshaller) MarshalJSON() ([]byte, error) {
+	// This produces similar output to a map[string]int64, but maintains the order of the slice.
+	buf := bytes.Buffer{}
+	buf.WriteRune('{')
+	for i, counter := range counters {
+		name, err := json.Marshal(counter.Name)
+		if err != nil {
+			return nil, err
+		}
+		buf.Write(name)
+		buf.WriteByte(':')
+		value, err := json.Marshal(counter.Value)
+		if err != nil {
+			return nil, err
+		}
+		buf.Write(value)
+		if i != len(counters)-1 {
+			buf.WriteRune(',')
+		}
+	}
+	buf.WriteRune('}')
+	return buf.Bytes(), nil
+}
+
+// CountersAtTime writes a Counter event at the given timestamp in nanoseconds.
+func (t *tracerImpl) CountersAtTime(name string, thread Thread, time uint64, counters []Counter) {
+	t.writeEvent(&viewerEvent{
+		Name:  name,
+		Phase: "C",
+		Time:  time / 1000,
+		Pid:   0,
+		Tid:   uint64(thread),
+		Arg:   countersMarshaller(counters),
+	})
+}