Merge "have a per-module switch to turn the symlinking optimizaiton off"
diff --git a/Android.bp b/Android.bp
index f425c3f..2a4653a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -204,6 +204,7 @@
         "cc/linker.go",
 
         "cc/binary.go",
+        "cc/binary_sdk_member.go",
         "cc/fuzz.go",
         "cc/library.go",
         "cc/library_sdk_member.go",
diff --git a/android/apex.go b/android/apex.go
index 17ec9b1..43a42df 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -19,6 +19,14 @@
 	"sync"
 )
 
+type ApexInfo struct {
+	// Name of the apex variant that this module is mutated into
+	ApexName string
+
+	// Whether this apex variant needs to target Android 10
+	LegacyAndroid10Support bool
+}
+
 // ApexModule is the interface that a module type is expected to implement if
 // the module has to be built differently depending on whether the module
 // is destined for an apex or not (installed to one of the regular partitions).
@@ -38,12 +46,12 @@
 	Module
 	apexModuleBase() *ApexModuleBase
 
-	// Marks that this module should be built for the APEXes of the specified names.
+	// Marks that this module should be built for the specified APEXes.
 	// Call this before apex.apexMutator is run.
-	BuildForApexes(apexNames []string)
+	BuildForApexes(apexes []ApexInfo)
 
-	// Returns the name of the APEXes that this modoule will be built for
-	ApexVariations() []string
+	// Returns the APEXes that this module will be built for
+	ApexVariations() []ApexInfo
 
 	// Returns the name of APEX that this module will be built for. Empty string
 	// is returned when 'IsForPlatform() == true'. Note that a module can be
@@ -72,10 +80,6 @@
 	// for an APEX marked via BuildForApexes().
 	CreateApexVariations(mctx BottomUpMutatorContext) []Module
 
-	// Sets the name of the apex variant of this module. Called inside
-	// CreateApexVariations.
-	setApexName(apexName string)
-
 	// Tests if this module is available for the specified APEX or ":platform"
 	AvailableFor(what string) bool
 
@@ -94,8 +98,7 @@
 	// Default is ["//apex_available:platform"].
 	Apex_available []string
 
-	// Name of the apex variant that this module is mutated into
-	ApexName string `blueprint:"mutated"`
+	Info ApexInfo `blueprint:"mutated"`
 }
 
 // Provides default implementation for the ApexModule interface. APEX-aware
@@ -106,37 +109,37 @@
 	canHaveApexVariants bool
 
 	apexVariationsLock sync.Mutex // protects apexVariations during parallel apexDepsMutator
-	apexVariations     []string
+	apexVariations     []ApexInfo
 }
 
 func (m *ApexModuleBase) apexModuleBase() *ApexModuleBase {
 	return m
 }
 
-func (m *ApexModuleBase) BuildForApexes(apexNames []string) {
+func (m *ApexModuleBase) BuildForApexes(apexes []ApexInfo) {
 	m.apexVariationsLock.Lock()
 	defer m.apexVariationsLock.Unlock()
-	for _, apexName := range apexNames {
-		if !InList(apexName, m.apexVariations) {
-			m.apexVariations = append(m.apexVariations, apexName)
+nextApex:
+	for _, apex := range apexes {
+		for _, v := range m.apexVariations {
+			if v.ApexName == apex.ApexName {
+				continue nextApex
+			}
 		}
+		m.apexVariations = append(m.apexVariations, apex)
 	}
 }
 
-func (m *ApexModuleBase) ApexVariations() []string {
+func (m *ApexModuleBase) ApexVariations() []ApexInfo {
 	return m.apexVariations
 }
 
 func (m *ApexModuleBase) ApexName() string {
-	return m.ApexProperties.ApexName
+	return m.ApexProperties.Info.ApexName
 }
 
 func (m *ApexModuleBase) IsForPlatform() bool {
-	return m.ApexProperties.ApexName == ""
-}
-
-func (m *ApexModuleBase) setApexName(apexName string) {
-	m.ApexProperties.ApexName = apexName
+	return m.ApexProperties.Info.ApexName == ""
 }
 
 func (m *ApexModuleBase) CanHaveApexVariants() bool {
@@ -185,25 +188,35 @@
 	}
 }
 
+type byApexName []ApexInfo
+
+func (a byApexName) Len() int           { return len(a) }
+func (a byApexName) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
+func (a byApexName) Less(i, j int) bool { return a[i].ApexName < a[j].ApexName }
+
 func (m *ApexModuleBase) CreateApexVariations(mctx BottomUpMutatorContext) []Module {
 	if len(m.apexVariations) > 0 {
 		m.checkApexAvailableProperty(mctx)
 
-		sort.Strings(m.apexVariations)
+		sort.Sort(byApexName(m.apexVariations))
 		variations := []string{}
 		variations = append(variations, "") // Original variation for platform
-		variations = append(variations, m.apexVariations...)
+		for _, apex := range m.apexVariations {
+			variations = append(variations, apex.ApexName)
+		}
 
 		defaultVariation := ""
 		mctx.SetDefaultDependencyVariation(&defaultVariation)
 
 		modules := mctx.CreateVariations(variations...)
-		for i, m := range modules {
+		for i, mod := range modules {
 			platformVariation := i == 0
-			if platformVariation && !mctx.Host() && !m.(ApexModule).AvailableFor(AvailableToPlatform) {
-				m.SkipInstall()
+			if platformVariation && !mctx.Host() && !mod.(ApexModule).AvailableFor(AvailableToPlatform) {
+				mod.SkipInstall()
 			}
-			m.(ApexModule).setApexName(variations[i])
+			if !platformVariation {
+				mod.(ApexModule).apexModuleBase().ApexProperties.Info = m.apexVariations[i-1]
+			}
 		}
 		return modules
 	}
@@ -230,16 +243,16 @@
 // depended on by the specified APEXes. Directly depending means that a module
 // is explicitly listed in the build definition of the APEX via properties like
 // native_shared_libs, java_libs, etc.
-func UpdateApexDependency(apexNames []string, moduleName string, directDep bool) {
+func UpdateApexDependency(apexes []ApexInfo, moduleName string, directDep bool) {
 	apexNamesMapMutex.Lock()
 	defer apexNamesMapMutex.Unlock()
-	for _, apexName := range apexNames {
+	for _, apex := range apexes {
 		apexesForModule, ok := apexNamesMap()[moduleName]
 		if !ok {
 			apexesForModule = make(map[string]bool)
 			apexNamesMap()[moduleName] = apexesForModule
 		}
-		apexesForModule[apexName] = apexesForModule[apexName] || directDep
+		apexesForModule[apex.ApexName] = apexesForModule[apex.ApexName] || directDep
 	}
 }
 
diff --git a/android/arch.go b/android/arch.go
index fb1accc..73a490d 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -1521,12 +1521,7 @@
 
 // hasArmAbi returns true if arch has at least one arm ABI
 func hasArmAbi(arch Arch) bool {
-	for _, abi := range arch.Abi {
-		if strings.HasPrefix(abi, "arm") {
-			return true
-		}
-	}
-	return false
+	return PrefixInList(arch.Abi, "arm")
 }
 
 // hasArmArch returns true if targets has at least non-native_bridge arm Android arch
diff --git a/android/config.go b/android/config.go
index 9cf9662..1fe6f05 100644
--- a/android/config.go
+++ b/android/config.go
@@ -890,11 +890,7 @@
 func (c *config) EnforceRROExcludedOverlay(path string) bool {
 	excluded := c.productVariables.EnforceRROExcludedOverlays
 	if excluded != nil {
-		for _, exclude := range excluded {
-			if strings.HasPrefix(path, exclude) {
-				return true
-			}
-		}
+		return HasAnyPrefix(path, excluded)
 	}
 	return false
 }
@@ -1050,12 +1046,12 @@
 func (c *deviceConfig) CoverageEnabledForPath(path string) bool {
 	coverage := false
 	if c.config.productVariables.CoveragePaths != nil {
-		if InList("*", c.config.productVariables.CoveragePaths) || PrefixInList(path, c.config.productVariables.CoveragePaths) {
+		if InList("*", c.config.productVariables.CoveragePaths) || HasAnyPrefix(path, c.config.productVariables.CoveragePaths) {
 			coverage = true
 		}
 	}
 	if coverage && c.config.productVariables.CoverageExcludePaths != nil {
-		if PrefixInList(path, c.config.productVariables.CoverageExcludePaths) {
+		if HasAnyPrefix(path, c.config.productVariables.CoverageExcludePaths) {
 			coverage = false
 		}
 	}
@@ -1128,21 +1124,21 @@
 	if c.productVariables.IntegerOverflowExcludePaths == nil {
 		return false
 	}
-	return PrefixInList(path, c.productVariables.IntegerOverflowExcludePaths)
+	return HasAnyPrefix(path, c.productVariables.IntegerOverflowExcludePaths)
 }
 
 func (c *config) CFIDisabledForPath(path string) bool {
 	if c.productVariables.CFIExcludePaths == nil {
 		return false
 	}
-	return PrefixInList(path, c.productVariables.CFIExcludePaths)
+	return HasAnyPrefix(path, c.productVariables.CFIExcludePaths)
 }
 
 func (c *config) CFIEnabledForPath(path string) bool {
 	if c.productVariables.CFIIncludePaths == nil {
 		return false
 	}
-	return PrefixInList(path, c.productVariables.CFIIncludePaths)
+	return HasAnyPrefix(path, c.productVariables.CFIIncludePaths)
 }
 
 func (c *config) VendorConfig(name string) VendorConfig {
diff --git a/android/neverallow.go b/android/neverallow.go
index 48581df..0cb2029 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -407,8 +407,8 @@
 }
 
 func (r *rule) appliesToPath(dir string) bool {
-	includePath := len(r.paths) == 0 || hasAnyPrefix(dir, r.paths)
-	excludePath := hasAnyPrefix(dir, r.unlessPaths)
+	includePath := len(r.paths) == 0 || HasAnyPrefix(dir, r.paths)
+	excludePath := HasAnyPrefix(dir, r.unlessPaths)
 	return includePath && !excludePath
 }
 
@@ -474,15 +474,6 @@
 	return names
 }
 
-func hasAnyPrefix(s string, prefixes []string) bool {
-	for _, prefix := range prefixes {
-		if strings.HasPrefix(s, prefix) {
-			return true
-		}
-	}
-	return false
-}
-
 func hasAnyProperty(properties []interface{}, props []ruleProperty) bool {
 	for _, v := range props {
 		if hasProperty(properties, v) {
diff --git a/android/util.go b/android/util.go
index e985fc1..ade851e 100644
--- a/android/util.go
+++ b/android/util.go
@@ -122,7 +122,7 @@
 }
 
 // Returns true if the given string s is prefixed with any string in the given prefix list.
-func PrefixInList(s string, prefixList []string) bool {
+func HasAnyPrefix(s string, prefixList []string) bool {
 	for _, prefix := range prefixList {
 		if strings.HasPrefix(s, prefix) {
 			return true
@@ -132,7 +132,7 @@
 }
 
 // Returns true if any string in the given list has the given prefix.
-func PrefixedStringInList(list []string, prefix string) bool {
+func PrefixInList(list []string, prefix string) bool {
 	for _, s := range list {
 		if strings.HasPrefix(s, prefix) {
 			return true
diff --git a/android/util_test.go b/android/util_test.go
index 90fefee..1f9ca36 100644
--- a/android/util_test.go
+++ b/android/util_test.go
@@ -252,7 +252,7 @@
 
 	for _, testCase := range testcases {
 		t.Run(testCase.str, func(t *testing.T) {
-			out := PrefixInList(testCase.str, prefixes)
+			out := HasAnyPrefix(testCase.str, prefixes)
 			if out != testCase.expected {
 				t.Errorf("incorrect output:")
 				t.Errorf("       str: %#v", testCase.str)
diff --git a/android/vts_config.go b/android/vts_config.go
index 86f6e72..9a1df7c 100644
--- a/android/vts_config.go
+++ b/android/vts_config.go
@@ -17,6 +17,7 @@
 import (
 	"fmt"
 	"io"
+	"strings"
 )
 
 func init() {
@@ -26,6 +27,8 @@
 type vtsConfigProperties struct {
 	// Override the default (AndroidTest.xml) test manifest file name.
 	Test_config *string
+	// Additional test suites to add the test to.
+	Test_suites []string `android:"arch_variant"`
 }
 
 type VtsConfig struct {
@@ -50,7 +53,8 @@
 				fmt.Fprintf(w, "LOCAL_TEST_CONFIG := %s\n",
 					*me.properties.Test_config)
 			}
-			fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE := vts")
+			fmt.Fprintf(w, "LOCAL_COMPATIBILITY_SUITE := vts %s\n",
+				strings.Join(me.properties.Test_suites, " "))
 		},
 	}
 	return androidMkData
diff --git a/apex/apex.go b/apex/apex.go
index c5e0920..79fdb71 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -1024,17 +1024,17 @@
 // Mark the direct and transitive dependencies of apex bundles so that they
 // can be built for the apex bundles.
 func apexDepsMutator(mctx android.TopDownMutatorContext) {
-	var apexBundleNames []string
+	var apexBundles []android.ApexInfo
 	var directDep bool
 	if a, ok := mctx.Module().(*apexBundle); ok && !a.vndkApex {
-		apexBundleNames = []string{mctx.ModuleName()}
+		apexBundles = []android.ApexInfo{{mctx.ModuleName(), proptools.Bool(a.properties.Legacy_android10_support)}}
 		directDep = true
 	} else if am, ok := mctx.Module().(android.ApexModule); ok {
-		apexBundleNames = am.ApexVariations()
+		apexBundles = am.ApexVariations()
 		directDep = false
 	}
 
-	if len(apexBundleNames) == 0 {
+	if len(apexBundles) == 0 {
 		return
 	}
 
@@ -1042,8 +1042,8 @@
 		depName := mctx.OtherModuleName(child)
 		if am, ok := child.(android.ApexModule); ok && am.CanHaveApexVariants() &&
 			(directDep || am.DepIsInSameApex(mctx, child)) {
-			android.UpdateApexDependency(apexBundleNames, depName, directDep)
-			am.BuildForApexes(apexBundleNames)
+			android.UpdateApexDependency(apexBundles, depName, directDep)
+			am.BuildForApexes(apexBundles)
 		}
 	})
 }
@@ -2116,13 +2116,6 @@
 						return false
 					}
 					filesInfo = append(filesInfo, af)
-
-					pf := sdkLib.XmlPermissionsFile()
-					if pf == nil {
-						ctx.PropertyErrorf("java_libs", "%q failed to generate permission XML", depName)
-						return false
-					}
-					filesInfo = append(filesInfo, newApexFile(ctx, pf, pf.Base(), "etc/permissions", etc, nil))
 					return true // track transitive dependencies
 				} else {
 					ctx.PropertyErrorf("java_libs", "%q of type %q is not supported", depName, ctx.OtherModuleType(child))
@@ -2235,6 +2228,10 @@
 					}
 				} else if java.IsJniDepTag(depTag) {
 					return true
+				} else if java.IsXmlPermissionsFileDepTag(depTag) {
+					if prebuilt, ok := child.(android.PrebuiltEtcModule); ok {
+						filesInfo = append(filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, depName))
+					}
 				} else if am.CanHaveApexVariants() && am.IsInstallableToApex() {
 					ctx.ModuleErrorf("unexpected tag %q for indirect dependency %q", depTag, depName)
 				}
diff --git a/apex/apex_test.go b/apex/apex_test.go
index e41b6d5..e5847ab 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -3438,6 +3438,7 @@
 		apex {
 			name: "myapex",
 			key: "myapex.key",
+			native_shared_libs: ["mylib"],
 			legacy_android10_support: true,
 		}
 
@@ -3446,12 +3447,54 @@
 			public_key: "testkey.avbpubkey",
 			private_key: "testkey.pem",
 		}
-	`)
+
+		cc_library {
+			name: "mylib",
+			srcs: ["mylib.cpp"],
+			stl: "libc++",
+			system_shared_libs: [],
+			apex_available: [ "myapex" ],
+		}
+
+		cc_library {
+			name: "libc++",
+			srcs: ["mylib.cpp"],
+			stl: "none",
+			system_shared_libs: [],
+			apex_available: [ "myapex" ],
+		}
+
+		cc_library_static {
+			name: "libc++demangle",
+			srcs: ["mylib.cpp"],
+			stl: "none",
+			system_shared_libs: [],
+		}
+
+		cc_library_static {
+			name: "libunwind_llvm",
+			srcs: ["mylib.cpp"],
+			stl: "none",
+			system_shared_libs: [],
+		}
+	`, withUnbundledBuild)
 
 	module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
 	args := module.Rule("apexRule").Args
 	ensureContains(t, args["opt_flags"], "--manifest_json "+module.Output("apex_manifest.json").Output.String())
 	ensureNotContains(t, args["opt_flags"], "--no_hashtree")
+
+	// The copies of the libraries in the apex should have one more dependency than
+	// the ones outside the apex, namely the unwinder. Ideally we should check
+	// the dependency names directly here but for some reason the names are blank in
+	// this test.
+	for _, lib := range []string{"libc++", "mylib"} {
+		apexImplicits := ctx.ModuleForTests(lib, "android_arm64_armv8-a_shared_myapex").Rule("ld").Implicits
+		nonApexImplicits := ctx.ModuleForTests(lib, "android_arm64_armv8-a_shared").Rule("ld").Implicits
+		if len(apexImplicits) != len(nonApexImplicits)+1 {
+			t.Errorf("%q missing unwinder dep", lib)
+		}
+	}
 }
 
 func TestJavaSDKLibrary(t *testing.T) {
@@ -3489,9 +3532,8 @@
 		"etc/permissions/foo.xml",
 	})
 	// Permission XML should point to the activated path of impl jar of java_sdk_library
-	sdkLibrary := ctx.ModuleForTests("foo", "android_common_myapex").Module().(*java.SdkLibrary)
-	xml := sdkLibrary.XmlPermissionsFileContent()
-	ensureContains(t, xml, `<library name="foo" file="/apex/myapex/javalib/foo.jar"`)
+	sdkLibrary := ctx.ModuleForTests("foo.xml", "android_common_myapex").Rule("java_sdk_xml")
+	ensureContains(t, sdkLibrary.RuleParams.Command, `<library name=\"foo\" file=\"/apex/myapex/javalib/foo.jar\"`)
 }
 
 func TestCompatConfig(t *testing.T) {
diff --git a/cc/androidmk.go b/cc/androidmk.go
index d8210fc..a78e455 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -413,12 +413,9 @@
 }
 
 func (c *vndkPrebuiltLibraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
-	// Each vndk prebuilt is exported to androidMk only when BOARD_VNDK_VERSION != current
-	// and the version of the prebuilt is same as BOARD_VNDK_VERSION.
 	ret.Class = "SHARED_LIBRARIES"
 
-	// shouldn't add any suffixes due to mk modules
-	ret.SubName = ""
+	ret.SubName = c.androidMkSuffix
 
 	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
 		c.libraryDecorator.androidMkWriteExportedFlags(w)
@@ -455,19 +452,21 @@
 	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
 		c.libraryDecorator.androidMkWriteExportedFlags(w)
 
-		if c.shared() {
+		if c.shared() || c.static() {
 			path, file := filepath.Split(c.path.ToMakePath().String())
 			stem, suffix, ext := android.SplitFileExt(file)
 			fmt.Fprintln(w, "LOCAL_BUILT_MODULE_STEM := $(LOCAL_MODULE)"+ext)
 			fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := "+suffix)
+			fmt.Fprintln(w, "LOCAL_MODULE_STEM := "+stem)
 			if c.shared() {
 				fmt.Fprintln(w, "LOCAL_MODULE_PATH := "+path)
-				fmt.Fprintln(w, "LOCAL_MODULE_STEM := "+stem)
 			}
 			if c.tocFile.Valid() {
 				fmt.Fprintln(w, "LOCAL_SOONG_TOC := "+c.tocFile.String())
 			}
-		} else { // static or header
+		}
+
+		if !c.shared() { // static or header
 			fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
 		}
 	})
diff --git a/cc/binary.go b/cc/binary.go
index 280d17b..661264e 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -200,6 +200,11 @@
 	module.compiler = NewBaseCompiler()
 	module.linker = binary
 	module.installer = binary
+
+	// Allow module to be added as member of an sdk/module_exports.
+	module.sdkMemberTypes = []android.SdkMemberType{
+		ccBinarySdkMemberType,
+	}
 	return module, binary
 }
 
diff --git a/cc/binary_sdk_member.go b/cc/binary_sdk_member.go
new file mode 100644
index 0000000..53bc065
--- /dev/null
+++ b/cc/binary_sdk_member.go
@@ -0,0 +1,143 @@
+// 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 cc
+
+import (
+	"path/filepath"
+
+	"android/soong/android"
+	"github.com/google/blueprint"
+)
+
+func init() {
+	android.RegisterSdkMemberType(ccBinarySdkMemberType)
+}
+
+var ccBinarySdkMemberType = &binarySdkMemberType{
+	SdkMemberTypeBase: android.SdkMemberTypeBase{
+		PropertyName: "native_binaries",
+	},
+}
+
+type binarySdkMemberType struct {
+	android.SdkMemberTypeBase
+}
+
+func (mt *binarySdkMemberType) AddDependencies(mctx android.BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) {
+	targets := mctx.MultiTargets()
+	for _, lib := range names {
+		for _, target := range targets {
+			name, version := StubsLibNameAndVersion(lib)
+			if version == "" {
+				version = LatestStubsVersionFor(mctx.Config(), name)
+			}
+			mctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
+				{Mutator: "version", Variation: version},
+			}...), dependencyTag, name)
+		}
+	}
+}
+
+func (mt *binarySdkMemberType) IsInstance(module android.Module) bool {
+	// Check the module to see if it can be used with this module type.
+	if m, ok := module.(*Module); ok {
+		for _, allowableMemberType := range m.sdkMemberTypes {
+			if allowableMemberType == mt {
+				return true
+			}
+		}
+	}
+
+	return false
+}
+
+func (mt *binarySdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
+	info := mt.organizeVariants(member)
+	buildSharedNativeBinarySnapshot(info, builder, member)
+}
+
+// Organize the variants by architecture.
+func (mt *binarySdkMemberType) organizeVariants(member android.SdkMember) *nativeBinaryInfo {
+	memberName := member.Name()
+	info := &nativeBinaryInfo{
+		name:       memberName,
+		memberType: mt,
+	}
+
+	for _, variant := range member.Variants() {
+		ccModule := variant.(*Module)
+
+		info.archVariantProperties = append(info.archVariantProperties, nativeBinaryInfoProperties{
+			name:       memberName,
+			archType:   ccModule.Target().Arch.ArchType.String(),
+			outputFile: ccModule.OutputFile().Path(),
+		})
+	}
+
+	// Initialize the unexported properties that will not be set during the
+	// extraction process.
+	info.commonProperties.name = memberName
+
+	// Extract common properties from the arch specific properties.
+	extractCommonProperties(&info.commonProperties, info.archVariantProperties)
+
+	return info
+}
+
+func buildSharedNativeBinarySnapshot(info *nativeBinaryInfo, builder android.SnapshotBuilder, member android.SdkMember) {
+	pbm := builder.AddPrebuiltModule(member, "cc_prebuilt_binary")
+	pbm.AddProperty("compile_multilib", "both")
+	archProperties := pbm.AddPropertySet("arch")
+	for _, av := range info.archVariantProperties {
+		archTypeProperties := archProperties.AddPropertySet(av.archType)
+		archTypeProperties.AddProperty("srcs", []string{nativeBinaryPathFor(av)})
+
+		builder.CopyToSnapshot(av.outputFile, nativeBinaryPathFor(av))
+	}
+}
+
+const (
+	nativeBinaryDir = "bin"
+)
+
+// path to the native binary. Relative to <sdk_root>/<api_dir>
+func nativeBinaryPathFor(lib nativeBinaryInfoProperties) string {
+	return filepath.Join(lib.archType,
+		nativeBinaryDir, lib.outputFile.Base())
+}
+
+// nativeBinaryInfoProperties represents properties of a native binary
+//
+// The exported (capitalized) fields will be examined and may be changed during common value extraction.
+// The unexported fields will be left untouched.
+type nativeBinaryInfoProperties struct {
+	// The name of the library, is not exported as this must not be changed during optimization.
+	name string
+
+	// archType is not exported as if set (to a non default value) it is always arch specific.
+	// This is "" for common properties.
+	archType string
+
+	// outputFile is not exported as it is always arch specific.
+	outputFile android.Path
+}
+
+// nativeBinaryInfo represents a collection of arch-specific modules having the same name
+type nativeBinaryInfo struct {
+	name                  string
+	memberType            *binarySdkMemberType
+	archVariantProperties []nativeBinaryInfoProperties
+	commonProperties      nativeBinaryInfoProperties
+}
diff --git a/cc/builder.go b/cc/builder.go
index 3ecfe54..136263b 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -55,9 +55,9 @@
 		},
 		"ccCmd", "cFlags")
 
-	ccNoDeps = pctx.AndroidRemoteStaticRule("ccNoDeps", android.RemoteRuleSupports{Goma: true},
+	ccNoDeps = pctx.AndroidStaticRule("ccNoDeps",
 		blueprint.RuleParams{
-			Command:     "$relPwd ${config.CcWrapper}$ccCmd -c $cFlags -o $out $in",
+			Command:     "$relPwd $ccCmd -c $cFlags -o $out $in",
 			CommandDeps: []string{"$ccCmd"},
 		},
 		"ccCmd", "cFlags")
diff --git a/cc/cc.go b/cc/cc.go
index b70e55c..5af8459 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -95,6 +95,8 @@
 	HeaderLibs                                  []string
 	RuntimeLibs                                 []string
 
+	StaticUnwinderIfLegacy bool
+
 	ReexportSharedLibHeaders, ReexportStaticLibHeaders, ReexportHeaderLibHeaders []string
 
 	ObjFiles []string
@@ -385,6 +387,7 @@
 	lateSharedDepTag      = DependencyTag{Name: "late shared", Library: true, Shared: true}
 	staticExportDepTag    = DependencyTag{Name: "static", Library: true, ReexportFlags: true}
 	lateStaticDepTag      = DependencyTag{Name: "late static", Library: true}
+	staticUnwinderDepTag  = DependencyTag{Name: "static unwinder", Library: true}
 	wholeStaticDepTag     = DependencyTag{Name: "whole static", Library: true, ReexportFlags: true}
 	headerDepTag          = DependencyTag{Name: "header", Library: true}
 	headerExportDepTag    = DependencyTag{Name: "header", Library: true, ReexportFlags: true}
@@ -1788,6 +1791,12 @@
 		}, depTag, lib)
 	}
 
+	if deps.StaticUnwinderIfLegacy && ctx.Config().UnbundledBuild() {
+		actx.AddVariationDependencies([]blueprint.Variation{
+			{Mutator: "link", Variation: "static"},
+		}, staticUnwinderDepTag, staticUnwinder(actx))
+	}
+
 	for _, lib := range deps.LateStaticLibs {
 		actx.AddVariationDependencies([]blueprint.Variation{
 			{Mutator: "link", Variation: "static"},
@@ -2161,6 +2170,14 @@
 			}
 		}
 
+		if depTag == staticUnwinderDepTag {
+			if c.ApexProperties.Info.LegacyAndroid10Support {
+				depTag = StaticDepTag
+			} else {
+				return
+			}
+		}
+
 		// Extract ExplicitlyVersioned field from the depTag and reset it inside the struct.
 		// Otherwise, SharedDepTag and lateSharedDepTag with ExplicitlyVersioned set to true
 		// won't be matched to SharedDepTag and lateSharedDepTag.
diff --git a/cc/cflag_artifacts.go b/cc/cflag_artifacts.go
index b61f2a8..855ff25 100644
--- a/cc/cflag_artifacts.go
+++ b/cc/cflag_artifacts.go
@@ -41,12 +41,7 @@
 // filter.
 func allowedDir(subdir string) bool {
 	subdir += "/"
-	for _, prefix := range TrackedCFlagsDir {
-		if strings.HasPrefix(subdir, prefix) {
-			return true
-		}
-	}
-	return false
+	return android.HasAnyPrefix(subdir, TrackedCFlagsDir)
 }
 
 func (s *cflagArtifactsText) genFlagFilename(flag string) string {
diff --git a/cc/compiler.go b/cc/compiler.go
index 1ced451..c1a8d96 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -241,12 +241,7 @@
 // Return true if the module is in the WarningAllowedProjects.
 func warningsAreAllowed(subdir string) bool {
 	subdir += "/"
-	for _, prefix := range config.WarningAllowedProjects {
-		if strings.HasPrefix(subdir, prefix) {
-			return true
-		}
-	}
-	return false
+	return android.HasAnyPrefix(subdir, config.WarningAllowedProjects)
 }
 
 func addToModuleList(ctx ModuleContext, key android.OnceKey, module string) {
@@ -515,7 +510,7 @@
 
 	// Exclude directories from manual binder interface whitelisting.
 	//TODO(b/145621474): Move this check into IInterface.h when clang-tidy no longer uses absolute paths.
-	if android.PrefixInList(ctx.ModuleDir(), allowedManualInterfacePaths) {
+	if android.HasAnyPrefix(ctx.ModuleDir(), allowedManualInterfacePaths) {
 		flags.Local.CFlags = append(flags.Local.CFlags, "-DDO_NOT_CHECK_MANUAL_BINDER_INTERFACES")
 	}
 
@@ -604,16 +599,12 @@
 func isThirdParty(path string) bool {
 	thirdPartyDirPrefixes := []string{"external/", "vendor/", "hardware/"}
 
-	for _, prefix := range thirdPartyDirPrefixes {
-		if strings.HasPrefix(path, prefix) {
-			for _, prefix := range thirdPartyDirPrefixExceptions {
-				if prefix.MatchString(path) {
-					return false
-				}
+	if android.HasAnyPrefix(path, thirdPartyDirPrefixes) {
+		for _, prefix := range thirdPartyDirPrefixExceptions {
+			if prefix.MatchString(path) {
+				return false
 			}
-			break
 		}
 	}
-
 	return true
 }
diff --git a/cc/config/clang.go b/cc/config/clang.go
index 26a104b..0d03699 100644
--- a/cc/config/clang.go
+++ b/cc/config/clang.go
@@ -171,10 +171,8 @@
 		"-Wno-implicit-int-float-conversion",
 		// New warnings to be fixed after clang-r377782.
 		"-Wno-bitwise-conditional-parentheses", // http://b/148286937
-		"-Wno-bool-operation",                  // http://b/148287141
 		"-Wno-int-in-bool-context",             // http://b/148287349
 		"-Wno-sizeof-array-div",                // http://b/148815709
-		"-Wno-tautological-bitwise-compare",    // http://b/148831363
 		"-Wno-tautological-overlap-compare",    // http://b/148815696
 	}, " "))
 
diff --git a/cc/config/global.go b/cc/config/global.go
index 57a5852..d01dd84 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -127,8 +127,8 @@
 
 	// prebuilts/clang default settings.
 	ClangDefaultBase         = "prebuilts/clang/host"
-	ClangDefaultVersion      = "clang-r377782"
-	ClangDefaultShortVersion = "10.0.3"
+	ClangDefaultVersion      = "clang-r377782b"
+	ClangDefaultShortVersion = "10.0.4"
 
 	// Directories with warnings from Android.bp files.
 	WarningAllowedProjects = []string{
diff --git a/cc/config/vndk.go b/cc/config/vndk.go
index 5cecbd6..54f693e 100644
--- a/cc/config/vndk.go
+++ b/cc/config/vndk.go
@@ -19,6 +19,7 @@
 // has VndkUseCoreVariant set.
 var VndkMustUseVendorVariantList = []string{
 	"android.hardware.light-ndk_platform",
+	"android.hardware.identity-ndk_platform",
 	"android.hardware.nfc@1.2",
 	"android.hardware.power-ndk_platform",
 	"android.hardware.vibrator-ndk_platform",
diff --git a/cc/gen.go b/cc/gen.go
index 17ab45f..b0aadc6 100644
--- a/cc/gen.go
+++ b/cc/gen.go
@@ -162,17 +162,19 @@
 	})
 }
 
-func genSysprop(ctx android.ModuleContext, syspropFile android.Path) (android.Path, android.Path) {
+func genSysprop(ctx android.ModuleContext, syspropFile android.Path) (android.Path, android.Paths) {
 	headerFile := android.PathForModuleGen(ctx, "sysprop", "include", syspropFile.Rel()+".h")
 	publicHeaderFile := android.PathForModuleGen(ctx, "sysprop/public", "include", syspropFile.Rel()+".h")
 	cppFile := android.PathForModuleGen(ctx, "sysprop", syspropFile.Rel()+".cpp")
 
+	headers := android.WritablePaths{headerFile, publicHeaderFile}
+
 	ctx.Build(pctx, android.BuildParams{
-		Rule:           sysprop,
-		Description:    "sysprop " + syspropFile.Rel(),
-		Output:         cppFile,
-		ImplicitOutput: headerFile,
-		Input:          syspropFile,
+		Rule:            sysprop,
+		Description:     "sysprop " + syspropFile.Rel(),
+		Output:          cppFile,
+		ImplicitOutputs: headers,
+		Input:           syspropFile,
 		Args: map[string]string{
 			"headerOutDir": filepath.Dir(headerFile.String()),
 			"publicOutDir": filepath.Dir(publicHeaderFile.String()),
@@ -181,7 +183,7 @@
 		},
 	})
 
-	return cppFile, headerFile
+	return cppFile, headers.Paths()
 }
 
 func genWinMsg(ctx android.ModuleContext, srcFile android.Path, flags builderFlags) (android.Path, android.Path) {
@@ -259,9 +261,9 @@
 			srcFiles[i] = rcFile
 			deps = append(deps, headerFile)
 		case ".sysprop":
-			cppFile, headerFile := genSysprop(ctx, srcFile)
+			cppFile, headerFiles := genSysprop(ctx, srcFile)
 			srcFiles[i] = cppFile
-			deps = append(deps, headerFile)
+			deps = append(deps, headerFiles...)
 		}
 	}
 
diff --git a/cc/library.go b/cc/library.go
index 0bddab5..bca9a96 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -281,11 +281,9 @@
 }
 
 func (f *flagExporter) reexportFlags(flags ...string) {
-	for _, flag := range flags {
-		if strings.HasPrefix(flag, "-I") || strings.HasPrefix(flag, "-isystem") {
-			panic(fmt.Errorf("Exporting invalid flag %q: "+
-				"use reexportDirs or reexportSystemDirs to export directories", flag))
-		}
+	if android.PrefixInList(flags, "-I") || android.PrefixInList(flags, "-isystem") {
+		panic(fmt.Errorf("Exporting invalid flag %q: "+
+			"use reexportDirs or reexportSystemDirs to export directories", flag))
 	}
 	f.flags = append(f.flags, flags...)
 }
diff --git a/cc/stl.go b/cc/stl.go
index af015f9..eda8a4f 100644
--- a/cc/stl.go
+++ b/cc/stl.go
@@ -151,6 +151,14 @@
 	return version < 21
 }
 
+func staticUnwinder(ctx android.BaseModuleContext) string {
+	if ctx.Arch().ArchType == android.Arm {
+		return "libunwind_llvm"
+	} else {
+		return "libgcc_stripped"
+	}
+}
+
 func (stl *stl) deps(ctx BaseModuleContext, deps Deps) Deps {
 	switch stl.Properties.SelectedStl {
 	case "libstdc++":
@@ -172,16 +180,16 @@
 		}
 		if ctx.toolchain().Bionic() {
 			if ctx.staticBinary() {
-				deps.StaticLibs = append(deps.StaticLibs, "libm", "libc")
-				if ctx.Arch().ArchType == android.Arm {
-					deps.StaticLibs = append(deps.StaticLibs, "libunwind_llvm")
-				} else {
-					deps.StaticLibs = append(deps.StaticLibs, "libgcc_stripped")
-				}
+				deps.StaticLibs = append(deps.StaticLibs, "libm", "libc", staticUnwinder(ctx))
+			} else {
+				deps.StaticUnwinderIfLegacy = true
 			}
 		}
 	case "":
 		// None or error.
+		if ctx.toolchain().Bionic() && ctx.Module().Name() == "libc++" {
+			deps.StaticUnwinderIfLegacy = true
+		}
 	case "ndk_system":
 		// TODO: Make a system STL prebuilt for the NDK.
 		// The system STL doesn't have a prebuilt (it uses the system's libstdc++), but it does have
diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go
index d92caa1..aed7918 100644
--- a/cc/vendor_snapshot.go
+++ b/cc/vendor_snapshot.go
@@ -41,7 +41,7 @@
 	vendorSnapshotBinariesKey   = android.NewOnceKey("vendorSnapshotBinaries")
 )
 
-// vendor snapshot maps hold names of vendor snapshot modules per arch.
+// vendor snapshot maps hold names of vendor snapshot modules per arch
 func vendorSuffixModules(config android.Config) map[string]bool {
 	return config.Once(vendorSuffixModulesKey, func() interface{} {
 		return make(map[string]bool)
@@ -772,6 +772,10 @@
 
 // Disables source modules which have snapshots
 func VendorSnapshotSourceMutator(ctx android.BottomUpMutatorContext) {
+	if !ctx.Device() {
+		return
+	}
+
 	vndkVersion := ctx.DeviceConfig().VndkVersion()
 	// don't need snapshot if current
 	if vndkVersion == "current" || vndkVersion == "" {
@@ -783,11 +787,19 @@
 		return
 	}
 
-	if module.HasVendorVariant() {
-		vendorSnapshotsLock.Lock()
-		defer vendorSnapshotsLock.Unlock()
+	// vendor suffix should be added to snapshots if the source module isn't vendor: true.
+	if !module.SocSpecific() {
+		// But we can't just check SocSpecific() since we already passed the image mutator.
+		// Check ramdisk and recovery to see if we are real "vendor: true" module.
+		ramdisk_available := module.InRamdisk() && !module.OnlyInRamdisk()
+		recovery_available := module.InRecovery() && !module.OnlyInRecovery()
 
-		vendorSuffixModules(ctx.Config())[ctx.ModuleName()] = true
+		if !ramdisk_available && !recovery_available {
+			vendorSnapshotsLock.Lock()
+			defer vendorSnapshotsLock.Unlock()
+
+			vendorSuffixModules(ctx.Config())[ctx.ModuleName()] = true
+		}
 	}
 
 	if module.isSnapshotPrebuilt() || module.VndkVersion() != ctx.DeviceConfig().VndkVersion() {
diff --git a/cc/vndk_prebuilt.go b/cc/vndk_prebuilt.go
index 50bc325..53b5181 100644
--- a/cc/vndk_prebuilt.go
+++ b/cc/vndk_prebuilt.go
@@ -72,7 +72,8 @@
 
 type vndkPrebuiltLibraryDecorator struct {
 	*libraryDecorator
-	properties vndkPrebuiltProperties
+	properties      vndkPrebuiltProperties
+	androidMkSuffix string
 }
 
 func (p *vndkPrebuiltLibraryDecorator) Name(name string) string {
@@ -153,6 +154,13 @@
 		p.tocFile = android.OptionalPathForPath(tocFile)
 		TransformSharedObjectToToc(ctx, in, tocFile, builderFlags)
 
+		p.androidMkSuffix = p.NameSuffix()
+
+		vndkVersion := ctx.DeviceConfig().VndkVersion()
+		if vndkVersion == p.version() {
+			p.androidMkSuffix = ""
+		}
+
 		return in
 	}
 
@@ -224,15 +232,6 @@
 		&prebuilt.properties,
 	)
 
-	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
-		// Only vndk snapshots of BOARD_VNDK_VERSION will be used when building.
-		if prebuilt.version() != ctx.DeviceConfig().VndkVersion() {
-			module.SkipInstall()
-			module.Properties.HideFromMake = true
-			return
-		}
-	})
-
 	return module
 }
 
diff --git a/cmd/sbox/sbox.go b/cmd/sbox/sbox.go
index 7057b33..65a34fd 100644
--- a/cmd/sbox/sbox.go
+++ b/cmd/sbox/sbox.go
@@ -36,6 +36,7 @@
 	outputRoot    string
 	keepOutDir    bool
 	depfileOut    string
+	inputHash     string
 )
 
 func init() {
@@ -51,6 +52,8 @@
 	flag.StringVar(&depfileOut, "depfile-out", "",
 		"file path of the depfile to generate. This value will replace '__SBOX_DEPFILE__' in the command and will be treated as an output but won't be added to __SBOX_OUT_FILES__")
 
+	flag.StringVar(&inputHash, "input-hash", "",
+		"This option is ignored. Typical usage is to supply a hash of the list of input names so that the module will be rebuilt if the list (and thus the hash) changes.")
 }
 
 func usageViolation(violation string) {
@@ -59,7 +62,7 @@
 	}
 
 	fmt.Fprintf(os.Stderr,
-		"Usage: sbox -c <commandToRun> --sandbox-path <sandboxPath> --output-root <outputRoot> [--depfile-out depFile] <outputFile> [<outputFile>...]\n"+
+		"Usage: sbox -c <commandToRun> --sandbox-path <sandboxPath> --output-root <outputRoot> [--depfile-out depFile] [--input-hash hash] <outputFile> [<outputFile>...]\n"+
 			"\n"+
 			"Deletes <outputRoot>,"+
 			"runs <commandToRun>,"+
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index 9b0e7a5..6cb9873 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -426,7 +426,7 @@
 		cmd.FlagWithArg("--copy-dex-files=", "false")
 	}
 
-	if !anyHavePrefix(preoptFlags, "--compiler-filter=") {
+	if !android.PrefixInList(preoptFlags, "--compiler-filter=") {
 		var compilerFilter string
 		if contains(global.SystemServerJars, module.Name) {
 			// Jars of system server, use the product option if it is set, speed otherwise.
@@ -618,32 +618,4 @@
 	return false
 }
 
-// remove all elements in a from b, returning a new slice
-func filterOut(a []string, b []string) []string {
-	var ret []string
-	for _, x := range b {
-		if !contains(a, x) {
-			ret = append(ret, x)
-		}
-	}
-	return ret
-}
-
-func replace(l []string, from, to string) {
-	for i := range l {
-		if l[i] == from {
-			l[i] = to
-		}
-	}
-}
-
 var copyOf = android.CopyOf
-
-func anyHavePrefix(l []string, prefix string) bool {
-	for _, x := range l {
-		if strings.HasPrefix(x, prefix) {
-			return true
-		}
-	}
-	return false
-}
diff --git a/genrule/genrule.go b/genrule/genrule.go
index a0008d3..fe877fe 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -26,6 +26,7 @@
 
 	"android/soong/android"
 	"android/soong/shared"
+	"crypto/sha256"
 	"path/filepath"
 )
 
@@ -309,6 +310,7 @@
 			addLocationLabel(out.Rel(), []string{filepath.Join("__SBOX_OUT_DIR__", out.Rel())})
 		}
 
+		referencedIn := false
 		referencedDepfile := false
 
 		rawCommand, err := android.ExpandNinjaEscaped(task.cmd, func(name string) (string, bool, error) {
@@ -333,6 +335,7 @@
 				}
 				return locationLabels[firstLabel][0], false, nil
 			case "in":
+				referencedIn = true
 				return "${in}", true, nil
 			case "out":
 				return "__SBOX_OUT_FILES__", false, nil
@@ -398,8 +401,16 @@
 		// Escape the command for the shell
 		rawCommand = "'" + strings.Replace(rawCommand, "'", `'\''`, -1) + "'"
 		g.rawCommands = append(g.rawCommands, rawCommand)
-		sandboxCommand := fmt.Sprintf("rm -rf %s && $sboxCmd --sandbox-path %s --output-root %s -c %s %s $allouts",
-			task.genDir, sandboxPath, task.genDir, rawCommand, depfilePlaceholder)
+
+		sandboxCommand := fmt.Sprintf("rm -rf %s && $sboxCmd --sandbox-path %s --output-root %s",
+			task.genDir, sandboxPath, task.genDir)
+
+		if !referencedIn {
+			sandboxCommand = sandboxCommand + hashSrcFiles(srcFiles)
+		}
+
+		sandboxCommand = sandboxCommand + fmt.Sprintf(" -c %s %s $allouts",
+			rawCommand, depfilePlaceholder)
 
 		ruleParams := blueprint.RuleParams{
 			Command:     sandboxCommand,
@@ -463,6 +474,14 @@
 
 }
 
+func hashSrcFiles(srcFiles android.Paths) string {
+	h := sha256.New()
+	for _, src := range srcFiles {
+		h.Write([]byte(src.String()))
+	}
+	return fmt.Sprintf(" --input-hash %x", h.Sum(nil))
+}
+
 func (g *Module) generateSourceFile(ctx android.ModuleContext, task generateTask, rule blueprint.Rule) {
 	desc := "generate"
 	if len(task.out) == 0 {
diff --git a/genrule/genrule_test.go b/genrule/genrule_test.go
index 7eb43ac..4b36600 100644
--- a/genrule/genrule_test.go
+++ b/genrule/genrule_test.go
@@ -502,6 +502,93 @@
 	}
 }
 
+func TestGenruleHashInputs(t *testing.T) {
+
+	// The basic idea here is to verify that the sbox command (which is
+	// in the Command field of the generate rule) contains a hash of the
+	// inputs, but only if $(in) is not referenced in the genrule cmd
+	// property.
+
+	// By including a hash of the inputs, we cause the rule to re-run if
+	// the list of inputs changes (because the sbox command changes).
+
+	// However, if the genrule cmd property already contains $(in), then
+	// the dependency is already expressed, so we don't need to include the
+	// hash in that case.
+
+	bp := `
+			genrule {
+				name: "hash0",
+				srcs: ["in1.txt", "in2.txt"],
+				out: ["out"],
+				cmd: "echo foo > $(out)",
+			}
+			genrule {
+				name: "hash1",
+				srcs: ["*.txt"],
+				out: ["out"],
+				cmd: "echo bar > $(out)",
+			}
+			genrule {
+				name: "hash2",
+				srcs: ["*.txt"],
+				out: ["out"],
+				cmd: "echo $(in) > $(out)",
+			}
+		`
+	testcases := []struct {
+		name         string
+		expectedHash string
+	}{
+		{
+			name: "hash0",
+			// sha256 value obtained from: echo -n 'in1.txtin2.txt' | sha256sum
+			expectedHash: "031097e11e0a8c822c960eb9742474f46336360a515744000d086d94335a9cb9",
+		},
+		{
+			name: "hash1",
+			// sha256 value obtained from: echo -n 'in1.txtin2.txtin3.txt' | sha256sum
+			expectedHash: "de5d22a4a7ab50d250cc59fcdf7a7e0775790d270bfca3a7a9e1f18a70dd996c",
+		},
+		{
+			name: "hash2",
+			// $(in) is present, option should not appear
+			expectedHash: "",
+		},
+	}
+
+	config := testConfig(bp, nil)
+	ctx := testContext(config)
+	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+	if errs == nil {
+		_, errs = ctx.PrepareBuildActions(config)
+	}
+	if errs != nil {
+		t.Fatal(errs)
+	}
+
+	for _, test := range testcases {
+		t.Run(test.name, func(t *testing.T) {
+			gen := ctx.ModuleForTests(test.name, "")
+			command := gen.Rule("generator").RuleParams.Command
+
+			if len(test.expectedHash) > 0 {
+				// We add spaces before and after to make sure that
+				// this option doesn't abutt another sbox option.
+				expectedInputHashOption := " --input-hash " + test.expectedHash + " "
+
+				if !strings.Contains(command, expectedInputHashOption) {
+					t.Errorf("Expected command \"%s\" to contain \"%s\"", command, expectedInputHashOption)
+				}
+			} else {
+				if strings.Contains(command, "--input-hash") {
+					t.Errorf("Unexpected \"--input-hash\" found in command: \"%s\"", command)
+				}
+			}
+		})
+	}
+}
+
 func TestGenSrcs(t *testing.T) {
 	testcases := []struct {
 		name string
diff --git a/java/aar.go b/java/aar.go
index 24c5e7d..6e3b9e6 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -101,6 +101,7 @@
 	usesNonSdkApis          bool
 	sdkLibraries            []string
 	hasNoCode               bool
+	LoggingParent           string
 
 	splitNames []string
 	splits     []split
@@ -134,15 +135,8 @@
 	manifestPath android.Path) (compileFlags, linkFlags []string, linkDeps android.Paths,
 	resDirs, overlayDirs []globbedResourceDir, rroDirs []rroDir, resZips android.Paths) {
 
-	hasVersionCode := false
-	hasVersionName := false
-	for _, f := range a.aaptProperties.Aaptflags {
-		if strings.HasPrefix(f, "--version-code") {
-			hasVersionCode = true
-		} else if strings.HasPrefix(f, "--version-name") {
-			hasVersionName = true
-		}
-	}
+	hasVersionCode := android.PrefixInList(a.aaptProperties.Aaptflags, "--version-code")
+	hasVersionName := android.PrefixInList(a.aaptProperties.Aaptflags, "--version-name")
 
 	// Flags specified in Android.bp
 	linkFlags = append(linkFlags, a.aaptProperties.Aaptflags...)
@@ -241,7 +235,8 @@
 	manifestSrcPath := android.PathForModuleSrc(ctx, manifestFile)
 
 	manifestPath := manifestFixer(ctx, manifestSrcPath, sdkContext, sdkLibraries,
-		a.isLibrary, a.useEmbeddedNativeLibs, a.usesNonSdkApis, a.useEmbeddedDex, a.hasNoCode)
+		a.isLibrary, a.useEmbeddedNativeLibs, a.usesNonSdkApis, a.useEmbeddedDex, a.hasNoCode,
+		a.LoggingParent)
 
 	// Add additional manifest files to transitive manifests.
 	additionalManifests := android.PathsForModuleSrc(ctx, a.aaptProperties.Additional_manifests)
@@ -337,7 +332,7 @@
 
 	// Extract assets from the resource package output so that they can be used later in aapt2link
 	// for modules that depend on this one.
-	if android.PrefixedStringInList(linkFlags, "-A ") || len(assetPackages) > 0 {
+	if android.PrefixInList(linkFlags, "-A ") || len(assetPackages) > 0 {
 		assets := android.PathForModuleOut(ctx, "assets.zip")
 		ctx.Build(pctx, android.BuildParams{
 			Rule:        extractAssetsRule,
diff --git a/java/android_manifest.go b/java/android_manifest.go
index e3646f5..9a71be2 100644
--- a/java/android_manifest.go
+++ b/java/android_manifest.go
@@ -53,7 +53,7 @@
 
 // Uses manifest_fixer.py to inject minSdkVersion, etc. into an AndroidManifest.xml
 func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext sdkContext, sdkLibraries []string,
-	isLibrary, useEmbeddedNativeLibs, usesNonSdkApis, useEmbeddedDex, hasNoCode bool) android.Path {
+	isLibrary, useEmbeddedNativeLibs, usesNonSdkApis, useEmbeddedDex, hasNoCode bool, loggingParent string) android.Path {
 
 	var args []string
 	if isLibrary {
@@ -91,6 +91,9 @@
 		args = append(args, "--has-no-code")
 	}
 
+	if loggingParent != "" {
+		args = append(args, "--logging-parent", loggingParent)
+	}
 	var deps android.Paths
 	targetSdkVersion, err := sdkContext.targetSdkVersion().effectiveVersionString(ctx)
 	if err != nil {
diff --git a/java/app.go b/java/app.go
index 02f3e7f..71bad68 100755
--- a/java/app.go
+++ b/java/app.go
@@ -111,6 +111,9 @@
 
 	// the package name of this app. The package name in the manifest file is used if one was not given.
 	Package_name *string
+
+	// the logging parent of this app.
+	Logging_parent *string
 }
 
 type AndroidApp struct {
@@ -273,13 +276,7 @@
 	aaptLinkFlags := []string{}
 
 	// Add TARGET_AAPT_CHARACTERISTICS values to AAPT link flags if they exist and --product flags were not provided.
-	hasProduct := false
-	for _, f := range a.aaptProperties.Aaptflags {
-		if strings.HasPrefix(f, "--product") {
-			hasProduct = true
-			break
-		}
-	}
+	hasProduct := android.PrefixInList(a.aaptProperties.Aaptflags, "--product")
 	if !hasProduct && len(ctx.Config().ProductAAPTCharacteristics()) > 0 {
 		aaptLinkFlags = append(aaptLinkFlags, "--product", ctx.Config().ProductAAPTCharacteristics())
 	}
@@ -309,7 +306,7 @@
 
 	a.aapt.splitNames = a.appProperties.Package_splits
 	a.aapt.sdkLibraries = a.exportedSdkLibs
-
+	a.aapt.LoggingParent = String(a.overridableAppProperties.Logging_parent)
 	a.aapt.buildActions(ctx, sdkContext(a), aaptLinkFlags...)
 
 	// apps manifests are handled by aapt, don't let Module see them
diff --git a/java/app_test.go b/java/app_test.go
index c86b038..6d94160 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -1181,6 +1181,7 @@
 			name: "bar",
 			base: "foo",
 			certificate: ":new_certificate",
+			logging_parent: "bah",
 		}
 
 		android_app_certificate {
@@ -1196,37 +1197,41 @@
 		`)
 
 	expectedVariants := []struct {
-		moduleName  string
-		variantName string
-		apkName     string
-		apkPath     string
-		signFlag    string
-		overrides   []string
-		aaptFlag    string
+		moduleName     string
+		variantName    string
+		apkName        string
+		apkPath        string
+		signFlag       string
+		overrides      []string
+		aaptFlag       string
+		logging_parent string
 	}{
 		{
-			moduleName:  "foo",
-			variantName: "android_common",
-			apkPath:     "/target/product/test_device/system/app/foo/foo.apk",
-			signFlag:    "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
-			overrides:   []string{"qux"},
-			aaptFlag:    "",
+			moduleName:     "foo",
+			variantName:    "android_common",
+			apkPath:        "/target/product/test_device/system/app/foo/foo.apk",
+			signFlag:       "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
+			overrides:      []string{"qux"},
+			aaptFlag:       "",
+			logging_parent: "",
 		},
 		{
-			moduleName:  "bar",
-			variantName: "android_common_bar",
-			apkPath:     "/target/product/test_device/system/app/bar/bar.apk",
-			signFlag:    "cert/new_cert.x509.pem cert/new_cert.pk8",
-			overrides:   []string{"qux", "foo"},
-			aaptFlag:    "",
+			moduleName:     "bar",
+			variantName:    "android_common_bar",
+			apkPath:        "/target/product/test_device/system/app/bar/bar.apk",
+			signFlag:       "cert/new_cert.x509.pem cert/new_cert.pk8",
+			overrides:      []string{"qux", "foo"},
+			aaptFlag:       "",
+			logging_parent: "bah",
 		},
 		{
-			moduleName:  "baz",
-			variantName: "android_common_baz",
-			apkPath:     "/target/product/test_device/system/app/baz/baz.apk",
-			signFlag:    "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
-			overrides:   []string{"qux", "foo"},
-			aaptFlag:    "--rename-manifest-package org.dandroid.bp",
+			moduleName:     "baz",
+			variantName:    "android_common_baz",
+			apkPath:        "/target/product/test_device/system/app/baz/baz.apk",
+			signFlag:       "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
+			overrides:      []string{"qux", "foo"},
+			aaptFlag:       "--rename-manifest-package org.dandroid.bp",
+			logging_parent: "",
 		},
 	}
 	for _, expected := range expectedVariants {
@@ -1260,6 +1265,13 @@
 				expected.overrides, mod.appProperties.Overrides)
 		}
 
+		// Test Overridable property: Logging_parent
+		logging_parent := mod.aapt.LoggingParent
+		if expected.logging_parent != logging_parent {
+			t.Errorf("Incorrect overrides property value for logging parent, expected: %q, got: %q",
+				expected.logging_parent, logging_parent)
+		}
+
 		// Check the package renaming flag, if exists.
 		res := variant.Output("package-res.apk")
 		aapt2Flags := res.Args["flags"]
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index 96f8042..28f56d2 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -15,6 +15,7 @@
 package java
 
 import (
+	"fmt"
 	"path/filepath"
 	"strings"
 
@@ -29,14 +30,29 @@
 	return ctx.Config().OnceStringSlice(systemServerClasspathKey, func() []string {
 		global := dexpreopt.GetGlobalConfig(ctx)
 		var systemServerClasspathLocations []string
-		for _, m := range *DexpreoptedSystemServerJars(ctx.Config()) {
+		var dexpreoptJars = *DexpreoptedSystemServerJars(ctx.Config())
+		// 1) The jars that are dexpreopted.
+		for _, m := range dexpreoptJars {
 			systemServerClasspathLocations = append(systemServerClasspathLocations,
 				filepath.Join("/system/framework", m+".jar"))
 		}
+		// 2) The jars that are from an updatable apex.
 		for _, m := range global.UpdatableSystemServerJars {
 			systemServerClasspathLocations = append(systemServerClasspathLocations,
 				dexpreopt.GetJarLocationFromApexJarPair(m))
 		}
+		// 3) The jars from make (which are not updatable, not preopted).
+		for _, m := range dexpreopt.NonUpdatableSystemServerJars(ctx, global) {
+			if !android.InList(m, dexpreoptJars) {
+				systemServerClasspathLocations = append(systemServerClasspathLocations,
+					filepath.Join("/system/framework", m+".jar"))
+			}
+		}
+		if len(systemServerClasspathLocations) != len(global.SystemServerJars)+len(global.UpdatableSystemServerJars) {
+			panic(fmt.Errorf("Wrong number of system server jars, got %d, expected %d",
+				len(systemServerClasspathLocations),
+				len(global.SystemServerJars)+len(global.UpdatableSystemServerJars)))
+		}
 		return systemServerClasspathLocations
 	})
 }
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 959f1c7..fd4b90d 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -547,10 +547,10 @@
 		case bootClasspathTag:
 			if dep, ok := module.(Dependency); ok {
 				deps.bootClasspath = append(deps.bootClasspath, dep.ImplementationJars()...)
-			} else if sm, ok := module.(*SystemModules); ok {
+			} else if sm, ok := module.(SystemModulesProvider); ok {
 				// A system modules dependency has been added to the bootclasspath
 				// so add its libs to the bootclasspath.
-				deps.bootClasspath = append(deps.bootClasspath, sm.headerJars...)
+				deps.bootClasspath = append(deps.bootClasspath, sm.HeaderJars()...)
 			} else {
 				panic(fmt.Errorf("unknown dependency %q for %q", otherName, ctx.ModuleName()))
 			}
@@ -578,11 +578,9 @@
 			if deps.systemModules != nil {
 				panic("Found two system module dependencies")
 			}
-			sm := module.(*SystemModules)
-			if sm.outputDir == nil && len(sm.outputDeps) == 0 {
-				panic("Missing directory for system module dependency")
-			}
-			deps.systemModules = &systemModules{sm.outputDir, sm.outputDeps}
+			sm := module.(SystemModulesProvider)
+			outputDir, outputDeps := sm.OutputDirAndDeps()
+			deps.systemModules = &systemModules{outputDir, outputDeps}
 		}
 	})
 	// do not pass exclude_srcs directly when expanding srcFiles since exclude_srcs
@@ -605,11 +603,8 @@
 				continue
 			}
 			packageName := strings.ReplaceAll(filepath.Dir(src.Rel()), "/", ".")
-			for _, pkg := range filterPackages {
-				if strings.HasPrefix(packageName, pkg) {
-					filtered = append(filtered, src)
-					break
-				}
+			if android.HasAnyPrefix(packageName, filterPackages) {
+				filtered = append(filtered, src)
 			}
 		}
 		return filtered
diff --git a/java/java.go b/java/java.go
index c3e2c96..462dba8 100644
--- a/java/java.go
+++ b/java/java.go
@@ -1031,18 +1031,16 @@
 			case bootClasspathTag:
 				// If a system modules dependency has been added to the bootclasspath
 				// then add its libs to the bootclasspath.
-				sm := module.(*SystemModules)
-				deps.bootClasspath = append(deps.bootClasspath, sm.headerJars...)
+				sm := module.(SystemModulesProvider)
+				deps.bootClasspath = append(deps.bootClasspath, sm.HeaderJars()...)
 
 			case systemModulesTag:
 				if deps.systemModules != nil {
 					panic("Found two system module dependencies")
 				}
-				sm := module.(*SystemModules)
-				if sm.outputDir == nil || len(sm.outputDeps) == 0 {
-					panic("Missing directory for system module dependency")
-				}
-				deps.systemModules = &systemModules{sm.outputDir, sm.outputDeps}
+				sm := module.(SystemModulesProvider)
+				outputDir, outputDeps := sm.OutputDirAndDeps()
+				deps.systemModules = &systemModules{outputDir, outputDeps}
 			}
 		}
 	})
diff --git a/java/java_test.go b/java/java_test.go
index a2226b5..7c06699 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -982,6 +982,65 @@
 	}
 }
 
+func TestDroidstubsWithSystemModules(t *testing.T) {
+	ctx, _ := testJava(t, `
+		droidstubs {
+		    name: "stubs-source-system-modules",
+		    srcs: [
+		        "bar-doc/*.java",
+		    ],
+				sdk_version: "none",
+				system_modules: "source-system-modules",
+		}
+
+		java_library {
+				name: "source-jar",
+		    srcs: [
+		        "a.java",
+		    ],
+		}
+
+		java_system_modules {
+				name: "source-system-modules",
+				libs: ["source-jar"],
+		}
+
+		droidstubs {
+		    name: "stubs-prebuilt-system-modules",
+		    srcs: [
+		        "bar-doc/*.java",
+		    ],
+				sdk_version: "none",
+				system_modules: "prebuilt-system-modules",
+		}
+
+		java_import {
+				name: "prebuilt-jar",
+				jars: ["a.jar"],
+		}
+
+		java_system_modules_import {
+				name: "prebuilt-system-modules",
+				libs: ["prebuilt-jar"],
+		}
+		`)
+
+	checkSystemModulesUseByDroidstubs(t, ctx, "stubs-source-system-modules", "source-jar.jar")
+
+	checkSystemModulesUseByDroidstubs(t, ctx, "stubs-prebuilt-system-modules", "prebuilt-jar.jar")
+}
+
+func checkSystemModulesUseByDroidstubs(t *testing.T, ctx *android.TestContext, moduleName string, systemJar string) {
+	metalavaRule := ctx.ModuleForTests(moduleName, "android_common").Rule("metalava")
+	var systemJars []string
+	for _, i := range metalavaRule.Implicits {
+		systemJars = append(systemJars, i.Base())
+	}
+	if len(systemJars) != 1 || systemJars[0] != systemJar {
+		t.Errorf("inputs of %q must be []string{%q}, but was %#v.", moduleName, systemJar, systemJars)
+	}
+}
+
 func TestJarGenrules(t *testing.T) {
 	ctx, _ := testJava(t, `
 		java_library {
@@ -1125,7 +1184,7 @@
 	ctx.ModuleForTests("foo"+sdkStubsSourceSuffix, "android_common")
 	ctx.ModuleForTests("foo"+sdkStubsSourceSuffix+sdkSystemApiSuffix, "android_common")
 	ctx.ModuleForTests("foo"+sdkStubsSourceSuffix+sdkTestApiSuffix, "android_common")
-	ctx.ModuleForTests("foo"+sdkXmlFileSuffix, "android_arm64_armv8-a")
+	ctx.ModuleForTests("foo"+sdkXmlFileSuffix, "android_common")
 	ctx.ModuleForTests("foo.api.public.28", "")
 	ctx.ModuleForTests("foo.api.system.28", "")
 	ctx.ModuleForTests("foo.api.test.28", "")
@@ -1377,3 +1436,59 @@
 		}
 	}
 }
+
+func TestJavaLibraryWithSystemModules(t *testing.T) {
+	ctx, _ := testJava(t, `
+		java_library {
+		    name: "lib-with-source-system-modules",
+		    srcs: [
+		        "a.java",
+		    ],
+				sdk_version: "none",
+				system_modules: "source-system-modules",
+		}
+
+		java_library {
+				name: "source-jar",
+		    srcs: [
+		        "a.java",
+		    ],
+		}
+
+		java_system_modules {
+				name: "source-system-modules",
+				libs: ["source-jar"],
+		}
+
+		java_library {
+		    name: "lib-with-prebuilt-system-modules",
+		    srcs: [
+		        "a.java",
+		    ],
+				sdk_version: "none",
+				system_modules: "prebuilt-system-modules",
+		}
+
+		java_import {
+				name: "prebuilt-jar",
+				jars: ["a.jar"],
+		}
+
+		java_system_modules_import {
+				name: "prebuilt-system-modules",
+				libs: ["prebuilt-jar"],
+		}
+		`)
+
+	checkBootClasspathForSystemModule(t, ctx, "lib-with-source-system-modules", "/source-jar.jar")
+
+	checkBootClasspathForSystemModule(t, ctx, "lib-with-prebuilt-system-modules", "/prebuilt-jar.jar")
+}
+
+func checkBootClasspathForSystemModule(t *testing.T, ctx *android.TestContext, moduleName string, expectedSuffix string) {
+	javacRule := ctx.ModuleForTests(moduleName, "android_common").Rule("javac")
+	bootClasspath := javacRule.Args["bootClasspath"]
+	if strings.HasPrefix(bootClasspath, "--system ") && strings.HasSuffix(bootClasspath, expectedSuffix) {
+		t.Errorf("bootclasspath of %q must start with --system and end with %q, but was %#v.", moduleName, expectedSuffix, bootClasspath)
+	}
+}
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 4f4029a..a8edf1d 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -16,7 +16,6 @@
 
 import (
 	"android/soong/android"
-	"android/soong/genrule"
 
 	"fmt"
 	"io"
@@ -36,23 +35,23 @@
 	sdkTestApiSuffix      = ".test"
 	sdkStubsSourceSuffix  = ".stubs.source"
 	sdkXmlFileSuffix      = ".xml"
-	permissionsTemplate   = `<?xml version="1.0" encoding="utf-8"?>\n` +
+	permissionsTemplate   = `<?xml version=\"1.0\" encoding=\"utf-8\"?>\n` +
 		`<!-- Copyright (C) 2018 The Android Open Source Project\n` +
 		`\n` +
-		`    Licensed under the Apache License, Version 2.0 (the "License");\n` +
+		`    Licensed under the Apache License, Version 2.0 (the \"License\");\n` +
 		`    you may not use this file except in compliance with the License.\n` +
 		`    You may obtain a copy of the License at\n` +
 		`\n` +
 		`        http://www.apache.org/licenses/LICENSE-2.0\n` +
 		`\n` +
 		`    Unless required by applicable law or agreed to in writing, software\n` +
-		`    distributed under the License is distributed on an "AS IS" BASIS,\n` +
+		`    distributed under the License is distributed on an \"AS IS\" BASIS,\n` +
 		`    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n` +
 		`    See the License for the specific language governing permissions and\n` +
 		`    limitations under the License.\n` +
 		`-->\n` +
 		`<permissions>\n` +
-		`    <library name="%s" file="%s"/>\n` +
+		`    <library name=\"%s\" file=\"%s\"/>\n` +
 		`</permissions>\n`
 )
 
@@ -250,8 +249,6 @@
 	sdkLibraryProperties sdkLibraryProperties
 
 	commonToSdkLibraryAndImport
-
-	permissionsFile android.Path
 }
 
 var _ Dependency = (*SdkLibrary)(nil)
@@ -267,6 +264,13 @@
 
 var xmlPermissionsFileTag = dependencyTag{name: "xml-permissions-file"}
 
+func IsXmlPermissionsFileDepTag(depTag blueprint.DependencyTag) bool {
+	if dt, ok := depTag.(dependencyTag); ok {
+		return dt == xmlPermissionsFileTag
+	}
+	return false
+}
+
 func (module *SdkLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
 	for _, apiScope := range module.getActiveApiScopes() {
 		// Add dependencies to the stubs library
@@ -278,7 +282,7 @@
 
 	if !proptools.Bool(module.sdkLibraryProperties.Api_only) {
 		// Add dependency to the rule for generating the xml permissions file
-		ctx.AddDependency(module, xmlPermissionsFileTag, module.genXmlPermissionsFileName())
+		ctx.AddDependency(module, xmlPermissionsFileTag, module.xmlFileName())
 	}
 
 	module.Library.deps(ctx)
@@ -314,18 +318,6 @@
 				ctx.ModuleErrorf("depends on module %q of unknown tag %q", otherName, tag)
 			}
 		}
-		if tag == xmlPermissionsFileTag {
-			if genRule, ok := to.(genrule.SourceFileGenerator); ok {
-				pf := genRule.GeneratedSourceFiles()
-				if len(pf) != 1 {
-					ctx.ModuleErrorf("%q failed to generate permission XML", otherName)
-				} else {
-					module.permissionsFile = pf[0]
-				}
-			} else {
-				ctx.ModuleErrorf("depends on module %q to generate xml permissions file but it does not provide any outputs", otherName)
-			}
-		}
 	})
 }
 
@@ -389,37 +381,11 @@
 	return module.BaseModuleName()
 }
 
-// File path to the runtime implementation library
-func (module *SdkLibrary) implPath() string {
-	if apexName := module.ApexName(); apexName != "" {
-		// TODO(b/146468504): ApexName() is only a soong module name, not apex name.
-		// In most cases, this works fine. But when apex_name is set or override_apex is used
-		// this can be wrong.
-		return fmt.Sprintf("/apex/%s/javalib/%s.jar", apexName, module.implName())
-	}
-	partition := "system"
-	if module.SocSpecific() {
-		partition = "vendor"
-	} else if module.DeviceSpecific() {
-		partition = "odm"
-	} else if module.ProductSpecific() {
-		partition = "product"
-	} else if module.SystemExtSpecific() {
-		partition = "system_ext"
-	}
-	return "/" + partition + "/framework/" + module.implName() + ".jar"
-}
-
 // Module name of the XML file for the lib
 func (module *SdkLibrary) xmlFileName() string {
 	return module.BaseModuleName() + sdkXmlFileSuffix
 }
 
-// Module name of the rule for generating the XML permissions file
-func (module *SdkLibrary) genXmlPermissionsFileName() string {
-	return "gen-" + module.BaseModuleName() + sdkXmlFileSuffix
-}
-
 // Get the sdk version for use when compiling the stubs library.
 func (module *SdkLibrary) sdkVersionForStubsLibrary(mctx android.LoadHookContext, apiScope *apiScope) string {
 	sdkDep := decodeSdkDep(mctx, sdkContext(&module.Library))
@@ -615,58 +581,31 @@
 	mctx.CreateModule(DroidstubsFactory, &props)
 }
 
-func (module *SdkLibrary) XmlPermissionsFile() android.Path {
-	return module.permissionsFile
-}
-
-func (module *SdkLibrary) XmlPermissionsFileContent() string {
-	return fmt.Sprintf(permissionsTemplate, module.BaseModuleName(), module.implPath())
-}
-
 // Creates the xml file that publicizes the runtime library
 func (module *SdkLibrary) createXmlFile(mctx android.LoadHookContext) {
-
-	xmlContent := module.XmlPermissionsFileContent()
-
-	genRuleName := module.genXmlPermissionsFileName()
-
-	// Create a genrule module to create the XML permissions file.
-	genRuleProps := struct {
-		Name *string
-		Cmd  *string
-		Out  []string
-	}{
-		Name: proptools.StringPtr(genRuleName),
-		Cmd:  proptools.StringPtr("echo -e '" + xmlContent + "' > '$(out)'"),
-		Out:  []string{module.xmlFileName()},
-	}
-
-	mctx.CreateModule(genrule.GenRuleFactory, &genRuleProps)
-
-	// creates a prebuilt_etc module to actually place the xml file under
-	// <partition>/etc/permissions
-	etcProps := struct {
+	props := struct {
 		Name                *string
-		Src                 *string
-		Sub_dir             *string
+		Lib_name            *string
 		Soc_specific        *bool
 		Device_specific     *bool
 		Product_specific    *bool
 		System_ext_specific *bool
-	}{}
-	etcProps.Name = proptools.StringPtr(module.xmlFileName())
-	etcProps.Src = proptools.StringPtr(":" + genRuleName)
-	etcProps.Sub_dir = proptools.StringPtr("permissions")
-	if module.SocSpecific() {
-		etcProps.Soc_specific = proptools.BoolPtr(true)
-	} else if module.DeviceSpecific() {
-		etcProps.Device_specific = proptools.BoolPtr(true)
-	} else if module.ProductSpecific() {
-		etcProps.Product_specific = proptools.BoolPtr(true)
-	} else if module.SystemExtSpecific() {
-		etcProps.System_ext_specific = proptools.BoolPtr(true)
+	}{
+		Name:     proptools.StringPtr(module.xmlFileName()),
+		Lib_name: proptools.StringPtr(module.BaseModuleName()),
 	}
-	mctx.CreateModule(android.PrebuiltEtcFactory, &etcProps)
+
+	if module.SocSpecific() {
+		props.Soc_specific = proptools.BoolPtr(true)
+	} else if module.DeviceSpecific() {
+		props.Device_specific = proptools.BoolPtr(true)
+	} else if module.ProductSpecific() {
+		props.Product_specific = proptools.BoolPtr(true)
+	} else if module.SystemExtSpecific() {
+		props.System_ext_specific = proptools.BoolPtr(true)
+	}
+
+	mctx.CreateModule(sdkLibraryXmlFactory, &props)
 }
 
 func PrebuiltJars(ctx android.BaseModuleContext, baseName string, s sdkSpec) android.Paths {
@@ -1039,3 +978,111 @@
 	// This module is just a wrapper for the stubs.
 	return module.sdkJars(ctx, sdkVersion)
 }
+
+//
+// java_sdk_library_xml
+//
+type sdkLibraryXml struct {
+	android.ModuleBase
+	android.DefaultableModuleBase
+	android.ApexModuleBase
+
+	properties sdkLibraryXmlProperties
+
+	outputFilePath android.OutputPath
+	installDirPath android.InstallPath
+}
+
+type sdkLibraryXmlProperties struct {
+	// canonical name of the lib
+	Lib_name *string
+}
+
+// java_sdk_library_xml builds the permission xml file for a java_sdk_library.
+// Not to be used directly by users. java_sdk_library internally uses this.
+func sdkLibraryXmlFactory() android.Module {
+	module := &sdkLibraryXml{}
+
+	module.AddProperties(&module.properties)
+
+	android.InitApexModule(module)
+	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+
+	return module
+}
+
+// from android.PrebuiltEtcModule
+func (module *sdkLibraryXml) SubDir() string {
+	return "permissions"
+}
+
+// from android.PrebuiltEtcModule
+func (module *sdkLibraryXml) OutputFile() android.OutputPath {
+	return module.outputFilePath
+}
+
+// from android.ApexModule
+func (module *sdkLibraryXml) AvailableFor(what string) bool {
+	return true
+}
+
+func (module *sdkLibraryXml) DepsMutator(ctx android.BottomUpMutatorContext) {
+	// do nothing
+}
+
+// File path to the runtime implementation library
+func (module *sdkLibraryXml) implPath() string {
+	implName := proptools.String(module.properties.Lib_name)
+	if apexName := module.ApexName(); apexName != "" {
+		// TODO(b/146468504): ApexName() is only a soong module name, not apex name.
+		// In most cases, this works fine. But when apex_name is set or override_apex is used
+		// this can be wrong.
+		return fmt.Sprintf("/apex/%s/javalib/%s.jar", apexName, implName)
+	}
+	partition := "system"
+	if module.SocSpecific() {
+		partition = "vendor"
+	} else if module.DeviceSpecific() {
+		partition = "odm"
+	} else if module.ProductSpecific() {
+		partition = "product"
+	} else if module.SystemExtSpecific() {
+		partition = "system_ext"
+	}
+	return "/" + partition + "/framework/" + implName + ".jar"
+}
+
+func (module *sdkLibraryXml) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	libName := proptools.String(module.properties.Lib_name)
+	xmlContent := fmt.Sprintf(permissionsTemplate, libName, module.implPath())
+
+	module.outputFilePath = android.PathForModuleOut(ctx, libName+".xml").OutputPath
+	rule := android.NewRuleBuilder()
+	rule.Command().
+		Text("/bin/bash -c \"echo -e '" + xmlContent + "'\" > ").
+		Output(module.outputFilePath)
+
+	rule.Build(pctx, ctx, "java_sdk_xml", "Permission XML")
+
+	module.installDirPath = android.PathForModuleInstall(ctx, "etc", module.SubDir())
+}
+
+func (module *sdkLibraryXml) AndroidMkEntries() []android.AndroidMkEntries {
+	if !module.IsForPlatform() {
+		return []android.AndroidMkEntries{android.AndroidMkEntries{
+			Disabled: true,
+		}}
+	}
+
+	return []android.AndroidMkEntries{android.AndroidMkEntries{
+		Class:      "ETC",
+		OutputFile: android.OptionalPathForPath(module.outputFilePath),
+		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+			func(entries *android.AndroidMkEntries) {
+				entries.SetString("LOCAL_MODULE_TAGS", "optional")
+				entries.SetString("LOCAL_MODULE_PATH", module.installDirPath.ToMakePath().String())
+				entries.SetString("LOCAL_INSTALLED_MODULE_STEM", module.outputFilePath.Base())
+			},
+		},
+	}}
+}
diff --git a/java/system_modules.go b/java/system_modules.go
index 731503f..47de6e3 100644
--- a/java/system_modules.go
+++ b/java/system_modules.go
@@ -117,6 +117,15 @@
 	return module
 }
 
+type SystemModulesProvider interface {
+	HeaderJars() android.Paths
+	OutputDirAndDeps() (android.Path, android.Paths)
+}
+
+var _ SystemModulesProvider = (*SystemModules)(nil)
+
+var _ SystemModulesProvider = (*systemModulesImport)(nil)
+
 type SystemModules struct {
 	android.ModuleBase
 	android.DefaultableModuleBase
@@ -136,6 +145,17 @@
 	Libs []string
 }
 
+func (system *SystemModules) HeaderJars() android.Paths {
+	return system.headerJars
+}
+
+func (system *SystemModules) OutputDirAndDeps() (android.Path, android.Paths) {
+	if system.outputDir == nil || len(system.outputDeps) == 0 {
+		panic("Missing directory for system module dependency")
+	}
+	return system.outputDir, system.outputDeps
+}
+
 func (system *SystemModules) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	var jars android.Paths
 
diff --git a/scripts/manifest_fixer.py b/scripts/manifest_fixer.py
index 945bc18..c59732b 100755
--- a/scripts/manifest_fixer.py
+++ b/scripts/manifest_fixer.py
@@ -51,6 +51,9 @@
                       help='specify additional <uses-library> tag to add. android:requred is set to false')
   parser.add_argument('--uses-non-sdk-api', dest='uses_non_sdk_api', action='store_true',
                       help='manifest is for a package built against the platform')
+  parser.add_argument('--logging-parent', dest='logging_parent', default='',
+                      help=('specify logging parent as an additional <meta-data> tag. '
+                            'This value is ignored if the logging_parent meta-data tag is present.'))
   parser.add_argument('--use-embedded-dex', dest='use_embedded_dex', action='store_true',
                       help=('specify if the app wants to use embedded dex and avoid extracted,'
                             'locally compiled code. Must not conflict if already declared '
@@ -124,6 +127,52 @@
     element.setAttributeNode(target_attr)
 
 
+def add_logging_parent(doc, logging_parent_value):
+  """Add logging parent as an additional <meta-data> tag.
+
+  Args:
+    doc: The XML document. May be modified by this function.
+    logging_parent_value: A string representing the logging
+      parent value.
+  Raises:
+    RuntimeError: Invalid manifest
+  """
+  manifest = parse_manifest(doc)
+
+  logging_parent_key = 'android.content.pm.LOGGING_PARENT'
+  elems = get_children_with_tag(manifest, 'application')
+  application = elems[0] if len(elems) == 1 else None
+  if len(elems) > 1:
+    raise RuntimeError('found multiple <application> tags')
+  elif not elems:
+    application = doc.createElement('application')
+    indent = get_indent(manifest.firstChild, 1)
+    first = manifest.firstChild
+    manifest.insertBefore(doc.createTextNode(indent), first)
+    manifest.insertBefore(application, first)
+
+  indent = get_indent(application.firstChild, 2)
+
+  last = application.lastChild
+  if last is not None and last.nodeType != minidom.Node.TEXT_NODE:
+    last = None
+
+  if not find_child_with_attribute(application, 'meta-data', android_ns,
+                                   'name', logging_parent_key):
+    ul = doc.createElement('meta-data')
+    ul.setAttributeNS(android_ns, 'android:name', logging_parent_key)
+    ul.setAttributeNS(android_ns, 'android:value', logging_parent_value)
+    application.insertBefore(doc.createTextNode(indent), last)
+    application.insertBefore(ul, last)
+    last = application.lastChild
+
+  # align the closing tag with the opening tag if it's not
+  # indented
+  if last and last.nodeType != minidom.Node.TEXT_NODE:
+    indent = get_indent(application.previousSibling, 1)
+    application.appendChild(doc.createTextNode(indent))
+
+
 def add_uses_libraries(doc, new_uses_libraries, required):
   """Add additional <uses-library> tags
 
@@ -291,6 +340,9 @@
     if args.uses_non_sdk_api:
       add_uses_non_sdk_api(doc)
 
+    if args.logging_parent:
+      add_logging_parent(doc, args.logging_parent)
+
     if args.use_embedded_dex:
       add_use_embedded_dex(doc)
 
diff --git a/scripts/manifest_fixer_test.py b/scripts/manifest_fixer_test.py
index ea8095e..d6e7f26 100755
--- a/scripts/manifest_fixer_test.py
+++ b/scripts/manifest_fixer_test.py
@@ -226,6 +226,47 @@
     self.assertEqual(output, expected)
 
 
+class AddLoggingParentTest(unittest.TestCase):
+  """Unit tests for add_logging_parent function."""
+
+  def add_logging_parent_test(self, input_manifest, logging_parent=None):
+    doc = minidom.parseString(input_manifest)
+    if logging_parent:
+      manifest_fixer.add_logging_parent(doc, logging_parent)
+    output = StringIO.StringIO()
+    manifest_fixer.write_xml(output, doc)
+    return output.getvalue()
+
+  manifest_tmpl = (
+      '<?xml version="1.0" encoding="utf-8"?>\n'
+      '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
+      '%s'
+      '</manifest>\n')
+
+  def uses_logging_parent(self, logging_parent=None):
+    attrs = ''
+    if logging_parent:
+      meta_text = ('<meta-data android:name="android.content.pm.LOGGING_PARENT" '
+                   'android:value="%s"/>\n') % (logging_parent)
+      attrs += '    <application>\n        %s    </application>\n' % (meta_text)
+
+    return attrs
+
+  def test_no_logging_parent(self):
+    """Tests manifest_fixer with no logging_parent."""
+    manifest_input = self.manifest_tmpl % ''
+    expected = self.manifest_tmpl % self.uses_logging_parent()
+    output = self.add_logging_parent_test(manifest_input)
+    self.assertEqual(output, expected)
+
+  def test_logging_parent(self):
+    """Tests manifest_fixer with no logging_parent."""
+    manifest_input = self.manifest_tmpl % ''
+    expected = self.manifest_tmpl % self.uses_logging_parent('FOO')
+    output = self.add_logging_parent_test(manifest_input, 'FOO')
+    self.assertEqual(output, expected)
+
+
 class AddUsesLibrariesTest(unittest.TestCase):
   """Unit tests for add_uses_libraries function."""
 
diff --git a/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go
index 9a75610..8c32d8c 100644
--- a/sdk/cc_sdk_test.go
+++ b/sdk/cc_sdk_test.go
@@ -337,6 +337,68 @@
 	)
 }
 
+func TestSnapshotWithCcBinary(t *testing.T) {
+	result := testSdkWithCc(t, `
+		module_exports {
+			name: "mymodule_exports",
+			native_binaries: ["mynativebinary"],
+		}
+
+		cc_binary {
+			name: "mynativebinary",
+			srcs: [
+				"Test.cpp",
+			],
+			compile_multilib: "both",
+			system_shared_libs: [],
+			stl: "none",
+		}
+	`)
+
+	result.CheckSnapshot("mymodule_exports", "android_common", "",
+		checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_binary {
+    name: "mymodule_exports_mynativebinary@current",
+    sdk_member_name: "mynativebinary",
+    compile_multilib: "both",
+    arch: {
+        arm64: {
+            srcs: ["arm64/bin/mynativebinary"],
+        },
+        arm: {
+            srcs: ["arm/bin/mynativebinary"],
+        },
+    },
+}
+
+cc_prebuilt_binary {
+    name: "mynativebinary",
+    prefer: false,
+    compile_multilib: "both",
+    arch: {
+        arm64: {
+            srcs: ["arm64/bin/mynativebinary"],
+        },
+        arm: {
+            srcs: ["arm/bin/mynativebinary"],
+        },
+    },
+}
+
+module_exports_snapshot {
+    name: "mymodule_exports@current",
+    native_binaries: ["mymodule_exports_mynativebinary@current"],
+}
+`),
+		checkAllCopyRules(`
+.intermediates/mynativebinary/android_arm64_armv8-a/mynativebinary -> arm64/bin/mynativebinary
+.intermediates/mynativebinary/android_arm_armv7-a-neon/mynativebinary -> arm/bin/mynativebinary
+`),
+	)
+}
+
 func TestSnapshotWithCcSharedLibrary(t *testing.T) {
 	result := testSdkWithCc(t, `
 		sdk {
diff --git a/ui/build/ninja.go b/ui/build/ninja.go
index 22ec1f1..0749fe3 100644
--- a/ui/build/ninja.go
+++ b/ui/build/ninja.go
@@ -142,6 +142,7 @@
 			"CCACHE_SLOPPINESS",
 			"CCACHE_BASEDIR",
 			"CCACHE_CPP2",
+			"CCACHE_DIR",
 		}, config.BuildBrokenNinjaUsesEnvVars()...)...)
 	}