Merge "java_sdk_library: Remove unused SetNoDist method"
diff --git a/android/Android.bp b/android/Android.bp
index 26605a7..66d361e 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -15,6 +15,7 @@
         "apex.go",
         "api_levels.go",
         "arch.go",
+        "arch_list.go",
         "bazel_handler.go",
         "config.go",
         "csuite_config.go",
diff --git a/android/arch.go b/android/arch.go
index afb9c7f..eb651e6 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -27,28 +27,6 @@
 	"github.com/google/blueprint/proptools"
 )
 
-const COMMON_VARIANT = "common"
-
-var (
-	archTypeList []ArchType
-
-	Arm    = newArch("arm", "lib32")
-	Arm64  = newArch("arm64", "lib64")
-	X86    = newArch("x86", "lib32")
-	X86_64 = newArch("x86_64", "lib64")
-
-	Common = ArchType{
-		Name: COMMON_VARIANT,
-	}
-)
-
-var archTypeMap = map[string]ArchType{
-	"arm":    Arm,
-	"arm64":  Arm64,
-	"x86":    X86,
-	"x86_64": X86_64,
-}
-
 /*
 Example blueprints file containing all variant property groups, with comment listing what type
 of variants get properties in that group:
@@ -111,405 +89,26 @@
 }
 */
 
-var archVariants = map[ArchType][]string{
-	Arm: {
-		"armv7-a",
-		"armv7-a-neon",
-		"armv8-a",
-		"armv8-2a",
-		"cortex-a7",
-		"cortex-a8",
-		"cortex-a9",
-		"cortex-a15",
-		"cortex-a53",
-		"cortex-a53-a57",
-		"cortex-a55",
-		"cortex-a72",
-		"cortex-a73",
-		"cortex-a75",
-		"cortex-a76",
-		"krait",
-		"kryo",
-		"kryo385",
-		"exynos-m1",
-		"exynos-m2",
-	},
-	Arm64: {
-		"armv8_a",
-		"armv8_2a",
-		"armv8-2a-dotprod",
-		"cortex-a53",
-		"cortex-a55",
-		"cortex-a72",
-		"cortex-a73",
-		"cortex-a75",
-		"cortex-a76",
-		"kryo",
-		"kryo385",
-		"exynos-m1",
-		"exynos-m2",
-	},
-	X86: {
-		"amberlake",
-		"atom",
-		"broadwell",
-		"haswell",
-		"icelake",
-		"ivybridge",
-		"kabylake",
-		"sandybridge",
-		"silvermont",
-		"skylake",
-		"stoneyridge",
-		"tigerlake",
-		"whiskeylake",
-		"x86_64",
-	},
-	X86_64: {
-		"amberlake",
-		"broadwell",
-		"haswell",
-		"icelake",
-		"ivybridge",
-		"kabylake",
-		"sandybridge",
-		"silvermont",
-		"skylake",
-		"stoneyridge",
-		"tigerlake",
-		"whiskeylake",
-	},
-}
-
-var archFeatures = map[ArchType][]string{
-	Arm: {
-		"neon",
-	},
-	Arm64: {
-		"dotprod",
-	},
-	X86: {
-		"ssse3",
-		"sse4",
-		"sse4_1",
-		"sse4_2",
-		"aes_ni",
-		"avx",
-		"avx2",
-		"avx512",
-		"popcnt",
-		"movbe",
-	},
-	X86_64: {
-		"ssse3",
-		"sse4",
-		"sse4_1",
-		"sse4_2",
-		"aes_ni",
-		"avx",
-		"avx2",
-		"avx512",
-		"popcnt",
-	},
-}
-
-var archFeatureMap = map[ArchType]map[string][]string{
-	Arm: {
-		"armv7-a-neon": {
-			"neon",
-		},
-		"armv8-a": {
-			"neon",
-		},
-		"armv8-2a": {
-			"neon",
-		},
-	},
-	Arm64: {
-		"armv8-2a-dotprod": {
-			"dotprod",
-		},
-	},
-	X86: {
-		"amberlake": {
-			"ssse3",
-			"sse4",
-			"sse4_1",
-			"sse4_2",
-			"avx",
-			"avx2",
-			"aes_ni",
-			"popcnt",
-		},
-		"atom": {
-			"ssse3",
-			"movbe",
-		},
-		"broadwell": {
-			"ssse3",
-			"sse4",
-			"sse4_1",
-			"sse4_2",
-			"avx",
-			"avx2",
-			"aes_ni",
-			"popcnt",
-		},
-		"haswell": {
-			"ssse3",
-			"sse4",
-			"sse4_1",
-			"sse4_2",
-			"aes_ni",
-			"avx",
-			"popcnt",
-			"movbe",
-		},
-		"icelake": {
-			"ssse3",
-			"sse4",
-			"sse4_1",
-			"sse4_2",
-			"avx",
-			"avx2",
-			"avx512",
-			"aes_ni",
-			"popcnt",
-		},
-		"ivybridge": {
-			"ssse3",
-			"sse4",
-			"sse4_1",
-			"sse4_2",
-			"aes_ni",
-			"avx",
-			"popcnt",
-		},
-		"kabylake": {
-			"ssse3",
-			"sse4",
-			"sse4_1",
-			"sse4_2",
-			"avx",
-			"avx2",
-			"aes_ni",
-			"popcnt",
-		},
-		"sandybridge": {
-			"ssse3",
-			"sse4",
-			"sse4_1",
-			"sse4_2",
-			"popcnt",
-		},
-		"silvermont": {
-			"ssse3",
-			"sse4",
-			"sse4_1",
-			"sse4_2",
-			"aes_ni",
-			"popcnt",
-			"movbe",
-		},
-		"skylake": {
-			"ssse3",
-			"sse4",
-			"sse4_1",
-			"sse4_2",
-			"avx",
-			"avx2",
-			"avx512",
-			"aes_ni",
-			"popcnt",
-		},
-		"stoneyridge": {
-			"ssse3",
-			"sse4",
-			"sse4_1",
-			"sse4_2",
-			"aes_ni",
-			"avx",
-			"avx2",
-			"popcnt",
-			"movbe",
-		},
-		"tigerlake": {
-			"ssse3",
-			"sse4",
-			"sse4_1",
-			"sse4_2",
-			"avx",
-			"avx2",
-			"avx512",
-			"aes_ni",
-			"popcnt",
-		},
-		"whiskeylake": {
-			"ssse3",
-			"sse4",
-			"sse4_1",
-			"sse4_2",
-			"avx",
-			"avx2",
-			"avx512",
-			"aes_ni",
-			"popcnt",
-		},
-		"x86_64": {
-			"ssse3",
-			"sse4",
-			"sse4_1",
-			"sse4_2",
-			"popcnt",
-		},
-	},
-	X86_64: {
-		"amberlake": {
-			"ssse3",
-			"sse4",
-			"sse4_1",
-			"sse4_2",
-			"avx",
-			"avx2",
-			"aes_ni",
-			"popcnt",
-		},
-		"broadwell": {
-			"ssse3",
-			"sse4",
-			"sse4_1",
-			"sse4_2",
-			"avx",
-			"avx2",
-			"aes_ni",
-			"popcnt",
-		},
-		"haswell": {
-			"ssse3",
-			"sse4",
-			"sse4_1",
-			"sse4_2",
-			"aes_ni",
-			"avx",
-			"popcnt",
-		},
-		"icelake": {
-			"ssse3",
-			"sse4",
-			"sse4_1",
-			"sse4_2",
-			"avx",
-			"avx2",
-			"avx512",
-			"aes_ni",
-			"popcnt",
-		},
-		"ivybridge": {
-			"ssse3",
-			"sse4",
-			"sse4_1",
-			"sse4_2",
-			"aes_ni",
-			"avx",
-			"popcnt",
-		},
-		"kabylake": {
-			"ssse3",
-			"sse4",
-			"sse4_1",
-			"sse4_2",
-			"avx",
-			"avx2",
-			"aes_ni",
-			"popcnt",
-		},
-		"sandybridge": {
-			"ssse3",
-			"sse4",
-			"sse4_1",
-			"sse4_2",
-			"popcnt",
-		},
-		"silvermont": {
-			"ssse3",
-			"sse4",
-			"sse4_1",
-			"sse4_2",
-			"aes_ni",
-			"popcnt",
-		},
-		"skylake": {
-			"ssse3",
-			"sse4",
-			"sse4_1",
-			"sse4_2",
-			"avx",
-			"avx2",
-			"avx512",
-			"aes_ni",
-			"popcnt",
-		},
-		"stoneyridge": {
-			"ssse3",
-			"sse4",
-			"sse4_1",
-			"sse4_2",
-			"aes_ni",
-			"avx",
-			"avx2",
-			"popcnt",
-		},
-		"tigerlake": {
-			"ssse3",
-			"sse4",
-			"sse4_1",
-			"sse4_2",
-			"avx",
-			"avx2",
-			"avx512",
-			"aes_ni",
-			"popcnt",
-		},
-		"whiskeylake": {
-			"ssse3",
-			"sse4",
-			"sse4_1",
-			"sse4_2",
-			"avx",
-			"avx2",
-			"avx512",
-			"aes_ni",
-			"popcnt",
-		},
-	},
-}
-
-var defaultArchFeatureMap = map[OsType]map[ArchType][]string{}
-
-func RegisterDefaultArchVariantFeatures(os OsType, arch ArchType, features ...string) {
-	checkCalledFromInit()
-
-	for _, feature := range features {
-		if !InList(feature, archFeatures[arch]) {
-			panic(fmt.Errorf("Invalid feature %q for arch %q variant \"\"", feature, arch))
-		}
-	}
-
-	if defaultArchFeatureMap[os] == nil {
-		defaultArchFeatureMap[os] = make(map[ArchType][]string)
-	}
-	defaultArchFeatureMap[os][arch] = features
-}
-
 // An Arch indicates a single CPU architecture.
 type Arch struct {
-	ArchType     ArchType
-	ArchVariant  string
-	CpuVariant   string
-	Abi          []string
+	// The type of the architecture (arm, arm64, x86, or x86_64).
+	ArchType ArchType
+
+	// The variant of the architecture, for example "armv7-a" or "armv7-a-neon" for arm.
+	ArchVariant string
+
+	// The variant of the CPU, for example "cortex-a53" for arm64.
+	CpuVariant string
+
+	// The list of Android app ABIs supported by the CPU architecture, for example "arm64-v8a".
+	Abi []string
+
+	// The list of arch-specific features supported by the CPU architecture, for example "neon".
 	ArchFeatures []string
 }
 
+// String returns the Arch as a string.  The value is used as the name of the variant created
+// by archMutator.
 func (a Arch) String() string {
 	s := a.ArchType.String()
 	if a.ArchVariant != "" {
@@ -521,12 +120,42 @@
 	return s
 }
 
+// ArchType is used to define the 4 supported architecture types (arm, arm64, x86, x86_64), as
+// well as the "common" architecture used for modules that support multiple architectures, for
+// example Java modules.
 type ArchType struct {
-	Name     string
-	Field    string
+	// Name is the name of the architecture type, "arm", "arm64", "x86", or "x86_64".
+	Name string
+
+	// Field is the name of the field used in properties that refer to the architecture, e.g. "Arm64".
+	Field string
+
+	// Multilib is either "lib32" or "lib64" for 32-bit or 64-bit architectures.
 	Multilib string
 }
 
+// String returns the name of the ArchType.
+func (a ArchType) String() string {
+	return a.Name
+}
+
+const COMMON_VARIANT = "common"
+
+var (
+	archTypeList []ArchType
+
+	Arm    = newArch("arm", "lib32")
+	Arm64  = newArch("arm64", "lib64")
+	X86    = newArch("x86", "lib32")
+	X86_64 = newArch("x86_64", "lib64")
+
+	Common = ArchType{
+		Name: COMMON_VARIANT,
+	}
+)
+
+var archTypeMap = map[string]ArchType{}
+
 func newArch(name, multilib string) ArchType {
 	archType := ArchType{
 		Name:     name,
@@ -534,25 +163,25 @@
 		Multilib: multilib,
 	}
 	archTypeList = append(archTypeList, archType)
+	archTypeMap[name] = archType
 	return archType
 }
 
+// ArchTypeList returns the 4 supported ArchTypes for arm, arm64, x86 and x86_64.
 func ArchTypeList() []ArchType {
 	return append([]ArchType(nil), archTypeList...)
 }
 
-func (a ArchType) String() string {
-	return a.Name
-}
-
-var _ encoding.TextMarshaler = ArchType{}
-
+// MarshalText allows an ArchType to be serialized through any encoder that supports
+// encoding.TextMarshaler.
 func (a ArchType) MarshalText() ([]byte, error) {
 	return []byte(strconv.Quote(a.String())), nil
 }
 
-var _ encoding.TextUnmarshaler = &ArchType{}
+var _ encoding.TextMarshaler = ArchType{}
 
+// UnmarshalText allows an ArchType to be deserialized through any decoder that supports
+// encoding.TextUnmarshaler.
 func (a *ArchType) UnmarshalText(text []byte) error {
 	if u, ok := archTypeMap[string(text)]; ok {
 		*a = u
@@ -562,67 +191,22 @@
 	return fmt.Errorf("unknown ArchType %q", text)
 }
 
-var BuildOs = func() OsType {
-	switch runtime.GOOS {
-	case "linux":
-		return Linux
-	case "darwin":
-		return Darwin
-	default:
-		panic(fmt.Sprintf("unsupported OS: %s", runtime.GOOS))
-	}
-}()
+var _ encoding.TextUnmarshaler = &ArchType{}
 
-var BuildArch = func() ArchType {
-	switch runtime.GOARCH {
-	case "amd64":
-		return X86_64
-	default:
-		panic(fmt.Sprintf("unsupported Arch: %s", runtime.GOARCH))
-	}
-}()
-
-var (
-	OsTypeList      []OsType
-	commonTargetMap = make(map[string]Target)
-
-	NoOsType    OsType
-	Linux       = NewOsType("linux_glibc", Host, false)
-	Darwin      = NewOsType("darwin", Host, false)
-	LinuxBionic = NewOsType("linux_bionic", Host, false)
-	Windows     = NewOsType("windows", Host, true)
-	Android     = NewOsType("android", Device, false)
-	Fuchsia     = NewOsType("fuchsia", Device, false)
-
-	// A pseudo OSType for a common os variant, which is OSType agnostic and which
-	// has dependencies on all the OS variants.
-	CommonOS = NewOsType("common_os", Generic, false)
-
-	osArchTypeMap = map[OsType][]ArchType{
-		Linux:       []ArchType{X86, X86_64},
-		LinuxBionic: []ArchType{Arm64, X86_64},
-		Darwin:      []ArchType{X86_64},
-		Windows:     []ArchType{X86, X86_64},
-		Android:     []ArchType{Arm, Arm64, X86, X86_64},
-		Fuchsia:     []ArchType{Arm64, X86_64},
-	}
-)
-
-type OsType struct {
-	Name, Field string
-	Class       OsClass
-
-	DefaultDisabled bool
-}
-
+// OsClass is an enum that describes whether a variant of a module runs on the host, on the device,
+// or is generic.
 type OsClass int
 
 const (
+	// Generic is used for variants of modules that are not OS-specific.
 	Generic OsClass = iota
+	// Device is used for variants of modules that run on the device.
 	Device
+	// Host is used for variants of modules that run on the host.
 	Host
 )
 
+// String returns the OsClass as a string.
 func (class OsClass) String() string {
 	switch class {
 	case Generic:
@@ -636,22 +220,48 @@
 	}
 }
 
+// OsType describes an OS variant of a module.
+type OsType struct {
+	// Name is the name of the OS.  It is also used as the name of the property in Android.bp
+	// files.
+	Name string
+
+	// Field is the name of the OS converted to an exported field name, i.e. with the first
+	// character capitalized.
+	Field string
+
+	// Class is the OsClass of the OS.
+	Class OsClass
+
+	// DefaultDisabled is set when the module variants for the OS should not be created unless
+	// the module explicitly requests them.  This is used to limit Windows cross compilation to
+	// only modules that need it.
+	DefaultDisabled bool
+}
+
+// String returns the name of the OsType.
 func (os OsType) String() string {
 	return os.Name
 }
 
+// Bionic returns true if the OS uses the Bionic libc runtime, i.e. if the OS is Android or
+// is Linux with Bionic.
 func (os OsType) Bionic() bool {
 	return os == Android || os == LinuxBionic
 }
 
+// Linux returns true if the OS uses the Linux kernel, i.e. if the OS is Android or is Linux
+// with or without the Bionic libc runtime.
 func (os OsType) Linux() bool {
 	return os == Android || os == Linux || os == LinuxBionic
 }
 
-func NewOsType(name string, class OsClass, defDisabled bool) OsType {
+// newOsType constructs an OsType and adds it to the global lists.
+func newOsType(name string, class OsClass, defDisabled bool, archTypes ...ArchType) OsType {
+	checkCalledFromInit()
 	os := OsType{
 		Name:  name,
-		Field: strings.Title(name),
+		Field: proptools.FieldNameForProperty(name),
 		Class: class,
 
 		DefaultDisabled: defDisabled,
@@ -663,10 +273,12 @@
 	} else {
 		commonTargetMap[name] = Target{Os: os, Arch: Arch{ArchType: Common}}
 	}
+	osArchTypeMap[os] = archTypes
 
 	return os
 }
 
+// osByName returns the OsType that has the given name, or NoOsType if none match.
 func osByName(name string) OsType {
 	for _, os := range OsTypeList {
 		if os.Name == name {
@@ -677,18 +289,74 @@
 	return NoOsType
 }
 
-type NativeBridgeSupport bool
+// BuildOs returns the OsType for the OS that the build is running on.
+var BuildOs = func() OsType {
+	switch runtime.GOOS {
+	case "linux":
+		return Linux
+	case "darwin":
+		return Darwin
+	default:
+		panic(fmt.Sprintf("unsupported OS: %s", runtime.GOOS))
+	}
+}()
 
-const (
-	NativeBridgeDisabled NativeBridgeSupport = false
-	NativeBridgeEnabled  NativeBridgeSupport = true
+// BuildArch returns the ArchType for the CPU that the build is running on.
+var BuildArch = func() ArchType {
+	switch runtime.GOARCH {
+	case "amd64":
+		return X86_64
+	default:
+		panic(fmt.Sprintf("unsupported Arch: %s", runtime.GOARCH))
+	}
+}()
+
+var (
+	// OsTypeList contains a list of all the supported OsTypes, including ones not supported
+	// by the current build host or the target device.
+	OsTypeList []OsType
+	// commonTargetMap maps names of OsTypes to the corresponding common Target, i.e. the
+	// Target with the same OsType and the common ArchType.
+	commonTargetMap = make(map[string]Target)
+	// osArchTypeMap maps OsTypes to the list of supported ArchTypes for that OS.
+	osArchTypeMap = map[OsType][]ArchType{}
+
+	// NoOsType is a placeholder for when no OS is needed.
+	NoOsType OsType
+	// Linux is the OS for the Linux kernel plus the glibc runtime.
+	Linux = newOsType("linux_glibc", Host, false, X86, X86_64)
+	// Darwin is the OS for MacOS/Darwin host machines.
+	Darwin = newOsType("darwin", Host, false, X86_64)
+	// LinuxBionic is the OS for the Linux kernel plus the Bionic libc runtime, but without the
+	// rest of Android.
+	LinuxBionic = newOsType("linux_bionic", Host, false, Arm64, X86_64)
+	// Windows the OS for Windows host machines.
+	Windows = newOsType("windows", Host, true, X86, X86_64)
+	// Android is the OS for target devices that run all of Android, including the Linux kernel
+	// and the Bionic libc runtime.
+	Android = newOsType("android", Device, false, Arm, Arm64, X86, X86_64)
+	// Fuchsia is the OS for target devices that run Fuchsia.
+	Fuchsia = newOsType("fuchsia", Device, false, Arm64, X86_64)
+
+	// CommonOS is a pseudo OSType for a common OS variant, which is OsType agnostic and which
+	// has dependencies on all the OS variants.
+	CommonOS = newOsType("common_os", Generic, false)
 )
 
+// Target specifies the OS and architecture that a module is being compiled for.
 type Target struct {
-	Os                       OsType
-	Arch                     Arch
-	NativeBridge             NativeBridgeSupport
+	// Os the OS that the module is being compiled for (e.g. "linux_glibc", "android").
+	Os OsType
+	// Arch is the architecture that the module is being compiled for.
+	Arch Arch
+	// NativeBridge is NativeBridgeEnabled if the architecture is supported using NativeBridge
+	// (i.e. arm on x86) for this device.
+	NativeBridge NativeBridgeSupport
+	// NativeBridgeHostArchName is the name of the real architecture that is used to implement
+	// the NativeBridge architecture.  For example, for arm on x86 this would be "x86".
 	NativeBridgeHostArchName string
+	// NativeBridgeRelativePath is the name of the subdirectory that will contain NativeBridge
+	// libraries and binaries.
 	NativeBridgeRelativePath string
 
 	// HostCross is true when the target cannot run natively on the current build host.
@@ -697,14 +365,25 @@
 	HostCross bool
 }
 
+// NativeBridgeSupport is an enum that specifies if a Target supports NativeBridge.
+type NativeBridgeSupport bool
+
+const (
+	NativeBridgeDisabled NativeBridgeSupport = false
+	NativeBridgeEnabled  NativeBridgeSupport = true
+)
+
+// String returns the OS and arch variations used for the Target.
 func (target Target) String() string {
 	return target.OsVariation() + "_" + target.ArchVariation()
 }
 
+// OsVariation returns the name of the variation used by the osMutator for the Target.
 func (target Target) OsVariation() string {
 	return target.Os.String()
 }
 
+// ArchVariation returns the name of the variation used by the archMutator for the Target.
 func (target Target) ArchVariation() string {
 	var variation string
 	if target.NativeBridge {
@@ -715,6 +394,8 @@
 	return variation
 }
 
+// Variations returns a list of blueprint.Variations for the osMutator and archMutator for the
+// Target.
 func (target Target) Variations() []blueprint.Variation {
 	return []blueprint.Variation{
 		{Mutator: "os", Variation: target.OsVariation()},
@@ -722,10 +403,16 @@
 	}
 }
 
+// osMutator splits an arch-specific module into a variant for each OS that is enabled for the
+// module.  It uses the HostOrDevice value passed to InitAndroidArchModule and the
+// device_supported and host_supported properties to determine which OsTypes are enabled for this
+// module, then searches through the Targets to determine which have enabled Targets for this
+// module.
 func osMutator(bpctx blueprint.BottomUpMutatorContext) {
 	var module Module
 	var ok bool
 	if module, ok = bpctx.Module().(Module); !ok {
+		// The module is not a Soong module, it is a Blueprint module.
 		if bootstrap.IsBootstrapModule(bpctx.Module()) {
 			// Bootstrap Go modules are always the build OS or linux bionic.
 			config := bpctx.Config().(Config)
@@ -749,12 +436,14 @@
 
 	base := module.base()
 
+	// Nothing to do for modules that are not architecture specific (e.g. a genrule).
 	if !base.ArchSpecific() {
 		return
 	}
 
+	// Collect a list of OSTypes supported by this module based on the HostOrDevice value
+	// passed to InitAndroidArchModule and the device_supported and host_supported properties.
 	var moduleOSList []OsType
-
 	for _, os := range OsTypeList {
 		for _, t := range mctx.Config().Targets[os] {
 			if base.supportsTarget(t) {
@@ -764,20 +453,21 @@
 		}
 	}
 
+	// If there are no supported OSes then disable the module.
 	if len(moduleOSList) == 0 {
 		base.Disable()
 		return
 	}
 
+	// Convert the list of supported OsTypes to the variation names.
 	osNames := make([]string, len(moduleOSList))
-
 	for i, os := range moduleOSList {
 		osNames[i] = os.String()
 	}
 
 	createCommonOSVariant := base.commonProperties.CreateCommonOSVariant
 	if createCommonOSVariant {
-		// A CommonOS variant was requested so add it to the list of OS's variants to
+		// A CommonOS variant was requested so add it to the list of OS variants to
 		// create. It needs to be added to the end because it needs to depend on the
 		// the other variants in the list returned by CreateVariations(...) and inter
 		// variant dependencies can only be created from a later variant in that list to
@@ -787,6 +477,8 @@
 		moduleOSList = append(moduleOSList, CommonOS)
 	}
 
+	// Create the variations, annotate each one with which OS it was created for, and
+	// squash the appropriate OS-specific properties into the top level properties.
 	modules := mctx.CreateVariations(osNames...)
 	for i, m := range modules {
 		m.base().commonProperties.CompileOS = moduleOSList[i]
@@ -841,7 +533,7 @@
 }
 
 // archMutator splits a module into a variant for each Target requested by the module.  Target selection
-// for a module is in three levels, OsClass, mulitlib, and then Target.
+// for a module is in three levels, OsClass, multilib, and then Target.
 // OsClass selection is determined by:
 //    - The HostOrDeviceSupported value passed in to InitAndroidArchModule by the module type factory, which selects
 //      whether the module type can compile for host, device or both.
@@ -858,7 +550,11 @@
 //        but may be arm for a 32-bit only build.
 //    "32": compile for only a single 32-bit Target supported by the OsClass.
 //    "64": compile for only a single 64-bit Target supported by the OsClass.
-//    "common": compile a for a single Target that will work on all Targets suported by the OsClass (for example Java).
+//    "common": compile a for a single Target that will work on all Targets supported by the OsClass (for example Java).
+//    "common_first": compile a for a Target that will work on all Targets supported by the OsClass
+//        (same as "common"), plus a second Target for the preferred Target supported by the OsClass
+//        (same as "first").  This is used for java_binary that produces a common .jar and a wrapper
+//        executable script.
 //
 // Once the list of Targets is determined, the module is split into a variant for each Target.
 //
@@ -899,8 +595,8 @@
 
 	osTargets := mctx.Config().Targets[os]
 	image := base.commonProperties.ImageVariation
-	// Filter NativeBridge targets unless they are explicitly supported
-	// Skip creating native bridge variants for vendor modules
+	// Filter NativeBridge targets unless they are explicitly supported.
+	// Skip creating native bridge variants for non-core modules.
 	if os == Android &&
 		!(Bool(base.commonProperties.Native_bridge_supported) && image == CoreVariation) {
 
@@ -919,17 +615,24 @@
 		osTargets = []Target{osTargets[0]}
 	}
 
+	// Some modules want compile_multilib: "first" to mean 32-bit, not 64-bit.
+	// This is used for Windows support and for HOST_PREFER_32_BIT=true support for Art modules.
 	prefer32 := false
 	if base.prefer32 != nil {
 		prefer32 = base.prefer32(mctx, base, os)
 	}
 
+	// Determine the multilib selection for this module.
 	multilib, extraMultilib := decodeMultilib(base, os.Class)
+
+	// Convert the multilib selection into a list of Targets.
 	targets, err := decodeMultilibTargets(multilib, osTargets, prefer32)
 	if err != nil {
 		mctx.ModuleErrorf("%s", err.Error())
 	}
 
+	// If the module is using extraMultilib, decode the extraMultilib selection into
+	// a separate list of Targets.
 	var multiTargets []Target
 	if extraMultilib != "" {
 		multiTargets, err = decodeMultilibTargets(extraMultilib, osTargets, prefer32)
@@ -938,23 +641,27 @@
 		}
 	}
 
+	// Recovery is always the primary architecture, filter out any other architectures.
 	if image == RecoveryVariation {
 		primaryArch := mctx.Config().DevicePrimaryArchType()
 		targets = filterToArch(targets, primaryArch)
 		multiTargets = filterToArch(multiTargets, primaryArch)
 	}
 
+	// If there are no supported targets disable the module.
 	if len(targets) == 0 {
 		base.Disable()
 		return
 	}
 
+	// Convert the targets into a list of arch variation names.
 	targetNames := make([]string, len(targets))
-
 	for i, target := range targets {
 		targetNames[i] = target.ArchVariation()
 	}
 
+	// Create the variations, annotate each one with which Target it was created for, and
+	// squash the appropriate arch-specific properties into the top level properties.
 	modules := mctx.CreateVariations(targetNames...)
 	for i, m := range modules {
 		addTargetProperties(m, targets[i], multiTargets, i == 0)
@@ -968,22 +675,34 @@
 	}
 }
 
+// addTargetProperties annotates a variant with the Target is is being compiled for, the list
+// of additional Targets it is supporting (if any), and whether it is the primary Target for
+// the module.
 func addTargetProperties(m Module, target Target, multiTargets []Target, primaryTarget bool) {
 	m.base().commonProperties.CompileTarget = target
 	m.base().commonProperties.CompileMultiTargets = multiTargets
 	m.base().commonProperties.CompilePrimary = primaryTarget
 }
 
+// decodeMultilib returns the appropriate compile_multilib property for the module, or the default
+// multilib from the factory's call to InitAndroidArchModule if none was set.  For modules that
+// called InitAndroidMultiTargetsArchModule it always returns "common" for multilib, and returns
+// the actual multilib in extraMultilib.
 func decodeMultilib(base *ModuleBase, class OsClass) (multilib, extraMultilib string) {
+	// First check the "android.compile_multilib" or "host.compile_multilib" properties.
 	switch class {
 	case Device:
 		multilib = String(base.commonProperties.Target.Android.Compile_multilib)
 	case Host:
 		multilib = String(base.commonProperties.Target.Host.Compile_multilib)
 	}
+
+	// If those aren't set, try the "compile_multilib" property.
 	if multilib == "" {
 		multilib = String(base.commonProperties.Compile_multilib)
 	}
+
+	// If that wasn't set, use the default multilib set by the factory.
 	if multilib == "" {
 		multilib = base.commonProperties.Default_multilib
 	}
@@ -1000,6 +719,8 @@
 	}
 }
 
+// filterToArch takes a list of Targets and an ArchType, and returns a modified list that contains
+// only Targets that have the specified ArchType.
 func filterToArch(targets []Target, arch ArchType) []Target {
 	for i := 0; i < len(targets); i++ {
 		if targets[i].Arch.ArchType != arch {
@@ -1010,17 +731,27 @@
 	return targets
 }
 
-type archPropTypeDesc struct {
-	arch, multilib, target reflect.Type
-}
-
+// archPropRoot is a struct type used as the top level of the arch-specific properties.  It
+// contains the "arch", "multilib", and "target" property structs.  It is used to split up the
+// property structs to limit how much is allocated when a single arch-specific property group is
+// used.  The types are interface{} because they will hold instances of runtime-created types.
 type archPropRoot struct {
 	Arch, Multilib, Target interface{}
 }
 
+// archPropTypeDesc holds the runtime-created types for the property structs to instantiate to
+// create an archPropRoot property struct.
+type archPropTypeDesc struct {
+	arch, multilib, target reflect.Type
+}
+
 // createArchPropTypeDesc takes a reflect.Type that is either a struct or a pointer to a struct, and
 // returns lists of reflect.Types that contains the arch-variant properties inside structs for each
 // arch, multilib and target property.
+//
+// This is a relatively expensive operation, so the results are cached in the global
+// archPropTypeMap.  It is constructed entirely based on compile-time data, so there is no need
+// to isolate the results between multiple tests running in parallel.
 func createArchPropTypeDesc(props reflect.Type) []archPropTypeDesc {
 	// Each property struct shard will be nested many times under the runtime generated arch struct,
 	// which can hit the limit of 64kB for the name of runtime generated structs.  They are nested
@@ -1029,7 +760,12 @@
 	// could cause problems if a single deeply nested property no longer fits in the name.
 	const maxArchTypeNameSize = 500
 
+	// Convert the type to a new set of types that contains only the arch-specific properties
+	// (those that are tagged with `android:"arch_specific"`), and sharded into multiple types
+	// to keep the runtime-generated names under the limit.
 	propShards, _ := proptools.FilterPropertyStructSharded(props, maxArchTypeNameSize, filterArchStruct)
+
+	// If the type has no arch-specific properties there is nothing to do.
 	if len(propShards) == 0 {
 		return nil
 	}
@@ -1037,6 +773,8 @@
 	var ret []archPropTypeDesc
 	for _, props := range propShards {
 
+		// variantFields takes a list of variant property field names and returns a list the
+		// StructFields with the names and the type of the current shard.
 		variantFields := func(names []string) []reflect.StructField {
 			ret := make([]reflect.StructField, len(names))
 
@@ -1048,9 +786,11 @@
 			return ret
 		}
 
+		// Create a type that contains the properties in this shard repeated for each
+		// architecture, architecture variant, and architecture feature.
 		archFields := make([]reflect.StructField, len(archTypeList))
 		for i, arch := range archTypeList {
-			variants := []string{}
+			var variants []string
 
 			for _, archVariant := range archVariants[arch] {
 				archVariant := variantReplacer.Replace(archVariant)
@@ -1061,8 +801,13 @@
 				variants = append(variants, proptools.FieldNameForProperty(feature))
 			}
 
+			// Create the StructFields for each architecture variant architecture feature
+			// (e.g. "arch.arm.cortex-a53" or "arch.arm.neon").
 			fields := variantFields(variants)
 
+			// Create the StructField for the architecture itself (e.g. "arch.arm").  The special
+			// "BlueprintEmbed" name is used by Blueprint to put the properties in the
+			// parent struct.
 			fields = append([]reflect.StructField{{
 				Name:      "BlueprintEmbed",
 				Type:      props,
@@ -1074,10 +819,15 @@
 				Type: reflect.StructOf(fields),
 			}
 		}
+
+		// Create the type of the "arch" property struct for this shard.
 		archType := reflect.StructOf(archFields)
 
+		// Create the type for the "multilib" property struct for this shard, containing the
+		// "multilib.lib32" and "multilib.lib64" property structs.
 		multilibType := reflect.StructOf(variantFields([]string{"Lib32", "Lib64"}))
 
+		// Start with a list of the special targets
 		targets := []string{
 			"Host",
 			"Android64",
@@ -1090,11 +840,14 @@
 			"Native_bridge",
 		}
 		for _, os := range OsTypeList {
+			// Add all the OSes.
 			targets = append(targets, os.Field)
 
+			// Add the OS/Arch combinations, e.g. "android_arm64".
 			for _, archType := range osArchTypeMap[os] {
 				targets = append(targets, os.Field+"_"+archType.Name)
 
+				// Also add the special "linux_<arch>" and "bionic_<arch>" property structs.
 				if os.Linux() {
 					target := "Linux_" + archType.Name
 					if !InList(target, targets) {
@@ -1110,8 +863,10 @@
 			}
 		}
 
+		// Create the type for the "target" property struct for this shard.
 		targetType := reflect.StructOf(variantFields(targets))
 
+		// Return a descriptor of the 3 runtime-created types.
 		ret = append(ret, archPropTypeDesc{
 			arch:     reflect.PtrTo(archType),
 			multilib: reflect.PtrTo(multilibType),
@@ -1121,6 +876,11 @@
 	return ret
 }
 
+// variantReplacer converts architecture variant or architecture feature names into names that
+// are valid for an Android.bp file.
+var variantReplacer = strings.NewReplacer("-", "_", ".", "_")
+
+// filterArchStruct returns true if the given field is an architecture specific property.
 func filterArchStruct(field reflect.StructField, prefix string) (bool, reflect.StructField) {
 	if proptools.HasTag(field, "android", "arch_variant") {
 		// The arch_variant field isn't necessary past this point
@@ -1147,12 +907,17 @@
 	return false, field
 }
 
+// archPropTypeMap contains a cache of the results of createArchPropTypeDesc for each type.  It is
+// shared across all Contexts, but is constructed based only on compile-time information so there
+// is no risk of contaminating one Context with data from another.
 var archPropTypeMap OncePer
 
-func InitArchModule(m Module) {
+// initArchModule adds the architecture-specific property structs to a Module.
+func initArchModule(m Module) {
 
 	base := m.base()
 
+	// Store the original list of top level property structs
 	base.generalProperties = m.GetProperties()
 
 	for _, properties := range base.generalProperties {
@@ -1169,10 +934,13 @@
 				propertiesValue.Interface()))
 		}
 
+		// Get or create the arch-specific property struct types for this property struct type.
 		archPropTypes := archPropTypeMap.Once(NewCustomOnceKey(t), func() interface{} {
 			return createArchPropTypeDesc(t)
 		}).([]archPropTypeDesc)
 
+		// Instantiate one of each arch-specific property struct type and add it to the
+		// properties for the Module.
 		var archProperties []interface{}
 		for _, t := range archPropTypes {
 			archProperties = append(archProperties, &archPropRoot{
@@ -1185,14 +953,18 @@
 		m.AddProperties(archProperties...)
 	}
 
+	// Update the list of properties that can be set by a defaults module or a call to
+	// AppendMatchingProperties or PrependMatchingProperties.
 	base.customizableProperties = m.GetProperties()
 }
 
-var variantReplacer = strings.NewReplacer("-", "_", ".", "_")
-
+// appendProperties squashes properties from the given field of the given src property struct
+// into the dst property struct.  Returns the reflect.Value of the field in the src property
+// struct to be used for further appendProperties calls on fields of that property struct.
 func (m *ModuleBase) appendProperties(ctx BottomUpMutatorContext,
 	dst interface{}, src reflect.Value, field, srcPrefix string) reflect.Value {
 
+	// Step into non-nil pointers to structs in the src value.
 	if src.Kind() == reflect.Ptr {
 		if src.IsNil() {
 			return src
@@ -1200,18 +972,25 @@
 		src = src.Elem()
 	}
 
+	// Find the requested field in the src struct.
 	src = src.FieldByName(field)
 	if !src.IsValid() {
 		ctx.ModuleErrorf("field %q does not exist", srcPrefix)
 		return src
 	}
 
+	// Save the value of the field in the src struct to return.
 	ret := src
 
+	// If the value of the field is a struct (as opposed to a pointer to a struct) then step
+	// into the BlueprintEmbed field.
 	if src.Kind() == reflect.Struct {
 		src = src.FieldByName("BlueprintEmbed")
 	}
 
+	// order checks the `android:"variant_prepend"` tag to handle properties where the
+	// arch-specific value needs to come before the generic value, for example for lists of
+	// include directories.
 	order := func(property string,
 		dstField, srcField reflect.StructField,
 		dstValue, srcValue interface{}) (proptools.Order, error) {
@@ -1222,6 +1001,7 @@
 		}
 	}
 
+	// Squash the located property struct into the destination property struct.
 	err := proptools.ExtendMatchingProperties([]interface{}{dst}, src.Interface(), nil, order)
 	if err != nil {
 		if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
@@ -1234,7 +1014,8 @@
 	return ret
 }
 
-// Rewrite the module's properties structs to contain os-specific values.
+// Squash the appropriate OS-specific property structs into the matching top level property structs
+// based on the CompileOS value that was annotated on the variant.
 func (m *ModuleBase) setOSProperties(ctx BottomUpMutatorContext) {
 	os := m.commonProperties.CompileOS
 
@@ -1328,7 +1109,8 @@
 	}
 }
 
-// Rewrite the module's properties structs to contain arch-specific values.
+// Squash the appropriate arch-specific property structs into the matching top level property
+// structs based on the CompileTarget value that was annotated on the variant.
 func (m *ModuleBase) setArchProperties(ctx BottomUpMutatorContext) {
 	arch := m.Arch()
 	os := m.Os()
@@ -1480,22 +1262,7 @@
 	}
 }
 
-func forEachInterface(v reflect.Value, f func(reflect.Value)) {
-	switch v.Kind() {
-	case reflect.Interface:
-		f(v)
-	case reflect.Struct:
-		for i := 0; i < v.NumField(); i++ {
-			forEachInterface(v.Field(i), f)
-		}
-	case reflect.Ptr:
-		forEachInterface(v.Elem(), f)
-	default:
-		panic(fmt.Errorf("Unsupported kind %s", v.Kind()))
-	}
-}
-
-// Convert the arch product variables into a list of targets for each os class structs
+// Convert the arch product variables into a list of targets for each OsType.
 func decodeTargetProductVariables(config *config) (map[OsType][]Target, error) {
 	variables := config.productVariables
 
@@ -1567,19 +1334,26 @@
 		return nil, fmt.Errorf("No host primary architecture set")
 	}
 
+	// The primary host target, which must always exist.
 	addTarget(BuildOs, *variables.HostArch, nil, nil, nil, NativeBridgeDisabled, nil, nil)
 
+	// An optional secondary host target.
 	if variables.HostSecondaryArch != nil && *variables.HostSecondaryArch != "" {
 		addTarget(BuildOs, *variables.HostSecondaryArch, nil, nil, nil, NativeBridgeDisabled, nil, nil)
 	}
 
+	// An optional host target that uses the Bionic glibc runtime.
 	if Bool(config.Host_bionic) {
 		addTarget(LinuxBionic, "x86_64", nil, nil, nil, NativeBridgeDisabled, nil, nil)
 	}
+
+	// An optional cross-compiled host target that uses the Bionic glibc runtime on an arm64
+	// architecture.
 	if Bool(config.Host_bionic_arm64) {
 		addTarget(LinuxBionic, "arm64", nil, nil, nil, NativeBridgeDisabled, nil, nil)
 	}
 
+	// Optional cross-compiled host targets, generally Windows.
 	if String(variables.CrossHost) != "" {
 		crossHostOs := osByName(*variables.CrossHost)
 		if crossHostOs == NoOsType {
@@ -1590,28 +1364,34 @@
 			return nil, fmt.Errorf("No cross-host primary architecture set")
 		}
 
+		// The primary cross-compiled host target.
 		addTarget(crossHostOs, *variables.CrossHostArch, nil, nil, nil, NativeBridgeDisabled, nil, nil)
 
+		// An optional secondary cross-compiled host target.
 		if variables.CrossHostSecondaryArch != nil && *variables.CrossHostSecondaryArch != "" {
 			addTarget(crossHostOs, *variables.CrossHostSecondaryArch, nil, nil, nil, NativeBridgeDisabled, nil, nil)
 		}
 	}
 
+	// Optional device targets
 	if variables.DeviceArch != nil && *variables.DeviceArch != "" {
 		var target = Android
 		if Bool(variables.Fuchsia) {
 			target = Fuchsia
 		}
 
+		// The primary device target.
 		addTarget(target, *variables.DeviceArch, variables.DeviceArchVariant,
 			variables.DeviceCpuVariant, variables.DeviceAbi, NativeBridgeDisabled, nil, nil)
 
+		// An optional secondary device target.
 		if variables.DeviceSecondaryArch != nil && *variables.DeviceSecondaryArch != "" {
 			addTarget(Android, *variables.DeviceSecondaryArch,
 				variables.DeviceSecondaryArchVariant, variables.DeviceSecondaryCpuVariant,
 				variables.DeviceSecondaryAbi, NativeBridgeDisabled, nil, nil)
 		}
 
+		// An optional NativeBridge device target.
 		if variables.NativeBridgeArch != nil && *variables.NativeBridgeArch != "" {
 			addTarget(Android, *variables.NativeBridgeArch,
 				variables.NativeBridgeArchVariant, variables.NativeBridgeCpuVariant,
@@ -1619,6 +1399,7 @@
 				variables.NativeBridgeRelativePath)
 		}
 
+		// An optional secondary NativeBridge device target.
 		if variables.DeviceSecondaryArch != nil && *variables.DeviceSecondaryArch != "" &&
 			variables.NativeBridgeSecondaryArch != nil && *variables.NativeBridgeSecondaryArch != "" {
 			addTarget(Android, *variables.NativeBridgeSecondaryArch,
@@ -1653,6 +1434,7 @@
 	return false
 }
 
+// archConfig describes a built-in configuration.
 type archConfig struct {
 	arch        string
 	archVariant string
@@ -1660,6 +1442,7 @@
 	abi         []string
 }
 
+// getMegaDeviceConfig returns a list of archConfigs for every architecture simultaneously.
 func getMegaDeviceConfig() []archConfig {
 	return []archConfig{
 		{"arm", "armv7-a", "generic", []string{"armeabi-v7a"}},
@@ -1706,6 +1489,7 @@
 	}
 }
 
+// getNdkAbisConfig returns a list of archConfigs for the ABIs supported by the NDK.
 func getNdkAbisConfig() []archConfig {
 	return []archConfig{
 		{"arm", "armv7-a", "", []string{"armeabi-v7a"}},
@@ -1715,6 +1499,7 @@
 	}
 }
 
+// getAmlAbisConfig returns a list of archConfigs for the ABIs supported by mainline modules.
 func getAmlAbisConfig() []archConfig {
 	return []archConfig{
 		{"arm", "armv7-a-neon", "", []string{"armeabi-v7a"}},
@@ -1724,6 +1509,7 @@
 	}
 }
 
+// decodeArchSettings converts a list of archConfigs into a list of Targets for the given OsType.
 func decodeArchSettings(os OsType, archConfigs []archConfig) ([]Target, error) {
 	var ret []Target
 
@@ -1743,15 +1529,9 @@
 	return ret, nil
 }
 
-// Convert a set of strings from product variables into a single Arch struct
+// decodeArch converts a set of strings from product variables into an Arch struct.
 func decodeArch(os OsType, arch string, archVariant, cpuVariant *string, abi []string) (Arch, error) {
-	stringPtr := func(p *string) string {
-		if p != nil {
-			return *p
-		}
-		return ""
-	}
-
+	// Verify the arch is valid
 	archType, ok := archTypeMap[arch]
 	if !ok {
 		return Arch{}, fmt.Errorf("unknown arch %q", arch)
@@ -1759,19 +1539,22 @@
 
 	a := Arch{
 		ArchType:    archType,
-		ArchVariant: stringPtr(archVariant),
-		CpuVariant:  stringPtr(cpuVariant),
+		ArchVariant: String(archVariant),
+		CpuVariant:  String(cpuVariant),
 		Abi:         abi,
 	}
 
+	// Convert generic arch variants into the empty string.
 	if a.ArchVariant == a.ArchType.Name || a.ArchVariant == "generic" {
 		a.ArchVariant = ""
 	}
 
+	// Convert generic CPU variants into the empty string.
 	if a.CpuVariant == a.ArchType.Name || a.CpuVariant == "generic" {
 		a.CpuVariant = ""
 	}
 
+	// Filter empty ABIs out of the list.
 	for i := 0; i < len(a.Abi); i++ {
 		if a.Abi[i] == "" {
 			a.Abi = append(a.Abi[:i], a.Abi[i+1:]...)
@@ -1780,10 +1563,12 @@
 	}
 
 	if a.ArchVariant == "" {
+		// Set ArchFeatures from the default arch features.
 		if featureMap, ok := defaultArchFeatureMap[os]; ok {
 			a.ArchFeatures = featureMap[archType]
 		}
 	} else {
+		// Set ArchFeatures from the arch type.
 		if featureMap, ok := archFeatureMap[archType]; ok {
 			a.ArchFeatures = featureMap[a.ArchVariant]
 		}
@@ -1792,6 +1577,8 @@
 	return a, nil
 }
 
+// filterMultilibTargets takes a list of Targets and a multilib value and returns a new list of
+// Targets containing only those that have the given multilib value.
 func filterMultilibTargets(targets []Target, multilib string) []Target {
 	var ret []Target
 	for _, t := range targets {
@@ -1802,8 +1589,8 @@
 	return ret
 }
 
-// Return the set of Os specific common architecture targets for each Os in a list of
-// targets.
+// getCommonTargets returns the set of Os specific common architecture targets for each Os in a list
+// of targets.
 func getCommonTargets(targets []Target) []Target {
 	var ret []Target
 	set := make(map[string]bool)
@@ -1818,6 +1605,9 @@
 	return ret
 }
 
+// firstTarget takes a list of Targets and a list of multilib values and returns a list of Targets
+// that contains zero or one Target for each OsType, selecting the one that matches the earliest
+// filter.
 func firstTarget(targets []Target, filters ...string) []Target {
 	// find the first target from each OS
 	var ret []Target
@@ -1837,9 +1627,10 @@
 	return ret
 }
 
-// Use the module multilib setting to select one or more targets from a target list
+// decodeMultilibTargets uses the module's multilib setting to select one or more targets from a
+// list of Targets.
 func decodeMultilibTargets(multilib string, targets []Target, prefer32 bool) ([]Target, error) {
-	buildTargets := []Target{}
+	var buildTargets []Target
 
 	switch multilib {
 	case "common":
diff --git a/android/arch_list.go b/android/arch_list.go
new file mode 100644
index 0000000..0c33b9d
--- /dev/null
+++ b/android/arch_list.go
@@ -0,0 +1,410 @@
+// Copyright 2020 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package android
+
+import "fmt"
+
+var archVariants = map[ArchType][]string{
+	Arm: {
+		"armv7-a",
+		"armv7-a-neon",
+		"armv8-a",
+		"armv8-2a",
+		"cortex-a7",
+		"cortex-a8",
+		"cortex-a9",
+		"cortex-a15",
+		"cortex-a53",
+		"cortex-a53-a57",
+		"cortex-a55",
+		"cortex-a72",
+		"cortex-a73",
+		"cortex-a75",
+		"cortex-a76",
+		"krait",
+		"kryo",
+		"kryo385",
+		"exynos-m1",
+		"exynos-m2",
+	},
+	Arm64: {
+		"armv8_a",
+		"armv8_2a",
+		"armv8-2a-dotprod",
+		"cortex-a53",
+		"cortex-a55",
+		"cortex-a72",
+		"cortex-a73",
+		"cortex-a75",
+		"cortex-a76",
+		"kryo",
+		"kryo385",
+		"exynos-m1",
+		"exynos-m2",
+	},
+	X86: {
+		"amberlake",
+		"atom",
+		"broadwell",
+		"haswell",
+		"icelake",
+		"ivybridge",
+		"kabylake",
+		"sandybridge",
+		"silvermont",
+		"skylake",
+		"stoneyridge",
+		"tigerlake",
+		"whiskeylake",
+		"x86_64",
+	},
+	X86_64: {
+		"amberlake",
+		"broadwell",
+		"haswell",
+		"icelake",
+		"ivybridge",
+		"kabylake",
+		"sandybridge",
+		"silvermont",
+		"skylake",
+		"stoneyridge",
+		"tigerlake",
+		"whiskeylake",
+	},
+}
+
+var archFeatures = map[ArchType][]string{
+	Arm: {
+		"neon",
+	},
+	Arm64: {
+		"dotprod",
+	},
+	X86: {
+		"ssse3",
+		"sse4",
+		"sse4_1",
+		"sse4_2",
+		"aes_ni",
+		"avx",
+		"avx2",
+		"avx512",
+		"popcnt",
+		"movbe",
+	},
+	X86_64: {
+		"ssse3",
+		"sse4",
+		"sse4_1",
+		"sse4_2",
+		"aes_ni",
+		"avx",
+		"avx2",
+		"avx512",
+		"popcnt",
+	},
+}
+
+var archFeatureMap = map[ArchType]map[string][]string{
+	Arm: {
+		"armv7-a-neon": {
+			"neon",
+		},
+		"armv8-a": {
+			"neon",
+		},
+		"armv8-2a": {
+			"neon",
+		},
+	},
+	Arm64: {
+		"armv8-2a-dotprod": {
+			"dotprod",
+		},
+	},
+	X86: {
+		"amberlake": {
+			"ssse3",
+			"sse4",
+			"sse4_1",
+			"sse4_2",
+			"avx",
+			"avx2",
+			"aes_ni",
+			"popcnt",
+		},
+		"atom": {
+			"ssse3",
+			"movbe",
+		},
+		"broadwell": {
+			"ssse3",
+			"sse4",
+			"sse4_1",
+			"sse4_2",
+			"avx",
+			"avx2",
+			"aes_ni",
+			"popcnt",
+		},
+		"haswell": {
+			"ssse3",
+			"sse4",
+			"sse4_1",
+			"sse4_2",
+			"aes_ni",
+			"avx",
+			"popcnt",
+			"movbe",
+		},
+		"icelake": {
+			"ssse3",
+			"sse4",
+			"sse4_1",
+			"sse4_2",
+			"avx",
+			"avx2",
+			"avx512",
+			"aes_ni",
+			"popcnt",
+		},
+		"ivybridge": {
+			"ssse3",
+			"sse4",
+			"sse4_1",
+			"sse4_2",
+			"aes_ni",
+			"avx",
+			"popcnt",
+		},
+		"kabylake": {
+			"ssse3",
+			"sse4",
+			"sse4_1",
+			"sse4_2",
+			"avx",
+			"avx2",
+			"aes_ni",
+			"popcnt",
+		},
+		"sandybridge": {
+			"ssse3",
+			"sse4",
+			"sse4_1",
+			"sse4_2",
+			"popcnt",
+		},
+		"silvermont": {
+			"ssse3",
+			"sse4",
+			"sse4_1",
+			"sse4_2",
+			"aes_ni",
+			"popcnt",
+			"movbe",
+		},
+		"skylake": {
+			"ssse3",
+			"sse4",
+			"sse4_1",
+			"sse4_2",
+			"avx",
+			"avx2",
+			"avx512",
+			"aes_ni",
+			"popcnt",
+		},
+		"stoneyridge": {
+			"ssse3",
+			"sse4",
+			"sse4_1",
+			"sse4_2",
+			"aes_ni",
+			"avx",
+			"avx2",
+			"popcnt",
+			"movbe",
+		},
+		"tigerlake": {
+			"ssse3",
+			"sse4",
+			"sse4_1",
+			"sse4_2",
+			"avx",
+			"avx2",
+			"avx512",
+			"aes_ni",
+			"popcnt",
+		},
+		"whiskeylake": {
+			"ssse3",
+			"sse4",
+			"sse4_1",
+			"sse4_2",
+			"avx",
+			"avx2",
+			"avx512",
+			"aes_ni",
+			"popcnt",
+		},
+		"x86_64": {
+			"ssse3",
+			"sse4",
+			"sse4_1",
+			"sse4_2",
+			"popcnt",
+		},
+	},
+	X86_64: {
+		"amberlake": {
+			"ssse3",
+			"sse4",
+			"sse4_1",
+			"sse4_2",
+			"avx",
+			"avx2",
+			"aes_ni",
+			"popcnt",
+		},
+		"broadwell": {
+			"ssse3",
+			"sse4",
+			"sse4_1",
+			"sse4_2",
+			"avx",
+			"avx2",
+			"aes_ni",
+			"popcnt",
+		},
+		"haswell": {
+			"ssse3",
+			"sse4",
+			"sse4_1",
+			"sse4_2",
+			"aes_ni",
+			"avx",
+			"popcnt",
+		},
+		"icelake": {
+			"ssse3",
+			"sse4",
+			"sse4_1",
+			"sse4_2",
+			"avx",
+			"avx2",
+			"avx512",
+			"aes_ni",
+			"popcnt",
+		},
+		"ivybridge": {
+			"ssse3",
+			"sse4",
+			"sse4_1",
+			"sse4_2",
+			"aes_ni",
+			"avx",
+			"popcnt",
+		},
+		"kabylake": {
+			"ssse3",
+			"sse4",
+			"sse4_1",
+			"sse4_2",
+			"avx",
+			"avx2",
+			"aes_ni",
+			"popcnt",
+		},
+		"sandybridge": {
+			"ssse3",
+			"sse4",
+			"sse4_1",
+			"sse4_2",
+			"popcnt",
+		},
+		"silvermont": {
+			"ssse3",
+			"sse4",
+			"sse4_1",
+			"sse4_2",
+			"aes_ni",
+			"popcnt",
+		},
+		"skylake": {
+			"ssse3",
+			"sse4",
+			"sse4_1",
+			"sse4_2",
+			"avx",
+			"avx2",
+			"avx512",
+			"aes_ni",
+			"popcnt",
+		},
+		"stoneyridge": {
+			"ssse3",
+			"sse4",
+			"sse4_1",
+			"sse4_2",
+			"aes_ni",
+			"avx",
+			"avx2",
+			"popcnt",
+		},
+		"tigerlake": {
+			"ssse3",
+			"sse4",
+			"sse4_1",
+			"sse4_2",
+			"avx",
+			"avx2",
+			"avx512",
+			"aes_ni",
+			"popcnt",
+		},
+		"whiskeylake": {
+			"ssse3",
+			"sse4",
+			"sse4_1",
+			"sse4_2",
+			"avx",
+			"avx2",
+			"avx512",
+			"aes_ni",
+			"popcnt",
+		},
+	},
+}
+
+var defaultArchFeatureMap = map[OsType]map[ArchType][]string{}
+
+// RegisterDefaultArchVariantFeatures is called by files that define Toolchains to specify the
+// arch features that are available for the default arch variant.  It must be called from an
+// init() function.
+func RegisterDefaultArchVariantFeatures(os OsType, arch ArchType, features ...string) {
+	checkCalledFromInit()
+
+	for _, feature := range features {
+		if !InList(feature, archFeatures[arch]) {
+			panic(fmt.Errorf("Invalid feature %q for arch %q variant \"\"", feature, arch))
+		}
+	}
+
+	if defaultArchFeatureMap[os] == nil {
+		defaultArchFeatureMap[os] = make(map[ArchType][]string)
+	}
+	defaultArchFeatureMap[os][arch] = features
+}
diff --git a/android/defaults.go b/android/defaults.go
index eb013d7..44753ce 100644
--- a/android/defaults.go
+++ b/android/defaults.go
@@ -183,7 +183,7 @@
 
 	initAndroidModuleBase(module)
 	initProductVariableModule(module)
-	InitArchModule(module)
+	initArchModule(module)
 	InitDefaultableModule(module)
 
 	// Add properties that will not have defaults applied to them.
diff --git a/android/module.go b/android/module.go
index eeb4fae..6b659d2 100644
--- a/android/module.go
+++ b/android/module.go
@@ -717,7 +717,9 @@
 	DebugMutators   []string `blueprint:"mutated"`
 	DebugVariations []string `blueprint:"mutated"`
 
-	// set by ImageMutator
+	// ImageVariation is set by ImageMutator to specify which image this variation is for,
+	// for example "" for core or "recovery" for recovery.  It will often be set to one of the
+	// constants in image.go, but can also be set to a custom value by individual module types.
 	ImageVariation string `blueprint:"mutated"`
 }
 
@@ -825,6 +827,8 @@
 	m.base().module = m
 }
 
+// InitAndroidModule initializes the Module as an Android module that is not architecture-specific.
+// It adds the common properties, for example "name" and "enabled".
 func InitAndroidModule(m Module) {
 	initAndroidModuleBase(m)
 	base := m.base()
@@ -844,6 +848,12 @@
 	setPrimaryVisibilityProperty(m, "visibility", &base.commonProperties.Visibility)
 }
 
+// InitAndroidArchModule initializes the Module as an Android module that is architecture-specific.
+// It adds the common properties, for example "name" and "enabled", as well as runtime generated
+// property structs for architecture-specific versions of generic properties tagged with
+// `android:"arch_variant"`.
+//
+//  InitAndroidModule should not be called if InitAndroidArchModule was called.
 func InitAndroidArchModule(m Module, hod HostOrDeviceSupported, defaultMultilib Multilib) {
 	InitAndroidModule(m)
 
@@ -857,16 +867,33 @@
 		m.AddProperties(&base.hostAndDeviceProperties)
 	}
 
-	InitArchModule(m)
+	initArchModule(m)
 }
 
+// InitAndroidMultiTargetsArchModule initializes the Module as an Android module that is
+// architecture-specific, but will only have a single variant per OS that handles all the
+// architectures simultaneously.  The list of Targets that it must handle will be available from
+// ModuleContext.MultiTargets. It adds the common properties, for example "name" and "enabled", as
+// well as runtime generated property structs for architecture-specific versions of generic
+// properties tagged with `android:"arch_variant"`.
+//
+// InitAndroidModule or InitAndroidArchModule should not be called if
+// InitAndroidMultiTargetsArchModule was called.
 func InitAndroidMultiTargetsArchModule(m Module, hod HostOrDeviceSupported, defaultMultilib Multilib) {
 	InitAndroidArchModule(m, hod, defaultMultilib)
 	m.base().commonProperties.UseTargetVariants = false
 }
 
-// As InitAndroidMultiTargetsArchModule except it creates an additional CommonOS variant that
-// has dependencies on all the OsType specific variants.
+// InitCommonOSAndroidMultiTargetsArchModule initializes the Module as an Android module that is
+// architecture-specific, but will only have a single variant per OS that handles all the
+// architectures simultaneously, and will also have an additional CommonOS variant that has
+// dependencies on all the OS-specific variants.  The list of Targets that it must handle will be
+// available from ModuleContext.MultiTargets.  It adds the common properties, for example "name" and
+// "enabled", as well as runtime generated property structs for architecture-specific versions of
+// generic properties tagged with `android:"arch_variant"`.
+//
+// InitAndroidModule, InitAndroidArchModule or InitAndroidMultiTargetsArchModule should not be
+// called if InitCommonOSAndroidMultiTargetsArchModule was called.
 func InitCommonOSAndroidMultiTargetsArchModule(m Module, hod HostOrDeviceSupported, defaultMultilib Multilib) {
 	InitAndroidArchModule(m, hod, defaultMultilib)
 	m.base().commonProperties.UseTargetVariants = false
diff --git a/androidmk/androidmk/androidmk.go b/androidmk/androidmk/androidmk.go
index 03cf74d..f4e5fa0 100644
--- a/androidmk/androidmk/androidmk.go
+++ b/androidmk/androidmk/androidmk.go
@@ -137,7 +137,14 @@
 
 		switch x := node.(type) {
 		case *mkparser.Comment:
-			file.insertComment("//" + x.Comment)
+			// Split the comment on escaped newlines and then
+			// add each chunk separately.
+			chunks := strings.Split(x.Comment, "\\\n")
+			file.insertComment("//" + chunks[0])
+			for i := 1; i < len(chunks); i++ {
+				file.bpPos.Line++
+				file.insertComment("//" + chunks[i])
+			}
 		case *mkparser.Assignment:
 			handleAssignment(file, x, assignmentCond)
 		case *mkparser.Directive:
diff --git a/androidmk/androidmk/androidmk_test.go b/androidmk/androidmk/androidmk_test.go
index 16cb138..f32ff2a 100644
--- a/androidmk/androidmk/androidmk_test.go
+++ b/androidmk/androidmk/androidmk_test.go
@@ -1260,10 +1260,10 @@
 		desc: "comment with ESC",
 		in: `
 # Comment line 1 \
-# Comment line 2
+ Comment line 2
 `,
 		expected: `
-// Comment line 1 \
+// Comment line 1
 // Comment line 2
 `,
 	},
diff --git a/androidmk/parser/parser.go b/androidmk/parser/parser.go
index e61241b..c14910a 100644
--- a/androidmk/parser/parser.go
+++ b/androidmk/parser/parser.go
@@ -497,12 +497,6 @@
 		switch p.tok {
 		case '\\':
 			p.parseEscape()
-			if p.tok == '\n' {
-				// Special case: '\' does not "escape" newline in comment (b/127521510)
-				comment += "\\"
-				p.accept(p.tok)
-				break loop
-			}
 			comment += "\\" + p.scanner.TokenText()
 			p.accept(p.tok)
 		case '\n':
diff --git a/apex/apex.go b/apex/apex.go
index 91770f4..ce323ca 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -33,19 +33,456 @@
 	"android/soong/sh"
 )
 
+func init() {
+	android.RegisterModuleType("apex", BundleFactory)
+	android.RegisterModuleType("apex_test", testApexBundleFactory)
+	android.RegisterModuleType("apex_vndk", vndkApexBundleFactory)
+	android.RegisterModuleType("apex_defaults", defaultsFactory)
+	android.RegisterModuleType("prebuilt_apex", PrebuiltFactory)
+	android.RegisterModuleType("override_apex", overrideApexFactory)
+	android.RegisterModuleType("apex_set", apexSetFactory)
+
+	android.PreDepsMutators(RegisterPreDepsMutators)
+	android.PostDepsMutators(RegisterPostDepsMutators)
+}
+
+func RegisterPreDepsMutators(ctx android.RegisterMutatorsContext) {
+	ctx.TopDown("apex_vndk", apexVndkMutator).Parallel()
+	ctx.BottomUp("apex_vndk_deps", apexVndkDepsMutator).Parallel()
+}
+
+func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) {
+	ctx.TopDown("apex_deps", apexDepsMutator).Parallel()
+	ctx.BottomUp("apex_unique", apexUniqueVariationsMutator).Parallel()
+	ctx.BottomUp("apex_test_for_deps", apexTestForDepsMutator).Parallel()
+	ctx.BottomUp("apex_test_for", apexTestForMutator).Parallel()
+	ctx.BottomUp("apex", apexMutator).Parallel()
+	ctx.BottomUp("apex_directly_in_any", apexDirectlyInAnyMutator).Parallel()
+	ctx.BottomUp("apex_flattened", apexFlattenedMutator).Parallel()
+	ctx.BottomUp("mark_platform_availability", markPlatformAvailability).Parallel()
+}
+
+type apexBundleProperties struct {
+	// Json manifest file describing meta info of this APEX bundle. Default:
+	// "apex_manifest.json"
+	Manifest *string `android:"path"`
+
+	// AndroidManifest.xml file used for the zip container of this APEX bundle.
+	// If unspecified, a default one is automatically generated.
+	AndroidManifest *string `android:"path"`
+
+	// Canonical name of the APEX bundle. Used to determine the path to the activated APEX on
+	// device (/apex/<apex_name>).
+	// If unspecified, defaults to the value of name.
+	Apex_name *string
+
+	// Determines the file contexts file for setting security context to each file in this APEX bundle.
+	// For platform APEXes, this should points to a file under /system/sepolicy
+	// Default: /system/sepolicy/apex/<module_name>_file_contexts.
+	File_contexts *string `android:"path"`
+
+	ApexNativeDependencies
+
+	// List of java libraries that are embedded inside this APEX bundle
+	Java_libs []string
+
+	// List of prebuilt files that are embedded inside this APEX bundle
+	Prebuilts []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
+
+	// The type of APEX to build. Controls what the APEX payload is. Either
+	// 'image', 'zip' or 'both'. Default: 'image'.
+	Payload_type *string
+
+	// The name of a certificate in the default certificate directory, blank to use the default product certificate,
+	// or an android_app_certificate module name in the form ":module".
+	Certificate *string
+
+	// Whether this APEX is installable to one of the partitions. Default: true.
+	Installable *bool
+
+	// For native libraries and binaries, use the vendor variant instead of the core (platform) variant.
+	// Default is false.
+	Use_vendor *bool
+
+	// For telling the apex to ignore special handling for system libraries such as bionic. Default is false.
+	Ignore_system_library_special_case *bool
+
+	Multilib apexMultilibProperties
+
+	// List of sanitizer names that this APEX is enabled for
+	SanitizerNames []string `blueprint:"mutated"`
+
+	PreventInstall bool `blueprint:"mutated"`
+
+	HideFromMake bool `blueprint:"mutated"`
+
+	// package format of this apex variant; could be non-flattened, flattened, or zip.
+	// imageApex, zipApex or flattened
+	ApexType apexPackaging `blueprint:"mutated"`
+
+	// List of SDKs that are used to build this APEX. A reference to an SDK should be either
+	// `name#version` or `name` which is an alias for `name#current`. If left empty, `platform#current`
+	// is implied. This value affects all modules included in this APEX. In other words, they are
+	// also built with the SDKs specified here.
+	Uses_sdks []string
+
+	// Whenever apex_payload.img of the APEX should include dm-verity hashtree.
+	// Should be only used in tests#.
+	Test_only_no_hashtree *bool
+
+	// Whenever apex_payload.img of the APEX should not be dm-verity signed.
+	// Should be only used in tests#.
+	Test_only_unsigned_payload *bool
+
+	IsCoverageVariant bool `blueprint:"mutated"`
+
+	// Whether this APEX is considered updatable or not. When set to true, this will enforce additional
+	// rules for making sure that the APEX is truly updatable.
+	// - To be updatable, min_sdk_version should be set as well
+	// This will also disable the size optimizations like symlinking to the system libs.
+	// Default is false.
+	Updatable *bool
+
+	// The minimum SDK version that this apex must be compatibile with.
+	Min_sdk_version *string
+
+	// If set true, VNDK libs are considered as stable libs and are not included in this apex.
+	// Should be only used in non-system apexes (e.g. vendor: true).
+	// Default is false.
+	Use_vndk_as_stable *bool
+
+	// The type of filesystem to use for an image apex. Either 'ext4' or 'f2fs'.
+	// Default 'ext4'.
+	Payload_fs_type *string
+}
+
+type ApexNativeDependencies struct {
+	// List of native libraries
+	Native_shared_libs []string
+
+	// List of JNI libraries
+	Jni_libs []string
+
+	// List of native executables
+	Binaries []string
+
+	// List of native tests
+	Tests []string
+}
+
+type apexMultilibProperties struct {
+	// Native dependencies whose compile_multilib is "first"
+	First ApexNativeDependencies
+
+	// Native dependencies whose compile_multilib is "both"
+	Both ApexNativeDependencies
+
+	// Native dependencies whose compile_multilib is "prefer32"
+	Prefer32 ApexNativeDependencies
+
+	// Native dependencies whose compile_multilib is "32"
+	Lib32 ApexNativeDependencies
+
+	// Native dependencies whose compile_multilib is "64"
+	Lib64 ApexNativeDependencies
+}
+
+type apexTargetBundleProperties struct {
+	Target struct {
+		// Multilib properties only for android.
+		Android struct {
+			Multilib apexMultilibProperties
+		}
+
+		// Multilib properties only for host.
+		Host struct {
+			Multilib apexMultilibProperties
+		}
+
+		// Multilib properties only for host linux_bionic.
+		Linux_bionic struct {
+			Multilib apexMultilibProperties
+		}
+
+		// Multilib properties only for host linux_glibc.
+		Linux_glibc struct {
+			Multilib apexMultilibProperties
+		}
+	}
+}
+
+type overridableProperties struct {
+	// List of APKs to package inside APEX
+	Apps []string
+
+	// List of runtime resource overlays (RROs) inside APEX
+	Rros []string
+
+	// Names of modules to be overridden. Listed modules can only be other binaries
+	// (in Make or Soong).
+	// This does not completely prevent installation of the overridden binaries, but if both
+	// binaries would be installed by default (in PRODUCT_PACKAGES) the other binary will be removed
+	// from PRODUCT_PACKAGES.
+	Overrides []string
+
+	// Logging Parent value
+	Logging_parent string
+
+	// Apex Container Package Name.
+	// Override value for attribute package:name in AndroidManifest.xml
+	Package_name string
+
+	// A txt file containing list of files that are allowed to be included in this APEX.
+	Allowed_files *string `android:"path"`
+}
+
+type apexBundle struct {
+	android.ModuleBase
+	android.DefaultableModuleBase
+	android.OverridableModuleBase
+	android.SdkBase
+
+	properties            apexBundleProperties
+	targetProperties      apexTargetBundleProperties
+	overridableProperties overridableProperties
+
+	// specific to apex_vndk modules
+	vndkProperties apexVndkProperties
+
+	bundleModuleFile android.WritablePath
+	outputFile       android.WritablePath
+	installDir       android.InstallPath
+
+	prebuiltFileToDelete string
+
+	public_key_file  android.Path
+	private_key_file android.Path
+
+	container_certificate_file android.Path
+	container_private_key_file android.Path
+
+	fileContexts android.WritablePath
+
+	// list of files to be included in this apex
+	filesInfo []apexFile
+
+	// list of module names that should be installed along with this APEX
+	requiredDeps []string
+
+	// list of module names that this APEX is including (to be shown via *-deps-info target)
+	android.ApexBundleDepsInfo
+
+	testApex        bool
+	vndkApex        bool
+	artApex         bool
+	primaryApexType bool
+
+	manifestJsonOut android.WritablePath
+	manifestPbOut   android.WritablePath
+
+	// list of commands to create symlinks for backward compatibility.
+	// these commands will be attached as LOCAL_POST_INSTALL_CMD to
+	// apex package itself(for unflattened build) or apex_manifest(for flattened build)
+	// so that compat symlinks are always installed regardless of TARGET_FLATTEN_APEX setting.
+	compatSymlinks []string
+
+	// Suffix of module name in Android.mk
+	// ".flattened", ".apex", ".zipapex", or ""
+	suffix string
+
+	installedFilesFile android.WritablePath
+
+	// Whether to create symlink to the system file instead of having a file
+	// inside the apex or not
+	linkToSystemLib bool
+
+	// Struct holding the merged notice file paths in different formats
+	mergedNotices android.NoticeOutputs
+
+	// Optional list of lint report zip files for apexes that contain java or app modules
+	lintReports android.Paths
+
+	payloadFsType fsType
+
+	distFiles android.TaggedDistFiles
+}
+
+type apexFileClass int
+
 const (
-	imageApexSuffix = ".apex"
-	zipApexSuffix   = ".zipapex"
-	flattenedSuffix = ".flattened"
-
-	imageApexType     = "image"
-	zipApexType       = "zip"
-	flattenedApexType = "flattened"
-
-	ext4FsType = "ext4"
-	f2fsFsType = "f2fs"
+	etc apexFileClass = iota
+	nativeSharedLib
+	nativeExecutable
+	shBinary
+	pyBinary
+	goBinary
+	javaSharedLib
+	nativeTest
+	app
+	appSet
 )
 
+func (class apexFileClass) NameInMake() string {
+	switch class {
+	case etc:
+		return "ETC"
+	case nativeSharedLib:
+		return "SHARED_LIBRARIES"
+	case nativeExecutable, shBinary, pyBinary, goBinary:
+		return "EXECUTABLES"
+	case javaSharedLib:
+		return "JAVA_LIBRARIES"
+	case nativeTest:
+		return "NATIVE_TESTS"
+	case app, appSet:
+		// b/142537672 Why isn't this APP? We want to have full control over
+		// the paths and file names of the apk file under the flattend APEX.
+		// If this is set to APP, then the paths and file names are modified
+		// by the Make build system. For example, it is installed to
+		// /system/apex/<apexname>/app/<Appname>/<apexname>.<Appname>/ instead of
+		// /system/apex/<apexname>/app/<Appname> because the build system automatically
+		// appends module name (which is <apexname>.<Appname> to the path.
+		return "ETC"
+	default:
+		panic(fmt.Errorf("unknown class %d", class))
+	}
+}
+
+// apexFile represents a file in an APEX bundle
+type apexFile struct {
+	builtFile android.Path
+	stem      string
+	// Module name of `module` in AndroidMk. Note the generated AndroidMk module for
+	// apexFile is named something like <AndroidMk module name>.<apex name>[<apex suffix>]
+	androidMkModuleName string
+	installDir          string
+	class               apexFileClass
+	module              android.Module
+	// list of symlinks that will be created in installDir that point to this apexFile
+	symlinks      []string
+	dataPaths     []android.DataPath
+	transitiveDep bool
+	moduleDir     string
+
+	requiredModuleNames       []string
+	targetRequiredModuleNames []string
+	hostRequiredModuleNames   []string
+
+	jacocoReportClassesFile android.Path     // only for javalibs and apps
+	lintDepSets             java.LintDepSets // only for javalibs and apps
+	certificate             java.Certificate // only for apps
+	overriddenPackageName   string           // only for apps
+
+	isJniLib bool
+
+	noticeFiles android.Paths
+}
+
+func newApexFile(ctx android.BaseModuleContext, builtFile android.Path, androidMkModuleName string, installDir string, class apexFileClass, module android.Module) apexFile {
+	ret := apexFile{
+		builtFile:           builtFile,
+		androidMkModuleName: androidMkModuleName,
+		installDir:          installDir,
+		class:               class,
+		module:              module,
+	}
+	if module != nil {
+		ret.moduleDir = ctx.OtherModuleDir(module)
+		ret.requiredModuleNames = module.RequiredModuleNames()
+		ret.targetRequiredModuleNames = module.TargetRequiredModuleNames()
+		ret.hostRequiredModuleNames = module.HostRequiredModuleNames()
+		ret.noticeFiles = module.NoticeFiles()
+	}
+	return ret
+}
+
+func (af *apexFile) Ok() bool {
+	return af.builtFile != nil && af.builtFile.String() != ""
+}
+
+func (af *apexFile) apexRelativePath(path string) string {
+	return filepath.Join(af.installDir, path)
+}
+
+// Path() returns path of this apex file relative to the APEX root
+func (af *apexFile) Path() string {
+	return af.apexRelativePath(af.Stem())
+}
+
+func (af *apexFile) Stem() string {
+	if af.stem != "" {
+		return af.stem
+	}
+	return af.builtFile.Base()
+}
+
+// SymlinkPaths() returns paths of the symlinks (if any) relative to the APEX root
+func (af *apexFile) SymlinkPaths() []string {
+	var ret []string
+	for _, symlink := range af.symlinks {
+		ret = append(ret, af.apexRelativePath(symlink))
+	}
+	return ret
+}
+
+func (af *apexFile) AvailableToPlatform() bool {
+	if af.module == nil {
+		return false
+	}
+	if am, ok := af.module.(android.ApexModule); ok {
+		return am.AvailableFor(android.AvailableToPlatform)
+	}
+	return false
+}
+
+func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext,
+	nativeModules ApexNativeDependencies,
+	target android.Target, imageVariation string) {
+	// Use *FarVariation* to be able to depend on modules having
+	// conflicting variations with this module. This is required since
+	// arch variant of an APEX bundle is 'common' but it is 'arm' or 'arm64'
+	// for native shared libs.
+
+	binVariations := target.Variations()
+	libVariations := append(target.Variations(),
+		blueprint.Variation{Mutator: "link", Variation: "shared"})
+
+	if ctx.Device() {
+		binVariations = append(binVariations,
+			blueprint.Variation{Mutator: "image", Variation: imageVariation})
+		libVariations = append(libVariations,
+			blueprint.Variation{Mutator: "image", Variation: imageVariation},
+			blueprint.Variation{Mutator: "version", Variation: ""}) // "" is the non-stub variant
+	}
+
+	ctx.AddFarVariationDependencies(libVariations, sharedLibTag, nativeModules.Native_shared_libs...)
+
+	ctx.AddFarVariationDependencies(libVariations, jniLibTag, nativeModules.Jni_libs...)
+
+	ctx.AddFarVariationDependencies(binVariations, executableTag, nativeModules.Binaries...)
+
+	ctx.AddFarVariationDependencies(binVariations, testTag, nativeModules.Tests...)
+}
+
+func (a *apexBundle) combineProperties(ctx android.BottomUpMutatorContext) {
+	if ctx.Os().Class == android.Device {
+		proptools.AppendProperties(&a.properties.Multilib, &a.targetProperties.Target.Android.Multilib, nil)
+	} else {
+		proptools.AppendProperties(&a.properties.Multilib, &a.targetProperties.Target.Host.Multilib, nil)
+		if ctx.Os().Bionic() {
+			proptools.AppendProperties(&a.properties.Multilib, &a.targetProperties.Target.Linux_bionic.Multilib, nil)
+		} else {
+			proptools.AppendProperties(&a.properties.Multilib, &a.targetProperties.Target.Linux_glibc.Multilib, nil)
+		}
+	}
+}
+
 type dependencyTag struct {
 	blueprint.BaseDependencyTag
 	name string
@@ -67,704 +504,162 @@
 	rroTag         = dependencyTag{name: "rro", payload: true}
 	bpfTag         = dependencyTag{name: "bpf", payload: true}
 	testForTag     = dependencyTag{name: "test for"}
-
-	apexAvailBaseline = makeApexAvailableBaseline()
-
-	inverseApexAvailBaseline = invertApexBaseline(apexAvailBaseline)
 )
 
-// Transform the map of apex -> modules to module -> apexes.
-func invertApexBaseline(m map[string][]string) map[string][]string {
-	r := make(map[string][]string)
-	for apex, modules := range m {
-		for _, module := range modules {
-			r[module] = append(r[module], apex)
+func (a *apexBundle) DepsMutator(ctx android.BottomUpMutatorContext) {
+	if proptools.Bool(a.properties.Use_vendor) && !android.InList(a.Name(), useVendorAllowList(ctx.Config())) {
+		ctx.PropertyErrorf("use_vendor", "not allowed to set use_vendor: true")
+	}
+
+	targets := ctx.MultiTargets()
+	config := ctx.DeviceConfig()
+	imageVariation := a.getImageVariation(ctx)
+
+	a.combineProperties(ctx)
+
+	has32BitTarget := false
+	for _, target := range targets {
+		if target.Arch.ArchType.Multilib == "lib32" {
+			has32BitTarget = true
 		}
 	}
-	return r
-}
+	for i, target := range targets {
+		if target.HostCross {
+			// Don't include artifats for the host cross targets because there is no way
+			// for us to run those artifacts natively on host
+			continue
+		}
 
-// Retrieve the baseline of apexes to which the supplied module belongs.
-func BaselineApexAvailable(moduleName string) []string {
-	return inverseApexAvailBaseline[normalizeModuleName(moduleName)]
-}
+		// When multilib.* is omitted for native_shared_libs/jni_libs/tests, it implies
+		// multilib.both
+		addDependenciesForNativeModules(ctx,
+			ApexNativeDependencies{
+				Native_shared_libs: a.properties.Native_shared_libs,
+				Tests:              a.properties.Tests,
+				Jni_libs:           a.properties.Jni_libs,
+				Binaries:           nil,
+			},
+			target, imageVariation)
 
-// This is a map from apex to modules, which overrides the
-// apex_available setting for that particular module to make
-// it available for the apex regardless of its setting.
-// TODO(b/147364041): remove this
-func makeApexAvailableBaseline() map[string][]string {
-	// The "Module separator"s below are employed to minimize merge conflicts.
-	m := make(map[string][]string)
-	//
-	// Module separator
-	//
-	m["com.android.appsearch"] = []string{
-		"icing-java-proto-lite",
-		"libprotobuf-java-lite",
-	}
-	//
-	// Module separator
-	//
-	m["com.android.bluetooth.updatable"] = []string{
-		"android.hardware.audio.common@5.0",
-		"android.hardware.bluetooth.a2dp@1.0",
-		"android.hardware.bluetooth.audio@2.0",
-		"android.hardware.bluetooth@1.0",
-		"android.hardware.bluetooth@1.1",
-		"android.hardware.graphics.bufferqueue@1.0",
-		"android.hardware.graphics.bufferqueue@2.0",
-		"android.hardware.graphics.common@1.0",
-		"android.hardware.graphics.common@1.1",
-		"android.hardware.graphics.common@1.2",
-		"android.hardware.media@1.0",
-		"android.hidl.safe_union@1.0",
-		"android.hidl.token@1.0",
-		"android.hidl.token@1.0-utils",
-		"avrcp-target-service",
-		"avrcp_headers",
-		"bluetooth-protos-lite",
-		"bluetooth.mapsapi",
-		"com.android.vcard",
-		"dnsresolver_aidl_interface-V2-java",
-		"ipmemorystore-aidl-interfaces-V5-java",
-		"ipmemorystore-aidl-interfaces-java",
-		"internal_include_headers",
-		"lib-bt-packets",
-		"lib-bt-packets-avrcp",
-		"lib-bt-packets-base",
-		"libFraunhoferAAC",
-		"libaudio-a2dp-hw-utils",
-		"libaudio-hearing-aid-hw-utils",
-		"libbinder_headers",
-		"libbluetooth",
-		"libbluetooth-types",
-		"libbluetooth-types-header",
-		"libbluetooth_gd",
-		"libbluetooth_headers",
-		"libbluetooth_jni",
-		"libbt-audio-hal-interface",
-		"libbt-bta",
-		"libbt-common",
-		"libbt-hci",
-		"libbt-platform-protos-lite",
-		"libbt-protos-lite",
-		"libbt-sbc-decoder",
-		"libbt-sbc-encoder",
-		"libbt-stack",
-		"libbt-utils",
-		"libbtcore",
-		"libbtdevice",
-		"libbte",
-		"libbtif",
-		"libchrome",
-		"libevent",
-		"libfmq",
-		"libg722codec",
-		"libgui_headers",
-		"libmedia_headers",
-		"libmodpb64",
-		"libosi",
-		"libstagefright_foundation_headers",
-		"libstagefright_headers",
-		"libstatslog",
-		"libstatssocket",
-		"libtinyxml2",
-		"libudrv-uipc",
-		"libz",
-		"media_plugin_headers",
-		"net-utils-services-common",
-		"netd_aidl_interface-unstable-java",
-		"netd_event_listener_interface-java",
-		"netlink-client",
-		"networkstack-client",
-		"sap-api-java-static",
-		"services.net",
-	}
-	//
-	// Module separator
-	//
-	m["com.android.cellbroadcast"] = []string{"CellBroadcastApp", "CellBroadcastServiceModule"}
-	//
-	// Module separator
-	//
-	m["com.android.extservices"] = []string{
-		"error_prone_annotations",
-		"ExtServices-core",
-		"ExtServices",
-		"libtextclassifier-java",
-		"libz_current",
-		"textclassifier-statsd",
-		"TextClassifierNotificationLibNoManifest",
-		"TextClassifierServiceLibNoManifest",
-	}
-	//
-	// Module separator
-	//
-	m["com.android.neuralnetworks"] = []string{
-		"android.hardware.neuralnetworks@1.0",
-		"android.hardware.neuralnetworks@1.1",
-		"android.hardware.neuralnetworks@1.2",
-		"android.hardware.neuralnetworks@1.3",
-		"android.hidl.allocator@1.0",
-		"android.hidl.memory.token@1.0",
-		"android.hidl.memory@1.0",
-		"android.hidl.safe_union@1.0",
-		"libarect",
-		"libbuildversion",
-		"libmath",
-		"libprocpartition",
-		"libsync",
-	}
-	//
-	// Module separator
-	//
-	m["com.android.media"] = []string{
-		"android.frameworks.bufferhub@1.0",
-		"android.hardware.cas.native@1.0",
-		"android.hardware.cas@1.0",
-		"android.hardware.configstore-utils",
-		"android.hardware.configstore@1.0",
-		"android.hardware.configstore@1.1",
-		"android.hardware.graphics.allocator@2.0",
-		"android.hardware.graphics.allocator@3.0",
-		"android.hardware.graphics.bufferqueue@1.0",
-		"android.hardware.graphics.bufferqueue@2.0",
-		"android.hardware.graphics.common@1.0",
-		"android.hardware.graphics.common@1.1",
-		"android.hardware.graphics.common@1.2",
-		"android.hardware.graphics.mapper@2.0",
-		"android.hardware.graphics.mapper@2.1",
-		"android.hardware.graphics.mapper@3.0",
-		"android.hardware.media.omx@1.0",
-		"android.hardware.media@1.0",
-		"android.hidl.allocator@1.0",
-		"android.hidl.memory.token@1.0",
-		"android.hidl.memory@1.0",
-		"android.hidl.token@1.0",
-		"android.hidl.token@1.0-utils",
-		"bionic_libc_platform_headers",
-		"exoplayer2-extractor",
-		"exoplayer2-extractor-annotation-stubs",
-		"gl_headers",
-		"jsr305",
-		"libEGL",
-		"libEGL_blobCache",
-		"libEGL_getProcAddress",
-		"libFLAC",
-		"libFLAC-config",
-		"libFLAC-headers",
-		"libGLESv2",
-		"libaacextractor",
-		"libamrextractor",
-		"libarect",
-		"libaudio_system_headers",
-		"libaudioclient",
-		"libaudioclient_headers",
-		"libaudiofoundation",
-		"libaudiofoundation_headers",
-		"libaudiomanager",
-		"libaudiopolicy",
-		"libaudioutils",
-		"libaudioutils_fixedfft",
-		"libbinder_headers",
-		"libbluetooth-types-header",
-		"libbufferhub",
-		"libbufferhub_headers",
-		"libbufferhubqueue",
-		"libc_malloc_debug_backtrace",
-		"libcamera_client",
-		"libcamera_metadata",
-		"libdvr_headers",
-		"libexpat",
-		"libfifo",
-		"libflacextractor",
-		"libgrallocusage",
-		"libgraphicsenv",
-		"libgui",
-		"libgui_headers",
-		"libhardware_headers",
-		"libinput",
-		"liblzma",
-		"libmath",
-		"libmedia",
-		"libmedia_codeclist",
-		"libmedia_headers",
-		"libmedia_helper",
-		"libmedia_helper_headers",
-		"libmedia_midiiowrapper",
-		"libmedia_omx",
-		"libmediautils",
-		"libmidiextractor",
-		"libmkvextractor",
-		"libmp3extractor",
-		"libmp4extractor",
-		"libmpeg2extractor",
-		"libnativebase_headers",
-		"libnativewindow_headers",
-		"libnblog",
-		"liboggextractor",
-		"libpackagelistparser",
-		"libpdx",
-		"libpdx_default_transport",
-		"libpdx_headers",
-		"libpdx_uds",
-		"libprocinfo",
-		"libspeexresampler",
-		"libspeexresampler",
-		"libstagefright_esds",
-		"libstagefright_flacdec",
-		"libstagefright_flacdec",
-		"libstagefright_foundation",
-		"libstagefright_foundation_headers",
-		"libstagefright_foundation_without_imemory",
-		"libstagefright_headers",
-		"libstagefright_id3",
-		"libstagefright_metadatautils",
-		"libstagefright_mpeg2extractor",
-		"libstagefright_mpeg2support",
-		"libsync",
-		"libui",
-		"libui_headers",
-		"libunwindstack",
-		"libvibrator",
-		"libvorbisidec",
-		"libwavextractor",
-		"libwebm",
-		"media_ndk_headers",
-		"media_plugin_headers",
-		"updatable-media",
-	}
-	//
-	// Module separator
-	//
-	m["com.android.media.swcodec"] = []string{
-		"android.frameworks.bufferhub@1.0",
-		"android.hardware.common-ndk_platform",
-		"android.hardware.configstore-utils",
-		"android.hardware.configstore@1.0",
-		"android.hardware.configstore@1.1",
-		"android.hardware.graphics.allocator@2.0",
-		"android.hardware.graphics.allocator@3.0",
-		"android.hardware.graphics.allocator@4.0",
-		"android.hardware.graphics.bufferqueue@1.0",
-		"android.hardware.graphics.bufferqueue@2.0",
-		"android.hardware.graphics.common-ndk_platform",
-		"android.hardware.graphics.common@1.0",
-		"android.hardware.graphics.common@1.1",
-		"android.hardware.graphics.common@1.2",
-		"android.hardware.graphics.mapper@2.0",
-		"android.hardware.graphics.mapper@2.1",
-		"android.hardware.graphics.mapper@3.0",
-		"android.hardware.graphics.mapper@4.0",
-		"android.hardware.media.bufferpool@2.0",
-		"android.hardware.media.c2@1.0",
-		"android.hardware.media.c2@1.1",
-		"android.hardware.media.omx@1.0",
-		"android.hardware.media@1.0",
-		"android.hardware.media@1.0",
-		"android.hidl.memory.token@1.0",
-		"android.hidl.memory@1.0",
-		"android.hidl.safe_union@1.0",
-		"android.hidl.token@1.0",
-		"android.hidl.token@1.0-utils",
-		"libEGL",
-		"libFLAC",
-		"libFLAC-config",
-		"libFLAC-headers",
-		"libFraunhoferAAC",
-		"libLibGuiProperties",
-		"libarect",
-		"libaudio_system_headers",
-		"libaudioutils",
-		"libaudioutils",
-		"libaudioutils_fixedfft",
-		"libavcdec",
-		"libavcenc",
-		"libavservices_minijail",
-		"libavservices_minijail",
-		"libbinder_headers",
-		"libbinderthreadstateutils",
-		"libbluetooth-types-header",
-		"libbufferhub_headers",
-		"libcodec2",
-		"libcodec2_headers",
-		"libcodec2_hidl@1.0",
-		"libcodec2_hidl@1.1",
-		"libcodec2_internal",
-		"libcodec2_soft_aacdec",
-		"libcodec2_soft_aacenc",
-		"libcodec2_soft_amrnbdec",
-		"libcodec2_soft_amrnbenc",
-		"libcodec2_soft_amrwbdec",
-		"libcodec2_soft_amrwbenc",
-		"libcodec2_soft_av1dec_gav1",
-		"libcodec2_soft_avcdec",
-		"libcodec2_soft_avcenc",
-		"libcodec2_soft_common",
-		"libcodec2_soft_flacdec",
-		"libcodec2_soft_flacenc",
-		"libcodec2_soft_g711alawdec",
-		"libcodec2_soft_g711mlawdec",
-		"libcodec2_soft_gsmdec",
-		"libcodec2_soft_h263dec",
-		"libcodec2_soft_h263enc",
-		"libcodec2_soft_hevcdec",
-		"libcodec2_soft_hevcenc",
-		"libcodec2_soft_mp3dec",
-		"libcodec2_soft_mpeg2dec",
-		"libcodec2_soft_mpeg4dec",
-		"libcodec2_soft_mpeg4enc",
-		"libcodec2_soft_opusdec",
-		"libcodec2_soft_opusenc",
-		"libcodec2_soft_rawdec",
-		"libcodec2_soft_vorbisdec",
-		"libcodec2_soft_vp8dec",
-		"libcodec2_soft_vp8enc",
-		"libcodec2_soft_vp9dec",
-		"libcodec2_soft_vp9enc",
-		"libcodec2_vndk",
-		"libdvr_headers",
-		"libfmq",
-		"libfmq",
-		"libgav1",
-		"libgralloctypes",
-		"libgrallocusage",
-		"libgraphicsenv",
-		"libgsm",
-		"libgui_bufferqueue_static",
-		"libgui_headers",
-		"libhardware",
-		"libhardware_headers",
-		"libhevcdec",
-		"libhevcenc",
-		"libion",
-		"libjpeg",
-		"liblzma",
-		"libmath",
-		"libmedia_codecserviceregistrant",
-		"libmedia_headers",
-		"libmpeg2dec",
-		"libnativebase_headers",
-		"libnativewindow_headers",
-		"libpdx_headers",
-		"libscudo_wrapper",
-		"libsfplugin_ccodec_utils",
-		"libspeexresampler",
-		"libstagefright_amrnb_common",
-		"libstagefright_amrnbdec",
-		"libstagefright_amrnbenc",
-		"libstagefright_amrwbdec",
-		"libstagefright_amrwbenc",
-		"libstagefright_bufferpool@2.0.1",
-		"libstagefright_bufferqueue_helper",
-		"libstagefright_enc_common",
-		"libstagefright_flacdec",
-		"libstagefright_foundation",
-		"libstagefright_foundation_headers",
-		"libstagefright_headers",
-		"libstagefright_m4vh263dec",
-		"libstagefright_m4vh263enc",
-		"libstagefright_mp3dec",
-		"libsync",
-		"libui",
-		"libui_headers",
-		"libunwindstack",
-		"libvorbisidec",
-		"libvpx",
-		"libyuv",
-		"libyuv_static",
-		"media_ndk_headers",
-		"media_plugin_headers",
-		"mediaswcodec",
-	}
-	//
-	// Module separator
-	//
-	m["com.android.mediaprovider"] = []string{
-		"MediaProvider",
-		"MediaProviderGoogle",
-		"fmtlib_ndk",
-		"libbase_ndk",
-		"libfuse",
-		"libfuse_jni",
-	}
-	//
-	// Module separator
-	//
-	m["com.android.permission"] = []string{
-		"car-ui-lib",
-		"iconloader",
-		"kotlin-annotations",
-		"kotlin-stdlib",
-		"kotlin-stdlib-jdk7",
-		"kotlin-stdlib-jdk8",
-		"kotlinx-coroutines-android",
-		"kotlinx-coroutines-android-nodeps",
-		"kotlinx-coroutines-core",
-		"kotlinx-coroutines-core-nodeps",
-		"permissioncontroller-statsd",
-		"GooglePermissionController",
-		"PermissionController",
-		"SettingsLibActionBarShadow",
-		"SettingsLibAppPreference",
-		"SettingsLibBarChartPreference",
-		"SettingsLibLayoutPreference",
-		"SettingsLibProgressBar",
-		"SettingsLibSearchWidget",
-		"SettingsLibSettingsTheme",
-		"SettingsLibRestrictedLockUtils",
-		"SettingsLibHelpUtils",
-	}
-	//
-	// Module separator
-	//
-	m["com.android.runtime"] = []string{
-		"bionic_libc_platform_headers",
-		"libarm-optimized-routines-math",
-		"libc_aeabi",
-		"libc_bionic",
-		"libc_bionic_ndk",
-		"libc_bootstrap",
-		"libc_common",
-		"libc_common_shared",
-		"libc_common_static",
-		"libc_dns",
-		"libc_dynamic_dispatch",
-		"libc_fortify",
-		"libc_freebsd",
-		"libc_freebsd_large_stack",
-		"libc_gdtoa",
-		"libc_init_dynamic",
-		"libc_init_static",
-		"libc_jemalloc_wrapper",
-		"libc_netbsd",
-		"libc_nomalloc",
-		"libc_nopthread",
-		"libc_openbsd",
-		"libc_openbsd_large_stack",
-		"libc_openbsd_ndk",
-		"libc_pthread",
-		"libc_static_dispatch",
-		"libc_syscalls",
-		"libc_tzcode",
-		"libc_unwind_static",
-		"libdebuggerd",
-		"libdebuggerd_common_headers",
-		"libdebuggerd_handler_core",
-		"libdebuggerd_handler_fallback",
-		"libdl_static",
-		"libjemalloc5",
-		"liblinker_main",
-		"liblinker_malloc",
-		"liblz4",
-		"liblzma",
-		"libprocinfo",
-		"libpropertyinfoparser",
-		"libscudo",
-		"libstdc++",
-		"libsystemproperties",
-		"libtombstoned_client_static",
-		"libunwindstack",
-		"libz",
-		"libziparchive",
-	}
-	//
-	// Module separator
-	//
-	m["com.android.tethering"] = []string{
-		"android.hardware.tetheroffload.config-V1.0-java",
-		"android.hardware.tetheroffload.control-V1.0-java",
-		"android.hidl.base-V1.0-java",
-		"libcgrouprc",
-		"libcgrouprc_format",
-		"libtetherutilsjni",
-		"libvndksupport",
-		"net-utils-framework-common",
-		"netd_aidl_interface-V3-java",
-		"netlink-client",
-		"networkstack-aidl-interfaces-java",
-		"tethering-aidl-interfaces-java",
-		"TetheringApiCurrentLib",
-	}
-	//
-	// Module separator
-	//
-	m["com.android.wifi"] = []string{
-		"PlatformProperties",
-		"android.hardware.wifi-V1.0-java",
-		"android.hardware.wifi-V1.0-java-constants",
-		"android.hardware.wifi-V1.1-java",
-		"android.hardware.wifi-V1.2-java",
-		"android.hardware.wifi-V1.3-java",
-		"android.hardware.wifi-V1.4-java",
-		"android.hardware.wifi.hostapd-V1.0-java",
-		"android.hardware.wifi.hostapd-V1.1-java",
-		"android.hardware.wifi.hostapd-V1.2-java",
-		"android.hardware.wifi.supplicant-V1.0-java",
-		"android.hardware.wifi.supplicant-V1.1-java",
-		"android.hardware.wifi.supplicant-V1.2-java",
-		"android.hardware.wifi.supplicant-V1.3-java",
-		"android.hidl.base-V1.0-java",
-		"android.hidl.manager-V1.0-java",
-		"android.hidl.manager-V1.1-java",
-		"android.hidl.manager-V1.2-java",
-		"bouncycastle-unbundled",
-		"dnsresolver_aidl_interface-V2-java",
-		"error_prone_annotations",
-		"framework-wifi-pre-jarjar",
-		"framework-wifi-util-lib",
-		"ipmemorystore-aidl-interfaces-V3-java",
-		"ipmemorystore-aidl-interfaces-java",
-		"ksoap2",
-		"libnanohttpd",
-		"libwifi-jni",
-		"net-utils-services-common",
-		"netd_aidl_interface-V2-java",
-		"netd_aidl_interface-unstable-java",
-		"netd_event_listener_interface-java",
-		"netlink-client",
-		"networkstack-client",
-		"services.net",
-		"wifi-lite-protos",
-		"wifi-nano-protos",
-		"wifi-service-pre-jarjar",
-		"wifi-service-resources",
-	}
-	//
-	// Module separator
-	//
-	m["com.android.sdkext"] = []string{
-		"fmtlib_ndk",
-		"libbase_ndk",
-		"libprotobuf-cpp-lite-ndk",
-	}
-	//
-	// Module separator
-	//
-	m["com.android.os.statsd"] = []string{
-		"libstatssocket",
-	}
-	//
-	// Module separator
-	//
-	m[android.AvailableToAnyApex] = []string{
-		// TODO(b/156996905) Set apex_available/min_sdk_version for androidx/extras support libraries
-		"androidx",
-		"androidx-constraintlayout_constraintlayout",
-		"androidx-constraintlayout_constraintlayout-nodeps",
-		"androidx-constraintlayout_constraintlayout-solver",
-		"androidx-constraintlayout_constraintlayout-solver-nodeps",
-		"com.google.android.material_material",
-		"com.google.android.material_material-nodeps",
+		// Add native modules targetting both ABIs
+		addDependenciesForNativeModules(ctx,
+			a.properties.Multilib.Both,
+			target,
+			imageVariation)
 
-		"libatomic",
-		"libclang_rt",
-		"libgcc_stripped",
-		"libprofile-clang-extras",
-		"libprofile-clang-extras_ndk",
-		"libprofile-extras",
-		"libprofile-extras_ndk",
-		"libunwind_llvm",
-	}
-	return m
-}
+		isPrimaryAbi := i == 0
+		if isPrimaryAbi {
+			// When multilib.* is omitted for binaries, it implies
+			// multilib.first
+			addDependenciesForNativeModules(ctx,
+				ApexNativeDependencies{
+					Native_shared_libs: nil,
+					Tests:              nil,
+					Jni_libs:           nil,
+					Binaries:           a.properties.Binaries,
+				},
+				target, imageVariation)
 
-// DO NOT EDIT! These are the package prefixes that are exempted from being AOT'ed by ART.
-// Adding code to the bootclasspath in new packages will cause issues on module update.
-func qModulesPackages() map[string][]string {
-	return map[string][]string{
-		"com.android.conscrypt": []string{
-			"android.net.ssl",
-			"com.android.org.conscrypt",
-		},
-		"com.android.media": []string{
-			"android.media",
-		},
+			// Add native modules targetting the first ABI
+			addDependenciesForNativeModules(ctx,
+				a.properties.Multilib.First,
+				target,
+				imageVariation)
+		}
+
+		switch target.Arch.ArchType.Multilib {
+		case "lib32":
+			// Add native modules targetting 32-bit ABI
+			addDependenciesForNativeModules(ctx,
+				a.properties.Multilib.Lib32,
+				target,
+				imageVariation)
+
+			addDependenciesForNativeModules(ctx,
+				a.properties.Multilib.Prefer32,
+				target,
+				imageVariation)
+		case "lib64":
+			// Add native modules targetting 64-bit ABI
+			addDependenciesForNativeModules(ctx,
+				a.properties.Multilib.Lib64,
+				target,
+				imageVariation)
+
+			if !has32BitTarget {
+				addDependenciesForNativeModules(ctx,
+					a.properties.Multilib.Prefer32,
+					target,
+					imageVariation)
+			}
+		}
+	}
+
+	// For prebuilt_etc, use the first variant (64 on 64/32bit device,
+	// 32 on 32bit device) regardless of the TARGET_PREFER_* setting.
+	// b/144532908
+	archForPrebuiltEtc := config.Arches()[0]
+	for _, arch := range config.Arches() {
+		// Prefer 64-bit arch if there is any
+		if arch.ArchType.Multilib == "lib64" {
+			archForPrebuiltEtc = arch
+			break
+		}
+	}
+	ctx.AddFarVariationDependencies([]blueprint.Variation{
+		{Mutator: "os", Variation: ctx.Os().String()},
+		{Mutator: "arch", Variation: archForPrebuiltEtc.String()},
+	}, prebuiltTag, a.properties.Prebuilts...)
+
+	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(),
+			javaLibTag, "jacocoagent")
+	}
+
+	if String(a.properties.Key) == "" {
+		ctx.ModuleErrorf("key is missing")
+		return
+	}
+	ctx.AddDependency(ctx.Module(), keyTag, String(a.properties.Key))
+
+	cert := android.SrcIsModule(a.getCertString(ctx))
+	if cert != "" {
+		ctx.AddDependency(ctx.Module(), certificateTag, cert)
+	}
+
+	// TODO(jiyong): ensure that all apexes are with non-empty uses_sdks
+	if len(a.properties.Uses_sdks) > 0 {
+		sdkRefs := []android.SdkRef{}
+		for _, str := range a.properties.Uses_sdks {
+			parsed := android.ParseSdkRef(ctx, str, "uses_sdks")
+			sdkRefs = append(sdkRefs, parsed)
+		}
+		a.BuildWithSdks(sdkRefs)
 	}
 }
 
-// DO NOT EDIT! These are the package prefixes that are exempted from being AOT'ed by ART.
-// Adding code to the bootclasspath in new packages will cause issues on module update.
-func rModulesPackages() map[string][]string {
-	return map[string][]string{
-		"com.android.mediaprovider": []string{
-			"android.provider",
-		},
-		"com.android.permission": []string{
-			"android.permission",
-			"android.app.role",
-			"com.android.permission",
-			"com.android.role",
-		},
-		"com.android.sdkext": []string{
-			"android.os.ext",
-		},
-		"com.android.os.statsd": []string{
-			"android.app",
-			"android.os",
-			"android.util",
-			"com.android.internal.statsd",
-			"com.android.server.stats",
-		},
-		"com.android.wifi": []string{
-			"com.android.server.wifi",
-			"com.android.wifi.x",
-			"android.hardware.wifi",
-			"android.net.wifi",
-		},
-		"com.android.tethering": []string{
-			"android.net",
-		},
+func (a *apexBundle) OverridablePropertiesDepsMutator(ctx android.BottomUpMutatorContext) {
+	if a.overridableProperties.Allowed_files != nil {
+		android.ExtractSourceDeps(ctx, a.overridableProperties.Allowed_files)
 	}
+	ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(),
+		androidAppTag, a.overridableProperties.Apps...)
+	ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(),
+		rroTag, a.overridableProperties.Rros...)
 }
 
-func init() {
-	android.RegisterModuleType("apex", BundleFactory)
-	android.RegisterModuleType("apex_test", testApexBundleFactory)
-	android.RegisterModuleType("apex_vndk", vndkApexBundleFactory)
-	android.RegisterModuleType("apex_defaults", defaultsFactory)
-	android.RegisterModuleType("prebuilt_apex", PrebuiltFactory)
-	android.RegisterModuleType("override_apex", overrideApexFactory)
-	android.RegisterModuleType("apex_set", apexSetFactory)
-
-	android.PreDepsMutators(RegisterPreDepsMutators)
-	android.PostDepsMutators(RegisterPostDepsMutators)
-
-	android.AddNeverAllowRules(createApexPermittedPackagesRules(qModulesPackages())...)
-	android.AddNeverAllowRules(createApexPermittedPackagesRules(rModulesPackages())...)
+type ApexBundleInfo struct {
+	Contents *android.ApexContents
 }
 
-func createApexPermittedPackagesRules(modules_packages map[string][]string) []android.Rule {
-	rules := make([]android.Rule, 0, len(modules_packages))
-	for module_name, module_packages := range modules_packages {
-		permitted_packages_rule := android.NeverAllow().
-			BootclasspathJar().
-			With("apex_available", module_name).
-			WithMatcher("permitted_packages", android.NotInList(module_packages)).
-			Because("jars that are part of the " + module_name +
-				" module may only allow these packages: " + strings.Join(module_packages, ",") +
-				". Please jarjar or move code around.")
-		rules = append(rules, permitted_packages_rule)
-	}
-	return rules
-}
-
-func RegisterPreDepsMutators(ctx android.RegisterMutatorsContext) {
-	ctx.TopDown("apex_vndk", apexVndkMutator).Parallel()
-	ctx.BottomUp("apex_vndk_deps", apexVndkDepsMutator).Parallel()
-}
-
-func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) {
-	ctx.TopDown("apex_deps", apexDepsMutator).Parallel()
-	ctx.BottomUp("apex_unique", apexUniqueVariationsMutator).Parallel()
-	ctx.BottomUp("apex_test_for_deps", apexTestForDepsMutator).Parallel()
-	ctx.BottomUp("apex_test_for", apexTestForMutator).Parallel()
-	ctx.BottomUp("apex", apexMutator).Parallel()
-	ctx.BottomUp("apex_directly_in_any", apexDirectlyInAnyMutator).Parallel()
-	ctx.BottomUp("apex_flattened", apexFlattenedMutator).Parallel()
-	ctx.BottomUp("mark_platform_availability", markPlatformAvailability).Parallel()
-}
+var ApexBundleInfoProvider = blueprint.NewMutatorProvider(ApexBundleInfo{}, "apex_deps")
 
 // Mark the direct and transitive dependencies of apex bundles so that they
 // can be built for the apex bundles.
@@ -967,6 +862,50 @@
 	}
 }
 
+type apexPackaging int
+
+const (
+	imageApex apexPackaging = iota
+	zipApex
+	flattenedApex
+)
+
+const (
+	imageApexSuffix = ".apex"
+	zipApexSuffix   = ".zipapex"
+	flattenedSuffix = ".flattened"
+
+	imageApexType     = "image"
+	zipApexType       = "zip"
+	flattenedApexType = "flattened"
+
+	ext4FsType = "ext4"
+	f2fsFsType = "f2fs"
+)
+
+// The suffix for the output "file", not the module
+func (a apexPackaging) suffix() string {
+	switch a {
+	case imageApex:
+		return imageApexSuffix
+	case zipApex:
+		return zipApexSuffix
+	default:
+		panic(fmt.Errorf("unknown APEX type %d", a))
+	}
+}
+
+func (a apexPackaging) name() string {
+	switch a {
+	case imageApex:
+		return imageApexType
+	case zipApex:
+		return zipApexType
+	default:
+		panic(fmt.Errorf("unknown APEX type %d", a))
+	}
+}
+
 func apexFlattenedMutator(mctx android.BottomUpMutatorContext) {
 	if !mctx.Module().Enabled() {
 		return
@@ -1033,351 +972,6 @@
 	})
 }
 
-type ApexNativeDependencies struct {
-	// List of native libraries
-	Native_shared_libs []string
-
-	// List of JNI libraries
-	Jni_libs []string
-
-	// List of native executables
-	Binaries []string
-
-	// List of native tests
-	Tests []string
-}
-
-type apexMultilibProperties struct {
-	// Native dependencies whose compile_multilib is "first"
-	First ApexNativeDependencies
-
-	// Native dependencies whose compile_multilib is "both"
-	Both ApexNativeDependencies
-
-	// Native dependencies whose compile_multilib is "prefer32"
-	Prefer32 ApexNativeDependencies
-
-	// Native dependencies whose compile_multilib is "32"
-	Lib32 ApexNativeDependencies
-
-	// Native dependencies whose compile_multilib is "64"
-	Lib64 ApexNativeDependencies
-}
-
-type apexBundleProperties struct {
-	// Json manifest file describing meta info of this APEX bundle. Default:
-	// "apex_manifest.json"
-	Manifest *string `android:"path"`
-
-	// AndroidManifest.xml file used for the zip container of this APEX bundle.
-	// If unspecified, a default one is automatically generated.
-	AndroidManifest *string `android:"path"`
-
-	// Canonical name of the APEX bundle. Used to determine the path to the activated APEX on
-	// device (/apex/<apex_name>).
-	// If unspecified, defaults to the value of name.
-	Apex_name *string
-
-	// Determines the file contexts file for setting security context to each file in this APEX bundle.
-	// For platform APEXes, this should points to a file under /system/sepolicy
-	// Default: /system/sepolicy/apex/<module_name>_file_contexts.
-	File_contexts *string `android:"path"`
-
-	ApexNativeDependencies
-
-	// List of java libraries that are embedded inside this APEX bundle
-	Java_libs []string
-
-	// List of prebuilt files that are embedded inside this APEX bundle
-	Prebuilts []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
-
-	// The type of APEX to build. Controls what the APEX payload is. Either
-	// 'image', 'zip' or 'both'. Default: 'image'.
-	Payload_type *string
-
-	// The name of a certificate in the default certificate directory, blank to use the default product certificate,
-	// or an android_app_certificate module name in the form ":module".
-	Certificate *string
-
-	// Whether this APEX is installable to one of the partitions. Default: true.
-	Installable *bool
-
-	// For native libraries and binaries, use the vendor variant instead of the core (platform) variant.
-	// Default is false.
-	Use_vendor *bool
-
-	// For telling the apex to ignore special handling for system libraries such as bionic. Default is false.
-	Ignore_system_library_special_case *bool
-
-	Multilib apexMultilibProperties
-
-	// List of sanitizer names that this APEX is enabled for
-	SanitizerNames []string `blueprint:"mutated"`
-
-	PreventInstall bool `blueprint:"mutated"`
-
-	HideFromMake bool `blueprint:"mutated"`
-
-	// package format of this apex variant; could be non-flattened, flattened, or zip.
-	// imageApex, zipApex or flattened
-	ApexType apexPackaging `blueprint:"mutated"`
-
-	// List of SDKs that are used to build this APEX. A reference to an SDK should be either
-	// `name#version` or `name` which is an alias for `name#current`. If left empty, `platform#current`
-	// is implied. This value affects all modules included in this APEX. In other words, they are
-	// also built with the SDKs specified here.
-	Uses_sdks []string
-
-	// Whenever apex_payload.img of the APEX should include dm-verity hashtree.
-	// Should be only used in tests#.
-	Test_only_no_hashtree *bool
-
-	// Whenever apex_payload.img of the APEX should not be dm-verity signed.
-	// Should be only used in tests#.
-	Test_only_unsigned_payload *bool
-
-	IsCoverageVariant bool `blueprint:"mutated"`
-
-	// Whether this APEX is considered updatable or not. When set to true, this will enforce additional
-	// rules for making sure that the APEX is truly updatable.
-	// - To be updatable, min_sdk_version should be set as well
-	// This will also disable the size optimizations like symlinking to the system libs.
-	// Default is false.
-	Updatable *bool
-
-	// The minimum SDK version that this apex must be compatibile with.
-	Min_sdk_version *string
-
-	// If set true, VNDK libs are considered as stable libs and are not included in this apex.
-	// Should be only used in non-system apexes (e.g. vendor: true).
-	// Default is false.
-	Use_vndk_as_stable *bool
-
-	// The type of filesystem to use for an image apex. Either 'ext4' or 'f2fs'.
-	// Default 'ext4'.
-	Payload_fs_type *string
-}
-
-type ApexBundleInfo struct {
-	Contents *android.ApexContents
-}
-
-var ApexBundleInfoProvider = blueprint.NewMutatorProvider(ApexBundleInfo{}, "apex_deps")
-
-type apexTargetBundleProperties struct {
-	Target struct {
-		// Multilib properties only for android.
-		Android struct {
-			Multilib apexMultilibProperties
-		}
-
-		// Multilib properties only for host.
-		Host struct {
-			Multilib apexMultilibProperties
-		}
-
-		// Multilib properties only for host linux_bionic.
-		Linux_bionic struct {
-			Multilib apexMultilibProperties
-		}
-
-		// Multilib properties only for host linux_glibc.
-		Linux_glibc struct {
-			Multilib apexMultilibProperties
-		}
-	}
-}
-
-type overridableProperties struct {
-	// List of APKs to package inside APEX
-	Apps []string
-
-	// List of runtime resource overlays (RROs) inside APEX
-	Rros []string
-
-	// Names of modules to be overridden. Listed modules can only be other binaries
-	// (in Make or Soong).
-	// This does not completely prevent installation of the overridden binaries, but if both
-	// binaries would be installed by default (in PRODUCT_PACKAGES) the other binary will be removed
-	// from PRODUCT_PACKAGES.
-	Overrides []string
-
-	// Logging Parent value
-	Logging_parent string
-
-	// Apex Container Package Name.
-	// Override value for attribute package:name in AndroidManifest.xml
-	Package_name string
-
-	// A txt file containing list of files that are allowed to be included in this APEX.
-	Allowed_files *string `android:"path"`
-}
-
-type apexPackaging int
-
-const (
-	imageApex apexPackaging = iota
-	zipApex
-	flattenedApex
-)
-
-// The suffix for the output "file", not the module
-func (a apexPackaging) suffix() string {
-	switch a {
-	case imageApex:
-		return imageApexSuffix
-	case zipApex:
-		return zipApexSuffix
-	default:
-		panic(fmt.Errorf("unknown APEX type %d", a))
-	}
-}
-
-func (a apexPackaging) name() string {
-	switch a {
-	case imageApex:
-		return imageApexType
-	case zipApex:
-		return zipApexType
-	default:
-		panic(fmt.Errorf("unknown APEX type %d", a))
-	}
-}
-
-type apexFileClass int
-
-const (
-	etc apexFileClass = iota
-	nativeSharedLib
-	nativeExecutable
-	shBinary
-	pyBinary
-	goBinary
-	javaSharedLib
-	nativeTest
-	app
-	appSet
-)
-
-func (class apexFileClass) NameInMake() string {
-	switch class {
-	case etc:
-		return "ETC"
-	case nativeSharedLib:
-		return "SHARED_LIBRARIES"
-	case nativeExecutable, shBinary, pyBinary, goBinary:
-		return "EXECUTABLES"
-	case javaSharedLib:
-		return "JAVA_LIBRARIES"
-	case nativeTest:
-		return "NATIVE_TESTS"
-	case app, appSet:
-		// b/142537672 Why isn't this APP? We want to have full control over
-		// the paths and file names of the apk file under the flattend APEX.
-		// If this is set to APP, then the paths and file names are modified
-		// by the Make build system. For example, it is installed to
-		// /system/apex/<apexname>/app/<Appname>/<apexname>.<Appname>/ instead of
-		// /system/apex/<apexname>/app/<Appname> because the build system automatically
-		// appends module name (which is <apexname>.<Appname> to the path.
-		return "ETC"
-	default:
-		panic(fmt.Errorf("unknown class %d", class))
-	}
-}
-
-// apexFile represents a file in an APEX bundle
-type apexFile struct {
-	builtFile android.Path
-	stem      string
-	// Module name of `module` in AndroidMk. Note the generated AndroidMk module for
-	// apexFile is named something like <AndroidMk module name>.<apex name>[<apex suffix>]
-	androidMkModuleName string
-	installDir          string
-	class               apexFileClass
-	module              android.Module
-	// list of symlinks that will be created in installDir that point to this apexFile
-	symlinks      []string
-	dataPaths     []android.DataPath
-	transitiveDep bool
-	moduleDir     string
-
-	requiredModuleNames       []string
-	targetRequiredModuleNames []string
-	hostRequiredModuleNames   []string
-
-	jacocoReportClassesFile android.Path     // only for javalibs and apps
-	lintDepSets             java.LintDepSets // only for javalibs and apps
-	certificate             java.Certificate // only for apps
-	overriddenPackageName   string           // only for apps
-
-	isJniLib bool
-
-	noticeFiles android.Paths
-}
-
-func newApexFile(ctx android.BaseModuleContext, builtFile android.Path, androidMkModuleName string, installDir string, class apexFileClass, module android.Module) apexFile {
-	ret := apexFile{
-		builtFile:           builtFile,
-		androidMkModuleName: androidMkModuleName,
-		installDir:          installDir,
-		class:               class,
-		module:              module,
-	}
-	if module != nil {
-		ret.moduleDir = ctx.OtherModuleDir(module)
-		ret.requiredModuleNames = module.RequiredModuleNames()
-		ret.targetRequiredModuleNames = module.TargetRequiredModuleNames()
-		ret.hostRequiredModuleNames = module.HostRequiredModuleNames()
-		ret.noticeFiles = module.NoticeFiles()
-	}
-	return ret
-}
-
-func (af *apexFile) Ok() bool {
-	return af.builtFile != nil && af.builtFile.String() != ""
-}
-
-func (af *apexFile) apexRelativePath(path string) string {
-	return filepath.Join(af.installDir, path)
-}
-
-// Path() returns path of this apex file relative to the APEX root
-func (af *apexFile) Path() string {
-	return af.apexRelativePath(af.Stem())
-}
-
-func (af *apexFile) Stem() string {
-	if af.stem != "" {
-		return af.stem
-	}
-	return af.builtFile.Base()
-}
-
-// SymlinkPaths() returns paths of the symlinks (if any) relative to the APEX root
-func (af *apexFile) SymlinkPaths() []string {
-	var ret []string
-	for _, symlink := range af.symlinks {
-		ret = append(ret, af.apexRelativePath(symlink))
-	}
-	return ret
-}
-
-func (af *apexFile) AvailableToPlatform() bool {
-	if af.module == nil {
-		return false
-	}
-	if am, ok := af.module.(android.ApexModule); ok {
-		return am.AvailableFor(android.AvailableToPlatform)
-	}
-	return false
-}
-
 type fsType int
 
 const (
@@ -1396,268 +990,6 @@
 	}
 }
 
-type apexBundle struct {
-	android.ModuleBase
-	android.DefaultableModuleBase
-	android.OverridableModuleBase
-	android.SdkBase
-
-	properties            apexBundleProperties
-	targetProperties      apexTargetBundleProperties
-	overridableProperties overridableProperties
-
-	// specific to apex_vndk modules
-	vndkProperties apexVndkProperties
-
-	bundleModuleFile android.WritablePath
-	outputFile       android.WritablePath
-	installDir       android.InstallPath
-
-	prebuiltFileToDelete string
-
-	public_key_file  android.Path
-	private_key_file android.Path
-
-	container_certificate_file android.Path
-	container_private_key_file android.Path
-
-	fileContexts android.WritablePath
-
-	// list of files to be included in this apex
-	filesInfo []apexFile
-
-	// list of module names that should be installed along with this APEX
-	requiredDeps []string
-
-	// list of module names that this APEX is including (to be shown via *-deps-info target)
-	android.ApexBundleDepsInfo
-
-	testApex        bool
-	vndkApex        bool
-	artApex         bool
-	primaryApexType bool
-
-	manifestJsonOut android.WritablePath
-	manifestPbOut   android.WritablePath
-
-	// list of commands to create symlinks for backward compatibility.
-	// these commands will be attached as LOCAL_POST_INSTALL_CMD to
-	// apex package itself(for unflattened build) or apex_manifest(for flattened build)
-	// so that compat symlinks are always installed regardless of TARGET_FLATTEN_APEX setting.
-	compatSymlinks []string
-
-	// Suffix of module name in Android.mk
-	// ".flattened", ".apex", ".zipapex", or ""
-	suffix string
-
-	installedFilesFile android.WritablePath
-
-	// Whether to create symlink to the system file instead of having a file
-	// inside the apex or not
-	linkToSystemLib bool
-
-	// Struct holding the merged notice file paths in different formats
-	mergedNotices android.NoticeOutputs
-
-	// Optional list of lint report zip files for apexes that contain java or app modules
-	lintReports android.Paths
-
-	payloadFsType fsType
-
-	distFiles android.TaggedDistFiles
-}
-
-func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext,
-	nativeModules ApexNativeDependencies,
-	target android.Target, imageVariation string) {
-	// Use *FarVariation* to be able to depend on modules having
-	// conflicting variations with this module. This is required since
-	// arch variant of an APEX bundle is 'common' but it is 'arm' or 'arm64'
-	// for native shared libs.
-
-	binVariations := target.Variations()
-	libVariations := append(target.Variations(),
-		blueprint.Variation{Mutator: "link", Variation: "shared"})
-
-	if ctx.Device() {
-		binVariations = append(binVariations,
-			blueprint.Variation{Mutator: "image", Variation: imageVariation})
-		libVariations = append(libVariations,
-			blueprint.Variation{Mutator: "image", Variation: imageVariation},
-			blueprint.Variation{Mutator: "version", Variation: ""}) // "" is the non-stub variant
-	}
-
-	ctx.AddFarVariationDependencies(libVariations, sharedLibTag, nativeModules.Native_shared_libs...)
-
-	ctx.AddFarVariationDependencies(libVariations, jniLibTag, nativeModules.Jni_libs...)
-
-	ctx.AddFarVariationDependencies(binVariations, executableTag, nativeModules.Binaries...)
-
-	ctx.AddFarVariationDependencies(binVariations, testTag, nativeModules.Tests...)
-}
-
-func (a *apexBundle) combineProperties(ctx android.BottomUpMutatorContext) {
-	if ctx.Os().Class == android.Device {
-		proptools.AppendProperties(&a.properties.Multilib, &a.targetProperties.Target.Android.Multilib, nil)
-	} else {
-		proptools.AppendProperties(&a.properties.Multilib, &a.targetProperties.Target.Host.Multilib, nil)
-		if ctx.Os().Bionic() {
-			proptools.AppendProperties(&a.properties.Multilib, &a.targetProperties.Target.Linux_bionic.Multilib, nil)
-		} else {
-			proptools.AppendProperties(&a.properties.Multilib, &a.targetProperties.Target.Linux_glibc.Multilib, nil)
-		}
-	}
-}
-
-func (a *apexBundle) DepsMutator(ctx android.BottomUpMutatorContext) {
-	if proptools.Bool(a.properties.Use_vendor) && !android.InList(a.Name(), useVendorAllowList(ctx.Config())) {
-		ctx.PropertyErrorf("use_vendor", "not allowed to set use_vendor: true")
-	}
-
-	targets := ctx.MultiTargets()
-	config := ctx.DeviceConfig()
-	imageVariation := a.getImageVariation(ctx)
-
-	a.combineProperties(ctx)
-
-	has32BitTarget := false
-	for _, target := range targets {
-		if target.Arch.ArchType.Multilib == "lib32" {
-			has32BitTarget = true
-		}
-	}
-	for i, target := range targets {
-		if target.HostCross {
-			// Don't include artifats for the host cross targets because there is no way
-			// for us to run those artifacts natively on host
-			continue
-		}
-
-		// When multilib.* is omitted for native_shared_libs/jni_libs/tests, it implies
-		// multilib.both
-		addDependenciesForNativeModules(ctx,
-			ApexNativeDependencies{
-				Native_shared_libs: a.properties.Native_shared_libs,
-				Tests:              a.properties.Tests,
-				Jni_libs:           a.properties.Jni_libs,
-				Binaries:           nil,
-			},
-			target, imageVariation)
-
-		// Add native modules targetting both ABIs
-		addDependenciesForNativeModules(ctx,
-			a.properties.Multilib.Both,
-			target,
-			imageVariation)
-
-		isPrimaryAbi := i == 0
-		if isPrimaryAbi {
-			// When multilib.* is omitted for binaries, it implies
-			// multilib.first
-			addDependenciesForNativeModules(ctx,
-				ApexNativeDependencies{
-					Native_shared_libs: nil,
-					Tests:              nil,
-					Jni_libs:           nil,
-					Binaries:           a.properties.Binaries,
-				},
-				target, imageVariation)
-
-			// Add native modules targetting the first ABI
-			addDependenciesForNativeModules(ctx,
-				a.properties.Multilib.First,
-				target,
-				imageVariation)
-		}
-
-		switch target.Arch.ArchType.Multilib {
-		case "lib32":
-			// Add native modules targetting 32-bit ABI
-			addDependenciesForNativeModules(ctx,
-				a.properties.Multilib.Lib32,
-				target,
-				imageVariation)
-
-			addDependenciesForNativeModules(ctx,
-				a.properties.Multilib.Prefer32,
-				target,
-				imageVariation)
-		case "lib64":
-			// Add native modules targetting 64-bit ABI
-			addDependenciesForNativeModules(ctx,
-				a.properties.Multilib.Lib64,
-				target,
-				imageVariation)
-
-			if !has32BitTarget {
-				addDependenciesForNativeModules(ctx,
-					a.properties.Multilib.Prefer32,
-					target,
-					imageVariation)
-			}
-		}
-	}
-
-	// For prebuilt_etc, use the first variant (64 on 64/32bit device,
-	// 32 on 32bit device) regardless of the TARGET_PREFER_* setting.
-	// b/144532908
-	archForPrebuiltEtc := config.Arches()[0]
-	for _, arch := range config.Arches() {
-		// Prefer 64-bit arch if there is any
-		if arch.ArchType.Multilib == "lib64" {
-			archForPrebuiltEtc = arch
-			break
-		}
-	}
-	ctx.AddFarVariationDependencies([]blueprint.Variation{
-		{Mutator: "os", Variation: ctx.Os().String()},
-		{Mutator: "arch", Variation: archForPrebuiltEtc.String()},
-	}, prebuiltTag, a.properties.Prebuilts...)
-
-	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(),
-			javaLibTag, "jacocoagent")
-	}
-
-	if String(a.properties.Key) == "" {
-		ctx.ModuleErrorf("key is missing")
-		return
-	}
-	ctx.AddDependency(ctx.Module(), keyTag, String(a.properties.Key))
-
-	cert := android.SrcIsModule(a.getCertString(ctx))
-	if cert != "" {
-		ctx.AddDependency(ctx.Module(), certificateTag, cert)
-	}
-
-	// TODO(jiyong): ensure that all apexes are with non-empty uses_sdks
-	if len(a.properties.Uses_sdks) > 0 {
-		sdkRefs := []android.SdkRef{}
-		for _, str := range a.properties.Uses_sdks {
-			parsed := android.ParseSdkRef(ctx, str, "uses_sdks")
-			sdkRefs = append(sdkRefs, parsed)
-		}
-		a.BuildWithSdks(sdkRefs)
-	}
-}
-
-func (a *apexBundle) OverridablePropertiesDepsMutator(ctx android.BottomUpMutatorContext) {
-	if a.overridableProperties.Allowed_files != nil {
-		android.ExtractSourceDeps(ctx, a.overridableProperties.Allowed_files)
-	}
-	ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(),
-		androidAppTag, a.overridableProperties.Apps...)
-	ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(),
-		rroTag, a.overridableProperties.Rros...)
-}
-
 func (a *apexBundle) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
 	// direct deps of an APEX bundle are all part of the APEX bundle
 	return true
@@ -2615,3 +1947,674 @@
 	android.InitOverrideModule(m)
 	return m
 }
+
+var (
+	apexAvailBaseline        = makeApexAvailableBaseline()
+	inverseApexAvailBaseline = invertApexBaseline(apexAvailBaseline)
+)
+
+// Transform the map of apex -> modules to module -> apexes.
+func invertApexBaseline(m map[string][]string) map[string][]string {
+	r := make(map[string][]string)
+	for apex, modules := range m {
+		for _, module := range modules {
+			r[module] = append(r[module], apex)
+		}
+	}
+	return r
+}
+
+// Retrieve the baseline of apexes to which the supplied module belongs.
+func BaselineApexAvailable(moduleName string) []string {
+	return inverseApexAvailBaseline[normalizeModuleName(moduleName)]
+}
+
+// This is a map from apex to modules, which overrides the
+// apex_available setting for that particular module to make
+// it available for the apex regardless of its setting.
+// TODO(b/147364041): remove this
+func makeApexAvailableBaseline() map[string][]string {
+	// The "Module separator"s below are employed to minimize merge conflicts.
+	m := make(map[string][]string)
+	//
+	// Module separator
+	//
+	m["com.android.appsearch"] = []string{
+		"icing-java-proto-lite",
+		"libprotobuf-java-lite",
+	}
+	//
+	// Module separator
+	//
+	m["com.android.bluetooth.updatable"] = []string{
+		"android.hardware.audio.common@5.0",
+		"android.hardware.bluetooth.a2dp@1.0",
+		"android.hardware.bluetooth.audio@2.0",
+		"android.hardware.bluetooth@1.0",
+		"android.hardware.bluetooth@1.1",
+		"android.hardware.graphics.bufferqueue@1.0",
+		"android.hardware.graphics.bufferqueue@2.0",
+		"android.hardware.graphics.common@1.0",
+		"android.hardware.graphics.common@1.1",
+		"android.hardware.graphics.common@1.2",
+		"android.hardware.media@1.0",
+		"android.hidl.safe_union@1.0",
+		"android.hidl.token@1.0",
+		"android.hidl.token@1.0-utils",
+		"avrcp-target-service",
+		"avrcp_headers",
+		"bluetooth-protos-lite",
+		"bluetooth.mapsapi",
+		"com.android.vcard",
+		"dnsresolver_aidl_interface-V2-java",
+		"ipmemorystore-aidl-interfaces-V5-java",
+		"ipmemorystore-aidl-interfaces-java",
+		"internal_include_headers",
+		"lib-bt-packets",
+		"lib-bt-packets-avrcp",
+		"lib-bt-packets-base",
+		"libFraunhoferAAC",
+		"libaudio-a2dp-hw-utils",
+		"libaudio-hearing-aid-hw-utils",
+		"libbinder_headers",
+		"libbluetooth",
+		"libbluetooth-types",
+		"libbluetooth-types-header",
+		"libbluetooth_gd",
+		"libbluetooth_headers",
+		"libbluetooth_jni",
+		"libbt-audio-hal-interface",
+		"libbt-bta",
+		"libbt-common",
+		"libbt-hci",
+		"libbt-platform-protos-lite",
+		"libbt-protos-lite",
+		"libbt-sbc-decoder",
+		"libbt-sbc-encoder",
+		"libbt-stack",
+		"libbt-utils",
+		"libbtcore",
+		"libbtdevice",
+		"libbte",
+		"libbtif",
+		"libchrome",
+		"libevent",
+		"libfmq",
+		"libg722codec",
+		"libgui_headers",
+		"libmedia_headers",
+		"libmodpb64",
+		"libosi",
+		"libstagefright_foundation_headers",
+		"libstagefright_headers",
+		"libstatslog",
+		"libstatssocket",
+		"libtinyxml2",
+		"libudrv-uipc",
+		"libz",
+		"media_plugin_headers",
+		"net-utils-services-common",
+		"netd_aidl_interface-unstable-java",
+		"netd_event_listener_interface-java",
+		"netlink-client",
+		"networkstack-client",
+		"sap-api-java-static",
+		"services.net",
+	}
+	//
+	// Module separator
+	//
+	m["com.android.cellbroadcast"] = []string{"CellBroadcastApp", "CellBroadcastServiceModule"}
+	//
+	// Module separator
+	//
+	m["com.android.extservices"] = []string{
+		"error_prone_annotations",
+		"ExtServices-core",
+		"ExtServices",
+		"libtextclassifier-java",
+		"libz_current",
+		"textclassifier-statsd",
+		"TextClassifierNotificationLibNoManifest",
+		"TextClassifierServiceLibNoManifest",
+	}
+	//
+	// Module separator
+	//
+	m["com.android.neuralnetworks"] = []string{
+		"android.hardware.neuralnetworks@1.0",
+		"android.hardware.neuralnetworks@1.1",
+		"android.hardware.neuralnetworks@1.2",
+		"android.hardware.neuralnetworks@1.3",
+		"android.hidl.allocator@1.0",
+		"android.hidl.memory.token@1.0",
+		"android.hidl.memory@1.0",
+		"android.hidl.safe_union@1.0",
+		"libarect",
+		"libbuildversion",
+		"libmath",
+		"libprocpartition",
+		"libsync",
+	}
+	//
+	// Module separator
+	//
+	m["com.android.media"] = []string{
+		"android.frameworks.bufferhub@1.0",
+		"android.hardware.cas.native@1.0",
+		"android.hardware.cas@1.0",
+		"android.hardware.configstore-utils",
+		"android.hardware.configstore@1.0",
+		"android.hardware.configstore@1.1",
+		"android.hardware.graphics.allocator@2.0",
+		"android.hardware.graphics.allocator@3.0",
+		"android.hardware.graphics.bufferqueue@1.0",
+		"android.hardware.graphics.bufferqueue@2.0",
+		"android.hardware.graphics.common@1.0",
+		"android.hardware.graphics.common@1.1",
+		"android.hardware.graphics.common@1.2",
+		"android.hardware.graphics.mapper@2.0",
+		"android.hardware.graphics.mapper@2.1",
+		"android.hardware.graphics.mapper@3.0",
+		"android.hardware.media.omx@1.0",
+		"android.hardware.media@1.0",
+		"android.hidl.allocator@1.0",
+		"android.hidl.memory.token@1.0",
+		"android.hidl.memory@1.0",
+		"android.hidl.token@1.0",
+		"android.hidl.token@1.0-utils",
+		"bionic_libc_platform_headers",
+		"exoplayer2-extractor",
+		"exoplayer2-extractor-annotation-stubs",
+		"gl_headers",
+		"jsr305",
+		"libEGL",
+		"libEGL_blobCache",
+		"libEGL_getProcAddress",
+		"libFLAC",
+		"libFLAC-config",
+		"libFLAC-headers",
+		"libGLESv2",
+		"libaacextractor",
+		"libamrextractor",
+		"libarect",
+		"libaudio_system_headers",
+		"libaudioclient",
+		"libaudioclient_headers",
+		"libaudiofoundation",
+		"libaudiofoundation_headers",
+		"libaudiomanager",
+		"libaudiopolicy",
+		"libaudioutils",
+		"libaudioutils_fixedfft",
+		"libbinder_headers",
+		"libbluetooth-types-header",
+		"libbufferhub",
+		"libbufferhub_headers",
+		"libbufferhubqueue",
+		"libc_malloc_debug_backtrace",
+		"libcamera_client",
+		"libcamera_metadata",
+		"libdvr_headers",
+		"libexpat",
+		"libfifo",
+		"libflacextractor",
+		"libgrallocusage",
+		"libgraphicsenv",
+		"libgui",
+		"libgui_headers",
+		"libhardware_headers",
+		"libinput",
+		"liblzma",
+		"libmath",
+		"libmedia",
+		"libmedia_codeclist",
+		"libmedia_headers",
+		"libmedia_helper",
+		"libmedia_helper_headers",
+		"libmedia_midiiowrapper",
+		"libmedia_omx",
+		"libmediautils",
+		"libmidiextractor",
+		"libmkvextractor",
+		"libmp3extractor",
+		"libmp4extractor",
+		"libmpeg2extractor",
+		"libnativebase_headers",
+		"libnativewindow_headers",
+		"libnblog",
+		"liboggextractor",
+		"libpackagelistparser",
+		"libpdx",
+		"libpdx_default_transport",
+		"libpdx_headers",
+		"libpdx_uds",
+		"libprocinfo",
+		"libspeexresampler",
+		"libspeexresampler",
+		"libstagefright_esds",
+		"libstagefright_flacdec",
+		"libstagefright_flacdec",
+		"libstagefright_foundation",
+		"libstagefright_foundation_headers",
+		"libstagefright_foundation_without_imemory",
+		"libstagefright_headers",
+		"libstagefright_id3",
+		"libstagefright_metadatautils",
+		"libstagefright_mpeg2extractor",
+		"libstagefright_mpeg2support",
+		"libsync",
+		"libui",
+		"libui_headers",
+		"libunwindstack",
+		"libvibrator",
+		"libvorbisidec",
+		"libwavextractor",
+		"libwebm",
+		"media_ndk_headers",
+		"media_plugin_headers",
+		"updatable-media",
+	}
+	//
+	// Module separator
+	//
+	m["com.android.media.swcodec"] = []string{
+		"android.frameworks.bufferhub@1.0",
+		"android.hardware.common-ndk_platform",
+		"android.hardware.configstore-utils",
+		"android.hardware.configstore@1.0",
+		"android.hardware.configstore@1.1",
+		"android.hardware.graphics.allocator@2.0",
+		"android.hardware.graphics.allocator@3.0",
+		"android.hardware.graphics.allocator@4.0",
+		"android.hardware.graphics.bufferqueue@1.0",
+		"android.hardware.graphics.bufferqueue@2.0",
+		"android.hardware.graphics.common-ndk_platform",
+		"android.hardware.graphics.common@1.0",
+		"android.hardware.graphics.common@1.1",
+		"android.hardware.graphics.common@1.2",
+		"android.hardware.graphics.mapper@2.0",
+		"android.hardware.graphics.mapper@2.1",
+		"android.hardware.graphics.mapper@3.0",
+		"android.hardware.graphics.mapper@4.0",
+		"android.hardware.media.bufferpool@2.0",
+		"android.hardware.media.c2@1.0",
+		"android.hardware.media.c2@1.1",
+		"android.hardware.media.omx@1.0",
+		"android.hardware.media@1.0",
+		"android.hardware.media@1.0",
+		"android.hidl.memory.token@1.0",
+		"android.hidl.memory@1.0",
+		"android.hidl.safe_union@1.0",
+		"android.hidl.token@1.0",
+		"android.hidl.token@1.0-utils",
+		"libEGL",
+		"libFLAC",
+		"libFLAC-config",
+		"libFLAC-headers",
+		"libFraunhoferAAC",
+		"libLibGuiProperties",
+		"libarect",
+		"libaudio_system_headers",
+		"libaudioutils",
+		"libaudioutils",
+		"libaudioutils_fixedfft",
+		"libavcdec",
+		"libavcenc",
+		"libavservices_minijail",
+		"libavservices_minijail",
+		"libbinder_headers",
+		"libbinderthreadstateutils",
+		"libbluetooth-types-header",
+		"libbufferhub_headers",
+		"libcodec2",
+		"libcodec2_headers",
+		"libcodec2_hidl@1.0",
+		"libcodec2_hidl@1.1",
+		"libcodec2_internal",
+		"libcodec2_soft_aacdec",
+		"libcodec2_soft_aacenc",
+		"libcodec2_soft_amrnbdec",
+		"libcodec2_soft_amrnbenc",
+		"libcodec2_soft_amrwbdec",
+		"libcodec2_soft_amrwbenc",
+		"libcodec2_soft_av1dec_gav1",
+		"libcodec2_soft_avcdec",
+		"libcodec2_soft_avcenc",
+		"libcodec2_soft_common",
+		"libcodec2_soft_flacdec",
+		"libcodec2_soft_flacenc",
+		"libcodec2_soft_g711alawdec",
+		"libcodec2_soft_g711mlawdec",
+		"libcodec2_soft_gsmdec",
+		"libcodec2_soft_h263dec",
+		"libcodec2_soft_h263enc",
+		"libcodec2_soft_hevcdec",
+		"libcodec2_soft_hevcenc",
+		"libcodec2_soft_mp3dec",
+		"libcodec2_soft_mpeg2dec",
+		"libcodec2_soft_mpeg4dec",
+		"libcodec2_soft_mpeg4enc",
+		"libcodec2_soft_opusdec",
+		"libcodec2_soft_opusenc",
+		"libcodec2_soft_rawdec",
+		"libcodec2_soft_vorbisdec",
+		"libcodec2_soft_vp8dec",
+		"libcodec2_soft_vp8enc",
+		"libcodec2_soft_vp9dec",
+		"libcodec2_soft_vp9enc",
+		"libcodec2_vndk",
+		"libdvr_headers",
+		"libfmq",
+		"libfmq",
+		"libgav1",
+		"libgralloctypes",
+		"libgrallocusage",
+		"libgraphicsenv",
+		"libgsm",
+		"libgui_bufferqueue_static",
+		"libgui_headers",
+		"libhardware",
+		"libhardware_headers",
+		"libhevcdec",
+		"libhevcenc",
+		"libion",
+		"libjpeg",
+		"liblzma",
+		"libmath",
+		"libmedia_codecserviceregistrant",
+		"libmedia_headers",
+		"libmpeg2dec",
+		"libnativebase_headers",
+		"libnativewindow_headers",
+		"libpdx_headers",
+		"libscudo_wrapper",
+		"libsfplugin_ccodec_utils",
+		"libspeexresampler",
+		"libstagefright_amrnb_common",
+		"libstagefright_amrnbdec",
+		"libstagefright_amrnbenc",
+		"libstagefright_amrwbdec",
+		"libstagefright_amrwbenc",
+		"libstagefright_bufferpool@2.0.1",
+		"libstagefright_bufferqueue_helper",
+		"libstagefright_enc_common",
+		"libstagefright_flacdec",
+		"libstagefright_foundation",
+		"libstagefright_foundation_headers",
+		"libstagefright_headers",
+		"libstagefright_m4vh263dec",
+		"libstagefright_m4vh263enc",
+		"libstagefright_mp3dec",
+		"libsync",
+		"libui",
+		"libui_headers",
+		"libunwindstack",
+		"libvorbisidec",
+		"libvpx",
+		"libyuv",
+		"libyuv_static",
+		"media_ndk_headers",
+		"media_plugin_headers",
+		"mediaswcodec",
+	}
+	//
+	// Module separator
+	//
+	m["com.android.mediaprovider"] = []string{
+		"MediaProvider",
+		"MediaProviderGoogle",
+		"fmtlib_ndk",
+		"libbase_ndk",
+		"libfuse",
+		"libfuse_jni",
+	}
+	//
+	// Module separator
+	//
+	m["com.android.permission"] = []string{
+		"car-ui-lib",
+		"iconloader",
+		"kotlin-annotations",
+		"kotlin-stdlib",
+		"kotlin-stdlib-jdk7",
+		"kotlin-stdlib-jdk8",
+		"kotlinx-coroutines-android",
+		"kotlinx-coroutines-android-nodeps",
+		"kotlinx-coroutines-core",
+		"kotlinx-coroutines-core-nodeps",
+		"permissioncontroller-statsd",
+		"GooglePermissionController",
+		"PermissionController",
+		"SettingsLibActionBarShadow",
+		"SettingsLibAppPreference",
+		"SettingsLibBarChartPreference",
+		"SettingsLibLayoutPreference",
+		"SettingsLibProgressBar",
+		"SettingsLibSearchWidget",
+		"SettingsLibSettingsTheme",
+		"SettingsLibRestrictedLockUtils",
+		"SettingsLibHelpUtils",
+	}
+	//
+	// Module separator
+	//
+	m["com.android.runtime"] = []string{
+		"bionic_libc_platform_headers",
+		"libarm-optimized-routines-math",
+		"libc_aeabi",
+		"libc_bionic",
+		"libc_bionic_ndk",
+		"libc_bootstrap",
+		"libc_common",
+		"libc_common_shared",
+		"libc_common_static",
+		"libc_dns",
+		"libc_dynamic_dispatch",
+		"libc_fortify",
+		"libc_freebsd",
+		"libc_freebsd_large_stack",
+		"libc_gdtoa",
+		"libc_init_dynamic",
+		"libc_init_static",
+		"libc_jemalloc_wrapper",
+		"libc_netbsd",
+		"libc_nomalloc",
+		"libc_nopthread",
+		"libc_openbsd",
+		"libc_openbsd_large_stack",
+		"libc_openbsd_ndk",
+		"libc_pthread",
+		"libc_static_dispatch",
+		"libc_syscalls",
+		"libc_tzcode",
+		"libc_unwind_static",
+		"libdebuggerd",
+		"libdebuggerd_common_headers",
+		"libdebuggerd_handler_core",
+		"libdebuggerd_handler_fallback",
+		"libdl_static",
+		"libjemalloc5",
+		"liblinker_main",
+		"liblinker_malloc",
+		"liblz4",
+		"liblzma",
+		"libprocinfo",
+		"libpropertyinfoparser",
+		"libscudo",
+		"libstdc++",
+		"libsystemproperties",
+		"libtombstoned_client_static",
+		"libunwindstack",
+		"libz",
+		"libziparchive",
+	}
+	//
+	// Module separator
+	//
+	m["com.android.tethering"] = []string{
+		"android.hardware.tetheroffload.config-V1.0-java",
+		"android.hardware.tetheroffload.control-V1.0-java",
+		"android.hidl.base-V1.0-java",
+		"libcgrouprc",
+		"libcgrouprc_format",
+		"libtetherutilsjni",
+		"libvndksupport",
+		"net-utils-framework-common",
+		"netd_aidl_interface-V3-java",
+		"netlink-client",
+		"networkstack-aidl-interfaces-java",
+		"tethering-aidl-interfaces-java",
+		"TetheringApiCurrentLib",
+	}
+	//
+	// Module separator
+	//
+	m["com.android.wifi"] = []string{
+		"PlatformProperties",
+		"android.hardware.wifi-V1.0-java",
+		"android.hardware.wifi-V1.0-java-constants",
+		"android.hardware.wifi-V1.1-java",
+		"android.hardware.wifi-V1.2-java",
+		"android.hardware.wifi-V1.3-java",
+		"android.hardware.wifi-V1.4-java",
+		"android.hardware.wifi.hostapd-V1.0-java",
+		"android.hardware.wifi.hostapd-V1.1-java",
+		"android.hardware.wifi.hostapd-V1.2-java",
+		"android.hardware.wifi.supplicant-V1.0-java",
+		"android.hardware.wifi.supplicant-V1.1-java",
+		"android.hardware.wifi.supplicant-V1.2-java",
+		"android.hardware.wifi.supplicant-V1.3-java",
+		"android.hidl.base-V1.0-java",
+		"android.hidl.manager-V1.0-java",
+		"android.hidl.manager-V1.1-java",
+		"android.hidl.manager-V1.2-java",
+		"bouncycastle-unbundled",
+		"dnsresolver_aidl_interface-V2-java",
+		"error_prone_annotations",
+		"framework-wifi-pre-jarjar",
+		"framework-wifi-util-lib",
+		"ipmemorystore-aidl-interfaces-V3-java",
+		"ipmemorystore-aidl-interfaces-java",
+		"ksoap2",
+		"libnanohttpd",
+		"libwifi-jni",
+		"net-utils-services-common",
+		"netd_aidl_interface-V2-java",
+		"netd_aidl_interface-unstable-java",
+		"netd_event_listener_interface-java",
+		"netlink-client",
+		"networkstack-client",
+		"services.net",
+		"wifi-lite-protos",
+		"wifi-nano-protos",
+		"wifi-service-pre-jarjar",
+		"wifi-service-resources",
+	}
+	//
+	// Module separator
+	//
+	m["com.android.sdkext"] = []string{
+		"fmtlib_ndk",
+		"libbase_ndk",
+		"libprotobuf-cpp-lite-ndk",
+	}
+	//
+	// Module separator
+	//
+	m["com.android.os.statsd"] = []string{
+		"libstatssocket",
+	}
+	//
+	// Module separator
+	//
+	m[android.AvailableToAnyApex] = []string{
+		// TODO(b/156996905) Set apex_available/min_sdk_version for androidx/extras support libraries
+		"androidx",
+		"androidx-constraintlayout_constraintlayout",
+		"androidx-constraintlayout_constraintlayout-nodeps",
+		"androidx-constraintlayout_constraintlayout-solver",
+		"androidx-constraintlayout_constraintlayout-solver-nodeps",
+		"com.google.android.material_material",
+		"com.google.android.material_material-nodeps",
+
+		"libatomic",
+		"libclang_rt",
+		"libgcc_stripped",
+		"libprofile-clang-extras",
+		"libprofile-clang-extras_ndk",
+		"libprofile-extras",
+		"libprofile-extras_ndk",
+		"libunwind_llvm",
+	}
+	return m
+}
+
+func init() {
+	android.AddNeverAllowRules(createApexPermittedPackagesRules(qModulesPackages())...)
+	android.AddNeverAllowRules(createApexPermittedPackagesRules(rModulesPackages())...)
+}
+
+func createApexPermittedPackagesRules(modules_packages map[string][]string) []android.Rule {
+	rules := make([]android.Rule, 0, len(modules_packages))
+	for module_name, module_packages := range modules_packages {
+		permitted_packages_rule := android.NeverAllow().
+			BootclasspathJar().
+			With("apex_available", module_name).
+			WithMatcher("permitted_packages", android.NotInList(module_packages)).
+			Because("jars that are part of the " + module_name +
+				" module may only allow these packages: " + strings.Join(module_packages, ",") +
+				". Please jarjar or move code around.")
+		rules = append(rules, permitted_packages_rule)
+	}
+	return rules
+}
+
+// DO NOT EDIT! These are the package prefixes that are exempted from being AOT'ed by ART.
+// Adding code to the bootclasspath in new packages will cause issues on module update.
+func qModulesPackages() map[string][]string {
+	return map[string][]string{
+		"com.android.conscrypt": []string{
+			"android.net.ssl",
+			"com.android.org.conscrypt",
+		},
+		"com.android.media": []string{
+			"android.media",
+		},
+	}
+}
+
+// DO NOT EDIT! These are the package prefixes that are exempted from being AOT'ed by ART.
+// Adding code to the bootclasspath in new packages will cause issues on module update.
+func rModulesPackages() map[string][]string {
+	return map[string][]string{
+		"com.android.mediaprovider": []string{
+			"android.provider",
+		},
+		"com.android.permission": []string{
+			"android.permission",
+			"android.app.role",
+			"com.android.permission",
+			"com.android.role",
+		},
+		"com.android.sdkext": []string{
+			"android.os.ext",
+		},
+		"com.android.os.statsd": []string{
+			"android.app",
+			"android.os",
+			"android.util",
+			"com.android.internal.statsd",
+			"com.android.server.stats",
+		},
+		"com.android.wifi": []string{
+			"com.android.server.wifi",
+			"com.android.wifi.x",
+			"android.hardware.wifi",
+			"android.net.wifi",
+		},
+		"com.android.tethering": []string{
+			"android.net",
+		},
+	}
+}
diff --git a/java/app_test.go b/java/app_test.go
index 6429ab8..6efb0dc 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -291,7 +291,7 @@
 		}
 	`)
 
-	testJavaError(t, "Adjust sdk_version: property of the source or target module so that target module is built with the same or smaller API set than the source.", `
+	testJavaError(t, "consider adjusting sdk_version: OR platform_apis:", `
 		android_app {
 			name: "foo",
 			srcs: ["a.java"],
@@ -335,7 +335,7 @@
 		}
 	`)
 
-	testJavaError(t, "Adjust sdk_version: property of the source or target module so that target module is built with the same or smaller API set than the source.", `
+	testJavaError(t, "consider adjusting sdk_version: OR platform_apis:", `
 		android_app {
 			name: "foo",
 			srcs: ["a.java"],
diff --git a/java/droiddoc.go b/java/droiddoc.go
index c7a27c2..cf7f4fb 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -1748,8 +1748,6 @@
 
 	properties PrebuiltStubsSourcesProperties
 
-	// The source directories containing stubs source files.
-	srcDirs     android.Paths
 	stubsSrcJar android.ModuleOutPath
 }
 
@@ -1769,21 +1767,29 @@
 func (p *PrebuiltStubsSources) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	p.stubsSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar")
 
-	p.srcDirs = android.PathsForModuleSrc(ctx, p.properties.Srcs)
+	if len(p.properties.Srcs) != 1 {
+		ctx.PropertyErrorf("srcs", "must only specify one directory path, contains %d paths", len(p.properties.Srcs))
+		return
+	}
+
+	localSrcDir := p.properties.Srcs[0]
+	// Although PathForModuleSrc can return nil if either the path doesn't exist or
+	// the path components are invalid it won't in this case because no components
+	// are specified and the module directory must exist in order to get this far.
+	srcDir := android.PathForModuleSrc(ctx).(android.SourcePath).Join(ctx, localSrcDir)
+
+	// Glob the contents of the directory just in case the directory does not exist.
+	srcGlob := localSrcDir + "/**/*"
+	srcPaths := android.PathsForModuleSrc(ctx, []string{srcGlob})
 
 	rule := android.NewRuleBuilder()
-	command := rule.Command().
+	rule.Command().
 		BuiltTool(ctx, "soong_zip").
 		Flag("-write_if_changed").
 		Flag("-jar").
-		FlagWithOutput("-o ", p.stubsSrcJar)
-
-	for _, d := range p.srcDirs {
-		dir := d.String()
-		command.
-			FlagWithArg("-C ", dir).
-			FlagWithInput("-D ", d)
-	}
+		FlagWithOutput("-o ", p.stubsSrcJar).
+		FlagWithArg("-C ", srcDir.String()).
+		FlagWithRspFileInputList("-r ", srcPaths)
 
 	rule.Restat()
 
diff --git a/java/java.go b/java/java.go
index a23c649..7cf04fa 100644
--- a/java/java.go
+++ b/java/java.go
@@ -248,6 +248,9 @@
 	Errorprone struct {
 		// List of javac flags that should only be used when running errorprone.
 		Javacflags []string
+
+		// List of java_plugin modules that provide extra errorprone checks.
+		Extra_check_modules []string
 	}
 
 	Proto struct {
@@ -569,6 +572,7 @@
 	libTag                = dependencyTag{name: "javalib"}
 	java9LibTag           = dependencyTag{name: "java9lib"}
 	pluginTag             = dependencyTag{name: "plugin"}
+	errorpronePluginTag   = dependencyTag{name: "errorprone-plugin"}
 	exportedPluginTag     = dependencyTag{name: "exported-plugin"}
 	bootClasspathTag      = dependencyTag{name: "bootclasspath"}
 	systemModulesTag      = dependencyTag{name: "system modules"}
@@ -765,6 +769,7 @@
 	}
 
 	ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), pluginTag, j.properties.Plugins...)
+	ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), errorpronePluginTag, j.properties.Errorprone.Extra_check_modules...)
 	ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), exportedPluginTag, j.properties.Exported_plugins...)
 
 	android.ProtoDeps(ctx, &j.protoProperties)
@@ -852,21 +857,22 @@
 }
 
 type deps struct {
-	classpath          classpath
-	java9Classpath     classpath
-	bootClasspath      classpath
-	processorPath      classpath
-	processorClasses   []string
-	staticJars         android.Paths
-	staticHeaderJars   android.Paths
-	staticResourceJars android.Paths
-	aidlIncludeDirs    android.Paths
-	srcs               android.Paths
-	srcJars            android.Paths
-	systemModules      *systemModules
-	aidlPreprocess     android.OptionalPath
-	kotlinStdlib       android.Paths
-	kotlinAnnotations  android.Paths
+	classpath               classpath
+	java9Classpath          classpath
+	bootClasspath           classpath
+	processorPath           classpath
+	errorProneProcessorPath classpath
+	processorClasses        []string
+	staticJars              android.Paths
+	staticHeaderJars        android.Paths
+	staticResourceJars      android.Paths
+	aidlIncludeDirs         android.Paths
+	srcs                    android.Paths
+	srcJars                 android.Paths
+	systemModules           *systemModules
+	aidlPreprocess          android.OptionalPath
+	kotlinStdlib            android.Paths
+	kotlinAnnotations       android.Paths
 
 	disableTurbine bool
 }
@@ -952,7 +958,9 @@
 		return
 	}
 	otherLinkType, _ := to.getLinkType(ctx.OtherModuleName(to))
-	commonMessage := "Adjust sdk_version: property of the source or target module so that target module is built with the same or smaller API set than the source."
+	commonMessage := " In order to fix this, consider adjusting sdk_version: OR platform_apis: " +
+		"property of the source or target module so that target module is built with the same " +
+		"or smaller API set when compared to the source."
 
 	switch myLinkType {
 	case javaCore:
@@ -1066,6 +1074,12 @@
 				} else {
 					ctx.PropertyErrorf("plugins", "%q is not a java_plugin module", otherName)
 				}
+			case errorpronePluginTag:
+				if plugin, ok := dep.(*Plugin); ok {
+					deps.errorProneProcessorPath = append(deps.errorProneProcessorPath, plugin.ImplementationAndResourcesJars()...)
+				} else {
+					ctx.PropertyErrorf("plugins", "%q is not a java_plugin module", otherName)
+				}
 			case exportedPluginTag:
 				if plugin, ok := dep.(*Plugin); ok {
 					if plugin.pluginProperties.Generates_api != nil && *plugin.pluginProperties.Generates_api {
@@ -1189,7 +1203,7 @@
 	flags.javaVersion = getJavaVersion(ctx, String(j.properties.Java_version), sdkContext(j))
 
 	if ctx.Config().RunErrorProne() {
-		if config.ErrorProneClasspath == nil {
+		if config.ErrorProneClasspath == nil && ctx.Config().TestProductVariables == nil {
 			ctx.ModuleErrorf("cannot build with Error Prone, missing external/error_prone?")
 		}
 
@@ -1209,6 +1223,7 @@
 	flags.classpath = append(flags.classpath, deps.classpath...)
 	flags.java9Classpath = append(flags.java9Classpath, deps.java9Classpath...)
 	flags.processorPath = append(flags.processorPath, deps.processorPath...)
+	flags.errorProneProcessorPath = append(flags.errorProneProcessorPath, deps.errorProneProcessorPath...)
 
 	flags.processors = append(flags.processors, deps.processorClasses...)
 	flags.processors = android.FirstUniqueStrings(flags.processors)
@@ -2325,7 +2340,7 @@
 
 func (j *Test) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	j.testConfig = tradefed.AutoGenJavaTestConfig(ctx, j.testProperties.Test_config, j.testProperties.Test_config_template,
-		j.testProperties.Test_suites, j.testProperties.Auto_gen_config)
+		j.testProperties.Test_suites, j.testProperties.Auto_gen_config, j.testProperties.Test_options.Unit_test)
 
 	j.data = android.PathsForModuleSrc(ctx, j.testProperties.Data)
 
@@ -2344,7 +2359,7 @@
 
 func (j *JavaTestImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	j.testConfig = tradefed.AutoGenJavaTestConfig(ctx, j.prebuiltTestProperties.Test_config, nil,
-		j.prebuiltTestProperties.Test_suites, nil)
+		j.prebuiltTestProperties.Test_suites, nil, nil)
 
 	j.Import.GenerateAndroidBuildActions(ctx)
 }
diff --git a/java/java_test.go b/java/java_test.go
index 845a03a..cf56e66 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -15,6 +15,7 @@
 package java
 
 import (
+	"fmt"
 	"io/ioutil"
 	"os"
 	"path/filepath"
@@ -202,7 +203,7 @@
 		}
 	`)
 
-	testJavaError(t, "Adjust sdk_version: property of the source or target module so that target module is built with the same or smaller API set than the source.", `
+	testJavaError(t, "consider adjusting sdk_version: OR platform_apis:", `
 		java_library {
 			name: "foo",
 			srcs: ["a.java"],
@@ -246,7 +247,7 @@
 		}
 	`)
 
-	testJavaError(t, "Adjust sdk_version: property of the source or target module so that target module is built with the same or smaller API set than the source.", `
+	testJavaError(t, "consider adjusting sdk_version: OR platform_apis:", `
 		java_library {
 			name: "foo",
 			srcs: ["a.java"],
@@ -622,6 +623,35 @@
 	}
 }
 
+func TestPrebuiltStubsSources(t *testing.T) {
+	test := func(t *testing.T, sourcesPath string, expectedInputs []string) {
+		ctx, _ := testJavaWithFS(t, fmt.Sprintf(`
+prebuilt_stubs_sources {
+  name: "stubs-source",
+	srcs: ["%s"],
+}`, sourcesPath), map[string][]byte{
+			"stubs/sources/pkg/A.java": nil,
+			"stubs/sources/pkg/B.java": nil,
+		})
+
+		zipSrc := ctx.ModuleForTests("stubs-source", "android_common").Rule("zip_src")
+		if expected, actual := expectedInputs, zipSrc.Inputs.Strings(); !reflect.DeepEqual(expected, actual) {
+			t.Errorf("mismatch of inputs to soong_zip: expected %q, actual %q", expected, actual)
+		}
+	}
+
+	t.Run("empty/missing directory", func(t *testing.T) {
+		test(t, "empty-directory", []string{})
+	})
+
+	t.Run("non-empty set of sources", func(t *testing.T) {
+		test(t, "stubs/sources", []string{
+			"stubs/sources/pkg/A.java",
+			"stubs/sources/pkg/B.java",
+		})
+	})
+}
+
 func TestJavaSdkLibraryImport(t *testing.T) {
 	ctx, _ := testJava(t, `
 		java_library {
diff --git a/java/kotlin_test.go b/java/kotlin_test.go
index 60ca1c4..77ef294 100644
--- a/java/kotlin_test.go
+++ b/java/kotlin_test.go
@@ -84,11 +84,14 @@
 }
 
 func TestKapt(t *testing.T) {
-	ctx, _ := testJava(t, `
+	bp := `
 		java_library {
 			name: "foo",
 			srcs: ["a.java", "b.kt"],
 			plugins: ["bar", "baz"],
+			errorprone: {
+				extra_check_modules: ["my_check"],
+			},
 		}
 
 		java_plugin {
@@ -102,64 +105,119 @@
 			processor_class: "com.baz",
 			srcs: ["b.java"],
 		}
-		`)
 
-	buildOS := android.BuildOs.String()
+		java_plugin {
+			name: "my_check",
+			srcs: ["b.java"],
+		}
+	`
+	t.Run("", func(t *testing.T) {
+		ctx, _ := testJava(t, bp)
 
-	kapt := ctx.ModuleForTests("foo", "android_common").Rule("kapt")
-	kotlinc := ctx.ModuleForTests("foo", "android_common").Rule("kotlinc")
-	javac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
+		buildOS := android.BuildOs.String()
 
-	bar := ctx.ModuleForTests("bar", buildOS+"_common").Rule("javac").Output.String()
-	baz := ctx.ModuleForTests("baz", buildOS+"_common").Rule("javac").Output.String()
+		kapt := ctx.ModuleForTests("foo", "android_common").Rule("kapt")
+		kotlinc := ctx.ModuleForTests("foo", "android_common").Rule("kotlinc")
+		javac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
 
-	// Test that the kotlin and java sources are passed to kapt and kotlinc
-	if len(kapt.Inputs) != 2 || kapt.Inputs[0].String() != "a.java" || kapt.Inputs[1].String() != "b.kt" {
-		t.Errorf(`foo kapt inputs %v != ["a.java", "b.kt"]`, kapt.Inputs)
-	}
-	if len(kotlinc.Inputs) != 2 || kotlinc.Inputs[0].String() != "a.java" || kotlinc.Inputs[1].String() != "b.kt" {
-		t.Errorf(`foo kotlinc inputs %v != ["a.java", "b.kt"]`, kotlinc.Inputs)
-	}
+		bar := ctx.ModuleForTests("bar", buildOS+"_common").Rule("javac").Output.String()
+		baz := ctx.ModuleForTests("baz", buildOS+"_common").Rule("javac").Output.String()
 
-	// Test that only the java sources are passed to javac
-	if len(javac.Inputs) != 1 || javac.Inputs[0].String() != "a.java" {
-		t.Errorf(`foo inputs %v != ["a.java"]`, javac.Inputs)
-	}
+		// Test that the kotlin and java sources are passed to kapt and kotlinc
+		if len(kapt.Inputs) != 2 || kapt.Inputs[0].String() != "a.java" || kapt.Inputs[1].String() != "b.kt" {
+			t.Errorf(`foo kapt inputs %v != ["a.java", "b.kt"]`, kapt.Inputs)
+		}
+		if len(kotlinc.Inputs) != 2 || kotlinc.Inputs[0].String() != "a.java" || kotlinc.Inputs[1].String() != "b.kt" {
+			t.Errorf(`foo kotlinc inputs %v != ["a.java", "b.kt"]`, kotlinc.Inputs)
+		}
 
-	// Test that the kapt srcjar is a dependency of kotlinc and javac rules
-	if !inList(kapt.Output.String(), kotlinc.Implicits.Strings()) {
-		t.Errorf("expected %q in kotlinc implicits %v", kapt.Output.String(), kotlinc.Implicits.Strings())
-	}
-	if !inList(kapt.Output.String(), javac.Implicits.Strings()) {
-		t.Errorf("expected %q in javac implicits %v", kapt.Output.String(), javac.Implicits.Strings())
-	}
+		// Test that only the java sources are passed to javac
+		if len(javac.Inputs) != 1 || javac.Inputs[0].String() != "a.java" {
+			t.Errorf(`foo inputs %v != ["a.java"]`, javac.Inputs)
+		}
 
-	// Test that the kapt srcjar is extracted by the kotlinc and javac rules
-	if kotlinc.Args["srcJars"] != kapt.Output.String() {
-		t.Errorf("expected %q in kotlinc srcjars %v", kapt.Output.String(), kotlinc.Args["srcJars"])
-	}
-	if javac.Args["srcJars"] != kapt.Output.String() {
-		t.Errorf("expected %q in javac srcjars %v", kapt.Output.String(), kotlinc.Args["srcJars"])
-	}
+		// Test that the kapt srcjar is a dependency of kotlinc and javac rules
+		if !inList(kapt.Output.String(), kotlinc.Implicits.Strings()) {
+			t.Errorf("expected %q in kotlinc implicits %v", kapt.Output.String(), kotlinc.Implicits.Strings())
+		}
+		if !inList(kapt.Output.String(), javac.Implicits.Strings()) {
+			t.Errorf("expected %q in javac implicits %v", kapt.Output.String(), javac.Implicits.Strings())
+		}
 
-	// Test that the processors are passed to kapt
-	expectedProcessorPath := "-P plugin:org.jetbrains.kotlin.kapt3:apclasspath=" + bar +
-		" -P plugin:org.jetbrains.kotlin.kapt3:apclasspath=" + baz
-	if kapt.Args["kaptProcessorPath"] != expectedProcessorPath {
-		t.Errorf("expected kaptProcessorPath %q, got %q", expectedProcessorPath, kapt.Args["kaptProcessorPath"])
-	}
-	expectedProcessor := "-P plugin:org.jetbrains.kotlin.kapt3:processors=com.bar -P plugin:org.jetbrains.kotlin.kapt3:processors=com.baz"
-	if kapt.Args["kaptProcessor"] != expectedProcessor {
-		t.Errorf("expected kaptProcessor %q, got %q", expectedProcessor, kapt.Args["kaptProcessor"])
-	}
+		// Test that the kapt srcjar is extracted by the kotlinc and javac rules
+		if kotlinc.Args["srcJars"] != kapt.Output.String() {
+			t.Errorf("expected %q in kotlinc srcjars %v", kapt.Output.String(), kotlinc.Args["srcJars"])
+		}
+		if javac.Args["srcJars"] != kapt.Output.String() {
+			t.Errorf("expected %q in javac srcjars %v", kapt.Output.String(), kotlinc.Args["srcJars"])
+		}
 
-	// Test that the processors are not passed to javac
-	if javac.Args["processorPath"] != "" {
-		t.Errorf("expected processorPath '', got %q", javac.Args["processorPath"])
-	}
-	if javac.Args["processor"] != "-proc:none" {
-		t.Errorf("expected processor '-proc:none', got %q", javac.Args["processor"])
-	}
+		// Test that the processors are passed to kapt
+		expectedProcessorPath := "-P plugin:org.jetbrains.kotlin.kapt3:apclasspath=" + bar +
+			" -P plugin:org.jetbrains.kotlin.kapt3:apclasspath=" + baz
+		if kapt.Args["kaptProcessorPath"] != expectedProcessorPath {
+			t.Errorf("expected kaptProcessorPath %q, got %q", expectedProcessorPath, kapt.Args["kaptProcessorPath"])
+		}
+		expectedProcessor := "-P plugin:org.jetbrains.kotlin.kapt3:processors=com.bar -P plugin:org.jetbrains.kotlin.kapt3:processors=com.baz"
+		if kapt.Args["kaptProcessor"] != expectedProcessor {
+			t.Errorf("expected kaptProcessor %q, got %q", expectedProcessor, kapt.Args["kaptProcessor"])
+		}
+
+		// Test that the processors are not passed to javac
+		if javac.Args["processorpath"] != "" {
+			t.Errorf("expected processorPath '', got %q", javac.Args["processorpath"])
+		}
+		if javac.Args["processor"] != "-proc:none" {
+			t.Errorf("expected processor '-proc:none', got %q", javac.Args["processor"])
+		}
+	})
+
+	t.Run("errorprone", func(t *testing.T) {
+		env := map[string]string{
+			"RUN_ERROR_PRONE": "true",
+		}
+		config := testConfig(env, bp, nil)
+		ctx, _ := testJavaWithConfig(t, config)
+
+		buildOS := android.BuildOs.String()
+
+		kapt := ctx.ModuleForTests("foo", "android_common").Rule("kapt")
+		//kotlinc := ctx.ModuleForTests("foo", "android_common").Rule("kotlinc")
+		javac := ctx.ModuleForTests("foo", "android_common").Description("javac")
+		errorprone := ctx.ModuleForTests("foo", "android_common").Description("errorprone")
+
+		bar := ctx.ModuleForTests("bar", buildOS+"_common").Description("javac").Output.String()
+		baz := ctx.ModuleForTests("baz", buildOS+"_common").Description("javac").Output.String()
+		myCheck := ctx.ModuleForTests("my_check", buildOS+"_common").Description("javac").Output.String()
+
+		// Test that the errorprone plugins are not passed to kapt
+		expectedProcessorPath := "-P plugin:org.jetbrains.kotlin.kapt3:apclasspath=" + bar +
+			" -P plugin:org.jetbrains.kotlin.kapt3:apclasspath=" + baz
+		if kapt.Args["kaptProcessorPath"] != expectedProcessorPath {
+			t.Errorf("expected kaptProcessorPath %q, got %q", expectedProcessorPath, kapt.Args["kaptProcessorPath"])
+		}
+		expectedProcessor := "-P plugin:org.jetbrains.kotlin.kapt3:processors=com.bar -P plugin:org.jetbrains.kotlin.kapt3:processors=com.baz"
+		if kapt.Args["kaptProcessor"] != expectedProcessor {
+			t.Errorf("expected kaptProcessor %q, got %q", expectedProcessor, kapt.Args["kaptProcessor"])
+		}
+
+		// Test that the errorprone plugins are not passed to javac
+		if javac.Args["processorpath"] != "" {
+			t.Errorf("expected processorPath '', got %q", javac.Args["processorpath"])
+		}
+		if javac.Args["processor"] != "-proc:none" {
+			t.Errorf("expected processor '-proc:none', got %q", javac.Args["processor"])
+		}
+
+		// Test that the errorprone plugins are passed to errorprone
+		expectedProcessorPath = "-processorpath " + myCheck
+		if errorprone.Args["processorpath"] != expectedProcessorPath {
+			t.Errorf("expected processorpath %q, got %q", expectedProcessorPath, errorprone.Args["processorpath"])
+		}
+		if errorprone.Args["processor"] != "-proc:none" {
+			t.Errorf("expected processor '-proc:none', got %q", errorprone.Args["processor"])
+		}
+	})
 }
 
 func TestKaptEncodeFlags(t *testing.T) {
diff --git a/java/sdk_library.go b/java/sdk_library.go
index a259822..9bb6ae8 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -2296,11 +2296,10 @@
 			scopeSet.AddProperty("jars", jars)
 
 			// Merge the stubs source jar into the snapshot zip so that when it is unpacked
-			// the source files are also unpacked. Use a glob so that if the directory is missing
-			// (because there are no stubs sources for this scope) it will not fail.
+			// the source files are also unpacked.
 			snapshotRelativeDir := filepath.Join(scopeDir, ctx.Name()+"_stub_sources")
 			ctx.SnapshotBuilder().UnzipToSnapshot(properties.StubsSrcJar, snapshotRelativeDir)
-			scopeSet.AddProperty("stub_srcs", []string{snapshotRelativeDir + "/**/*.java"})
+			scopeSet.AddProperty("stub_srcs", []string{snapshotRelativeDir})
 
 			if properties.CurrentApiFile != nil {
 				currentApiSnapshotPath := filepath.Join(scopeDir, ctx.Name()+".txt")
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index ec8ebb3..b44f66e 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -976,21 +976,21 @@
     shared_library: false,
     public: {
         jars: ["sdk_library/public/myjavalib-stubs.jar"],
-        stub_srcs: ["sdk_library/public/myjavalib_stub_sources/**/*.java"],
+        stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],
         current_api: "sdk_library/public/myjavalib.txt",
         removed_api: "sdk_library/public/myjavalib-removed.txt",
         sdk_version: "current",
     },
     system: {
         jars: ["sdk_library/system/myjavalib-stubs.jar"],
-        stub_srcs: ["sdk_library/system/myjavalib_stub_sources/**/*.java"],
+        stub_srcs: ["sdk_library/system/myjavalib_stub_sources"],
         current_api: "sdk_library/system/myjavalib.txt",
         removed_api: "sdk_library/system/myjavalib-removed.txt",
         sdk_version: "system_current",
     },
     test: {
         jars: ["sdk_library/test/myjavalib-stubs.jar"],
-        stub_srcs: ["sdk_library/test/myjavalib_stub_sources/**/*.java"],
+        stub_srcs: ["sdk_library/test/myjavalib_stub_sources"],
         current_api: "sdk_library/test/myjavalib.txt",
         removed_api: "sdk_library/test/myjavalib-removed.txt",
         sdk_version: "test_current",
@@ -1005,21 +1005,21 @@
     shared_library: false,
     public: {
         jars: ["sdk_library/public/myjavalib-stubs.jar"],
-        stub_srcs: ["sdk_library/public/myjavalib_stub_sources/**/*.java"],
+        stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],
         current_api: "sdk_library/public/myjavalib.txt",
         removed_api: "sdk_library/public/myjavalib-removed.txt",
         sdk_version: "current",
     },
     system: {
         jars: ["sdk_library/system/myjavalib-stubs.jar"],
-        stub_srcs: ["sdk_library/system/myjavalib_stub_sources/**/*.java"],
+        stub_srcs: ["sdk_library/system/myjavalib_stub_sources"],
         current_api: "sdk_library/system/myjavalib.txt",
         removed_api: "sdk_library/system/myjavalib-removed.txt",
         sdk_version: "system_current",
     },
     test: {
         jars: ["sdk_library/test/myjavalib-stubs.jar"],
-        stub_srcs: ["sdk_library/test/myjavalib_stub_sources/**/*.java"],
+        stub_srcs: ["sdk_library/test/myjavalib_stub_sources"],
         current_api: "sdk_library/test/myjavalib.txt",
         removed_api: "sdk_library/test/myjavalib-removed.txt",
         sdk_version: "test_current",
@@ -1077,7 +1077,7 @@
     shared_library: true,
     public: {
         jars: ["sdk_library/public/myjavalib-stubs.jar"],
-        stub_srcs: ["sdk_library/public/myjavalib_stub_sources/**/*.java"],
+        stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],
         current_api: "sdk_library/public/myjavalib.txt",
         removed_api: "sdk_library/public/myjavalib-removed.txt",
         sdk_version: "none",
@@ -1092,7 +1092,7 @@
     shared_library: true,
     public: {
         jars: ["sdk_library/public/myjavalib-stubs.jar"],
-        stub_srcs: ["sdk_library/public/myjavalib_stub_sources/**/*.java"],
+        stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],
         current_api: "sdk_library/public/myjavalib.txt",
         removed_api: "sdk_library/public/myjavalib-removed.txt",
         sdk_version: "none",
@@ -1146,7 +1146,7 @@
     shared_library: true,
     public: {
         jars: ["sdk_library/public/myjavalib-stubs.jar"],
-        stub_srcs: ["sdk_library/public/myjavalib_stub_sources/**/*.java"],
+        stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],
         current_api: "sdk_library/public/myjavalib.txt",
         removed_api: "sdk_library/public/myjavalib-removed.txt",
         sdk_version: "module_current",
@@ -1161,7 +1161,7 @@
     shared_library: true,
     public: {
         jars: ["sdk_library/public/myjavalib-stubs.jar"],
-        stub_srcs: ["sdk_library/public/myjavalib_stub_sources/**/*.java"],
+        stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],
         current_api: "sdk_library/public/myjavalib.txt",
         removed_api: "sdk_library/public/myjavalib-removed.txt",
         sdk_version: "module_current",
@@ -1218,14 +1218,14 @@
     shared_library: true,
     public: {
         jars: ["sdk_library/public/myjavalib-stubs.jar"],
-        stub_srcs: ["sdk_library/public/myjavalib_stub_sources/**/*.java"],
+        stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],
         current_api: "sdk_library/public/myjavalib.txt",
         removed_api: "sdk_library/public/myjavalib-removed.txt",
         sdk_version: "current",
     },
     system: {
         jars: ["sdk_library/system/myjavalib-stubs.jar"],
-        stub_srcs: ["sdk_library/system/myjavalib_stub_sources/**/*.java"],
+        stub_srcs: ["sdk_library/system/myjavalib_stub_sources"],
         current_api: "sdk_library/system/myjavalib.txt",
         removed_api: "sdk_library/system/myjavalib-removed.txt",
         sdk_version: "system_current",
@@ -1240,14 +1240,14 @@
     shared_library: true,
     public: {
         jars: ["sdk_library/public/myjavalib-stubs.jar"],
-        stub_srcs: ["sdk_library/public/myjavalib_stub_sources/**/*.java"],
+        stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],
         current_api: "sdk_library/public/myjavalib.txt",
         removed_api: "sdk_library/public/myjavalib-removed.txt",
         sdk_version: "current",
     },
     system: {
         jars: ["sdk_library/system/myjavalib-stubs.jar"],
-        stub_srcs: ["sdk_library/system/myjavalib_stub_sources/**/*.java"],
+        stub_srcs: ["sdk_library/system/myjavalib_stub_sources"],
         current_api: "sdk_library/system/myjavalib.txt",
         removed_api: "sdk_library/system/myjavalib-removed.txt",
         sdk_version: "system_current",
@@ -1311,21 +1311,21 @@
     shared_library: true,
     public: {
         jars: ["sdk_library/public/myjavalib-stubs.jar"],
-        stub_srcs: ["sdk_library/public/myjavalib_stub_sources/**/*.java"],
+        stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],
         current_api: "sdk_library/public/myjavalib.txt",
         removed_api: "sdk_library/public/myjavalib-removed.txt",
         sdk_version: "current",
     },
     system: {
         jars: ["sdk_library/system/myjavalib-stubs.jar"],
-        stub_srcs: ["sdk_library/system/myjavalib_stub_sources/**/*.java"],
+        stub_srcs: ["sdk_library/system/myjavalib_stub_sources"],
         current_api: "sdk_library/system/myjavalib.txt",
         removed_api: "sdk_library/system/myjavalib-removed.txt",
         sdk_version: "system_current",
     },
     module_lib: {
         jars: ["sdk_library/module-lib/myjavalib-stubs.jar"],
-        stub_srcs: ["sdk_library/module-lib/myjavalib_stub_sources/**/*.java"],
+        stub_srcs: ["sdk_library/module-lib/myjavalib_stub_sources"],
         current_api: "sdk_library/module-lib/myjavalib.txt",
         removed_api: "sdk_library/module-lib/myjavalib-removed.txt",
         sdk_version: "module_current",
@@ -1340,21 +1340,21 @@
     shared_library: true,
     public: {
         jars: ["sdk_library/public/myjavalib-stubs.jar"],
-        stub_srcs: ["sdk_library/public/myjavalib_stub_sources/**/*.java"],
+        stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],
         current_api: "sdk_library/public/myjavalib.txt",
         removed_api: "sdk_library/public/myjavalib-removed.txt",
         sdk_version: "current",
     },
     system: {
         jars: ["sdk_library/system/myjavalib-stubs.jar"],
-        stub_srcs: ["sdk_library/system/myjavalib_stub_sources/**/*.java"],
+        stub_srcs: ["sdk_library/system/myjavalib_stub_sources"],
         current_api: "sdk_library/system/myjavalib.txt",
         removed_api: "sdk_library/system/myjavalib-removed.txt",
         sdk_version: "system_current",
     },
     module_lib: {
         jars: ["sdk_library/module-lib/myjavalib-stubs.jar"],
-        stub_srcs: ["sdk_library/module-lib/myjavalib_stub_sources/**/*.java"],
+        stub_srcs: ["sdk_library/module-lib/myjavalib_stub_sources"],
         current_api: "sdk_library/module-lib/myjavalib.txt",
         removed_api: "sdk_library/module-lib/myjavalib-removed.txt",
         sdk_version: "module_current",
@@ -1419,14 +1419,14 @@
     shared_library: true,
     public: {
         jars: ["sdk_library/public/myjavalib-stubs.jar"],
-        stub_srcs: ["sdk_library/public/myjavalib_stub_sources/**/*.java"],
+        stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],
         current_api: "sdk_library/public/myjavalib.txt",
         removed_api: "sdk_library/public/myjavalib-removed.txt",
         sdk_version: "current",
     },
     system_server: {
         jars: ["sdk_library/system-server/myjavalib-stubs.jar"],
-        stub_srcs: ["sdk_library/system-server/myjavalib_stub_sources/**/*.java"],
+        stub_srcs: ["sdk_library/system-server/myjavalib_stub_sources"],
         current_api: "sdk_library/system-server/myjavalib.txt",
         removed_api: "sdk_library/system-server/myjavalib-removed.txt",
         sdk_version: "system_server_current",
@@ -1441,14 +1441,14 @@
     shared_library: true,
     public: {
         jars: ["sdk_library/public/myjavalib-stubs.jar"],
-        stub_srcs: ["sdk_library/public/myjavalib_stub_sources/**/*.java"],
+        stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],
         current_api: "sdk_library/public/myjavalib.txt",
         removed_api: "sdk_library/public/myjavalib-removed.txt",
         sdk_version: "current",
     },
     system_server: {
         jars: ["sdk_library/system-server/myjavalib-stubs.jar"],
-        stub_srcs: ["sdk_library/system-server/myjavalib_stub_sources/**/*.java"],
+        stub_srcs: ["sdk_library/system-server/myjavalib_stub_sources"],
         current_api: "sdk_library/system-server/myjavalib.txt",
         removed_api: "sdk_library/system-server/myjavalib-removed.txt",
         sdk_version: "system_server_current",
@@ -1508,7 +1508,7 @@
     shared_library: true,
     public: {
         jars: ["sdk_library/public/myjavalib-stubs.jar"],
-        stub_srcs: ["sdk_library/public/myjavalib_stub_sources/**/*.java"],
+        stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],
         current_api: "sdk_library/public/myjavalib.txt",
         removed_api: "sdk_library/public/myjavalib-removed.txt",
         sdk_version: "current",
@@ -1524,7 +1524,7 @@
     shared_library: true,
     public: {
         jars: ["sdk_library/public/myjavalib-stubs.jar"],
-        stub_srcs: ["sdk_library/public/myjavalib_stub_sources/**/*.java"],
+        stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],
         current_api: "sdk_library/public/myjavalib.txt",
         removed_api: "sdk_library/public/myjavalib-removed.txt",
         sdk_version: "current",
@@ -1584,7 +1584,7 @@
     doctag_files: ["doctags/docs/known_doctags"],
     public: {
         jars: ["sdk_library/public/myjavalib-stubs.jar"],
-        stub_srcs: ["sdk_library/public/myjavalib_stub_sources/**/*.java"],
+        stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],
         current_api: "sdk_library/public/myjavalib.txt",
         removed_api: "sdk_library/public/myjavalib-removed.txt",
         sdk_version: "current",
@@ -1600,7 +1600,7 @@
     doctag_files: ["doctags/docs/known_doctags"],
     public: {
         jars: ["sdk_library/public/myjavalib-stubs.jar"],
-        stub_srcs: ["sdk_library/public/myjavalib_stub_sources/**/*.java"],
+        stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],
         current_api: "sdk_library/public/myjavalib.txt",
         removed_api: "sdk_library/public/myjavalib-removed.txt",
         sdk_version: "current",
diff --git a/tradefed/autogen.go b/tradefed/autogen.go
index b35f831..27d71e8 100644
--- a/tradefed/autogen.go
+++ b/tradefed/autogen.go
@@ -188,7 +188,7 @@
 }
 
 func AutoGenJavaTestConfig(ctx android.ModuleContext, testConfigProp *string, testConfigTemplateProp *string,
-	testSuites []string, autoGenConfig *bool) android.Path {
+	testSuites []string, autoGenConfig *bool, unitTest *bool) android.Path {
 	path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp)
 	if autogenPath != nil {
 		templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
@@ -198,7 +198,11 @@
 			if ctx.Device() {
 				autogenTemplate(ctx, autogenPath, "${JavaTestConfigTemplate}", nil, "")
 			} else {
-				autogenTemplate(ctx, autogenPath, "${JavaHostTestConfigTemplate}", nil, "")
+				if Bool(unitTest) {
+					autogenTemplate(ctx, autogenPath, "${JavaHostUnitTestConfigTemplate}", nil, "")
+				} else {
+					autogenTemplate(ctx, autogenPath, "${JavaHostTestConfigTemplate}", nil, "")
+				}
 			}
 		}
 		return autogenPath
diff --git a/tradefed/config.go b/tradefed/config.go
index f7e8349..f3566a8 100644
--- a/tradefed/config.go
+++ b/tradefed/config.go
@@ -27,6 +27,7 @@
 	pctx.SourcePathVariable("InstrumentationTestConfigTemplate", "build/make/core/instrumentation_test_config_template.xml")
 	pctx.SourcePathVariable("JavaTestConfigTemplate", "build/make/core/java_test_config_template.xml")
 	pctx.SourcePathVariable("JavaHostTestConfigTemplate", "build/make/core/java_host_test_config_template.xml")
+	pctx.SourcePathVariable("JavaHostUnitTestConfigTemplate", "build/make/core/java_host_unit_test_config_template.xml")
 	pctx.SourcePathVariable("NativeBenchmarkTestConfigTemplate", "build/make/core/native_benchmark_test_config_template.xml")
 	pctx.SourcePathVariable("NativeHostTestConfigTemplate", "build/make/core/native_host_test_config_template.xml")
 	pctx.SourcePathVariable("NativeTestConfigTemplate", "build/make/core/native_test_config_template.xml")
diff --git a/ui/build/kati.go b/ui/build/kati.go
index f6c0f52..06ec646 100644
--- a/ui/build/kati.go
+++ b/ui/build/kati.go
@@ -33,12 +33,18 @@
 const katiCleanspecSuffix = "-cleanspec"
 const katiPackageSuffix = "-package"
 
-// genKatiSuffix creates a suffix for kati-generated files so that we can cache
-// them based on their inputs. So this should encode all common changes to Kati
-// inputs. Currently that includes the TARGET_PRODUCT, kati-processed command
-// line arguments, and the directories specified by mm/mmm.
+// genKatiSuffix creates a filename suffix for kati-generated files so that we
+// can cache them based on their inputs. Such files include the generated Ninja
+// files and env.sh environment variable setup files.
+//
+// The filename suffix should encode all common changes to Kati inputs.
+// Currently that includes the TARGET_PRODUCT and kati-processed command line
+// arguments.
 func genKatiSuffix(ctx Context, config Config) {
+	// Construct the base suffix.
 	katiSuffix := "-" + config.TargetProduct()
+
+	// Append kati arguments to the suffix.
 	if args := config.KatiArgs(); len(args) > 0 {
 		katiSuffix += "-" + spaceSlashReplacer.Replace(strings.Join(args, "_"))
 	}
@@ -60,51 +66,101 @@
 	}
 }
 
+// Base function to construct and run the Kati command line with additional
+// arguments, and a custom function closure to mutate the environment Kati runs
+// in.
 func runKati(ctx Context, config Config, extraSuffix string, args []string, envFunc func(*Environment)) {
 	executable := config.PrebuiltBuildTool("ckati")
+	// cKati arguments.
 	args = append([]string{
+		// Instead of executing commands directly, generate a Ninja file.
 		"--ninja",
+		// Generate Ninja files in the output directory.
 		"--ninja_dir=" + config.OutDir(),
+		// Filename suffix of the generated Ninja file.
 		"--ninja_suffix=" + config.KatiSuffix() + extraSuffix,
+		// Remove common parts at the beginning of a Ninja file, like build_dir,
+		// local_pool and _kati_always_build_. Allows Kati to be run multiple
+		// times, with generated Ninja files combined in a single invocation
+		// using 'include'.
 		"--no_ninja_prelude",
+		// Support declaring phony outputs in AOSP Ninja.
 		"--use_ninja_phony_output",
+		// Support declaring symlink outputs in AOSP Ninja.
 		"--use_ninja_symlink_outputs",
+		// Regenerate the Ninja file if environment inputs have changed. e.g.
+		// CLI flags, .mk file timestamps, env vars, $(wildcard ..) and some
+		// $(shell ..) results.
 		"--regen",
+		// Skip '-include' directives starting with the specified path. Used to
+		// ignore generated .mk files.
 		"--ignore_optional_include=" + filepath.Join(config.OutDir(), "%.P"),
+		// Detect the use of $(shell echo ...).
 		"--detect_android_echo",
+		// Colorful ANSI-based warning and error messages.
 		"--color_warnings",
+		// Generate all targets, not just the top level requested ones.
 		"--gen_all_targets",
+		// Use the built-in emulator of GNU find for better file finding
+		// performance. Used with $(shell find ...).
 		"--use_find_emulator",
+		// Fail when the find emulator encounters problems.
 		"--werror_find_emulator",
+		// Do not provide any built-in rules.
 		"--no_builtin_rules",
+		// Fail when suffix rules are used.
 		"--werror_suffix_rules",
-		"--warn_real_to_phony",
-		"--warn_phony_looks_real",
+		// Fail when a real target depends on a phony target.
 		"--werror_real_to_phony",
-		"--werror_phony_looks_real",
-		"--werror_writable",
+		// Makes real_to_phony checks assume that any top-level or leaf
+		// dependencies that does *not* have a '/' in it is a phony target.
 		"--top_level_phony",
+		// Fail when a phony target contains slashes.
+		"--werror_phony_looks_real",
+		// Fail when writing to a read-only directory.
+		"--werror_writable",
+		// Print Kati's internal statistics, such as the number of variables,
+		// implicit/explicit/suffix rules, and so on.
 		"--kati_stats",
 	}, args...)
 
+	// Generate a minimal Ninja file.
+	//
+	// Used for build_test and multiproduct_kati, which runs Kati several
+	// hundred times for different configurations to test file generation logic.
+	// These can result in generating Ninja files reaching ~1GB or more,
+	// resulting in ~hundreds of GBs of writes.
+	//
+	// Since we don't care about executing the Ninja files in these test cases,
+	// generating the Ninja file content wastes time, so skip writing any
+	// information out with --empty_ninja_file.
+	//
+	// From https://github.com/google/kati/commit/87b8da7af2c8bea28b1d8ab17679453d859f96e5
 	if config.Environment().IsEnvTrue("EMPTY_NINJA_FILE") {
 		args = append(args, "--empty_ninja_file")
 	}
 
+	// Apply 'local_pool' to to all rules that don't specify a pool.
 	if config.UseRemoteBuild() {
 		args = append(args, "--default_pool=local_pool")
 	}
 
 	cmd := Command(ctx, config, "ckati", executable, args...)
+
+	// Set up the nsjail sandbox.
 	cmd.Sandbox = katiSandbox
+
+	// Set up stdout and stderr.
 	pipe, err := cmd.StdoutPipe()
 	if err != nil {
 		ctx.Fatalln("Error getting output pipe for ckati:", err)
 	}
 	cmd.Stderr = cmd.Stdout
 
+	// Apply the caller's function closure to mutate the environment variables.
 	envFunc(cmd.Environment)
 
+	// Pass on various build environment metadata to Kati.
 	if _, ok := cmd.Environment.Get("BUILD_USERNAME"); !ok {
 		username := "unknown"
 		if u, err := user.Current(); err == nil {
@@ -125,6 +181,8 @@
 	}
 
 	cmd.StartOrFatal()
+	// Set up the ToolStatus command line reader for Kati for a consistent UI
+	// for the user.
 	status.KatiReader(ctx.Status.StartTool(), pipe)
 	cmd.WaitOrFatal()
 }
@@ -134,35 +192,57 @@
 	defer ctx.EndTrace()
 
 	args := []string{
+		// Mark the output directory as writable.
 		"--writable", config.OutDir() + "/",
+		// Fail when encountering implicit rules. e.g.
+		// %.foo: %.bar
+		//   cp $< $@
 		"--werror_implicit_rules",
+		// Entry point for the Kati Ninja file generation.
 		"-f", "build/make/core/main.mk",
 	}
 
 	if !config.BuildBrokenDupRules() {
+		// Fail when redefining / duplicating a target.
 		args = append(args, "--werror_overriding_commands")
 	}
 
 	args = append(args, config.KatiArgs()...)
 
 	args = append(args,
+		// Location of the Make vars .mk file generated by Soong.
 		"SOONG_MAKEVARS_MK="+config.SoongMakeVarsMk(),
+		// Location of the Android.mk file generated by Soong. This
+		// file contains Soong modules represented as Kati modules,
+		// allowing Kati modules to depend on Soong modules.
 		"SOONG_ANDROID_MK="+config.SoongAndroidMk(),
+		// Directory containing outputs for the target device.
 		"TARGET_DEVICE_DIR="+config.TargetDeviceDir(),
+		// Directory containing .mk files for packaging purposes, such as
+		// the dist.mk file, containing dist-for-goals data.
 		"KATI_PACKAGE_MK_DIR="+config.KatiPackageMkDir())
 
 	runKati(ctx, config, katiBuildSuffix, args, func(env *Environment) {})
 
+	// compress and dist the main build ninja file.
 	distGzipFile(ctx, config, config.KatiBuildNinjaFile())
 
+	// Cleanup steps.
 	cleanCopyHeaders(ctx, config)
 	cleanOldInstalledFiles(ctx, config)
 }
 
+// Clean out obsolete header files on the disk that were *not copied* during the
+// build with BUILD_COPY_HEADERS and LOCAL_COPY_HEADERS.
+//
+// These should be increasingly uncommon, as it's a deprecated feature and there
+// isn't an equivalent feature in Soong.
 func cleanCopyHeaders(ctx Context, config Config) {
 	ctx.BeginTrace("clean", "clean copy headers")
 	defer ctx.EndTrace()
 
+	// Read and parse the list of copied headers from a file in the product
+	// output directory.
 	data, err := ioutil.ReadFile(filepath.Join(config.ProductOut(), ".copied_headers_list"))
 	if err != nil {
 		if os.IsNotExist(err) {
@@ -178,6 +258,8 @@
 	headerDir := headers[0]
 	headers = headers[1:]
 
+	// Walk the tree and remove any headers that are not in the list of copied
+	// headers in the current build.
 	filepath.Walk(headerDir,
 		func(path string, info os.FileInfo, err error) error {
 			if err != nil {
@@ -196,6 +278,8 @@
 		})
 }
 
+// Clean out any previously installed files from the disk that are not installed
+// in the current build.
 func cleanOldInstalledFiles(ctx Context, config Config) {
 	ctx.BeginTrace("clean", "clean old installed files")
 	defer ctx.EndTrace()
@@ -213,18 +297,27 @@
 	cleanOldFiles(ctx, config.HostOut(), ".installable_test_files")
 }
 
+// Generate the Ninja file containing the packaging command lines for the dist
+// dir.
 func runKatiPackage(ctx Context, config Config) {
 	ctx.BeginTrace(metrics.RunKati, "kati package")
 	defer ctx.EndTrace()
 
 	args := []string{
+		// Mark the dist dir as writable.
 		"--writable", config.DistDir() + "/",
+		// Fail when encountering implicit rules. e.g.
 		"--werror_implicit_rules",
+		// Fail when redefining / duplicating a target.
 		"--werror_overriding_commands",
+		// Entry point.
 		"-f", "build/make/packaging/main.mk",
+		// Directory containing .mk files for packaging purposes, such as
+		// the dist.mk file, containing dist-for-goals data.
 		"KATI_PACKAGE_MK_DIR=" + config.KatiPackageMkDir(),
 	}
 
+	// Run Kati against a restricted set of environment variables.
 	runKati(ctx, config, katiPackageSuffix, args, func(env *Environment) {
 		env.Allow([]string{
 			// Some generic basics
@@ -251,16 +344,21 @@
 		}
 	})
 
+	// Compress and dist the packaging Ninja file.
 	distGzipFile(ctx, config, config.KatiPackageNinjaFile())
 }
 
+// Run Kati on the cleanspec files to clean the build.
 func runKatiCleanSpec(ctx Context, config Config) {
 	ctx.BeginTrace(metrics.RunKati, "kati cleanspec")
 	defer ctx.EndTrace()
 
 	runKati(ctx, config, katiCleanspecSuffix, []string{
+		// Fail when encountering implicit rules. e.g.
 		"--werror_implicit_rules",
+		// Fail when redefining / duplicating a target.
 		"--werror_overriding_commands",
+		// Entry point.
 		"-f", "build/make/core/cleanbuild.mk",
 		"SOONG_MAKEVARS_MK=" + config.SoongMakeVarsMk(),
 		"TARGET_DEVICE_DIR=" + config.TargetDeviceDir(),
diff --git a/ui/build/path.go b/ui/build/path.go
index 6f5cf78..86e61c0 100644
--- a/ui/build/path.go
+++ b/ui/build/path.go
@@ -29,6 +29,9 @@
 	"android/soong/ui/metrics"
 )
 
+// parsePathDir returns the list of filenames of readable files in a directory.
+// This does not recurse into subdirectories, and does not contain subdirectory
+// names in the list.
 func parsePathDir(dir string) []string {
 	f, err := os.Open(dir)
 	if err != nil {
@@ -54,10 +57,12 @@
 	return ret
 }
 
-// A "lite" version of SetupPath used for dumpvars, or other places that need
-// minimal overhead (but at the expense of logging). If tmpDir is empty, the
-// default TMPDIR is used from config.
+// SetupLitePath is the "lite" version of SetupPath used for dumpvars, or other
+// places that does not need the full logging capabilities of path_interposer,
+// wants the minimal performance overhead, and still get the benefits of $PATH
+// hermeticity.
 func SetupLitePath(ctx Context, config Config, tmpDir string) {
+	// Don't replace the path twice.
 	if config.pathReplaced {
 		return
 	}
@@ -67,6 +72,7 @@
 
 	origPath, _ := config.Environment().Get("PATH")
 
+	// If tmpDir is empty, the default TMPDIR is used from config.
 	if tmpDir == "" {
 		tmpDir, _ = config.Environment().Get("TMPDIR")
 	}
@@ -74,8 +80,10 @@
 	ensureEmptyDirectoriesExist(ctx, myPath)
 
 	os.Setenv("PATH", origPath)
+	// Iterate over the ACL configuration of host tools for this build.
 	for name, pathConfig := range paths.Configuration {
 		if !pathConfig.Symlink {
+			// Excludes 'Forbidden' and 'LinuxOnlyPrebuilt' PathConfigs.
 			continue
 		}
 
@@ -88,6 +96,7 @@
 			continue
 		}
 
+		// Symlink allowed host tools into a directory for hermeticity.
 		err = os.Symlink(origExec, filepath.Join(myPath, name))
 		if err != nil {
 			ctx.Fatalln("Failed to create symlink:", err)
@@ -96,14 +105,26 @@
 
 	myPath, _ = filepath.Abs(myPath)
 
+	// Set up the checked-in prebuilts path directory for the current host OS.
 	prebuiltsPath, _ := filepath.Abs("prebuilts/build-tools/path/" + runtime.GOOS + "-x86")
 	myPath = prebuiltsPath + string(os.PathListSeparator) + myPath
 
+	// Set $PATH to be the directories containing the host tool symlinks, and
+	// the prebuilts directory for the current host OS.
 	config.Environment().Set("PATH", myPath)
 	config.pathReplaced = true
 }
 
+// SetupPath uses the path_interposer to intercept calls to $PATH binaries, and
+// communicates with the interposer to validate allowed $PATH binaries at
+// runtime, using logs as a medium.
+//
+// This results in hermetic directories in $PATH containing only allowed host
+// tools for the build, and replaces $PATH to contain *only* these directories,
+// and enables an incremental restriction of tools allowed in the $PATH without
+// breaking existing use cases.
 func SetupPath(ctx Context, config Config) {
+	// Don't replace $PATH twice.
 	if config.pathReplaced {
 		return
 	}
@@ -112,9 +133,11 @@
 	defer ctx.EndTrace()
 
 	origPath, _ := config.Environment().Get("PATH")
+	// The directory containing symlinks from binaries in $PATH to the interposer.
 	myPath := filepath.Join(config.OutDir(), ".path")
 	interposer := myPath + "_interposer"
 
+	// Bootstrap the path_interposer Go binary with microfactory.
 	var cfg microfactory.Config
 	cfg.Map("android/soong", "build/soong")
 	cfg.TrimPath, _ = filepath.Abs(".")
@@ -122,15 +145,20 @@
 		ctx.Fatalln("Failed to build path interposer:", err)
 	}
 
+	// Save the original $PATH in a file.
 	if err := ioutil.WriteFile(interposer+"_origpath", []byte(origPath), 0777); err != nil {
 		ctx.Fatalln("Failed to write original path:", err)
 	}
 
+	// Communication with the path interposer works over log entries. Set up the
+	// listener channel for the log entries here.
 	entries, err := paths.LogListener(ctx.Context, interposer+"_log")
 	if err != nil {
 		ctx.Fatalln("Failed to listen for path logs:", err)
 	}
 
+	// Loop over all log entry listener channels to validate usage of only
+	// allowed PATH tools at runtime.
 	go func() {
 		for log := range entries {
 			curPid := os.Getpid()
@@ -140,6 +168,8 @@
 					break
 				}
 			}
+			// Compute the error message along with the process tree, including
+			// parents, for this log line.
 			procPrints := []string{
 				"See https://android.googlesource.com/platform/build/+/master/Changes.md#PATH_Tools for more information.",
 			}
@@ -150,6 +180,7 @@
 				}
 			}
 
+			// Validate usage against disallowed or missing PATH tools.
 			config := paths.GetConfig(log.Basename)
 			if config.Error {
 				ctx.Printf("Disallowed PATH tool %q used: %#v", log.Basename, log.Args)
@@ -165,8 +196,10 @@
 		}
 	}()
 
+	// Create the .path directory.
 	ensureEmptyDirectoriesExist(ctx, myPath)
 
+	// Compute the full list of binaries available in the original $PATH.
 	var execs []string
 	for _, pathEntry := range filepath.SplitList(origPath) {
 		if pathEntry == "" {
@@ -185,8 +218,14 @@
 		ctx.Fatalln("TEMPORARY_DISABLE_PATH_RESTRICTIONS was a temporary migration method, and is now obsolete.")
 	}
 
+	// Create symlinks from the path_interposer binary to all binaries for each
+	// directory in the original $PATH. This ensures that during the build,
+	// every call to a binary that's expected to be in the $PATH will be
+	// intercepted by the path_interposer binary, and validated with the
+	// LogEntry listener above at build time.
 	for _, name := range execs {
 		if !paths.GetConfig(name).Symlink {
+			// Ignore host tools that shouldn't be symlinked.
 			continue
 		}
 
@@ -200,11 +239,13 @@
 
 	myPath, _ = filepath.Abs(myPath)
 
-	// We put some prebuilts in $PATH, since it's infeasible to add dependencies for all of
-	// them.
+	// We put some prebuilts in $PATH, since it's infeasible to add dependencies
+	// for all of them.
 	prebuiltsPath, _ := filepath.Abs("prebuilts/build-tools/path/" + runtime.GOOS + "-x86")
 	myPath = prebuiltsPath + string(os.PathListSeparator) + myPath
 
+	// Replace the $PATH variable with the path_interposer symlinks, and
+	// checked-in prebuilts.
 	config.Environment().Set("PATH", myPath)
 	config.pathReplaced = true
 }