Merge "Switch to clang-r349610"
diff --git a/Android.bp b/Android.bp
index 3215fa2..a70f73c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -61,6 +61,7 @@
         "android/prebuilt_etc.go",
         "android/proto.go",
         "android/register.go",
+        "android/sh_binary.go",
         "android/singleton.go",
         "android/testing.go",
         "android/util.go",
diff --git a/OWNERS b/OWNERS
index 7983c19..85c70df 100644
--- a/OWNERS
+++ b/OWNERS
@@ -3,4 +3,3 @@
 per-file clang.go,global.go = srhines@google.com, chh@google.com, pirama@google.com, yikong@google.com
 per-file tidy.go = srhines@google.com, chh@google.com
 per-file lto.go,pgo.go = srhines@google.com, pirama@google.com, yikong@google.com
-per-file apex.go = jiyong@google.com
diff --git a/android/prebuilt_etc.go b/android/prebuilt_etc.go
index 46d128e..42c7c2c 100644
--- a/android/prebuilt_etc.go
+++ b/android/prebuilt_etc.go
@@ -125,7 +125,8 @@
 	p.outputFilePath = PathForModuleOut(ctx, filename).OutputPath
 	p.installDirPath = PathForModuleInstall(ctx, "etc", String(p.properties.Sub_dir))
 
-	// This ensures that outputFilePath has the same name as this module.
+	// This ensures that outputFilePath has the correct name for others to
+	// use, as the source file may have a different name.
 	ctx.Build(pctx, BuildParams{
 		Rule:   Cp,
 		Output: p.outputFilePath,
diff --git a/android/sh_binary.go b/android/sh_binary.go
new file mode 100644
index 0000000..3915193
--- /dev/null
+++ b/android/sh_binary.go
@@ -0,0 +1,141 @@
+// Copyright 2019 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"
+	"io"
+)
+
+// sh_binary is for shell scripts (and batch files) that are installed as
+// executable files into .../bin/
+//
+// Do not use them for prebuilt C/C++/etc files.  Use cc_prebuilt_binary
+// instead.
+
+func init() {
+	RegisterModuleType("sh_binary", ShBinaryFactory)
+	RegisterModuleType("sh_binary_host", ShBinaryHostFactory)
+}
+
+type shBinaryProperties struct {
+	// Source file of this prebuilt.
+	Src *string `android:"arch_variant"`
+
+	// optional subdirectory under which this file is installed into
+	Sub_dir *string `android:"arch_variant"`
+
+	// optional name for the installed file. If unspecified, name of the module is used as the file name
+	Filename *string `android:"arch_variant"`
+
+	// when set to true, and filename property is not set, the name for the installed file
+	// is the same as the file name of the source file.
+	Filename_from_src *bool `android:"arch_variant"`
+
+	// Whether this module is directly installable to one of the partitions. Default: true.
+	Installable *bool
+}
+
+type ShBinary struct {
+	ModuleBase
+
+	properties shBinaryProperties
+
+	sourceFilePath Path
+	outputFilePath OutputPath
+}
+
+func (s *ShBinary) DepsMutator(ctx BottomUpMutatorContext) {
+	if s.properties.Src == nil {
+		ctx.PropertyErrorf("src", "missing prebuilt source file")
+	}
+
+	// To support ":modulename" in src
+	ExtractSourceDeps(ctx, s.properties.Src)
+}
+
+func (s *ShBinary) SourceFilePath(ctx ModuleContext) Path {
+	return ctx.ExpandSource(String(s.properties.Src), "src")
+}
+
+func (s *ShBinary) OutputFile() OutputPath {
+	return s.outputFilePath
+}
+
+func (s *ShBinary) SubDir() string {
+	return String(s.properties.Sub_dir)
+}
+
+func (s *ShBinary) Installable() bool {
+	return s.properties.Installable == nil || Bool(s.properties.Installable)
+}
+
+func (s *ShBinary) GenerateAndroidBuildActions(ctx ModuleContext) {
+	s.sourceFilePath = ctx.ExpandSource(String(s.properties.Src), "src")
+	filename := String(s.properties.Filename)
+	filename_from_src := Bool(s.properties.Filename_from_src)
+	if filename == "" {
+		if filename_from_src {
+			filename = s.sourceFilePath.Base()
+		} else {
+			filename = ctx.ModuleName()
+		}
+	} else if filename_from_src {
+		ctx.PropertyErrorf("filename_from_src", "filename is set. filename_from_src can't be true")
+		return
+	}
+	s.outputFilePath = PathForModuleOut(ctx, filename).OutputPath
+
+	// This ensures that outputFilePath has the correct name for others to
+	// use, as the source file may have a different name.
+	ctx.Build(pctx, BuildParams{
+		Rule:   CpExecutable,
+		Output: s.outputFilePath,
+		Input:  s.sourceFilePath,
+	})
+}
+
+func (s *ShBinary) AndroidMk() AndroidMkData {
+	return AndroidMkData{
+		Class:      "EXECUTABLES",
+		OutputFile: OptionalPathForPath(s.outputFilePath),
+		Include:    "$(BUILD_SYSTEM)/soong_cc_prebuilt.mk",
+		Extra: []AndroidMkExtraFunc{
+			func(w io.Writer, outputFile Path) {
+				fmt.Fprintln(w, "LOCAL_MODULE_RELATIVE_PATH :=", String(s.properties.Sub_dir))
+				fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX :=")
+				fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", s.outputFilePath.Rel())
+			},
+		},
+	}
+}
+
+func InitShBinaryModule(s *ShBinary) {
+	s.AddProperties(&s.properties)
+}
+
+func ShBinaryFactory() Module {
+	module := &ShBinary{}
+	InitShBinaryModule(module)
+	InitAndroidArchModule(module, HostAndDeviceSupported, MultilibFirst)
+	return module
+}
+
+func ShBinaryHostFactory() Module {
+	module := &ShBinary{}
+	InitShBinaryModule(module)
+	InitAndroidArchModule(module, HostSupported, MultilibFirst)
+	return module
+}
diff --git a/apex/OWNERS b/apex/OWNERS
new file mode 100644
index 0000000..a382ae8
--- /dev/null
+++ b/apex/OWNERS
@@ -0,0 +1 @@
+per-file * = jiyong@google.com
\ No newline at end of file
diff --git a/apex/apex.go b/apex/apex.go
index 96a4bd5..f6daf9b 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -177,6 +177,29 @@
 	}
 }
 
+type apexNativeDependencies struct {
+	// List of native libraries
+	Native_shared_libs []string
+	// List of native executables
+	Binaries []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"
@@ -218,36 +241,29 @@
 	// Default is false.
 	Use_vendor *bool
 
-	Multilib struct {
-		First struct {
-			// List of native libraries whose compile_multilib is "first"
-			Native_shared_libs []string
-			// List of native executables whose compile_multilib is "first"
-			Binaries []string
+	// 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
+}
+
+type apexTargetBundleProperties struct {
+	Target struct {
+		// Multilib properties only for android.
+		Android struct {
+			Multilib apexMultilibProperties
 		}
-		Both struct {
-			// List of native libraries whose compile_multilib is "both"
-			Native_shared_libs []string
-			// List of native executables whose compile_multilib is "both"
-			Binaries []string
+		// Multilib properties only for host.
+		Host struct {
+			Multilib apexMultilibProperties
 		}
-		Prefer32 struct {
-			// List of native libraries whose compile_multilib is "prefer32"
-			Native_shared_libs []string
-			// List of native executables whose compile_multilib is "prefer32"
-			Binaries []string
+		// Multilib properties only for host linux_bionic.
+		Linux_bionic struct {
+			Multilib apexMultilibProperties
 		}
-		Lib32 struct {
-			// List of native libraries whose compile_multilib is "32"
-			Native_shared_libs []string
-			// List of native executables whose compile_multilib is "32"
-			Binaries []string
-		}
-		Lib64 struct {
-			// List of native libraries whose compile_multilib is "64"
-			Native_shared_libs []string
-			// List of native executables whose compile_multilib is "64"
-			Binaries []string
+		// Multilib properties only for host linux_glibc.
+		Linux_glibc struct {
+			Multilib apexMultilibProperties
 		}
 	}
 }
@@ -329,7 +345,6 @@
 type apexFile struct {
 	builtFile  android.Path
 	moduleName string
-	archType   android.ArchType
 	installDir string
 	class      apexFileClass
 	module     android.Module
@@ -340,7 +355,8 @@
 	android.ModuleBase
 	android.DefaultableModuleBase
 
-	properties apexBundleProperties
+	properties       apexBundleProperties
+	targetProperties apexTargetBundleProperties
 
 	apexTypes apexPackaging
 
@@ -373,9 +389,26 @@
 	}, executableTag, binaries...)
 }
 
+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) {
+
 	targets := ctx.MultiTargets()
 	config := ctx.DeviceConfig()
+
+	a.combineProperties(ctx)
+
 	has32BitTarget := false
 	for _, target := range targets {
 		if target.Arch.ArchType.Multilib == "lib32" {
@@ -498,7 +531,7 @@
 	return android.InList(sanitizerName, globalSanitizerNames)
 }
 
-func getCopyManifestForNativeLibrary(cc *cc.Module) (fileToCopy android.Path, dirInApex string) {
+func getCopyManifestForNativeLibrary(cc *cc.Module, handleSpecialLibs bool) (fileToCopy android.Path, dirInApex string) {
 	// Decide the APEX-local directory by the multilib of the library
 	// In the future, we may query this to the module.
 	switch cc.Arch().ArchType.Multilib {
@@ -510,18 +543,20 @@
 	if !cc.Arch().Native {
 		dirInApex = filepath.Join(dirInApex, cc.Arch().ArchType.String())
 	}
-	switch cc.Name() {
-	case "libc", "libm", "libdl":
-		// Special case for bionic libs. This is to prevent the bionic libs
-		// from being included in the search path /apex/com.android.apex/lib.
-		// This exclusion is required because bionic libs in the runtime APEX
-		// are available via the legacy paths /system/lib/libc.so, etc. By the
-		// init process, the bionic libs in the APEX are bind-mounted to the
-		// legacy paths and thus will be loaded into the default linker namespace.
-		// If the bionic libs are directly in /apex/com.android.apex/lib then
-		// the same libs will be again loaded to the runtime linker namespace,
-		// which will result double loading of bionic libs that isn't supported.
-		dirInApex = filepath.Join(dirInApex, "bionic")
+	if handleSpecialLibs {
+		switch cc.Name() {
+		case "libc", "libm", "libdl":
+			// Special case for bionic libs. This is to prevent the bionic libs
+			// from being included in the search path /apex/com.android.apex/lib.
+			// This exclusion is required because bionic libs in the runtime APEX
+			// are available via the legacy paths /system/lib/libc.so, etc. By the
+			// init process, the bionic libs in the APEX are bind-mounted to the
+			// legacy paths and thus will be loaded into the default linker namespace.
+			// If the bionic libs are directly in /apex/com.android.apex/lib then
+			// the same libs will be again loaded to the runtime linker namespace,
+			// which will result double loading of bionic libs that isn't supported.
+			dirInApex = filepath.Join(dirInApex, "bionic")
+		}
 	}
 
 	fileToCopy = cc.OutputFile().Path()
@@ -564,6 +599,8 @@
 		return
 	}
 
+	handleSpecialLibs := !android.Bool(a.properties.Ignore_system_library_special_case)
+
 	ctx.WalkDeps(func(child, parent android.Module) bool {
 		if _, ok := parent.(*apexBundle); ok {
 			// direct dependencies
@@ -572,8 +609,8 @@
 			switch depTag {
 			case sharedLibTag:
 				if cc, ok := child.(*cc.Module); ok {
-					fileToCopy, dirInApex := getCopyManifestForNativeLibrary(cc)
-					filesInfo = append(filesInfo, apexFile{fileToCopy, depName, cc.Arch().ArchType, dirInApex, nativeSharedLib, cc, nil})
+					fileToCopy, dirInApex := getCopyManifestForNativeLibrary(cc, handleSpecialLibs)
+					filesInfo = append(filesInfo, apexFile{fileToCopy, depName, dirInApex, nativeSharedLib, cc, nil})
 					return true
 				} else {
 					ctx.PropertyErrorf("native_shared_libs", "%q is not a cc_library or cc_library_shared module", depName)
@@ -586,7 +623,7 @@
 						return true
 					}
 					fileToCopy, dirInApex := getCopyManifestForExecutable(cc)
-					filesInfo = append(filesInfo, apexFile{fileToCopy, depName, cc.Arch().ArchType, dirInApex, nativeExecutable, cc, cc.Symlinks()})
+					filesInfo = append(filesInfo, apexFile{fileToCopy, depName, dirInApex, nativeExecutable, cc, cc.Symlinks()})
 					return true
 				} else {
 					ctx.PropertyErrorf("binaries", "%q is not a cc_binary module", depName)
@@ -597,7 +634,7 @@
 					if fileToCopy == nil {
 						ctx.PropertyErrorf("java_libs", "%q is not configured to be compiled into dex", depName)
 					} else {
-						filesInfo = append(filesInfo, apexFile{fileToCopy, depName, java.Arch().ArchType, dirInApex, javaSharedLib, java, nil})
+						filesInfo = append(filesInfo, apexFile{fileToCopy, depName, dirInApex, javaSharedLib, java, nil})
 					}
 					return true
 				} else {
@@ -606,7 +643,7 @@
 			case prebuiltTag:
 				if prebuilt, ok := child.(*android.PrebuiltEtc); ok {
 					fileToCopy, dirInApex := getCopyManifestForPrebuiltEtc(prebuilt)
-					filesInfo = append(filesInfo, apexFile{fileToCopy, depName, prebuilt.Arch().ArchType, dirInApex, etc, prebuilt, nil})
+					filesInfo = append(filesInfo, apexFile{fileToCopy, depName, dirInApex, etc, prebuilt, nil})
 					return true
 				} else {
 					ctx.PropertyErrorf("prebuilts", "%q is not a prebuilt_etc module", depName)
@@ -640,8 +677,8 @@
 						return false
 					}
 					depName := ctx.OtherModuleName(child)
-					fileToCopy, dirInApex := getCopyManifestForNativeLibrary(cc)
-					filesInfo = append(filesInfo, apexFile{fileToCopy, depName, cc.Arch().ArchType, dirInApex, nativeSharedLib, cc, nil})
+					fileToCopy, dirInApex := getCopyManifestForNativeLibrary(cc, handleSpecialLibs)
+					filesInfo = append(filesInfo, apexFile{fileToCopy, depName, dirInApex, nativeSharedLib, cc, nil})
 					return true
 				}
 			}
@@ -888,7 +925,7 @@
 			Input:  manifest,
 			Output: copiedManifest,
 		})
-		a.filesInfo = append(a.filesInfo, apexFile{copiedManifest, ctx.ModuleName() + ".apex_manifest.json", android.Common, ".", etc, nil, nil})
+		a.filesInfo = append(a.filesInfo, apexFile{copiedManifest, ctx.ModuleName() + ".apex_manifest.json", ".", etc, nil, nil})
 
 		for _, fi := range a.filesInfo {
 			dir := filepath.Join("apex", ctx.ModuleName(), fi.installDir)
@@ -914,57 +951,92 @@
 }
 
 func (a *apexBundle) androidMkForType(apexType apexPackaging) android.AndroidMkData {
-	// Only image APEXes can be flattened.
-	if a.flattened && apexType.image() {
-		return android.AndroidMkData{
-			Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
-				moduleNames := []string{}
-				for _, fi := range a.filesInfo {
-					if !android.InList(fi.moduleName, moduleNames) {
-						moduleNames = append(moduleNames, fi.moduleName)
+	return android.AndroidMkData{
+		Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
+			moduleNames := []string{}
+			for _, fi := range a.filesInfo {
+				if !android.InList(fi.moduleName, moduleNames) {
+					moduleNames = append(moduleNames, fi.moduleName)
+				}
+			}
+
+			for _, fi := range a.filesInfo {
+				if cc, ok := fi.module.(*cc.Module); ok && cc.Properties.HideFromMake {
+					continue
+				}
+				fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)")
+				fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
+				fmt.Fprintln(w, "LOCAL_MODULE :=", fi.moduleName)
+				if a.flattened {
+					// /system/apex/<name>/{lib|framework|...}
+					fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", filepath.Join("$(OUT_DIR)",
+						a.installDir.RelPathString(), name, fi.installDir))
+				} else {
+					// /apex/<name>/{lib|framework|...}
+					fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", filepath.Join("$(PRODUCT_OUT)",
+						"apex", name, fi.installDir))
+				}
+				fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", fi.builtFile.String())
+				fmt.Fprintln(w, "LOCAL_MODULE_CLASS :=", fi.class.NameInMake())
+				fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE :=", !a.installable())
+				if fi.module != nil {
+					archStr := fi.module.Target().Arch.ArchType.String()
+					host := false
+					switch fi.module.Target().Os.Class {
+					case android.Host:
+						if archStr != "common" {
+							fmt.Fprintln(w, "LOCAL_MODULE_HOST_ARCH :=", archStr)
+						}
+						host = true
+					case android.HostCross:
+						if archStr != "common" {
+							fmt.Fprintln(w, "LOCAL_MODULE_HOST_CROSS_ARCH :=", archStr)
+						}
+						host = true
+					case android.Device:
+						if archStr != "common" {
+							fmt.Fprintln(w, "LOCAL_MODULE_TARGET_ARCH :=", archStr)
+						}
+					}
+					if host {
+						makeOs := fi.module.Target().Os.String()
+						if fi.module.Target().Os == android.Linux || fi.module.Target().Os == android.LinuxBionic {
+							makeOs = "linux"
+						}
+						fmt.Fprintln(w, "LOCAL_MODULE_HOST_OS :=", makeOs)
+						fmt.Fprintln(w, "LOCAL_IS_HOST_MODULE := true")
 					}
 				}
+				if fi.class == javaSharedLib {
+					javaModule := fi.module.(*java.Library)
+					// soong_java_prebuilt.mk sets LOCAL_MODULE_SUFFIX := .jar  Therefore
+					// we need to remove the suffix from LOCAL_MODULE_STEM, otherwise
+					// we will have foo.jar.jar
+					fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", strings.TrimSuffix(fi.builtFile.Base(), ".jar"))
+					fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", javaModule.ImplementationAndResourcesJars()[0].String())
+					fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", javaModule.HeaderJars()[0].String())
+					fmt.Fprintln(w, "LOCAL_SOONG_DEX_JAR :=", fi.builtFile.String())
+					fmt.Fprintln(w, "LOCAL_DEX_PREOPT := false")
+					fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_java_prebuilt.mk")
+				} else if fi.class == nativeSharedLib || fi.class == nativeExecutable {
+					fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", fi.builtFile.Base())
+					if cc, ok := fi.module.(*cc.Module); ok && cc.UnstrippedOutputFile() != nil {
+						fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", cc.UnstrippedOutputFile().String())
+					}
+					fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_cc_prebuilt.mk")
+				} else {
+					fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", fi.builtFile.Base())
+					fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
+				}
+			}
+			if a.flattened && apexType.image() {
+				// Only image APEXes can be flattened.
 				fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)")
 				fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
 				fmt.Fprintln(w, "LOCAL_MODULE :=", name)
 				fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", strings.Join(moduleNames, " "))
 				fmt.Fprintln(w, "include $(BUILD_PHONY_PACKAGE)")
-
-				for _, fi := range a.filesInfo {
-					if cc, ok := fi.module.(*cc.Module); ok && cc.Properties.HideFromMake {
-						continue
-					}
-					fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)")
-					fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
-					fmt.Fprintln(w, "LOCAL_MODULE :=", fi.moduleName)
-					fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", filepath.Join("$(OUT_DIR)", a.installDir.RelPathString(), name, fi.installDir))
-					fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", fi.builtFile.String())
-					fmt.Fprintln(w, "LOCAL_MODULE_CLASS :=", fi.class.NameInMake())
-					fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE :=", !a.installable())
-					archStr := fi.archType.String()
-					if archStr != "common" {
-						fmt.Fprintln(w, "LOCAL_MODULE_TARGET_ARCH :=", archStr)
-					}
-					if fi.class == javaSharedLib {
-						javaModule := fi.module.(*java.Library)
-						// soong_java_prebuilt.mk sets LOCAL_MODULE_SUFFIX := .jar  Therefore
-						// we need to remove the suffix from LOCAL_MODULE_STEM, otherwise
-						// we will have foo.jar.jar
-						fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", strings.TrimSuffix(fi.builtFile.Base(), ".jar"))
-						fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", javaModule.ImplementationAndResourcesJars()[0].String())
-						fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", javaModule.HeaderJars()[0].String())
-						fmt.Fprintln(w, "LOCAL_SOONG_DEX_JAR :=", fi.builtFile.String())
-						fmt.Fprintln(w, "LOCAL_DEX_PREOPT := false")
-						fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_java_prebuilt.mk")
-					} else {
-						fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", fi.builtFile.Base())
-						fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
-					}
-				}
-			}}
-	} else {
-		return android.AndroidMkData{
-			Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
+			} else {
 				// zip-apex is the less common type so have the name refer to the image-apex
 				// only and use {name}.zip if you want the zip-apex
 				if apexType == zipApex && a.apexTypes == both {
@@ -979,13 +1051,14 @@
 				fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", name+apexType.suffix())
 				fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE :=", !a.installable())
 				fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", String(a.properties.Key))
+				fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES +=", strings.Join(moduleNames, " "))
 				fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
 
 				if apexType == imageApex {
 					fmt.Fprintln(w, "ALL_MODULES.$(LOCAL_MODULE).BUNDLE :=", a.bundleModuleFile.String())
 				}
-			}}
-	}
+			}
+		}}
 }
 
 func ApexBundleFactory() android.Module {
@@ -993,6 +1066,7 @@
 		outputFiles: map[apexPackaging]android.WritablePath{},
 	}
 	module.AddProperties(&module.properties)
+	module.AddProperties(&module.targetProperties)
 	module.Prefer32(func(ctx android.BaseModuleContext, base *android.ModuleBase, class android.OsClass) bool {
 		return class == android.Device && ctx.Config().DevicePrefer32BitExecutables()
 	})
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 7ae49f6..9d33060 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -864,3 +864,83 @@
 	// Ensure that the include path of the header lib is exported to 'otherlib'
 	ensureContains(t, cFlags, "-Imy_include")
 }
+
+func TestApexWithTarget(t *testing.T) {
+	ctx := testApex(t, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			multilib: {
+				first: {
+					native_shared_libs: ["mylib_common"],
+				}
+			},
+			target: {
+				android: {
+					multilib: {
+						first: {
+							native_shared_libs: ["mylib"],
+						}
+					}
+				},
+				host: {
+					multilib: {
+						first: {
+							native_shared_libs: ["mylib2"],
+						}
+					}
+				}
+			}
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		cc_library {
+			name: "mylib",
+			srcs: ["mylib.cpp"],
+			system_shared_libs: [],
+			stl: "none",
+		}
+
+		cc_library {
+			name: "mylib_common",
+			srcs: ["mylib.cpp"],
+			system_shared_libs: [],
+			stl: "none",
+			compile_multilib: "first",
+		}
+
+		cc_library {
+			name: "mylib2",
+			srcs: ["mylib.cpp"],
+			system_shared_libs: [],
+			stl: "none",
+			compile_multilib: "first",
+		}
+	`)
+
+	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
+	copyCmds := apexRule.Args["copy_commands"]
+
+	// Ensure that main rule creates an output
+	ensureContains(t, apexRule.Output.String(), "myapex.apex.unsigned")
+
+	// Ensure that apex variant is created for the direct dep
+	ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_core_shared_myapex")
+	ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common"), "android_arm64_armv8-a_core_shared_myapex")
+	ensureListNotContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_core_shared_myapex")
+
+	// Ensure that both direct and indirect deps are copied into apex
+	ensureContains(t, copyCmds, "image.apex/lib64/mylib.so")
+	ensureContains(t, copyCmds, "image.apex/lib64/mylib_common.so")
+	ensureNotContains(t, copyCmds, "image.apex/lib64/mylib2.so")
+
+	// Ensure that the platform variant ends with _core_shared
+	ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_core_shared")
+	ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common"), "android_arm64_armv8-a_core_shared")
+	ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_core_shared")
+}
diff --git a/cc/binary.go b/cc/binary.go
index 4c86371..a8eb641 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -249,7 +249,11 @@
 				} else {
 					switch ctx.Os() {
 					case android.Android:
-						flags.DynamicLinker = "/system/bin/linker"
+						if ctx.bootstrap() {
+							flags.DynamicLinker = "/system/bin/bootstrap/linker"
+						} else {
+							flags.DynamicLinker = "/system/bin/linker"
+						}
 						if flags.Toolchain.Is64Bit() {
 							flags.DynamicLinker += "64"
 						}
@@ -401,6 +405,10 @@
 	return ret
 }
 
+func (binary *binaryDecorator) unstrippedOutputFilePath() android.Path {
+	return binary.unstrippedOutputFile
+}
+
 func (binary *binaryDecorator) symlinkList() []string {
 	return binary.symlinks
 }
diff --git a/cc/builder.go b/cc/builder.go
index b012d6f..645b3c2 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -663,18 +663,33 @@
 // Generate a rule to combine .dump sAbi dump files from multiple source files
 // into a single .ldump sAbi dump file
 func TransformDumpToLinkedDump(ctx android.ModuleContext, sAbiDumps android.Paths, soFile android.Path,
-	baseName, exportedHeaderFlags string) android.OptionalPath {
+	baseName, exportedHeaderFlags string, symbolFile android.OptionalPath,
+	excludedSymbolVersions, excludedSymbolTags []string) android.OptionalPath {
+
 	outputFile := android.PathForModuleOut(ctx, baseName+".lsdump")
 	sabiLock.Lock()
 	lsdumpPaths = append(lsdumpPaths, outputFile.String())
 	sabiLock.Unlock()
+
+	implicits := android.Paths{soFile}
 	symbolFilterStr := "-so " + soFile.String()
+
+	if symbolFile.Valid() {
+		implicits = append(implicits, symbolFile.Path())
+		symbolFilterStr += " -v " + symbolFile.String()
+	}
+	for _, ver := range excludedSymbolVersions {
+		symbolFilterStr += " --exclude-symbol-version " + ver
+	}
+	for _, tag := range excludedSymbolTags {
+		symbolFilterStr += " --exclude-symbol-tag " + tag
+	}
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        sAbiLink,
 		Description: "header-abi-linker " + outputFile.Base(),
 		Output:      outputFile,
 		Inputs:      sAbiDumps,
-		Implicit:    soFile,
+		Implicits:   implicits,
 		Args: map[string]string{
 			"symbolFilter":        symbolFilterStr,
 			"arch":                ctx.Arch().ArchType.Name,
diff --git a/cc/cc.go b/cc/cc.go
index a30708a..4c26e60 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -261,6 +261,7 @@
 	apexName() string
 	hasStubsVariants() bool
 	isStubs() bool
+	bootstrap() bool
 }
 
 type ModuleContext interface {
@@ -305,6 +306,7 @@
 
 	link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path
 	appendLdflags([]string)
+	unstrippedOutputFilePath() android.Path
 }
 
 type installer interface {
@@ -404,6 +406,13 @@
 	return c.outputFile
 }
 
+func (c *Module) UnstrippedOutputFile() android.Path {
+	if c.linker != nil {
+		return c.linker.unstrippedOutputFilePath()
+	}
+	return nil
+}
+
 func (c *Module) Init() android.Module {
 	c.AddProperties(&c.Properties, &c.VendorProperties)
 	if c.compiler != nil {
@@ -562,6 +571,10 @@
 	return false
 }
 
+func (c *Module) bootstrap() bool {
+	return Bool(c.Properties.Bootstrap)
+}
+
 type baseModuleContext struct {
 	android.BaseContext
 	moduleContextImpl
@@ -732,6 +745,10 @@
 	return ctx.mod.IsStubs()
 }
 
+func (ctx *moduleContextImpl) bootstrap() bool {
+	return ctx.mod.bootstrap()
+}
+
 func newBaseModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Module {
 	return &Module{
 		hod:      hod,
@@ -1166,15 +1183,9 @@
 			depTag = headerExportDepTag
 		}
 		if buildStubs {
-			imageVariation := "core"
-			if c.useVndk() {
-				imageVariation = "vendor"
-			} else if c.inRecovery() {
-				imageVariation = "recovery"
-			}
 			actx.AddFarVariationDependencies([]blueprint.Variation{
 				{Mutator: "arch", Variation: ctx.Target().String()},
-				{Mutator: "image", Variation: imageVariation},
+				{Mutator: "image", Variation: c.imageVariation()},
 			}, depTag, lib)
 		} else {
 			actx.AddVariationDependencies(nil, depTag, lib)
@@ -1550,7 +1561,7 @@
 					// If not building for APEX, use stubs only when it is from
 					// an APEX (and not from platform)
 					useThisDep = (depInPlatform != depIsStubs)
-					if c.inRecovery() || Bool(c.Properties.Bootstrap) {
+					if c.inRecovery() || c.bootstrap() {
 						// However, for recovery or bootstrap modules,
 						// always link to non-stub variant
 						useThisDep = !depIsStubs
@@ -1836,6 +1847,16 @@
 	return false
 }
 
+func (c *Module) imageVariation() string {
+	variation := "core"
+	if c.useVndk() {
+		variation = "vendor"
+	} else if c.inRecovery() {
+		variation = "recovery"
+	}
+	return variation
+}
+
 //
 // Defaults
 //
diff --git a/cc/library.go b/cc/library.go
index ad07db4..13acfae 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -87,6 +87,19 @@
 	// binaries would be installed by default (in PRODUCT_PACKAGES) the other library will be removed
 	// from PRODUCT_PACKAGES.
 	Overrides []string
+
+	// Properties for ABI compatibility checker
+	Header_abi_checker struct {
+		// Path to a symbol file that specifies the symbols to be included in the generated
+		// ABI dump file
+		Symbol_file *string
+
+		// Symbol versions that should be ignored from the symbol file
+		Exclude_symbol_versions []string
+
+		// Symbol tags that should be ignored from the symbol file
+		Exclude_symbol_tags []string
+	}
 }
 
 type LibraryMutatedProperties struct {
@@ -567,11 +580,15 @@
 		deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, library.baseLinker.Properties.Target.Vendor.Exclude_static_libs)
 		deps.SharedLibs = removeListFromList(deps.SharedLibs, library.baseLinker.Properties.Target.Vendor.Exclude_shared_libs)
 		deps.StaticLibs = removeListFromList(deps.StaticLibs, library.baseLinker.Properties.Target.Vendor.Exclude_static_libs)
+		deps.ReexportSharedLibHeaders = removeListFromList(deps.ReexportSharedLibHeaders, library.baseLinker.Properties.Target.Vendor.Exclude_shared_libs)
+		deps.ReexportStaticLibHeaders = removeListFromList(deps.ReexportStaticLibHeaders, library.baseLinker.Properties.Target.Vendor.Exclude_static_libs)
 	}
 	if ctx.inRecovery() {
 		deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, library.baseLinker.Properties.Target.Recovery.Exclude_static_libs)
 		deps.SharedLibs = removeListFromList(deps.SharedLibs, library.baseLinker.Properties.Target.Recovery.Exclude_shared_libs)
 		deps.StaticLibs = removeListFromList(deps.StaticLibs, library.baseLinker.Properties.Target.Recovery.Exclude_static_libs)
+		deps.ReexportSharedLibHeaders = removeListFromList(deps.ReexportSharedLibHeaders, library.baseLinker.Properties.Target.Recovery.Exclude_shared_libs)
+		deps.ReexportStaticLibHeaders = removeListFromList(deps.ReexportStaticLibHeaders, library.baseLinker.Properties.Target.Recovery.Exclude_static_libs)
 	}
 
 	android.ExtractSourceDeps(ctx, library.Properties.Unexported_symbols_list)
@@ -723,6 +740,10 @@
 	return ret
 }
 
+func (library *libraryDecorator) unstrippedOutputFilePath() android.Path {
+	return library.unstrippedOutputFile
+}
+
 func getRefAbiDumpFile(ctx ModuleContext, vndkVersion, fileName string) android.Path {
 	isLlndk := inList(ctx.baseModuleName(), llndkLibraries) || inList(ctx.baseModuleName(), ndkMigratedLibs)
 
@@ -760,7 +781,10 @@
 			SourceAbiFlags = append(SourceAbiFlags, reexportedInclude)
 		}
 		exportedHeaderFlags := strings.Join(SourceAbiFlags, " ")
-		library.sAbiOutputFile = TransformDumpToLinkedDump(ctx, objs.sAbiDumpFiles, soFile, fileName, exportedHeaderFlags)
+		library.sAbiOutputFile = TransformDumpToLinkedDump(ctx, objs.sAbiDumpFiles, soFile, fileName, exportedHeaderFlags,
+			android.OptionalPathForModuleSrc(ctx, library.Properties.Header_abi_checker.Symbol_file),
+			library.Properties.Header_abi_checker.Exclude_symbol_versions,
+			library.Properties.Header_abi_checker.Exclude_symbol_tags)
 
 		refAbiDumpFile := getRefAbiDumpFile(ctx, vndkVersion, fileName)
 		if refAbiDumpFile != nil {
@@ -867,6 +891,18 @@
 					library.baseInstaller.subDir += "-" + vndkVersion
 				}
 			}
+		} else if len(library.Properties.Stubs.Versions) > 0 && android.DirectlyInAnyApex(ctx, ctx.ModuleName()) {
+			// If a library in an APEX has stable versioned APIs, we basically don't need
+			// to have the platform variant of the library in /system partition because
+			// platform components can just use the lib from the APEX without fearing about
+			// compatibility. However, if the library is required for some early processes
+			// before the APEX is activated, the platform variant may also be required.
+			// In that case, it is installed to the subdirectory 'bootstrap' in order to
+			// be distinguished/isolated from other non-bootstrap libraries in /system/lib
+			// so that the bootstrap libraries are used only when the APEX isn't ready.
+			if !library.buildStubs() && ctx.Arch().Native {
+				library.baseInstaller.subDir = "bootstrap"
+			}
 		}
 		library.baseInstaller.install(ctx, file)
 	}
diff --git a/cc/object.go b/cc/object.go
index 552f639..b9c5742 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -107,3 +107,7 @@
 	ctx.CheckbuildFile(outputFile)
 	return outputFile
 }
+
+func (object *objectLinker) unstrippedOutputFilePath() android.Path {
+	return nil
+}
diff --git a/cc/sanitize.go b/cc/sanitize.go
index b95e2a8..b9787f0 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -79,7 +79,8 @@
 	scs
 )
 
-func (t sanitizerType) String() string {
+// Name of the sanitizer variation for this sanitizer type
+func (t sanitizerType) variationName() string {
 	switch t {
 	case asan:
 		return "asan"
@@ -98,6 +99,26 @@
 	}
 }
 
+// This is the sanitizer names in SANITIZE_[TARGET|HOST]
+func (t sanitizerType) name() string {
+	switch t {
+	case asan:
+		return "address"
+	case hwasan:
+		return "hwaddress"
+	case tsan:
+		return "thread"
+	case intOverflow:
+		return "integer_overflow"
+	case cfi:
+		return "cfi"
+	case scs:
+		return "shadow-call-stack"
+	default:
+		panic(fmt.Errorf("unknown sanitizerType %d", t))
+	}
+}
+
 type SanitizeProperties struct {
 	// enable AddressSanitizer, ThreadSanitizer, or UndefinedBehaviorSanitizer
 	Sanitize struct {
@@ -787,7 +808,7 @@
 		}
 
 		if mctx.Device() && runtimeLibrary != "" {
-			if inList(runtimeLibrary, llndkLibraries) && !c.static() {
+			if inList(runtimeLibrary, llndkLibraries) && !c.static() && c.useVndk() {
 				runtimeLibrary = runtimeLibrary + llndkLibrarySuffix
 			}
 
@@ -802,12 +823,14 @@
 				// static executable gets static runtime libs
 				mctx.AddFarVariationDependencies([]blueprint.Variation{
 					{Mutator: "link", Variation: "static"},
+					{Mutator: "image", Variation: c.imageVariation()},
 					{Mutator: "arch", Variation: mctx.Target().String()},
 				}, staticDepTag, runtimeLibrary)
 			} else if !c.static() {
-				// dynamic executable andshared libs get shared runtime libs
+				// dynamic executable and shared libs get shared runtime libs
 				mctx.AddFarVariationDependencies([]blueprint.Variation{
 					{Mutator: "link", Variation: "shared"},
+					{Mutator: "image", Variation: c.imageVariation()},
 					{Mutator: "arch", Variation: mctx.Target().String()},
 				}, earlySharedDepTag, runtimeLibrary)
 			}
@@ -828,14 +851,14 @@
 	return func(mctx android.BottomUpMutatorContext) {
 		if c, ok := mctx.Module().(*Module); ok && c.sanitize != nil {
 			if c.isDependencyRoot() && c.sanitize.isSanitizerEnabled(t) {
-				modules := mctx.CreateVariations(t.String())
+				modules := mctx.CreateVariations(t.variationName())
 				modules[0].(*Module).sanitize.SetSanitizer(t, true)
 			} else if c.sanitize.isSanitizerEnabled(t) || c.sanitize.Properties.SanitizeDep {
 				// Save original sanitizer status before we assign values to variant
 				// 0 as that overwrites the original.
 				isSanitizerEnabled := c.sanitize.isSanitizerEnabled(t)
 
-				modules := mctx.CreateVariations("", t.String())
+				modules := mctx.CreateVariations("", t.variationName())
 				modules[0].(*Module).sanitize.SetSanitizer(t, false)
 				modules[1].(*Module).sanitize.SetSanitizer(t, true)
 
@@ -924,9 +947,9 @@
 				}
 			}
 			c.sanitize.Properties.SanitizeDep = false
-		} else if sanitizeable, ok := mctx.Module().(Sanitizeable); ok && sanitizeable.IsSanitizerEnabled(mctx, t.String()) {
+		} else if sanitizeable, ok := mctx.Module().(Sanitizeable); ok && sanitizeable.IsSanitizerEnabled(mctx, t.name()) {
 			// APEX modules fall here
-			mctx.CreateVariations(t.String())
+			mctx.CreateVariations(t.variationName())
 		}
 	}
 }
diff --git a/cc/xom.go b/cc/xom.go
index 182069f..9337990 100644
--- a/cc/xom.go
+++ b/cc/xom.go
@@ -50,7 +50,7 @@
 	// If any static dependencies have XOM disabled, we should disable XOM in this module,
 	// the assumption being if it's been explicitly disabled then there's probably incompatible
 	// code in the library which may get pulled in.
-	if !ctx.static() && !disableXom {
+	if !disableXom {
 		ctx.VisitDirectDeps(func(m android.Module) {
 			cc, ok := m.(*Module)
 			if !ok || cc.xom == nil || !cc.static() {
diff --git a/java/android_resources.go b/java/android_resources.go
index 47535d2..efd3e3d 100644
--- a/java/android_resources.go
+++ b/java/android_resources.go
@@ -44,10 +44,6 @@
 type overlayGlobResult struct {
 	dir   string
 	paths android.DirectorySortedPaths
-
-	// Set to true of the product has selected that values in this overlay should not be moved to
-	// Runtime Resource Overlay (RRO) packages.
-	excludeFromRRO bool
 }
 
 const overlayDataKey = "overlayDataKey"
@@ -69,10 +65,11 @@
 		files := data.paths.PathsInDirectory(filepath.Join(data.dir, dir.String()))
 		if len(files) > 0 {
 			overlayModuleDir := android.PathForSource(ctx, data.dir, dir.String())
+
 			// If enforce RRO is enabled for this module and this overlay is not in the
 			// exclusion list, ignore the overlay.  The list of ignored overlays will be
 			// passed to Make to be turned into an RRO package.
-			if rroEnabled && !data.excludeFromRRO {
+			if rroEnabled && !ctx.Config().EnforceRROExcludedOverlay(overlayModuleDir.String()) {
 				rroDirs = append(rroDirs, overlayModuleDir)
 			} else {
 				res = append(res, globbedResourceDir{
@@ -102,10 +99,6 @@
 		var result overlayGlobResult
 		result.dir = overlay
 
-		// Mark overlays that will not have Runtime Resource Overlays enforced on them
-		// based on the product config
-		result.excludeFromRRO = ctx.Config().EnforceRROExcludedOverlay(overlay)
-
 		files, err := ctx.GlobWithDeps(filepath.Join(overlay, "**/*"), androidResourceIgnoreFilenames)
 		if err != nil {
 			ctx.Errorf("failed to glob resource dir %q: %s", overlay, err.Error())
diff --git a/java/androidmk.go b/java/androidmk.go
index ccb5109..089ed4f 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -381,6 +381,15 @@
 					fmt.Fprintln(w, ".PHONY:", ddoc.Name()+"-check-last-released-api")
 					fmt.Fprintln(w, ddoc.Name()+"-check-last-released-api:",
 						ddoc.checkLastReleasedApiTimestamp.String())
+
+					if ddoc.Name() == "api-stubs-docs" || ddoc.Name() == "system-api-stubs-docs" {
+						fmt.Fprintln(w, ".PHONY: checkapi")
+						fmt.Fprintln(w, "checkapi:",
+							ddoc.checkLastReleasedApiTimestamp.String())
+
+						fmt.Fprintln(w, ".PHONY: droidcore")
+						fmt.Fprintln(w, "droidcore: checkapi")
+					}
 				}
 				apiFilePrefix := "INTERNAL_PLATFORM_"
 				if String(ddoc.properties.Api_tag_name) != "" {
@@ -459,6 +468,15 @@
 					fmt.Fprintln(w, ".PHONY:", dstubs.Name()+"-check-last-released-api")
 					fmt.Fprintln(w, dstubs.Name()+"-check-last-released-api:",
 						dstubs.checkLastReleasedApiTimestamp.String())
+
+					if dstubs.Name() == "api-stubs-docs" || dstubs.Name() == "system-api-stubs-docs" {
+						fmt.Fprintln(w, ".PHONY: checkapi")
+						fmt.Fprintln(w, "checkapi:",
+							dstubs.checkLastReleasedApiTimestamp.String())
+
+						fmt.Fprintln(w, ".PHONY: droidcore")
+						fmt.Fprintln(w, "droidcore: checkapi")
+					}
 				}
 				if dstubs.checkNullabilityWarningsTimestamp != nil {
 					fmt.Fprintln(w, ".PHONY:", dstubs.Name()+"-check-nullability-warnings")
diff --git a/java/app_test.go b/java/app_test.go
index 7e06dba..21bda3c 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -149,9 +149,13 @@
 		},
 	},
 	{
-		name:                       "enforce RRO on all",
-		enforceRROTargets:          []string{"*"},
-		enforceRROExcludedOverlays: []string{"device/vendor/blah/static_overlay"},
+		name:              "enforce RRO on all",
+		enforceRROTargets: []string{"*"},
+		enforceRROExcludedOverlays: []string{
+			// Excluding specific apps/res directories also allowed.
+			"device/vendor/blah/static_overlay/foo",
+			"device/vendor/blah/static_overlay/bar/res",
+		},
 		overlayFiles: map[string][]string{
 			"foo": []string{"device/vendor/blah/static_overlay/foo/res/values/strings.xml"},
 			"bar": []string{"device/vendor/blah/static_overlay/bar/res/values/strings.xml"},
@@ -208,11 +212,12 @@
 
 			getOverlays := func(moduleName string) ([]string, []string) {
 				module := ctx.ModuleForTests(moduleName, "android_common")
-				overlayCompiledPaths := module.Output("aapt2/overlay.list").Inputs.Strings()
-
+				overlayFile := module.MaybeOutput("aapt2/overlay.list")
 				var overlayFiles []string
-				for _, o := range overlayCompiledPaths {
-					overlayFiles = append(overlayFiles, module.Output(o).Inputs.Strings()...)
+				if overlayFile.Rule != nil {
+					for _, o := range overlayFile.Inputs.Strings() {
+						overlayFiles = append(overlayFiles, module.Output(o).Inputs.Strings()...)
+					}
 				}
 
 				rroDirs := module.Module().(*AndroidApp).rroDirs.Strings()
diff --git a/ui/status/kati.go b/ui/status/kati.go
index 7c26d42..1485c8d 100644
--- a/ui/status/kati.go
+++ b/ui/status/kati.go
@@ -121,6 +121,7 @@
 	}
 
 	scanner := bufio.NewScanner(pipe)
+	scanner.Buffer(nil, 2*1024*1024)
 	for scanner.Scan() {
 		parser.parseLine(scanner.Text())
 	}