Merge changes Ie769b9a9,Idb4e15b5 into rvc-dev am: 5ba6237c25

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

Change-Id: Iba8ec1d4d747533575c4b1eade0468888d29e7c6
diff --git a/android/androidmk.go b/android/androidmk.go
index 54a0c64..57908c7 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -46,7 +46,7 @@
 type AndroidMkData struct {
 	Class           string
 	SubName         string
-	DistFile        OptionalPath
+	DistFiles       TaggedDistFiles
 	OutputFile      OptionalPath
 	Disabled        bool
 	Include         string
@@ -72,7 +72,7 @@
 type AndroidMkEntries struct {
 	Class           string
 	SubName         string
-	DistFile        OptionalPath
+	DistFiles       TaggedDistFiles
 	OutputFile      OptionalPath
 	Disabled        bool
 	Include         string
@@ -176,6 +176,99 @@
 	a.EntryMap[name] = append(a.EntryMap[name], value...)
 }
 
+// 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
+}
+
 func (a *AndroidMkEntries) fillInEntries(config Config, bpPath string, mod blueprint.Module) {
 	a.EntryMap = make(map[string][]string)
 	amod := mod.(Module).base()
@@ -188,42 +281,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)")
@@ -469,7 +528,7 @@
 	entries := AndroidMkEntries{
 		Class:           data.Class,
 		SubName:         data.SubName,
-		DistFile:        data.DistFile,
+		DistFiles:       data.DistFiles,
 		OutputFile:      data.OutputFile,
 		Disabled:        data.Disabled,
 		Include:         data.Include,
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..8ec79ef 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -446,15 +446,15 @@
 	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/defaults.go b/android/defaults.go
index 81e340e..23aa7b4 100644
--- a/android/defaults.go
+++ b/android/defaults.go
@@ -195,7 +195,8 @@
 	module.AddProperties(
 		&hostAndDeviceProperties{},
 		commonProperties,
-		&ApexProperties{})
+		&ApexProperties{},
+		&distProperties{})
 
 	initAndroidModuleBase(module)
 	initProductVariableModule(module)
diff --git a/android/module.go b/android/module.go
index cd4baab..6c6c0ea 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 {
@@ -300,6 +301,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
@@ -439,24 +462,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
@@ -522,6 +527,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
@@ -603,7 +632,8 @@
 
 	m.AddProperties(
 		&base.nameProperties,
-		&base.commonProperties)
+		&base.commonProperties,
+		&base.distProperties)
 
 	initProductVariableModule(m)
 
@@ -694,6 +724,7 @@
 
 	nameProperties          nameProperties
 	commonProperties        commonProperties
+	distProperties          distProperties
 	variableProperties      interface{}
 	hostAndDeviceProperties hostAndDeviceProperties
 	generalProperties       []interface{}
@@ -800,6 +831,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
 }
@@ -1079,7 +1145,7 @@
 
 	var deps Paths
 
-	namespacePrefix := ctx.Namespace().(*Namespace).id
+	namespacePrefix := ctx.Namespace().id
 	if namespacePrefix != "" {
 		namespacePrefix = namespacePrefix + "-"
 	}
@@ -1235,20 +1301,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.")
 		}
 	}
@@ -1377,6 +1443,10 @@
 	return e.kind == systemExtSpecificModule
 }
 
+func (e *earlyModuleContext) Namespace() *Namespace {
+	return e.EarlyModuleContext.Namespace().(*Namespace)
+}
+
 type baseModuleContext struct {
 	bp blueprint.BaseModuleContext
 	earlyModuleContext
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/paths.go b/android/paths.go
index ddbeed3..e2e1faf 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))
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..793f3ed 100644
--- a/apex/OWNERS
+++ b/apex/OWNERS
@@ -1 +1,4 @@
-per-file * = jiyong@google.com
\ No newline at end of file
+per-file * = jiyong@google.com
+
+per-file allowed_deps.txt = set noparent
+per-file allowed_deps.txt = dariofreni@google.com,hansson@google.com,harpin@google.com,jiyong@google.com,narayan@google.com,omakoto@google.com,jham@google.com
diff --git a/apex/allowed_deps.txt b/apex/allowed_deps.txt
new file mode 100644
index 0000000..490a0e3
--- /dev/null
+++ b/apex/allowed_deps.txt
@@ -0,0 +1,544 @@
+# A list of allowed dependencies for all updatable modules.
+#
+# The list tracks all direct and transitive dependencies that end up within any
+# of the updatable binaries; specifically excluding external dependencies
+# required to compile those binaries. This prevents potential regressions in
+# case a new dependency is not aware of the different functional and
+# non-functional requirements being part of an updatable module, for example
+# setting correct min_sdk_version.
+#
+# To update the list, run:
+# repo-root$ build/soong/scripts/update-apex-allowed-deps.sh
+#
+# See go/apex-allowed-deps-error for more details.
+# TODO(b/157465465): introduce automated quality signals and remove this list.
+
+adbd(minSdkVersion:(no version))
+android.hardware.cas.native@1.0(minSdkVersion:29)
+android.hardware.cas@1.0(minSdkVersion:29)
+android.hardware.common-ndk_platform(minSdkVersion:29)
+android.hardware.graphics.allocator@2.0(minSdkVersion:29)
+android.hardware.graphics.allocator@3.0(minSdkVersion:29)
+android.hardware.graphics.allocator@4.0(minSdkVersion:29)
+android.hardware.graphics.bufferqueue@1.0(minSdkVersion:29)
+android.hardware.graphics.bufferqueue@2.0(minSdkVersion:29)
+android.hardware.graphics.common-ndk_platform(minSdkVersion:29)
+android.hardware.graphics.common@1.0(minSdkVersion:29)
+android.hardware.graphics.common@1.1(minSdkVersion:29)
+android.hardware.graphics.common@1.2(minSdkVersion:29)
+android.hardware.graphics.mapper@2.0(minSdkVersion:29)
+android.hardware.graphics.mapper@2.1(minSdkVersion:29)
+android.hardware.graphics.mapper@3.0(minSdkVersion:29)
+android.hardware.graphics.mapper@4.0(minSdkVersion:29)
+android.hardware.media.bufferpool@2.0(minSdkVersion:29)
+android.hardware.media.c2@1.0(minSdkVersion:29)
+android.hardware.media.c2@1.1(minSdkVersion:29)
+android.hardware.media.omx@1.0(minSdkVersion:29)
+android.hardware.media@1.0(minSdkVersion:29)
+android.hardware.neuralnetworks@1.0(minSdkVersion:30)
+android.hardware.neuralnetworks@1.1(minSdkVersion:30)
+android.hardware.neuralnetworks@1.2(minSdkVersion:30)
+android.hardware.neuralnetworks@1.3(minSdkVersion:30)
+android.hardware.tetheroffload.config-V1.0-java(minSdkVersion:current)
+android.hardware.tetheroffload.control-V1.0-java(minSdkVersion:current)
+android.hidl.allocator@1.0(minSdkVersion:29)
+android.hidl.base-V1.0-java(minSdkVersion:current)
+android.hidl.memory.token@1.0(minSdkVersion:29)
+android.hidl.memory@1.0(minSdkVersion:29)
+android.hidl.safe_union@1.0(minSdkVersion:29)
+android.hidl.token@1.0(minSdkVersion:29)
+android.hidl.token@1.0-utils(minSdkVersion:29)
+android.net.ipsec.ike(minSdkVersion:current)
+android.net.ipsec.ike.xml(minSdkVersion:(no version))
+androidx-constraintlayout_constraintlayout(minSdkVersion:14)
+androidx-constraintlayout_constraintlayout-solver(minSdkVersion:24)
+androidx.activity_activity(minSdkVersion:14)
+androidx.activity_activity-ktx(minSdkVersion:14)
+androidx.annotation_annotation(minSdkVersion:24)
+androidx.annotation_annotation-experimental(minSdkVersion:14)
+androidx.appcompat_appcompat(minSdkVersion:14)
+androidx.appcompat_appcompat-resources(minSdkVersion:14)
+androidx.arch.core_core-common(minSdkVersion:24)
+androidx.arch.core_core-runtime(minSdkVersion:14)
+androidx.asynclayoutinflater_asynclayoutinflater(minSdkVersion:14)
+androidx.autofill_autofill(minSdkVersion:14)
+androidx.cardview_cardview(minSdkVersion:14)
+androidx.collection_collection(minSdkVersion:24)
+androidx.collection_collection-ktx(minSdkVersion:24)
+androidx.coordinatorlayout_coordinatorlayout(minSdkVersion:14)
+androidx.core_core(minSdkVersion:14)
+androidx.core_core-ktx(minSdkVersion:14)
+androidx.cursoradapter_cursoradapter(minSdkVersion:14)
+androidx.customview_customview(minSdkVersion:14)
+androidx.documentfile_documentfile(minSdkVersion:14)
+androidx.drawerlayout_drawerlayout(minSdkVersion:14)
+androidx.fragment_fragment(minSdkVersion:14)
+androidx.fragment_fragment-ktx(minSdkVersion:14)
+androidx.interpolator_interpolator(minSdkVersion:14)
+androidx.leanback_leanback(minSdkVersion:17)
+androidx.leanback_leanback-preference(minSdkVersion:21)
+androidx.legacy_legacy-preference-v14(minSdkVersion:14)
+androidx.legacy_legacy-support-core-ui(minSdkVersion:14)
+androidx.legacy_legacy-support-core-utils(minSdkVersion:14)
+androidx.legacy_legacy-support-v13(minSdkVersion:14)
+androidx.legacy_legacy-support-v4(minSdkVersion:14)
+androidx.lifecycle_lifecycle-common(minSdkVersion:24)
+androidx.lifecycle_lifecycle-common-java8(minSdkVersion:24)
+androidx.lifecycle_lifecycle-extensions(minSdkVersion:14)
+androidx.lifecycle_lifecycle-livedata(minSdkVersion:14)
+androidx.lifecycle_lifecycle-livedata-core(minSdkVersion:14)
+androidx.lifecycle_lifecycle-livedata-core-ktx(minSdkVersion:14)
+androidx.lifecycle_lifecycle-process(minSdkVersion:14)
+androidx.lifecycle_lifecycle-runtime(minSdkVersion:14)
+androidx.lifecycle_lifecycle-runtime-ktx(minSdkVersion:14)
+androidx.lifecycle_lifecycle-service(minSdkVersion:14)
+androidx.lifecycle_lifecycle-viewmodel(minSdkVersion:14)
+androidx.lifecycle_lifecycle-viewmodel-ktx(minSdkVersion:14)
+androidx.lifecycle_lifecycle-viewmodel-savedstate(minSdkVersion:14)
+androidx.loader_loader(minSdkVersion:14)
+androidx.localbroadcastmanager_localbroadcastmanager(minSdkVersion:14)
+androidx.media_media(minSdkVersion:14)
+androidx.navigation_navigation-common(minSdkVersion:14)
+androidx.navigation_navigation-common-ktx(minSdkVersion:14)
+androidx.navigation_navigation-fragment(minSdkVersion:14)
+androidx.navigation_navigation-fragment-ktx(minSdkVersion:14)
+androidx.navigation_navigation-runtime(minSdkVersion:14)
+androidx.navigation_navigation-runtime-ktx(minSdkVersion:14)
+androidx.navigation_navigation-ui(minSdkVersion:14)
+androidx.navigation_navigation-ui-ktx(minSdkVersion:14)
+androidx.preference_preference(minSdkVersion:14)
+androidx.print_print(minSdkVersion:14)
+androidx.recyclerview_recyclerview(minSdkVersion:14)
+androidx.recyclerview_recyclerview-selection(minSdkVersion:14)
+androidx.savedstate_savedstate(minSdkVersion:14)
+androidx.slidingpanelayout_slidingpanelayout(minSdkVersion:14)
+androidx.swiperefreshlayout_swiperefreshlayout(minSdkVersion:14)
+androidx.transition_transition(minSdkVersion:14)
+androidx.vectordrawable_vectordrawable(minSdkVersion:14)
+androidx.vectordrawable_vectordrawable-animated(minSdkVersion:14)
+androidx.versionedparcelable_versionedparcelable(minSdkVersion:14)
+androidx.viewpager_viewpager(minSdkVersion:14)
+apache-commons-compress(minSdkVersion:current)
+art.module.public.api.stubs(minSdkVersion:(no version))
+bcm_object(minSdkVersion:29)
+boringssl_self_test(minSdkVersion:29)
+bouncycastle_ike_digests(minSdkVersion:current)
+brotli-java(minSdkVersion:current)
+captiveportal-lib(minSdkVersion:29)
+captiveportal-lib(minSdkVersion:current)
+car-ui-lib(minSdkVersion:28)
+CellBroadcastApp(minSdkVersion:29)
+CellBroadcastServiceModule(minSdkVersion:29)
+codecs_g711dec(minSdkVersion:29)
+com.google.android.material_material(minSdkVersion:14)
+conscrypt(minSdkVersion:29)
+conscrypt.module.platform.api.stubs(minSdkVersion:(no version))
+conscrypt.module.public.api.stubs(minSdkVersion:(no version))
+core-lambda-stubs(minSdkVersion:(no version))
+core.current.stubs(minSdkVersion:(no version))
+crtbegin_dynamic(minSdkVersion:apex_inherit)
+crtbegin_dynamic1(minSdkVersion:apex_inherit)
+crtbegin_so(minSdkVersion:apex_inherit)
+crtbegin_so1(minSdkVersion:apex_inherit)
+crtbrand(minSdkVersion:apex_inherit)
+crtend_android(minSdkVersion:apex_inherit)
+crtend_so(minSdkVersion:apex_inherit)
+datastallprotosnano(minSdkVersion:29)
+datastallprotosnano(minSdkVersion:current)
+derive_sdk(minSdkVersion:current)
+derive_sdk_prefer32(minSdkVersion:current)
+dnsresolver_aidl_interface-ndk_platform(minSdkVersion:29)
+dnsresolver_aidl_interface-unstable-ndk_platform(minSdkVersion:29)
+DocumentsUI-res-lib(minSdkVersion:29)
+exoplayer2-extractor(minSdkVersion:16)
+exoplayer2-extractor-annotation-stubs(minSdkVersion:16)
+ExtServices(minSdkVersion:current)
+ExtServices-core(minSdkVersion:current)
+flatbuffer_headers(minSdkVersion:(no version))
+fmtlib(minSdkVersion:29)
+framework-permission(minSdkVersion:current)
+framework-sdkextensions(minSdkVersion:current)
+framework-statsd(minSdkVersion:current)
+framework-tethering(minSdkVersion:current)
+gemmlowp_headers(minSdkVersion:(no version))
+GoogleCellBroadcastApp(minSdkVersion:29)
+GoogleCellBroadcastServiceModule(minSdkVersion:29)
+GoogleExtServices(minSdkVersion:current)
+GooglePermissionController(minSdkVersion:28)
+guava(minSdkVersion:current)
+gwp_asan_headers(minSdkVersion:(no version))
+i18n.module.public.api.stubs(minSdkVersion:(no version))
+iconloader(minSdkVersion:21)
+ike-internals(minSdkVersion:current)
+InProcessTethering(minSdkVersion:current)
+ipmemorystore-aidl-interfaces-java(minSdkVersion:29)
+ipmemorystore-aidl-interfaces-java(minSdkVersion:current)
+ipmemorystore-aidl-interfaces-unstable-java(minSdkVersion:29)
+jni_headers(minSdkVersion:29)
+jsr305(minSdkVersion:14)
+kotlinx-coroutines-android(minSdkVersion:current)
+kotlinx-coroutines-core(minSdkVersion:current)
+legacy.art.module.platform.api.stubs(minSdkVersion:(no version))
+legacy.core.platform.api.stubs(minSdkVersion:(no version))
+legacy.i18n.module.platform.api.stubs(minSdkVersion:(no version))
+libaacextractor(minSdkVersion:29)
+libadb_crypto(minSdkVersion:(no version))
+libadb_pairing_auth(minSdkVersion:(no version))
+libadb_pairing_connection(minSdkVersion:(no version))
+libadb_pairing_server(minSdkVersion:(no version))
+libadb_protos(minSdkVersion:(no version))
+libadb_sysdeps(minSdkVersion:apex_inherit)
+libadb_tls_connection(minSdkVersion:(no version))
+libadbconnection_client(minSdkVersion:(no version))
+libadbconnection_server(minSdkVersion:(no version))
+libadbd(minSdkVersion:(no version))
+libadbd_core(minSdkVersion:(no version))
+libadbd_services(minSdkVersion:(no version))
+libamrextractor(minSdkVersion:29)
+libapp_processes_protos_lite(minSdkVersion:(no version))
+libarect(minSdkVersion:29)
+libasyncio(minSdkVersion:(no version))
+libatomic(minSdkVersion:(no version))
+libaudio_system_headers(minSdkVersion:29)
+libaudioclient_headers(minSdkVersion:29)
+libaudiofoundation_headers(minSdkVersion:29)
+libaudioutils(minSdkVersion:29)
+libaudioutils_fixedfft(minSdkVersion:29)
+libavcdec(minSdkVersion:29)
+libavcenc(minSdkVersion:29)
+libavservices_minijail(minSdkVersion:29)
+libbacktrace_headers(minSdkVersion:apex_inherit)
+libbase(minSdkVersion:29)
+libbase_headers(minSdkVersion:29)
+libbinder(minSdkVersion:29)
+libbinder_headers(minSdkVersion:29)
+libbinderthreadstateutils(minSdkVersion:29)
+libbluetooth-types-header(minSdkVersion:29)
+libbrotli(minSdkVersion:(no version))
+libbuildversion(minSdkVersion:(no version))
+libc(minSdkVersion:(no version))
+libc++(minSdkVersion:apex_inherit)
+libc++_static(minSdkVersion:apex_inherit)
+libc++abi(minSdkVersion:apex_inherit)
+libc++demangle(minSdkVersion:apex_inherit)
+libc_headers(minSdkVersion:apex_inherit)
+libc_headers_arch(minSdkVersion:apex_inherit)
+libc_scudo(minSdkVersion:apex_inherit)
+libcap(minSdkVersion:29)
+libclang_rt.hwasan-aarch64-android.llndk(minSdkVersion:(no version))
+libcodec2(minSdkVersion:29)
+libcodec2_headers(minSdkVersion:29)
+libcodec2_hidl@1.0(minSdkVersion:29)
+libcodec2_hidl@1.1(minSdkVersion:29)
+libcodec2_internal(minSdkVersion:29)
+libcodec2_soft_aacdec(minSdkVersion:29)
+libcodec2_soft_aacenc(minSdkVersion:29)
+libcodec2_soft_amrnbdec(minSdkVersion:29)
+libcodec2_soft_amrnbenc(minSdkVersion:29)
+libcodec2_soft_amrwbdec(minSdkVersion:29)
+libcodec2_soft_amrwbenc(minSdkVersion:29)
+libcodec2_soft_av1dec_gav1(minSdkVersion:29)
+libcodec2_soft_avcdec(minSdkVersion:29)
+libcodec2_soft_avcenc(minSdkVersion:29)
+libcodec2_soft_common(minSdkVersion:29)
+libcodec2_soft_flacdec(minSdkVersion:29)
+libcodec2_soft_flacenc(minSdkVersion:29)
+libcodec2_soft_g711alawdec(minSdkVersion:29)
+libcodec2_soft_g711mlawdec(minSdkVersion:29)
+libcodec2_soft_gsmdec(minSdkVersion:29)
+libcodec2_soft_h263dec(minSdkVersion:29)
+libcodec2_soft_h263enc(minSdkVersion:29)
+libcodec2_soft_hevcdec(minSdkVersion:29)
+libcodec2_soft_hevcenc(minSdkVersion:29)
+libcodec2_soft_mp3dec(minSdkVersion:29)
+libcodec2_soft_mpeg2dec(minSdkVersion:29)
+libcodec2_soft_mpeg4dec(minSdkVersion:29)
+libcodec2_soft_mpeg4enc(minSdkVersion:29)
+libcodec2_soft_opusdec(minSdkVersion:29)
+libcodec2_soft_opusenc(minSdkVersion:29)
+libcodec2_soft_rawdec(minSdkVersion:29)
+libcodec2_soft_vorbisdec(minSdkVersion:29)
+libcodec2_soft_vp8dec(minSdkVersion:29)
+libcodec2_soft_vp8enc(minSdkVersion:29)
+libcodec2_soft_vp9dec(minSdkVersion:29)
+libcodec2_soft_vp9enc(minSdkVersion:29)
+libcodec2_vndk(minSdkVersion:29)
+libcrypto(minSdkVersion:29)
+libcrypto_static(minSdkVersion:(no version))
+libcrypto_utils(minSdkVersion:(no version))
+libcutils(minSdkVersion:29)
+libcutils_headers(minSdkVersion:29)
+libcutils_sockets(minSdkVersion:29)
+libdiagnose_usb(minSdkVersion:(no version))
+libdl(minSdkVersion:(no version))
+libeigen(minSdkVersion:(no version))
+libfifo(minSdkVersion:29)
+libFLAC(minSdkVersion:29)
+libFLAC-config(minSdkVersion:29)
+libFLAC-headers(minSdkVersion:29)
+libflacextractor(minSdkVersion:29)
+libfmq(minSdkVersion:29)
+libFraunhoferAAC(minSdkVersion:29)
+libgav1(minSdkVersion:29)
+libgcc_stripped(minSdkVersion:(no version))
+libgralloctypes(minSdkVersion:29)
+libgrallocusage(minSdkVersion:29)
+libgsm(minSdkVersion:apex_inherit)
+libgtest_prod(minSdkVersion:apex_inherit)
+libgui_bufferqueue_static(minSdkVersion:29)
+libgui_headers(minSdkVersion:29)
+libhardware(minSdkVersion:29)
+libhardware_headers(minSdkVersion:29)
+libhevcdec(minSdkVersion:29)
+libhevcenc(minSdkVersion:29)
+libhidlbase(minSdkVersion:29)
+libhidlmemory(minSdkVersion:29)
+libhwbinder-impl-internal(minSdkVersion:29)
+libhwbinder_headers(minSdkVersion:29)
+libion(minSdkVersion:29)
+libjavacrypto(minSdkVersion:29)
+libjsoncpp(minSdkVersion:29)
+libLibGuiProperties(minSdkVersion:29)
+liblog(minSdkVersion:(no version))
+liblog_headers(minSdkVersion:29)
+liblua(minSdkVersion:(no version))
+liblz4(minSdkVersion:(no version))
+libm(minSdkVersion:(no version))
+libmath(minSdkVersion:29)
+libmdnssd(minSdkVersion:(no version))
+libmedia_codecserviceregistrant(minSdkVersion:29)
+libmedia_datasource_headers(minSdkVersion:29)
+libmedia_headers(minSdkVersion:29)
+libmedia_helper_headers(minSdkVersion:29)
+libmedia_midiiowrapper(minSdkVersion:29)
+libmidiextractor(minSdkVersion:29)
+libminijail(minSdkVersion:29)
+libminijail_gen_constants(minSdkVersion:(no version))
+libminijail_gen_constants_obj(minSdkVersion:29)
+libminijail_gen_syscall(minSdkVersion:(no version))
+libminijail_gen_syscall_obj(minSdkVersion:29)
+libminijail_generated(minSdkVersion:29)
+libmkvextractor(minSdkVersion:29)
+libmp3extractor(minSdkVersion:29)
+libmp4extractor(minSdkVersion:29)
+libmpeg2dec(minSdkVersion:29)
+libmpeg2extractor(minSdkVersion:29)
+libnativebase_headers(minSdkVersion:29)
+libnativehelper_compat_libc++(minSdkVersion:(no version))
+libnativehelper_header_only(minSdkVersion:29)
+libnativewindow_headers(minSdkVersion:29)
+libnetd_resolv(minSdkVersion:29)
+libnetdbinder_utils_headers(minSdkVersion:29)
+libnetdutils(minSdkVersion:29)
+libnetworkstackutilsjni(minSdkVersion:29)
+libneuralnetworks(minSdkVersion:(no version))
+libneuralnetworks_common(minSdkVersion:(no version))
+libneuralnetworks_headers(minSdkVersion:(no version))
+liboggextractor(minSdkVersion:29)
+libopus(minSdkVersion:29)
+libprocessgroup(minSdkVersion:29)
+libprocessgroup_headers(minSdkVersion:29)
+libprocpartition(minSdkVersion:(no version))
+libprotobuf-cpp-lite(minSdkVersion:29)
+libprotobuf-java-lite(minSdkVersion:current)
+libprotobuf-java-nano(minSdkVersion:9)
+libprotoutil(minSdkVersion:(no version))
+libqemu_pipe(minSdkVersion:(no version))
+libsfplugin_ccodec_utils(minSdkVersion:29)
+libsonivoxwithoutjet(minSdkVersion:29)
+libspeexresampler(minSdkVersion:29)
+libssl(minSdkVersion:29)
+libstagefright_amrnb_common(minSdkVersion:29)
+libstagefright_amrnbdec(minSdkVersion:29)
+libstagefright_amrnbenc(minSdkVersion:29)
+libstagefright_amrwbdec(minSdkVersion:29)
+libstagefright_amrwbenc(minSdkVersion:29)
+libstagefright_bufferpool@2.0.1(minSdkVersion:29)
+libstagefright_bufferqueue_helper(minSdkVersion:29)
+libstagefright_bufferqueue_helper_novndk(minSdkVersion:(no version))
+libstagefright_enc_common(minSdkVersion:29)
+libstagefright_esds(minSdkVersion:29)
+libstagefright_flacdec(minSdkVersion:29)
+libstagefright_foundation(minSdkVersion:29)
+libstagefright_foundation_headers(minSdkVersion:29)
+libstagefright_foundation_without_imemory(minSdkVersion:29)
+libstagefright_headers(minSdkVersion:29)
+libstagefright_id3(minSdkVersion:29)
+libstagefright_m4vh263dec(minSdkVersion:29)
+libstagefright_m4vh263enc(minSdkVersion:29)
+libstagefright_metadatautils(minSdkVersion:29)
+libstagefright_mp3dec(minSdkVersion:29)
+libstagefright_mpeg2extractor(minSdkVersion:29)
+libstagefright_mpeg2support(minSdkVersion:29)
+libstagefright_mpeg2support_nocrypto(minSdkVersion:29)
+libstats_jni(minSdkVersion:(no version))
+libstatslog_resolv(minSdkVersion:29)
+libstatslog_statsd(minSdkVersion:(no version))
+libstatspull(minSdkVersion:(no version))
+libstatspush_compat(minSdkVersion:29)
+libstatssocket(minSdkVersion:(no version))
+libstatssocket_headers(minSdkVersion:29)
+libsync(minSdkVersion:(no version))
+libsystem_headers(minSdkVersion:apex_inherit)
+libsysutils(minSdkVersion:apex_inherit)
+libtetherutilsjni(minSdkVersion:current)
+libtextclassifier(minSdkVersion:(no version))
+libtextclassifier-java(minSdkVersion:28)
+libtextclassifier-java(minSdkVersion:current)
+libtextclassifier_flatbuffer_headers(minSdkVersion:(no version))
+libtextclassifier_hash_headers(minSdkVersion:(no version))
+libtextclassifier_hash_static(minSdkVersion:(no version))
+libtflite_kernel_utils(minSdkVersion:(no version))
+libtflite_static(minSdkVersion:(no version))
+libui(minSdkVersion:29)
+libui-types(minSdkVersion:apex_inherit)
+libui_headers(minSdkVersion:29)
+libunwind_llvm(minSdkVersion:apex_inherit)
+libutf(minSdkVersion:(no version))
+libutils(minSdkVersion:apex_inherit)
+libutils_headers(minSdkVersion:apex_inherit)
+libvorbisidec(minSdkVersion:29)
+libvpx(minSdkVersion:29)
+libwatchdog(minSdkVersion:29)
+libwavextractor(minSdkVersion:29)
+libwebm(minSdkVersion:29)
+libyuv(minSdkVersion:29)
+libyuv_static(minSdkVersion:29)
+libz_current(minSdkVersion:(no version))
+libzstd(minSdkVersion:(no version))
+media_ndk_headers(minSdkVersion:29)
+media_plugin_headers(minSdkVersion:29)
+mediaswcodec(minSdkVersion:29)
+metrics-constants-protos(minSdkVersion:29)
+metrics-constants-protos(minSdkVersion:current)
+ndk_crtbegin_so.19(minSdkVersion:(no version))
+ndk_crtbegin_so.21(minSdkVersion:(no version))
+ndk_crtbegin_so.27(minSdkVersion:(no version))
+ndk_crtend_so.19(minSdkVersion:(no version))
+ndk_crtend_so.21(minSdkVersion:(no version))
+ndk_crtend_so.27(minSdkVersion:(no version))
+ndk_libandroid_support(minSdkVersion:(no version))
+ndk_libc++_static(minSdkVersion:(no version))
+ndk_libc++abi(minSdkVersion:(no version))
+ndk_libunwind(minSdkVersion:(no version))
+net-utils-device-common(minSdkVersion:29)
+net-utils-framework-common(minSdkVersion:current)
+netd_aidl_interface-java(minSdkVersion:current)
+netd_aidl_interface-unstable-java(minSdkVersion:29)
+netd_event_listener_interface-ndk_platform(minSdkVersion:29)
+netlink-client(minSdkVersion:29)
+netlink-client(minSdkVersion:current)
+networkstack-aidl-interfaces-java(minSdkVersion:29)
+networkstack-aidl-interfaces-java(minSdkVersion:current)
+networkstack-aidl-interfaces-unstable-java(minSdkVersion:29)
+networkstack-client(minSdkVersion:29)
+networkstack-client(minSdkVersion:current)
+NetworkStackApiStableDependencies(minSdkVersion:29)
+NetworkStackApiStableLib(minSdkVersion:29)
+networkstackprotos(minSdkVersion:29)
+PermissionController(minSdkVersion:28)
+permissioncontroller-statsd(minSdkVersion:current)
+philox_random(minSdkVersion:(no version))
+philox_random_headers(minSdkVersion:(no version))
+prebuilt_androidx-constraintlayout_constraintlayout-nodeps(minSdkVersion:(no version))
+prebuilt_androidx-constraintlayout_constraintlayout-solver-nodeps(minSdkVersion:current)
+prebuilt_androidx.activity_activity-ktx-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.activity_activity-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.annotation_annotation-experimental-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.annotation_annotation-nodeps(minSdkVersion:current)
+prebuilt_androidx.appcompat_appcompat-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.appcompat_appcompat-resources-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.arch.core_core-common-nodeps(minSdkVersion:current)
+prebuilt_androidx.arch.core_core-runtime-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.asynclayoutinflater_asynclayoutinflater-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.autofill_autofill-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.cardview_cardview-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.collection_collection-ktx-nodeps(minSdkVersion:current)
+prebuilt_androidx.collection_collection-nodeps(minSdkVersion:current)
+prebuilt_androidx.coordinatorlayout_coordinatorlayout-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.core_core-ktx-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.core_core-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.cursoradapter_cursoradapter-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.customview_customview-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.documentfile_documentfile-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.drawerlayout_drawerlayout-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.fragment_fragment-ktx-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.fragment_fragment-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.interpolator_interpolator-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.leanback_leanback-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.leanback_leanback-preference-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.legacy_legacy-support-core-ui-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.legacy_legacy-support-core-utils-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.legacy_legacy-support-v13-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.lifecycle_lifecycle-common-java8-nodeps(minSdkVersion:current)
+prebuilt_androidx.lifecycle_lifecycle-common-nodeps(minSdkVersion:current)
+prebuilt_androidx.lifecycle_lifecycle-extensions-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.lifecycle_lifecycle-livedata-core-ktx-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.lifecycle_lifecycle-livedata-core-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.lifecycle_lifecycle-livedata-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.lifecycle_lifecycle-process-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.lifecycle_lifecycle-runtime-ktx-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.lifecycle_lifecycle-runtime-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.lifecycle_lifecycle-service-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.lifecycle_lifecycle-viewmodel-ktx-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.lifecycle_lifecycle-viewmodel-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.lifecycle_lifecycle-viewmodel-savedstate-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.loader_loader-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.localbroadcastmanager_localbroadcastmanager-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.media_media-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.navigation_navigation-common-ktx-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.navigation_navigation-common-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.navigation_navigation-fragment-ktx-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.navigation_navigation-fragment-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.navigation_navigation-runtime-ktx-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.navigation_navigation-runtime-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.navigation_navigation-ui-ktx-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.navigation_navigation-ui-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.preference_preference-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.print_print-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.recyclerview_recyclerview-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.recyclerview_recyclerview-selection-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.savedstate_savedstate-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.slidingpanelayout_slidingpanelayout-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.swiperefreshlayout_swiperefreshlayout-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.transition_transition-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.vectordrawable_vectordrawable-animated-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.vectordrawable_vectordrawable-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.versionedparcelable_versionedparcelable-nodeps(minSdkVersion:(no version))
+prebuilt_androidx.viewpager_viewpager-nodeps(minSdkVersion:(no version))
+prebuilt_com.google.android.material_material-nodeps(minSdkVersion:(no version))
+prebuilt_error_prone_annotations(minSdkVersion:(no version))
+prebuilt_kotlin-stdlib(minSdkVersion:current)
+prebuilt_kotlinx-coroutines-android-nodeps(minSdkVersion:(no version))
+prebuilt_kotlinx-coroutines-core-nodeps(minSdkVersion:(no version))
+prebuilt_libclang_rt.builtins-aarch64-android(minSdkVersion:(no version))
+prebuilt_libclang_rt.builtins-arm-android(minSdkVersion:(no version))
+prebuilt_libclang_rt.builtins-i686-android(minSdkVersion:(no version))
+prebuilt_libclang_rt.builtins-x86_64-android(minSdkVersion:(no version))
+prebuilt_test_framework-sdkextensions(minSdkVersion:(no version))
+server_configurable_flags(minSdkVersion:29)
+service-permission(minSdkVersion:current)
+service-statsd(minSdkVersion:current)
+SettingsLibActionBarShadow(minSdkVersion:21)
+SettingsLibAppPreference(minSdkVersion:21)
+SettingsLibBarChartPreference(minSdkVersion:21)
+SettingsLibHelpUtils(minSdkVersion:21)
+SettingsLibLayoutPreference(minSdkVersion:21)
+SettingsLibProgressBar(minSdkVersion:21)
+SettingsLibRestrictedLockUtils(minSdkVersion:21)
+SettingsLibSearchWidget(minSdkVersion:21)
+SettingsLibSettingsTheme(minSdkVersion:21)
+SettingsLibUtils(minSdkVersion:21)
+stats_proto(minSdkVersion:29)
+statsd(minSdkVersion:(no version))
+statsd-aidl-ndk_platform(minSdkVersion:(no version))
+statsprotos(minSdkVersion:29)
+tensorflow_headers(minSdkVersion:(no version))
+Tethering(minSdkVersion:current)
+TetheringApiCurrentLib(minSdkVersion:current)
+TetheringGoogle(minSdkVersion:current)
+textclassifier-statsd(minSdkVersion:current)
+TextClassifierNotificationLibNoManifest(minSdkVersion:29)
+TextClassifierServiceLibNoManifest(minSdkVersion:28)
+updatable-media(minSdkVersion:29)
+xz-java(minSdkVersion:current)
diff --git a/apex/apex.go b/apex/apex.go
index 7da8e1c..927aa0b 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
 }
@@ -1552,6 +1560,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 +1824,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 +2095,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..314ec8b 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 build/soong/apex/allowed_deps.txt, please run:";
+				echo "$$ (croot && build/soong/scripts/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, "build/soong/apex/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..ecdb88e 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,18 @@
 	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, "  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")
 
 	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, "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)")
 }
 
 func TestDefaults(t *testing.T) {
@@ -556,6 +558,7 @@
 			native_shared_libs: ["mylib"],
 			java_libs: ["myjar"],
 			apps: ["AppFoo"],
+			bpfs: ["bpf"],
 		}
 
 		prebuilt_etc {
@@ -596,12 +599,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 +857,14 @@
 	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, "  mylib(minSdkVersion:(no version)) <- myapex2")
+	ensureListContains(t, fullDepsInfo, "  libbaz(minSdkVersion:(no version)) <- 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, "mylib(minSdkVersion:(no version))")
+	ensureListContains(t, flatDepsInfo, "libbaz(minSdkVersion:(no version))")
+	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..72ad66d 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -237,6 +237,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{}
 	}
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..cb83e7e 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 {
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/java/androidmk.go b/java/androidmk.go
index ae257d7..08febcd 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())
 
@@ -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 e75d874..c9412c4 100755
--- a/java/app.go
+++ b/java/app.go
@@ -585,11 +585,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)
@@ -999,8 +999,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)
@@ -1117,7 +1117,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)
@@ -1168,7 +1168,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)
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..862f2bb 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -1510,7 +1510,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/java.go b/java/java.go
index 4612b76..486404c 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)
 	}
@@ -681,28 +636,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)
 
 		if ctx.ModuleName() == "android_stubs_current" ||
 			ctx.ModuleName() == "android_system_stubs_current" ||
@@ -1609,8 +1568,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)
@@ -1618,10 +1577,14 @@
 	}
 
 	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
 		}
@@ -1631,7 +1594,7 @@
 
 		// 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 {
@@ -1639,7 +1602,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
@@ -1903,18 +1866,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)
 }
 
@@ -1956,11 +1910,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()
@@ -1973,14 +1927,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) {
@@ -2098,7 +2045,6 @@
 	module := &Library{}
 
 	module.addHostAndDeviceProperties()
-	module.AddProperties(&module.libraryProperties)
 
 	module.initModuleAndImport(&module.ModuleBase)
 
@@ -2197,6 +2143,7 @@
 	prebuiltTestProperties prebuiltTestProperties
 
 	testConfig android.Path
+	dexJarFile android.Path
 }
 
 func (j *Test) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -2495,8 +2442,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
 }
@@ -2505,10 +2458,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()
 }
@@ -2535,6 +2500,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) {
@@ -2557,6 +2526,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)
@@ -2565,12 +2536,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)
 			}
@@ -2582,6 +2557,32 @@
 		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
+		}
+
+		j.dexJarFile = dexOutputFile
+	}
 }
 
 var _ Dependency = (*Import)(nil)
@@ -2612,7 +2613,7 @@
 }
 
 func (j *Import) DexJar() android.Path {
-	return nil
+	return j.dexJarFile
 }
 
 func (j *Import) AidlIncludeDirs() android.Paths {
@@ -2671,10 +2672,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)
@@ -2873,6 +2879,7 @@
 	module.AddProperties(
 		&CompilerProperties{},
 		&CompilerDeviceProperties{},
+		&DexProperties{},
 		&DexpreoptProperties{},
 		&android.ProtoProperties{},
 		&aaptProperties{},
diff --git a/java/java_test.go b/java/java_test.go
index 8797119..266cada 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -486,6 +486,8 @@
 		java_import {
 			name: "baz",
 			jars: ["b.jar"],
+			sdk_version: "current",
+			compile_dex: true,
 		}
 
 		dex_import {
@@ -516,8 +518,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 +536,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 +549,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")
 }
 
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..6c16651 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"
 	}
diff --git a/java/sdk_library.go b/java/sdk_library.go
index f2a509a..0f7bbb5 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -137,6 +137,7 @@
 	droidstubsArgsForGeneratingApi []string
 
 	// True if the stubs source and api can be created by the same metalava invocation.
+	// TODO(b/146727827) Now that metalava supports "API hierarchy", do we still need it?
 	createStubsSourceAndApiTogether bool
 
 	// Whether the api scope can be treated as unstable, and should skip compat checks.
@@ -278,6 +279,7 @@
 		sdkVersion:    "module_current",
 		droidstubsArgs: []string{
 			"--show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES\\)",
+			"--show-for-stub-purposes-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS\\)",
 		},
 	})
 	apiScopeSystemServer = initApiScope(&apiScope{
@@ -1086,11 +1088,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 +1114,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 +1126,7 @@
 		&module.properties,
 		&module.protoProperties,
 		&module.deviceProperties,
+		&module.dexProperties,
 		&module.dexpreoptProperties,
 		&module.linter.properties,
 		&props,
@@ -1149,12 +1166,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 +1186,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.
@@ -1236,12 +1248,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
diff --git a/rust/androidmk.go b/rust/androidmk.go
index 0fba739..99880a8 100644
--- a/rust/androidmk.go
+++ b/rust/androidmk.go
@@ -80,8 +80,11 @@
 func (binary *binaryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
 	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())
 	})
@@ -119,7 +122,10 @@
 		ret.Class = "SHARED_LIBRARIES"
 	}
 
-	ret.DistFile = library.distFile
+	if library.distFile.Valid() {
+		ret.DistFiles = android.MakeDefaultDistFiles(library.distFile.Path())
+	}
+
 	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
 		if !library.rlib() {
 			fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", library.unstrippedOutputFile.String())
@@ -131,7 +137,9 @@
 	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())
+	}
 
 }
 
diff --git a/scripts/update-apex-allowed-deps.sh b/scripts/update-apex-allowed-deps.sh
new file mode 100755
index 0000000..872d746
--- /dev/null
+++ b/scripts/update-apex-allowed-deps.sh
@@ -0,0 +1,39 @@
+#!/bin/bash -e
+#
+# The script to run locally to re-generate global allowed list of dependencies
+# for updatable modules.
+
+if [ ! -e "build/envsetup.sh" ]; then
+  echo "ERROR: $0 must be run from the top of the tree"
+  exit 1
+fi
+
+source build/envsetup.sh > /dev/null || exit 1
+
+readonly OUT_DIR=$(get_build_var OUT_DIR)
+
+readonly ALLOWED_DEPS_FILE="build/soong/apex/allowed_deps.txt"
+readonly NEW_ALLOWED_DEPS_FILE="${OUT_DIR}/soong/apex/depsinfo/new-allowed-deps.txt"
+
+# If the script is run after droidcore failure, ${NEW_ALLOWED_DEPS_FILE}
+# should already be built. If running the script manually, make sure it exists.
+m "${NEW_ALLOWED_DEPS_FILE}" -j
+
+cat > "${ALLOWED_DEPS_FILE}" << EndOfFileComment
+# A list of allowed dependencies for all updatable modules.
+#
+# The list tracks all direct and transitive dependencies that end up within any
+# of the updatable binaries; specifically excluding external dependencies
+# required to compile those binaries. This prevents potential regressions in
+# case a new dependency is not aware of the different functional and
+# non-functional requirements being part of an updatable module, for example
+# setting correct min_sdk_version.
+#
+# To update the list, run:
+# repo-root$ build/soong/scripts/update-apex-allowed-deps.sh
+#
+# See go/apex-allowed-deps-error for more details.
+# TODO(b/157465465): introduce automated quality signals and remove this list.
+EndOfFileComment
+
+cat "${NEW_ALLOWED_DEPS_FILE}" >> "${ALLOWED_DEPS_FILE}"
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) {