Revert "Load env variables before c.config()" am: 4e88859af0

Original change: https://googleplex-android-review.googlesource.com/c/platform/build/soong/+/15741350

Change-Id: I954c16917928fe1e4eace7209558b42d517c14ab
diff --git a/OWNERS b/OWNERS
index 8bb5c30..e9bbbab 100644
--- a/OWNERS
+++ b/OWNERS
@@ -4,6 +4,7 @@
 per-file * = eakammer@google.com
 per-file * = jungjw@google.com
 per-file * = patricearruda@google.com
+per-file * = hansson@google.com
 per-file * = paulduffin@google.com
 
 per-file ndk_*.go, *gen_stub_libs.py = danalbert@google.com
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 928ca03..7c4d3e0 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,2 +1,5 @@
 [Builtin Hooks]
 gofmt = true
+
+[Hook Scripts]
+do_not_use_DO_NOT_MERGE = ${REPO_ROOT}/build/soong/scripts/check_do_not_merge.sh ${PREUPLOAD_COMMIT}
diff --git a/android/Android.bp b/android/Android.bp
index bd72b7b..593399e 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -24,6 +24,8 @@
         "hooks.go",
         "image.go",
         "license.go",
+        "license_kind.go",
+        "licenses.go",
         "makevars.go",
         "module.go",
         "mutator.go",
@@ -63,7 +65,6 @@
         "csuite_config_test.go",
         "depset_test.go",
         "expand_test.go",
-        "license_test.go",
         "module_test.go",
         "mutator_test.go",
         "namespace_test.go",
diff --git a/android/androidmk.go b/android/androidmk.go
index 54a0c64..5bcf1fe 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -21,6 +21,7 @@
 	"io/ioutil"
 	"os"
 	"path/filepath"
+	"reflect"
 	"sort"
 	"strings"
 
@@ -46,7 +47,7 @@
 type AndroidMkData struct {
 	Class           string
 	SubName         string
-	DistFile        OptionalPath
+	DistFiles       TaggedDistFiles
 	OutputFile      OptionalPath
 	Disabled        bool
 	Include         string
@@ -72,7 +73,7 @@
 type AndroidMkEntries struct {
 	Class           string
 	SubName         string
-	DistFile        OptionalPath
+	DistFiles       TaggedDistFiles
 	OutputFile      OptionalPath
 	Disabled        bool
 	Include         string
@@ -176,6 +177,122 @@
 	a.EntryMap[name] = append(a.EntryMap[name], value...)
 }
 
+// AddCompatibilityTestSuites adds the supplied test suites to the EntryMap, with special handling
+// for partial MTS test suites.
+func (a *AndroidMkEntries) AddCompatibilityTestSuites(suites ...string) {
+	// MTS supports a full test suite and partial per-module MTS test suites, with naming mts-${MODULE}.
+	// To reduce repetition, if we find a partial MTS test suite without an full MTS test suite,
+	// we add the full test suite to our list.
+	if PrefixInList(suites, "mts-") && !InList("mts", suites) {
+		suites = append(suites, "mts")
+	}
+	a.AddStrings("LOCAL_COMPATIBILITY_SUITE", suites...)
+}
+
+// Compute the list of Make strings to declare phone goals and dist-for-goals
+// calls from the module's dist and dists properties.
+func (a *AndroidMkEntries) GetDistForGoals(mod blueprint.Module) []string {
+	amod := mod.(Module).base()
+	name := amod.BaseModuleName()
+
+	var ret []string
+	var availableTaggedDists TaggedDistFiles
+
+	if a.DistFiles != nil {
+		availableTaggedDists = a.DistFiles
+	} else if a.OutputFile.Valid() {
+		availableTaggedDists = MakeDefaultDistFiles(a.OutputFile.Path())
+	} else {
+		// Nothing dist-able for this module.
+		return nil
+	}
+
+	// Iterate over this module's dist structs, merged from the dist and dists properties.
+	for _, dist := range amod.Dists() {
+		// Get the list of goals this dist should be enabled for. e.g. sdk, droidcore
+		goals := strings.Join(dist.Targets, " ")
+
+		// Get the tag representing the output files to be dist'd. e.g. ".jar", ".proguard_map"
+		var tag string
+		if dist.Tag == nil {
+			// If the dist struct does not specify a tag, use the default output files tag.
+			tag = ""
+		} else {
+			tag = *dist.Tag
+		}
+
+		// Get the paths of the output files to be dist'd, represented by the tag.
+		// Can be an empty list.
+		tagPaths := availableTaggedDists[tag]
+		if len(tagPaths) == 0 {
+			// Nothing to dist for this tag, continue to the next dist.
+			continue
+		}
+
+		if len(tagPaths) > 1 && (dist.Dest != nil || dist.Suffix != nil) {
+			errorMessage := "Cannot apply dest/suffix for more than one dist " +
+				"file for %s goals in module %s. The list of dist files, " +
+				"which should have a single element, is:\n%s"
+			panic(fmt.Errorf(errorMessage, goals, name, tagPaths))
+		}
+
+		ret = append(ret, fmt.Sprintf(".PHONY: %s\n", goals))
+
+		// Create dist-for-goals calls for each path in the dist'd files.
+		for _, path := range tagPaths {
+			// It's possible that the Path is nil from errant modules. Be defensive here.
+			if path == nil {
+				tagName := "default" // for error message readability
+				if dist.Tag != nil {
+					tagName = *dist.Tag
+				}
+				panic(fmt.Errorf("Dist file should not be nil for the %s tag in %s", tagName, name))
+			}
+
+			dest := filepath.Base(path.String())
+
+			if dist.Dest != nil {
+				var err error
+				if dest, err = validateSafePath(*dist.Dest); err != nil {
+					// This was checked in ModuleBase.GenerateBuildActions
+					panic(err)
+				}
+			}
+
+			if dist.Suffix != nil {
+				ext := filepath.Ext(dest)
+				suffix := *dist.Suffix
+				dest = strings.TrimSuffix(dest, ext) + suffix + ext
+			}
+
+			if dist.Dir != nil {
+				var err error
+				if dest, err = validateSafePath(*dist.Dir, dest); err != nil {
+					// This was checked in ModuleBase.GenerateBuildActions
+					panic(err)
+				}
+			}
+
+			ret = append(
+				ret,
+				fmt.Sprintf("$(call dist-for-goals,%s,%s:%s)\n", goals, path.String(), dest))
+		}
+	}
+
+	return ret
+}
+
+// Write the license variables to Make for AndroidMkData.Custom(..) methods that do not call WriteAndroidMkData(..)
+// It's required to propagate the license metadata even for module types that have non-standard interfaces to Make.
+func (a *AndroidMkEntries) WriteLicenseVariables(w io.Writer) {
+	fmt.Fprintln(w, "LOCAL_LICENSE_KINDS :=", strings.Join(a.EntryMap["LOCAL_LICENSE_KINDS"], " "))
+	fmt.Fprintln(w, "LOCAL_LICENSE_CONDITIONS :=", strings.Join(a.EntryMap["LOCAL_LICENSE_CONDITIONS"], " "))
+	fmt.Fprintln(w, "LOCAL_NOTICE_FILE :=", strings.Join(a.EntryMap["LOCAL_NOTICE_FILE"], " "))
+	if pn, ok := a.EntryMap["LOCAL_LICENSE_PACKAGE_NAME"]; ok {
+		fmt.Fprintln(w, "LOCAL_LICENSE_PACKAGE_NAME :=", strings.Join(pn, " "))
+	}
+}
+
 func (a *AndroidMkEntries) fillInEntries(config Config, bpPath string, mod blueprint.Module) {
 	a.EntryMap = make(map[string][]string)
 	amod := mod.(Module).base()
@@ -188,42 +305,8 @@
 	a.Host_required = append(a.Host_required, amod.commonProperties.Host_required...)
 	a.Target_required = append(a.Target_required, amod.commonProperties.Target_required...)
 
-	// Fill in the header part.
-	if len(amod.commonProperties.Dist.Targets) > 0 {
-		distFile := a.DistFile
-		if !distFile.Valid() {
-			distFile = a.OutputFile
-		}
-		if distFile.Valid() {
-			dest := filepath.Base(distFile.String())
-
-			if amod.commonProperties.Dist.Dest != nil {
-				var err error
-				if dest, err = validateSafePath(*amod.commonProperties.Dist.Dest); err != nil {
-					// This was checked in ModuleBase.GenerateBuildActions
-					panic(err)
-				}
-			}
-
-			if amod.commonProperties.Dist.Suffix != nil {
-				ext := filepath.Ext(dest)
-				suffix := *amod.commonProperties.Dist.Suffix
-				dest = strings.TrimSuffix(dest, ext) + suffix + ext
-			}
-
-			if amod.commonProperties.Dist.Dir != nil {
-				var err error
-				if dest, err = validateSafePath(*amod.commonProperties.Dist.Dir, dest); err != nil {
-					// This was checked in ModuleBase.GenerateBuildActions
-					panic(err)
-				}
-			}
-
-			goals := strings.Join(amod.commonProperties.Dist.Targets, " ")
-			fmt.Fprintln(&a.header, ".PHONY:", goals)
-			fmt.Fprintf(&a.header, "$(call dist-for-goals,%s,%s:%s)\n",
-				goals, distFile.String(), dest)
-		}
+	for _, distString := range a.GetDistForGoals(mod) {
+		fmt.Fprintf(&a.header, distString)
 	}
 
 	fmt.Fprintln(&a.header, "\ninclude $(CLEAR_VARS)")
@@ -231,6 +314,13 @@
 	// Collect make variable assignment entries.
 	a.SetString("LOCAL_PATH", filepath.Dir(bpPath))
 	a.SetString("LOCAL_MODULE", name+a.SubName)
+	a.AddStrings("LOCAL_LICENSE_KINDS", amod.commonProperties.Effective_license_kinds...)
+	a.AddStrings("LOCAL_LICENSE_CONDITIONS", amod.commonProperties.Effective_license_conditions...)
+	a.AddStrings("LOCAL_NOTICE_FILE", amod.commonProperties.Effective_license_text...)
+	// TODO(b/151177513): Does this code need to set LOCAL_MODULE_IS_CONTAINER ?
+	if amod.commonProperties.Effective_package_name != nil {
+		a.SetString("LOCAL_LICENSE_PACKAGE_NAME", *amod.commonProperties.Effective_package_name)
+	}
 	a.SetString("LOCAL_MODULE_CLASS", a.Class)
 	a.SetString("LOCAL_PREBUILT_MODULE_FILE", a.OutputFile.String())
 	a.AddStrings("LOCAL_REQUIRED_MODULES", a.Required...)
@@ -441,6 +531,7 @@
 		}
 	}()
 
+	// Additional cases here require review for correct license propagation to make.
 	switch x := mod.(type) {
 	case AndroidMkDataProvider:
 		return translateAndroidModule(ctx, w, mod, x)
@@ -449,6 +540,7 @@
 	case AndroidMkEntriesProvider:
 		return translateAndroidMkEntriesModule(ctx, w, mod, x)
 	default:
+		// Not exported to make so no make variables to set.
 		return nil
 	}
 }
@@ -460,6 +552,10 @@
 	fmt.Fprintln(w, ".PHONY:", name)
 	fmt.Fprintln(w, name+":", goBinary.InstallPath())
 	fmt.Fprintln(w, "")
+	// Assuming no rules in make include go binaries in distributables.
+	// If the assumption is wrong, make will fail to build without the necessary .meta_lic and .meta_module files.
+	// In that case, add the targets and rules here to build a .meta_lic file for `name` and a .meta_module for
+	// `goBinary.InstallPath()` pointing to the `name`.meta_lic file.
 
 	return nil
 }
@@ -469,7 +565,7 @@
 	entries := AndroidMkEntries{
 		Class:           data.Class,
 		SubName:         data.SubName,
-		DistFile:        data.DistFile,
+		DistFiles:       data.DistFiles,
 		OutputFile:      data.OutputFile,
 		Disabled:        data.Disabled,
 		Include:         data.Include,
@@ -525,6 +621,25 @@
 	blueprintDir := filepath.Dir(ctx.BlueprintFile(mod))
 
 	if data.Custom != nil {
+		// List of module types allowed to use .Custom(...)
+		// Additions to the list require careful review for proper license handling.
+		switch reflect.TypeOf(mod).String() { // ctx.ModuleType(mod) doesn't work: aidl_interface creates phony without type
+		case "*aidl.aidlApi": // writes non-custom before adding .phony
+		case "*aidl.aidlMapping": // writes non-custom before adding .phony
+		case "*android.customModule": // appears in tests only
+		case "*apex.apexBundle": // license properties written
+		case "*bpf.bpf": // license properties written (both for module and objs)
+		case "*genrule.Module": // writes non-custom before adding .phony
+		case "*java.SystemModules": // doesn't go through base_rules
+		case "*java.systemModulesImport": // doesn't go through base_rules
+		case "*phony.phony": // license properties written
+		case "*selinux.selinuxContextsModule": // license properties written
+		case "*sysprop.syspropLibrary": // license properties written
+		default:
+			if ctx.Config().IsEnvTrue("ANDROID_REQUIRE_LICENSES") {
+				return fmt.Errorf("custom make rules not allowed for %q (%q) module %q", ctx.ModuleType(mod), reflect.TypeOf(mod), ctx.ModuleName(mod))
+			}
+		}
 		data.Custom(w, name, prefix, blueprintDir, data)
 	} else {
 		WriteAndroidMkData(w, data)
@@ -557,6 +672,7 @@
 		return nil
 	}
 
+	// Any new or special cases here need review to verify correct propagation of license information.
 	for _, entries := range provider.AndroidMkEntries() {
 		entries.fillInEntries(ctx.Config(), ctx.BlueprintFile(mod), mod)
 		entries.write(w)
diff --git a/android/androidmk_test.go b/android/androidmk_test.go
index 71f8020..a558f45 100644
--- a/android/androidmk_test.go
+++ b/android/androidmk_test.go
@@ -15,6 +15,7 @@
 package android
 
 import (
+	"fmt"
 	"io"
 	"reflect"
 	"testing"
@@ -22,10 +23,12 @@
 
 type customModule struct {
 	ModuleBase
-	data AndroidMkData
+	data      AndroidMkData
+	distFiles TaggedDistFiles
 }
 
 func (m *customModule) GenerateAndroidBuildActions(ctx ModuleContext) {
+	m.distFiles = m.GenerateTaggedDistFiles(ctx)
 }
 
 func (m *customModule) AndroidMk() AndroidMkData {
@@ -36,6 +39,28 @@
 	}
 }
 
+func (m *customModule) OutputFiles(tag string) (Paths, error) {
+	switch tag {
+	case "":
+		return PathsForTesting("one.out"), nil
+	case ".multiple":
+		return PathsForTesting("two.out", "three/four.out"), nil
+	case ".another-tag":
+		return PathsForTesting("another.out"), nil
+	default:
+		return nil, fmt.Errorf("unsupported module reference tag %q", tag)
+	}
+}
+
+func (m *customModule) AndroidMkEntries() []AndroidMkEntries {
+	return []AndroidMkEntries{
+		{
+			Class:     "CUSTOM_MODULE",
+			DistFiles: m.distFiles,
+		},
+	}
+}
+
 func customModuleFactory() Module {
 	module := &customModule{}
 	InitAndroidModule(module)
@@ -76,3 +101,191 @@
 	assertEqual([]string{"baz"}, m.data.Host_required)
 	assertEqual([]string{"qux"}, m.data.Target_required)
 }
+
+func TestGetDistForGoals(t *testing.T) {
+	testCases := []struct {
+		bp                     string
+		expectedAndroidMkLines []string
+	}{
+		{
+			bp: `
+			custom {
+				name: "foo",
+				dist: {
+					targets: ["my_goal"]
+				}
+			}
+			`,
+			expectedAndroidMkLines: []string{
+				".PHONY: my_goal\n",
+				"$(call dist-for-goals,my_goal,one.out:one.out)\n",
+			},
+		},
+		{
+			bp: `
+			custom {
+				name: "foo",
+				dist: {
+					targets: ["my_goal"],
+					tag: ".another-tag",
+				}
+			}
+			`,
+			expectedAndroidMkLines: []string{
+				".PHONY: my_goal\n",
+				"$(call dist-for-goals,my_goal,another.out:another.out)\n",
+			},
+		},
+		{
+			bp: `
+			custom {
+				name: "foo",
+				dists: [
+					{
+						targets: ["my_goal"],
+						tag: ".another-tag",
+					},
+				],
+			}
+			`,
+			expectedAndroidMkLines: []string{
+				".PHONY: my_goal\n",
+				"$(call dist-for-goals,my_goal,another.out:another.out)\n",
+			},
+		},
+		{
+			bp: `
+			custom {
+				name: "foo",
+				dists: [
+					{
+						targets: ["my_goal"],
+					},
+					{
+						targets: ["my_second_goal", "my_third_goal"],
+					},
+				],
+			}
+			`,
+			expectedAndroidMkLines: []string{
+				".PHONY: my_goal\n",
+				"$(call dist-for-goals,my_goal,one.out:one.out)\n",
+				".PHONY: my_second_goal my_third_goal\n",
+				"$(call dist-for-goals,my_second_goal my_third_goal,one.out:one.out)\n",
+			},
+		},
+		{
+			bp: `
+			custom {
+				name: "foo",
+				dist: {
+					targets: ["my_goal"],
+				},
+				dists: [
+					{
+						targets: ["my_second_goal", "my_third_goal"],
+					},
+				],
+			}
+			`,
+			expectedAndroidMkLines: []string{
+				".PHONY: my_second_goal my_third_goal\n",
+				"$(call dist-for-goals,my_second_goal my_third_goal,one.out:one.out)\n",
+				".PHONY: my_goal\n",
+				"$(call dist-for-goals,my_goal,one.out:one.out)\n",
+			},
+		},
+		{
+			bp: `
+			custom {
+				name: "foo",
+				dist: {
+					targets: ["my_goal", "my_other_goal"],
+					tag: ".multiple",
+				},
+				dists: [
+					{
+						targets: ["my_second_goal"],
+						tag: ".multiple",
+					},
+					{
+						targets: ["my_third_goal"],
+						dir: "test/dir",
+					},
+					{
+						targets: ["my_fourth_goal"],
+						suffix: ".suffix",
+					},
+					{
+						targets: ["my_fifth_goal"],
+						dest: "new-name",
+					},
+					{
+						targets: ["my_sixth_goal"],
+						dest: "new-name",
+						dir: "some/dir",
+						suffix: ".suffix",
+					},
+				],
+			}
+			`,
+			expectedAndroidMkLines: []string{
+				".PHONY: my_second_goal\n",
+				"$(call dist-for-goals,my_second_goal,two.out:two.out)\n",
+				"$(call dist-for-goals,my_second_goal,three/four.out:four.out)\n",
+				".PHONY: my_third_goal\n",
+				"$(call dist-for-goals,my_third_goal,one.out:test/dir/one.out)\n",
+				".PHONY: my_fourth_goal\n",
+				"$(call dist-for-goals,my_fourth_goal,one.out:one.suffix.out)\n",
+				".PHONY: my_fifth_goal\n",
+				"$(call dist-for-goals,my_fifth_goal,one.out:new-name)\n",
+				".PHONY: my_sixth_goal\n",
+				"$(call dist-for-goals,my_sixth_goal,one.out:some/dir/new-name.suffix)\n",
+				".PHONY: my_goal my_other_goal\n",
+				"$(call dist-for-goals,my_goal my_other_goal,two.out:two.out)\n",
+				"$(call dist-for-goals,my_goal my_other_goal,three/four.out:four.out)\n",
+			},
+		},
+	}
+
+	for _, testCase := range testCases {
+		config := TestConfig(buildDir, nil, testCase.bp, nil)
+		config.inMake = true // Enable androidmk Singleton
+
+		ctx := NewTestContext()
+		ctx.RegisterSingletonType("androidmk", AndroidMkSingleton)
+		ctx.RegisterModuleType("custom", customModuleFactory)
+		ctx.Register(config)
+
+		_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+		FailIfErrored(t, errs)
+		_, errs = ctx.PrepareBuildActions(config)
+		FailIfErrored(t, errs)
+
+		module := ctx.ModuleForTests("foo", "").Module().(*customModule)
+		entries := AndroidMkEntriesForTest(t, config, "", module)
+		if len(entries) != 1 {
+			t.Errorf("Expected a single AndroidMk entry, got %d", len(entries))
+		}
+		androidMkLines := entries[0].GetDistForGoals(module)
+
+		if len(androidMkLines) != len(testCase.expectedAndroidMkLines) {
+			t.Errorf(
+				"Expected %d AndroidMk lines, got %d:\n%v",
+				len(testCase.expectedAndroidMkLines),
+				len(androidMkLines),
+				androidMkLines,
+			)
+		}
+		for idx, line := range androidMkLines {
+			expectedLine := testCase.expectedAndroidMkLines[idx]
+			if line != expectedLine {
+				t.Errorf(
+					"Expected AndroidMk line to be '%s', got '%s'",
+					line,
+					expectedLine,
+				)
+			}
+		}
+	}
+}
diff --git a/android/apex.go b/android/apex.go
index 30152db..4c914ee 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -442,19 +442,21 @@
 // Generate two module out files:
 // 1. FullList with transitive deps and their parents in the dep graph
 // 2. FlatList with a flat list of transitive deps
+// In both cases transitive deps of external deps are not included. Neither are deps that are only
+// available to APEXes; they are developed with updatability in mind and don't need manual approval.
 func (d *ApexBundleDepsInfo) BuildDepsInfoLists(ctx ModuleContext, minSdkVersion string, depInfos DepNameToDepInfoMap) {
 	var fullContent strings.Builder
 	var flatContent strings.Builder
 
-	fmt.Fprintf(&flatContent, "%s(minSdkVersion:%s):\\n", ctx.ModuleName(), minSdkVersion)
+	fmt.Fprintf(&fullContent, "%s(minSdkVersion:%s):\\n", ctx.ModuleName(), minSdkVersion)
 	for _, key := range FirstUniqueStrings(SortedStringKeys(depInfos)) {
 		info := depInfos[key]
 		toName := fmt.Sprintf("%s(minSdkVersion:%s)", info.To, info.MinSdkVersion)
 		if info.IsExternal {
 			toName = toName + " (external)"
 		}
-		fmt.Fprintf(&fullContent, "%s <- %s\\n", toName, strings.Join(SortedUniqueStrings(info.From), ", "))
-		fmt.Fprintf(&flatContent, "  %s\\n", toName)
+		fmt.Fprintf(&fullContent, "  %s <- %s\\n", toName, strings.Join(SortedUniqueStrings(info.From), ", "))
+		fmt.Fprintf(&flatContent, "%s\\n", toName)
 	}
 
 	d.fullListPath = PathForModuleOut(ctx, "depsinfo", "fulllist.txt").OutputPath
diff --git a/android/config.go b/android/config.go
index 3541f83..24ec29d 100644
--- a/android/config.go
+++ b/android/config.go
@@ -113,7 +113,7 @@
 
 	// If testAllowNonExistentPaths is true then PathForSource and PathForModuleSrc won't error
 	// in tests when a path doesn't exist.
-	testAllowNonExistentPaths bool
+	TestAllowNonExistentPaths bool
 
 	OncePer
 }
@@ -237,7 +237,7 @@
 
 		// Set testAllowNonExistentPaths so that test contexts don't need to specify every path
 		// passed to PathForSource or PathForModuleSrc.
-		testAllowNonExistentPaths: true,
+		TestAllowNonExistentPaths: true,
 	}
 	config.deviceConfig = &deviceConfig{
 		config: config,
diff --git a/android/csuite_config.go b/android/csuite_config.go
index 15c518a..bf24d98 100644
--- a/android/csuite_config.go
+++ b/android/csuite_config.go
@@ -14,11 +14,6 @@
 
 package android
 
-import (
-	"fmt"
-	"io"
-)
-
 func init() {
 	RegisterModuleType("csuite_config", CSuiteConfigFactory)
 }
@@ -38,22 +33,21 @@
 	me.OutputFilePath = PathForModuleOut(ctx, me.BaseModuleName()).OutputPath
 }
 
-func (me *CSuiteConfig) AndroidMk() AndroidMkData {
-	androidMkData := AndroidMkData{
+func (me *CSuiteConfig) AndroidMkEntries() []AndroidMkEntries {
+	androidMkEntries := AndroidMkEntries{
 		Class:      "FAKE",
 		Include:    "$(BUILD_SYSTEM)/suite_host_config.mk",
 		OutputFile: OptionalPathForPath(me.OutputFilePath),
 	}
-	androidMkData.Extra = []AndroidMkExtraFunc{
-		func(w io.Writer, outputFile Path) {
+	androidMkEntries.ExtraEntries = []AndroidMkExtraEntriesFunc{
+		func(entries *AndroidMkEntries) {
 			if me.properties.Test_config != nil {
-				fmt.Fprintf(w, "LOCAL_TEST_CONFIG := %s\n",
-					*me.properties.Test_config)
+				entries.SetString("LOCAL_TEST_CONFIG", *me.properties.Test_config)
 			}
-			fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE := csuite")
+			entries.AddCompatibilityTestSuites("csuite")
 		},
 	}
-	return androidMkData
+	return []AndroidMkEntries{androidMkEntries}
 }
 
 func InitCSuiteConfigModule(me *CSuiteConfig) {
diff --git a/android/defaults.go b/android/defaults.go
index 81e340e..880c689 100644
--- a/android/defaults.go
+++ b/android/defaults.go
@@ -95,6 +95,8 @@
 	module.setProperties(module.(Module).GetProperties(), module.(Module).base().variableProperties)
 
 	module.AddProperties(module.defaults())
+
+	module.base().customizableProperties = module.GetProperties()
 }
 
 // A restricted subset of context methods, similar to LoadHookContext.
@@ -195,7 +197,8 @@
 	module.AddProperties(
 		&hostAndDeviceProperties{},
 		commonProperties,
-		&ApexProperties{})
+		&ApexProperties{},
+		&distProperties{})
 
 	initAndroidModuleBase(module)
 	initProductVariableModule(module)
@@ -220,6 +223,9 @@
 	// its checking phase and parsing phase so add it to the list as a normal property.
 	AddVisibilityProperty(module, "visibility", &commonProperties.Visibility)
 
+	// The applicable licenses property for defaults is 'licenses'.
+	setPrimaryLicensesProperty(module, "licenses", &commonProperties.Licenses)
+
 	base.module = module
 }
 
diff --git a/android/license.go b/android/license.go
index 00ddacd..3bc6199 100644
--- a/android/license.go
+++ b/android/license.go
@@ -14,6 +14,18 @@
 
 package android
 
+import (
+	"github.com/google/blueprint"
+)
+
+type licenseKindDependencyTag struct {
+	blueprint.BaseDependencyTag
+}
+
+var (
+	licenseKindTag = licenseKindDependencyTag{}
+)
+
 func init() {
 	RegisterLicenseBuildComponents(InitRegistrationContext)
 }
@@ -44,7 +56,7 @@
 }
 
 func (m *licenseModule) DepsMutator(ctx BottomUpMutatorContext) {
-	// Do nothing.
+	ctx.AddVariationDependencies(nil, licenseKindTag, m.properties.License_kinds...)
 }
 
 func (m *licenseModule) GenerateAndroidBuildActions(ctx ModuleContext) {
diff --git a/android/license_kind.go b/android/license_kind.go
new file mode 100644
index 0000000..ddecd77
--- /dev/null
+++ b/android/license_kind.go
@@ -0,0 +1,66 @@
+// 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 android
+
+func init() {
+	RegisterLicenseKindBuildComponents(InitRegistrationContext)
+}
+
+// Register the license_kind module type.
+func RegisterLicenseKindBuildComponents(ctx RegistrationContext) {
+	ctx.RegisterModuleType("license_kind", LicenseKindFactory)
+}
+
+type licenseKindProperties struct {
+	// Specifies the conditions for all licenses of the kind.
+	Conditions []string
+	// Specifies the url to the canonical license definition.
+	Url string
+	// Specifies where this license can be used
+	Visibility []string
+}
+
+type licenseKindModule struct {
+	ModuleBase
+	DefaultableModuleBase
+
+	properties licenseKindProperties
+}
+
+func (m *licenseKindModule) DepsMutator(ctx BottomUpMutatorContext) {
+	// Nothing to do.
+}
+
+func (m *licenseKindModule) GenerateAndroidBuildActions(ModuleContext) {
+	// Nothing to do.
+}
+
+func LicenseKindFactory() Module {
+	module := &licenseKindModule{}
+
+	base := module.base()
+	module.AddProperties(&base.nameProperties, &module.properties)
+
+	base.generalProperties = module.GetProperties()
+	base.customizableProperties = module.GetProperties()
+
+	// The visibility property needs to be checked and parsed by the visibility module.
+	setPrimaryVisibilityProperty(module, "visibility", &module.properties.Visibility)
+
+	initAndroidModuleBase(module)
+	InitDefaultableModule(module)
+
+	return module
+}
diff --git a/android/license_test.go b/android/license_test.go
deleted file mode 100644
index e80ba5e..0000000
--- a/android/license_test.go
+++ /dev/null
@@ -1,142 +0,0 @@
-package android
-
-import (
-	"testing"
-)
-
-var licenseTests = []struct {
-	name           string
-	fs             map[string][]byte
-	expectedErrors []string
-}{
-	{
-		name: "license must not accept licenses property",
-		fs: map[string][]byte{
-			"top/Blueprints": []byte(`
-				license {
-					name: "top_license",
-					visibility: ["//visibility:private"],
-					licenses: ["other_license"],
-
-				}`),
-		},
-		expectedErrors: []string{
-			`top/Blueprints:5:14: unrecognized property "licenses"`,
-		},
-	},
-	{
-		name: "public license",
-		fs: map[string][]byte{
-			"top/Blueprints": []byte(`
-				license {
-					name: "top_proprietary",
-					license_kinds: ["top_by_exception_only"],
-					visibility: ["//visibility:public"],
-				}`),
-			"other/Blueprints": []byte(`
-				rule {
-					name: "arule",
-					licenses: ["top_proprietary"],
-
-				}`),
-			"yetmore/Blueprints": []byte(`
-				package {
-					default_applicable_licenses: ["top_proprietary"],
-				}`),
-		},
-	},
-	{
-		name: "multiple licenses",
-		fs: map[string][]byte{
-			"top/Blueprints": []byte(`
-				package {
-					default_applicable_licenses: ["top_proprietary"],
-				}
-				license {
-					name: "top_allowed_as_notice",
-					license_kinds: ["top_notice"],
-				}
-				license {
-					name: "top_proprietary",
-					license_kinds: ["top_by_exception_only"],
-					visibility: ["//visibility:public"],
-				}
-				rule {
-					name: "myrule",
-					licenses: ["top_allowed_as_notice", "top_proprietary"]
-				}`),
-			"other/Blueprints": []byte(`
-				rule {
-					name: "arule",
-					licenses: ["top_proprietary"],
-
-				}`),
-			"yetmore/Blueprints": []byte(`
-				package {
-					default_applicable_licenses: ["top_proprietary"],
-				}`),
-		},
-	},
-}
-
-func TestLicense(t *testing.T) {
-	for _, test := range licenseTests {
-		t.Run(test.name, func(t *testing.T) {
-			_, errs := testLicense(test.fs)
-			expectedErrors := test.expectedErrors
-			if expectedErrors == nil {
-				FailIfErrored(t, errs)
-			} else {
-				for _, expectedError := range expectedErrors {
-					FailIfNoMatchingErrors(t, expectedError, errs)
-				}
-				if len(errs) > len(expectedErrors) {
-					t.Errorf("additional errors found, expected %d, found %d", len(expectedErrors), len(errs))
-					for i, expectedError := range expectedErrors {
-						t.Errorf("expectedErrors[%d] = %s", i, expectedError)
-					}
-					for i, err := range errs {
-						t.Errorf("errs[%d] = %s", i, err)
-					}
-				}
-			}
-		})
-	}
-}
-func testLicense(fs map[string][]byte) (*TestContext, []error) {
-	// Create a new config per test as visibility information is stored in the config.
-	env := make(map[string]string)
-	env["ANDROID_REQUIRE_LICENSES"] = "1"
-	config := TestArchConfig(buildDir, env, "", fs)
-	ctx := NewTestArchContext()
-	RegisterPackageBuildComponents(ctx)
-	registerTestPrebuiltBuildComponents(ctx)
-	RegisterLicenseBuildComponents(ctx)
-	ctx.RegisterModuleType("rule", newMockRuleModule)
-	ctx.PreArchMutators(RegisterVisibilityRuleChecker)
-	ctx.PreArchMutators(RegisterDefaultsPreArchMutators)
-	ctx.PreArchMutators(RegisterVisibilityRuleGatherer)
-	ctx.PostDepsMutators(RegisterVisibilityRuleEnforcer)
-	ctx.Register(config)
-	_, errs := ctx.ParseBlueprintsFiles(".")
-	if len(errs) > 0 {
-		return ctx, errs
-	}
-	_, errs = ctx.PrepareBuildActions(config)
-	return ctx, errs
-}
-
-type mockRuleModule struct {
-	ModuleBase
-	DefaultableModuleBase
-}
-
-func newMockRuleModule() Module {
-	m := &mockRuleModule{}
-	InitAndroidModule(m)
-	InitDefaultableModule(m)
-	return m
-}
-
-func (p *mockRuleModule) GenerateAndroidBuildActions(ModuleContext) {
-}
diff --git a/android/licenses.go b/android/licenses.go
new file mode 100644
index 0000000..2838f5d
--- /dev/null
+++ b/android/licenses.go
@@ -0,0 +1,295 @@
+// 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 android
+
+import (
+	"reflect"
+	"sync"
+
+	"github.com/google/blueprint"
+)
+
+// Adds cross-cutting licenses dependency to propagate license metadata through the build system.
+//
+// Stage 1 - bottom-up records package-level default_applicable_licenses property mapped by package name.
+// Stage 2 - bottom-up converts licenses property or package default_applicable_licenses to dependencies.
+// Stage 3 - bottom-up type-checks every added applicable license dependency and license_kind dependency.
+// Stage 4 - GenerateBuildActions calculates properties for the union of license kinds, conditions and texts.
+
+type licensesDependencyTag struct {
+	blueprint.BaseDependencyTag
+}
+
+var (
+	licensesTag = licensesDependencyTag{}
+)
+
+// Describes the property provided by a module to reference applicable licenses.
+type applicableLicensesProperty interface {
+	// The name of the property. e.g. default_applicable_licenses or licenses
+	getName() string
+	// The values assigned to the property. (Must reference license modules.)
+	getStrings() []string
+}
+
+type applicableLicensesPropertyImpl struct {
+	name             string
+	licensesProperty *[]string
+}
+
+func newApplicableLicensesProperty(name string, licensesProperty *[]string) applicableLicensesProperty {
+	return applicableLicensesPropertyImpl{
+		name:             name,
+		licensesProperty: licensesProperty,
+	}
+}
+
+func (p applicableLicensesPropertyImpl) getName() string {
+	return p.name
+}
+
+func (p applicableLicensesPropertyImpl) getStrings() []string {
+	return *p.licensesProperty
+}
+
+// Set the primary applicable licenses property for a module.
+func setPrimaryLicensesProperty(module Module, name string, licensesProperty *[]string) {
+	module.base().primaryLicensesProperty = newApplicableLicensesProperty(name, licensesProperty)
+}
+
+// Storage blob for a package's default_applicable_licenses mapped by package directory.
+type licensesContainer struct {
+	licenses []string
+}
+
+func (r licensesContainer) getLicenses() []string {
+	return r.licenses
+}
+
+var packageDefaultLicensesMap = NewOnceKey("packageDefaultLicensesMap")
+
+// The map from package dir name to default applicable licenses as a licensesContainer.
+func moduleToPackageDefaultLicensesMap(config Config) *sync.Map {
+	return config.Once(packageDefaultLicensesMap, func() interface{} {
+		return &sync.Map{}
+	}).(*sync.Map)
+}
+
+// Registers the function that maps each package to its default_applicable_licenses.
+//
+// This goes before defaults expansion so the defaults can pick up the package default.
+func RegisterLicensesPackageMapper(ctx RegisterMutatorsContext) {
+	ctx.BottomUp("licensesPackageMapper", licensesPackageMapper).Parallel()
+}
+
+// Registers the function that gathers the license dependencies for each module.
+//
+// This goes after defaults expansion so that it can pick up default licenses and before visibility enforcement.
+func RegisterLicensesPropertyGatherer(ctx RegisterMutatorsContext) {
+	ctx.BottomUp("licensesPropertyGatherer", licensesPropertyGatherer).Parallel()
+}
+
+// Registers the function that verifies the licenses and license_kinds dependency types for each module.
+func RegisterLicensesDependencyChecker(ctx RegisterMutatorsContext) {
+	ctx.BottomUp("licensesPropertyChecker", licensesDependencyChecker).Parallel()
+}
+
+// Maps each package to its default applicable licenses.
+func licensesPackageMapper(ctx BottomUpMutatorContext) {
+	p, ok := ctx.Module().(*packageModule)
+	if !ok {
+		return
+	}
+
+	licenses := getLicenses(ctx, p)
+
+	dir := ctx.ModuleDir()
+	c := makeLicensesContainer(licenses)
+	moduleToPackageDefaultLicensesMap(ctx.Config()).Store(dir, c)
+}
+
+// Copies the default_applicable_licenses property values for mapping by package directory.
+func makeLicensesContainer(propVals []string) licensesContainer {
+	licenses := make([]string, 0, len(propVals))
+	licenses = append(licenses, propVals...)
+
+	return licensesContainer{licenses}
+}
+
+// Gathers the applicable licenses into dependency references after defaults expansion.
+func licensesPropertyGatherer(ctx BottomUpMutatorContext) {
+	m, ok := ctx.Module().(Module)
+	if !ok {
+		return
+	}
+
+	if exemptFromRequiredApplicableLicensesProperty(m) {
+		return
+	}
+
+	licenses := getLicenses(ctx, m)
+
+	ctx.AddVariationDependencies(nil, licensesTag, licenses...)
+}
+
+// Verifies the license and license_kind dependencies are each the correct kind of module.
+func licensesDependencyChecker(ctx BottomUpMutatorContext) {
+	m, ok := ctx.Module().(Module)
+	if !ok {
+		return
+	}
+
+	// license modules have no licenses, but license_kinds must refer to license_kind modules
+	if _, ok := m.(*licenseModule); ok {
+		for _, module := range ctx.GetDirectDepsWithTag(licenseKindTag) {
+			if _, ok := module.(*licenseKindModule); !ok {
+				ctx.ModuleErrorf("license_kinds property %q is not a license_kind module", ctx.OtherModuleName(module))
+			}
+		}
+		return
+	}
+
+	if exemptFromRequiredApplicableLicensesProperty(m) {
+		return
+	}
+
+	for _, module := range ctx.GetDirectDepsWithTag(licensesTag) {
+		if _, ok := module.(*licenseModule); !ok {
+			propertyName := "licenses"
+			primaryProperty := m.base().primaryLicensesProperty
+			if primaryProperty != nil {
+				propertyName = primaryProperty.getName()
+			}
+			ctx.ModuleErrorf("%s property %q is not a license module", propertyName, ctx.OtherModuleName(module))
+		}
+	}
+}
+
+// Flattens license and license_kind dependencies into calculated properties.
+//
+// Re-validates applicable licenses properties refer only to license modules and license_kinds properties refer
+// only to license_kind modules.
+func licensesPropertyFlattener(ctx ModuleContext) {
+	m, ok := ctx.Module().(Module)
+	if !ok {
+		return
+	}
+
+	// license modules have no licenses, but license_kinds must refer to license_kind modules
+	if l, ok := m.(*licenseModule); ok {
+		mergeProps(&m.base().commonProperties.Effective_licenses, ctx.ModuleName())
+		mergeProps(&m.base().commonProperties.Effective_license_text, PathsForModuleSrc(ctx, l.properties.License_text).Strings()...)
+		for _, module := range ctx.GetDirectDepsWithTag(licenseKindTag) {
+			if lk, ok := module.(*licenseKindModule); ok {
+				mergeProps(&m.base().commonProperties.Effective_license_conditions, lk.properties.Conditions...)
+				mergeProps(&m.base().commonProperties.Effective_license_kinds, ctx.OtherModuleName(module))
+			} else {
+				ctx.ModuleErrorf("license_kinds property %q is not a license_kind module", ctx.OtherModuleName(module))
+			}
+		}
+		return
+	}
+
+	if exemptFromRequiredApplicableLicensesProperty(m) {
+		return
+	}
+
+	for _, module := range ctx.GetDirectDepsWithTag(licensesTag) {
+		if l, ok := module.(*licenseModule); ok {
+			if m.base().commonProperties.Effective_package_name == nil && l.properties.Package_name != nil {
+				m.base().commonProperties.Effective_package_name = l.properties.Package_name
+			}
+			mergeProps(&m.base().commonProperties.Effective_licenses, module.base().commonProperties.Effective_licenses...)
+			mergeProps(&m.base().commonProperties.Effective_license_text, module.base().commonProperties.Effective_license_text...)
+			mergeProps(&m.base().commonProperties.Effective_license_kinds, module.base().commonProperties.Effective_license_kinds...)
+			mergeProps(&m.base().commonProperties.Effective_license_conditions, module.base().commonProperties.Effective_license_conditions...)
+		} else {
+			propertyName := "licenses"
+			primaryProperty := m.base().primaryLicensesProperty
+			if primaryProperty != nil {
+				propertyName = primaryProperty.getName()
+			}
+			ctx.ModuleErrorf("%s property %q is not a license module", propertyName, ctx.OtherModuleName(module))
+		}
+	}
+}
+
+// Update a property string array with a distinct union of its values and a list of new values.
+func mergeProps(prop *[]string, values ...string) {
+	s := make(map[string]bool)
+	for _, v := range *prop {
+		s[v] = true
+	}
+	for _, v := range values {
+		s[v] = true
+	}
+	*prop = []string{}
+	*prop = append(*prop, SortedStringKeys(s)...)
+}
+
+// Get the licenses property falling back to the package default.
+func getLicenses(ctx BaseModuleContext, module Module) []string {
+	if exemptFromRequiredApplicableLicensesProperty(module) {
+		return nil
+	}
+
+	primaryProperty := module.base().primaryLicensesProperty
+	if primaryProperty == nil {
+		if ctx.Config().IsEnvTrue("ANDROID_REQUIRE_LICENSES") {
+			ctx.ModuleErrorf("module type %q must have an applicable licenses property", ctx.OtherModuleType(module))
+		}
+		return nil
+	}
+
+	licenses := primaryProperty.getStrings()
+	if len(licenses) > 0 {
+		s := make(map[string]bool)
+		for _, l := range licenses {
+			if _, ok := s[l]; ok {
+				ctx.ModuleErrorf("duplicate %q %s", l, primaryProperty.getName())
+			}
+			s[l] = true
+		}
+		return licenses
+	}
+
+	dir := ctx.OtherModuleDir(module)
+
+	moduleToApplicableLicenses := moduleToPackageDefaultLicensesMap(ctx.Config())
+	value, ok := moduleToApplicableLicenses.Load(dir)
+	var c licensesContainer
+	if ok {
+		c = value.(licensesContainer)
+	} else {
+		c = licensesContainer{}
+	}
+	return c.getLicenses()
+}
+
+// Returns whether a module is an allowed list of modules that do not have or need applicable licenses.
+func exemptFromRequiredApplicableLicensesProperty(module Module) bool {
+	switch reflect.TypeOf(module).String() {
+	case "*android.licenseModule": // is a license, doesn't need one
+	case "*android.licenseKindModule": // is a license, doesn't need one
+	case "*android.NamespaceModule": // just partitions things, doesn't add anything
+	case "*android.soongConfigModuleTypeModule": // creates aliases for modules with licenses
+	case "*android.soongConfigModuleTypeImport": // creates aliases for modules with licenses
+	case "*android.soongConfigStringVariableDummyModule": // used for creating aliases
+	case "*android.SoongConfigBoolVariableDummyModule": // used for creating aliases
+	default:
+		return false
+	}
+	return true
+}
diff --git a/android/module.go b/android/module.go
index a498839..6b00d79 100644
--- a/android/module.go
+++ b/android/module.go
@@ -94,6 +94,8 @@
 	GlobFiles(globPattern string, excludes []string) Paths
 	IsSymlink(path Path) bool
 	Readlink(path Path) string
+
+	Namespace() *Namespace
 }
 
 // BaseModuleContext is the same as blueprint.BaseModuleContext except that Config() returns
@@ -204,7 +206,6 @@
 	VisitAllModuleVariants(visit func(Module))
 
 	GetMissingDependencies() []string
-	Namespace() blueprint.Namespace
 }
 
 type Module interface {
@@ -231,6 +232,8 @@
 	InstallBypassMake() bool
 	SkipInstall()
 	IsSkipInstall() bool
+	ReplacedByPrebuilt()
+	IsReplacedByPrebuilt() bool
 	ExportedToMake() bool
 	InitRc() Paths
 	VintfFragments() Paths
@@ -300,6 +303,28 @@
 	return qualifiedModuleName{pkg: pkg, name: ""}
 }
 
+type Dist struct {
+	// Copy the output of this module to the $DIST_DIR when `dist` is specified on the
+	// command line and any of these targets are also on the command line, or otherwise
+	// built
+	Targets []string `android:"arch_variant"`
+
+	// The name of the output artifact. This defaults to the basename of the output of
+	// the module.
+	Dest *string `android:"arch_variant"`
+
+	// The directory within the dist directory to store the artifact. Defaults to the
+	// top level directory ("").
+	Dir *string `android:"arch_variant"`
+
+	// A suffix to add to the artifact file name (before any extension).
+	Suffix *string `android:"arch_variant"`
+
+	// A string tag to select the OutputFiles associated with the tag. Defaults to the
+	// the empty "" string.
+	Tag *string `android:"arch_variant"`
+}
+
 type nameProperties struct {
 	// The name of the module.  Must be unique across all modules.
 	Name *string
@@ -360,9 +385,20 @@
 	// more details.
 	Visibility []string
 
-	// Names of the licenses that apply to this module.
+	// Describes the licenses applicable to this module. Must reference license modules.
 	Licenses []string
 
+	// Flattened from direct license dependencies. Equal to Licenses unless particular module adds more.
+	Effective_licenses []string `blueprint:"mutated"`
+	// Override of module name when reporting licenses
+	Effective_package_name *string `blueprint:"mutated"`
+	// Notice files
+	Effective_license_text []string `blueprint:"mutated"`
+	// License names
+	Effective_license_kinds []string `blueprint:"mutated"`
+	// License conditions
+	Effective_license_conditions []string `blueprint:"mutated"`
+
 	// control whether this module compiles for 32-bit, 64-bit, or both.  Possible values
 	// are "32" (compile for 32-bit only), "64" (compile for 64-bit only), "both" (compile for both
 	// architectures), or "first" (compile for 64-bit on a 64-bit platform, and 32-bit on a 32-bit
@@ -442,24 +478,6 @@
 	// relative path to a file to include in the list of notices for the device
 	Notice *string `android:"path"`
 
-	Dist struct {
-		// copy the output of this module to the $DIST_DIR when `dist` is specified on the
-		// command line and  any of these targets are also on the command line, or otherwise
-		// built
-		Targets []string `android:"arch_variant"`
-
-		// The name of the output artifact. This defaults to the basename of the output of
-		// the module.
-		Dest *string `android:"arch_variant"`
-
-		// The directory within the dist directory to store the artifact. Defaults to the
-		// top level directory ("").
-		Dir *string `android:"arch_variant"`
-
-		// A suffix to add to the artifact file name (before any extension).
-		Suffix *string `android:"arch_variant"`
-	} `android:"arch_variant"`
-
 	// The OsType of artifacts that this module variant is responsible for creating.
 	//
 	// Set by osMutator
@@ -512,6 +530,9 @@
 
 	SkipInstall bool `blueprint:"mutated"`
 
+	// Whether the module has been replaced by a prebuilt
+	ReplacedByPrebuilt bool `blueprint:"mutated"`
+
 	NamespaceExportedToMake bool `blueprint:"mutated"`
 
 	MissingDeps []string `blueprint:"mutated"`
@@ -525,6 +546,30 @@
 	ImageVariation string `blueprint:"mutated"`
 }
 
+type distProperties struct {
+	// configuration to distribute output files from this module to the distribution
+	// directory (default: $OUT/dist, configurable with $DIST_DIR)
+	Dist Dist `android:"arch_variant"`
+
+	// a list of configurations to distribute output files from this module to the
+	// distribution directory (default: $OUT/dist, configurable with $DIST_DIR)
+	Dists []Dist `android:"arch_variant"`
+}
+
+// A map of OutputFile tag keys to Paths, for disting purposes.
+type TaggedDistFiles map[string]Paths
+
+func MakeDefaultDistFiles(paths ...Path) TaggedDistFiles {
+	for _, path := range paths {
+		if path == nil {
+			panic("The path to a dist file cannot be nil.")
+		}
+	}
+
+	// The default OutputFile tag is the empty "" string.
+	return TaggedDistFiles{"": paths}
+}
+
 type hostAndDeviceProperties struct {
 	// If set to true, build a variant of the module for the host.  Defaults to false.
 	Host_supported *bool
@@ -606,7 +651,8 @@
 
 	m.AddProperties(
 		&base.nameProperties,
-		&base.commonProperties)
+		&base.commonProperties,
+		&base.distProperties)
 
 	initProductVariableModule(m)
 
@@ -616,6 +662,10 @@
 	// The default_visibility property needs to be checked and parsed by the visibility module during
 	// its checking and parsing phases so make it the primary visibility property.
 	setPrimaryVisibilityProperty(m, "visibility", &base.commonProperties.Visibility)
+
+	// The default_applicable_licenses property needs to be checked and parsed by the licenses module during
+	// its checking and parsing phases so make it the primary licenses property.
+	setPrimaryLicensesProperty(m, "licenses", &base.commonProperties.Licenses)
 }
 
 func InitAndroidArchModule(m Module, hod HostOrDeviceSupported, defaultMultilib Multilib) {
@@ -697,6 +747,7 @@
 
 	nameProperties          nameProperties
 	commonProperties        commonProperties
+	distProperties          distProperties
 	variableProperties      interface{}
 	hostAndDeviceProperties hostAndDeviceProperties
 	generalProperties       []interface{}
@@ -710,6 +761,9 @@
 	// The primary visibility property, may be nil, that controls access to the module.
 	primaryVisibilityProperty visibilityProperty
 
+	// The primary licenses property, may be nil, records license metadata for the module.
+	primaryLicensesProperty applicableLicensesProperty
+
 	noAddressSanitizer bool
 	installFiles       Paths
 	checkbuildFiles    Paths
@@ -803,6 +857,41 @@
 	return m.visibilityPropertyInfo
 }
 
+func (m *ModuleBase) Dists() []Dist {
+	if len(m.distProperties.Dist.Targets) > 0 {
+		// Make a copy of the underlying Dists slice to protect against
+		// backing array modifications with repeated calls to this method.
+		distsCopy := append([]Dist(nil), m.distProperties.Dists...)
+		return append(distsCopy, m.distProperties.Dist)
+	} else {
+		return m.distProperties.Dists
+	}
+}
+
+func (m *ModuleBase) GenerateTaggedDistFiles(ctx BaseModuleContext) TaggedDistFiles {
+	distFiles := make(TaggedDistFiles)
+	for _, dist := range m.Dists() {
+		var tag string
+		var distFilesForTag Paths
+		if dist.Tag == nil {
+			tag = ""
+		} else {
+			tag = *dist.Tag
+		}
+		distFilesForTag, err := m.base().module.(OutputFileProducer).OutputFiles(tag)
+		if err != nil {
+			ctx.PropertyErrorf("dist.tag", "%s", err.Error())
+		}
+		for _, distFile := range distFilesForTag {
+			if distFile != nil && !distFiles[tag].containsPath(distFile) {
+				distFiles[tag] = append(distFiles[tag], distFile)
+			}
+		}
+	}
+
+	return distFiles
+}
+
 func (m *ModuleBase) Target() Target {
 	return m.commonProperties.CompileTarget
 }
@@ -959,6 +1048,15 @@
 	return m.commonProperties.SkipInstall == true
 }
 
+func (m *ModuleBase) ReplacedByPrebuilt() {
+	m.commonProperties.ReplacedByPrebuilt = true
+	m.SkipInstall()
+}
+
+func (m *ModuleBase) IsReplacedByPrebuilt() bool {
+	return m.commonProperties.ReplacedByPrebuilt
+}
+
 func (m *ModuleBase) ExportedToMake() bool {
 	return m.commonProperties.NamespaceExportedToMake
 }
@@ -1082,7 +1180,7 @@
 
 	var deps Paths
 
-	namespacePrefix := ctx.Namespace().(*Namespace).id
+	namespacePrefix := ctx.Namespace().id
 	if namespacePrefix != "" {
 		namespacePrefix = namespacePrefix + "-"
 	}
@@ -1238,20 +1336,20 @@
 	ctx.Variable(pctx, "moduleDescSuffix", s)
 
 	// Some common property checks for properties that will be used later in androidmk.go
-	if m.commonProperties.Dist.Dest != nil {
-		_, err := validateSafePath(*m.commonProperties.Dist.Dest)
+	if m.distProperties.Dist.Dest != nil {
+		_, err := validateSafePath(*m.distProperties.Dist.Dest)
 		if err != nil {
 			ctx.PropertyErrorf("dist.dest", "%s", err.Error())
 		}
 	}
-	if m.commonProperties.Dist.Dir != nil {
-		_, err := validateSafePath(*m.commonProperties.Dist.Dir)
+	if m.distProperties.Dist.Dir != nil {
+		_, err := validateSafePath(*m.distProperties.Dist.Dir)
 		if err != nil {
 			ctx.PropertyErrorf("dist.dir", "%s", err.Error())
 		}
 	}
-	if m.commonProperties.Dist.Suffix != nil {
-		if strings.Contains(*m.commonProperties.Dist.Suffix, "/") {
+	if m.distProperties.Dist.Suffix != nil {
+		if strings.Contains(*m.distProperties.Dist.Suffix, "/") {
 			ctx.PropertyErrorf("dist.suffix", "Suffix may not contain a '/' character.")
 		}
 	}
@@ -1267,11 +1365,16 @@
 		notice := proptools.StringDefault(m.commonProperties.Notice, "NOTICE")
 		if module := SrcIsModule(notice); module != "" {
 			m.noticeFile = ctx.ExpandOptionalSource(&notice, "notice")
-		} else {
+		} else if notice != "" {
 			noticePath := filepath.Join(ctx.ModuleDir(), notice)
 			m.noticeFile = ExistentPathForSource(ctx, noticePath)
 		}
 
+		licensesPropertyFlattener(ctx)
+		if ctx.Failed() {
+			return
+		}
+
 		m.module.GenerateAndroidBuildActions(ctx)
 		if ctx.Failed() {
 			return
@@ -1380,6 +1483,10 @@
 	return e.kind == systemExtSpecificModule
 }
 
+func (e *earlyModuleContext) Namespace() *Namespace {
+	return e.EarlyModuleContext.Namespace().(*Namespace)
+}
+
 type baseModuleContext struct {
 	bp blueprint.BaseModuleContext
 	earlyModuleContext
@@ -1734,6 +1841,16 @@
 	return m.bp.FinalModule().(Module)
 }
 
+// IsMetaDependencyTag returns true for cross-cutting metadata dependencies.
+func IsMetaDependencyTag(tag blueprint.DependencyTag) bool {
+	if tag == licenseKindTag {
+		return true
+	} else if tag == licensesTag {
+		return true
+	}
+	return false
+}
+
 func (m *moduleContext) ModuleSubDir() string {
 	return m.bp.ModuleSubDir()
 }
diff --git a/android/mutator.go b/android/mutator.go
index 77d5f43..49c6322 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -109,6 +109,11 @@
 	//
 	RegisterVisibilityRuleChecker,
 
+	// Record the default_applicable_licenses for each package.
+	//
+	// This must run before the defaults so that defaults modules can pick up the package default.
+	RegisterLicensesPackageMapper,
+
 	// Apply properties from defaults modules to the referencing modules.
 	//
 	// Any mutators that are added before this will not see any modules created by
@@ -123,6 +128,12 @@
 	// prebuilt.
 	RegisterPrebuiltsPreArchMutators,
 
+	// Gather the licenses properties for all modules for use during expansion and enforcement.
+	//
+	// This must come after the defaults mutators to ensure that any licenses supplied
+	// in a defaults module has been successfully applied before the rules are gathered.
+	RegisterLicensesPropertyGatherer,
+
 	// Gather the visibility rules for all modules for us during visibility enforcement.
 	//
 	// This must come after the defaults mutators to ensure that any visibility supplied
@@ -144,6 +155,7 @@
 	registerPathDepsMutator,
 	RegisterPrebuiltsPostDepsMutators,
 	RegisterVisibilityRuleEnforcer,
+	RegisterLicensesDependencyChecker,
 	RegisterNeverallowMutator,
 	RegisterOverridePostDepsMutators,
 }
diff --git a/android/neverallow.go b/android/neverallow.go
index 2eba4a9..620d616 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -51,7 +51,6 @@
 func init() {
 	AddNeverAllowRules(createIncludeDirsRules()...)
 	AddNeverAllowRules(createTrebleRules()...)
-	AddNeverAllowRules(createLibcoreRules()...)
 	AddNeverAllowRules(createMediaRules()...)
 	AddNeverAllowRules(createJavaDeviceForHostRules()...)
 	AddNeverAllowRules(createCcSdkVariantRules()...)
@@ -132,31 +131,6 @@
 	}
 }
 
-func createLibcoreRules() []Rule {
-	var coreLibraryProjects = []string{
-		"libcore",
-		"external/apache-harmony",
-		"external/apache-xml",
-		"external/bouncycastle",
-		"external/conscrypt",
-		"external/icu",
-		"external/okhttp",
-		"external/wycheproof",
-		"prebuilts",
-	}
-
-	// Core library constraints. The sdk_version: "none" can only be used in core library projects.
-	// Access to core library targets is restricted using visibility rules.
-	rules := []Rule{
-		NeverAllow().
-			NotIn(coreLibraryProjects...).
-			With("sdk_version", "none").
-			WithoutMatcher("name", Regexp("^android_.*stubs_current$")),
-	}
-
-	return rules
-}
-
 func createMediaRules() []Rule {
 	return []Rule{
 		NeverAllow().
@@ -187,6 +161,10 @@
 		// derive_sdk_prefer32 suppress the platform installation rules, but fails when
 		// the APEX modules contain the SDK variant and the platform variant still exists.
 		"frameworks/base/apex/sdkextensions/derive_sdk",
+
+		// libtextclassifier_tests needs to use the SDK variant so that the coverage data
+		// aligns with the usage in a mainline module. b/166040889
+		"external/libtextclassifier/native",
 	}
 
 	platformVariantPropertiesAllowedList := []string{
diff --git a/android/neverallow_test.go b/android/neverallow_test.go
index 45d36a6..b72ab8c 100644
--- a/android/neverallow_test.go
+++ b/android/neverallow_test.go
@@ -215,50 +215,6 @@
 			"java_device_for_host can only be used in allowed projects",
 		},
 	},
-	// Libcore rule tests
-	{
-		name: "sdk_version: \"none\" inside core libraries",
-		fs: map[string][]byte{
-			"libcore/Android.bp": []byte(`
-				java_library {
-					name: "inside_core_libraries",
-					sdk_version: "none",
-				}`),
-		},
-	},
-	{
-		name: "sdk_version: \"none\" on android_*stubs_current stub",
-		fs: map[string][]byte{
-			"frameworks/base/Android.bp": []byte(`
-				java_library {
-					name: "android_stubs_current",
-					sdk_version: "none",
-				}`),
-		},
-	},
-	{
-		name: "sdk_version: \"none\" outside core libraries",
-		fs: map[string][]byte{
-			"Android.bp": []byte(`
-				java_library {
-					name: "outside_core_libraries",
-					sdk_version: "none",
-				}`),
-		},
-		expectedErrors: []string{
-			"module \"outside_core_libraries\": violates neverallow",
-		},
-	},
-	{
-		name: "sdk_version: \"current\"",
-		fs: map[string][]byte{
-			"Android.bp": []byte(`
-				java_library {
-					name: "outside_core_libraries",
-					sdk_version: "current",
-				}`),
-		},
-	},
 	// CC sdk rule tests
 	{
 		name: `"sdk_variant_only" outside allowed list`,
diff --git a/android/override_module.go b/android/override_module.go
index 90ddf50..3d8b18b 100644
--- a/android/override_module.go
+++ b/android/override_module.go
@@ -302,3 +302,15 @@
 		}
 	}
 }
+
+// ModuleNameWithPossibleOverride returns the name of the OverrideModule that overrides the current
+// variant of this OverridableModule, or ctx.ModuleName() if this module is not an OverridableModule
+// or if this variant is not overridden.
+func ModuleNameWithPossibleOverride(ctx ModuleContext) string {
+	if overridable, ok := ctx.Module().(OverridableModule); ok {
+		if o := overridable.GetOverriddenBy(); o != "" {
+			return o
+		}
+	}
+	return ctx.ModuleName()
+}
diff --git a/android/package.go b/android/package.go
index 053fec2..7012fc7 100644
--- a/android/package.go
+++ b/android/package.go
@@ -31,7 +31,7 @@
 type packageProperties struct {
 	// Specifies the default visibility for all modules defined in this package.
 	Default_visibility []string
-	// Specifies the names of the default licenses for all modules defined in this package.
+	// Specifies the default license terms for all modules defined in this package.
 	Default_applicable_licenses []string
 }
 
@@ -70,5 +70,9 @@
 	// its checking and parsing phases so make it the primary visibility property.
 	setPrimaryVisibilityProperty(module, "default_visibility", &module.properties.Default_visibility)
 
+	// The default_applicable_licenses property needs to be checked and parsed by the licenses module during
+	// its checking and parsing phases so make it the primary licenses property.
+	setPrimaryLicensesProperty(module, "default_applicable_licenses", &module.properties.Default_applicable_licenses)
+
 	return module
 }
diff --git a/android/package_test.go b/android/package_test.go
index f25599c..9321ba8 100644
--- a/android/package_test.go
+++ b/android/package_test.go
@@ -17,9 +17,11 @@
 				package {
 					name: "package",
 					visibility: ["//visibility:private"],
+					licenses: ["license"],
 				}`),
 		},
 		expectedErrors: []string{
+			`top/Blueprints:5:14: unrecognized property "licenses"`,
 			`top/Blueprints:3:10: unrecognized property "name"`,
 			`top/Blueprints:4:16: unrecognized property "visibility"`,
 		},
@@ -47,7 +49,7 @@
 					default_applicable_licenses: ["license"],
 				}
 
-        package {
+			        package {
 				}`),
 		},
 		expectedErrors: []string{
diff --git a/android/paths.go b/android/paths.go
index ddbeed3..2e0b251 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -211,6 +211,15 @@
 // Paths is a slice of Path objects, with helpers to operate on the collection.
 type Paths []Path
 
+func (paths Paths) containsPath(path Path) bool {
+	for _, p := range paths {
+		if p == path {
+			return true
+		}
+	}
+	return false
+}
+
 // PathsForSource returns Paths rooted from SrcDir
 func PathsForSource(ctx PathContext, paths []string) Paths {
 	ret := make(Paths, len(paths))
@@ -396,7 +405,7 @@
 		p := pathForModuleSrc(ctx, s)
 		if exists, _, err := ctx.Config().fs.Exists(p.String()); err != nil {
 			reportPathErrorf(ctx, "%s: %s", p, err.Error())
-		} else if !exists && !ctx.Config().testAllowNonExistentPaths {
+		} else if !exists && !ctx.Config().TestAllowNonExistentPaths {
 			reportPathErrorf(ctx, "module source path %q does not exist", p)
 		}
 
@@ -771,7 +780,7 @@
 		}
 	} else if exists, _, err := ctx.Config().fs.Exists(path.String()); err != nil {
 		reportPathErrorf(ctx, "%s: %s", path, err.Error())
-	} else if !exists && !ctx.Config().testAllowNonExistentPaths {
+	} else if !exists && !ctx.Config().TestAllowNonExistentPaths {
 		reportPathErrorf(ctx, "source path %q does not exist", path)
 	}
 	return path
diff --git a/android/prebuilt.go b/android/prebuilt.go
index ee4a13a..8ad81e6 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -227,7 +227,7 @@
 			p := m.(PrebuiltInterface).Prebuilt()
 			if p.usePrebuilt(ctx, s) {
 				p.properties.UsePrebuilt = true
-				s.SkipInstall()
+				s.ReplacedByPrebuilt()
 			}
 		})
 	}
diff --git a/android/soong_config_modules_test.go b/android/soong_config_modules_test.go
index f905b1a..9677f34 100644
--- a/android/soong_config_modules_test.go
+++ b/android/soong_config_modules_test.go
@@ -19,8 +19,24 @@
 	"testing"
 )
 
+type soongConfigTestDefaultsModuleProperties struct {
+}
+
+type soongConfigTestDefaultsModule struct {
+	ModuleBase
+	DefaultsModuleBase
+}
+
+func soongConfigTestDefaultsModuleFactory() Module {
+	m := &soongConfigTestDefaultsModule{}
+	m.AddProperties(&soongConfigTestModuleProperties{})
+	InitDefaultsModule(m)
+	return m
+}
+
 type soongConfigTestModule struct {
 	ModuleBase
+	DefaultableModuleBase
 	props soongConfigTestModuleProperties
 }
 
@@ -32,6 +48,7 @@
 	m := &soongConfigTestModule{}
 	m.AddProperties(&m.props)
 	InitAndroidModule(m)
+	InitDefaultableModule(m)
 	return m
 }
 
@@ -40,13 +57,13 @@
 func TestSoongConfigModule(t *testing.T) {
 	configBp := `
 		soong_config_module_type {
-			name: "acme_test_defaults",
-			module_type: "test_defaults",
+			name: "acme_test",
+			module_type: "test",
 			config_namespace: "acme",
 			variables: ["board", "feature1", "FEATURE3"],
 			bool_variables: ["feature2"],
 			value_variables: ["size"],
-			properties: ["cflags", "srcs"],
+			properties: ["cflags", "srcs", "defaults"],
 		}
 
 		soong_config_string_variable {
@@ -66,14 +83,20 @@
 	importBp := `
 		soong_config_module_type_import {
 			from: "SoongConfig.bp",
-			module_types: ["acme_test_defaults"],
+			module_types: ["acme_test"],
 		}
 	`
 
 	bp := `
-		acme_test_defaults {
+		test_defaults {
+			name: "foo_defaults",
+			cflags: ["DEFAULT"],
+		}
+
+		acme_test {
 			name: "foo",
 			cflags: ["-DGENERIC"],
+			defaults: ["foo_defaults"],
 			soong_config_variables: {
 				board: {
 					soc_a: {
@@ -97,6 +120,46 @@
 				},
 			},
 		}
+
+		test_defaults {
+			name: "foo_defaults_a",
+			cflags: ["DEFAULT_A"],
+		}
+
+		test_defaults {
+			name: "foo_defaults_b",
+			cflags: ["DEFAULT_B"],
+		}
+
+		acme_test {
+			name: "foo_with_defaults",
+			cflags: ["-DGENERIC"],
+			defaults: ["foo_defaults"],
+			soong_config_variables: {
+				board: {
+					soc_a: {
+						cflags: ["-DSOC_A"],
+						defaults: ["foo_defaults_a"],
+					},
+					soc_b: {
+						cflags: ["-DSOC_B"],
+						defaults: ["foo_defaults_b"],
+					},
+				},
+				size: {
+					cflags: ["-DSIZE=%s"],
+				},
+				feature1: {
+					cflags: ["-DFEATURE1"],
+				},
+				feature2: {
+					cflags: ["-DFEATURE2"],
+				},
+				FEATURE3: {
+					cflags: ["-DFEATURE3"],
+				},
+			},
+		}
     `
 
 	run := func(t *testing.T, bp string, fs map[string][]byte) {
@@ -117,7 +180,9 @@
 		ctx.RegisterModuleType("soong_config_module_type", soongConfigModuleTypeFactory)
 		ctx.RegisterModuleType("soong_config_string_variable", soongConfigStringVariableDummyFactory)
 		ctx.RegisterModuleType("soong_config_bool_variable", soongConfigBoolVariableDummyFactory)
-		ctx.RegisterModuleType("test_defaults", soongConfigTestModuleFactory)
+		ctx.RegisterModuleType("test_defaults", soongConfigTestDefaultsModuleFactory)
+		ctx.RegisterModuleType("test", soongConfigTestModuleFactory)
+		ctx.PreArchMutators(RegisterDefaultsPreArchMutators)
 		ctx.Register(config)
 
 		_, errs := ctx.ParseBlueprintsFiles("Android.bp")
@@ -125,10 +190,18 @@
 		_, errs = ctx.PrepareBuildActions(config)
 		FailIfErrored(t, errs)
 
+		basicCFlags := []string{"DEFAULT", "-DGENERIC", "-DSIZE=42", "-DSOC_A", "-DFEATURE1"}
+
 		foo := ctx.ModuleForTests("foo", "").Module().(*soongConfigTestModule)
-		if g, w := foo.props.Cflags, []string{"-DGENERIC", "-DSIZE=42", "-DSOC_A", "-DFEATURE1"}; !reflect.DeepEqual(g, w) {
+		if g, w := foo.props.Cflags, basicCFlags; !reflect.DeepEqual(g, w) {
 			t.Errorf("wanted foo cflags %q, got %q", w, g)
 		}
+
+		fooDefaults := ctx.ModuleForTests("foo_with_defaults", "").Module().(*soongConfigTestModule)
+		if g, w := fooDefaults.props.Cflags, append([]string{"DEFAULT_A"}, basicCFlags...); !reflect.DeepEqual(g, w) {
+			t.Errorf("wanted foo_with_defaults cflags %q, got %q", w, g)
+		}
+
 	}
 
 	t.Run("single file", func(t *testing.T) {
diff --git a/apex/Android.bp b/apex/Android.bp
index 144f441..1a5f683 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -5,6 +5,7 @@
         "blueprint",
         "soong",
         "soong-android",
+        "soong-bpf",
         "soong-cc",
         "soong-java",
         "soong-python",
diff --git a/apex/OWNERS b/apex/OWNERS
index a382ae8..8e4ba5c 100644
--- a/apex/OWNERS
+++ b/apex/OWNERS
@@ -1 +1 @@
-per-file * = jiyong@google.com
\ No newline at end of file
+per-file * = jiyong@google.com
diff --git a/apex/androidmk.go b/apex/androidmk.go
index e4cdef0..66f4dc8 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -79,10 +79,6 @@
 	}
 
 	for _, fi := range a.filesInfo {
-		if ccMod, ok := fi.module.(*cc.Module); ok && ccMod.Properties.HideFromMake {
-			continue
-		}
-
 		linkToSystemLib := a.linkToSystemLib && fi.transitiveDep && fi.AvailableToPlatform()
 
 		var moduleName string
@@ -254,7 +250,7 @@
 	return moduleNames
 }
 
-func (a *apexBundle) writeRequiredModules(w io.Writer) {
+func (a *apexBundle) writeRequiredModules(w io.Writer, apexBundleName string) {
 	var required []string
 	var targetRequired []string
 	var hostRequired []string
@@ -293,7 +289,7 @@
 				if len(moduleNames) > 0 {
 					fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", strings.Join(moduleNames, " "))
 				}
-				a.writeRequiredModules(w)
+				a.writeRequiredModules(w, name)
 				fmt.Fprintln(w, "include $(BUILD_PHONY_PACKAGE)")
 
 			} else {
@@ -312,7 +308,7 @@
 				if len(a.requiredDeps) > 0 {
 					fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES +=", strings.Join(a.requiredDeps, " "))
 				}
-				a.writeRequiredModules(w)
+				a.writeRequiredModules(w, name)
 				var postInstallCommands []string
 				if a.prebuiltFileToDelete != "" {
 					postInstallCommands = append(postInstallCommands, "rm -rf "+
@@ -345,6 +341,24 @@
 					fmt.Fprintf(w, "$(call dist-for-goals,%s,%s:%s)\n",
 						goal, a.installedFilesFile.String(), distFile)
 				}
+
+				if a.apisUsedByModuleFile.String() != "" {
+					goal := "apps_only"
+					distFile := a.apisUsedByModuleFile.String()
+					fmt.Fprintf(w, "ifneq (,$(filter $(my_register_name),$(TARGET_BUILD_APPS)))\n"+
+						" $(call dist-for-goals,%s,%s:ndk_apis_usedby_apex/$(notdir %s))\n"+
+						"endif\n",
+						goal, distFile, distFile)
+				}
+
+				if a.apisBackedByModuleFile.String() != "" {
+					goal := "apps_only"
+					distFile := a.apisBackedByModuleFile.String()
+					fmt.Fprintf(w, "ifneq (,$(filter $(my_register_name),$(TARGET_BUILD_APPS)))\n"+
+						" $(call dist-for-goals,%s,%s:ndk_apis_backedby_apex/$(notdir %s))\n"+
+						"endif\n",
+						goal, distFile, distFile)
+				}
 			}
 		}}
 }
diff --git a/apex/apex.go b/apex/apex.go
index 7da8e1c..e4b0525 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -28,6 +28,7 @@
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
+	"android/soong/bpf"
 	"android/soong/cc"
 	prebuilt_etc "android/soong/etc"
 	"android/soong/java"
@@ -63,6 +64,7 @@
 	certificateTag = dependencyTag{name: "certificate"}
 	usesTag        = dependencyTag{name: "uses"}
 	androidAppTag  = dependencyTag{name: "androidApp", payload: true}
+	bpfTag         = dependencyTag{name: "bpf", payload: true}
 
 	apexAvailBaseline = makeApexAvailableBaseline()
 
@@ -1062,6 +1064,9 @@
 	// List of tests that are embedded inside this APEX bundle
 	Tests []string
 
+	// List of BPF programs inside APEX
+	Bpfs []string
+
 	// Name of the apex_key module that provides the private key to sign APEX
 	Key *string
 
@@ -1268,6 +1273,8 @@
 	lintDepSets             java.LintDepSets // only for javalibs and apps
 	certificate             java.Certificate // only for apps
 	overriddenPackageName   string           // only for apps
+
+	noticeFile android.OptionalPath
 }
 
 func newApexFile(ctx android.BaseModuleContext, builtFile android.Path, moduleName string, installDir string, class apexFileClass, module android.Module) apexFile {
@@ -1283,6 +1290,7 @@
 		ret.requiredModuleNames = module.RequiredModuleNames()
 		ret.targetRequiredModuleNames = module.TargetRequiredModuleNames()
 		ret.hostRequiredModuleNames = module.HostRequiredModuleNames()
+		ret.noticeFile = module.NoticeFile()
 	}
 	return ret
 }
@@ -1391,6 +1399,10 @@
 
 	// Optional list of lint report zip files for apexes that contain java or app modules
 	lintReports android.Paths
+
+	// Path of API coverage generate files
+	apisUsedByModuleFile   android.ModuleOutPath
+	apisBackedByModuleFile android.ModuleOutPath
 }
 
 func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext,
@@ -1552,6 +1564,9 @@
 	ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(),
 		javaLibTag, a.properties.Java_libs...)
 
+	ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(),
+		bpfTag, a.properties.Bpfs...)
+
 	// With EMMA_INSTRUMENT_FRAMEWORK=true the ART boot image includes jacoco library.
 	if a.artApex && ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") {
 		ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(),
@@ -1813,6 +1828,11 @@
 	return af
 }
 
+func apexFileForBpfProgram(ctx android.BaseModuleContext, builtFile android.Path, bpfProgram bpf.BpfModule) apexFile {
+	dirInApex := filepath.Join("etc", "bpf")
+	return newApexFile(ctx, builtFile, builtFile.Base(), dirInApex, etc, bpfProgram)
+}
+
 // Context "decorator", overriding the InstallBypassMake method to always reply `true`.
 type flattenedApexContext struct {
 	android.ModuleContext
@@ -2079,6 +2099,15 @@
 				} else {
 					ctx.PropertyErrorf("apps", "%q is not an android_app module", depName)
 				}
+			case bpfTag:
+				if bpfProgram, ok := child.(bpf.BpfModule); ok {
+					filesToCopy, _ := bpfProgram.OutputFiles("")
+					for _, bpfFile := range filesToCopy {
+						filesInfo = append(filesInfo, apexFileForBpfProgram(ctx, bpfFile, bpfProgram))
+					}
+				} else {
+					ctx.PropertyErrorf("bpfs", "%q is not a bpf module", depName)
+				}
 			case prebuiltTag:
 				if prebuilt, ok := child.(prebuilt_etc.PrebuiltEtcModule); ok {
 					filesInfo = append(filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, depName))
diff --git a/apex/apex_singleton.go b/apex/apex_singleton.go
index 83a56a2..1ac2e5c 100644
--- a/apex/apex_singleton.go
+++ b/apex/apex_singleton.go
@@ -27,39 +27,81 @@
 }
 
 type apexDepsInfoSingleton struct {
-	// Output file with all flatlists from updatable modules' deps-info combined
-	updatableFlatListsPath android.OutputPath
+	allowedApexDepsInfoCheckResult android.OutputPath
 }
 
 func apexDepsInfoSingletonFactory() android.Singleton {
 	return &apexDepsInfoSingleton{}
 }
 
-var combineFilesRule = pctx.AndroidStaticRule("combineFilesRule",
-	blueprint.RuleParams{
-		Command:        "cat $out.rsp | xargs cat > $out",
+var (
+	// Generate new apex allowed_deps.txt by merging all internal dependencies.
+	generateApexDepsInfoFilesRule = pctx.AndroidStaticRule("generateApexDepsInfoFilesRule", blueprint.RuleParams{
+		Command: "cat $out.rsp | xargs cat" +
+			// Only track non-external dependencies, i.e. those that end up in the binary
+			" | grep -v '(external)'" +
+			// Ignore comments in any of the files
+			" | grep -v '^#'" +
+			" | sort -u -f >$out",
 		Rspfile:        "$out.rsp",
 		RspfileContent: "$in",
-	},
+	})
+
+	// Diff two given lists while ignoring comments in the allowed deps file.
+	diffAllowedApexDepsInfoRule = pctx.AndroidStaticRule("diffAllowedApexDepsInfoRule", blueprint.RuleParams{
+		Description: "Diff ${allowed_deps} and ${new_allowed_deps}",
+		Command: `
+			if grep -v '^#' ${allowed_deps} | diff -B - ${new_allowed_deps}; then
+			   touch ${out};
+			else
+				echo -e "\n******************************";
+				echo "ERROR: go/apex-allowed-deps-error";
+				echo "******************************";
+				echo "Detected changes to allowed dependencies in updatable modules.";
+				echo "To fix and update packages/modules/common/build/allowed_deps.txt, please run:";
+				echo "$$ (croot && packages/modules/common/build/update-apex-allowed-deps.sh)";
+				echo "Members of mainline-modularization@google.com will review the changes.";
+				echo -e "******************************\n";
+				exit 1;
+			fi;
+		`,
+	}, "allowed_deps", "new_allowed_deps")
 )
 
 func (s *apexDepsInfoSingleton) GenerateBuildActions(ctx android.SingletonContext) {
 	updatableFlatLists := android.Paths{}
 	ctx.VisitAllModules(func(module android.Module) {
 		if binaryInfo, ok := module.(android.ApexBundleDepsInfoIntf); ok {
-			if path := binaryInfo.FlatListPath(); path != nil {
-				if binaryInfo.Updatable() {
-					updatableFlatLists = append(updatableFlatLists, path)
-				}
+			if path := binaryInfo.FlatListPath(); path != nil && binaryInfo.Updatable() {
+				updatableFlatLists = append(updatableFlatLists, path)
 			}
 		}
 	})
 
-	s.updatableFlatListsPath = android.PathForOutput(ctx, "apex", "depsinfo", "updatable-flatlists.txt")
+	allowedDeps := android.ExistentPathForSource(ctx, "packages/modules/common/build/allowed_deps.txt").Path()
+
+	newAllowedDeps := android.PathForOutput(ctx, "apex", "depsinfo", "new-allowed-deps.txt")
 	ctx.Build(pctx, android.BuildParams{
-		Rule:        combineFilesRule,
-		Description: "Generate " + s.updatableFlatListsPath.String(),
-		Inputs:      updatableFlatLists,
-		Output:      s.updatableFlatListsPath,
+		Rule:   generateApexDepsInfoFilesRule,
+		Inputs: append(updatableFlatLists, allowedDeps),
+		Output: newAllowedDeps,
 	})
+
+	s.allowedApexDepsInfoCheckResult = android.PathForOutput(ctx, newAllowedDeps.Rel()+".check")
+	ctx.Build(pctx, android.BuildParams{
+		Rule:   diffAllowedApexDepsInfoRule,
+		Input:  newAllowedDeps,
+		Output: s.allowedApexDepsInfoCheckResult,
+		Args: map[string]string{
+			"allowed_deps":     allowedDeps.String(),
+			"new_allowed_deps": newAllowedDeps.String(),
+		},
+	})
+
+	ctx.Phony("apex-allowed-deps-check", s.allowedApexDepsInfoCheckResult)
+}
+
+func (s *apexDepsInfoSingleton) MakeVars(ctx android.MakeVarsContext) {
+	// Export check result to Make. The path is added to droidcore.
+	ctx.Strict("APEX_ALLOWED_DEPS_CHECK", s.allowedApexDepsInfoCheckResult.String())
 }
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 8803a5f..3442b6d 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -27,6 +27,7 @@
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
+	"android/soong/bpf"
 	"android/soong/cc"
 	"android/soong/dexpreopt"
 	prebuilt_etc "android/soong/etc"
@@ -232,6 +233,7 @@
 	java.RegisterAppBuildComponents(ctx)
 	java.RegisterSdkLibraryBuildComponents(ctx)
 	ctx.RegisterSingletonType("apex_keys_text", apexKeysTextFactory)
+	ctx.RegisterModuleType("bpf", bpf.BpfFactory)
 
 	ctx.PreDepsMutators(RegisterPreDepsMutators)
 	ctx.PostDepsMutators(RegisterPostDepsMutators)
@@ -533,18 +535,16 @@
 	ensureListContains(t, noticeInputs, "custom_notice_for_static_lib")
 
 	fullDepsInfo := strings.Split(ctx.ModuleForTests("myapex", "android_common_myapex_image").Output("depsinfo/fulllist.txt").Args["content"], "\\n")
-	ensureListContains(t, fullDepsInfo, "myjar(minSdkVersion:(no version)) <- myapex")
-	ensureListContains(t, fullDepsInfo, "mylib(minSdkVersion:(no version)) <- myapex")
-	ensureListContains(t, fullDepsInfo, "mylib2(minSdkVersion:(no version)) <- mylib")
-	ensureListContains(t, fullDepsInfo, "myotherjar(minSdkVersion:(no version)) <- myjar")
-	ensureListContains(t, fullDepsInfo, "mysharedjar(minSdkVersion:(no version)) (external) <- myjar")
+	ensureListContains(t, fullDepsInfo, "  myjar(minSdkVersion:(no version)) <- myapex")
+	ensureListContains(t, fullDepsInfo, "  mylib2(minSdkVersion:(no version)) <- mylib")
+	ensureListContains(t, fullDepsInfo, "  myotherjar(minSdkVersion:(no version)) <- myjar")
+	ensureListContains(t, fullDepsInfo, "  mysharedjar(minSdkVersion:(no version)) (external) <- myjar")
 
 	flatDepsInfo := strings.Split(ctx.ModuleForTests("myapex", "android_common_myapex_image").Output("depsinfo/flatlist.txt").Args["content"], "\\n")
-	ensureListContains(t, flatDepsInfo, "  myjar(minSdkVersion:(no version))")
-	ensureListContains(t, flatDepsInfo, "  mylib(minSdkVersion:(no version))")
-	ensureListContains(t, flatDepsInfo, "  mylib2(minSdkVersion:(no version))")
-	ensureListContains(t, flatDepsInfo, "  myotherjar(minSdkVersion:(no version))")
-	ensureListContains(t, flatDepsInfo, "  mysharedjar(minSdkVersion:(no version)) (external)")
+	ensureListContains(t, flatDepsInfo, "myjar(minSdkVersion:(no version))")
+	ensureListContains(t, flatDepsInfo, "mylib2(minSdkVersion:(no version))")
+	ensureListContains(t, flatDepsInfo, "myotherjar(minSdkVersion:(no version))")
+	ensureListContains(t, flatDepsInfo, "mysharedjar(minSdkVersion:(no version)) (external)")
 }
 
 func TestDefaults(t *testing.T) {
@@ -556,6 +556,7 @@
 			native_shared_libs: ["mylib"],
 			java_libs: ["myjar"],
 			apps: ["AppFoo"],
+			bpfs: ["bpf"],
 		}
 
 		prebuilt_etc {
@@ -596,12 +597,20 @@
 			system_modules: "none",
 			apex_available: [ "myapex" ],
 		}
+
+		bpf {
+			name: "bpf",
+			srcs: ["bpf.c", "bpf2.c"],
+		}
+
 	`)
 	ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
 		"etc/myetc",
 		"javalib/myjar.jar",
 		"lib64/mylib.so",
 		"app/AppFoo/AppFoo.apk",
+		"etc/bpf/bpf.o",
+		"etc/bpf/bpf2.o",
 	})
 }
 
@@ -846,14 +855,10 @@
 	ensureNotContains(t, libFooStubsLdFlags, "libbar.so")
 
 	fullDepsInfo := strings.Split(ctx.ModuleForTests("myapex2", "android_common_myapex2_image").Output("depsinfo/fulllist.txt").Args["content"], "\\n")
-	ensureListContains(t, fullDepsInfo, "mylib(minSdkVersion:(no version)) <- myapex2")
-	ensureListContains(t, fullDepsInfo, "libbaz(minSdkVersion:(no version)) <- mylib")
-	ensureListContains(t, fullDepsInfo, "libfoo(minSdkVersion:(no version)) (external) <- mylib")
+	ensureListContains(t, fullDepsInfo, "  libfoo(minSdkVersion:(no version)) (external) <- mylib")
 
 	flatDepsInfo := strings.Split(ctx.ModuleForTests("myapex2", "android_common_myapex2_image").Output("depsinfo/flatlist.txt").Args["content"], "\\n")
-	ensureListContains(t, flatDepsInfo, "  mylib(minSdkVersion:(no version))")
-	ensureListContains(t, flatDepsInfo, "  libbaz(minSdkVersion:(no version))")
-	ensureListContains(t, flatDepsInfo, "  libfoo(minSdkVersion:(no version)) (external)")
+	ensureListContains(t, flatDepsInfo, "libfoo(minSdkVersion:(no version)) (external)")
 }
 
 func TestApexWithRuntimeLibsDependency(t *testing.T) {
diff --git a/apex/builder.go b/apex/builder.go
index 8573dc0..47ced77 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -36,6 +36,7 @@
 
 func init() {
 	pctx.Import("android/soong/android")
+	pctx.Import("android/soong/cc/config")
 	pctx.Import("android/soong/java")
 	pctx.HostBinToolVariable("apexer", "apexer")
 	// ART minimal builds (using the master-art manifest) do not have the "frameworks/base"
@@ -62,6 +63,7 @@
 	pctx.HostBinToolVariable("jsonmodify", "jsonmodify")
 	pctx.HostBinToolVariable("conv_apex_manifest", "conv_apex_manifest")
 	pctx.HostBinToolVariable("extract_apks", "extract_apks")
+	pctx.SourcePathVariable("genNdkUsedbyApexPath", "build/soong/scripts/gen_ndk_usedby_apex.sh")
 }
 
 var (
@@ -172,6 +174,12 @@
 			`exit 1); touch ${out}`,
 		Description: "Diff ${image_content_file} and ${allowed_files_file}",
 	}, "image_content_file", "allowed_files_file", "apex_module_name")
+
+	generateAPIsUsedbyApexRule = pctx.StaticRule("generateAPIsUsedbyApexRule", blueprint.RuleParams{
+		Command:     "$genNdkUsedbyApexPath ${image_dir} ${readelf} ${out}",
+		CommandDeps: []string{"${genNdkUsedbyApexPath}"},
+		Description: "Generate symbol list used by Apex",
+	}, "image_dir", "readelf")
 )
 
 func (a *apexBundle) buildManifest(ctx android.ModuleContext, provideNativeLibs, requireNativeLibs []string) {
@@ -237,6 +245,12 @@
 		return true
 	})
 
+	for _, fi := range a.filesInfo {
+		if fi.noticeFile.Valid() {
+			noticeFiles = append(noticeFiles, fi.noticeFile.Path())
+		}
+	}
+
 	if len(noticeFiles) == 0 {
 		return android.NoticeOutputs{}
 	}
@@ -463,13 +477,10 @@
 			optFlags = append(optFlags, "--android_manifest "+androidManifestFile.String())
 		}
 
-		targetSdkVersion := ctx.Config().DefaultAppTargetSdk()
-		// TODO(b/157078772): propagate min_sdk_version to apexer.
-		minSdkVersion := ctx.Config().DefaultAppTargetSdk()
-
-		if a.minSdkVersion(ctx) == android.SdkVersion_Android10 {
-			minSdkVersion = strconv.Itoa(a.minSdkVersion(ctx))
-		}
+		minSdkVersion := strconv.Itoa(a.minSdkVersion(ctx))
+		// apex module doesn't have a concept of target_sdk_version, hence for the time being
+		// targetSdkVersion == default targetSdkVersion of the branch.
+		targetSdkVersion := strconv.Itoa(ctx.Config().DefaultAppTargetSdkInt())
 
 		if java.UseApiFingerprint(ctx) {
 			targetSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", java.ApiFingerprintPath(ctx).String())
@@ -547,6 +558,39 @@
 			Description: "apex proto convert",
 		})
 
+		implicitInputs = append(implicitInputs, unsignedOutputFile)
+
+		// Run coverage analysis
+		apisUsedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_using.txt")
+		ctx.Build(pctx, android.BuildParams{
+			Rule:        generateAPIsUsedbyApexRule,
+			Implicits:   implicitInputs,
+			Description: "coverage",
+			Output:      apisUsedbyOutputFile,
+			Args: map[string]string{
+				"image_dir": imageDir.String(),
+				"readelf":   "${config.ClangBin}/llvm-readelf",
+			},
+		})
+		a.apisUsedByModuleFile = apisUsedbyOutputFile
+
+		var libNames []string
+		for _, f := range a.filesInfo {
+			if f.class == nativeSharedLib {
+				libNames = append(libNames, f.Stem())
+			}
+		}
+		apisBackedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_backing.txt")
+		ndkLibraryList := android.PathForSource(ctx, "system/core/rootdir/etc/public.libraries.android.txt")
+		rule := android.NewRuleBuilder()
+		rule.Command().
+			Tool(android.PathForSource(ctx, "build/soong/scripts/gen_ndk_backedby_apex.sh")).
+			Output(apisBackedbyOutputFile).
+			Input(ndkLibraryList).
+			Flags(libNames)
+		rule.Build(pctx, ctx, "ndk_backedby_list", "Generate API libraries backed by Apex")
+		a.apisBackedByModuleFile = apisBackedbyOutputFile
+
 		bundleConfig := a.buildBundleConfig(ctx)
 
 		ctx.Build(pctx, android.BuildParams{
@@ -715,6 +759,12 @@
 			return !externalDep
 		}
 
+		// Skip dependencies that are only available to APEXes; they are developed with updatability
+		// in mind and don't need manual approval.
+		if to.(android.ApexModule).NotAvailableForPlatform() {
+			return !externalDep
+		}
+
 		if info, exists := depInfos[to.Name()]; exists {
 			if !android.InList(from.Name(), info.From) {
 				info.From = append(info.From, from.Name())
diff --git a/bpf/bpf.go b/bpf/bpf.go
index 59d1502..4b52375 100644
--- a/bpf/bpf.go
+++ b/bpf/bpf.go
@@ -26,7 +26,7 @@
 )
 
 func init() {
-	android.RegisterModuleType("bpf", bpfFactory)
+	android.RegisterModuleType("bpf", BpfFactory)
 	pctx.Import("android/soong/cc/config")
 }
 
@@ -43,6 +43,13 @@
 		"ccCmd", "cFlags")
 )
 
+// BpfModule interface is used by the apex package to gather information from a bpf module.
+type BpfModule interface {
+	android.Module
+
+	OutputFiles(tag string) (android.Paths, error)
+}
+
 type BpfProperties struct {
 	Srcs         []string `android:"path"`
 	Cflags       []string
@@ -137,7 +144,7 @@
 
 var _ android.OutputFileProducer = (*bpf)(nil)
 
-func bpfFactory() android.Module {
+func BpfFactory() android.Module {
 	module := &bpf{}
 
 	module.AddProperties(&module.properties)
diff --git a/bpf/bpf_test.go b/bpf/bpf_test.go
index eeca057..d06d7d1 100644
--- a/bpf/bpf_test.go
+++ b/bpf/bpf_test.go
@@ -59,7 +59,7 @@
 
 func testContext(config android.Config) *android.TestContext {
 	ctx := cc.CreateTestContext()
-	ctx.RegisterModuleType("bpf", bpfFactory)
+	ctx.RegisterModuleType("bpf", BpfFactory)
 	ctx.Register(config)
 
 	return ctx
diff --git a/cc/androidmk.go b/cc/androidmk.go
index fede601..8208ea3 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -241,7 +241,10 @@
 		entries.Class = "HEADER_LIBRARIES"
 	}
 
-	entries.DistFile = library.distFile
+	if library.distFile != nil {
+		entries.DistFiles = android.MakeDefaultDistFiles(library.distFile)
+	}
+
 	entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
 		library.androidMkWriteExportedFlags(entries)
 		library.androidMkEntriesWriteAdditionalDependenciesForSourceAbiDiff(entries)
@@ -310,7 +313,7 @@
 	ctx.subAndroidMk(entries, binary.baseInstaller)
 
 	entries.Class = "EXECUTABLES"
-	entries.DistFile = binary.distFile
+	entries.DistFiles = binary.distFiles
 	entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
 		entries.SetString("LOCAL_SOONG_UNSTRIPPED_BINARY", binary.unstrippedOutputFile.String())
 		if len(binary.symlinks) > 0 {
@@ -335,8 +338,7 @@
 	entries.Class = "NATIVE_TESTS"
 	entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
 		if len(benchmark.Properties.Test_suites) > 0 {
-			entries.SetString("LOCAL_COMPATIBILITY_SUITE",
-				strings.Join(benchmark.Properties.Test_suites, " "))
+			entries.AddCompatibilityTestSuites(benchmark.Properties.Test_suites...)
 		}
 		if benchmark.testConfig != nil {
 			entries.SetString("LOCAL_FULL_TEST_CONFIG", benchmark.testConfig.String())
@@ -358,8 +360,7 @@
 	}
 	entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
 		if len(test.Properties.Test_suites) > 0 {
-			entries.SetString("LOCAL_COMPATIBILITY_SUITE",
-				strings.Join(test.Properties.Test_suites, " "))
+			entries.AddCompatibilityTestSuites(test.Properties.Test_suites...)
 		}
 		if test.testConfig != nil {
 			entries.SetString("LOCAL_FULL_TEST_CONFIG", test.testConfig.String())
diff --git a/cc/binary.go b/cc/binary.go
index 251b7f0..565cb8a 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -98,8 +98,8 @@
 	// Output archive of gcno coverage information
 	coverageOutputFile android.OptionalPath
 
-	// Location of the file that should be copied to dist dir when requested
-	distFile android.OptionalPath
+	// Location of the files that should be copied to dist dir when requested
+	distFiles android.TaggedDistFiles
 
 	post_install_cmds []string
 }
@@ -367,11 +367,11 @@
 			binary.injectVersionSymbol(ctx, outputFile, versionedOutputFile)
 		} else {
 			versionedOutputFile := android.PathForModuleOut(ctx, "versioned", fileName)
-			binary.distFile = android.OptionalPathForPath(versionedOutputFile)
+			binary.distFiles = android.MakeDefaultDistFiles(versionedOutputFile)
 
 			if binary.stripper.needsStrip(ctx) {
 				out := android.PathForModuleOut(ctx, "versioned-stripped", fileName)
-				binary.distFile = android.OptionalPathForPath(out)
+				binary.distFiles = android.MakeDefaultDistFiles(out)
 				binary.stripper.stripExecutableOrSharedLib(ctx, versionedOutputFile, out, builderFlags)
 			}
 
diff --git a/cc/library.go b/cc/library.go
index 3deb173..24c0629 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -365,7 +365,7 @@
 	unstrippedOutputFile android.Path
 
 	// Location of the file that should be copied to dist dir when requested
-	distFile android.OptionalPath
+	distFile android.Path
 
 	versionScriptPath android.ModuleGenPath
 
@@ -890,7 +890,7 @@
 			library.injectVersionSymbol(ctx, outputFile, versionedOutputFile)
 		} else {
 			versionedOutputFile := android.PathForModuleOut(ctx, "versioned", fileName)
-			library.distFile = android.OptionalPathForPath(versionedOutputFile)
+			library.distFile = versionedOutputFile
 			library.injectVersionSymbol(ctx, outputFile, versionedOutputFile)
 		}
 	}
@@ -984,11 +984,11 @@
 			library.injectVersionSymbol(ctx, outputFile, versionedOutputFile)
 		} else {
 			versionedOutputFile := android.PathForModuleOut(ctx, "versioned", fileName)
-			library.distFile = android.OptionalPathForPath(versionedOutputFile)
+			library.distFile = versionedOutputFile
 
 			if library.stripper.needsStrip(ctx) {
 				out := android.PathForModuleOut(ctx, "versioned-stripped", fileName)
-				library.distFile = android.OptionalPathForPath(out)
+				library.distFile = out
 				library.stripper.stripExecutableOrSharedLib(ctx, versionedOutputFile, out, builderFlags)
 			}
 
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index 8453413..ffe502a 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -174,7 +174,6 @@
 
 	met := metrics.New()
 	met.SetBuildDateTime(buildStarted)
-	met.SetBuildCommand(os.Args)
 
 	stat := &status.Status{}
 	defer stat.Finish()
diff --git a/java/Android.bp b/java/Android.bp
index 1fda7f7..f9ef551 100644
--- a/java/Android.bp
+++ b/java/Android.bp
@@ -57,6 +57,7 @@
         "device_host_converter_test.go",
         "dexpreopt_test.go",
         "dexpreopt_bootjars_test.go",
+        "hiddenapi_singleton_test.go",
         "java_test.go",
         "jdeps_test.go",
         "kotlin_test.go",
diff --git a/java/androidmk.go b/java/androidmk.go
index ae257d7..413988e 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -91,7 +91,7 @@
 	} else {
 		mainEntries = android.AndroidMkEntries{
 			Class:      "JAVA_LIBRARIES",
-			DistFile:   android.OptionalPathForPath(library.distFile),
+			DistFiles:  library.distFiles,
 			OutputFile: android.OptionalPathForPath(library.outputFile),
 			Include:    "$(BUILD_SYSTEM)/soong_java_prebuilt.mk",
 			ExtraEntries: []android.AndroidMkExtraEntriesFunc{
@@ -127,8 +127,11 @@
 						entries.AddStrings("LOCAL_ADDITIONAL_CHECKED_MODULE", library.additionalCheckedModules.Strings()...)
 					}
 
-					if library.proguardDictionary != nil {
-						entries.SetPath("LOCAL_SOONG_PROGUARD_DICT", library.proguardDictionary)
+					if library.dexer.proguardDictionary.Valid() {
+						entries.SetPath("LOCAL_SOONG_PROGUARD_DICT", library.dexer.proguardDictionary.Path())
+					}
+					if library.proguardUsageZip.Valid() {
+						entries.SetPath("LOCAL_SOONG_PROGUARD_USAGE_ZIP", library.proguardUsageZip.Path())
 					}
 					entries.SetString("LOCAL_MODULE_STEM", library.Stem())
 
@@ -148,9 +151,9 @@
 func testSuiteComponent(entries *android.AndroidMkEntries, test_suites []string) {
 	entries.SetString("LOCAL_MODULE_TAGS", "tests")
 	if len(test_suites) > 0 {
-		entries.AddStrings("LOCAL_COMPATIBILITY_SUITE", test_suites...)
+		entries.AddCompatibilityTestSuites(test_suites...)
 	} else {
-		entries.SetString("LOCAL_COMPATIBILITY_SUITE", "null-suite")
+		entries.AddCompatibilityTestSuites("null-suite")
 	}
 }
 
@@ -196,7 +199,7 @@
 				entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", !Bool(prebuilt.properties.Installable))
 				entries.SetPath("LOCAL_SOONG_HEADER_JAR", prebuilt.combinedClasspathFile)
 				entries.SetPath("LOCAL_SOONG_CLASSES_JAR", prebuilt.combinedClasspathFile)
-				entries.SetString("LOCAL_SDK_VERSION", prebuilt.sdkVersion().raw)
+				entries.SetString("LOCAL_SDK_VERSION", prebuilt.makeSdkVersion())
 				entries.SetString("LOCAL_MODULE_STEM", prebuilt.Stem())
 			},
 		},
@@ -332,8 +335,11 @@
 				if app.jacocoReportClassesFile != nil {
 					entries.SetPath("LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR", app.jacocoReportClassesFile)
 				}
-				if app.proguardDictionary != nil {
-					entries.SetPath("LOCAL_SOONG_PROGUARD_DICT", app.proguardDictionary)
+				if app.dexer.proguardDictionary.Valid() {
+					entries.SetPath("LOCAL_SOONG_PROGUARD_DICT", app.dexer.proguardDictionary.Path())
+				}
+				if app.proguardUsageZip.Valid() {
+					entries.SetPath("LOCAL_SOONG_PROGUARD_USAGE_ZIP", app.proguardUsageZip.Path())
 				}
 
 				if app.Name() == "framework-res" {
@@ -561,15 +567,21 @@
 	// are created in make if only the api txt file is being generated. This is
 	// needed because an invalid output file would prevent the make entries from
 	// being written.
+	//
+	// Note that dstubs.apiFile can be also be nil if WITHOUT_CHECKS_API is true.
 	// TODO(b/146727827): Revert when we do not need to generate stubs and API separately.
-	distFile := android.OptionalPathForPath(dstubs.apiFile)
+
+	var distFiles android.TaggedDistFiles
+	if dstubs.apiFile != nil {
+		distFiles = android.MakeDefaultDistFiles(dstubs.apiFile)
+	}
 	outputFile := android.OptionalPathForPath(dstubs.stubsSrcJar)
 	if !outputFile.Valid() {
-		outputFile = distFile
+		outputFile = android.OptionalPathForPath(dstubs.apiFile)
 	}
 	return []android.AndroidMkEntries{android.AndroidMkEntries{
 		Class:      "JAVA_LIBRARIES",
-		DistFile:   distFile,
+		DistFiles:  distFiles,
 		OutputFile: outputFile,
 		Include:    "$(BUILD_SYSTEM)/soong_droiddoc_prebuilt.mk",
 		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
diff --git a/java/androidmk_test.go b/java/androidmk_test.go
index 7daa624..49cc035 100644
--- a/java/androidmk_test.go
+++ b/java/androidmk_test.go
@@ -156,16 +156,157 @@
 		}
 	`)
 
-	without_tag_entries := android.AndroidMkEntriesForTest(t, config, "", ctx.ModuleForTests("foo_without_tag", "android_common").Module())
-	with_tag_entries := android.AndroidMkEntriesForTest(t, config, "", ctx.ModuleForTests("foo_with_tag", "android_common").Module())
+	withoutTagEntries := android.AndroidMkEntriesForTest(t, config, "", ctx.ModuleForTests("foo_without_tag", "android_common").Module())
+	withTagEntries := android.AndroidMkEntriesForTest(t, config, "", ctx.ModuleForTests("foo_with_tag", "android_common").Module())
 
-	if len(without_tag_entries) != 2 || len(with_tag_entries) != 2 {
-		t.Errorf("two mk entries per module expected, got %d and %d", len(without_tag_entries), len(with_tag_entries))
+	if len(withoutTagEntries) != 2 || len(withTagEntries) != 2 {
+		t.Errorf("two mk entries per module expected, got %d and %d", len(withoutTagEntries), len(withTagEntries))
 	}
-	if !with_tag_entries[0].DistFile.Valid() || !strings.Contains(with_tag_entries[0].DistFile.String(), "/javac/foo_with_tag.jar") {
-		t.Errorf("expected classes.jar DistFile, got %v", with_tag_entries[0].DistFile)
+	if len(withTagEntries[0].DistFiles[".jar"]) != 1 ||
+		!strings.Contains(withTagEntries[0].DistFiles[".jar"][0].String(), "/javac/foo_with_tag.jar") {
+		t.Errorf("expected DistFiles to contain classes.jar, got %v", withTagEntries[0].DistFiles)
 	}
-	if without_tag_entries[0].DistFile.Valid() {
-		t.Errorf("did not expect explicit DistFile, got %v", without_tag_entries[0].DistFile)
+	if len(withoutTagEntries[0].DistFiles[".jar"]) > 0 {
+		t.Errorf("did not expect explicit DistFile for .jar tag, got %v", withoutTagEntries[0].DistFiles[".jar"])
+	}
+}
+
+func TestDistWithDest(t *testing.T) {
+	ctx, config := testJava(t, `
+		java_library {
+			name: "foo",
+			srcs: ["a.java"],
+			compile_dex: true,
+			dist: {
+				targets: ["my_goal"],
+				dest: "my/custom/dest/dir",
+			},
+		}
+	`)
+
+	module := ctx.ModuleForTests("foo", "android_common").Module()
+	entries := android.AndroidMkEntriesForTest(t, config, "", module)
+	if len(entries) != 2 {
+		t.Errorf("Expected 2 AndroidMk entries, got %d", len(entries))
+	}
+
+	distStrings := entries[0].GetDistForGoals(module)
+
+	if len(distStrings) != 2 {
+		t.Errorf("Expected 2 entries for dist: PHONY and dist-for-goals, but got %q", distStrings)
+	}
+
+	if distStrings[0] != ".PHONY: my_goal\n" {
+		t.Errorf("Expected .PHONY entry to declare my_goal, but got: %s", distStrings[0])
+	}
+
+	if !strings.Contains(distStrings[1], "$(call dist-for-goals,my_goal") ||
+		!strings.Contains(distStrings[1], ".intermediates/foo/android_common/dex/foo.jar:my/custom/dest/dir") {
+		t.Errorf(
+			"Expected dist-for-goals entry to contain my_goal and new dest dir, but got: %s", distStrings[1])
+	}
+}
+
+func TestDistsWithAllProperties(t *testing.T) {
+	ctx, config := testJava(t, `
+		java_library {
+			name: "foo",
+			srcs: ["a.java"],
+			compile_dex: true,
+			dist: {
+				targets: ["baz"],
+			},
+			dists: [
+				{
+					targets: ["bar"],
+					tag: ".jar",
+					dest: "bar.jar",
+					dir: "bar/dir",
+					suffix: ".qux",
+				},
+			]
+		}
+	`)
+
+	module := ctx.ModuleForTests("foo", "android_common").Module()
+	entries := android.AndroidMkEntriesForTest(t, config, "", module)
+	if len(entries) != 2 {
+		t.Errorf("Expected 2 AndroidMk entries, got %d", len(entries))
+	}
+
+	distStrings := entries[0].GetDistForGoals(module)
+
+	if len(distStrings) != 4 {
+		t.Errorf("Expected 4 entries for dist: PHONY and dist-for-goals, but got %d", len(distStrings))
+	}
+
+	if distStrings[0] != ".PHONY: bar\n" {
+		t.Errorf("Expected .PHONY entry to declare bar, but got: %s", distStrings[0])
+	}
+
+	if !strings.Contains(distStrings[1], "$(call dist-for-goals,bar") ||
+		!strings.Contains(
+			distStrings[1],
+			".intermediates/foo/android_common/javac/foo.jar:bar/dir/bar.qux.jar") {
+		t.Errorf(
+			"Expected dist-for-goals entry to contain bar and new dest dir, but got: %s", distStrings[1])
+	}
+
+	if distStrings[2] != ".PHONY: baz\n" {
+		t.Errorf("Expected .PHONY entry to declare baz, but got: %s", distStrings[2])
+	}
+
+	if !strings.Contains(distStrings[3], "$(call dist-for-goals,baz") ||
+		!strings.Contains(distStrings[3], ".intermediates/foo/android_common/dex/foo.jar:foo.jar") {
+		t.Errorf(
+			"Expected dist-for-goals entry to contain my_other_goal and new dest dir, but got: %s",
+			distStrings[3])
+	}
+}
+
+func TestDistsWithTag(t *testing.T) {
+	ctx, config := testJava(t, `
+		java_library {
+			name: "foo_without_tag",
+			srcs: ["a.java"],
+			compile_dex: true,
+			dists: [
+				{
+					targets: ["hi"],
+				},
+			],
+		}
+		java_library {
+			name: "foo_with_tag",
+			srcs: ["a.java"],
+			compile_dex: true,
+			dists: [
+				{
+					targets: ["hi"],
+					tag: ".jar",
+				},
+			],
+		}
+	`)
+
+	moduleWithoutTag := ctx.ModuleForTests("foo_without_tag", "android_common").Module()
+	moduleWithTag := ctx.ModuleForTests("foo_with_tag", "android_common").Module()
+
+	withoutTagEntries := android.AndroidMkEntriesForTest(t, config, "", moduleWithoutTag)
+	withTagEntries := android.AndroidMkEntriesForTest(t, config, "", moduleWithTag)
+
+	if len(withoutTagEntries) != 2 || len(withTagEntries) != 2 {
+		t.Errorf("two mk entries per module expected, got %d and %d", len(withoutTagEntries), len(withTagEntries))
+	}
+
+	distFilesWithoutTag := withoutTagEntries[0].DistFiles
+	distFilesWithTag := withTagEntries[0].DistFiles
+
+	if len(distFilesWithTag[".jar"]) != 1 ||
+		!strings.Contains(distFilesWithTag[".jar"][0].String(), "/javac/foo_with_tag.jar") {
+		t.Errorf("expected foo_with_tag's .jar-tagged DistFiles to contain classes.jar, got %v", distFilesWithTag[".jar"])
+	}
+	if len(distFilesWithoutTag[".jar"]) > 0 {
+		t.Errorf("did not expect foo_without_tag's .jar-tagged DistFiles to contain files, but got %v", distFilesWithoutTag[".jar"])
 	}
 }
diff --git a/java/app.go b/java/app.go
index 2ec27f3..ff3b8a4 100755
--- a/java/app.go
+++ b/java/app.go
@@ -267,6 +267,9 @@
 
 	// the logging parent of this app.
 	Logging_parent *string
+
+	// Whether to rename the package in resources to the override name rather than the base name. Defaults to true.
+	Rename_resources_package *bool
 }
 
 // runtime_resource_overlay properties that can be overridden by override_runtime_resource_overlay
@@ -504,10 +507,23 @@
 		!a.IsForPlatform() || a.appProperties.AlwaysPackageNativeLibs
 }
 
+func generateAaptRenamePackageFlags(packageName string, renameResourcesPackage bool) []string {
+	aaptFlags := []string{"--rename-manifest-package " + packageName}
+	if renameResourcesPackage {
+		// Required to rename the package name in the resources table.
+		aaptFlags = append(aaptFlags, "--rename-resources-package "+packageName)
+	}
+	return aaptFlags
+}
+
 func (a *AndroidApp) OverriddenManifestPackageName() string {
 	return a.overriddenManifestPackageName
 }
 
+func (a *AndroidApp) renameResourcesPackage() bool {
+	return proptools.BoolDefault(a.overridableAppProperties.Rename_resources_package, true)
+}
+
 func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) {
 	a.aapt.usesNonSdkApis = Bool(a.Module.deviceProperties.Platform_apis)
 
@@ -540,7 +556,7 @@
 		if !overridden {
 			manifestPackageName = *a.overridableAppProperties.Package_name
 		}
-		aaptLinkFlags = append(aaptLinkFlags, "--rename-manifest-package "+manifestPackageName)
+		aaptLinkFlags = append(aaptLinkFlags, generateAaptRenamePackageFlags(manifestPackageName, a.renameResourcesPackage())...)
 		a.overriddenManifestPackageName = manifestPackageName
 	}
 
@@ -585,11 +601,11 @@
 
 func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) android.Path {
 	a.dexpreopter.installPath = a.installPath(ctx)
-	if a.deviceProperties.Uncompress_dex == nil {
+	if a.dexProperties.Uncompress_dex == nil {
 		// If the value was not force-set by the user, use reasonable default based on the module.
-		a.deviceProperties.Uncompress_dex = proptools.BoolPtr(a.shouldUncompressDex(ctx))
+		a.dexProperties.Uncompress_dex = proptools.BoolPtr(a.shouldUncompressDex(ctx))
 	}
-	a.dexpreopter.uncompressedDex = *a.deviceProperties.Uncompress_dex
+	a.dexpreopter.uncompressedDex = *a.dexProperties.Uncompress_dex
 	a.dexpreopter.enforceUsesLibs = a.usesLibrary.enforceUsesLibraries()
 	a.dexpreopter.usesLibs = a.usesLibrary.usesLibraryProperties.Uses_libs
 	a.dexpreopter.optionalUsesLibs = a.usesLibrary.presentOptionalUsesLibs(ctx)
@@ -922,6 +938,13 @@
 	depsInfo := android.DepNameToDepInfoMap{}
 	a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) {
 		depName := to.Name()
+
+		// Skip dependencies that are only available to APEXes; they are developed with updatability
+		// in mind and don't need manual approval.
+		if to.(android.ApexModule).NotAvailableForPlatform() {
+			return
+		}
+
 		if info, exist := depsInfo[depName]; exist {
 			info.From = append(info.From, from.Name())
 			info.IsExternal = info.IsExternal && externalDep
@@ -1001,8 +1024,8 @@
 func AndroidAppFactory() android.Module {
 	module := &AndroidApp{}
 
-	module.Module.deviceProperties.Optimize.EnabledByDefault = true
-	module.Module.deviceProperties.Optimize.Shrink = proptools.BoolPtr(true)
+	module.Module.dexProperties.Optimize.EnabledByDefault = true
+	module.Module.dexProperties.Optimize.Shrink = proptools.BoolPtr(true)
 
 	module.Module.properties.Instrument = true
 	module.Module.properties.Installable = proptools.BoolPtr(true)
@@ -1119,7 +1142,7 @@
 func AndroidTestFactory() android.Module {
 	module := &AndroidTest{}
 
-	module.Module.deviceProperties.Optimize.EnabledByDefault = true
+	module.Module.dexProperties.Optimize.EnabledByDefault = true
 
 	module.Module.properties.Instrument = true
 	module.Module.properties.Installable = proptools.BoolPtr(true)
@@ -1170,7 +1193,7 @@
 func AndroidTestHelperAppFactory() android.Module {
 	module := &AndroidTestHelperApp{}
 
-	module.Module.deviceProperties.Optimize.EnabledByDefault = true
+	module.Module.dexProperties.Optimize.EnabledByDefault = true
 
 	module.Module.properties.Installable = proptools.BoolPtr(true)
 	module.appProperties.Use_embedded_native_libs = proptools.BoolPtr(true)
@@ -1775,7 +1798,7 @@
 		if !overridden {
 			manifestPackageName = *r.overridableProperties.Package_name
 		}
-		aaptLinkFlags = append(aaptLinkFlags, "--rename-manifest-package "+manifestPackageName)
+		aaptLinkFlags = append(aaptLinkFlags, generateAaptRenamePackageFlags(manifestPackageName, false)...)
 	}
 	if r.overridableProperties.Target_package_name != nil {
 		aaptLinkFlags = append(aaptLinkFlags,
diff --git a/java/app_test.go b/java/app_test.go
index 8ef3152..620a8dd 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -1743,52 +1743,125 @@
 			base: "foo",
 			package_name: "org.dandroid.bp",
 		}
+
+		override_android_app {
+			name: "baz_no_rename_resources",
+			base: "foo",
+			package_name: "org.dandroid.bp",
+			rename_resources_package: false,
+		}
+
+		android_app {
+			name: "foo_no_rename_resources",
+			srcs: ["a.java"],
+			certificate: "expiredkey",
+			overrides: ["qux"],
+			rename_resources_package: false,
+			sdk_version: "current",
+		}
+
+		override_android_app {
+			name: "baz_base_no_rename_resources",
+			base: "foo_no_rename_resources",
+			package_name: "org.dandroid.bp",
+		}
+
+		override_android_app {
+			name: "baz_override_base_rename_resources",
+			base: "foo_no_rename_resources",
+			package_name: "org.dandroid.bp",
+			rename_resources_package: true,
+		}
 		`)
 
 	expectedVariants := []struct {
-		moduleName     string
-		variantName    string
-		apkName        string
-		apkPath        string
-		certFlag       string
-		lineageFlag    string
-		overrides      []string
-		aaptFlag       string
-		logging_parent string
+		name            string
+		moduleName      string
+		variantName     string
+		apkName         string
+		apkPath         string
+		certFlag        string
+		lineageFlag     string
+		overrides       []string
+		packageFlag     string
+		renameResources bool
+		logging_parent  string
 	}{
 		{
-			moduleName:     "foo",
-			variantName:    "android_common",
-			apkPath:        "/target/product/test_device/system/app/foo/foo.apk",
-			certFlag:       "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
-			lineageFlag:    "",
-			overrides:      []string{"qux"},
-			aaptFlag:       "",
-			logging_parent: "",
+			name:            "foo",
+			moduleName:      "foo",
+			variantName:     "android_common",
+			apkPath:         "/target/product/test_device/system/app/foo/foo.apk",
+			certFlag:        "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
+			lineageFlag:     "",
+			overrides:       []string{"qux"},
+			packageFlag:     "",
+			renameResources: false,
+			logging_parent:  "",
 		},
 		{
-			moduleName:     "bar",
-			variantName:    "android_common_bar",
-			apkPath:        "/target/product/test_device/system/app/bar/bar.apk",
-			certFlag:       "cert/new_cert.x509.pem cert/new_cert.pk8",
-			lineageFlag:    "--lineage lineage.bin",
-			overrides:      []string{"qux", "foo"},
-			aaptFlag:       "",
-			logging_parent: "bah",
+			name:            "foo",
+			moduleName:      "bar",
+			variantName:     "android_common_bar",
+			apkPath:         "/target/product/test_device/system/app/bar/bar.apk",
+			certFlag:        "cert/new_cert.x509.pem cert/new_cert.pk8",
+			lineageFlag:     "--lineage lineage.bin",
+			overrides:       []string{"qux", "foo"},
+			packageFlag:     "",
+			renameResources: false,
+			logging_parent:  "bah",
 		},
 		{
-			moduleName:     "baz",
-			variantName:    "android_common_baz",
-			apkPath:        "/target/product/test_device/system/app/baz/baz.apk",
-			certFlag:       "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
-			lineageFlag:    "",
-			overrides:      []string{"qux", "foo"},
-			aaptFlag:       "--rename-manifest-package org.dandroid.bp",
-			logging_parent: "",
+			name:            "foo",
+			moduleName:      "baz",
+			variantName:     "android_common_baz",
+			apkPath:         "/target/product/test_device/system/app/baz/baz.apk",
+			certFlag:        "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
+			lineageFlag:     "",
+			overrides:       []string{"qux", "foo"},
+			packageFlag:     "org.dandroid.bp",
+			renameResources: true,
+			logging_parent:  "",
+		},
+		{
+			name:            "foo",
+			moduleName:      "baz_no_rename_resources",
+			variantName:     "android_common_baz_no_rename_resources",
+			apkPath:         "/target/product/test_device/system/app/baz_no_rename_resources/baz_no_rename_resources.apk",
+			certFlag:        "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
+			lineageFlag:     "",
+			overrides:       []string{"qux", "foo"},
+			packageFlag:     "org.dandroid.bp",
+			renameResources: false,
+			logging_parent:  "",
+		},
+		{
+			name:            "foo_no_rename_resources",
+			moduleName:      "baz_base_no_rename_resources",
+			variantName:     "android_common_baz_base_no_rename_resources",
+			apkPath:         "/target/product/test_device/system/app/baz_base_no_rename_resources/baz_base_no_rename_resources.apk",
+			certFlag:        "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
+			lineageFlag:     "",
+			overrides:       []string{"qux", "foo_no_rename_resources"},
+			packageFlag:     "org.dandroid.bp",
+			renameResources: false,
+			logging_parent:  "",
+		},
+		{
+			name:            "foo_no_rename_resources",
+			moduleName:      "baz_override_base_rename_resources",
+			variantName:     "android_common_baz_override_base_rename_resources",
+			apkPath:         "/target/product/test_device/system/app/baz_override_base_rename_resources/baz_override_base_rename_resources.apk",
+			certFlag:        "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
+			lineageFlag:     "",
+			overrides:       []string{"qux", "foo_no_rename_resources"},
+			packageFlag:     "org.dandroid.bp",
+			renameResources: true,
+			logging_parent:  "",
 		},
 	}
 	for _, expected := range expectedVariants {
-		variant := ctx.ModuleForTests("foo", expected.variantName)
+		variant := ctx.ModuleForTests(expected.name, expected.variantName)
 
 		// Check the final apk name
 		outputs := variant.AllOutputs()
@@ -1834,9 +1907,12 @@
 		// Check the package renaming flag, if exists.
 		res := variant.Output("package-res.apk")
 		aapt2Flags := res.Args["flags"]
-		if !strings.Contains(aapt2Flags, expected.aaptFlag) {
-			t.Errorf("package renaming flag, %q is missing in aapt2 link flags, %q", expected.aaptFlag, aapt2Flags)
+		checkAapt2LinkFlag(t, aapt2Flags, "rename-manifest-package", expected.packageFlag)
+		expectedPackage := expected.packageFlag
+		if !expected.renameResources {
+			expectedPackage = ""
 		}
+		checkAapt2LinkFlag(t, aapt2Flags, "rename-resources-package", expectedPackage)
 	}
 }
 
@@ -1973,6 +2049,7 @@
 		res := variant.Output("package-res.apk")
 		aapt2Flags := res.Args["flags"]
 		checkAapt2LinkFlag(t, aapt2Flags, "rename-manifest-package", expected.packageFlag)
+		checkAapt2LinkFlag(t, aapt2Flags, "rename-resources-package", expected.packageFlag)
 		checkAapt2LinkFlag(t, aapt2Flags, "rename-instrumentation-target-package", expected.targetPackageFlag)
 	}
 }
@@ -3190,6 +3267,7 @@
 		res := variant.Output("package-res.apk")
 		aapt2Flags := res.Args["flags"]
 		checkAapt2LinkFlag(t, aapt2Flags, "rename-manifest-package", expected.packageFlag)
+		checkAapt2LinkFlag(t, aapt2Flags, "rename-resources-package", "")
 		checkAapt2LinkFlag(t, aapt2Flags, "rename-overlay-target-package", expected.targetPackageFlag)
 	}
 }
diff --git a/java/dex.go b/java/dex.go
index 9e61e95..dba2836 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -24,6 +24,61 @@
 	"android/soong/remoteexec"
 )
 
+type DexProperties struct {
+	// If set to true, compile dex regardless of installable.  Defaults to false.
+	Compile_dex *bool
+
+	// list of module-specific flags that will be used for dex compiles
+	Dxflags []string `android:"arch_variant"`
+
+	Optimize struct {
+		// If false, disable all optimization.  Defaults to true for android_app and android_test
+		// modules, false for java_library and java_test modules.
+		Enabled *bool
+		// True if the module containing this has it set by default.
+		EnabledByDefault bool `blueprint:"mutated"`
+
+		// If true, optimize for size by removing unused code.  Defaults to true for apps,
+		// false for libraries and tests.
+		Shrink *bool
+
+		// If true, optimize bytecode.  Defaults to false.
+		Optimize *bool
+
+		// If true, obfuscate bytecode.  Defaults to false.
+		Obfuscate *bool
+
+		// If true, do not use the flag files generated by aapt that automatically keep
+		// classes referenced by the app manifest.  Defaults to false.
+		No_aapt_flags *bool
+
+		// Flags to pass to proguard.
+		Proguard_flags []string
+
+		// Specifies the locations of files containing proguard flags.
+		Proguard_flags_files []string `android:"path"`
+	}
+
+	// Keep the data uncompressed. We always need uncompressed dex for execution,
+	// so this might actually save space by avoiding storing the same data twice.
+	// This defaults to reasonable value based on module and should not be set.
+	// It exists only to support ART tests.
+	Uncompress_dex *bool
+}
+
+type dexer struct {
+	dexProperties DexProperties
+
+	// list of extra proguard flag files
+	extraProguardFlagFiles android.Paths
+	proguardDictionary     android.OptionalPath
+	proguardUsageZip       android.OptionalPath
+}
+
+func (d *dexer) effectiveOptimizeEnabled() bool {
+	return BoolDefault(d.dexProperties.Optimize.Enabled, d.dexProperties.Optimize.EnabledByDefault)
+}
+
 var d8, d8RE = remoteexec.MultiCommandStaticRules(pctx, "d8",
 	blueprint.RuleParams{
 		Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` +
@@ -55,13 +110,17 @@
 var r8, r8RE = remoteexec.MultiCommandStaticRules(pctx, "r8",
 	blueprint.RuleParams{
 		Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` +
-			`rm -f "$outDict" && ` +
+			`rm -f "$outDict" && rm -rf "${outUsageDir}" && ` +
+			`mkdir -p $$(dirname ${outUsage}) && ` +
 			`$r8Template${config.R8Cmd} ${config.DexFlags} -injars $in --output $outDir ` +
 			`--force-proguard-compatibility ` +
 			`--no-data-resources ` +
-			`-printmapping $outDict ` +
+			`-printmapping ${outDict} ` +
+			`-printusage ${outUsage} ` +
 			`$r8Flags && ` +
-			`touch "$outDict" && ` +
+			`touch "${outDict}" "${outUsage}" && ` +
+			`${config.SoongZipCmd} -o ${outUsageZip} -C ${outUsageDir} -f ${outUsage} && ` +
+			`rm -rf ${outUsageDir} && ` +
 			`$zipTemplate${config.SoongZipCmd} $zipFlags -o $outDir/classes.dex.jar -C $outDir -f "$outDir/classes*.dex" && ` +
 			`${config.MergeZipsCmd} -D -stripFile "**/*.class" $out $outDir/classes.dex.jar $in`,
 		CommandDeps: []string{
@@ -84,10 +143,18 @@
 			ExecStrategy: "${config.RER8ExecStrategy}",
 			Platform:     map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
 		},
-	}, []string{"outDir", "outDict", "r8Flags", "zipFlags"}, []string{"implicits"})
+		"$zipUsageTemplate": &remoteexec.REParams{
+			Labels:       map[string]string{"type": "tool", "name": "soong_zip"},
+			Inputs:       []string{"${config.SoongZipCmd}", "${outUsage}"},
+			OutputFiles:  []string{"${outUsageZip}"},
+			ExecStrategy: "${config.RER8ExecStrategy}",
+			Platform:     map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
+		},
+	}, []string{"outDir", "outDict", "outUsage", "outUsageZip", "outUsageDir",
+		"r8Flags", "zipFlags"}, []string{"implicits"})
 
-func (j *Module) dexCommonFlags(ctx android.ModuleContext) []string {
-	flags := j.deviceProperties.Dxflags
+func (d *dexer) dexCommonFlags(ctx android.ModuleContext, minSdkVersion sdkSpec) []string {
+	flags := d.dexProperties.Dxflags
 	// Translate all the DX flags to D8 ones until all the build files have been migrated
 	// to D8 flags. See: b/69377755
 	flags = android.RemoveListFromList(flags,
@@ -103,30 +170,27 @@
 			"--verbose")
 	}
 
-	minSdkVersion, err := j.minSdkVersion().effectiveVersion(ctx)
+	effectiveVersion, err := minSdkVersion.effectiveVersion(ctx)
 	if err != nil {
 		ctx.PropertyErrorf("min_sdk_version", "%s", err)
 	}
 
-	flags = append(flags, "--min-api "+minSdkVersion.asNumberString())
+	flags = append(flags, "--min-api "+effectiveVersion.asNumberString())
 	return flags
 }
 
-func (j *Module) d8Flags(ctx android.ModuleContext, flags javaBuilderFlags) ([]string, android.Paths) {
-	d8Flags := j.dexCommonFlags(ctx)
-
+func d8Flags(flags javaBuilderFlags) (d8Flags []string, d8Deps android.Paths) {
 	d8Flags = append(d8Flags, flags.bootClasspath.FormRepeatedClassPath("--lib ")...)
 	d8Flags = append(d8Flags, flags.classpath.FormRepeatedClassPath("--lib ")...)
 
-	var d8Deps android.Paths
 	d8Deps = append(d8Deps, flags.bootClasspath...)
 	d8Deps = append(d8Deps, flags.classpath...)
 
 	return d8Flags, d8Deps
 }
 
-func (j *Module) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8Flags []string, r8Deps android.Paths) {
-	opt := j.deviceProperties.Optimize
+func (d *dexer) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8Flags []string, r8Deps android.Paths) {
+	opt := d.dexProperties.Optimize
 
 	// When an app contains references to APIs that are not in the SDK specified by
 	// its LOCAL_SDK_VERSION for example added by support library or by runtime
@@ -140,8 +204,6 @@
 		proguardRaiseDeps = append(proguardRaiseDeps, dep.(Dependency).HeaderJars()...)
 	})
 
-	r8Flags = append(r8Flags, j.dexCommonFlags(ctx)...)
-
 	r8Flags = append(r8Flags, proguardRaiseDeps.FormJavaClassPath("-libraryjars"))
 	r8Flags = append(r8Flags, flags.bootClasspath.FormJavaClassPath("-libraryjars"))
 	r8Flags = append(r8Flags, flags.classpath.FormJavaClassPath("-libraryjars"))
@@ -154,15 +216,10 @@
 		android.PathForSource(ctx, "build/make/core/proguard.flags"),
 	}
 
-	if j.shouldInstrumentStatic(ctx) {
-		flagFiles = append(flagFiles,
-			android.PathForSource(ctx, "build/make/core/proguard.jacoco.flags"))
-	}
-
-	flagFiles = append(flagFiles, j.extraProguardFlagFiles...)
+	flagFiles = append(flagFiles, d.extraProguardFlagFiles...)
 	// TODO(ccross): static android library proguard files
 
-	flagFiles = append(flagFiles, android.PathsForModuleSrc(ctx, j.deviceProperties.Optimize.Proguard_flags_files)...)
+	flagFiles = append(flagFiles, android.PathsForModuleSrc(ctx, opt.Proguard_flags_files)...)
 
 	r8Flags = append(r8Flags, android.JoinWithPrefix(flagFiles.Strings(), "-include "))
 	r8Deps = append(r8Deps, flagFiles...)
@@ -171,7 +228,7 @@
 	r8Deps = append(r8Deps, android.PathForSource(ctx,
 		"build/make/core/proguard_basic_keeps.flags"))
 
-	r8Flags = append(r8Flags, j.deviceProperties.Optimize.Proguard_flags...)
+	r8Flags = append(r8Flags, opt.Proguard_flags...)
 
 	// TODO(ccross): Don't shrink app instrumentation tests by default.
 	if !Bool(opt.Shrink) {
@@ -197,46 +254,55 @@
 	return r8Flags, r8Deps
 }
 
-func (j *Module) compileDex(ctx android.ModuleContext, flags javaBuilderFlags,
+func (d *dexer) compileDex(ctx android.ModuleContext, flags javaBuilderFlags, minSdkVersion sdkSpec,
 	classesJar android.Path, jarName string) android.ModuleOutPath {
 
-	useR8 := j.deviceProperties.EffectiveOptimizeEnabled()
-
 	// Compile classes.jar into classes.dex and then javalib.jar
 	javalibJar := android.PathForModuleOut(ctx, "dex", jarName)
 	outDir := android.PathForModuleOut(ctx, "dex")
 
 	zipFlags := "--ignore_missing_files"
-	if proptools.Bool(j.deviceProperties.Uncompress_dex) {
+	if proptools.Bool(d.dexProperties.Uncompress_dex) {
 		zipFlags += " -L 0"
 	}
 
+	commonFlags := d.dexCommonFlags(ctx, minSdkVersion)
+
+	useR8 := d.effectiveOptimizeEnabled()
 	if useR8 {
 		proguardDictionary := android.PathForModuleOut(ctx, "proguard_dictionary")
-		j.proguardDictionary = proguardDictionary
-		r8Flags, r8Deps := j.r8Flags(ctx, flags)
+		d.proguardDictionary = android.OptionalPathForPath(proguardDictionary)
+		proguardUsageDir := android.PathForModuleOut(ctx, "proguard_usage")
+		proguardUsage := proguardUsageDir.Join(ctx, ctx.Namespace().Path,
+			android.ModuleNameWithPossibleOverride(ctx), "unused.txt")
+		proguardUsageZip := android.PathForModuleOut(ctx, "proguard_usage.zip")
+		d.proguardUsageZip = android.OptionalPathForPath(proguardUsageZip)
+		r8Flags, r8Deps := d.r8Flags(ctx, flags)
 		rule := r8
 		args := map[string]string{
-			"r8Flags":  strings.Join(r8Flags, " "),
-			"zipFlags": zipFlags,
-			"outDict":  j.proguardDictionary.String(),
-			"outDir":   outDir.String(),
+			"r8Flags":     strings.Join(append(r8Flags, commonFlags...), " "),
+			"zipFlags":    zipFlags,
+			"outDict":     proguardDictionary.String(),
+			"outUsageDir": proguardUsageDir.String(),
+			"outUsage":    proguardUsage.String(),
+			"outUsageZip": proguardUsageZip.String(),
+			"outDir":      outDir.String(),
 		}
 		if ctx.Config().IsEnvTrue("RBE_R8") {
 			rule = r8RE
 			args["implicits"] = strings.Join(r8Deps.Strings(), ",")
 		}
 		ctx.Build(pctx, android.BuildParams{
-			Rule:           rule,
-			Description:    "r8",
-			Output:         javalibJar,
-			ImplicitOutput: proguardDictionary,
-			Input:          classesJar,
-			Implicits:      r8Deps,
-			Args:           args,
+			Rule:            rule,
+			Description:     "r8",
+			Output:          javalibJar,
+			ImplicitOutputs: android.WritablePaths{proguardDictionary, proguardUsageZip},
+			Input:           classesJar,
+			Implicits:       r8Deps,
+			Args:            args,
 		})
 	} else {
-		d8Flags, d8Deps := j.d8Flags(ctx, flags)
+		d8Flags, d8Deps := d8Flags(flags)
 		rule := d8
 		if ctx.Config().IsEnvTrue("RBE_D8") {
 			rule = d8RE
@@ -248,13 +314,13 @@
 			Input:       classesJar,
 			Implicits:   d8Deps,
 			Args: map[string]string{
-				"d8Flags":  strings.Join(d8Flags, " "),
+				"d8Flags":  strings.Join(append(commonFlags, d8Flags...), " "),
 				"zipFlags": zipFlags,
 				"outDir":   outDir.String(),
 			},
 		})
 	}
-	if proptools.Bool(j.deviceProperties.Uncompress_dex) {
+	if proptools.Bool(d.dexProperties.Uncompress_dex) {
 		alignedJavalibJar := android.PathForModuleOut(ctx, "aligned", jarName)
 		TransformZipAlign(ctx, alignedJavalibJar, javalibJar)
 		javalibJar = alignedJavalibJar
diff --git a/java/droiddoc.go b/java/droiddoc.go
index b564fea..66eec2c 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -191,7 +191,7 @@
 	// the generated removed Dex API filename by Doclava.
 	Removed_dex_api_filename *string
 
-	// if set to false, don't allow droiddoc to generate stubs source files. Defaults to true.
+	// if set to false, don't allow droiddoc to generate stubs source files. Defaults to false.
 	Create_stubs *bool
 
 	Check_api struct {
@@ -857,6 +857,10 @@
 	}
 }
 
+func (d *Droiddoc) createStubs() bool {
+	return BoolDefault(d.properties.Create_stubs, false)
+}
+
 func (d *Droiddoc) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsDir android.WritablePath) {
 	if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
 		apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") ||
@@ -879,7 +883,7 @@
 		cmd.FlagWithOutput("-removedDexApi ", d.removedDexApiFile)
 	}
 
-	if BoolDefault(d.properties.Create_stubs, true) {
+	if d.createStubs() {
 		cmd.FlagWithArg("-stubs ", stubsDir.String())
 	}
 
@@ -1510,7 +1514,9 @@
 	cmd.Flag("--no-banner").
 		Flag("--color").
 		Flag("--quiet").
-		Flag("--format=v2")
+		Flag("--format=v2").
+		FlagWithArg("--repeat-errors-max ", "10").
+		FlagWithArg("--hide ", "UnresolvedImport")
 
 	return cmd
 }
diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go
index 95dd0bb..e27519b 100644
--- a/java/hiddenapi_singleton.go
+++ b/java/hiddenapi_singleton.go
@@ -92,31 +92,34 @@
 // stubFlagsRule creates the rule to build hiddenapi-stub-flags.txt out of dex jars from stub modules and boot image
 // modules.
 func stubFlagsRule(ctx android.SingletonContext) {
-	// Public API stubs
-	publicStubModules := []string{
-		"android_stubs_current",
+	var publicStubModules []string
+	var systemStubModules []string
+	var testStubModules []string
+	var corePlatformStubModules []string
+
+	if ctx.Config().UnbundledBuildUsePrebuiltSdks() {
+		// Build configuration mandates using prebuilt stub modules
+		publicStubModules = append(publicStubModules, "sdk_public_current_android")
+		systemStubModules = append(systemStubModules, "sdk_system_current_android")
+		testStubModules = append(testStubModules, "sdk_test_current_android")
+	} else {
+		// Use stub modules built from source
+		publicStubModules = append(publicStubModules, "android_stubs_current")
+		systemStubModules = append(systemStubModules, "android_system_stubs_current")
+		testStubModules = append(testStubModules, "android_test_stubs_current")
 	}
+	// We do not have prebuilts of the core platform api yet
+	corePlatformStubModules = append(corePlatformStubModules, "core.platform.api.stubs")
 
 	// Add the android.test.base to the set of stubs only if the android.test.base module is on
 	// the boot jars list as the runtime will only enforce hiddenapi access against modules on
 	// that list.
-	if inList("android.test.base", ctx.Config().BootJars()) && !ctx.Config().UnbundledBuildUsePrebuiltSdks() {
-		publicStubModules = append(publicStubModules, "android.test.base.stubs")
-	}
-
-	// System API stubs
-	systemStubModules := []string{
-		"android_system_stubs_current",
-	}
-
-	// Test API stubs
-	testStubModules := []string{
-		"android_test_stubs_current",
-	}
-
-	// Core Platform API stubs
-	corePlatformStubModules := []string{
-		"core.platform.api.stubs",
+	if inList("android.test.base", ctx.Config().BootJars()) {
+		if ctx.Config().UnbundledBuildUsePrebuiltSdks() {
+			publicStubModules = append(publicStubModules, "sdk_public_current_android.test.base")
+		} else {
+			publicStubModules = append(publicStubModules, "android.test.base.stubs")
+		}
 	}
 
 	// Allow products to define their own stubs for custom product jars that apps can use.
@@ -163,6 +166,7 @@
 						return
 					}
 				}
+
 				bootDexJars = append(bootDexJars, jar)
 			}
 		}
diff --git a/java/hiddenapi_singleton_test.go b/java/hiddenapi_singleton_test.go
new file mode 100644
index 0000000..2010bc9
--- /dev/null
+++ b/java/hiddenapi_singleton_test.go
@@ -0,0 +1,219 @@
+// 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 java
+
+import (
+	"android/soong/android"
+	"fmt"
+	"strings"
+	"testing"
+
+	"github.com/google/blueprint/proptools"
+)
+
+func testConfigWithBootJars(bp string, bootJars []string) android.Config {
+	config := testConfig(nil, bp, nil)
+	config.TestProductVariables.BootJars = bootJars
+	return config
+}
+
+func testContextWithHiddenAPI() *android.TestContext {
+	ctx := testContext()
+	ctx.RegisterSingletonType("hiddenapi", hiddenAPISingletonFactory)
+	return ctx
+}
+
+func testHiddenAPIWithConfig(t *testing.T, config android.Config) *android.TestContext {
+	t.Helper()
+
+	ctx := testContextWithHiddenAPI()
+
+	run(t, ctx, config)
+	return ctx
+}
+
+func testHiddenAPIBootJars(t *testing.T, bp string, bootJars []string) (*android.TestContext, android.Config) {
+	config := testConfigWithBootJars(bp, bootJars)
+
+	return testHiddenAPIWithConfig(t, config), config
+}
+
+func testHiddenAPIUnbundled(t *testing.T, unbundled bool) (*android.TestContext, android.Config) {
+	config := testConfig(nil, ``, nil)
+	config.TestProductVariables.Unbundled_build = proptools.BoolPtr(unbundled)
+
+	return testHiddenAPIWithConfig(t, config), config
+}
+
+func TestHiddenAPISingleton(t *testing.T) {
+	ctx, _ := testHiddenAPIBootJars(t, `
+		java_library {
+			name: "foo",
+			srcs: ["a.java"],
+			compile_dex: true,
+	}
+	`, []string{"foo"})
+
+	hiddenAPI := ctx.SingletonForTests("hiddenapi")
+	hiddenapiRule := hiddenAPI.Rule("hiddenapi")
+	want := "--boot-dex=" + buildDir + "/.intermediates/foo/android_common/aligned/foo.jar"
+	if !strings.Contains(hiddenapiRule.RuleParams.Command, want) {
+		t.Errorf("Expected %s in hiddenapi command, but it was not present: %s", want, hiddenapiRule.RuleParams.Command)
+	}
+}
+
+func TestHiddenAPISingletonWithPrebuilt(t *testing.T) {
+	ctx, _ := testHiddenAPIBootJars(t, `
+		java_import {
+			name: "foo",
+			jars: ["a.jar"],
+			compile_dex: true,
+	}
+	`, []string{"foo"})
+
+	hiddenAPI := ctx.SingletonForTests("hiddenapi")
+	hiddenapiRule := hiddenAPI.Rule("hiddenapi")
+	want := "--boot-dex=" + buildDir + "/.intermediates/foo/android_common/dex/foo.jar"
+	if !strings.Contains(hiddenapiRule.RuleParams.Command, want) {
+		t.Errorf("Expected %s in hiddenapi command, but it was not present: %s", want, hiddenapiRule.RuleParams.Command)
+	}
+}
+
+func TestHiddenAPISingletonWithPrebuiltUseSource(t *testing.T) {
+	ctx, _ := testHiddenAPIBootJars(t, `
+		java_library {
+			name: "foo",
+			srcs: ["a.java"],
+			compile_dex: true,
+	}
+
+		java_import {
+			name: "foo",
+			jars: ["a.jar"],
+			compile_dex: true,
+			prefer: false,
+	}
+	`, []string{"foo"})
+
+	hiddenAPI := ctx.SingletonForTests("hiddenapi")
+	hiddenapiRule := hiddenAPI.Rule("hiddenapi")
+	fromSourceJarArg := "--boot-dex=" + buildDir + "/.intermediates/foo/android_common/aligned/foo.jar"
+	if !strings.Contains(hiddenapiRule.RuleParams.Command, fromSourceJarArg) {
+		t.Errorf("Expected %s in hiddenapi command, but it was not present: %s", fromSourceJarArg, hiddenapiRule.RuleParams.Command)
+	}
+
+	prebuiltJarArg := "--boot-dex=" + buildDir + "/.intermediates/foo/android_common/dex/foo.jar"
+	if strings.Contains(hiddenapiRule.RuleParams.Command, prebuiltJarArg) {
+		t.Errorf("Did not expect %s in hiddenapi command, but it was present: %s", prebuiltJarArg, hiddenapiRule.RuleParams.Command)
+	}
+}
+
+func TestHiddenAPISingletonWithPrebuiltOverrideSource(t *testing.T) {
+	ctx, _ := testHiddenAPIBootJars(t, `
+		java_library {
+			name: "foo",
+			srcs: ["a.java"],
+			compile_dex: true,
+	}
+
+		java_import {
+			name: "foo",
+			jars: ["a.jar"],
+			compile_dex: true,
+			prefer: true,
+	}
+	`, []string{"foo"})
+
+	hiddenAPI := ctx.SingletonForTests("hiddenapi")
+	hiddenapiRule := hiddenAPI.Rule("hiddenapi")
+	prebuiltJarArg := "--boot-dex=" + buildDir + "/.intermediates/prebuilt_foo/android_common/dex/foo.jar"
+	if !strings.Contains(hiddenapiRule.RuleParams.Command, prebuiltJarArg) {
+		t.Errorf("Expected %s in hiddenapi command, but it was not present: %s", prebuiltJarArg, hiddenapiRule.RuleParams.Command)
+	}
+
+	fromSourceJarArg := "--boot-dex=" + buildDir + "/.intermediates/foo/android_common/aligned/foo.jar"
+	if strings.Contains(hiddenapiRule.RuleParams.Command, fromSourceJarArg) {
+		t.Errorf("Did not expect %s in hiddenapi command, but it was present: %s", fromSourceJarArg, hiddenapiRule.RuleParams.Command)
+	}
+}
+
+func TestHiddenAPISingletonSdks(t *testing.T) {
+	testCases := []struct {
+		name             string
+		unbundledBuild   bool
+		publicStub       string
+		systemStub       string
+		testStub         string
+		corePlatformStub string
+	}{
+		{
+			name:             "testBundled",
+			unbundledBuild:   false,
+			publicStub:       "android_stubs_current",
+			systemStub:       "android_system_stubs_current",
+			testStub:         "android_test_stubs_current",
+			corePlatformStub: "core.platform.api.stubs",
+		}, {
+			name:             "testUnbundled",
+			unbundledBuild:   true,
+			publicStub:       "sdk_public_current_android",
+			systemStub:       "sdk_system_current_android",
+			testStub:         "sdk_test_current_android",
+			corePlatformStub: "core.platform.api.stubs",
+		},
+	}
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			ctx, _ := testHiddenAPIUnbundled(t, tc.unbundledBuild)
+
+			hiddenAPI := ctx.SingletonForTests("hiddenapi")
+			hiddenapiRule := hiddenAPI.Rule("hiddenapi")
+			wantPublicStubs := "--public-stub-classpath=" + generateSdkDexPath(tc.publicStub, tc.unbundledBuild)
+			if !strings.Contains(hiddenapiRule.RuleParams.Command, wantPublicStubs) {
+				t.Errorf("Expected %s in hiddenapi command, but it was not present: %s", wantPublicStubs, hiddenapiRule.RuleParams.Command)
+			}
+
+			wantSystemStubs := "--system-stub-classpath=" + generateSdkDexPath(tc.systemStub, tc.unbundledBuild)
+			if !strings.Contains(hiddenapiRule.RuleParams.Command, wantSystemStubs) {
+				t.Errorf("Expected %s in hiddenapi command, but it was not present: %s", wantSystemStubs, hiddenapiRule.RuleParams.Command)
+			}
+
+			wantTestStubs := "--test-stub-classpath=" + generateSdkDexPath(tc.testStub, tc.unbundledBuild)
+			if !strings.Contains(hiddenapiRule.RuleParams.Command, wantTestStubs) {
+				t.Errorf("Expected %s in hiddenapi command, but it was not present: %s", wantTestStubs, hiddenapiRule.RuleParams.Command)
+			}
+
+			wantCorePlatformStubs := "--core-platform-stub-classpath=" + generateDexPath(tc.corePlatformStub)
+			if !strings.Contains(hiddenapiRule.RuleParams.Command, wantCorePlatformStubs) {
+				t.Errorf("Expected %s in hiddenapi command, but it was not present: %s", wantCorePlatformStubs, hiddenapiRule.RuleParams.Command)
+			}
+		})
+	}
+}
+
+func generateDexedPath(subDir, dex, module string) string {
+	return fmt.Sprintf("%s/.intermediates/%s/android_common/%s/%s.jar", buildDir, subDir, dex, module)
+}
+
+func generateDexPath(module string) string {
+	return generateDexedPath(module, "dex", module)
+}
+
+func generateSdkDexPath(module string, unbundled bool) string {
+	if unbundled {
+		return generateDexedPath("prebuilts/sdk/"+module, "dex", module)
+	}
+	return generateDexPath(module)
+}
diff --git a/java/java.go b/java/java.go
index 69826ee..18def0b 100644
--- a/java/java.go
+++ b/java/java.go
@@ -259,9 +259,6 @@
 }
 
 type CompilerDeviceProperties struct {
-	// list of module-specific flags that will be used for dex compiles
-	Dxflags []string `android:"arch_variant"`
-
 	// if not blank, set to the version of the sdk to compile against.
 	// Defaults to compiling against the current platform.
 	Sdk_version *string
@@ -307,37 +304,6 @@
 		}
 	}
 
-	// If set to true, compile dex regardless of installable.  Defaults to false.
-	Compile_dex *bool
-
-	Optimize struct {
-		// If false, disable all optimization.  Defaults to true for android_app and android_test
-		// modules, false for java_library and java_test modules.
-		Enabled *bool
-		// True if the module containing this has it set by default.
-		EnabledByDefault bool `blueprint:"mutated"`
-
-		// If true, optimize for size by removing unused code.  Defaults to true for apps,
-		// false for libraries and tests.
-		Shrink *bool
-
-		// If true, optimize bytecode.  Defaults to false.
-		Optimize *bool
-
-		// If true, obfuscate bytecode.  Defaults to false.
-		Obfuscate *bool
-
-		// If true, do not use the flag files generated by aapt that automatically keep
-		// classes referenced by the app manifest.  Defaults to false.
-		No_aapt_flags *bool
-
-		// Flags to pass to proguard.
-		Proguard_flags []string
-
-		// Specifies the locations of files containing proguard flags.
-		Proguard_flags_files []string `android:"path"`
-	}
-
 	// When targeting 1.9 and above, override the modules to use with --system,
 	// otherwise provides defaults libraries to add to the bootclasspath.
 	System_modules *string
@@ -351,12 +317,6 @@
 	// set the name of the output
 	Stem *string
 
-	// Keep the data uncompressed. We always need uncompressed dex for execution,
-	// so this might actually save space by avoiding storing the same data twice.
-	// This defaults to reasonable value based on module and should not be set.
-	// It exists only to support ART tests.
-	Uncompress_dex *bool
-
 	IsSDKLibrary bool `blueprint:"mutated"`
 
 	// If true, generate the signature file of APK Signing Scheme V4, along side the signed APK file.
@@ -364,10 +324,6 @@
 	V4_signature *bool
 }
 
-func (me *CompilerDeviceProperties) EffectiveOptimizeEnabled() bool {
-	return BoolDefault(me.Optimize.Enabled, me.Optimize.EnabledByDefault)
-}
-
 // Functionality common to Module and Import
 //
 // It is embedded in Module so its functionality can be used by methods in Module
@@ -436,9 +392,6 @@
 	// output file containing uninstrumented classes that will be instrumented by jacoco
 	jacocoReportClassesFile android.Path
 
-	// output file containing mapping of obfuscated names
-	proguardDictionary android.Path
-
 	// output file of the module, which may be a classes jar or a dex jar
 	outputFile       android.Path
 	extraOutputFiles android.Paths
@@ -454,9 +407,6 @@
 	compiledJavaSrcs android.Paths
 	compiledSrcJars  android.Paths
 
-	// list of extra progurad flag files
-	extraProguardFlagFiles android.Paths
-
 	// manifest file to use instead of properties.Manifest
 	overrideManifest android.OptionalPath
 
@@ -483,13 +433,14 @@
 	extraResources android.Paths
 
 	hiddenAPI
+	dexer
 	dexpreopter
 	linter
 
 	// list of the xref extraction files
 	kytheFiles android.Paths
 
-	distFile android.Path
+	distFiles android.TaggedDistFiles
 }
 
 func (j *Module) addHostProperties() {
@@ -503,6 +454,7 @@
 	j.addHostProperties()
 	j.AddProperties(
 		&j.deviceProperties,
+		&j.dexer.dexProperties,
 		&j.dexpreoptProperties,
 		&j.linter.properties,
 	)
@@ -515,7 +467,10 @@
 	case ".jar":
 		return android.Paths{j.implementationAndResourcesJar}, nil
 	case ".proguard_map":
-		return android.Paths{j.proguardDictionary}, nil
+		if j.dexer.proguardDictionary.Valid() {
+			return android.Paths{j.dexer.proguardDictionary.Path()}, nil
+		}
+		return nil, fmt.Errorf("%q was requested, but no output file was found.", tag)
 	default:
 		return nil, fmt.Errorf("unsupported module reference tag %q", tag)
 	}
@@ -680,28 +635,32 @@
 	return j.ApexModuleBase.AvailableFor(what)
 }
 
+func sdkDeps(ctx android.BottomUpMutatorContext, sdkContext sdkContext, d dexer) {
+	sdkDep := decodeSdkDep(ctx, sdkContext)
+	if sdkDep.useDefaultLibs {
+		ctx.AddVariationDependencies(nil, bootClasspathTag, config.DefaultBootclasspathLibraries...)
+		ctx.AddVariationDependencies(nil, systemModulesTag, config.DefaultSystemModules)
+		if sdkDep.hasFrameworkLibs() {
+			ctx.AddVariationDependencies(nil, libTag, config.DefaultLibraries...)
+		}
+	} else if sdkDep.useModule {
+		ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.bootclasspath...)
+		ctx.AddVariationDependencies(nil, java9LibTag, sdkDep.java9Classpath...)
+		if d.effectiveOptimizeEnabled() && sdkDep.hasStandardLibs() {
+			ctx.AddVariationDependencies(nil, proguardRaiseTag, config.DefaultBootclasspathLibraries...)
+			ctx.AddVariationDependencies(nil, proguardRaiseTag, config.DefaultLibraries...)
+		}
+	}
+	if sdkDep.systemModules != "" {
+		ctx.AddVariationDependencies(nil, systemModulesTag, sdkDep.systemModules)
+	}
+}
+
 func (j *Module) deps(ctx android.BottomUpMutatorContext) {
 	if ctx.Device() {
 		j.linter.deps(ctx)
 
-		sdkDep := decodeSdkDep(ctx, sdkContext(j))
-		if sdkDep.useDefaultLibs {
-			ctx.AddVariationDependencies(nil, bootClasspathTag, config.DefaultBootclasspathLibraries...)
-			ctx.AddVariationDependencies(nil, systemModulesTag, config.DefaultSystemModules)
-			if sdkDep.hasFrameworkLibs() {
-				ctx.AddVariationDependencies(nil, libTag, config.DefaultLibraries...)
-			}
-		} else if sdkDep.useModule {
-			ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.bootclasspath...)
-			ctx.AddVariationDependencies(nil, java9LibTag, sdkDep.java9Classpath...)
-			if j.deviceProperties.EffectiveOptimizeEnabled() && sdkDep.hasStandardLibs() {
-				ctx.AddVariationDependencies(nil, proguardRaiseTag, config.DefaultBootclasspathLibraries...)
-				ctx.AddVariationDependencies(nil, proguardRaiseTag, config.DefaultLibraries...)
-			}
-		}
-		if sdkDep.systemModules != "" {
-			ctx.AddVariationDependencies(nil, systemModulesTag, sdkDep.systemModules)
-		}
+		sdkDeps(ctx, sdkContext(j), j.dexer)
 	}
 
 	syspropPublicStubs := syspropPublicStubs(ctx.Config())
@@ -1590,8 +1549,8 @@
 
 	// Enable dex compilation for the APEX variants, unless it is disabled explicitly
 	if android.DirectlyInAnyApex(ctx, ctx.ModuleName()) && !j.IsForPlatform() {
-		if j.deviceProperties.Compile_dex == nil {
-			j.deviceProperties.Compile_dex = proptools.BoolPtr(true)
+		if j.dexProperties.Compile_dex == nil {
+			j.dexProperties.Compile_dex = proptools.BoolPtr(true)
 		}
 		if j.deviceProperties.Hostdex == nil {
 			j.deviceProperties.Hostdex = proptools.BoolPtr(true)
@@ -1599,20 +1558,27 @@
 	}
 
 	if ctx.Device() && j.hasCode(ctx) &&
-		(Bool(j.properties.Installable) || Bool(j.deviceProperties.Compile_dex)) {
+		(Bool(j.properties.Installable) || Bool(j.dexProperties.Compile_dex)) {
+		if j.shouldInstrumentStatic(ctx) {
+			j.dexer.extraProguardFlagFiles = append(j.dexer.extraProguardFlagFiles,
+				android.PathForSource(ctx, "build/make/core/proguard.jacoco.flags"))
+		}
 		// Dex compilation
 		var dexOutputFile android.ModuleOutPath
-		dexOutputFile = j.compileDex(ctx, flags, outputFile, jarName)
+		dexOutputFile = j.dexer.compileDex(ctx, flags, j.minSdkVersion(), outputFile, jarName)
 		if ctx.Failed() {
 			return
 		}
 
 		configurationName := j.ConfigurationName()
 		primary := configurationName == ctx.ModuleName()
+		// If the prebuilt is being used rather than the from source, skip this
+		// module to prevent duplicated classes
+		primary = primary && !j.IsReplacedByPrebuilt()
 
 		// Hidden API CSV generation and dex encoding
 		dexOutputFile = j.hiddenAPI.hiddenAPI(ctx, configurationName, primary, dexOutputFile, j.implementationJarFile,
-			proptools.Bool(j.deviceProperties.Uncompress_dex))
+			proptools.Bool(j.dexProperties.Uncompress_dex))
 
 		// merge dex jar with resources if necessary
 		if j.resourceJar != nil {
@@ -1620,7 +1586,7 @@
 			combinedJar := android.PathForModuleOut(ctx, "dex-withres", jarName)
 			TransformJarsToJar(ctx, combinedJar, "for dex resources", jars, android.OptionalPath{},
 				false, nil, nil)
-			if *j.deviceProperties.Uncompress_dex {
+			if *j.dexProperties.Uncompress_dex {
 				combinedAlignedJar := android.PathForModuleOut(ctx, "dex-withres-aligned", jarName)
 				TransformZipAlign(ctx, combinedAlignedJar, combinedJar)
 				dexOutputFile = combinedAlignedJar
@@ -1884,18 +1850,9 @@
 // Java libraries (.jar file)
 //
 
-type LibraryProperties struct {
-	Dist struct {
-		// The tag of the output of this module that should be output.
-		Tag *string `android:"arch_variant"`
-	} `android:"arch_variant"`
-}
-
 type Library struct {
 	Module
 
-	libraryProperties LibraryProperties
-
 	InstallMixin func(ctx android.ModuleContext, installPath android.Path) (extraInstallDeps android.Paths)
 }
 
@@ -1937,11 +1894,11 @@
 	j.checkSdkVersions(ctx)
 	j.dexpreopter.installPath = android.PathForModuleInstall(ctx, "framework", j.Stem()+".jar")
 	j.dexpreopter.isSDKLibrary = j.deviceProperties.IsSDKLibrary
-	if j.deviceProperties.Uncompress_dex == nil {
+	if j.dexProperties.Uncompress_dex == nil {
 		// If the value was not force-set by the user, use reasonable default based on the module.
-		j.deviceProperties.Uncompress_dex = proptools.BoolPtr(shouldUncompressDex(ctx, &j.dexpreopter))
+		j.dexProperties.Uncompress_dex = proptools.BoolPtr(shouldUncompressDex(ctx, &j.dexpreopter))
 	}
-	j.dexpreopter.uncompressedDex = *j.deviceProperties.Uncompress_dex
+	j.dexpreopter.uncompressedDex = *j.dexProperties.Uncompress_dex
 	j.compile(ctx, nil)
 
 	exclusivelyForApex := android.InAnyApex(ctx.ModuleName()) && !j.IsForPlatform()
@@ -1954,14 +1911,7 @@
 			j.Stem()+".jar", j.outputFile, extraInstallDeps...)
 	}
 
-	// Verify Dist.Tag is set to a supported output
-	if j.libraryProperties.Dist.Tag != nil {
-		distFiles, err := j.OutputFiles(*j.libraryProperties.Dist.Tag)
-		if err != nil {
-			ctx.PropertyErrorf("dist.tag", "%s", err.Error())
-		}
-		j.distFile = distFiles[0]
-	}
+	j.distFiles = j.GenerateTaggedDistFiles(ctx)
 }
 
 func (j *Library) DepsMutator(ctx android.BottomUpMutatorContext) {
@@ -2079,7 +2029,6 @@
 	module := &Library{}
 
 	module.addHostAndDeviceProperties()
-	module.AddProperties(&module.libraryProperties)
 
 	module.initModuleAndImport(&module.ModuleBase)
 
@@ -2178,6 +2127,7 @@
 	prebuiltTestProperties prebuiltTestProperties
 
 	testConfig android.Path
+	dexJarFile android.Path
 }
 
 func (j *Test) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -2476,8 +2426,14 @@
 	// Functionality common to Module and Import.
 	embeddableInModuleAndImport
 
+	hiddenAPI
+	dexer
+
 	properties ImportProperties
 
+	// output file containing classes.dex and resources
+	dexJarFile android.Path
+
 	combinedClasspathFile android.Path
 	exportedSdkLibs       []string
 }
@@ -2486,10 +2442,22 @@
 	return sdkSpecFrom(String(j.properties.Sdk_version))
 }
 
+func (j *Import) makeSdkVersion() string {
+	return j.sdkVersion().raw
+}
+
+func (j *Import) systemModules() string {
+	return "none"
+}
+
 func (j *Import) minSdkVersion() sdkSpec {
 	return j.sdkVersion()
 }
 
+func (j *Import) targetSdkVersion() sdkSpec {
+	return j.sdkVersion()
+}
+
 func (j *Import) MinSdkVersion() string {
 	return j.minSdkVersion().version.String()
 }
@@ -2516,6 +2484,10 @@
 
 func (j *Import) DepsMutator(ctx android.BottomUpMutatorContext) {
 	ctx.AddVariationDependencies(nil, libTag, j.properties.Libs...)
+
+	if ctx.Device() && Bool(j.dexProperties.Compile_dex) {
+		sdkDeps(ctx, sdkContext(j), j.dexer)
+	}
 }
 
 func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -2538,6 +2510,8 @@
 	// added to the Android manifest.
 	j.exportedSdkLibs = append(j.exportedSdkLibs, j.OptionalImplicitSdkLibrary()...)
 
+	var flags javaBuilderFlags
+
 	ctx.VisitDirectDeps(func(module android.Module) {
 		otherName := ctx.OtherModuleName(module)
 		tag := ctx.OtherModuleDependencyTag(module)
@@ -2546,12 +2520,16 @@
 		case Dependency:
 			switch tag {
 			case libTag, staticLibTag:
+				flags.classpath = append(flags.classpath, dep.HeaderJars()...)
 				// sdk lib names from dependencies are re-exported
 				j.exportedSdkLibs = append(j.exportedSdkLibs, dep.ExportedSdkLibs()...)
+			case bootClasspathTag:
+				flags.bootClasspath = append(flags.bootClasspath, dep.HeaderJars()...)
 			}
 		case SdkLibraryDependency:
 			switch tag {
 			case libTag:
+				flags.classpath = append(flags.classpath, dep.SdkHeaderJars(ctx, j.sdkVersion())...)
 				// names of sdk libs that are directly depended are exported
 				j.exportedSdkLibs = append(j.exportedSdkLibs, otherName)
 			}
@@ -2563,6 +2541,39 @@
 		ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"),
 			jarName, outputFile)
 	}
+
+	// If this is a component library (impl, stubs, etc.) for a java_sdk_library then
+	// add the name of that java_sdk_library to the exported sdk libs to make sure
+	// that, if necessary, a <uses-library> element for that java_sdk_library is
+	// added to the Android manifest.
+	j.exportedSdkLibs = append(j.exportedSdkLibs, j.OptionalImplicitSdkLibrary()...)
+
+	if ctx.Device() && Bool(j.dexProperties.Compile_dex) {
+		sdkDep := decodeSdkDep(ctx, sdkContext(j))
+		if sdkDep.invalidVersion {
+			ctx.AddMissingDependencies(sdkDep.bootclasspath)
+			ctx.AddMissingDependencies(sdkDep.java9Classpath)
+		} else if sdkDep.useFiles {
+			// sdkDep.jar is actually equivalent to turbine header.jar.
+			flags.classpath = append(flags.classpath, sdkDep.jars...)
+		}
+
+		// Dex compilation
+		var dexOutputFile android.ModuleOutPath
+		dexOutputFile = j.dexer.compileDex(ctx, flags, j.minSdkVersion(), outputFile, jarName)
+		if ctx.Failed() {
+			return
+		}
+
+		configurationName := j.BaseModuleName()
+		primary := j.Prebuilt().UsePrebuilt()
+
+		// Hidden API CSV generation and dex encoding
+		dexOutputFile = j.hiddenAPI.hiddenAPI(ctx, configurationName, primary, dexOutputFile, outputFile,
+			proptools.Bool(j.dexProperties.Uncompress_dex))
+
+		j.dexJarFile = dexOutputFile
+	}
 }
 
 var _ Dependency = (*Import)(nil)
@@ -2593,7 +2604,7 @@
 }
 
 func (j *Import) DexJar() android.Path {
-	return nil
+	return j.dexJarFile
 }
 
 func (j *Import) AidlIncludeDirs() android.Paths {
@@ -2652,10 +2663,15 @@
 func ImportFactory() android.Module {
 	module := &Import{}
 
-	module.AddProperties(&module.properties)
+	module.AddProperties(
+		&module.properties,
+		&module.dexer.dexProperties,
+	)
 
 	module.initModuleAndImport(&module.ModuleBase)
 
+	module.dexProperties.Optimize.EnabledByDefault = false
+
 	android.InitPrebuiltModule(module, &module.properties.Jars)
 	android.InitApexModule(module)
 	android.InitSdkAwareModule(module)
@@ -2854,6 +2870,7 @@
 	module.AddProperties(
 		&CompilerProperties{},
 		&CompilerDeviceProperties{},
+		&DexProperties{},
 		&DexpreoptProperties{},
 		&android.ProtoProperties{},
 		&aaptProperties{},
diff --git a/java/java_test.go b/java/java_test.go
index 8797119..29daa67 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -138,7 +138,6 @@
 	}
 
 	t.Fatalf("missing expected error %q (0 errors are returned)", pattern)
-
 	return ctx, config
 }
 
@@ -486,6 +485,8 @@
 		java_import {
 			name: "baz",
 			jars: ["b.jar"],
+			sdk_version: "current",
+			compile_dex: true,
 		}
 
 		dex_import {
@@ -516,8 +517,10 @@
 	fooModule := ctx.ModuleForTests("foo", "android_common")
 	javac := fooModule.Rule("javac")
 	combineJar := ctx.ModuleForTests("foo", "android_common").Description("for javac")
-	barJar := ctx.ModuleForTests("bar", "android_common").Rule("combineJar").Output
-	bazJar := ctx.ModuleForTests("baz", "android_common").Rule("combineJar").Output
+	barModule := ctx.ModuleForTests("bar", "android_common")
+	barJar := barModule.Rule("combineJar").Output
+	bazModule := ctx.ModuleForTests("baz", "android_common")
+	bazJar := bazModule.Rule("combineJar").Output
 	sdklibStubsJar := ctx.ModuleForTests("sdklib.stubs", "android_common").Rule("combineJar").Output
 
 	fooLibrary := fooModule.Module().(*Library)
@@ -532,6 +535,11 @@
 		t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], barJar.String())
 	}
 
+	barDexJar := barModule.Module().(*Import).DexJar()
+	if barDexJar != nil {
+		t.Errorf("bar dex jar build path expected to be nil, got %q", barDexJar)
+	}
+
 	if !strings.Contains(javac.Args["classpath"], sdklibStubsJar.String()) {
 		t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], sdklibStubsJar.String())
 	}
@@ -540,6 +548,12 @@
 		t.Errorf("foo combineJar inputs %v does not contain %q", combineJar.Inputs, bazJar.String())
 	}
 
+	bazDexJar := bazModule.Module().(*Import).DexJar().String()
+	expectedDexJar := buildDir + "/.intermediates/baz/android_common/dex/baz.jar"
+	if bazDexJar != expectedDexJar {
+		t.Errorf("baz dex jar build path expected %q, got %q", expectedDexJar, bazDexJar)
+	}
+
 	ctx.ModuleForTests("qux", "android_common").Rule("Cp")
 }
 
@@ -846,6 +860,110 @@
 	}
 }
 
+func TestJavaLint(t *testing.T) {
+	ctx, _ := testJavaWithFS(t, `
+		java_library {
+			name: "foo",
+			srcs: [
+				"a.java",
+				"b.java",
+				"c.java",
+			],
+			min_sdk_version: "29",
+			sdk_version: "system_current",
+		}
+       `, map[string][]byte{
+		"lint-baseline.xml": nil,
+	})
+
+	foo := ctx.ModuleForTests("foo", "android_common")
+	rule := foo.Rule("lint")
+
+	if !strings.Contains(rule.RuleParams.Command, "--baseline lint-baseline.xml") {
+		t.Error("did not pass --baseline flag")
+	}
+}
+
+func TestJavaLintWithoutBaseline(t *testing.T) {
+	ctx, _ := testJavaWithFS(t, `
+		java_library {
+			name: "foo",
+			srcs: [
+				"a.java",
+				"b.java",
+				"c.java",
+			],
+			min_sdk_version: "29",
+			sdk_version: "system_current",
+		}
+       `, map[string][]byte{})
+
+	foo := ctx.ModuleForTests("foo", "android_common")
+	rule := foo.Rule("lint")
+
+	if strings.Contains(rule.RuleParams.Command, "--baseline") {
+		t.Error("passed --baseline flag for non existent file")
+	}
+}
+
+func TestJavaLintRequiresCustomLintFileToExist(t *testing.T) {
+	config := testConfig(
+		nil,
+		`
+		java_library {
+			name: "foo",
+			srcs: [
+			],
+			min_sdk_version: "29",
+			sdk_version: "system_current",
+			lint: {
+				baseline_filename: "mybaseline.xml",
+			},
+		}
+     `, map[string][]byte{
+			"build/soong/java/lint_defaults.txt":                   nil,
+			"prebuilts/cmdline-tools/tools/bin/lint":               nil,
+			"prebuilts/cmdline-tools/tools/lib/lint-classpath.jar": nil,
+			"framework/aidl":                     nil,
+			"a.java":                             nil,
+			"AndroidManifest.xml":                nil,
+			"build/make/target/product/security": nil,
+		})
+	config.TestAllowNonExistentPaths = false
+	testJavaErrorWithConfig(t,
+		"source path \"mybaseline.xml\" does not exist",
+		config,
+	)
+}
+
+func TestJavaLintUsesCorrectBpConfig(t *testing.T) {
+	ctx, _ := testJavaWithFS(t, `
+		java_library {
+			name: "foo",
+			srcs: [
+				"a.java",
+				"b.java",
+				"c.java",
+			],
+			min_sdk_version: "29",
+			sdk_version: "system_current",
+			lint: {
+				error_checks: ["SomeCheck"],
+				baseline_filename: "mybaseline.xml",
+			},
+		}
+       `, map[string][]byte{
+		"mybaseline.xml": nil,
+	})
+
+	foo := ctx.ModuleForTests("foo", "android_common")
+	rule := foo.Rule("lint")
+
+	if !strings.Contains(rule.RuleParams.Command, "--baseline mybaseline.xml") {
+		t.Error("did not use the correct file for baseline")
+	}
+}
+
 func TestGeneratedSources(t *testing.T) {
 	ctx, _ := testJavaWithFS(t, `
 		java_library {
@@ -986,8 +1104,13 @@
 			"bar-doc/a.java": nil,
 			"bar-doc/b.java": nil,
 		})
+	barDocModule := ctx.ModuleForTests("bar-doc", "android_common")
+	barDoc := barDocModule.Rule("javadoc")
+	notExpected := " -stubs "
+	if strings.Contains(barDoc.RuleParams.Command, notExpected) {
+		t.Errorf("bar-doc command contains flag %q to create stubs, but should not", notExpected)
+	}
 
-	barDoc := ctx.ModuleForTests("bar-doc", "android_common").Rule("javadoc")
 	var javaSrcs []string
 	for _, i := range barDoc.Inputs {
 		javaSrcs = append(javaSrcs, i.Base())
@@ -996,7 +1119,7 @@
 		t.Errorf("inputs of bar-doc must be []string{\"a.java\"}, but was %#v.", javaSrcs)
 	}
 
-	aidl := ctx.ModuleForTests("bar-doc", "android_common").Rule("aidl")
+	aidl := barDocModule.Rule("aidl")
 	if g, w := barDoc.Implicits.Strings(), aidl.Output.String(); !inList(w, g) {
 		t.Errorf("implicits of bar-doc must contain %q, but was %q.", w, g)
 	}
@@ -1283,6 +1406,12 @@
 			libs: ["foo"],
 			sdk_version: "system_29",
 		}
+		java_library {
+			name: "baz-module-30",
+			srcs: ["c.java"],
+			libs: ["foo"],
+			sdk_version: "module_30",
+		}
 		`)
 
 	// check the existence of the internal modules
@@ -1329,6 +1458,13 @@
 			"prebuilts/sdk/29/system/foo.jar")
 	}
 
+	bazModule30Javac := ctx.ModuleForTests("baz-module-30", "android_common").Rule("javac")
+	// tests if "baz-module-30" is actually linked to the module 30 stubs lib
+	if !strings.Contains(bazModule30Javac.Args["classpath"], "prebuilts/sdk/30/module-lib/foo.jar") {
+		t.Errorf("baz-module-30 javac classpath %v does not contain %q", bazModule30Javac.Args["classpath"],
+			"prebuilts/sdk/30/module-lib/foo.jar")
+	}
+
 	// test if baz has exported SDK lib names foo and bar to qux
 	qux := ctx.ModuleForTests("qux", "android_common")
 	if quxLib, ok := qux.Module().(*Library); ok {
diff --git a/java/lint.go b/java/lint.go
index 6391067..7119724 100644
--- a/java/lint.go
+++ b/java/lint.go
@@ -19,6 +19,8 @@
 	"sort"
 	"strings"
 
+	"github.com/google/blueprint/proptools"
+
 	"android/soong/android"
 )
 
@@ -46,6 +48,9 @@
 
 		// Modules that provide extra lint checks
 		Extra_check_modules []string
+
+		// Name of the file that lint uses as the baseline. Defaults to "lint-baseline.xml".
+		Baseline_filename *string
 	}
 }
 
@@ -319,7 +324,7 @@
 
 	cmd := rule.Command().
 		Text("(").
-		Flag("JAVA_OPTS=-Xmx2048m").
+		Flag(`JAVA_OPTS=-"Xmx2048m --add-opens java.base/java.util=ALL-UNNAMED"`).
 		FlagWithArg("ANDROID_SDK_HOME=", homeDir.String()).
 		FlagWithInput("SDK_ANNOTATIONS=", annotationsZipPath).
 		FlagWithInput("LINT_OPTS=-DLINT_API_DATABASE=", apiVersionsXMLPath).
@@ -343,6 +348,19 @@
 		cmd.FlagWithArg("--check ", checkOnly)
 	}
 
+	if lintFilename := proptools.StringDefault(l.properties.Lint.Baseline_filename, "lint-baseline.xml"); lintFilename != "" {
+		var lintBaseline android.OptionalPath
+		if String(l.properties.Lint.Baseline_filename) != "" {
+			// if manually specified, we require the file to exist
+			lintBaseline = android.OptionalPathForPath(android.PathForModuleSrc(ctx, lintFilename))
+		} else {
+			lintBaseline = android.ExistentPathForSource(ctx, ctx.ModuleDir(), lintFilename)
+		}
+		if lintBaseline.Valid() {
+			cmd.FlagWithInput("--baseline ", lintBaseline.Path())
+		}
+	}
+
 	cmd.Text("|| (").Text("cat").Input(text).Text("; exit 7)").Text(")")
 
 	rule.Command().Text("rm -rf").Flag(cacheDir.String()).Flag(homeDir.String())
diff --git a/java/lint_defaults.txt b/java/lint_defaults.txt
index 0786b7c..2de05b0 100644
--- a/java/lint_defaults.txt
+++ b/java/lint_defaults.txt
@@ -76,3 +76,5 @@
 
 # TODO(b/158390965): remove this when lint doesn't crash
 --disable_check HardcodedDebugMode
+
+--warning_check QueryAllPackagesPermission
diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go
index 999c72f..bcc6cc0 100644
--- a/java/prebuilt_apis.go
+++ b/java/prebuilt_apis.go
@@ -34,6 +34,13 @@
 type prebuiltApisProperties struct {
 	// list of api version directories
 	Api_dirs []string
+
+	// The sdk_version of java_import modules generated based on jar files.
+	// Defaults to "current"
+	Imports_sdk_version *string
+
+	// If set to true, compile dex for java_import modules. Defaults to false.
+	Imports_compile_dex *bool
 }
 
 type prebuiltApis struct {
@@ -74,18 +81,19 @@
 	return mctx.ModuleName() + "_" + scope + "_" + apiver + "_" + module
 }
 
-func createImport(mctx android.LoadHookContext, module string, scope string, apiver string, path string) {
+func createImport(mctx android.LoadHookContext, module, scope, apiver, path, sdkVersion string, compileDex bool) {
 	props := struct {
 		Name        *string
 		Jars        []string
 		Sdk_version *string
 		Installable *bool
+		Compile_dex *bool
 	}{}
 	props.Name = proptools.StringPtr(prebuiltApiModuleName(mctx, module, scope, apiver))
 	props.Jars = append(props.Jars, path)
-	// TODO(hansson): change to scope after migration is done.
-	props.Sdk_version = proptools.StringPtr("current")
+	props.Sdk_version = proptools.StringPtr(sdkVersion)
 	props.Installable = proptools.BoolPtr(false)
+	props.Compile_dex = proptools.BoolPtr(compileDex)
 
 	mctx.CreateModule(ImportFactory, &props)
 }
@@ -101,10 +109,10 @@
 	mctx.CreateModule(android.FileGroupFactory, &filegroupProps)
 }
 
-func getPrebuiltFiles(mctx android.LoadHookContext, name string) []string {
+func getPrebuiltFiles(mctx android.LoadHookContext, p *prebuiltApis, name string) []string {
 	mydir := mctx.ModuleDir() + "/"
 	var files []string
-	for _, apiver := range mctx.Module().(*prebuiltApis).properties.Api_dirs {
+	for _, apiver := range p.properties.Api_dirs {
 		for _, scope := range []string{"public", "system", "test", "core", "module-lib", "system-server"} {
 			vfiles, err := mctx.GlobWithDeps(mydir+apiver+"/"+scope+"/"+name, nil)
 			if err != nil {
@@ -116,16 +124,19 @@
 	return files
 }
 
-func prebuiltSdkStubs(mctx android.LoadHookContext) {
+func prebuiltSdkStubs(mctx android.LoadHookContext, p *prebuiltApis) {
 	mydir := mctx.ModuleDir() + "/"
 	// <apiver>/<scope>/<module>.jar
-	files := getPrebuiltFiles(mctx, "*.jar")
+	files := getPrebuiltFiles(mctx, p, "*.jar")
+
+	sdkVersion := proptools.StringDefault(p.properties.Imports_sdk_version, "current")
+	compileDex := proptools.BoolDefault(p.properties.Imports_compile_dex, false)
 
 	for _, f := range files {
 		// create a Import module for each jar file
 		localPath := strings.TrimPrefix(f, mydir)
 		module, apiver, scope := parseJarPath(localPath)
-		createImport(mctx, module, scope, apiver, localPath)
+		createImport(mctx, module, scope, apiver, localPath, sdkVersion, compileDex)
 	}
 }
 
@@ -140,8 +151,8 @@
 	mctx.CreateModule(SystemModulesFactory, &props)
 }
 
-func prebuiltSdkSystemModules(mctx android.LoadHookContext) {
-	for _, apiver := range mctx.Module().(*prebuiltApis).properties.Api_dirs {
+func prebuiltSdkSystemModules(mctx android.LoadHookContext, p *prebuiltApis) {
+	for _, apiver := range p.properties.Api_dirs {
 		jar := android.ExistentPathForSource(mctx,
 			mctx.ModuleDir(), apiver, "public", "core-for-system-modules.jar")
 		if jar.Valid() {
@@ -150,10 +161,10 @@
 	}
 }
 
-func prebuiltApiFiles(mctx android.LoadHookContext) {
+func prebuiltApiFiles(mctx android.LoadHookContext, p *prebuiltApis) {
 	mydir := mctx.ModuleDir() + "/"
 	// <apiver>/<scope>/api/<module>.txt
-	files := getPrebuiltFiles(mctx, "api/*.txt")
+	files := getPrebuiltFiles(mctx, p, "api/*.txt")
 
 	if len(files) == 0 {
 		mctx.ModuleErrorf("no api file found under %q", mydir)
@@ -201,10 +212,10 @@
 }
 
 func createPrebuiltApiModules(mctx android.LoadHookContext) {
-	if _, ok := mctx.Module().(*prebuiltApis); ok {
-		prebuiltApiFiles(mctx)
-		prebuiltSdkStubs(mctx)
-		prebuiltSdkSystemModules(mctx)
+	if p, ok := mctx.Module().(*prebuiltApis); ok {
+		prebuiltApiFiles(mctx, p)
+		prebuiltSdkStubs(mctx, p)
+		prebuiltSdkSystemModules(mctx, p)
 	}
 }
 
diff --git a/java/sdk.go b/java/sdk.go
index f96ecde..5a6c530 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -94,9 +94,9 @@
 	case sdkCorePlatform:
 		return "core_platform"
 	case sdkModule:
-		return "module"
+		return "module-lib"
 	case sdkSystemServer:
-		return "system_server"
+		return "system-server"
 	default:
 		return "invalid"
 	}
@@ -215,7 +215,7 @@
 		return ctx.Config().UnbundledBuildUsePrebuiltSdks()
 	} else if s.version.isNumbered() {
 		// sanity check
-		if s.kind != sdkPublic && s.kind != sdkSystem && s.kind != sdkTest {
+		if s.kind != sdkPublic && s.kind != sdkSystem && s.kind != sdkTest && s.kind != sdkModule {
 			panic(fmt.Errorf("prebuilt SDK is not not available for sdkKind=%q", s.kind))
 			return false
 		}
diff --git a/java/sdk_library.go b/java/sdk_library.go
index f2a509a..f26f61c 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -120,24 +120,23 @@
 	// the prebuilt jar.
 	sdkVersion string
 
+	// The annotation that identifies this API level, empty for the public API scope.
+	annotation string
+
 	// Extra arguments to pass to droidstubs for this scope.
-	droidstubsArgs []string
-
-	// The args that must be passed to droidstubs to generate the stubs source
-	// for this scope.
 	//
-	// The stubs source must include the definitions of everything that is in this
-	// api scope and all the scopes that this one extends.
-	droidstubsArgsForGeneratingStubsSource []string
+	// This is not used directly but is used to construct the droidstubsArgs.
+	extraArgs []string
 
-	// The args that must be passed to droidstubs to generate the API for this scope.
+	// The args that must be passed to droidstubs to generate the API and stubs source
+	// for this scope, constructed dynamically by initApiScope().
 	//
 	// The API only includes the additional members that this scope adds over the scope
 	// that it extends.
-	droidstubsArgsForGeneratingApi []string
-
-	// True if the stubs source and api can be created by the same metalava invocation.
-	createStubsSourceAndApiTogether bool
+	//
+	// The stubs source must include the definitions of everything that is in this
+	// api scope and all the scopes that this one extends.
+	droidstubsArgs []string
 
 	// Whether the api scope can be treated as unstable, and should skip compat checks.
 	unstable bool
@@ -174,21 +173,23 @@
 	// To get the args needed to generate the stubs source append all the args from
 	// this scope and all the scopes it extends as each set of args adds additional
 	// members to the stubs.
-	var stubsSourceArgs []string
-	for s := scope; s != nil; s = s.extends {
-		stubsSourceArgs = append(stubsSourceArgs, s.droidstubsArgs...)
+	var scopeSpecificArgs []string
+	if scope.annotation != "" {
+		scopeSpecificArgs = []string{"--show-annotation", scope.annotation}
 	}
-	scope.droidstubsArgsForGeneratingStubsSource = stubsSourceArgs
+	for s := scope; s != nil; s = s.extends {
+		scopeSpecificArgs = append(scopeSpecificArgs, s.extraArgs...)
 
-	// Currently the args needed to generate the API are the same as the args
-	// needed to add additional members.
-	apiArgs := scope.droidstubsArgs
-	scope.droidstubsArgsForGeneratingApi = apiArgs
+		// Ensure that the generated stubs includes all the API elements from the API scope
+		// that this scope extends.
+		if s != scope && s.annotation != "" {
+			scopeSpecificArgs = append(scopeSpecificArgs, "--show-for-stub-purposes-annotation", s.annotation)
+		}
+	}
 
-	// If the args needed to generate the stubs and API are the same then they
-	// can be generated in a single invocation of metalava, otherwise they will
-	// need separate invocations.
-	scope.createStubsSourceAndApiTogether = reflect.DeepEqual(stubsSourceArgs, apiArgs)
+	// Escape any special characters in the arguments. This is needed because droidstubs
+	// passes these directly to the shell command.
+	scope.droidstubsArgs = proptools.ShellEscapeList(scopeSpecificArgs)
 
 	return scope
 }
@@ -243,23 +244,23 @@
 		scopeSpecificProperties: func(module *SdkLibrary) *ApiScopeProperties {
 			return &module.sdkLibraryProperties.System
 		},
-		apiFilePrefix:  "system-",
-		moduleSuffix:   ".system",
-		sdkVersion:     "system_current",
-		droidstubsArgs: []string{"-showAnnotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS\\)"},
+		apiFilePrefix: "system-",
+		moduleSuffix:  ".system",
+		sdkVersion:    "system_current",
+		annotation:    "android.annotation.SystemApi(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS)",
 	})
 	apiScopeTest = initApiScope(&apiScope{
 		name:                "test",
-		extends:             apiScopePublic,
+		extends:             apiScopeSystem,
 		legacyEnabledStatus: (*SdkLibrary).generateTestAndSystemScopesByDefault,
 		scopeSpecificProperties: func(module *SdkLibrary) *ApiScopeProperties {
 			return &module.sdkLibraryProperties.Test
 		},
-		apiFilePrefix:  "test-",
-		moduleSuffix:   ".test",
-		sdkVersion:     "test_current",
-		droidstubsArgs: []string{"-showAnnotation android.annotation.TestApi"},
-		unstable:       true,
+		apiFilePrefix: "test-",
+		moduleSuffix:  ".test",
+		sdkVersion:    "test_current",
+		annotation:    "android.annotation.TestApi",
+		unstable:      true,
 	})
 	apiScopeModuleLib = initApiScope(&apiScope{
 		name:    "module-lib",
@@ -276,9 +277,7 @@
 		apiFilePrefix: "module-lib-",
 		moduleSuffix:  ".module_lib",
 		sdkVersion:    "module_current",
-		droidstubsArgs: []string{
-			"--show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES\\)",
-		},
+		annotation:    "android.annotation.SystemApi(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES)",
 	})
 	apiScopeSystemServer = initApiScope(&apiScope{
 		name:    "system-server",
@@ -295,11 +294,11 @@
 		apiFilePrefix: "system-server-",
 		moduleSuffix:  ".system_server",
 		sdkVersion:    "system_server_current",
-		droidstubsArgs: []string{
-			"--show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.SYSTEM_SERVER\\) ",
-			"--hide-annotation android.annotation.Hide",
+		annotation:    "android.annotation.SystemApi(client=android.annotation.SystemApi.Client.SYSTEM_SERVER)",
+		extraArgs: []string{
+			"--hide-annotation", "android.annotation.Hide",
 			// com.android.* classes are okay in this interface"
-			"--hide InternalClasses",
+			"--hide", "InternalClasses",
 		},
 	})
 	allApiScopes = apiScopes{
@@ -981,16 +980,8 @@
 		// Add dependencies to the stubs library
 		ctx.AddVariationDependencies(nil, apiScope.stubsTag, module.stubsLibraryModuleName(apiScope))
 
-		// If the stubs source and API cannot be generated together then add an additional dependency on
-		// the API module.
-		if apiScope.createStubsSourceAndApiTogether {
-			// Add a dependency on the stubs source in order to access both stubs source and api information.
-			ctx.AddVariationDependencies(nil, apiScope.stubsSourceAndApiTag, module.stubsSourceModuleName(apiScope))
-		} else {
-			// Add separate dependencies on the creators of the stubs source files and the API.
-			ctx.AddVariationDependencies(nil, apiScope.stubsSourceTag, module.stubsSourceModuleName(apiScope))
-			ctx.AddVariationDependencies(nil, apiScope.apiFileTag, module.apiModuleName(apiScope))
-		}
+		// Add a dependency on the stubs source in order to access both stubs source and api information.
+		ctx.AddVariationDependencies(nil, apiScope.stubsSourceAndApiTag, module.stubsSourceModuleName(apiScope))
 	}
 
 	if module.requiresRuntimeImplementationLibrary() {
@@ -1086,11 +1077,25 @@
 	return ":" + module.BaseModuleName() + "-removed.api." + apiScope.name + ".latest"
 }
 
+func childModuleVisibility(childVisibility []string) []string {
+	if childVisibility == nil {
+		// No child visibility set. The child will use the visibility of the sdk_library.
+		return nil
+	}
+
+	// Prepend an override to ignore the sdk_library's visibility, and rely on the child visibility.
+	var visibility []string
+	visibility = append(visibility, "//visibility:override")
+	visibility = append(visibility, childVisibility...)
+	return visibility
+}
+
 // Creates the implementation java library
 func (module *SdkLibrary) createImplLibrary(mctx android.DefaultableHookContext) {
-
 	moduleNamePtr := proptools.StringPtr(module.BaseModuleName())
 
+	visibility := childModuleVisibility(module.sdkLibraryProperties.Impl_library_visibility)
+
 	props := struct {
 		Name              *string
 		Visibility        []string
@@ -1098,7 +1103,7 @@
 		ConfigurationName *string
 	}{
 		Name:       proptools.StringPtr(module.implLibraryModuleName()),
-		Visibility: module.sdkLibraryProperties.Impl_library_visibility,
+		Visibility: visibility,
 		// Set the instrument property to ensure it is instrumented when instrumentation is required.
 		Instrument: true,
 
@@ -1110,6 +1115,7 @@
 		&module.properties,
 		&module.protoProperties,
 		&module.deviceProperties,
+		&module.dexProperties,
 		&module.dexpreoptProperties,
 		&module.linter.properties,
 		&props,
@@ -1149,12 +1155,7 @@
 	}{}
 
 	props.Name = proptools.StringPtr(module.stubsLibraryModuleName(apiScope))
-
-	// If stubs_library_visibility is not set then the created module will use the
-	// visibility of this module.
-	visibility := module.sdkLibraryProperties.Stubs_library_visibility
-	props.Visibility = visibility
-
+	props.Visibility = childModuleVisibility(module.sdkLibraryProperties.Stubs_library_visibility)
 	// sources are generated from the droiddoc
 	props.Srcs = []string{":" + module.stubsSourceModuleName(apiScope)}
 	sdkVersion := module.sdkVersionForStubsLibrary(mctx, apiScope)
@@ -1174,8 +1175,8 @@
 	// We compile the stubs for 1.8 in line with the main android.jar stubs, and potential
 	// interop with older developer tools that don't support 1.9.
 	props.Java_version = proptools.StringPtr("1.8")
-	if module.deviceProperties.Compile_dex != nil {
-		props.Compile_dex = module.deviceProperties.Compile_dex
+	if module.dexProperties.Compile_dex != nil {
+		props.Compile_dex = module.dexProperties.Compile_dex
 	}
 
 	// Dist the class jar artifact for sdk builds.
@@ -1191,7 +1192,7 @@
 
 // Creates a droidstubs module that creates stubs source files from the given full source
 // files and also updates and checks the API specification files.
-func (module *SdkLibrary) createStubsSourcesAndApi(mctx android.DefaultableHookContext, apiScope *apiScope, name string, createStubSources, createApi bool, scopeSpecificDroidstubsArgs []string) {
+func (module *SdkLibrary) createStubsSourcesAndApi(mctx android.DefaultableHookContext, apiScope *apiScope, name string, scopeSpecificDroidstubsArgs []string) {
 	props := struct {
 		Name                             *string
 		Visibility                       []string
@@ -1236,12 +1237,7 @@
 	// * libs (static_libs/libs)
 
 	props.Name = proptools.StringPtr(name)
-
-	// If stubs_source_visibility is not set then the created module will use the
-	// visibility of this module.
-	visibility := module.sdkLibraryProperties.Stubs_source_visibility
-	props.Visibility = visibility
-
+	props.Visibility = childModuleVisibility(module.sdkLibraryProperties.Stubs_source_visibility)
 	props.Srcs = append(props.Srcs, module.properties.Srcs...)
 	props.Sdk_version = module.deviceProperties.Sdk_version
 	props.System_modules = module.deviceProperties.System_modules
@@ -1280,64 +1276,57 @@
 	}
 	droidstubsArgs = append(droidstubsArgs, android.JoinWithPrefix(disabledWarnings, "--hide "))
 
-	if !createStubSources {
-		// Stubs are not required.
-		props.Generate_stubs = proptools.BoolPtr(false)
-	}
-
 	// Add in scope specific arguments.
 	droidstubsArgs = append(droidstubsArgs, scopeSpecificDroidstubsArgs...)
 	props.Arg_files = module.sdkLibraryProperties.Droiddoc_option_files
 	props.Args = proptools.StringPtr(strings.Join(droidstubsArgs, " "))
 
-	if createApi {
-		// List of APIs identified from the provided source files are created. They are later
-		// compared against to the not-yet-released (a.k.a current) list of APIs and to the
-		// last-released (a.k.a numbered) list of API.
-		currentApiFileName := apiScope.apiFilePrefix + "current.txt"
-		removedApiFileName := apiScope.apiFilePrefix + "removed.txt"
-		apiDir := module.getApiDir()
-		currentApiFileName = path.Join(apiDir, currentApiFileName)
-		removedApiFileName = path.Join(apiDir, removedApiFileName)
+	// List of APIs identified from the provided source files are created. They are later
+	// compared against to the not-yet-released (a.k.a current) list of APIs and to the
+	// last-released (a.k.a numbered) list of API.
+	currentApiFileName := apiScope.apiFilePrefix + "current.txt"
+	removedApiFileName := apiScope.apiFilePrefix + "removed.txt"
+	apiDir := module.getApiDir()
+	currentApiFileName = path.Join(apiDir, currentApiFileName)
+	removedApiFileName = path.Join(apiDir, removedApiFileName)
 
-		// check against the not-yet-release API
-		props.Check_api.Current.Api_file = proptools.StringPtr(currentApiFileName)
-		props.Check_api.Current.Removed_api_file = proptools.StringPtr(removedApiFileName)
+	// check against the not-yet-release API
+	props.Check_api.Current.Api_file = proptools.StringPtr(currentApiFileName)
+	props.Check_api.Current.Removed_api_file = proptools.StringPtr(removedApiFileName)
 
-		if !apiScope.unstable {
-			// check against the latest released API
-			latestApiFilegroupName := proptools.StringPtr(module.latestApiFilegroupName(apiScope))
-			props.Check_api.Last_released.Api_file = latestApiFilegroupName
-			props.Check_api.Last_released.Removed_api_file = proptools.StringPtr(
-				module.latestRemovedApiFilegroupName(apiScope))
-			props.Check_api.Ignore_missing_latest_api = proptools.BoolPtr(true)
+	if !apiScope.unstable {
+		// check against the latest released API
+		latestApiFilegroupName := proptools.StringPtr(module.latestApiFilegroupName(apiScope))
+		props.Check_api.Last_released.Api_file = latestApiFilegroupName
+		props.Check_api.Last_released.Removed_api_file = proptools.StringPtr(
+			module.latestRemovedApiFilegroupName(apiScope))
+		props.Check_api.Ignore_missing_latest_api = proptools.BoolPtr(true)
 
-			if proptools.Bool(module.sdkLibraryProperties.Api_lint.Enabled) {
-				// Enable api lint.
-				props.Check_api.Api_lint.Enabled = proptools.BoolPtr(true)
-				props.Check_api.Api_lint.New_since = latestApiFilegroupName
+		if proptools.Bool(module.sdkLibraryProperties.Api_lint.Enabled) {
+			// Enable api lint.
+			props.Check_api.Api_lint.Enabled = proptools.BoolPtr(true)
+			props.Check_api.Api_lint.New_since = latestApiFilegroupName
 
-				// If it exists then pass a lint-baseline.txt through to droidstubs.
-				baselinePath := path.Join(apiDir, apiScope.apiFilePrefix+"lint-baseline.txt")
-				baselinePathRelativeToRoot := path.Join(mctx.ModuleDir(), baselinePath)
-				paths, err := mctx.GlobWithDeps(baselinePathRelativeToRoot, nil)
-				if err != nil {
-					mctx.ModuleErrorf("error checking for presence of %s: %s", baselinePathRelativeToRoot, err)
-				}
-				if len(paths) == 1 {
-					props.Check_api.Api_lint.Baseline_file = proptools.StringPtr(baselinePath)
-				} else if len(paths) != 0 {
-					mctx.ModuleErrorf("error checking for presence of %s: expected one path, found: %v", baselinePathRelativeToRoot, paths)
-				}
+			// If it exists then pass a lint-baseline.txt through to droidstubs.
+			baselinePath := path.Join(apiDir, apiScope.apiFilePrefix+"lint-baseline.txt")
+			baselinePathRelativeToRoot := path.Join(mctx.ModuleDir(), baselinePath)
+			paths, err := mctx.GlobWithDeps(baselinePathRelativeToRoot, nil)
+			if err != nil {
+				mctx.ModuleErrorf("error checking for presence of %s: %s", baselinePathRelativeToRoot, err)
+			}
+			if len(paths) == 1 {
+				props.Check_api.Api_lint.Baseline_file = proptools.StringPtr(baselinePath)
+			} else if len(paths) != 0 {
+				mctx.ModuleErrorf("error checking for presence of %s: expected one path, found: %v", baselinePathRelativeToRoot, paths)
 			}
 		}
+	}
 
-		// Dist the api txt artifact for sdk builds.
-		if !Bool(module.sdkLibraryProperties.No_dist) {
-			props.Dist.Targets = []string{"sdk", "win_sdk"}
-			props.Dist.Dest = proptools.StringPtr(fmt.Sprintf("%v.txt", module.BaseModuleName()))
-			props.Dist.Dir = proptools.StringPtr(path.Join(module.apiDistPath(apiScope), "api"))
-		}
+	// Dist the api txt artifact for sdk builds.
+	if !Bool(module.sdkLibraryProperties.No_dist) {
+		props.Dist.Targets = []string{"sdk", "win_sdk"}
+		props.Dist.Dest = proptools.StringPtr(fmt.Sprintf("%v.txt", module.BaseModuleName()))
+		props.Dist.Dir = proptools.StringPtr(path.Join(module.apiDistPath(apiScope), "api"))
 	}
 
 	mctx.CreateModule(DroidstubsFactory, &props)
@@ -1520,22 +1509,8 @@
 	}
 
 	for _, scope := range generatedScopes {
-		stubsSourceArgs := scope.droidstubsArgsForGeneratingStubsSource
-		stubsSourceModuleName := module.stubsSourceModuleName(scope)
-
-		// If the args needed to generate the stubs and API are the same then they
-		// can be generated in a single invocation of metalava, otherwise they will
-		// need separate invocations.
-		if scope.createStubsSourceAndApiTogether {
-			// Use the stubs source name for legacy reasons.
-			module.createStubsSourcesAndApi(mctx, scope, stubsSourceModuleName, true, true, stubsSourceArgs)
-		} else {
-			module.createStubsSourcesAndApi(mctx, scope, stubsSourceModuleName, true, false, stubsSourceArgs)
-
-			apiArgs := scope.droidstubsArgsForGeneratingApi
-			apiName := module.apiModuleName(scope)
-			module.createStubsSourcesAndApi(mctx, scope, apiName, false, true, apiArgs)
-		}
+		// Use the stubs source name for legacy reasons.
+		module.createStubsSourcesAndApi(mctx, scope, module.stubsSourceModuleName(scope), scope.droidstubsArgs)
 
 		module.createStubsLibrary(mctx, scope)
 	}
diff --git a/java/system_modules.go b/java/system_modules.go
index 7394fd5..5cc546d 100644
--- a/java/system_modules.go
+++ b/java/system_modules.go
@@ -192,6 +192,7 @@
 
 			fmt.Fprintln(w, name+":", "$("+makevar+")")
 			fmt.Fprintln(w, ".PHONY:", name)
+			// TODO(b/151177513): Licenses: Doesn't go through base_rules. May have to generate meta_lic and meta_module here.
 		},
 	}
 }
diff --git a/java/testing.go b/java/testing.go
index 48e449f..f373d77 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -46,6 +46,8 @@
 		"prebuilts/sdk/30/public/framework.aidl":                   nil,
 		"prebuilts/sdk/30/system/android.jar":                      nil,
 		"prebuilts/sdk/30/system/foo.jar":                          nil,
+		"prebuilts/sdk/30/module-lib/android.jar":                  nil,
+		"prebuilts/sdk/30/module-lib/foo.jar":                      nil,
 		"prebuilts/sdk/30/public/core-for-system-modules.jar":      nil,
 		"prebuilts/sdk/current/core/android.jar":                   nil,
 		"prebuilts/sdk/current/public/android.jar":                 nil,
@@ -79,7 +81,7 @@
 		"prebuilts/sdk/30/system/api/bar-removed.txt":              nil,
 		"prebuilts/sdk/30/test/api/bar-removed.txt":                nil,
 		"prebuilts/sdk/tools/core-lambda-stubs.jar":                nil,
-		"prebuilts/sdk/Android.bp":                                 []byte(`prebuilt_apis { name: "sdk", api_dirs: ["14", "28", "30", "current"],}`),
+		"prebuilts/sdk/Android.bp":                                 []byte(`prebuilt_apis { name: "sdk", api_dirs: ["14", "28", "30", "current"], imports_sdk_version: "none", imports_compile_dex:true,}`),
 
 		// For java_sdk_library
 		"api/module-lib-current.txt":                        nil,
@@ -132,6 +134,7 @@
 				srcs: ["a.java"],
 				sdk_version: "none",
 				system_modules: "core-platform-api-stubs-system-modules",
+				compile_dex: true,
 			}
 		`, extra)
 	}
diff --git a/licenses/Android.bp b/licenses/Android.bp
new file mode 100644
index 0000000..c70d6bd
--- /dev/null
+++ b/licenses/Android.bp
@@ -0,0 +1,1256 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_visibility: ["//visibility:public"],
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+license {
+    name: "Android-Apache-2.0",
+    license_kinds: ["SPDX-license-identifier-Apache-2.0"],
+    copyright_notice: "Copyright (C) The Android Open Source Project",
+    license_text: ["LICENSE"],
+}
+
+license_kind {
+    name: "SPDX-license-identifier-0BSD",
+    conditions: ["unencumbered"],
+    url: "https://spdx.org/licenses/0BSD",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-AFL-1.1",
+    conditions: ["by_exception_only"],
+    url: "https://spdx.org/licenses/AFL-1.1.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-AFL-1.2",
+    conditions: ["by_exception_only"],
+    url: "https://spdx.org/licenses/AFL-1.2.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-AFL-2.0",
+    conditions: ["by_exception_only"],
+    url: "https://spdx.org/licenses/AFL-2.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-AFL-2.1",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/AFL-2.1.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-AFL-3.0",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/AFL-3.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-AGPL",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/AGPL.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-AGPL-1.0",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/AGPL-1.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-AGPL-1.0-only",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/AGPL-1.0-only.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-AGPL-1.0-or-later",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/AGPL-1.0-or-later.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-AGPL-3.0",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/AGPL-3.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-AGPL-3.0-only",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/AGPL-3.0-only.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-AGPL-3.0-or-later",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/AGPL-3.0-or-later.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-APSL-1.1",
+    conditions: [
+        "reciprocal",
+    ],
+    url: "https://spdx.org/licenses/APSL-1.1.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-APSL-2.0",
+    conditions: [
+        "reciprocal",
+    ],
+    url: "https://spdx.org/licenses/APSL-2.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-Apache",
+    conditions: ["notice"],
+}
+
+license_kind {
+    name: "SPDX-license-identifier-Apache-1.0",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/Apache-1.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-Apache-1.1",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/Apache-1.1.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-Apache-2.0",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/Apache-2.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-Artistic",
+    conditions: ["notice"],
+}
+
+license_kind {
+    name: "SPDX-license-identifier-Artistic-1.0",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/Artistic-1.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-Artistic-1.0-Perl",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/Artistic-1.0-Perl.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-Artistic-1.0-cl8",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/Artistic-1.0-cl8.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-Artistic-2.0",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/Artistic-2.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-BSD",
+    conditions: ["notice"],
+}
+
+license_kind {
+    name: "SPDX-license-identifier-BSD-1-Clause",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/BSD-1-Clause.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-BSD-2-Clause",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/BSD-2-Clause.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-BSD-2-Clause-FreeBSD",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/BSD-2-Clause-FreeBSD.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-BSD-2-Clause-NetBSD",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/BSD-2-Clause-NetBSD.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-BSD-2-Clause-Patent",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/BSD-2-Clause-Patent.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-BSD-3-Clause",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/BSD-3-Clause.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-BSD-3-Clause-Attribution",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/BSD-3-Clause-Attribution.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-BSD-3-Clause-Clear",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/BSD-3-Clause-Clear.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-BSD-3-Clause-LBNL",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/BSD-3-Clause-LBNL.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-BSD-3-Clause-No-Nuclear-License",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/BSD-3-Clause-No-Nuclear-License.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-BSD-3-Clause-No-Nuclear-License-2014",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/BSD-3-Clause-No-Nuclear-License-2014.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-BSD-3-Clause-No-Nuclear-Warranty",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/BSD-3-Clause-No-Nuclear-Warranty.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-BSD-3-Clause-Open-MPI",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/BSD-3-Clause-Open-MPI.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-BSD-4-Clause",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/BSD-4-Clause.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-BSD-4-Clause-UC",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/BSD-4-Clause-UC.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-BSD-Protection",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/BSD-Protection.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-BSD-Source-Code",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/BSD-Source-Code.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-BSL-1.0",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/BSL-1.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-Beerware",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/Beerware.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CC-BY",
+    conditions: ["notice"],
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CC-BY-1.0",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/CC-BY-1.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CC-BY-2.0",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/CC-BY-2.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CC-BY-2.5",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/CC-BY-2.5.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CC-BY-3.0",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/CC-BY-3.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CC-BY-4.0",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/CC-BY-4.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CC-BY-NC",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CC-BY-NC-1.0",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/CC-BY-NC-1.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CC-BY-NC-2.0",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/CC-BY-NC-2.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CC-BY-NC-2.5",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/CC-BY-NC-2.5.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CC-BY-NC-3.0",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/CC-BY-NC-3.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CC-BY-NC-4.0",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/CC-BY-NC-4.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CC-BY-NC-ND-1.0",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/CC-BY-NC-ND-1.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CC-BY-NC-ND-2.0",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/CC-BY-NC-ND-2.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CC-BY-NC-ND-2.5",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/CC-BY-NC-ND-2.5.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CC-BY-NC-ND-3.0",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/CC-BY-NC-ND-3.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CC-BY-NC-ND-4.0",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/CC-BY-NC-ND-4.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CC-BY-NC-SA-1.0",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/CC-BY-NC-SA-1.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CC-BY-NC-SA-2.0",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/CC-BY-NC-SA-2.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CC-BY-NC-SA-2.5",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/CC-BY-NC-SA-2.5.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CC-BY-NC-SA-3.0",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/CC-BY-NC-SA-3.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CC-BY-NC-SA-4.0",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/CC-BY-NC-SA-4.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CC-BY-ND",
+    conditions: ["restricted"],
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CC-BY-ND-1.0",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/CC-BY-ND-1.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CC-BY-ND-2.0",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/CC-BY-ND-2.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CC-BY-ND-2.5",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/CC-BY-ND-2.5.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CC-BY-ND-3.0",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/CC-BY-ND-3.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CC-BY-ND-4.0",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/CC-BY-ND-4.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CC-BY-SA",
+    conditions: ["restricted"],
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CC-BY-SA-1.0",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/CC-BY-SA-1.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CC-BY-SA-2.0",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/CC-BY-SA-2.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CC-BY-SA-2.5",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/CC-BY-SA-2.5.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CC-BY-SA-3.0",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/CC-BY-SA-3.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CC-BY-SA-4.0",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/CC-BY-SA-4.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CC-BY-SA-ND",
+    conditions: ["restricted"],
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CC0-1.0",
+    conditions: ["unencumbered"],
+    url: "https://spdx.org/licenses/CC0-1.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CDDL",
+    conditions: ["reciprocal"],
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CDDL-1.0",
+    conditions: ["reciprocal"],
+    url: "https://spdx.org/licenses/CDLL-1.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CDDL-1.1",
+    conditions: ["reciprocal"],
+    url: "https://spdx.org/licenses/CDLL-1.1.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CPAL-1.0",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/CPAL-1.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-CPL-1.0",
+    conditions: ["reciprocal"],
+    url: "https://spdx.org/licenses/CPL-1.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-EPL",
+    conditions: ["reciprocal"],
+}
+
+license_kind {
+    name: "SPDX-license-identifier-EPL-1.0",
+    conditions: ["reciprocal"],
+    url: "https://spdx.org/licenses/EPL-1.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-EPL-2.0",
+    conditions: ["reciprocal"],
+    url: "https://spdx.org/licenses/EPL-2.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-EUPL",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+}
+
+license_kind {
+    name: "SPDX-license-identifier-EUPL-1.0",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/EUPL-1.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-EUPL-1.1",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/EUPL-1.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-EUPL-1.2",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/EUPL-1.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-FSFAP",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/FSFAP",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-FTL",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/FTL.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-GFDL",
+    conditions: ["by_exception_only"],
+}
+
+license_kind {
+    name: "SPDX-license-identifier-GPL",
+    conditions: ["restricted"],
+}
+
+license_kind {
+    name: "SPDX-license-identifier-GPL-1.0",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/GPL-1.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-GPL-1.0+",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/GPL-1.0+.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-GPL-1.0-only",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/GPL-1.0-only.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-GPL-1.0-or-later",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/GPL-1.0-or-later.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-GPL-2.0",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/GPL-2.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-GPL-2.0+",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/GPL-2.0+.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-GPL-2.0-only",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/GPL-2.0-only.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-GPL-2.0-or-later",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/GPL-2.0-or-later.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-GPL-2.0-with-GCC-exception",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/GPL-2.0-with-GCC-exception.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-GPL-2.0-with-autoconf-exception",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/GPL-2.0-with-autoconf-exception.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-GPL-2.0-with-bison-exception",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/GPL-2.0-with-bison-exception.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-GPL-2.0-with-classpath-exception",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/GPL-2.0-with-classpath-exception.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-GPL-2.0-with-font-exception",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/GPL-2.0-with-font-exception.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-GPL-3.0",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/GPL-3.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-GPL-3.0+",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/GPL-3.0+.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-GPL-3.0-only",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/GPL-3.0-only.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-GPL-3.0-or-later",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/GPL-3.0-or-later.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-GPL-3.0-with-GCC-exception",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/GPL-3.0-with-GCC-exception.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-GPL-3.0-with-autoconf-exception",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/GPL-3.0-with-autoconf-exception.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-GPL-with-classpath-exception",
+    conditions: ["restricted"],
+}
+
+license_kind {
+    name: "SPDX-license-identifier-HPND",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/HPND.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-ICU",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/ICU.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-ISC",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/ISC.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-JSON",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/JSON.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-LGPL",
+    conditions: ["restricted"],
+}
+
+license_kind {
+    name: "SPDX-license-identifier-LGPL-2.0",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/LGPL-2.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-LGPL-2.0+",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/LGPL-2.0+.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-LGPL-2.0-only",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/LGPL-2.0-only.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-LGPL-2.0-or-later",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/LGPL-2.0-or-later.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-LGPL-2.1",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/LGPL-2.1.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-LGPL-2.1+",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/LGPL-2.1+.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-LGPL-2.1-only",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/LGPL-2.1-only.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-LGPL-2.1-or-later",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/LGPL-2.1-or-later.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-LGPL-3.0",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/LGPL-3.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-LGPL-3.0+",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/LGPL-3.0+.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-LGPL-3.0-only",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/LGPL-3.0-only.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-LGPL-3.0-or-later",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/LGPL-3.0-or-later.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-LGPLLR",
+    conditions: ["restricted"],
+    url: "https://spdx.org/licenses/LGPLLR.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-LPL-1.02",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/LPL-1.02.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-MIT",
+    conditions: ["notice"],
+}
+
+license_kind {
+    name: "SPDX-license-identifier-MIT-0",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/MIT-0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-MIT-CMU",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/MIT-CMU.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-MIT-advertising",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/MIT-advertising.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-MIT-enna",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/MIT-enna.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-MIT-feh",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/MIT-feh.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-MITNFA",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/MITNFA.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-MPL",
+    conditions: ["reciprocal"],
+}
+
+license_kind {
+    name: "SPDX-license-identifier-MPL-1.0",
+    conditions: ["reciprocal"],
+    url: "https://spdx.org/licenses/MPL-1.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-MPL-1.1",
+    conditions: ["reciprocal"],
+    url: "https://spdx.org/licenses/MPL-1.1.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-MPL-2.0",
+    conditions: ["reciprocal"],
+    url: "https://spdx.org/licenses/MPL-2.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-MPL-2.0-no-copyleft-exception",
+    conditions: ["reciprocal"],
+    url: "https://spdx.org/licenses/MPL-2.0-no-copyleft-exception.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-MS-PL",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/MS-PL.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-MS-RL",
+    conditions: ["by_exception_only"],
+    url: "https://spdx.org/licenses/MS-RL.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-NCSA",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/NCSA.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-OFL",
+    conditions: ["by_exception_only"],
+}
+
+license_kind {
+    name: "SPDX-license-identifier-OFL-1.0",
+    conditions: ["by_exception_only"],
+    url: "https://spdx.org/licenses/OFL-1.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-OFL-1.0-RFN",
+    conditions: ["by_exception_only"],
+    url: "https://spdx.org/licenses/OFL-1.0-RFN.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-OFL-1.0-no-RFN",
+    conditions: ["by_exception_only"],
+    url: "https://spdx.org/licenses/OFL-1.0-no-RFN.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-OFL-1.1",
+    conditions: ["by_exception_only"],
+    url: "https://spdx.org/licenses/OFL-1.1.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-OFL-1.1-RFN",
+    conditions: ["by_exception_only"],
+    url: "https://spdx.org/licenses/OFL-1.1-RFN.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-OFL-1.1-no-RFN",
+    conditions: ["by_exception_only"],
+    url: "https://spdx.org/licenses/OFL-1.1-no-RFN.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-OpenSSL",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/OpenSSL.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-PSF-2.0",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/PSF-2.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-SISSL",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/SISSL.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-SISSL-1.2",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/SISSL-1.2.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-SPL-1.0",
+    conditions: [
+        "by_exception_only",
+        "reciprocal",
+    ],
+    url: "https://spdx.org/licenses/SPL-1.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-SSPL",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/SSPL.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-UPL-1.0",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/UPL-1.-.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-Unicode-DFS",
+    conditions: ["notice"],
+}
+
+license_kind {
+    name: "SPDX-license-identifier-Unicode-DFS-2015",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/Unicode-DFS-2015.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-Unicode-DFS-2016",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/Unicode-DFS-2016.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-Unlicense",
+    conditions: ["unencumbered"],
+    url: "https://spdx.org/licenses/Unlicense.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-W3C",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/W3C.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-W3C-19980720",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/W3C-19980720.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-W3C-20150513",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/W3C-20150513.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-WTFPL",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/WTFPL.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-Watcom-1.0",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/Watcom-1.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-Xnet",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/Xnet.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-ZPL",
+    conditions: ["notice"],
+}
+
+license_kind {
+    name: "SPDX-license-identifier-ZPL-1.1",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/ZPL-1.1.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-ZPL-2.0",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/ZPL-2.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-ZPL-2.1",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/ZPL-2.1.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-Zend-2.0",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/Zend-2.0.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-Zlib",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/Zlib.html",
+}
+
+license_kind {
+    name: "SPDX-license-identifier-libtiff",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/libtiff.html",
+}
+
+// Legacy license kinds -- do not add new references -- use an spdx kind instead.
+license_kind {
+    name: "legacy_unknown",
+    conditions: ["by_exception_only"],
+}
+
+license_kind {
+    name: "legacy_unencumbered",
+    conditions: ["unencumbered"],
+}
+
+license_kind {
+    name: "legacy_permissive",
+    conditions: ["permissive"],
+}
+
+license_kind {
+    name: "legacy_notice",
+    conditions: ["notice"],
+}
+
+license_kind {
+    name: "legacy_reciprocal",
+    conditions: ["reciprocal"],
+}
+
+license_kind {
+    name: "legacy_restricted",
+    conditions: ["restricted"],
+}
+
+license_kind {
+    name: "legacy_by_exception_only",
+    conditions: ["by_exception_only"],
+}
+
+license_kind {
+    name: "legacy_not_a_contribution",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+}
+
+license_kind {
+    name: "legacy_not_allowed",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+}
+
+license_kind {
+    name: "legacy_proprietary",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+        "proprietary",
+    ],
+}
diff --git a/licenses/LICENSE b/licenses/LICENSE
new file mode 100644
index 0000000..dae0406
--- /dev/null
+++ b/licenses/LICENSE
@@ -0,0 +1,214 @@
+
+   Copyright (c) The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+
+   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.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   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.
diff --git a/python/androidmk.go b/python/androidmk.go
index 247b80d..648b14d 100644
--- a/python/androidmk.go
+++ b/python/androidmk.go
@@ -16,84 +16,74 @@
 
 import (
 	"android/soong/android"
-	"fmt"
-	"io"
 	"path/filepath"
 	"strings"
 )
 
 type subAndroidMkProvider interface {
-	AndroidMk(*Module, *android.AndroidMkData)
+	AndroidMk(*Module, *android.AndroidMkEntries)
 }
 
-func (p *Module) subAndroidMk(data *android.AndroidMkData, obj interface{}) {
+func (p *Module) subAndroidMk(entries *android.AndroidMkEntries, obj interface{}) {
 	if p.subAndroidMkOnce == nil {
 		p.subAndroidMkOnce = make(map[subAndroidMkProvider]bool)
 	}
 	if androidmk, ok := obj.(subAndroidMkProvider); ok {
 		if !p.subAndroidMkOnce[androidmk] {
 			p.subAndroidMkOnce[androidmk] = true
-			androidmk.AndroidMk(p, data)
+			androidmk.AndroidMk(p, entries)
 		}
 	}
 }
 
-func (p *Module) AndroidMk() android.AndroidMkData {
-	ret := android.AndroidMkData{OutputFile: p.installSource}
+func (p *Module) AndroidMkEntries() []android.AndroidMkEntries {
+	entries := android.AndroidMkEntries{OutputFile: p.installSource}
 
-	p.subAndroidMk(&ret, p.installer)
+	p.subAndroidMk(&entries, p.installer)
 
-	return ret
+	return []android.AndroidMkEntries{entries}
 }
 
-func (p *binaryDecorator) AndroidMk(base *Module, ret *android.AndroidMkData) {
-	ret.Class = "EXECUTABLES"
+func (p *binaryDecorator) AndroidMk(base *Module, entries *android.AndroidMkEntries) {
+	entries.Class = "EXECUTABLES"
 
-	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
-		if len(p.binaryProperties.Test_suites) > 0 {
-			fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE :=",
-				strings.Join(p.binaryProperties.Test_suites, " "))
-		}
+	entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+		entries.AddCompatibilityTestSuites(p.binaryProperties.Test_suites...)
 	})
-	base.subAndroidMk(ret, p.pythonInstaller)
+	base.subAndroidMk(entries, p.pythonInstaller)
 }
 
-func (p *testDecorator) AndroidMk(base *Module, ret *android.AndroidMkData) {
-	ret.Class = "NATIVE_TESTS"
+func (p *testDecorator) AndroidMk(base *Module, entries *android.AndroidMkEntries) {
+	entries.Class = "NATIVE_TESTS"
 
-	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
-		if len(p.binaryDecorator.binaryProperties.Test_suites) > 0 {
-			fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE :=",
-				strings.Join(p.binaryDecorator.binaryProperties.Test_suites, " "))
-		}
+	entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+		entries.AddCompatibilityTestSuites(p.binaryDecorator.binaryProperties.Test_suites...)
 		if p.testConfig != nil {
-			fmt.Fprintln(w, "LOCAL_FULL_TEST_CONFIG :=",
-				p.testConfig.String())
+			entries.SetString("LOCAL_FULL_TEST_CONFIG", p.testConfig.String())
 		}
 
-		if !BoolDefault(p.binaryProperties.Auto_gen_config, true) {
-			fmt.Fprintln(w, "LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG := true")
-		}
+		entries.SetBoolIfTrue("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", !BoolDefault(p.binaryProperties.Auto_gen_config, true))
+
 	})
-	base.subAndroidMk(ret, p.binaryDecorator.pythonInstaller)
+	base.subAndroidMk(entries, p.binaryDecorator.pythonInstaller)
 }
 
-func (installer *pythonInstaller) AndroidMk(base *Module, ret *android.AndroidMkData) {
+func (installer *pythonInstaller) AndroidMk(base *Module, entries *android.AndroidMkEntries) {
 	// Soong installation is only supported for host modules. Have Make
 	// installation trigger Soong installation.
 	if base.Target().Os.Class == android.Host {
-		ret.OutputFile = android.OptionalPathForPath(installer.path)
+		entries.OutputFile = android.OptionalPathForPath(installer.path)
 	}
 
-	ret.Required = append(ret.Required, "libc++")
-	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
+	entries.Required = append(entries.Required, "libc++")
+	entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
 		path, file := filepath.Split(installer.path.ToMakePath().String())
 		stem := strings.TrimSuffix(file, filepath.Ext(file))
 
-		fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := "+filepath.Ext(file))
-		fmt.Fprintln(w, "LOCAL_MODULE_PATH := "+path)
-		fmt.Fprintln(w, "LOCAL_MODULE_STEM := "+stem)
-		fmt.Fprintln(w, "LOCAL_SHARED_LIBRARIES := "+strings.Join(installer.androidMkSharedLibs, " "))
-		fmt.Fprintln(w, "LOCAL_CHECK_ELF_FILES := false")
+		entries.SetString("LOCAL_MODULE_SUFFIX", filepath.Ext(file))
+		entries.SetString("LOCAL_MODULE_PATH", path)
+		entries.SetString("LOCAL_MODULE_STEM", stem)
+		entries.AddStrings("LOCAL_SHARED_LIBRARIES", installer.androidMkSharedLibs...)
+		entries.SetBool("LOCAL_CHECK_ELF_FILES", false)
 	})
 }
diff --git a/python/python.go b/python/python.go
index 8b912be..83ce42d 100644
--- a/python/python.go
+++ b/python/python.go
@@ -185,7 +185,7 @@
 
 var _ PythonDependency = (*Module)(nil)
 
-var _ android.AndroidMkDataProvider = (*Module)(nil)
+var _ android.AndroidMkEntriesProvider = (*Module)(nil)
 
 func (p *Module) Init() android.Module {
 
@@ -251,6 +251,18 @@
 	return android.OptionalPathForPath(p.installer.(*binaryDecorator).path)
 }
 
+func (p *Module) OutputFiles(tag string) (android.Paths, error) {
+	switch tag {
+	case "":
+		if outputFile := p.installSource; outputFile.Valid() {
+			return android.Paths{outputFile.Path()}, nil
+		}
+		return android.Paths{}, nil
+	default:
+		return nil, fmt.Errorf("unsupported module reference tag %q", tag)
+	}
+}
+
 func (p *Module) isEmbeddedLauncherEnabled(actual_version string) bool {
 	switch actual_version {
 	case pyVersion2:
diff --git a/rust/androidmk.go b/rust/androidmk.go
index 0fba739..758e63f 100644
--- a/rust/androidmk.go
+++ b/rust/androidmk.go
@@ -15,10 +15,7 @@
 package rust
 
 import (
-	"fmt"
-	"io"
 	"path/filepath"
-	"strings"
 
 	"android/soong/android"
 )
@@ -26,14 +23,14 @@
 type AndroidMkContext interface {
 	Name() string
 	Target() android.Target
-	subAndroidMk(*android.AndroidMkData, interface{})
+	subAndroidMk(*android.AndroidMkEntries, interface{})
 }
 
 type subAndroidMkProvider interface {
-	AndroidMk(AndroidMkContext, *android.AndroidMkData)
+	AndroidMk(AndroidMkContext, *android.AndroidMkEntries)
 }
 
-func (mod *Module) subAndroidMk(data *android.AndroidMkData, obj interface{}) {
+func (mod *Module) subAndroidMk(data *android.AndroidMkEntries, obj interface{}) {
 	if mod.subAndroidMkOnce == nil {
 		mod.subAndroidMkOnce = make(map[subAndroidMkProvider]bool)
 	}
@@ -45,27 +42,17 @@
 	}
 }
 
-func (mod *Module) AndroidMk() android.AndroidMkData {
-	ret := android.AndroidMkData{
+func (mod *Module) AndroidMkEntries() []android.AndroidMkEntries {
+	ret := android.AndroidMkEntries{
 		OutputFile: mod.outputFile,
 		Include:    "$(BUILD_SYSTEM)/soong_rust_prebuilt.mk",
-		Extra: []android.AndroidMkExtraFunc{
-			func(w io.Writer, outputFile android.Path) {
-				if len(mod.Properties.AndroidMkRlibs) > 0 {
-					fmt.Fprintln(w, "LOCAL_RLIB_LIBRARIES := "+strings.Join(mod.Properties.AndroidMkRlibs, " "))
-				}
-				if len(mod.Properties.AndroidMkDylibs) > 0 {
-					fmt.Fprintln(w, "LOCAL_DYLIB_LIBRARIES := "+strings.Join(mod.Properties.AndroidMkDylibs, " "))
-				}
-				if len(mod.Properties.AndroidMkProcMacroLibs) > 0 {
-					fmt.Fprintln(w, "LOCAL_PROC_MACRO_LIBRARIES := "+strings.Join(mod.Properties.AndroidMkProcMacroLibs, " "))
-				}
-				if len(mod.Properties.AndroidMkSharedLibs) > 0 {
-					fmt.Fprintln(w, "LOCAL_SHARED_LIBRARIES := "+strings.Join(mod.Properties.AndroidMkSharedLibs, " "))
-				}
-				if len(mod.Properties.AndroidMkStaticLibs) > 0 {
-					fmt.Fprintln(w, "LOCAL_STATIC_LIBRARIES := "+strings.Join(mod.Properties.AndroidMkStaticLibs, " "))
-				}
+		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+			func(entries *android.AndroidMkEntries) {
+				entries.AddStrings("LOCAL_RLIB_LIBRARIES", mod.Properties.AndroidMkRlibs...)
+				entries.AddStrings("LOCAL_DYLIB_LIBRARIES", mod.Properties.AndroidMkDylibs...)
+				entries.AddStrings("LOCAL_PROC_MACRO_LIBRARIES", mod.Properties.AndroidMkProcMacroLibs...)
+				entries.AddStrings("LOCAL_SHARED_LIBRARIES", mod.Properties.AndroidMkSharedLibs...)
+				entries.AddStrings("LOCAL_STATIC_LIBRARIES", mod.Properties.AndroidMkStaticLibs...)
 			},
 		},
 	}
@@ -74,39 +61,37 @@
 
 	ret.SubName += mod.Properties.SubName
 
-	return ret
+	return []android.AndroidMkEntries{ret}
 }
 
-func (binary *binaryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+func (binary *binaryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkEntries) {
 	ctx.subAndroidMk(ret, binary.baseCompiler)
 
+	if binary.distFile.Valid() {
+		ret.DistFiles = android.MakeDefaultDistFiles(binary.distFile.Path())
+	}
+
 	ret.Class = "EXECUTABLES"
-	ret.DistFile = binary.distFile
-	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
-		fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", binary.unstrippedOutputFile.String())
+	ret.ExtraEntries = append(ret.ExtraEntries, func(entries *android.AndroidMkEntries) {
+		entries.SetPath("LOCAL_SOONG_UNSTRIPPED_BINARY", binary.unstrippedOutputFile)
 	})
 }
 
-func (test *testDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+func (test *testDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkEntries) {
 	test.binaryDecorator.AndroidMk(ctx, ret)
 	ret.Class = "NATIVE_TESTS"
 	ret.SubName = test.getMutatedModuleSubName(ctx.Name())
-	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
-		if len(test.Properties.Test_suites) > 0 {
-			fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE :=",
-				strings.Join(test.Properties.Test_suites, " "))
-		}
+	ret.ExtraEntries = append(ret.ExtraEntries, func(entries *android.AndroidMkEntries) {
+		entries.AddCompatibilityTestSuites(test.Properties.Test_suites...)
 		if test.testConfig != nil {
-			fmt.Fprintln(w, "LOCAL_FULL_TEST_CONFIG :=", test.testConfig.String())
+			entries.SetString("LOCAL_FULL_TEST_CONFIG", test.testConfig.String())
 		}
-		if !BoolDefault(test.Properties.Auto_gen_config, true) {
-			fmt.Fprintln(w, "LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG := true")
-		}
+		entries.SetBoolIfTrue("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", !BoolDefault(test.Properties.Auto_gen_config, true))
 	})
 	// TODO(chh): add test data with androidMkWriteTestData(test.data, ctx, ret)
 }
 
-func (library *libraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+func (library *libraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkEntries) {
 	ctx.subAndroidMk(ret, library.baseCompiler)
 
 	if library.rlib() {
@@ -119,33 +104,38 @@
 		ret.Class = "SHARED_LIBRARIES"
 	}
 
-	ret.DistFile = library.distFile
-	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
+	if library.distFile.Valid() {
+		ret.DistFiles = android.MakeDefaultDistFiles(library.distFile.Path())
+	}
+
+	ret.ExtraEntries = append(ret.ExtraEntries, func(entries *android.AndroidMkEntries) {
 		if !library.rlib() {
-			fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", library.unstrippedOutputFile.String())
+			entries.SetPath("LOCAL_SOONG_UNSTRIPPED_BINARY", library.unstrippedOutputFile)
 		}
 	})
 }
 
-func (procMacro *procMacroDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+func (procMacro *procMacroDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkEntries) {
 	ctx.subAndroidMk(ret, procMacro.baseCompiler)
 
 	ret.Class = "PROC_MACRO_LIBRARIES"
-	ret.DistFile = procMacro.distFile
+	if procMacro.distFile.Valid() {
+		ret.DistFiles = android.MakeDefaultDistFiles(procMacro.distFile.Path())
+	}
 
 }
 
-func (compiler *baseCompiler) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+func (compiler *baseCompiler) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkEntries) {
 	// Soong installation is only supported for host modules. Have Make
 	// installation trigger Soong installation.
 	if ctx.Target().Os.Class == android.Host {
 		ret.OutputFile = android.OptionalPathForPath(compiler.path)
 	}
-	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
+	ret.ExtraEntries = append(ret.ExtraEntries, func(entries *android.AndroidMkEntries) {
 		path, file := filepath.Split(compiler.path.ToMakePath().String())
 		stem, suffix, _ := android.SplitFileExt(file)
-		fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := "+suffix)
-		fmt.Fprintln(w, "LOCAL_MODULE_PATH := "+path)
-		fmt.Fprintln(w, "LOCAL_MODULE_STEM := "+stem)
+		entries.SetString("LOCAL_MODULE_SUFFIX", suffix)
+		entries.SetString("LOCAL_MODULE_PATH", path)
+		entries.SetString("LOCAL_MODULE_STEM", stem)
 	})
 }
diff --git a/scripts/OWNERS b/scripts/OWNERS
index 9e97a60..8751e75 100644
--- a/scripts/OWNERS
+++ b/scripts/OWNERS
@@ -1,2 +1,3 @@
 per-file system-clang-format,system-clang-format-2 = enh@google.com,smoreland@google.com
 per-file build-mainline-modules.sh = ngeoffray@google.com,paulduffin@google.com,mast@google.com
+per-file gen_ndk*.sh = sophiez@google.com, allenhair@google.com
diff --git a/scripts/check_do_not_merge.sh b/scripts/check_do_not_merge.sh
new file mode 100755
index 0000000..ad6a0a9
--- /dev/null
+++ b/scripts/check_do_not_merge.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+if git show -s --format=%s $1 | grep -qE '(DO NOT MERGE)|(RESTRICT AUTOMERGE)'; then
+    cat >&2 <<EOF
+DO NOT MERGE and RESTRICT AUTOMERGE very often lead to unintended results
+and are not allowed to be used in this project.
+Please use the Merged-In tag to be more explicit about where this change
+should merge to. Google-internal documentation exists at go/merged-in
+
+If this check is mis-triggering or you know Merged-In is incorrect in this
+situation you can bypass this check with \`repo upload --no-verify\`.
+EOF
+    exit 1
+fi
diff --git a/scripts/gen_ndk_backedby_apex.sh b/scripts/gen_ndk_backedby_apex.sh
new file mode 100755
index 0000000..4abaaba
--- /dev/null
+++ b/scripts/gen_ndk_backedby_apex.sh
@@ -0,0 +1,72 @@
+#!/bin/bash -e
+
+# 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.
+
+# Generates NDK API txt file used by Mainline modules. NDK APIs would have value
+# "UND" in Ndx column and have suffix "@LIB_NAME" in Name column.
+# For example, current line llvm-readelf output is:
+# 1: 00000000     0     FUNC      GLOBAL  DEFAULT   UND   dlopen@LIBC
+# After the parse function below "dlopen" would be write to the output file.
+printHelp() {
+    echo "**************************** Usage Instructions ****************************"
+    echo "This script is used to generate the Mainline modules backed-by NDK symbols."
+    echo ""
+    echo "To run this script use: ./gen_ndk_backed_by_apex.sh \$OUTPUT_FILE_PATH \$NDK_LIB_NAME_LIST \$MODULE_LIB1 \$MODULE_LIB2..."
+    echo "For example: If output write to /backedby.txt then the command would be:"
+    echo "./gen_ndk_backed_by_apex.sh /backedby.txt /ndkLibList.txt lib1.so lib2.so"
+    echo "If the module1 is backing lib1 then the backedby.txt would contains: "
+    echo "lib1"
+}
+
+contains() {
+  val="$1"
+  shift
+  for x in "$@"; do
+    if [ "$x" = "$val" ]; then
+      return 0
+    fi
+  done
+  return 1
+}
+
+
+genBackedByList() {
+  out="$1"
+  shift
+  ndk_list="$1"
+  shift
+  rm -f "$out"
+  touch "$out"
+  while IFS= read -r line
+  do
+    soFileName=$(echo "$line" | sed 's/\(.*so\).*/\1/')
+    if [[ ! -z "$soFileName" && "$soFileName" != *"#"* ]]
+    then
+      if contains "$soFileName" "$@"; then
+        echo "$soFileName" >> "$out"
+      fi
+    fi
+  done < "$ndk_list"
+}
+
+if [[ "$1" == "help" ]]
+then
+  printHelp
+elif [[ "$#" -lt 2 ]]
+then
+  echo "Wrong argument length. Expecting at least 2 argument representing output path, path to ndk library list, followed by a list of libraries in the Mainline module."
+else
+  genBackedByList "$@"
+fi
diff --git a/scripts/gen_ndk_usedby_apex.sh b/scripts/gen_ndk_usedby_apex.sh
new file mode 100755
index 0000000..0d3ed5a
--- /dev/null
+++ b/scripts/gen_ndk_usedby_apex.sh
@@ -0,0 +1,72 @@
+#!/bin/bash -e
+
+# 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.
+
+# Generates NDK API txt file used by Mainline modules. NDK APIs would have value
+# "UND" in Ndx column and have suffix "@LIB_NAME" in Name column.
+# For example, current line llvm-readelf output is:
+# 1: 00000000     0     FUNC      GLOBAL  DEFAULT   UND   dlopen@LIBC
+# After the parse function below "dlopen" would be write to the output file.
+printHelp() {
+    echo "**************************** Usage Instructions ****************************"
+    echo "This script is used to generate the Mainline modules used-by NDK symbols."
+    echo ""
+    echo "To run this script use: ./ndk_usedby_module.sh \$BINARY_IMAGE_DIRECTORY \$BINARY_LLVM_PATH \$OUTPUT_FILE_PATH"
+    echo "For example: If all the module image files that you would like to run is under directory '/myModule' and output write to /myModule.txt then the command would be:"
+    echo "./ndk_usedby_module.sh /myModule \$BINARY_LLVM_PATH /myModule.txt"
+}
+
+parseReadelfOutput() {
+  while IFS= read -r line
+  do
+      if [[ $line = *FUNC*GLOBAL*UND*@* ]] ;
+      then
+          echo "$line" | sed -r 's/.*UND (.*@.*)/\1/g' >> "$2"
+      fi
+  done < "$1"
+  echo "" >> "$2"
+}
+
+unzipJarAndApk() {
+  tmpUnzippedDir="$1"/tmpUnzipped
+  [[ -e "$tmpUnzippedDir" ]] && rm -rf "$tmpUnzippedDir"
+  mkdir -p "$tmpUnzippedDir"
+  find "$1" -name "*.jar" -exec unzip -o {} -d "$tmpUnzippedDir" \;
+  find "$1" -name "*.apk" -exec unzip -o {} -d "$tmpUnzippedDir" \;
+  find "$tmpUnzippedDir" -name "*.MF" -exec rm {} \;
+}
+
+lookForExecFile() {
+  dir="$1"
+  readelf="$2"
+  find "$dir" -type f -name "*.so"  -exec "$2" --dyn-symbols {} >> "$dir"/../tmpReadelf.txt \;
+  find "$dir" -type f -perm /111 ! -name "*.so"  -exec "$2" --dyn-symbols {} >> "$dir"/../tmpReadelf.txt \;
+}
+
+if [[ "$1" == "help" ]]
+then
+  printHelp
+elif [[ "$#" -ne 3 ]]
+then
+  echo "Wrong argument length. Expecting 3 argument representing image file directory, llvm-readelf tool path, output path."
+else
+  unzipJarAndApk "$1"
+  lookForExecFile "$1" "$2"
+  tmpReadelfOutput="$1/../tmpReadelf.txt"
+  [[ -e "$3" ]] && rm "$3"
+  parseReadelfOutput "$tmpReadelfOutput" "$3"
+  [[ -e "$tmpReadelfOutput" ]] && rm "$tmpReadelfOutput"
+  rm -rf "$1/tmpUnzipped"
+fi
\ No newline at end of file
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index db395c5..95b57d9 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -1392,8 +1392,8 @@
 .intermediates/myjavalib.stubs.source.system/android_common/myjavalib.stubs.source.system_api.txt -> sdk_library/system/myjavalib.txt
 .intermediates/myjavalib.stubs.source.system/android_common/myjavalib.stubs.source.system_removed.txt -> sdk_library/system/myjavalib-removed.txt
 .intermediates/myjavalib.stubs.module_lib/android_common/javac/myjavalib.stubs.module_lib.jar -> sdk_library/module-lib/myjavalib-stubs.jar
-.intermediates/myjavalib.api.module_lib/android_common/myjavalib.api.module_lib_api.txt -> sdk_library/module-lib/myjavalib.txt
-.intermediates/myjavalib.api.module_lib/android_common/myjavalib.api.module_lib_removed.txt -> sdk_library/module-lib/myjavalib-removed.txt
+.intermediates/myjavalib.stubs.source.module_lib/android_common/myjavalib.stubs.source.module_lib_api.txt -> sdk_library/module-lib/myjavalib.txt
+.intermediates/myjavalib.stubs.source.module_lib/android_common/myjavalib.stubs.source.module_lib_removed.txt -> sdk_library/module-lib/myjavalib-removed.txt
 `),
 		checkMergeZips(
 			".intermediates/mysdk/common_os/tmp/sdk_library/public/myjavalib_stub_sources.zip",
diff --git a/sdk/sdk.go b/sdk/sdk.go
index cb5a605..b9b8199 100644
--- a/sdk/sdk.go
+++ b/sdk/sdk.go
@@ -291,7 +291,7 @@
 	return []android.AndroidMkEntries{android.AndroidMkEntries{
 		Class:      "FAKE",
 		OutputFile: s.snapshotFile,
-		DistFile:   s.snapshotFile,
+		DistFiles:  android.MakeDefaultDistFiles(s.snapshotFile.Path()),
 		Include:    "$(BUILD_PHONY_PACKAGE)",
 		ExtraFooters: []android.AndroidMkExtraFootersFunc{
 			func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
diff --git a/sh/Android.bp b/sh/Android.bp
index 0f40c5f..e5ffeef 100644
--- a/sh/Android.bp
+++ b/sh/Android.bp
@@ -5,6 +5,7 @@
         "blueprint",
         "soong",
         "soong-android",
+        "soong-cc",
         "soong-tradefed",
     ],
     srcs: [
diff --git a/sh/sh_binary.go b/sh/sh_binary.go
index ab0490a..5272d41 100644
--- a/sh/sh_binary.go
+++ b/sh/sh_binary.go
@@ -17,11 +17,14 @@
 import (
 	"fmt"
 	"path/filepath"
+	"sort"
 	"strings"
 
+	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
+	"android/soong/cc"
 	"android/soong/tradefed"
 )
 
@@ -88,6 +91,20 @@
 	// doesn't exist next to the Android.bp, this attribute doesn't need to be set to true
 	// explicitly.
 	Auto_gen_config *bool
+
+	// list of binary modules that should be installed alongside the test
+	Data_bins []string `android:"path,arch_variant"`
+
+	// list of library modules that should be installed alongside the test
+	Data_libs []string `android:"path,arch_variant"`
+
+	// list of device binary modules that should be installed alongside the test.
+	// Only available for host sh_test modules.
+	Data_device_bins []string `android:"path,arch_variant"`
+
+	// list of device library modules that should be installed alongside the test.
+	// Only available for host sh_test modules.
+	Data_device_libs []string `android:"path,arch_variant"`
 }
 
 type ShBinary struct {
@@ -109,6 +126,8 @@
 
 	data       android.Paths
 	testConfig android.Path
+
+	dataModules map[string]android.Path
 }
 
 func (s *ShBinary) HostToolPath() android.OptionalPath {
@@ -190,6 +209,50 @@
 	}
 }
 
+type dependencyTag struct {
+	blueprint.BaseDependencyTag
+	name string
+}
+
+var (
+	shTestDataBinsTag       = dependencyTag{name: "dataBins"}
+	shTestDataLibsTag       = dependencyTag{name: "dataLibs"}
+	shTestDataDeviceBinsTag = dependencyTag{name: "dataDeviceBins"}
+	shTestDataDeviceLibsTag = dependencyTag{name: "dataDeviceLibs"}
+)
+
+var sharedLibVariations = []blueprint.Variation{{Mutator: "link", Variation: "shared"}}
+
+func (s *ShTest) DepsMutator(ctx android.BottomUpMutatorContext) {
+	s.ShBinary.DepsMutator(ctx)
+
+	ctx.AddFarVariationDependencies(ctx.Target().Variations(), shTestDataBinsTag, s.testProperties.Data_bins...)
+	ctx.AddFarVariationDependencies(append(ctx.Target().Variations(), sharedLibVariations...),
+		shTestDataLibsTag, s.testProperties.Data_libs...)
+	if ctx.Target().Os.Class == android.Host && len(ctx.Config().Targets[android.Android]) > 0 {
+		deviceVariations := ctx.Config().Targets[android.Android][0].Variations()
+		ctx.AddFarVariationDependencies(deviceVariations, shTestDataDeviceBinsTag, s.testProperties.Data_device_bins...)
+		ctx.AddFarVariationDependencies(append(deviceVariations, sharedLibVariations...),
+			shTestDataDeviceLibsTag, s.testProperties.Data_device_libs...)
+	} else if ctx.Target().Os.Class != android.Host {
+		if len(s.testProperties.Data_device_bins) > 0 {
+			ctx.PropertyErrorf("data_device_bins", "only available for host modules")
+		}
+		if len(s.testProperties.Data_device_libs) > 0 {
+			ctx.PropertyErrorf("data_device_libs", "only available for host modules")
+		}
+	}
+}
+
+func (s *ShTest) addToDataModules(ctx android.ModuleContext, relPath string, path android.Path) {
+	if _, exists := s.dataModules[relPath]; exists {
+		ctx.ModuleErrorf("data modules have a conflicting installation path, %v - %s, %s",
+			relPath, s.dataModules[relPath].String(), path.String())
+		return
+	}
+	s.dataModules[relPath] = path
+}
+
 func (s *ShTest) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	s.ShBinary.generateAndroidBuildActions(ctx)
 	testDir := "nativetest"
@@ -215,6 +278,43 @@
 	}
 	s.testConfig = tradefed.AutoGenShellTestConfig(ctx, s.testProperties.Test_config,
 		s.testProperties.Test_config_template, s.testProperties.Test_suites, configs, s.testProperties.Auto_gen_config, s.outputFilePath.Base())
+
+	s.dataModules = make(map[string]android.Path)
+	ctx.VisitDirectDeps(func(dep android.Module) {
+		depTag := ctx.OtherModuleDependencyTag(dep)
+		switch depTag {
+		case shTestDataBinsTag, shTestDataDeviceBinsTag:
+			path := android.OutputFileForModule(ctx, dep, "")
+			s.addToDataModules(ctx, path.Base(), path)
+		case shTestDataLibsTag, shTestDataDeviceLibsTag:
+			if cc, isCc := dep.(*cc.Module); isCc {
+				// Copy to an intermediate output directory to append "lib[64]" to the path,
+				// so that it's compatible with the default rpath values.
+				var relPath string
+				if cc.Arch().ArchType.Multilib == "lib64" {
+					relPath = filepath.Join("lib64", cc.OutputFile().Path().Base())
+				} else {
+					relPath = filepath.Join("lib", cc.OutputFile().Path().Base())
+				}
+				if _, exist := s.dataModules[relPath]; exist {
+					return
+				}
+				relocatedLib := android.PathForModuleOut(ctx, "relocated", relPath)
+				ctx.Build(pctx, android.BuildParams{
+					Rule:   android.Cp,
+					Input:  cc.OutputFile().Path(),
+					Output: relocatedLib,
+				})
+				s.addToDataModules(ctx, relPath, relocatedLib)
+				return
+			}
+			property := "data_libs"
+			if depTag == shTestDataDeviceBinsTag {
+				property = "data_device_libs"
+			}
+			ctx.PropertyErrorf(property, "%q of type %q is not supported", dep.Name(), ctx.OtherModuleType(dep))
+		}
+	})
 }
 
 func (s *ShTest) InstallInData() bool {
@@ -229,8 +329,7 @@
 		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
 			func(entries *android.AndroidMkEntries) {
 				s.customAndroidMkEntries(entries)
-
-				entries.AddStrings("LOCAL_COMPATIBILITY_SUITE", s.testProperties.Test_suites...)
+				entries.AddCompatibilityTestSuites(s.testProperties.Test_suites...)
 				if s.testConfig != nil {
 					entries.SetPath("LOCAL_FULL_TEST_CONFIG", s.testConfig)
 				}
@@ -243,6 +342,15 @@
 					path = strings.TrimSuffix(path, rel)
 					entries.AddStrings("LOCAL_TEST_DATA", path+":"+rel)
 				}
+				relPaths := make([]string, 0)
+				for relPath, _ := range s.dataModules {
+					relPaths = append(relPaths, relPath)
+				}
+				sort.Strings(relPaths)
+				for _, relPath := range relPaths {
+					dir := strings.TrimSuffix(s.dataModules[relPath].String(), relPath)
+					entries.AddStrings("LOCAL_TEST_DATA", dir+":"+relPath)
+				}
 			},
 		},
 	}}
diff --git a/sh/sh_binary_test.go b/sh/sh_binary_test.go
index 6c0d96a..232a281 100644
--- a/sh/sh_binary_test.go
+++ b/sh/sh_binary_test.go
@@ -3,10 +3,12 @@
 import (
 	"io/ioutil"
 	"os"
+	"path/filepath"
 	"reflect"
 	"testing"
 
 	"android/soong/android"
+	"android/soong/cc"
 )
 
 var buildDir string
@@ -46,6 +48,9 @@
 	ctx := android.NewTestArchContext()
 	ctx.RegisterModuleType("sh_test", ShTestFactory)
 	ctx.RegisterModuleType("sh_test_host", ShTestHostFactory)
+
+	cc.RegisterRequiredBuildComponentsForTest(ctx)
+
 	ctx.Register(config)
 	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
 	android.FailIfErrored(t, errs)
@@ -78,6 +83,65 @@
 	}
 }
 
+func TestShTest_dataModules(t *testing.T) {
+	ctx, config := testShBinary(t, `
+		sh_test {
+			name: "foo",
+			src: "test.sh",
+			host_supported: true,
+			data_bins: ["bar"],
+			data_libs: ["libbar"],
+		}
+
+		cc_binary {
+			name: "bar",
+			host_supported: true,
+			shared_libs: ["libbar"],
+			no_libcrt: true,
+			nocrt: true,
+			system_shared_libs: [],
+			stl: "none",
+		}
+
+		cc_library {
+			name: "libbar",
+			host_supported: true,
+			no_libcrt: true,
+			nocrt: true,
+			system_shared_libs: [],
+			stl: "none",
+		}
+	`)
+
+	buildOS := android.BuildOs.String()
+	arches := []string{"android_arm64_armv8-a", buildOS + "_x86_64"}
+	for _, arch := range arches {
+		variant := ctx.ModuleForTests("foo", arch)
+
+		libExt := ".so"
+		if arch == "darwin_x86_64" {
+			libExt = ".dylib"
+		}
+		relocated := variant.Output("relocated/lib64/libbar" + libExt)
+		expectedInput := filepath.Join(buildDir, ".intermediates/libbar/"+arch+"_shared/libbar"+libExt)
+		if relocated.Input.String() != expectedInput {
+			t.Errorf("Unexpected relocation input, expected: %q, actual: %q",
+				expectedInput, relocated.Input.String())
+		}
+
+		mod := variant.Module().(*ShTest)
+		entries := android.AndroidMkEntriesForTest(t, config, "", mod)[0]
+		expectedData := []string{
+			filepath.Join(buildDir, ".intermediates/bar", arch, ":bar"),
+			filepath.Join(buildDir, ".intermediates/foo", arch, "relocated/:lib64/libbar"+libExt),
+		}
+		actualData := entries.EntryMap["LOCAL_TEST_DATA"]
+		if !reflect.DeepEqual(expectedData, actualData) {
+			t.Errorf("Unexpected test data, expected: %q, actual: %q", expectedData, actualData)
+		}
+	}
+}
+
 func TestShTestHost(t *testing.T) {
 	ctx, _ := testShBinary(t, `
 		sh_test_host {
@@ -97,3 +161,53 @@
 		t.Errorf("host bit is not set for a sh_test_host module.")
 	}
 }
+
+func TestShTestHost_dataDeviceModules(t *testing.T) {
+	ctx, config := testShBinary(t, `
+		sh_test_host {
+			name: "foo",
+			src: "test.sh",
+			data_device_bins: ["bar"],
+			data_device_libs: ["libbar"],
+		}
+
+		cc_binary {
+			name: "bar",
+			shared_libs: ["libbar"],
+			no_libcrt: true,
+			nocrt: true,
+			system_shared_libs: [],
+			stl: "none",
+		}
+
+		cc_library {
+			name: "libbar",
+			no_libcrt: true,
+			nocrt: true,
+			system_shared_libs: [],
+			stl: "none",
+		}
+	`)
+
+	buildOS := android.BuildOs.String()
+	variant := ctx.ModuleForTests("foo", buildOS+"_x86_64")
+
+	relocated := variant.Output("relocated/lib64/libbar.so")
+	expectedInput := filepath.Join(buildDir, ".intermediates/libbar/android_arm64_armv8-a_shared/libbar.so")
+	if relocated.Input.String() != expectedInput {
+		t.Errorf("Unexpected relocation input, expected: %q, actual: %q",
+			expectedInput, relocated.Input.String())
+	}
+
+	mod := variant.Module().(*ShTest)
+	entries := android.AndroidMkEntriesForTest(t, config, "", mod)[0]
+	expectedData := []string{
+		filepath.Join(buildDir, ".intermediates/bar/android_arm64_armv8-a/:bar"),
+		// libbar has been relocated, and so has a variant that matches the host arch.
+		filepath.Join(buildDir, ".intermediates/foo/"+buildOS+"_x86_64/relocated/:lib64/libbar.so"),
+	}
+	actualData := entries.EntryMap["LOCAL_TEST_DATA"]
+	if !reflect.DeepEqual(expectedData, actualData) {
+		t.Errorf("Unexpected test data, expected: %q, actual: %q", expectedData, actualData)
+	}
+}
diff --git a/tradefed/Android.bp b/tradefed/Android.bp
index 6e5e533..f4e8334 100644
--- a/tradefed/Android.bp
+++ b/tradefed/Android.bp
@@ -12,3 +12,20 @@
     ],
     pluginFor: ["soong_build"],
 }
+
+bootstrap_go_package {
+    name: "soong-suite-harness",
+    pkgPath: "android/soong/suite_harness",
+    deps: [
+        "blueprint",
+        "blueprint-pathtools",
+        "blueprint-proptools",
+        "soong",
+        "soong-android",
+        "soong-java",
+    ],
+    srcs: [
+        "tradefed_binary.go",
+    ],
+    pluginFor: ["soong_build"],
+}
diff --git a/tradefed/tradefed_binary.go b/tradefed/tradefed_binary.go
new file mode 100644
index 0000000..7960fdc
--- /dev/null
+++ b/tradefed/tradefed_binary.go
@@ -0,0 +1,164 @@
+// Copyright 2018 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 suite_harness
+
+import (
+	"strings"
+
+	"github.com/google/blueprint"
+
+	"android/soong/android"
+	"android/soong/java"
+)
+
+var pctx = android.NewPackageContext("android/soong/suite_harness")
+
+func init() {
+	android.RegisterModuleType("tradefed_binary_host", tradefedBinaryFactory)
+
+	pctx.Import("android/soong/android")
+}
+
+type TradefedBinaryProperties struct {
+	Short_name                    string
+	Full_name                     string
+	Version                       string
+	Prepend_platform_version_name bool
+}
+
+// tradefedBinaryFactory creates an empty module for the tradefed_binary module type,
+// which is a java_binary with some additional processing in tradefedBinaryLoadHook.
+func tradefedBinaryFactory() android.Module {
+	props := &TradefedBinaryProperties{}
+	module := java.BinaryHostFactory()
+	module.AddProperties(props)
+	android.AddLoadHook(module, tradefedBinaryLoadHook(props))
+
+	return module
+}
+
+const genSuffix = "-gen"
+
+// tradefedBinaryLoadHook adds extra resources and libraries to tradefed_binary modules.
+func tradefedBinaryLoadHook(tfb *TradefedBinaryProperties) func(ctx android.LoadHookContext) {
+	return func(ctx android.LoadHookContext) {
+		genName := ctx.ModuleName() + genSuffix
+		version := tfb.Version
+		if tfb.Prepend_platform_version_name {
+			version = ctx.Config().PlatformVersionName() + tfb.Version
+		}
+
+		// Create a submodule that generates the test-suite-info.properties file
+		// and copies DynamicConfig.xml if it is present.
+		ctx.CreateModule(tradefedBinaryGenFactory,
+			&TradefedBinaryGenProperties{
+				Name:       &genName,
+				Short_name: tfb.Short_name,
+				Full_name:  tfb.Full_name,
+				Version:    version,
+			})
+
+		props := struct {
+			Java_resources []string
+			Libs           []string
+		}{}
+
+		// Add dependencies required by all tradefed_binary modules.
+		props.Libs = []string{
+			"tradefed",
+			"tradefed-test-framework",
+			"loganalysis",
+			"hosttestlib",
+			"compatibility-host-util",
+		}
+
+		// Add the files generated by the submodule created above to the resources.
+		props.Java_resources = []string{":" + genName}
+
+		ctx.AppendProperties(&props)
+
+	}
+}
+
+type TradefedBinaryGenProperties struct {
+	Name       *string
+	Short_name string
+	Full_name  string
+	Version    string
+}
+
+type tradefedBinaryGen struct {
+	android.ModuleBase
+
+	properties TradefedBinaryGenProperties
+
+	gen android.Paths
+}
+
+func tradefedBinaryGenFactory() android.Module {
+	tfg := &tradefedBinaryGen{}
+	tfg.AddProperties(&tfg.properties)
+	android.InitAndroidModule(tfg)
+	return tfg
+}
+
+func (tfg *tradefedBinaryGen) DepsMutator(android.BottomUpMutatorContext) {}
+
+var tradefedBinaryGenRule = pctx.StaticRule("tradefedBinaryGenRule", blueprint.RuleParams{
+	Command: `rm -f $out && touch $out && ` +
+		`echo "# This file is auto generated by Android.mk. Do not modify." >> $out && ` +
+		`echo "build_number = $$(cat ${buildNumberFile})" >> $out && ` +
+		`echo "target_arch = ${arch}" >> $out && ` +
+		`echo "name = ${name}" >> $out && ` +
+		`echo "fullname = ${fullname}" >> $out && ` +
+		`echo "version = ${version}" >> $out`,
+}, "buildNumberFile", "arch", "name", "fullname", "version")
+
+func (tfg *tradefedBinaryGen) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	buildNumberFile := ctx.Config().BuildNumberFile(ctx)
+	outputFile := android.PathForModuleOut(ctx, "test-suite-info.properties")
+	ctx.Build(pctx, android.BuildParams{
+		Rule:      tradefedBinaryGenRule,
+		Output:    outputFile,
+		OrderOnly: android.Paths{buildNumberFile},
+		Args: map[string]string{
+			"buildNumberFile": buildNumberFile.String(),
+			"arch":            ctx.Config().DevicePrimaryArchType().String(),
+			"name":            tfg.properties.Short_name,
+			"fullname":        tfg.properties.Full_name,
+			"version":         tfg.properties.Version,
+		},
+	})
+
+	tfg.gen = append(tfg.gen, outputFile)
+
+	dynamicConfig := android.ExistentPathForSource(ctx, ctx.ModuleDir(), "DynamicConfig.xml")
+	if dynamicConfig.Valid() {
+		outputFile := android.PathForModuleOut(ctx, strings.TrimSuffix(ctx.ModuleName(), genSuffix)+".dynamic")
+		ctx.Build(pctx, android.BuildParams{
+			Rule:   android.Cp,
+			Input:  dynamicConfig.Path(),
+			Output: outputFile,
+		})
+
+		tfg.gen = append(tfg.gen, outputFile)
+	}
+}
+
+func (tfg *tradefedBinaryGen) Srcs() android.Paths {
+	return append(android.Paths(nil), tfg.gen...)
+}
+
+var _ android.SourceFileProducer = (*tradefedBinaryGen)(nil)
diff --git a/ui/build/cleanbuild.go b/ui/build/cleanbuild.go
index 0bcdccb..594aeff 100644
--- a/ui/build/cleanbuild.go
+++ b/ui/build/cleanbuild.go
@@ -131,7 +131,8 @@
 		productOut("installer"),
 		productOut("odm"),
 		productOut("sysloader"),
-		productOut("testcases"))
+		productOut("testcases"),
+		productOut("symbols"))
 }
 
 // Since products and build variants (unfortunately) shared the same
diff --git a/ui/metrics/metrics.go b/ui/metrics/metrics.go
index ab57ee5..1018eb3 100644
--- a/ui/metrics/metrics.go
+++ b/ui/metrics/metrics.go
@@ -18,7 +18,6 @@
 	"io/ioutil"
 	"os"
 	"runtime"
-	"strings"
 	"time"
 
 	"github.com/golang/protobuf/proto"
@@ -139,10 +138,6 @@
 	m.metrics.BuildDateTimestamp = proto.Int64(buildTimestamp.UnixNano() / int64(time.Second))
 }
 
-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 {
 	// ignore the error if the hostname could not be retrieved as it
diff --git a/ui/metrics/metrics_proto/metrics.pb.go b/ui/metrics/metrics_proto/metrics.pb.go
index a2cfe5d..5e214a8 100644
--- a/ui/metrics/metrics_proto/metrics.pb.go
+++ b/ui/metrics/metrics_proto/metrics.pb.go
@@ -200,9 +200,7 @@
 	Total       *PerfInfo    `protobuf:"bytes,21,opt,name=total" json:"total,omitempty"`
 	BuildConfig *BuildConfig `protobuf:"bytes,23,opt,name=build_config,json=buildConfig" json:"build_config,omitempty"`
 	// The hostname of the machine.
-	Hostname *string `protobuf:"bytes,24,opt,name=hostname" json:"hostname,omitempty"`
-	// The build command that the user entered to the build system.
-	BuildCommand         *string  `protobuf:"bytes,26,opt,name=build_command,json=buildCommand" json:"build_command,omitempty"`
+	Hostname             *string  `protobuf:"bytes,24,opt,name=hostname" json:"hostname,omitempty"`
 	XXX_NoUnkeyedLiteral struct{} `json:"-"`
 	XXX_unrecognized     []byte   `json:"-"`
 	XXX_sizecache        int32    `json:"-"`
@@ -399,13 +397,6 @@
 	return ""
 }
 
-func (m *MetricsBase) GetBuildCommand() string {
-	if m != nil && m.BuildCommand != nil {
-		return *m.BuildCommand
-	}
-	return ""
-}
-
 type BuildConfig struct {
 	UseGoma              *bool    `protobuf:"varint,1,opt,name=use_goma,json=useGoma" json:"use_goma,omitempty"`
 	UseRbe               *bool    `protobuf:"varint,2,opt,name=use_rbe,json=useRbe" json:"use_rbe,omitempty"`
@@ -703,65 +694,64 @@
 func init() { proto.RegisterFile("metrics.proto", fileDescriptor_6039342a2ba47b72) }
 
 var fileDescriptor_6039342a2ba47b72 = []byte{
-	// 951 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0xdf, 0x4e, 0xdb, 0x48,
-	0x17, 0xaf, 0x49, 0x20, 0xf1, 0x71, 0x92, 0xba, 0x03, 0x15, 0x2e, 0x15, 0xfa, 0x22, 0x7f, 0xdb,
-	0x15, 0x17, 0x5b, 0x5a, 0xb1, 0x15, 0xaa, 0x50, 0xb5, 0x12, 0x04, 0x84, 0xba, 0x08, 0x52, 0x0d,
-	0xa4, 0x5b, 0xed, 0x5e, 0x58, 0x13, 0x7b, 0x02, 0xee, 0xc6, 0x9e, 0x68, 0x66, 0x5c, 0x2d, 0x0f,
-	0xb1, 0x8f, 0xb9, 0xda, 0xd7, 0x58, 0xcd, 0x19, 0xdb, 0x18, 0x29, 0x55, 0x51, 0xef, 0xec, 0xf3,
-	0xfb, 0x33, 0xbf, 0x33, 0x9e, 0x39, 0x32, 0xf4, 0x33, 0xae, 0x65, 0x1a, 0xab, 0xdd, 0x85, 0x14,
-	0x5a, 0x90, 0x75, 0x25, 0x44, 0x7e, 0x1d, 0x4d, 0x8b, 0x74, 0x9e, 0x44, 0x25, 0x14, 0xfe, 0x0b,
-	0xe0, 0x9d, 0xdb, 0xe7, 0x23, 0xa6, 0x38, 0x79, 0x0d, 0x1b, 0x96, 0x90, 0x30, 0xcd, 0x23, 0x9d,
-	0x66, 0x5c, 0x69, 0x96, 0x2d, 0x02, 0x67, 0xe8, 0xec, 0xb4, 0x28, 0x41, 0xec, 0x98, 0x69, 0x7e,
-	0x55, 0x21, 0xe4, 0x19, 0x74, 0xad, 0x22, 0x4d, 0x82, 0x95, 0xa1, 0xb3, 0xe3, 0xd2, 0x0e, 0xbe,
-	0xbf, 0x4f, 0xc8, 0x01, 0x3c, 0x5b, 0xcc, 0x99, 0x9e, 0x09, 0x99, 0x45, 0x5f, 0xb8, 0x54, 0xa9,
-	0xc8, 0xa3, 0x58, 0x24, 0x3c, 0x67, 0x19, 0x0f, 0x5a, 0xc8, 0xdd, 0xac, 0x08, 0x1f, 0x2d, 0x3e,
-	0x2a, 0x61, 0xf2, 0x02, 0x06, 0x9a, 0xc9, 0x6b, 0xae, 0xa3, 0x85, 0x14, 0x49, 0x11, 0xeb, 0xa0,
-	0x8d, 0x82, 0xbe, 0xad, 0x7e, 0xb0, 0x45, 0x92, 0xc0, 0x46, 0x49, 0xb3, 0x21, 0xbe, 0x30, 0x99,
-	0xb2, 0x5c, 0x07, 0xab, 0x43, 0x67, 0x67, 0xb0, 0xf7, 0x72, 0x77, 0x49, 0xcf, 0xbb, 0x8d, 0x7e,
-	0x77, 0x8f, 0x0c, 0xf2, 0xd1, 0x8a, 0x0e, 0x5a, 0x27, 0x17, 0xa7, 0x94, 0x58, 0xbf, 0x26, 0x40,
-	0xc6, 0xe0, 0x95, 0xab, 0x30, 0x19, 0xdf, 0x04, 0x6b, 0x68, 0xfe, 0xe2, 0x9b, 0xe6, 0x87, 0x32,
-	0xbe, 0x39, 0xe8, 0x4c, 0x2e, 0xce, 0x2e, 0xc6, 0xbf, 0x5d, 0x50, 0xb0, 0x16, 0xa6, 0x48, 0x76,
-	0x61, 0xbd, 0x61, 0x58, 0xa7, 0xee, 0x60, 0x8b, 0x4f, 0xee, 0x88, 0x55, 0x80, 0x9f, 0xa0, 0x8c,
-	0x15, 0xc5, 0x8b, 0xa2, 0xa6, 0x77, 0x91, 0xee, 0x5b, 0x64, 0xb4, 0x28, 0x2a, 0xf6, 0x19, 0xb8,
-	0x37, 0x42, 0x95, 0x61, 0xdd, 0xef, 0x0a, 0xdb, 0x35, 0x06, 0x18, 0x95, 0x42, 0x1f, 0xcd, 0xf6,
-	0xf2, 0xc4, 0x1a, 0xc2, 0x77, 0x19, 0x7a, 0xc6, 0x64, 0x2f, 0x4f, 0xd0, 0x73, 0x13, 0x3a, 0xe8,
-	0x29, 0x54, 0xe0, 0x61, 0x0f, 0x6b, 0xe6, 0x75, 0xac, 0x48, 0x58, 0x2e, 0x26, 0x54, 0xc4, 0xff,
-	0xd2, 0x92, 0x05, 0x3d, 0x84, 0x3d, 0x0b, 0x9f, 0x98, 0x52, 0xcd, 0x89, 0xa5, 0x50, 0xca, 0x58,
-	0xf4, 0xef, 0x38, 0x23, 0x53, 0x1b, 0x2b, 0xf2, 0x23, 0x3c, 0x6e, 0x70, 0x30, 0xf6, 0xc0, 0x1e,
-	0x9f, 0x9a, 0x85, 0x41, 0x5e, 0xc2, 0x7a, 0x83, 0x57, 0xb7, 0xf8, 0xd8, 0x6e, 0x6c, 0xcd, 0x6d,
-	0xe4, 0x16, 0x85, 0x8e, 0x92, 0x54, 0x06, 0xbe, 0xcd, 0x2d, 0x0a, 0x7d, 0x9c, 0x4a, 0xf2, 0x0b,
-	0x78, 0x8a, 0xeb, 0x62, 0x11, 0x69, 0x21, 0xe6, 0x2a, 0x78, 0x32, 0x6c, 0xed, 0x78, 0x7b, 0xdb,
-	0x4b, 0xb7, 0xe8, 0x03, 0x97, 0xb3, 0xf7, 0xf9, 0x4c, 0x50, 0x40, 0xc5, 0x95, 0x11, 0x90, 0x03,
-	0x70, 0xff, 0x64, 0x3a, 0x8d, 0x64, 0x91, 0xab, 0x80, 0x3c, 0x44, 0xdd, 0x35, 0x7c, 0x5a, 0xe4,
-	0x8a, 0xbc, 0x03, 0xb0, 0x4c, 0x14, 0xaf, 0x3f, 0x44, 0xec, 0x22, 0x5a, 0xa9, 0xf3, 0x34, 0xff,
-	0xcc, 0xac, 0x7a, 0xe3, 0x41, 0x6a, 0x14, 0xa0, 0xfa, 0x67, 0x58, 0xd5, 0x42, 0xb3, 0x79, 0xf0,
-	0x74, 0xe8, 0x7c, 0x5b, 0x68, 0xb9, 0x64, 0x04, 0x3d, 0x4b, 0x88, 0x45, 0x3e, 0x4b, 0xaf, 0x83,
-	0x4d, 0xd4, 0x0e, 0x97, 0x6a, 0xf1, 0x1a, 0x8e, 0x90, 0x47, 0xbd, 0xe9, 0xdd, 0x0b, 0xd9, 0x02,
-	0x3c, 0xa2, 0x38, 0x4a, 0x02, 0xfc, 0x16, 0xf5, 0x3b, 0xf9, 0x3f, 0xf4, 0xab, 0x05, 0xb2, 0x8c,
-	0xe5, 0x49, 0xb0, 0x85, 0x84, 0x5e, 0xa9, 0xc7, 0x5a, 0xf8, 0x1a, 0x7a, 0xf7, 0xee, 0x78, 0x17,
-	0xda, 0x93, 0xcb, 0x13, 0xea, 0x3f, 0x22, 0x7d, 0x70, 0xcd, 0xd3, 0xf1, 0xc9, 0xd1, 0xe4, 0xd4,
-	0x77, 0x48, 0x07, 0xcc, 0x5c, 0xf0, 0x57, 0xc2, 0x77, 0xd0, 0xc6, 0x53, 0xe0, 0x41, 0x75, 0xaa,
-	0xfd, 0x47, 0x06, 0x3d, 0xa4, 0xe7, 0xbe, 0x43, 0x5c, 0x58, 0x3d, 0xa4, 0xe7, 0xfb, 0x6f, 0xfc,
-	0x15, 0x53, 0xfb, 0xf4, 0x76, 0xdf, 0x6f, 0x11, 0x80, 0xb5, 0x4f, 0x6f, 0xf7, 0xa3, 0xfd, 0x37,
-	0x7e, 0x3b, 0xbc, 0x06, 0xaf, 0xd1, 0x8c, 0x19, 0x9b, 0x85, 0xe2, 0xd1, 0xb5, 0xc8, 0x18, 0x0e,
-	0xd7, 0x2e, 0xed, 0x14, 0x8a, 0x9f, 0x8a, 0x8c, 0x99, 0x53, 0x66, 0x20, 0x39, 0xe5, 0x38, 0x50,
-	0xbb, 0x74, 0xad, 0x50, 0x9c, 0x4e, 0x39, 0xf9, 0x01, 0x06, 0x33, 0x21, 0x63, 0x1e, 0xd5, 0xca,
-	0x16, 0xe2, 0x3d, 0xac, 0x4e, 0xac, 0x3c, 0xfc, 0xdb, 0x81, 0x6e, 0xb5, 0xe5, 0x84, 0x40, 0x3b,
-	0xe1, 0x2a, 0xc6, 0x25, 0x5c, 0x8a, 0xcf, 0xa6, 0x86, 0xdb, 0x66, 0xa7, 0x35, 0x3e, 0x93, 0x6d,
-	0x00, 0xa5, 0x99, 0xd4, 0x38, 0xf2, 0xd1, 0xb6, 0x4d, 0x5d, 0xac, 0x98, 0x49, 0x4f, 0x9e, 0x83,
-	0x2b, 0x39, 0x9b, 0x5b, 0xb4, 0x8d, 0x68, 0xd7, 0x14, 0x10, 0xdc, 0x06, 0xc8, 0x78, 0x26, 0xe4,
-	0xad, 0xc9, 0x85, 0x93, 0xb7, 0x4d, 0x5d, 0x5b, 0x99, 0x28, 0x1e, 0xfe, 0xe3, 0xc0, 0xe0, 0x5c,
-	0x24, 0xc5, 0x9c, 0x5f, 0xdd, 0x2e, 0x38, 0xa6, 0xfa, 0xa3, 0x3a, 0x01, 0xea, 0x56, 0x69, 0x9e,
-	0x61, 0xba, 0xc1, 0xde, 0xab, 0xe5, 0x23, 0xe5, 0x9e, 0xd4, 0x1e, 0x88, 0x4b, 0x94, 0x35, 0x86,
-	0xcb, 0xf4, 0xae, 0x4a, 0xfe, 0x07, 0x5e, 0x86, 0x9a, 0x48, 0xdf, 0x2e, 0xaa, 0x2e, 0x21, 0xab,
-	0x6d, 0xcc, 0x36, 0xe6, 0x45, 0x16, 0x89, 0x59, 0x64, 0x8b, 0x0a, 0xfb, 0xed, 0xd3, 0x5e, 0x5e,
-	0x64, 0xe3, 0x99, 0x5d, 0x4f, 0x85, 0xaf, 0xca, 0xef, 0x55, 0xba, 0xde, 0xfb, 0xe8, 0x2e, 0xac,
-	0x5e, 0x8e, 0xc7, 0x17, 0xe6, 0x74, 0x74, 0xa1, 0x7d, 0x7e, 0x78, 0x76, 0xe2, 0xaf, 0x84, 0x73,
-	0xd8, 0x1a, 0xc9, 0x54, 0xa7, 0x31, 0x9b, 0x4f, 0x14, 0x97, 0xbf, 0x8a, 0x42, 0xe6, 0xfc, 0xb6,
-	0x9c, 0x88, 0xf5, 0xa6, 0x3b, 0x8d, 0x4d, 0x3f, 0x80, 0x4e, 0xd9, 0x25, 0xa6, 0xfc, 0xda, 0x1d,
-	0x68, 0x0c, 0x55, 0x5a, 0x09, 0xc2, 0x29, 0x3c, 0x5f, 0xb2, 0x9a, 0xaa, 0x96, 0x1b, 0x41, 0x3b,
-	0x2e, 0x3e, 0xab, 0xc0, 0xc1, 0x0b, 0xbd, 0x7c, 0x67, 0xbf, 0x9e, 0x96, 0xa2, 0xf8, 0xe8, 0xe9,
-	0xef, 0xe5, 0x3f, 0x43, 0xa9, 0x88, 0xf0, 0x47, 0xe2, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x94,
-	0x52, 0xed, 0xc2, 0x58, 0x08, 0x00, 0x00,
+	// 934 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0x6f, 0x6b, 0xdb, 0x46,
+	0x18, 0xaf, 0x62, 0x25, 0x96, 0x1e, 0xc5, 0xae, 0x7a, 0x69, 0x89, 0xda, 0x12, 0x66, 0xc4, 0x3a,
+	0xf2, 0x62, 0x4d, 0x4b, 0x56, 0x42, 0x09, 0x65, 0x90, 0x38, 0x21, 0x74, 0x21, 0x71, 0xb9, 0xc4,
+	0x5d, 0xd9, 0x5e, 0x08, 0x59, 0x3a, 0x3b, 0xea, 0x2c, 0x9d, 0xb9, 0x3b, 0x95, 0xf9, 0x43, 0xec,
+	0x4b, 0xed, 0xbb, 0xec, 0x7b, 0x8c, 0x7b, 0x4e, 0x52, 0x14, 0x70, 0x69, 0xe8, 0x3b, 0xe9, 0xf9,
+	0xfd, 0xb9, 0xdf, 0x3d, 0x77, 0x7a, 0x10, 0xf4, 0x72, 0xa6, 0x44, 0x96, 0xc8, 0xbd, 0x85, 0xe0,
+	0x8a, 0x93, 0x2d, 0xc9, 0x79, 0x31, 0x8b, 0x26, 0x65, 0x36, 0x4f, 0xa3, 0x0a, 0x0a, 0xff, 0x05,
+	0xf0, 0x2e, 0xcc, 0xf3, 0x71, 0x2c, 0x19, 0x79, 0x0d, 0x8f, 0x0d, 0x21, 0x8d, 0x15, 0x8b, 0x54,
+	0x96, 0x33, 0xa9, 0xe2, 0x7c, 0x11, 0x58, 0x03, 0x6b, 0xb7, 0x43, 0x09, 0x62, 0x27, 0xb1, 0x62,
+	0xd7, 0x35, 0x42, 0x9e, 0x82, 0x63, 0x14, 0x59, 0x1a, 0xac, 0x0d, 0xac, 0x5d, 0x97, 0x76, 0xf1,
+	0xfd, 0x7d, 0x4a, 0x0e, 0xe1, 0xe9, 0x62, 0x1e, 0xab, 0x29, 0x17, 0x79, 0xf4, 0x85, 0x09, 0x99,
+	0xf1, 0x22, 0x4a, 0x78, 0xca, 0x8a, 0x38, 0x67, 0x41, 0x07, 0xb9, 0xdb, 0x35, 0xe1, 0xa3, 0xc1,
+	0x87, 0x15, 0x4c, 0x5e, 0x40, 0x5f, 0xc5, 0x62, 0xc6, 0x54, 0xb4, 0x10, 0x3c, 0x2d, 0x13, 0x15,
+	0xd8, 0x28, 0xe8, 0x99, 0xea, 0x07, 0x53, 0x24, 0x29, 0x3c, 0xae, 0x68, 0x26, 0xc4, 0x97, 0x58,
+	0x64, 0x71, 0xa1, 0x82, 0xf5, 0x81, 0xb5, 0xdb, 0xdf, 0x7f, 0xb9, 0xb7, 0x62, 0xcf, 0x7b, 0xad,
+	0xfd, 0xee, 0x1d, 0x6b, 0xe4, 0xa3, 0x11, 0x1d, 0x76, 0x4e, 0x2f, 0xcf, 0x28, 0x31, 0x7e, 0x6d,
+	0x80, 0x8c, 0xc0, 0xab, 0x56, 0x89, 0x45, 0x72, 0x13, 0x6c, 0xa0, 0xf9, 0x8b, 0x6f, 0x9a, 0x1f,
+	0x89, 0xe4, 0xe6, 0xb0, 0x3b, 0xbe, 0x3c, 0xbf, 0x1c, 0xfd, 0x7e, 0x49, 0xc1, 0x58, 0xe8, 0x22,
+	0xd9, 0x83, 0xad, 0x96, 0x61, 0x93, 0xba, 0x8b, 0x5b, 0x7c, 0x74, 0x4b, 0xac, 0x03, 0xfc, 0x0c,
+	0x55, 0xac, 0x28, 0x59, 0x94, 0x0d, 0xdd, 0x41, 0xba, 0x6f, 0x90, 0xe1, 0xa2, 0xac, 0xd9, 0xe7,
+	0xe0, 0xde, 0x70, 0x59, 0x85, 0x75, 0xbf, 0x2b, 0xac, 0xa3, 0x0d, 0x30, 0x2a, 0x85, 0x1e, 0x9a,
+	0xed, 0x17, 0xa9, 0x31, 0x84, 0xef, 0x32, 0xf4, 0xb4, 0xc9, 0x7e, 0x91, 0xa2, 0xe7, 0x36, 0x74,
+	0xd1, 0x93, 0xcb, 0xc0, 0xc3, 0x3d, 0x6c, 0xe8, 0xd7, 0x91, 0x24, 0x61, 0xb5, 0x18, 0x97, 0x11,
+	0xfb, 0x5b, 0x89, 0x38, 0xd8, 0x44, 0xd8, 0x33, 0xf0, 0xa9, 0x2e, 0x35, 0x9c, 0x44, 0x70, 0x29,
+	0xb5, 0x45, 0xef, 0x96, 0x33, 0xd4, 0xb5, 0x91, 0x24, 0x3f, 0xc1, 0xc3, 0x16, 0x07, 0x63, 0xf7,
+	0xcd, 0xf5, 0x69, 0x58, 0x18, 0xe4, 0x25, 0x6c, 0xb5, 0x78, 0xcd, 0x16, 0x1f, 0x9a, 0xc6, 0x36,
+	0xdc, 0x56, 0x6e, 0x5e, 0xaa, 0x28, 0xcd, 0x44, 0xe0, 0x9b, 0xdc, 0xbc, 0x54, 0x27, 0x99, 0x20,
+	0xbf, 0x82, 0x27, 0x99, 0x2a, 0x17, 0x91, 0xe2, 0x7c, 0x2e, 0x83, 0x47, 0x83, 0xce, 0xae, 0xb7,
+	0xbf, 0xb3, 0xb2, 0x45, 0x1f, 0x98, 0x98, 0xbe, 0x2f, 0xa6, 0x9c, 0x02, 0x2a, 0xae, 0xb5, 0x80,
+	0x1c, 0x82, 0xfb, 0x57, 0xac, 0xb2, 0x48, 0x94, 0x85, 0x0c, 0xc8, 0x7d, 0xd4, 0x8e, 0xe6, 0xd3,
+	0xb2, 0x90, 0xe4, 0x1d, 0x80, 0x61, 0xa2, 0x78, 0xeb, 0x3e, 0x62, 0x17, 0xd1, 0x5a, 0x5d, 0x64,
+	0xc5, 0xe7, 0xd8, 0xa8, 0x1f, 0xdf, 0x4b, 0x8d, 0x02, 0x54, 0xff, 0x02, 0xeb, 0x8a, 0xab, 0x78,
+	0x1e, 0x3c, 0x19, 0x58, 0xdf, 0x16, 0x1a, 0x2e, 0x19, 0xc2, 0xa6, 0x21, 0x24, 0xbc, 0x98, 0x66,
+	0xb3, 0x60, 0x1b, 0xb5, 0x83, 0x95, 0x5a, 0xfc, 0x0c, 0x87, 0xc8, 0xa3, 0xde, 0xe4, 0xf6, 0x85,
+	0x3c, 0x03, 0xbc, 0xa2, 0x38, 0x4a, 0x02, 0x3c, 0x8b, 0xe6, 0x3d, 0x7c, 0x0d, 0x9b, 0x77, 0x3e,
+	0x5f, 0x07, 0xec, 0xf1, 0xd5, 0x29, 0xf5, 0x1f, 0x90, 0x1e, 0xb8, 0xfa, 0xe9, 0xe4, 0xf4, 0x78,
+	0x7c, 0xe6, 0x5b, 0xa4, 0x0b, 0xfa, 0x93, 0xf7, 0xd7, 0xc2, 0x77, 0x60, 0xe3, 0x01, 0x7b, 0x50,
+	0x5f, 0x58, 0xff, 0x81, 0x46, 0x8f, 0xe8, 0x85, 0x6f, 0x11, 0x17, 0xd6, 0x8f, 0xe8, 0xc5, 0xc1,
+	0x1b, 0x7f, 0x4d, 0xd7, 0x3e, 0xbd, 0x3d, 0xf0, 0x3b, 0x04, 0x60, 0xe3, 0xd3, 0xdb, 0x83, 0xe8,
+	0xe0, 0x8d, 0x6f, 0x87, 0x33, 0xf0, 0x5a, 0x39, 0xf5, 0x44, 0x2c, 0x25, 0x8b, 0x66, 0x3c, 0x8f,
+	0x71, 0x6e, 0x3a, 0xb4, 0x5b, 0x4a, 0x76, 0xc6, 0xf3, 0x58, 0x5f, 0x20, 0x0d, 0x89, 0x09, 0xc3,
+	0x59, 0xe9, 0xd0, 0x8d, 0x52, 0x32, 0x3a, 0x61, 0xe4, 0x47, 0xe8, 0x4f, 0xb9, 0x48, 0x58, 0xd4,
+	0x28, 0x3b, 0x88, 0x6f, 0x62, 0x75, 0x6c, 0xe4, 0xe1, 0x3f, 0x16, 0x38, 0x75, 0x37, 0x09, 0x01,
+	0x3b, 0x65, 0x32, 0xc1, 0x25, 0x5c, 0x8a, 0xcf, 0xba, 0x86, 0x1d, 0x31, 0x83, 0x18, 0x9f, 0xc9,
+	0x0e, 0x80, 0x54, 0xb1, 0x50, 0x38, 0xcd, 0xd1, 0xd6, 0xa6, 0x2e, 0x56, 0xf4, 0x10, 0x27, 0xcf,
+	0xc1, 0x15, 0x2c, 0x9e, 0x1b, 0xd4, 0x46, 0xd4, 0xd1, 0x05, 0x04, 0x77, 0x00, 0x72, 0x96, 0x73,
+	0xb1, 0xd4, 0xb9, 0x70, 0xa8, 0xda, 0xd4, 0x35, 0x95, 0xb1, 0x64, 0xe1, 0x7f, 0x16, 0xf4, 0x2f,
+	0x78, 0x5a, 0xce, 0xd9, 0xf5, 0x72, 0xc1, 0x30, 0xd5, 0x9f, 0xf5, 0xe1, 0xca, 0xa5, 0x54, 0x2c,
+	0xc7, 0x74, 0xfd, 0xfd, 0x57, 0xab, 0xa7, 0xc5, 0x1d, 0xa9, 0x39, 0xeb, 0x2b, 0x94, 0xb5, 0xe6,
+	0xc6, 0xe4, 0xb6, 0x4a, 0x7e, 0x00, 0x2f, 0x47, 0x4d, 0xa4, 0x96, 0x8b, 0x7a, 0x97, 0x90, 0x37,
+	0x36, 0xba, 0x8d, 0x45, 0x99, 0x47, 0x7c, 0x1a, 0x99, 0xa2, 0xc4, 0xfd, 0xf6, 0xe8, 0x66, 0x51,
+	0xe6, 0xa3, 0xa9, 0x59, 0x4f, 0x86, 0xaf, 0xaa, 0xf3, 0xaa, 0x5c, 0xef, 0x1c, 0xba, 0x0b, 0xeb,
+	0x57, 0xa3, 0xd1, 0xa5, 0xbe, 0x1d, 0x0e, 0xd8, 0x17, 0x47, 0xe7, 0xa7, 0xfe, 0x5a, 0x38, 0x87,
+	0x67, 0x43, 0x91, 0xa9, 0x2c, 0x89, 0xe7, 0x63, 0xc9, 0xc4, 0x6f, 0xbc, 0x14, 0x05, 0x5b, 0x56,
+	0xc3, 0xae, 0x69, 0xba, 0xd5, 0x6a, 0xfa, 0x21, 0x74, 0xab, 0x5d, 0x62, 0xca, 0xaf, 0x5d, 0xef,
+	0xd6, 0xbc, 0xa4, 0xb5, 0x20, 0x9c, 0xc0, 0xf3, 0x15, 0xab, 0xc9, 0x7a, 0xb9, 0x21, 0xd8, 0x49,
+	0xf9, 0x59, 0x06, 0x16, 0x7e, 0xab, 0xab, 0x3b, 0xfb, 0xf5, 0xb4, 0x14, 0xc5, 0xc7, 0x4f, 0xfe,
+	0xa8, 0x7e, 0x07, 0x2a, 0x45, 0x84, 0xff, 0x08, 0xff, 0x07, 0x00, 0x00, 0xff, 0xff, 0x7d, 0x7b,
+	0xda, 0x72, 0x33, 0x08, 0x00, 0x00,
 }
diff --git a/ui/metrics/metrics_proto/metrics.proto b/ui/metrics/metrics_proto/metrics.proto
index bbb3021..e96a2e9 100644
--- a/ui/metrics/metrics_proto/metrics.proto
+++ b/ui/metrics/metrics_proto/metrics.proto
@@ -97,9 +97,6 @@
 
   // The hostname of the machine.
   optional string hostname = 24;
-
-  // The build command that the user entered to the build system.
-  optional string build_command = 26;
 }
 
 message BuildConfig {
@@ -156,4 +153,4 @@
 message CriticalUserJourneysMetrics {
   // A set of metrics from a run of the critical user journey tests.
   repeated CriticalUserJourneyMetrics cujs = 1;
-}
+}
\ No newline at end of file