Merge "Change default for source_build config variable to true."
diff --git a/android/androidmk.go b/android/androidmk.go
index b32048a..062dcb3 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -820,7 +820,7 @@
 	}
 
 	return !module.Enabled() ||
-		module.commonProperties.SkipInstall ||
+		module.commonProperties.HideFromMake ||
 		// Make does not understand LinuxBionic
 		module.Os() == LinuxBionic
 }
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 7d8d12f..81ca475 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -27,6 +27,9 @@
 	"sync"
 
 	"github.com/google/blueprint/bootstrap"
+
+	"android/soong/bazel"
+	"android/soong/shared"
 )
 
 type CqueryRequestType int
@@ -58,6 +61,12 @@
 
 	// Returns true if bazel is enabled for the given configuration.
 	BazelEnabled() bool
+
+	// Returns the bazel output base (the root directory for all bazel intermediate outputs).
+	OutputBase() string
+
+	// Returns build statements which should get registered to reflect Bazel's outputs.
+	BuildStatementsToRegister() []bazel.BuildStatement
 }
 
 // A context object which tracks queued requests that need to be made to Bazel,
@@ -68,11 +77,15 @@
 	outputBase   string
 	workspaceDir string
 	buildDir     string
+	metricsDir   string
 
 	requests     map[cqueryKey]bool // cquery requests that have not yet been issued to Bazel
 	requestMutex sync.Mutex         // requests can be written in parallel
 
 	results map[cqueryKey]string // Results of cquery requests after Bazel invocations
+
+	// Build statements which should get registered to reflect Bazel's outputs.
+	buildStatements []bazel.BuildStatement
 }
 
 var _ BazelContext = &bazelContext{}
@@ -100,6 +113,14 @@
 	return true
 }
 
+func (m MockBazelContext) OutputBase() string {
+	return "outputbase"
+}
+
+func (m MockBazelContext) BuildStatementsToRegister() []bazel.BuildStatement {
+	return []bazel.BuildStatement{}
+}
+
 var _ BazelContext = MockBazelContext{}
 
 func (bazelCtx *bazelContext) GetAllFiles(label string) ([]string, bool) {
@@ -120,10 +141,18 @@
 	panic("unimplemented")
 }
 
+func (m noopBazelContext) OutputBase() string {
+	return ""
+}
+
 func (n noopBazelContext) BazelEnabled() bool {
 	return false
 }
 
+func (m noopBazelContext) BuildStatementsToRegister() []bazel.BuildStatement {
+	return []bazel.BuildStatement{}
+}
+
 func NewBazelContext(c *config) (BazelContext, error) {
 	// TODO(cparsons): Assess USE_BAZEL=1 instead once "mixed Soong/Bazel builds"
 	// are production ready.
@@ -153,6 +182,11 @@
 	} else {
 		missingEnvVars = append(missingEnvVars, "BAZEL_WORKSPACE")
 	}
+	if len(c.Getenv("BAZEL_METRICS_DIR")) > 1 {
+		bazelCtx.metricsDir = c.Getenv("BAZEL_METRICS_DIR")
+	} else {
+		missingEnvVars = append(missingEnvVars, "BAZEL_METRICS_DIR")
+	}
 	if len(missingEnvVars) > 0 {
 		return nil, errors.New(fmt.Sprintf("missing required env vars to use bazel: %s", missingEnvVars))
 	} else {
@@ -160,6 +194,10 @@
 	}
 }
 
+func (context *bazelContext) BazelMetricsDir() string {
+	return context.metricsDir
+}
+
 func (context *bazelContext) BazelEnabled() bool {
 	return true
 }
@@ -189,12 +227,13 @@
 	return ""
 }
 
-func (context *bazelContext) issueBazelCommand(command string, labels []string,
+func (context *bazelContext) issueBazelCommand(runName bazel.RunName, command string, labels []string,
 	extraFlags ...string) (string, error) {
 
 	cmdFlags := []string{"--output_base=" + context.outputBase, command}
 	cmdFlags = append(cmdFlags, labels...)
 	cmdFlags = append(cmdFlags, "--package_path=%workspace%/"+context.intermediatesDir())
+	cmdFlags = append(cmdFlags, "--profile="+shared.BazelMetricsFilename(context, runName))
 	cmdFlags = append(cmdFlags, extraFlags...)
 
 	bazelCmd := exec.Command(context.bazelPath, cmdFlags...)
@@ -228,14 +267,32 @@
 
 func (context *bazelContext) mainBzlFileContents() []byte {
 	contents := `
+#####################################################
 # This file is generated by soong_build. Do not edit.
+#####################################################
+
 def _mixed_build_root_impl(ctx):
     return [DefaultInfo(files = depset(ctx.files.deps))]
 
+# Rule representing the root of the build, to depend on all Bazel targets that
+# are required for the build. Building this target will build the entire Bazel
+# build tree.
 mixed_build_root = rule(
     implementation = _mixed_build_root_impl,
     attrs = {"deps" : attr.label_list()},
 )
+
+def _phony_root_impl(ctx):
+    return []
+
+# Rule to depend on other targets but build nothing.
+# This is useful as follows: building a target of this rule will generate
+# symlink forests for all dependencies of the target, without executing any
+# actions of the build.
+phony_root = rule(
+    implementation = _phony_root_impl,
+    attrs = {"deps" : attr.label_list()},
+)
 `
 	return []byte(contents)
 }
@@ -255,11 +312,15 @@
 func (context *bazelContext) mainBuildFileContents() []byte {
 	formatString := `
 # This file is generated by soong_build. Do not edit.
-load(":main.bzl", "mixed_build_root")
+load(":main.bzl", "mixed_build_root", "phony_root")
 
 mixed_build_root(name = "buildroot",
     deps = [%s],
 )
+
+phony_root(name = "phonyroot",
+    deps = [":buildroot"],
+)
 `
 	var buildRootDeps []string = nil
 	for val, _ := range context.requests {
@@ -341,7 +402,7 @@
 		return err
 	}
 	buildroot_label := "//:buildroot"
-	cqueryOutput, err = context.issueBazelCommand("cquery",
+	cqueryOutput, err = context.issueBazelCommand(bazel.CqueryBuildRootRunName, "cquery",
 		[]string{fmt.Sprintf("deps(%s)", buildroot_label)},
 		"--output=starlark",
 		"--starlark:file="+cquery_file_relpath)
@@ -366,22 +427,46 @@
 		}
 	}
 
-	// Issue a build command.
-	// TODO(cparsons): Invoking bazel execution during soong_build should be avoided;
-	// bazel actions should either be added to the Ninja file and executed later,
-	// or bazel should handle execution.
+	// Issue an aquery command to retrieve action information about the bazel build tree.
+	//
 	// TODO(cparsons): Use --target_pattern_file to avoid command line limits.
-	_, err = context.issueBazelCommand("build", []string{buildroot_label})
+	var aqueryOutput string
+	aqueryOutput, err = context.issueBazelCommand(bazel.AqueryBuildRootRunName, "aquery",
+		[]string{fmt.Sprintf("deps(%s)", buildroot_label),
+			// Use jsonproto instead of proto; actual proto parsing would require a dependency on Bazel's
+			// proto sources, which would add a number of unnecessary dependencies.
+			"--output=jsonproto"})
 
 	if err != nil {
 		return err
 	}
 
+	context.buildStatements = bazel.AqueryBuildStatements([]byte(aqueryOutput))
+
+	// Issue a build command of the phony root to generate symlink forests for dependencies of the
+	// Bazel build. This is necessary because aquery invocations do not generate this symlink forest,
+	// but some of symlinks may be required to resolve source dependencies of the build.
+	_, err = context.issueBazelCommand(bazel.BazelBuildPhonyRootRunName, "build",
+		[]string{"//:phonyroot"})
+
+	if err != nil {
+		return err
+	}
+
+	fmt.Printf("Build statements %s", context.buildStatements)
 	// Clear requests.
 	context.requests = map[cqueryKey]bool{}
 	return nil
 }
 
+func (context *bazelContext) BuildStatementsToRegister() []bazel.BuildStatement {
+	return context.buildStatements
+}
+
+func (context *bazelContext) OutputBase() string {
+	return context.outputBase
+}
+
 // Singleton used for registering BUILD file ninja dependencies (needed
 // for correctness of builds which use Bazel.
 func BazelSingleton() Singleton {
@@ -391,18 +476,45 @@
 type bazelSingleton struct{}
 
 func (c *bazelSingleton) GenerateBuildActions(ctx SingletonContext) {
-	if ctx.Config().BazelContext.BazelEnabled() {
-		bazelBuildList := absolutePath(filepath.Join(
-			filepath.Dir(bootstrap.ModuleListFile), "bazel.list"))
-		ctx.AddNinjaFileDeps(bazelBuildList)
+	// bazelSingleton is a no-op if mixed-soong-bazel-builds are disabled.
+	if !ctx.Config().BazelContext.BazelEnabled() {
+		return
+	}
 
-		data, err := ioutil.ReadFile(bazelBuildList)
-		if err != nil {
-			ctx.Errorf(err.Error())
+	// Add ninja file dependencies for files which all bazel invocations require.
+	bazelBuildList := absolutePath(filepath.Join(
+		filepath.Dir(bootstrap.ModuleListFile), "bazel.list"))
+	ctx.AddNinjaFileDeps(bazelBuildList)
+
+	data, err := ioutil.ReadFile(bazelBuildList)
+	if err != nil {
+		ctx.Errorf(err.Error())
+	}
+	files := strings.Split(strings.TrimSpace(string(data)), "\n")
+	for _, file := range files {
+		ctx.AddNinjaFileDeps(file)
+	}
+
+	// Register bazel-owned build statements (obtained from the aquery invocation).
+	for index, buildStatement := range ctx.Config().BazelContext.BuildStatementsToRegister() {
+		rule := NewRuleBuilder(pctx, ctx)
+		cmd := rule.Command()
+		cmd.Text(fmt.Sprintf("cd %s/execroot/__main__ && %s",
+			ctx.Config().BazelContext.OutputBase(), buildStatement.Command))
+
+		for _, outputPath := range buildStatement.OutputPaths {
+			cmd.ImplicitOutput(PathForBazelOut(ctx, outputPath))
 		}
-		files := strings.Split(strings.TrimSpace(string(data)), "\n")
-		for _, file := range files {
-			ctx.AddNinjaFileDeps(file)
+		for _, inputPath := range buildStatement.InputPaths {
+			cmd.Implicit(PathForBazelOut(ctx, inputPath))
 		}
+
+		// This is required to silence warnings pertaining to unexpected timestamps. Particularly,
+		// some Bazel builtins (such as files in the bazel_tools directory) have far-future
+		// timestamps. Without restat, Ninja would emit warnings that the input files of a
+		// build statement have later timestamps than the outputs.
+		rule.Restat()
+
+		rule.Build(fmt.Sprintf("bazel %s", index), buildStatement.Mnemonic)
 	}
 }
diff --git a/android/config.go b/android/config.go
index 453e074..89467d8 100644
--- a/android/config.go
+++ b/android/config.go
@@ -1324,10 +1324,6 @@
 	return c.productVariables.ProductPrivateSepolicyDirs
 }
 
-func (c *config) ProductCompatibleProperty() bool {
-	return Bool(c.productVariables.ProductCompatibleProperty)
-}
-
 func (c *config) MissingUsesLibraries() []string {
 	return c.productVariables.MissingUsesLibraries
 }
diff --git a/android/module.go b/android/module.go
index 429f311..cfb32c1 100644
--- a/android/module.go
+++ b/android/module.go
@@ -452,8 +452,8 @@
 	InstallInRoot() bool
 	InstallBypassMake() bool
 	InstallForceOS() (*OsType, *ArchType)
-	SkipInstall()
-	IsSkipInstall() bool
+	HideFromMake()
+	IsHideFromMake() bool
 	MakeUninstallable()
 	ReplacedByPrebuilt()
 	IsReplacedByPrebuilt() bool
@@ -751,6 +751,13 @@
 	// Set by osMutator.
 	CommonOSVariant bool `blueprint:"mutated"`
 
+	// When HideFromMake is set to true, no entry for this variant will be emitted in the
+	// generated Android.mk file.
+	HideFromMake bool `blueprint:"mutated"`
+
+	// When SkipInstall is set to true, calls to ctx.InstallFile, ctx.InstallExecutable,
+	// ctx.InstallSymlink and ctx.InstallAbsoluteSymlink act like calls to ctx.PackageFile
+	// and don't create a rule to install the file.
 	SkipInstall bool `blueprint:"mutated"`
 
 	// Whether the module has been replaced by a prebuilt
@@ -1355,26 +1362,33 @@
 	m.commonProperties.ForcedDisabled = true
 }
 
+// HideFromMake marks this variant so that it is not emitted in the generated Android.mk file.
+func (m *ModuleBase) HideFromMake() {
+	m.commonProperties.HideFromMake = true
+}
+
+// IsHideFromMake returns true if HideFromMake was previously called.
+func (m *ModuleBase) IsHideFromMake() bool {
+	return m.commonProperties.HideFromMake == true
+}
+
+// SkipInstall marks this variant to not create install rules when ctx.Install* are called.
 func (m *ModuleBase) SkipInstall() {
 	m.commonProperties.SkipInstall = true
 }
 
-func (m *ModuleBase) IsSkipInstall() bool {
-	return m.commonProperties.SkipInstall == true
-}
-
-// Similar to SkipInstall, but if the AndroidMk entry would set
+// Similar to HideFromMake, but if the AndroidMk entry would set
 // LOCAL_UNINSTALLABLE_MODULE then this variant may still output that entry
 // rather than leaving it out altogether. That happens in cases where it would
 // have other side effects, in particular when it adds a NOTICE file target,
 // which other install targets might depend on.
 func (m *ModuleBase) MakeUninstallable() {
-	m.SkipInstall()
+	m.HideFromMake()
 }
 
 func (m *ModuleBase) ReplacedByPrebuilt() {
 	m.commonProperties.ReplacedByPrebuilt = true
-	m.SkipInstall()
+	m.HideFromMake()
 }
 
 func (m *ModuleBase) IsReplacedByPrebuilt() bool {
@@ -2440,11 +2454,15 @@
 	return m.module.InstallForceOS()
 }
 
-func (m *moduleContext) skipInstall(fullInstallPath InstallPath) bool {
+func (m *moduleContext) skipInstall() bool {
 	if m.module.base().commonProperties.SkipInstall {
 		return true
 	}
 
+	if m.module.base().commonProperties.HideFromMake {
+		return true
+	}
+
 	// We'll need a solution for choosing which of modules with the same name in different
 	// namespaces to install.  For now, reuse the list of namespaces exported to Make as the
 	// list of namespaces to install in a Soong-only build.
@@ -2492,7 +2510,7 @@
 	fullInstallPath := installPath.Join(m, name)
 	m.module.base().hooks.runInstallHooks(m, srcPath, fullInstallPath, false)
 
-	if !m.skipInstall(fullInstallPath) {
+	if !m.skipInstall() {
 		deps = append(deps, m.module.base().installFilesDepSet.ToList().Paths()...)
 
 		var implicitDeps, orderOnlyDeps Paths
@@ -2526,6 +2544,7 @@
 	m.packageFile(fullInstallPath, srcPath, executable)
 
 	m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
+
 	return fullInstallPath
 }
 
@@ -2537,7 +2556,7 @@
 	if err != nil {
 		panic(fmt.Sprintf("Unable to generate symlink between %q and %q: %s", fullInstallPath.Base(), srcPath.Base(), err))
 	}
-	if !m.skipInstall(fullInstallPath) {
+	if !m.skipInstall() {
 
 		m.Build(pctx, BuildParams{
 			Rule:        Symlink,
@@ -2570,7 +2589,7 @@
 	fullInstallPath := installPath.Join(m, name)
 	m.module.base().hooks.runInstallHooks(m, nil, fullInstallPath, true)
 
-	if !m.skipInstall(fullInstallPath) {
+	if !m.skipInstall() {
 		m.Build(pctx, BuildParams{
 			Rule:        Symlink,
 			Description: "install symlink " + fullInstallPath.Base() + " -> " + absPath,
@@ -2738,6 +2757,7 @@
 // Modules can implement HostToolProvider and return a valid OptionalPath from HostToolPath() to
 // specify that they can be used as a tool by a genrule module.
 type HostToolProvider interface {
+	Module
 	// HostToolPath returns the path to the host tool for the module if it is one, or an invalid
 	// OptionalPath.
 	HostToolPath() OptionalPath
diff --git a/android/override_module.go b/android/override_module.go
index f8342d5..fa08566 100644
--- a/android/override_module.go
+++ b/android/override_module.go
@@ -235,7 +235,7 @@
 			return
 		}
 		// See if there's a prebuilt module that overrides this override module with prefer flag,
-		// in which case we call SkipInstall on the corresponding variant later.
+		// in which case we call HideFromMake on the corresponding variant later.
 		ctx.VisitDirectDepsWithTag(PrebuiltDepTag, func(dep Module) {
 			prebuilt, ok := dep.(PrebuiltInterface)
 			if !ok {
@@ -284,7 +284,7 @@
 			mods[i+1].(OverridableModule).override(ctx, o)
 			if o.getOverriddenByPrebuilt() {
 				// The overriding module itself, too, is overridden by a prebuilt. Skip its installation.
-				mods[i+1].SkipInstall()
+				mods[i+1].HideFromMake()
 			}
 		}
 	} else if o, ok := ctx.Module().(OverrideModule); ok {
diff --git a/android/paths.go b/android/paths.go
index 0238a3f..10d8d0d 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -1154,6 +1154,17 @@
 	return PathForOutput(ctx, ".intermediates", ctx.ModuleDir(), ctx.ModuleName(), ctx.ModuleSubDir())
 }
 
+type BazelOutPath struct {
+	OutputPath
+}
+
+var _ Path = BazelOutPath{}
+var _ objPathProvider = BazelOutPath{}
+
+func (p BazelOutPath) objPathWithExt(ctx ModuleContext, subdir, ext string) ModuleObjPath {
+	return PathForModuleObj(ctx, subdir, pathtools.ReplaceExtension(p.path, ext))
+}
+
 // PathForVndkRefAbiDump returns an OptionalPath representing the path of the
 // reference abi dump for the given module. This is not guaranteed to be valid.
 func PathForVndkRefAbiDump(ctx ModuleContext, version, fileName string,
@@ -1192,6 +1203,24 @@
 		fileName+ext)
 }
 
+// PathForBazelOut returns a Path representing the paths... under an output directory dedicated to
+// bazel-owned outputs.
+func PathForBazelOut(ctx PathContext, paths ...string) BazelOutPath {
+	execRootPathComponents := append([]string{"execroot", "__main__"}, paths...)
+	execRootPath := filepath.Join(execRootPathComponents...)
+	validatedExecRootPath, err := validatePath(execRootPath)
+	if err != nil {
+		reportPathError(ctx, err)
+	}
+
+	outputPath := OutputPath{basePath{"", ctx.Config(), ""},
+		ctx.Config().BazelContext.OutputBase()}
+
+	return BazelOutPath{
+		OutputPath: outputPath.withRel(validatedExecRootPath),
+	}
+}
+
 // PathForModuleOut returns a Path representing the paths... under the module's
 // output directory.
 func PathForModuleOut(ctx ModuleContext, paths ...string) ModuleOutPath {
diff --git a/android/prebuilt.go b/android/prebuilt.go
index bb98ed4..39d30c5 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -17,6 +17,7 @@
 import (
 	"fmt"
 	"reflect"
+	"strings"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
@@ -74,6 +75,12 @@
 	srcsPropertyName string
 }
 
+// RemoveOptionalPrebuiltPrefix returns the result of removing the "prebuilt_" prefix from the
+// supplied name if it has one, or returns the name unmodified if it does not.
+func RemoveOptionalPrebuiltPrefix(name string) string {
+	return strings.TrimPrefix(name, "prebuilt_")
+}
+
 func (p *Prebuilt) Name(name string) string {
 	return "prebuilt_" + name
 }
@@ -282,7 +289,7 @@
 				})
 			}
 		} else {
-			m.SkipInstall()
+			m.HideFromMake()
 		}
 	}
 }
diff --git a/android/rule_builder.go b/android/rule_builder.go
index e2d8187..84501fe 100644
--- a/android/rule_builder.go
+++ b/android/rule_builder.go
@@ -32,6 +32,7 @@
 
 const sboxSandboxBaseDir = "__SBOX_SANDBOX_DIR__"
 const sboxOutSubDir = "out"
+const sboxToolsSubDir = "tools"
 const sboxOutDir = sboxSandboxBaseDir + "/" + sboxOutSubDir
 
 // RuleBuilder provides an alternative to ModuleContext.Rule and ModuleContext.Build to add a command line to the build
@@ -48,6 +49,7 @@
 	highmem          bool
 	remoteable       RemoteRuleSupports
 	outDir           WritablePath
+	sboxTools        bool
 	sboxManifestPath WritablePath
 	missingDeps      []string
 }
@@ -140,6 +142,19 @@
 	return r
 }
 
+// SandboxTools enables tool sandboxing for the rule by copying any referenced tools into the
+// sandbox.
+func (r *RuleBuilder) SandboxTools() *RuleBuilder {
+	if !r.sbox {
+		panic("SandboxTools() must be called after Sbox()")
+	}
+	if len(r.commands) > 0 {
+		panic("SandboxTools() may not be called after Command()")
+	}
+	r.sboxTools = true
+	return r
+}
+
 // Install associates an output of the rule with an install location, which can be retrieved later using
 // RuleBuilder.Installs.
 func (r *RuleBuilder) Install(from Path, to string) {
@@ -468,8 +483,29 @@
 			manifest.OutputDepfile = proto.String(depFile.String())
 		}
 
+		// If sandboxing tools is enabled, add copy rules to the manifest to copy each tool
+		// into the sbox directory.
+		if r.sboxTools {
+			for _, tool := range tools {
+				command.CopyBefore = append(command.CopyBefore, &sbox_proto.Copy{
+					From: proto.String(tool.String()),
+					To:   proto.String(sboxPathForToolRel(r.ctx, tool)),
+				})
+			}
+			for _, c := range r.commands {
+				for _, tool := range c.packagedTools {
+					command.CopyBefore = append(command.CopyBefore, &sbox_proto.Copy{
+						From:       proto.String(tool.srcPath.String()),
+						To:         proto.String(sboxPathForPackagedToolRel(tool)),
+						Executable: proto.Bool(tool.executable),
+					})
+					tools = append(tools, tool.srcPath)
+				}
+			}
+		}
+
 		// Add copy rules to the manifest to copy each output file from the sbox directory.
-		// to the output directory.
+		// to the output directory after running the commands.
 		sboxOutputs := make([]string, len(outputs))
 		for i, output := range outputs {
 			rel := Rel(r.ctx, r.outDir.String(), output.String())
@@ -582,6 +618,7 @@
 	symlinkOutputs WritablePaths
 	depFiles       WritablePaths
 	tools          Paths
+	packagedTools  []PackagingSpec
 	rspFileInputs  Paths
 
 	// spans [start,end) of the command that should not be ninja escaped
@@ -625,6 +662,79 @@
 	return path.String()
 }
 
+// SboxPathForTool takes a path to a tool, which may be an output file or a source file, and returns
+// the corresponding path for the tool in the sbox sandbox.  It assumes that sandboxing and tool
+// sandboxing are enabled.
+func SboxPathForTool(ctx BuilderContext, path Path) string {
+	return filepath.Join(sboxSandboxBaseDir, sboxPathForToolRel(ctx, path))
+}
+
+func sboxPathForToolRel(ctx BuilderContext, path Path) string {
+	// Errors will be handled in RuleBuilder.Build where we have a context to report them
+	relOut, isRelOut, _ := maybeRelErr(PathForOutput(ctx, "host", ctx.Config().PrebuiltOS()).String(), path.String())
+	if isRelOut {
+		// The tool is in the output directory, it will be copied to __SBOX_OUT_DIR__/tools/out
+		return filepath.Join(sboxToolsSubDir, "out", relOut)
+	}
+	// The tool is in the source directory, it will be copied to __SBOX_OUT_DIR__/tools/src
+	return filepath.Join(sboxToolsSubDir, "src", path.String())
+}
+
+// SboxPathForPackagedTool takes a PackageSpec for a tool and returns the corresponding path for the
+// tool after copying it into the sandbox.  This can be used  on the RuleBuilder command line to
+// reference the tool.
+func SboxPathForPackagedTool(spec PackagingSpec) string {
+	return filepath.Join(sboxSandboxBaseDir, sboxPathForPackagedToolRel(spec))
+}
+
+func sboxPathForPackagedToolRel(spec PackagingSpec) string {
+	return filepath.Join(sboxToolsSubDir, "out", spec.relPathInPackage)
+}
+
+// PathForTool takes a path to a tool, which may be an output file or a source file, and returns
+// the corresponding path for the tool in the sbox sandbox if sbox is enabled, or the original path
+// if it is not.  This can be used  on the RuleBuilder command line to reference the tool.
+func (c *RuleBuilderCommand) PathForTool(path Path) string {
+	if c.rule.sbox && c.rule.sboxTools {
+		return filepath.Join(sboxSandboxBaseDir, sboxPathForToolRel(c.rule.ctx, path))
+	}
+	return path.String()
+}
+
+// PackagedTool adds the specified tool path to the command line.  It can only be used with tool
+// sandboxing enabled by SandboxTools(), and will copy the tool into the sandbox.
+func (c *RuleBuilderCommand) PackagedTool(spec PackagingSpec) *RuleBuilderCommand {
+	if !c.rule.sboxTools {
+		panic("PackagedTool() requires SandboxTools()")
+	}
+
+	c.packagedTools = append(c.packagedTools, spec)
+	c.Text(sboxPathForPackagedToolRel(spec))
+	return c
+}
+
+// ImplicitPackagedTool copies the specified tool into the sandbox without modifying the command
+// line.  It can only be used with tool sandboxing enabled by SandboxTools().
+func (c *RuleBuilderCommand) ImplicitPackagedTool(spec PackagingSpec) *RuleBuilderCommand {
+	if !c.rule.sboxTools {
+		panic("ImplicitPackagedTool() requires SandboxTools()")
+	}
+
+	c.packagedTools = append(c.packagedTools, spec)
+	return c
+}
+
+// ImplicitPackagedTools copies the specified tools into the sandbox without modifying the command
+// line.  It can only be used with tool sandboxing enabled by SandboxTools().
+func (c *RuleBuilderCommand) ImplicitPackagedTools(specs []PackagingSpec) *RuleBuilderCommand {
+	if !c.rule.sboxTools {
+		panic("ImplicitPackagedTools() requires SandboxTools()")
+	}
+
+	c.packagedTools = append(c.packagedTools, specs...)
+	return c
+}
+
 // Text adds the specified raw text to the command line.  The text should not contain input or output paths or the
 // rule will not have them listed in its dependencies or outputs.
 func (c *RuleBuilderCommand) Text(text string) *RuleBuilderCommand {
@@ -693,7 +803,19 @@
 // RuleBuilder.Tools.
 func (c *RuleBuilderCommand) Tool(path Path) *RuleBuilderCommand {
 	c.tools = append(c.tools, path)
-	return c.Text(path.String())
+	return c.Text(c.PathForTool(path))
+}
+
+// Tool adds the specified tool path to the dependencies returned by RuleBuilder.Tools.
+func (c *RuleBuilderCommand) ImplicitTool(path Path) *RuleBuilderCommand {
+	c.tools = append(c.tools, path)
+	return c
+}
+
+// Tool adds the specified tool path to the dependencies returned by RuleBuilder.Tools.
+func (c *RuleBuilderCommand) ImplicitTools(paths Paths) *RuleBuilderCommand {
+	c.tools = append(c.tools, paths...)
+	return c
 }
 
 // BuiltTool adds the specified tool path that was built using a host Soong module to the command line.  The path will
diff --git a/android/rule_builder_test.go b/android/rule_builder_test.go
index e676e4a..06ea124 100644
--- a/android/rule_builder_test.go
+++ b/android/rule_builder_test.go
@@ -436,6 +436,44 @@
 			t.Errorf("\nwant rule.depFileMergerCmd() = %#v\n                   got %#v", w, g)
 		}
 	})
+
+	t.Run("sbox tools", func(t *testing.T) {
+		rule := NewRuleBuilder(pctx, ctx).Sbox(PathForOutput(ctx, ""),
+			PathForOutput(ctx, "sbox.textproto")).SandboxTools()
+		addCommands(rule)
+
+		wantCommands := []string{
+			"__SBOX_SANDBOX_DIR__/out/DepFile Flag FlagWithArg=arg FlagWithDepFile=__SBOX_SANDBOX_DIR__/out/depfile FlagWithInput=input FlagWithOutput=__SBOX_SANDBOX_DIR__/out/output Input __SBOX_SANDBOX_DIR__/out/Output __SBOX_SANDBOX_DIR__/out/SymlinkOutput Text __SBOX_SANDBOX_DIR__/tools/src/Tool after command2 old cmd",
+			"command2 __SBOX_SANDBOX_DIR__/out/depfile2 input2 __SBOX_SANDBOX_DIR__/out/output2 __SBOX_SANDBOX_DIR__/tools/src/tool2",
+			"command3 input3 __SBOX_SANDBOX_DIR__/out/output2 __SBOX_SANDBOX_DIR__/out/output3",
+		}
+
+		wantDepMergerCommand := "__SBOX_SANDBOX_DIR__/tools/out/bin/dep_fixer __SBOX_SANDBOX_DIR__/out/DepFile __SBOX_SANDBOX_DIR__/out/depfile __SBOX_SANDBOX_DIR__/out/ImplicitDepFile __SBOX_SANDBOX_DIR__/out/depfile2"
+
+		if g, w := rule.Commands(), wantCommands; !reflect.DeepEqual(g, w) {
+			t.Errorf("\nwant rule.Commands() = %#v\n                   got %#v", w, g)
+		}
+
+		if g, w := rule.Inputs(), wantInputs; !reflect.DeepEqual(w, g) {
+			t.Errorf("\nwant rule.Inputs() = %#v\n                 got %#v", w, g)
+		}
+		if g, w := rule.Outputs(), wantOutputs; !reflect.DeepEqual(w, g) {
+			t.Errorf("\nwant rule.Outputs() = %#v\n                  got %#v", w, g)
+		}
+		if g, w := rule.DepFiles(), wantDepFiles; !reflect.DeepEqual(w, g) {
+			t.Errorf("\nwant rule.DepFiles() = %#v\n                  got %#v", w, g)
+		}
+		if g, w := rule.Tools(), wantTools; !reflect.DeepEqual(w, g) {
+			t.Errorf("\nwant rule.Tools() = %#v\n                got %#v", w, g)
+		}
+		if g, w := rule.OrderOnlys(), wantOrderOnlys; !reflect.DeepEqual(w, g) {
+			t.Errorf("\nwant rule.OrderOnlys() = %#v\n                got %#v", w, g)
+		}
+
+		if g, w := rule.depFileMergerCmd(rule.DepFiles()).String(), wantDepMergerCommand; g != w {
+			t.Errorf("\nwant rule.depFileMergerCmd() = %#v\n                   got %#v", w, g)
+		}
+	})
 }
 
 func testRuleBuilderFactory() Module {
diff --git a/android/soongconfig/modules.go b/android/soongconfig/modules.go
index 142a813..5a6917e 100644
--- a/android/soongconfig/modules.go
+++ b/android/soongconfig/modules.go
@@ -158,11 +158,7 @@
 			return []error{fmt.Errorf("bool_variable name must not be blank")}
 		}
 
-		mt.Variables = append(mt.Variables, &boolVariable{
-			baseVariable: baseVariable{
-				variable: name,
-			},
-		})
+		mt.Variables = append(mt.Variables, newBoolVariable(name))
 	}
 
 	for _, name := range props.Value_variables {
@@ -420,6 +416,9 @@
 
 // PropertiesToApply returns the applicable properties from a ModuleType that should be applied
 // based on SoongConfig values.
+// Expects that props contains a struct field with name soong_config_variables. The fields within
+// soong_config_variables are expected to be in the same order as moduleType.Variables. In general,
+// props should be generated via CreateProperties.
 func PropertiesToApply(moduleType *ModuleType, props reflect.Value, config SoongConfig) ([]interface{}, error) {
 	var ret []interface{}
 	props = props.Elem().FieldByName(soongConfigProperty)
@@ -505,6 +504,14 @@
 	baseVariable
 }
 
+func newBoolVariable(name string) *boolVariable {
+	return &boolVariable{
+		baseVariable{
+			variable: name,
+		},
+	}
+}
+
 func (b boolVariable) variableValuesType() reflect.Type {
 	return emptyInterfaceType
 }
diff --git a/android/soongconfig/modules_test.go b/android/soongconfig/modules_test.go
index 4190016..fb0e189 100644
--- a/android/soongconfig/modules_test.go
+++ b/android/soongconfig/modules_test.go
@@ -17,6 +17,8 @@
 import (
 	"reflect"
 	"testing"
+
+	"github.com/google/blueprint/proptools"
 )
 
 func Test_CanonicalizeToProperty(t *testing.T) {
@@ -247,3 +249,72 @@
 		})
 	}
 }
+
+type properties struct {
+	A *string
+	B bool
+}
+type soongConfigVariables struct {
+	Bool_var       properties
+	Other_bool_var properties
+}
+
+type soongConfigProps struct {
+	Soong_config_variables soongConfigVariables
+}
+
+func Test_PropertiesToApply(t *testing.T) {
+
+	mt := &ModuleType{
+		BaseModuleType:  "foo",
+		ConfigNamespace: "bar",
+		Variables: []soongConfigVariable{
+			newBoolVariable("bool_var"),
+			newBoolVariable("other_bool_var"),
+		},
+		affectableProperties: []string{
+			"a",
+			"b",
+		},
+	}
+	props := soongConfigProps{
+		Soong_config_variables: soongConfigVariables{
+			Bool_var: properties{
+				A: proptools.StringPtr("a"),
+				B: true,
+			},
+			Other_bool_var: properties{
+				A: proptools.StringPtr("other"),
+				B: false,
+			},
+		},
+	}
+
+	testCases := []struct {
+		config    SoongConfig
+		wantProps []interface{}
+	}{
+		{
+			config: Config(map[string]string{}),
+		},
+		{
+			config:    Config(map[string]string{"bool_var": "y"}),
+			wantProps: []interface{}{props.Soong_config_variables.Bool_var},
+		},
+		{
+			config:    Config(map[string]string{"other_bool_var": "y"}),
+			wantProps: []interface{}{props.Soong_config_variables.Other_bool_var},
+		},
+	}
+
+	for _, tc := range testCases {
+		gotProps, err := PropertiesToApply(mt, reflect.ValueOf(&props), tc.config)
+		if err != nil {
+			t.Errorf("Unexpected error in PropertiesToApply: %s", err)
+		}
+
+		if !reflect.DeepEqual(gotProps, tc.wantProps) {
+			t.Errorf("Expected %s, got %s", tc.wantProps, gotProps)
+		}
+	}
+}
diff --git a/android/variable.go b/android/variable.go
index aed145c..93dac3d 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -338,7 +338,6 @@
 
 	ProductPublicSepolicyDirs  []string `json:",omitempty"`
 	ProductPrivateSepolicyDirs []string `json:",omitempty"`
-	ProductCompatibleProperty  *bool    `json:",omitempty"`
 
 	ProductVndkVersion *string `json:",omitempty"`
 
diff --git a/apex/allowed_deps.txt b/apex/allowed_deps.txt
index a2f8797..c5f2bf8 100644
--- a/apex/allowed_deps.txt
+++ b/apex/allowed_deps.txt
@@ -209,6 +209,7 @@
 libadbd(minSdkVersion:(no version))
 libadbd_core(minSdkVersion:(no version))
 libadbd_services(minSdkVersion:(no version))
+liballoc.rust_sysroot(minSdkVersion:29)
 libamrextractor(minSdkVersion:29)
 libapp_processes_protos_lite(minSdkVersion:(no version))
 libarect(minSdkVersion:29)
@@ -223,6 +224,8 @@
 libavcenc(minSdkVersion:29)
 libavservices_minijail(minSdkVersion:29)
 libbacktrace_headers(minSdkVersion:apex_inherit)
+libbacktrace_rs.rust_sysroot(minSdkVersion:29)
+libbacktrace_sys.rust_sysroot(minSdkVersion:29)
 libbase(minSdkVersion:29)
 libbase_headers(minSdkVersion:29)
 libbinder_headers(minSdkVersion:29)
@@ -238,6 +241,8 @@
 libc_headers(minSdkVersion:apex_inherit)
 libc_headers_arch(minSdkVersion:apex_inherit)
 libcap(minSdkVersion:29)
+libcfg_if(minSdkVersion:29)
+libcfg_if.rust_sysroot(minSdkVersion:29)
 libclang_rt.hwasan-aarch64-android.llndk(minSdkVersion:(no version))
 libcodec2(minSdkVersion:29)
 libcodec2_headers(minSdkVersion:29)
@@ -276,6 +281,8 @@
 libcodec2_soft_vp9dec(minSdkVersion:29)
 libcodec2_soft_vp9enc(minSdkVersion:29)
 libcodec2_vndk(minSdkVersion:29)
+libcompiler_builtins.rust_sysroot(minSdkVersion:29)
+libcore.rust_sysroot(minSdkVersion:29)
 libcrypto(minSdkVersion:29)
 libcrypto_static(minSdkVersion:(no version))
 libcrypto_utils(minSdkVersion:(no version))
@@ -295,7 +302,9 @@
 libfmq-base(minSdkVersion:29)
 libFraunhoferAAC(minSdkVersion:29)
 libgav1(minSdkVersion:29)
+libgcc(minSdkVersion:(no version))
 libgcc_stripped(minSdkVersion:(no version))
+libgetopts(minSdkVersion:29)
 libgralloctypes(minSdkVersion:29)
 libgrallocusage(minSdkVersion:29)
 libgsm(minSdkVersion:apex_inherit)
@@ -304,6 +313,7 @@
 libgui_headers(minSdkVersion:29)
 libhardware(minSdkVersion:29)
 libhardware_headers(minSdkVersion:29)
+libhashbrown.rust_sysroot(minSdkVersion:29)
 libhevcdec(minSdkVersion:29)
 libhevcenc(minSdkVersion:29)
 libhidlbase(minSdkVersion:29)
@@ -313,9 +323,14 @@
 libion(minSdkVersion:29)
 libjavacrypto(minSdkVersion:29)
 libjsoncpp(minSdkVersion:29)
+liblazy_static(minSdkVersion:29)
+liblibc(minSdkVersion:29)
+liblibc.rust_sysroot(minSdkVersion:29)
 libLibGuiProperties(minSdkVersion:29)
+liblibm(minSdkVersion:29)
 liblog(minSdkVersion:(no version))
 liblog_headers(minSdkVersion:29)
+liblog_rust(minSdkVersion:29)
 liblua(minSdkVersion:(no version))
 liblz4(minSdkVersion:(no version))
 libm(minSdkVersion:(no version))
@@ -346,23 +361,32 @@
 libnetd_resolv(minSdkVersion:29)
 libnetdbinder_utils_headers(minSdkVersion:29)
 libnetdutils(minSdkVersion:29)
+libnetjniutils(minSdkVersion:29)
 libnetworkstackutilsjni(minSdkVersion:29)
 libneuralnetworks(minSdkVersion:(no version))
 libneuralnetworks_common(minSdkVersion:(no version))
 libneuralnetworks_headers(minSdkVersion:(no version))
 liboggextractor(minSdkVersion:29)
+libonce_cell(minSdkVersion:29)
 libopus(minSdkVersion:29)
+libpanic_unwind.rust_sysroot(minSdkVersion:29)
 libprocessgroup(minSdkVersion:29)
 libprocessgroup_headers(minSdkVersion:29)
 libprocpartition(minSdkVersion:(no version))
+libprofiler_builtins.rust_sysroot(minSdkVersion:29)
 libprotobuf-cpp-lite(minSdkVersion:29)
 libprotobuf-java-lite(minSdkVersion:current)
 libprotobuf-java-nano(minSdkVersion:9)
 libprotoutil(minSdkVersion:(no version))
 libqemu_pipe(minSdkVersion:(no version))
+libquiche_ffi(minSdkVersion:29)
+libring(minSdkVersion:29)
+libring-core(minSdkVersion:29)
+librustc_demangle.rust_sysroot(minSdkVersion:29)
 libsfplugin_ccodec_utils(minSdkVersion:29)
 libsonivoxwithoutjet(minSdkVersion:29)
 libspeexresampler(minSdkVersion:29)
+libspin(minSdkVersion:29)
 libssl(minSdkVersion:29)
 libstagefright_amrnb_common(minSdkVersion:29)
 libstagefright_amrnbdec(minSdkVersion:29)
@@ -383,6 +407,7 @@
 libstagefright_m4vh263enc(minSdkVersion:29)
 libstagefright_metadatautils(minSdkVersion:29)
 libstagefright_mp3dec(minSdkVersion:29)
+libstagefright_mp3dec_headers(minSdkVersion:29)
 libstagefright_mpeg2extractor(minSdkVersion:29)
 libstagefright_mpeg2support_nocrypto(minSdkVersion:29)
 libstats_jni(minSdkVersion:(no version))
@@ -392,8 +417,11 @@
 libstatspush_compat(minSdkVersion:29)
 libstatssocket(minSdkVersion:(no version))
 libstatssocket_headers(minSdkVersion:29)
+libstd(minSdkVersion:29)
 libsystem_headers(minSdkVersion:apex_inherit)
 libsysutils(minSdkVersion:apex_inherit)
+libterm(minSdkVersion:29)
+libtest(minSdkVersion:29)
 libtetherutilsjni(minSdkVersion:30)
 libtetherutilsjni(minSdkVersion:current)
 libtextclassifier(minSdkVersion:(no version))
@@ -404,6 +432,9 @@
 libtflite_static(minSdkVersion:(no version))
 libui(minSdkVersion:29)
 libui_headers(minSdkVersion:29)
+libunicode_width.rust_sysroot(minSdkVersion:29)
+libuntrusted(minSdkVersion:29)
+libunwind.rust_sysroot(minSdkVersion:29)
 libunwind_llvm(minSdkVersion:apex_inherit)
 libutf(minSdkVersion:(no version))
 libutils(minSdkVersion:apex_inherit)
@@ -420,6 +451,7 @@
 media_plugin_headers(minSdkVersion:29)
 mediaswcodec(minSdkVersion:29)
 metrics-constants-protos(minSdkVersion:29)
+modules-utils-build(minSdkVersion:29)
 ndk_crtbegin_so.19(minSdkVersion:(no version))
 ndk_crtbegin_so.21(minSdkVersion:(no version))
 ndk_crtbegin_so.27(minSdkVersion:(no version))
diff --git a/apex/apex.go b/apex/apex.go
index 2a81b9b..88d93af 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -237,6 +237,23 @@
 	}
 }
 
+type apexArchBundleProperties struct {
+	Arch struct {
+		Arm struct {
+			ApexNativeDependencies
+		}
+		Arm64 struct {
+			ApexNativeDependencies
+		}
+		X86 struct {
+			ApexNativeDependencies
+		}
+		X86_64 struct {
+			ApexNativeDependencies
+		}
+	}
+}
+
 // These properties can be used in override_apex to override the corresponding properties in the
 // base apex.
 type overridableProperties struct {
@@ -273,6 +290,7 @@
 	// Properties
 	properties            apexBundleProperties
 	targetProperties      apexTargetBundleProperties
+	archProperties        apexArchBundleProperties
 	overridableProperties overridableProperties
 	vndkProperties        apexVndkProperties // only for apex_vndk modules
 
@@ -653,6 +671,20 @@
 			}
 		}
 
+		// Add native modules targeting a specific arch variant
+		switch target.Arch.ArchType {
+		case android.Arm:
+			depsList = append(depsList, a.archProperties.Arch.Arm.ApexNativeDependencies)
+		case android.Arm64:
+			depsList = append(depsList, a.archProperties.Arch.Arm64.ApexNativeDependencies)
+		case android.X86:
+			depsList = append(depsList, a.archProperties.Arch.X86.ApexNativeDependencies)
+		case android.X86_64:
+			depsList = append(depsList, a.archProperties.Arch.X86_64.ApexNativeDependencies)
+		default:
+			panic(fmt.Errorf("unsupported arch %v\n", ctx.Arch().ArchType))
+		}
+
 		for _, d := range depsList {
 			addDependenciesForNativeModules(ctx, d, target, imageVariation)
 		}
@@ -728,7 +760,9 @@
 
 var ApexBundleInfoProvider = blueprint.NewMutatorProvider(ApexBundleInfo{}, "apex_info")
 
-// apexInfoMutator is responsible for collecting modules that need to have apex variants. They are
+var _ ApexInfoMutator = (*apexBundle)(nil)
+
+// ApexInfoMutator is responsible for collecting modules that need to have apex variants. They are
 // identified by doing a graph walk starting from an apexBundle. Basically, all the (direct and
 // indirect) dependencies are collected. But a few types of modules that shouldn't be included in
 // the apexBundle (e.g. stub libraries) are not collected. Note that a single module can be depended
@@ -739,15 +773,7 @@
 // The apexMutator uses that list to create module variants for the apexes to which it belongs.
 // The relationship between module variants and apexes is not one-to-one as variants will be
 // shared between compatible apexes.
-func apexInfoMutator(mctx android.TopDownMutatorContext) {
-	if !mctx.Module().Enabled() {
-		return
-	}
-
-	a, ok := mctx.Module().(*apexBundle)
-	if !ok {
-		return
-	}
+func (a *apexBundle) ApexInfoMutator(mctx android.TopDownMutatorContext) {
 
 	// The VNDK APEX is special. For the APEX, the membership is described in a very different
 	// way. There is no dependency from the VNDK APEX to the VNDK libraries. Instead, VNDK
@@ -826,6 +852,25 @@
 	})
 }
 
+type ApexInfoMutator interface {
+	// ApexInfoMutator implementations must call BuildForApex(ApexInfo) on any modules that are
+	// depended upon by an apex and which require an apex specific variant.
+	ApexInfoMutator(android.TopDownMutatorContext)
+}
+
+// apexInfoMutator delegates the work of identifying which modules need an ApexInfo and apex
+// specific variant to modules that support the ApexInfoMutator.
+func apexInfoMutator(mctx android.TopDownMutatorContext) {
+	if !mctx.Module().Enabled() {
+		return
+	}
+
+	if a, ok := mctx.Module().(ApexInfoMutator); ok {
+		a.ApexInfoMutator(mctx)
+		return
+	}
+}
+
 // apexUniqueVariationsMutator checks if any dependencies use unique apex variations. If so, use
 // unique apex variations for this module. See android/apex.go for more about unique apex variant.
 // TODO(jiyong): move this to android/apex.go?
@@ -1669,8 +1714,15 @@
 						}
 						af := apexFileForNativeLibrary(ctx, cc, handleSpecialLibs)
 						af.transitiveDep = true
+
+						// Always track transitive dependencies for host.
+						if a.Host() {
+							filesInfo = append(filesInfo, af)
+							return true
+						}
+
 						abInfo := ctx.Provider(ApexBundleInfoProvider).(ApexBundleInfo)
-						if !a.Host() && !abInfo.Contents.DirectlyInApex(depName) && (cc.IsStubs() || cc.HasStubsVariants()) {
+						if !abInfo.Contents.DirectlyInApex(depName) && (cc.IsStubs() || cc.HasStubsVariants()) {
 							// If the dependency is a stubs lib, don't include it in this APEX,
 							// but make sure that the lib is installed on the device.
 							// In case no APEX is having the lib, the lib is installed to the system
@@ -1703,7 +1755,8 @@
 						// else-if clause for the indirect dependencies.
 						// Currently, that's impossible because we would
 						// like to record requiredNativeLibs even when
-						// DepIsInSameAPex is false.
+						// DepIsInSameAPex is false. We also shouldn't do
+						// this for host.
 						if !am.DepIsInSameApex(ctx, am) {
 							return false
 						}
@@ -1910,6 +1963,7 @@
 
 	module.AddProperties(&module.properties)
 	module.AddProperties(&module.targetProperties)
+	module.AddProperties(&module.archProperties)
 	module.AddProperties(&module.overridableProperties)
 
 	android.InitAndroidMultiTargetsArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
@@ -2165,7 +2219,7 @@
 func normalizeModuleName(moduleName string) string {
 	// Prebuilt modules (e.g. java_import, etc.) have "prebuilt_" prefix added by the build
 	// system. Trim the prefix for the check since they are confusing
-	moduleName = strings.TrimPrefix(moduleName, "prebuilt_")
+	moduleName = android.RemoveOptionalPrebuiltPrefix(moduleName)
 	if strings.HasPrefix(moduleName, "libclang_rt.") {
 		// This module has many arch variants that depend on the product being built.
 		// We don't want to list them all
diff --git a/apex/apex_test.go b/apex/apex_test.go
index f71e7ef..4a6aecf 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -3891,6 +3891,64 @@
 	ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared")
 }
 
+func TestApexWithArch(t *testing.T) {
+	ctx, _ := testApex(t, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			arch: {
+				arm64: {
+					native_shared_libs: ["mylib.arm64"],
+				},
+				x86_64: {
+					native_shared_libs: ["mylib.x64"],
+				},
+			}
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		cc_library {
+			name: "mylib.arm64",
+			srcs: ["mylib.cpp"],
+			system_shared_libs: [],
+			stl: "none",
+			// TODO: remove //apex_available:platform
+			apex_available: [
+				"//apex_available:platform",
+				"myapex",
+			],
+		}
+
+		cc_library {
+			name: "mylib.x64",
+			srcs: ["mylib.cpp"],
+			system_shared_libs: [],
+			stl: "none",
+			// TODO: remove //apex_available:platform
+			apex_available: [
+				"//apex_available:platform",
+				"myapex",
+			],
+		}
+	`)
+
+	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule")
+	copyCmds := apexRule.Args["copy_commands"]
+
+	// Ensure that apex variant is created for the direct dep
+	ensureListContains(t, ctx.ModuleVariantsForTests("mylib.arm64"), "android_arm64_armv8-a_shared_apex10000")
+	ensureListNotContains(t, ctx.ModuleVariantsForTests("mylib.x64"), "android_arm64_armv8-a_shared_apex10000")
+
+	// Ensure that both direct and indirect deps are copied into apex
+	ensureContains(t, copyCmds, "image.apex/lib64/mylib.arm64.so")
+	ensureNotContains(t, copyCmds, "image.apex/lib64/mylib.x64.so")
+}
+
 func TestApexWithShBinary(t *testing.T) {
 	ctx, _ := testApex(t, `
 		apex {
@@ -6520,7 +6578,7 @@
 								continue
 							}
 							mod := ctx.ModuleForTests(modName, variant).Module().(*cc.Module)
-							if !mod.Enabled() || mod.IsSkipInstall() {
+							if !mod.Enabled() || mod.IsHideFromMake() {
 								continue
 							}
 							for _, ent := range android.AndroidMkEntriesForTest(t, config, "", mod) {
@@ -6559,6 +6617,11 @@
 						if entry.mkEntries.EntryMap["LOCAL_NOT_AVAILABLE_FOR_PLATFORM"] != nil {
 							t.Errorf("AndroidMk entry for \"stublib\" has LOCAL_NOT_AVAILABLE_FOR_PLATFORM set: %+v", entry.mkEntries)
 						}
+						cflags := entry.mkEntries.EntryMap["LOCAL_EXPORT_CFLAGS"]
+						expected := "-D__STUBLIB_API__=1"
+						if !android.InList(expected, cflags) {
+							t.Errorf("LOCAL_EXPORT_CFLAGS expected to have %q, but got %q", expected, cflags)
+						}
 					}
 				})
 			}
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index ce16d73..7931e9e 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -218,7 +218,7 @@
 	})
 
 	if p.prebuiltCommon.checkForceDisable(ctx) {
-		p.SkipInstall()
+		p.HideFromMake()
 		return
 	}
 
@@ -392,7 +392,7 @@
 		})
 
 	if a.prebuiltCommon.checkForceDisable(ctx) {
-		a.SkipInstall()
+		a.HideFromMake()
 		return
 	}
 
diff --git a/bazel/Android.bp b/bazel/Android.bp
index 0113726..05eddc1 100644
--- a/bazel/Android.bp
+++ b/bazel/Android.bp
@@ -2,9 +2,14 @@
     name: "soong-bazel",
     pkgPath: "android/soong/bazel",
     srcs: [
+        "aquery.go",
+        "constants.go",
         "properties.go",
     ],
     pluginFor: [
         "soong_build",
     ],
+    deps: [
+        "blueprint",
+    ],
 }
diff --git a/bazel/aquery.go b/bazel/aquery.go
new file mode 100644
index 0000000..69d4fde
--- /dev/null
+++ b/bazel/aquery.go
@@ -0,0 +1,116 @@
+// Copyright 2020 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package bazel
+
+import (
+	"encoding/json"
+	"strings"
+
+	"github.com/google/blueprint/proptools"
+)
+
+// artifact contains relevant portions of Bazel's aquery proto, Artifact.
+// Represents a single artifact, whether it's a source file or a derived output file.
+type artifact struct {
+	Id       string
+	ExecPath string
+}
+
+// KeyValuePair represents Bazel's aquery proto, KeyValuePair.
+type KeyValuePair struct {
+	Key   string
+	Value string
+}
+
+// depSetOfFiles contains relevant portions of Bazel's aquery proto, DepSetOfFiles.
+// Represents a data structure containing one or more files. Depsets in Bazel are an efficient
+// data structure for storing large numbers of file paths.
+type depSetOfFiles struct {
+	Id string
+	// TODO(cparsons): Handle non-flat depsets.
+	DirectArtifactIds []string
+}
+
+// action contains relevant portions of Bazel's aquery proto, Action.
+// Represents a single command line invocation in the Bazel build graph.
+type action struct {
+	Arguments            []string
+	EnvironmentVariables []KeyValuePair
+	InputDepSetIds       []string
+	Mnemonic             string
+	OutputIds            []string
+}
+
+// actionGraphContainer contains relevant portions of Bazel's aquery proto, ActionGraphContainer.
+// An aquery response from Bazel contains a single ActionGraphContainer proto.
+type actionGraphContainer struct {
+	Artifacts     []artifact
+	Actions       []action
+	DepSetOfFiles []depSetOfFiles
+}
+
+// BuildStatement contains information to register a build statement corresponding (one to one)
+// with a Bazel action from Bazel's action graph.
+type BuildStatement struct {
+	Command     string
+	OutputPaths []string
+	InputPaths  []string
+	Env         []KeyValuePair
+	Mnemonic    string
+}
+
+// AqueryBuildStatements returns an array of BuildStatements which should be registered (and output
+// to a ninja file) to correspond one-to-one with the given action graph json proto (from a bazel
+// aquery invocation).
+func AqueryBuildStatements(aqueryJsonProto []byte) []BuildStatement {
+	buildStatements := []BuildStatement{}
+
+	var aqueryResult actionGraphContainer
+	json.Unmarshal(aqueryJsonProto, &aqueryResult)
+
+	artifactIdToPath := map[string]string{}
+	for _, artifact := range aqueryResult.Artifacts {
+		artifactIdToPath[artifact.Id] = artifact.ExecPath
+	}
+	depsetIdToArtifactIds := map[string][]string{}
+	for _, depset := range aqueryResult.DepSetOfFiles {
+		depsetIdToArtifactIds[depset.Id] = depset.DirectArtifactIds
+	}
+
+	for _, actionEntry := range aqueryResult.Actions {
+		outputPaths := []string{}
+		for _, outputId := range actionEntry.OutputIds {
+			// TODO(cparsons): Validate the id is present.
+			outputPaths = append(outputPaths, artifactIdToPath[outputId])
+		}
+		inputPaths := []string{}
+		for _, inputDepSetId := range actionEntry.InputDepSetIds {
+			// TODO(cparsons): Validate the id is present.
+			for _, inputId := range depsetIdToArtifactIds[inputDepSetId] {
+				// TODO(cparsons): Validate the id is present.
+				inputPaths = append(inputPaths, artifactIdToPath[inputId])
+			}
+		}
+		buildStatement := BuildStatement{
+			Command:     strings.Join(proptools.ShellEscapeList(actionEntry.Arguments), " "),
+			OutputPaths: outputPaths,
+			InputPaths:  inputPaths,
+			Env:         actionEntry.EnvironmentVariables,
+			Mnemonic:    actionEntry.Mnemonic}
+		buildStatements = append(buildStatements, buildStatement)
+	}
+
+	return buildStatements
+}
diff --git a/bazel/constants.go b/bazel/constants.go
new file mode 100644
index 0000000..15c75cf
--- /dev/null
+++ b/bazel/constants.go
@@ -0,0 +1,26 @@
+package bazel
+
+type RunName string
+
+// Below is a list bazel execution run names used through out the
+// Platform Build systems. Each run name represents an unique key
+// to query the bazel metrics.
+const (
+	// Perform a bazel build of the phony root to generate symlink forests
+	// for dependencies of the bazel build.
+	BazelBuildPhonyRootRunName = RunName("bazel-build-phony-root")
+
+	// Perform aquery of the bazel build root to retrieve action information.
+	AqueryBuildRootRunName = RunName("aquery-buildroot")
+
+	// Perform cquery of the Bazel build root and its dependencies.
+	CqueryBuildRootRunName = RunName("cquery-buildroot")
+
+	// Run bazel as a ninja executer
+	BazelNinjaExecRunName = RunName("bazel-ninja-exec")
+)
+
+// String returns the name of the run.
+func (c RunName) String() string {
+	return string(c)
+}
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 187a2ff..ddacb70 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -273,7 +273,7 @@
 			entries.SubName = "." + library.stubsVersion()
 		}
 		entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
-			// library.makeUninstallable() depends on this to bypass SkipInstall() for
+			// library.makeUninstallable() depends on this to bypass HideFromMake() for
 			// static libraries.
 			entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
 			if library.buildStubs() {
diff --git a/cc/cc.go b/cc/cc.go
index 0e58436..1cc2bd5 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -79,7 +79,6 @@
 		ctx.BottomUp("sanitize_runtime", sanitizerRuntimeMutator).Parallel()
 
 		ctx.BottomUp("coverage", coverageMutator).Parallel()
-		ctx.TopDown("vndk_deps", sabiDepsMutator)
 
 		ctx.TopDown("lto_deps", ltoDepsMutator)
 		ctx.BottomUp("lto", ltoMutator).Parallel()
@@ -88,6 +87,11 @@
 		ctx.TopDown("double_loadable", checkDoubleLoadableLibraries).Parallel()
 	})
 
+	ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) {
+		// sabi mutator needs to be run after apex mutator finishes.
+		ctx.TopDown("sabi_deps", sabiDepsMutator)
+	})
+
 	ctx.RegisterSingletonType("kythe_extract_all", kytheExtractAllFactory)
 }
 
@@ -415,7 +419,6 @@
 	inRamdisk() bool
 	inVendorRamdisk() bool
 	inRecovery() bool
-	shouldCreateSourceAbiDump() bool
 	selectedStl() string
 	baseModuleName() string
 	getVndkExtendsModuleName() string
@@ -429,6 +432,7 @@
 	mustUseVendorVariant() bool
 	nativeCoverage() bool
 	directlyInAnyApex() bool
+	isPreventInstall() bool
 }
 
 type ModuleContext interface {
@@ -1279,42 +1283,6 @@
 	return ctx.mod.MustUseVendorVariant()
 }
 
-// Check whether ABI dumps should be created for this module.
-func (ctx *moduleContextImpl) shouldCreateSourceAbiDump() bool {
-	if ctx.ctx.Config().IsEnvTrue("SKIP_ABI_CHECKS") {
-		return false
-	}
-
-	// Coverage builds have extra symbols.
-	if ctx.mod.isCoverageVariant() {
-		return false
-	}
-
-	if ctx.ctx.Fuchsia() {
-		return false
-	}
-
-	if sanitize := ctx.mod.sanitize; sanitize != nil {
-		if !sanitize.isVariantOnProductionDevice() {
-			return false
-		}
-	}
-	if !ctx.ctx.Device() {
-		// Host modules do not need ABI dumps.
-		return false
-	}
-	if ctx.isNDKStubLibrary() {
-		// Stubs do not need ABI dumps.
-		return false
-	}
-	if lib := ctx.mod.library; lib != nil && lib.buildStubs() {
-		// Stubs do not need ABI dumps.
-		return false
-	}
-
-	return true
-}
-
 func (ctx *moduleContextImpl) selectedStl() string {
 	if stl := ctx.mod.stl; stl != nil {
 		return stl.Properties.SelectedStl
@@ -1358,6 +1326,10 @@
 	return ctx.mod.DirectlyInAnyApex()
 }
 
+func (ctx *moduleContextImpl) isPreventInstall() bool {
+	return ctx.mod.Properties.PreventInstall
+}
+
 func newBaseModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Module {
 	return &Module{
 		hod:      hod,
@@ -1608,18 +1580,24 @@
 		}
 	}
 
-	if c.installable(apexInfo) {
+	if !proptools.BoolDefault(c.Properties.Installable, true) {
+		// If the module has been specifically configure to not be installed then
+		// hide from make as otherwise it will break when running inside make
+		// as the output path to install will not be specified. Not all uninstallable
+		// modules can be hidden from make as some are needed for resolving make side
+		// dependencies.
+		c.HideFromMake()
+	} else if !c.installable(apexInfo) {
+		c.SkipInstall()
+	}
+
+	// Still call c.installer.install though, the installs will be stored as PackageSpecs
+	// to allow using the outputs in a genrule.
+	if c.installer != nil && c.outputFile.Valid() {
 		c.installer.install(ctx, c.outputFile.Path())
 		if ctx.Failed() {
 			return
 		}
-	} else if !proptools.BoolDefault(c.Properties.Installable, true) {
-		// If the module has been specifically configure to not be installed then
-		// skip the installation as otherwise it will break when running inside make
-		// as the output path to install will not be specified. Not all uninstallable
-		// modules can skip installation as some are needed for resolving make side
-		// dependencies.
-		c.SkipInstall()
 	}
 }
 
@@ -2444,7 +2422,14 @@
 
 			switch {
 			case libDepTag.header():
-				// nothing
+				if !ctx.OtherModuleHasProvider(dep, HeaderLibraryInfoProvider) {
+					if !ctx.Config().AllowMissingDependencies() {
+						ctx.ModuleErrorf("module %q is not a header library", depName)
+					} else {
+						ctx.AddMissingDependencies([]string{depName})
+					}
+					return
+				}
 			case libDepTag.shared():
 				if !ctx.OtherModuleHasProvider(dep, SharedLibraryInfoProvider) {
 					if !ctx.Config().AllowMissingDependencies() {
@@ -2750,7 +2735,7 @@
 func baseLibName(depName string) string {
 	libName := strings.TrimSuffix(depName, llndkLibrarySuffix)
 	libName = strings.TrimSuffix(libName, vendorPublicLibrarySuffix)
-	libName = strings.TrimPrefix(libName, "prebuilt_")
+	libName = android.RemoveOptionalPrebuiltPrefix(libName)
 	return libName
 }
 
@@ -3025,6 +3010,9 @@
 	}
 }
 
+var _ android.ApexModule = (*Module)(nil)
+
+// Implements android.ApexModule
 func (c *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
 	depTag := ctx.OtherModuleDependencyTag(dep)
 	libDepTag, isLibDepTag := depTag.(libraryDependencyTag)
@@ -3058,6 +3046,7 @@
 	return true
 }
 
+// Implements android.ApexModule
 func (c *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext,
 	sdkVersion android.ApiLevel) error {
 	// We ignore libclang_rt.* prebuilt libs since they declare sdk_version: 14(b/121358700)
diff --git a/cc/config/clang.go b/cc/config/clang.go
index 441bff2..519a9e2 100644
--- a/cc/config/clang.go
+++ b/cc/config/clang.go
@@ -249,6 +249,10 @@
 	return result
 }
 
+func ClangLibToolingFilterUnknownCflags(libToolingFlags []string) []string {
+	return android.RemoveListFromList(libToolingFlags, ClangLibToolingUnknownCflags)
+}
+
 func inListSorted(s string, list []string) bool {
 	for _, l := range list {
 		if s == l {
diff --git a/cc/image.go b/cc/image.go
index 32325b9..cca454a 100644
--- a/cc/image.go
+++ b/cc/image.go
@@ -454,7 +454,7 @@
 		vndkVersion := ctx.DeviceConfig().VndkVersion()
 		if vndkVersion != "current" && vndkVersion != "" && vndkVersion != m.Properties.VndkVersion {
 			m.Properties.HideFromMake = true
-			m.SkipInstall()
+			m.HideFromMake()
 		}
 	} else if strings.HasPrefix(variant, ProductVariationPrefix) {
 		m.Properties.ImageVariationPrefix = ProductVariationPrefix
diff --git a/cc/library.go b/cc/library.go
index 06b9905..11ee7dd 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -594,59 +594,12 @@
 	return flags
 }
 
-// Returns a string that represents the class of the ABI dump.
-// Returns an empty string if ABI check is disabled for this library.
-func (library *libraryDecorator) classifySourceAbiDump(ctx ModuleContext) string {
-	enabled := library.Properties.Header_abi_checker.Enabled
-	if enabled != nil && !Bool(enabled) {
-		return ""
-	}
-	// Return NDK if the library is both NDK and LLNDK.
-	if ctx.isNdk(ctx.Config()) {
-		return "NDK"
-	}
-	if ctx.isLlndkPublic(ctx.Config()) {
-		return "LLNDK"
-	}
-	if ctx.useVndk() && ctx.isVndk() && !ctx.isVndkPrivate(ctx.Config()) {
-		if ctx.isVndkSp() {
-			if ctx.IsVndkExt() {
-				return "VNDK-SP-ext"
-			} else {
-				return "VNDK-SP"
-			}
-		} else {
-			if ctx.IsVndkExt() {
-				return "VNDK-ext"
-			} else {
-				return "VNDK-core"
-			}
-		}
-	}
-	if Bool(enabled) || library.hasStubsVariants() {
-		return "PLATFORM"
-	}
-	return ""
+func (library *libraryDecorator) headerAbiCheckerEnabled() bool {
+	return Bool(library.Properties.Header_abi_checker.Enabled)
 }
 
-func (library *libraryDecorator) shouldCreateSourceAbiDump(ctx ModuleContext) bool {
-	if !ctx.shouldCreateSourceAbiDump() {
-		return false
-	}
-	if !ctx.isForPlatform() {
-		if !library.hasStubsVariants() {
-			// Skip ABI checks if this library is for APEX but isn't exported.
-			return false
-		}
-		if !Bool(library.Properties.Header_abi_checker.Enabled) {
-			// Skip ABI checks if this library is for APEX and did not explicitly enable
-			// ABI checks.
-			// TODO(b/145608479): ABI checks should be enabled by default. Remove this
-			// after evaluating the extra build time.
-			return false
-		}
-	}
-	return library.classifySourceAbiDump(ctx) != ""
+func (library *libraryDecorator) headerAbiCheckerExplicitlyDisabled() bool {
+	return !BoolDefault(library.Properties.Header_abi_checker.Enabled, true)
 }
 
 func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
@@ -668,7 +621,7 @@
 		}
 		return Objects{}
 	}
-	if library.shouldCreateSourceAbiDump(ctx) || library.sabi.Properties.CreateSAbiDumps {
+	if library.sabi.shouldCreateSourceAbiDump() {
 		exportIncludeDirs := library.flagExporter.exportedIncludes(ctx)
 		var SourceAbiFlags []string
 		for _, dir := range exportIncludeDirs.Strings() {
@@ -718,6 +671,10 @@
 	setStatic()
 	setShared()
 
+	// Check whether header_abi_checker is enabled or explicitly disabled.
+	headerAbiCheckerEnabled() bool
+	headerAbiCheckerExplicitlyDisabled() bool
+
 	// Write LOCAL_ADDITIONAL_DEPENDENCIES for ABI diff
 	androidMkWriteAdditionalDependenciesForSourceAbiDiff(w io.Writer)
 
@@ -940,16 +897,22 @@
 
 	ctx.CheckbuildFile(outputFile)
 
-	ctx.SetProvider(StaticLibraryInfoProvider, StaticLibraryInfo{
-		StaticLibrary: outputFile,
-		ReuseObjects:  library.reuseObjects,
-		Objects:       library.objects,
+	if library.static() {
+		ctx.SetProvider(StaticLibraryInfoProvider, StaticLibraryInfo{
+			StaticLibrary: outputFile,
+			ReuseObjects:  library.reuseObjects,
+			Objects:       library.objects,
 
-		TransitiveStaticLibrariesForOrdering: android.NewDepSetBuilder(android.TOPOLOGICAL).
-			Direct(outputFile).
-			Transitive(deps.TranstiveStaticLibrariesForOrdering).
-			Build(),
-	})
+			TransitiveStaticLibrariesForOrdering: android.NewDepSetBuilder(android.TOPOLOGICAL).
+				Direct(outputFile).
+				Transitive(deps.TranstiveStaticLibrariesForOrdering).
+				Build(),
+		})
+	}
+
+	if library.header() {
+		ctx.SetProvider(HeaderLibraryInfoProvider, HeaderLibraryInfo{})
+	}
 
 	return outputFile
 }
@@ -1158,7 +1121,7 @@
 }
 
 func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, objs Objects, fileName string, soFile android.Path) {
-	if library.shouldCreateSourceAbiDump(ctx) {
+	if library.sabi.shouldCreateSourceAbiDump() {
 		var vndkVersion string
 
 		if ctx.useVndk() {
@@ -1183,7 +1146,7 @@
 			library.Properties.Header_abi_checker.Exclude_symbol_versions,
 			library.Properties.Header_abi_checker.Exclude_symbol_tags)
 
-		addLsdumpPath(library.classifySourceAbiDump(ctx) + ":" + library.sAbiOutputFile.String())
+		addLsdumpPath(classifySourceAbiDump(ctx) + ":" + library.sAbiOutputFile.String())
 
 		refAbiDumpFile := getRefAbiDumpFile(ctx, vndkVersion, fileName)
 		if refAbiDumpFile != nil {
@@ -1274,9 +1237,7 @@
 	}
 
 	// Add stub-related flags if this library is a stub library.
-	if library.buildStubs() && !library.skipAPIDefine {
-		library.reexportFlags("-D" + versioningMacroName(ctx.Module().(*Module).ImplementationModuleName(ctx)) + "=" + library.stubsVersion())
-	}
+	library.exportVersioningMacroIfNeeded(ctx)
 
 	// Propagate a Provider containing information about exported flags, deps, and include paths.
 	library.flagExporter.setProvider(ctx)
@@ -1284,6 +1245,14 @@
 	return out
 }
 
+func (library *libraryDecorator) exportVersioningMacroIfNeeded(ctx android.BaseModuleContext) {
+	if library.buildStubs() && !library.skipAPIDefine {
+		name := versioningMacroName(ctx.Module().(*Module).ImplementationModuleName(ctx))
+		ver := library.stubsVersion()
+		library.reexportFlags("-D" + name + "=" + ver)
+	}
+}
+
 // buildStatic returns true if this library should be built as a static library.
 func (library *libraryDecorator) buildStatic() bool {
 	return library.MutatedProperties.BuildStatic &&
@@ -1367,7 +1336,7 @@
 			}
 		} else if ctx.directlyInAnyApex() && ctx.isLlndk(ctx.Config()) && !isBionic(ctx.baseModuleName()) {
 			// Skip installing LLNDK (non-bionic) libraries moved to APEX.
-			ctx.Module().SkipInstall()
+			ctx.Module().HideFromMake()
 		}
 
 		library.baseInstaller.install(ctx, file)
@@ -1376,7 +1345,7 @@
 	if Bool(library.Properties.Static_ndk_lib) && library.static() &&
 		!ctx.useVndk() && !ctx.inRamdisk() && !ctx.inVendorRamdisk() && !ctx.inRecovery() && ctx.Device() &&
 		library.baseLinker.sanitize.isUnsanitizedVariant() &&
-		!library.buildStubs() && ctx.sdkVersion() == "" {
+		ctx.isForPlatform() && !ctx.isPreventInstall() {
 		installPath := getNdkSysrootBase(ctx).Join(
 			ctx, "usr/lib", config.NDKTriple(ctx.toolchain()), file.Base())
 
diff --git a/cc/linkable.go b/cc/linkable.go
index 4efe2a7..d010985 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -130,6 +130,13 @@
 
 var StaticLibraryInfoProvider = blueprint.NewProvider(StaticLibraryInfo{})
 
+// HeaderLibraryInfo is a marker provider that identifies a module as a header library.
+type HeaderLibraryInfo struct {
+}
+
+// HeaderLibraryInfoProvider is a marker provider that identifies a module as a header library.
+var HeaderLibraryInfoProvider = blueprint.NewProvider(HeaderLibraryInfo{})
+
 // FlagExporterInfo is a provider to propagate transitive library information
 // pertaining to exported include paths and flags.
 type FlagExporterInfo struct {
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index 37df4ba..2cd18cb 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -17,6 +17,7 @@
 import (
 	"android/soong/android"
 	"path/filepath"
+	"strings"
 )
 
 func init() {
@@ -117,6 +118,8 @@
 			return nil
 		}
 
+		p.libraryDecorator.exportVersioningMacroIfNeeded(ctx)
+
 		in := android.PathForModuleSrc(ctx, srcs[0])
 
 		if p.static() {
@@ -190,6 +193,12 @@
 		}
 	}
 
+	if p.header() {
+		ctx.SetProvider(HeaderLibraryInfoProvider, HeaderLibraryInfo{})
+
+		return nil
+	}
+
 	return nil
 }
 
@@ -220,6 +229,11 @@
 	p.properties.Srcs = nil
 }
 
+// Implements versionedInterface
+func (p *prebuiltLibraryLinker) implementationModuleName(name string) string {
+	return strings.TrimPrefix(name, "prebuilt_")
+}
+
 func NewPrebuiltLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorator) {
 	module, library := NewLibrary(hod)
 	module.compiler = nil
diff --git a/cc/sabi.go b/cc/sabi.go
index ef6bead..c357f8d 100644
--- a/cc/sabi.go
+++ b/cc/sabi.go
@@ -15,7 +15,6 @@
 package cc
 
 import (
-	"strings"
 	"sync"
 
 	"android/soong/android"
@@ -23,12 +22,18 @@
 )
 
 var (
-	lsdumpPaths []string
-	sabiLock    sync.Mutex
+	lsdumpPaths     []string
+	lsdumpPathsLock sync.Mutex
 )
 
 type SAbiProperties struct {
-	CreateSAbiDumps    bool     `blueprint:"mutated"`
+	// Whether ABI dump should be created for this module.
+	// Set by `sabiDepsMutator` if this module is a shared library that needs ABI check, or a static
+	// library that is depended on by an ABI checked library.
+	ShouldCreateSourceAbiDump bool `blueprint:"mutated"`
+
+	// Include directories that may contain ABI information exported by a library.
+	// These directories are passed to the header-abi-dumper.
 	ReexportedIncludes []string `blueprint:"mutated"`
 }
 
@@ -36,66 +41,172 @@
 	Properties SAbiProperties
 }
 
-func (sabimod *sabi) props() []interface{} {
-	return []interface{}{&sabimod.Properties}
+func (sabi *sabi) props() []interface{} {
+	return []interface{}{&sabi.Properties}
 }
 
-func (sabimod *sabi) begin(ctx BaseModuleContext) {}
+func (sabi *sabi) begin(ctx BaseModuleContext) {}
 
-func (sabimod *sabi) deps(ctx BaseModuleContext, deps Deps) Deps {
+func (sabi *sabi) deps(ctx BaseModuleContext, deps Deps) Deps {
 	return deps
 }
 
-func inListWithPrefixSearch(flag string, filter []string) bool {
-	// Assuming the filter is small enough.
-	// If the suffix of a filter element is *, try matching prefixes as well.
-	for _, f := range filter {
-		if (f == flag) || (strings.HasSuffix(f, "*") && strings.HasPrefix(flag, strings.TrimSuffix(f, "*"))) {
-			return true
-		}
-	}
-	return false
-}
-
-func filterOutWithPrefix(list []string, filter []string) (remainder []string) {
-	// Go through the filter, matching and optionally doing a prefix search for list elements.
-	for _, l := range list {
-		if !inListWithPrefixSearch(l, filter) {
-			remainder = append(remainder, l)
-		}
-	}
-	return
-}
-
-func (sabimod *sabi) flags(ctx ModuleContext, flags Flags) Flags {
-	// Assuming that the cflags which clang LibTooling tools cannot
-	// understand have not been converted to ninja variables yet.
-	flags.Local.ToolingCFlags = filterOutWithPrefix(flags.Local.CFlags, config.ClangLibToolingUnknownCflags)
-	flags.Global.ToolingCFlags = filterOutWithPrefix(flags.Global.CFlags, config.ClangLibToolingUnknownCflags)
-	flags.Local.ToolingCppFlags = filterOutWithPrefix(flags.Local.CppFlags, config.ClangLibToolingUnknownCflags)
-	flags.Global.ToolingCppFlags = filterOutWithPrefix(flags.Global.CppFlags, config.ClangLibToolingUnknownCflags)
-
+func (sabi *sabi) flags(ctx ModuleContext, flags Flags) Flags {
+	// Filter out flags which libTooling don't understand.
+	// This is here for legacy reasons and future-proof, in case the version of libTooling and clang
+	// diverge.
+	flags.Local.ToolingCFlags = config.ClangLibToolingFilterUnknownCflags(flags.Local.CFlags)
+	flags.Global.ToolingCFlags = config.ClangLibToolingFilterUnknownCflags(flags.Global.CFlags)
+	flags.Local.ToolingCppFlags = config.ClangLibToolingFilterUnknownCflags(flags.Local.CppFlags)
+	flags.Global.ToolingCppFlags = config.ClangLibToolingFilterUnknownCflags(flags.Global.CppFlags)
 	return flags
 }
 
-func sabiDepsMutator(mctx android.TopDownMutatorContext) {
-	if c, ok := mctx.Module().(*Module); ok &&
-		((c.IsVndk() && c.UseVndk()) || c.isLlndk(mctx.Config()) ||
-			(c.sabi != nil && c.sabi.Properties.CreateSAbiDumps)) {
-		mctx.VisitDirectDeps(func(m android.Module) {
-			if tag, ok := mctx.OtherModuleDependencyTag(m).(libraryDependencyTag); ok && tag.static() {
-				cc, _ := m.(*Module)
-				if cc == nil {
-					return
-				}
-				cc.sabi.Properties.CreateSAbiDumps = true
+// Returns true if ABI dump should be created for this library, either because library is ABI
+// checked or is depended on by an ABI checked library.
+// Could be called as a nil receiver.
+func (sabi *sabi) shouldCreateSourceAbiDump() bool {
+	return sabi != nil && sabi.Properties.ShouldCreateSourceAbiDump
+}
+
+// Returns a string that represents the class of the ABI dump.
+// Returns an empty string if ABI check is disabled for this library.
+func classifySourceAbiDump(ctx android.BaseModuleContext) string {
+	m := ctx.Module().(*Module)
+	if m.library.headerAbiCheckerExplicitlyDisabled() {
+		return ""
+	}
+	// Return NDK if the library is both NDK and LLNDK.
+	if m.IsNdk(ctx.Config()) {
+		return "NDK"
+	}
+	if m.isLlndkPublic(ctx.Config()) {
+		return "LLNDK"
+	}
+	if m.UseVndk() && m.IsVndk() && !m.IsVndkPrivate(ctx.Config()) {
+		if m.isVndkSp() {
+			if m.IsVndkExt() {
+				return "VNDK-SP-ext"
+			} else {
+				return "VNDK-SP"
 			}
-		})
+		} else {
+			if m.IsVndkExt() {
+				return "VNDK-ext"
+			} else {
+				return "VNDK-core"
+			}
+		}
+	}
+	if m.library.headerAbiCheckerEnabled() || m.library.hasStubsVariants() {
+		return "PLATFORM"
+	}
+	return ""
+}
+
+// Called from sabiDepsMutator to check whether ABI dumps should be created for this module.
+// ctx should be wrapping a native library type module.
+func shouldCreateSourceAbiDumpForLibrary(ctx android.BaseModuleContext) bool {
+	if ctx.Fuchsia() {
+		return false
+	}
+
+	// Only generate ABI dump for device modules.
+	if !ctx.Device() {
+		return false
+	}
+
+	m := ctx.Module().(*Module)
+
+	// Only create ABI dump for native library module types.
+	if m.library == nil {
+		return false
+	}
+
+	// Create ABI dump for static libraries only if they are dependencies of ABI checked libraries.
+	if m.library.static() {
+		return m.sabi.shouldCreateSourceAbiDump()
+	}
+
+	// Module is shared library type.
+
+	// Don't check uninstallable modules.
+	if m.IsHideFromMake() {
+		return false
+	}
+
+	// Don't check ramdisk or recovery variants. Only check core, vendor or product variants.
+	if m.InRamdisk() || m.InVendorRamdisk() || m.InRecovery() {
+		return false
+	}
+
+	// Don't create ABI dump for prebuilts.
+	if m.Prebuilt() != nil || m.isSnapshotPrebuilt() {
+		return false
+	}
+
+	// Coverage builds have extra symbols.
+	if m.isCoverageVariant() {
+		return false
+	}
+
+	// Some sanitizer variants may have different ABI.
+	if m.sanitize != nil && !m.sanitize.isVariantOnProductionDevice() {
+		return false
+	}
+
+	// Don't create ABI dump for stubs.
+	if m.isNDKStubLibrary() || m.IsStubs() {
+		return false
+	}
+
+	isPlatformVariant := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform()
+	if isPlatformVariant {
+		// Bionic libraries that are installed to the bootstrap directory are not ABI checked.
+		// Only the runtime APEX variants, which are the implementation libraries of bionic NDK stubs,
+		// are checked.
+		if InstallToBootstrap(m.BaseModuleName(), ctx.Config()) {
+			return false
+		}
+	} else {
+		// Don't create ABI dump if this library is for APEX but isn't exported.
+		if !m.HasStubsVariants() {
+			return false
+		}
+	}
+	return classifySourceAbiDump(ctx) != ""
+}
+
+// Mark the direct and transitive dependencies of libraries that need ABI check, so that ABI dumps
+// of their dependencies would be generated.
+func sabiDepsMutator(mctx android.TopDownMutatorContext) {
+	// Escape hatch to not check any ABI dump.
+	if mctx.Config().IsEnvTrue("SKIP_ABI_CHECKS") {
+		return
+	}
+	// Only create ABI dump for native shared libraries and their static library dependencies.
+	if m, ok := mctx.Module().(*Module); ok && m.sabi != nil {
+		if shouldCreateSourceAbiDumpForLibrary(mctx) {
+			// Mark this module so that .sdump / .lsdump for this library can be generated.
+			m.sabi.Properties.ShouldCreateSourceAbiDump = true
+			// Mark all of its static library dependencies.
+			mctx.VisitDirectDeps(func(child android.Module) {
+				depTag := mctx.OtherModuleDependencyTag(child)
+				if libDepTag, ok := depTag.(libraryDependencyTag); ok && libDepTag.static() {
+					if c, ok := child.(*Module); ok && c.sabi != nil {
+						// Mark this module so that .sdump for this static library can be generated.
+						c.sabi.Properties.ShouldCreateSourceAbiDump = true
+					}
+				}
+			})
+		}
 	}
 }
 
+// Add an entry to the global list of lsdump. The list is exported to a Make variable by
+// `cc.makeVarsProvider`.
 func addLsdumpPath(lsdumpPath string) {
-	sabiLock.Lock()
+	lsdumpPathsLock.Lock()
+	defer lsdumpPathsLock.Unlock()
 	lsdumpPaths = append(lsdumpPaths, lsdumpPath)
-	sabiLock.Unlock()
 }
diff --git a/cc/snapshot_prebuilt.go b/cc/snapshot_prebuilt.go
index b291bd0..f5f8121 100644
--- a/cc/snapshot_prebuilt.go
+++ b/cc/snapshot_prebuilt.go
@@ -836,7 +836,7 @@
 	// Disables source modules if corresponding snapshot exists.
 	if lib, ok := module.linker.(libraryInterface); ok && lib.buildStatic() && lib.buildShared() {
 		// But do not disable because the shared variant depends on the static variant.
-		module.SkipInstall()
+		module.HideFromMake()
 		module.Properties.HideFromMake = true
 	} else {
 		module.Disable()
diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go
index da37d0f..bca76dc 100644
--- a/cc/vendor_snapshot.go
+++ b/cc/vendor_snapshot.go
@@ -181,8 +181,8 @@
 		return false
 	}
 	// When android/prebuilt.go selects between source and prebuilt, it sets
-	// SkipInstall on the other one to avoid duplicate install rules in make.
-	if m.IsSkipInstall() {
+	// HideFromMake on the other one to avoid duplicate install rules in make.
+	if m.IsHideFromMake() {
 		return false
 	}
 	// skip proprietary modules, but (for the vendor snapshot only)
diff --git a/cc/vndk_prebuilt.go b/cc/vndk_prebuilt.go
index e6e2ad8..04162cd 100644
--- a/cc/vndk_prebuilt.go
+++ b/cc/vndk_prebuilt.go
@@ -130,7 +130,7 @@
 	flags Flags, deps PathDeps, objs Objects) android.Path {
 
 	if !p.matchesWithDevice(ctx.DeviceConfig()) {
-		ctx.Module().SkipInstall()
+		ctx.Module().HideFromMake()
 		return nil
 	}
 
@@ -175,7 +175,7 @@
 		return in
 	}
 
-	ctx.Module().SkipInstall()
+	ctx.Module().HideFromMake()
 	return nil
 }
 
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index bd1d450..74ede68 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -174,7 +174,7 @@
 
 	build.SetupOutDir(buildCtx, config)
 
-	if config.UseBazel() {
+	if config.UseBazel() && config.Dist() {
 		defer populateExternalDistDir(buildCtx, config)
 	}
 
@@ -547,6 +547,12 @@
 		return
 	}
 
+	// Make sure the internal DIST_DIR actually exists before trying to read from it
+	if _, err = os.Stat(internalDistDirPath); os.IsNotExist(err) {
+		ctx.Println("Skipping Bazel dist dir migration - nothing to do!")
+		return
+	}
+
 	// Make sure the external DIST_DIR actually exists before trying to write to it
 	if err = os.MkdirAll(externalDistDirPath, 0755); err != nil {
 		ctx.Fatalf("Unable to make directory %s: %s", externalDistDirPath, err)
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 93938c9..8df32f2 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -139,7 +139,6 @@
 	// number of shards the input files are sharded into.
 	taskGenerator taskFunc
 
-	deps        android.Paths
 	rule        blueprint.Rule
 	rawCommands []string
 
@@ -206,7 +205,7 @@
 	if ok {
 		var bazelOutputFiles android.Paths
 		for _, bazelOutputFile := range filePaths {
-			bazelOutputFiles = append(bazelOutputFiles, android.PathForSource(ctx, bazelOutputFile))
+			bazelOutputFiles = append(bazelOutputFiles, android.PathForBazelOut(ctx, bazelOutputFile))
 		}
 		c.outputFiles = bazelOutputFiles
 		c.outputDeps = bazelOutputFiles
@@ -244,6 +243,8 @@
 		}
 	}
 
+	var tools android.Paths
+	var packagedTools []android.PackagingSpec
 	if len(g.properties.Tools) > 0 {
 		seenTools := make(map[string]bool)
 
@@ -251,37 +252,52 @@
 			switch tag := ctx.OtherModuleDependencyTag(module).(type) {
 			case hostToolDependencyTag:
 				tool := ctx.OtherModuleName(module)
-				var path android.OptionalPath
 
-				if t, ok := module.(android.HostToolProvider); ok {
+				switch t := module.(type) {
+				case android.HostToolProvider:
+					// A HostToolProvider provides the path to a tool, which will be copied
+					// into the sandbox.
 					if !t.(android.Module).Enabled() {
 						if ctx.Config().AllowMissingDependencies() {
 							ctx.AddMissingDependencies([]string{tool})
 						} else {
 							ctx.ModuleErrorf("depends on disabled module %q", tool)
 						}
-						break
+						return
 					}
-					path = t.HostToolPath()
-				} else if t, ok := module.(bootstrap.GoBinaryTool); ok {
+					path := t.HostToolPath()
+					if !path.Valid() {
+						ctx.ModuleErrorf("host tool %q missing output file", tool)
+						return
+					}
+					if specs := t.TransitivePackagingSpecs(); specs != nil {
+						// If the HostToolProvider has PackgingSpecs, which are definitions of the
+						// required relative locations of the tool and its dependencies, use those
+						// instead.  They will be copied to those relative locations in the sbox
+						// sandbox.
+						packagedTools = append(packagedTools, specs...)
+						// Assume that the first PackagingSpec of the module is the tool.
+						addLocationLabel(tag.label, []string{android.SboxPathForPackagedTool(specs[0])})
+					} else {
+						tools = append(tools, path.Path())
+						addLocationLabel(tag.label, []string{android.SboxPathForTool(ctx, path.Path())})
+					}
+				case bootstrap.GoBinaryTool:
+					// A GoBinaryTool provides the install path to a tool, which will be copied.
 					if s, err := filepath.Rel(android.PathForOutput(ctx).String(), t.InstallPath()); err == nil {
-						path = android.OptionalPathForPath(android.PathForOutput(ctx, s))
+						toolPath := android.PathForOutput(ctx, s)
+						tools = append(tools, toolPath)
+						addLocationLabel(tag.label, []string{android.SboxPathForTool(ctx, toolPath)})
 					} else {
 						ctx.ModuleErrorf("cannot find path for %q: %v", tool, err)
-						break
+						return
 					}
-				} else {
+				default:
 					ctx.ModuleErrorf("%q is not a host tool provider", tool)
-					break
+					return
 				}
 
-				if path.Valid() {
-					g.deps = append(g.deps, path.Path())
-					addLocationLabel(tag.label, []string{path.Path().String()})
-					seenTools[tag.label] = true
-				} else {
-					ctx.ModuleErrorf("host tool %q missing output file", tool)
-				}
+				seenTools[tag.label] = true
 			}
 		})
 
@@ -305,8 +321,12 @@
 
 	for _, toolFile := range g.properties.Tool_files {
 		paths := android.PathsForModuleSrc(ctx, []string{toolFile})
-		g.deps = append(g.deps, paths...)
-		addLocationLabel(toolFile, paths.Strings())
+		tools = append(tools, paths...)
+		var sandboxPaths []string
+		for _, path := range paths {
+			sandboxPaths = append(sandboxPaths, android.SboxPathForTool(ctx, path))
+		}
+		addLocationLabel(toolFile, sandboxPaths)
 	}
 
 	var srcFiles android.Paths
@@ -358,7 +378,7 @@
 		manifestPath := android.PathForModuleOut(ctx, manifestName)
 
 		// Use a RuleBuilder to create a rule that runs the command inside an sbox sandbox.
-		rule := android.NewRuleBuilder(pctx, ctx).Sbox(task.genDir, manifestPath)
+		rule := android.NewRuleBuilder(pctx, ctx).Sbox(task.genDir, manifestPath).SandboxTools()
 		cmd := rule.Command()
 
 		for _, out := range task.out {
@@ -448,8 +468,9 @@
 		cmd.Text(rawCommand)
 		cmd.ImplicitOutputs(task.out)
 		cmd.Implicits(task.in)
-		cmd.Implicits(g.deps)
-		cmd.Implicits(task.extraTools)
+		cmd.ImplicitTools(tools)
+		cmd.ImplicitTools(task.extraTools)
+		cmd.ImplicitPackagedTools(packagedTools)
 		if Bool(g.properties.Depfile) {
 			cmd.ImplicitDepFile(task.depFile)
 		}
@@ -547,6 +568,9 @@
 	}
 }
 
+var _ android.ApexModule = (*Module)(nil)
+
+// Implements android.ApexModule
 func (g *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext,
 	sdkVersion android.ApiLevel) error {
 	// Because generated outputs are checked by client modules(e.g. cc_library, ...)
@@ -616,7 +640,7 @@
 			// TODO(ccross): this RuleBuilder is a hack to be able to call
 			// rule.Command().PathForOutput.  Replace this with passing the rule into the
 			// generator.
-			rule := android.NewRuleBuilder(pctx, ctx).Sbox(genDir, nil)
+			rule := android.NewRuleBuilder(pctx, ctx).Sbox(genDir, nil).SandboxTools()
 
 			for _, in := range shard {
 				outFile := android.GenPathWithExt(ctx, finalSubDir, in, String(properties.Output_extension))
@@ -669,7 +693,8 @@
 				outputDepfile = android.PathForModuleGen(ctx, genSubDir, "gensrcs.d")
 				depFixerTool := ctx.Config().HostToolPath(ctx, "dep_fixer")
 				fullCommand += fmt.Sprintf(" && %s -o $(depfile) %s",
-					depFixerTool.String(), strings.Join(commandDepFiles, " "))
+					android.SboxPathForTool(ctx, depFixerTool),
+					strings.Join(commandDepFiles, " "))
 				extraTools = append(extraTools, depFixerTool)
 			}
 
diff --git a/genrule/genrule_test.go b/genrule/genrule_test.go
index 8d3cfcb..2f5605e 100644
--- a/genrule/genrule_test.go
+++ b/genrule/genrule_test.go
@@ -141,7 +141,7 @@
 				out: ["out"],
 				cmd: "$(location) > $(out)",
 			`,
-			expect: "out/tool > __SBOX_SANDBOX_DIR__/out/out",
+			expect: "__SBOX_SANDBOX_DIR__/tools/out/bin/tool > __SBOX_SANDBOX_DIR__/out/out",
 		},
 		{
 			name: "empty location tool2",
@@ -150,7 +150,7 @@
 				out: ["out"],
 				cmd: "$(location) > $(out)",
 			`,
-			expect: "out/tool > __SBOX_SANDBOX_DIR__/out/out",
+			expect: "__SBOX_SANDBOX_DIR__/tools/out/bin/tool > __SBOX_SANDBOX_DIR__/out/out",
 		},
 		{
 			name: "empty location tool file",
@@ -159,7 +159,7 @@
 				out: ["out"],
 				cmd: "$(location) > $(out)",
 			`,
-			expect: "tool_file1 > __SBOX_SANDBOX_DIR__/out/out",
+			expect: "__SBOX_SANDBOX_DIR__/tools/src/tool_file1 > __SBOX_SANDBOX_DIR__/out/out",
 		},
 		{
 			name: "empty location tool file fg",
@@ -168,7 +168,7 @@
 				out: ["out"],
 				cmd: "$(location) > $(out)",
 			`,
-			expect: "tool_file1 > __SBOX_SANDBOX_DIR__/out/out",
+			expect: "__SBOX_SANDBOX_DIR__/tools/src/tool_file1 > __SBOX_SANDBOX_DIR__/out/out",
 		},
 		{
 			name: "empty location tool and tool file",
@@ -178,7 +178,7 @@
 				out: ["out"],
 				cmd: "$(location) > $(out)",
 			`,
-			expect: "out/tool > __SBOX_SANDBOX_DIR__/out/out",
+			expect: "__SBOX_SANDBOX_DIR__/tools/out/bin/tool > __SBOX_SANDBOX_DIR__/out/out",
 		},
 		{
 			name: "tool",
@@ -187,7 +187,7 @@
 				out: ["out"],
 				cmd: "$(location tool) > $(out)",
 			`,
-			expect: "out/tool > __SBOX_SANDBOX_DIR__/out/out",
+			expect: "__SBOX_SANDBOX_DIR__/tools/out/bin/tool > __SBOX_SANDBOX_DIR__/out/out",
 		},
 		{
 			name: "tool2",
@@ -196,7 +196,7 @@
 				out: ["out"],
 				cmd: "$(location :tool) > $(out)",
 			`,
-			expect: "out/tool > __SBOX_SANDBOX_DIR__/out/out",
+			expect: "__SBOX_SANDBOX_DIR__/tools/out/bin/tool > __SBOX_SANDBOX_DIR__/out/out",
 		},
 		{
 			name: "tool file",
@@ -205,7 +205,7 @@
 				out: ["out"],
 				cmd: "$(location tool_file1) > $(out)",
 			`,
-			expect: "tool_file1 > __SBOX_SANDBOX_DIR__/out/out",
+			expect: "__SBOX_SANDBOX_DIR__/tools/src/tool_file1 > __SBOX_SANDBOX_DIR__/out/out",
 		},
 		{
 			name: "tool file fg",
@@ -214,7 +214,7 @@
 				out: ["out"],
 				cmd: "$(location :1tool_file) > $(out)",
 			`,
-			expect: "tool_file1 > __SBOX_SANDBOX_DIR__/out/out",
+			expect: "__SBOX_SANDBOX_DIR__/tools/src/tool_file1 > __SBOX_SANDBOX_DIR__/out/out",
 		},
 		{
 			name: "tool files",
@@ -223,7 +223,7 @@
 				out: ["out"],
 				cmd: "$(locations :tool_files) > $(out)",
 			`,
-			expect: "tool_file1 tool_file2 > __SBOX_SANDBOX_DIR__/out/out",
+			expect: "__SBOX_SANDBOX_DIR__/tools/src/tool_file1 __SBOX_SANDBOX_DIR__/tools/src/tool_file2 > __SBOX_SANDBOX_DIR__/out/out",
 		},
 		{
 			name: "in1",
@@ -600,7 +600,7 @@
 				cmd: "$(location) $(in) > $(out)",
 			`,
 			cmds: []string{
-				"bash -c 'out/tool in1.txt > __SBOX_SANDBOX_DIR__/out/in1.h' && bash -c 'out/tool in2.txt > __SBOX_SANDBOX_DIR__/out/in2.h'",
+				"bash -c '__SBOX_SANDBOX_DIR__/tools/out/bin/tool in1.txt > __SBOX_SANDBOX_DIR__/out/in1.h' && bash -c '__SBOX_SANDBOX_DIR__/tools/out/bin/tool in2.txt > __SBOX_SANDBOX_DIR__/out/in2.h'",
 			},
 			deps:  []string{buildDir + "/.intermediates/gen/gen/gensrcs/in1.h", buildDir + "/.intermediates/gen/gen/gensrcs/in2.h"},
 			files: []string{buildDir + "/.intermediates/gen/gen/gensrcs/in1.h", buildDir + "/.intermediates/gen/gen/gensrcs/in2.h"},
@@ -614,8 +614,8 @@
 				shard_size: 2,
 			`,
 			cmds: []string{
-				"bash -c 'out/tool in1.txt > __SBOX_SANDBOX_DIR__/out/in1.h' && bash -c 'out/tool in2.txt > __SBOX_SANDBOX_DIR__/out/in2.h'",
-				"bash -c 'out/tool in3.txt > __SBOX_SANDBOX_DIR__/out/in3.h'",
+				"bash -c '__SBOX_SANDBOX_DIR__/tools/out/bin/tool in1.txt > __SBOX_SANDBOX_DIR__/out/in1.h' && bash -c '__SBOX_SANDBOX_DIR__/tools/out/bin/tool in2.txt > __SBOX_SANDBOX_DIR__/out/in2.h'",
+				"bash -c '__SBOX_SANDBOX_DIR__/tools/out/bin/tool in3.txt > __SBOX_SANDBOX_DIR__/out/in3.h'",
 			},
 			deps:  []string{buildDir + "/.intermediates/gen/gen/gensrcs/in1.h", buildDir + "/.intermediates/gen/gen/gensrcs/in2.h", buildDir + "/.intermediates/gen/gen/gensrcs/in3.h"},
 			files: []string{buildDir + "/.intermediates/gen/gen/gensrcs/in1.h", buildDir + "/.intermediates/gen/gen/gensrcs/in2.h", buildDir + "/.intermediates/gen/gen/gensrcs/in3.h"},
@@ -736,7 +736,8 @@
 	}
 	gen := ctx.ModuleForTests("foo", "").Module().(*Module)
 
-	expectedOutputFiles := []string{"bazelone.txt", "bazeltwo.txt"}
+	expectedOutputFiles := []string{"outputbase/execroot/__main__/bazelone.txt",
+		"outputbase/execroot/__main__/bazeltwo.txt"}
 	if !reflect.DeepEqual(gen.outputFiles.Strings(), expectedOutputFiles) {
 		t.Errorf("Expected output files: %q, actual: %q", expectedOutputFiles, gen.outputFiles)
 	}
@@ -757,7 +758,7 @@
 }
 
 func (t *testTool) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	t.outputFile = android.PathForTesting("out", ctx.ModuleName())
+	t.outputFile = ctx.InstallFile(android.PathForModuleInstall(ctx, "bin"), ctx.ModuleName(), android.PathForOutput(ctx, ctx.ModuleName()))
 }
 
 func (t *testTool) HostToolPath() android.OptionalPath {
diff --git a/java/aar.go b/java/aar.go
index 3750f72..dfcd956 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -851,10 +851,14 @@
 	return nil, nil
 }
 
+var _ android.ApexModule = (*AARImport)(nil)
+
+// Implements android.ApexModule
 func (a *AARImport) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
 	return a.depIsInSameApex(ctx, dep)
 }
 
+// Implements android.ApexModule
 func (g *AARImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext,
 	sdkVersion android.ApiLevel) error {
 	return nil
diff --git a/java/app.go b/java/app.go
index e6d9550..c0ac9c2 100755
--- a/java/app.go
+++ b/java/app.go
@@ -1653,6 +1653,9 @@
 	return sdkSpecFrom("")
 }
 
+var _ android.ApexModule = (*AndroidAppImport)(nil)
+
+// Implements android.ApexModule
 func (j *AndroidAppImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext,
 	sdkVersion android.ApiLevel) error {
 	// Do not check for prebuilts against the min_sdk_version of enclosing APEX
diff --git a/java/java.go b/java/java.go
index d44719e..02d78f2 100644
--- a/java/java.go
+++ b/java/java.go
@@ -2021,10 +2021,12 @@
 	return len(srcFiles) > 0 || len(ctx.GetDirectDepsWithTag(staticLibTag)) > 0
 }
 
+// Implements android.ApexModule
 func (j *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
 	return j.depIsInSameApex(ctx, dep)
 }
 
+// Implements android.ApexModule
 func (j *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext,
 	sdkVersion android.ApiLevel) error {
 	sdkSpec := j.minSdkVersion()
@@ -2070,6 +2072,8 @@
 	InstallMixin func(ctx android.ModuleContext, installPath android.Path) (extraInstallDeps android.Paths)
 }
 
+var _ android.ApexModule = (*Library)(nil)
+
 // Provides access to the list of permitted packages from updatable boot jars.
 type PermittedPackagesForUpdatableBootJars interface {
 	PermittedPackagesForUpdatableBootJars() []string
@@ -2934,10 +2938,14 @@
 	return nil, nil
 }
 
+var _ android.ApexModule = (*Import)(nil)
+
+// Implements android.ApexModule
 func (j *Import) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
 	return j.depIsInSameApex(ctx, dep)
 }
 
+// Implements android.ApexModule
 func (j *Import) ShouldSupportSdkVersion(ctx android.BaseModuleContext,
 	sdkVersion android.ApiLevel) error {
 	// Do not check for prebuilts against the min_sdk_version of enclosing APEX
@@ -3129,6 +3137,9 @@
 	return j.dexJarFile
 }
 
+var _ android.ApexModule = (*DexImport)(nil)
+
+// Implements android.ApexModule
 func (j *DexImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext,
 	sdkVersion android.ApiLevel) error {
 	// we don't check prebuilt modules for sdk_version
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 4e33d74..2e10f9c 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -1925,6 +1925,9 @@
 	}
 }
 
+var _ android.ApexModule = (*SdkLibraryImport)(nil)
+
+// Implements android.ApexModule
 func (module *SdkLibraryImport) DepIsInSameApex(mctx android.BaseModuleContext, dep android.Module) bool {
 	depTag := mctx.OtherModuleDependencyTag(dep)
 	if depTag == xmlPermissionsFileTag {
@@ -1936,6 +1939,7 @@
 	return false
 }
 
+// Implements android.ApexModule
 func (module *SdkLibraryImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext,
 	sdkVersion android.ApiLevel) error {
 	// we don't check prebuilt modules for sdk_version
@@ -2141,6 +2145,9 @@
 	// do nothing
 }
 
+var _ android.ApexModule = (*sdkLibraryXml)(nil)
+
+// Implements android.ApexModule
 func (module *sdkLibraryXml) ShouldSupportSdkVersion(ctx android.BaseModuleContext,
 	sdkVersion android.ApiLevel) error {
 	// sdkLibraryXml doesn't need to be checked separately because java_sdk_library is checked
diff --git a/rust/config/allowed_list.go b/rust/config/allowed_list.go
index df31d60..21df024 100644
--- a/rust/config/allowed_list.go
+++ b/rust/config/allowed_list.go
@@ -9,6 +9,7 @@
 		"device/google/cuttlefish",
 		"external/adhd",
 		"external/crosvm",
+		"external/libchromeos-rs",
 		"external/minijail",
 		"external/rust",
 		"external/vm_tools/p9",
diff --git a/rust/image.go b/rust/image.go
index 4951d2b..af8c3b2 100644
--- a/rust/image.go
+++ b/rust/image.go
@@ -90,7 +90,7 @@
 		vndkVersion := ctx.DeviceConfig().VndkVersion()
 		if vndkVersion != "current" && vndkVersion != "" && vndkVersion != m.Properties.VndkVersion {
 			m.Properties.HideFromMake = true
-			m.SkipInstall()
+			m.HideFromMake()
 		}
 	}
 }
diff --git a/rust/protobuf.go b/rust/protobuf.go
index 4fba34f..b91fea8 100644
--- a/rust/protobuf.go
+++ b/rust/protobuf.go
@@ -31,24 +31,22 @@
 
 type PluginType int
 
-const (
-	Protobuf PluginType = iota
-	Grpc
-)
-
 func init() {
 	android.RegisterModuleType("rust_protobuf", RustProtobufFactory)
 	android.RegisterModuleType("rust_protobuf_host", RustProtobufHostFactory)
-	android.RegisterModuleType("rust_grpcio", RustGrpcioFactory)
-	android.RegisterModuleType("rust_grpcio_host", RustGrpcioHostFactory)
 }
 
 var _ SourceProvider = (*protobufDecorator)(nil)
 
 type ProtobufProperties struct {
-	// List of relative paths to proto files that will be used to generate the source
+	// List of relative paths to proto files that will be used to generate the source.
+	// Either this or grpc_protos must be defined.
 	Protos []string `android:"path,arch_variant"`
 
+	// List of relative paths to GRPC-containing proto files that will be used to generate the source.
+	// Either this or protos must be defined.
+	Grpc_protos []string `android:"path,arch_variant"`
+
 	// List of additional flags to pass to aprotoc
 	Proto_flags []string `android:"arch_variant"`
 
@@ -60,33 +58,54 @@
 	*BaseSourceProvider
 
 	Properties ProtobufProperties
-	plugin     PluginType
+	protoNames []string
+	grpcNames  []string
+
+	grpcProtoFlags android.ProtoFlags
+	protoFlags     android.ProtoFlags
 }
 
 func (proto *protobufDecorator) GenerateSource(ctx ModuleContext, deps PathDeps) android.Path {
 	var protoFlags android.ProtoFlags
-	var pluginPaths android.Paths
-	var protoNames []string
+	var grpcProtoFlags android.ProtoFlags
+	var commonProtoFlags []string
 
-	protoFlags.OutTypeFlag = "--rust_out"
 	outDir := android.PathForModuleOut(ctx)
-
-	pluginPaths, protoFlags = proto.setupPlugin(ctx, protoFlags, outDir)
-
-	protoFlags.Flags = append(protoFlags.Flags, defaultProtobufFlags...)
-	protoFlags.Flags = append(protoFlags.Flags, proto.Properties.Proto_flags...)
-
-	protoFlags.Deps = append(protoFlags.Deps, pluginPaths...)
-
 	protoFiles := android.PathsForModuleSrc(ctx, proto.Properties.Protos)
+	grpcFiles := android.PathsForModuleSrc(ctx, proto.Properties.Grpc_protos)
+	protoPluginPath := ctx.Config().HostToolPath(ctx, "protoc-gen-rust")
 
-	if len(protoFiles) == 0 {
-		ctx.PropertyErrorf("protos", "at least one protobuf must be defined.")
+	commonProtoFlags = append(commonProtoFlags, defaultProtobufFlags...)
+	commonProtoFlags = append(commonProtoFlags, proto.Properties.Proto_flags...)
+	commonProtoFlags = append(commonProtoFlags, "--plugin=protoc-gen-rust="+protoPluginPath.String())
+
+	if len(protoFiles) > 0 {
+		protoFlags.OutTypeFlag = "--rust_out"
+		protoFlags.Flags = append(protoFlags.Flags, commonProtoFlags...)
+
+		protoFlags.Deps = append(protoFlags.Deps, protoPluginPath)
+	}
+
+	if len(grpcFiles) > 0 {
+		grpcPath := ctx.Config().HostToolPath(ctx, "grpc_rust_plugin")
+
+		grpcProtoFlags.OutTypeFlag = "--rust_out"
+		grpcProtoFlags.Flags = append(grpcProtoFlags.Flags, "--grpc_out="+outDir.String())
+		grpcProtoFlags.Flags = append(grpcProtoFlags.Flags, "--plugin=protoc-gen-grpc="+grpcPath.String())
+		grpcProtoFlags.Flags = append(grpcProtoFlags.Flags, commonProtoFlags...)
+
+		grpcProtoFlags.Deps = append(grpcProtoFlags.Deps, grpcPath, protoPluginPath)
+	}
+
+	if len(protoFiles) == 0 && len(grpcFiles) == 0 {
+		ctx.PropertyErrorf("protos",
+			"at least one protobuf must be defined in either protos or grpc_protos.")
 	}
 
 	// Add exported dependency include paths
 	for _, include := range deps.depIncludePaths {
 		protoFlags.Flags = append(protoFlags.Flags, "-I"+include.String())
+		grpcProtoFlags.Flags = append(grpcProtoFlags.Flags, "-I"+include.String())
 	}
 
 	stem := proto.BaseSourceProvider.getStem(ctx)
@@ -98,25 +117,50 @@
 	var outputs android.WritablePaths
 
 	rule := android.NewRuleBuilder(pctx, ctx)
+
 	for _, protoFile := range protoFiles {
-		protoName := strings.TrimSuffix(protoFile.Base(), ".proto")
-		protoNames = append(protoNames, protoName)
-
-		protoOut := android.PathForModuleOut(ctx, protoName+".rs")
-		ruleOutputs := android.WritablePaths{android.WritablePath(protoOut)}
-
-		if proto.plugin == Grpc {
-			grpcOut := android.PathForModuleOut(ctx, protoName+grpcSuffix+".rs")
-			ruleOutputs = append(ruleOutputs, android.WritablePath(grpcOut))
+		// Since we're iterating over the protoFiles already, make sure they're not redeclared in grpcFiles
+		if android.InList(protoFile.String(), grpcFiles.Strings()) {
+			ctx.PropertyErrorf("protos",
+				"A proto can only be added once to either grpc_protos or protos. %q is declared in both properties",
+				protoFile.String())
 		}
 
+		protoName := strings.TrimSuffix(protoFile.Base(), ".proto")
+		proto.protoNames = append(proto.protoNames, protoName)
+
+		protoOut := android.PathForModuleOut(ctx, protoName+".rs")
 		depFile := android.PathForModuleOut(ctx, protoName+".d")
 
+		ruleOutputs := android.WritablePaths{protoOut, depFile}
+
 		android.ProtoRule(rule, protoFile, protoFlags, protoFlags.Deps, outDir, depFile, ruleOutputs)
 		outputs = append(outputs, ruleOutputs...)
 	}
 
-	android.WriteFileRule(ctx, stemFile, proto.genModFileContents(ctx, protoNames))
+	for _, grpcFile := range grpcFiles {
+		grpcName := strings.TrimSuffix(grpcFile.Base(), ".proto")
+		proto.grpcNames = append(proto.grpcNames, grpcName)
+
+		// GRPC protos produce two files, a proto.rs and a proto_grpc.rs
+		protoOut := android.WritablePath(android.PathForModuleOut(ctx, grpcName+".rs"))
+		grpcOut := android.WritablePath(android.PathForModuleOut(ctx, grpcName+grpcSuffix+".rs"))
+		depFile := android.PathForModuleOut(ctx, grpcName+".d")
+
+		ruleOutputs := android.WritablePaths{protoOut, grpcOut, depFile}
+
+		android.ProtoRule(rule, grpcFile, grpcProtoFlags, grpcProtoFlags.Deps, outDir, depFile, ruleOutputs)
+		outputs = append(outputs, ruleOutputs...)
+	}
+
+	// Check that all proto base filenames are unique as outputs are written to the same directory.
+	baseFilenames := append(proto.protoNames, proto.grpcNames...)
+	if len(baseFilenames) != len(android.FirstUniqueStrings(baseFilenames)) {
+		ctx.PropertyErrorf("protos", "proto filenames must be unique across  'protos' and 'grpc_protos' "+
+			"to be used in the same rust_protobuf module. For example, foo.proto and src/foo.proto will conflict.")
+	}
+
+	android.WriteFileRule(ctx, stemFile, proto.genModFileContents())
 
 	rule.Build("protoc_"+ctx.ModuleName(), "protoc "+ctx.ModuleName())
 
@@ -127,19 +171,19 @@
 	return stemFile
 }
 
-func (proto *protobufDecorator) genModFileContents(ctx ModuleContext, protoNames []string) string {
+func (proto *protobufDecorator) genModFileContents() string {
 	lines := []string{
 		"// @Soong generated Source",
 	}
-	for _, protoName := range protoNames {
+	for _, protoName := range proto.protoNames {
 		lines = append(lines, fmt.Sprintf("pub mod %s;", protoName))
-
-		if proto.plugin == Grpc {
-			lines = append(lines, fmt.Sprintf("pub mod %s%s;", protoName, grpcSuffix))
-		}
 	}
 
-	if proto.plugin == Grpc {
+	for _, grpcName := range proto.grpcNames {
+		lines = append(lines, fmt.Sprintf("pub mod %s;", grpcName))
+		lines = append(lines, fmt.Sprintf("pub mod %s%s;", grpcName, grpcSuffix))
+	}
+	if len(proto.grpcNames) > 0 {
 		lines = append(
 			lines,
 			"pub mod empty {",
@@ -150,27 +194,6 @@
 	return strings.Join(lines, "\n")
 }
 
-func (proto *protobufDecorator) setupPlugin(ctx ModuleContext, protoFlags android.ProtoFlags, outDir android.ModuleOutPath) (android.Paths, android.ProtoFlags) {
-	pluginPaths := []android.Path{}
-
-	if proto.plugin == Protobuf {
-		pluginPath := ctx.Config().HostToolPath(ctx, "protoc-gen-rust")
-		pluginPaths = append(pluginPaths, pluginPath)
-		protoFlags.Flags = append(protoFlags.Flags, "--plugin="+pluginPath.String())
-	} else if proto.plugin == Grpc {
-		grpcPath := ctx.Config().HostToolPath(ctx, "grpc_rust_plugin")
-		protobufPath := ctx.Config().HostToolPath(ctx, "protoc-gen-rust")
-		pluginPaths = append(pluginPaths, grpcPath, protobufPath)
-		protoFlags.Flags = append(protoFlags.Flags, "--grpc_out="+outDir.String())
-		protoFlags.Flags = append(protoFlags.Flags, "--plugin=protoc-gen-grpc="+grpcPath.String())
-		protoFlags.Flags = append(protoFlags.Flags, "--plugin=protoc-gen-rust="+protobufPath.String())
-	} else {
-		ctx.ModuleErrorf("Unknown protobuf plugin type requested")
-	}
-
-	return pluginPaths, protoFlags
-}
-
 func (proto *protobufDecorator) SourceProviderProps() []interface{} {
 	return append(proto.BaseSourceProvider.SourceProviderProps(), &proto.Properties)
 }
@@ -180,7 +203,7 @@
 	deps.Rustlibs = append(deps.Rustlibs, "libprotobuf")
 	deps.HeaderLibs = append(deps.SharedLibs, proto.Properties.Header_libs...)
 
-	if proto.plugin == Grpc {
+	if len(proto.Properties.Grpc_protos) > 0 {
 		deps.Rustlibs = append(deps.Rustlibs, "libgrpcio", "libfutures")
 		deps.HeaderLibs = append(deps.HeaderLibs, "libprotobuf-cpp-full")
 	}
@@ -203,34 +226,10 @@
 	return module.Init()
 }
 
-func RustGrpcioFactory() android.Module {
-	module, _ := NewRustGrpcio(android.HostAndDeviceSupported)
-	return module.Init()
-}
-
-// A host-only variant of rust_protobuf. Refer to rust_protobuf for more details.
-func RustGrpcioHostFactory() android.Module {
-	module, _ := NewRustGrpcio(android.HostSupported)
-	return module.Init()
-}
-
 func NewRustProtobuf(hod android.HostOrDeviceSupported) (*Module, *protobufDecorator) {
 	protobuf := &protobufDecorator{
 		BaseSourceProvider: NewSourceProvider(),
 		Properties:         ProtobufProperties{},
-		plugin:             Protobuf,
-	}
-
-	module := NewSourceProviderModule(hod, protobuf, false)
-
-	return module, protobuf
-}
-
-func NewRustGrpcio(hod android.HostOrDeviceSupported) (*Module, *protobufDecorator) {
-	protobuf := &protobufDecorator{
-		BaseSourceProvider: NewSourceProvider(),
-		Properties:         ProtobufProperties{},
-		plugin:             Grpc,
 	}
 
 	module := NewSourceProviderModule(hod, protobuf, false)
diff --git a/rust/protobuf_test.go b/rust/protobuf_test.go
index 608a4e8..1ac66f3 100644
--- a/rust/protobuf_test.go
+++ b/rust/protobuf_test.go
@@ -69,31 +69,19 @@
 	}
 }
 
-func TestRustGrpcio(t *testing.T) {
+func TestRustGrpc(t *testing.T) {
 	ctx := testRust(t, `
-		rust_grpcio {
+		rust_protobuf {
 			name: "librust_grpcio",
-			protos: ["buf.proto", "proto.proto"],
+			protos: ["buf.proto"],
+			grpc_protos: ["foo.proto", "proto.proto"],
 			crate_name: "rust_grpcio",
 			source_stem: "buf",
-			shared_libs: ["libfoo_shared"],
-			static_libs: ["libfoo_static"],
-		}
-		cc_library_shared {
-			name: "libfoo_shared",
-			export_include_dirs: ["shared_include"],
-		}
-		cc_library_static {
-			name: "libfoo_static",
-			export_include_dirs: ["static_include"],
 		}
 	`)
 
 	// Check that libprotobuf is added as a dependency.
 	librust_grpcio_module := ctx.ModuleForTests("librust_grpcio", "android_arm64_armv8-a_dylib").Module().(*Module)
-	if !android.InList("libprotobuf", librust_grpcio_module.Properties.AndroidMkDylibs) {
-		t.Errorf("libprotobuf dependency missing for rust_grpcio (dependency missing from AndroidMkDylibs)")
-	}
 
 	// Check that libgrpcio is added as a dependency.
 	if !android.InList("libgrpcio", librust_grpcio_module.Properties.AndroidMkDylibs) {
@@ -106,20 +94,12 @@
 	}
 
 	// Make sure the correct plugin is being used.
-	librust_grpcio_out := ctx.ModuleForTests("librust_grpcio", "android_arm64_armv8-a_source").Output("buf_grpc.rs")
+	librust_grpcio_out := ctx.ModuleForTests("librust_grpcio", "android_arm64_armv8-a_source").Output("foo_grpc.rs")
 	cmd := librust_grpcio_out.RuleParams.Command
 	if w := "protoc-gen-grpc"; !strings.Contains(cmd, w) {
 		t.Errorf("expected %q in %q", w, cmd)
 	}
 
-	// Check exported include directories
-	if w := "-Ishared_include"; !strings.Contains(cmd, w) {
-		t.Errorf("expected %q in %q", w, cmd)
-	}
-	if w := "-Istatic_include"; !strings.Contains(cmd, w) {
-		t.Errorf("expected %q in %q", w, cmd)
-	}
-
 	// Check that we're including the exported directory from libprotobuf-cpp-full
 	if w := "-Ilibprotobuf-cpp-full-includes"; !strings.Contains(cmd, w) {
 		t.Errorf("expected %q in %q", w, cmd)
@@ -132,3 +112,25 @@
 			librust_grpcio_outputs)
 	}
 }
+
+func TestRustProtoErrors(t *testing.T) {
+	testRustError(t, "A proto can only be added once to either grpc_protos or protos.*", `
+		rust_protobuf {
+			name: "librust_grpcio",
+			protos: ["buf.proto"],
+			grpc_protos: ["buf.proto"],
+			crate_name: "rust_grpcio",
+			source_stem: "buf",
+		}
+	`)
+
+	testRustError(t, "proto filenames must be unique across  'protos' and 'grpc_protos'.*", `
+		rust_protobuf {
+			name: "librust_grpcio",
+			protos: ["buf.proto"],
+			grpc_protos: ["proto/buf.proto"],
+			crate_name: "rust_grpcio",
+			source_stem: "buf",
+		}
+	`)
+}
diff --git a/rust/rust.go b/rust/rust.go
index 3d70121..21da5ae 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -1065,6 +1065,9 @@
 	return String(mod.Properties.Min_sdk_version)
 }
 
+var _ android.ApexModule = (*Module)(nil)
+
+// Implements android.ApexModule
 func (mod *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion android.ApiLevel) error {
 	minSdkVersion := mod.minSdkVersion()
 	if minSdkVersion == "apex_inherit" {
@@ -1087,6 +1090,7 @@
 	return nil
 }
 
+// Implements android.ApexModule
 func (mod *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
 	depTag := ctx.OtherModuleDependencyTag(dep)
 
diff --git a/rust/rust_test.go b/rust/rust_test.go
index 4edc6cd..48c8d74 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -106,14 +106,16 @@
 // useMockedFs setup a default mocked filesystem for the test environment.
 func (tctx *testRustCtx) useMockedFs() {
 	tctx.fs = map[string][]byte{
-		"foo.rs":      nil,
-		"foo.c":       nil,
-		"src/bar.rs":  nil,
-		"src/any.h":   nil,
-		"proto.proto": nil,
-		"buf.proto":   nil,
-		"liby.so":     nil,
-		"libz.so":     nil,
+		"foo.rs":          nil,
+		"foo.c":           nil,
+		"src/bar.rs":      nil,
+		"src/any.h":       nil,
+		"proto.proto":     nil,
+		"proto/buf.proto": nil,
+		"buf.proto":       nil,
+		"foo.proto":       nil,
+		"liby.so":         nil,
+		"libz.so":         nil,
 	}
 }
 
diff --git a/rust/testing.go b/rust/testing.go
index 963a4ea..07f557a 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -153,8 +153,6 @@
 	ctx.RegisterModuleType("rust_ffi_host", RustFFIHostFactory)
 	ctx.RegisterModuleType("rust_ffi_host_shared", RustFFISharedHostFactory)
 	ctx.RegisterModuleType("rust_ffi_host_static", RustFFIStaticHostFactory)
-	ctx.RegisterModuleType("rust_grpcio", RustGrpcioFactory)
-	ctx.RegisterModuleType("rust_grpcio_host", RustGrpcioHostFactory)
 	ctx.RegisterModuleType("rust_proc_macro", ProcMacroFactory)
 	ctx.RegisterModuleType("rust_protobuf", RustProtobufFactory)
 	ctx.RegisterModuleType("rust_protobuf_host", RustProtobufHostFactory)
diff --git a/scripts/build-aml-prebuilts.sh b/scripts/build-aml-prebuilts.sh
index e6e541e..4b08ac3 100755
--- a/scripts/build-aml-prebuilts.sh
+++ b/scripts/build-aml-prebuilts.sh
@@ -54,6 +54,11 @@
 PLATFORM_VERSION_ALL_CODENAMES="${PLATFORM_VERSION_ALL_CODENAMES/,/'","'}"
 PLATFORM_VERSION_ALL_CODENAMES="[\"${PLATFORM_VERSION_ALL_CODENAMES}\"]"
 
+# Get the list of missing <uses-library> modules and convert it to a JSON array
+# (quote module names, add comma separator and wrap in brackets).
+MISSING_USES_LIBRARIES="$(my_get_build_var INTERNAL_PLATFORM_MISSING_USES_LIBRARIES)"
+MISSING_USES_LIBRARIES="[$(echo $MISSING_USES_LIBRARIES | sed -e 's/\([^ ]\+\)/\"\1\"/g' -e 's/[ ]\+/, /g')]"
+
 # Logic from build/make/core/goma.mk
 if [ "${USE_GOMA}" = true ]; then
   if [ -n "${GOMA_DIR}" ]; then
@@ -84,6 +89,7 @@
 {
     "BuildNumberFile": "build_number.txt",
 
+    "Platform_version_name": "${PLATFORM_VERSION}",
     "Platform_sdk_version": ${PLATFORM_SDK_VERSION},
     "Platform_sdk_codename": "${PLATFORM_VERSION}",
     "Platform_version_active_codenames": ${PLATFORM_VERSION_ALL_CODENAMES},
@@ -103,7 +109,9 @@
         "art_module": {
             "source_build": "${ENABLE_ART_SOURCE_BUILD:-true}"
         }
-    }
+    },
+
+    "MissingUsesLibraries": ${MISSING_USES_LIBRARIES}
 }
 EOF
 
diff --git a/scripts/build-mainline-modules.sh b/scripts/build-mainline-modules.sh
index b8dd7aa..6db870f 100755
--- a/scripts/build-mainline-modules.sh
+++ b/scripts/build-mainline-modules.sh
@@ -16,15 +16,16 @@
 MODULES_SDK_AND_EXPORTS=(
   art-module-sdk
   art-module-test-exports
+  conscrypt-module-host-exports
   conscrypt-module-sdk
   conscrypt-module-test-exports
-  conscrypt-module-host-exports
-  runtime-module-sdk
-  runtime-module-host-exports
-  i18n-module-test-exports
+  i18n-module-host-exports
   i18n-module-sdk
+  i18n-module-test-exports
   platform-mainline-sdk
   platform-mainline-test-exports
+  runtime-module-host-exports
+  runtime-module-sdk
 )
 
 # List of libraries installed on the platform that are needed for ART chroot
diff --git a/scripts/build-ndk-prebuilts.sh b/scripts/build-ndk-prebuilts.sh
index b6ed659..1a33219 100755
--- a/scripts/build-ndk-prebuilts.sh
+++ b/scripts/build-ndk-prebuilts.sh
@@ -30,6 +30,11 @@
 PLATFORM_VERSION_ALL_CODENAMES=${PLATFORM_VERSION_ALL_CODENAMES/,/'","'}
 PLATFORM_VERSION_ALL_CODENAMES="[\"${PLATFORM_VERSION_ALL_CODENAMES}\"]"
 
+# Get the list of missing <uses-library> modules and convert it to a JSON array
+# (quote module names, add comma separator and wrap in brackets).
+MISSING_USES_LIBRARIES="$(get_build_var INTERNAL_PLATFORM_MISSING_USES_LIBRARIES)"
+MISSING_USES_LIBRARIES="[$(echo $MISSING_USES_LIBRARIES | sed -e 's/\([^ ]\+\)/\"\1\"/g' -e 's/[ ]\+/, /g')]"
+
 SOONG_OUT=${OUT_DIR}/soong
 SOONG_NDK_OUT=${OUT_DIR}/soong/ndk
 rm -rf ${SOONG_OUT}
@@ -49,7 +54,9 @@
     "Safestack": false,
 
     "Ndk_abis": true,
-    "Exclude_draft_ndk_apis": true
+    "Exclude_draft_ndk_apis": true,
+
+    "MissingUsesLibraries": ${MISSING_USES_LIBRARIES}
 }
 EOF
 m --skip-make ${SOONG_OUT}/ndk.timestamp
diff --git a/shared/Android.bp b/shared/Android.bp
index 07dfe11..2a4f56f 100644
--- a/shared/Android.bp
+++ b/shared/Android.bp
@@ -4,4 +4,7 @@
     srcs: [
         "paths.go",
     ],
+    deps: [
+        "soong-bazel",
+    ],
 }
diff --git a/shared/paths.go b/shared/paths.go
index f5dc5dd..1b9ff60 100644
--- a/shared/paths.go
+++ b/shared/paths.go
@@ -18,6 +18,8 @@
 
 import (
 	"path/filepath"
+
+	"android/soong/bazel"
 )
 
 // A SharedPaths represents a list of paths that are shared between
@@ -37,6 +39,6 @@
 // on the action name. This is to help to store a set of bazel
 // profiles since bazel may execute multiple times during a single
 // build.
-func BazelMetricsFilename(s SharedPaths, actionName string) string {
-	return filepath.Join(s.BazelMetricsDir(), actionName+"_bazel_profile.gz")
+func BazelMetricsFilename(s SharedPaths, actionName bazel.RunName) string {
+	return filepath.Join(s.BazelMetricsDir(), actionName.String()+"_bazel_profile.gz")
 }
diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go
index 6a53414..93a3fe0 100644
--- a/sysprop/sysprop_library.go
+++ b/sysprop/sysprop_library.go
@@ -322,6 +322,9 @@
 		}}
 }
 
+var _ android.ApexModule = (*syspropLibrary)(nil)
+
+// Implements android.ApexModule
 func (m *syspropLibrary) ShouldSupportSdkVersion(ctx android.BaseModuleContext,
 	sdkVersion android.ApiLevel) error {
 	return fmt.Errorf("sysprop_library is not supposed to be part of apex modules")
diff --git a/ui/build/bazel.go b/ui/build/bazel.go
index 4f2d645..81ce939 100644
--- a/ui/build/bazel.go
+++ b/ui/build/bazel.go
@@ -22,6 +22,7 @@
 	"path/filepath"
 	"strings"
 
+	"android/soong/bazel"
 	"android/soong/shared"
 	"android/soong/ui/metrics"
 )
@@ -97,9 +98,9 @@
 	}
 
 	// Start constructing the `build` command.
-	actionName := "build"
+	actionName := bazel.BazelNinjaExecRunName
 	cmd.Args = append(cmd.Args,
-		actionName,
+		"build",
 		// Use output_groups to select the set of outputs to produce from a
 		// ninja_build target.
 		"--output_groups="+outputGroups,
diff --git a/ui/build/soong.go b/ui/build/soong.go
index 08c2ee1..6a93672 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -156,6 +156,7 @@
 		cmd.Environment.Set("BAZEL_HOME", filepath.Join(config.BazelOutDir(), "bazelhome"))
 		cmd.Environment.Set("BAZEL_OUTPUT_BASE", filepath.Join(config.BazelOutDir(), "output"))
 		cmd.Environment.Set("BAZEL_WORKSPACE", absPath(ctx, "."))
+		cmd.Environment.Set("BAZEL_METRICS_DIR", config.BazelMetricsDir())
 
 		cmd.Environment.Set("SOONG_SANDBOX_SOONG_BUILD", "true")
 		cmd.Sandbox = soongSandbox
diff --git a/ui/metrics/event.go b/ui/metrics/event.go
index 6becfd1..87c1b84 100644
--- a/ui/metrics/event.go
+++ b/ui/metrics/event.go
@@ -14,6 +14,17 @@
 
 package metrics
 
+// This file contains the functionality to represent a build event in respect
+// to the metric system. A build event corresponds to a block of scoped code
+// that contains a "Begin()" and immediately followed by "defer End()" trace.
+// When defined, the duration of the scoped code is measure along with other
+// performance measurements such as memory.
+//
+// As explained in the metrics package, the metrics system is a stacked based
+// system since the collected metrics is considered to be topline metrics.
+// The steps of the build system in the UI layer is sequential. Hence, the
+// functionality defined below follows the stack data structure operations.
+
 import (
 	"os"
 	"syscall"
@@ -21,54 +32,97 @@
 
 	"android/soong/ui/metrics/metrics_proto"
 	"android/soong/ui/tracer"
+
 	"github.com/golang/protobuf/proto"
 )
 
-// for testing purpose only
-var _now = now
-
-type event struct {
-	desc string
-	name string
-
-	// the time that the event started to occur.
-	start time.Time
-
-	// The list of process resource information that was executed
-	procResInfo []*soong_metrics_proto.ProcessResourceInfo
-}
-
-type EventTracer interface {
-	Begin(name, desc string, thread tracer.Thread)
-	End(thread tracer.Thread) soong_metrics_proto.PerfInfo
-	AddProcResInfo(string, *os.ProcessState)
-}
-
-type eventTracerImpl struct {
-	activeEvents []event
-}
-
-var _ EventTracer = &eventTracerImpl{}
-
-func now() time.Time {
+// _now wraps the time.Now() function. _now is declared for unit testing purpose.
+var _now = func() time.Time {
 	return time.Now()
 }
 
-// AddProcResInfo adds information on an executed process such as max resident set memory
-// and the number of voluntary context switches.
-func (t *eventTracerImpl) AddProcResInfo(name string, state *os.ProcessState) {
-	if len(t.activeEvents) < 1 {
+// event holds the performance metrics data of a single build event.
+type event struct {
+	// The event name (mostly used for grouping a set of events)
+	name string
+
+	// The description of the event (used to uniquely identify an event
+	// for metrics analysis).
+	desc string
+
+	// The time that the event started to occur.
+	start time.Time
+
+	// The list of process resource information that was executed.
+	procResInfo []*soong_metrics_proto.ProcessResourceInfo
+}
+
+// newEvent returns an event with start populated with the now time.
+func newEvent(name, desc string) *event {
+	return &event{
+		name:  name,
+		desc:  desc,
+		start: _now(),
+	}
+}
+
+func (e event) perfInfo() soong_metrics_proto.PerfInfo {
+	realTime := uint64(_now().Sub(e.start).Nanoseconds())
+	return soong_metrics_proto.PerfInfo{
+		Desc:                  proto.String(e.desc),
+		Name:                  proto.String(e.name),
+		StartTime:             proto.Uint64(uint64(e.start.UnixNano())),
+		RealTime:              proto.Uint64(realTime),
+		ProcessesResourceInfo: e.procResInfo,
+	}
+}
+
+// EventTracer is an array of events that provides functionality to trace a
+// block of code on time and performance. The End call expects the Begin is
+// invoked, otherwise panic is raised.
+type EventTracer []*event
+
+// empty returns true if there are no pending events.
+func (t *EventTracer) empty() bool {
+	return len(*t) == 0
+}
+
+// lastIndex returns the index of the last element of events.
+func (t *EventTracer) lastIndex() int {
+	return len(*t) - 1
+}
+
+// peek returns the active build event.
+func (t *EventTracer) peek() *event {
+	return (*t)[t.lastIndex()]
+}
+
+// push adds the active build event in the stack.
+func (t *EventTracer) push(e *event) {
+	*t = append(*t, e)
+}
+
+// pop removes the active event from the stack since the event has completed.
+// A panic is raised if there are no pending events.
+func (t *EventTracer) pop() *event {
+	if t.empty() {
+		panic("Internal error: No pending events")
+	}
+	e := (*t)[t.lastIndex()]
+	*t = (*t)[:t.lastIndex()]
+	return e
+}
+
+// AddProcResInfo adds information on an executed process such as max resident
+// set memory and the number of voluntary context switches.
+func (t *EventTracer) AddProcResInfo(name string, state *os.ProcessState) {
+	if t.empty() {
 		return
 	}
 
 	rusage := state.SysUsage().(*syscall.Rusage)
-	// The implementation of the metrics system is a stacked based system. The steps of the
-	// build system in the UI layer is sequential so the Begin function is invoked when a
-	// function (or scoped code) is invoked. That is translated to a new event which is added
-	// at the end of the activeEvents array. When the invoking function is completed, End is
-	// invoked which is a pop operation from activeEvents.
-	curEvent := &t.activeEvents[len(t.activeEvents)-1]
-	curEvent.procResInfo = append(curEvent.procResInfo, &soong_metrics_proto.ProcessResourceInfo{
+	e := t.peek()
+	e.procResInfo = append(e.procResInfo, &soong_metrics_proto.ProcessResourceInfo{
 		Name:             proto.String(name),
 		UserTimeMicros:   proto.Uint64(uint64(rusage.Utime.Usec)),
 		SystemTimeMicros: proto.Uint64(uint64(rusage.Stime.Usec)),
@@ -82,23 +136,13 @@
 	})
 }
 
-func (t *eventTracerImpl) Begin(name, desc string, _ tracer.Thread) {
-	t.activeEvents = append(t.activeEvents, event{name: name, desc: desc, start: _now()})
+// Begin starts tracing the event.
+func (t *EventTracer) Begin(name, desc string, _ tracer.Thread) {
+	t.push(newEvent(name, desc))
 }
 
-func (t *eventTracerImpl) End(tracer.Thread) soong_metrics_proto.PerfInfo {
-	if len(t.activeEvents) < 1 {
-		panic("Internal error: No pending events for endAt to end!")
-	}
-	lastEvent := t.activeEvents[len(t.activeEvents)-1]
-	t.activeEvents = t.activeEvents[:len(t.activeEvents)-1]
-	realTime := uint64(_now().Sub(lastEvent.start).Nanoseconds())
-
-	return soong_metrics_proto.PerfInfo{
-		Desc:                  proto.String(lastEvent.desc),
-		Name:                  proto.String(lastEvent.name),
-		StartTime:             proto.Uint64(uint64(lastEvent.start.UnixNano())),
-		RealTime:              proto.Uint64(realTime),
-		ProcessesResourceInfo: lastEvent.procResInfo,
-	}
+// End performs post calculations such as duration of the event, aggregates
+// the collected performance information into PerfInfo protobuf message.
+func (t *EventTracer) End(tracer.Thread) soong_metrics_proto.PerfInfo {
+	return t.pop().perfInfo()
 }
diff --git a/ui/metrics/event_test.go b/ui/metrics/event_test.go
index 6fc0b50..043450b 100644
--- a/ui/metrics/event_test.go
+++ b/ui/metrics/event_test.go
@@ -28,14 +28,14 @@
 	_now = func() time.Time { return startTime.Add(dur) }
 	defer func() { _now = initialNow }()
 
-	eventTracer := &eventTracerImpl{}
-	eventTracer.activeEvents = append(eventTracer.activeEvents, event{
+	et := &EventTracer{}
+	et.push(&event{
 		desc:  "test",
 		name:  "test",
 		start: startTime,
 	})
 
-	perf := eventTracer.End(tracer.Thread(0))
+	perf := et.End(tracer.Thread(0))
 	if perf.GetRealTime() != uint64(dur.Nanoseconds()) {
 		t.Errorf("got %d, want %d nanoseconds for event duration", perf.GetRealTime(), dur.Nanoseconds())
 	}
diff --git a/ui/metrics/metrics.go b/ui/metrics/metrics.go
index 7031042..efb572c 100644
--- a/ui/metrics/metrics.go
+++ b/ui/metrics/metrics.go
@@ -12,8 +12,30 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+// Package metrics represents the metrics system for Android Platform Build Systems.
 package metrics
 
+// This is the main heart of the metrics system for Android Platform Build Systems.
+// The starting of the soong_ui (cmd/soong_ui/main.go), the metrics system is
+// initialized by the invocation of New and is then stored in the context
+// (ui/build/context.go) to be used throughout the system. During the build
+// initialization phase, several functions in this file are invoked to store
+// information such as the environment, build configuration and build metadata.
+// There are several scoped code that has Begin() and defer End() functions
+// that captures the metrics and is them added as a perfInfo into the set
+// of the collected metrics. Finally, when soong_ui has finished the build,
+// the defer Dump function is invoked to store the collected metrics to the
+// raw protobuf file in the $OUT directory.
+//
+// There is one additional step that occurs after the raw protobuf file is written.
+// If the configuration environment variable ANDROID_ENABLE_METRICS_UPLOAD is
+// set with the path, the raw protobuf file is uploaded to the destination. See
+// ui/build/upload.go for more details. The filename of the raw protobuf file
+// and the list of files to be uploaded is defined in cmd/soong_ui/main.go.
+//
+// See ui/metrics/event.go for the explanation of what an event is and how
+// the metrics system is a stack based system.
+
 import (
 	"io/ioutil"
 	"os"
@@ -23,33 +45,51 @@
 
 	"github.com/golang/protobuf/proto"
 
-	soong_metrics_proto "android/soong/ui/metrics/metrics_proto"
+	"android/soong/ui/metrics/metrics_proto"
 )
 
 const (
-	PrimaryNinja    = "ninja"
-	RunKati         = "kati"
+	// Below is a list of names passed in to the Begin tracing functions. These
+	// names are used to group a set of metrics.
+
+	// Setup and tear down of the build systems.
 	RunSetupTool    = "setup"
 	RunShutdownTool = "shutdown"
-	RunSoong        = "soong"
-	RunBazel        = "bazel"
 	TestRun         = "test"
-	Total           = "total"
+
+	// List of build system tools.
+	RunSoong     = "soong"
+	PrimaryNinja = "ninja"
+	RunKati      = "kati"
+	RunBazel     = "bazel"
+
+	// Overall build from building the graph to building the target.
+	Total = "total"
 )
 
+// Metrics is a struct that stores collected metrics during the course
+// of a build which later is dumped to a MetricsBase protobuf file.
+// See ui/metrics/metrics_proto/metrics.proto for further details
+// on what information is collected.
 type Metrics struct {
-	metrics     soong_metrics_proto.MetricsBase
-	EventTracer EventTracer
+	// The protobuf message that is later written to the file.
+	metrics soong_metrics_proto.MetricsBase
+
+	// A list of pending build events.
+	EventTracer *EventTracer
 }
 
+// New returns a pointer of Metrics to store a set of metrics.
 func New() (metrics *Metrics) {
 	m := &Metrics{
 		metrics:     soong_metrics_proto.MetricsBase{},
-		EventTracer: &eventTracerImpl{},
+		EventTracer: &EventTracer{},
 	}
 	return m
 }
 
+// SetTimeMetrics stores performance information from an executed block of
+// code.
 func (m *Metrics) SetTimeMetrics(perf soong_metrics_proto.PerfInfo) {
 	switch perf.GetName() {
 	case RunKati:
@@ -60,19 +100,26 @@
 		m.metrics.BazelRuns = append(m.metrics.BazelRuns, &perf)
 	case PrimaryNinja:
 		m.metrics.NinjaRuns = append(m.metrics.NinjaRuns, &perf)
+	case RunSetupTool:
+		m.metrics.SetupTools = append(m.metrics.SetupTools, &perf)
 	case Total:
 		m.metrics.Total = &perf
 	}
 }
 
+// BuildConfig stores information about the build configuration.
 func (m *Metrics) BuildConfig(b *soong_metrics_proto.BuildConfig) {
 	m.metrics.BuildConfig = b
 }
 
+// SystemResourceInfo stores information related to the host system such
+// as total CPU and memory.
 func (m *Metrics) SystemResourceInfo(b *soong_metrics_proto.SystemResourceInfo) {
 	m.metrics.SystemResourceInfo = b
 }
 
+// SetMetadataMetrics sets information about the build such as the target
+// product, host architecture and out directory.
 func (m *Metrics) SetMetadataMetrics(metadata map[string]string) {
 	for k, v := range metadata {
 		switch k {
@@ -92,15 +139,15 @@
 				m.metrics.TargetBuildVariant = soong_metrics_proto.MetricsBase_ENG.Enum()
 			}
 		case "TARGET_ARCH":
-			m.metrics.TargetArch = m.getArch(v)
+			m.metrics.TargetArch = arch(v)
 		case "TARGET_ARCH_VARIANT":
 			m.metrics.TargetArchVariant = proto.String(v)
 		case "TARGET_CPU_VARIANT":
 			m.metrics.TargetCpuVariant = proto.String(v)
 		case "HOST_ARCH":
-			m.metrics.HostArch = m.getArch(v)
+			m.metrics.HostArch = arch(v)
 		case "HOST_2ND_ARCH":
-			m.metrics.Host_2NdArch = m.getArch(v)
+			m.metrics.Host_2NdArch = arch(v)
 		case "HOST_OS_EXTRA":
 			m.metrics.HostOsExtra = proto.String(v)
 		case "HOST_CROSS_OS":
@@ -115,8 +162,10 @@
 	}
 }
 
-func (m *Metrics) getArch(arch string) *soong_metrics_proto.MetricsBase_Arch {
-	switch arch {
+// arch returns the corresponding MetricsBase_Arch based on the string
+// parameter.
+func arch(a string) *soong_metrics_proto.MetricsBase_Arch {
+	switch a {
 	case "arm":
 		return soong_metrics_proto.MetricsBase_ARM.Enum()
 	case "arm64":
@@ -130,37 +179,51 @@
 	}
 }
 
+// SetBuildDateTime sets the build date and time. The value written
+// to the protobuf file is in seconds.
 func (m *Metrics) SetBuildDateTime(buildTimestamp time.Time) {
 	m.metrics.BuildDateTimestamp = proto.Int64(buildTimestamp.UnixNano() / int64(time.Second))
 }
 
+// SetBuildCommand adds the build command specified by the user to the
+// list of collected metrics.
 func (m *Metrics) SetBuildCommand(cmd []string) {
 	m.metrics.BuildCommand = proto.String(strings.Join(cmd, " "))
 }
 
-// exports the output to the file at outputPath
-func (m *Metrics) Dump(outputPath string) error {
+// Dump exports the collected metrics from the executed build to the file at
+// out path.
+func (m *Metrics) Dump(out string) error {
 	// ignore the error if the hostname could not be retrieved as it
 	// is not a critical metric to extract.
 	if hostname, err := os.Hostname(); err == nil {
 		m.metrics.Hostname = proto.String(hostname)
 	}
 	m.metrics.HostOs = proto.String(runtime.GOOS)
-	return writeMessageToFile(&m.metrics, outputPath)
+
+	return save(&m.metrics, out)
 }
 
+// SetSoongBuildMetrics sets the metrics collected from the soong_build
+// execution.
 func (m *Metrics) SetSoongBuildMetrics(metrics *soong_metrics_proto.SoongBuildMetrics) {
 	m.metrics.SoongBuildMetrics = metrics
 }
 
+// A CriticalUserJourneysMetrics is a struct that contains critical user journey
+// metrics. These critical user journeys are defined under cuj/cuj.go file.
 type CriticalUserJourneysMetrics struct {
+	// A list of collected CUJ metrics.
 	cujs soong_metrics_proto.CriticalUserJourneysMetrics
 }
 
+// NewCriticalUserJourneyMetrics returns a pointer of CriticalUserJourneyMetrics
+// to capture CUJs metrics.
 func NewCriticalUserJourneysMetrics() *CriticalUserJourneysMetrics {
 	return &CriticalUserJourneysMetrics{}
 }
 
+// Add adds a set of collected metrics from an executed critical user journey.
 func (c *CriticalUserJourneysMetrics) Add(name string, metrics *Metrics) {
 	c.cujs.Cujs = append(c.cujs.Cujs, &soong_metrics_proto.CriticalUserJourneyMetrics{
 		Name:    proto.String(name),
@@ -168,22 +231,25 @@
 	})
 }
 
-func (c *CriticalUserJourneysMetrics) Dump(outputPath string) (err error) {
-	return writeMessageToFile(&c.cujs, outputPath)
+// Dump saves the collected CUJs metrics to the raw protobuf file.
+func (c *CriticalUserJourneysMetrics) Dump(filename string) (err error) {
+	return save(&c.cujs, filename)
 }
 
-func writeMessageToFile(pb proto.Message, outputPath string) (err error) {
+// save takes a protobuf message, marshals to an array of bytes
+// and is then saved to a file.
+func save(pb proto.Message, filename string) (err error) {
 	data, err := proto.Marshal(pb)
 	if err != nil {
 		return err
 	}
-	tempPath := outputPath + ".tmp"
-	err = ioutil.WriteFile(tempPath, []byte(data), 0644)
-	if err != nil {
+
+	tempFilename := filename + ".tmp"
+	if err := ioutil.WriteFile(tempFilename, []byte(data), 0644 /* rw-r--r-- */); err != nil {
 		return err
 	}
-	err = os.Rename(tempPath, outputPath)
-	if err != nil {
+
+	if err := os.Rename(tempFilename, filename); err != nil {
 		return err
 	}