Merge "rust: Emit toc files for cdylibs"
diff --git a/android/licenses.go b/android/licenses.go
index bcd85f9..e9e271b 100644
--- a/android/licenses.go
+++ b/android/licenses.go
@@ -308,3 +308,12 @@
 }
 
 var LicenseInfoProvider = blueprint.NewProvider(LicenseInfo{})
+
+func init() {
+	RegisterMakeVarsProvider(pctx, licensesMakeVarsProvider)
+}
+
+func licensesMakeVarsProvider(ctx MakeVarsContext) {
+	ctx.Strict("BUILD_LICENSE_METADATA",
+		ctx.Config().HostToolPath(ctx, "build_license_metadata").String())
+}
diff --git a/apex/androidmk.go b/apex/androidmk.go
index 94b8116..80237fb 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -326,6 +326,9 @@
 	var required []string
 	var targetRequired []string
 	var hostRequired []string
+	required = append(required, a.RequiredModuleNames()...)
+	targetRequired = append(targetRequired, a.TargetRequiredModuleNames()...)
+	hostRequired = append(hostRequired, a.HostRequiredModuleNames()...)
 	installMapSet := make(map[string]bool) // set of dependency module:location mappings
 	for _, fi := range a.filesInfo {
 		required = append(required, fi.requiredModuleNames...)
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 8aaa31a..59ea206 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -8350,6 +8350,46 @@
 		})
 }
 
+func TestAndroidMk_RequiredModules(t *testing.T) {
+	ctx := testApex(t, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			updatable: false,
+			java_libs: ["foo"],
+			required: ["otherapex"],
+		}
+
+		apex {
+			name: "otherapex",
+			key: "myapex.key",
+			updatable: false,
+			java_libs: ["foo"],
+			required: ["otherapex"],
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		java_library {
+			name: "foo",
+			srcs: ["foo.java"],
+			apex_available: ["myapex", "otherapex"],
+			installable: true,
+		}
+	`)
+
+	apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+	data := android.AndroidMkDataForTest(t, ctx, apexBundle)
+	var builder strings.Builder
+	data.Custom(&builder, apexBundle.BaseModuleName(), "TARGET_", "", data)
+	androidMk := builder.String()
+	ensureContains(t, androidMk, "LOCAL_REQUIRED_MODULES += otherapex")
+}
+
 func TestMain(m *testing.M) {
 	os.Exit(m.Run())
 }
diff --git a/bazel/aquery.go b/bazel/aquery.go
index 0dedcf4..6d96b1c 100644
--- a/bazel/aquery.go
+++ b/bazel/aquery.go
@@ -245,9 +245,9 @@
 			out := outputPaths[0]
 			outDir := proptools.ShellEscapeIncludingSpaces(filepath.Dir(out))
 			out = proptools.ShellEscapeIncludingSpaces(out)
-			in := proptools.ShellEscapeIncludingSpaces(inputPaths[0])
-			// Use hard links, because some soong actions expect real files (for example, `cp -d`).
-			buildStatement.Command = fmt.Sprintf("mkdir -p %[1]s && rm -f %[2]s && ln -f %[3]s %[2]s", outDir, out, in)
+			in := filepath.Join("$PWD", proptools.ShellEscapeIncludingSpaces(inputPaths[0]))
+			// Use absolute paths, because some soong actions don't play well with relative paths (for example, `cp -d`).
+			buildStatement.Command = fmt.Sprintf("mkdir -p %[1]s && rm -f %[2]s && ln -sf %[3]s %[2]s", outDir, out, in)
 			buildStatement.SymlinkPaths = outputPaths[:]
 		} else if len(actionEntry.Arguments) < 1 {
 			return nil, fmt.Errorf("received action with no command: [%v]", buildStatement)
diff --git a/bazel/aquery_test.go b/bazel/aquery_test.go
index 88066c8..69f1115 100644
--- a/bazel/aquery_test.go
+++ b/bazel/aquery_test.go
@@ -859,7 +859,7 @@
 		BuildStatement{
 			Command: "mkdir -p one/symlink_subdir && " +
 				"rm -f one/symlink_subdir/symlink && " +
-				"ln -f one/file_subdir/file one/symlink_subdir/symlink",
+				"ln -sf $PWD/one/file_subdir/file one/symlink_subdir/symlink",
 			InputPaths:   []string{"one/file_subdir/file"},
 			OutputPaths:  []string{"one/symlink_subdir/symlink"},
 			SymlinkPaths: []string{"one/symlink_subdir/symlink"},
@@ -923,14 +923,14 @@
 		BuildStatement{
 			Command: "mkdir -p 'one/symlink subdir' && " +
 				"rm -f 'one/symlink subdir/symlink' && " +
-				"ln -f 'one/file subdir/file' 'one/symlink subdir/symlink'",
+				"ln -sf $PWD/'one/file subdir/file' 'one/symlink subdir/symlink'",
 			InputPaths:   []string{"one/file subdir/file"},
 			OutputPaths:  []string{"one/symlink subdir/symlink"},
 			SymlinkPaths: []string{"one/symlink subdir/symlink"},
 			Mnemonic:     "SolibSymlink",
 		},
 	}
-	assertBuildStatements(t, actual, expectedBuildStatements)
+	assertBuildStatements(t, expectedBuildStatements, actual)
 }
 
 func TestSymlinkMultipleInputs(t *testing.T) {
diff --git a/cc/sanitize.go b/cc/sanitize.go
index f6a9d5b..c7e8411 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -39,8 +39,15 @@
 	}
 	asanLdflags = []string{"-Wl,-u,__asan_preinit"}
 
-	hwasanCflags = []string{"-fno-omit-frame-pointer", "-Wno-frame-larger-than=",
+	hwasanCflags = []string{
+		"-fno-omit-frame-pointer",
+		"-Wno-frame-larger-than=",
 		"-fsanitize-hwaddress-abi=platform",
+	}
+
+	// ThinLTO performs codegen during link time, thus these flags need to
+	// passed to both CFLAGS and LDFLAGS.
+	hwasanCommonflags = []string{
 		// The following improves debug location information
 		// availability at the cost of its accuracy. It increases
 		// the likelihood of a stack variable's frame offset
@@ -48,11 +55,11 @@
 		// for the quality of hwasan reports. The downside is a
 		// higher number of "optimized out" stack variables.
 		// b/112437883.
-		"-mllvm", "-instcombine-lower-dbg-declare=0",
+		"-instcombine-lower-dbg-declare=0",
 		// TODO(b/159343917): HWASan and GlobalISel don't play nicely, and
 		// GlobalISel is the default at -O0 on aarch64.
-		"-mllvm", "--aarch64-enable-global-isel-at-O=-1",
-		"-mllvm", "-fast-isel=false",
+		"--aarch64-enable-global-isel-at-O=-1",
+		"-fast-isel=false",
 	}
 
 	cfiCflags = []string{"-flto", "-fsanitize-cfi-cross-dso",
@@ -629,6 +636,14 @@
 
 	if Bool(sanitize.Properties.Sanitize.Hwaddress) {
 		flags.Local.CFlags = append(flags.Local.CFlags, hwasanCflags...)
+
+		for _, flag := range hwasanCommonflags {
+			flags.Local.CFlags = append(flags.Local.CFlags, "-mllvm", flag)
+		}
+		for _, flag := range hwasanCommonflags {
+			flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-mllvm,"+flag)
+		}
+
 		if Bool(sanitize.Properties.Sanitize.Writeonly) {
 			flags.Local.CFlags = append(flags.Local.CFlags, "-mllvm", "-hwasan-instrument-reads=0")
 		}
diff --git a/compliance/build_license_metadata/Android.bp b/compliance/build_license_metadata/Android.bp
new file mode 100644
index 0000000..5000346
--- /dev/null
+++ b/compliance/build_license_metadata/Android.bp
@@ -0,0 +1,29 @@
+// Copyright 2021 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 {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+blueprint_go_binary {
+    name: "build_license_metadata",
+    srcs: [
+        "build_license_metadata.go",
+    ],
+    deps: [
+        "license_metadata_proto",
+        "golang-protobuf-proto",
+        "golang-protobuf-encoding-prototext",
+    ],
+}
diff --git a/compliance/build_license_metadata/build_license_metadata.go b/compliance/build_license_metadata/build_license_metadata.go
new file mode 100644
index 0000000..ba3cc3e
--- /dev/null
+++ b/compliance/build_license_metadata/build_license_metadata.go
@@ -0,0 +1,174 @@
+// Copyright 2021 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 main
+
+import (
+	"flag"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"strings"
+
+	"google.golang.org/protobuf/encoding/prototext"
+	"google.golang.org/protobuf/proto"
+
+	"android/soong/compliance/license_metadata_proto"
+)
+
+var (
+	packageName  = flag.String("p", "", "license package name")
+	moduleType   = newMultiString("mt", "module type")
+	moduleClass  = newMultiString("mc", "module class")
+	kinds        = newMultiString("k", "license kinds")
+	conditions   = newMultiString("c", "license conditions")
+	notices      = newMultiString("n", "license notice file")
+	deps         = newMultiString("d", "license metadata file dependency")
+	sources      = newMultiString("s", "source (input) dependency")
+	built        = newMultiString("t", "built targets")
+	installed    = newMultiString("i", "installed targets")
+	roots        = newMultiString("r", "root directory of project")
+	installedMap = newMultiString("m", "map dependent targets to their installed names")
+	isContainer  = flag.Bool("is_container", false, "preserved dependent target name when given")
+	outFile      = flag.String("o", "", "output file")
+)
+
+func newMultiString(name, usage string) *multiString {
+	var f multiString
+	flag.Var(&f, name, usage)
+	return &f
+}
+
+type multiString []string
+
+func (ms *multiString) String() string     { return strings.Join(*ms, ", ") }
+func (ms *multiString) Set(s string) error { *ms = append(*ms, s); return nil }
+
+func main() {
+	flag.Parse()
+
+	metadata := license_metadata_proto.LicenseMetadata{}
+	metadata.PackageName = proto.String(*packageName)
+	metadata.ModuleTypes = *moduleType
+	metadata.ModuleClasses = *moduleClass
+	metadata.IsContainer = proto.Bool(*isContainer)
+	metadata.Projects = findGitRoots(*roots)
+	metadata.LicenseKinds = *kinds
+	metadata.LicenseConditions = *conditions
+	metadata.LicenseTexts = *notices
+	metadata.Built = *built
+	metadata.Installed = *installed
+	metadata.InstallMap = convertInstalledMap(*installedMap)
+	metadata.Sources = *sources
+	metadata.Deps = convertDependencies(*deps)
+
+	err := writeMetadata(*outFile, &metadata)
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "error: %s\n", err.Error())
+		os.Exit(2)
+	}
+}
+
+func findGitRoots(dirs []string) []string {
+	ret := make([]string, len(dirs))
+	for i, dir := range dirs {
+		ret[i] = findGitRoot(dir)
+	}
+	return ret
+}
+
+// findGitRoot finds the directory at or above dir that contains a ".git" directory.  This isn't
+// guaranteed to exist, for example during remote execution, when sandboxed, when building from
+// infrastructure that doesn't use git, or when the .git directory has been removed to save space,
+// but it should be good enough for local builds.  If no .git directory is found the original value
+// is returned.
+func findGitRoot(dir string) string {
+	orig := dir
+	for dir != "" && dir != "." && dir != "/" {
+		_, err := os.Stat(filepath.Join(dir, ".git"))
+		if err == nil {
+			// Found dir/.git, return dir.
+			return dir
+		} else if !os.IsNotExist(err) {
+			// Error finding .git, return original input.
+			return orig
+		}
+		dir, _ = filepath.Split(dir)
+		dir = strings.TrimSuffix(dir, "/")
+	}
+	return orig
+}
+
+// convertInstalledMap converts a list of colon-separated from:to pairs into InstallMap proto
+// messages.
+func convertInstalledMap(installMaps []string) []*license_metadata_proto.InstallMap {
+	var ret []*license_metadata_proto.InstallMap
+
+	for _, installMap := range installMaps {
+		components := strings.Split(installMap, ":")
+		if len(components) != 2 {
+			panic(fmt.Errorf("install map entry %q contains %d colons, expected 1", len(components)-1))
+		}
+		ret = append(ret, &license_metadata_proto.InstallMap{
+			FromPath:      proto.String(components[0]),
+			ContainerPath: proto.String(components[1]),
+		})
+	}
+
+	return ret
+}
+
+// convertDependencies converts a colon-separated tuple of dependency:annotation:annotation...
+// into AnnotatedDependency proto messages.
+func convertDependencies(deps []string) []*license_metadata_proto.AnnotatedDependency {
+	var ret []*license_metadata_proto.AnnotatedDependency
+
+	for _, d := range deps {
+		components := strings.Split(d, ":")
+		dep := components[0]
+		components = components[1:]
+		ad := &license_metadata_proto.AnnotatedDependency{
+			File: proto.String(dep),
+			Annotations: make([]string, 0, len(components)),
+		}
+		for _, ann := range components {
+			if len(ann) == 0 {
+				continue
+			}
+			ad.Annotations = append(ad.Annotations, ann)
+		}
+		ret = append(ret, ad)
+	}
+
+	return ret
+}
+
+func writeMetadata(file string, metadata *license_metadata_proto.LicenseMetadata) error {
+	buf, err := prototext.MarshalOptions{Multiline: true}.Marshal(metadata)
+	if err != nil {
+		return fmt.Errorf("error marshalling textproto: %w", err)
+	}
+
+	if file != "" {
+		err = ioutil.WriteFile(file, buf, 0666)
+		if err != nil {
+			return fmt.Errorf("error writing textproto %q: %w", file, err)
+		}
+	} else {
+		_, _ = os.Stdout.Write(buf)
+	}
+
+	return nil
+}
diff --git a/compliance/license_metadata_proto/Android.bp b/compliance/license_metadata_proto/Android.bp
new file mode 100644
index 0000000..3c041e4
--- /dev/null
+++ b/compliance/license_metadata_proto/Android.bp
@@ -0,0 +1,27 @@
+// Copyright 2021 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 {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+bootstrap_go_package {
+    name: "license_metadata_proto",
+    pkgPath: "android/soong/compliance/license_metadata_proto",
+    srcs: ["license_metadata.pb.go"],
+    deps: [
+        "golang-protobuf-reflect-protoreflect",
+        "golang-protobuf-runtime-protoimpl",
+    ],
+}
diff --git a/compliance/license_metadata_proto/license_metadata.pb.go b/compliance/license_metadata_proto/license_metadata.pb.go
new file mode 100644
index 0000000..44dbc78
--- /dev/null
+++ b/compliance/license_metadata_proto/license_metadata.pb.go
@@ -0,0 +1,451 @@
+// Copyright 2021 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.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.27.1
+// 	protoc        v3.19.0
+// source: license_metadata.proto
+
+package license_metadata_proto
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type LicenseMetadata struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// package_name identifies the source package. License texts are named relative to the package name.
+	PackageName   *string  `protobuf:"bytes,1,opt,name=package_name,json=packageName" json:"package_name,omitempty"`
+	ModuleTypes   []string `protobuf:"bytes,2,rep,name=module_types,json=moduleTypes" json:"module_types,omitempty"`
+	ModuleClasses []string `protobuf:"bytes,3,rep,name=module_classes,json=moduleClasses" json:"module_classes,omitempty"`
+	// projects identifies the git project(s) containing the associated source code.
+	Projects []string `protobuf:"bytes,4,rep,name=projects" json:"projects,omitempty"`
+	// license_kinds lists the kinds of licenses. e.g. SPDX-license-identifier-Apache-2.0 or legacy_notice.
+	LicenseKinds []string `protobuf:"bytes,5,rep,name=license_kinds,json=licenseKinds" json:"license_kinds,omitempty"`
+	// license_conditions lists the conditions that apply to the license kinds. e.g. notice or restricted.
+	LicenseConditions []string `protobuf:"bytes,6,rep,name=license_conditions,json=licenseConditions" json:"license_conditions,omitempty"`
+	// license_texts lists the filenames of the associated license text(s).
+	LicenseTexts []string `protobuf:"bytes,7,rep,name=license_texts,json=licenseTexts" json:"license_texts,omitempty"`
+	// is_container is true for target types that merely aggregate. e.g. .img or .zip files.
+	IsContainer *bool `protobuf:"varint,8,opt,name=is_container,json=isContainer" json:"is_container,omitempty"`
+	// built lists the built targets.
+	Built []string `protobuf:"bytes,9,rep,name=built" json:"built,omitempty"`
+	// installed lists the installed targets.
+	Installed []string `protobuf:"bytes,10,rep,name=installed" json:"installed,omitempty"`
+	// installMap identifies the substitutions to make to path names when moving into installed location.
+	InstallMap []*InstallMap `protobuf:"bytes,11,rep,name=install_map,json=installMap" json:"install_map,omitempty"`
+	// sources lists the targets depended on.
+	Sources []string `protobuf:"bytes,12,rep,name=sources" json:"sources,omitempty"`
+	// deps lists the license metadata files depended on.
+	Deps []*AnnotatedDependency `protobuf:"bytes,13,rep,name=deps" json:"deps,omitempty"`
+}
+
+func (x *LicenseMetadata) Reset() {
+	*x = LicenseMetadata{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_license_metadata_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *LicenseMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*LicenseMetadata) ProtoMessage() {}
+
+func (x *LicenseMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_license_metadata_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use LicenseMetadata.ProtoReflect.Descriptor instead.
+func (*LicenseMetadata) Descriptor() ([]byte, []int) {
+	return file_license_metadata_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *LicenseMetadata) GetPackageName() string {
+	if x != nil && x.PackageName != nil {
+		return *x.PackageName
+	}
+	return ""
+}
+
+func (x *LicenseMetadata) GetModuleTypes() []string {
+	if x != nil {
+		return x.ModuleTypes
+	}
+	return nil
+}
+
+func (x *LicenseMetadata) GetModuleClasses() []string {
+	if x != nil {
+		return x.ModuleClasses
+	}
+	return nil
+}
+
+func (x *LicenseMetadata) GetProjects() []string {
+	if x != nil {
+		return x.Projects
+	}
+	return nil
+}
+
+func (x *LicenseMetadata) GetLicenseKinds() []string {
+	if x != nil {
+		return x.LicenseKinds
+	}
+	return nil
+}
+
+func (x *LicenseMetadata) GetLicenseConditions() []string {
+	if x != nil {
+		return x.LicenseConditions
+	}
+	return nil
+}
+
+func (x *LicenseMetadata) GetLicenseTexts() []string {
+	if x != nil {
+		return x.LicenseTexts
+	}
+	return nil
+}
+
+func (x *LicenseMetadata) GetIsContainer() bool {
+	if x != nil && x.IsContainer != nil {
+		return *x.IsContainer
+	}
+	return false
+}
+
+func (x *LicenseMetadata) GetBuilt() []string {
+	if x != nil {
+		return x.Built
+	}
+	return nil
+}
+
+func (x *LicenseMetadata) GetInstalled() []string {
+	if x != nil {
+		return x.Installed
+	}
+	return nil
+}
+
+func (x *LicenseMetadata) GetInstallMap() []*InstallMap {
+	if x != nil {
+		return x.InstallMap
+	}
+	return nil
+}
+
+func (x *LicenseMetadata) GetSources() []string {
+	if x != nil {
+		return x.Sources
+	}
+	return nil
+}
+
+func (x *LicenseMetadata) GetDeps() []*AnnotatedDependency {
+	if x != nil {
+		return x.Deps
+	}
+	return nil
+}
+
+// InstallMap messages describe the mapping from an input filesystem file to the path to the file
+// in a container.
+type InstallMap struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// The input path on the filesystem.
+	FromPath *string `protobuf:"bytes,1,opt,name=from_path,json=fromPath" json:"from_path,omitempty"`
+	// The path to the file inside the container or installed location.
+	ContainerPath *string `protobuf:"bytes,2,opt,name=container_path,json=containerPath" json:"container_path,omitempty"`
+}
+
+func (x *InstallMap) Reset() {
+	*x = InstallMap{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_license_metadata_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *InstallMap) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*InstallMap) ProtoMessage() {}
+
+func (x *InstallMap) ProtoReflect() protoreflect.Message {
+	mi := &file_license_metadata_proto_msgTypes[1]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use InstallMap.ProtoReflect.Descriptor instead.
+func (*InstallMap) Descriptor() ([]byte, []int) {
+	return file_license_metadata_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *InstallMap) GetFromPath() string {
+	if x != nil && x.FromPath != nil {
+		return *x.FromPath
+	}
+	return ""
+}
+
+func (x *InstallMap) GetContainerPath() string {
+	if x != nil && x.ContainerPath != nil {
+		return *x.ContainerPath
+	}
+	return ""
+}
+
+// AnnotateDepencency messages describe edges in the build graph.
+type AnnotatedDependency struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// The path to the dependency license metadata file.
+	File *string `protobuf:"bytes,1,opt,name=file" json:"file,omitempty"`
+	// The annotations attached to the dependency.
+	Annotations []string `protobuf:"bytes,2,rep,name=annotations" json:"annotations,omitempty"`
+}
+
+func (x *AnnotatedDependency) Reset() {
+	*x = AnnotatedDependency{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_license_metadata_proto_msgTypes[2]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *AnnotatedDependency) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AnnotatedDependency) ProtoMessage() {}
+
+func (x *AnnotatedDependency) ProtoReflect() protoreflect.Message {
+	mi := &file_license_metadata_proto_msgTypes[2]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use AnnotatedDependency.ProtoReflect.Descriptor instead.
+func (*AnnotatedDependency) Descriptor() ([]byte, []int) {
+	return file_license_metadata_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *AnnotatedDependency) GetFile() string {
+	if x != nil && x.File != nil {
+		return *x.File
+	}
+	return ""
+}
+
+func (x *AnnotatedDependency) GetAnnotations() []string {
+	if x != nil {
+		return x.Annotations
+	}
+	return nil
+}
+
+var File_license_metadata_proto protoreflect.FileDescriptor
+
+var file_license_metadata_proto_rawDesc = []byte{
+	0x0a, 0x16, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61,
+	0x74, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x16, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f,
+	0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
+	0x22, 0x8a, 0x04, 0x0a, 0x0f, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61,
+	0x64, 0x61, 0x74, 0x61, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x5f,
+	0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x61, 0x63, 0x6b,
+	0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x6f, 0x64, 0x75, 0x6c,
+	0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x6d,
+	0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x6d, 0x6f,
+	0x64, 0x75, 0x6c, 0x65, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03,
+	0x28, 0x09, 0x52, 0x0d, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x65,
+	0x73, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x18, 0x04, 0x20,
+	0x03, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x23, 0x0a,
+	0x0d, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x6b, 0x69, 0x6e, 0x64, 0x73, 0x18, 0x05,
+	0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x4b, 0x69, 0x6e,
+	0x64, 0x73, 0x12, 0x2d, 0x0a, 0x12, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x63, 0x6f,
+	0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x11,
+	0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e,
+	0x73, 0x12, 0x23, 0x0a, 0x0d, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x74, 0x65, 0x78,
+	0x74, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73,
+	0x65, 0x54, 0x65, 0x78, 0x74, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x73, 0x5f, 0x63, 0x6f, 0x6e,
+	0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73,
+	0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x75, 0x69,
+	0x6c, 0x74, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x62, 0x75, 0x69, 0x6c, 0x74, 0x12,
+	0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x03,
+	0x28, 0x09, 0x52, 0x09, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x12, 0x43, 0x0a,
+	0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x5f, 0x6d, 0x61, 0x70, 0x18, 0x0b, 0x20, 0x03,
+	0x28, 0x0b, 0x32, 0x22, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6c, 0x69, 0x63, 0x65, 0x6e,
+	0x73, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x49, 0x6e, 0x73, 0x74,
+	0x61, 0x6c, 0x6c, 0x4d, 0x61, 0x70, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x4d,
+	0x61, 0x70, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x0c, 0x20,
+	0x03, 0x28, 0x09, 0x52, 0x07, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x3f, 0x0a, 0x04,
+	0x64, 0x65, 0x70, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x62, 0x75, 0x69,
+	0x6c, 0x64, 0x5f, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64,
+	0x61, 0x74, 0x61, 0x2e, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x44, 0x65, 0x70,
+	0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x04, 0x64, 0x65, 0x70, 0x73, 0x22, 0x50, 0x0a,
+	0x0a, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x4d, 0x61, 0x70, 0x12, 0x1b, 0x0a, 0x09, 0x66,
+	0x72, 0x6f, 0x6d, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
+	0x66, 0x72, 0x6f, 0x6d, 0x50, 0x61, 0x74, 0x68, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6f, 0x6e, 0x74,
+	0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x50, 0x61, 0x74, 0x68, 0x22,
+	0x4b, 0x0a, 0x13, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x44, 0x65, 0x70, 0x65,
+	0x6e, 0x64, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x61, 0x6e,
+	0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52,
+	0x0b, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x31, 0x5a, 0x2f,
+	0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x63, 0x6f,
+	0x6d, 0x70, 0x6c, 0x69, 0x61, 0x6e, 0x63, 0x65, 0x2f, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65,
+	0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+}
+
+var (
+	file_license_metadata_proto_rawDescOnce sync.Once
+	file_license_metadata_proto_rawDescData = file_license_metadata_proto_rawDesc
+)
+
+func file_license_metadata_proto_rawDescGZIP() []byte {
+	file_license_metadata_proto_rawDescOnce.Do(func() {
+		file_license_metadata_proto_rawDescData = protoimpl.X.CompressGZIP(file_license_metadata_proto_rawDescData)
+	})
+	return file_license_metadata_proto_rawDescData
+}
+
+var file_license_metadata_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
+var file_license_metadata_proto_goTypes = []interface{}{
+	(*LicenseMetadata)(nil),     // 0: build_license_metadata.LicenseMetadata
+	(*InstallMap)(nil),          // 1: build_license_metadata.InstallMap
+	(*AnnotatedDependency)(nil), // 2: build_license_metadata.AnnotatedDependency
+}
+var file_license_metadata_proto_depIdxs = []int32{
+	1, // 0: build_license_metadata.LicenseMetadata.install_map:type_name -> build_license_metadata.InstallMap
+	2, // 1: build_license_metadata.LicenseMetadata.deps:type_name -> build_license_metadata.AnnotatedDependency
+	2, // [2:2] is the sub-list for method output_type
+	2, // [2:2] is the sub-list for method input_type
+	2, // [2:2] is the sub-list for extension type_name
+	2, // [2:2] is the sub-list for extension extendee
+	0, // [0:2] is the sub-list for field type_name
+}
+
+func init() { file_license_metadata_proto_init() }
+func file_license_metadata_proto_init() {
+	if File_license_metadata_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_license_metadata_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*LicenseMetadata); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_license_metadata_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*InstallMap); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_license_metadata_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*AnnotatedDependency); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_license_metadata_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   3,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_license_metadata_proto_goTypes,
+		DependencyIndexes: file_license_metadata_proto_depIdxs,
+		MessageInfos:      file_license_metadata_proto_msgTypes,
+	}.Build()
+	File_license_metadata_proto = out.File
+	file_license_metadata_proto_rawDesc = nil
+	file_license_metadata_proto_goTypes = nil
+	file_license_metadata_proto_depIdxs = nil
+}
diff --git a/compliance/license_metadata_proto/license_metadata.proto b/compliance/license_metadata_proto/license_metadata.proto
new file mode 100644
index 0000000..1b4f34f
--- /dev/null
+++ b/compliance/license_metadata_proto/license_metadata.proto
@@ -0,0 +1,76 @@
+// Copyright 2021 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.
+
+syntax = "proto2";
+
+package build_license_metadata;
+option go_package = "android/soong/compliance/license_metadata_proto";
+
+message LicenseMetadata {
+  // package_name identifies the source package. License texts are named relative to the package name.
+  optional string package_name = 1;
+
+  repeated string module_types = 2;
+
+  repeated string module_classes = 3;
+
+  // projects identifies the git project(s) containing the associated source code.
+  repeated string projects = 4;
+
+  // license_kinds lists the kinds of licenses. e.g. SPDX-license-identifier-Apache-2.0 or legacy_notice.
+  repeated string license_kinds = 5;
+
+  // license_conditions lists the conditions that apply to the license kinds. e.g. notice or restricted.
+  repeated string license_conditions = 6;
+
+  // license_texts lists the filenames of the associated license text(s).
+  repeated string license_texts = 7;
+
+  // is_container is true for target types that merely aggregate. e.g. .img or .zip files.
+  optional bool is_container = 8;
+
+  // built lists the built targets.
+  repeated string built = 9;
+
+  // installed lists the installed targets.
+  repeated string installed = 10;
+
+  // installMap identifies the substitutions to make to path names when moving into installed location.
+  repeated InstallMap install_map = 11;
+
+  // sources lists the targets depended on.
+  repeated string sources = 12;
+
+  // deps lists the license metadata files depended on.
+  repeated AnnotatedDependency deps = 13;
+}
+
+// InstallMap messages describe the mapping from an input filesystem file to the path to the file
+// in a container.
+message InstallMap {
+  // The input path on the filesystem.
+  optional string from_path = 1;
+
+  // The path to the file inside the container or installed location.
+  optional string container_path = 2;
+}
+
+// AnnotateDepencency messages describe edges in the build graph.
+message AnnotatedDependency {
+  // The path to the dependency license metadata file.
+  optional string file = 1;
+
+  // The annotations attached to the dependency.
+  repeated string annotations = 2;
+}
diff --git a/java/core-libraries/Android.bp b/java/core-libraries/Android.bp
index 2eafe9d..cf39746 100644
--- a/java/core-libraries/Android.bp
+++ b/java/core-libraries/Android.bp
@@ -86,7 +86,7 @@
 
 // Used when compiling higher-level code against core.current.stubs.
 java_system_modules {
-    name: "core-current-stubs-system-modules",
+    name: "core-public-stubs-system-modules",
     visibility: ["//visibility:public"],
     libs: [
         "core-current-stubs-for-system-modules",
diff --git a/java/droidstubs.go b/java/droidstubs.go
index 0c66ccf..7ad316f 100644
--- a/java/droidstubs.go
+++ b/java/droidstubs.go
@@ -16,6 +16,7 @@
 
 import (
 	"fmt"
+	"path/filepath"
 	"strings"
 
 	"github.com/google/blueprint/proptools"
@@ -805,7 +806,7 @@
 
 	properties PrebuiltStubsSourcesProperties
 
-	stubsSrcJar android.ModuleOutPath
+	stubsSrcJar android.Path
 }
 
 func (p *PrebuiltStubsSources) OutputFiles(tag string) (android.Paths, error) {
@@ -822,35 +823,39 @@
 }
 
 func (p *PrebuiltStubsSources) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	p.stubsSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar")
-
 	if len(p.properties.Srcs) != 1 {
-		ctx.PropertyErrorf("srcs", "must only specify one directory path, contains %d paths", len(p.properties.Srcs))
+		ctx.PropertyErrorf("srcs", "must only specify one directory path or srcjar, contains %d paths", len(p.properties.Srcs))
 		return
 	}
 
-	localSrcDir := p.properties.Srcs[0]
-	// Although PathForModuleSrc can return nil if either the path doesn't exist or
-	// the path components are invalid it won't in this case because no components
-	// are specified and the module directory must exist in order to get this far.
-	srcDir := android.PathForModuleSrc(ctx).(android.SourcePath).Join(ctx, localSrcDir)
+	src := p.properties.Srcs[0]
+	if filepath.Ext(src) == ".srcjar" {
+		// This is a srcjar. We can use it directly.
+		p.stubsSrcJar = android.PathForModuleSrc(ctx, src)
+	} else {
+		outPath := android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar")
 
-	// Glob the contents of the directory just in case the directory does not exist.
-	srcGlob := localSrcDir + "/**/*"
-	srcPaths := android.PathsForModuleSrc(ctx, []string{srcGlob})
+		// This is a directory. Glob the contents just in case the directory does not exist.
+		srcGlob := src + "/**/*"
+		srcPaths := android.PathsForModuleSrc(ctx, []string{srcGlob})
 
-	rule := android.NewRuleBuilder(pctx, ctx)
-	rule.Command().
-		BuiltTool("soong_zip").
-		Flag("-write_if_changed").
-		Flag("-jar").
-		FlagWithOutput("-o ", p.stubsSrcJar).
-		FlagWithArg("-C ", srcDir.String()).
-		FlagWithRspFileInputList("-r ", p.stubsSrcJar.ReplaceExtension(ctx, "rsp"), srcPaths)
+		// Although PathForModuleSrc can return nil if either the path doesn't exist or
+		// the path components are invalid it won't in this case because no components
+		// are specified and the module directory must exist in order to get this far.
+		srcDir := android.PathForModuleSrc(ctx).(android.SourcePath).Join(ctx, src)
 
-	rule.Restat()
-
-	rule.Build("zip src", "Create srcjar from prebuilt source")
+		rule := android.NewRuleBuilder(pctx, ctx)
+		rule.Command().
+			BuiltTool("soong_zip").
+			Flag("-write_if_changed").
+			Flag("-jar").
+			FlagWithOutput("-o ", outPath).
+			FlagWithArg("-C ", srcDir.String()).
+			FlagWithRspFileInputList("-r ", outPath.ReplaceExtension(ctx, "rsp"), srcPaths)
+		rule.Restat()
+		rule.Build("zip src", "Create srcjar from prebuilt source")
+		p.stubsSrcJar = outPath
+	}
 }
 
 func (p *PrebuiltStubsSources) Prebuilt() *android.Prebuilt {
diff --git a/java/sdk.go b/java/sdk.go
index 34d68ae..e6bf220 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -141,11 +141,13 @@
 		}
 	}
 
-	toModule := func(systemModules string, module string, aidl android.Path) sdkDep {
+	toModule := func(module string, aidl android.Path) sdkDep {
+		// Select the kind of system modules needed for the sdk version.
+		systemModulesKind := systemModuleKind(sdkVersion.Kind, android.FutureApiLevel)
 		return sdkDep{
 			useModule:          true,
 			bootclasspath:      []string{module, config.DefaultLambdaStubsLibrary},
-			systemModules:      systemModules,
+			systemModules:      fmt.Sprintf("core-%s-stubs-system-modules", systemModulesKind),
 			java9Classpath:     []string{module},
 			frameworkResModule: "framework-res",
 			aidl:               android.OptionalPathForPath(aidl),
@@ -186,24 +188,24 @@
 			noFrameworksLibs: true,
 		}
 	case android.SdkPublic:
-		return toModule("core-current-stubs-system-modules", "android_stubs_current", sdkFrameworkAidlPath(ctx))
+		return toModule("android_stubs_current", sdkFrameworkAidlPath(ctx))
 	case android.SdkSystem:
-		return toModule("core-current-stubs-system-modules", "android_system_stubs_current", sdkFrameworkAidlPath(ctx))
+		return toModule("android_system_stubs_current", sdkFrameworkAidlPath(ctx))
 	case android.SdkTest:
-		return toModule("core-current-stubs-system-modules", "android_test_stubs_current", sdkFrameworkAidlPath(ctx))
+		return toModule("android_test_stubs_current", sdkFrameworkAidlPath(ctx))
 	case android.SdkCore:
 		return sdkDep{
 			useModule:        true,
 			bootclasspath:    []string{"core.current.stubs", config.DefaultLambdaStubsLibrary},
-			systemModules:    "core-current-stubs-system-modules",
+			systemModules:    "core-public-stubs-system-modules",
 			noFrameworksLibs: true,
 		}
 	case android.SdkModule:
 		// TODO(146757305): provide .apk and .aidl that have more APIs for modules
-		return toModule("core-module-lib-stubs-system-modules", "android_module_lib_stubs_current", nonUpdatableFrameworkAidlPath(ctx))
+		return toModule("android_module_lib_stubs_current", nonUpdatableFrameworkAidlPath(ctx))
 	case android.SdkSystemServer:
 		// TODO(146757305): provide .apk and .aidl that have more APIs for modules
-		return toModule("core-module-lib-stubs-system-modules", "android_system_server_stubs_current", sdkFrameworkAidlPath(ctx))
+		return toModule("android_system_server_stubs_current", sdkFrameworkAidlPath(ctx))
 	default:
 		panic(fmt.Errorf("invalid sdk %q", sdkVersion.Raw))
 	}
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 273efec..d7f14d6 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -361,13 +361,14 @@
 	// The sdk_version to use for building the stubs.
 	//
 	// If not specified then it will use an sdk_version determined as follows:
+	//
 	// 1) If the sdk_version specified on the java_sdk_library is none then this
-	//    will be none. This is used for java_sdk_library instances that are used
-	//    to create stubs that contribute to the core_current sdk version.
-	// 2) Otherwise, it is assumed that this library extends but does not contribute
-	//    directly to a specific sdk_version and so this uses the sdk_version appropriate
-	//    for the api scope. e.g. public will use sdk_version: current, system will use
-	//    sdk_version: system_current, etc.
+	// will be none. This is used for java_sdk_library instances that are used
+	// to create stubs that contribute to the core_current sdk version.
+	// 2) Otherwise, it is assumed that this library extends but does not
+	// contribute directly to a specific sdk_version and so this uses the
+	// sdk_version appropriate for the api scope. e.g. public will use
+	// sdk_version: current, system will use sdk_version: system_current, etc.
 	//
 	// This does not affect the sdk_version used for either generating the stubs source
 	// or the API file. They both have to use the same sdk_version as is used for
diff --git a/java/sdk_test.go b/java/sdk_test.go
index 5c4a6d2..9e8ba6e 100644
--- a/java/sdk_test.go
+++ b/java/sdk_test.go
@@ -106,7 +106,7 @@
 			name:           "current",
 			properties:     `sdk_version: "current",`,
 			bootclasspath:  []string{"android_stubs_current", "core-lambda-stubs"},
-			system:         "core-current-stubs-system-modules",
+			system:         "core-public-stubs-system-modules",
 			java9classpath: []string{"android_stubs_current"},
 			aidl:           "-pout/soong/framework.aidl",
 		},
@@ -129,7 +129,7 @@
 			name:           "system_current",
 			properties:     `sdk_version: "system_current",`,
 			bootclasspath:  []string{"android_system_stubs_current", "core-lambda-stubs"},
-			system:         "core-current-stubs-system-modules",
+			system:         "core-public-stubs-system-modules",
 			java9classpath: []string{"android_system_stubs_current"},
 			aidl:           "-pout/soong/framework.aidl",
 		},
@@ -169,7 +169,7 @@
 			name:           "test_current",
 			properties:     `sdk_version: "test_current",`,
 			bootclasspath:  []string{"android_test_stubs_current", "core-lambda-stubs"},
-			system:         "core-current-stubs-system-modules",
+			system:         "core-public-stubs-system-modules",
 			java9classpath: []string{"android_test_stubs_current"},
 			aidl:           "-pout/soong/framework.aidl",
 		},
@@ -201,7 +201,7 @@
 			name:          "core_current",
 			properties:    `sdk_version: "core_current",`,
 			bootclasspath: []string{"core.current.stubs", "core-lambda-stubs"},
-			system:        "core-current-stubs-system-modules",
+			system:        "core-public-stubs-system-modules",
 		},
 		{
 			// Test case only applies when Always_use_prebuilt_sdks=true.
diff --git a/java/testing.go b/java/testing.go
index 3397e46..7441e44 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -344,7 +344,7 @@
 		}`
 
 	systemModules := []string{
-		"core-current-stubs-system-modules",
+		"core-public-stubs-system-modules",
 		"core-module-lib-stubs-system-modules",
 		"legacy-core-platform-api-stubs-system-modules",
 		"stable-core-platform-api-stubs-system-modules",
diff --git a/scripts/rbc-run b/scripts/rbc-run
index a0907cf..ecc6edd 100755
--- a/scripts/rbc-run
+++ b/scripts/rbc-run
@@ -4,12 +4,13 @@
 #       that will be passed to rbcrun.
 [[ $# -gt 0 && -f "$1" ]] || { echo "Usage: ${0##*/} product.mk [Additional rbcrun arguments]" >&2; exit 1; }
 set -eu
-declare -r output_root=${OUT_DIR:-out}
-declare -r runner="$output_root/soong/.bootstrap/bin/rbcrun"
-declare -r converter="$output_root/soong/.bootstrap/bin/mk2rbc"
-declare -r launcher=$output_root/launchers/run.rbc
-declare -r makefile=$1
+
+declare -r output_root="${OUT_DIR:-out}"
+declare -r runner="${output_root}/soong/rbcrun"
+declare -r converter="${output_root}/soong/mk2rbc"
+declare -r launcher="${output_root}/launchers/run.rbc"
+declare -r makefile="$1"
 shift
-$converter -mode=write -r --outdir $output_root --launcher=$launcher $makefile
-$runner RBC_OUT="make,global" RBC_DEBUG="${RBC_DEBUG:-}" $@ $launcher
+"${converter}" -mode=write -r --outdir "${output_root}" --launcher="${launcher}" "${makefile}"
+"${runner}" RBC_OUT="make,global" RBC_DEBUG="${RBC_DEBUG:-}" $@ "${launcher}"
 
diff --git a/tests/bootstrap_test.sh b/tests/bootstrap_test.sh
index a22adc5..e92a561 100755
--- a/tests/bootstrap_test.sh
+++ b/tests/bootstrap_test.sh
@@ -17,10 +17,10 @@
 function test_null_build() {
   setup
   run_soong
-  local bootstrap_mtime1=$(stat -c "%y" out/soong/.bootstrap/build.ninja)
+  local bootstrap_mtime1=$(stat -c "%y" out/soong/bootstrap.ninja)
   local output_mtime1=$(stat -c "%y" out/soong/build.ninja)
   run_soong
-  local bootstrap_mtime2=$(stat -c "%y" out/soong/.bootstrap/build.ninja)
+  local bootstrap_mtime2=$(stat -c "%y" out/soong/bootstrap.ninja)
   local output_mtime2=$(stat -c "%y" out/soong/build.ninja)
 
   if [[ "$bootstrap_mtime1" == "$bootstrap_mtime2" ]]; then
@@ -36,12 +36,12 @@
 function test_soong_build_rebuilt_if_blueprint_changes() {
   setup
   run_soong
-  local mtime1=$(stat -c "%y" out/soong/.bootstrap/build.ninja)
+  local mtime1=$(stat -c "%y" out/soong/bootstrap.ninja)
 
   sed -i 's/pluginGenSrcCmd/pluginGenSrcCmd2/g' build/blueprint/bootstrap/bootstrap.go
 
   run_soong
-  local mtime2=$(stat -c "%y" out/soong/.bootstrap/build.ninja)
+  local mtime2=$(stat -c "%y" out/soong/bootstrap.ninja)
 
   if [[ "$mtime1" == "$mtime2" ]]; then
     fail "Bootstrap Ninja file did not change"
@@ -541,7 +541,7 @@
 function test_bp2build_smoke {
   setup
   run_soong bp2build
-  [[ -e out/soong/.bootstrap/bp2build_workspace_marker ]] || fail "bp2build marker file not created"
+  [[ -e out/soong/bp2build_workspace_marker ]] || fail "bp2build marker file not created"
   [[ -e out/soong/workspace ]] || fail "Bazel workspace not created"
 }
 
@@ -551,7 +551,7 @@
 
   run_soong bp2build
 
-  if [[ ! -f "./out/soong/.bootstrap/bp2build_workspace_marker" ]]; then
+  if [[ ! -f "./out/soong/bp2build_workspace_marker" ]]; then
     fail "Marker file was not generated"
   fi
 }
@@ -592,10 +592,10 @@
   setup
 
   run_soong bp2build
-  local mtime1=$(stat -c "%y" out/soong/.bootstrap/bp2build_workspace_marker)
+  local mtime1=$(stat -c "%y" out/soong/bp2build_workspace_marker)
 
   run_soong bp2build
-  local mtime2=$(stat -c "%y" out/soong/.bootstrap/bp2build_workspace_marker)
+  local mtime2=$(stat -c "%y" out/soong/bp2build_workspace_marker)
 
   if [[ "$mtime1" != "$mtime2" ]]; then
     fail "Output Ninja file changed on null build"
@@ -626,7 +626,7 @@
 function test_multiple_soong_build_modes() {
   setup
   run_soong json-module-graph bp2build nothing
-  if [[ ! -f "out/soong/.bootstrap/bp2build_workspace_marker" ]]; then
+  if [[ ! -f "out/soong/bp2build_workspace_marker" ]]; then
     fail "bp2build marker file was not generated"
   fi
 
@@ -780,11 +780,11 @@
     fail "Output Ninja file changed when switching to bp2build"
   fi
 
-  local marker_mtime1=$(stat -c "%y" out/soong/.bootstrap/bp2build_workspace_marker)
+  local marker_mtime1=$(stat -c "%y" out/soong/bp2build_workspace_marker)
 
   run_soong
   local output_mtime3=$(stat -c "%y" out/soong/build.ninja)
-  local marker_mtime2=$(stat -c "%y" out/soong/.bootstrap/bp2build_workspace_marker)
+  local marker_mtime2=$(stat -c "%y" out/soong/bp2build_workspace_marker)
   if [[ "$output_mtime1" != "$output_mtime3" ]]; then
     fail "Output Ninja file changed when switching to regular build from bp2build"
   fi
@@ -794,7 +794,7 @@
 
   run_soong bp2build
   local output_mtime4=$(stat -c "%y" out/soong/build.ninja)
-  local marker_mtime3=$(stat -c "%y" out/soong/.bootstrap/bp2build_workspace_marker)
+  local marker_mtime3=$(stat -c "%y" out/soong/bp2build_workspace_marker)
   if [[ "$output_mtime1" != "$output_mtime4" ]]; then
     fail "Output Ninja file changed when switching back to bp2build"
   fi
diff --git a/tests/bp2build_bazel_test.sh b/tests/bp2build_bazel_test.sh
index 379eb65..01b4760 100755
--- a/tests/bp2build_bazel_test.sh
+++ b/tests/bp2build_bazel_test.sh
@@ -11,10 +11,10 @@
 function test_bp2build_null_build() {
   setup
   run_soong bp2build
-  local output_mtime1=$(stat -c "%y" out/soong/.bootstrap/bp2build_workspace_marker)
+  local output_mtime1=$(stat -c "%y" out/soong/bp2build_workspace_marker)
 
   run_soong bp2build
-  local output_mtime2=$(stat -c "%y" out/soong/.bootstrap/bp2build_workspace_marker)
+  local output_mtime2=$(stat -c "%y" out/soong/bp2build_workspace_marker)
 
   if [[ "$output_mtime1" != "$output_mtime2" ]]; then
     fail "Output bp2build marker file changed on null build"
@@ -36,10 +36,10 @@
   touch foo/bar/a.txt foo/bar/b.txt
 
   run_soong bp2build
-  local output_mtime1=$(stat -c "%y" out/soong/.bootstrap/bp2build_workspace_marker)
+  local output_mtime1=$(stat -c "%y" out/soong/bp2build_workspace_marker)
 
   run_soong bp2build
-  local output_mtime2=$(stat -c "%y" out/soong/.bootstrap/bp2build_workspace_marker)
+  local output_mtime2=$(stat -c "%y" out/soong/bp2build_workspace_marker)
 
   if [[ "$output_mtime1" != "$output_mtime2" ]]; then
     fail "Output bp2build marker file changed on null build"
diff --git a/tests/run_integration_tests.sh b/tests/run_integration_tests.sh
index 6304a11..a376e06 100755
--- a/tests/run_integration_tests.sh
+++ b/tests/run_integration_tests.sh
@@ -7,3 +7,4 @@
 "$TOP/build/soong/tests/mixed_mode_test.sh"
 "$TOP/build/soong/tests/bp2build_bazel_test.sh"
 "$TOP/build/soong/tests/soong_test.sh"
+"$TOP/build/bazel/ci/rbc_product_config.sh" aosp_arm64-userdebug
diff --git a/ui/build/config.go b/ui/build/config.go
index 07ffb44..e0fa503 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -784,12 +784,13 @@
 		panic("Unknown GOOS")
 	}
 }
+
 func (c *configImpl) HostToolDir() string {
 	return filepath.Join(c.SoongOutDir(), "host", c.PrebuiltOS(), "bin")
 }
 
 func (c *configImpl) NamedGlobFile(name string) string {
-	return shared.JoinPath(c.SoongOutDir(), ".bootstrap/build-globs."+name+".ninja")
+	return shared.JoinPath(c.SoongOutDir(), "globs-"+name+".ninja")
 }
 
 func (c *configImpl) UsedEnvFile(tag string) string {
@@ -797,7 +798,7 @@
 }
 
 func (c *configImpl) Bp2BuildMarkerFile() string {
-	return shared.JoinPath(c.SoongOutDir(), ".bootstrap/bp2build_workspace_marker")
+	return shared.JoinPath(c.SoongOutDir(), "bp2build_workspace_marker")
 }
 
 func (c *configImpl) SoongDocsHtml() string {
diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go
index afec829..3f10f75 100644
--- a/ui/build/dumpvars.go
+++ b/ui/build/dumpvars.go
@@ -263,9 +263,9 @@
 	}, exportEnvVars...), BannerVars...)
 
 	// We need Roboleaf converter and runner in the mixed mode
-	runMicrofactory(ctx, config, ".bootstrap/bin/mk2rbc", "android/soong/mk2rbc/cmd",
+	runMicrofactory(ctx, config, "mk2rbc", "android/soong/mk2rbc/cmd",
 		map[string]string{"android/soong": "build/soong"})
-	runMicrofactory(ctx, config, ".bootstrap/bin/rbcrun", "rbcrun/cmd",
+	runMicrofactory(ctx, config, "rbcrun", "rbcrun/cmd",
 		map[string]string{"go.starlark.net": "external/starlark-go", "rbcrun": "build/make/tools/rbcrun"})
 
 	makeVars, err := dumpMakeVars(ctx, config, config.Arguments(), allVars, true, "")
diff --git a/ui/build/soong.go b/ui/build/soong.go
index 1c7fbac..4ced722 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -49,7 +49,7 @@
 	// version of bootstrap and needs cleaning before continuing the build.  Increment this for
 	// incompatible changes, for example when moving the location of the bpglob binary that is
 	// executed during bootstrap before the primary builder has had a chance to update the path.
-	bootstrapEpoch = 0
+	bootstrapEpoch = 1
 )
 
 func writeEnvironmentFile(ctx Context, envFile string, envDeps map[string]string) error {
@@ -292,7 +292,7 @@
 	var blueprintArgs bootstrap.Args
 
 	blueprintArgs.ModuleListFile = filepath.Join(config.FileListDir(), "Android.bp.list")
-	blueprintArgs.OutFile = shared.JoinPath(config.SoongOutDir(), ".bootstrap/build.ninja")
+	blueprintArgs.OutFile = shared.JoinPath(config.SoongOutDir(), "bootstrap.ninja")
 	blueprintArgs.EmptyNinjaFile = false
 
 	blueprintCtx := blueprint.NewContext()
@@ -314,7 +314,7 @@
 	}
 
 	bootstrapDeps := bootstrap.RunBlueprint(blueprintArgs, bootstrap.DoEverything, blueprintCtx, blueprintConfig)
-	bootstrapDepFile := shared.JoinPath(config.SoongOutDir(), ".bootstrap/build.ninja.d")
+	bootstrapDepFile := shared.JoinPath(config.SoongOutDir(), "bootstrap.ninja.d")
 	err := deptools.WriteDepFile(bootstrapDepFile, blueprintArgs.OutFile, bootstrapDeps)
 	if err != nil {
 		ctx.Fatalf("Error writing depfile '%s': %s", bootstrapDepFile, err)
@@ -342,11 +342,6 @@
 	// unused variables were changed?
 	envFile := filepath.Join(config.SoongOutDir(), availableEnvFile)
 
-	dir := filepath.Join(config.SoongOutDir(), ".bootstrap")
-	if err := os.MkdirAll(dir, 0755); err != nil {
-		ctx.Fatalf("Cannot mkdir " + dir)
-	}
-
 	buildMode := config.bazelBuildMode()
 	integratedBp2Build := buildMode == mixedBuild
 
@@ -457,7 +452,7 @@
 		targets = append(targets, config.SoongNinjaFile())
 	}
 
-	ninja("bootstrap", ".bootstrap/build.ninja", targets...)
+	ninja("bootstrap", "bootstrap.ninja", targets...)
 
 	var soongBuildMetrics *soong_metrics_proto.SoongBuildMetrics
 	if shouldCollectBuildSoongMetrics(config) {
@@ -477,8 +472,7 @@
 	}
 }
 
-func runMicrofactory(ctx Context, config Config, relExePath string, pkg string, mapping map[string]string) {
-	name := filepath.Base(relExePath)
+func runMicrofactory(ctx Context, config Config, name string, pkg string, mapping map[string]string) {
 	ctx.BeginTrace(metrics.RunSoong, name)
 	defer ctx.EndTrace()
 	cfg := microfactory.Config{TrimPath: absPath(ctx, ".")}
@@ -486,7 +480,7 @@
 		cfg.Map(pkgPrefix, pathPrefix)
 	}
 
-	exePath := filepath.Join(config.SoongOutDir(), relExePath)
+	exePath := filepath.Join(config.SoongOutDir(), name)
 	dir := filepath.Dir(exePath)
 	if err := os.MkdirAll(dir, 0777); err != nil {
 		ctx.Fatalf("cannot create %s: %s", dir, err)
diff --git a/ui/build/test_build.go b/ui/build/test_build.go
index f9a60b6..83007be 100644
--- a/ui/build/test_build.go
+++ b/ui/build/test_build.go
@@ -63,7 +63,6 @@
 	cmd.StartOrFatal()
 
 	outDir := config.OutDir()
-	bootstrapDir := filepath.Join(outDir, "soong", ".bootstrap")
 	modulePathsDir := filepath.Join(outDir, ".module_paths")
 	variablesFilePath := filepath.Join(outDir, "soong", "soong.variables")
 
@@ -86,8 +85,7 @@
 			// Leaf node is not in the out directory.
 			continue
 		}
-		if strings.HasPrefix(line, bootstrapDir) ||
-			strings.HasPrefix(line, modulePathsDir) ||
+		if strings.HasPrefix(line, modulePathsDir) ||
 			line == variablesFilePath ||
 			line == dexpreoptConfigFilePath ||
 			line == buildDatetimeFilePath {