Merge "Static variant of a stubs lib is correctly tracked"
diff --git a/README.md b/README.md
index 74d49bb..44a98f3 100644
--- a/README.md
+++ b/README.md
@@ -34,7 +34,7 @@
 all Android.bp files.
 
 For a list of valid module types and their properties see
-[$OUT_DIR/soong/.bootstrap/docs/soong_build.html](http://go/Android.bp).
+[$OUT_DIR/soong/docs/soong_build.html](http://go/Android.bp).
 
 ### Globs
 
diff --git a/android/makevars.go b/android/makevars.go
index 3a7ec6e..366bb6b 100644
--- a/android/makevars.go
+++ b/android/makevars.go
@@ -22,6 +22,8 @@
 	"strconv"
 	"strings"
 
+	"github.com/google/blueprint"
+	"github.com/google/blueprint/pathtools"
 	"github.com/google/blueprint/proptools"
 )
 
@@ -38,7 +40,21 @@
 type MakeVarsContext interface {
 	Config() Config
 	DeviceConfig() DeviceConfig
-	SingletonContext() SingletonContext
+	AddNinjaFileDeps(deps ...string)
+	Fs() pathtools.FileSystem
+
+	ModuleName(module blueprint.Module) string
+	ModuleDir(module blueprint.Module) string
+	ModuleSubDir(module blueprint.Module) string
+	ModuleType(module blueprint.Module) string
+	BlueprintFile(module blueprint.Module) string
+
+	ModuleErrorf(module blueprint.Module, format string, args ...interface{})
+	Errorf(format string, args ...interface{})
+	Failed() bool
+
+	VisitAllModules(visit func(Module))
+	VisitAllModulesIf(pred func(Module) bool, visit func(Module))
 
 	// Verify the make variable matches the Soong version, fail the build
 	// if it does not. If the make variable is empty, just set it.
@@ -66,6 +82,8 @@
 	CheckRaw(name, value string)
 }
 
+var _ PathContext = MakeVarsContext(nil)
+
 type MakeVarsProvider func(ctx MakeVarsContext)
 
 func RegisterMakeVarsProvider(pctx PackageContext, provider MakeVarsProvider) {
@@ -92,8 +110,8 @@
 var makeVarsProviders []makeVarsProvider
 
 type makeVarsContext struct {
+	SingletonContext
 	config Config
-	ctx    SingletonContext
 	pctx   PackageContext
 	vars   []makeVarsVariable
 }
@@ -121,9 +139,8 @@
 	vars := []makeVarsVariable{}
 	for _, provider := range makeVarsProviders {
 		mctx := &makeVarsContext{
-			config: ctx.Config(),
-			ctx:    ctx,
-			pctx:   provider.pctx,
+			SingletonContext: ctx,
+			pctx:             provider.pctx,
 		}
 
 		provider.call(mctx)
@@ -229,22 +246,14 @@
 	return buf.Bytes()
 }
 
-func (c *makeVarsContext) Config() Config {
-	return c.config
-}
-
 func (c *makeVarsContext) DeviceConfig() DeviceConfig {
-	return DeviceConfig{c.config.deviceConfig}
-}
-
-func (c *makeVarsContext) SingletonContext() SingletonContext {
-	return c.ctx
+	return DeviceConfig{c.Config().deviceConfig}
 }
 
 var ninjaDescaper = strings.NewReplacer("$$", "$")
 
 func (c *makeVarsContext) Eval(ninjaStr string) (string, error) {
-	s, err := c.ctx.Eval(c.pctx, ninjaStr)
+	s, err := c.SingletonContext.Eval(c.pctx, ninjaStr)
 	if err != nil {
 		return "", err
 	}
@@ -265,7 +274,7 @@
 func (c *makeVarsContext) addVariable(name, ninjaStr string, strict, sort bool) {
 	value, err := c.Eval(ninjaStr)
 	if err != nil {
-		c.ctx.Errorf(err.Error())
+		c.SingletonContext.Errorf(err.Error())
 	}
 	c.addVariableRaw(name, value, strict, sort)
 }
diff --git a/android/paths.go b/android/paths.go
index 4b84c97..0c65b83 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -244,7 +244,7 @@
 		}
 		path := filepath.Clean(p)
 		if !strings.HasPrefix(path, prefix) {
-			reportPathErrorf(ctx, "Path '%s' is not in module source directory '%s'", p, prefix)
+			reportPathErrorf(ctx, "Path %q is not in module source directory %q", p, prefix)
 			continue
 		}
 
@@ -263,9 +263,9 @@
 }
 
 // PathsWithOptionalDefaultForModuleSrc returns Paths rooted from the module's
-// local source directory. If none are provided, use the default if it exists.
+// local source directory. If input is nil, use the default if it exists.  If input is empty, returns nil.
 func PathsWithOptionalDefaultForModuleSrc(ctx ModuleContext, input []string, def string) Paths {
-	if len(input) > 0 {
+	if input != nil {
 		return PathsForModuleSrc(ctx, input)
 	}
 	// Use Glob so that if the default doesn't exist, a dependency is added so that when it
@@ -505,7 +505,7 @@
 
 	// absolute path already checked by validateSafePath
 	if strings.HasPrefix(ret.String(), ctx.Config().buildDir) {
-		return ret, fmt.Errorf("source path %s is in output", ret.String())
+		return ret, fmt.Errorf("source path %q is in output", ret.String())
 	}
 
 	return ret, err
@@ -521,7 +521,7 @@
 
 	// absolute path already checked by validatePath
 	if strings.HasPrefix(ret.String(), ctx.Config().buildDir) {
-		return ret, fmt.Errorf("source path %s is in output", ret.String())
+		return ret, fmt.Errorf("source path %q is in output", ret.String())
 	}
 
 	return ret, nil
@@ -575,7 +575,7 @@
 	} else if exists, _, err := ctx.Fs().Exists(path.String()); err != nil {
 		reportPathErrorf(ctx, "%s: %s", path, err.Error())
 	} else if !exists {
-		reportPathErrorf(ctx, "source path %s does not exist", path)
+		reportPathErrorf(ctx, "source path %q does not exist", path)
 	}
 	return path
 }
@@ -740,7 +740,7 @@
 	if exists, _, err := ctx.Fs().Exists(path.String()); err != nil {
 		reportPathErrorf(ctx, "%s: %s", path, err.Error())
 	} else if !exists {
-		reportPathErrorf(ctx, "module source path %s does not exist", path)
+		reportPathErrorf(ctx, "module source path %q does not exist", path)
 	}
 
 	return path
diff --git a/android/singleton.go b/android/singleton.go
index f926435..05ec6b5 100644
--- a/android/singleton.go
+++ b/android/singleton.go
@@ -22,6 +22,7 @@
 // SingletonContext
 type SingletonContext interface {
 	Config() Config
+	DeviceConfig() DeviceConfig
 
 	ModuleName(module blueprint.Module) string
 	ModuleDir(module blueprint.Module) string
@@ -93,6 +94,10 @@
 	return s.SingletonContext.Config().(Config)
 }
 
+func (s singletonContextAdaptor) DeviceConfig() DeviceConfig {
+	return DeviceConfig{s.Config().deviceConfig}
+}
+
 func (s singletonContextAdaptor) Variable(pctx PackageContext, name, value string) {
 	s.SingletonContext.Variable(pctx.PackageContext, name, value)
 }
diff --git a/androidmk/cmd/androidmk/android.go b/androidmk/cmd/androidmk/android.go
index aef8944..abe7917 100644
--- a/androidmk/cmd/androidmk/android.go
+++ b/androidmk/cmd/androidmk/android.go
@@ -188,6 +188,7 @@
 			"LOCAL_EXPORT_PACKAGE_RESOURCES":   "export_package_resources",
 			"LOCAL_PRIVILEGED_MODULE":          "privileged",
 			"LOCAL_AAPT_INCLUDE_ALL_RESOURCES": "aapt_include_all_resources",
+			"LOCAL_USE_EMBEDDED_NATIVE_LIBS":   "use_embedded_native_libs",
 
 			"LOCAL_DEX_PREOPT":                  "dex_preopt.enabled",
 			"LOCAL_DEX_PREOPT_APP_IMAGE":        "dex_preopt.app_image",
diff --git a/apex/apex.go b/apex/apex.go
index 3584896..95cee0c 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -136,7 +136,9 @@
 	pctx.HostBinToolVariable("zip2zip", "zip2zip")
 	pctx.HostBinToolVariable("zipalign", "zipalign")
 
-	android.RegisterModuleType("apex", ApexBundleFactory)
+	android.RegisterModuleType("apex", apexBundleFactory)
+	android.RegisterModuleType("apex_test", testApexBundleFactory)
+	android.RegisterModuleType("apex_defaults", defaultsFactory)
 
 	android.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
 		ctx.TopDown("apex_deps", apexDepsMutator)
@@ -147,13 +149,18 @@
 // Mark the direct and transitive dependencies of apex bundles so that they
 // can be built for the apex bundles.
 func apexDepsMutator(mctx android.TopDownMutatorContext) {
-	if _, ok := mctx.Module().(*apexBundle); ok {
+	if a, ok := mctx.Module().(*apexBundle); ok {
 		apexBundleName := mctx.ModuleName()
 		mctx.WalkDeps(func(child, parent android.Module) bool {
 			depName := mctx.OtherModuleName(child)
 			// If the parent is apexBundle, this child is directly depended.
 			_, directDep := parent.(*apexBundle)
-			android.UpdateApexDependency(apexBundleName, depName, directDep)
+			if a.installable() && !a.testApex {
+				// TODO(b/123892969): Workaround for not having any way to annotate test-apexs
+				// non-installable apex's cannot be installed and so should not prevent libraries from being
+				// installed to the system.
+				android.UpdateApexDependency(apexBundleName, depName, directDep)
+			}
 
 			if am, ok := child.(android.ApexModule); ok && am.CanHaveApexVariants() {
 				am.BuildForApex(apexBundleName)
@@ -369,6 +376,8 @@
 	filesInfo []apexFile
 
 	flattened bool
+
+	testApex bool
 }
 
 func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext,
@@ -1046,7 +1055,7 @@
 		Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
 			moduleNames := []string{}
 			if a.installable() {
-				a.androidMkForFiles(w, name, moduleDir)
+				moduleNames = a.androidMkForFiles(w, name, moduleDir)
 			}
 
 			if a.flattened && apexType.image() {
@@ -1085,9 +1094,18 @@
 		}}
 }
 
-func ApexBundleFactory() android.Module {
+func testApexBundleFactory() android.Module {
+	return ApexBundleFactory( /*testApex*/ true)
+}
+
+func apexBundleFactory() android.Module {
+	return ApexBundleFactory( /*testApex*/ false)
+}
+
+func ApexBundleFactory(testApex bool) android.Module {
 	module := &apexBundle{
 		outputFiles: map[apexPackaging]android.WritablePath{},
+		testApex:    testApex,
 	}
 	module.AddProperties(&module.properties)
 	module.AddProperties(&module.targetProperties)
@@ -1098,3 +1116,31 @@
 	android.InitDefaultableModule(module)
 	return module
 }
+
+//
+// Defaults
+//
+type Defaults struct {
+	android.ModuleBase
+	android.DefaultsModuleBase
+}
+
+func (*Defaults) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+}
+
+func defaultsFactory() android.Module {
+	return DefaultsFactory()
+}
+
+func DefaultsFactory(props ...interface{}) android.Module {
+	module := &Defaults{}
+
+	module.AddProperties(props...)
+	module.AddProperties(
+		&apexBundleProperties{},
+		&apexTargetBundleProperties{},
+	)
+
+	android.InitDefaultsModule(module)
+	return module
+}
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 56ddd5f..2c7f285 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -31,8 +31,11 @@
 	defer teardown(buildDir)
 
 	ctx := android.NewTestArchContext()
-	ctx.RegisterModuleType("apex", android.ModuleFactoryAdaptor(ApexBundleFactory))
+	ctx.RegisterModuleType("apex", android.ModuleFactoryAdaptor(apexBundleFactory))
+	ctx.RegisterModuleType("apex_test", android.ModuleFactoryAdaptor(testApexBundleFactory))
 	ctx.RegisterModuleType("apex_key", android.ModuleFactoryAdaptor(apexKeyFactory))
+	ctx.RegisterModuleType("apex_defaults", android.ModuleFactoryAdaptor(defaultsFactory))
+	ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
 
 	ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
 		ctx.TopDown("apex_deps", apexDepsMutator)
@@ -201,8 +204,8 @@
 // Minimal test
 func TestBasicApex(t *testing.T) {
 	ctx := testApex(t, `
-		apex {
-			name: "myapex",
+		apex_defaults {
+			name: "myapex-defaults",
 			key: "myapex.key",
 			native_shared_libs: ["mylib"],
 			multilib: {
@@ -212,6 +215,11 @@
 			}
 		}
 
+		apex {
+			name: "myapex",
+			defaults: ["myapex-defaults"],
+		}
+
 		apex_key {
 			name: "myapex.key",
 			public_key: "testkey.avbpubkey",
@@ -897,6 +905,105 @@
 	ensureContains(t, cFlags, "-Imy_include")
 }
 
+func TestNonTestApex(t *testing.T) {
+	ctx := testApex(t, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			native_shared_libs: ["mylib_common"],
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		cc_library {
+			name: "mylib_common",
+			srcs: ["mylib.cpp"],
+			system_shared_libs: [],
+			stl: "none",
+		}
+	`)
+
+	module := ctx.ModuleForTests("myapex", "android_common_myapex")
+	apexRule := module.Rule("apexRule")
+	copyCmds := apexRule.Args["copy_commands"]
+
+	if apex, ok := module.Module().(*apexBundle); !ok || apex.testApex {
+		t.Log("Apex was a test apex!")
+		t.Fail()
+	}
+	// 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_common"), "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_common.so")
+
+	// Ensure that the platform variant ends with _core_shared
+	ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common"), "android_arm64_armv8-a_core_shared")
+
+	if !android.InAnyApex("mylib_common") {
+		t.Log("Found mylib_common not in any apex!")
+		t.Fail()
+	}
+}
+
+func TestTestApex(t *testing.T) {
+	if android.InAnyApex("mylib_common_test") {
+		t.Fatal("mylib_common_test must not be used in any other tests since this checks that global state is not updated in an illegal way!")
+	}
+	ctx := testApex(t, `
+		apex_test {
+			name: "myapex",
+			key: "myapex.key",
+			native_shared_libs: ["mylib_common_test"],
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		cc_library {
+			name: "mylib_common_test",
+			srcs: ["mylib.cpp"],
+			system_shared_libs: [],
+			stl: "none",
+		}
+	`)
+
+	module := ctx.ModuleForTests("myapex", "android_common_myapex")
+	apexRule := module.Rule("apexRule")
+	copyCmds := apexRule.Args["copy_commands"]
+
+	if apex, ok := module.Module().(*apexBundle); !ok || !apex.testApex {
+		t.Log("Apex was not a test apex!")
+		t.Fail()
+	}
+	// 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_common_test"), "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_common_test.so")
+
+	// Ensure that the platform variant ends with _core_shared
+	ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common_test"), "android_arm64_armv8-a_core_shared")
+
+	if android.InAnyApex("mylib_common_test") {
+		t.Log("Found mylib_common_test in some apex!")
+		t.Fail()
+	}
+}
+
 func TestApexWithTarget(t *testing.T) {
 	ctx := testApex(t, `
 		apex {
diff --git a/cc/gen_stub_libs.py b/cc/gen_stub_libs.py
index 4906ea2..81bc398 100755
--- a/cc/gen_stub_libs.py
+++ b/cc/gen_stub_libs.py
@@ -119,9 +119,12 @@
         return True
     if 'platform-only' in version.tags:
         return True
-    if 'vndk' in version.tags and not vndk:
-        return True
-    if 'apex' in version.tags and not apex:
+
+    no_vndk_no_apex = 'vndk' not in version.tags and 'apex' not in version.tags
+    keep = no_vndk_no_apex or \
+           ('vndk' in version.tags and vndk) or \
+           ('apex' in version.tags and apex)
+    if not keep:
         return True
     if not symbol_in_arch(version.tags, arch):
         return True
@@ -132,9 +135,11 @@
 
 def should_omit_symbol(symbol, arch, api, vndk, apex):
     """Returns True if the symbol should be omitted."""
-    if not vndk and 'vndk' in symbol.tags:
-        return True
-    if not apex and 'apex' in symbol.tags:
+    no_vndk_no_apex = 'vndk' not in symbol.tags and 'apex' not in symbol.tags
+    keep = no_vndk_no_apex or \
+           ('vndk' in symbol.tags and vndk) or \
+           ('apex' in symbol.tags and apex)
+    if not keep:
         return True
     if not symbol_in_arch(symbol.tags, arch):
         return True
diff --git a/cc/makevars.go b/cc/makevars.go
index d91735f..4a9ade2 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -100,7 +100,7 @@
 
 	// Filter vendor_public_library that are exported to make
 	exportedVendorPublicLibraries := []string{}
-	ctx.SingletonContext().VisitAllModules(func(module android.Module) {
+	ctx.VisitAllModules(func(module android.Module) {
 		if ccModule, ok := module.(*Module); ok {
 			baseName := ccModule.BaseModuleName()
 			if inList(baseName, vendorPublicLibraries) && module.ExportedToMake() {
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index 1b09f88..3ae4452 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -53,6 +53,7 @@
 		"OpenMAXAL",
 		"OpenSLES",
 		"stdc++",
+		"sync",
 		"vulkan",
 		"z",
 	}
diff --git a/cc/test_gen_stub_libs.py b/cc/test_gen_stub_libs.py
index 594c1bc..2ee9886 100755
--- a/cc/test_gen_stub_libs.py
+++ b/cc/test_gen_stub_libs.py
@@ -751,6 +751,8 @@
                 wibble;
                 wizzes; # vndk
                 waggle; # apex
+                bubble; # apex vndk
+                duddle; # vndk apex
             } VERSION_2;
 
             VERSION_5 { # versioned=14
@@ -771,6 +773,8 @@
             void qux() {}
             void wibble() {}
             void waggle() {}
+            void bubble() {}
+            void duddle() {}
             void wobble() {}
         """)
         self.assertEqual(expected_src, src_file.getvalue())
@@ -788,6 +792,8 @@
                 global:
                     wibble;
                     waggle;
+                    bubble;
+                    duddle;
             } VERSION_2;
         """)
         self.assertEqual(expected_version, version_file.getvalue())
diff --git a/cmd/multiproduct_kati/main.go b/cmd/multiproduct_kati/main.go
index 6a3d579..330c5dd 100644
--- a/cmd/multiproduct_kati/main.go
+++ b/cmd/multiproduct_kati/main.go
@@ -172,7 +172,8 @@
 
 	stat := &status.Status{}
 	defer stat.Finish()
-	stat.AddOutput(terminal.NewStatusOutput(writer, ""))
+	stat.AddOutput(terminal.NewStatusOutput(writer, "",
+		build.OsEnvironment().IsEnvTrue("ANDROID_QUIET_BUILD")))
 
 	var failures failureCount
 	stat.AddOutput(&failures)
@@ -389,7 +390,8 @@
 		Thread:  mpctx.Tracer.NewThread(product),
 		Status:  &status.Status{},
 	}}
-	ctx.Status.AddOutput(terminal.NewStatusOutput(ctx.Writer, ""))
+	ctx.Status.AddOutput(terminal.NewStatusOutput(ctx.Writer, "",
+		build.OsEnvironment().IsEnvTrue("ANDROID_QUIET_BUILD")))
 
 	config := build.NewConfig(ctx, flag.Args()...)
 	config.Environment().Set("OUT_DIR", outDir)
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index 0380368..d6999c5 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -78,7 +78,8 @@
 
 	stat := &status.Status{}
 	defer stat.Finish()
-	stat.AddOutput(terminal.NewStatusOutput(writer, os.Getenv("NINJA_STATUS")))
+	stat.AddOutput(terminal.NewStatusOutput(writer, os.Getenv("NINJA_STATUS"),
+		build.OsEnvironment().IsEnvTrue("ANDROID_QUIET_BUILD")))
 	stat.AddOutput(trace.StatusTracer())
 
 	build.SetupSignals(log, cancel, func() {
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index 3725146..319e36e 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -91,7 +91,6 @@
 	DexLocation     string // dex location on device
 	BuildPath       string
 	DexPath         string
-	UseEmbeddedDex  bool
 	UncompressedDex bool
 	HasApkLibraries bool
 	PreoptFlags     []string
diff --git a/dexpreopt/dexpreopt_test.go b/dexpreopt/dexpreopt_test.go
index 6e520f1..d949852 100644
--- a/dexpreopt/dexpreopt_test.go
+++ b/dexpreopt/dexpreopt_test.go
@@ -67,7 +67,6 @@
 	DexLocation:            "",
 	BuildPath:              "",
 	DexPath:                "",
-	UseEmbeddedDex:         false,
 	UncompressedDex:        false,
 	HasApkLibraries:        false,
 	PreoptFlags:            nil,
diff --git a/java/aar.go b/java/aar.go
index b01962a..f6a3d3a 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -53,11 +53,13 @@
 	Aapt_include_all_resources *bool
 
 	// list of directories relative to the Blueprints file containing assets.
-	// Defaults to "assets"
+	// Defaults to ["assets"] if a directory called assets exists.  Set to []
+	// to disable the default.
 	Asset_dirs []string
 
 	// list of directories relative to the Blueprints file containing
-	// Android resources
+	// Android resources.  Defaults to ["res"] if a directory called res exists.
+	// Set to [] to disable the default.
 	Resource_dirs []string
 
 	// path to AndroidManifest.xml.  If unset, defaults to "AndroidManifest.xml".
@@ -73,6 +75,7 @@
 	rTxt                  android.Path
 	extraAaptPackagesFile android.Path
 	isLibrary             bool
+	uncompressedJNI       bool
 
 	aaptProperties aaptProperties
 }
@@ -179,11 +182,13 @@
 	manifestFile := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml")
 	manifestSrcPath := android.PathForModuleSrc(ctx, manifestFile)
 
-	manifestPath := manifestMerger(ctx, manifestSrcPath, sdkContext, staticLibManifests, a.isLibrary)
+	manifestPath := manifestMerger(ctx, manifestSrcPath, sdkContext, staticLibManifests, a.isLibrary, a.uncompressedJNI)
 
 	linkFlags, linkDeps, resDirs, overlayDirs, rroDirs := a.aapt2Flags(ctx, sdkContext, manifestPath)
 
 	rroDirs = append(rroDirs, staticRRODirs...)
+	// TODO(b/124035856): stop de-duping when there are no more dupe resource dirs.
+	rroDirs = android.FirstUniquePaths(rroDirs)
 
 	linkFlags = append(linkFlags, libFlags...)
 	linkDeps = append(linkDeps, libDeps...)
@@ -326,7 +331,7 @@
 }
 
 func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	a.isLibrary = true
+	a.aapt.isLibrary = true
 	a.aapt.buildActions(ctx, sdkContext(a))
 
 	ctx.CheckbuildFile(a.proguardOptionsFile)
diff --git a/java/android_manifest.go b/java/android_manifest.go
index 36f24ff..6d4399d 100644
--- a/java/android_manifest.go
+++ b/java/android_manifest.go
@@ -15,12 +15,13 @@
 package java
 
 import (
-	"android/soong/java/config"
+	"fmt"
 	"strings"
 
 	"github.com/google/blueprint"
 
 	"android/soong/android"
+	"android/soong/java/config"
 )
 
 var manifestFixerRule = pctx.AndroidStaticRule("manifestFixer",
@@ -43,11 +44,22 @@
 	"libs")
 
 func manifestMerger(ctx android.ModuleContext, manifest android.Path, sdkContext sdkContext,
-	staticLibManifests android.Paths, isLibrary bool) android.Path {
+	staticLibManifests android.Paths, isLibrary bool, uncompressedJNI bool) android.Path {
 
 	var args []string
 	if isLibrary {
 		args = append(args, "--library")
+	} else {
+		minSdkVersion, err := sdkVersionToNumber(ctx, sdkContext.minSdkVersion())
+		if err != nil {
+			ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
+		}
+		if minSdkVersion >= 23 {
+			args = append(args, fmt.Sprintf("--extract-native-libs=%v", !uncompressedJNI))
+		} else if uncompressedJNI {
+			ctx.ModuleErrorf("module attempted to store uncompressed native libraries, but minSdkVersion=%d doesn't support it",
+				minSdkVersion)
+		}
 	}
 
 	// Inject minSdkVersion into the manifest
diff --git a/java/androidmk.go b/java/androidmk.go
index 089ed4f..d86e71f 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -203,6 +203,11 @@
 		Include:    "$(BUILD_SYSTEM)/soong_app_prebuilt.mk",
 		Extra: []android.AndroidMkExtraFunc{
 			func(w io.Writer, outputFile android.Path) {
+				// TODO(jungjw): This, outputting two LOCAL_MODULE lines, works, but is not ideal. Find a better solution.
+				if app.Name() != app.installApkName {
+					fmt.Fprintln(w, "# Overridden by PRODUCT_PACKAGE_NAME_OVERRIDES")
+					fmt.Fprintln(w, "LOCAL_MODULE :=", app.installApkName)
+				}
 				fmt.Fprintln(w, "LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE :=", app.exportPackage.String())
 				if app.dexJarFile != nil {
 					fmt.Fprintln(w, "LOCAL_SOONG_DEX_JAR :=", app.dexJarFile.String())
@@ -247,8 +252,8 @@
 				}
 
 				fmt.Fprintln(w, "LOCAL_CERTIFICATE :=", app.certificate.Pem.String())
-				if len(app.appProperties.Overrides) > 0 {
-					fmt.Fprintln(w, "LOCAL_OVERRIDES_PACKAGES := "+strings.Join(app.appProperties.Overrides, " "))
+				if overriddenPkgs := app.getOverriddenPackages(); len(overriddenPkgs) > 0 {
+					fmt.Fprintln(w, "LOCAL_OVERRIDES_PACKAGES :=", strings.Join(overriddenPkgs, " "))
 				}
 
 				for _, jniLib := range app.installJniLibs {
@@ -262,6 +267,17 @@
 	}
 }
 
+func (a *AndroidApp) getOverriddenPackages() []string {
+	var overridden []string
+	if len(a.appProperties.Overrides) > 0 {
+		overridden = append(overridden, a.appProperties.Overrides...)
+	}
+	if a.Name() != a.installApkName {
+		overridden = append(overridden, a.Name())
+	}
+	return overridden
+}
+
 func (a *AndroidTest) AndroidMk() android.AndroidMkData {
 	data := a.AndroidApp.AndroidMk()
 	data.Extra = append(data.Extra, func(w io.Writer, outputFile android.Path) {
diff --git a/java/app.go b/java/app.go
index 08714f2..47f4f0d 100644
--- a/java/app.go
+++ b/java/app.go
@@ -68,7 +68,11 @@
 	// list of native libraries that will be provided in or alongside the resulting jar
 	Jni_libs []string `android:"arch_variant"`
 
-	EmbedJNI bool `blueprint:"mutated"`
+	// Store native libraries uncompressed in the APK and set the android:extractNativeLibs="false" manifest
+	// flag so that they are used from inside the APK at runtime.  Defaults to true for android_test modules unless
+	// sdk_version or min_sdk_version is set to a version that doesn't support it (<23), defaults to false for other
+	// module types where the native libraries are generally preinstalled outside the APK.
+	Use_embedded_native_libs *bool
 }
 
 type AndroidApp struct {
@@ -136,9 +140,21 @@
 }
 
 func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	a.aapt.uncompressedJNI = a.shouldUncompressJNI(ctx)
 	a.generateAndroidBuildActions(ctx)
 }
 
+// shouldUncompressJNI returns true if the native libraries should be stored in the APK uncompressed and the
+// extractNativeLibs application flag should be set to false in the manifest.
+func (a *AndroidApp) shouldUncompressJNI(ctx android.ModuleContext) bool {
+	minSdkVersion, err := sdkVersionToNumber(ctx, a.minSdkVersion())
+	if err != nil {
+		ctx.PropertyErrorf("min_sdk_version", "invalid value %q: %s", a.minSdkVersion(), err)
+	}
+
+	return minSdkVersion >= 23 && Bool(a.appProperties.Use_embedded_native_libs)
+}
+
 // Returns whether this module should have the dex file stored uncompressed in the APK.
 func (a *AndroidApp) shouldUncompressDex(ctx android.ModuleContext) bool {
 	if ctx.Config().UnbundledBuild() {
@@ -230,10 +246,10 @@
 func (a *AndroidApp) jniBuildActions(jniLibs []jniLib, ctx android.ModuleContext) android.WritablePath {
 	var jniJarFile android.WritablePath
 	if len(jniLibs) > 0 {
-		embedJni := ctx.Config().UnbundledBuild() || a.appProperties.EmbedJNI
+		embedJni := ctx.Config().UnbundledBuild() || Bool(a.appProperties.Use_embedded_native_libs)
 		if embedJni {
 			jniJarFile = android.PathForModuleOut(ctx, "jnilibs.zip")
-			TransformJniLibsToJar(ctx, jniJarFile, jniLibs)
+			TransformJniLibsToJar(ctx, jniJarFile, jniLibs, a.shouldUncompressJNI(ctx))
 		} else {
 			a.installJniLibs = jniLibs
 		}
@@ -428,7 +444,7 @@
 
 	module.Module.properties.Instrument = true
 	module.Module.properties.Installable = proptools.BoolPtr(true)
-	module.appProperties.EmbedJNI = true
+	module.appProperties.Use_embedded_native_libs = proptools.BoolPtr(true)
 	module.Module.dexpreopter.isTest = true
 
 	module.AddProperties(
@@ -464,7 +480,7 @@
 	module.Module.deviceProperties.Optimize.Enabled = proptools.BoolPtr(true)
 
 	module.Module.properties.Installable = proptools.BoolPtr(true)
-	module.appProperties.EmbedJNI = true
+	module.appProperties.Use_embedded_native_libs = proptools.BoolPtr(true)
 	module.Module.dexpreopter.isTest = true
 
 	module.AddProperties(
diff --git a/java/app_builder.go b/java/app_builder.go
index 5b999d8..6cc2159 100644
--- a/java/app_builder.go
+++ b/java/app_builder.go
@@ -200,14 +200,14 @@
 }
 
 func TransformJniLibsToJar(ctx android.ModuleContext, outputFile android.WritablePath,
-	jniLibs []jniLib) {
+	jniLibs []jniLib, uncompressJNI bool) {
 
 	var deps android.Paths
 	jarArgs := []string{
 		"-j", // junk paths, they will be added back with -P arguments
 	}
 
-	if !ctx.Config().UnbundledBuild() {
+	if uncompressJNI {
 		jarArgs = append(jarArgs, "-L 0")
 	}
 
diff --git a/java/app_test.go b/java/app_test.go
index 93d20d0..103f24b 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -106,6 +106,64 @@
 	}
 }
 
+func TestResourceDirs(t *testing.T) {
+	testCases := []struct {
+		name      string
+		prop      string
+		resources []string
+	}{
+		{
+			name:      "no resource_dirs",
+			prop:      "",
+			resources: []string{"res/res/values/strings.xml"},
+		},
+		{
+			name:      "resource_dirs",
+			prop:      `resource_dirs: ["res"]`,
+			resources: []string{"res/res/values/strings.xml"},
+		},
+		{
+			name:      "empty resource_dirs",
+			prop:      `resource_dirs: []`,
+			resources: nil,
+		},
+	}
+
+	fs := map[string][]byte{
+		"res/res/values/strings.xml": nil,
+	}
+
+	bp := `
+			android_app {
+				name: "foo",
+				%s
+			}
+		`
+
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+			config := testConfig(nil)
+			ctx := testContext(config, fmt.Sprintf(bp, testCase.prop), fs)
+			run(t, ctx, config)
+
+			module := ctx.ModuleForTests("foo", "android_common")
+			resourceList := module.MaybeOutput("aapt2/res.list")
+
+			var resources []string
+			if resourceList.Rule != nil {
+				for _, compiledResource := range resourceList.Inputs.Strings() {
+					resources = append(resources, module.Output(compiledResource).Inputs.Strings()...)
+				}
+			}
+
+			if !reflect.DeepEqual(resources, testCase.resources) {
+				t.Errorf("expected resource files %q, got %q",
+					testCase.resources, resources)
+			}
+		})
+	}
+}
+
 func TestEnforceRRO(t *testing.T) {
 	testCases := []struct {
 		name                       string
diff --git a/java/builder.go b/java/builder.go
index 7aac881..aa61a85 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -122,8 +122,8 @@
 
 	zipalign = pctx.AndroidStaticRule("zipalign",
 		blueprint.RuleParams{
-			Command: "if ! ${config.ZipAlign} -c 4 $in > /dev/null; then " +
-				"${config.ZipAlign} -f 4 $in $out; " +
+			Command: "if ! ${config.ZipAlign} -c -p 4 $in > /dev/null; then " +
+				"${config.ZipAlign} -f -p 4 $in $out; " +
 				"else " +
 				"cp -f $in $out; " +
 				"fi",
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index 33c46f4..55662cf 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -149,7 +149,6 @@
 		DexLocation:     dexLocation,
 		BuildPath:       android.PathForModuleOut(ctx, "dexpreopt", ctx.ModuleName()+".jar").String(),
 		DexPath:         dexJarFile.String(),
-		UseEmbeddedDex:  false,
 		UncompressedDex: d.uncompressedDex,
 		HasApkLibraries: false,
 		PreoptFlags:     nil,
diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go
index 96de755..de1bcf5 100644
--- a/java/hiddenapi_singleton.go
+++ b/java/hiddenapi_singleton.go
@@ -283,7 +283,7 @@
 // Both paths are used to call dist-for-goals.
 func hiddenAPIMakeVars(ctx android.MakeVarsContext) {
 	if !ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
-		singletonPaths := ctx.Config().Get(hiddenAPISingletonPathsKey).(hiddenAPISingletonPathsStruct)
+		singletonPaths := hiddenAPISingletonPaths(ctx)
 		ctx.Strict("INTERNAL_PLATFORM_HIDDENAPI_FLAGS", singletonPaths.flags.String())
 		ctx.Strict("INTERNAL_PLATFORM_HIDDENAPI_GREYLIST_METADATA", singletonPaths.metadata.String())
 	}
diff --git a/java/java.go b/java/java.go
index 22829e4..3d7d6ad 100644
--- a/java/java.go
+++ b/java/java.go
@@ -1423,6 +1423,11 @@
 		android.DirectlyInAnyApex(ctx, ctx.ModuleName()) {
 		return true
 	}
+	if ctx.Config().UncompressPrivAppDex() &&
+		inList(ctx.ModuleName(), ctx.Config().ModulesLoadedByPrivilegedModules()) {
+		return true
+	}
+
 	return false
 }
 
diff --git a/java/support_libraries.go b/java/support_libraries.go
index 320afae..5a72f41 100644
--- a/java/support_libraries.go
+++ b/java/support_libraries.go
@@ -28,9 +28,8 @@
 func supportLibrariesMakeVarsProvider(ctx android.MakeVarsContext) {
 	var supportAars, supportJars []string
 
-	sctx := ctx.SingletonContext()
-	sctx.VisitAllModules(func(module android.Module) {
-		dir := sctx.ModuleDir(module)
+	ctx.VisitAllModules(func(module android.Module) {
+		dir := ctx.ModuleDir(module)
 		switch {
 		case strings.HasPrefix(dir, "prebuilts/sdk/current/extras"),
 			dir == "prebuilts/sdk/current/androidx",
@@ -43,7 +42,7 @@
 			return
 		}
 
-		name := sctx.ModuleName(module)
+		name := ctx.ModuleName(module)
 		if strings.HasSuffix(name, "-nodeps") {
 			return
 		}
@@ -54,7 +53,7 @@
 		case *Library, *Import:
 			supportJars = append(supportJars, name)
 		default:
-			sctx.ModuleErrorf(module, "unknown module type %t", module)
+			ctx.ModuleErrorf(module, "unknown module type %t", module)
 		}
 	})
 
diff --git a/scripts/manifest_fixer.py b/scripts/manifest_fixer.py
index 917f55b..83868e6 100755
--- a/scripts/manifest_fixer.py
+++ b/scripts/manifest_fixer.py
@@ -63,8 +63,12 @@
                       help='manifest is for a package built against the platform')
   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. Should not be conflict if already declared '
+                            'locally compiled code. Must not conflict if already declared '
                             'in the manifest.'))
+  parser.add_argument('--extract-native-libs', dest='extract_native_libs',
+                      default=None, type=lambda x: (str(x).lower() == 'true'),
+                      help=('specify if the app wants to use embedded native libraries. Must not conflict '
+                            'if already declared in the manifest.'))
   parser.add_argument('input', help='input AndroidManifest.xml file')
   parser.add_argument('output', help='output AndroidManifest.xml file')
   return parser.parse_args()
@@ -295,6 +299,30 @@
     raise RuntimeError('existing attribute mismatches the option of --use-embedded-dex')
 
 
+def add_extract_native_libs(doc, extract_native_libs):
+  manifest = parse_manifest(doc)
+  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)
+
+  value = str(extract_native_libs).lower()
+  attr = application.getAttributeNodeNS(android_ns, 'extractNativeLibs')
+  if attr is None:
+    attr = doc.createAttributeNS(android_ns, 'android:extractNativeLibs')
+    attr.value = value
+    application.setAttributeNode(attr)
+  elif attr.value != value:
+    raise RuntimeError('existing attribute extractNativeLibs="%s" conflicts with --extract-native-libs="%s"' %
+                       (attr.value, value))
+
+
 def write_xml(f, doc):
   f.write('<?xml version="1.0" encoding="utf-8"?>\n')
   for node in doc.childNodes:
@@ -325,6 +353,9 @@
     if args.use_embedded_dex:
       add_use_embedded_dex(doc)
 
+    if args.extract_native_libs is not None:
+      add_extract_native_libs(doc, args.extract_native_libs)
+
     with open(args.output, 'wb') as f:
       write_xml(f, doc)
 
diff --git a/scripts/manifest_fixer_test.py b/scripts/manifest_fixer_test.py
index 1d8de55..4ad9afa 100755
--- a/scripts/manifest_fixer_test.py
+++ b/scripts/manifest_fixer_test.py
@@ -381,5 +381,48 @@
     manifest_input = self.manifest_tmpl % self.use_embedded_dex('false')
     self.assertRaises(RuntimeError, self.run_test, manifest_input)
 
+
+class AddExtractNativeLibsTest(unittest.TestCase):
+  """Unit tests for add_extract_native_libs function."""
+
+  def run_test(self, input_manifest, value):
+    doc = minidom.parseString(input_manifest)
+    manifest_fixer.add_extract_native_libs(doc, value)
+    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'
+    '    <application%s/>\n'
+    '</manifest>\n')
+
+  def extract_native_libs(self, value):
+    return ' android:extractNativeLibs="%s"' % value
+
+  def test_set_true(self):
+    manifest_input = self.manifest_tmpl % ''
+    expected = self.manifest_tmpl % self.extract_native_libs('true')
+    output = self.run_test(manifest_input, True)
+    self.assertEqual(output, expected)
+
+  def test_set_false(self):
+    manifest_input = self.manifest_tmpl % ''
+    expected = self.manifest_tmpl % self.extract_native_libs('false')
+    output = self.run_test(manifest_input, False)
+    self.assertEqual(output, expected)
+
+  def test_match(self):
+    manifest_input = self.manifest_tmpl % self.extract_native_libs('true')
+    expected = manifest_input
+    output = self.run_test(manifest_input, True)
+    self.assertEqual(output, expected)
+
+  def test_conflict(self):
+    manifest_input = self.manifest_tmpl % self.extract_native_libs('true')
+    self.assertRaises(RuntimeError, self.run_test, manifest_input, False)
+
+
 if __name__ == '__main__':
   unittest.main()
diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go
index 98bb1c5..d644f5f 100644
--- a/ui/build/dumpvars.go
+++ b/ui/build/dumpvars.go
@@ -214,11 +214,13 @@
 		ctx.Fatalln("Error dumping make vars:", err)
 	}
 
+	env := config.Environment()
 	// Print the banner like make does
-	ctx.Writer.Print(Banner(make_vars))
+	if !env.IsEnvTrue("ANDROID_QUIET_BUILD") {
+		ctx.Writer.Print(Banner(make_vars))
+	}
 
 	// Populate the environment
-	env := config.Environment()
 	for _, name := range exportEnvVars {
 		if make_vars[name] == "" {
 			env.Unset(name)
diff --git a/ui/terminal/status.go b/ui/terminal/status.go
index c8eb382..2445c5b 100644
--- a/ui/terminal/status.go
+++ b/ui/terminal/status.go
@@ -27,6 +27,7 @@
 	format string
 
 	start time.Time
+	quiet bool
 }
 
 // NewStatusOutput returns a StatusOutput that represents the
@@ -35,12 +36,13 @@
 //
 // statusFormat takes nearly all the same options as NINJA_STATUS.
 // %c is currently unsupported.
-func NewStatusOutput(w Writer, statusFormat string) status.StatusOutput {
+func NewStatusOutput(w Writer, statusFormat string, quietBuild bool) status.StatusOutput {
 	return &statusOutput{
 		writer: w,
 		format: statusFormat,
 
 		start: time.Now(),
+		quiet: quietBuild,
 	}
 }
 
@@ -76,13 +78,12 @@
 	progress := s.progress(counts) + str
 
 	if result.Error != nil {
-		hasCommand := ""
-		if result.Command != "" {
-			hasCommand = "\n"
+		targets := strings.Join(result.Outputs, " ")
+		if s.quiet || result.Command == "" {
+			s.writer.StatusAndMessage(progress, fmt.Sprintf("FAILED: %s\n%s", targets, result.Output))
+		} else {
+			s.writer.StatusAndMessage(progress, fmt.Sprintf("FAILED: %s\n%s\n%s", targets, result.Command, result.Output))
 		}
-
-		s.writer.StatusAndMessage(progress, fmt.Sprintf("FAILED: %s\n%s%s%s",
-			strings.Join(result.Outputs, " "), result.Command, hasCommand, result.Output))
 	} else if result.Output != "" {
 		s.writer.StatusAndMessage(progress, result.Output)
 	} else {