Snap for 6001391 from 0d0b3980b83623189cdcfc2c8ea1d3a49f742050 to qt-aml-resolv-release

Change-Id: I5f6667013b5b40b8926d7736dfe38a7e582a5cc9
diff --git a/Android.bp b/Android.bp
index 20d45e5..8d0c1ea 100644
--- a/Android.bp
+++ b/Android.bp
@@ -157,6 +157,7 @@
         "cc/check.go",
         "cc/coverage.go",
         "cc/gen.go",
+        "cc/linkable.go",
         "cc/lto.go",
         "cc/makevars.go",
         "cc/pgo.go",
@@ -365,6 +366,7 @@
         "rust/prebuilt.go",
         "rust/proc_macro.go",
         "rust/rust.go",
+        "rust/test.go",
         "rust/testing.go",
     ],
     testSrcs: [
@@ -372,6 +374,7 @@
         "rust/compiler_test.go",
         "rust/library_test.go",
         "rust/rust_test.go",
+        "rust/test_test.go",
     ],
     pluginFor: ["soong_build"],
 }
@@ -580,104 +583,21 @@
     arch: {
         arm: {
             src: "prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/lib/gcc/arm-linux-androideabi/4.9.x/libgcc.a",
-            strip: {
-                keep_symbols_list: [
-                    // unwind-arm.o
-                    "_Unwind_Complete",
-                    "_Unwind_DeleteException",
-                    "_Unwind_GetCFA",
-                    "_Unwind_VRS_Get",
-                    "_Unwind_VRS_Pop",
-                    "_Unwind_VRS_Set",
-                    "__aeabi_unwind_cpp_pr0",
-                    "__aeabi_unwind_cpp_pr1",
-                    "__aeabi_unwind_cpp_pr2",
-                    "__gnu_Unwind_Backtrace",
-                    "__gnu_Unwind_ForcedUnwind",
-                    "__gnu_Unwind_RaiseException",
-                    "__gnu_Unwind_Resume",
-                    "__gnu_Unwind_Resume_or_Rethrow",
-
-                    // libunwind.o
-                    "_Unwind_Backtrace",
-                    "_Unwind_ForcedUnwind",
-                    "_Unwind_RaiseException",
-                    "_Unwind_Resume",
-                    "_Unwind_Resume_or_Rethrow",
-                    "___Unwind_Backtrace",
-                    "___Unwind_ForcedUnwind",
-                    "___Unwind_RaiseException",
-                    "___Unwind_Resume",
-                    "___Unwind_Resume_or_Rethrow",
-                    "__gnu_Unwind_Restore_VFP",
-                    "__gnu_Unwind_Restore_VFP_D",
-                    "__gnu_Unwind_Restore_VFP_D_16_to_31",
-                    "__gnu_Unwind_Restore_WMMXC",
-                    "__gnu_Unwind_Restore_WMMXD",
-                    "__gnu_Unwind_Save_VFP",
-                    "__gnu_Unwind_Save_VFP_D",
-                    "__gnu_Unwind_Save_VFP_D_16_to_31",
-                    "__gnu_Unwind_Save_WMMXC",
-                    "__gnu_Unwind_Save_WMMXD",
-                    "__restore_core_regs",
-                    "restore_core_regs",
-
-                    // pr-support.o
-                    "_Unwind_GetDataRelBase",
-                    "_Unwind_GetLanguageSpecificData",
-                    "_Unwind_GetRegionStart",
-                    "_Unwind_GetTextRelBase",
-                    "__gnu_unwind_execute",
-                    "__gnu_unwind_frame",
-                ],
-            },
+            repack_objects_to_keep: ["unwind-arm.o", "libunwind.o", "pr-support.o"],
         },
         arm64: {
             src: "prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/lib/gcc/aarch64-linux-android/4.9.x/libgcc.a",
+            repack_objects_to_keep: ["unwind-dw2.o", "unwind-dw2-fde-dip.o"],
         },
         x86: {
             src: "prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/lib/gcc/x86_64-linux-android/4.9.x/32/libgcc.a",
-
+            repack_objects_to_keep: ["unwind-dw2.o", "unwind-dw2-fde-dip.o"],
         },
         x86_64: {
             src: "prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/lib/gcc/x86_64-linux-android/4.9.x/libgcc.a",
+            repack_objects_to_keep: ["unwind-dw2.o", "unwind-dw2-fde-dip.o"],
         },
     },
-    strip: {
-        keep_symbols_list: [
-            // unwind-dw2.o
-            "_Unwind_Backtrace",
-            "_Unwind_DeleteException",
-            "_Unwind_FindEnclosingFunction",
-            "_Unwind_ForcedUnwind",
-            "_Unwind_GetCFA",
-            "_Unwind_GetDataRelBase",
-            "_Unwind_GetGR",
-            "_Unwind_GetIP",
-            "_Unwind_GetIPInfo",
-            "_Unwind_GetLanguageSpecificData",
-            "_Unwind_GetRegionStart",
-            "_Unwind_GetTextRelBase",
-            "_Unwind_RaiseException",
-            "_Unwind_Resume",
-            "_Unwind_Resume_or_Rethrow",
-            "_Unwind_SetGR",
-            "_Unwind_SetIP",
-            "__frame_state_for",
-
-            // unwind-dw2-fde-dip.o
-            "_Unwind_Find_FDE",
-            "__deregister_frame",
-            "__deregister_frame_info",
-            "__deregister_frame_info_bases",
-            "__register_frame",
-            "__register_frame_info",
-            "__register_frame_info_bases",
-            "__register_frame_info_table",
-            "__register_frame_info_table_bases",
-            "__register_frame_table",
-        ],
-    },
 }
 
 toolchain_library {
diff --git a/OWNERS b/OWNERS
index 797229f..4ae045d 100644
--- a/OWNERS
+++ b/OWNERS
@@ -4,4 +4,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 rust/config/whitelist.go = chh@google.com, ivanlozano@google.com, jeffv@google.com, jgalenson@google.com, srhines@google.com
diff --git a/android/config.go b/android/config.go
index e208dcd..1e5a24d 100644
--- a/android/config.go
+++ b/android/config.go
@@ -113,8 +113,6 @@
 	captureBuild      bool // true for tests, saves build parameters for each module
 	ignoreEnvironment bool // true for tests, returns empty from all Getenv calls
 
-	targetOpenJDK9 bool // Target 1.9
-
 	stopBefore bootstrap.StopBefore
 
 	OncePer
@@ -214,9 +212,9 @@
 	config := &config{
 		productVariables: productVariables{
 			DeviceName:                  stringPtr("test_device"),
-			Platform_sdk_version:        intPtr(26),
+			Platform_sdk_version:        intPtr(30),
 			DeviceSystemSdkVersions:     []string{"14", "15"},
-			Platform_systemsdk_versions: []string{"25", "26"},
+			Platform_systemsdk_versions: []string{"29", "30"},
 			AAPTConfig:                  []string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"},
 			AAPTPreferredConfig:         stringPtr("xhdpi"),
 			AAPTCharacteristics:         stringPtr("nosdcard"),
@@ -392,13 +390,9 @@
 func (c *config) fromEnv() error {
 	switch c.Getenv("EXPERIMENTAL_JAVA_LANGUAGE_LEVEL_9") {
 	case "", "true":
-		// Use -source 9 -target 9. This is the default.
-		c.targetOpenJDK9 = true
-	case "false":
-		// Use -source 8 -target 8. This is the legacy behaviour.
-		c.targetOpenJDK9 = false
+		// Do nothing
 	default:
-		return fmt.Errorf(`Invalid value for EXPERIMENTAL_JAVA_LANGUAGE_LEVEL_9, should be "", "true", or "false"`)
+		return fmt.Errorf("The environment variable EXPERIMENTAL_JAVA_LANGUAGE_LEVEL_9 is no longer supported. Java language level 9 is now the global default.")
 	}
 
 	return nil
@@ -779,11 +773,6 @@
 	return c.XrefCorpusName() != ""
 }
 
-// Returns true if -source 1.9 -target 1.9 is being passed to javac
-func (c *config) TargetOpenJDK9() bool {
-	return c.targetOpenJDK9
-}
-
 func (c *config) ClangTidy() bool {
 	return Bool(c.productVariables.ClangTidy)
 }
@@ -1098,6 +1087,10 @@
 	return c.productVariables.EnforceSystemCertificateWhitelist
 }
 
+func (c *config) EnforceProductPartitionInterface() bool {
+	return Bool(c.productVariables.EnforceProductPartitionInterface)
+}
+
 func (c *config) ProductHiddenAPIStubs() []string {
 	return c.productVariables.ProductHiddenAPIStubs
 }
diff --git a/android/module.go b/android/module.go
index 70b602b..a6b8d53 100644
--- a/android/module.go
+++ b/android/module.go
@@ -1195,9 +1195,9 @@
 func (m *moduleContext) Rule(pctx PackageContext, name string, params blueprint.RuleParams,
 	argNames ...string) blueprint.Rule {
 
-	if m.config.UseGoma() && params.Pool == nil {
-		// When USE_GOMA=true is set and the rule is not supported by goma, restrict jobs to the
-		// local parallelism value
+	if (m.config.UseGoma() || m.config.UseRBE()) && params.Pool == nil {
+		// When USE_GOMA=true or USE_RBE=true are set and the rule is not supported by goma/RBE, restrict
+		// jobs to the local parallelism value
 		params.Pool = localPool
 	}
 
diff --git a/android/neverallow.go b/android/neverallow.go
index aff706c..48efb4f 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -64,6 +64,8 @@
 	// The list of paths that cannot be referenced using include_dirs
 	paths := []string{
 		"art",
+		"art/libnativebridge",
+		"art/libnativeloader",
 		"libcore",
 		"libnativehelper",
 		"external/apache-harmony",
@@ -75,8 +77,6 @@
 		"external/okhttp",
 		"external/vixl",
 		"external/wycheproof",
-		"system/core/libnativebridge",
-		"system/core/libnativehelper",
 	}
 
 	// Create a composite matcher that will match if the value starts with any of the restricted
diff --git a/android/package_ctx.go b/android/package_ctx.go
index 548450e..cf8face 100644
--- a/android/package_ctx.go
+++ b/android/package_ctx.go
@@ -115,9 +115,9 @@
 		if len(ctx.errors) > 0 {
 			return params, ctx.errors[0]
 		}
-		if ctx.Config().UseGoma() && params.Pool == nil {
-			// When USE_GOMA=true is set and the rule is not supported by goma, restrict jobs to the
-			// local parallelism value
+		if (ctx.Config().UseGoma() || ctx.Config().UseRBE()) && params.Pool == nil {
+			// When USE_GOMA=true or USE_RBE=true are set and the rule is not supported by
+			// goma/RBE, restrict jobs to the local parallelism value
 			params.Pool = localPool
 		}
 		return params, nil
@@ -254,9 +254,35 @@
 	}, argNames...)
 }
 
-// AndroidGomaStaticRule wraps blueprint.StaticRule but uses goma's parallelism if goma is enabled
-func (p PackageContext) AndroidGomaStaticRule(name string, params blueprint.RuleParams,
+// RemoteRuleSupports selects if a AndroidRemoteStaticRule supports goma, RBE, or both.
+type RemoteRuleSupports int
+
+const (
+	SUPPORTS_NONE = 0
+	SUPPORTS_GOMA = 1 << iota
+	SUPPORTS_RBE  = 1 << iota
+	SUPPORTS_BOTH = SUPPORTS_GOMA | SUPPORTS_RBE
+)
+
+// AndroidRemoteStaticRule wraps blueprint.StaticRule but uses goma or RBE's parallelism if goma or RBE are enabled
+// and the appropriate SUPPORTS_* flag is set.
+func (p PackageContext) AndroidRemoteStaticRule(name string, supports RemoteRuleSupports, params blueprint.RuleParams,
 	argNames ...string) blueprint.Rule {
-	// bypass android.PackageContext.StaticRule so that Pool does not get set to local_pool.
-	return p.PackageContext.StaticRule(name, params, argNames...)
+
+	return p.PackageContext.RuleFunc(name, func(config interface{}) (blueprint.RuleParams, error) {
+		ctx := &configErrorWrapper{p, config.(Config), nil}
+		if ctx.Config().UseGoma() && supports&SUPPORTS_GOMA == 0 {
+			// When USE_GOMA=true is set and the rule is not supported by goma, restrict jobs to the
+			// local parallelism value
+			params.Pool = localPool
+		}
+
+		if ctx.Config().UseRBE() && supports&SUPPORTS_RBE == 0 {
+			// When USE_RBE=true is set and the rule is not supported by RBE, restrict jobs to the
+			// local parallelism value
+			params.Pool = localPool
+		}
+
+		return params, nil
+	}, argNames...)
 }
diff --git a/android/prebuilt_etc.go b/android/prebuilt_etc.go
index 6c4813b..6c80370 100644
--- a/android/prebuilt_etc.go
+++ b/android/prebuilt_etc.go
@@ -54,6 +54,12 @@
 	Installable *bool
 }
 
+type PrebuiltEtcModule interface {
+	Module
+	SubDir() string
+	OutputFile() OutputPath
+}
+
 type PrebuiltEtc struct {
 	ModuleBase
 
diff --git a/android/singleton.go b/android/singleton.go
index 33bc6d1..5519ca0 100644
--- a/android/singleton.go
+++ b/android/singleton.go
@@ -131,9 +131,9 @@
 }
 
 func (s *singletonContextAdaptor) Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule {
-	if s.Config().UseGoma() && params.Pool == nil {
-		// When USE_GOMA=true is set and the rule is not supported by goma, restrict jobs to the
-		// local parallelism value
+	if (s.Config().UseGoma() || s.Config().UseRBE()) && params.Pool == nil {
+		// When USE_GOMA=true or USE_RBE=true are set and the rule is not supported by goma/RBE, restrict
+		// jobs to the local parallelism value
 		params.Pool = localPool
 	}
 	rule := s.SingletonContext.Rule(pctx.PackageContext, name, params, argNames...)
diff --git a/android/util.go b/android/util.go
index 71ded5e..81f481d 100644
--- a/android/util.go
+++ b/android/util.go
@@ -93,6 +93,20 @@
 	return s
 }
 
+func SortedStringMapValues(m interface{}) []string {
+	v := reflect.ValueOf(m)
+	if v.Kind() != reflect.Map {
+		panic(fmt.Sprintf("%#v is not a map", m))
+	}
+	keys := v.MapKeys()
+	s := make([]string, 0, len(keys))
+	for _, key := range keys {
+		s = append(s, v.MapIndex(key).String())
+	}
+	sort.Strings(s)
+	return s
+}
+
 func IndexList(s string, list []string) int {
 	for i, l := range list {
 		if l == s {
@@ -352,3 +366,14 @@
 	}
 	return ret
 }
+
+func CheckDuplicate(values []string) (duplicate string, found bool) {
+	seen := make(map[string]string)
+	for _, v := range values {
+		if duplicate, found = seen[v]; found {
+			return
+		}
+		seen[v] = v
+	}
+	return
+}
diff --git a/android/variable.go b/android/variable.go
index 41943b0..25a5dc0 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -119,6 +119,10 @@
 		Flatten_apex struct {
 			Enabled *bool
 		}
+
+		Experimental_mte struct {
+			Cflags []string `android:"arch_variant"`
+		} `android:"arch_variant"`
 	} `android:"arch_variant"`
 }
 
@@ -228,6 +232,8 @@
 	EnableXOM       *bool    `json:",omitempty"`
 	XOMExcludePaths []string `json:",omitempty"`
 
+	Experimental_mte *bool `json:",omitempty"`
+
 	VendorPath    *string `json:",omitempty"`
 	OdmPath       *string `json:",omitempty"`
 	ProductPath   *string `json:",omitempty"`
@@ -303,6 +309,8 @@
 	TargetFSConfigGen []string `json:",omitempty"`
 
 	MissingUsesLibraries []string `json:",omitempty"`
+
+	EnforceProductPartitionInterface *bool `json:",omitempty"`
 }
 
 func boolPtr(v bool) *bool {
diff --git a/androidmk/Android.bp b/androidmk/Android.bp
index 79fe530..4110073 100644
--- a/androidmk/Android.bp
+++ b/androidmk/Android.bp
@@ -19,12 +19,23 @@
 blueprint_go_binary {
     name: "androidmk",
     srcs: [
-        "cmd/androidmk/android.go",
-        "cmd/androidmk/androidmk.go",
-        "cmd/androidmk/values.go",
+        "cmd/androidmk.go",
+    ],
+    deps: [
+        "androidmk-lib",
+    ],
+}
+
+bootstrap_go_package {
+    name: "androidmk-lib",
+    pkgPath: "android/soong/androidmk/androidmk",
+    srcs: [
+        "androidmk/android.go",
+        "androidmk/androidmk.go",
+        "androidmk/values.go",
     ],
     testSrcs: [
-        "cmd/androidmk/androidmk_test.go",
+        "androidmk/androidmk_test.go",
     ],
     deps: [
         "androidmk-parser",
diff --git a/androidmk/cmd/androidmk/android.go b/androidmk/androidmk/android.go
similarity index 99%
rename from androidmk/cmd/androidmk/android.go
rename to androidmk/androidmk/android.go
index fcadd03..0082d8b 100644
--- a/androidmk/cmd/androidmk/android.go
+++ b/androidmk/androidmk/android.go
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package main
+package androidmk
 
 import (
 	"android/soong/android"
@@ -198,6 +198,7 @@
 			"LOCAL_EXPORT_PACKAGE_RESOURCES":   "export_package_resources",
 			"LOCAL_PRIVILEGED_MODULE":          "privileged",
 			"LOCAL_AAPT_INCLUDE_ALL_RESOURCES": "aapt_include_all_resources",
+			"LOCAL_DONT_MERGE_MANIFESTS":       "dont_merge_manifests",
 			"LOCAL_USE_EMBEDDED_NATIVE_LIBS":   "use_embedded_native_libs",
 			"LOCAL_USE_EMBEDDED_DEX":           "use_embedded_dex",
 
diff --git a/androidmk/cmd/androidmk/androidmk.go b/androidmk/androidmk/androidmk.go
similarity index 93%
rename from androidmk/cmd/androidmk/androidmk.go
rename to androidmk/androidmk/androidmk.go
index d2a84d1..9d0c3ac 100644
--- a/androidmk/cmd/androidmk/androidmk.go
+++ b/androidmk/androidmk/androidmk.go
@@ -12,14 +12,11 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package main
+package androidmk
 
 import (
 	"bytes"
-	"flag"
 	"fmt"
-	"io/ioutil"
-	"os"
 	"strings"
 	"text/scanner"
 
@@ -30,13 +27,6 @@
 	bpparser "github.com/google/blueprint/parser"
 )
 
-var usage = func() {
-	fmt.Fprintf(os.Stderr, "usage: androidmk [flags] <inputFile>\n"+
-		"\nandroidmk parses <inputFile> as an Android.mk file and attempts to output an analogous Android.bp file (to standard out)\n")
-	flag.PrintDefaults()
-	os.Exit(1)
-}
-
 // TODO: non-expanded variables with expressions
 
 type bpFile struct {
@@ -118,31 +108,7 @@
 	eq   bool
 }
 
-func main() {
-	flag.Usage = usage
-	flag.Parse()
-	if len(flag.Args()) != 1 {
-		usage()
-	}
-	filePathToRead := flag.Arg(0)
-	b, err := ioutil.ReadFile(filePathToRead)
-	if err != nil {
-		fmt.Println(err.Error())
-		return
-	}
-
-	output, errs := convertFile(os.Args[1], bytes.NewBuffer(b))
-	if len(errs) > 0 {
-		for _, err := range errs {
-			fmt.Fprintln(os.Stderr, "ERROR: ", err)
-		}
-		os.Exit(1)
-	}
-
-	fmt.Print(output)
-}
-
-func convertFile(filename string, buffer *bytes.Buffer) (string, []error) {
+func ConvertFile(filename string, buffer *bytes.Buffer) (string, []error) {
 	p := mkparser.NewParser(filename, buffer)
 
 	nodes, errs := p.Parse()
diff --git a/androidmk/cmd/androidmk/androidmk_test.go b/androidmk/androidmk/androidmk_test.go
similarity index 99%
rename from androidmk/cmd/androidmk/androidmk_test.go
rename to androidmk/androidmk/androidmk_test.go
index dbb7fde..7e1a72c 100644
--- a/androidmk/cmd/androidmk/androidmk_test.go
+++ b/androidmk/androidmk/androidmk_test.go
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package main
+package androidmk
 
 import (
 	"bytes"
@@ -1350,7 +1350,7 @@
 			t.Error(err)
 		}
 
-		got, errs := convertFile(fmt.Sprintf("<testcase %d>", i), bytes.NewBufferString(test.in))
+		got, errs := ConvertFile(fmt.Sprintf("<testcase %d>", i), bytes.NewBufferString(test.in))
 		if len(errs) > 0 {
 			t.Errorf("Unexpected errors: %q", errs)
 			continue
diff --git a/androidmk/cmd/androidmk/values.go b/androidmk/androidmk/values.go
similarity index 99%
rename from androidmk/cmd/androidmk/values.go
rename to androidmk/androidmk/values.go
index 90f2e74..6b18a65 100644
--- a/androidmk/cmd/androidmk/values.go
+++ b/androidmk/androidmk/values.go
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package main
+package androidmk
 
 import (
 	"fmt"
diff --git a/androidmk/cmd/androidmk.go b/androidmk/cmd/androidmk.go
new file mode 100644
index 0000000..00488eb
--- /dev/null
+++ b/androidmk/cmd/androidmk.go
@@ -0,0 +1,56 @@
+// Copyright 2017 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 main
+
+import (
+	"bytes"
+	"flag"
+	"fmt"
+	"io/ioutil"
+	"os"
+
+	"android/soong/androidmk/androidmk"
+)
+
+var usage = func() {
+	fmt.Fprintf(os.Stderr, "usage: androidmk [flags] <inputFile>\n"+
+		"\nandroidmk parses <inputFile> as an Android.mk file and attempts to output an analogous Android.bp file (to standard out)\n")
+	flag.PrintDefaults()
+	os.Exit(1)
+}
+
+func main() {
+	flag.Usage = usage
+	flag.Parse()
+	if len(flag.Args()) != 1 {
+		usage()
+	}
+	filePathToRead := flag.Arg(0)
+	b, err := ioutil.ReadFile(filePathToRead)
+	if err != nil {
+		fmt.Println(err.Error())
+		return
+	}
+
+	output, errs := androidmk.ConvertFile(os.Args[1], bytes.NewBuffer(b))
+	if len(errs) > 0 {
+		for _, err := range errs {
+			fmt.Fprintln(os.Stderr, "ERROR: ", err)
+		}
+		os.Exit(1)
+	}
+
+	fmt.Print(output)
+}
diff --git a/androidmk/partner_androidmk/Android.bp b/androidmk/partner_androidmk/Android.bp
new file mode 100644
index 0000000..532116a
--- /dev/null
+++ b/androidmk/partner_androidmk/Android.bp
@@ -0,0 +1,49 @@
+// Copyright 2015 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.
+
+//
+// Sample project for creating an extended androidmk
+//
+
+blueprint_go_binary {
+    name: "partner_androidmk",
+    srcs: [
+        "partner_androidmk/androidmk.go",
+    ],
+    testSrcs: [
+        "partner_androidmk/androidmk_test.go",
+    ],
+    deps: [
+        "androidmk-lib",
+        "partner_bpfix_extensions",
+    ],
+}
+
+blueprint_go_binary {
+    name: "partner_bpfix",
+    srcs: [
+        "partner_bpfix/bpfix.go",
+    ],
+    deps: [
+        "bpfix-cmd",
+        "partner_bpfix_extensions",
+    ],
+}
+
+bootstrap_go_package {
+    name: "partner_bpfix_extensions",
+    pkgPath: "partner/android/bpfix/extensions",
+    srcs: ["fixes/headers.go"],
+    deps: ["bpfix-lib"],
+}
diff --git a/androidmk/partner_androidmk/fixes/headers.go b/androidmk/partner_androidmk/fixes/headers.go
new file mode 100644
index 0000000..169dab6
--- /dev/null
+++ b/androidmk/partner_androidmk/fixes/headers.go
@@ -0,0 +1,120 @@
+package extensions
+
+import (
+	"strings"
+
+	"github.com/google/blueprint/parser"
+
+	"android/soong/bpfix/bpfix"
+)
+
+var fixSteps = bpfix.FixStepsExtension{
+	Name: "partner-include-dirs",
+	Steps: []bpfix.FixStep{
+		{
+			Name: "fixIncludeDirs",
+			Fix:  fixIncludeDirs,
+		},
+	},
+}
+
+func init() {
+	bpfix.RegisterFixStepExtension(&fixSteps)
+}
+
+type includeDirFix struct {
+	libName  string
+	libType  string
+	variable string
+	subdir   string
+}
+
+var commonIncludeDirs = []includeDirFix{
+	{
+		libName:  "my_header_lib",
+		libType:  "header_libs",
+		variable: "TARGET_OUT_HEADERS",
+		subdir:   "/my_headers",
+	},
+}
+
+func findHeaderLib(e parser.Expression) (*includeDirFix, bool) {
+	if op, ok := e.(*parser.Operator); ok {
+		if op.Operator != '+' {
+			return nil, false
+		}
+		arg0, ok := op.Args[0].(*parser.Variable)
+		arg1, ok1 := op.Args[1].(*parser.String)
+		if !ok || !ok1 {
+			return nil, false
+		}
+		for _, lib := range commonIncludeDirs {
+			if arg0.Name == lib.variable && arg1.Value == lib.subdir {
+				return &lib, true
+			}
+		}
+	}
+	return nil, false
+}
+func searchThroughOperatorList(mod *parser.Module, e parser.Expression) {
+	if list, ok := e.(*parser.List); ok {
+		newList := make([]parser.Expression, 0, len(list.Values))
+		for _, item := range list.Values {
+			if lib, found := findHeaderLib(item); found {
+				if lib.libName != "" {
+					addLibrary(mod, lib.libType, lib.libName)
+				}
+			} else {
+				newList = append(newList, item)
+			}
+		}
+		list.Values = newList
+	}
+	if op, ok := e.(*parser.Operator); ok {
+		searchThroughOperatorList(mod, op.Args[0])
+		searchThroughOperatorList(mod, op.Args[1])
+	}
+}
+func getLiteralListProperty(mod *parser.Module, name string) (list *parser.List, found bool) {
+	prop, ok := mod.GetProperty(name)
+	if !ok {
+		return nil, false
+	}
+	list, ok = prop.Value.(*parser.List)
+	return list, ok
+}
+func addLibrary(mod *parser.Module, libType string, libName string) {
+	var list, ok = getLiteralListProperty(mod, libType)
+	if !ok {
+		list = new(parser.List)
+		prop := new(parser.Property)
+		prop.Name = libType
+		prop.Value = list
+		mod.Properties = append(mod.Properties, prop)
+	} else {
+		for _, v := range list.Values {
+			if stringValue, ok := v.(*parser.String); ok && stringValue.Value == libName {
+				return
+			}
+		}
+	}
+	lib := new(parser.String)
+	lib.Value = libName
+	list.Values = append(list.Values, lib)
+}
+func fixIncludeDirs(f *bpfix.Fixer) error {
+	tree := f.Tree()
+	for _, def := range tree.Defs {
+		mod, ok := def.(*parser.Module)
+		if !ok {
+			continue
+		}
+		if !strings.HasPrefix(mod.Type, "cc_") {
+			continue
+		}
+		if prop, ok := mod.GetProperty("include_dirs"); ok {
+			searchThroughOperatorList(mod, prop.Value)
+		}
+	}
+	return nil
+}
diff --git a/androidmk/partner_androidmk/partner_androidmk/androidmk.go b/androidmk/partner_androidmk/partner_androidmk/androidmk.go
new file mode 100644
index 0000000..af8cdf3
--- /dev/null
+++ b/androidmk/partner_androidmk/partner_androidmk/androidmk.go
@@ -0,0 +1,58 @@
+// Copyright 2017 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 main
+
+import (
+	"bytes"
+	"flag"
+	"fmt"
+	"io/ioutil"
+	"os"
+
+	"android/soong/androidmk/androidmk"
+
+	_ "partner/android/bpfix/extensions"
+)
+
+var usage = func() {
+	fmt.Fprintf(os.Stderr, "usage: %s [flags] <inputFile>\n"+
+		"\n%s parses <inputFile> as an Android.mk file and attempts to output an analogous Android.bp file (to standard out)\n", os.Args[0], os.Args[0])
+	flag.PrintDefaults()
+	os.Exit(1)
+}
+
+func main() {
+	flag.Usage = usage
+	flag.Parse()
+	if len(flag.Args()) != 1 {
+		usage()
+	}
+	filePathToRead := flag.Arg(0)
+	b, err := ioutil.ReadFile(filePathToRead)
+	if err != nil {
+		fmt.Println(err.Error())
+		return
+	}
+
+	output, errs := androidmk.ConvertFile(os.Args[1], bytes.NewBuffer(b))
+	if len(errs) > 0 {
+		for _, err := range errs {
+			fmt.Fprintln(os.Stderr, "ERROR: ", err)
+		}
+		os.Exit(1)
+	}
+
+	fmt.Print(output)
+}
diff --git a/androidmk/partner_androidmk/partner_androidmk/androidmk_test.go b/androidmk/partner_androidmk/partner_androidmk/androidmk_test.go
new file mode 100644
index 0000000..ff04e88
--- /dev/null
+++ b/androidmk/partner_androidmk/partner_androidmk/androidmk_test.go
@@ -0,0 +1,73 @@
+// Copyright 2016 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 main
+
+import (
+	"bytes"
+	"fmt"
+	"strings"
+	"testing"
+
+	"android/soong/androidmk/androidmk"
+	"android/soong/bpfix/bpfix"
+
+	_ "partner/android/bpfix/extensions"
+)
+
+var testCases = []struct {
+	desc     string
+	in       string
+	expected string
+}{
+	{
+		desc: "headers replacement",
+		in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := test
+LOCAL_SRC_FILES := a.c
+LOCAL_C_INCLUDES := test1 $(TARGET_OUT_HEADERS)/my_headers test2
+include $(BUILD_SHARED_LIBRARY)`,
+		expected: `
+cc_library_shared {
+    name: "test",
+	srcs: ["a.c"],
+	include_dirs: [
+		"test1",
+
+		"test2",
+	],
+	header_libs: ["my_header_lib"]
+}`,
+	},
+}
+
+func TestEndToEnd(t *testing.T) {
+	for i, test := range testCases {
+		expected, err := bpfix.Reformat(test.expected)
+		if err != nil {
+			t.Error(err)
+		}
+
+		got, errs := androidmk.ConvertFile(fmt.Sprintf("<testcase %d>", i), bytes.NewBufferString(test.in))
+		if len(errs) > 0 {
+			t.Errorf("Unexpected errors: %q", errs)
+			continue
+		}
+
+		if got != expected {
+			t.Errorf("failed testcase '%s'\ninput:\n%s\n\nexpected:\n%s\ngot:\n%s\n", test.desc, strings.TrimSpace(test.in), expected, got)
+		}
+	}
+}
diff --git a/androidmk/partner_androidmk/partner_bpfix/bpfix.go b/androidmk/partner_androidmk/partner_bpfix/bpfix.go
new file mode 100644
index 0000000..2c8e0a8
--- /dev/null
+++ b/androidmk/partner_androidmk/partner_bpfix/bpfix.go
@@ -0,0 +1,27 @@
+// Copyright 2017 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.
+
+// This file provides a command-line interface to bpfix
+
+package main
+
+import (
+	"android/soong/bpfix/bpfix/cmd"
+
+	_ "partner/android/bpfix/extensions"
+)
+
+func main() {
+	cmd.Run()
+}
diff --git a/apex/apex.go b/apex/apex.go
index c9b989a..f03a8f9 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -41,7 +41,6 @@
 	// TODO(b/113082813) make this configurable using config.fs syntax
 	generateFsConfig = pctx.StaticRule("generateFsConfig", blueprint.RuleParams{
 		Command: `echo '/ 1000 1000 0755' > ${out} && ` +
-			`echo '/apex_manifest.json 1000 1000 0644' >> ${out} && ` +
 			`echo ${ro_paths} | tr ' ' '\n' | awk '{print "/"$$1 " 1000 1000 0644"}' >> ${out} && ` +
 			`echo ${exec_paths} | tr ' ' '\n' | awk '{print "/"$$1 " 0 2000 0755"}' >> ${out}`,
 		Description: "fs_config ${out}",
@@ -57,6 +56,18 @@
 		Description: "prepare ${out}",
 	}, "provideNativeLibs", "requireNativeLibs", "opt")
 
+	stripApexManifestRule = pctx.StaticRule("stripApexManifestRule", blueprint.RuleParams{
+		Command:     `rm -f $out && ${conv_apex_manifest} strip $in -o $out`,
+		CommandDeps: []string{"${conv_apex_manifest}"},
+		Description: "strip ${in}=>${out}",
+	})
+
+	pbApexManifestRule = pctx.StaticRule("pbApexManifestRule", blueprint.RuleParams{
+		Command:     `rm -f $out && ${conv_apex_manifest} proto $in -o $out`,
+		CommandDeps: []string{"${conv_apex_manifest}"},
+		Description: "convert ${in}=>${out}",
+	})
+
 	// TODO(b/113233103): make sure that file_contexts is sane, i.e., validate
 	// against the binary policy using sefcontext_compiler -p <policy>.
 
@@ -66,6 +77,7 @@
 			`(. ${out}.copy_commands) && ` +
 			`APEXER_TOOL_PATH=${tool_path} ` +
 			`${apexer} --force --manifest ${manifest} ` +
+			`--manifest_json ${manifest_json} --manifest_json_full ${manifest_json_full} ` +
 			`--file_contexts ${file_contexts} ` +
 			`--canned_fs_config ${canned_fs_config} ` +
 			`--payload_type image ` +
@@ -76,20 +88,22 @@
 		Rspfile:        "${out}.copy_commands",
 		RspfileContent: "${copy_commands}",
 		Description:    "APEX ${image_dir} => ${out}",
-	}, "tool_path", "image_dir", "copy_commands", "manifest", "file_contexts", "canned_fs_config", "key", "opt_flags")
+	}, "tool_path", "image_dir", "copy_commands", "file_contexts", "canned_fs_config", "key", "opt_flags",
+		"manifest", "manifest_json", "manifest_json_full",
+	)
 
 	zipApexRule = pctx.StaticRule("zipApexRule", blueprint.RuleParams{
 		Command: `rm -rf ${image_dir} && mkdir -p ${image_dir} && ` +
 			`(. ${out}.copy_commands) && ` +
 			`APEXER_TOOL_PATH=${tool_path} ` +
-			`${apexer} --force --manifest ${manifest} ` +
+			`${apexer} --force --manifest ${manifest} --manifest_json_full ${manifest_json_full} ` +
 			`--payload_type zip ` +
 			`${image_dir} ${out} `,
 		CommandDeps:    []string{"${apexer}", "${merge_zips}", "${soong_zip}", "${zipalign}", "${aapt2}"},
 		Rspfile:        "${out}.copy_commands",
 		RspfileContent: "${copy_commands}",
 		Description:    "ZipAPEX ${image_dir} => ${out}",
-	}, "tool_path", "image_dir", "copy_commands", "manifest")
+	}, "tool_path", "image_dir", "copy_commands", "manifest", "manifest_json_full")
 
 	apexProtoConvertRule = pctx.AndroidStaticRule("apexProtoConvertRule",
 		blueprint.RuleParams{
@@ -126,11 +140,17 @@
 	}, "image_content_file", "whitelisted_files_file", "apex_module_name")
 )
 
-var imageApexSuffix = ".apex"
-var zipApexSuffix = ".zipapex"
+const (
+	imageApexSuffix = ".apex"
+	zipApexSuffix   = ".zipapex"
+	flattenedSuffix = ".flattened"
 
-var imageApexType = "image"
-var zipApexType = "zip"
+	imageApexType     = "image"
+	zipApexType       = "zip"
+	flattenedApexType = "flattened"
+
+	vndkApexNamePrefix = "com.android.vndk.v"
+)
 
 type dependencyTag struct {
 	blueprint.BaseDependencyTag
@@ -175,6 +195,7 @@
 	pctx.HostBinToolVariable("zip2zip", "zip2zip")
 	pctx.HostBinToolVariable("zipalign", "zipalign")
 	pctx.HostBinToolVariable("jsonmodify", "jsonmodify")
+	pctx.HostBinToolVariable("conv_apex_manifest", "conv_apex_manifest")
 
 	android.RegisterModuleType("apex", BundleFactory)
 	android.RegisterModuleType("apex_test", testApexBundleFactory)
@@ -182,10 +203,7 @@
 	android.RegisterModuleType("apex_defaults", defaultsFactory)
 	android.RegisterModuleType("prebuilt_apex", PrebuiltFactory)
 
-	android.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
-		ctx.TopDown("apex_vndk_gather", apexVndkGatherMutator).Parallel()
-		ctx.BottomUp("apex_vndk_add_deps", apexVndkAddDepsMutator).Parallel()
-	})
+	android.PreDepsMutators(RegisterPreDepsMutators)
 	android.PostDepsMutators(RegisterPostDepsMutators)
 
 	android.RegisterMakeVarsProvider(pctx, func(ctx android.MakeVarsContext) {
@@ -195,6 +213,11 @@
 	})
 }
 
+func RegisterPreDepsMutators(ctx android.RegisterMutatorsContext) {
+	ctx.TopDown("apex_vndk", apexVndkMutator).Parallel()
+	ctx.BottomUp("apex_vndk_deps", apexVndkDepsMutator).Parallel()
+}
+
 func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) {
 	ctx.TopDown("apex_deps", apexDepsMutator)
 	ctx.BottomUp("apex", apexMutator).Parallel()
@@ -207,45 +230,43 @@
 	vndkApexListMutex sync.Mutex
 )
 
-func vndkApexList(config android.Config) map[string]*apexBundle {
+func vndkApexList(config android.Config) map[string]string {
 	return config.Once(vndkApexListKey, func() interface{} {
-		return map[string]*apexBundle{}
-	}).(map[string]*apexBundle)
+		return map[string]string{}
+	}).(map[string]string)
 }
 
-// apexVndkGatherMutator gathers "apex_vndk" modules and puts them in a map with vndk_version as a key.
-func apexVndkGatherMutator(mctx android.TopDownMutatorContext) {
+func apexVndkMutator(mctx android.TopDownMutatorContext) {
 	if ab, ok := mctx.Module().(*apexBundle); ok && ab.vndkApex {
 		if ab.IsNativeBridgeSupported() {
 			mctx.PropertyErrorf("native_bridge_supported", "%q doesn't support native bridge binary.", mctx.ModuleType())
 		}
 
-		vndkVersion := proptools.String(ab.vndkProperties.Vndk_version)
+		vndkVersion := ab.vndkVersion(mctx.DeviceConfig())
+		// Ensure VNDK APEX mount point is formatted as com.android.vndk.v###
+		ab.properties.Apex_name = proptools.StringPtr(vndkApexNamePrefix + vndkVersion)
 
+		// vndk_version should be unique
 		vndkApexListMutex.Lock()
 		defer vndkApexListMutex.Unlock()
 		vndkApexList := vndkApexList(mctx.Config())
 		if other, ok := vndkApexList[vndkVersion]; ok {
-			mctx.PropertyErrorf("vndk_version", "%v is already defined in %q", vndkVersion, other.BaseModuleName())
+			mctx.PropertyErrorf("vndk_version", "%v is already defined in %q", vndkVersion, other)
 		}
-		vndkApexList[vndkVersion] = ab
+		vndkApexList[vndkVersion] = mctx.ModuleName()
 	}
 }
 
-// apexVndkAddDepsMutator adds (reverse) dependencies from vndk libs to apex_vndk modules.
-// It filters only libs with matching targets.
-func apexVndkAddDepsMutator(mctx android.BottomUpMutatorContext) {
-	if cc, ok := mctx.Module().(*cc.Module); ok && cc.IsVndkOnSystem() {
+func apexVndkDepsMutator(mctx android.BottomUpMutatorContext) {
+	if m, ok := mctx.Module().(*cc.Module); ok && cc.IsForVndkApex(mctx, m) {
+		vndkVersion := m.VndkVersion()
 		vndkApexList := vndkApexList(mctx.Config())
-		if ab, ok := vndkApexList[cc.VndkVersion()]; ok {
-			targetArch := cc.Target().String()
-			for _, target := range ab.MultiTargets() {
-				if target.String() == targetArch {
-					mctx.AddReverseDependency(mctx.Module(), sharedLibTag, ab.Name())
-					break
-				}
-			}
+		if vndkApex, ok := vndkApexList[vndkVersion]; ok {
+			mctx.AddReverseDependency(mctx.Module(), sharedLibTag, vndkApex)
 		}
+	} else if a, ok := mctx.Module().(*apexBundle); ok && a.vndkApex {
+		vndkVersion := proptools.StringDefault(a.vndkProperties.Vndk_version, "current")
+		mctx.AddDependency(mctx.Module(), prebuiltTag, cc.VndkLibrariesTxtModules(vndkVersion)...)
 	}
 }
 
@@ -315,13 +336,30 @@
 
 func apexFlattenedMutator(mctx android.BottomUpMutatorContext) {
 	if ab, ok := mctx.Module().(*apexBundle); ok {
-		if !mctx.Config().FlattenApex() || mctx.Config().UnbundledBuild() {
-			modules := mctx.CreateLocalVariations("", "flattened")
-			modules[0].(*apexBundle).SetFlattened(false)
-			modules[1].(*apexBundle).SetFlattened(true)
-		} else {
-			ab.SetFlattened(true)
-			ab.SetFlattenedConfigValue()
+		var variants []string
+		switch proptools.StringDefault(ab.properties.Payload_type, "image") {
+		case "image":
+			variants = append(variants, imageApexType, flattenedApexType)
+		case "zip":
+			variants = append(variants, zipApexType)
+		case "both":
+			variants = append(variants, imageApexType, zipApexType, flattenedApexType)
+		default:
+			mctx.PropertyErrorf("type", "%q is not one of \"image\" or \"zip\".", *ab.properties.Payload_type)
+			return
+		}
+
+		modules := mctx.CreateLocalVariations(variants...)
+
+		for i, v := range variants {
+			switch v {
+			case imageApexType:
+				modules[i].(*apexBundle).properties.ApexType = imageApex
+			case zipApexType:
+				modules[i].(*apexBundle).properties.ApexType = zipApex
+			case flattenedApexType:
+				modules[i].(*apexBundle).properties.ApexType = flattenedApex
+			}
 		}
 	}
 }
@@ -332,6 +370,34 @@
 	}
 }
 
+var (
+	useVendorWhitelistKey = android.NewOnceKey("useVendorWhitelist")
+)
+
+// useVendorWhitelist returns the list of APEXes which are allowed to use_vendor.
+// When use_vendor is used, native modules are built with __ANDROID_VNDK__ and __ANDROID_APEX__,
+// which may cause compatibility issues. (e.g. libbinder)
+// Even though libbinder restricts its availability via 'apex_available' property and relies on
+// yet another macro __ANDROID_APEX_<NAME>__, we restrict usage of "use_vendor:" from other APEX modules
+// to avoid similar problems.
+func useVendorWhitelist(config android.Config) []string {
+	return config.Once(useVendorWhitelistKey, func() interface{} {
+		return []string{
+			// swcodec uses "vendor" variants for smaller size
+			"com.android.media.swcodec",
+			"test_com.android.media.swcodec",
+		}
+	}).([]string)
+}
+
+// setUseVendorWhitelistForTest overrides useVendorWhitelist and must be
+// called before the first call to useVendorWhitelist()
+func setUseVendorWhitelistForTest(config android.Config, whitelist []string) {
+	config.Once(useVendorWhitelistKey, func() interface{} {
+		return whitelist
+	})
+}
+
 type apexNativeDependencies struct {
 	// List of native libraries
 	Native_shared_libs []string
@@ -437,13 +503,9 @@
 	// List of APKs to package inside APEX
 	Apps []string
 
-	// To distinguish between flattened and non-flattened apex.
-	// if set true, then output files are flattened.
-	Flattened bool `blueprint:"mutated"`
-
-	// if true, it means that TARGET_FLATTEN_APEX is true and
-	// TARGET_BUILD_APPS is false
-	FlattenedConfigValue bool `blueprint:"mutated"`
+	// package format of this apex variant; could be non-flattened, flattened, or zip.
+	// imageApex, zipApex or flattened
+	ApexType apexPackaging `blueprint:"mutated"`
 
 	// List of SDKs that are used to build this APEX. A reference to an SDK should be either
 	// `name#version` or `name` which is an alias for `name#current`. If left empty, `platform#current`
@@ -500,33 +562,16 @@
 const (
 	imageApex apexPackaging = iota
 	zipApex
-	both
+	flattenedApex
 )
 
-func (a apexPackaging) image() bool {
-	switch a {
-	case imageApex, both:
-		return true
-	}
-	return false
-}
-
-func (a apexPackaging) zip() bool {
-	switch a {
-	case zipApex, both:
-		return true
-	}
-	return false
-}
-
+// The suffix for the output "file", not the module
 func (a apexPackaging) suffix() string {
 	switch a {
 	case imageApex:
 		return imageApexSuffix
 	case zipApex:
 		return zipApexSuffix
-	case both:
-		panic(fmt.Errorf("must be either zip or image"))
 	default:
 		panic(fmt.Errorf("unknown APEX type %d", a))
 	}
@@ -538,8 +583,6 @@
 		return imageApexType
 	case zipApex:
 		return zipApexType
-	case both:
-		panic(fmt.Errorf("must be either zip or image"))
 	default:
 		panic(fmt.Errorf("unknown APEX type %d", a))
 	}
@@ -589,11 +632,8 @@
 	targetProperties apexTargetBundleProperties
 	vndkProperties   apexVndkProperties
 
-	apexTypes apexPackaging
-
 	bundleModuleFile android.WritablePath
-	outputFiles      map[apexPackaging]android.WritablePath
-	flattenedOutput  android.InstallPath
+	outputFile       android.WritablePath
 	installDir       android.InstallPath
 
 	prebuiltFileToDelete string
@@ -610,11 +650,25 @@
 	// list of module names that this APEX is depending on
 	externalDeps []string
 
-	testApex bool
-	vndkApex bool
+	testApex        bool
+	vndkApex        bool
+	artApex         bool
+	primaryApexType bool
 
 	// intermediate path for apex_manifest.json
-	manifestOut android.WritablePath
+	manifestJsonOut     android.WritablePath
+	manifestJsonFullOut android.WritablePath
+	manifestPbOut       android.WritablePath
+
+	// list of commands to create symlinks for backward compatibility
+	// these commands will be attached as LOCAL_POST_INSTALL_CMD to
+	// apex package itself(for unflattened build) or apex_manifest.json(for flattened build)
+	// so that compat symlinks are always installed regardless of TARGET_FLATTEN_APEX setting.
+	compatSymlinks []string
+
+	// Suffix of module name in Android.mk
+	// ".flattened", ".apex", ".zipapex", or ""
+	suffix string
 }
 
 func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext,
@@ -654,6 +708,9 @@
 }
 
 func (a *apexBundle) DepsMutator(ctx android.BottomUpMutatorContext) {
+	if proptools.Bool(a.properties.Use_vendor) && !android.InList(a.Name(), useVendorWhitelist(ctx.Config())) {
+		ctx.PropertyErrorf("use_vendor", "not allowed to set use_vendor: true")
+	}
 
 	targets := ctx.MultiTargets()
 	config := ctx.DeviceConfig()
@@ -802,18 +859,7 @@
 func (a *apexBundle) OutputFiles(tag string) (android.Paths, error) {
 	switch tag {
 	case "":
-		if file, ok := a.outputFiles[imageApex]; ok {
-			return android.Paths{file}, nil
-		} else {
-			return nil, nil
-		}
-	case ".flattened":
-		if a.properties.Flattened {
-			flattenedApexPath := a.flattenedOutput
-			return android.Paths{flattenedApexPath}, nil
-		} else {
-			return nil, nil
-		}
+		return android.Paths{a.outputFile}, nil
 	default:
 		return nil, fmt.Errorf("unsupported module reference tag %q", tag)
 	}
@@ -824,6 +870,9 @@
 }
 
 func (a *apexBundle) getImageVariation(config android.DeviceConfig) string {
+	if a.vndkApex {
+		return "vendor." + a.vndkVersion(config)
+	}
 	if config.VndkVersion() != "" && proptools.Bool(a.properties.Use_vendor) {
 		return "vendor." + config.PlatformVndkVersion()
 	} else {
@@ -867,24 +916,6 @@
 	a.properties.HideFromMake = true
 }
 
-func (a *apexBundle) SetFlattened(flattened bool) {
-	a.properties.Flattened = flattened
-}
-
-func (a *apexBundle) SetFlattenedConfigValue() {
-	a.properties.FlattenedConfigValue = true
-}
-
-// isFlattenedVariant returns true when the current module is the flattened
-// variant of an apex that has both a flattened and an unflattened variant.
-// It returns false when the current module is flattened but there is no
-// unflattened variant, which occurs when ctx.Config().FlattenedApex() returns
-// true. It can be used to avoid collisions between the install paths of the
-// flattened and unflattened variants.
-func (a *apexBundle) isFlattenedVariant() bool {
-	return a.properties.Flattened && !a.properties.FlattenedConfigValue
-}
-
 func getCopyManifestForNativeLibrary(ccMod *cc.Module, config android.Config, 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.
@@ -965,7 +996,7 @@
 	return
 }
 
-func getCopyManifestForPrebuiltEtc(prebuilt *android.PrebuiltEtc) (fileToCopy android.Path, dirInApex string) {
+func getCopyManifestForPrebuiltEtc(prebuilt android.PrebuiltEtcModule) (fileToCopy android.Path, dirInApex string) {
 	dirInApex = filepath.Join("etc", prebuilt.SubDir())
 	fileToCopy = prebuilt.OutputFile()
 	return
@@ -981,6 +1012,16 @@
 	return
 }
 
+func getCopyManifestForAndroidAppImport(app *java.AndroidAppImport, pkgName string) (fileToCopy android.Path, dirInApex string) {
+	appDir := "app"
+	if app.Privileged() {
+		appDir = "priv-app"
+	}
+	dirInApex = filepath.Join(appDir, pkgName)
+	fileToCopy = app.OutputFile()
+	return
+}
+
 // Context "decorator", overriding the InstallBypassMake method to always reply `true`.
 type flattenedApexContext struct {
 	android.ModuleContext
@@ -993,15 +1034,29 @@
 func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	filesInfo := []apexFile{}
 
-	if a.properties.Payload_type == nil || *a.properties.Payload_type == "image" {
-		a.apexTypes = imageApex
-	} else if *a.properties.Payload_type == "zip" {
-		a.apexTypes = zipApex
-	} else if *a.properties.Payload_type == "both" {
-		a.apexTypes = both
-	} else {
-		ctx.PropertyErrorf("type", "%q is not one of \"image\", \"zip\", or \"both\".", *a.properties.Payload_type)
-		return
+	buildFlattenedAsDefault := ctx.Config().FlattenApex() && !ctx.Config().UnbundledBuild()
+	switch a.properties.ApexType {
+	case imageApex:
+		if buildFlattenedAsDefault {
+			a.suffix = imageApexSuffix
+		} else {
+			a.suffix = ""
+			a.primaryApexType = true
+		}
+	case zipApex:
+		if proptools.String(a.properties.Payload_type) == "zip" {
+			a.suffix = ""
+			a.primaryApexType = true
+		} else {
+			a.suffix = zipApexSuffix
+		}
+	case flattenedApex:
+		if buildFlattenedAsDefault {
+			a.suffix = ""
+			a.primaryApexType = true
+		} else {
+			a.suffix = flattenedSuffix
+		}
 	}
 
 	if len(a.properties.Tests) > 0 && !a.testApex {
@@ -1097,7 +1152,7 @@
 					ctx.PropertyErrorf("java_libs", "%q of type %q is not supported", depName, ctx.OtherModuleType(child))
 				}
 			case prebuiltTag:
-				if prebuilt, ok := child.(*android.PrebuiltEtc); ok {
+				if prebuilt, ok := child.(android.PrebuiltEtcModule); ok {
 					fileToCopy, dirInApex := getCopyManifestForPrebuiltEtc(prebuilt)
 					filesInfo = append(filesInfo, apexFile{fileToCopy, depName, dirInApex, etc, prebuilt, nil})
 					return true
@@ -1150,16 +1205,19 @@
 					fileToCopy, dirInApex := getCopyManifestForAndroidApp(ap, ctx.DeviceConfig().OverridePackageNameFor(depName))
 					filesInfo = append(filesInfo, apexFile{fileToCopy, depName, dirInApex, app, ap, nil})
 					return true
+				} else if ap, ok := child.(*java.AndroidAppImport); ok {
+					fileToCopy, dirInApex := getCopyManifestForAndroidAppImport(ap, ctx.DeviceConfig().OverridePackageNameFor(depName))
+					filesInfo = append(filesInfo, apexFile{fileToCopy, depName, dirInApex, app, ap, nil})
 				} else {
 					ctx.PropertyErrorf("apps", "%q is not an android_app module", depName)
 				}
 			}
-		} else {
+		} else if !a.vndkApex {
 			// indirect dependencies
 			if am, ok := child.(android.ApexModule); ok {
 				// We cannot use a switch statement on `depTag` here as the checked
 				// tags used below are private (e.g. `cc.sharedDepTag`).
-				if cc.IsSharedDepTag(depTag) || cc.IsRuntimeDepTag(depTag) {
+				if cc.IsSharedDepTag(depTag) || cc.IsRuntimeDepTag(depTag) || java.IsJniDepTag(depTag) {
 					if cc, ok := child.(*cc.Module); ok {
 						if android.InList(cc.Name(), providedNativeSharedLibs) {
 							// If we're using a shared library which is provided from other APEX,
@@ -1204,6 +1262,19 @@
 		return false
 	})
 
+	// Specific to the ART apex: dexpreopt artifacts for libcore Java libraries.
+	// Build rules are generated by the dexpreopt singleton, and here we access build artifacts
+	// via the global boot image config.
+	if a.artApex {
+		for arch, files := range java.DexpreoptedArtApexJars(ctx) {
+			dirInApex := filepath.Join("javalib", arch.String())
+			for _, f := range files {
+				localModule := "javalib_" + arch.String() + "_" + filepath.Base(f.String())
+				filesInfo = append(filesInfo, apexFile{f, localModule, dirInApex, etc, nil, nil})
+			}
+		}
+	}
+
 	if a.private_key_file == nil {
 		ctx.PropertyErrorf("key", "private_key for %q could not be found", String(a.properties.Key))
 		return
@@ -1244,16 +1315,31 @@
 	// prepend the name of this APEX to the module names. These names will be the names of
 	// modules that will be defined if the APEX is flattened.
 	for i := range filesInfo {
-		filesInfo[i].moduleName = ctx.ModuleName() + "." + filesInfo[i].moduleName
+		filesInfo[i].moduleName = filesInfo[i].moduleName + "." + ctx.ModuleName() + a.suffix
 	}
 
 	a.installDir = android.PathForModuleInstall(ctx, "apex")
 	a.filesInfo = filesInfo
 
 	// prepare apex_manifest.json
-	a.manifestOut = android.PathForModuleOut(ctx, "apex_manifest.json")
+	a.buildManifest(ctx, provideNativeLibs, requireNativeLibs)
+
+	a.setCertificateAndPrivateKey(ctx)
+	if a.properties.ApexType == flattenedApex {
+		a.buildFlattenedApex(ctx)
+	} else {
+		a.buildUnflattenedApex(ctx)
+	}
+
+	apexName := proptools.StringDefault(a.properties.Apex_name, ctx.ModuleName())
+	a.compatSymlinks = makeCompatSymlinks(apexName, ctx)
+}
+
+func (a *apexBundle) buildManifest(ctx android.ModuleContext, provideNativeLibs, requireNativeLibs []string) {
 	manifestSrc := android.PathForModuleSrc(ctx, proptools.StringDefault(a.properties.Manifest, "apex_manifest.json"))
 
+	a.manifestJsonFullOut = android.PathForModuleOut(ctx, "apex_manifest_full.json")
+
 	// put dependency({provide|require}NativeLibs) in apex_manifest.json
 	provideNativeLibs = android.SortedUniqueStrings(provideNativeLibs)
 	requireNativeLibs = android.SortedUniqueStrings(android.RemoveListFromList(requireNativeLibs, provideNativeLibs))
@@ -1267,7 +1353,7 @@
 	ctx.Build(pctx, android.BuildParams{
 		Rule:   apexManifestRule,
 		Input:  manifestSrc,
-		Output: a.manifestOut,
+		Output: a.manifestJsonFullOut,
 		Args: map[string]string{
 			"provideNativeLibs": strings.Join(provideNativeLibs, " "),
 			"requireNativeLibs": strings.Join(requireNativeLibs, " "),
@@ -1275,26 +1361,22 @@
 		},
 	})
 
-	// Temporarily wrap the original `ctx` into a `flattenedApexContext` to have it
-	// reply true to `InstallBypassMake()` (thus making the call
-	// `android.PathForModuleInstall` below use `android.pathForInstallInMakeDir`
-	// instead of `android.PathForOutput`) to return the correct path to the flattened
-	// APEX (as its contents is installed by Make, not Soong).
-	factx := flattenedApexContext{ctx}
-	apexName := proptools.StringDefault(a.properties.Apex_name, ctx.ModuleName())
-	a.flattenedOutput = android.PathForModuleInstall(&factx, "apex", apexName)
+	// b/143654022 Q apexd can't understand newly added keys in apex_manifest.json
+	// prepare stripp-downed version so that APEX modules built from R+ can be installed to Q
+	a.manifestJsonOut = android.PathForModuleOut(ctx, "apex_manifest.json")
+	ctx.Build(pctx, android.BuildParams{
+		Rule:   stripApexManifestRule,
+		Input:  a.manifestJsonFullOut,
+		Output: a.manifestJsonOut,
+	})
 
-	if a.apexTypes.zip() {
-		a.buildUnflattenedApex(ctx, zipApex)
-	}
-	if a.apexTypes.image() {
-		// Build rule for unflattened APEX is created even when ctx.Config().FlattenApex()
-		// is true. This is to support referencing APEX via ":<module_name>" syntax
-		// in other modules. It is in AndroidMk where the selection of flattened
-		// or unflattened APEX is made.
-		a.buildUnflattenedApex(ctx, imageApex)
-		a.buildFlattenedApex(ctx)
-	}
+	// from R+, protobuf binary format (.pb) is the standard format for apex_manifest
+	a.manifestPbOut = android.PathForModuleOut(ctx, "apex_manifest.pb")
+	ctx.Build(pctx, android.BuildParams{
+		Rule:   pbApexManifestRule,
+		Input:  a.manifestJsonFullOut,
+		Output: a.manifestPbOut,
+	})
 }
 
 func (a *apexBundle) buildNoticeFile(ctx android.ModuleContext, apexFileName string) android.OptionalPath {
@@ -1319,18 +1401,7 @@
 	return android.BuildNoticeOutput(ctx, a.installDir, apexFileName, android.FirstUniquePaths(noticeFiles)).HtmlGzOutput
 }
 
-func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext, apexType apexPackaging) {
-	cert := String(a.properties.Certificate)
-	if cert != "" && android.SrcIsModule(cert) == "" {
-		defaultDir := ctx.Config().DefaultAppCertificateDir(ctx)
-		a.container_certificate_file = defaultDir.Join(ctx, cert+".x509.pem")
-		a.container_private_key_file = defaultDir.Join(ctx, cert+".pk8")
-	} else if cert == "" {
-		pem, key := ctx.Config().DefaultAppCertificate(ctx)
-		a.container_certificate_file = pem
-		a.container_private_key_file = key
-	}
-
+func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) {
 	var abis []string
 	for _, target := range ctx.MultiTargets() {
 		if len(target.Arch.Abi) > 0 {
@@ -1340,6 +1411,7 @@
 
 	abis = android.FirstUniqueStrings(abis)
 
+	apexType := a.properties.ApexType
 	suffix := apexType.suffix()
 	unsignedOutputFile := android.PathForModuleOut(ctx, ctx.ModuleName()+suffix+".unsigned")
 
@@ -1363,8 +1435,10 @@
 			copyCommands = append(copyCommands, "ln -s "+filepath.Base(dest)+" "+symlinkDest)
 		}
 	}
+	emitCommands = append(emitCommands, "sort -o "+imageContentFile.String()+" "+imageContentFile.String())
+
 	implicitInputs := append(android.Paths(nil), filesToCopy...)
-	implicitInputs = append(implicitInputs, a.manifestOut)
+	implicitInputs = append(implicitInputs, a.manifestPbOut, a.manifestJsonFullOut, a.manifestJsonOut)
 
 	if a.properties.Whitelisted_files != nil {
 		ctx.Build(pctx, android.BuildParams{
@@ -1398,9 +1472,9 @@
 	outHostBinDir := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "bin").String()
 	prebuiltSdkToolsBinDir := filepath.Join("prebuilts", "sdk", "tools", runtime.GOOS, "bin")
 
-	if apexType.image() {
+	if apexType == imageApex {
 		// files and dirs that will be created in APEX
-		var readOnlyPaths []string
+		var readOnlyPaths = []string{"apex_manifest.json", "apex_manifest.pb"}
 		var executablePaths []string // this also includes dirs
 		for _, f := range a.filesInfo {
 			pathInApex := filepath.Join(f.installDir, f.builtFile.Base())
@@ -1498,14 +1572,16 @@
 			Output:      unsignedOutputFile,
 			Description: "apex (" + apexType.name() + ")",
 			Args: map[string]string{
-				"tool_path":        outHostBinDir + ":" + prebuiltSdkToolsBinDir,
-				"image_dir":        android.PathForModuleOut(ctx, "image"+suffix).String(),
-				"copy_commands":    strings.Join(copyCommands, " && "),
-				"manifest":         a.manifestOut.String(),
-				"file_contexts":    fileContexts.String(),
-				"canned_fs_config": cannedFsConfig.String(),
-				"key":              a.private_key_file.String(),
-				"opt_flags":        strings.Join(optFlags, " "),
+				"tool_path":          outHostBinDir + ":" + prebuiltSdkToolsBinDir,
+				"image_dir":          android.PathForModuleOut(ctx, "image"+suffix).String(),
+				"copy_commands":      strings.Join(copyCommands, " && "),
+				"manifest_json_full": a.manifestJsonFullOut.String(),
+				"manifest_json":      a.manifestJsonOut.String(),
+				"manifest":           a.manifestPbOut.String(),
+				"file_contexts":      fileContexts.String(),
+				"canned_fs_config":   cannedFsConfig.String(),
+				"key":                a.private_key_file.String(),
+				"opt_flags":          strings.Join(optFlags, " "),
 			},
 		})
 
@@ -1536,19 +1612,20 @@
 			Output:      unsignedOutputFile,
 			Description: "apex (" + apexType.name() + ")",
 			Args: map[string]string{
-				"tool_path":     outHostBinDir + ":" + prebuiltSdkToolsBinDir,
-				"image_dir":     android.PathForModuleOut(ctx, "image"+suffix).String(),
-				"copy_commands": strings.Join(copyCommands, " && "),
-				"manifest":      a.manifestOut.String(),
+				"tool_path":          outHostBinDir + ":" + prebuiltSdkToolsBinDir,
+				"image_dir":          android.PathForModuleOut(ctx, "image"+suffix).String(),
+				"copy_commands":      strings.Join(copyCommands, " && "),
+				"manifest":           a.manifestPbOut.String(),
+				"manifest_json_full": a.manifestJsonFullOut.String(),
 			},
 		})
 	}
 
-	a.outputFiles[apexType] = android.PathForModuleOut(ctx, ctx.ModuleName()+suffix)
+	a.outputFile = android.PathForModuleOut(ctx, ctx.ModuleName()+suffix)
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        java.Signapk,
 		Description: "signapk",
-		Output:      a.outputFiles[apexType],
+		Output:      a.outputFile,
 		Input:       unsignedOutputFile,
 		Implicits: []android.Path{
 			a.container_certificate_file,
@@ -1561,16 +1638,44 @@
 	})
 
 	// Install to $OUT/soong/{target,host}/.../apex
-	if a.installable() && (!ctx.Config().FlattenApex() || apexType.zip()) && !a.isFlattenedVariant() {
-		ctx.InstallFile(a.installDir, ctx.ModuleName()+suffix, a.outputFiles[apexType])
+	if a.installable() {
+		ctx.InstallFile(a.installDir, ctx.ModuleName()+suffix, a.outputFile)
 	}
+	a.buildFilesInfo(ctx)
 }
 
 func (a *apexBundle) buildFlattenedApex(ctx android.ModuleContext) {
+	// Temporarily wrap the original `ctx` into a `flattenedApexContext` to have it
+	// reply true to `InstallBypassMake()` (thus making the call
+	// `android.PathForModuleInstall` below use `android.pathForInstallInMakeDir`
+	// instead of `android.PathForOutput`) to return the correct path to the flattened
+	// APEX (as its contents is installed by Make, not Soong).
+	factx := flattenedApexContext{ctx}
+	apexName := proptools.StringDefault(a.properties.Apex_name, ctx.ModuleName())
+	a.outputFile = android.PathForModuleInstall(&factx, "apex", apexName)
+
+	a.buildFilesInfo(ctx)
+}
+
+func (a *apexBundle) setCertificateAndPrivateKey(ctx android.ModuleContext) {
+	cert := String(a.properties.Certificate)
+	if cert != "" && android.SrcIsModule(cert) == "" {
+		defaultDir := ctx.Config().DefaultAppCertificateDir(ctx)
+		a.container_certificate_file = defaultDir.Join(ctx, cert+".x509.pem")
+		a.container_private_key_file = defaultDir.Join(ctx, cert+".pk8")
+	} else if cert == "" {
+		pem, key := ctx.Config().DefaultAppCertificate(ctx)
+		a.container_certificate_file = pem
+		a.container_private_key_file = key
+	}
+}
+
+func (a *apexBundle) buildFilesInfo(ctx android.ModuleContext) {
 	if a.installable() {
 		// For flattened APEX, do nothing but make sure that apex_manifest.json and apex_pubkey are also copied along
 		// with other ordinary files.
-		a.filesInfo = append(a.filesInfo, apexFile{a.manifestOut, ctx.ModuleName() + ".apex_manifest.json", ".", etc, nil, nil})
+		a.filesInfo = append(a.filesInfo, apexFile{a.manifestJsonOut, "apex_manifest.json." + ctx.ModuleName() + a.suffix, ".", etc, nil, nil})
+		a.filesInfo = append(a.filesInfo, apexFile{a.manifestPbOut, "apex_manifest.pb." + ctx.ModuleName() + a.suffix, ".", etc, nil, nil})
 
 		// rename to apex_pubkey
 		copiedPubkey := android.PathForModuleOut(ctx, "apex_pubkey")
@@ -1579,9 +1684,9 @@
 			Input:  a.public_key_file,
 			Output: copiedPubkey,
 		})
-		a.filesInfo = append(a.filesInfo, apexFile{copiedPubkey, ctx.ModuleName() + ".apex_pubkey", ".", etc, nil, nil})
+		a.filesInfo = append(a.filesInfo, apexFile{copiedPubkey, "apex_pubkey." + ctx.ModuleName() + a.suffix, ".", etc, nil, nil})
 
-		if ctx.Config().FlattenApex() {
+		if a.properties.ApexType == flattenedApex {
 			apexName := proptools.StringDefault(a.properties.Apex_name, ctx.ModuleName())
 			for _, fi := range a.filesInfo {
 				dir := filepath.Join("apex", apexName, fi.installDir)
@@ -1601,12 +1706,7 @@
 		}
 	}
 	writers := []android.AndroidMkData{}
-	if a.apexTypes.image() {
-		writers = append(writers, a.androidMkForType(imageApex))
-	}
-	if a.apexTypes.zip() {
-		writers = append(writers, a.androidMkForType(zipApex))
-	}
+	writers = append(writers, a.androidMkForType())
 	return android.AndroidMkData{
 		Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
 			for _, data := range writers {
@@ -1615,36 +1715,35 @@
 		}}
 }
 
-func (a *apexBundle) androidMkForFiles(w io.Writer, apexName, moduleDir string, apexType apexPackaging) []string {
+func (a *apexBundle) androidMkForFiles(w io.Writer, apexName, moduleDir string) []string {
 	moduleNames := []string{}
+	apexType := a.properties.ApexType
+	// To avoid creating duplicate build rules, run this function only when primaryApexType is true
+	// to install symbol files in $(PRODUCT_OUT}/apex.
+	// And if apexType is flattened, run this function to install files in $(PRODUCT_OUT}/system/apex.
+	if !a.primaryApexType && apexType != flattenedApex {
+		return moduleNames
+	}
 
 	for _, fi := range a.filesInfo {
 		if cc, ok := fi.module.(*cc.Module); ok && cc.Properties.HideFromMake {
 			continue
 		}
-		if a.properties.Flattened && !apexType.image() {
-			continue
-		}
-
-		var suffix string
-		if a.isFlattenedVariant() {
-			suffix = ".flattened"
-		}
 
 		if !android.InList(fi.moduleName, moduleNames) {
-			moduleNames = append(moduleNames, fi.moduleName+suffix)
+			moduleNames = append(moduleNames, fi.moduleName)
 		}
 
 		fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)")
 		fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
-		fmt.Fprintln(w, "LOCAL_MODULE :=", fi.moduleName+suffix)
+		fmt.Fprintln(w, "LOCAL_MODULE :=", fi.moduleName)
 		// /apex/<apex_name>/{lib|framework|...}
 		pathWhenActivated := filepath.Join("$(PRODUCT_OUT)", "apex", apexName, fi.installDir)
-		if a.properties.Flattened && apexType.image() {
+		if apexType == flattenedApex {
 			// /system/apex/<name>/{lib|framework|...}
 			fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", filepath.Join(a.installDir.ToMakePath().String(),
 				apexName, fi.installDir))
-			if !a.isFlattenedVariant() {
+			if a.primaryApexType {
 				fmt.Fprintln(w, "LOCAL_SOONG_SYMBOL_PATH :=", pathWhenActivated)
 			}
 			if len(fi.symlinks) > 0 {
@@ -1712,47 +1811,43 @@
 			fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_cc_prebuilt.mk")
 		} else {
 			fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", fi.builtFile.Base())
+			// For flattened apexes, compat symlinks are attached to apex_manifest.json which is guaranteed for every apex
+			if a.primaryApexType && fi.builtFile == a.manifestPbOut && len(a.compatSymlinks) > 0 {
+				fmt.Fprintln(w, "LOCAL_POST_INSTALL_CMD :=", strings.Join(a.compatSymlinks, " && "))
+			}
 			fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
 		}
 	}
 	return moduleNames
 }
 
-func (a *apexBundle) androidMkForType(apexType apexPackaging) android.AndroidMkData {
+func (a *apexBundle) androidMkForType() android.AndroidMkData {
 	return android.AndroidMkData{
 		Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
 			moduleNames := []string{}
+			apexType := a.properties.ApexType
 			if a.installable() {
 				apexName := proptools.StringDefault(a.properties.Apex_name, name)
-				moduleNames = a.androidMkForFiles(w, apexName, moduleDir, apexType)
+				moduleNames = a.androidMkForFiles(w, apexName, moduleDir)
 			}
 
-			if a.isFlattenedVariant() {
-				name = name + ".flattened"
-			}
-
-			if a.properties.Flattened && apexType.image() {
+			if apexType == flattenedApex {
 				// 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_MODULE :=", name+a.suffix)
 				if len(moduleNames) > 0 {
 					fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", strings.Join(moduleNames, " "))
 				}
 				fmt.Fprintln(w, "include $(BUILD_PHONY_PACKAGE)")
-				fmt.Fprintln(w, "$(LOCAL_INSTALLED_MODULE): .KATI_IMPLICIT_OUTPUTS :=", a.flattenedOutput.String())
+				fmt.Fprintln(w, "$(LOCAL_INSTALLED_MODULE): .KATI_IMPLICIT_OUTPUTS :=", a.outputFile.String())
 
-			} else if !a.isFlattenedVariant() {
-				// 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 {
-					name = name + ".zip"
-				}
+			} else {
 				fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)")
 				fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
-				fmt.Fprintln(w, "LOCAL_MODULE :=", name)
+				fmt.Fprintln(w, "LOCAL_MODULE :=", name+a.suffix)
 				fmt.Fprintln(w, "LOCAL_MODULE_CLASS := ETC") // do we need a new class?
-				fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", a.outputFiles[apexType].String())
+				fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", a.outputFile.String())
 				fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", a.installDir.ToMakePath().String())
 				fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", name+apexType.suffix())
 				fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE :=", !a.installable())
@@ -1762,10 +1857,16 @@
 				if len(a.externalDeps) > 0 {
 					fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES +=", strings.Join(a.externalDeps, " "))
 				}
+				var postInstallCommands []string
 				if a.prebuiltFileToDelete != "" {
-					fmt.Fprintln(w, "LOCAL_POST_INSTALL_CMD :=", "rm -rf "+
+					postInstallCommands = append(postInstallCommands, "rm -rf "+
 						filepath.Join(a.installDir.ToMakePath().String(), a.prebuiltFileToDelete))
 				}
+				// For unflattened apexes, compat symlinks are attached to apex package itself as LOCAL_POST_INSTALL_CMD
+				postInstallCommands = append(postInstallCommands, a.compatSymlinks...)
+				if len(postInstallCommands) > 0 {
+					fmt.Fprintln(w, "LOCAL_POST_INSTALL_CMD :=", strings.Join(postInstallCommands, " && "))
+				}
 				fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
 
 				if apexType == imageApex {
@@ -1776,9 +1877,7 @@
 }
 
 func newApexBundle() *apexBundle {
-	module := &apexBundle{
-		outputFiles: map[apexPackaging]android.WritablePath{},
-	}
+	module := &apexBundle{}
 	module.AddProperties(&module.properties)
 	module.AddProperties(&module.targetProperties)
 	module.Prefer32(func(ctx android.BaseModuleContext, base *android.ModuleBase, class android.OsClass) bool {
@@ -1790,9 +1889,10 @@
 	return module
 }
 
-func ApexBundleFactory(testApex bool) android.Module {
+func ApexBundleFactory(testApex bool, artApex bool) android.Module {
 	bundle := newApexBundle()
 	bundle.testApex = testApex
+	bundle.artApex = artApex
 	return bundle
 }
 
@@ -1819,19 +1919,18 @@
 		}{
 			proptools.StringPtr("both"),
 		})
-
-		vndkVersion := proptools.StringDefault(bundle.vndkProperties.Vndk_version, "current")
-		if vndkVersion == "current" {
-			vndkVersion = ctx.DeviceConfig().PlatformVndkVersion()
-			bundle.vndkProperties.Vndk_version = proptools.StringPtr(vndkVersion)
-		}
-
-		// Ensure VNDK APEX mount point is formatted as com.android.vndk.v###
-		bundle.properties.Apex_name = proptools.StringPtr("com.android.vndk.v" + vndkVersion)
 	})
 	return bundle
 }
 
+func (a *apexBundle) vndkVersion(config android.DeviceConfig) string {
+	vndkVersion := proptools.StringDefault(a.vndkProperties.Vndk_version, "current")
+	if vndkVersion == "current" {
+		vndkVersion = config.PlatformVndkVersion()
+	}
+	return vndkVersion
+}
+
 //
 // Defaults
 //
@@ -1997,6 +2096,8 @@
 	if p.installable() {
 		ctx.InstallFile(p.installDir, p.installFilename, p.inputApex)
 	}
+
+	// TODO(b/143192278): Add compat symlinks for prebuilt_apex
 }
 
 func (p *Prebuilt) Prebuilt() *android.Prebuilt {
@@ -2031,3 +2132,30 @@
 	android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
 	return module
 }
+
+func makeCompatSymlinks(apexName string, ctx android.ModuleContext) (symlinks []string) {
+	// small helper to add symlink commands
+	addSymlink := func(target, dir, linkName string) {
+		outDir := filepath.Join("$(PRODUCT_OUT)", dir)
+		link := filepath.Join(outDir, linkName)
+		symlinks = append(symlinks, "mkdir -p "+outDir+" && rm -rf "+link+" && ln -sf "+target+" "+link)
+	}
+
+	// TODO(b/142911355): [VNDK APEX] Fix hard-coded references to /system/lib/vndk
+	// When all hard-coded references are fixed, remove symbolic links
+	// Note that  we should keep following symlinks for older VNDKs (<=29)
+	// Since prebuilt vndk libs still depend on system/lib/vndk path
+	if strings.HasPrefix(apexName, vndkApexNamePrefix) {
+		// the name of vndk apex is formatted "com.android.vndk.v" + version
+		vndkVersion := strings.TrimPrefix(apexName, vndkApexNamePrefix)
+		if ctx.Config().Android64() {
+			addSymlink("/apex/"+apexName+"/lib64", "/system/lib64", "vndk-sp-"+vndkVersion)
+			addSymlink("/apex/"+apexName+"/lib64", "/system/lib64", "vndk-"+vndkVersion)
+		}
+		if !ctx.Config().Android64() || ctx.DeviceConfig().DeviceSecondaryArch() != "" {
+			addSymlink("/apex/"+apexName+"/lib", "/system/lib", "vndk-sp-"+vndkVersion)
+			addSymlink("/apex/"+apexName+"/lib", "/system/lib", "vndk-"+vndkVersion)
+		}
+	}
+	return
+}
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 7a51bb6..614164d 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -17,7 +17,9 @@
 import (
 	"io/ioutil"
 	"os"
+	"path"
 	"reflect"
+	"sort"
 	"strings"
 	"testing"
 
@@ -85,6 +87,10 @@
 	}
 }
 
+func withBinder32bit(fs map[string][]byte, config android.Config) {
+	config.TestProductVariables.Binder32bit = proptools.BoolPtr(true)
+}
+
 func testApexContext(t *testing.T, bp string, handlers ...testCustomizer) (*android.TestContext, android.Config) {
 	config := android.TestArchConfig(buildDir, nil)
 	config.TestProductVariables.DeviceVndkVersion = proptools.StringPtr("current")
@@ -112,6 +118,7 @@
 	ctx.RegisterModuleType("cc_test", android.ModuleFactoryAdaptor(cc.TestFactory))
 	ctx.RegisterModuleType("llndk_library", android.ModuleFactoryAdaptor(cc.LlndkLibraryFactory))
 	ctx.RegisterModuleType("vndk_prebuilt_shared", android.ModuleFactoryAdaptor(cc.VndkPrebuiltSharedFactory))
+	ctx.RegisterModuleType("vndk_libraries_txt", android.ModuleFactoryAdaptor(cc.VndkLibrariesTxtFactory))
 	ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(cc.ToolchainLibraryFactory))
 	ctx.RegisterModuleType("prebuilt_etc", android.ModuleFactoryAdaptor(android.PrebuiltEtcFactory))
 	ctx.RegisterModuleType("sh_binary", android.ModuleFactoryAdaptor(android.ShBinaryFactory))
@@ -119,7 +126,9 @@
 	ctx.RegisterModuleType("filegroup", android.ModuleFactoryAdaptor(android.FileGroupFactory))
 	ctx.RegisterModuleType("java_library", android.ModuleFactoryAdaptor(java.LibraryFactory))
 	ctx.RegisterModuleType("java_import", android.ModuleFactoryAdaptor(java.ImportFactory))
+	ctx.RegisterModuleType("java_system_modules", android.ModuleFactoryAdaptor(java.SystemModulesFactory))
 	ctx.RegisterModuleType("android_app", android.ModuleFactoryAdaptor(java.AndroidAppFactory))
+	ctx.RegisterModuleType("android_app_import", android.ModuleFactoryAdaptor(java.AndroidAppImportFactory))
 
 	ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
 	ctx.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
@@ -132,13 +141,10 @@
 		ctx.BottomUp("test_per_src", cc.TestPerSrcMutator).Parallel()
 		ctx.BottomUp("version", cc.VersionMutator).Parallel()
 		ctx.BottomUp("begin", cc.BeginMutator).Parallel()
-		ctx.TopDown("apex_vndk_gather", apexVndkGatherMutator)
-		ctx.BottomUp("apex_vndk_add_deps", apexVndkAddDepsMutator)
 	})
+	ctx.PreDepsMutators(RegisterPreDepsMutators)
+	ctx.PostDepsMutators(RegisterPostDepsMutators)
 	ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
-		ctx.TopDown("apex_deps", apexDepsMutator)
-		ctx.BottomUp("apex", apexMutator)
-		ctx.BottomUp("apex_uses", apexUsesMutator)
 		ctx.TopDown("prebuilt_select", android.PrebuiltSelectModuleMutator).Parallel()
 		ctx.BottomUp("prebuilt_postdeps", android.PrebuiltPostDepsMutator).Parallel()
 	})
@@ -252,13 +258,17 @@
 			native_bridge_supported: true,
 		}
 	`
+	bp = bp + java.GatherRequiredDepsForTest()
 
 	fs := map[string][]byte{
-		"Android.bp":                                        []byte(bp),
-		"build/make/target/product/security":                nil,
-		"apex_manifest.json":                                nil,
-		"AndroidManifest.xml":                               nil,
-		"system/sepolicy/apex/myapex-file_contexts":         nil,
+		"Android.bp":                                []byte(bp),
+		"a.java":                                    nil,
+		"PrebuiltAppFoo.apk":                        nil,
+		"PrebuiltAppFooPriv.apk":                    nil,
+		"build/make/target/product/security":        nil,
+		"apex_manifest.json":                        nil,
+		"AndroidManifest.xml":                       nil,
+		"system/sepolicy/apex/myapex-file_contexts": nil,
 		"system/sepolicy/apex/myapex_keytest-file_contexts": nil,
 		"system/sepolicy/apex/otherapex-file_contexts":      nil,
 		"system/sepolicy/apex/commonapex-file_contexts":     nil,
@@ -287,8 +297,10 @@
 		"myapex-arm64.apex":                          nil,
 		"myapex-arm.apex":                            nil,
 		"frameworks/base/api/current.txt":            nil,
+		"framework/aidl/a.aidl":                      nil,
 		"build/make/core/proguard.flags":             nil,
 		"build/make/core/proguard_basic_keeps.flags": nil,
+		"dummy.txt":                                  nil,
 	}
 
 	for _, handler := range handlers {
@@ -446,12 +458,12 @@
 		}
 	`)
 
-	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
+	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule")
 
 	optFlags := apexRule.Args["opt_flags"]
 	ensureContains(t, optFlags, "--pubkey vendor/foo/devkeys/testkey.avbpubkey")
 	// Ensure that the NOTICE output is being packaged as an asset.
-	ensureContains(t, optFlags, "--assets_dir "+buildDir+"/.intermediates/myapex/android_common_myapex/NOTICE")
+	ensureContains(t, optFlags, "--assets_dir "+buildDir+"/.intermediates/myapex/android_common_myapex_image/NOTICE")
 
 	copyCmds := apexRule.Args["copy_commands"]
 
@@ -499,7 +511,7 @@
 		t.Errorf("Could not find all expected symlinks! foo: %t, foo_link_64: %t. Command was %s", found_foo, found_foo_link_64, copyCmds)
 	}
 
-	mergeNoticesRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("mergeNoticesRule")
+	mergeNoticesRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("mergeNoticesRule")
 	noticeInputs := mergeNoticesRule.Inputs.Strings()
 	if len(noticeInputs) != 2 {
 		t.Errorf("number of input notice files: expected = 2, actual = %q", len(noticeInputs))
@@ -508,6 +520,26 @@
 	ensureListContains(t, noticeInputs, "custom_notice")
 }
 
+func TestApexManifest(t *testing.T) {
+	ctx, _ := testApex(t, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+	`)
+
+	module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+	module.Output("apex_manifest.pb")
+	module.Output("apex_manifest.json")
+	module.Output("apex_manifest_full.json")
+}
+
 func TestBasicZipApex(t *testing.T) {
 	ctx, _ := testApex(t, `
 		apex {
@@ -539,7 +571,7 @@
 		}
 	`)
 
-	zipApexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("zipApexRule")
+	zipApexRule := ctx.ModuleForTests("myapex", "android_common_myapex_zip").Rule("zipApexRule")
 	copyCmds := zipApexRule.Args["copy_commands"]
 
 	// Ensure that main rule creates an output
@@ -608,7 +640,7 @@
 		}
 	`)
 
-	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
+	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
 	// Ensure that direct non-stubs dep is always included
@@ -682,7 +714,7 @@
 
 	`)
 
-	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
+	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
 	// Ensure that direct non-stubs dep is always included
@@ -756,7 +788,7 @@
 
 	`)
 
-	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
+	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
 	// Ensure that direct non-stubs dep is always included
@@ -768,7 +800,7 @@
 	// Ensure that runtime_libs dep in included
 	ensureContains(t, copyCmds, "image.apex/lib64/libbar.so")
 
-	apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexManifestRule")
+	apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule")
 	ensureListEmpty(t, names(apexManifestRule.Args["provideNativeLibs"]))
 	ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libfoo.so")
 
@@ -809,16 +841,17 @@
 			name: "libbar",
 			symbol_file: "",
 		}
+	`, func(fs map[string][]byte, config android.Config) {
+		setUseVendorWhitelistForTest(config, []string{"myapex"})
+	})
 
-	`)
-
-	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
+	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
 	// Ensure that LLNDK dep is not included
 	ensureNotContains(t, copyCmds, "image.apex/lib64/libbar.so")
 
-	apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexManifestRule")
+	apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule")
 	ensureListEmpty(t, names(apexManifestRule.Args["provideNativeLibs"]))
 
 	// Ensure that LLNDK dep is required
@@ -895,7 +928,7 @@
 		}
 	`)
 
-	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
+	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
 	// Ensure that mylib, libm, libdl are included.
@@ -988,7 +1021,7 @@
 		}
 	`)
 
-	generateFsRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("generateFsConfig")
+	generateFsRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("generateFsConfig")
 	dirs := strings.Split(generateFsRule.Args["exec_paths"], " ")
 
 	// Ensure that the subdirectories are all listed
@@ -1038,10 +1071,12 @@
 			vendor_available: true,
 			stl: "none",
 		}
-	`)
+	`, func(fs map[string][]byte, config android.Config) {
+		setUseVendorWhitelistForTest(config, []string{"myapex"})
+	})
 
 	inputsList := []string{}
-	for _, i := range ctx.ModuleForTests("myapex", "android_common_myapex").Module().BuildParamsForTests() {
+	for _, i := range ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().BuildParamsForTests() {
 		for _, implicit := range i.Implicits {
 			inputsList = append(inputsList, implicit.String())
 		}
@@ -1057,6 +1092,38 @@
 	ensureNotContains(t, inputsString, "android_arm64_armv8-a_core_shared_myapex/mylib2.so")
 }
 
+func TestUseVendorRestriction(t *testing.T) {
+	testApexError(t, `module "myapex" .*: use_vendor: not allowed`, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			use_vendor: true,
+		}
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+	`, func(fs map[string][]byte, config android.Config) {
+		setUseVendorWhitelistForTest(config, []string{""})
+	})
+	// no error with whitelist
+	testApex(t, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			use_vendor: true,
+		}
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+	`, func(fs map[string][]byte, config android.Config) {
+		setUseVendorWhitelistForTest(config, []string{"myapex"})
+	})
+}
+
 func TestUseVendorFailsIfNotVendorAvailable(t *testing.T) {
 	testApexError(t, `dependency "mylib" of "myapex" missing variant:\n.*image:vendor`, `
 		apex {
@@ -1168,7 +1235,7 @@
 	}
 
 	// check the APK certs. It should be overridden to myapex.certificate.override
-	certs := ctx.ModuleForTests("myapex_keytest", "android_common_myapex_keytest").Rule("signapk").Args["certificates"]
+	certs := ctx.ModuleForTests("myapex_keytest", "android_common_myapex_keytest_image").Rule("signapk").Args["certificates"]
 	if certs != "testkey.override.x509.pem testkey.override.pk8" {
 		t.Errorf("cert and private key %q are not %q", certs,
 			"testkey.override.509.pem testkey.override.pk8")
@@ -1203,20 +1270,23 @@
 		}
 	`)
 
-	// non-APEX variant does not have __ANDROID__APEX__ defined
+	// non-APEX variant does not have __ANDROID_APEX(_NAME)__ defined
 	mylibCFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_core_static").Rule("cc").Args["cFlags"]
-	ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__=myapex")
-	ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__=otherapex")
+	ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__")
+	ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_MYAPEX__")
+	ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__")
 
-	// APEX variant has __ANDROID_APEX__=<apexname> defined
+	// APEX variant has __ANDROID_APEX(_NAME)__ defined
 	mylibCFlags = ctx.ModuleForTests("mylib", "android_arm64_armv8-a_core_static_myapex").Rule("cc").Args["cFlags"]
-	ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__=myapex")
-	ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__=otherapex")
+	ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__")
+	ensureContains(t, mylibCFlags, "-D__ANDROID_APEX_MYAPEX__")
+	ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__")
 
-	// APEX variant has __ANDROID_APEX__=<apexname> defined
+	// APEX variant has __ANDROID_APEX(_NAME)__ defined
 	mylibCFlags = ctx.ModuleForTests("mylib", "android_arm64_armv8-a_core_static_otherapex").Rule("cc").Args["cFlags"]
-	ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__=myapex")
-	ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__=otherapex")
+	ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__")
+	ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_MYAPEX__")
+	ensureContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__")
 }
 
 func TestHeaderLibsDependency(t *testing.T) {
@@ -1267,6 +1337,69 @@
 	ensureContains(t, cFlags, "-Imy_include")
 }
 
+func ensureExactContents(t *testing.T, ctx *android.TestContext, moduleName string, files []string) {
+	t.Helper()
+	apexRule := ctx.ModuleForTests(moduleName, "android_common_"+moduleName+"_image").Rule("apexRule")
+	copyCmds := apexRule.Args["copy_commands"]
+	imageApexDir := "/image.apex/"
+	var failed bool
+	var surplus []string
+	filesMatched := make(map[string]bool)
+	addContent := func(content string) {
+		for _, expected := range files {
+			if matched, _ := path.Match(expected, content); matched {
+				filesMatched[expected] = true
+				return
+			}
+		}
+		surplus = append(surplus, content)
+	}
+	for _, cmd := range strings.Split(copyCmds, "&&") {
+		cmd = strings.TrimSpace(cmd)
+		if cmd == "" {
+			continue
+		}
+		terms := strings.Split(cmd, " ")
+		switch terms[0] {
+		case "mkdir":
+		case "cp":
+			if len(terms) != 3 {
+				t.Fatal("copyCmds contains invalid cp command", cmd)
+			}
+			dst := terms[2]
+			index := strings.Index(dst, imageApexDir)
+			if index == -1 {
+				t.Fatal("copyCmds should copy a file to image.apex/", cmd)
+			}
+			dstFile := dst[index+len(imageApexDir):]
+			addContent(dstFile)
+		default:
+			t.Fatalf("copyCmds should contain mkdir/cp commands only: %q", cmd)
+		}
+	}
+
+	if len(surplus) > 0 {
+		sort.Strings(surplus)
+		t.Log("surplus files", surplus)
+		failed = true
+	}
+
+	if len(files) > len(filesMatched) {
+		var missing []string
+		for _, expected := range files {
+			if !filesMatched[expected] {
+				missing = append(missing, expected)
+			}
+		}
+		sort.Strings(missing)
+		t.Log("missing files", missing)
+		failed = true
+	}
+	if failed {
+		t.Fail()
+	}
+}
+
 func TestVndkApexCurrent(t *testing.T) {
 	ctx, _ := testApex(t, `
 		apex_vndk {
@@ -1303,14 +1436,19 @@
 			system_shared_libs: [],
 			stl: "none",
 		}
-	`)
+	`+vndkLibrariesTxtFiles("current"))
 
-	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
-	copyCmds := apexRule.Args["copy_commands"]
-	ensureContains(t, copyCmds, "image.apex/lib/libvndk.so")
-	ensureContains(t, copyCmds, "image.apex/lib/libvndksp.so")
-	ensureContains(t, copyCmds, "image.apex/lib64/libvndk.so")
-	ensureContains(t, copyCmds, "image.apex/lib64/libvndksp.so")
+	ensureExactContents(t, ctx, "myapex", []string{
+		"lib/libvndk.so",
+		"lib/libvndksp.so",
+		"lib64/libvndk.so",
+		"lib64/libvndksp.so",
+		"etc/llndk.libraries.VER.txt",
+		"etc/vndkcore.libraries.VER.txt",
+		"etc/vndksp.libraries.VER.txt",
+		"etc/vndkprivate.libraries.VER.txt",
+		"etc/vndkcorevariant.libraries.VER.txt",
+	})
 }
 
 func TestVndkApexWithPrebuilt(t *testing.T) {
@@ -1328,8 +1466,8 @@
 		}
 
 		cc_prebuilt_library_shared {
-			name: "libvndkshared",
-			srcs: ["libvndkshared.so"],
+			name: "libvndk",
+			srcs: ["libvndk.so"],
 			vendor_available: true,
 			vndk: {
 				enabled: true,
@@ -1337,13 +1475,59 @@
 			system_shared_libs: [],
 			stl: "none",
 		}
-	`, withFiles(map[string][]byte{
-		"libvndkshared.so": nil,
-	}))
 
-	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
-	copyCmds := apexRule.Args["copy_commands"]
-	ensureContains(t, copyCmds, "image.apex/lib/libvndkshared.so")
+		cc_prebuilt_library_shared {
+			name: "libvndk.arm",
+			srcs: ["libvndk.arm.so"],
+			vendor_available: true,
+			vndk: {
+				enabled: true,
+			},
+			enabled: false,
+			arch: {
+				arm: {
+					enabled: true,
+				},
+			},
+			system_shared_libs: [],
+			stl: "none",
+		}
+		`+vndkLibrariesTxtFiles("current"),
+		withFiles(map[string][]byte{
+			"libvndk.so":     nil,
+			"libvndk.arm.so": nil,
+		}))
+
+	ensureExactContents(t, ctx, "myapex", []string{
+		"lib/libvndk.so",
+		"lib/libvndk.arm.so",
+		"lib64/libvndk.so",
+		"etc/*",
+	})
+}
+
+func vndkLibrariesTxtFiles(vers ...string) (result string) {
+	for _, v := range vers {
+		if v == "current" {
+			for _, txt := range []string{"llndk", "vndkcore", "vndksp", "vndkprivate", "vndkcorevariant"} {
+				result += `
+					vndk_libraries_txt {
+						name: "` + txt + `.libraries.txt",
+					}
+				`
+			}
+		} else {
+			for _, txt := range []string{"llndk", "vndkcore", "vndksp", "vndkprivate"} {
+				result += `
+					prebuilt_etc {
+						name: "` + txt + `.libraries.` + v + `.txt",
+						src: "dummy.txt",
+					}
+				`
+			}
+		}
+	}
+	return
 }
 
 func TestVndkApexVersion(t *testing.T) {
@@ -1361,15 +1545,22 @@
 			private_key: "testkey.pem",
 		}
 
-		cc_library {
-			name: "libvndk",
-			srcs: ["mylib.cpp"],
+		vndk_prebuilt_shared {
+			name: "libvndk27",
+			version: "27",
 			vendor_available: true,
 			vndk: {
 				enabled: true,
 			},
-			system_shared_libs: [],
-			stl: "none",
+			target_arch: "arm64",
+			arch: {
+				arm: {
+					srcs: ["libvndk27_arm.so"],
+				},
+				arm64: {
+					srcs: ["libvndk27_arm64.so"],
+				},
+			},
 		}
 
 		vndk_prebuilt_shared {
@@ -1379,18 +1570,29 @@
 			vndk: {
 				enabled: true,
 			},
-			target_arch: "arm64",
-			srcs: ["libvndk27.so"],
+			target_arch: "x86_64",
+			arch: {
+				x86: {
+					srcs: ["libvndk27_x86.so"],
+				},
+				x86_64: {
+					srcs: ["libvndk27_x86_64.so"],
+				},
+			},
 		}
-	`, withFiles(map[string][]byte{
-		"libvndk27.so": nil,
-	}))
+		`+vndkLibrariesTxtFiles("27"),
+		withFiles(map[string][]byte{
+			"libvndk27_arm.so":    nil,
+			"libvndk27_arm64.so":  nil,
+			"libvndk27_x86.so":    nil,
+			"libvndk27_x86_64.so": nil,
+		}))
 
-	apexRule := ctx.ModuleForTests("myapex_v27", "android_common_myapex_v27").Rule("apexRule")
-	copyCmds := apexRule.Args["copy_commands"]
-	ensureContains(t, copyCmds, "image.apex/lib/libvndk27.so")
-	ensureContains(t, copyCmds, "image.apex/lib64/libvndk27.so")
-	ensureNotContains(t, copyCmds, "image.apex/lib/libvndk.so")
+	ensureExactContents(t, ctx, "myapex_v27", []string{
+		"lib/libvndk27_arm.so",
+		"lib64/libvndk27_arm64.so",
+		"etc/*",
+	})
 }
 
 func TestVndkApexErrorWithDuplicateVersion(t *testing.T) {
@@ -1456,10 +1658,10 @@
 			name: "myapex.key",
 			public_key: "testkey.avbpubkey",
 			private_key: "testkey.pem",
-		}`)
+		}`+vndkLibrariesTxtFiles("28", "current"))
 
 	assertApexName := func(expected, moduleName string) {
-		bundle := ctx.ModuleForTests(moduleName, "android_common_"+moduleName).Module().(*apexBundle)
+		bundle := ctx.ModuleForTests(moduleName, "android_common_"+moduleName+"_image").Module().(*apexBundle)
 		actual := proptools.String(bundle.properties.Apex_name)
 		if !reflect.DeepEqual(actual, expected) {
 			t.Errorf("Got '%v', expected '%v'", actual, expected)
@@ -1496,23 +1698,21 @@
 			system_shared_libs: [],
 			stl: "none",
 		}
-	`, withTargets(map[android.OsType][]android.Target{
-		android.Android: []android.Target{
-			{Os: android.Android, Arch: android.Arch{ArchType: android.Arm64, ArchVariant: "armv8-a", Abi: []string{"arm64-v8a"}}, NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: ""},
-			{Os: android.Android, Arch: android.Arch{ArchType: android.Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}}, NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: ""},
-			{Os: android.Android, Arch: android.Arch{ArchType: android.X86_64, ArchVariant: "silvermont", Abi: []string{"arm64-v8a"}}, NativeBridge: android.NativeBridgeEnabled, NativeBridgeHostArchName: "arm64", NativeBridgeRelativePath: "x86_64"},
-			{Os: android.Android, Arch: android.Arch{ArchType: android.X86, ArchVariant: "silvermont", Abi: []string{"armeabi-v7a"}}, NativeBridge: android.NativeBridgeEnabled, NativeBridgeHostArchName: "arm", NativeBridgeRelativePath: "x86"},
-		},
-	}))
+		`+vndkLibrariesTxtFiles("current"),
+		withTargets(map[android.OsType][]android.Target{
+			android.Android: []android.Target{
+				{Os: android.Android, Arch: android.Arch{ArchType: android.Arm64, ArchVariant: "armv8-a", Abi: []string{"arm64-v8a"}}, NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: ""},
+				{Os: android.Android, Arch: android.Arch{ArchType: android.Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}}, NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: ""},
+				{Os: android.Android, Arch: android.Arch{ArchType: android.X86_64, ArchVariant: "silvermont", Abi: []string{"arm64-v8a"}}, NativeBridge: android.NativeBridgeEnabled, NativeBridgeHostArchName: "arm64", NativeBridgeRelativePath: "x86_64"},
+				{Os: android.Android, Arch: android.Arch{ArchType: android.X86, ArchVariant: "silvermont", Abi: []string{"armeabi-v7a"}}, NativeBridge: android.NativeBridgeEnabled, NativeBridgeHostArchName: "arm", NativeBridgeRelativePath: "x86"},
+			},
+		}))
 
-	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
-	copyCmds := apexRule.Args["copy_commands"]
-	ensureContains(t, copyCmds, "image.apex/lib/libvndk.so")
-	ensureContains(t, copyCmds, "image.apex/lib64/libvndk.so")
-
-	// apex
-	ensureNotContains(t, copyCmds, "image.apex/lib/x86/libvndk.so")
-	ensureNotContains(t, copyCmds, "image.apex/lib64/x86_64/libvndk.so")
+	ensureExactContents(t, ctx, "myapex", []string{
+		"lib/libvndk.so",
+		"lib64/libvndk.so",
+		"etc/*",
+	})
 }
 
 func TestVndkApexDoesntSupportNativeBridgeSupported(t *testing.T) {
@@ -1545,6 +1745,70 @@
 	`)
 }
 
+func TestVndkApexWithBinder32(t *testing.T) {
+	ctx, _ := testApex(t, `
+		apex_vndk {
+			name: "myapex_v27",
+			key: "myapex.key",
+			file_contexts: "myapex",
+			vndk_version: "27",
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		vndk_prebuilt_shared {
+			name: "libvndk27",
+			version: "27",
+			target_arch: "arm",
+			vendor_available: true,
+			vndk: {
+				enabled: true,
+			},
+			arch: {
+				arm: {
+					srcs: ["libvndk27.so"],
+				}
+			},
+		}
+
+		vndk_prebuilt_shared {
+			name: "libvndk27",
+			version: "27",
+			target_arch: "arm",
+			binder32bit: true,
+			vendor_available: true,
+			vndk: {
+				enabled: true,
+			},
+			arch: {
+				arm: {
+					srcs: ["libvndk27binder32.so"],
+				}
+			},
+		}
+		`+vndkLibrariesTxtFiles("27"),
+		withFiles(map[string][]byte{
+			"libvndk27.so":         nil,
+			"libvndk27binder32.so": nil,
+		}),
+		withBinder32bit,
+		withTargets(map[android.OsType][]android.Target{
+			android.Android: []android.Target{
+				{Os: android.Android, Arch: android.Arch{ArchType: android.Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}}, NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: ""},
+			},
+		}),
+	)
+
+	ensureExactContents(t, ctx, "myapex_v27", []string{
+		"lib/libvndk27binder32.so",
+		"etc/*",
+	})
+}
+
 func TestDependenciesInApexManifest(t *testing.T) {
 	ctx, _ := testApex(t, `
 		apex {
@@ -1614,25 +1878,25 @@
 	var apexManifestRule android.TestingBuildParams
 	var provideNativeLibs, requireNativeLibs []string
 
-	apexManifestRule = ctx.ModuleForTests("myapex_nodep", "android_common_myapex_nodep").Rule("apexManifestRule")
+	apexManifestRule = ctx.ModuleForTests("myapex_nodep", "android_common_myapex_nodep_image").Rule("apexManifestRule")
 	provideNativeLibs = names(apexManifestRule.Args["provideNativeLibs"])
 	requireNativeLibs = names(apexManifestRule.Args["requireNativeLibs"])
 	ensureListEmpty(t, provideNativeLibs)
 	ensureListEmpty(t, requireNativeLibs)
 
-	apexManifestRule = ctx.ModuleForTests("myapex_dep", "android_common_myapex_dep").Rule("apexManifestRule")
+	apexManifestRule = ctx.ModuleForTests("myapex_dep", "android_common_myapex_dep_image").Rule("apexManifestRule")
 	provideNativeLibs = names(apexManifestRule.Args["provideNativeLibs"])
 	requireNativeLibs = names(apexManifestRule.Args["requireNativeLibs"])
 	ensureListEmpty(t, provideNativeLibs)
 	ensureListContains(t, requireNativeLibs, "libfoo.so")
 
-	apexManifestRule = ctx.ModuleForTests("myapex_provider", "android_common_myapex_provider").Rule("apexManifestRule")
+	apexManifestRule = ctx.ModuleForTests("myapex_provider", "android_common_myapex_provider_image").Rule("apexManifestRule")
 	provideNativeLibs = names(apexManifestRule.Args["provideNativeLibs"])
 	requireNativeLibs = names(apexManifestRule.Args["requireNativeLibs"])
 	ensureListContains(t, provideNativeLibs, "libfoo.so")
 	ensureListEmpty(t, requireNativeLibs)
 
-	apexManifestRule = ctx.ModuleForTests("myapex_selfcontained", "android_common_myapex_selfcontained").Rule("apexManifestRule")
+	apexManifestRule = ctx.ModuleForTests("myapex_selfcontained", "android_common_myapex_selfcontained_image").Rule("apexManifestRule")
 	provideNativeLibs = names(apexManifestRule.Args["provideNativeLibs"])
 	requireNativeLibs = names(apexManifestRule.Args["requireNativeLibs"])
 	ensureListContains(t, provideNativeLibs, "libfoo.so")
@@ -1654,7 +1918,7 @@
 		}
 	`)
 
-	module := ctx.ModuleForTests("myapex", "android_common_myapex")
+	module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
 	apexManifestRule := module.Rule("apexManifestRule")
 	ensureContains(t, apexManifestRule.Args["opt"], "-v name com.android.myapex")
 	apexRule := module.Rule("apexRule")
@@ -1683,7 +1947,7 @@
 		}
 	`)
 
-	module := ctx.ModuleForTests("myapex", "android_common_myapex")
+	module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
 	apexRule := module.Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
@@ -1734,7 +1998,7 @@
 		}
 	`)
 
-	module := ctx.ModuleForTests("myapex", "android_common_myapex")
+	module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
 	apexRule := module.Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
@@ -1818,7 +2082,7 @@
 		}
 	`)
 
-	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
+	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
 	// Ensure that main rule creates an output
@@ -1862,7 +2126,7 @@
 		}
 	`)
 
-	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
+	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
 	ensureContains(t, copyCmds, "image.apex/bin/script/myscript.sh")
@@ -1892,7 +2156,7 @@
 		}
 	`)
 
-	apex := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle)
+	apex := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
 	expected := buildDir + "/target/product/test_device/product/apex"
 	actual := apex.installDir.String()
 	if actual != expected {
@@ -2036,7 +2300,7 @@
 		}
 	`)
 
-	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
+	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
 	// Ensure that test dep is copied into apex.
@@ -2048,19 +2312,19 @@
 	ensureContains(t, copyCmds, "image.apex/bin/test/mytest3")
 
 	// Ensure the module is correctly translated.
-	apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle)
+	apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
 	data := android.AndroidMkDataForTest(t, config, "", apexBundle)
 	name := apexBundle.BaseModuleName()
 	prefix := "TARGET_"
 	var builder strings.Builder
 	data.Custom(&builder, name, prefix, "", data)
 	androidMk := builder.String()
-	ensureContains(t, androidMk, "LOCAL_MODULE := myapex.mytest\n")
-	ensureContains(t, androidMk, "LOCAL_MODULE := myapex.mytest1\n")
-	ensureContains(t, androidMk, "LOCAL_MODULE := myapex.mytest2\n")
-	ensureContains(t, androidMk, "LOCAL_MODULE := myapex.mytest3\n")
-	ensureContains(t, androidMk, "LOCAL_MODULE := myapex.apex_manifest.json\n")
-	ensureContains(t, androidMk, "LOCAL_MODULE := myapex.apex_pubkey\n")
+	ensureContains(t, androidMk, "LOCAL_MODULE := mytest.myapex\n")
+	ensureContains(t, androidMk, "LOCAL_MODULE := mytest1.myapex\n")
+	ensureContains(t, androidMk, "LOCAL_MODULE := mytest2.myapex\n")
+	ensureContains(t, androidMk, "LOCAL_MODULE := mytest3.myapex\n")
+	ensureContains(t, androidMk, "LOCAL_MODULE := apex_manifest.json.myapex\n")
+	ensureContains(t, androidMk, "LOCAL_MODULE := apex_pubkey.myapex\n")
 	ensureContains(t, androidMk, "LOCAL_MODULE := myapex\n")
 }
 
@@ -2102,11 +2366,11 @@
 		}
 	`)
 
-	module1 := ctx.ModuleForTests("myapex", "android_common_myapex")
+	module1 := ctx.ModuleForTests("myapex", "android_common_myapex_image")
 	apexRule1 := module1.Rule("apexRule")
 	copyCmds1 := apexRule1.Args["copy_commands"]
 
-	module2 := ctx.ModuleForTests("commonapex", "android_common_commonapex")
+	module2 := ctx.ModuleForTests("commonapex", "android_common_commonapex_image")
 	apexRule2 := module2.Rule("apexRule")
 	copyCmds2 := apexRule2.Args["copy_commands"]
 
@@ -2177,7 +2441,9 @@
 			public_key: "testkey.avbpubkey",
 			private_key: "testkey.pem",
 		}
-	`)
+	`, func(fs map[string][]byte, config android.Config) {
+		setUseVendorWhitelistForTest(config, []string{"myapex"})
+	})
 }
 
 func TestErrorsIfDepsAreNotEnabled(t *testing.T) {
@@ -2247,6 +2513,7 @@
 			srcs: ["foo/bar/MyClass.java"],
 			sdk_version: "none",
 			system_modules: "none",
+			jni_libs: ["libjni"],
 		}
 
 		android_app {
@@ -2256,15 +2523,67 @@
 			system_modules: "none",
 			privileged: true,
 		}
+
+		cc_library_shared {
+			name: "libjni",
+			srcs: ["mylib.cpp"],
+			stl: "none",
+			system_shared_libs: [],
+		}
 	`)
 
-	module := ctx.ModuleForTests("myapex", "android_common_myapex")
+	module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
 	apexRule := module.Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
 	ensureContains(t, copyCmds, "image.apex/app/AppFoo/AppFoo.apk")
 	ensureContains(t, copyCmds, "image.apex/priv-app/AppFooPriv/AppFooPriv.apk")
+	ensureContains(t, copyCmds, "image.apex/lib64/libjni.so")
+}
 
+func TestApexWithAppImports(t *testing.T) {
+	ctx, _ := testApex(t, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			apps: [
+				"AppFooPrebuilt",
+				"AppFooPrivPrebuilt",
+			],
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		android_app_import {
+			name: "AppFooPrebuilt",
+			apk: "PrebuiltAppFoo.apk",
+			presigned: true,
+			dex_preopt: {
+				enabled: false,
+			},
+		}
+
+		android_app_import {
+			name: "AppFooPrivPrebuilt",
+			apk: "PrebuiltAppFooPriv.apk",
+			privileged: true,
+			presigned: true,
+			dex_preopt: {
+				enabled: false,
+			},
+		}
+	`)
+
+	module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+	apexRule := module.Rule("apexRule")
+	copyCmds := apexRule.Args["copy_commands"]
+
+	ensureContains(t, copyCmds, "image.apex/app/AppFooPrebuilt/AppFooPrebuilt.apk")
+	ensureContains(t, copyCmds, "image.apex/priv-app/AppFooPrivPrebuilt/AppFooPrivPrebuilt.apk")
 }
 
 func TestApexAvailable(t *testing.T) {
diff --git a/bpf/bpf.go b/bpf/bpf.go
index 90ec963..024fcbc 100644
--- a/bpf/bpf.go
+++ b/bpf/bpf.go
@@ -33,7 +33,7 @@
 var (
 	pctx = android.NewPackageContext("android/soong/bpf")
 
-	ccRule = pctx.AndroidGomaStaticRule("ccRule",
+	ccRule = pctx.AndroidRemoteStaticRule("ccRule", android.SUPPORTS_GOMA,
 		blueprint.RuleParams{
 			Depfile:     "${out}.d",
 			Deps:        blueprint.DepsGCC,
diff --git a/bpfix/Android.bp b/bpfix/Android.bp
index 90a453d..aec9ff9 100644
--- a/bpfix/Android.bp
+++ b/bpfix/Android.bp
@@ -19,7 +19,18 @@
 blueprint_go_binary {
     name: "bpfix",
     srcs: [
-        "cmd/bpfix.go",
+        "cmd/main.go",
+    ],
+    deps: [
+        "bpfix-cmd",
+    ],
+}
+
+bootstrap_go_package {
+    name: "bpfix-cmd",
+    pkgPath: "android/soong/bpfix/bpfix/cmd",
+    srcs: [
+        "cmd-lib/bpfix.go",
     ],
     deps: [
         "bpfix-lib",
diff --git a/bpfix/bpfix/bpfix.go b/bpfix/bpfix/bpfix.go
index 5f1cce8..4633aa6 100644
--- a/bpfix/bpfix/bpfix.go
+++ b/bpfix/bpfix/bpfix.go
@@ -45,66 +45,80 @@
 // A FixRequest specifies the details of which fixes to apply to an individual file
 // A FixRequest doesn't specify whether to do a dry run or where to write the results; that's in cmd/bpfix.go
 type FixRequest struct {
-	steps []fixStep
+	steps []FixStep
+}
+type FixStepsExtension struct {
+	Name  string
+	Steps []FixStep
 }
 
-type fixStep struct {
-	name string
-	fix  func(f *Fixer) error
+type FixStep struct {
+	Name string
+	Fix  func(f *Fixer) error
 }
 
-var fixSteps = []fixStep{
+var fixStepsExtensions = []*FixStepsExtension(nil)
+
+func RegisterFixStepExtension(extension *FixStepsExtension) {
+	fixStepsExtensions = append(fixStepsExtensions, extension)
+}
+
+var fixSteps = []FixStep{
 	{
-		name: "simplifyKnownRedundantVariables",
-		fix:  runPatchListMod(simplifyKnownPropertiesDuplicatingEachOther),
+		Name: "simplifyKnownRedundantVariables",
+		Fix:  runPatchListMod(simplifyKnownPropertiesDuplicatingEachOther),
 	},
 	{
-		name: "rewriteIncorrectAndroidmkPrebuilts",
-		fix:  rewriteIncorrectAndroidmkPrebuilts,
+		Name: "rewriteIncorrectAndroidmkPrebuilts",
+		Fix:  rewriteIncorrectAndroidmkPrebuilts,
 	},
 	{
-		name: "rewriteCtsModuleTypes",
-		fix:  rewriteCtsModuleTypes,
+		Name: "rewriteCtsModuleTypes",
+		Fix:  rewriteCtsModuleTypes,
 	},
 	{
-		name: "rewriteIncorrectAndroidmkAndroidLibraries",
-		fix:  rewriteIncorrectAndroidmkAndroidLibraries,
+		Name: "rewriteIncorrectAndroidmkAndroidLibraries",
+		Fix:  rewriteIncorrectAndroidmkAndroidLibraries,
 	},
 	{
-		name: "rewriteTestModuleTypes",
-		fix:  rewriteTestModuleTypes,
+		Name: "rewriteTestModuleTypes",
+		Fix:  rewriteTestModuleTypes,
 	},
 	{
-		name: "rewriteAndroidmkJavaLibs",
-		fix:  rewriteAndroidmkJavaLibs,
+		Name: "rewriteAndroidmkJavaLibs",
+		Fix:  rewriteAndroidmkJavaLibs,
 	},
 	{
-		name: "rewriteJavaStaticLibs",
-		fix:  rewriteJavaStaticLibs,
+		Name: "rewriteJavaStaticLibs",
+		Fix:  rewriteJavaStaticLibs,
 	},
 	{
-		name: "rewritePrebuiltEtc",
-		fix:  rewriteAndroidmkPrebuiltEtc,
+		Name: "rewritePrebuiltEtc",
+		Fix:  rewriteAndroidmkPrebuiltEtc,
 	},
 	{
-		name: "mergeMatchingModuleProperties",
-		fix:  runPatchListMod(mergeMatchingModuleProperties),
+		Name: "mergeMatchingModuleProperties",
+		Fix:  runPatchListMod(mergeMatchingModuleProperties),
 	},
 	{
-		name: "reorderCommonProperties",
-		fix:  runPatchListMod(reorderCommonProperties),
+		Name: "reorderCommonProperties",
+		Fix:  runPatchListMod(reorderCommonProperties),
 	},
 	{
-		name: "removeTags",
-		fix:  runPatchListMod(removeTags),
+		Name: "removeTags",
+		Fix:  runPatchListMod(removeTags),
 	},
 	{
-		name: "rewriteAndroidTest",
-		fix:  rewriteAndroidTest,
+		Name: "rewriteAndroidTest",
+		Fix:  rewriteAndroidTest,
 	},
 	{
-		name: "rewriteAndroidAppImport",
-		fix:  rewriteAndroidAppImport,
+		Name: "rewriteAndroidAppImport",
+		Fix:  rewriteAndroidAppImport,
+	},
+	{
+		Name: "removeEmptyLibDependencies",
+		Fix:  removeEmptyLibDependencies,
 	},
 }
 
@@ -113,8 +127,27 @@
 }
 
 func (r FixRequest) AddAll() (result FixRequest) {
-	result.steps = append([]fixStep(nil), r.steps...)
+	result.steps = append([]FixStep(nil), r.steps...)
 	result.steps = append(result.steps, fixSteps...)
+	for _, extension := range fixStepsExtensions {
+		result.steps = append(result.steps, extension.Steps...)
+	}
+	return result
+}
+
+func (r FixRequest) AddBase() (result FixRequest) {
+	result.steps = append([]FixStep(nil), r.steps...)
+	result.steps = append(result.steps, fixSteps...)
+	return result
+}
+
+func (r FixRequest) AddMatchingExtensions(pattern string) (result FixRequest) {
+	result.steps = append([]FixStep(nil), r.steps...)
+	for _, extension := range fixStepsExtensions {
+		if match, _ := filepath.Match(pattern, extension.Name); match {
+			result.steps = append(result.steps, extension.Steps...)
+		}
+	}
 	return result
 }
 
@@ -122,6 +155,10 @@
 	tree *parser.File
 }
 
+func (f Fixer) Tree() *parser.File {
+	return f.tree
+}
+
 func NewFixer(tree *parser.File) *Fixer {
 	fixer := &Fixer{tree}
 
@@ -198,7 +235,7 @@
 
 func (f *Fixer) fixTreeOnce(config FixRequest) error {
 	for _, fix := range config.steps {
-		err := fix.fix(f)
+		err := fix.Fix(f)
 		if err != nil {
 			return err
 		}
@@ -617,6 +654,50 @@
 	return nil
 }
 
+// Removes library dependencies which are empty (and restricted from usage in Soong)
+func removeEmptyLibDependencies(f *Fixer) error {
+	emptyLibraries := []string{
+		"libhidltransport",
+		"libhwbinder",
+	}
+	relevantFields := []string{
+		"export_shared_lib_headers",
+		"export_static_lib_headers",
+		"static_libs",
+		"whole_static_libs",
+		"shared_libs",
+	}
+	for _, def := range f.tree.Defs {
+		mod, ok := def.(*parser.Module)
+		if !ok {
+			continue
+		}
+		for _, field := range relevantFields {
+			listValue, ok := getLiteralListProperty(mod, field)
+			if !ok {
+				continue
+			}
+			newValues := []parser.Expression{}
+			for _, v := range listValue.Values {
+				stringValue, ok := v.(*parser.String)
+				if !ok {
+					return fmt.Errorf("Expecting string for %s.%s fields", mod.Type, field)
+				}
+				if inList(stringValue.Value, emptyLibraries) {
+					continue
+				}
+				newValues = append(newValues, stringValue)
+			}
+			if len(newValues) == 0 && len(listValue.Values) != 0 {
+				removeProperty(mod, field)
+			} else {
+				listValue.Values = newValues
+			}
+		}
+	}
+	return nil
+}
+
 // Converts the default source list property, 'srcs', to a single source property with a given name.
 // "LOCAL_MODULE" reference is also resolved during the conversion process.
 func convertToSingleSource(mod *parser.Module, srcPropertyName string) {
@@ -1051,3 +1132,12 @@
 	}
 	mod.Properties = newList
 }
+
+func inList(s string, list []string) bool {
+	for _, v := range list {
+		if s == v {
+			return true
+		}
+	}
+	return false
+}
diff --git a/bpfix/bpfix/bpfix_test.go b/bpfix/bpfix/bpfix_test.go
index 5e0b817..032282f 100644
--- a/bpfix/bpfix/bpfix_test.go
+++ b/bpfix/bpfix/bpfix_test.go
@@ -833,3 +833,57 @@
 		})
 	}
 }
+
+func TestRemoveEmptyLibDependencies(t *testing.T) {
+	tests := []struct {
+		name string
+		in   string
+		out  string
+	}{
+		{
+			name: "remove sole shared lib",
+			in: `
+				cc_library {
+					name: "foo",
+					shared_libs: ["libhwbinder"],
+				}
+			`,
+			out: `
+				cc_library {
+					name: "foo",
+
+				}
+			`,
+		},
+		{
+			name: "remove a shared lib",
+			in: `
+				cc_library {
+					name: "foo",
+					shared_libs: [
+						"libhwbinder",
+						"libfoo",
+						"libhidltransport",
+					],
+				}
+			`,
+			out: `
+				cc_library {
+					name: "foo",
+					shared_libs: [
+
+						"libfoo",
+
+					],
+				}
+			`,
+		},
+	}
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			runPass(t, test.in, test.out, func(fixer *Fixer) error {
+				return removeEmptyLibDependencies(fixer)
+			})
+		})
+	}
+}
diff --git a/bpfix/cmd/bpfix.go b/bpfix/cmd-lib/bpfix.go
similarity index 97%
rename from bpfix/cmd/bpfix.go
rename to bpfix/cmd-lib/bpfix.go
index ccdae16..98122f2 100644
--- a/bpfix/cmd/bpfix.go
+++ b/bpfix/cmd-lib/bpfix.go
@@ -12,11 +12,11 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// This file provides a command-line interface to bpfix
+// This file provides a bpfix command-line library
 
 // TODO(jeffrygaston) should this file be consolidated with bpfmt.go?
 
-package main
+package cmd
 
 import (
 	"bytes"
@@ -128,7 +128,7 @@
 	filepath.Walk(path, makeFileVisitor(fixRequest))
 }
 
-func main() {
+func Run() {
 	flag.Parse()
 
 	fixRequest := bpfix.NewFixRequest().AddAll()
diff --git a/bpfix/cmd/main.go b/bpfix/cmd/main.go
new file mode 100644
index 0000000..8ca16b4
--- /dev/null
+++ b/bpfix/cmd/main.go
@@ -0,0 +1,25 @@
+// Copyright 2017 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.
+
+// This file provides a wrapper to the bpfix command-line library
+
+package main
+
+import (
+	"android/soong/bpfix/bpfix/cmd"
+)
+
+func main() {
+	cmd.Run()
+}
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 9a98b0e..ff181d8 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -36,10 +36,10 @@
 	Arch() android.Arch
 	Os() android.OsType
 	Host() bool
-	useVndk() bool
+	UseVndk() bool
 	vndkVersion() string
 	static() bool
-	inRecovery() bool
+	InRecovery() bool
 }
 
 type subAndroidMkProvider interface {
@@ -89,10 +89,15 @@
 					fmt.Fprintln(w, "LOCAL_WHOLE_STATIC_LIBRARIES := "+strings.Join(c.Properties.AndroidMkWholeStaticLibs, " "))
 				}
 				fmt.Fprintln(w, "LOCAL_SOONG_LINK_TYPE :=", c.makeLinkType)
-				if c.useVndk() {
+				if c.UseVndk() {
 					fmt.Fprintln(w, "LOCAL_USE_VNDK := true")
-					if c.isVndk() && !c.static() {
+					if c.IsVndk() && !c.static() {
 						fmt.Fprintln(w, "LOCAL_SOONG_VNDK_VERSION := "+c.vndkVersion())
+						// VNDK libraries available to vendor are not installed because
+						// they are packaged in VNDK APEX and installed by APEX packages (apex/apex.go)
+						if !c.isVndkExt() {
+							fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
+						}
 					}
 				}
 			},
@@ -148,10 +153,10 @@
 func (library *libraryDecorator) androidMkWriteExportedFlags(w io.Writer) {
 	exportedFlags := library.exportedFlags()
 	for _, dir := range library.exportedDirs() {
-		exportedFlags = append(exportedFlags, "-I"+dir)
+		exportedFlags = append(exportedFlags, "-I"+dir.String())
 	}
 	for _, dir := range library.exportedSystemDirs() {
-		exportedFlags = append(exportedFlags, "-isystem "+dir)
+		exportedFlags = append(exportedFlags, "-isystem "+dir.String())
 	}
 	if len(exportedFlags) > 0 {
 		fmt.Fprintln(w, "LOCAL_EXPORT_CFLAGS :=", strings.Join(exportedFlags, " "))
@@ -224,7 +229,7 @@
 		})
 	}
 	if len(library.Properties.Stubs.Versions) > 0 &&
-		android.DirectlyInAnyApex(ctx, ctx.Name()) && !ctx.inRecovery() && !ctx.useVndk() &&
+		android.DirectlyInAnyApex(ctx, ctx.Name()) && !ctx.InRecovery() && !ctx.UseVndk() &&
 		!ctx.static() {
 		if !library.buildStubs() {
 			ret.SubName = ".bootstrap"
@@ -317,14 +322,20 @@
 			filepath.Dir(fuzz.dictionary.String())+":"+fuzz.dictionary.Base())
 	}
 
-	if len(fuzzFiles) > 0 {
-		ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
-			fmt.Fprintln(w, "LOCAL_TEST_DATA := "+strings.Join(fuzzFiles, " "))
-		})
+	if fuzz.config != nil {
+		fuzzFiles = append(fuzzFiles,
+			filepath.Dir(fuzz.config.String())+":config.json")
 	}
 
 	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
 		fmt.Fprintln(w, "LOCAL_IS_FUZZ_TARGET := true")
+		if len(fuzzFiles) > 0 {
+			fmt.Fprintln(w, "LOCAL_TEST_DATA := "+strings.Join(fuzzFiles, " "))
+		}
+		if fuzz.installedSharedDeps != nil {
+			fmt.Fprintln(w, "LOCAL_FUZZ_INSTALLED_SHARED_DEPS :="+
+				strings.Join(fuzz.installedSharedDeps, " "))
+		}
 	})
 }
 
diff --git a/cc/binary.go b/cc/binary.go
index 9f18d6c..617d4dd 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -158,7 +158,7 @@
 
 		if binary.static() {
 			if ctx.selectedStl() == "libc++_static" {
-				deps.StaticLibs = append(deps.StaticLibs, "libm", "libc", "libdl")
+				deps.StaticLibs = append(deps.StaticLibs, "libm", "libc")
 			}
 			// static libraries libcompiler_rt, libc and libc_nomalloc need to be linked with
 			// --start-group/--end-group along with libgcc.  If they are in deps.StaticLibs,
@@ -227,7 +227,7 @@
 
 	if ctx.Host() && !ctx.Windows() && !binary.static() {
 		if !ctx.Config().IsEnvTrue("DISABLE_HOST_PIE") {
-			flags.LdFlags = append(flags.LdFlags, "-pie")
+			flags.Global.LdFlags = append(flags.Global.LdFlags, "-pie")
 		}
 	}
 
@@ -235,7 +235,7 @@
 	// all code is position independent, and then those warnings get promoted to
 	// errors.
 	if !ctx.Windows() {
-		flags.CFlags = append(flags.CFlags, "-fPIE")
+		flags.Global.CFlags = append(flags.Global.CFlags, "-fPIE")
 	}
 
 	if ctx.toolchain().Bionic() {
@@ -244,11 +244,11 @@
 			// However, bionic/linker uses -shared to overwrite.
 			// Linker for x86 targets does not allow coexistance of -static and -shared,
 			// so we add -static only if -shared is not used.
-			if !inList("-shared", flags.LdFlags) {
-				flags.LdFlags = append(flags.LdFlags, "-static")
+			if !inList("-shared", flags.Local.LdFlags) {
+				flags.Global.LdFlags = append(flags.Global.LdFlags, "-static")
 			}
 
-			flags.LdFlags = append(flags.LdFlags,
+			flags.Global.LdFlags = append(flags.Global.LdFlags,
 				"-nostdlib",
 				"-Bstatic",
 				"-Wl,--gc-sections",
@@ -278,14 +278,14 @@
 				if ctx.Os() == android.LinuxBionic {
 					// Use the dlwrap entry point, but keep _start around so
 					// that it can be used by host_bionic_inject
-					flags.LdFlags = append(flags.LdFlags,
+					flags.Global.LdFlags = append(flags.Global.LdFlags,
 						"-Wl,--entry=__dlwrap__start",
 						"-Wl,--undefined=_start",
 					)
 				}
 			}
 
-			flags.LdFlags = append(flags.LdFlags,
+			flags.Global.LdFlags = append(flags.Global.LdFlags,
 				"-pie",
 				"-nostdlib",
 				"-Bdynamic",
@@ -295,10 +295,10 @@
 		}
 	} else {
 		if binary.static() {
-			flags.LdFlags = append(flags.LdFlags, "-static")
+			flags.Global.LdFlags = append(flags.Global.LdFlags, "-static")
 		}
 		if ctx.Darwin() {
-			flags.LdFlags = append(flags.LdFlags, "-Wl,-headerpad_max_install_names")
+			flags.Global.LdFlags = append(flags.Global.LdFlags, "-Wl,-headerpad_max_install_names")
 		}
 	}
 
@@ -315,14 +315,14 @@
 	var linkerDeps android.Paths
 
 	if deps.LinkerFlagsFile.Valid() {
-		flags.LdFlags = append(flags.LdFlags, "$$(cat "+deps.LinkerFlagsFile.String()+")")
+		flags.Local.LdFlags = append(flags.Local.LdFlags, "$$(cat "+deps.LinkerFlagsFile.String()+")")
 		linkerDeps = append(linkerDeps, deps.LinkerFlagsFile.Path())
 	}
 
 	if flags.DynamicLinker != "" {
-		flags.LdFlags = append(flags.LdFlags, "-Wl,-dynamic-linker,"+flags.DynamicLinker)
+		flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-dynamic-linker,"+flags.DynamicLinker)
 	} else if ctx.toolchain().Bionic() && !binary.static() {
-		flags.LdFlags = append(flags.LdFlags, "-Wl,--no-dynamic-linker")
+		flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--no-dynamic-linker")
 	}
 
 	builderFlags := flagsToBuilderFlags(flags)
diff --git a/cc/builder.go b/cc/builder.go
index 0760dd4..1ec323f 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -46,7 +46,7 @@
 var (
 	pctx = android.NewPackageContext("android/soong/cc")
 
-	cc = pctx.AndroidGomaStaticRule("cc",
+	cc = pctx.AndroidRemoteStaticRule("cc", android.SUPPORTS_BOTH,
 		blueprint.RuleParams{
 			Depfile:     "${out}.d",
 			Deps:        blueprint.DepsGCC,
@@ -55,7 +55,7 @@
 		},
 		"ccCmd", "cFlags")
 
-	ccNoDeps = pctx.AndroidGomaStaticRule("ccNoDeps",
+	ccNoDeps = pctx.AndroidRemoteStaticRule("ccNoDeps", android.SUPPORTS_GOMA,
 		blueprint.RuleParams{
 			Command:     "$relPwd ${config.CcWrapper}$ccCmd -c $cFlags -o $out $in",
 			CommandDeps: []string{"$ccCmd"},
@@ -130,6 +130,17 @@
 		},
 		"args", "crossCompile")
 
+	_ = pctx.SourcePathVariable("archiveRepackPath", "build/soong/scripts/archive_repack.sh")
+
+	archiveRepack = pctx.AndroidStaticRule("archiveRepack",
+		blueprint.RuleParams{
+			Depfile:     "${out}.d",
+			Deps:        blueprint.DepsGCC,
+			Command:     "CLANG_BIN=${config.ClangBin} $archiveRepackPath -i ${in} -o ${out} -d ${out}.d ${objects}",
+			CommandDeps: []string{"$archiveRepackPath"},
+		},
+		"objects")
+
 	emptyFile = pctx.AndroidStaticRule("emptyFile",
 		blueprint.RuleParams{
 			Command: "rm -f $out && touch $out",
@@ -250,27 +261,37 @@
 }
 
 type builderFlags struct {
-	globalFlags     string
-	arFlags         string
-	asFlags         string
-	cFlags          string
-	toolingCFlags   string // A separate set of cFlags for clang LibTooling tools
-	toolingCppFlags string // A separate set of cppFlags for clang LibTooling tools
-	conlyFlags      string
-	cppFlags        string
-	ldFlags         string
-	libFlags        string
-	extraLibFlags   string
-	tidyFlags       string
-	sAbiFlags       string
-	yasmFlags       string
-	aidlFlags       string
-	rsFlags         string
-	toolchain       config.Toolchain
-	tidy            bool
-	coverage        bool
-	sAbiDump        bool
-	emitXrefs       bool
+	globalCommonFlags     string
+	globalAsFlags         string
+	globalYasmFlags       string
+	globalCFlags          string
+	globalToolingCFlags   string // A separate set of cFlags for clang LibTooling tools
+	globalToolingCppFlags string // A separate set of cppFlags for clang LibTooling tools
+	globalConlyFlags      string
+	globalCppFlags        string
+	globalLdFlags         string
+
+	localCommonFlags     string
+	localAsFlags         string
+	localYasmFlags       string
+	localCFlags          string
+	localToolingCFlags   string // A separate set of cFlags for clang LibTooling tools
+	localToolingCppFlags string // A separate set of cppFlags for clang LibTooling tools
+	localConlyFlags      string
+	localCppFlags        string
+	localLdFlags         string
+
+	libFlags      string
+	extraLibFlags string
+	tidyFlags     string
+	sAbiFlags     string
+	aidlFlags     string
+	rsFlags       string
+	toolchain     config.Toolchain
+	tidy          bool
+	coverage      bool
+	sAbiDump      bool
+	emitXrefs     bool
 
 	assemblerWithCpp bool
 
@@ -338,39 +359,45 @@
 		kytheFiles = make(android.Paths, 0, len(srcFiles))
 	}
 
-	commonFlags := strings.Join([]string{
-		flags.globalFlags,
-		flags.systemIncludeFlags,
-	}, " ")
+	// Produce fully expanded flags for use by C tools, C compiles, C++ tools, C++ compiles, and asm compiles
+	// respectively.
+	toolingCflags := flags.globalCommonFlags + " " +
+		flags.globalToolingCFlags + " " +
+		flags.globalConlyFlags + " " +
+		flags.localCommonFlags + " " +
+		flags.localToolingCFlags + " " +
+		flags.localConlyFlags + " " +
+		flags.systemIncludeFlags
 
-	toolingCflags := strings.Join([]string{
-		commonFlags,
-		flags.toolingCFlags,
-		flags.conlyFlags,
-	}, " ")
+	cflags := flags.globalCommonFlags + " " +
+		flags.globalCFlags + " " +
+		flags.globalConlyFlags + " " +
+		flags.localCommonFlags + " " +
+		flags.localCFlags + " " +
+		flags.localConlyFlags + " " +
+		flags.systemIncludeFlags
 
-	cflags := strings.Join([]string{
-		commonFlags,
-		flags.cFlags,
-		flags.conlyFlags,
-	}, " ")
+	toolingCppflags := flags.globalCommonFlags + " " +
+		flags.globalToolingCFlags + " " +
+		flags.globalToolingCppFlags + " " +
+		flags.localCommonFlags + " " +
+		flags.localToolingCFlags + " " +
+		flags.localToolingCppFlags + " " +
+		flags.systemIncludeFlags
 
-	toolingCppflags := strings.Join([]string{
-		commonFlags,
-		flags.toolingCFlags,
-		flags.toolingCppFlags,
-	}, " ")
+	cppflags := flags.globalCommonFlags + " " +
+		flags.globalCFlags + " " +
+		flags.globalCppFlags + " " +
+		flags.localCommonFlags + " " +
+		flags.localCFlags + " " +
+		flags.localCppFlags + " " +
+		flags.systemIncludeFlags
 
-	cppflags := strings.Join([]string{
-		commonFlags,
-		flags.cFlags,
-		flags.cppFlags,
-	}, " ")
-
-	asflags := strings.Join([]string{
-		commonFlags,
-		flags.asFlags,
-	}, " ")
+	asflags := flags.globalCommonFlags + " " +
+		flags.globalAsFlags + " " +
+		flags.localCommonFlags + " " +
+		flags.localAsFlags + " " +
+		flags.systemIncludeFlags
 
 	var sAbiDumpFiles android.Paths
 	if flags.sAbiDump {
@@ -397,7 +424,7 @@
 				Implicits:   cFlagsDeps,
 				OrderOnly:   pathDeps,
 				Args: map[string]string{
-					"asFlags": flags.yasmFlags,
+					"asFlags": flags.globalYasmFlags + " " + flags.localYasmFlags,
 				},
 			})
 			continue
@@ -420,8 +447,9 @@
 			continue
 		}
 
-		var moduleCflags string
-		var moduleToolingCflags string
+		var moduleFlags string
+		var moduleToolingFlags string
+
 		var ccCmd string
 		tidy := flags.tidy
 		coverage := flags.coverage
@@ -437,19 +465,19 @@
 			fallthrough
 		case ".S":
 			ccCmd = "clang"
-			moduleCflags = asflags
+			moduleFlags = asflags
 			tidy = false
 			coverage = false
 			dump = false
 			emitXref = false
 		case ".c":
 			ccCmd = "clang"
-			moduleCflags = cflags
-			moduleToolingCflags = toolingCflags
+			moduleFlags = cflags
+			moduleToolingFlags = toolingCflags
 		case ".cpp", ".cc", ".cxx", ".mm":
 			ccCmd = "clang++"
-			moduleCflags = cppflags
-			moduleToolingCflags = toolingCppflags
+			moduleFlags = cppflags
+			moduleToolingFlags = toolingCppflags
 		default:
 			ctx.ModuleErrorf("File %s has unknown extension", srcFile)
 			continue
@@ -475,7 +503,7 @@
 			Implicits:       cFlagsDeps,
 			OrderOnly:       pathDeps,
 			Args: map[string]string{
-				"cFlags": moduleCflags,
+				"cFlags": moduleFlags,
 				"ccCmd":  ccCmd,
 			},
 		})
@@ -490,7 +518,7 @@
 				Implicits:   cFlagsDeps,
 				OrderOnly:   pathDeps,
 				Args: map[string]string{
-					"cFlags": moduleCflags,
+					"cFlags": moduleFlags,
 				},
 			})
 			kytheFiles = append(kytheFiles, kytheFile)
@@ -511,7 +539,7 @@
 				Implicits: cFlagsDeps,
 				OrderOnly: pathDeps,
 				Args: map[string]string{
-					"cFlags":    moduleToolingCflags,
+					"cFlags":    moduleToolingFlags,
 					"tidyFlags": flags.tidyFlags,
 				},
 			})
@@ -530,7 +558,7 @@
 				Implicits:   cFlagsDeps,
 				OrderOnly:   pathDeps,
 				Args: map[string]string{
-					"cFlags":     moduleToolingCflags,
+					"cFlags":     moduleToolingFlags,
 					"exportDirs": flags.sAbiFlags,
 				},
 			})
@@ -556,9 +584,6 @@
 	if !ctx.Darwin() {
 		arFlags += " -format=gnu"
 	}
-	if flags.arFlags != "" {
-		arFlags += " " + flags.arFlags
-	}
 
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        ar,
@@ -640,7 +665,7 @@
 			"crtBegin":      crtBegin.String(),
 			"libFlags":      strings.Join(libFlagsList, " "),
 			"extraLibFlags": flags.extraLibFlags,
-			"ldFlags":       flags.ldFlags,
+			"ldFlags":       flags.globalLdFlags + " " + flags.localLdFlags,
 			"crtEnd":        crtEnd.String(),
 		},
 	})
@@ -777,7 +802,7 @@
 		Implicits:   deps,
 		Args: map[string]string{
 			"ldCmd":   ldCmd,
-			"ldFlags": flags.ldFlags,
+			"ldFlags": flags.globalLdFlags + " " + flags.localLdFlags,
 		},
 	})
 }
@@ -866,6 +891,20 @@
 	return android.OptionalPath{}
 }
 
+func TransformArchiveRepack(ctx android.ModuleContext, inputFile android.Path,
+	outputFile android.WritablePath, objects []string) {
+
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        archiveRepack,
+		Description: "Repack archive " + outputFile.Base(),
+		Output:      outputFile,
+		Input:       inputFile,
+		Args: map[string]string{
+			"objects": strings.Join(objects, " "),
+		},
+	})
+}
+
 func gccCmd(toolchain config.Toolchain, cmd string) string {
 	return filepath.Join(toolchain.GccRoot(), "bin", toolchain.GccTriple()+"-"+cmd)
 }
diff --git a/cc/cc.go b/cc/cc.go
index 806a6ed..840fe24 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -123,10 +123,10 @@
 	GeneratedHeaders android.Paths
 
 	Flags                []string
-	IncludeDirs          []string
-	SystemIncludeDirs    []string
-	ReexportedDirs       []string
-	ReexportedSystemDirs []string
+	IncludeDirs          android.Paths
+	SystemIncludeDirs    android.Paths
+	ReexportedDirs       android.Paths
+	ReexportedSystemDirs android.Paths
 	ReexportedFlags      []string
 	ReexportedDeps       android.Paths
 
@@ -140,26 +140,34 @@
 	DynamicLinker android.OptionalPath
 }
 
-type Flags struct {
-	GlobalFlags     []string // Flags that apply to C, C++, and assembly source files
-	ArFlags         []string // Flags that apply to ar
+// LocalOrGlobalFlags contains flags that need to have values set globally by the build system or locally by the module
+// tracked separately, in order to maintain the required ordering (most of the global flags need to go first on the
+// command line so they can be overridden by the local module flags).
+type LocalOrGlobalFlags struct {
+	CommonFlags     []string // Flags that apply to C, C++, and assembly source files
 	AsFlags         []string // Flags that apply to assembly source files
+	YasmFlags       []string // Flags that apply to yasm assembly source files
 	CFlags          []string // Flags that apply to C and C++ source files
 	ToolingCFlags   []string // Flags that apply to C and C++ source files parsed by clang LibTooling tools
 	ConlyFlags      []string // Flags that apply to C source files
 	CppFlags        []string // Flags that apply to C++ source files
 	ToolingCppFlags []string // Flags that apply to C++ source files parsed by clang LibTooling tools
-	aidlFlags       []string // Flags that apply to aidl source files
-	rsFlags         []string // Flags that apply to renderscript source files
 	LdFlags         []string // Flags that apply to linker command lines
-	libFlags        []string // Flags to add libraries early to the link order
-	extraLibFlags   []string // Flags to add libraries late in the link order after LdFlags
-	TidyFlags       []string // Flags that apply to clang-tidy
-	SAbiFlags       []string // Flags that apply to header-abi-dumper
-	YasmFlags       []string // Flags that apply to yasm assembly source files
+}
+
+type Flags struct {
+	Local  LocalOrGlobalFlags
+	Global LocalOrGlobalFlags
+
+	aidlFlags     []string // Flags that apply to aidl source files
+	rsFlags       []string // Flags that apply to renderscript source files
+	libFlags      []string // Flags to add libraries early to the link order
+	extraLibFlags []string // Flags to add libraries late in the link order after LdFlags
+	TidyFlags     []string // Flags that apply to clang-tidy
+	SAbiFlags     []string // Flags that apply to header-abi-dumper
 
 	// Global include flags that apply to C, C++, and assembly source files
-	// These must be after any module include flags, which will be in GlobalFlags.
+	// These must be after any module include flags, which will be in CommonFlags.
 	SystemIncludeFlags []string
 
 	Toolchain config.Toolchain
@@ -215,6 +223,10 @@
 	// Allows this module to use non-APEX version of libraries. Useful
 	// for building binaries that are started before APEXes are activated.
 	Bootstrap *bool
+
+	// Even if DeviceConfig().VndkUseCoreVariant() is set, this module must use vendor variant.
+	// see soong/cc/config/vndk.go
+	MustUseVendorVariant bool `blueprint:"mutated"`
 }
 
 type VendorProperties struct {
@@ -334,81 +346,50 @@
 	relativeInstallPath() string
 }
 
-type dependencyTag struct {
-	blueprint.BaseDependencyTag
-	name    string
-	library bool
-	shared  bool
-
-	reexportFlags bool
-
-	explicitlyVersioned bool
-}
-
 type xref interface {
 	XrefCcFiles() android.Paths
 }
 
 var (
-	sharedDepTag          = dependencyTag{name: "shared", library: true, shared: true}
-	sharedExportDepTag    = dependencyTag{name: "shared", library: true, shared: true, reexportFlags: true}
-	earlySharedDepTag     = dependencyTag{name: "early_shared", library: true, shared: true}
-	lateSharedDepTag      = dependencyTag{name: "late shared", library: true, shared: true}
-	staticDepTag          = dependencyTag{name: "static", library: true}
-	staticExportDepTag    = dependencyTag{name: "static", library: true, reexportFlags: true}
-	lateStaticDepTag      = dependencyTag{name: "late static", 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}
-	genSourceDepTag       = dependencyTag{name: "gen source"}
-	genHeaderDepTag       = dependencyTag{name: "gen header"}
-	genHeaderExportDepTag = dependencyTag{name: "gen header", reexportFlags: true}
-	objDepTag             = dependencyTag{name: "obj"}
-	crtBeginDepTag        = dependencyTag{name: "crtbegin"}
-	crtEndDepTag          = dependencyTag{name: "crtend"}
-	linkerFlagsDepTag     = dependencyTag{name: "linker flags file"}
-	dynamicLinkerDepTag   = dependencyTag{name: "dynamic linker"}
-	reuseObjTag           = dependencyTag{name: "reuse objects"}
-	staticVariantTag      = dependencyTag{name: "static variant"}
-	ndkStubDepTag         = dependencyTag{name: "ndk stub", library: true}
-	ndkLateStubDepTag     = dependencyTag{name: "ndk late stub", library: true}
-	vndkExtDepTag         = dependencyTag{name: "vndk extends", library: true}
-	runtimeDepTag         = dependencyTag{name: "runtime lib"}
-	coverageDepTag        = dependencyTag{name: "coverage"}
-	testPerSrcDepTag      = dependencyTag{name: "test_per_src"}
+	sharedExportDepTag    = DependencyTag{Name: "shared", Library: true, Shared: true, ReexportFlags: true}
+	earlySharedDepTag     = DependencyTag{Name: "early_shared", Library: true, Shared: true}
+	lateSharedDepTag      = DependencyTag{Name: "late shared", Library: true, Shared: true}
+	staticExportDepTag    = DependencyTag{Name: "static", Library: true, ReexportFlags: true}
+	lateStaticDepTag      = DependencyTag{Name: "late static", 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}
+	genSourceDepTag       = DependencyTag{Name: "gen source"}
+	genHeaderDepTag       = DependencyTag{Name: "gen header"}
+	genHeaderExportDepTag = DependencyTag{Name: "gen header", ReexportFlags: true}
+	objDepTag             = DependencyTag{Name: "obj"}
+	linkerFlagsDepTag     = DependencyTag{Name: "linker flags file"}
+	dynamicLinkerDepTag   = DependencyTag{Name: "dynamic linker"}
+	reuseObjTag           = DependencyTag{Name: "reuse objects"}
+	staticVariantTag      = DependencyTag{Name: "static variant"}
+	ndkStubDepTag         = DependencyTag{Name: "ndk stub", Library: true}
+	ndkLateStubDepTag     = DependencyTag{Name: "ndk late stub", Library: true}
+	vndkExtDepTag         = DependencyTag{Name: "vndk extends", Library: true}
+	runtimeDepTag         = DependencyTag{Name: "runtime lib"}
+	coverageDepTag        = DependencyTag{Name: "coverage"}
+	testPerSrcDepTag      = DependencyTag{Name: "test_per_src"}
 )
 
 func IsSharedDepTag(depTag blueprint.DependencyTag) bool {
-	ccDepTag, ok := depTag.(dependencyTag)
-	return ok && ccDepTag.shared
+	ccDepTag, ok := depTag.(DependencyTag)
+	return ok && ccDepTag.Shared
 }
 
 func IsRuntimeDepTag(depTag blueprint.DependencyTag) bool {
-	ccDepTag, ok := depTag.(dependencyTag)
+	ccDepTag, ok := depTag.(DependencyTag)
 	return ok && ccDepTag == runtimeDepTag
 }
 
 func IsTestPerSrcDepTag(depTag blueprint.DependencyTag) bool {
-	ccDepTag, ok := depTag.(dependencyTag)
+	ccDepTag, ok := depTag.(DependencyTag)
 	return ok && ccDepTag == testPerSrcDepTag
 }
 
-func SharedDepTag() dependencyTag {
-	return sharedDepTag
-}
-
-func StaticDepTag() dependencyTag {
-	return staticDepTag
-}
-
-func CrtBeginDepTag() dependencyTag {
-	return crtBeginDepTag
-}
-
-func CrtEndDepTag() dependencyTag {
-	return crtEndDepTag
-}
-
 // Module contains the properties and members used by all C/C++ module types, and implements
 // the blueprint.Module interface.  It delegates to compiler, linker, and installer interfaces
 // to construct the output file.  Behavior can be customized with a Customizer interface
@@ -456,17 +437,212 @@
 	depsInLinkOrder android.Paths
 
 	// only non-nil when this is a shared library that reuses the objects of a static library
-	staticVariant *Module
+	staticVariant LinkableInterface
 
 	makeLinkType string
 	// Kythe (source file indexer) paths for this compilation module
 	kytheFiles android.Paths
 }
 
+func (c *Module) Toc() android.OptionalPath {
+	if c.linker != nil {
+		if library, ok := c.linker.(libraryInterface); ok {
+			return library.toc()
+		}
+	}
+	panic(fmt.Errorf("Toc() called on non-library module: %q", c.BaseModuleName()))
+}
+
+func (c *Module) ApiLevel() string {
+	if c.linker != nil {
+		if stub, ok := c.linker.(*stubDecorator); ok {
+			return stub.properties.ApiLevel
+		}
+	}
+	panic(fmt.Errorf("ApiLevel() called on non-stub library module: %q", c.BaseModuleName()))
+}
+
+func (c *Module) Static() bool {
+	if c.linker != nil {
+		if library, ok := c.linker.(libraryInterface); ok {
+			return library.static()
+		}
+	}
+	panic(fmt.Errorf("Static() called on non-library module: %q", c.BaseModuleName()))
+}
+
+func (c *Module) Shared() bool {
+	if c.linker != nil {
+		if library, ok := c.linker.(libraryInterface); ok {
+			return library.shared()
+		}
+	}
+	panic(fmt.Errorf("Shared() called on non-library module: %q", c.BaseModuleName()))
+}
+
+func (c *Module) SelectedStl() string {
+	return c.stl.Properties.SelectedStl
+}
+
+func (c *Module) ToolchainLibrary() bool {
+	if _, ok := c.linker.(*toolchainLibraryDecorator); ok {
+		return true
+	}
+	return false
+}
+
+func (c *Module) NdkPrebuiltStl() bool {
+	if _, ok := c.linker.(*ndkPrebuiltStlLinker); ok {
+		return true
+	}
+	return false
+}
+
+func (c *Module) StubDecorator() bool {
+	if _, ok := c.linker.(*stubDecorator); ok {
+		return true
+	}
+	return false
+}
+
+func (c *Module) SdkVersion() string {
+	return String(c.Properties.Sdk_version)
+}
+
+func (c *Module) IncludeDirs(ctx android.BaseModuleContext) android.Paths {
+	if c.linker != nil {
+		if library, ok := c.linker.(exportedFlagsProducer); ok {
+			return library.exportedDirs()
+		}
+	}
+	panic(fmt.Errorf("IncludeDirs called on non-exportedFlagsProducer module: %q", c.BaseModuleName()))
+}
+
+func (c *Module) HasStaticVariant() bool {
+	if c.staticVariant != nil {
+		return true
+	}
+	return false
+}
+
+func (c *Module) GetStaticVariant() LinkableInterface {
+	return c.staticVariant
+}
+
+func (c *Module) SetDepsInLinkOrder(depsInLinkOrder []android.Path) {
+	c.depsInLinkOrder = depsInLinkOrder
+}
+
+func (c *Module) GetDepsInLinkOrder() []android.Path {
+	return c.depsInLinkOrder
+}
+
+func (c *Module) StubsVersions() []string {
+	if c.linker != nil {
+		if library, ok := c.linker.(*libraryDecorator); ok {
+			return library.Properties.Stubs.Versions
+		}
+	}
+	panic(fmt.Errorf("StubsVersions called on non-library module: %q", c.BaseModuleName()))
+}
+
+func (c *Module) CcLibrary() bool {
+	if c.linker != nil {
+		if _, ok := c.linker.(*libraryDecorator); ok {
+			return true
+		}
+	}
+	return false
+}
+
+func (c *Module) CcLibraryInterface() bool {
+	if _, ok := c.linker.(libraryInterface); ok {
+		return true
+	}
+	return false
+}
+
+func (c *Module) SetBuildStubs() {
+	if c.linker != nil {
+		if library, ok := c.linker.(*libraryDecorator); ok {
+			library.MutatedProperties.BuildStubs = true
+			c.Properties.HideFromMake = true
+			c.sanitize = nil
+			c.stl = nil
+			c.Properties.PreventInstall = true
+			return
+		}
+	}
+	panic(fmt.Errorf("SetBuildStubs called on non-library module: %q", c.BaseModuleName()))
+}
+
+func (c *Module) BuildStubs() bool {
+	if c.linker != nil {
+		if library, ok := c.linker.(*libraryDecorator); ok {
+			return library.buildStubs()
+		}
+	}
+	panic(fmt.Errorf("BuildStubs called on non-library module: %q", c.BaseModuleName()))
+}
+
+func (c *Module) SetStubsVersions(version string) {
+	if c.linker != nil {
+		if library, ok := c.linker.(*libraryDecorator); ok {
+			library.MutatedProperties.StubsVersion = version
+			return
+		}
+	}
+	panic(fmt.Errorf("SetStubsVersions called on non-library module: %q", c.BaseModuleName()))
+}
+
+func (c *Module) SetStatic() {
+	if c.linker != nil {
+		if library, ok := c.linker.(libraryInterface); ok {
+			library.setStatic()
+			return
+		}
+	}
+	panic(fmt.Errorf("SetStatic called on non-library module: %q", c.BaseModuleName()))
+}
+
+func (c *Module) SetShared() {
+	if c.linker != nil {
+		if library, ok := c.linker.(libraryInterface); ok {
+			library.setShared()
+			return
+		}
+	}
+	panic(fmt.Errorf("SetShared called on non-library module: %q", c.BaseModuleName()))
+}
+
+func (c *Module) BuildStaticVariant() bool {
+	if c.linker != nil {
+		if library, ok := c.linker.(libraryInterface); ok {
+			return library.buildStatic()
+		}
+	}
+	panic(fmt.Errorf("BuildStaticVariant called on non-library module: %q", c.BaseModuleName()))
+}
+
+func (c *Module) BuildSharedVariant() bool {
+	if c.linker != nil {
+		if library, ok := c.linker.(libraryInterface); ok {
+			return library.buildShared()
+		}
+	}
+	panic(fmt.Errorf("BuildSharedVariant called on non-library module: %q", c.BaseModuleName()))
+}
+
+func (c *Module) Module() android.Module {
+	return c
+}
+
 func (c *Module) OutputFile() android.OptionalPath {
 	return c.outputFile
 }
 
+var _ LinkableInterface = (*Module)(nil)
+
 func (c *Module) UnstrippedOutputFile() android.Path {
 	if c.linker != nil {
 		return c.linker.unstrippedOutputFilePath()
@@ -488,15 +664,6 @@
 	return ""
 }
 
-// IsVndkOnSystem returns true if a module is supposed to be a vndk library provided by system to vendor
-func (c *Module) IsVndkOnSystem() bool {
-	if linker, ok := c.linker.(libraryInterface); ok {
-		return linker.shared() && c.isVndk() && c.useVndk() && !c.isVndkExt()
-	}
-
-	return false
-}
-
 func (c *Module) VndkVersion() string {
 	return c.vndkVersion()
 }
@@ -572,7 +739,7 @@
 	return false
 }
 
-func (c *Module) useVndk() bool {
+func (c *Module) UseVndk() bool {
 	return c.Properties.VndkVersion != ""
 }
 
@@ -586,20 +753,21 @@
 
 func (c *Module) isLlndk(config android.Config) bool {
 	// Returns true for both LLNDK (public) and LLNDK-private libs.
-	return inList(c.Name(), *llndkLibraries(config))
+	return isLlndkLibrary(c.BaseModuleName(), config)
 }
 
 func (c *Module) isLlndkPublic(config android.Config) bool {
 	// Returns true only for LLNDK (public) libs.
-	return c.isLlndk(config) && !c.isVndkPrivate(config)
+	name := c.BaseModuleName()
+	return isLlndkLibrary(name, config) && !isVndkPrivateLibrary(name, config)
 }
 
 func (c *Module) isVndkPrivate(config android.Config) bool {
 	// Returns true for LLNDK-private, VNDK-SP-private, and VNDK-core-private.
-	return inList(c.Name(), *vndkPrivateLibraries(config))
+	return isVndkPrivateLibrary(c.BaseModuleName(), config)
 }
 
-func (c *Module) isVndk() bool {
+func (c *Module) IsVndk() bool {
 	if vndkdep := c.vndkdep; vndkdep != nil {
 		return vndkdep.isVndk()
 	}
@@ -638,8 +806,8 @@
 	return false
 }
 
-func (c *Module) mustUseVendorVariant() bool {
-	return c.isVndkSp() || inList(c.Name(), config.VndkMustUseVendorVariantList)
+func (c *Module) MustUseVendorVariant() bool {
+	return c.isVndkSp() || c.Properties.MustUseVendorVariant
 }
 
 func (c *Module) getVndkExtendsModuleName() string {
@@ -651,15 +819,15 @@
 
 // Returns true only when this module is configured to have core and vendor
 // variants.
-func (c *Module) hasVendorVariant() bool {
-	return c.isVndk() || Bool(c.VendorProperties.Vendor_available)
+func (c *Module) HasVendorVariant() bool {
+	return c.IsVndk() || Bool(c.VendorProperties.Vendor_available)
 }
 
-func (c *Module) inRecovery() bool {
+func (c *Module) InRecovery() bool {
 	return c.Properties.InRecovery || c.ModuleBase.InstallInRecovery()
 }
 
-func (c *Module) onlyInRecovery() bool {
+func (c *Module) OnlyInRecovery() bool {
 	return c.ModuleBase.InstallInRecovery()
 }
 
@@ -694,6 +862,34 @@
 	return c.linker != nil && c.linker.nativeCoverage()
 }
 
+func (c *Module) ExportedIncludeDirs() android.Paths {
+	if flagsProducer, ok := c.linker.(exportedFlagsProducer); ok {
+		return flagsProducer.exportedDirs()
+	}
+	return nil
+}
+
+func (c *Module) ExportedSystemIncludeDirs() android.Paths {
+	if flagsProducer, ok := c.linker.(exportedFlagsProducer); ok {
+		return flagsProducer.exportedSystemDirs()
+	}
+	return nil
+}
+
+func (c *Module) ExportedFlags() []string {
+	if flagsProducer, ok := c.linker.(exportedFlagsProducer); ok {
+		return flagsProducer.exportedFlags()
+	}
+	return nil
+}
+
+func (c *Module) ExportedDeps() android.Paths {
+	if flagsProducer, ok := c.linker.(exportedFlagsProducer); ok {
+		return flagsProducer.exportedDeps()
+	}
+	return nil
+}
+
 func isBionic(name string) bool {
 	switch name {
 	case "libc", "libm", "libdl", "linker":
@@ -730,7 +926,7 @@
 
 func (ctx *moduleContext) SocSpecific() bool {
 	return ctx.ModuleContext.SocSpecific() ||
-		(ctx.mod.hasVendorVariant() && ctx.mod.useVndk() && !ctx.mod.isVndk())
+		(ctx.mod.HasVendorVariant() && ctx.mod.UseVndk() && !ctx.mod.IsVndk())
 }
 
 type moduleContextImpl struct {
@@ -780,7 +976,7 @@
 }
 
 func (ctx *moduleContextImpl) useVndk() bool {
-	return ctx.mod.useVndk()
+	return ctx.mod.UseVndk()
 }
 
 func (ctx *moduleContextImpl) isNdk() bool {
@@ -800,7 +996,7 @@
 }
 
 func (ctx *moduleContextImpl) isVndk() bool {
-	return ctx.mod.isVndk()
+	return ctx.mod.IsVndk()
 }
 
 func (ctx *moduleContextImpl) isPgoCompile() bool {
@@ -820,11 +1016,11 @@
 }
 
 func (ctx *moduleContextImpl) mustUseVendorVariant() bool {
-	return ctx.mod.mustUseVendorVariant()
+	return ctx.mod.MustUseVendorVariant()
 }
 
 func (ctx *moduleContextImpl) inRecovery() bool {
-	return ctx.mod.inRecovery()
+	return ctx.mod.InRecovery()
 }
 
 // Check whether ABI dumps should be created for this module.
@@ -976,25 +1172,27 @@
 	return orderedAllDeps, orderedDeclaredDeps
 }
 
-func orderStaticModuleDeps(module *Module, staticDeps []*Module, sharedDeps []*Module) (results []android.Path) {
+func orderStaticModuleDeps(module LinkableInterface, staticDeps []LinkableInterface, sharedDeps []LinkableInterface) (results []android.Path) {
 	// convert Module to Path
+	var depsInLinkOrder []android.Path
 	allTransitiveDeps := make(map[android.Path][]android.Path, len(staticDeps))
 	staticDepFiles := []android.Path{}
 	for _, dep := range staticDeps {
-		allTransitiveDeps[dep.outputFile.Path()] = dep.depsInLinkOrder
-		staticDepFiles = append(staticDepFiles, dep.outputFile.Path())
+		allTransitiveDeps[dep.OutputFile().Path()] = dep.GetDepsInLinkOrder()
+		staticDepFiles = append(staticDepFiles, dep.OutputFile().Path())
 	}
 	sharedDepFiles := []android.Path{}
 	for _, sharedDep := range sharedDeps {
-		staticAnalogue := sharedDep.staticVariant
-		if staticAnalogue != nil {
-			allTransitiveDeps[staticAnalogue.outputFile.Path()] = staticAnalogue.depsInLinkOrder
-			sharedDepFiles = append(sharedDepFiles, staticAnalogue.outputFile.Path())
+		if sharedDep.HasStaticVariant() {
+			staticAnalogue := sharedDep.GetStaticVariant()
+			allTransitiveDeps[staticAnalogue.OutputFile().Path()] = staticAnalogue.GetDepsInLinkOrder()
+			sharedDepFiles = append(sharedDepFiles, staticAnalogue.OutputFile().Path())
 		}
 	}
 
 	// reorder the dependencies based on transitive dependencies
-	module.depsInLinkOrder, results = orderDeps(staticDepFiles, sharedDepFiles, allTransitiveDeps)
+	depsInLinkOrder, results = orderDeps(staticDepFiles, sharedDepFiles, allTransitiveDeps)
+	module.SetDepsInLinkOrder(depsInLinkOrder)
 
 	return results
 }
@@ -1027,7 +1225,7 @@
 		// .vendor suffix is added for backward compatibility with VNDK snapshot whose names with
 		// such suffixes are already hard-coded in prebuilts/vndk/.../Android.bp.
 		c.Properties.SubName += vendorSuffix
-	} else if _, ok := c.linker.(*llndkStubDecorator); ok || (c.useVndk() && c.hasVendorVariant()) {
+	} else if _, ok := c.linker.(*llndkStubDecorator); ok || (c.UseVndk() && c.HasVendorVariant()) {
 		// .vendor.{version} suffix is added only when we will have two variants: core and vendor.
 		// The suffix is not added for vendor-only module.
 		c.Properties.SubName += vendorSuffix
@@ -1038,7 +1236,7 @@
 		if c.Properties.VndkVersion != vendorVersion {
 			c.Properties.SubName += "." + c.Properties.VndkVersion
 		}
-	} else if c.inRecovery() && !c.onlyInRecovery() {
+	} else if c.InRecovery() && !c.OnlyInRecovery() {
 		c.Properties.SubName += recoverySuffix
 	}
 
@@ -1094,17 +1292,17 @@
 		return
 	}
 
-	flags.CFlags, _ = filterList(flags.CFlags, config.IllegalFlags)
-	flags.CppFlags, _ = filterList(flags.CppFlags, config.IllegalFlags)
-	flags.ConlyFlags, _ = filterList(flags.ConlyFlags, config.IllegalFlags)
+	flags.Local.CFlags, _ = filterList(flags.Local.CFlags, config.IllegalFlags)
+	flags.Local.CppFlags, _ = filterList(flags.Local.CppFlags, config.IllegalFlags)
+	flags.Local.ConlyFlags, _ = filterList(flags.Local.ConlyFlags, config.IllegalFlags)
 
-	flags.GlobalFlags = append(flags.GlobalFlags, deps.Flags...)
+	flags.Local.CommonFlags = append(flags.Local.CommonFlags, deps.Flags...)
 
 	for _, dir := range deps.IncludeDirs {
-		flags.GlobalFlags = append(flags.GlobalFlags, "-I"+dir)
+		flags.Local.CommonFlags = append(flags.Local.CommonFlags, "-I"+dir.String())
 	}
 	for _, dir := range deps.SystemIncludeDirs {
-		flags.GlobalFlags = append(flags.GlobalFlags, "-isystem "+dir)
+		flags.Local.CommonFlags = append(flags.Local.CommonFlags, "-isystem "+dir.String())
 	}
 
 	c.flags = flags
@@ -1113,16 +1311,16 @@
 		flags = c.sabi.flags(ctx, flags)
 	}
 
-	flags.AssemblerWithCpp = inList("-xassembler-with-cpp", flags.AsFlags)
+	flags.AssemblerWithCpp = inList("-xassembler-with-cpp", flags.Local.AsFlags)
 
 	// Optimization to reduce size of build.ninja
 	// Replace the long list of flags for each file with a module-local variable
-	ctx.Variable(pctx, "cflags", strings.Join(flags.CFlags, " "))
-	ctx.Variable(pctx, "cppflags", strings.Join(flags.CppFlags, " "))
-	ctx.Variable(pctx, "asflags", strings.Join(flags.AsFlags, " "))
-	flags.CFlags = []string{"$cflags"}
-	flags.CppFlags = []string{"$cppflags"}
-	flags.AsFlags = []string{"$asflags"}
+	ctx.Variable(pctx, "cflags", strings.Join(flags.Local.CFlags, " "))
+	ctx.Variable(pctx, "cppflags", strings.Join(flags.Local.CppFlags, " "))
+	ctx.Variable(pctx, "asflags", strings.Join(flags.Local.AsFlags, " "))
+	flags.Local.CFlags = []string{"$cflags"}
+	flags.Local.CppFlags = []string{"$cppflags"}
+	flags.Local.AsFlags = []string{"$asflags"}
 
 	var objs Objects
 	if c.compiler != nil {
@@ -1148,7 +1346,7 @@
 		// module is marked with 'bootstrap: true').
 		if c.HasStubsVariants() &&
 			android.DirectlyInAnyApex(ctx, ctx.baseModuleName()) &&
-			!c.inRecovery() && !c.useVndk() && !c.static() && !c.isCoverageVariant() &&
+			!c.InRecovery() && !c.UseVndk() && !c.static() && !c.isCoverageVariant() &&
 			c.IsStubs() {
 			c.Properties.HideFromMake = false // unhide
 			// Note: this is still non-installable
@@ -1295,7 +1493,7 @@
 }
 
 // Split name#version into name and version
-func stubsLibNameAndVersion(name string) (string, string) {
+func StubsLibNameAndVersion(name string) (string, string) {
 	if sharp := strings.LastIndex(name, "#"); sharp != -1 && sharp != len(name)-1 {
 		version := name[sharp+1:]
 		libname := name[:sharp]
@@ -1335,21 +1533,20 @@
 		// The caller can then know to add the variantLibs dependencies differently from the
 		// nonvariantLibs
 
-		llndkLibraries := llndkLibraries(actx.Config())
 		vendorPublicLibraries := vendorPublicLibraries(actx.Config())
 		rewriteNdkLibs := func(list []string) (nonvariantLibs []string, variantLibs []string) {
 			variantLibs = []string{}
 			nonvariantLibs = []string{}
 			for _, entry := range list {
 				// strip #version suffix out
-				name, _ := stubsLibNameAndVersion(entry)
+				name, _ := StubsLibNameAndVersion(entry)
 				if ctx.useSdk() && inList(name, ndkPrebuiltSharedLibraries) {
 					if !inList(name, ndkMigratedLibs) {
 						nonvariantLibs = append(nonvariantLibs, name+".ndk."+version)
 					} else {
 						variantLibs = append(variantLibs, name+ndkLibrarySuffix)
 					}
-				} else if ctx.useVndk() && inList(name, *llndkLibraries) {
+				} else if ctx.useVndk() && isLlndkLibrary(name, ctx.Config()) {
 					nonvariantLibs = append(nonvariantLibs, name+llndkLibrarySuffix)
 				} else if (ctx.Platform() || ctx.ProductSpecific()) && inList(name, *vendorPublicLibraries) {
 					vendorPublicLib := name + vendorPublicLibrarySuffix
@@ -1416,7 +1613,7 @@
 	}
 
 	for _, lib := range deps.StaticLibs {
-		depTag := staticDepTag
+		depTag := StaticDepTag
 		if inList(lib, deps.ReexportStaticLibHeaders) {
 			depTag = staticExportDepTag
 		}
@@ -1434,27 +1631,27 @@
 		{Mutator: "link", Variation: "static"},
 	}, lateStaticDepTag, deps.LateStaticLibs...)
 
-	addSharedLibDependencies := func(depTag dependencyTag, name string, version string) {
+	addSharedLibDependencies := func(depTag DependencyTag, name string, version string) {
 		var variations []blueprint.Variation
 		variations = append(variations, blueprint.Variation{Mutator: "link", Variation: "shared"})
-		versionVariantAvail := !ctx.useVndk() && !c.inRecovery()
+		versionVariantAvail := !ctx.useVndk() && !c.InRecovery()
 		if version != "" && versionVariantAvail {
 			// Version is explicitly specified. i.e. libFoo#30
 			variations = append(variations, blueprint.Variation{Mutator: "version", Variation: version})
-			depTag.explicitlyVersioned = true
+			depTag.ExplicitlyVersioned = true
 		}
 		actx.AddVariationDependencies(variations, depTag, name)
 
 		// If the version is not specified, add dependency to the latest stubs library.
 		// The stubs library will be used when the depending module is built for APEX and
 		// the dependent module is not in the same APEX.
-		latestVersion := latestStubsVersionFor(actx.Config(), name)
+		latestVersion := LatestStubsVersionFor(actx.Config(), name)
 		if version == "" && latestVersion != "" && versionVariantAvail {
 			actx.AddVariationDependencies([]blueprint.Variation{
 				{Mutator: "link", Variation: "shared"},
 				{Mutator: "version", Variation: latestVersion},
 			}, depTag, name)
-			// Note that depTag.explicitlyVersioned is false in this case.
+			// Note that depTag.ExplicitlyVersioned is false in this case.
 		}
 	}
 
@@ -1462,7 +1659,7 @@
 	var sharedLibNames []string
 
 	for _, lib := range deps.SharedLibs {
-		depTag := sharedDepTag
+		depTag := SharedDepTag
 		if inList(lib, deps.ReexportSharedLibHeaders) {
 			depTag = sharedExportDepTag
 		}
@@ -1471,7 +1668,7 @@
 			lib = impl
 		}
 
-		name, version := stubsLibNameAndVersion(lib)
+		name, version := StubsLibNameAndVersion(lib)
 		sharedLibNames = append(sharedLibNames, name)
 
 		addSharedLibDependencies(depTag, name, version)
@@ -1504,10 +1701,10 @@
 	actx.AddVariationDependencies(nil, objDepTag, deps.ObjFiles...)
 
 	if deps.CrtBegin != "" {
-		actx.AddVariationDependencies(nil, crtBeginDepTag, deps.CrtBegin)
+		actx.AddVariationDependencies(nil, CrtBeginDepTag, deps.CrtBegin)
 	}
 	if deps.CrtEnd != "" {
-		actx.AddVariationDependencies(nil, crtEndDepTag, deps.CrtEnd)
+		actx.AddVariationDependencies(nil, CrtEndDepTag, deps.CrtEnd)
 	}
 	if deps.LinkerFlagsFile != "" {
 		actx.AddDependency(c, linkerFlagsDepTag, deps.LinkerFlagsFile)
@@ -1550,52 +1747,58 @@
 
 // Whether a module can link to another module, taking into
 // account NDK linking.
-func checkLinkType(ctx android.ModuleContext, from *Module, to *Module, tag dependencyTag) {
-	if from.Target().Os != android.Android {
+func checkLinkType(ctx android.ModuleContext, from LinkableInterface, to LinkableInterface, tag DependencyTag) {
+	if from.Module().Target().Os != android.Android {
 		// Host code is not restricted
 		return
 	}
-	if from.useVndk() {
+
+	// VNDK is cc.Module supported only for now.
+	if ccFrom, ok := from.(*Module); ok && from.UseVndk() {
 		// Though vendor code is limited by the vendor mutator,
 		// each vendor-available module needs to check
 		// link-type for VNDK.
-		if from.vndkdep != nil {
-			from.vndkdep.vndkCheckLinkType(ctx, to, tag)
+		if ccTo, ok := to.(*Module); ok {
+			if ccFrom.vndkdep != nil {
+				ccFrom.vndkdep.vndkCheckLinkType(ctx, ccTo, tag)
+			}
+		} else {
+			ctx.ModuleErrorf("Attempting to link VNDK cc.Module with unsupported module type")
 		}
 		return
 	}
-	if String(from.Properties.Sdk_version) == "" {
+	if from.SdkVersion() == "" {
 		// Platform code can link to anything
 		return
 	}
-	if from.inRecovery() {
+	if from.InRecovery() {
 		// Recovery code is not NDK
 		return
 	}
-	if _, ok := to.linker.(*toolchainLibraryDecorator); ok {
+	if to.ToolchainLibrary() {
 		// These are always allowed
 		return
 	}
-	if _, ok := to.linker.(*ndkPrebuiltStlLinker); ok {
+	if to.NdkPrebuiltStl() {
 		// These are allowed, but they don't set sdk_version
 		return
 	}
-	if _, ok := to.linker.(*stubDecorator); ok {
+	if to.StubDecorator() {
 		// These aren't real libraries, but are the stub shared libraries that are included in
 		// the NDK.
 		return
 	}
 
-	if strings.HasPrefix(ctx.ModuleName(), "libclang_rt.") && to.Name() == "libc++" {
+	if strings.HasPrefix(ctx.ModuleName(), "libclang_rt.") && to.Module().Name() == "libc++" {
 		// Bug: http://b/121358700 - Allow libclang_rt.* shared libraries (with sdk_version)
 		// to link to libc++ (non-NDK and without sdk_version).
 		return
 	}
 
-	if String(to.Properties.Sdk_version) == "" {
+	if to.SdkVersion() == "" {
 		// NDK code linking to platform code is never okay.
 		ctx.ModuleErrorf("depends on non-NDK-built library %q",
-			ctx.OtherModuleName(to))
+			ctx.OtherModuleName(to.Module()))
 		return
 	}
 
@@ -1605,36 +1808,36 @@
 	// APIs.
 
 	// Current can link against anything.
-	if String(from.Properties.Sdk_version) != "current" {
+	if from.SdkVersion() != "current" {
 		// Otherwise we need to check.
-		if String(to.Properties.Sdk_version) == "current" {
+		if to.SdkVersion() == "current" {
 			// Current can't be linked against by anything else.
 			ctx.ModuleErrorf("links %q built against newer API version %q",
-				ctx.OtherModuleName(to), "current")
+				ctx.OtherModuleName(to.Module()), "current")
 		} else {
-			fromApi, err := strconv.Atoi(String(from.Properties.Sdk_version))
+			fromApi, err := strconv.Atoi(from.SdkVersion())
 			if err != nil {
 				ctx.PropertyErrorf("sdk_version",
 					"Invalid sdk_version value (must be int or current): %q",
-					String(from.Properties.Sdk_version))
+					from.SdkVersion())
 			}
-			toApi, err := strconv.Atoi(String(to.Properties.Sdk_version))
+			toApi, err := strconv.Atoi(to.SdkVersion())
 			if err != nil {
 				ctx.PropertyErrorf("sdk_version",
 					"Invalid sdk_version value (must be int or current): %q",
-					String(to.Properties.Sdk_version))
+					to.SdkVersion())
 			}
 
 			if toApi > fromApi {
 				ctx.ModuleErrorf("links %q built against newer API version %q",
-					ctx.OtherModuleName(to), String(to.Properties.Sdk_version))
+					ctx.OtherModuleName(to.Module()), to.SdkVersion())
 			}
 		}
 	}
 
 	// Also check that the two STL choices are compatible.
-	fromStl := from.stl.Properties.SelectedStl
-	toStl := to.stl.Properties.SelectedStl
+	fromStl := from.SelectedStl()
+	toStl := to.SelectedStl()
 	if fromStl == "" || toStl == "" {
 		// Libraries that don't use the STL are unrestricted.
 	} else if fromStl == "ndk_system" || toStl == "ndk_system" {
@@ -1643,8 +1846,8 @@
 		// using either libc++ or nothing.
 	} else if getNdkStlFamily(from) != getNdkStlFamily(to) {
 		ctx.ModuleErrorf("uses %q and depends on %q which uses incompatible %q",
-			from.stl.Properties.SelectedStl, ctx.OtherModuleName(to),
-			to.stl.Properties.SelectedStl)
+			from.SelectedStl(), ctx.OtherModuleName(to.Module()),
+			to.SelectedStl())
 	}
 }
 
@@ -1653,7 +1856,6 @@
 // it is subject to be double loaded. Such lib should be explicitly marked as double_loadable: true
 // or as vndk-sp (vndk: { enabled: true, support_system_process: true}).
 func checkDoubleLoadableLibraries(ctx android.TopDownMutatorContext) {
-	llndkLibraries := llndkLibraries(ctx.Config())
 	check := func(child, parent android.Module) bool {
 		to, ok := child.(*Module)
 		if !ok {
@@ -1666,11 +1868,11 @@
 		}
 
 		// if target lib has no vendor variant, keep checking dependency graph
-		if !to.hasVendorVariant() {
+		if !to.HasVendorVariant() {
 			return true
 		}
 
-		if to.isVndkSp() || inList(child.Name(), *llndkLibraries) || Bool(to.VendorProperties.Double_loadable) {
+		if to.isVndkSp() || to.isLlndk(ctx.Config()) || Bool(to.VendorProperties.Double_loadable) {
 			return false
 		}
 
@@ -1685,7 +1887,7 @@
 	}
 	if module, ok := ctx.Module().(*Module); ok {
 		if lib, ok := module.linker.(*libraryDecorator); ok && lib.shared() {
-			if inList(ctx.ModuleName(), *llndkLibraries) || Bool(module.VendorProperties.Double_loadable) {
+			if module.isLlndk(ctx.Config()) || Bool(module.VendorProperties.Double_loadable) {
 				ctx.WalkDeps(check)
 			}
 		}
@@ -1696,10 +1898,9 @@
 func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
 	var depPaths PathDeps
 
-	directStaticDeps := []*Module{}
-	directSharedDeps := []*Module{}
+	directStaticDeps := []LinkableInterface{}
+	directSharedDeps := []LinkableInterface{}
 
-	llndkLibraries := llndkLibraries(ctx.Config())
 	vendorPublicLibraries := vendorPublicLibraries(ctx.Config())
 
 	reexportExporter := func(exporter exportedFlagsProducer) {
@@ -1713,8 +1914,9 @@
 		depName := ctx.OtherModuleName(dep)
 		depTag := ctx.OtherModuleDependencyTag(dep)
 
-		ccDep, _ := dep.(*Module)
-		if ccDep == nil {
+		ccDep, ok := dep.(LinkableInterface)
+		if !ok {
+
 			// handling for a few module types that aren't cc Module but that are also supported
 			switch depTag {
 			case genSourceDepTag:
@@ -1730,13 +1932,13 @@
 				if genRule, ok := dep.(genrule.SourceFileGenerator); ok {
 					depPaths.GeneratedHeaders = append(depPaths.GeneratedHeaders,
 						genRule.GeneratedDeps()...)
-					dirs := genRule.GeneratedHeaderDirs().Strings()
+					dirs := genRule.GeneratedHeaderDirs()
 					depPaths.IncludeDirs = append(depPaths.IncludeDirs, dirs...)
 					if depTag == genHeaderExportDepTag {
 						depPaths.ReexportedDirs = append(depPaths.ReexportedDirs, dirs...)
 						depPaths.ReexportedDeps = append(depPaths.ReexportedDeps, genRule.GeneratedDeps()...)
 						// Add these re-exported flags to help header-abi-dumper to infer the abi exported by a library.
-						c.sabi.Properties.ReexportedIncludes = append(c.sabi.Properties.ReexportedIncludes, dirs...)
+						c.sabi.Properties.ReexportedIncludes = append(c.sabi.Properties.ReexportedIncludes, dirs.Strings()...)
 
 					}
 				} else {
@@ -1772,9 +1974,10 @@
 
 		// re-exporting flags
 		if depTag == reuseObjTag {
-			if l, ok := ccDep.compiler.(libraryInterface); ok {
+			// reusing objects only make sense for cc.Modules.
+			if ccReuseDep, ok := ccDep.(*Module); ok && ccDep.CcLibraryInterface() {
 				c.staticVariant = ccDep
-				objs, exporter := l.reuseObjs()
+				objs, exporter := ccReuseDep.compiler.(libraryInterface).reuseObjs()
 				depPaths.Objs = depPaths.Objs.Append(objs)
 				reexportExporter(exporter)
 				return
@@ -1782,30 +1985,31 @@
 		}
 
 		if depTag == staticVariantTag {
-			if _, ok := ccDep.compiler.(libraryInterface); ok {
+			// staticVariants are a cc.Module specific concept.
+			if _, ok := ccDep.(*Module); ok && ccDep.CcLibraryInterface() {
 				c.staticVariant = ccDep
 				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.
+		// 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.
 		explicitlyVersioned := false
-		if t, ok := depTag.(dependencyTag); ok {
-			explicitlyVersioned = t.explicitlyVersioned
-			t.explicitlyVersioned = false
+		if t, ok := depTag.(DependencyTag); ok {
+			explicitlyVersioned = t.ExplicitlyVersioned
+			t.ExplicitlyVersioned = false
 			depTag = t
 		}
 
-		if t, ok := depTag.(dependencyTag); ok && t.library {
+		if t, ok := depTag.(DependencyTag); ok && t.Library {
 			depIsStatic := false
 			switch depTag {
-			case staticDepTag, staticExportDepTag, lateStaticDepTag, wholeStaticDepTag:
+			case StaticDepTag, staticExportDepTag, lateStaticDepTag, wholeStaticDepTag:
 				depIsStatic = true
 			}
-			if dependentLibrary, ok := ccDep.linker.(*libraryDecorator); ok && !depIsStatic {
-				depIsStubs := dependentLibrary.buildStubs()
+			if ccDep.CcLibrary() && !depIsStatic {
+				depIsStubs := ccDep.BuildStubs()
 				depHasStubs := ccDep.HasStubsVariants()
 				depInSameApex := android.DirectlyInApex(c.ApexName(), depName)
 				depInPlatform := !android.DirectlyInAnyApex(ctx, depName)
@@ -1822,7 +2026,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() || c.bootstrap() {
+					if c.InRecovery() || c.bootstrap() {
 						// However, for recovery or bootstrap modules,
 						// always link to non-stub variant
 						useThisDep = !depIsStubs
@@ -1838,85 +2042,95 @@
 				}
 			}
 
-			if i, ok := ccDep.linker.(exportedFlagsProducer); ok {
-				depPaths.IncludeDirs = append(depPaths.IncludeDirs, i.exportedDirs()...)
-				depPaths.SystemIncludeDirs = append(depPaths.SystemIncludeDirs, i.exportedSystemDirs()...)
-				depPaths.GeneratedHeaders = append(depPaths.GeneratedHeaders, i.exportedDeps()...)
-				depPaths.Flags = append(depPaths.Flags, i.exportedFlags()...)
+			// Exporting flags only makes sense for cc.Modules
+			if _, ok := ccDep.(*Module); ok {
+				if i, ok := ccDep.(*Module).linker.(exportedFlagsProducer); ok {
+					depPaths.IncludeDirs = append(depPaths.IncludeDirs, i.exportedDirs()...)
+					depPaths.SystemIncludeDirs = append(depPaths.SystemIncludeDirs, i.exportedSystemDirs()...)
+					depPaths.GeneratedHeaders = append(depPaths.GeneratedHeaders, i.exportedDeps()...)
+					depPaths.Flags = append(depPaths.Flags, i.exportedFlags()...)
 
-				if t.reexportFlags {
-					reexportExporter(i)
-					// Add these re-exported flags to help header-abi-dumper to infer the abi exported by a library.
-					// Re-exported shared library headers must be included as well since they can help us with type information
-					// about template instantiations (instantiated from their headers).
-					// -isystem headers are not included since for bionic libraries, abi-filtering is taken care of by version
-					// scripts.
-					c.sabi.Properties.ReexportedIncludes = append(
-						c.sabi.Properties.ReexportedIncludes, i.exportedDirs()...)
+					if t.ReexportFlags {
+						reexportExporter(i)
+						// Add these re-exported flags to help header-abi-dumper to infer the abi exported by a library.
+						// Re-exported shared library headers must be included as well since they can help us with type information
+						// about template instantiations (instantiated from their headers).
+						// -isystem headers are not included since for bionic libraries, abi-filtering is taken care of by version
+						// scripts.
+						c.sabi.Properties.ReexportedIncludes = append(
+							c.sabi.Properties.ReexportedIncludes, i.exportedDirs().Strings()...)
+					}
 				}
 			}
-
 			checkLinkType(ctx, c, ccDep, t)
 		}
 
 		var ptr *android.Paths
 		var depPtr *android.Paths
 
-		linkFile := ccDep.outputFile
+		linkFile := ccDep.OutputFile()
 		depFile := android.OptionalPath{}
 
 		switch depTag {
-		case ndkStubDepTag, sharedDepTag, sharedExportDepTag:
+		case ndkStubDepTag, SharedDepTag, sharedExportDepTag:
 			ptr = &depPaths.SharedLibs
 			depPtr = &depPaths.SharedLibsDeps
-			depFile = ccDep.linker.(libraryInterface).toc()
+			depFile = ccDep.Toc()
 			directSharedDeps = append(directSharedDeps, ccDep)
+
 		case earlySharedDepTag:
 			ptr = &depPaths.EarlySharedLibs
 			depPtr = &depPaths.EarlySharedLibsDeps
-			depFile = ccDep.linker.(libraryInterface).toc()
+			depFile = ccDep.Toc()
 			directSharedDeps = append(directSharedDeps, ccDep)
 		case lateSharedDepTag, ndkLateStubDepTag:
 			ptr = &depPaths.LateSharedLibs
 			depPtr = &depPaths.LateSharedLibsDeps
-			depFile = ccDep.linker.(libraryInterface).toc()
-		case staticDepTag, staticExportDepTag:
+			depFile = ccDep.Toc()
+		case StaticDepTag, staticExportDepTag:
 			ptr = nil
 			directStaticDeps = append(directStaticDeps, ccDep)
 		case lateStaticDepTag:
 			ptr = &depPaths.LateStaticLibs
 		case wholeStaticDepTag:
 			ptr = &depPaths.WholeStaticLibs
-			staticLib, ok := ccDep.linker.(libraryInterface)
-			if !ok || !staticLib.static() {
+			if !ccDep.CcLibraryInterface() || !ccDep.Static() {
 				ctx.ModuleErrorf("module %q not a static library", depName)
 				return
 			}
 
-			if missingDeps := staticLib.getWholeStaticMissingDeps(); missingDeps != nil {
-				postfix := " (required by " + ctx.OtherModuleName(dep) + ")"
-				for i := range missingDeps {
-					missingDeps[i] += postfix
+			// Because the static library objects are included, this only makes sense
+			// in the context of proper cc.Modules.
+			if ccWholeStaticLib, ok := ccDep.(*Module); ok {
+				staticLib := ccWholeStaticLib.linker.(libraryInterface)
+				if missingDeps := staticLib.getWholeStaticMissingDeps(); missingDeps != nil {
+					postfix := " (required by " + ctx.OtherModuleName(dep) + ")"
+					for i := range missingDeps {
+						missingDeps[i] += postfix
+					}
+					ctx.AddMissingDependencies(missingDeps)
 				}
-				ctx.AddMissingDependencies(missingDeps)
+				depPaths.WholeStaticLibObjs = depPaths.WholeStaticLibObjs.Append(staticLib.objs())
+			} else {
+				ctx.ModuleErrorf(
+					"non-cc.Modules cannot be included as whole static libraries.", depName)
+				return
 			}
-			depPaths.WholeStaticLibObjs = depPaths.WholeStaticLibObjs.Append(staticLib.objs())
 		case headerDepTag:
 			// Nothing
 		case objDepTag:
 			depPaths.Objs.objFiles = append(depPaths.Objs.objFiles, linkFile.Path())
-		case crtBeginDepTag:
+		case CrtBeginDepTag:
 			depPaths.CrtBegin = linkFile
-		case crtEndDepTag:
+		case CrtEndDepTag:
 			depPaths.CrtEnd = linkFile
 		case dynamicLinkerDepTag:
 			depPaths.DynamicLinker = linkFile
 		}
 
 		switch depTag {
-		case staticDepTag, staticExportDepTag, lateStaticDepTag:
-			staticLib, ok := ccDep.linker.(libraryInterface)
-			if !ok || !staticLib.static() {
+		case StaticDepTag, staticExportDepTag, lateStaticDepTag:
+			if !ccDep.CcLibraryInterface() || !ccDep.Static() {
 				ctx.ModuleErrorf("module %q not a static library", depName)
 				return
 			}
@@ -1924,11 +2138,14 @@
 			// When combining coverage files for shared libraries and executables, coverage files
 			// in static libraries act as if they were whole static libraries. The same goes for
 			// source based Abi dump files.
-			depPaths.StaticLibObjs.coverageFiles = append(depPaths.StaticLibObjs.coverageFiles,
-				staticLib.objs().coverageFiles...)
-			depPaths.StaticLibObjs.sAbiDumpFiles = append(depPaths.StaticLibObjs.sAbiDumpFiles,
-				staticLib.objs().sAbiDumpFiles...)
-
+			// This should only be done for cc.Modules
+			if c, ok := ccDep.(*Module); ok {
+				staticLib := c.linker.(libraryInterface)
+				depPaths.StaticLibObjs.coverageFiles = append(depPaths.StaticLibObjs.coverageFiles,
+					staticLib.objs().coverageFiles...)
+				depPaths.StaticLibObjs.sAbiDumpFiles = append(depPaths.StaticLibObjs.sAbiDumpFiles,
+					staticLib.objs().sAbiDumpFiles...)
+			}
 		}
 
 		if ptr != nil {
@@ -1955,15 +2172,15 @@
 			libName := strings.TrimSuffix(depName, llndkLibrarySuffix)
 			libName = strings.TrimSuffix(libName, vendorPublicLibrarySuffix)
 			libName = strings.TrimPrefix(libName, "prebuilt_")
-			isLLndk := inList(libName, *llndkLibraries)
+			isLLndk := isLlndkLibrary(libName, ctx.Config())
 			isVendorPublicLib := inList(libName, *vendorPublicLibraries)
-			bothVendorAndCoreVariantsExist := ccDep.hasVendorVariant() || isLLndk
+			bothVendorAndCoreVariantsExist := ccDep.HasVendorVariant() || isLLndk
 
-			if ctx.DeviceConfig().VndkUseCoreVariant() && ccDep.isVndk() && !ccDep.mustUseVendorVariant() && !c.inRecovery() {
+			if ctx.DeviceConfig().VndkUseCoreVariant() && ccDep.IsVndk() && !ccDep.MustUseVendorVariant() && !c.InRecovery() {
 				// The vendor module is a no-vendor-variant VNDK library.  Depend on the
 				// core module instead.
 				return libName
-			} else if c.useVndk() && bothVendorAndCoreVariantsExist {
+			} else if c.UseVndk() && bothVendorAndCoreVariantsExist {
 				// The vendor module in Make will have been renamed to not conflict with the core
 				// module, so update the dependency name here accordingly.
 				ret := libName + vendorSuffix
@@ -1977,9 +2194,9 @@
 				return ret
 			} else if (ctx.Platform() || ctx.ProductSpecific()) && isVendorPublicLib {
 				return libName + vendorPublicLibrarySuffix
-			} else if ccDep.inRecovery() && !ccDep.onlyInRecovery() {
+			} else if ccDep.InRecovery() && !ccDep.OnlyInRecovery() {
 				return libName + recoverySuffix
-			} else if ccDep.Target().NativeBridge == android.NativeBridgeEnabled {
+			} else if ccDep.Module().Target().NativeBridge == android.NativeBridgeEnabled {
 				return libName + nativeBridgeSuffix
 			} else {
 				return libName
@@ -1988,9 +2205,9 @@
 
 		// Export the shared libs to Make.
 		switch depTag {
-		case sharedDepTag, sharedExportDepTag, lateSharedDepTag, earlySharedDepTag:
-			if dependentLibrary, ok := ccDep.linker.(*libraryDecorator); ok {
-				if dependentLibrary.buildStubs() && android.InAnyApex(depName) {
+		case SharedDepTag, sharedExportDepTag, lateSharedDepTag, earlySharedDepTag:
+			if ccDep.CcLibrary() {
+				if ccDep.BuildStubs() && android.InAnyApex(depName) {
 					// Add the dependency to the APEX(es) providing the library so that
 					// m <module> can trigger building the APEXes as well.
 					for _, an := range android.GetApexesForModule(depName) {
@@ -2005,11 +2222,10 @@
 			c.Properties.AndroidMkSharedLibs = append(
 				c.Properties.AndroidMkSharedLibs, makeLibName(depName))
 		case ndkStubDepTag, ndkLateStubDepTag:
-			ndkStub := ccDep.linker.(*stubDecorator)
 			c.Properties.AndroidMkSharedLibs = append(
 				c.Properties.AndroidMkSharedLibs,
-				depName+"."+ndkStub.properties.ApiLevel)
-		case staticDepTag, staticExportDepTag, lateStaticDepTag:
+				depName+"."+ccDep.ApiLevel())
+		case StaticDepTag, staticExportDepTag, lateStaticDepTag:
 			c.Properties.AndroidMkStaticLibs = append(
 				c.Properties.AndroidMkStaticLibs, makeLibName(depName))
 		case runtimeDepTag:
@@ -2026,11 +2242,11 @@
 
 	// Dedup exported flags from dependencies
 	depPaths.Flags = android.FirstUniqueStrings(depPaths.Flags)
-	depPaths.IncludeDirs = android.FirstUniqueStrings(depPaths.IncludeDirs)
-	depPaths.SystemIncludeDirs = android.FirstUniqueStrings(depPaths.SystemIncludeDirs)
+	depPaths.IncludeDirs = android.FirstUniquePaths(depPaths.IncludeDirs)
+	depPaths.SystemIncludeDirs = android.FirstUniquePaths(depPaths.SystemIncludeDirs)
 	depPaths.GeneratedHeaders = android.FirstUniquePaths(depPaths.GeneratedHeaders)
-	depPaths.ReexportedDirs = android.FirstUniqueStrings(depPaths.ReexportedDirs)
-	depPaths.ReexportedSystemDirs = android.FirstUniqueStrings(depPaths.ReexportedSystemDirs)
+	depPaths.ReexportedDirs = android.FirstUniquePaths(depPaths.ReexportedDirs)
+	depPaths.ReexportedSystemDirs = android.FirstUniquePaths(depPaths.ReexportedSystemDirs)
 	depPaths.ReexportedFlags = android.FirstUniqueStrings(depPaths.ReexportedFlags)
 	depPaths.ReexportedDeps = android.FirstUniquePaths(depPaths.ReexportedDeps)
 
@@ -2059,7 +2275,7 @@
 }
 
 func (c *Module) InstallInRecovery() bool {
-	return c.inRecovery()
+	return c.InRecovery()
 }
 
 func (c *Module) HostToolPath() android.OptionalPath {
@@ -2113,29 +2329,28 @@
 }
 
 func (c *Module) getMakeLinkType(actx android.ModuleContext) string {
-	name := actx.ModuleName()
-	if c.useVndk() {
+	if c.UseVndk() {
 		if lib, ok := c.linker.(*llndkStubDecorator); ok {
 			if Bool(lib.Properties.Vendor_available) {
 				return "native:vndk"
 			}
 			return "native:vndk_private"
 		}
-		if c.isVndk() && !c.isVndkExt() {
+		if c.IsVndk() && !c.isVndkExt() {
 			if Bool(c.VendorProperties.Vendor_available) {
 				return "native:vndk"
 			}
 			return "native:vndk_private"
 		}
 		return "native:vendor"
-	} else if c.inRecovery() {
+	} else if c.InRecovery() {
 		return "native:recovery"
 	} else if c.Target().Os == android.Android && String(c.Properties.Sdk_version) != "" {
 		return "native:ndk:none:none"
 		// TODO(b/114741097): use the correct ndk stl once build errors have been fixed
 		//family, link := getNdkStlFamilyAndLinkType(c)
 		//return fmt.Sprintf("native:ndk:%s:%s", family, link)
-	} else if inList(name, *vndkUsingCoreVariantLibraries(actx.Config())) {
+	} else if actx.DeviceConfig().VndkUseCoreVariant() && !c.MustUseVendorVariant() {
 		return "native:platform_vndk"
 	} else {
 		return "native:platform"
@@ -2148,7 +2363,9 @@
 	if shared, ok := c.linker.(interface {
 		shared() bool
 	}); ok {
-		return shared.shared()
+		// Stub libs and prebuilt libs in a versioned SDK are not
+		// installable to APEX even though they are shared libs.
+		return shared.shared() && !c.IsStubs() && c.ContainingSdk().Unversioned()
 	} else if _, ok := c.linker.(testPerSrc); ok {
 		return true
 	}
@@ -2170,9 +2387,9 @@
 }
 
 func (c *Module) imageVariation() string {
-	if c.useVndk() {
+	if c.UseVndk() {
 		return vendorMode + "." + c.Properties.VndkVersion
-	} else if c.inRecovery() {
+	} else if c.InRecovery() {
 		return recoveryMode
 	}
 	return coreMode
@@ -2195,8 +2412,8 @@
 }
 
 func (c *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
-	if depTag, ok := ctx.OtherModuleDependencyTag(dep).(dependencyTag); ok {
-		if cc, ok := dep.(*Module); ok && cc.IsStubs() && depTag.shared {
+	if depTag, ok := ctx.OtherModuleDependencyTag(dep).(DependencyTag); ok {
+		if cc, ok := dep.(*Module); ok && cc.IsStubs() && depTag.Shared {
 			// dynamic dep to a stubs lib crosses APEX boundary
 			return false
 		}
@@ -2347,8 +2564,16 @@
 		}
 	}
 
+	//TODO When LinkableInterface supports VNDK, this should be mctx.Module().(LinkableInterface)
 	m, ok := mctx.Module().(*Module)
 	if !ok {
+		if linkable, ok := mctx.Module().(LinkableInterface); ok {
+			variations := []string{coreMode}
+			if linkable.InRecovery() {
+				variations = append(variations, recoveryMode)
+			}
+			mctx.CreateVariations(variations...)
+		}
 		return
 	}
 
@@ -2438,12 +2663,16 @@
 		// Make vendor variants only for the versions in BOARD_VNDK_VERSION and
 		// PRODUCT_EXTRA_VNDK_VERSIONS.
 		vendorVariants = append(vendorVariants, lib.version())
-	} else if m.hasVendorVariant() && !vendorSpecific {
+	} else if m.HasVendorVariant() && !vendorSpecific {
 		// This will be available in both /system and /vendor
 		// or a /system directory that is available to vendor.
 		coreVariantNeeded = true
 		vendorVariants = append(vendorVariants, platformVndkVersion)
-		if m.isVndk() {
+		// VNDK modules must not create BOARD_VNDK_VERSION variant because its
+		// code is PLATFORM_VNDK_VERSION.
+		// On the other hand, vendor_available modules which are not VNDK should
+		// also build BOARD_VNDK_VERSION because it's installed in /vendor.
+		if !m.IsVndk() {
 			vendorVariants = append(vendorVariants, deviceVndkVersion)
 		}
 	} else if vendorSpecific && String(m.Properties.Sdk_version) == "" {
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 0649c2d..0cbdd52 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -213,7 +213,7 @@
 	t.Helper()
 
 	mod := ctx.ModuleForTests(name, vendorVariant).Module().(*Module)
-	if !mod.hasVendorVariant() {
+	if !mod.HasVendorVariant() {
 		t.Errorf("%q must have vendor variant", name)
 	}
 
@@ -230,8 +230,8 @@
 	if mod.vndkdep == nil {
 		t.Fatalf("%q must have `vndkdep`", name)
 	}
-	if !mod.isVndk() {
-		t.Errorf("%q isVndk() must equal to true", name)
+	if !mod.IsVndk() {
+		t.Errorf("%q IsVndk() must equal to true", name)
 	}
 	if mod.isVndkSp() != isVndkSp {
 		t.Errorf("%q isVndkSp() must equal to %t", name, isVndkSp)
@@ -248,22 +248,47 @@
 	}
 }
 
-func checkVndkSnapshot(t *testing.T, ctx *android.TestContext, name, subDir, variant string) {
+func checkVndkSnapshot(t *testing.T, ctx *android.TestContext, moduleName, snapshotFilename, subDir, variant string) {
 	vndkSnapshot := ctx.SingletonForTests("vndk-snapshot")
 
-	snapshotPath := filepath.Join(subDir, name+".so")
-	mod := ctx.ModuleForTests(name, variant).Module().(*Module)
-	if !mod.outputFile.Valid() {
-		t.Errorf("%q must have output\n", name)
+	mod, ok := ctx.ModuleForTests(moduleName, variant).Module().(android.OutputFileProducer)
+	if !ok {
+		t.Errorf("%q must have output\n", moduleName)
 		return
 	}
+	outputFiles, err := mod.OutputFiles("")
+	if err != nil || len(outputFiles) != 1 {
+		t.Errorf("%q must have single output\n", moduleName)
+		return
+	}
+	snapshotPath := filepath.Join(subDir, snapshotFilename)
 
 	out := vndkSnapshot.Output(snapshotPath)
-	if out.Input != mod.outputFile.Path() {
-		t.Errorf("The input of VNDK snapshot must be %q, but %q", out.Input.String(), mod.outputFile.String())
+	if out.Input.String() != outputFiles[0].String() {
+		t.Errorf("The input of VNDK snapshot must be %q, but %q", out.Input.String(), outputFiles[0])
 	}
 }
 
+func checkWriteFileOutput(t *testing.T, params android.TestingBuildParams, expected []string) {
+	t.Helper()
+	assertString(t, params.Rule.String(), android.WriteFile.String())
+	actual := strings.FieldsFunc(strings.ReplaceAll(params.Args["content"], "\\n", "\n"), func(r rune) bool { return r == '\n' })
+	assertArrayString(t, actual, expected)
+}
+
+func checkVndkOutput(t *testing.T, ctx *android.TestContext, output string, expected []string) {
+	t.Helper()
+	vndkSnapshot := ctx.SingletonForTests("vndk-snapshot")
+	checkWriteFileOutput(t, vndkSnapshot.Output(output), expected)
+}
+
+func checkVndkLibrariesOutput(t *testing.T, ctx *android.TestContext, module string, expected []string) {
+	t.Helper()
+	vndkLibraries := ctx.ModuleForTests(module, "")
+	output := insertVndkVersion(module, "VER")
+	checkWriteFileOutput(t, vndkLibraries.Output(output), expected)
+}
+
 func TestVndk(t *testing.T) {
 	config := android.TestArchConfig(buildDir, nil)
 	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
@@ -286,6 +311,7 @@
 				enabled: true,
 			},
 			nocrt: true,
+			stem: "libvndk-private",
 		}
 
 		cc_library {
@@ -296,6 +322,7 @@
 				support_system_process: true,
 			},
 			nocrt: true,
+			suffix: "-x",
 		}
 
 		cc_library {
@@ -306,6 +333,26 @@
 				support_system_process: true,
 			},
 			nocrt: true,
+			target: {
+				vendor: {
+					suffix: "-x",
+				},
+			},
+		}
+		vndk_libraries_txt {
+			name: "llndk.libraries.txt",
+		}
+		vndk_libraries_txt {
+			name: "vndkcore.libraries.txt",
+		}
+		vndk_libraries_txt {
+			name: "vndksp.libraries.txt",
+		}
+		vndk_libraries_txt {
+			name: "vndkprivate.libraries.txt",
+		}
+		vndk_libraries_txt {
+			name: "vndkcorevariant.libraries.txt",
 		}
 	`, config)
 
@@ -332,10 +379,118 @@
 	variant := "android_arm64_armv8-a_vendor.VER_shared"
 	variant2nd := "android_arm_armv7-a-neon_vendor.VER_shared"
 
-	checkVndkSnapshot(t, ctx, "libvndk", vndkCoreLibPath, variant)
-	checkVndkSnapshot(t, ctx, "libvndk", vndkCoreLib2ndPath, variant2nd)
-	checkVndkSnapshot(t, ctx, "libvndk_sp", vndkSpLibPath, variant)
-	checkVndkSnapshot(t, ctx, "libvndk_sp", vndkSpLib2ndPath, variant2nd)
+	checkVndkSnapshot(t, ctx, "libvndk", "libvndk.so", vndkCoreLibPath, variant)
+	checkVndkSnapshot(t, ctx, "libvndk", "libvndk.so", vndkCoreLib2ndPath, variant2nd)
+	checkVndkSnapshot(t, ctx, "libvndk_sp", "libvndk_sp-x.so", vndkSpLibPath, variant)
+	checkVndkSnapshot(t, ctx, "libvndk_sp", "libvndk_sp-x.so", vndkSpLib2ndPath, variant2nd)
+
+	snapshotConfigsPath := filepath.Join(snapshotVariantPath, "configs")
+	checkVndkSnapshot(t, ctx, "llndk.libraries.txt", "llndk.libraries.txt", snapshotConfigsPath, "")
+	checkVndkSnapshot(t, ctx, "vndkcore.libraries.txt", "vndkcore.libraries.txt", snapshotConfigsPath, "")
+	checkVndkSnapshot(t, ctx, "vndksp.libraries.txt", "vndksp.libraries.txt", snapshotConfigsPath, "")
+	checkVndkSnapshot(t, ctx, "vndkprivate.libraries.txt", "vndkprivate.libraries.txt", snapshotConfigsPath, "")
+
+	checkVndkOutput(t, ctx, "vndk/vndk.libraries.txt", []string{
+		"LLNDK: libc.so",
+		"LLNDK: libdl.so",
+		"LLNDK: libft2.so",
+		"LLNDK: libm.so",
+		"VNDK-SP: libc++.so",
+		"VNDK-SP: libvndk_sp-x.so",
+		"VNDK-SP: libvndk_sp_private-x.so",
+		"VNDK-core: libvndk-private.so",
+		"VNDK-core: libvndk.so",
+		"VNDK-private: libft2.so",
+		"VNDK-private: libvndk-private.so",
+		"VNDK-private: libvndk_sp_private-x.so",
+	})
+	checkVndkLibrariesOutput(t, ctx, "llndk.libraries.txt", []string{"libc.so", "libdl.so", "libft2.so", "libm.so"})
+	checkVndkLibrariesOutput(t, ctx, "vndkcore.libraries.txt", []string{"libvndk-private.so", "libvndk.so"})
+	checkVndkLibrariesOutput(t, ctx, "vndkprivate.libraries.txt", []string{"libft2.so", "libvndk-private.so", "libvndk_sp_private-x.so"})
+	checkVndkLibrariesOutput(t, ctx, "vndksp.libraries.txt", []string{"libc++.so", "libvndk_sp-x.so", "libvndk_sp_private-x.so"})
+	checkVndkLibrariesOutput(t, ctx, "vndkcorevariant.libraries.txt", nil)
+}
+
+func TestVndkLibrariesTxtAndroidMk(t *testing.T) {
+	config := android.TestArchConfig(buildDir, nil)
+	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	ctx := testCcWithConfig(t, `
+		vndk_libraries_txt {
+			name: "llndk.libraries.txt",
+		}`, config)
+
+	module := ctx.ModuleForTests("llndk.libraries.txt", "")
+	entries := android.AndroidMkEntriesForTest(t, config, "", module.Module())
+	assertArrayString(t, entries.EntryMap["LOCAL_MODULE_STEM"], []string{"llndk.libraries.VER.txt"})
+}
+
+func TestVndkUsingCoreVariant(t *testing.T) {
+	config := android.TestArchConfig(buildDir, nil)
+	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	config.TestProductVariables.VndkUseCoreVariant = BoolPtr(true)
+
+	setVndkMustUseVendorVariantListForTest(config, []string{"libvndk"})
+
+	ctx := testCcWithConfig(t, `
+		cc_library {
+			name: "libvndk",
+			vendor_available: true,
+			vndk: {
+				enabled: true,
+			},
+			nocrt: true,
+		}
+
+		cc_library {
+			name: "libvndk_sp",
+			vendor_available: true,
+			vndk: {
+				enabled: true,
+				support_system_process: true,
+			},
+			nocrt: true,
+		}
+
+		cc_library {
+			name: "libvndk2",
+			vendor_available: false,
+			vndk: {
+				enabled: true,
+			},
+			nocrt: true,
+		}
+
+		vndk_libraries_txt {
+			name: "vndkcorevariant.libraries.txt",
+		}
+	`, config)
+
+	checkVndkLibrariesOutput(t, ctx, "vndkcorevariant.libraries.txt", []string{"libc++.so", "libvndk2.so", "libvndk_sp.so"})
+}
+
+func TestVndkWhenVndkVersionIsNotSet(t *testing.T) {
+	ctx := testCcNoVndk(t, `
+		cc_library {
+			name: "libvndk",
+			vendor_available: true,
+			vndk: {
+				enabled: true,
+			},
+			nocrt: true,
+		}
+	`)
+
+	checkVndkOutput(t, ctx, "vndk/vndk.libraries.txt", []string{
+		"LLNDK: libc.so",
+		"LLNDK: libdl.so",
+		"LLNDK: libft2.so",
+		"LLNDK: libm.so",
+		"VNDK-SP: libc++.so",
+		"VNDK-core: libvndk.so",
+		"VNDK-private: libft2.so",
+	})
 }
 
 func TestVndkDepError(t *testing.T) {
@@ -1361,14 +1516,14 @@
 		symbol_file: "",
 	}`, config)
 
-	assertArrayString(t, *vndkCoreLibraries(config),
+	assertMapKeys(t, vndkCoreLibraries(config),
 		[]string{"libvndk", "libvndkprivate"})
-	assertArrayString(t, *vndkSpLibraries(config),
+	assertMapKeys(t, vndkSpLibraries(config),
 		[]string{"libc++", "libvndksp"})
-	assertArrayString(t, *llndkLibraries(config),
-		[]string{"libc", "libdl", "libllndk", "libllndkprivate", "libm"})
-	assertArrayString(t, *vndkPrivateLibraries(config),
-		[]string{"libllndkprivate", "libvndkprivate"})
+	assertMapKeys(t, llndkLibraries(config),
+		[]string{"libc", "libdl", "libft2", "libllndk", "libllndkprivate", "libm"})
+	assertMapKeys(t, vndkPrivateLibraries(config),
+		[]string{"libft2", "libllndkprivate", "libvndkprivate"})
 
 	vendorVariant27 := "android_arm64_armv8-a_vendor.27_shared"
 
@@ -2239,7 +2394,7 @@
 	variant := "android_arm64_armv8-a_core"
 	binModuleRule := ctx.ModuleForTests("static_test", variant).Rule("ld")
 	libFlags := binModuleRule.Args["libFlags"]
-	systemStaticLibs := []string{"libc.a", "libm.a", "libdl.a"}
+	systemStaticLibs := []string{"libc.a", "libm.a"}
 	for _, lib := range systemStaticLibs {
 		if !strings.Contains(libFlags, lib) {
 			t.Errorf("Static lib %q was not found in %q", lib, libFlags)
@@ -2349,6 +2504,11 @@
 	}
 }
 
+func assertMapKeys(t *testing.T, m map[string]string, expected []string) {
+	t.Helper()
+	assertArrayString(t, android.SortedStringKeys(m), expected)
+}
+
 func TestDefaults(t *testing.T) {
 	ctx := testCc(t, `
 		cc_defaults {
diff --git a/cc/cflag_artifacts.go b/cc/cflag_artifacts.go
index 9ed3876..b61f2a8 100644
--- a/cc/cflag_artifacts.go
+++ b/cc/cflag_artifacts.go
@@ -147,8 +147,8 @@
 	ctx.VisitAllModules(func(module android.Module) {
 		if ccModule, ok := module.(*Module); ok {
 			if allowedDir(ctx.ModuleDir(ccModule)) {
-				cflags := ccModule.flags.CFlags
-				cppflags := ccModule.flags.CppFlags
+				cflags := ccModule.flags.Local.CFlags
+				cppflags := ccModule.flags.Local.CppFlags
 				module := fmt.Sprintf("%s:%s (%s)",
 					ctx.BlueprintFile(ccModule),
 					ctx.ModuleName(ccModule),
diff --git a/cc/cmakelists.go b/cc/cmakelists.go
index 7b4f89b..97d21f4 100644
--- a/cc/cmakelists.go
+++ b/cc/cmakelists.go
@@ -162,25 +162,41 @@
 	f.WriteString(")\n")
 
 	// Add all header search path and compiler parameters (-D, -W, -f, -XXXX)
-	f.WriteString("\n# GLOBAL FLAGS:\n")
-	globalParameters := parseCompilerParameters(ccModule.flags.GlobalFlags, ctx, f)
-	translateToCMake(globalParameters, f, true, true)
+	f.WriteString("\n# GLOBAL ALL FLAGS:\n")
+	globalAllParameters := parseCompilerParameters(ccModule.flags.Global.CommonFlags, ctx, f)
+	translateToCMake(globalAllParameters, f, true, true)
 
-	f.WriteString("\n# CFLAGS:\n")
-	cParameters := parseCompilerParameters(ccModule.flags.CFlags, ctx, f)
-	translateToCMake(cParameters, f, true, true)
+	f.WriteString("\n# LOCAL ALL FLAGS:\n")
+	localAllParameters := parseCompilerParameters(ccModule.flags.Local.CommonFlags, ctx, f)
+	translateToCMake(localAllParameters, f, true, true)
 
-	f.WriteString("\n# C ONLY FLAGS:\n")
-	cOnlyParameters := parseCompilerParameters(ccModule.flags.ConlyFlags, ctx, f)
-	translateToCMake(cOnlyParameters, f, true, false)
+	f.WriteString("\n# GLOBAL CFLAGS:\n")
+	globalCParameters := parseCompilerParameters(ccModule.flags.Global.CFlags, ctx, f)
+	translateToCMake(globalCParameters, f, true, true)
 
-	f.WriteString("\n# CPP FLAGS:\n")
-	cppParameters := parseCompilerParameters(ccModule.flags.CppFlags, ctx, f)
-	translateToCMake(cppParameters, f, false, true)
+	f.WriteString("\n# LOCAL CFLAGS:\n")
+	localCParameters := parseCompilerParameters(ccModule.flags.Local.CFlags, ctx, f)
+	translateToCMake(localCParameters, f, true, true)
 
-	f.WriteString("\n# SYSTEM INCLUDE FLAGS:\n")
-	includeParameters := parseCompilerParameters(ccModule.flags.SystemIncludeFlags, ctx, f)
-	translateToCMake(includeParameters, f, true, true)
+	f.WriteString("\n# GLOBAL C ONLY FLAGS:\n")
+	globalConlyParameters := parseCompilerParameters(ccModule.flags.Global.ConlyFlags, ctx, f)
+	translateToCMake(globalConlyParameters, f, true, false)
+
+	f.WriteString("\n# LOCAL C ONLY FLAGS:\n")
+	localConlyParameters := parseCompilerParameters(ccModule.flags.Local.ConlyFlags, ctx, f)
+	translateToCMake(localConlyParameters, f, true, false)
+
+	f.WriteString("\n# GLOBAL CPP FLAGS:\n")
+	globalCppParameters := parseCompilerParameters(ccModule.flags.Global.CppFlags, ctx, f)
+	translateToCMake(globalCppParameters, f, false, true)
+
+	f.WriteString("\n# LOCAL CPP FLAGS:\n")
+	localCppParameters := parseCompilerParameters(ccModule.flags.Local.CppFlags, ctx, f)
+	translateToCMake(localCppParameters, f, false, true)
+
+	f.WriteString("\n# GLOBAL SYSTEM INCLUDE FLAGS:\n")
+	globalIncludeParameters := parseCompilerParameters(ccModule.flags.SystemIncludeFlags, ctx, f)
+	translateToCMake(globalIncludeParameters, f, true, true)
 
 	// Add project executable.
 	f.WriteString(fmt.Sprintf("\nadd_executable(%s ${SOURCE_FILES})\n",
@@ -306,6 +322,20 @@
 	return flag
 }
 
+// Flattens a list of strings potentially containing space characters into a list of string containing no
+// spaces.
+func normalizeParameters(params []string) []string {
+	var flatParams []string
+	for _, s := range params {
+		s = strings.Trim(s, " ")
+		if len(s) == 0 {
+			continue
+		}
+		flatParams = append(flatParams, strings.Split(s, " ")...)
+	}
+	return flatParams
+}
+
 func parseCompilerParameters(params []string, ctx android.SingletonContext, f *os.File) compilerParameters {
 	var compilerParameters = makeCompilerParameters()
 
@@ -313,6 +343,15 @@
 		f.WriteString(fmt.Sprintf("# Raw param [%d] = '%s'\n", i, str))
 	}
 
+	// Soong does not guarantee that each flag will be in an individual string. e.g: The
+	// input received could be:
+	// params = {"-isystem", "path/to/system"}
+	// or it could be
+	// params = {"-isystem path/to/system"}
+	// To normalize the input, we split all strings with the "space" character and consolidate
+	// all tokens into a flattened parameters list
+	params = normalizeParameters(params)
+
 	for i := 0; i < len(params); i++ {
 		param := params[i]
 		if param == "" {
diff --git a/cc/compdb.go b/cc/compdb.go
index ecc67b8..519380f 100644
--- a/cc/compdb.go
+++ b/cc/compdb.go
@@ -152,12 +152,16 @@
 		clangPath = ccPath
 	}
 	args = append(args, clangPath)
-	args = append(args, expandAllVars(ctx, ccModule.flags.GlobalFlags)...)
-	args = append(args, expandAllVars(ctx, ccModule.flags.CFlags)...)
+	args = append(args, expandAllVars(ctx, ccModule.flags.Global.CommonFlags)...)
+	args = append(args, expandAllVars(ctx, ccModule.flags.Local.CommonFlags)...)
+	args = append(args, expandAllVars(ctx, ccModule.flags.Global.CFlags)...)
+	args = append(args, expandAllVars(ctx, ccModule.flags.Local.CFlags)...)
 	if isCpp {
-		args = append(args, expandAllVars(ctx, ccModule.flags.CppFlags)...)
+		args = append(args, expandAllVars(ctx, ccModule.flags.Global.CppFlags)...)
+		args = append(args, expandAllVars(ctx, ccModule.flags.Local.CppFlags)...)
 	} else if !isAsm {
-		args = append(args, expandAllVars(ctx, ccModule.flags.ConlyFlags)...)
+		args = append(args, expandAllVars(ctx, ccModule.flags.Global.ConlyFlags)...)
+		args = append(args, expandAllVars(ctx, ccModule.flags.Local.ConlyFlags)...)
 	}
 	args = append(args, expandAllVars(ctx, ccModule.flags.SystemIncludeFlags)...)
 	args = append(args, src.String())
diff --git a/cc/compiler.go b/cc/compiler.go
index ffb6ad2..bb40a5b 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -265,11 +265,11 @@
 
 	esc := proptools.NinjaAndShellEscapeList
 
-	flags.CFlags = append(flags.CFlags, esc(compiler.Properties.Cflags)...)
-	flags.CppFlags = append(flags.CppFlags, esc(compiler.Properties.Cppflags)...)
-	flags.ConlyFlags = append(flags.ConlyFlags, esc(compiler.Properties.Conlyflags)...)
-	flags.AsFlags = append(flags.AsFlags, esc(compiler.Properties.Asflags)...)
-	flags.YasmFlags = append(flags.YasmFlags, esc(compiler.Properties.Asflags)...)
+	flags.Local.CFlags = append(flags.Local.CFlags, esc(compiler.Properties.Cflags)...)
+	flags.Local.CppFlags = append(flags.Local.CppFlags, esc(compiler.Properties.Cppflags)...)
+	flags.Local.ConlyFlags = append(flags.Local.ConlyFlags, esc(compiler.Properties.Conlyflags)...)
+	flags.Local.AsFlags = append(flags.Local.AsFlags, esc(compiler.Properties.Asflags)...)
+	flags.Local.YasmFlags = append(flags.Local.YasmFlags, esc(compiler.Properties.Asflags)...)
 
 	flags.Yacc = compiler.Properties.Yacc
 
@@ -277,20 +277,20 @@
 	localIncludeDirs := android.PathsForModuleSrc(ctx, compiler.Properties.Local_include_dirs)
 	if len(localIncludeDirs) > 0 {
 		f := includeDirsToFlags(localIncludeDirs)
-		flags.GlobalFlags = append(flags.GlobalFlags, f)
-		flags.YasmFlags = append(flags.YasmFlags, f)
+		flags.Local.CommonFlags = append(flags.Local.CommonFlags, f)
+		flags.Local.YasmFlags = append(flags.Local.YasmFlags, f)
 	}
 	rootIncludeDirs := android.PathsForSource(ctx, compiler.Properties.Include_dirs)
 	if len(rootIncludeDirs) > 0 {
 		f := includeDirsToFlags(rootIncludeDirs)
-		flags.GlobalFlags = append(flags.GlobalFlags, f)
-		flags.YasmFlags = append(flags.YasmFlags, f)
+		flags.Local.CommonFlags = append(flags.Local.CommonFlags, f)
+		flags.Local.YasmFlags = append(flags.Local.YasmFlags, f)
 	}
 
 	if compiler.Properties.Include_build_directory == nil ||
 		*compiler.Properties.Include_build_directory {
-		flags.GlobalFlags = append(flags.GlobalFlags, "-I"+android.PathForModuleSrc(ctx).String())
-		flags.YasmFlags = append(flags.YasmFlags, "-I"+android.PathForModuleSrc(ctx).String())
+		flags.Local.CommonFlags = append(flags.Local.CommonFlags, "-I"+android.PathForModuleSrc(ctx).String())
+		flags.Local.YasmFlags = append(flags.Local.YasmFlags, "-I"+android.PathForModuleSrc(ctx).String())
 	}
 
 	if !(ctx.useSdk() || ctx.useVndk()) || ctx.Host() {
@@ -312,15 +312,17 @@
 	}
 
 	if ctx.useVndk() {
-		flags.GlobalFlags = append(flags.GlobalFlags, "-D__ANDROID_VNDK__")
+		flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_VNDK__")
 	}
 
 	if ctx.inRecovery() {
-		flags.GlobalFlags = append(flags.GlobalFlags, "-D__ANDROID_RECOVERY__")
+		flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_RECOVERY__")
 	}
 
 	if ctx.apexName() != "" {
-		flags.GlobalFlags = append(flags.GlobalFlags, "-D__ANDROID_APEX__="+ctx.apexName())
+		flags.Global.CommonFlags = append(flags.Global.CommonFlags,
+			"-D__ANDROID_APEX__",
+			"-D__ANDROID_APEX_"+makeDefineString(ctx.apexName())+"__")
 	}
 
 	instructionSet := String(compiler.Properties.Instruction_set)
@@ -335,17 +337,17 @@
 	CheckBadCompilerFlags(ctx, "release.cflags", compiler.Properties.Release.Cflags)
 
 	// TODO: debug
-	flags.CFlags = append(flags.CFlags, esc(compiler.Properties.Release.Cflags)...)
+	flags.Local.CFlags = append(flags.Local.CFlags, esc(compiler.Properties.Release.Cflags)...)
 
 	CheckBadCompilerFlags(ctx, "clang_cflags", compiler.Properties.Clang_cflags)
 	CheckBadCompilerFlags(ctx, "clang_asflags", compiler.Properties.Clang_asflags)
 
-	flags.CFlags = config.ClangFilterUnknownCflags(flags.CFlags)
-	flags.CFlags = append(flags.CFlags, esc(compiler.Properties.Clang_cflags)...)
-	flags.AsFlags = append(flags.AsFlags, esc(compiler.Properties.Clang_asflags)...)
-	flags.CppFlags = config.ClangFilterUnknownCflags(flags.CppFlags)
-	flags.ConlyFlags = config.ClangFilterUnknownCflags(flags.ConlyFlags)
-	flags.LdFlags = config.ClangFilterUnknownCflags(flags.LdFlags)
+	flags.Local.CFlags = config.ClangFilterUnknownCflags(flags.Local.CFlags)
+	flags.Local.CFlags = append(flags.Local.CFlags, esc(compiler.Properties.Clang_cflags)...)
+	flags.Local.AsFlags = append(flags.Local.AsFlags, esc(compiler.Properties.Clang_asflags)...)
+	flags.Local.CppFlags = config.ClangFilterUnknownCflags(flags.Local.CppFlags)
+	flags.Local.ConlyFlags = config.ClangFilterUnknownCflags(flags.Local.ConlyFlags)
+	flags.Local.LdFlags = config.ClangFilterUnknownCflags(flags.Local.LdFlags)
 
 	target := "-target " + tc.ClangTriple()
 	if ctx.Os().Class == android.Device {
@@ -359,45 +361,45 @@
 
 	gccPrefix := "-B" + config.ToolPath(tc)
 
-	flags.CFlags = append(flags.CFlags, target, gccPrefix)
-	flags.AsFlags = append(flags.AsFlags, target, gccPrefix)
-	flags.LdFlags = append(flags.LdFlags, target, gccPrefix)
+	flags.Global.CFlags = append(flags.Global.CFlags, target, gccPrefix)
+	flags.Global.AsFlags = append(flags.Global.AsFlags, target, gccPrefix)
+	flags.Global.LdFlags = append(flags.Global.LdFlags, target, gccPrefix)
 
 	hod := "Host"
 	if ctx.Os().Class == android.Device {
 		hod = "Device"
 	}
 
-	flags.GlobalFlags = append(flags.GlobalFlags, instructionSetFlags)
-	flags.ConlyFlags = append([]string{"${config.CommonGlobalConlyflags}"}, flags.ConlyFlags...)
-	flags.CppFlags = append([]string{fmt.Sprintf("${config.%sGlobalCppflags}", hod)}, flags.CppFlags...)
+	flags.Global.CommonFlags = append(flags.Global.CommonFlags, instructionSetFlags)
+	flags.Global.ConlyFlags = append([]string{"${config.CommonGlobalConlyflags}"}, flags.Global.ConlyFlags...)
+	flags.Global.CppFlags = append([]string{fmt.Sprintf("${config.%sGlobalCppflags}", hod)}, flags.Global.CppFlags...)
 
-	flags.AsFlags = append(flags.AsFlags, tc.ClangAsflags())
-	flags.CppFlags = append([]string{"${config.CommonClangGlobalCppflags}"}, flags.CppFlags...)
-	flags.GlobalFlags = append(flags.GlobalFlags,
+	flags.Global.AsFlags = append(flags.Global.AsFlags, tc.ClangAsflags())
+	flags.Global.CppFlags = append([]string{"${config.CommonClangGlobalCppflags}"}, flags.Global.CppFlags...)
+	flags.Global.CommonFlags = append(flags.Global.CommonFlags,
 		tc.ClangCflags(),
 		"${config.CommonClangGlobalCflags}",
 		fmt.Sprintf("${config.%sClangGlobalCflags}", hod))
 
 	if strings.HasPrefix(android.PathForModuleSrc(ctx).String(), "external/") {
-		flags.GlobalFlags = append([]string{"${config.ClangExternalCflags}"}, flags.GlobalFlags...)
+		flags.Global.CommonFlags = append([]string{"${config.ClangExternalCflags}"}, flags.Global.CommonFlags...)
 	}
 
 	if tc.Bionic() {
 		if Bool(compiler.Properties.Rtti) {
-			flags.CppFlags = append(flags.CppFlags, "-frtti")
+			flags.Local.CppFlags = append(flags.Local.CppFlags, "-frtti")
 		} else {
-			flags.CppFlags = append(flags.CppFlags, "-fno-rtti")
+			flags.Local.CppFlags = append(flags.Local.CppFlags, "-fno-rtti")
 		}
 	}
 
-	flags.AsFlags = append(flags.AsFlags, "-D__ASSEMBLY__")
+	flags.Global.AsFlags = append(flags.Global.AsFlags, "-D__ASSEMBLY__")
 
-	flags.CppFlags = append(flags.CppFlags, tc.ClangCppflags())
+	flags.Global.CppFlags = append(flags.Global.CppFlags, tc.ClangCppflags())
 
-	flags.YasmFlags = append(flags.YasmFlags, tc.YasmFlags())
+	flags.Global.YasmFlags = append(flags.Global.YasmFlags, tc.YasmFlags())
 
-	flags.GlobalFlags = append(flags.GlobalFlags, tc.ToolchainClangCflags())
+	flags.Global.CommonFlags = append(flags.Global.CommonFlags, tc.ToolchainClangCflags())
 
 	cStd := config.CStdVersion
 	if String(compiler.Properties.C_std) == "experimental" {
@@ -419,15 +421,15 @@
 		cppStd = gnuToCReplacer.Replace(cppStd)
 	}
 
-	flags.ConlyFlags = append([]string{"-std=" + cStd}, flags.ConlyFlags...)
-	flags.CppFlags = append([]string{"-std=" + cppStd}, flags.CppFlags...)
+	flags.Local.ConlyFlags = append([]string{"-std=" + cStd}, flags.Local.ConlyFlags...)
+	flags.Local.CppFlags = append([]string{"-std=" + cppStd}, flags.Local.CppFlags...)
 
 	if ctx.useVndk() {
-		flags.CFlags = append(flags.CFlags, esc(compiler.Properties.Target.Vendor.Cflags)...)
+		flags.Local.CFlags = append(flags.Local.CFlags, esc(compiler.Properties.Target.Vendor.Cflags)...)
 	}
 
 	if ctx.inRecovery() {
-		flags.CFlags = append(flags.CFlags, esc(compiler.Properties.Target.Recovery.Cflags)...)
+		flags.Local.CFlags = append(flags.Local.CFlags, esc(compiler.Properties.Target.Recovery.Cflags)...)
 	}
 
 	// We can enforce some rules more strictly in the code we own. strict
@@ -443,7 +445,7 @@
 	// Can be used to make some annotations stricter for code we can fix
 	// (such as when we mark functions as deprecated).
 	if strict {
-		flags.CFlags = append(flags.CFlags, "-DANDROID_STRICT")
+		flags.Global.CFlags = append(flags.Global.CFlags, "-DANDROID_STRICT")
 	}
 
 	if compiler.hasSrcExt(".proto") {
@@ -451,12 +453,12 @@
 	}
 
 	if compiler.hasSrcExt(".y") || compiler.hasSrcExt(".yy") {
-		flags.GlobalFlags = append(flags.GlobalFlags,
+		flags.Local.CommonFlags = append(flags.Local.CommonFlags,
 			"-I"+android.PathForModuleGen(ctx, "yacc", ctx.ModuleDir()).String())
 	}
 
 	if compiler.hasSrcExt(".mc") {
-		flags.GlobalFlags = append(flags.GlobalFlags,
+		flags.Local.CommonFlags = append(flags.Local.CommonFlags,
 			"-I"+android.PathForModuleGen(ctx, "windmc", ctx.ModuleDir()).String())
 	}
 
@@ -474,7 +476,7 @@
 			flags.aidlFlags = append(flags.aidlFlags, "-t")
 		}
 
-		flags.GlobalFlags = append(flags.GlobalFlags,
+		flags.Local.CommonFlags = append(flags.Local.CommonFlags,
 			"-I"+android.PathForModuleGen(ctx, "aidl").String())
 	}
 
@@ -483,26 +485,26 @@
 	}
 
 	if compiler.hasSrcExt(".sysprop") {
-		flags.GlobalFlags = append(flags.GlobalFlags,
+		flags.Local.CommonFlags = append(flags.Local.CommonFlags,
 			"-I"+android.PathForModuleGen(ctx, "sysprop", "include").String())
 	}
 
 	if len(compiler.Properties.Srcs) > 0 {
 		module := ctx.ModuleDir() + "/Android.bp:" + ctx.ModuleName()
-		if inList("-Wno-error", flags.CFlags) || inList("-Wno-error", flags.CppFlags) {
+		if inList("-Wno-error", flags.Local.CFlags) || inList("-Wno-error", flags.Local.CppFlags) {
 			addToModuleList(ctx, modulesUsingWnoErrorKey, module)
-		} else if !inList("-Werror", flags.CFlags) && !inList("-Werror", flags.CppFlags) {
+		} else if !inList("-Werror", flags.Local.CFlags) && !inList("-Werror", flags.Local.CppFlags) {
 			if warningsAreAllowed(ctx.ModuleDir()) {
 				addToModuleList(ctx, modulesAddedWallKey, module)
-				flags.CFlags = append([]string{"-Wall"}, flags.CFlags...)
+				flags.Local.CFlags = append([]string{"-Wall"}, flags.Local.CFlags...)
 			} else {
-				flags.CFlags = append([]string{"-Wall", "-Werror"}, flags.CFlags...)
+				flags.Local.CFlags = append([]string{"-Wall", "-Werror"}, flags.Local.CFlags...)
 			}
 		}
 	}
 
 	if Bool(compiler.Properties.Openmp) {
-		flags.CFlags = append(flags.CFlags, "-fopenmp")
+		flags.Local.CFlags = append(flags.Local.CFlags, "-fopenmp")
 	}
 
 	return flags
@@ -528,6 +530,12 @@
 	return false
 }
 
+// makeDefineString transforms a name of an APEX module into a value to be used as value for C define
+// For example, com.android.foo => COM_ANDROID_FOO
+func makeDefineString(name string) string {
+	return strings.ReplaceAll(strings.ToUpper(name), ".", "_")
+}
+
 var gnuToCReplacer = strings.NewReplacer("gnu", "c")
 
 func ndkPathDeps(ctx ModuleContext) android.Paths {
diff --git a/cc/config/clang.go b/cc/config/clang.go
index 71bea42..030a076 100644
--- a/cc/config/clang.go
+++ b/cc/config/clang.go
@@ -101,9 +101,6 @@
 		// not emit the table by default on Android since NDK still uses GNU binutils.
 		"-faddrsig",
 
-		// -Wimplicit-fallthrough is not enabled by -Wall.
-		"-Wimplicit-fallthrough",
-
 		// Help catch common 32/64-bit errors.
 		"-Werror=int-conversion",
 
@@ -138,10 +135,11 @@
 	}, " "))
 
 	pctx.StaticVariable("ClangExtraCppflags", strings.Join([]string{
+		// -Wimplicit-fallthrough is not enabled by -Wall.
+		"-Wimplicit-fallthrough",
+
 		// Enable clang's thread-safety annotations in libcxx.
-		// Turn off -Wthread-safety-negative, to avoid breaking projects that use -Weverything.
 		"-D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS",
-		"-Wno-thread-safety-negative",
 
 		// libc++'s math.h has an #include_next outside of system_headers.
 		"-Wno-gnu-include-next",
diff --git a/cc/coverage.go b/cc/coverage.go
index 2e81a9e..c03a568 100644
--- a/cc/coverage.go
+++ b/cc/coverage.go
@@ -69,12 +69,12 @@
 
 	if cov.Properties.CoverageEnabled {
 		flags.Coverage = true
-		flags.GlobalFlags = append(flags.GlobalFlags, "--coverage", "-O0")
+		flags.Local.CommonFlags = append(flags.Local.CommonFlags, "--coverage", "-O0")
 		cov.linkCoverage = true
 
 		// Override -Wframe-larger-than and non-default optimization
 		// flags that the module may use.
-		flags.CFlags = append(flags.CFlags, "-Wno-frame-larger-than=", "-O0")
+		flags.Local.CFlags = append(flags.Local.CFlags, "-Wno-frame-larger-than=", "-O0")
 	}
 
 	// Even if we don't have coverage enabled, if any of our object files were compiled
@@ -112,12 +112,12 @@
 	}
 
 	if cov.linkCoverage {
-		flags.LdFlags = append(flags.LdFlags, "--coverage")
+		flags.Local.LdFlags = append(flags.Local.LdFlags, "--coverage")
 
 		coverage := ctx.GetDirectDepWithTag(getProfileLibraryName(ctx), coverageDepTag).(*Module)
 		deps.WholeStaticLibs = append(deps.WholeStaticLibs, coverage.OutputFile().Path())
 
-		flags.LdFlags = append(flags.LdFlags, "-Wl,--wrap,getenv")
+		flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--wrap,getenv")
 	}
 
 	return flags, deps
diff --git a/cc/fuzz.go b/cc/fuzz.go
index a99b0bb..1f06fb0 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -15,21 +15,44 @@
 package cc
 
 import (
+	"encoding/json"
 	"path/filepath"
+	"sort"
 	"strings"
 
-	"github.com/google/blueprint/proptools"
-
 	"android/soong/android"
 	"android/soong/cc/config"
 )
 
+type FuzzConfig struct {
+	// Email address of people to CC on bugs or contact about this fuzz target.
+	Cc []string `json:"cc,omitempty"`
+	// Boolean specifying whether to disable the fuzz target from running
+	// automatically in continuous fuzzing infrastructure.
+	Disable *bool `json:"disable,omitempty"`
+	// Component in Google's bug tracking system that bugs should be filed to.
+	Componentid *int64 `json:"componentid,omitempty"`
+	// Hotlists in Google's bug tracking system that bugs should be marked with.
+	Hotlists []string `json:"hotlists,omitempty"`
+}
+
+func (f *FuzzConfig) String() string {
+	b, err := json.Marshal(f)
+	if err != nil {
+		panic(err)
+	}
+
+	return string(b)
+}
+
 type FuzzProperties struct {
 	// Optional list of seed files to be installed to the fuzz target's output
 	// directory.
 	Corpus []string `android:"path"`
 	// Optional dictionary to be installed to the fuzz target's output directory.
 	Dictionary *string `android:"path"`
+	// Config for running the target on fuzzing infrastructure.
+	Fuzz_config *FuzzConfig
 }
 
 func init() {
@@ -57,6 +80,8 @@
 	dictionary            android.Path
 	corpus                android.Paths
 	corpusIntermediateDir android.Path
+	config                android.Path
+	installedSharedDeps   []string
 }
 
 func (fuzz *fuzzBinary) linkerProps() []interface{} {
@@ -66,21 +91,6 @@
 }
 
 func (fuzz *fuzzBinary) linkerInit(ctx BaseModuleContext) {
-	// Add ../lib[64] to rpath so that out/host/linux-x86/fuzz/<fuzzer> can
-	// find out/host/linux-x86/lib[64]/library.so
-	runpaths := []string{"../lib"}
-	for _, runpath := range runpaths {
-		if ctx.toolchain().Is64Bit() {
-			runpath += "64"
-		}
-		fuzz.binaryDecorator.baseLinker.dynamicProperties.RunPaths = append(
-			fuzz.binaryDecorator.baseLinker.dynamicProperties.RunPaths, runpath)
-	}
-
-	// add "" to rpath so that fuzzer binaries can find libraries in their own fuzz directory
-	fuzz.binaryDecorator.baseLinker.dynamicProperties.RunPaths = append(
-		fuzz.binaryDecorator.baseLinker.dynamicProperties.RunPaths, "")
-
 	fuzz.binaryDecorator.linkerInit(ctx)
 }
 
@@ -93,9 +103,80 @@
 
 func (fuzz *fuzzBinary) linkerFlags(ctx ModuleContext, flags Flags) Flags {
 	flags = fuzz.binaryDecorator.linkerFlags(ctx, flags)
+	// RunPaths on devices isn't instantiated by the base linker.
+	flags.Local.LdFlags = append(flags.Local.LdFlags, `-Wl,-rpath,\$$ORIGIN/../lib`)
 	return flags
 }
 
+// This function performs a breadth-first search over the provided module's
+// dependencies using `visitDirectDeps` to enumerate all shared library
+// dependencies. We require breadth-first expansion, as otherwise we may
+// incorrectly use the core libraries (sanitizer runtimes, libc, libdl, etc.)
+// from a dependency. This may cause issues when dependencies have explicit
+// sanitizer tags, as we may get a dependency on an unsanitized libc, etc.
+func collectAllSharedDependencies(
+	module android.Module,
+	sharedDeps map[string]android.Path,
+	ctx android.SingletonContext) {
+	var fringe []android.Module
+
+	// Enumerate the first level of dependencies, as we discard all non-library
+	// modules in the BFS loop below.
+	ctx.VisitDirectDeps(module, func(dep android.Module) {
+		fringe = append(fringe, dep)
+	})
+
+	for i := 0; i < len(fringe); i++ {
+		module := fringe[i]
+		if !isValidSharedDependency(module, sharedDeps) {
+			continue
+		}
+
+		ccModule := module.(*Module)
+		sharedDeps[ccModule.Name()] = ccModule.UnstrippedOutputFile()
+		ctx.VisitDirectDeps(module, func(dep android.Module) {
+			fringe = append(fringe, dep)
+		})
+	}
+}
+
+// This function takes a module and determines if it is a unique shared library
+// that should be installed in the fuzz target output directories. This function
+// returns true, unless:
+//  - The module already exists in `sharedDeps`, or
+//  - The module is not a shared library, or
+//  - The module is a header, stub, or vendor-linked library.
+func isValidSharedDependency(
+	dependency android.Module,
+	sharedDeps map[string]android.Path) bool {
+	// TODO(b/144090547): We should be parsing these modules using
+	// ModuleDependencyTag instead of the current brute-force checking.
+
+	if linkable, ok := dependency.(LinkableInterface); !ok || // Discard non-linkables.
+		!linkable.CcLibraryInterface() || !linkable.Shared() || // Discard static libs.
+		linkable.UseVndk() || // Discard vendor linked libraries.
+		!linkable.CcLibrary() || linkable.BuildStubs() { // Discard stubs libs (only CCLibrary variants).
+		return false
+	}
+
+	// If this library has already been traversed, we don't need to do any more work.
+	if _, exists := sharedDeps[dependency.Name()]; exists {
+		return false
+	}
+	return true
+}
+
+func sharedLibraryInstallLocation(
+	libraryPath android.Path, isHost bool, archString string) string {
+	installLocation := "$(PRODUCT_OUT)/data"
+	if isHost {
+		installLocation = "$(HOST_OUT)"
+	}
+	installLocation = filepath.Join(
+		installLocation, "fuzz", archString, "lib", libraryPath.Base())
+	return installLocation
+}
+
 func (fuzz *fuzzBinary) install(ctx ModuleContext, file android.Path) {
 	fuzz.binaryDecorator.baseInstaller.dir = filepath.Join(
 		"fuzz", ctx.Target().Arch.ArchType.String(), ctx.ModuleName())
@@ -122,6 +203,35 @@
 				fuzz.dictionary.String())
 		}
 	}
+
+	if fuzz.Properties.Fuzz_config != nil {
+		configPath := android.PathForModuleOut(ctx, "config").Join(ctx, "config.json")
+		ctx.Build(pctx, android.BuildParams{
+			Rule:        android.WriteFile,
+			Description: "fuzzer infrastructure configuration",
+			Output:      configPath,
+			Args: map[string]string{
+				"content": fuzz.Properties.Fuzz_config.String(),
+			},
+		})
+		fuzz.config = configPath
+	}
+
+	// Grab the list of required shared libraries.
+	sharedLibraries := make(map[string]android.Path)
+	ctx.WalkDeps(func(child, parent android.Module) bool {
+		if isValidSharedDependency(child, sharedLibraries) {
+			sharedLibraries[child.Name()] = child.(*Module).UnstrippedOutputFile()
+			return true
+		}
+		return false
+	})
+
+	for _, lib := range sharedLibraries {
+		fuzz.installedSharedDeps = append(fuzz.installedSharedDeps,
+			sharedLibraryInstallLocation(
+				lib, ctx.Host(), ctx.Arch().ArchType.String()))
+	}
 }
 
 func NewFuzz(hod android.HostOrDeviceSupported) *Module {
@@ -155,28 +265,15 @@
 		ctx.AppendProperties(&disableDarwinAndLinuxBionic)
 	})
 
-	// Statically link the STL. This allows fuzz target deployment to not have to
-	// include the STL.
-	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
-		staticStlLinkage := struct {
-			Target struct {
-				Linux_glibc struct {
-					Stl *string
-				}
-			}
-		}{}
-
-		staticStlLinkage.Target.Linux_glibc.Stl = proptools.StringPtr("libc++_static")
-		ctx.AppendProperties(&staticStlLinkage)
-	})
-
 	return module
 }
 
 // Responsible for generating GNU Make rules that package fuzz targets into
 // their architecture & target/host specific zip file.
 type fuzzPackager struct {
-	packages android.Paths
+	packages                android.Paths
+	sharedLibInstallStrings []string
+	fuzzTargets             map[string]bool
 }
 
 func fuzzPackagingFactory() android.Singleton {
@@ -188,18 +285,31 @@
 	DestinationPathPrefix string
 }
 
+type archAndLibraryKey struct {
+	ArchDir android.OutputPath
+	Library android.Path
+}
+
 func (s *fuzzPackager) GenerateBuildActions(ctx android.SingletonContext) {
 	// Map between each architecture + host/device combination, and the files that
 	// need to be packaged (in the tuple of {source file, destination folder in
 	// archive}).
 	archDirs := make(map[android.OutputPath][]fileToZip)
 
+	// List of shared library dependencies for each architecture + host/device combo.
+	archSharedLibraryDeps := make(map[archAndLibraryKey]bool)
+
+	// List of individual fuzz targets, so that 'make fuzz' also installs the targets
+	// to the correct output directories as well.
+	s.fuzzTargets = make(map[string]bool)
+
 	ctx.VisitAllModules(func(module android.Module) {
 		// Discard non-fuzz targets.
 		ccModule, ok := module.(*Module)
 		if !ok {
 			return
 		}
+
 		fuzzModule, ok := ccModule.compiler.(*fuzzBinary)
 		if !ok {
 			return
@@ -207,10 +317,12 @@
 
 		// Discard vendor-NDK-linked modules, they're duplicates of fuzz targets
 		// we're going to package anyway.
-		if ccModule.useVndk() || !ccModule.Enabled() {
+		if ccModule.UseVndk() || !ccModule.Enabled() {
 			return
 		}
 
+		s.fuzzTargets[module.Name()] = true
+
 		hostOrTargetString := "target"
 		if ccModule.Host() {
 			hostOrTargetString = "host"
@@ -219,9 +331,32 @@
 		archString := ccModule.Arch().ArchType.String()
 		archDir := android.PathForIntermediates(ctx, "fuzz", hostOrTargetString, archString)
 
+		// Grab the list of required shared libraries.
+		sharedLibraries := make(map[string]android.Path)
+		collectAllSharedDependencies(module, sharedLibraries, ctx)
+
+		for _, library := range sharedLibraries {
+			if _, exists := archSharedLibraryDeps[archAndLibraryKey{archDir, library}]; exists {
+				continue
+			}
+
+			// For each architecture-specific shared library dependency, we need to
+			// install it to the output directory. Setup the install destination here,
+			// which will be used by $(copy-many-files) in the Make backend.
+			archSharedLibraryDeps[archAndLibraryKey{archDir, library}] = true
+			installDestination := sharedLibraryInstallLocation(
+				library, ccModule.Host(), archString)
+			// Escape all the variables, as the install destination here will be called
+			// via. $(eval) in Make.
+			installDestination = strings.ReplaceAll(
+				installDestination, "$", "$$")
+			s.sharedLibInstallStrings = append(s.sharedLibInstallStrings,
+				library.String()+":"+installDestination)
+		}
+
 		// The executable.
 		archDirs[archDir] = append(archDirs[archDir],
-			fileToZip{ccModule.outputFile.Path(), ccModule.Name()})
+			fileToZip{ccModule.UnstrippedOutputFile(), ccModule.Name()})
 
 		// The corpora.
 		for _, corpusEntry := range fuzzModule.corpus {
@@ -234,8 +369,20 @@
 			archDirs[archDir] = append(archDirs[archDir],
 				fileToZip{fuzzModule.dictionary, ccModule.Name()})
 		}
+
+		// Additional fuzz config.
+		if fuzzModule.config != nil {
+			archDirs[archDir] = append(archDirs[archDir],
+				fileToZip{fuzzModule.config, ccModule.Name()})
+		}
 	})
 
+	// Add the shared library deps for packaging.
+	for key, _ := range archSharedLibraryDeps {
+		archDirs[key.ArchDir] = append(archDirs[key.ArchDir],
+			fileToZip{key.Library, "lib"})
+	}
+
 	for archDir, filesToZip := range archDirs {
 		arch := archDir.Base()
 		hostOrTarget := filepath.Base(filepath.Dir(archDir.String()))
@@ -258,9 +405,22 @@
 }
 
 func (s *fuzzPackager) MakeVars(ctx android.MakeVarsContext) {
+	packages := s.packages.Strings()
+	sort.Strings(packages)
+	sort.Strings(s.sharedLibInstallStrings)
 	// TODO(mitchp): Migrate this to use MakeVarsContext::DistForGoal() when it's
 	// ready to handle phony targets created in Soong. In the meantime, this
 	// exports the phony 'fuzz' target and dependencies on packages to
 	// core/main.mk so that we can use dist-for-goals.
-	ctx.Strict("SOONG_FUZZ_PACKAGING_ARCH_MODULES", strings.Join(s.packages.Strings(), " "))
+	ctx.Strict("SOONG_FUZZ_PACKAGING_ARCH_MODULES", strings.Join(packages, " "))
+	ctx.Strict("FUZZ_TARGET_SHARED_DEPS_INSTALL_PAIRS",
+		strings.Join(s.sharedLibInstallStrings, " "))
+
+	// Preallocate the slice of fuzz targets to minimise memory allocations.
+	fuzzTargets := make([]string, 0, len(s.fuzzTargets))
+	for target, _ := range s.fuzzTargets {
+		fuzzTargets = append(fuzzTargets, target)
+	}
+	sort.Strings(fuzzTargets)
+	ctx.Strict("ALL_FUZZ_TARGETS", strings.Join(fuzzTargets, " "))
 }
diff --git a/cc/gen_test.go b/cc/gen_test.go
index da3b4e8..ceecf1c 100644
--- a/cc/gen_test.go
+++ b/cc/gen_test.go
@@ -34,7 +34,7 @@
 		aidl := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_core_shared").Rule("aidl")
 		libfoo := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_core_shared").Module().(*Module)
 
-		if !inList("-I"+filepath.Dir(aidl.Output.String()), libfoo.flags.GlobalFlags) {
+		if !inList("-I"+filepath.Dir(aidl.Output.String()), libfoo.flags.Local.CommonFlags) {
 			t.Errorf("missing aidl includes in global flags")
 		}
 	})
@@ -58,7 +58,7 @@
 		aidl := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_core_shared").Rule("aidl")
 		libfoo := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_core_shared").Module().(*Module)
 
-		if !inList("-I"+filepath.Dir(aidl.Output.String()), libfoo.flags.GlobalFlags) {
+		if !inList("-I"+filepath.Dir(aidl.Output.String()), libfoo.flags.Local.CommonFlags) {
 			t.Errorf("missing aidl includes in global flags")
 		}
 
diff --git a/cc/kernel_headers.go b/cc/kernel_headers.go
index fff419e..796de62 100644
--- a/cc/kernel_headers.go
+++ b/cc/kernel_headers.go
@@ -25,7 +25,7 @@
 func (stub *kernelHeadersDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path {
 	if ctx.Device() {
 		f := &stub.libraryDecorator.flagExporter
-		f.reexportSystemDirs(ctx.DeviceConfig().DeviceKernelHeaderDirs()...)
+		f.reexportSystemDirs(android.PathsForSource(ctx, ctx.DeviceConfig().DeviceKernelHeaderDirs())...)
 	}
 	return stub.libraryDecorator.linkStatic(ctx, flags, deps, objs)
 }
diff --git a/cc/library.go b/cc/library.go
index 829c617..dde067c 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -158,6 +158,10 @@
 	// listed in local_include_dirs.
 	Export_include_dirs []string `android:"arch_variant"`
 
+	// list of directories that will be added to the system include path
+	// using -isystem for this module and any module that links against this module.
+	Export_system_include_dirs []string `android:"arch_variant"`
+
 	Target struct {
 		Vendor struct {
 			// list of exported include directories, like
@@ -229,8 +233,8 @@
 type flagExporter struct {
 	Properties FlagExporterProperties
 
-	dirs       []string
-	systemDirs []string
+	dirs       android.Paths
+	systemDirs android.Paths
 	flags      []string
 	deps       android.Paths
 }
@@ -244,18 +248,21 @@
 }
 
 func (f *flagExporter) exportIncludes(ctx ModuleContext) {
-	f.dirs = append(f.dirs, f.exportedIncludes(ctx).Strings()...)
+	f.dirs = append(f.dirs, f.exportedIncludes(ctx)...)
+	f.systemDirs = append(f.systemDirs, android.PathsForModuleSrc(ctx, f.Properties.Export_system_include_dirs)...)
 }
 
 func (f *flagExporter) exportIncludesAsSystem(ctx ModuleContext) {
-	f.systemDirs = append(f.systemDirs, f.exportedIncludes(ctx).Strings()...)
+	// all dirs are force exported as system
+	f.systemDirs = append(f.systemDirs, f.exportedIncludes(ctx)...)
+	f.systemDirs = append(f.systemDirs, android.PathsForModuleSrc(ctx, f.Properties.Export_system_include_dirs)...)
 }
 
-func (f *flagExporter) reexportDirs(dirs ...string) {
+func (f *flagExporter) reexportDirs(dirs ...android.Path) {
 	f.dirs = append(f.dirs, dirs...)
 }
 
-func (f *flagExporter) reexportSystemDirs(dirs ...string) {
+func (f *flagExporter) reexportSystemDirs(dirs ...android.Path) {
 	f.systemDirs = append(f.systemDirs, dirs...)
 }
 
@@ -273,11 +280,11 @@
 	f.deps = append(f.deps, deps...)
 }
 
-func (f *flagExporter) exportedDirs() []string {
+func (f *flagExporter) exportedDirs() android.Paths {
 	return f.dirs
 }
 
-func (f *flagExporter) exportedSystemDirs() []string {
+func (f *flagExporter) exportedSystemDirs() android.Paths {
 	return f.systemDirs
 }
 
@@ -290,8 +297,8 @@
 }
 
 type exportedFlagsProducer interface {
-	exportedDirs() []string
-	exportedSystemDirs() []string
+	exportedDirs() android.Paths
+	exportedSystemDirs() android.Paths
 	exportedFlags() []string
 	exportedDeps() android.Paths
 }
@@ -387,13 +394,13 @@
 	// all code is position independent, and then those warnings get promoted to
 	// errors.
 	if !ctx.Windows() {
-		flags.CFlags = append(flags.CFlags, "-fPIC")
+		flags.Global.CFlags = append(flags.Global.CFlags, "-fPIC")
 	}
 
 	if library.static() {
-		flags.CFlags = append(flags.CFlags, library.StaticProperties.Static.Cflags...)
+		flags.Local.CFlags = append(flags.Local.CFlags, library.StaticProperties.Static.Cflags...)
 	} else if library.shared() {
-		flags.CFlags = append(flags.CFlags, library.SharedProperties.Shared.Cflags...)
+		flags.Local.CFlags = append(flags.Local.CFlags, library.SharedProperties.Shared.Cflags...)
 	}
 
 	if library.shared() {
@@ -424,7 +431,7 @@
 			}
 		}
 
-		flags.LdFlags = append(f, flags.LdFlags...)
+		flags.Global.LdFlags = append(flags.Global.LdFlags, f...)
 	}
 
 	return flags
@@ -434,8 +441,8 @@
 	exportIncludeDirs := library.flagExporter.exportedIncludes(ctx)
 	if len(exportIncludeDirs) > 0 {
 		f := includeDirsToFlags(exportIncludeDirs)
-		flags.GlobalFlags = append(flags.GlobalFlags, f)
-		flags.YasmFlags = append(flags.YasmFlags, f)
+		flags.Local.CommonFlags = append(flags.Local.CommonFlags, f)
+		flags.Local.YasmFlags = append(flags.Local.YasmFlags, f)
 	}
 
 	flags = library.baseCompiler.compilerFlags(ctx, flags, deps)
@@ -455,8 +462,8 @@
 			}
 			return ret
 		}
-		flags.GlobalFlags = removeInclude(flags.GlobalFlags)
-		flags.CFlags = removeInclude(flags.CFlags)
+		flags.Local.CommonFlags = removeInclude(flags.Local.CommonFlags)
+		flags.Local.CFlags = removeInclude(flags.Local.CFlags)
 
 		flags = addStubLibraryCompilerFlags(flags)
 	}
@@ -579,24 +586,28 @@
 	availableFor(string) bool
 }
 
-func (library *libraryDecorator) getLibName(ctx BaseModuleContext) string {
+func (library *libraryDecorator) getLibNameHelper(baseModuleName string, useVndk bool) string {
 	name := library.libName
 	if name == "" {
 		name = String(library.Properties.Stem)
 		if name == "" {
-			name = ctx.baseModuleName()
+			name = baseModuleName
 		}
 	}
 
 	suffix := ""
-	if ctx.useVndk() {
+	if useVndk {
 		suffix = String(library.Properties.Target.Vendor.Suffix)
 	}
 	if suffix == "" {
 		suffix = String(library.Properties.Suffix)
 	}
 
-	name += suffix
+	return name + suffix
+}
+
+func (library *libraryDecorator) getLibName(ctx BaseModuleContext) string {
+	name := library.getLibNameHelper(ctx.baseModuleName(), ctx.useVndk())
 
 	if ctx.isVndkExt() {
 		// vndk-ext lib should have the same name with original lib
@@ -765,21 +776,21 @@
 		}
 	} else {
 		if unexportedSymbols.Valid() {
-			flags.LdFlags = append(flags.LdFlags, "-Wl,-unexported_symbols_list,"+unexportedSymbols.String())
+			flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-unexported_symbols_list,"+unexportedSymbols.String())
 			linkerDeps = append(linkerDeps, unexportedSymbols.Path())
 		}
 		if forceNotWeakSymbols.Valid() {
-			flags.LdFlags = append(flags.LdFlags, "-Wl,-force_symbols_not_weak_list,"+forceNotWeakSymbols.String())
+			flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-force_symbols_not_weak_list,"+forceNotWeakSymbols.String())
 			linkerDeps = append(linkerDeps, forceNotWeakSymbols.Path())
 		}
 		if forceWeakSymbols.Valid() {
-			flags.LdFlags = append(flags.LdFlags, "-Wl,-force_symbols_weak_list,"+forceWeakSymbols.String())
+			flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-force_symbols_weak_list,"+forceWeakSymbols.String())
 			linkerDeps = append(linkerDeps, forceWeakSymbols.Path())
 		}
 	}
 	if library.buildStubs() {
 		linkerScriptFlags := "-Wl,--version-script," + library.versionScriptPath.String()
-		flags.LdFlags = append(flags.LdFlags, linkerScriptFlags)
+		flags.Local.LdFlags = append(flags.Local.LdFlags, linkerScriptFlags)
 		linkerDeps = append(linkerDeps, library.versionScriptPath)
 	}
 
@@ -791,7 +802,7 @@
 	if ctx.Windows() {
 		importLibraryPath := android.PathForModuleOut(ctx, pathtools.ReplaceExtension(fileName, "lib"))
 
-		flags.LdFlags = append(flags.LdFlags, "-Wl,--out-implib="+importLibraryPath.String())
+		flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--out-implib="+importLibraryPath.String())
 		implicitOutputs = append(implicitOutputs, importLibraryPath)
 	}
 
@@ -851,7 +862,7 @@
 
 		symbolOrderingFile := android.PathForModuleOut(ctx, "unsorted", fileName+".symbol_order")
 		symbolOrderingFlag := library.baseLinker.sortBssSymbolsBySize(ctx, unsortedOutputFile, symbolOrderingFile, builderFlags)
-		builderFlags.ldFlags += " " + symbolOrderingFlag
+		builderFlags.localLdFlags += " " + symbolOrderingFlag
 		linkerDeps = append(linkerDeps, symbolOrderingFile)
 	}
 
@@ -958,7 +969,7 @@
 
 	if Bool(library.Properties.Aidl.Export_aidl_headers) {
 		if library.baseCompiler.hasSrcExt(".aidl") {
-			dir := android.PathForModuleGen(ctx, "aidl").String()
+			dir := android.PathForModuleGen(ctx, "aidl")
 			library.reexportDirs(dir)
 			library.reexportDeps(library.baseCompiler.pathDeps...) // TODO: restrict to aidl deps
 		}
@@ -966,25 +977,25 @@
 
 	if Bool(library.Properties.Proto.Export_proto_headers) {
 		if library.baseCompiler.hasSrcExt(".proto") {
-			includes := []string{}
+			var includes android.Paths
 			if flags.proto.CanonicalPathFromRoot {
-				includes = append(includes, flags.proto.SubDir.String())
+				includes = append(includes, flags.proto.SubDir)
 			}
-			includes = append(includes, flags.proto.Dir.String())
+			includes = append(includes, flags.proto.Dir)
 			library.reexportDirs(includes...)
 			library.reexportDeps(library.baseCompiler.pathDeps...) // TODO: restrict to proto deps
 		}
 	}
 
 	if library.baseCompiler.hasSrcExt(".sysprop") {
-		dir := android.PathForModuleGen(ctx, "sysprop", "include").String()
+		dir := android.PathForModuleGen(ctx, "sysprop", "include")
 		if library.Properties.Sysprop.Platform != nil {
 			isProduct := ctx.ProductSpecific() && !ctx.useVndk()
 			isVendor := ctx.useVndk()
 			isOwnerPlatform := Bool(library.Properties.Sysprop.Platform)
 
 			if !ctx.inRecovery() && (isProduct || (isOwnerPlatform == isVendor)) {
-				dir = android.PathForModuleGen(ctx, "sysprop/public", "include").String()
+				dir = android.PathForModuleGen(ctx, "sysprop/public", "include")
 			}
 		}
 
@@ -1227,45 +1238,59 @@
 }
 
 func LinkageMutator(mctx android.BottomUpMutatorContext) {
+	cc_prebuilt := false
 	if m, ok := mctx.Module().(*Module); ok && m.linker != nil {
-		switch library := m.linker.(type) {
-		case prebuiltLibraryInterface:
-			// Always create both the static and shared variants for prebuilt libraries, and then disable the one
-			// that is not being used.  This allows them to share the name of a cc_library module, which requires that
-			// all the variants of the cc_library also exist on the prebuilt.
-			modules := mctx.CreateLocalVariations("static", "shared")
-			static := modules[0].(*Module)
-			shared := modules[1].(*Module)
+		_, cc_prebuilt = m.linker.(prebuiltLibraryInterface)
+	}
+	if cc_prebuilt {
+		library := mctx.Module().(*Module).linker.(prebuiltLibraryInterface)
 
-			static.linker.(prebuiltLibraryInterface).setStatic()
-			shared.linker.(prebuiltLibraryInterface).setShared()
+		// Always create both the static and shared variants for prebuilt libraries, and then disable the one
+		// that is not being used.  This allows them to share the name of a cc_library module, which requires that
+		// all the variants of the cc_library also exist on the prebuilt.
+		modules := mctx.CreateLocalVariations("static", "shared")
+		static := modules[0].(*Module)
+		shared := modules[1].(*Module)
 
-			if !library.buildStatic() {
-				static.linker.(prebuiltLibraryInterface).disablePrebuilt()
-			}
-			if !library.buildShared() {
-				shared.linker.(prebuiltLibraryInterface).disablePrebuilt()
-			}
+		static.linker.(prebuiltLibraryInterface).setStatic()
+		shared.linker.(prebuiltLibraryInterface).setShared()
 
-		case libraryInterface:
-			if library.buildStatic() && library.buildShared() {
-				modules := mctx.CreateLocalVariations("static", "shared")
-				static := modules[0].(*Module)
-				shared := modules[1].(*Module)
-
-				static.linker.(libraryInterface).setStatic()
-				shared.linker.(libraryInterface).setShared()
-
-				reuseStaticLibrary(mctx, static, shared)
-
-			} else if library.buildStatic() {
-				modules := mctx.CreateLocalVariations("static")
-				modules[0].(*Module).linker.(libraryInterface).setStatic()
-			} else if library.buildShared() {
-				modules := mctx.CreateLocalVariations("shared")
-				modules[0].(*Module).linker.(libraryInterface).setShared()
-			}
+		if !library.buildStatic() {
+			static.linker.(prebuiltLibraryInterface).disablePrebuilt()
 		}
+		if !library.buildShared() {
+			shared.linker.(prebuiltLibraryInterface).disablePrebuilt()
+		}
+	} else if library, ok := mctx.Module().(LinkableInterface); ok && library.CcLibraryInterface() {
+		if library.BuildStaticVariant() && library.BuildSharedVariant() {
+			variations := []string{"static", "shared"}
+
+			// Non-cc.Modules need an empty variant for their mutators.
+			if _, ok := mctx.Module().(*Module); !ok {
+				variations = append(variations, "")
+			}
+
+			modules := mctx.CreateLocalVariations(variations...)
+			static := modules[0].(LinkableInterface)
+			shared := modules[1].(LinkableInterface)
+
+			static.SetStatic()
+			shared.SetShared()
+
+			if _, ok := library.(*Module); ok {
+				reuseStaticLibrary(mctx, static.(*Module), shared.(*Module))
+			}
+		} else if library.BuildStaticVariant() {
+			modules := mctx.CreateLocalVariations("static")
+			modules[0].(LinkableInterface).SetStatic()
+		} else if library.BuildSharedVariant() {
+			modules := mctx.CreateLocalVariations("shared")
+			modules[0].(LinkableInterface).SetShared()
+		} else if _, ok := mctx.Module().(*Module); !ok {
+			// Non-cc.Modules need an empty variant for their mutators.
+			mctx.CreateLocalVariations("")
+		}
+
 	}
 }
 
@@ -1280,7 +1305,7 @@
 
 var stubsVersionsLock sync.Mutex
 
-func latestStubsVersionFor(config android.Config, name string) string {
+func LatestStubsVersionFor(config android.Config, name string) string {
 	versions, ok := stubsVersionsFor(config)[name]
 	if ok && len(versions) > 0 {
 		// the versions are alreay sorted in ascending order
@@ -1292,11 +1317,10 @@
 // Version mutator splits a module into the mandatory non-stubs variant
 // (which is unnamed) and zero or more stubs variants.
 func VersionMutator(mctx android.BottomUpMutatorContext) {
-	if m, ok := mctx.Module().(*Module); ok && !m.inRecovery() && m.linker != nil {
-		if library, ok := m.linker.(*libraryDecorator); ok && library.buildShared() &&
-			len(library.Properties.Stubs.Versions) > 0 {
+	if library, ok := mctx.Module().(LinkableInterface); ok && !library.InRecovery() {
+		if library.CcLibrary() && library.BuildSharedVariant() && len(library.StubsVersions()) > 0 {
 			versions := []string{}
-			for _, v := range library.Properties.Stubs.Versions {
+			for _, v := range library.StubsVersions() {
 				if _, err := strconv.Atoi(v); err != nil {
 					mctx.PropertyErrorf("versions", "%q is not a number", v)
 				}
@@ -1320,14 +1344,9 @@
 
 			modules := mctx.CreateVariations(versions...)
 			for i, m := range modules {
-				l := m.(*Module).linker.(*libraryDecorator)
 				if versions[i] != "" {
-					l.MutatedProperties.BuildStubs = true
-					l.MutatedProperties.StubsVersion = versions[i]
-					m.(*Module).Properties.HideFromMake = true
-					m.(*Module).sanitize = nil
-					m.(*Module).stl = nil
-					m.(*Module).Properties.PreventInstall = true
+					m.(LinkableInterface).SetBuildStubs()
+					m.(LinkableInterface).SetStubsVersions(versions[i])
 				}
 			}
 		} else {
@@ -1353,7 +1372,7 @@
 	injectBoringSSLHash := Bool(inject)
 	ctx.VisitDirectDeps(func(dep android.Module) {
 		tag := ctx.OtherModuleDependencyTag(dep)
-		if tag == staticDepTag || tag == staticExportDepTag || tag == wholeStaticDepTag || tag == lateStaticDepTag {
+		if tag == StaticDepTag || tag == staticExportDepTag || tag == wholeStaticDepTag || tag == lateStaticDepTag {
 			if cc, ok := dep.(*Module); ok {
 				if library, ok := cc.linker.(*libraryDecorator); ok {
 					if Bool(library.Properties.Inject_bssl_hash) {
diff --git a/cc/library_test.go b/cc/library_test.go
index 2acae35..f8d8934 100644
--- a/cc/library_test.go
+++ b/cc/library_test.go
@@ -181,7 +181,7 @@
 		}
 
 		libfoo := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_core_shared").Module().(*Module)
-		if !inList("-DGOOGLE_PROTOBUF_NO_RTTI", libfoo.flags.CFlags) {
+		if !inList("-DGOOGLE_PROTOBUF_NO_RTTI", libfoo.flags.Local.CFlags) {
 			t.Errorf("missing protobuf cflags")
 		}
 	})
diff --git a/cc/linkable.go b/cc/linkable.go
new file mode 100644
index 0000000..cfbaffe
--- /dev/null
+++ b/cc/linkable.go
@@ -0,0 +1,71 @@
+package cc
+
+import (
+	"github.com/google/blueprint"
+
+	"android/soong/android"
+)
+
+type LinkableInterface interface {
+	Module() android.Module
+	CcLibrary() bool
+	CcLibraryInterface() bool
+
+	OutputFile() android.OptionalPath
+
+	IncludeDirs(ctx android.BaseModuleContext) android.Paths
+	SetDepsInLinkOrder([]android.Path)
+	GetDepsInLinkOrder() []android.Path
+
+	HasStaticVariant() bool
+	GetStaticVariant() LinkableInterface
+
+	StubsVersions() []string
+	BuildStubs() bool
+	SetBuildStubs()
+	SetStubsVersions(string)
+	HasStubsVariants() bool
+	SelectedStl() string
+	ApiLevel() string
+
+	BuildStaticVariant() bool
+	BuildSharedVariant() bool
+	SetStatic()
+	SetShared()
+	Static() bool
+	Shared() bool
+	Toc() android.OptionalPath
+
+	InRecovery() bool
+	OnlyInRecovery() bool
+
+	UseVndk() bool
+	MustUseVendorVariant() bool
+	IsVndk() bool
+	HasVendorVariant() bool
+
+	SdkVersion() string
+
+	ToolchainLibrary() bool
+	NdkPrebuiltStl() bool
+	StubDecorator() bool
+}
+
+type DependencyTag struct {
+	blueprint.BaseDependencyTag
+	Name    string
+	Library bool
+	Shared  bool
+
+	ReexportFlags bool
+
+	ExplicitlyVersioned bool
+}
+
+var (
+	SharedDepTag = DependencyTag{Name: "shared", Library: true, Shared: true}
+	StaticDepTag = DependencyTag{Name: "static", Library: true}
+
+	CrtBeginDepTag = DependencyTag{Name: "crtbegin"}
+	CrtEndDepTag   = DependencyTag{Name: "crtend"}
+)
diff --git a/cc/linker.go b/cc/linker.go
index e5e1486..61ae757 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -331,65 +331,66 @@
 	}
 
 	if linker.useClangLld(ctx) {
-		flags.LdFlags = append(flags.LdFlags, fmt.Sprintf("${config.%sGlobalLldflags}", hod))
+		flags.Global.LdFlags = append(flags.Global.LdFlags, fmt.Sprintf("${config.%sGlobalLldflags}", hod))
 		if !BoolDefault(linker.Properties.Pack_relocations, true) {
-			flags.LdFlags = append(flags.LdFlags, "-Wl,--pack-dyn-relocs=none")
+			flags.Global.LdFlags = append(flags.Global.LdFlags, "-Wl,--pack-dyn-relocs=none")
 		} else if ctx.Device() {
 			// The SHT_RELR relocations is only supported by API level >= 28.
 			// Do not turn this on if older version NDK is used.
 			if !ctx.useSdk() || CheckSdkVersionAtLeast(ctx, 28) {
-				flags.LdFlags = append(flags.LdFlags, "-Wl,--pack-dyn-relocs=android+relr")
-				flags.LdFlags = append(flags.LdFlags, "-Wl,--use-android-relr-tags")
+				flags.Global.LdFlags = append(flags.Global.LdFlags,
+					"-Wl,--pack-dyn-relocs=android+relr",
+					"-Wl,--use-android-relr-tags")
 			}
 		}
 	} else {
-		flags.LdFlags = append(flags.LdFlags, fmt.Sprintf("${config.%sGlobalLdflags}", hod))
+		flags.Global.LdFlags = append(flags.Global.LdFlags, fmt.Sprintf("${config.%sGlobalLdflags}", hod))
 	}
 	if Bool(linker.Properties.Allow_undefined_symbols) {
 		if ctx.Darwin() {
 			// darwin defaults to treating undefined symbols as errors
-			flags.LdFlags = append(flags.LdFlags, "-Wl,-undefined,dynamic_lookup")
+			flags.Global.LdFlags = append(flags.Global.LdFlags, "-Wl,-undefined,dynamic_lookup")
 		}
 	} else if !ctx.Darwin() && !ctx.Windows() {
-		flags.LdFlags = append(flags.LdFlags, "-Wl,--no-undefined")
+		flags.Global.LdFlags = append(flags.Global.LdFlags, "-Wl,--no-undefined")
 	}
 
 	if linker.useClangLld(ctx) {
-		flags.LdFlags = append(flags.LdFlags, toolchain.ClangLldflags())
+		flags.Global.LdFlags = append(flags.Global.LdFlags, toolchain.ClangLldflags())
 	} else {
-		flags.LdFlags = append(flags.LdFlags, toolchain.ClangLdflags())
+		flags.Global.LdFlags = append(flags.Global.LdFlags, toolchain.ClangLdflags())
 	}
 
 	if !ctx.toolchain().Bionic() && !ctx.Fuchsia() {
 		CheckBadHostLdlibs(ctx, "host_ldlibs", linker.Properties.Host_ldlibs)
 
-		flags.LdFlags = append(flags.LdFlags, linker.Properties.Host_ldlibs...)
+		flags.Local.LdFlags = append(flags.Local.LdFlags, linker.Properties.Host_ldlibs...)
 
 		if !ctx.Windows() {
 			// Add -ldl, -lpthread, -lm and -lrt to host builds to match the default behavior of device
 			// builds
-			flags.LdFlags = append(flags.LdFlags,
+			flags.Global.LdFlags = append(flags.Global.LdFlags,
 				"-ldl",
 				"-lpthread",
 				"-lm",
 			)
 			if !ctx.Darwin() {
-				flags.LdFlags = append(flags.LdFlags, "-lrt")
+				flags.Global.LdFlags = append(flags.Global.LdFlags, "-lrt")
 			}
 		}
 	}
 
 	if ctx.Fuchsia() {
-		flags.LdFlags = append(flags.LdFlags, "-lfdio", "-lzircon")
+		flags.Global.LdFlags = append(flags.Global.LdFlags, "-lfdio", "-lzircon")
 	}
 
 	if ctx.toolchain().LibclangRuntimeLibraryArch() != "" {
-		flags.LdFlags = append(flags.LdFlags, "-Wl,--exclude-libs="+config.BuiltinsRuntimeLibrary(ctx.toolchain())+".a")
+		flags.Global.LdFlags = append(flags.Global.LdFlags, "-Wl,--exclude-libs="+config.BuiltinsRuntimeLibrary(ctx.toolchain())+".a")
 	}
 
 	CheckBadLinkerFlags(ctx, "ldflags", linker.Properties.Ldflags)
 
-	flags.LdFlags = append(flags.LdFlags, proptools.NinjaAndShellEscapeList(linker.Properties.Ldflags)...)
+	flags.Local.LdFlags = append(flags.Local.LdFlags, proptools.NinjaAndShellEscapeList(linker.Properties.Ldflags)...)
 
 	if ctx.Host() && !ctx.Windows() {
 		rpath_prefix := `\$$ORIGIN/`
@@ -399,7 +400,7 @@
 
 		if !ctx.static() {
 			for _, rpath := range linker.dynamicProperties.RunPaths {
-				flags.LdFlags = append(flags.LdFlags, "-Wl,-rpath,"+rpath_prefix+rpath)
+				flags.Global.LdFlags = append(flags.Global.LdFlags, "-Wl,-rpath,"+rpath_prefix+rpath)
 			}
 		}
 	}
@@ -409,10 +410,10 @@
 		// to older devices requires the old style hash. Fortunately, we can build with both and
 		// it'll work anywhere.
 		// This is not currently supported on MIPS architectures.
-		flags.LdFlags = append(flags.LdFlags, "-Wl,--hash-style=both")
+		flags.Global.LdFlags = append(flags.Global.LdFlags, "-Wl,--hash-style=both")
 	}
 
-	flags.LdFlags = append(flags.LdFlags, toolchain.ToolchainClangLdflags())
+	flags.Global.LdFlags = append(flags.Global.LdFlags, toolchain.ToolchainClangLdflags())
 
 	if Bool(linker.Properties.Group_static_libs) {
 		flags.GroupStaticLibs = true
@@ -434,13 +435,13 @@
 			if ctx.Darwin() {
 				ctx.PropertyErrorf("version_script", "Not supported on Darwin")
 			} else {
-				flags.LdFlags = append(flags.LdFlags,
+				flags.Local.LdFlags = append(flags.Local.LdFlags,
 					"-Wl,--version-script,"+versionScript.String())
 				flags.LdFlagsDeps = append(flags.LdFlagsDeps, versionScript.Path())
 
 				if linker.sanitize.isSanitizerEnabled(cfi) {
 					cfiExportsMap := android.PathForSource(ctx, cfiExportsMapPath)
-					flags.LdFlags = append(flags.LdFlags,
+					flags.Local.LdFlags = append(flags.Local.LdFlags,
 						"-Wl,--version-script,"+cfiExportsMap.String())
 					flags.LdFlagsDeps = append(flags.LdFlagsDeps, cfiExportsMap)
 				}
diff --git a/cc/llndk_library.go b/cc/llndk_library.go
index 9cbe800..3a5b3a6 100644
--- a/cc/llndk_library.go
+++ b/cc/llndk_library.go
@@ -133,7 +133,7 @@
 
 	if !Bool(stub.Properties.Unversioned) {
 		linkerScriptFlag := "-Wl,--version-script," + stub.versionScriptPath.String()
-		flags.LdFlags = append(flags.LdFlags, linkerScriptFlag)
+		flags.Local.LdFlags = append(flags.Local.LdFlags, linkerScriptFlag)
 		flags.LdFlagsDeps = append(flags.LdFlagsDeps, stub.versionScriptPath)
 	}
 
@@ -146,9 +146,9 @@
 		}
 
 		if Bool(stub.Properties.Export_headers_as_system) {
-			stub.reexportSystemDirs(genHeaderOutDir.String())
+			stub.reexportSystemDirs(genHeaderOutDir)
 		} else {
-			stub.reexportDirs(genHeaderOutDir.String())
+			stub.reexportDirs(genHeaderOutDir)
 		}
 
 		stub.reexportDeps(timestampFiles...)
diff --git a/cc/lto.go b/cc/lto.go
index 431d70d..4489fc7 100644
--- a/cc/lto.go
+++ b/cc/lto.go
@@ -82,7 +82,7 @@
 func (lto *lto) flags(ctx BaseModuleContext, flags Flags) Flags {
 	// TODO(b/131771163): Disable LTO when using explicit fuzzing configurations.
 	// LTO breaks fuzzer builds.
-	if inList("-fsanitize=fuzzer-no-link", flags.CFlags) {
+	if inList("-fsanitize=fuzzer-no-link", flags.Local.CFlags) {
 		return flags
 	}
 
@@ -94,27 +94,28 @@
 			ltoFlag = "-flto"
 		}
 
-		flags.CFlags = append(flags.CFlags, ltoFlag)
-		flags.LdFlags = append(flags.LdFlags, ltoFlag)
+		flags.Local.CFlags = append(flags.Local.CFlags, ltoFlag)
+		flags.Local.LdFlags = append(flags.Local.LdFlags, ltoFlag)
 
 		if ctx.Config().IsEnvTrue("USE_THINLTO_CACHE") && Bool(lto.Properties.Lto.Thin) && lto.useClangLld(ctx) {
 			// Set appropriate ThinLTO cache policy
 			cacheDirFormat := "-Wl,--thinlto-cache-dir="
 			cacheDir := android.PathForOutput(ctx, "thinlto-cache").String()
-			flags.LdFlags = append(flags.LdFlags, cacheDirFormat+cacheDir)
+			flags.Local.LdFlags = append(flags.Local.LdFlags, cacheDirFormat+cacheDir)
 
 			// Limit the size of the ThinLTO cache to the lesser of 10% of available
 			// disk space and 10GB.
 			cachePolicyFormat := "-Wl,--thinlto-cache-policy="
 			policy := "cache_size=10%:cache_size_bytes=10g"
-			flags.LdFlags = append(flags.LdFlags, cachePolicyFormat+policy)
+			flags.Local.LdFlags = append(flags.Local.LdFlags, cachePolicyFormat+policy)
 		}
 
 		// If the module does not have a profile, be conservative and do not inline
 		// or unroll loops during LTO, in order to prevent significant size bloat.
 		if !ctx.isPgoCompile() {
-			flags.LdFlags = append(flags.LdFlags, "-Wl,-plugin-opt,-inline-threshold=0")
-			flags.LdFlags = append(flags.LdFlags, "-Wl,-plugin-opt,-unroll-threshold=0")
+			flags.Local.LdFlags = append(flags.Local.LdFlags,
+				"-Wl,-plugin-opt,-inline-threshold=0",
+				"-Wl,-plugin-opt,-unroll-threshold=0")
 		}
 	}
 	return flags
@@ -148,7 +149,7 @@
 		mctx.WalkDeps(func(dep android.Module, parent android.Module) bool {
 			tag := mctx.OtherModuleDependencyTag(dep)
 			switch tag {
-			case staticDepTag, staticExportDepTag, lateStaticDepTag, wholeStaticDepTag, objDepTag, reuseObjTag:
+			case StaticDepTag, staticExportDepTag, lateStaticDepTag, wholeStaticDepTag, objDepTag, reuseObjTag:
 				if dep, ok := dep.(*Module); ok && dep.lto != nil &&
 					!dep.lto.Disabled() {
 					if full && !Bool(dep.lto.Properties.Lto.Full) {
diff --git a/cc/makevars.go b/cc/makevars.go
index f9c58b9..e8cedf0 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -101,35 +101,6 @@
 
 	ctx.Strict("BOARD_VNDK_VERSION", ctx.DeviceConfig().VndkVersion())
 
-	ctx.Strict("VNDK_CORE_LIBRARIES", strings.Join(*vndkCoreLibraries(ctx.Config()), " "))
-	ctx.Strict("VNDK_SAMEPROCESS_LIBRARIES", strings.Join(*vndkSpLibraries(ctx.Config()), " "))
-
-	// Make uses LLNDK_LIBRARIES to determine which libraries to install.
-	// HWASAN is only part of the LL-NDK in builds in which libc depends on HWASAN.
-	// Therefore, by removing the library here, we cause it to only be installed if libc
-	// depends on it.
-	installedLlndkLibraries := []string{}
-
-	// Make uses LLNDK_MOVED_TO_APEX_LIBRARIES to avoid installing libraries on /system if
-	// they been moved to an apex.
-	movedToApexLlndkLibraries := []string{}
-	for _, lib := range *llndkLibraries(ctx.Config()) {
-		if strings.HasPrefix(lib, "libclang_rt.hwasan-") {
-			continue
-		}
-		installedLlndkLibraries = append(installedLlndkLibraries, lib)
-
-		// Skip bionic libs, they are handled in different manner
-		if android.DirectlyInAnyApex(&notOnHostContext{}, lib) && !isBionic(lib) {
-			movedToApexLlndkLibraries = append(movedToApexLlndkLibraries, lib)
-		}
-	}
-	ctx.Strict("LLNDK_LIBRARIES", strings.Join(installedLlndkLibraries, " "))
-	ctx.Strict("LLNDK_MOVED_TO_APEX_LIBRARIES", strings.Join(movedToApexLlndkLibraries, " "))
-
-	ctx.Strict("VNDK_PRIVATE_LIBRARIES", strings.Join(*vndkPrivateLibraries(ctx.Config()), " "))
-	ctx.Strict("VNDK_USING_CORE_VARIANT_LIBRARIES", strings.Join(*vndkUsingCoreVariantLibraries(ctx.Config()), " "))
-
 	// Filter vendor_public_library that are exported to make
 	exportedVendorPublicLibraries := []string{}
 	ctx.VisitAllModules(func(module android.Module) {
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index 3747b41..b75c4c8 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -257,7 +257,7 @@
 }
 
 func addStubLibraryCompilerFlags(flags Flags) Flags {
-	flags.CFlags = append(flags.CFlags,
+	flags.Global.CFlags = append(flags.Global.CFlags,
 		// We're knowingly doing some otherwise unsightly things with builtin
 		// functions here. We're just generating stub libraries, so ignore it.
 		"-Wno-incompatible-library-redeclaration",
@@ -337,7 +337,7 @@
 
 	if useVersionScript {
 		linkerScriptFlag := "-Wl,--version-script," + stub.versionScriptPath.String()
-		flags.LdFlags = append(flags.LdFlags, linkerScriptFlag)
+		flags.Local.LdFlags = append(flags.Local.LdFlags, linkerScriptFlag)
 		flags.LdFlagsDeps = append(flags.LdFlagsDeps, stub.versionScriptPath)
 	}
 
diff --git a/cc/object.go b/cc/object.go
index 31729a5..ad31d09 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -87,10 +87,10 @@
 }
 
 func (object *objectLinker) linkerFlags(ctx ModuleContext, flags Flags) Flags {
-	flags.LdFlags = append(flags.LdFlags, ctx.toolchain().ToolchainClangLdflags())
+	flags.Global.LdFlags = append(flags.Global.LdFlags, ctx.toolchain().ToolchainClangLdflags())
 
 	if lds := android.OptionalPathForModuleSrc(ctx, object.Properties.Linker_script); lds.Valid() {
-		flags.LdFlags = append(flags.LdFlags, "-Wl,-T,"+lds.String())
+		flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-T,"+lds.String())
 		flags.LdFlagsDeps = append(flags.LdFlagsDeps, lds.Path())
 	}
 	return flags
diff --git a/cc/pgo.go b/cc/pgo.go
index 4e915ff..4618f4e 100644
--- a/cc/pgo.go
+++ b/cc/pgo.go
@@ -89,18 +89,18 @@
 }
 
 func (props *PgoProperties) addProfileGatherFlags(ctx ModuleContext, flags Flags) Flags {
-	flags.CFlags = append(flags.CFlags, props.Pgo.Cflags...)
+	flags.Local.CFlags = append(flags.Local.CFlags, props.Pgo.Cflags...)
 
 	if props.isInstrumentation() {
-		flags.CFlags = append(flags.CFlags, profileInstrumentFlag)
+		flags.Local.CFlags = append(flags.Local.CFlags, profileInstrumentFlag)
 		// The profile runtime is added below in deps().  Add the below
 		// flag, which is the only other link-time action performed by
 		// the Clang driver during link.
-		flags.LdFlags = append(flags.LdFlags, "-u__llvm_profile_runtime")
+		flags.Local.LdFlags = append(flags.Local.LdFlags, "-u__llvm_profile_runtime")
 	}
 	if props.isSampling() {
-		flags.CFlags = append(flags.CFlags, profileSamplingFlag)
-		flags.LdFlags = append(flags.LdFlags, profileSamplingFlag)
+		flags.Local.CFlags = append(flags.Local.CFlags, profileSamplingFlag)
+		flags.Local.LdFlags = append(flags.Local.LdFlags, profileSamplingFlag)
 	}
 	return flags
 }
@@ -170,8 +170,8 @@
 		profileFilePath := profileFile.Path()
 		profileUseFlags := props.profileUseFlags(ctx, profileFilePath.String())
 
-		flags.CFlags = append(flags.CFlags, profileUseFlags...)
-		flags.LdFlags = append(flags.LdFlags, profileUseFlags...)
+		flags.Local.CFlags = append(flags.Local.CFlags, profileUseFlags...)
+		flags.Local.LdFlags = append(flags.Local.LdFlags, profileUseFlags...)
 
 		// Update CFlagsDeps and LdFlagsDeps so the module is rebuilt
 		// if profileFile gets updated
diff --git a/cc/proto.go b/cc/proto.go
index f818edc..ae988ec 100644
--- a/cc/proto.go
+++ b/cc/proto.go
@@ -114,13 +114,13 @@
 }
 
 func protoFlags(ctx ModuleContext, flags Flags, p *android.ProtoProperties) Flags {
-	flags.CFlags = append(flags.CFlags, "-DGOOGLE_PROTOBUF_NO_RTTI")
+	flags.Local.CFlags = append(flags.Local.CFlags, "-DGOOGLE_PROTOBUF_NO_RTTI")
 
 	flags.proto = android.GetProtoFlags(ctx, p)
 	if flags.proto.CanonicalPathFromRoot {
-		flags.GlobalFlags = append(flags.GlobalFlags, "-I"+flags.proto.SubDir.String())
+		flags.Local.CommonFlags = append(flags.Local.CommonFlags, "-I"+flags.proto.SubDir.String())
 	}
-	flags.GlobalFlags = append(flags.GlobalFlags, "-I"+flags.proto.Dir.String())
+	flags.Local.CommonFlags = append(flags.Local.CommonFlags, "-I"+flags.proto.Dir.String())
 
 	if String(p.Proto.Plugin) == "" {
 		var plugin string
diff --git a/cc/rs.go b/cc/rs.go
index 5951edb..61fd1a8 100644
--- a/cc/rs.go
+++ b/cc/rs.go
@@ -123,7 +123,7 @@
 	rootRsIncludeDirs := android.PathsForSource(ctx, properties.Renderscript.Include_dirs)
 	flags.rsFlags = append(flags.rsFlags, includeDirsToFlags(rootRsIncludeDirs))
 
-	flags.GlobalFlags = append(flags.GlobalFlags,
+	flags.Local.CommonFlags = append(flags.Local.CommonFlags,
 		"-I"+android.PathForModuleGen(ctx, "rs").String(),
 		"-Iframeworks/rs",
 		"-Iframeworks/rs/cpp",
diff --git a/cc/sabi.go b/cc/sabi.go
index 0999151..8cef170 100644
--- a/cc/sabi.go
+++ b/cc/sabi.go
@@ -70,20 +70,22 @@
 func (sabimod *sabi) flags(ctx ModuleContext, flags Flags) Flags {
 	// Assuming that the cflags which clang LibTooling tools cannot
 	// understand have not been converted to ninja variables yet.
-	flags.ToolingCFlags = filterOutWithPrefix(flags.CFlags, config.ClangLibToolingUnknownCflags)
-	flags.ToolingCppFlags = filterOutWithPrefix(flags.CppFlags, config.ClangLibToolingUnknownCflags)
+	flags.Local.ToolingCFlags = filterOutWithPrefix(flags.Local.CFlags, config.ClangLibToolingUnknownCflags)
+	flags.Global.ToolingCFlags = filterOutWithPrefix(flags.Global.CFlags, config.ClangLibToolingUnknownCflags)
+	flags.Local.ToolingCppFlags = filterOutWithPrefix(flags.Local.CppFlags, config.ClangLibToolingUnknownCflags)
+	flags.Global.ToolingCppFlags = filterOutWithPrefix(flags.Global.CppFlags, config.ClangLibToolingUnknownCflags)
 
 	return flags
 }
 
 func sabiDepsMutator(mctx android.TopDownMutatorContext) {
 	if c, ok := mctx.Module().(*Module); ok &&
-		((c.isVndk() && c.useVndk()) || inList(c.Name(), *llndkLibraries(mctx.Config())) ||
+		((c.IsVndk() && c.UseVndk()) || c.isLlndk(mctx.Config()) ||
 			(c.sabi != nil && c.sabi.Properties.CreateSAbiDumps)) {
 		mctx.VisitDirectDeps(func(m android.Module) {
 			tag := mctx.OtherModuleDependencyTag(m)
 			switch tag {
-			case staticDepTag, staticExportDepTag, lateStaticDepTag, wholeStaticDepTag:
+			case StaticDepTag, staticExportDepTag, lateStaticDepTag, wholeStaticDepTag:
 
 				cc, _ := m.(*Module)
 				if cc == nil {
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 5172fc8..2bf051e 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -426,8 +426,9 @@
 	minimalRuntimePath := "${config.ClangAsanLibDir}/" + minimalRuntimeLib
 
 	if ctx.Device() && sanitize.Properties.MinimalRuntimeDep {
-		flags.LdFlags = append(flags.LdFlags, minimalRuntimePath)
-		flags.LdFlags = append(flags.LdFlags, "-Wl,--exclude-libs,"+minimalRuntimeLib)
+		flags.Local.LdFlags = append(flags.Local.LdFlags,
+			minimalRuntimePath,
+			"-Wl,--exclude-libs,"+minimalRuntimeLib)
 	}
 	if !sanitize.Properties.SanitizerEnabled && !sanitize.Properties.UbsanRuntimeDep {
 		return flags
@@ -439,15 +440,15 @@
 			// TODO: put in flags?
 			flags.RequiredInstructionSet = "arm"
 		}
-		flags.CFlags = append(flags.CFlags, asanCflags...)
-		flags.LdFlags = append(flags.LdFlags, asanLdflags...)
+		flags.Local.CFlags = append(flags.Local.CFlags, asanCflags...)
+		flags.Local.LdFlags = append(flags.Local.LdFlags, asanLdflags...)
 
 		if ctx.Host() {
 			// -nodefaultlibs (provided with libc++) prevents the driver from linking
 			// libraries needed with -fsanitize=address. http://b/18650275 (WAI)
-			flags.LdFlags = append(flags.LdFlags, "-Wl,--no-as-needed")
+			flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--no-as-needed")
 		} else {
-			flags.CFlags = append(flags.CFlags, "-mllvm", "-asan-globals=0")
+			flags.Local.CFlags = append(flags.Local.CFlags, "-mllvm", "-asan-globals=0")
 			if ctx.bootstrap() {
 				flags.DynamicLinker = "/system/bin/bootstrap/linker_asan"
 			} else {
@@ -460,33 +461,30 @@
 	}
 
 	if Bool(sanitize.Properties.Sanitize.Hwaddress) {
-		flags.CFlags = append(flags.CFlags, hwasanCflags...)
+		flags.Local.CFlags = append(flags.Local.CFlags, hwasanCflags...)
 	}
 
 	if Bool(sanitize.Properties.Sanitize.Fuzzer) {
-		flags.CFlags = append(flags.CFlags, "-fsanitize=fuzzer-no-link")
+		flags.Local.CFlags = append(flags.Local.CFlags, "-fsanitize=fuzzer-no-link")
 
 		// TODO(b/131771163): LTO and Fuzzer support is mutually incompatible.
-		_, flags.LdFlags = removeFromList("-flto", flags.LdFlags)
-		_, flags.CFlags = removeFromList("-flto", flags.CFlags)
-		flags.LdFlags = append(flags.LdFlags, "-fno-lto")
-		flags.CFlags = append(flags.CFlags, "-fno-lto")
+		_, flags.Local.LdFlags = removeFromList("-flto", flags.Local.LdFlags)
+		_, flags.Local.CFlags = removeFromList("-flto", flags.Local.CFlags)
+		flags.Local.LdFlags = append(flags.Local.LdFlags, "-fno-lto")
+		flags.Local.CFlags = append(flags.Local.CFlags, "-fno-lto")
 
 		// TODO(b/142430592): Upstream linker scripts for sanitizer runtime libraries
 		// discard the sancov_lowest_stack symbol, because it's emulated TLS (and thus
 		// doesn't match the linker script due to the "__emutls_v." prefix).
-		flags.LdFlags = append(flags.LdFlags, "-fno-sanitize-coverage=stack-depth")
-		flags.CFlags = append(flags.CFlags, "-fno-sanitize-coverage=stack-depth")
+		flags.Local.LdFlags = append(flags.Local.LdFlags, "-fno-sanitize-coverage=stack-depth")
+		flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize-coverage=stack-depth")
 
 		// TODO(b/133876586): Experimental PM breaks sanitizer coverage.
-		_, flags.CFlags = removeFromList("-fexperimental-new-pass-manager", flags.CFlags)
-		flags.CFlags = append(flags.CFlags, "-fno-experimental-new-pass-manager")
+		flags.Local.CFlags = append(flags.Local.CFlags, "-fno-experimental-new-pass-manager")
 
 		// Disable fortify for fuzzing builds. Generally, we'll be building with
 		// UBSan or ASan here and the fortify checks pollute the stack traces.
-		_, flags.CFlags = removeFromList("-D_FORTIFY_SOURCE=1", flags.CFlags)
-		_, flags.CFlags = removeFromList("-D_FORTIFY_SOURCE=2", flags.CFlags)
-		flags.CFlags = append(flags.CFlags, "-U_FORTIFY_SOURCE")
+		flags.Local.CFlags = append(flags.Local.CFlags, "-U_FORTIFY_SOURCE")
 	}
 
 	if Bool(sanitize.Properties.Sanitize.Cfi) {
@@ -496,75 +494,75 @@
 			flags.RequiredInstructionSet = "thumb"
 		}
 
-		flags.CFlags = append(flags.CFlags, cfiCflags...)
-		flags.AsFlags = append(flags.AsFlags, cfiAsflags...)
+		flags.Local.CFlags = append(flags.Local.CFlags, cfiCflags...)
+		flags.Local.AsFlags = append(flags.Local.AsFlags, cfiAsflags...)
 		// Only append the default visibility flag if -fvisibility has not already been set
 		// to hidden.
-		if !inList("-fvisibility=hidden", flags.CFlags) {
-			flags.CFlags = append(flags.CFlags, "-fvisibility=default")
+		if !inList("-fvisibility=hidden", flags.Local.CFlags) {
+			flags.Local.CFlags = append(flags.Local.CFlags, "-fvisibility=default")
 		}
-		flags.LdFlags = append(flags.LdFlags, cfiLdflags...)
+		flags.Local.LdFlags = append(flags.Local.LdFlags, cfiLdflags...)
 
 		if ctx.staticBinary() {
-			_, flags.CFlags = removeFromList("-fsanitize-cfi-cross-dso", flags.CFlags)
-			_, flags.LdFlags = removeFromList("-fsanitize-cfi-cross-dso", flags.LdFlags)
+			_, flags.Local.CFlags = removeFromList("-fsanitize-cfi-cross-dso", flags.Local.CFlags)
+			_, flags.Local.LdFlags = removeFromList("-fsanitize-cfi-cross-dso", flags.Local.LdFlags)
 		}
 	}
 
 	if Bool(sanitize.Properties.Sanitize.Integer_overflow) {
-		flags.CFlags = append(flags.CFlags, intOverflowCflags...)
+		flags.Local.CFlags = append(flags.Local.CFlags, intOverflowCflags...)
 	}
 
 	if len(sanitize.Properties.Sanitizers) > 0 {
 		sanitizeArg := "-fsanitize=" + strings.Join(sanitize.Properties.Sanitizers, ",")
 
-		flags.CFlags = append(flags.CFlags, sanitizeArg)
-		flags.AsFlags = append(flags.AsFlags, sanitizeArg)
+		flags.Local.CFlags = append(flags.Local.CFlags, sanitizeArg)
+		flags.Local.AsFlags = append(flags.Local.AsFlags, sanitizeArg)
 		if ctx.Host() {
 			// Host sanitizers only link symbols in the final executable, so
 			// there will always be undefined symbols in intermediate libraries.
-			_, flags.LdFlags = removeFromList("-Wl,--no-undefined", flags.LdFlags)
-			flags.LdFlags = append(flags.LdFlags, sanitizeArg)
+			_, flags.Global.LdFlags = removeFromList("-Wl,--no-undefined", flags.Global.LdFlags)
+			flags.Local.LdFlags = append(flags.Local.LdFlags, sanitizeArg)
 		} else {
 			if enableMinimalRuntime(sanitize) {
-				flags.CFlags = append(flags.CFlags, strings.Join(minimalRuntimeFlags, " "))
+				flags.Local.CFlags = append(flags.Local.CFlags, strings.Join(minimalRuntimeFlags, " "))
 				flags.libFlags = append([]string{minimalRuntimePath}, flags.libFlags...)
-				flags.LdFlags = append(flags.LdFlags, "-Wl,--exclude-libs,"+minimalRuntimeLib)
+				flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--exclude-libs,"+minimalRuntimeLib)
 			}
 		}
 
 		if Bool(sanitize.Properties.Sanitize.Fuzzer) {
 			// When fuzzing, we wish to crash with diagnostics on any bug.
-			flags.CFlags = append(flags.CFlags, "-fno-sanitize-trap=all", "-fno-sanitize-recover=all")
+			flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize-trap=all", "-fno-sanitize-recover=all")
 		} else if ctx.Host() {
-			flags.CFlags = append(flags.CFlags, "-fno-sanitize-recover=all")
+			flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize-recover=all")
 		} else {
-			flags.CFlags = append(flags.CFlags, "-fsanitize-trap=all", "-ftrap-function=abort")
+			flags.Local.CFlags = append(flags.Local.CFlags, "-fsanitize-trap=all", "-ftrap-function=abort")
 		}
 		// http://b/119329758, Android core does not boot up with this sanitizer yet.
-		if toDisableImplicitIntegerChange(flags.CFlags) {
-			flags.CFlags = append(flags.CFlags, "-fno-sanitize=implicit-integer-sign-change")
+		if toDisableImplicitIntegerChange(flags.Local.CFlags) {
+			flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize=implicit-integer-sign-change")
 		}
 	}
 
 	if len(sanitize.Properties.DiagSanitizers) > 0 {
-		flags.CFlags = append(flags.CFlags, "-fno-sanitize-trap="+strings.Join(sanitize.Properties.DiagSanitizers, ","))
+		flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize-trap="+strings.Join(sanitize.Properties.DiagSanitizers, ","))
 	}
 	// FIXME: enable RTTI if diag + (cfi or vptr)
 
 	if sanitize.Properties.Sanitize.Recover != nil {
-		flags.CFlags = append(flags.CFlags, "-fsanitize-recover="+
+		flags.Local.CFlags = append(flags.Local.CFlags, "-fsanitize-recover="+
 			strings.Join(sanitize.Properties.Sanitize.Recover, ","))
 	}
 
 	if sanitize.Properties.Sanitize.Diag.No_recover != nil {
-		flags.CFlags = append(flags.CFlags, "-fno-sanitize-recover="+
+		flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize-recover="+
 			strings.Join(sanitize.Properties.Sanitize.Diag.No_recover, ","))
 	}
 
 	blacklist := android.OptionalPathForModuleSrc(ctx, sanitize.Properties.Sanitize.Blacklist)
 	if blacklist.Valid() {
-		flags.CFlags = append(flags.CFlags, "-fsanitize-blacklist="+blacklist.String())
+		flags.Local.CFlags = append(flags.Local.CFlags, "-fsanitize-blacklist="+blacklist.String())
 		flags.CFlagsDeps = append(flags.CFlagsDeps, blacklist.Path())
 	}
 
@@ -678,8 +676,8 @@
 }
 
 func isSanitizableDependencyTag(tag blueprint.DependencyTag) bool {
-	t, ok := tag.(dependencyTag)
-	return ok && t.library || t == reuseObjTag || t == objDepTag
+	t, ok := tag.(DependencyTag)
+	return ok && t.Library || t == reuseObjTag || t == objDepTag
 }
 
 // Propagate sanitizer requirements down from binaries
@@ -848,12 +846,14 @@
 
 		// Determine the runtime library required
 		runtimeLibrary := ""
+		var extraStaticDeps []string
 		toolchain := c.toolchain(mctx)
 		if Bool(c.sanitize.Properties.Sanitize.Address) {
 			runtimeLibrary = config.AddressSanitizerRuntimeLibrary(toolchain)
 		} else if Bool(c.sanitize.Properties.Sanitize.Hwaddress) {
 			if c.staticBinary() {
 				runtimeLibrary = config.HWAddressSanitizerStaticLibrary(toolchain)
+				extraStaticDeps = []string{"libdl"}
 			} else {
 				runtimeLibrary = config.HWAddressSanitizerRuntimeLibrary(toolchain)
 			}
@@ -871,7 +871,7 @@
 		}
 
 		if mctx.Device() && runtimeLibrary != "" {
-			if inList(runtimeLibrary, *llndkLibraries(mctx.Config())) && !c.static() && c.useVndk() {
+			if isLlndkLibrary(runtimeLibrary, mctx.Config()) && !c.static() && c.UseVndk() {
 				runtimeLibrary = runtimeLibrary + llndkLibrarySuffix
 			}
 
@@ -887,7 +887,7 @@
 				mctx.AddFarVariationDependencies(append(mctx.Target().Variations(), []blueprint.Variation{
 					{Mutator: "link", Variation: "static"},
 					{Mutator: "image", Variation: c.imageVariation()},
-				}...), staticDepTag, runtimeLibrary)
+				}...), StaticDepTag, append([]string{runtimeLibrary}, extraStaticDeps...)...)
 			} else if !c.static() && !c.header() {
 				// dynamic executable and shared libs get shared runtime libs
 				mctx.AddFarVariationDependencies(append(mctx.Target().Variations(), []blueprint.Variation{
@@ -961,7 +961,7 @@
 						if t == cfi {
 							appendStringSync(c.Name(), cfiStaticLibs(mctx.Config()), &cfiStaticLibsMutex)
 						} else if t == hwasan {
-							if c.useVndk() {
+							if c.UseVndk() {
 								appendStringSync(c.Name(), hwasanVendorStaticLibs(mctx.Config()),
 									&hwasanStaticLibsMutex)
 							} else {
diff --git a/cc/stl.go b/cc/stl.go
index aa34240..5ccd44a 100644
--- a/cc/stl.go
+++ b/cc/stl.go
@@ -20,13 +20,13 @@
 	"strconv"
 )
 
-func getNdkStlFamily(m *Module) string {
+func getNdkStlFamily(m LinkableInterface) string {
 	family, _ := getNdkStlFamilyAndLinkType(m)
 	return family
 }
 
-func getNdkStlFamilyAndLinkType(m *Module) (string, string) {
-	stl := m.stl.Properties.SelectedStl
+func getNdkStlFamilyAndLinkType(m LinkableInterface) (string, string) {
+	stl := m.SelectedStl()
 	switch stl {
 	case "ndk_libc++_shared":
 		return "libc++", "shared"
@@ -175,7 +175,7 @@
 				deps.StaticLibs = append(deps.StaticLibs, "libunwind_llvm")
 			}
 			if ctx.staticBinary() {
-				deps.StaticLibs = append(deps.StaticLibs, "libm", "libc", "libdl")
+				deps.StaticLibs = append(deps.StaticLibs, "libm", "libc")
 			}
 		}
 	case "":
@@ -215,12 +215,12 @@
 			// these availability attributes are meaningless for us but cause
 			// build breaks when we try to use code that would not be available
 			// in the system's dylib.
-			flags.CppFlags = append(flags.CppFlags,
+			flags.Local.CppFlags = append(flags.Local.CppFlags,
 				"-D_LIBCPP_DISABLE_AVAILABILITY")
 		}
 
 		if !ctx.toolchain().Bionic() {
-			flags.CppFlags = append(flags.CppFlags, "-nostdinc++")
+			flags.Local.CppFlags = append(flags.Local.CppFlags, "-nostdinc++")
 			flags.extraLibFlags = append(flags.extraLibFlags, "-nostdlib++")
 			if ctx.Windows() {
 				if stl.Properties.SelectedStl == "libc++_static" {
@@ -231,9 +231,9 @@
 				// Use SjLj exceptions for 32-bit.  libgcc_eh implements SjLj
 				// exception model for 32-bit.
 				if ctx.Arch().ArchType == android.X86 {
-					flags.CppFlags = append(flags.CppFlags, "-fsjlj-exceptions")
+					flags.Local.CppFlags = append(flags.Local.CppFlags, "-fsjlj-exceptions")
 				}
-				flags.CppFlags = append(flags.CppFlags,
+				flags.Local.CppFlags = append(flags.Local.CppFlags,
 					// Disable visiblity annotations since we're using static
 					// libc++.
 					"-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
@@ -243,23 +243,23 @@
 			}
 		} else {
 			if ctx.Arch().ArchType == android.Arm {
-				flags.LdFlags = append(flags.LdFlags, "-Wl,--exclude-libs,libunwind_llvm.a")
+				flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--exclude-libs,libunwind_llvm.a")
 			}
 		}
 	case "libstdc++":
 		// Nothing
 	case "ndk_system":
 		ndkSrcRoot := android.PathForSource(ctx, "prebuilts/ndk/current/sources/cxx-stl/system/include")
-		flags.CFlags = append(flags.CFlags, "-isystem "+ndkSrcRoot.String())
+		flags.Local.CFlags = append(flags.Local.CFlags, "-isystem "+ndkSrcRoot.String())
 	case "ndk_libc++_shared", "ndk_libc++_static":
 		if ctx.Arch().ArchType == android.Arm {
 			// Make sure the _Unwind_XXX symbols are not re-exported.
-			flags.LdFlags = append(flags.LdFlags, "-Wl,--exclude-libs,libunwind.a")
+			flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--exclude-libs,libunwind.a")
 		}
 	case "":
 		// None or error.
 		if !ctx.toolchain().Bionic() {
-			flags.CppFlags = append(flags.CppFlags, "-nostdinc++")
+			flags.Local.CppFlags = append(flags.Local.CppFlags, "-nostdinc++")
 			flags.extraLibFlags = append(flags.extraLibFlags, "-nostdlib++")
 		}
 	default:
diff --git a/cc/test.go b/cc/test.go
index 0e66e28..05e6fe5 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -173,7 +173,7 @@
 		if test, ok := m.linker.(testPerSrc); ok {
 			numTests := len(test.srcs())
 			if test.testPerSrc() && numTests > 0 {
-				if duplicate, found := checkDuplicate(test.srcs()); found {
+				if duplicate, found := android.CheckDuplicate(test.srcs()); found {
 					mctx.PropertyErrorf("srcs", "found a duplicate entry %q", duplicate)
 					return
 				}
@@ -206,17 +206,6 @@
 	}
 }
 
-func checkDuplicate(values []string) (duplicate string, found bool) {
-	seen := make(map[string]string)
-	for _, v := range values {
-		if duplicate, found = seen[v]; found {
-			return
-		}
-		seen[v] = v
-	}
-	return
-}
-
 type testDecorator struct {
 	Properties TestProperties
 	linker     *baseLinker
@@ -231,20 +220,20 @@
 		return flags
 	}
 
-	flags.CFlags = append(flags.CFlags, "-DGTEST_HAS_STD_STRING")
+	flags.Local.CFlags = append(flags.Local.CFlags, "-DGTEST_HAS_STD_STRING")
 	if ctx.Host() {
-		flags.CFlags = append(flags.CFlags, "-O0", "-g")
+		flags.Local.CFlags = append(flags.Local.CFlags, "-O0", "-g")
 
 		switch ctx.Os() {
 		case android.Windows:
-			flags.CFlags = append(flags.CFlags, "-DGTEST_OS_WINDOWS")
+			flags.Local.CFlags = append(flags.Local.CFlags, "-DGTEST_OS_WINDOWS")
 		case android.Linux:
-			flags.CFlags = append(flags.CFlags, "-DGTEST_OS_LINUX")
+			flags.Local.CFlags = append(flags.Local.CFlags, "-DGTEST_OS_LINUX")
 		case android.Darwin:
-			flags.CFlags = append(flags.CFlags, "-DGTEST_OS_MAC")
+			flags.Local.CFlags = append(flags.Local.CFlags, "-DGTEST_OS_MAC")
 		}
 	} else {
-		flags.CFlags = append(flags.CFlags, "-DGTEST_OS_LINUX_ANDROID")
+		flags.Local.CFlags = append(flags.Local.CFlags, "-DGTEST_OS_LINUX_ANDROID")
 	}
 
 	return flags
diff --git a/cc/testing.go b/cc/testing.go
index 6fa6ea7..9ad72d9 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -145,6 +145,18 @@
 			symbol_file: "",
 		}
 		cc_library {
+			name: "libft2",
+			no_libcrt: true,
+			nocrt: true,
+			system_shared_libs: [],
+			recovery_available: true,
+		}
+		llndk_library {
+			name: "libft2",
+			symbol_file: "",
+			vendor_available: false,
+		}
+		cc_library {
 			name: "libc++_static",
 			no_libcrt: true,
 			nocrt: true,
@@ -257,6 +269,7 @@
 	ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(ObjectFactory))
 	ctx.RegisterModuleType("filegroup", android.ModuleFactoryAdaptor(android.FileGroupFactory))
 	ctx.RegisterModuleType("vndk_prebuilt_shared", android.ModuleFactoryAdaptor(VndkPrebuiltSharedFactory))
+	ctx.RegisterModuleType("vndk_libraries_txt", android.ModuleFactoryAdaptor(VndkLibrariesTxtFactory))
 	ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
 		ctx.BottomUp("image", ImageMutator).Parallel()
 		ctx.BottomUp("link", LinkageMutator).Parallel()
diff --git a/cc/toolchain_library.go b/cc/toolchain_library.go
index fef4508..dfc6f76 100644
--- a/cc/toolchain_library.go
+++ b/cc/toolchain_library.go
@@ -29,6 +29,9 @@
 type toolchainLibraryProperties struct {
 	// the prebuilt toolchain library, as a path from the top of the source tree
 	Src *string `android:"arch_variant"`
+
+	// Repack the archive with only the selected objects.
+	Repack_objects_to_keep []string `android:"arch_variant"`
 }
 
 type toolchainLibraryDecorator struct {
@@ -90,6 +93,14 @@
 		return outputFile
 	}
 
+	if library.Properties.Repack_objects_to_keep != nil {
+		fileName := ctx.ModuleName() + staticLibraryExtension
+		outputFile := android.PathForModuleOut(ctx, fileName)
+		TransformArchiveRepack(ctx, srcPath, outputFile, library.Properties.Repack_objects_to_keep)
+
+		return outputFile
+	}
+
 	return srcPath
 }
 
diff --git a/cc/util.go b/cc/util.go
index 2f7bec2..60070bb 100644
--- a/cc/util.go
+++ b/cc/util.go
@@ -55,27 +55,37 @@
 
 func flagsToBuilderFlags(in Flags) builderFlags {
 	return builderFlags{
-		globalFlags:     strings.Join(in.GlobalFlags, " "),
-		arFlags:         strings.Join(in.ArFlags, " "),
-		asFlags:         strings.Join(in.AsFlags, " "),
-		cFlags:          strings.Join(in.CFlags, " "),
-		toolingCFlags:   strings.Join(in.ToolingCFlags, " "),
-		toolingCppFlags: strings.Join(in.ToolingCppFlags, " "),
-		conlyFlags:      strings.Join(in.ConlyFlags, " "),
-		cppFlags:        strings.Join(in.CppFlags, " "),
-		aidlFlags:       strings.Join(in.aidlFlags, " "),
-		rsFlags:         strings.Join(in.rsFlags, " "),
-		ldFlags:         strings.Join(in.LdFlags, " "),
-		libFlags:        strings.Join(in.libFlags, " "),
-		extraLibFlags:   strings.Join(in.extraLibFlags, " "),
-		tidyFlags:       strings.Join(in.TidyFlags, " "),
-		sAbiFlags:       strings.Join(in.SAbiFlags, " "),
-		yasmFlags:       strings.Join(in.YasmFlags, " "),
-		toolchain:       in.Toolchain,
-		coverage:        in.Coverage,
-		tidy:            in.Tidy,
-		sAbiDump:        in.SAbiDump,
-		emitXrefs:       in.EmitXrefs,
+		globalCommonFlags:     strings.Join(in.Global.CommonFlags, " "),
+		globalAsFlags:         strings.Join(in.Global.AsFlags, " "),
+		globalYasmFlags:       strings.Join(in.Global.YasmFlags, " "),
+		globalCFlags:          strings.Join(in.Global.CFlags, " "),
+		globalToolingCFlags:   strings.Join(in.Global.ToolingCFlags, " "),
+		globalToolingCppFlags: strings.Join(in.Global.ToolingCppFlags, " "),
+		globalConlyFlags:      strings.Join(in.Global.ConlyFlags, " "),
+		globalCppFlags:        strings.Join(in.Global.CppFlags, " "),
+		globalLdFlags:         strings.Join(in.Global.LdFlags, " "),
+
+		localCommonFlags:     strings.Join(in.Local.CommonFlags, " "),
+		localAsFlags:         strings.Join(in.Local.AsFlags, " "),
+		localYasmFlags:       strings.Join(in.Local.YasmFlags, " "),
+		localCFlags:          strings.Join(in.Local.CFlags, " "),
+		localToolingCFlags:   strings.Join(in.Local.ToolingCFlags, " "),
+		localToolingCppFlags: strings.Join(in.Local.ToolingCppFlags, " "),
+		localConlyFlags:      strings.Join(in.Local.ConlyFlags, " "),
+		localCppFlags:        strings.Join(in.Local.CppFlags, " "),
+		localLdFlags:         strings.Join(in.Local.LdFlags, " "),
+
+		aidlFlags:     strings.Join(in.aidlFlags, " "),
+		rsFlags:       strings.Join(in.rsFlags, " "),
+		libFlags:      strings.Join(in.libFlags, " "),
+		extraLibFlags: strings.Join(in.extraLibFlags, " "),
+		tidyFlags:     strings.Join(in.TidyFlags, " "),
+		sAbiFlags:     strings.Join(in.SAbiFlags, " "),
+		toolchain:     in.Toolchain,
+		coverage:      in.Coverage,
+		tidy:          in.Tidy,
+		sAbiDump:      in.SAbiDump,
+		emitXrefs:     in.EmitXrefs,
 
 		systemIncludeFlags: strings.Join(in.SystemIncludeFlags, " "),
 
diff --git a/cc/vendor_public_library.go b/cc/vendor_public_library.go
index f0de267..e9d1c73 100644
--- a/cc/vendor_public_library.go
+++ b/cc/vendor_public_library.go
@@ -124,7 +124,7 @@
 	objs Objects) android.Path {
 	if !Bool(stub.Properties.Unversioned) {
 		linkerScriptFlag := "-Wl,--version-script," + stub.versionScriptPath.String()
-		flags.LdFlags = append(flags.LdFlags, linkerScriptFlag)
+		flags.Local.LdFlags = append(flags.Local.LdFlags, linkerScriptFlag)
 		flags.LdFlagsDeps = append(flags.LdFlagsDeps, stub.versionScriptPath)
 	}
 	return stub.libraryDecorator.link(ctx, flags, deps, objs)
diff --git a/cc/vndk.go b/cc/vndk.go
index 14bbf11..f25861a 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -17,6 +17,7 @@
 import (
 	"encoding/json"
 	"errors"
+	"fmt"
 	"path/filepath"
 	"sort"
 	"strings"
@@ -26,6 +27,34 @@
 	"android/soong/cc/config"
 )
 
+const (
+	llndkLibrariesTxt                = "llndk.libraries.txt"
+	vndkCoreLibrariesTxt             = "vndkcore.libraries.txt"
+	vndkSpLibrariesTxt               = "vndksp.libraries.txt"
+	vndkPrivateLibrariesTxt          = "vndkprivate.libraries.txt"
+	vndkUsingCoreVariantLibrariesTxt = "vndkcorevariant.libraries.txt"
+)
+
+func VndkLibrariesTxtModules(vndkVersion string) []string {
+	if vndkVersion == "current" {
+		return []string{
+			llndkLibrariesTxt,
+			vndkCoreLibrariesTxt,
+			vndkSpLibrariesTxt,
+			vndkPrivateLibrariesTxt,
+			vndkUsingCoreVariantLibrariesTxt,
+		}
+	}
+	// Snapshot vndks have their own *.libraries.VER.txt files.
+	// Note that snapshots don't have "vndkcorevariant.libraries.VER.txt"
+	return []string{
+		insertVndkVersion(llndkLibrariesTxt, vndkVersion),
+		insertVndkVersion(vndkCoreLibrariesTxt, vndkVersion),
+		insertVndkVersion(vndkSpLibrariesTxt, vndkVersion),
+		insertVndkVersion(vndkPrivateLibrariesTxt, vndkVersion),
+	}
+}
+
 type VndkProperties struct {
 	Vndk struct {
 		// declared as a VNDK or VNDK-SP module. The vendor variant
@@ -98,7 +127,7 @@
 	return "native:vendor:vndkspext"
 }
 
-func (vndk *vndkdep) vndkCheckLinkType(ctx android.ModuleContext, to *Module, tag dependencyTag) {
+func (vndk *vndkdep) vndkCheckLinkType(ctx android.ModuleContext, to *Module, tag DependencyTag) {
 	if to.linker == nil {
 		return
 	}
@@ -125,7 +154,7 @@
 		// Other (static and LL-NDK) libraries are allowed to link.
 		return
 	}
-	if !to.useVndk() {
+	if !to.UseVndk() {
 		ctx.ModuleErrorf("(%s) should not link to %q which is not a vendor-available library",
 			vndk.typeName(), to.Name())
 		return
@@ -199,114 +228,135 @@
 	llndkLibrariesKey                = android.NewOnceKey("llndkLibrarires")
 	vndkPrivateLibrariesKey          = android.NewOnceKey("vndkPrivateLibrarires")
 	vndkUsingCoreVariantLibrariesKey = android.NewOnceKey("vndkUsingCoreVariantLibrarires")
-	modulePathsKey                   = android.NewOnceKey("modulePaths")
-	vndkSnapshotOutputsKey           = android.NewOnceKey("vndkSnapshotOutputs")
+	vndkMustUseVendorVariantListKey  = android.NewOnceKey("vndkMustUseVendorVariantListKey")
 	vndkLibrariesLock                sync.Mutex
 
 	headerExts = []string{".h", ".hh", ".hpp", ".hxx", ".h++", ".inl", ".inc", ".ipp", ".h.generic"}
 )
 
-func vndkCoreLibraries(config android.Config) *[]string {
+func vndkCoreLibraries(config android.Config) map[string]string {
 	return config.Once(vndkCoreLibrariesKey, func() interface{} {
-		return &[]string{}
-	}).(*[]string)
-}
-
-func vndkSpLibraries(config android.Config) *[]string {
-	return config.Once(vndkSpLibrariesKey, func() interface{} {
-		return &[]string{}
-	}).(*[]string)
-}
-
-func llndkLibraries(config android.Config) *[]string {
-	return config.Once(llndkLibrariesKey, func() interface{} {
-		return &[]string{}
-	}).(*[]string)
-}
-
-func vndkPrivateLibraries(config android.Config) *[]string {
-	return config.Once(vndkPrivateLibrariesKey, func() interface{} {
-		return &[]string{}
-	}).(*[]string)
-}
-
-func vndkUsingCoreVariantLibraries(config android.Config) *[]string {
-	return config.Once(vndkUsingCoreVariantLibrariesKey, func() interface{} {
-		return &[]string{}
-	}).(*[]string)
-}
-
-func modulePaths(config android.Config) map[string]string {
-	return config.Once(modulePathsKey, func() interface{} {
 		return make(map[string]string)
 	}).(map[string]string)
 }
 
-func vndkSnapshotOutputs(config android.Config) *android.RuleBuilderInstalls {
-	return config.Once(vndkSnapshotOutputsKey, func() interface{} {
-		return &android.RuleBuilderInstalls{}
-	}).(*android.RuleBuilderInstalls)
+func vndkSpLibraries(config android.Config) map[string]string {
+	return config.Once(vndkSpLibrariesKey, func() interface{} {
+		return make(map[string]string)
+	}).(map[string]string)
+}
+
+func isLlndkLibrary(baseModuleName string, config android.Config) bool {
+	_, ok := llndkLibraries(config)[baseModuleName]
+	return ok
+}
+
+func llndkLibraries(config android.Config) map[string]string {
+	return config.Once(llndkLibrariesKey, func() interface{} {
+		return make(map[string]string)
+	}).(map[string]string)
+}
+
+func isVndkPrivateLibrary(baseModuleName string, config android.Config) bool {
+	_, ok := vndkPrivateLibraries(config)[baseModuleName]
+	return ok
+}
+
+func vndkPrivateLibraries(config android.Config) map[string]string {
+	return config.Once(vndkPrivateLibrariesKey, func() interface{} {
+		return make(map[string]string)
+	}).(map[string]string)
+}
+
+func vndkUsingCoreVariantLibraries(config android.Config) map[string]string {
+	return config.Once(vndkUsingCoreVariantLibrariesKey, func() interface{} {
+		return make(map[string]string)
+	}).(map[string]string)
+}
+
+func vndkMustUseVendorVariantList(cfg android.Config) []string {
+	return cfg.Once(vndkMustUseVendorVariantListKey, func() interface{} {
+		return config.VndkMustUseVendorVariantList
+	}).([]string)
+}
+
+// test may call this to override global configuration(config.VndkMustUseVendorVariantList)
+// when it is called, it must be before the first call to vndkMustUseVendorVariantList()
+func setVndkMustUseVendorVariantListForTest(config android.Config, mustUseVendorVariantList []string) {
+	config.Once(vndkMustUseVendorVariantListKey, func() interface{} {
+		return mustUseVendorVariantList
+	})
 }
 
 func processLlndkLibrary(mctx android.BottomUpMutatorContext, m *Module) {
 	lib := m.linker.(*llndkStubDecorator)
-	name := strings.TrimSuffix(m.Name(), llndkLibrarySuffix)
+	name := m.BaseModuleName()
+	filename := m.BaseModuleName() + ".so"
 
 	vndkLibrariesLock.Lock()
 	defer vndkLibrariesLock.Unlock()
 
-	llndkLibraries := llndkLibraries(mctx.Config())
-	if !inList(name, *llndkLibraries) {
-		*llndkLibraries = append(*llndkLibraries, name)
-		sort.Strings(*llndkLibraries)
-	}
+	llndkLibraries(mctx.Config())[name] = filename
 	if !Bool(lib.Properties.Vendor_available) {
-		vndkPrivateLibraries := vndkPrivateLibraries(mctx.Config())
-		if !inList(name, *vndkPrivateLibraries) {
-			*vndkPrivateLibraries = append(*vndkPrivateLibraries, name)
-			sort.Strings(*vndkPrivateLibraries)
-		}
+		vndkPrivateLibraries(mctx.Config())[name] = filename
 	}
 }
 
 func processVndkLibrary(mctx android.BottomUpMutatorContext, m *Module) {
-	name := strings.TrimPrefix(m.Name(), "prebuilt_")
+	name := m.BaseModuleName()
+	filename, err := getVndkFileName(m)
+	if err != nil {
+		panic(err)
+	}
 
 	vndkLibrariesLock.Lock()
 	defer vndkLibrariesLock.Unlock()
 
-	modulePaths := modulePaths(mctx.Config())
-	if mctx.DeviceConfig().VndkUseCoreVariant() && !inList(name, config.VndkMustUseVendorVariantList) {
-		vndkUsingCoreVariantLibraries := vndkUsingCoreVariantLibraries(mctx.Config())
-		if !inList(name, *vndkUsingCoreVariantLibraries) {
-			*vndkUsingCoreVariantLibraries = append(*vndkUsingCoreVariantLibraries, name)
-			sort.Strings(*vndkUsingCoreVariantLibraries)
-		}
+	if inList(name, vndkMustUseVendorVariantList(mctx.Config())) {
+		m.Properties.MustUseVendorVariant = true
 	}
+	if mctx.DeviceConfig().VndkUseCoreVariant() && !m.Properties.MustUseVendorVariant {
+		vndkUsingCoreVariantLibraries(mctx.Config())[name] = filename
+	}
+
 	if m.vndkdep.isVndkSp() {
-		vndkSpLibraries := vndkSpLibraries(mctx.Config())
-		if !inList(name, *vndkSpLibraries) {
-			*vndkSpLibraries = append(*vndkSpLibraries, name)
-			sort.Strings(*vndkSpLibraries)
-			modulePaths[name] = mctx.ModuleDir()
-		}
+		vndkSpLibraries(mctx.Config())[name] = filename
 	} else {
-		vndkCoreLibraries := vndkCoreLibraries(mctx.Config())
-		if !inList(name, *vndkCoreLibraries) {
-			*vndkCoreLibraries = append(*vndkCoreLibraries, name)
-			sort.Strings(*vndkCoreLibraries)
-			modulePaths[name] = mctx.ModuleDir()
-		}
+		vndkCoreLibraries(mctx.Config())[name] = filename
 	}
 	if !Bool(m.VendorProperties.Vendor_available) {
-		vndkPrivateLibraries := vndkPrivateLibraries(mctx.Config())
-		if !inList(name, *vndkPrivateLibraries) {
-			*vndkPrivateLibraries = append(*vndkPrivateLibraries, name)
-			sort.Strings(*vndkPrivateLibraries)
-		}
+		vndkPrivateLibraries(mctx.Config())[name] = filename
 	}
 }
 
+func IsForVndkApex(mctx android.BottomUpMutatorContext, m *Module) bool {
+	if !m.Enabled() {
+		return false
+	}
+
+	if !mctx.Device() {
+		return false
+	}
+
+	if m.Target().NativeBridge == android.NativeBridgeEnabled {
+		return false
+	}
+
+	// prebuilt vndk modules should match with device
+	// TODO(b/142675459): Use enabled: to select target device in vndk_prebuilt_shared
+	// When b/142675459 is landed, remove following check
+	if p, ok := m.linker.(*vndkPrebuiltLibraryDecorator); ok && !p.matchesWithDevice(mctx.DeviceConfig()) {
+		return false
+	}
+
+	if lib, ok := m.linker.(libraryInterface); ok {
+		useCoreVariant := m.vndkVersion() == mctx.DeviceConfig().PlatformVndkVersion() &&
+			mctx.DeviceConfig().VndkUseCoreVariant() && !m.MustUseVendorVariant()
+		return lib.shared() && m.UseVndk() && m.IsVndk() && !m.isVndkExt() && !useCoreVariant
+	}
+	return false
+}
+
 // gather list of vndk-core, vndk-sp, and ll-ndk libs
 func VndkMutator(mctx android.BottomUpMutatorContext) {
 	m, ok := mctx.Module().(*Module)
@@ -338,20 +388,115 @@
 }
 
 func init() {
+	android.RegisterModuleType("vndk_libraries_txt", VndkLibrariesTxtFactory)
 	android.RegisterSingletonType("vndk-snapshot", VndkSnapshotSingleton)
-	android.RegisterMakeVarsProvider(pctx, func(ctx android.MakeVarsContext) {
-		outputs := vndkSnapshotOutputs(ctx.Config())
-		ctx.Strict("SOONG_VNDK_SNAPSHOT_FILES", outputs.String())
+}
+
+type vndkLibrariesTxt struct {
+	android.ModuleBase
+	outputFile android.OutputPath
+}
+
+var _ android.PrebuiltEtcModule = &vndkLibrariesTxt{}
+var _ android.OutputFileProducer = &vndkLibrariesTxt{}
+
+// vndk_libraries_txt is a special kind of module type in that it name is one of
+// - llndk.libraries.txt
+// - vndkcore.libraries.txt
+// - vndksp.libraries.txt
+// - vndkprivate.libraries.txt
+// - vndkcorevariant.libraries.txt
+// A module behaves like a prebuilt_etc but its content is generated by soong.
+// By being a soong module, these files can be referenced by other soong modules.
+// For example, apex_vndk can depend on these files as prebuilt.
+func VndkLibrariesTxtFactory() android.Module {
+	m := &vndkLibrariesTxt{}
+	android.InitAndroidModule(m)
+	return m
+}
+
+func insertVndkVersion(filename string, vndkVersion string) string {
+	if index := strings.LastIndex(filename, "."); index != -1 {
+		return filename[:index] + "." + vndkVersion + filename[index:]
+	}
+	return filename
+}
+
+func (txt *vndkLibrariesTxt) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	var list []string
+	switch txt.Name() {
+	case llndkLibrariesTxt:
+		for _, filename := range android.SortedStringMapValues(llndkLibraries(ctx.Config())) {
+			if strings.HasPrefix(filename, "libclang_rt.hwasan-") {
+				continue
+			}
+			list = append(list, filename)
+		}
+	case vndkCoreLibrariesTxt:
+		list = android.SortedStringMapValues(vndkCoreLibraries(ctx.Config()))
+	case vndkSpLibrariesTxt:
+		list = android.SortedStringMapValues(vndkSpLibraries(ctx.Config()))
+	case vndkPrivateLibrariesTxt:
+		list = android.SortedStringMapValues(vndkPrivateLibraries(ctx.Config()))
+	case vndkUsingCoreVariantLibrariesTxt:
+		list = android.SortedStringMapValues(vndkUsingCoreVariantLibraries(ctx.Config()))
+	default:
+		ctx.ModuleErrorf("name(%s) is unknown.", txt.Name())
+		return
+	}
+
+	filename := insertVndkVersion(txt.Name(), ctx.DeviceConfig().PlatformVndkVersion())
+	txt.outputFile = android.PathForModuleOut(ctx, filename).OutputPath
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        android.WriteFile,
+		Output:      txt.outputFile,
+		Description: "Writing " + txt.outputFile.String(),
+		Args: map[string]string{
+			"content": strings.Join(list, "\\n"),
+		},
 	})
+
+	installPath := android.PathForModuleInstall(ctx, "etc")
+	ctx.InstallFile(installPath, filename, txt.outputFile)
+}
+
+func (txt *vndkLibrariesTxt) AndroidMkEntries() android.AndroidMkEntries {
+	return android.AndroidMkEntries{
+		Class:      "ETC",
+		OutputFile: android.OptionalPathForPath(txt.outputFile),
+		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+			func(entries *android.AndroidMkEntries) {
+				entries.SetString("LOCAL_MODULE_STEM", txt.outputFile.Base())
+			},
+		},
+	}
+}
+
+func (txt *vndkLibrariesTxt) OutputFile() android.OutputPath {
+	return txt.outputFile
+}
+
+func (txt *vndkLibrariesTxt) OutputFiles(tag string) (android.Paths, error) {
+	return android.Paths{txt.outputFile}, nil
+}
+
+func (txt *vndkLibrariesTxt) SubDir() string {
+	return ""
 }
 
 func VndkSnapshotSingleton() android.Singleton {
 	return &vndkSnapshotSingleton{}
 }
 
-type vndkSnapshotSingleton struct{}
+type vndkSnapshotSingleton struct {
+	vndkLibrariesFile   android.OutputPath
+	vndkSnapshotZipFile android.OptionalPath
+}
 
 func (c *vndkSnapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) {
+	// build these files even if PlatformVndkVersion or BoardVndkVersion is not set
+	c.buildVndkLibrariesTxtFiles(ctx)
+
 	// BOARD_VNDK_VERSION must be set to 'current' in order to generate a VNDK snapshot.
 	if ctx.DeviceConfig().VndkVersion() != "current" {
 		return
@@ -365,15 +510,42 @@
 		return
 	}
 
-	outputs := vndkSnapshotOutputs(ctx.Config())
+	var snapshotOutputs android.Paths
+
+	/*
+		VNDK snapshot zipped artifacts directory structure:
+		{SNAPSHOT_ARCH}/
+			arch-{TARGET_ARCH}-{TARGET_ARCH_VARIANT}/
+				shared/
+					vndk-core/
+						(VNDK-core libraries, e.g. libbinder.so)
+					vndk-sp/
+						(VNDK-SP libraries, e.g. libc++.so)
+			arch-{TARGET_2ND_ARCH}-{TARGET_2ND_ARCH_VARIANT}/
+				shared/
+					vndk-core/
+						(VNDK-core libraries, e.g. libbinder.so)
+					vndk-sp/
+						(VNDK-SP libraries, e.g. libc++.so)
+			binder32/
+				(This directory is newly introduced in v28 (Android P) to hold
+				prebuilts built for 32-bit binder interface.)
+				arch-{TARGET_ARCH}-{TARGE_ARCH_VARIANT}/
+					...
+			configs/
+				(various *.txt configuration files)
+			include/
+				(header files of same directory structure with source tree)
+			NOTICE_FILES/
+				(notice files of libraries, e.g. libcutils.so.txt)
+	*/
 
 	snapshotDir := "vndk-snapshot"
+	snapshotArchDir := filepath.Join(snapshotDir, ctx.DeviceConfig().DeviceArch())
 
-	vndkLibDir := make(map[android.ArchType]string)
-
-	snapshotVariantDir := ctx.DeviceConfig().DeviceArch()
+	targetArchDirMap := make(map[android.ArchType]string)
 	for _, target := range ctx.Config().Targets[android.Android] {
-		dir := snapshotVariantDir
+		dir := snapshotArchDir
 		if ctx.DeviceConfig().BinderBitness() == "32" {
 			dir = filepath.Join(dir, "binder32")
 		}
@@ -382,64 +554,55 @@
 			arch += "-" + target.Arch.ArchVariant
 		}
 		dir = filepath.Join(dir, arch)
-		vndkLibDir[target.Arch.ArchType] = dir
+		targetArchDirMap[target.Arch.ArchType] = dir
 	}
-	configsDir := filepath.Join(snapshotVariantDir, "configs")
-	noticeDir := filepath.Join(snapshotVariantDir, "NOTICE_FILES")
-	includeDir := filepath.Join(snapshotVariantDir, "include")
+	configsDir := filepath.Join(snapshotArchDir, "configs")
+	noticeDir := filepath.Join(snapshotArchDir, "NOTICE_FILES")
+	includeDir := filepath.Join(snapshotArchDir, "include")
+
+	// set of include paths exported by VNDK libraries
+	exportedIncludes := make(map[string]bool)
+
+	// generated header files among exported headers.
+	var generatedHeaders android.Paths
+
+	// set of notice files copied.
 	noticeBuilt := make(map[string]bool)
 
-	installSnapshotFileFromPath := func(path android.Path, out string) {
+	// paths of VNDK modules for GPL license checking
+	modulePaths := make(map[string]string)
+
+	// actual module names of .so files
+	// e.g. moduleNames["libprotobuf-cpp-full-3.9.1.so"] = "libprotobuf-cpp-full"
+	moduleNames := make(map[string]string)
+
+	installSnapshotFileFromPath := func(path android.Path, out string) android.OutputPath {
+		outPath := android.PathForOutput(ctx, out)
 		ctx.Build(pctx, android.BuildParams{
 			Rule:        android.Cp,
 			Input:       path,
-			Output:      android.PathForOutput(ctx, snapshotDir, out),
+			Output:      outPath,
 			Description: "vndk snapshot " + out,
 			Args: map[string]string{
 				"cpFlags": "-f -L",
 			},
 		})
-		*outputs = append(*outputs, android.RuleBuilderInstall{
-			From: android.PathForOutput(ctx, snapshotDir, out),
-			To:   out,
-		})
+		return outPath
 	}
-	installSnapshotFileFromContent := func(content, out string) {
+
+	installSnapshotFileFromContent := func(content, out string) android.OutputPath {
+		outPath := android.PathForOutput(ctx, out)
 		ctx.Build(pctx, android.BuildParams{
 			Rule:        android.WriteFile,
-			Output:      android.PathForOutput(ctx, snapshotDir, out),
+			Output:      outPath,
 			Description: "vndk snapshot " + out,
 			Args: map[string]string{
 				"content": content,
 			},
 		})
-		*outputs = append(*outputs, android.RuleBuilderInstall{
-			From: android.PathForOutput(ctx, snapshotDir, out),
-			To:   out,
-		})
+		return outPath
 	}
 
-	tryBuildNotice := func(m *Module) {
-		name := ctx.ModuleName(m) + ".so.txt"
-
-		if _, ok := noticeBuilt[name]; ok {
-			return
-		}
-
-		noticeBuilt[name] = true
-
-		if m.NoticeFile().Valid() {
-			installSnapshotFileFromPath(m.NoticeFile().Path(), filepath.Join(noticeDir, name))
-		}
-	}
-
-	vndkCoreLibraries := vndkCoreLibraries(ctx.Config())
-	vndkSpLibraries := vndkSpLibraries(ctx.Config())
-	vndkPrivateLibraries := vndkPrivateLibraries(ctx.Config())
-
-	var generatedHeaders android.Paths
-	includeDirs := make(map[string]bool)
-
 	type vndkSnapshotLibraryInterface interface {
 		exportedFlagsProducer
 		libraryInterface
@@ -448,12 +611,31 @@
 	var _ vndkSnapshotLibraryInterface = (*prebuiltLibraryLinker)(nil)
 	var _ vndkSnapshotLibraryInterface = (*libraryDecorator)(nil)
 
-	installVndkSnapshotLib := func(m *Module, l vndkSnapshotLibraryInterface, dir string) bool {
-		name := ctx.ModuleName(m)
-		libOut := filepath.Join(dir, name+".so")
+	installVndkSnapshotLib := func(m *Module, l vndkSnapshotLibraryInterface, vndkType string) (android.Paths, bool) {
+		targetArchDir, ok := targetArchDirMap[m.Target().Arch.ArchType]
+		if !ok {
+			return nil, false
+		}
 
-		installSnapshotFileFromPath(m.outputFile.Path(), libOut)
-		tryBuildNotice(m)
+		var ret android.Paths
+
+		libPath := m.outputFile.Path()
+		stem := libPath.Base()
+		snapshotLibOut := filepath.Join(targetArchDir, "shared", vndkType, stem)
+		ret = append(ret, installSnapshotFileFromPath(libPath, snapshotLibOut))
+
+		moduleNames[stem] = ctx.ModuleName(m)
+		modulePaths[stem] = ctx.ModuleDir(m)
+
+		if m.NoticeFile().Valid() {
+			noticeName := stem + ".txt"
+			// skip already copied notice file
+			if _, ok := noticeBuilt[noticeName]; !ok {
+				noticeBuilt[noticeName] = true
+				ret = append(ret, installSnapshotFileFromPath(
+					m.NoticeFile().Path(), filepath.Join(noticeDir, noticeName)))
+			}
+		}
 
 		if ctx.Config().VndkSnapshotBuildArtifacts() {
 			prop := struct {
@@ -463,42 +645,42 @@
 				RelativeInstallPath string   `json:",omitempty"`
 			}{}
 			prop.ExportedFlags = l.exportedFlags()
-			prop.ExportedDirs = l.exportedDirs()
-			prop.ExportedSystemDirs = l.exportedSystemDirs()
+			prop.ExportedDirs = l.exportedDirs().Strings()
+			prop.ExportedSystemDirs = l.exportedSystemDirs().Strings()
 			prop.RelativeInstallPath = m.RelativeInstallPath()
 
-			propOut := libOut + ".json"
+			propOut := snapshotLibOut + ".json"
 
 			j, err := json.Marshal(prop)
 			if err != nil {
 				ctx.Errorf("json marshal to %q failed: %#v", propOut, err)
-				return false
+				return nil, false
 			}
-
-			installSnapshotFileFromContent(string(j), propOut)
+			ret = append(ret, installSnapshotFileFromContent(string(j), propOut))
 		}
-		return true
+		return ret, true
 	}
 
-	isVndkSnapshotLibrary := func(m *Module) (i vndkSnapshotLibraryInterface, libDir string, isVndkSnapshotLib bool) {
+	isVndkSnapshotLibrary := func(m *Module) (i vndkSnapshotLibraryInterface, vndkType string, isVndkSnapshotLib bool) {
 		if m.Target().NativeBridge == android.NativeBridgeEnabled {
 			return nil, "", false
 		}
-		if !m.useVndk() || !m.IsForPlatform() || !m.installable() {
+		if !m.UseVndk() || !m.IsForPlatform() || !m.installable() {
 			return nil, "", false
 		}
 		l, ok := m.linker.(vndkSnapshotLibraryInterface)
 		if !ok || !l.shared() {
 			return nil, "", false
 		}
-		name := ctx.ModuleName(m)
-		if inList(name, *vndkCoreLibraries) {
-			return l, filepath.Join("shared", "vndk-core"), true
-		} else if inList(name, *vndkSpLibraries) {
-			return l, filepath.Join("shared", "vndk-sp"), true
-		} else {
-			return nil, "", false
+		if m.vndkVersion() == ctx.DeviceConfig().PlatformVndkVersion() && m.IsVndk() && !m.isVndkExt() {
+			if m.isVndkSp() {
+				return l, "vndk-sp", true
+			} else {
+				return l, "vndk-core", true
+			}
 		}
+
+		return nil, "", false
 	}
 
 	ctx.VisitAllModules(func(module android.Module) {
@@ -507,31 +689,32 @@
 			return
 		}
 
-		baseDir, ok := vndkLibDir[m.Target().Arch.ArchType]
+		l, vndkType, ok := isVndkSnapshotLibrary(m)
 		if !ok {
 			return
 		}
 
-		l, libDir, ok := isVndkSnapshotLibrary(m)
+		libs, ok := installVndkSnapshotLib(m, l, vndkType)
 		if !ok {
 			return
 		}
 
-		if !installVndkSnapshotLib(m, l, filepath.Join(baseDir, libDir)) {
-			return
-		}
+		snapshotOutputs = append(snapshotOutputs, libs...)
 
+		// We glob headers from include directories inside source tree. So we first gather
+		// all include directories inside our source tree. On the contrast, we manually
+		// collect generated headers from dependencies as they can't globbed.
 		generatedHeaders = append(generatedHeaders, l.exportedDeps()...)
 		for _, dir := range append(l.exportedDirs(), l.exportedSystemDirs()...) {
-			includeDirs[dir] = true
+			exportedIncludes[dir.String()] = true
 		}
 	})
 
 	if ctx.Config().VndkSnapshotBuildArtifacts() {
-		headers := make(map[string]bool)
+		globbedHeaders := make(map[string]bool)
 
-		for _, dir := range android.SortedStringKeys(includeDirs) {
-			// workaround to determine if dir is under output directory
+		for _, dir := range android.SortedStringKeys(exportedIncludes) {
+			// Skip if dir is for generated headers
 			if strings.HasPrefix(dir, android.PathForOutput(ctx).String()) {
 				continue
 			}
@@ -550,14 +733,14 @@
 					if strings.HasSuffix(header, "/") {
 						continue
 					}
-					headers[header] = true
+					globbedHeaders[header] = true
 				}
 			}
 		}
 
-		for _, header := range android.SortedStringKeys(headers) {
-			installSnapshotFileFromPath(android.PathForSource(ctx, header),
-				filepath.Join(includeDir, header))
+		for _, header := range android.SortedStringKeys(globbedHeaders) {
+			snapshotOutputs = append(snapshotOutputs, installSnapshotFileFromPath(
+				android.PathForSource(ctx, header), filepath.Join(includeDir, header)))
 		}
 
 		isHeader := func(path string) bool {
@@ -569,6 +752,7 @@
 			return false
 		}
 
+		// For generated headers, manually install one by one, rather than glob
 		for _, path := range android.PathsToDirectorySortedPaths(android.FirstUniquePaths(generatedHeaders)) {
 			header := path.String()
 
@@ -576,31 +760,163 @@
 				continue
 			}
 
-			installSnapshotFileFromPath(path, filepath.Join(includeDir, header))
+			snapshotOutputs = append(snapshotOutputs, installSnapshotFileFromPath(
+				path, filepath.Join(includeDir, header)))
 		}
 	}
 
-	installSnapshotFileFromContent(android.JoinWithSuffix(*vndkCoreLibraries, ".so", "\\n"),
-		filepath.Join(configsDir, "vndkcore.libraries.txt"))
-	installSnapshotFileFromContent(android.JoinWithSuffix(*vndkPrivateLibraries, ".so", "\\n"),
-		filepath.Join(configsDir, "vndkprivate.libraries.txt"))
-
-	var modulePathTxtBuilder strings.Builder
-
-	modulePaths := modulePaths(ctx.Config())
-
-	first := true
-	for _, lib := range android.SortedStringKeys(modulePaths) {
-		if first {
-			first = false
-		} else {
-			modulePathTxtBuilder.WriteString("\\n")
+	// install *.libraries.txt except vndkcorevariant.libraries.txt
+	ctx.VisitAllModules(func(module android.Module) {
+		m, ok := module.(*vndkLibrariesTxt)
+		if !ok || !m.Enabled() || m.Name() == vndkUsingCoreVariantLibrariesTxt {
+			return
 		}
-		modulePathTxtBuilder.WriteString(lib)
-		modulePathTxtBuilder.WriteString(".so ")
-		modulePathTxtBuilder.WriteString(modulePaths[lib])
+		snapshotOutputs = append(snapshotOutputs, installSnapshotFileFromPath(m.OutputFile(), filepath.Join(configsDir, m.Name())))
+	})
+
+	/*
+		Dump a map to a list file as:
+
+		{key1} {value1}
+		{key2} {value2}
+		...
+	*/
+	installMapListFile := func(m map[string]string, path string) android.OutputPath {
+		var txtBuilder strings.Builder
+		for idx, k := range android.SortedStringKeys(m) {
+			if idx > 0 {
+				txtBuilder.WriteString("\\n")
+			}
+			txtBuilder.WriteString(k)
+			txtBuilder.WriteString(" ")
+			txtBuilder.WriteString(m[k])
+		}
+		return installSnapshotFileFromContent(txtBuilder.String(), path)
 	}
 
-	installSnapshotFileFromContent(modulePathTxtBuilder.String(),
-		filepath.Join(configsDir, "module_paths.txt"))
+	/*
+		module_paths.txt contains paths on which VNDK modules are defined.
+		e.g.,
+			libbase.so system/core/base
+			libc.so bionic/libc
+			...
+	*/
+	snapshotOutputs = append(snapshotOutputs, installMapListFile(modulePaths, filepath.Join(configsDir, "module_paths.txt")))
+
+	/*
+		module_names.txt contains names as which VNDK modules are defined,
+		because output filename and module name can be different with stem and suffix properties.
+
+		e.g.,
+			libcutils.so libcutils
+			libprotobuf-cpp-full-3.9.2.so libprotobuf-cpp-full
+			...
+	*/
+	snapshotOutputs = append(snapshotOutputs, installMapListFile(moduleNames, filepath.Join(configsDir, "module_names.txt")))
+
+	// All artifacts are ready. Sort them to normalize ninja and then zip.
+	sort.Slice(snapshotOutputs, func(i, j int) bool {
+		return snapshotOutputs[i].String() < snapshotOutputs[j].String()
+	})
+
+	zipPath := android.PathForOutput(ctx, snapshotDir, "android-vndk-"+ctx.DeviceConfig().DeviceArch()+".zip")
+	zipRule := android.NewRuleBuilder()
+
+	// If output files are too many, soong_zip command can exceed ARG_MAX.
+	// So first dump file lists into a single list file, and then feed it to Soong
+	snapshotOutputList := android.PathForOutput(ctx, snapshotDir, "android-vndk-"+ctx.DeviceConfig().DeviceArch()+"_list")
+	zipRule.Command().
+		Text("( xargs").
+		FlagWithRspFileInputList("-n1 echo < ", snapshotOutputs).
+		FlagWithOutput("| tr -d \\' > ", snapshotOutputList).
+		Text(")")
+
+	zipRule.Temporary(snapshotOutputList)
+
+	zipRule.Command().
+		BuiltTool(ctx, "soong_zip").
+		FlagWithOutput("-o ", zipPath).
+		FlagWithArg("-C ", android.PathForOutput(ctx, snapshotDir).String()).
+		FlagWithInput("-l ", snapshotOutputList)
+
+	zipRule.Build(pctx, ctx, zipPath.String(), "vndk snapshot "+zipPath.String())
+	c.vndkSnapshotZipFile = android.OptionalPathForPath(zipPath)
+}
+
+func getVndkFileName(m *Module) (string, error) {
+	if library, ok := m.linker.(*libraryDecorator); ok {
+		return library.getLibNameHelper(m.BaseModuleName(), true) + ".so", nil
+	}
+	if prebuilt, ok := m.linker.(*prebuiltLibraryLinker); ok {
+		return prebuilt.libraryDecorator.getLibNameHelper(m.BaseModuleName(), true) + ".so", nil
+	}
+	return "", fmt.Errorf("VNDK library should have libraryDecorator or prebuiltLibraryLinker as linker: %T", m.linker)
+}
+
+func (c *vndkSnapshotSingleton) buildVndkLibrariesTxtFiles(ctx android.SingletonContext) {
+	llndk := android.SortedStringMapValues(llndkLibraries(ctx.Config()))
+	vndkcore := android.SortedStringMapValues(vndkCoreLibraries(ctx.Config()))
+	vndksp := android.SortedStringMapValues(vndkSpLibraries(ctx.Config()))
+	vndkprivate := android.SortedStringMapValues(vndkPrivateLibraries(ctx.Config()))
+
+	// Build list of vndk libs as merged & tagged & filter-out(libclang_rt):
+	// Since each target have different set of libclang_rt.* files,
+	// keep the common set of files in vndk.libraries.txt
+	var merged []string
+	filterOutLibClangRt := func(libList []string) (filtered []string) {
+		for _, lib := range libList {
+			if !strings.HasPrefix(lib, "libclang_rt.") {
+				filtered = append(filtered, lib)
+			}
+		}
+		return
+	}
+	merged = append(merged, addPrefix(filterOutLibClangRt(llndk), "LLNDK: ")...)
+	merged = append(merged, addPrefix(vndksp, "VNDK-SP: ")...)
+	merged = append(merged, addPrefix(filterOutLibClangRt(vndkcore), "VNDK-core: ")...)
+	merged = append(merged, addPrefix(vndkprivate, "VNDK-private: ")...)
+	c.vndkLibrariesFile = android.PathForOutput(ctx, "vndk", "vndk.libraries.txt")
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        android.WriteFile,
+		Output:      c.vndkLibrariesFile,
+		Description: "Writing " + c.vndkLibrariesFile.String(),
+		Args: map[string]string{
+			"content": strings.Join(merged, "\\n"),
+		},
+	})
+}
+
+func (c *vndkSnapshotSingleton) MakeVars(ctx android.MakeVarsContext) {
+	// Make uses LLNDK_MOVED_TO_APEX_LIBRARIES to avoid installing libraries on /system if
+	// they been moved to an apex.
+	movedToApexLlndkLibraries := []string{}
+	for lib := range llndkLibraries(ctx.Config()) {
+		// Skip bionic libs, they are handled in different manner
+		if android.DirectlyInAnyApex(&notOnHostContext{}, lib) && !isBionic(lib) {
+			movedToApexLlndkLibraries = append(movedToApexLlndkLibraries, lib)
+		}
+	}
+	ctx.Strict("LLNDK_MOVED_TO_APEX_LIBRARIES", strings.Join(movedToApexLlndkLibraries, " "))
+
+	// Make uses LLNDK_LIBRARIES to determine which libraries to install.
+	// HWASAN is only part of the LL-NDK in builds in which libc depends on HWASAN.
+	// Therefore, by removing the library here, we cause it to only be installed if libc
+	// depends on it.
+	installedLlndkLibraries := []string{}
+	for lib := range llndkLibraries(ctx.Config()) {
+		if strings.HasPrefix(lib, "libclang_rt.hwasan-") {
+			continue
+		}
+		installedLlndkLibraries = append(installedLlndkLibraries, lib)
+	}
+	sort.Strings(installedLlndkLibraries)
+	ctx.Strict("LLNDK_LIBRARIES", strings.Join(installedLlndkLibraries, " "))
+
+	ctx.Strict("VNDK_CORE_LIBRARIES", strings.Join(android.SortedStringKeys(vndkCoreLibraries(ctx.Config())), " "))
+	ctx.Strict("VNDK_SAMEPROCESS_LIBRARIES", strings.Join(android.SortedStringKeys(vndkSpLibraries(ctx.Config())), " "))
+	ctx.Strict("VNDK_PRIVATE_LIBRARIES", strings.Join(android.SortedStringKeys(vndkPrivateLibraries(ctx.Config())), " "))
+	ctx.Strict("VNDK_USING_CORE_VARIANT_LIBRARIES", strings.Join(android.SortedStringKeys(vndkUsingCoreVariantLibraries(ctx.Config())), " "))
+
+	ctx.Strict("VNDK_LIBRARIES_FILE", c.vndkLibrariesFile.String())
+	ctx.Strict("SOONG_VNDK_SNAPSHOT_ZIP", c.vndkSnapshotZipFile.String())
 }
diff --git a/cc/vndk_prebuilt.go b/cc/vndk_prebuilt.go
index 2cebb6d..c941c46 100644
--- a/cc/vndk_prebuilt.go
+++ b/cc/vndk_prebuilt.go
@@ -130,20 +130,15 @@
 func (p *vndkPrebuiltLibraryDecorator) link(ctx ModuleContext,
 	flags Flags, deps PathDeps, objs Objects) android.Path {
 
-	arches := ctx.DeviceConfig().Arches()
-	if len(arches) == 0 || arches[0].ArchType.String() != p.arch() {
-		ctx.Module().SkipInstall()
-		return nil
-	}
-
-	if ctx.DeviceConfig().BinderBitness() != p.binderBit() {
+	if !p.matchesWithDevice(ctx.DeviceConfig()) {
 		ctx.Module().SkipInstall()
 		return nil
 	}
 
 	if len(p.properties.Srcs) > 0 && p.shared() {
 		p.libraryDecorator.exportIncludes(ctx)
-		p.libraryDecorator.reexportSystemDirs(p.properties.Export_system_include_dirs...)
+		p.libraryDecorator.reexportSystemDirs(
+			android.PathsForModuleSrc(ctx, p.properties.Export_system_include_dirs)...)
 		p.libraryDecorator.reexportFlags(p.properties.Export_flags...)
 		// current VNDK prebuilts are only shared libs.
 		return p.singleSourcePath(ctx)
@@ -153,6 +148,20 @@
 	return nil
 }
 
+func (p *vndkPrebuiltLibraryDecorator) matchesWithDevice(config android.DeviceConfig) bool {
+	arches := config.Arches()
+	if len(arches) == 0 || arches[0].ArchType.String() != p.arch() {
+		return false
+	}
+	if config.BinderBitness() != p.binderBit() {
+		return false
+	}
+	if len(p.properties.Srcs) == 0 {
+		return false
+	}
+	return true
+}
+
 func (p *vndkPrebuiltLibraryDecorator) nativeCoverage() bool {
 	return false
 }
diff --git a/cc/xom.go b/cc/xom.go
index 9337990..e1cac53 100644
--- a/cc/xom.go
+++ b/cc/xom.go
@@ -68,7 +68,7 @@
 	if !disableXom || (xom.Properties.Xom != nil && *xom.Properties.Xom) {
 		// XOM is only supported on AArch64 when using lld.
 		if ctx.Arch().ArchType == android.Arm64 && ctx.useClangLld(ctx) {
-			flags.LdFlags = append(flags.LdFlags, "-Wl,-execute-only")
+			flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-execute-only")
 		}
 	}
 
diff --git a/java/aar.go b/java/aar.go
index 6426ac3..d8db192 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -72,6 +72,9 @@
 
 	// paths to additional manifest files to merge with main manifest.
 	Additional_manifests []string `android:"path"`
+
+	// do not include AndroidManifest from dependent libraries
+	Dont_merge_manifests *bool
 }
 
 type aapt struct {
@@ -225,7 +228,7 @@
 	a.transitiveManifestPaths = append(android.Paths{manifestPath}, additionalManifests...)
 	a.transitiveManifestPaths = append(a.transitiveManifestPaths, transitiveStaticLibManifests...)
 
-	if len(a.transitiveManifestPaths) > 1 {
+	if len(a.transitiveManifestPaths) > 1 && !Bool(a.aaptProperties.Dont_merge_manifests) {
 		a.mergedManifestFile = manifestMerger(ctx, a.transitiveManifestPaths[0], a.transitiveManifestPaths[1:], a.isLibrary)
 		if !a.isLibrary {
 			// Only use the merged manifest for applications.  For libraries, the transitive closure of manifests
@@ -517,7 +520,7 @@
 }
 
 func (a *AARImport) sdkVersion() string {
-	return proptools.StringDefault(a.properties.Sdk_version, defaultSdkVersion(a))
+	return String(a.properties.Sdk_version)
 }
 
 func (a *AARImport) systemModules() string {
@@ -535,6 +538,10 @@
 	return a.sdkVersion()
 }
 
+func (a *AARImport) javaVersion() string {
+	return ""
+}
+
 var _ AndroidLibraryDependency = (*AARImport)(nil)
 
 func (a *AARImport) ExportPackage() android.Path {
diff --git a/java/androidmk.go b/java/androidmk.go
index 9e9b277..0510680 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -52,6 +52,7 @@
 		if r := library.deviceProperties.Target.Hostdex.Required; len(r) > 0 {
 			fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES +=", strings.Join(r, " "))
 		}
+		fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", library.Stem()+"-hostdex")
 		fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_java_prebuilt.mk")
 	}
 }
@@ -102,6 +103,7 @@
 				if library.proguardDictionary != nil {
 					entries.SetPath("LOCAL_SOONG_PROGUARD_DICT", library.proguardDictionary)
 				}
+				entries.SetString("LOCAL_MODULE_STEM", library.Stem())
 			},
 		},
 		ExtraFooters: []android.AndroidMkExtraFootersFunc{
@@ -160,6 +162,7 @@
 				entries.SetPath("LOCAL_SOONG_HEADER_JAR", prebuilt.combinedClasspathFile)
 				entries.SetPath("LOCAL_SOONG_CLASSES_JAR", prebuilt.combinedClasspathFile)
 				entries.SetString("LOCAL_SDK_VERSION", prebuilt.sdkVersion())
+				entries.SetString("LOCAL_MODULE_STEM", prebuilt.Stem())
 			},
 		},
 	}
@@ -187,6 +190,7 @@
 				if len(prebuilt.dexpreopter.builtInstalled) > 0 {
 					entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", prebuilt.dexpreopter.builtInstalled)
 				}
+				entries.SetString("LOCAL_MODULE_STEM", prebuilt.Stem())
 			},
 		},
 	}
@@ -328,10 +332,9 @@
 				if len(app.dexpreopter.builtInstalled) > 0 {
 					entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", app.dexpreopter.builtInstalled)
 				}
-				for _, split := range app.aapt.splits {
-					install := app.onDeviceDir + "/" +
-						strings.TrimSuffix(app.installApkName, ".apk") + "_" + split.suffix + ".apk"
-					entries.AddStrings("LOCAL_SOONG_BUILT_INSTALLED", split.path.String()+":"+install)
+				for _, extra := range app.extraOutputFiles {
+					install := app.onDeviceDir + "/" + extra.Base()
+					entries.AddStrings("LOCAL_SOONG_BUILT_INSTALLED", extra.String()+":"+install)
 				}
 			},
 		},
@@ -608,10 +611,15 @@
 
 					fmt.Fprintln(w, ".PHONY: checkapi")
 					fmt.Fprintln(w, "checkapi:",
-						dstubs.apiLintTimestamp.String())
+						dstubs.Name()+"-api-lint")
 
 					fmt.Fprintln(w, ".PHONY: droidcore")
 					fmt.Fprintln(w, "droidcore: checkapi")
+
+					if dstubs.apiLintReport != nil {
+						fmt.Fprintf(w, "$(call dist-for-goals,%s,%s:%s)\n", dstubs.Name()+"-api-lint",
+							dstubs.apiLintReport.String(), "apilint/"+dstubs.Name()+"-lint-report.txt")
+					}
 				}
 				if dstubs.checkNullabilityWarningsTimestamp != nil {
 					fmt.Fprintln(w, ".PHONY:", dstubs.Name()+"-check-nullability-warnings")
diff --git a/java/app.go b/java/app.go
index 3dbcbf4..d53d626 100644
--- a/java/app.go
+++ b/java/app.go
@@ -165,7 +165,6 @@
 		a.aapt.deps(ctx, sdkDep)
 	}
 
-	embedJni := a.shouldEmbedJnis(ctx)
 	for _, jniTarget := range ctx.MultiTargets() {
 		variation := append(jniTarget.Variations(),
 			blueprint.Variation{Mutator: "link", Variation: "shared"})
@@ -174,7 +173,7 @@
 		}
 		ctx.AddFarVariationDependencies(variation, tag, a.appProperties.Jni_libs...)
 		if String(a.appProperties.Stl) == "c++_shared" {
-			if embedJni {
+			if a.shouldEmbedJnis(ctx) {
 				ctx.AddFarVariationDependencies(variation, tag, "ndk_libc++_shared")
 			}
 		}
@@ -206,6 +205,7 @@
 
 func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	a.checkPlatformAPI(ctx)
+	a.checkSdkVersion(ctx)
 	a.generateAndroidBuildActions(ctx)
 }
 
@@ -479,14 +479,13 @@
 	a.certificate = certificates[0]
 
 	// Build a final signed app package.
-	// TODO(jungjw): Consider changing this to installApkName.
-	packageFile := android.PathForModuleOut(ctx, ctx.ModuleName()+".apk")
+	packageFile := android.PathForModuleOut(ctx, a.installApkName+".apk")
 	CreateAndSignAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, dexJarFile, certificates, apkDeps)
 	a.outputFile = packageFile
 
 	for _, split := range a.aapt.splits {
 		// Sign the split APKs
-		packageFile := android.PathForModuleOut(ctx, ctx.ModuleName()+"_"+split.suffix+".apk")
+		packageFile := android.PathForModuleOut(ctx, a.installApkName+"_"+split.suffix+".apk")
 		CreateAndSignAppPackage(ctx, packageFile, split.path, nil, nil, certificates, apkDeps)
 		a.extraOutputFiles = append(a.extraOutputFiles, packageFile)
 	}
@@ -497,9 +496,9 @@
 	a.bundleFile = bundleFile
 
 	// Install the app package.
-	ctx.InstallFile(a.installDir, a.installApkName+".apk", a.outputFile)
-	for _, split := range a.aapt.splits {
-		ctx.InstallFile(a.installDir, a.installApkName+"_"+split.suffix+".apk", split.path)
+	ctx.InstallFile(a.installDir, a.outputFile.Base(), a.outputFile)
+	for _, extra := range a.extraOutputFiles {
+		ctx.InstallFile(a.installDir, extra.Base(), extra)
 	}
 }
 
@@ -985,6 +984,10 @@
 	return a.prebuilt.Name(a.ModuleBase.Name())
 }
 
+func (a *AndroidAppImport) OutputFile() android.Path {
+	return a.outputFile
+}
+
 var dpiVariantGroupType reflect.Type
 var archVariantGroupType reflect.Type
 
diff --git a/java/app_test.go b/java/app_test.go
index 05ab856..7635f3d 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -666,6 +666,44 @@
 	}
 }
 
+func TestAppSdkVersionByPartition(t *testing.T) {
+	testJavaError(t, "sdk_version must have a value when the module is located at vendor or product", `
+		android_app {
+			name: "foo",
+			srcs: ["a.java"],
+			vendor: true,
+			platform_apis: true,
+		}
+	`)
+
+	testJava(t, `
+		android_app {
+			name: "bar",
+			srcs: ["b.java"],
+			platform_apis: true,
+		}
+	`)
+
+	for _, enforce := range []bool{true, false} {
+
+		config := testConfig(nil)
+		config.TestProductVariables.EnforceProductPartitionInterface = proptools.BoolPtr(enforce)
+		bp := `
+			android_app {
+				name: "foo",
+				srcs: ["a.java"],
+				product_specific: true,
+				platform_apis: true,
+			}
+		`
+		if enforce {
+			testJavaErrorWithConfig(t, "sdk_version must have a value when the module is located at vendor or product", bp, config)
+		} else {
+			testJavaWithConfig(t, bp, config)
+		}
+	}
+}
+
 func TestJNIPackaging(t *testing.T) {
 	ctx, _ := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
 		cc_library {
@@ -876,7 +914,7 @@
 			packageNameOverride: "foo:bar",
 			expected: []string{
 				// The package apk should be still be the original name for test dependencies.
-				buildDir + "/.intermediates/foo/android_common/foo.apk",
+				buildDir + "/.intermediates/foo/android_common/bar.apk",
 				buildDir + "/target/product/test_device/system/app/bar/bar.apk",
 			},
 		},
@@ -1016,7 +1054,7 @@
 		}
 
 		// Check the certificate paths
-		signapk := variant.Output("foo.apk")
+		signapk := variant.Output(expected.moduleName + ".apk")
 		signFlag := signapk.Args["certificates"]
 		if expected.signFlag != signFlag {
 			t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected.signFlag, signFlag)
diff --git a/java/builder.go b/java/builder.go
index 0a5c79b..417a7fa 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -38,7 +38,7 @@
 	// this, all java rules write into separate directories and then are combined into a .jar file
 	// (if the rule produces .class files) or a .srcjar file (if the rule produces .java files).
 	// .srcjar files are unzipped into a temporary directory when compiled with javac.
-	javac = pctx.AndroidGomaStaticRule("javac",
+	javac = pctx.AndroidRemoteStaticRule("javac", android.SUPPORTS_GOMA,
 		blueprint.RuleParams{
 			Command: `rm -rf "$outDir" "$annoDir" "$srcJarDir" && mkdir -p "$outDir" "$annoDir" "$srcJarDir" && ` +
 				`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
@@ -182,15 +182,16 @@
 }
 
 type javaBuilderFlags struct {
-	javacFlags    string
-	bootClasspath classpath
-	classpath     classpath
-	processorPath classpath
-	processor     string
-	systemModules *systemModules
-	aidlFlags     string
-	aidlDeps      android.Paths
-	javaVersion   string
+	javacFlags     string
+	bootClasspath  classpath
+	classpath      classpath
+	java9Classpath classpath
+	processorPath  classpath
+	processor      string
+	systemModules  *systemModules
+	aidlFlags      string
+	aidlDeps       android.Paths
+	javaVersion    javaVersion
 
 	errorProneExtraJavacFlags string
 	errorProneProcessorPath   classpath
@@ -237,12 +238,14 @@
 	flags javaBuilderFlags, deps android.Paths) {
 
 	deps = append(deps, srcJars...)
+	classpath := flags.classpath
 
 	var bootClasspath string
-	if flags.javaVersion == "1.9" {
+	if flags.javaVersion.usesJavaModules() {
 		var systemModuleDeps android.Paths
 		bootClasspath, systemModuleDeps = flags.systemModules.FormJavaSystemModulesPath(ctx.Device())
 		deps = append(deps, systemModuleDeps...)
+		classpath = append(flags.java9Classpath, classpath...)
 	} else {
 		deps = append(deps, flags.bootClasspath...)
 		if len(flags.bootClasspath) == 0 && ctx.Device() {
@@ -254,7 +257,7 @@
 		}
 	}
 
-	deps = append(deps, flags.classpath...)
+	deps = append(deps, classpath...)
 	deps = append(deps, flags.processorPath...)
 
 	processor := "-proc:none"
@@ -277,9 +280,9 @@
 			Args: map[string]string{
 				"annoDir":       android.PathForModuleOut(ctx, intermediatesDir, "anno").String(),
 				"bootClasspath": bootClasspath,
-				"classpath":     flags.classpath.FormJavaClassPath("-classpath"),
+				"classpath":     classpath.FormJavaClassPath("-classpath"),
 				"javacFlags":    flags.javacFlags,
-				"javaVersion":   flags.javaVersion,
+				"javaVersion":   flags.javaVersion.String(),
 				"outDir":        android.PathForModuleOut(ctx, "javac", "classes.xref").String(),
 				"processorpath": flags.processorPath.FormJavaClassPath("-processorpath"),
 				"processor":     processor,
@@ -294,18 +297,29 @@
 
 	var deps android.Paths
 	deps = append(deps, srcJars...)
-	deps = append(deps, flags.bootClasspath...)
-	deps = append(deps, flags.classpath...)
+
+	classpath := flags.classpath
 
 	var bootClasspath string
-	if len(flags.bootClasspath) == 0 && ctx.Device() {
-		// explicitly specify -bootclasspath "" if the bootclasspath is empty to
-		// ensure java does not fall back to the default bootclasspath.
-		bootClasspath = `--bootclasspath ""`
+	if flags.javaVersion.usesJavaModules() {
+		var systemModuleDeps android.Paths
+		bootClasspath, systemModuleDeps = flags.systemModules.FormTurbineSystemModulesPath(ctx.Device())
+		deps = append(deps, systemModuleDeps...)
+		classpath = append(flags.java9Classpath, classpath...)
 	} else {
-		bootClasspath = strings.Join(flags.bootClasspath.FormTurbineClasspath("--bootclasspath "), " ")
+		deps = append(deps, flags.bootClasspath...)
+		if len(flags.bootClasspath) == 0 && ctx.Device() {
+			// explicitly specify -bootclasspath "" if the bootclasspath is empty to
+			// ensure turbine does not fall back to the default bootclasspath.
+			bootClasspath = `--bootclasspath ""`
+		} else {
+			bootClasspath = flags.bootClasspath.FormTurbineClassPath("--bootclasspath ")
+		}
 	}
 
+	deps = append(deps, classpath...)
+	deps = append(deps, flags.processorPath...)
+
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        turbine,
 		Description: "turbine",
@@ -316,9 +330,9 @@
 			"javacFlags":    flags.javacFlags,
 			"bootClasspath": bootClasspath,
 			"srcJars":       strings.Join(srcJars.Strings(), " "),
-			"classpath":     strings.Join(flags.classpath.FormTurbineClasspath("--classpath "), " "),
+			"classpath":     classpath.FormTurbineClassPath("--classpath "),
 			"outDir":        android.PathForModuleOut(ctx, "turbine", "classes").String(),
-			"javaVersion":   flags.javaVersion,
+			"javaVersion":   flags.javaVersion.String(),
 		},
 	})
 }
@@ -339,11 +353,14 @@
 
 	deps = append(deps, srcJars...)
 
+	classpath := flags.classpath
+
 	var bootClasspath string
-	if flags.javaVersion == "1.9" {
+	if flags.javaVersion.usesJavaModules() {
 		var systemModuleDeps android.Paths
 		bootClasspath, systemModuleDeps = flags.systemModules.FormJavaSystemModulesPath(ctx.Device())
 		deps = append(deps, systemModuleDeps...)
+		classpath = append(flags.java9Classpath, classpath...)
 	} else {
 		deps = append(deps, flags.bootClasspath...)
 		if len(flags.bootClasspath) == 0 && ctx.Device() {
@@ -355,7 +372,7 @@
 		}
 	}
 
-	deps = append(deps, flags.classpath...)
+	deps = append(deps, classpath...)
 	deps = append(deps, flags.processorPath...)
 
 	processor := "-proc:none"
@@ -381,14 +398,14 @@
 		Args: map[string]string{
 			"javacFlags":    flags.javacFlags,
 			"bootClasspath": bootClasspath,
-			"classpath":     flags.classpath.FormJavaClassPath("-classpath"),
+			"classpath":     classpath.FormJavaClassPath("-classpath"),
 			"processorpath": flags.processorPath.FormJavaClassPath("-processorpath"),
 			"processor":     processor,
 			"srcJars":       strings.Join(srcJars.Strings(), " "),
 			"srcJarDir":     android.PathForModuleOut(ctx, intermediatesDir, srcJarDir).String(),
 			"outDir":        android.PathForModuleOut(ctx, intermediatesDir, outDir).String(),
 			"annoDir":       android.PathForModuleOut(ctx, intermediatesDir, annoDir).String(),
-			"javaVersion":   flags.javaVersion,
+			"javaVersion":   flags.javaVersion.String(),
 		},
 	})
 }
@@ -506,18 +523,26 @@
 
 type classpath android.Paths
 
-func (x *classpath) FormJavaClassPath(optName string) string {
+func (x *classpath) formJoinedClassPath(optName string, sep string) string {
 	if optName != "" && !strings.HasSuffix(optName, "=") && !strings.HasSuffix(optName, " ") {
 		optName += " "
 	}
 	if len(*x) > 0 {
-		return optName + strings.Join(x.Strings(), ":")
+		return optName + strings.Join(x.Strings(), sep)
 	} else {
 		return ""
 	}
 }
+func (x *classpath) FormJavaClassPath(optName string) string {
+	return x.formJoinedClassPath(optName, ":")
+}
 
-func (x *classpath) FormTurbineClasspath(optName string) []string {
+func (x *classpath) FormTurbineClassPath(optName string) string {
+	return x.formJoinedClassPath(optName, " ")
+}
+
+// FormRepeatedClassPath returns a list of arguments with the given optName prefixed to each element of the classpath.
+func (x *classpath) FormRepeatedClassPath(optName string) []string {
 	if x == nil || *x == nil {
 		return nil
 	}
@@ -550,9 +575,9 @@
 	deps android.Paths
 }
 
-// Returns a --system argument in the form javac expects with -source 1.9.  If forceEmpty is true,
-// returns --system=none if the list is empty to ensure javac does not fall back to the default
-// system modules.
+// Returns a --system argument in the form javac expects with -source 1.9 and the list of files to
+// depend on.  If forceEmpty is true, returns --system=none if the list is empty to ensure javac
+// does not fall back to the default system modules.
 func (x *systemModules) FormJavaSystemModulesPath(forceEmpty bool) (string, android.Paths) {
 	if x != nil {
 		return "--system=" + x.dir.String(), x.deps
@@ -562,3 +587,16 @@
 		return "", nil
 	}
 }
+
+// Returns a --system argument in the form turbine expects with -source 1.9 and the list of files to
+// depend on.  If forceEmpty is true, returns --bootclasspath "" if the list is empty to ensure turbine
+// does not fall back to the default bootclasspath.
+func (x *systemModules) FormTurbineSystemModulesPath(forceEmpty bool) (string, android.Paths) {
+	if x != nil {
+		return "--system " + x.dir.String(), x.deps
+	} else if forceEmpty {
+		return `--bootclasspath ""`, nil
+	} else {
+		return "", nil
+	}
+}
diff --git a/java/config/config.go b/java/config/config.go
index f418ee7..333de32 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -87,12 +87,10 @@
 		return ctx.Config().Getenv("ANDROID_JAVA_HOME")
 	})
 	pctx.VariableFunc("JlinkVersion", func(ctx android.PackageVarContext) string {
-		switch ctx.Config().Getenv("EXPERIMENTAL_USE_OPENJDK11_TOOLCHAIN") {
-		case "true":
-			return "11"
-		default:
-			return "9"
+		if override := ctx.Config().Getenv("OVERRIDE_JLINK_VERSION_NUMBER"); override != "" {
+			return override
 		}
+		return "11"
 	})
 
 	pctx.SourcePathVariable("JavaToolchain", "${JavaHome}/bin")
diff --git a/java/config/makevars.go b/java/config/makevars.go
index 2fa6f89..981a736 100644
--- a/java/config/makevars.go
+++ b/java/config/makevars.go
@@ -29,12 +29,6 @@
 	ctx.Strict("TARGET_DEFAULT_BOOTCLASSPATH_LIBRARIES", strings.Join(DefaultBootclasspathLibraries, " "))
 	ctx.Strict("DEFAULT_SYSTEM_MODULES", DefaultSystemModules)
 
-	if ctx.Config().TargetOpenJDK9() {
-		ctx.Strict("DEFAULT_JAVA_LANGUAGE_VERSION", "1.9")
-	} else {
-		ctx.Strict("DEFAULT_JAVA_LANGUAGE_VERSION", "1.8")
-	}
-
 	ctx.Strict("ANDROID_JAVA_HOME", "${JavaHome}")
 	ctx.Strict("ANDROID_JAVA8_HOME", "prebuilts/jdk/jdk8/${hostPrebuiltTag}")
 	ctx.Strict("ANDROID_JAVA9_HOME", "prebuilts/jdk/jdk9/${hostPrebuiltTag}")
diff --git a/java/dex.go b/java/dex.go
index c8a4fa8..5b25b21 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -85,8 +85,8 @@
 func (j *Module) d8Flags(ctx android.ModuleContext, flags javaBuilderFlags) ([]string, android.Paths) {
 	d8Flags := j.dexCommonFlags(ctx)
 
-	d8Flags = append(d8Flags, flags.bootClasspath.FormTurbineClasspath("--lib ")...)
-	d8Flags = append(d8Flags, flags.classpath.FormTurbineClasspath("--lib ")...)
+	d8Flags = append(d8Flags, flags.bootClasspath.FormRepeatedClassPath("--lib ")...)
+	d8Flags = append(d8Flags, flags.classpath.FormRepeatedClassPath("--lib ")...)
 
 	var d8Deps android.Paths
 	d8Deps = append(d8Deps, flags.bootClasspath...)
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 2a142ba..a29665e 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -51,6 +51,7 @@
 
 type bootImageConfig struct {
 	name         string
+	stem         string
 	modules      []string
 	dexLocations []string
 	dexPaths     android.WritablePaths
@@ -71,9 +72,9 @@
 	// In addition, each .art file has an associated .oat and .vdex file, and an
 	// unstripped .oat file
 	for i, m := range image.modules {
-		name := image.name
+		name := image.stem
 		if i != 0 {
-			name += "-" + m
+			name += "-" + stemOf(m)
 		}
 
 		for _, ext := range exts {
@@ -123,6 +124,10 @@
 }
 
 func skipDexpreoptBootJars(ctx android.PathContext) bool {
+	if dexpreoptGlobalConfig(ctx).DisablePreopt {
+		return true
+	}
+
 	if ctx.Config().UnbundledBuild() {
 		return true
 	}
@@ -135,6 +140,12 @@
 	return false
 }
 
+func skipDexpreoptArtBootJars(ctx android.BuilderContext) bool {
+	// with EMMA_INSTRUMENT_FRAMEWORK=true ART boot class path libraries have dependencies on framework,
+	// therefore dexpreopt ART libraries cannot be dexpreopted in isolation => no ART boot image
+	return ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK")
+}
+
 type dexpreoptBootJars struct {
 	defaultBootImage *bootImage
 	otherImages      []*bootImage
@@ -142,6 +153,14 @@
 	dexpreoptConfigForMake android.WritablePath
 }
 
+// Accessor function for the apex package. Returns nil if dexpreopt is disabled.
+func DexpreoptedArtApexJars(ctx android.BuilderContext) map[android.ArchType]android.Paths {
+	if skipDexpreoptBootJars(ctx) || skipDexpreoptArtBootJars(ctx) {
+		return nil
+	}
+	return artBootImageConfig(ctx).imagesDeps
+}
+
 // dexpreoptBoot singleton rules
 func (d *dexpreoptBootJars) GenerateBuildActions(ctx android.SingletonContext) {
 	if skipDexpreoptBootJars(ctx) {
@@ -165,7 +184,12 @@
 
 	// Always create the default boot image first, to get a unique profile rule for all images.
 	d.defaultBootImage = buildBootImage(ctx, defaultBootImageConfig(ctx))
+	if !skipDexpreoptArtBootJars(ctx) {
+		// Create boot image for the ART apex (build artifacts are accessed via the global boot image config).
+		buildBootImage(ctx, artBootImageConfig(ctx))
+	}
 	if global.GenerateApexImage {
+		// Create boot images for the JIT-zygote experiment.
 		d.otherImages = append(d.otherImages, buildBootImage(ctx, apexBootImageConfig(ctx)))
 	}
 
@@ -174,8 +198,6 @@
 
 // buildBootImage takes a bootImageConfig, creates rules to build it, and returns a *bootImage.
 func buildBootImage(ctx android.SingletonContext, config bootImageConfig) *bootImage {
-	global := dexpreoptGlobalConfig(ctx)
-
 	image := newBootImage(ctx, config)
 
 	bootDexJars := make(android.Paths, len(image.modules))
@@ -219,12 +241,9 @@
 	bootFrameworkProfileRule(ctx, image, missingDeps)
 
 	var allFiles android.Paths
-
-	if !global.DisablePreopt {
-		for _, target := range image.targets {
-			files := buildBootImageRuleForArch(ctx, image, target.Arch.ArchType, profile, missingDeps)
-			allFiles = append(allFiles, files.Paths()...)
-		}
+	for _, target := range image.targets {
+		files := buildBootImageRuleForArch(ctx, image, target.Arch.ArchType, profile, missingDeps)
+		allFiles = append(allFiles, files.Paths()...)
 	}
 
 	if image.zip != nil {
@@ -247,7 +266,7 @@
 	global := dexpreoptGlobalConfig(ctx)
 
 	symbolsDir := image.symbolsDir.Join(ctx, "system/framework", arch.String())
-	symbolsFile := symbolsDir.Join(ctx, image.name+".oat")
+	symbolsFile := symbolsDir.Join(ctx, image.stem+".oat")
 	outputDir := image.dir.Join(ctx, "system/framework", arch.String())
 	outputPath := image.images[arch]
 	oatLocation := pathtools.ReplaceExtension(dexpreopt.PathToLocation(outputPath, arch), "oat")
@@ -377,8 +396,9 @@
 	if global.DisableGenerateProfile || ctx.Config().IsPdkBuild() || ctx.Config().UnbundledBuild() {
 		return nil
 	}
-	return ctx.Config().Once(bootImageProfileRuleKey, func() interface{} {
+	profile := ctx.Config().Once(bootImageProfileRuleKey, func() interface{} {
 		tools := global.Tools
+		defaultProfile := "frameworks/base/config/boot-image-profile.txt"
 
 		rule := android.NewRuleBuilder()
 		rule.MissingDeps(missingDeps)
@@ -390,18 +410,13 @@
 			bootImageProfile = combinedBootImageProfile
 		} else if len(global.BootImageProfiles) == 1 {
 			bootImageProfile = global.BootImageProfiles[0]
+		} else if path := android.ExistentPathForSource(ctx, defaultProfile); path.Valid() {
+			bootImageProfile = path.Path()
 		} else {
-			// If not set, use the default.  Some branches like master-art-host don't have frameworks/base, so manually
-			// handle the case that the default is missing.  Those branches won't attempt to build the profile rule,
-			// and if they do they'll get a missing deps error.
-			defaultProfile := "frameworks/base/config/boot-image-profile.txt"
-			path := android.ExistentPathForSource(ctx, defaultProfile)
-			if path.Valid() {
-				bootImageProfile = path.Path()
-			} else {
-				missingDeps = append(missingDeps, defaultProfile)
-				bootImageProfile = android.PathForOutput(ctx, "missing")
-			}
+			// No profile (not even a default one, which is the case on some branches
+			// like master-art-host that don't have frameworks/base).
+			// Return nil and continue without profile.
+			return nil
 		}
 
 		profile := image.dir.Join(ctx, "boot.prof")
@@ -421,7 +436,11 @@
 		image.profileInstalls = rule.Installs()
 
 		return profile
-	}).(android.WritablePath)
+	})
+	if profile == nil {
+		return nil // wrap nil into a typed pointer with value nil
+	}
+	return profile.(android.WritablePath)
 }
 
 var bootImageProfileRuleKey = android.NewOnceKey("bootImageProfileRule")
diff --git a/java/dexpreopt_bootjars_test.go b/java/dexpreopt_bootjars_test.go
index 244bd52..a684ab2 100644
--- a/java/dexpreopt_bootjars_test.go
+++ b/java/dexpreopt_bootjars_test.go
@@ -62,7 +62,6 @@
 	bootArt := dexpreoptBootJars.Output("boot.art")
 
 	expectedInputs := []string{
-		"dex_bootjars/boot.prof",
 		"dex_bootjars_input/foo.jar",
 		"dex_bootjars_input/bar.jar",
 		"dex_bootjars_input/baz.jar",
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index 429bbdb..a6661b3 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -96,32 +96,53 @@
 	return targets
 }
 
-func getBootImageConfig(ctx android.PathContext, key android.OnceKey, name string,
-	needZip bool) bootImageConfig {
+func stemOf(moduleName string) string {
+	// b/139391334: the stem of framework-minus-apex is framework
+	// This is hard coded here until we find a good way to query the stem
+	// of a module before any other mutators are run
+	if moduleName == "framework-minus-apex" {
+		return "framework"
+	}
+	return moduleName
+}
+
+// Construct a variant of the global config for dexpreopted bootclasspath jars. The variants differ
+// in the list of input jars (libcore, framework, or both), in the naming scheme for the dexpreopt
+// files (ART recognizes "apex" names as special), and whether to include a zip archive.
+//
+// 'name' is a string unique for each profile (used in directory names and ninja rule names)
+// 'stem' is the basename of the image: the resulting filenames are <stem>[-<jar>].{art,oat,vdex}.
+func getBootImageConfig(ctx android.PathContext, key android.OnceKey, name string, stem string,
+	needZip bool, artApexJarsOnly bool) bootImageConfig {
+
 	return ctx.Config().Once(key, func() interface{} {
 		global := dexpreoptGlobalConfig(ctx)
 
 		artModules := global.ArtApexJars
-		nonFrameworkModules := concat(artModules, global.ProductUpdatableBootModules)
-		frameworkModules := android.RemoveListFromList(global.BootJars, nonFrameworkModules)
-		imageModules := concat(artModules, frameworkModules)
+		imageModules := artModules
 
 		var bootLocations []string
 
 		for _, m := range artModules {
 			bootLocations = append(bootLocations,
-				filepath.Join("/apex/com.android.art/javalib", m+".jar"))
+				filepath.Join("/apex/com.android.art/javalib", stemOf(m)+".jar"))
 		}
 
-		for _, m := range frameworkModules {
-			bootLocations = append(bootLocations,
-				filepath.Join("/system/framework", m+".jar"))
+		if !artApexJarsOnly {
+			nonFrameworkModules := concat(artModules, global.ProductUpdatableBootModules)
+			frameworkModules := android.RemoveListFromList(global.BootJars, nonFrameworkModules)
+			imageModules = concat(imageModules, frameworkModules)
+
+			for _, m := range frameworkModules {
+				bootLocations = append(bootLocations,
+					filepath.Join("/system/framework", stemOf(m)+".jar"))
+			}
 		}
 
 		// The path to bootclasspath dex files needs to be known at module GenerateAndroidBuildAction time, before
 		// the bootclasspath modules have been compiled.  Set up known paths for them, the singleton rules will copy
 		// them there.
-		// TODO: use module dependencies instead
+		// TODO(b/143682396): use module dependencies instead
 		var bootDexPaths android.WritablePaths
 		for _, m := range imageModules {
 			bootDexPaths = append(bootDexPaths,
@@ -133,13 +154,14 @@
 
 		var zip android.WritablePath
 		if needZip {
-			zip = dir.Join(ctx, name+".zip")
+			zip = dir.Join(ctx, stem+".zip")
 		}
 
 		targets := dexpreoptTargets(ctx)
 
 		imageConfig := bootImageConfig{
 			name:         name,
+			stem:         stem,
 			modules:      imageModules,
 			dexLocations: bootLocations,
 			dexPaths:     bootDexPaths,
@@ -153,7 +175,7 @@
 
 		for _, target := range targets {
 			imageDir := dir.Join(ctx, "system/framework", target.Arch.ArchType.String())
-			imageConfig.images[target.Arch.ArchType] = imageDir.Join(ctx, name+".art")
+			imageConfig.images[target.Arch.ArchType] = imageDir.Join(ctx, stem+".art")
 
 			imagesDeps := make([]android.Path, 0, len(imageConfig.modules)*3)
 			for _, dep := range imageConfig.moduleFiles(ctx, imageDir, ".art", ".oat", ".vdex") {
@@ -166,15 +188,25 @@
 	}).(bootImageConfig)
 }
 
+// Default config is the one that goes in the system image. It includes both libcore and framework.
 var defaultBootImageConfigKey = android.NewOnceKey("defaultBootImageConfig")
-var apexBootImageConfigKey = android.NewOnceKey("apexBootImageConfig")
 
 func defaultBootImageConfig(ctx android.PathContext) bootImageConfig {
-	return getBootImageConfig(ctx, defaultBootImageConfigKey, "boot", true)
+	return getBootImageConfig(ctx, defaultBootImageConfigKey, "boot", "boot", true, false)
 }
 
+// Apex config is used for the JIT-zygote experiment. It includes both libcore and framework, but AOT-compiles only libcore.
+var apexBootImageConfigKey = android.NewOnceKey("apexBootImageConfig")
+
 func apexBootImageConfig(ctx android.PathContext) bootImageConfig {
-	return getBootImageConfig(ctx, apexBootImageConfigKey, "apex", false)
+	return getBootImageConfig(ctx, apexBootImageConfigKey, "apex", "apex", false, false)
+}
+
+// ART config is the one used for the ART apex. It includes only libcore.
+var artBootImageConfigKey = android.NewOnceKey("artBootImageConfig")
+
+func artBootImageConfig(ctx android.PathContext) bootImageConfig {
+	return getBootImageConfig(ctx, artBootImageConfigKey, "art", "boot", false, true)
 }
 
 func defaultBootclasspath(ctx android.PathContext) []string {
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 12335ff..54f93fe 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -404,7 +404,7 @@
 var _ android.OutputFileProducer = (*Javadoc)(nil)
 
 func (j *Javadoc) sdkVersion() string {
-	return proptools.StringDefault(j.properties.Sdk_version, defaultSdkVersion(j))
+	return String(j.properties.Sdk_version)
 }
 
 func (j *Javadoc) systemModules() string {
@@ -422,25 +422,16 @@
 func (j *Javadoc) addDeps(ctx android.BottomUpMutatorContext) {
 	if ctx.Device() {
 		sdkDep := decodeSdkDep(ctx, sdkContext(j))
-		if sdkDep.hasStandardLibs() {
-			if sdkDep.useDefaultLibs {
-				ctx.AddVariationDependencies(nil, bootClasspathTag, config.DefaultBootclasspathLibraries...)
-				if ctx.Config().TargetOpenJDK9() {
-					ctx.AddVariationDependencies(nil, systemModulesTag, config.DefaultSystemModules)
-				}
-				if sdkDep.hasFrameworkLibs() {
-					ctx.AddVariationDependencies(nil, libTag, config.DefaultLibraries...)
-				}
-			} else if sdkDep.useModule {
-				if ctx.Config().TargetOpenJDK9() {
-					ctx.AddVariationDependencies(nil, systemModulesTag, sdkDep.systemModules)
-				}
-				ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.modules...)
+		if sdkDep.useDefaultLibs {
+			ctx.AddVariationDependencies(nil, bootClasspathTag, config.DefaultBootclasspathLibraries...)
+			ctx.AddVariationDependencies(nil, systemModulesTag, config.DefaultSystemModules)
+			if sdkDep.hasFrameworkLibs() {
+				ctx.AddVariationDependencies(nil, libTag, config.DefaultLibraries...)
 			}
-		} else if sdkDep.systemModules != "" {
-			// Add the system modules to both the system modules and bootclasspath.
+		} else if sdkDep.useModule {
+			ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.bootclasspath...)
 			ctx.AddVariationDependencies(nil, systemModulesTag, sdkDep.systemModules)
-			ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.systemModules)
+			ctx.AddVariationDependencies(nil, java9LibTag, sdkDep.java9Classpath...)
 		}
 	}
 
@@ -515,7 +506,8 @@
 
 	sdkDep := decodeSdkDep(ctx, sdkContext(j))
 	if sdkDep.invalidVersion {
-		ctx.AddMissingDependencies(sdkDep.modules)
+		ctx.AddMissingDependencies(sdkDep.bootclasspath)
+		ctx.AddMissingDependencies(sdkDep.java9Classpath)
 	} else if sdkDep.useFiles {
 		deps.bootClasspath = append(deps.bootClasspath, sdkDep.jars...)
 	}
@@ -548,6 +540,13 @@
 			default:
 				ctx.ModuleErrorf("depends on non-java module %q", otherName)
 			}
+		case java9LibTag:
+			switch dep := module.(type) {
+			case Dependency:
+				deps.java9Classpath = append(deps.java9Classpath, dep.HeaderJars()...)
+			default:
+				ctx.ModuleErrorf("depends on non-java module %q", otherName)
+			}
 		case systemModulesTag:
 			if deps.systemModules != nil {
 				panic("Found two system module dependencies")
@@ -669,7 +668,7 @@
 	cmd := javadocSystemModulesCmd(ctx, rule, j.srcFiles, outDir, srcJarDir, srcJarList,
 		deps.systemModules, deps.classpath, j.sourcepaths)
 
-	cmd.FlagWithArg("-source ", javaVersion).
+	cmd.FlagWithArg("-source ", javaVersion.String()).
 		Flag("-J-Xmx1024m").
 		Flag("-XDignore.symbol.file").
 		Flag("-Xdoclint:none")
@@ -1183,6 +1182,7 @@
 	updateCurrentApiTimestamp     android.WritablePath
 	checkLastReleasedApiTimestamp android.WritablePath
 	apiLintTimestamp              android.WritablePath
+	apiLintReport                 android.WritablePath
 
 	checkNullabilityWarningsTimestamp android.WritablePath
 
@@ -1325,13 +1325,8 @@
 		validatingNullability :=
 			strings.Contains(d.Javadoc.args, "--validate-nullability-from-merged-stubs") ||
 				String(d.properties.Validate_nullability_from_list) != ""
+
 		migratingNullability := String(d.properties.Previous_api) != ""
-
-		if !(migratingNullability || validatingNullability) {
-			ctx.PropertyErrorf("previous_api",
-				"has to be non-empty if annotations was enabled (unless validating nullability)")
-		}
-
 		if migratingNullability {
 			previousApi := android.PathForModuleSrc(ctx, String(d.properties.Previous_api))
 			cmd.FlagWithInput("--migrate-nullness ", previousApi)
@@ -1436,12 +1431,12 @@
 	}
 }
 
-func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersion string, srcs android.Paths,
+func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersion javaVersion, srcs android.Paths,
 	srcJarList android.Path, bootclasspath, classpath classpath, sourcepaths android.Paths) *android.RuleBuilderCommand {
 	cmd := rule.Command().BuiltTool(ctx, "metalava").
 		Flag(config.JavacVmFlags).
 		FlagWithArg("-encoding ", "UTF-8").
-		FlagWithArg("-source ", javaVersion).
+		FlagWithArg("-source ", javaVersion.String()).
 		FlagWithRspFileInputList("@", srcs).
 		FlagWithInput("@", srcJarList)
 
@@ -1553,6 +1548,8 @@
 		} else {
 			cmd.Flag("--api-lint")
 		}
+		d.apiLintReport = android.PathForModuleOut(ctx, "api_lint_report.txt")
+		cmd.FlagWithOutput("--report-even-if-suppressed ", d.apiLintReport)
 
 		d.inclusionAnnotationsFlags(ctx, cmd)
 		d.mergeAnnoDirFlags(ctx, cmd)
diff --git a/java/java.go b/java/java.go
index be48256..9bbdff7 100644
--- a/java/java.go
+++ b/java/java.go
@@ -54,6 +54,18 @@
 	android.RegisterSingletonType("kythe_java_extract", kytheExtractJavaFactory)
 }
 
+func (j *Module) checkSdkVersion(ctx android.ModuleContext) {
+	if j.SocSpecific() || j.DeviceSpecific() ||
+		(j.ProductSpecific() && ctx.Config().EnforceProductPartitionInterface()) {
+		if sc, ok := ctx.Module().(sdkContext); ok {
+			if sc.sdkVersion() == "" {
+				ctx.PropertyErrorf("sdk_version",
+					"sdk_version must have a value when the module is located at vendor or product(only if PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE is set).")
+			}
+		}
+	}
+}
+
 func (j *Module) checkPlatformAPI(ctx android.ModuleContext) {
 	if sc, ok := ctx.Module().(sdkContext); ok {
 		usePlatformAPI := proptools.Bool(j.deviceProperties.Platform_apis)
@@ -140,10 +152,10 @@
 	Use_tools_jar *bool
 
 	Openjdk9 struct {
-		// List of source files that should only be used when passing -source 1.9
+		// List of source files that should only be used when passing -source 1.9 or higher
 		Srcs []string `android:"path"`
 
-		// List of javac flags that should only be used when passing -source 1.9
+		// List of javac flags that should only be used when passing -source 1.9 or higher
 		Javacflags []string
 	}
 
@@ -274,6 +286,9 @@
 	// otherwise provides defaults libraries to add to the bootclasspath.
 	System_modules *string
 
+	// set the name of the output
+	Stem *string
+
 	UncompressDex bool `blueprint:"mutated"`
 	IsSDKLibrary  bool `blueprint:"mutated"`
 }
@@ -427,9 +442,15 @@
 	target android.Target
 }
 
+func IsJniDepTag(depTag blueprint.DependencyTag) bool {
+	_, ok := depTag.(*jniDependencyTag)
+	return ok
+}
+
 var (
 	staticLibTag          = dependencyTag{name: "staticlib"}
 	libTag                = dependencyTag{name: "javalib"}
+	java9LibTag           = dependencyTag{name: "java9lib"}
 	pluginTag             = dependencyTag{name: "plugin"}
 	bootClasspathTag      = dependencyTag{name: "bootclasspath"}
 	systemModulesTag      = dependencyTag{name: "system modules"}
@@ -443,27 +464,19 @@
 	usesLibTag            = dependencyTag{name: "uses-library"}
 )
 
-func defaultSdkVersion(ctx checkVendorModuleContext) string {
-	if ctx.SocSpecific() || ctx.DeviceSpecific() {
-		return "system_current"
-	}
-	return ""
-}
-
-type checkVendorModuleContext interface {
-	SocSpecific() bool
-	DeviceSpecific() bool
-}
-
 type sdkDep struct {
 	useModule, useFiles, useDefaultLibs, invalidVersion bool
 
-	modules []string
+	// The modules that will be added to the bootclasspath when targeting 1.8 or lower
+	bootclasspath []string
 
 	// The default system modules to use. Will be an empty string if no system
 	// modules are to be used.
 	systemModules string
 
+	// The modules that will be added ot the classpath when targeting 1.9 or higher
+	java9Classpath []string
+
 	frameworkResModule string
 
 	jars android.Paths
@@ -497,7 +510,7 @@
 }
 
 func (j *Module) sdkVersion() string {
-	return proptools.StringDefault(j.deviceProperties.Sdk_version, defaultSdkVersion(j))
+	return String(j.deviceProperties.Sdk_version)
 }
 
 func (j *Module) systemModules() string {
@@ -521,26 +534,22 @@
 func (j *Module) deps(ctx android.BottomUpMutatorContext) {
 	if ctx.Device() {
 		sdkDep := decodeSdkDep(ctx, sdkContext(j))
-		if sdkDep.hasStandardLibs() {
-			if sdkDep.useDefaultLibs {
-				ctx.AddVariationDependencies(nil, bootClasspathTag, config.DefaultBootclasspathLibraries...)
-				ctx.AddVariationDependencies(nil, systemModulesTag, config.DefaultSystemModules)
-				if sdkDep.hasFrameworkLibs() {
-					ctx.AddVariationDependencies(nil, libTag, config.DefaultLibraries...)
-				}
-			} else if sdkDep.useModule {
-				ctx.AddVariationDependencies(nil, systemModulesTag, sdkDep.systemModules)
-				ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.modules...)
-				if j.deviceProperties.EffectiveOptimizeEnabled() {
-					ctx.AddVariationDependencies(nil, proguardRaiseTag, config.DefaultBootclasspathLibraries...)
-					ctx.AddVariationDependencies(nil, proguardRaiseTag, config.DefaultLibraries...)
-				}
+		if sdkDep.useDefaultLibs {
+			ctx.AddVariationDependencies(nil, bootClasspathTag, config.DefaultBootclasspathLibraries...)
+			ctx.AddVariationDependencies(nil, systemModulesTag, config.DefaultSystemModules)
+			if sdkDep.hasFrameworkLibs() {
+				ctx.AddVariationDependencies(nil, libTag, config.DefaultLibraries...)
 			}
-		} else if sdkDep.systemModules != "" {
-			// Add the system modules to both the system modules and bootclasspath.
+		} else if sdkDep.useModule {
+			ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.bootclasspath...)
 			ctx.AddVariationDependencies(nil, systemModulesTag, sdkDep.systemModules)
-			ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.systemModules)
+			ctx.AddVariationDependencies(nil, java9LibTag, sdkDep.java9Classpath...)
+			if j.deviceProperties.EffectiveOptimizeEnabled() && sdkDep.hasStandardLibs() {
+				ctx.AddVariationDependencies(nil, proguardRaiseTag, config.DefaultBootclasspathLibraries...)
+				ctx.AddVariationDependencies(nil, proguardRaiseTag, config.DefaultLibraries...)
+			}
 		}
+
 		if ctx.ModuleName() == "android_stubs_current" ||
 			ctx.ModuleName() == "android_system_stubs_current" ||
 			ctx.ModuleName() == "android_test_stubs_current" {
@@ -632,6 +641,7 @@
 
 type deps struct {
 	classpath          classpath
+	java9Classpath     classpath
 	bootClasspath      classpath
 	processorPath      classpath
 	processorClasses   []string
@@ -741,7 +751,8 @@
 	if ctx.Device() {
 		sdkDep := decodeSdkDep(ctx, sdkContext(j))
 		if sdkDep.invalidVersion {
-			ctx.AddMissingDependencies(sdkDep.modules)
+			ctx.AddMissingDependencies(sdkDep.bootclasspath)
+			ctx.AddMissingDependencies(sdkDep.java9Classpath)
 		} else if sdkDep.useFiles {
 			// sdkDep.jar is actually equivalent to turbine header.jar.
 			deps.classpath = append(deps.classpath, sdkDep.jars...)
@@ -789,6 +800,8 @@
 				// sdk lib names from dependencies are re-exported
 				j.exportedSdkLibs = append(j.exportedSdkLibs, dep.ExportedSdkLibs()...)
 				deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...)
+			case java9LibTag:
+				deps.java9Classpath = append(deps.java9Classpath, dep.HeaderJars()...)
 			case staticLibTag:
 				deps.classpath = append(deps.classpath, dep.HeaderJars()...)
 				deps.staticJars = append(deps.staticJars, dep.ImplementationJars()...)
@@ -862,8 +875,7 @@
 	return deps
 }
 
-func getJavaVersion(ctx android.ModuleContext, javaVersion string, sdkContext sdkContext) string {
-	var ret string
+func getJavaVersion(ctx android.ModuleContext, javaVersion string, sdkContext sdkContext) javaVersion {
 	v := sdkContext.sdkVersion()
 	// For PDK builds, use the latest SDK version instead of "current"
 	if ctx.Config().IsPdkBuild() &&
@@ -881,41 +893,65 @@
 		ctx.PropertyErrorf("sdk_version", "%s", err)
 	}
 	if javaVersion != "" {
-		ret = normalizeJavaVersion(ctx, javaVersion)
+		return normalizeJavaVersion(ctx, javaVersion)
 	} else if ctx.Device() && sdk <= 23 {
-		ret = "1.7"
-	} else if ctx.Device() && sdk <= 29 || !ctx.Config().TargetOpenJDK9() {
-		ret = "1.8"
-	} else if ctx.Device() &&
-		sdkContext.sdkVersion() != "" &&
-		sdkContext.sdkVersion() != "none" &&
-		sdkContext.sdkVersion() != "core_platform" &&
-		sdk == android.FutureApiLevel {
-		// TODO(ccross): once we generate stubs we should be able to use 1.9 for sdk_version: "current"
-		ret = "1.8"
+		return JAVA_VERSION_7
+	} else if ctx.Device() && sdk <= 29 {
+		return JAVA_VERSION_8
+	} else if ctx.Device() && ctx.Config().UnbundledBuildUsePrebuiltSdks() {
+		// TODO(b/142896162): once we have prebuilt system modules we can use 1.9 for unbundled builds
+		return JAVA_VERSION_8
 	} else {
-		ret = "1.9"
+		return JAVA_VERSION_9
 	}
-
-	return ret
 }
 
-func normalizeJavaVersion(ctx android.ModuleContext, javaVersion string) string {
+type javaVersion int
+
+const (
+	JAVA_VERSION_UNSUPPORTED = 0
+	JAVA_VERSION_6           = 6
+	JAVA_VERSION_7           = 7
+	JAVA_VERSION_8           = 8
+	JAVA_VERSION_9           = 9
+)
+
+func (v javaVersion) String() string {
+	switch v {
+	case JAVA_VERSION_6:
+		return "1.6"
+	case JAVA_VERSION_7:
+		return "1.7"
+	case JAVA_VERSION_8:
+		return "1.8"
+	case JAVA_VERSION_9:
+		return "1.9"
+	default:
+		return "unsupported"
+	}
+}
+
+// Returns true if javac targeting this version uses system modules instead of a bootclasspath.
+func (v javaVersion) usesJavaModules() bool {
+	return v >= 9
+}
+
+func normalizeJavaVersion(ctx android.BaseModuleContext, javaVersion string) javaVersion {
 	switch javaVersion {
 	case "1.6", "6":
-		return "1.6"
+		return JAVA_VERSION_6
 	case "1.7", "7":
-		return "1.7"
+		return JAVA_VERSION_7
 	case "1.8", "8":
-		return "1.8"
+		return JAVA_VERSION_8
 	case "1.9", "9":
-		return "1.9"
+		return JAVA_VERSION_9
 	case "10", "11":
 		ctx.PropertyErrorf("java_version", "Java language levels above 9 are not supported")
-		return "unsupported"
+		return JAVA_VERSION_UNSUPPORTED
 	default:
 		ctx.PropertyErrorf("java_version", "Unrecognized Java language level")
-		return "unrecognized"
+		return JAVA_VERSION_UNSUPPORTED
 	}
 }
 
@@ -928,7 +964,7 @@
 
 	// javac flags.
 	javacFlags := j.properties.Javacflags
-	if flags.javaVersion == "1.9" {
+	if flags.javaVersion.usesJavaModules() {
 		javacFlags = append(javacFlags, j.properties.Openjdk9.Javacflags...)
 	}
 	if ctx.Config().MinimizeJavaDebugInfo() {
@@ -936,6 +972,7 @@
 		// disk and memory usage.
 		javacFlags = append(javacFlags, "-g:source,lines")
 	}
+	javacFlags = append(javacFlags, "-Xlint:-dep-ann")
 
 	if ctx.Config().RunErrorProne() {
 		if config.ErrorProneClasspath == nil {
@@ -956,13 +993,13 @@
 	// classpath
 	flags.bootClasspath = append(flags.bootClasspath, deps.bootClasspath...)
 	flags.classpath = append(flags.classpath, deps.classpath...)
+	flags.java9Classpath = append(flags.java9Classpath, deps.java9Classpath...)
 	flags.processorPath = append(flags.processorPath, deps.processorPath...)
 
 	flags.processor = strings.Join(deps.processorClasses, ",")
 
-	if len(flags.bootClasspath) == 0 && ctx.Host() && flags.javaVersion != "1.9" &&
-		decodeSdkDep(ctx, sdkContext(j)).hasStandardLibs() &&
-		inList(flags.javaVersion, []string{"1.6", "1.7", "1.8"}) {
+	if len(flags.bootClasspath) == 0 && ctx.Host() && !flags.javaVersion.usesJavaModules() &&
+		decodeSdkDep(ctx, sdkContext(j)).hasStandardLibs() {
 		// Give host-side tools a version of OpenJDK's standard libraries
 		// close to what they're targeting. As of Dec 2017, AOSP is only
 		// bundling OpenJDK 8 and 9, so nothing < 8 is available.
@@ -986,7 +1023,7 @@
 		}
 	}
 
-	if j.properties.Patch_module != nil && flags.javaVersion == "1.9" {
+	if j.properties.Patch_module != nil && flags.javaVersion.usesJavaModules() {
 		// Manually specify build directory in case it is not under the repo root.
 		// (javac doesn't seem to expand into symbolc links when searching for patch-module targets, so
 		// just adding a symlink under the root doesn't help.)
@@ -1019,7 +1056,7 @@
 	deps := j.collectDeps(ctx)
 	flags := j.collectBuilderFlags(ctx, deps)
 
-	if flags.javaVersion == "1.9" {
+	if flags.javaVersion.usesJavaModules() {
 		j.properties.Srcs = append(j.properties.Srcs, j.properties.Openjdk9.Srcs...)
 	}
 	srcFiles := android.PathsForModuleSrcExcludes(ctx, j.properties.Srcs, j.properties.Exclude_srcs)
@@ -1571,6 +1608,10 @@
 	return depTag == staticLibTag
 }
 
+func (j *Module) Stem() string {
+	return proptools.StringDefault(j.deviceProperties.Stem, j.Name())
+}
+
 //
 // Java libraries (.jar file)
 //
@@ -1600,7 +1641,8 @@
 }
 
 func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	j.dexpreopter.installPath = android.PathForModuleInstall(ctx, "framework", ctx.ModuleName()+".jar")
+	j.checkSdkVersion(ctx)
+	j.dexpreopter.installPath = android.PathForModuleInstall(ctx, "framework", j.Stem()+".jar")
 	j.dexpreopter.isSDKLibrary = j.deviceProperties.IsSDKLibrary
 	j.dexpreopter.isInstallable = Bool(j.properties.Installable)
 	j.dexpreopter.uncompressedDex = shouldUncompressDex(ctx, &j.dexpreopter)
@@ -1924,6 +1966,9 @@
 
 	// if set to true, run Jetifier against .jar file. Defaults to false.
 	Jetifier *bool
+
+	// set the name of the output
+	Stem *string
 }
 
 type Import struct {
@@ -1940,7 +1985,7 @@
 }
 
 func (j *Import) sdkVersion() string {
-	return proptools.StringDefault(j.properties.Sdk_version, defaultSdkVersion(j))
+	return String(j.properties.Sdk_version)
 }
 
 func (j *Import) minSdkVersion() string {
@@ -1959,6 +2004,10 @@
 	return j.prebuilt.Name(j.ModuleBase.Name())
 }
 
+func (j *Import) Stem() string {
+	return proptools.StringDefault(j.properties.Stem, j.ModuleBase.Name())
+}
+
 func (j *Import) DepsMutator(ctx android.BottomUpMutatorContext) {
 	ctx.AddVariationDependencies(nil, libTag, j.properties.Libs...)
 }
@@ -1966,7 +2015,7 @@
 func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	jars := android.PathsForModuleSrc(ctx, j.properties.Jars)
 
-	jarName := ctx.ModuleName() + ".jar"
+	jarName := j.Stem() + ".jar"
 	outputFile := android.PathForModuleOut(ctx, "combined", jarName)
 	TransformJarsToJar(ctx, outputFile, "for prebuilts", jars, android.OptionalPath{},
 		false, j.properties.Exclude_files, j.properties.Exclude_dirs)
@@ -2000,7 +2049,7 @@
 	j.exportedSdkLibs = android.FirstUniqueStrings(j.exportedSdkLibs)
 	if Bool(j.properties.Installable) {
 		ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"),
-			ctx.ModuleName()+".jar", outputFile)
+			jarName, outputFile)
 	}
 }
 
@@ -2112,6 +2161,9 @@
 
 type DexImportProperties struct {
 	Jars []string `android:"path"`
+
+	// set the name of the output
+	Stem *string
 }
 
 type DexImport struct {
@@ -2140,12 +2192,16 @@
 	return j.prebuilt.Name(j.ModuleBase.Name())
 }
 
+func (j *DexImport) Stem() string {
+	return proptools.StringDefault(j.properties.Stem, j.ModuleBase.Name())
+}
+
 func (j *DexImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	if len(j.properties.Jars) != 1 {
 		ctx.PropertyErrorf("jars", "exactly one jar must be provided")
 	}
 
-	j.dexpreopter.installPath = android.PathForModuleInstall(ctx, "framework", ctx.ModuleName()+".jar")
+	j.dexpreopter.installPath = android.PathForModuleInstall(ctx, "framework", j.Stem()+".jar")
 	j.dexpreopter.isInstallable = true
 	j.dexpreopter.uncompressedDex = shouldUncompressDex(ctx, &j.dexpreopter)
 
diff --git a/java/java_test.go b/java/java_test.go
index 3767d1b..e7b68dd 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -23,6 +23,8 @@
 	"strings"
 	"testing"
 
+	"github.com/google/blueprint/proptools"
+
 	"android/soong/android"
 	"android/soong/cc"
 	"android/soong/dexpreopt"
@@ -148,9 +150,9 @@
 		"prebuilts/sdk/17/public/android.jar":         nil,
 		"prebuilts/sdk/17/public/framework.aidl":      nil,
 		"prebuilts/sdk/17/system/android.jar":         nil,
-		"prebuilts/sdk/25/public/android.jar":         nil,
-		"prebuilts/sdk/25/public/framework.aidl":      nil,
-		"prebuilts/sdk/25/system/android.jar":         nil,
+		"prebuilts/sdk/29/public/android.jar":         nil,
+		"prebuilts/sdk/29/public/framework.aidl":      nil,
+		"prebuilts/sdk/29/system/android.jar":         nil,
 		"prebuilts/sdk/current/core/android.jar":      nil,
 		"prebuilts/sdk/current/public/android.jar":    nil,
 		"prebuilts/sdk/current/public/framework.aidl": nil,
@@ -228,9 +230,13 @@
 	android.FailIfErrored(t, errs)
 }
 
-func testJavaError(t *testing.T, pattern string, bp string) {
+func testJavaError(t *testing.T, pattern string, bp string) (*android.TestContext, android.Config) {
 	t.Helper()
-	config := testConfig(nil)
+	return testJavaErrorWithConfig(t, pattern, bp, testConfig(nil))
+}
+
+func testJavaErrorWithConfig(t *testing.T, pattern string, bp string, config android.Config) (*android.TestContext, android.Config) {
+	t.Helper()
 	ctx := testContext(bp, nil)
 
 	pathCtx := android.PathContextForTesting(config, nil)
@@ -240,20 +246,26 @@
 	_, errs := ctx.ParseBlueprintsFiles("Android.bp")
 	if len(errs) > 0 {
 		android.FailIfNoMatchingErrors(t, pattern, errs)
-		return
+		return ctx, config
 	}
 	_, errs = ctx.PrepareBuildActions(config)
 	if len(errs) > 0 {
 		android.FailIfNoMatchingErrors(t, pattern, errs)
-		return
+		return ctx, config
 	}
 
 	t.Fatalf("missing expected error %q (0 errors are returned)", pattern)
+
+	return ctx, config
 }
 
 func testJava(t *testing.T, bp string) (*android.TestContext, android.Config) {
 	t.Helper()
-	config := testConfig(nil)
+	return testJavaWithConfig(t, bp, testConfig(nil))
+}
+
+func testJavaWithConfig(t *testing.T, bp string, config android.Config) (*android.TestContext, android.Config) {
+	t.Helper()
 	ctx := testContext(bp, nil)
 	run(t, ctx, config)
 
@@ -315,29 +327,38 @@
 	}
 }
 
-func TestSdkVersion(t *testing.T) {
-	ctx, _ := testJava(t, `
+func TestSdkVersionByPartition(t *testing.T) {
+	testJavaError(t, "sdk_version must have a value when the module is located at vendor or product", `
 		java_library {
 			name: "foo",
 			srcs: ["a.java"],
 			vendor: true,
 		}
+	`)
 
+	testJava(t, `
 		java_library {
 			name: "bar",
 			srcs: ["b.java"],
 		}
 	`)
 
-	foo := ctx.ModuleForTests("foo", "android_common").Module().(*Library)
-	bar := ctx.ModuleForTests("bar", "android_common").Module().(*Library)
+	for _, enforce := range []bool{true, false} {
 
-	if foo.sdkVersion() != "system_current" {
-		t.Errorf("If sdk version of vendor module is empty, it must change to system_current.")
-	}
-
-	if bar.sdkVersion() != "" {
-		t.Errorf("If sdk version of non-vendor module is empty, it keeps empty.")
+		config := testConfig(nil)
+		config.TestProductVariables.EnforceProductPartitionInterface = proptools.BoolPtr(enforce)
+		bp := `
+			java_library {
+				name: "foo",
+				srcs: ["a.java"],
+				product_specific: true,
+			}
+		`
+		if enforce {
+			testJavaErrorWithConfig(t, "sdk_version must have a value when the module is located at vendor or product", bp, config)
+		} else {
+			testJavaWithConfig(t, bp, config)
+		}
 	}
 }
 
diff --git a/java/kotlin.go b/java/kotlin.go
index 8306907..5319a4f 100644
--- a/java/kotlin.go
+++ b/java/kotlin.go
@@ -26,7 +26,7 @@
 	"github.com/google/blueprint"
 )
 
-var kotlinc = pctx.AndroidGomaStaticRule("kotlinc",
+var kotlinc = pctx.AndroidRemoteStaticRule("kotlinc", android.SUPPORTS_GOMA,
 	blueprint.RuleParams{
 		Command: `rm -rf "$classesDir" "$srcJarDir" "$kotlinBuildFile" "$emptyDir" && ` +
 			`mkdir -p "$classesDir" "$srcJarDir" "$emptyDir" && ` +
@@ -88,7 +88,7 @@
 	})
 }
 
-var kapt = pctx.AndroidGomaStaticRule("kapt",
+var kapt = pctx.AndroidRemoteStaticRule("kapt", android.SUPPORTS_GOMA,
 	blueprint.RuleParams{
 		Command: `rm -rf "$srcJarDir" "$kotlinBuildFile" "$kaptDir" && mkdir -p "$srcJarDir" "$kaptDir" && ` +
 			`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
@@ -133,7 +133,7 @@
 	deps = append(deps, srcJars...)
 	deps = append(deps, flags.processorPath...)
 
-	kaptProcessorPath := flags.processorPath.FormTurbineClasspath("-P plugin:org.jetbrains.kotlin.kapt3:apclasspath=")
+	kaptProcessorPath := flags.processorPath.FormRepeatedClassPath("-P plugin:org.jetbrains.kotlin.kapt3:apclasspath=")
 
 	kaptProcessor := ""
 	if flags.processor != "" {
@@ -141,8 +141,8 @@
 	}
 
 	encodedJavacFlags := kaptEncodeFlags([][2]string{
-		{"-source", flags.javaVersion},
-		{"-target", flags.javaVersion},
+		{"-source", flags.javaVersion.String()},
+		{"-target", flags.javaVersion.String()},
 	})
 
 	kotlinName := filepath.Join(ctx.ModuleDir(), ctx.ModuleSubDir(), ctx.ModuleName())
diff --git a/java/proto.go b/java/proto.go
index e013bb4..4d735eb 100644
--- a/java/proto.go
+++ b/java/proto.go
@@ -108,10 +108,10 @@
 		case "nano":
 			flags.proto.OutTypeFlag = "--javanano_out"
 			typeToPlugin = "javanano"
-		case "lite":
+		case "lite", "":
 			flags.proto.OutTypeFlag = "--java_out"
 			flags.proto.OutParams = append(flags.proto.OutParams, "lite")
-		case "full", "":
+		case "full":
 			flags.proto.OutTypeFlag = "--java_out"
 		default:
 			ctx.PropertyErrorf("proto.type", "unknown proto type %q",
diff --git a/java/sdk.go b/java/sdk.go
index c6a9a73..6f0f432 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -122,7 +122,7 @@
 		if (!jarPath.Valid() || !aidlPath.Valid()) && ctx.Config().AllowMissingDependencies() {
 			return sdkDep{
 				invalidVersion: true,
-				modules:        []string{fmt.Sprintf("sdk_%s_%s_android", api, v)},
+				bootclasspath:  []string{fmt.Sprintf("sdk_%s_%s_android", api, v)},
 			}
 		}
 
@@ -144,20 +144,14 @@
 	}
 
 	toModule := func(m, r string, aidl android.Path) sdkDep {
-		ret := sdkDep{
+		return sdkDep{
 			useModule:          true,
-			modules:            []string{m, config.DefaultLambdaStubsLibrary},
-			systemModules:      m + "_system_modules",
+			bootclasspath:      []string{m, config.DefaultLambdaStubsLibrary},
+			systemModules:      "core-current-stubs-system-modules",
+			java9Classpath:     []string{m},
 			frameworkResModule: r,
 			aidl:               android.OptionalPathForPath(aidl),
 		}
-
-		if m == "core.current.stubs" {
-			ret.systemModules = "core-current-stubs-system-modules"
-			// core_current does not include framework classes.
-			ret.noFrameworksLibs = true
-		}
-		return ret
 	}
 
 	// Ensures that the specificed system SDK version is one of BOARD_SYSTEMSDK_VERSIONS (for vendor apks)
@@ -192,13 +186,16 @@
 			ctx.PropertyErrorf("sdk_version",
 				`system_modules is required to be set to a non-empty value when sdk_version is "none", did you mean sdk_version: "core_platform"?`)
 		} else if systemModules == "none" {
-			// Normalize no system modules to an empty string.
-			systemModules = ""
+			return sdkDep{
+				noStandardLibs: true,
+			}
 		}
 
 		return sdkDep{
+			useModule:      true,
 			noStandardLibs: true,
 			systemModules:  systemModules,
+			bootclasspath:  []string{systemModules},
 		}
 	case "core_platform":
 		return sdkDep{
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 476e549..b7efcff 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -79,9 +79,6 @@
 }
 
 type sdkLibraryProperties struct {
-	// list of optional source files that are part of API but not part of runtime library.
-	Api_srcs []string `android:"arch_variant"`
-
 	// List of Java libraries that will be in the classpath when building stubs
 	Stub_only_libs []string `android:"arch_variant"`
 
@@ -461,7 +458,6 @@
 
 	props.Name = proptools.StringPtr(module.docsName(apiScope))
 	props.Srcs = append(props.Srcs, module.Library.Module.properties.Srcs...)
-	props.Srcs = append(props.Srcs, module.sdkLibraryProperties.Api_srcs...)
 	props.Sdk_version = proptools.StringPtr(sdkVersion)
 	props.Installable = proptools.BoolPtr(false)
 	// A droiddoc module has only one Libs property and doesn't distinguish between
diff --git a/java/sdk_test.go b/java/sdk_test.go
index fd47d81..525c898 100644
--- a/java/sdk_test.go
+++ b/java/sdk_test.go
@@ -28,174 +28,188 @@
 
 func TestClasspath(t *testing.T) {
 	var classpathTestcases = []struct {
-		name          string
-		unbundled     bool
-		pdk           bool
-		moduleType    string
-		host          android.OsClass
-		properties    string
-		bootclasspath []string
-		system        string
-		classpath     []string
-		aidl          string
+		name       string
+		unbundled  bool
+		pdk        bool
+		moduleType string
+		host       android.OsClass
+		properties string
+
+		// for java 8
+		bootclasspath  []string
+		java8classpath []string
+
+		// for java 9
+		system         string
+		java9classpath []string
+
+		forces8 bool // if set, javac will always be called with java 8 arguments
+
+		aidl string
 	}{
 		{
-			name:          "default",
-			bootclasspath: config.DefaultBootclasspathLibraries,
-			system:        config.DefaultSystemModules,
-			classpath:     config.DefaultLibraries,
-			aidl:          "-Iframework/aidl",
+			name:           "default",
+			bootclasspath:  config.DefaultBootclasspathLibraries,
+			system:         config.DefaultSystemModules,
+			java8classpath: config.DefaultLibraries,
+			java9classpath: config.DefaultLibraries,
+			aidl:           "-Iframework/aidl",
 		},
 		{
-			name:          `sdk_version:"core_platform"`,
-			properties:    `sdk_version:"core_platform"`,
-			bootclasspath: config.DefaultBootclasspathLibraries,
-			system:        config.DefaultSystemModules,
-			classpath:     []string{},
-			aidl:          "",
+			name:           `sdk_version:"core_platform"`,
+			properties:     `sdk_version:"core_platform"`,
+			bootclasspath:  config.DefaultBootclasspathLibraries,
+			system:         config.DefaultSystemModules,
+			java8classpath: []string{},
+			aidl:           "",
 		},
 		{
-			name:          "blank sdk version",
-			properties:    `sdk_version: "",`,
-			bootclasspath: config.DefaultBootclasspathLibraries,
-			system:        config.DefaultSystemModules,
-			classpath:     config.DefaultLibraries,
-			aidl:          "-Iframework/aidl",
+			name:           "blank sdk version",
+			properties:     `sdk_version: "",`,
+			bootclasspath:  config.DefaultBootclasspathLibraries,
+			system:         config.DefaultSystemModules,
+			java8classpath: config.DefaultLibraries,
+			java9classpath: config.DefaultLibraries,
+			aidl:           "-Iframework/aidl",
 		},
 		{
 
-			name:          "sdk v25",
-			properties:    `sdk_version: "25",`,
-			bootclasspath: []string{`""`},
-			system:        "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
-			classpath:     []string{"prebuilts/sdk/25/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
-			aidl:          "-pprebuilts/sdk/25/public/framework.aidl",
+			name:           "sdk v29",
+			properties:     `sdk_version: "29",`,
+			bootclasspath:  []string{`""`},
+			forces8:        true,
+			java8classpath: []string{"prebuilts/sdk/29/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+			aidl:           "-pprebuilts/sdk/29/public/framework.aidl",
 		},
 		{
 
-			name:          "current",
-			properties:    `sdk_version: "current",`,
-			bootclasspath: []string{"android_stubs_current", "core-lambda-stubs"},
-			system:        "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
-			aidl:          "-p" + buildDir + "/framework.aidl",
+			name:           "current",
+			properties:     `sdk_version: "current",`,
+			bootclasspath:  []string{"android_stubs_current", "core-lambda-stubs"},
+			system:         "core-current-stubs-system-modules",
+			java9classpath: []string{"android_stubs_current"},
+			aidl:           "-p" + buildDir + "/framework.aidl",
 		},
 		{
 
-			name:          "system_current",
-			properties:    `sdk_version: "system_current",`,
-			bootclasspath: []string{"android_system_stubs_current", "core-lambda-stubs"},
-			system:        "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
-			aidl:          "-p" + buildDir + "/framework.aidl",
+			name:           "system_current",
+			properties:     `sdk_version: "system_current",`,
+			bootclasspath:  []string{"android_system_stubs_current", "core-lambda-stubs"},
+			system:         "core-current-stubs-system-modules",
+			java9classpath: []string{"android_system_stubs_current"},
+			aidl:           "-p" + buildDir + "/framework.aidl",
 		},
 		{
 
-			name:          "system_25",
-			properties:    `sdk_version: "system_25",`,
-			bootclasspath: []string{`""`},
-			system:        "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
-			classpath:     []string{"prebuilts/sdk/25/system/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
-			aidl:          "-pprebuilts/sdk/25/public/framework.aidl",
+			name:           "system_29",
+			properties:     `sdk_version: "system_29",`,
+			bootclasspath:  []string{`""`},
+			forces8:        true,
+			java8classpath: []string{"prebuilts/sdk/29/system/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+			aidl:           "-pprebuilts/sdk/29/public/framework.aidl",
 		},
 		{
 
-			name:          "test_current",
-			properties:    `sdk_version: "test_current",`,
-			bootclasspath: []string{"android_test_stubs_current", "core-lambda-stubs"},
-			system:        "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
-			aidl:          "-p" + buildDir + "/framework.aidl",
+			name:           "test_current",
+			properties:     `sdk_version: "test_current",`,
+			bootclasspath:  []string{"android_test_stubs_current", "core-lambda-stubs"},
+			system:         "core-current-stubs-system-modules",
+			java9classpath: []string{"android_test_stubs_current"},
+			aidl:           "-p" + buildDir + "/framework.aidl",
 		},
 		{
 
-			name:          "core_current",
-			properties:    `sdk_version: "core_current",`,
-			bootclasspath: []string{"core.current.stubs", "core-lambda-stubs"},
-			system:        "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
+			name:           "core_current",
+			properties:     `sdk_version: "core_current",`,
+			bootclasspath:  []string{"core.current.stubs", "core-lambda-stubs"},
+			system:         "core-current-stubs-system-modules",
+			java9classpath: []string{"core.current.stubs"},
 		},
 		{
 
-			name:          "nostdlib",
-			properties:    `sdk_version: "none", system_modules: "none"`,
-			system:        "none",
-			bootclasspath: []string{`""`},
-			classpath:     []string{},
+			name:           "nostdlib",
+			properties:     `sdk_version: "none", system_modules: "none"`,
+			system:         "none",
+			bootclasspath:  []string{`""`},
+			java8classpath: []string{},
 		},
 		{
 
-			name:          "nostdlib system_modules",
-			properties:    `sdk_version: "none", system_modules: "core-platform-api-stubs-system-modules"`,
-			system:        "core-platform-api-stubs-system-modules",
-			bootclasspath: []string{"core-platform-api-stubs-system-modules-lib"},
-			classpath:     []string{},
+			name:           "nostdlib system_modules",
+			properties:     `sdk_version: "none", system_modules: "core-platform-api-stubs-system-modules"`,
+			system:         "core-platform-api-stubs-system-modules",
+			bootclasspath:  []string{"core-platform-api-stubs-system-modules-lib"},
+			java8classpath: []string{},
 		},
 		{
 
-			name:          "host default",
-			moduleType:    "java_library_host",
-			properties:    ``,
-			host:          android.Host,
-			bootclasspath: []string{"jdk8/jre/lib/jce.jar", "jdk8/jre/lib/rt.jar"},
-			classpath:     []string{},
+			name:           "host default",
+			moduleType:     "java_library_host",
+			properties:     ``,
+			host:           android.Host,
+			bootclasspath:  []string{"jdk8/jre/lib/jce.jar", "jdk8/jre/lib/rt.jar"},
+			java8classpath: []string{},
 		},
 		{
 
-			name:          "host supported default",
-			host:          android.Host,
-			properties:    `host_supported: true,`,
-			classpath:     []string{},
-			bootclasspath: []string{"jdk8/jre/lib/jce.jar", "jdk8/jre/lib/rt.jar"},
+			name:           "host supported default",
+			host:           android.Host,
+			properties:     `host_supported: true,`,
+			java8classpath: []string{},
+			bootclasspath:  []string{"jdk8/jre/lib/jce.jar", "jdk8/jre/lib/rt.jar"},
 		},
 		{
-			name:       "host supported nostdlib",
-			host:       android.Host,
-			properties: `host_supported: true, sdk_version: "none", system_modules: "none"`,
-			classpath:  []string{},
+			name:           "host supported nostdlib",
+			host:           android.Host,
+			properties:     `host_supported: true, sdk_version: "none", system_modules: "none"`,
+			java8classpath: []string{},
 		},
 		{
 
-			name:          "unbundled sdk v25",
-			unbundled:     true,
-			properties:    `sdk_version: "25",`,
-			bootclasspath: []string{`""`},
-			system:        "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
-			classpath:     []string{"prebuilts/sdk/25/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
-			aidl:          "-pprebuilts/sdk/25/public/framework.aidl",
+			name:           "unbundled sdk v29",
+			unbundled:      true,
+			properties:     `sdk_version: "29",`,
+			bootclasspath:  []string{`""`},
+			forces8:        true,
+			java8classpath: []string{"prebuilts/sdk/29/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+			aidl:           "-pprebuilts/sdk/29/public/framework.aidl",
 		},
 		{
 
-			name:          "unbundled current",
-			unbundled:     true,
-			properties:    `sdk_version: "current",`,
-			bootclasspath: []string{`""`},
-			system:        "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
-			classpath:     []string{"prebuilts/sdk/current/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
-			aidl:          "-pprebuilts/sdk/current/public/framework.aidl",
+			name:           "unbundled current",
+			unbundled:      true,
+			properties:     `sdk_version: "current",`,
+			bootclasspath:  []string{`""`},
+			forces8:        true,
+			java8classpath: []string{"prebuilts/sdk/current/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+			aidl:           "-pprebuilts/sdk/current/public/framework.aidl",
 		},
 
 		{
-			name:          "pdk default",
-			pdk:           true,
-			bootclasspath: []string{`""`},
-			system:        "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
-			classpath:     []string{"prebuilts/sdk/25/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
-			aidl:          "-pprebuilts/sdk/25/public/framework.aidl",
+			name:           "pdk default",
+			pdk:            true,
+			bootclasspath:  []string{`""`},
+			forces8:        true,
+			java8classpath: []string{"prebuilts/sdk/29/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+			aidl:           "-pprebuilts/sdk/29/public/framework.aidl",
 		},
 		{
-			name:          "pdk current",
-			pdk:           true,
-			properties:    `sdk_version: "current",`,
-			bootclasspath: []string{`""`},
-			system:        "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
-			classpath:     []string{"prebuilts/sdk/25/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
-			aidl:          "-pprebuilts/sdk/25/public/framework.aidl",
+			name:           "pdk current",
+			pdk:            true,
+			properties:     `sdk_version: "current",`,
+			bootclasspath:  []string{`""`},
+			forces8:        true,
+			java8classpath: []string{"prebuilts/sdk/29/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+			aidl:           "-pprebuilts/sdk/29/public/framework.aidl",
 		},
 		{
-			name:          "pdk 25",
-			pdk:           true,
-			properties:    `sdk_version: "25",`,
-			bootclasspath: []string{`""`},
-			system:        "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
-			classpath:     []string{"prebuilts/sdk/25/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
-			aidl:          "-pprebuilts/sdk/25/public/framework.aidl",
+			name:           "pdk 29",
+			pdk:            true,
+			properties:     `sdk_version: "29",`,
+			bootclasspath:  []string{`""`},
+			forces8:        true,
+			java8classpath: []string{"prebuilts/sdk/29/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+			aidl:           "-pprebuilts/sdk/29/public/framework.aidl",
 		},
 	}
 
@@ -235,7 +249,8 @@
 			}
 
 			bootclasspath := convertModulesToPaths(testcase.bootclasspath)
-			classpath := convertModulesToPaths(testcase.classpath)
+			java8classpath := convertModulesToPaths(testcase.java8classpath)
+			java9classpath := convertModulesToPaths(testcase.java9classpath)
 
 			bc := ""
 			var bcDeps []string
@@ -246,18 +261,20 @@
 				}
 			}
 
-			c := ""
-			if len(classpath) > 0 {
-				c = "-classpath " + strings.Join(classpath, ":")
+			j8c := ""
+			if len(java8classpath) > 0 {
+				j8c = "-classpath " + strings.Join(java8classpath, ":")
+			}
+
+			j9c := ""
+			if len(java9classpath) > 0 {
+				j9c = "-classpath " + strings.Join(java9classpath, ":")
 			}
 
 			system := ""
 			var systemDeps []string
 			if testcase.system == "none" {
 				system = "--system=none"
-			} else if testcase.system == "bootclasspath" {
-				system = bc
-				systemDeps = bcDeps
 			} else if testcase.system != "" {
 				system = "--system=" + filepath.Join(buildDir, ".intermediates", testcase.system, "android_common", "system")
 				// The module-relative parts of these paths are hardcoded in system_modules.go:
@@ -280,7 +297,7 @@
 
 				got := javac.Args["bootClasspath"]
 				expected := ""
-				if isJava8 {
+				if isJava8 || testcase.forces8 {
 					expected = bc
 					deps = append(deps, bcDeps...)
 				} else {
@@ -291,11 +308,17 @@
 					t.Errorf("bootclasspath expected %q != got %q", expected, got)
 				}
 
-				got = javac.Args["classpath"]
-				if got != c {
-					t.Errorf("classpath expected %q != got %q", c, got)
+				if isJava8 || testcase.forces8 {
+					expected = j8c
+					deps = append(deps, java8classpath...)
+				} else {
+					expected = j9c
+					deps = append(deps, java9classpath...)
 				}
-				deps = append(deps, classpath...)
+				got = javac.Args["classpath"]
+				if got != expected {
+					t.Errorf("classpath expected %q != got %q", expected, got)
+				}
 
 				if !reflect.DeepEqual(javac.Implicits.Strings(), deps) {
 					t.Errorf("implicits expected %q != got %q", deps, javac.Implicits.Strings())
@@ -366,8 +389,23 @@
 				checkClasspath(t, ctx, true /* isJava8 */)
 			})
 
-			// TODO(b/142896162): Add a with PLATFORM_VERSION_CODENAME=REL, javac -source 9 -target 9, when that all works.
+			// Test again with PLATFORM_VERSION_CODENAME=REL, javac -source 9 -target 9
+			t.Run("REL + Java language level 9", func(t *testing.T) {
+				config := testConfig(nil)
+				config.TestProductVariables.Platform_sdk_codename = proptools.StringPtr("REL")
+				config.TestProductVariables.Platform_sdk_final = proptools.BoolPtr(true)
+
+				if testcase.unbundled {
+					config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true)
+				}
+				if testcase.pdk {
+					config.TestProductVariables.Pdk = proptools.BoolPtr(true)
+				}
+				ctx := testContext(bp, nil)
+				run(t, ctx, config)
+
+				checkClasspath(t, ctx, false /* isJava8 */)
+			})
 		})
 	}
-
 }
diff --git a/python/python.go b/python/python.go
index 1b606cb..c67c577 100644
--- a/python/python.go
+++ b/python/python.go
@@ -326,9 +326,24 @@
 				p.properties.Version.Py3.Libs)...)
 
 		if p.bootstrapper != nil && p.isEmbeddedLauncherEnabled(pyVersion3) {
-			//TODO(nanzhang): Add embedded launcher for Python3.
-			ctx.PropertyErrorf("version.py3.embedded_launcher",
-				"is not supported yet for Python3.")
+			ctx.AddVariationDependencies(nil, pythonLibTag, "py3-stdlib")
+
+			launcherModule := "py3-launcher"
+			if p.bootstrapper.autorun() {
+				launcherModule = "py3-launcher-autorun"
+			}
+			ctx.AddFarVariationDependencies(ctx.Target().Variations(), launcherTag, launcherModule)
+
+			// Add py3-launcher shared lib dependencies. Ideally, these should be
+			// derived from the `shared_libs` property of "py3-launcher". However, we
+			// cannot read the property at this stage and it will be too late to add
+			// dependencies later.
+			ctx.AddFarVariationDependencies(ctx.Target().Variations(), launcherSharedLibTag, "libsqlite")
+
+			if ctx.Target().Os.Bionic() {
+				ctx.AddFarVariationDependencies(ctx.Target().Variations(), launcherSharedLibTag,
+					"libc", "libdl", "libm")
+			}
 		}
 	default:
 		panic(fmt.Errorf("unknown Python Actual_version: %q for module: %q.",
@@ -370,11 +385,11 @@
 	// Only Python binaries and test has non-empty bootstrapper.
 	if p.bootstrapper != nil {
 		p.walkTransitiveDeps(ctx)
-		// TODO(nanzhang): Since embedded launcher is not supported for Python3 for now,
-		// so we initialize "embedded_launcher" to false.
 		embeddedLauncher := false
 		if p.properties.Actual_version == pyVersion2 {
 			embeddedLauncher = p.isEmbeddedLauncherEnabled(pyVersion2)
+		} else {
+			embeddedLauncher = p.isEmbeddedLauncherEnabled(pyVersion3)
 		}
 		p.installSource = p.bootstrapper.bootstrap(ctx, p.properties.Actual_version,
 			embeddedLauncher, p.srcsPathMappings, p.srcsZip, p.depsSrcsZips)
diff --git a/python/tests/Android.bp b/python/tests/Android.bp
index 1f4305c..c8bf420 100644
--- a/python/tests/Android.bp
+++ b/python/tests/Android.bp
@@ -27,6 +27,22 @@
         },
         py3: {
             enabled: false,
+            embedded_launcher: true,
+        },
+    },
+}
+
+python_test_host {
+    name: "par_test3",
+    main: "par_test.py",
+    srcs: [
+        "par_test.py",
+        "testpkg/par_test.py",
+    ],
+
+    version: {
+        py3: {
+            embedded_launcher: true,
         },
     },
 }
diff --git a/python/tests/runtest.sh b/python/tests/runtest.sh
index a319558..1ecdebc 100755
--- a/python/tests/runtest.sh
+++ b/python/tests/runtest.sh
@@ -23,8 +23,8 @@
   exit 1
 fi
 
-if [ ! -f $ANDROID_HOST_OUT/nativetest64/par_test/par_test ]; then
-  echo "Run 'm par_test' first"
+if [[ ( ! -f $ANDROID_HOST_OUT/nativetest64/par_test/par_test ) || ( ! -f $ANDROID_HOST_OUT/nativetest64/par_test3/par_test3 ) ]]; then
+  echo "Run 'm par_test par_test3' first"
   exit 1
 fi
 
@@ -36,4 +36,8 @@
 PYTHONHOME=/usr $ANDROID_HOST_OUT/nativetest64/par_test/par_test
 PYTHONPATH=/usr $ANDROID_HOST_OUT/nativetest64/par_test/par_test
 
+PYTHONHOME= PYTHONPATH= $ANDROID_HOST_OUT/nativetest64/par_test3/par_test3
+PYTHONHOME=/usr $ANDROID_HOST_OUT/nativetest64/par_test3/par_test3
+PYTHONPATH=/usr $ANDROID_HOST_OUT/nativetest64/par_test3/par_test3
+
 echo "Passed!"
diff --git a/python/tests/testpkg/par_test.py b/python/tests/testpkg/par_test.py
index 22dd095..ffad430 100644
--- a/python/tests/testpkg/par_test.py
+++ b/python/tests/testpkg/par_test.py
@@ -29,7 +29,13 @@
 
 assert_equal("__name__", __name__, "testpkg.par_test")
 assert_equal("__file__", __file__, os.path.join(archive, "testpkg/par_test.py"))
-assert_equal("__package__", __package__, "testpkg")
+
+# Python3 is returning None here for me, and I haven't found any problems caused by this.
+if sys.version_info[0] == 2:
+  assert_equal("__package__", __package__, "testpkg")
+else:
+  assert_equal("__package__", __package__, None)
+
 assert_equal("__loader__.archive", __loader__.archive, archive)
 assert_equal("__loader__.prefix", __loader__.prefix, "testpkg/")
 
diff --git a/rust/OWNERS b/rust/OWNERS
new file mode 100644
index 0000000..82713f9
--- /dev/null
+++ b/rust/OWNERS
@@ -0,0 +1,5 @@
+# Additional owner/reviewers for rust rules, including parent directory owners.
+per-file * = chh@google.com, ivanlozano@google.com, jeffv@google.com, srhines@google.com
+
+# Limited owners/reviewers of the whitelist.
+per-file whitelist.go = chh@google.com, ivanlozano@google.com, jeffv@google.com, jgalenson@google.com, srhines@google.com
diff --git a/rust/androidmk.go b/rust/androidmk.go
index a6208db..49115f2 100644
--- a/rust/androidmk.go
+++ b/rust/androidmk.go
@@ -72,6 +72,8 @@
 
 	mod.subAndroidMk(&ret, mod.compiler)
 
+	ret.SubName += mod.Properties.SubName
+
 	return ret
 }
 
@@ -85,6 +87,11 @@
 	})
 }
 
+func (test *testBinaryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+	test.binaryDecorator.AndroidMk(ctx, ret)
+	ret.SubName = "_" + String(test.baseCompiler.Properties.Stem)
+}
+
 func (library *libraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
 	ctx.subAndroidMk(ret, library.baseCompiler)
 
@@ -92,7 +99,12 @@
 		ret.Class = "RLIB_LIBRARIES"
 	} else if library.dylib() {
 		ret.Class = "DYLIB_LIBRARIES"
+	} else if library.static() {
+		ret.Class = "STATIC_LIBRARIES"
+	} else if library.shared() {
+		ret.Class = "SHARED_LIBRARIES"
 	}
+
 	ret.DistFile = library.distFile
 	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
 		if !library.rlib() {
diff --git a/rust/binary_test.go b/rust/binary_test.go
index cd41fcf..ab2dae1 100644
--- a/rust/binary_test.go
+++ b/rust/binary_test.go
@@ -36,11 +36,20 @@
 	fizzBuzz := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Output("fizz-buzz")
 	fizzBuzzDynamic := ctx.ModuleForTests("fizz-buzz-dynamic", "linux_glibc_x86_64").Output("fizz-buzz-dynamic")
 
-	if !strings.Contains(fizzBuzzDynamic.Args["rustcFlags"], "prefer-dynamic") {
-		t.Errorf("missing prefer-dynamic flag, rustcFlags: %#v", fizzBuzzDynamic.Args["rustcFlags"])
+	// Do not compile binary modules with the --test flag.
+	flags := fizzBuzzDynamic.Args["rustcFlags"]
+	if strings.Contains(flags, "--test") {
+		t.Errorf("extra --test flag, rustcFlags: %#v", flags)
+	}
+	if !strings.Contains(flags, "prefer-dynamic") {
+		t.Errorf("missing prefer-dynamic flag, rustcFlags: %#v", flags)
 	}
 
-	if strings.Contains(fizzBuzz.Args["rustcFlags"], "prefer-dynamic") {
-		t.Errorf("unexpected prefer-dynamic flag, rustcFlags: %#v", fizzBuzz.Args["rustcFlags"])
+	flags = fizzBuzz.Args["rustcFlags"]
+	if strings.Contains(flags, "--test") {
+		t.Errorf("extra --test flag, rustcFlags: %#v", flags)
+	}
+	if strings.Contains(flags, "prefer-dynamic") {
+		t.Errorf("unexpected prefer-dynamic flag, rustcFlags: %#v", flags)
 	}
 }
diff --git a/rust/builder.go b/rust/builder.go
index 104313f..d9e36db 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -53,6 +53,14 @@
 	transformSrctoCrate(ctx, mainSrc, deps.RLibs, deps.DyLibs, deps.ProcMacros, deps.StaticLibs, deps.SharedLibs, deps.CrtBegin, deps.CrtEnd, flags, outputFile, "dylib", includeDirs)
 }
 
+func TransformSrctoStatic(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags, outputFile android.WritablePath, includeDirs []string) {
+	transformSrctoCrate(ctx, mainSrc, deps.RLibs, deps.DyLibs, deps.ProcMacros, deps.StaticLibs, deps.SharedLibs, deps.CrtBegin, deps.CrtEnd, flags, outputFile, "staticlib", includeDirs)
+}
+
+func TransformSrctoShared(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags, outputFile android.WritablePath, includeDirs []string) {
+	transformSrctoCrate(ctx, mainSrc, deps.RLibs, deps.DyLibs, deps.ProcMacros, deps.StaticLibs, deps.SharedLibs, deps.CrtBegin, deps.CrtEnd, flags, outputFile, "cdylib", includeDirs)
+}
+
 func TransformSrctoProcMacro(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags, outputFile android.WritablePath, includeDirs []string) {
 	transformSrctoCrate(ctx, mainSrc, deps.RLibs, deps.DyLibs, deps.ProcMacros, deps.StaticLibs, deps.SharedLibs, deps.CrtBegin, deps.CrtEnd, flags, outputFile, "proc-macro", includeDirs)
 }
@@ -80,7 +88,9 @@
 	rustcFlags = append(rustcFlags, flags.GlobalRustFlags...)
 	rustcFlags = append(rustcFlags, flags.RustFlags...)
 	rustcFlags = append(rustcFlags, "--crate-type="+crate_type)
-	rustcFlags = append(rustcFlags, "--crate-name="+crate_name)
+	if crate_name != "" {
+		rustcFlags = append(rustcFlags, "--crate-name="+crate_name)
+	}
 	if targetTriple != "" {
 		rustcFlags = append(rustcFlags, "--target="+targetTriple)
 		linkFlags = append(linkFlags, "-target "+targetTriple)
diff --git a/rust/compiler.go b/rust/compiler.go
index 3f02835..85e8ba6 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -18,9 +18,10 @@
 	"fmt"
 	"path/filepath"
 
+	"github.com/google/blueprint/proptools"
+
 	"android/soong/android"
 	"android/soong/rust/config"
-	"github.com/google/blueprint/proptools"
 )
 
 func getEdition(compiler *baseCompiler) string {
@@ -64,7 +65,7 @@
 	// list of C static library dependencies
 	Static_libs []string `android:"arch_variant"`
 
-	// crate name (defaults to module name); if library, this must be the expected extern crate name
+	// crate name, required for libraries. This must be the expected extern crate name used in source
 	Crate_name string `android:"arch_variant"`
 
 	// list of features to enable for this crate
@@ -207,6 +208,7 @@
 
 	return stem
 }
+
 func (compiler *baseCompiler) relativeInstallPath() string {
 	return String(compiler.Properties.Relative_install_path)
 }
diff --git a/rust/config/toolchain.go b/rust/config/toolchain.go
index 328bca3..616d88b 100644
--- a/rust/config/toolchain.go
+++ b/rust/config/toolchain.go
@@ -95,7 +95,7 @@
 	return ".rlib"
 }
 func (toolchainBase) DylibSuffix() string {
-	return ".so"
+	return ".dylib.so"
 }
 
 func (toolchainBase) ProcMacroSuffix() string {
diff --git a/rust/config/whitelist.go b/rust/config/whitelist.go
index 4646264..8025bcf 100644
--- a/rust/config/whitelist.go
+++ b/rust/config/whitelist.go
@@ -2,7 +2,7 @@
 
 var (
 	RustAllowedPaths = []string{
-		"external/rust/crates",
+		"external/rust",
 		"external/crosvm",
 		"external/adhd",
 	}
diff --git a/rust/library.go b/rust/library.go
index c831727..adf6e95 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -15,6 +15,9 @@
 package rust
 
 import (
+	"regexp"
+	"strings"
+
 	"android/soong/android"
 )
 
@@ -25,8 +28,10 @@
 	android.RegisterModuleType("rust_library_host", RustLibraryHostFactory)
 	android.RegisterModuleType("rust_library_host_dylib", RustLibraryDylibHostFactory)
 	android.RegisterModuleType("rust_library_host_rlib", RustLibraryRlibHostFactory)
-
-	//TODO: Add support for generating standard shared/static libraries.
+	android.RegisterModuleType("rust_library_shared", RustLibrarySharedFactory)
+	android.RegisterModuleType("rust_library_static", RustLibraryStaticFactory)
+	android.RegisterModuleType("rust_library_host_shared", RustLibrarySharedHostFactory)
+	android.RegisterModuleType("rust_library_host_static", RustLibraryStaticHostFactory)
 }
 
 type VariantLibraryProperties struct {
@@ -34,25 +39,36 @@
 }
 
 type LibraryCompilerProperties struct {
-	Rlib  VariantLibraryProperties `android:"arch_variant"`
-	Dylib VariantLibraryProperties `android:"arch_variant"`
+	Rlib   VariantLibraryProperties `android:"arch_variant"`
+	Dylib  VariantLibraryProperties `android:"arch_variant"`
+	Shared VariantLibraryProperties `android:"arch_variant"`
+	Static VariantLibraryProperties `android:"arch_variant"`
 
 	// path to the source file that is the main entry point of the program (e.g. src/lib.rs)
 	Srcs []string `android:"path,arch_variant"`
+
+	// path to include directories to pass to cc_* modules, only relevant for static/shared variants.
+	Include_dirs []string `android:"path,arch_variant"`
 }
 
 type LibraryMutatedProperties struct {
-	VariantName string `blueprint:"mutated"`
-
 	// Build a dylib variant
 	BuildDylib bool `blueprint:"mutated"`
 	// Build an rlib variant
 	BuildRlib bool `blueprint:"mutated"`
+	// Build a shared library variant
+	BuildShared bool `blueprint:"mutated"`
+	// Build a static library variant
+	BuildStatic bool `blueprint:"mutated"`
 
 	// This variant is a dylib
 	VariantIsDylib bool `blueprint:"mutated"`
 	// This variant is an rlib
 	VariantIsRlib bool `blueprint:"mutated"`
+	// This variant is a shared library
+	VariantIsShared bool `blueprint:"mutated"`
+	// This variant is a static library
+	VariantIsStatic bool `blueprint:"mutated"`
 }
 
 type libraryDecorator struct {
@@ -67,14 +83,26 @@
 type libraryInterface interface {
 	rlib() bool
 	dylib() bool
+	static() bool
+	shared() bool
 
 	// Returns true if the build options for the module have selected a particular build type
 	buildRlib() bool
 	buildDylib() bool
+	buildShared() bool
+	buildStatic() bool
 
 	// Sets a particular variant type
 	setRlib()
 	setDylib()
+	setShared()
+	setStatic()
+
+	// Build a specific library variant
+	BuildOnlyRlib()
+	BuildOnlyDylib()
+	BuildOnlyStatic()
+	BuildOnlyShared()
 }
 
 func (library *libraryDecorator) exportedDirs() []string {
@@ -101,6 +129,14 @@
 	return library.MutatedProperties.VariantIsDylib
 }
 
+func (library *libraryDecorator) shared() bool {
+	return library.MutatedProperties.VariantIsShared
+}
+
+func (library *libraryDecorator) static() bool {
+	return library.MutatedProperties.VariantIsStatic
+}
+
 func (library *libraryDecorator) buildRlib() bool {
 	return library.MutatedProperties.BuildRlib && BoolDefault(library.Properties.Rlib.Enabled, true)
 }
@@ -109,17 +145,44 @@
 	return library.MutatedProperties.BuildDylib && BoolDefault(library.Properties.Dylib.Enabled, true)
 }
 
+func (library *libraryDecorator) buildShared() bool {
+	return library.MutatedProperties.BuildShared && BoolDefault(library.Properties.Shared.Enabled, true)
+}
+
+func (library *libraryDecorator) buildStatic() bool {
+	return library.MutatedProperties.BuildStatic && BoolDefault(library.Properties.Static.Enabled, true)
+}
+
 func (library *libraryDecorator) setRlib() {
 	library.MutatedProperties.VariantIsRlib = true
 	library.MutatedProperties.VariantIsDylib = false
+	library.MutatedProperties.VariantIsStatic = false
+	library.MutatedProperties.VariantIsShared = false
 }
 
 func (library *libraryDecorator) setDylib() {
 	library.MutatedProperties.VariantIsRlib = false
 	library.MutatedProperties.VariantIsDylib = true
+	library.MutatedProperties.VariantIsStatic = false
+	library.MutatedProperties.VariantIsShared = false
+}
+
+func (library *libraryDecorator) setShared() {
+	library.MutatedProperties.VariantIsStatic = false
+	library.MutatedProperties.VariantIsShared = true
+	library.MutatedProperties.VariantIsRlib = false
+	library.MutatedProperties.VariantIsDylib = false
+}
+
+func (library *libraryDecorator) setStatic() {
+	library.MutatedProperties.VariantIsStatic = true
+	library.MutatedProperties.VariantIsShared = false
+	library.MutatedProperties.VariantIsRlib = false
+	library.MutatedProperties.VariantIsDylib = false
 }
 
 var _ compiler = (*libraryDecorator)(nil)
+var _ libraryInterface = (*libraryDecorator)(nil)
 
 // rust_library produces all variants.
 func RustLibraryFactory() android.Module {
@@ -141,6 +204,20 @@
 	return module.Init()
 }
 
+// rust_library_shared produces a shared library.
+func RustLibrarySharedFactory() android.Module {
+	module, library := NewRustLibrary(android.HostAndDeviceSupported)
+	library.BuildOnlyShared()
+	return module.Init()
+}
+
+// rust_library_static produces a static library.
+func RustLibraryStaticFactory() android.Module {
+	module, library := NewRustLibrary(android.HostAndDeviceSupported)
+	library.BuildOnlyStatic()
+	return module.Init()
+}
+
 // rust_library_host produces all variants.
 func RustLibraryHostFactory() android.Module {
 	module, _ := NewRustLibrary(android.HostSupported)
@@ -161,12 +238,44 @@
 	return module.Init()
 }
 
+// rust_library_static_host produces a static library.
+func RustLibraryStaticHostFactory() android.Module {
+	module, library := NewRustLibrary(android.HostSupported)
+	library.BuildOnlyStatic()
+	return module.Init()
+}
+
+// rust_library_shared_host produces an shared library.
+func RustLibrarySharedHostFactory() android.Module {
+	module, library := NewRustLibrary(android.HostSupported)
+	library.BuildOnlyShared()
+	return module.Init()
+}
+
 func (library *libraryDecorator) BuildOnlyDylib() {
 	library.MutatedProperties.BuildRlib = false
+	library.MutatedProperties.BuildShared = false
+	library.MutatedProperties.BuildStatic = false
+
 }
 
 func (library *libraryDecorator) BuildOnlyRlib() {
 	library.MutatedProperties.BuildDylib = false
+	library.MutatedProperties.BuildShared = false
+	library.MutatedProperties.BuildStatic = false
+}
+
+func (library *libraryDecorator) BuildOnlyStatic() {
+	library.MutatedProperties.BuildShared = false
+	library.MutatedProperties.BuildRlib = false
+	library.MutatedProperties.BuildDylib = false
+
+}
+
+func (library *libraryDecorator) BuildOnlyShared() {
+	library.MutatedProperties.BuildStatic = false
+	library.MutatedProperties.BuildRlib = false
+	library.MutatedProperties.BuildDylib = false
 }
 
 func NewRustLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorator) {
@@ -174,8 +283,10 @@
 
 	library := &libraryDecorator{
 		MutatedProperties: LibraryMutatedProperties{
-			BuildDylib: true,
-			BuildRlib:  true,
+			BuildDylib:  true,
+			BuildRlib:   true,
+			BuildShared: true,
+			BuildStatic: true,
 		},
 		baseCompiler: NewBaseCompiler("lib", "lib64"),
 	}
@@ -194,7 +305,7 @@
 func (library *libraryDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps {
 	deps = library.baseCompiler.compilerDeps(ctx, deps)
 
-	if ctx.toolchain().Bionic() && library.dylib() {
+	if ctx.toolchain().Bionic() && (library.dylib() || library.shared()) {
 		deps = library.baseCompiler.bionicDeps(ctx, deps)
 	}
 
@@ -208,6 +319,13 @@
 
 	flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
 
+	if library.dylib() || library.shared() {
+		// We need prefer-dynamic for now to avoid linking in the static stdlib. See:
+		// https://github.com/rust-lang/rust/issues/19680
+		// https://github.com/rust-lang/rust/issues/34909
+		flags.RustFlags = append(flags.RustFlags, "-C prefer-dynamic")
+	}
+
 	if library.rlib() {
 		fileName := library.getStem(ctx) + ctx.toolchain().RlibSuffix()
 		outputFile = android.PathForModuleOut(ctx, fileName)
@@ -217,38 +335,78 @@
 		fileName := library.getStem(ctx) + ctx.toolchain().DylibSuffix()
 		outputFile = android.PathForModuleOut(ctx, fileName)
 
-		// We need prefer-dynamic for now to avoid linking in the static stdlib. See:
-		// https://github.com/rust-lang/rust/issues/19680
-		// https://github.com/rust-lang/rust/issues/34909
-		flags.RustFlags = append(flags.RustFlags, "-C prefer-dynamic")
-
 		TransformSrctoDylib(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
+	} else if library.static() {
+		fileName := library.getStem(ctx) + ctx.toolchain().StaticLibSuffix()
+		outputFile = android.PathForModuleOut(ctx, fileName)
+
+		TransformSrctoStatic(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
+	} else if library.shared() {
+		fileName := library.getStem(ctx) + ctx.toolchain().SharedLibSuffix()
+		outputFile = android.PathForModuleOut(ctx, fileName)
+
+		TransformSrctoShared(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
 	}
 
-	library.reexportDirs(deps.linkDirs...)
-	library.reexportDepFlags(deps.depFlags...)
+	if library.rlib() || library.dylib() {
+		library.reexportDirs(deps.linkDirs...)
+		library.reexportDepFlags(deps.depFlags...)
+	}
 	library.unstrippedOutputFile = outputFile
 
 	return outputFile
 }
 
+func (library *libraryDecorator) getStem(ctx ModuleContext) string {
+	stem := library.baseCompiler.getStemWithoutSuffix(ctx)
+	validateLibraryStem(ctx, stem, library.crateName())
+
+	return stem + String(library.baseCompiler.Properties.Suffix)
+}
+
+var validCrateName = regexp.MustCompile("[^a-zA-Z0-9_]+")
+
+func validateLibraryStem(ctx BaseModuleContext, filename string, crate_name string) {
+	if crate_name == "" {
+		ctx.PropertyErrorf("crate_name", "crate_name must be defined.")
+	}
+
+	// crate_names are used for the library output file, and rustc expects these
+	// to be alphanumeric with underscores allowed.
+	if validCrateName.MatchString(crate_name) {
+		ctx.PropertyErrorf("crate_name",
+			"library crate_names must be alphanumeric with underscores allowed")
+	}
+
+	// Libraries are expected to begin with "lib" followed by the crate_name
+	if !strings.HasPrefix(filename, "lib"+crate_name) {
+		ctx.ModuleErrorf("Invalid name or stem property; library filenames must start with lib<crate_name>")
+	}
+}
+
 func LibraryMutator(mctx android.BottomUpMutatorContext) {
 	if m, ok := mctx.Module().(*Module); ok && m.compiler != nil {
 		switch library := m.compiler.(type) {
 		case libraryInterface:
-			if library.buildRlib() && library.buildDylib() {
-				modules := mctx.CreateLocalVariations("rlib", "dylib")
-				rlib := modules[0].(*Module)
-				dylib := modules[1].(*Module)
 
-				rlib.compiler.(libraryInterface).setRlib()
-				dylib.compiler.(libraryInterface).setDylib()
-			} else if library.buildRlib() {
-				modules := mctx.CreateLocalVariations("rlib")
-				modules[0].(*Module).compiler.(libraryInterface).setRlib()
-			} else if library.buildDylib() {
-				modules := mctx.CreateLocalVariations("dylib")
-				modules[0].(*Module).compiler.(libraryInterface).setDylib()
+			// We only build the rust library variants here. This assumes that
+			// LinkageMutator runs first and there's an empty variant
+			// if rust variants are required.
+			if !library.static() && !library.shared() {
+				if library.buildRlib() && library.buildDylib() {
+					modules := mctx.CreateLocalVariations("rlib", "dylib")
+					rlib := modules[0].(*Module)
+					dylib := modules[1].(*Module)
+
+					rlib.compiler.(libraryInterface).setRlib()
+					dylib.compiler.(libraryInterface).setDylib()
+				} else if library.buildRlib() {
+					modules := mctx.CreateLocalVariations("rlib")
+					modules[0].(*Module).compiler.(libraryInterface).setRlib()
+				} else if library.buildDylib() {
+					modules := mctx.CreateLocalVariations("dylib")
+					modules[0].(*Module).compiler.(libraryInterface).setDylib()
+				}
 			}
 		}
 	}
diff --git a/rust/library_test.go b/rust/library_test.go
index bf8643e..9f9f374 100644
--- a/rust/library_test.go
+++ b/rust/library_test.go
@@ -29,19 +29,37 @@
 			crate_name: "foo",
 		}`)
 
-	// Test both variants are being built.
+	// Test all variants are being built.
 	libfooRlib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_rlib").Output("libfoo.rlib")
-	libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Output("libfoo.so")
+	libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Output("libfoo.dylib.so")
+	libfooStatic := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_static").Output("libfoo.a")
+	libfooShared := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_shared").Output("libfoo.so")
+
+	rlibCrateType := "rlib"
+	dylibCrateType := "dylib"
+	sharedCrateType := "cdylib"
+	staticCrateType := "static"
 
 	// Test crate type for rlib is correct.
-	if !strings.Contains(libfooRlib.Args["rustcFlags"], "crate-type=rlib") {
-		t.Errorf("missing crate-type for libfoo rlib, rustcFlags: %#v", libfooRlib.Args["rustcFlags"])
+	if !strings.Contains(libfooRlib.Args["rustcFlags"], "crate-type="+rlibCrateType) {
+		t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", rlibCrateType, libfooRlib.Args["rustcFlags"])
 	}
 
 	// Test crate type for dylib is correct.
-	if !strings.Contains(libfooDylib.Args["rustcFlags"], "crate-type=dylib") {
-		t.Errorf("missing crate-type for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"])
+	if !strings.Contains(libfooDylib.Args["rustcFlags"], "crate-type="+dylibCrateType) {
+		t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", dylibCrateType, libfooDylib.Args["rustcFlags"])
 	}
+
+	// Test crate type for C static libraries is correct.
+	if !strings.Contains(libfooStatic.Args["rustcFlags"], "crate-type="+staticCrateType) {
+		t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", staticCrateType, libfooStatic.Args["rustcFlags"])
+	}
+
+	// Test crate type for C shared libraries is correct.
+	if !strings.Contains(libfooShared.Args["rustcFlags"], "crate-type="+sharedCrateType) {
+		t.Errorf("missing crate-type for shared variant, expecting %#v, got rustcFlags: %#v", sharedCrateType, libfooShared.Args["rustcFlags"])
+	}
+
 }
 
 // Test that dylibs are not statically linking the standard library.
@@ -53,9 +71,46 @@
 			crate_name: "foo",
 		}`)
 
-	libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Output("libfoo.so")
+	libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Output("libfoo.dylib.so")
 
 	if !strings.Contains(libfooDylib.Args["rustcFlags"], "prefer-dynamic") {
 		t.Errorf("missing prefer-dynamic flag for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"])
 	}
 }
+
+func TestValidateLibraryStem(t *testing.T) {
+	testRustError(t, "crate_name must be defined.", `
+			rust_library_host {
+				name: "libfoo",
+				srcs: ["foo.rs"],
+			}`)
+
+	testRustError(t, "library crate_names must be alphanumeric with underscores allowed", `
+			rust_library_host {
+				name: "libfoo-bar",
+				srcs: ["foo.rs"],
+				crate_name: "foo-bar"
+			}`)
+
+	testRustError(t, "Invalid name or stem property; library filenames must start with lib<crate_name>", `
+			rust_library_host {
+				name: "foobar",
+				srcs: ["foo.rs"],
+				crate_name: "foo_bar"
+			}`)
+	testRustError(t, "Invalid name or stem property; library filenames must start with lib<crate_name>", `
+			rust_library_host {
+				name: "foobar",
+				stem: "libfoo",
+				srcs: ["foo.rs"],
+				crate_name: "foo_bar"
+			}`)
+	testRustError(t, "Invalid name or stem property; library filenames must start with lib<crate_name>", `
+			rust_library_host {
+				name: "foobar",
+				stem: "foo_bar",
+				srcs: ["foo.rs"],
+				crate_name: "foo_bar"
+			}`)
+
+}
diff --git a/rust/proc_macro.go b/rust/proc_macro.go
index 1a247d9..0da87da 100644
--- a/rust/proc_macro.go
+++ b/rust/proc_macro.go
@@ -77,3 +77,10 @@
 	TransformSrctoProcMacro(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
 	return outputFile
 }
+
+func (procMacro *procMacroDecorator) getStem(ctx ModuleContext) string {
+	stem := procMacro.baseCompiler.getStemWithoutSuffix(ctx)
+	validateLibraryStem(ctx, stem, procMacro.crateName())
+
+	return stem + String(procMacro.baseCompiler.Properties.Suffix)
+}
diff --git a/rust/rust.go b/rust/rust.go
index 707de4b..612e257 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -15,6 +15,7 @@
 package rust
 
 import (
+	"fmt"
 	"strings"
 
 	"github.com/google/blueprint"
@@ -38,6 +39,7 @@
 	android.RegisterModuleType("rust_defaults", defaultsFactory)
 	android.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
 		ctx.BottomUp("rust_libraries", LibraryMutator).Parallel()
+		ctx.BottomUp("rust_unit_tests", TestPerSrcMutator).Parallel()
 	})
 	pctx.Import("android/soong/rust/config")
 }
@@ -57,6 +59,7 @@
 	AndroidMkProcMacroLibs []string
 	AndroidMkSharedLibs    []string
 	AndroidMkStaticLibs    []string
+	SubName                string `blueprint:"mutated"`
 }
 
 type Module struct {
@@ -74,6 +77,85 @@
 	outputFile       android.OptionalPath
 }
 
+func (mod *Module) BuildStubs() bool {
+	return false
+}
+
+func (mod *Module) HasStubsVariants() bool {
+	return false
+}
+
+func (mod *Module) SelectedStl() string {
+	return ""
+}
+
+func (mod *Module) ApiLevel() string {
+	panic(fmt.Errorf("Called ApiLevel on Rust module %q; stubs libraries are not yet supported.", mod.BaseModuleName()))
+}
+
+func (mod *Module) Static() bool {
+	if mod.compiler != nil {
+		if library, ok := mod.compiler.(libraryInterface); ok {
+			return library.static()
+		}
+	}
+	panic(fmt.Errorf("Static called on non-library module: %q", mod.BaseModuleName()))
+}
+
+func (mod *Module) Shared() bool {
+	if mod.compiler != nil {
+		if library, ok := mod.compiler.(libraryInterface); ok {
+			return library.static()
+		}
+	}
+	panic(fmt.Errorf("Shared called on non-library module: %q", mod.BaseModuleName()))
+}
+
+func (mod *Module) Toc() android.OptionalPath {
+	if mod.compiler != nil {
+		if _, ok := mod.compiler.(libraryInterface); ok {
+			return android.OptionalPath{}
+		}
+	}
+	panic(fmt.Errorf("Toc() called on non-library module: %q", mod.BaseModuleName()))
+}
+
+func (mod *Module) OnlyInRecovery() bool {
+	return false
+}
+
+func (mod *Module) UseVndk() bool {
+	return false
+}
+
+func (mod *Module) MustUseVendorVariant() bool {
+	return false
+}
+
+func (mod *Module) IsVndk() bool {
+	return false
+}
+
+func (mod *Module) HasVendorVariant() bool {
+	return false
+}
+
+func (mod *Module) SdkVersion() string {
+	return ""
+}
+
+func (mod *Module) ToolchainLibrary() bool {
+	return false
+}
+
+func (mod *Module) NdkPrebuiltStl() bool {
+	return false
+}
+
+func (mod *Module) StubDecorator() bool {
+	return false
+}
+
 type Deps struct {
 	Dylibs     []string
 	Rlibs      []string
@@ -143,13 +225,124 @@
 }
 
 func (mod *Module) CrateName() string {
-	if mod.compiler != nil && mod.compiler.crateName() != "" {
-		return mod.compiler.crateName()
-	}
-	// Default crate names replace '-' in the name to '_'
-	return strings.Replace(mod.BaseModuleName(), "-", "_", -1)
+	return mod.compiler.crateName()
 }
 
+func (mod *Module) CcLibrary() bool {
+	if mod.compiler != nil {
+		if _, ok := mod.compiler.(*libraryDecorator); ok {
+			return true
+		}
+	}
+	return false
+}
+
+func (mod *Module) CcLibraryInterface() bool {
+	if mod.compiler != nil {
+		if _, ok := mod.compiler.(libraryInterface); ok {
+			return true
+		}
+	}
+	return false
+}
+
+func (mod *Module) IncludeDirs(ctx android.BaseModuleContext) android.Paths {
+	if mod.compiler != nil {
+		if library, ok := mod.compiler.(*libraryDecorator); ok {
+			return android.PathsForSource(ctx, library.Properties.Include_dirs)
+		}
+	}
+	panic(fmt.Errorf("IncludeDirs called on non-library module: %q", mod.BaseModuleName()))
+}
+
+func (mod *Module) SetStatic() {
+	if mod.compiler != nil {
+		if library, ok := mod.compiler.(libraryInterface); ok {
+			library.setStatic()
+			return
+		}
+	}
+	panic(fmt.Errorf("SetStatic called on non-library module: %q", mod.BaseModuleName()))
+}
+
+func (mod *Module) SetShared() {
+	if mod.compiler != nil {
+		if library, ok := mod.compiler.(libraryInterface); ok {
+			library.setShared()
+			return
+		}
+	}
+	panic(fmt.Errorf("SetShared called on non-library module: %q", mod.BaseModuleName()))
+}
+
+func (mod *Module) SetBuildStubs() {
+	panic("SetBuildStubs not yet implemented for rust modules")
+}
+
+func (mod *Module) SetStubsVersions(string) {
+	panic("SetStubsVersions not yet implemented for rust modules")
+}
+
+func (mod *Module) BuildStaticVariant() bool {
+	if mod.compiler != nil {
+		if library, ok := mod.compiler.(libraryInterface); ok {
+			return library.buildStatic()
+		}
+	}
+	panic(fmt.Errorf("BuildStaticVariant called on non-library module: %q", mod.BaseModuleName()))
+}
+
+func (mod *Module) BuildSharedVariant() bool {
+	if mod.compiler != nil {
+		if library, ok := mod.compiler.(libraryInterface); ok {
+			return library.buildShared()
+		}
+	}
+	panic(fmt.Errorf("BuildSharedVariant called on non-library module: %q", mod.BaseModuleName()))
+}
+
+// Rust module deps don't have a link order (?)
+func (mod *Module) SetDepsInLinkOrder([]android.Path) {}
+
+func (mod *Module) GetDepsInLinkOrder() []android.Path {
+	return []android.Path{}
+}
+
+func (mod *Module) GetStaticVariant() cc.LinkableInterface {
+	return nil
+}
+
+func (mod *Module) Module() android.Module {
+	return mod
+}
+
+func (mod *Module) StubsVersions() []string {
+	// For now, Rust has no stubs versions.
+	if mod.compiler != nil {
+		if _, ok := mod.compiler.(*libraryDecorator); ok {
+			return []string{}
+		}
+	}
+	panic(fmt.Errorf("StubsVersions called on non-library module: %q", mod.BaseModuleName()))
+}
+
+func (mod *Module) OutputFile() android.OptionalPath {
+	return mod.outputFile
+}
+
+func (mod *Module) InRecovery() bool {
+	// For now, Rust has no notion of the recovery image
+	return false
+}
+func (mod *Module) HasStaticVariant() bool {
+	if mod.GetStaticVariant() != nil {
+		return true
+	}
+	return false
+}
+
+var _ cc.LinkableInterface = (*Module)(nil)
+
 func (mod *Module) Init() android.Module {
 	mod.AddProperties(&mod.Properties)
 
@@ -300,9 +493,10 @@
 }
 
 var (
-	rlibDepTag      = dependencyTag{name: "rlibTag", library: true}
-	dylibDepTag     = dependencyTag{name: "dylib", library: true}
-	procMacroDepTag = dependencyTag{name: "procMacro", proc_macro: true}
+	rlibDepTag       = dependencyTag{name: "rlibTag", library: true}
+	dylibDepTag      = dependencyTag{name: "dylib", library: true}
+	procMacroDepTag  = dependencyTag{name: "procMacro", proc_macro: true}
+	testPerSrcDepTag = dependencyTag{name: "rust_unit_tests"}
 )
 
 func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
@@ -311,13 +505,12 @@
 	directRlibDeps := []*Module{}
 	directDylibDeps := []*Module{}
 	directProcMacroDeps := []*Module{}
-	directSharedLibDeps := []*(cc.Module){}
-	directStaticLibDeps := []*(cc.Module){}
+	directSharedLibDeps := [](cc.LinkableInterface){}
+	directStaticLibDeps := [](cc.LinkableInterface){}
 
 	ctx.VisitDirectDeps(func(dep android.Module) {
 		depName := ctx.OtherModuleName(dep)
 		depTag := ctx.OtherModuleDependencyTag(dep)
-
 		if rustDep, ok := dep.(*Module); ok {
 			//Handle Rust Modules
 
@@ -365,16 +558,19 @@
 				}
 			}
 
-		} else if ccDep, ok := dep.(*cc.Module); ok {
-			//Handle C dependencies
+		}
 
-			if ccDep.Target().Os != ctx.Os() {
-				ctx.ModuleErrorf("OS mismatch between %q and %q", ctx.ModuleName(), depName)
-				return
-			}
-			if ccDep.Target().Arch.ArchType != ctx.Arch().ArchType {
-				ctx.ModuleErrorf("Arch mismatch between %q and %q", ctx.ModuleName(), depName)
-				return
+		if ccDep, ok := dep.(cc.LinkableInterface); ok {
+			//Handle C dependencies
+			if _, ok := ccDep.(*Module); !ok {
+				if ccDep.Module().Target().Os != ctx.Os() {
+					ctx.ModuleErrorf("OS mismatch between %q and %q", ctx.ModuleName(), depName)
+					return
+				}
+				if ccDep.Module().Target().Arch.ArchType != ctx.Arch().ArchType {
+					ctx.ModuleErrorf("Arch mismatch between %q and %q", ctx.ModuleName(), depName)
+					return
+				}
 			}
 
 			linkFile := ccDep.OutputFile()
@@ -387,25 +583,25 @@
 			exportDep := false
 
 			switch depTag {
-			case cc.StaticDepTag():
+			case cc.StaticDepTag:
 				depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
 				depPaths.depFlags = append(depPaths.depFlags, "-l"+libName)
 				directStaticLibDeps = append(directStaticLibDeps, ccDep)
 				mod.Properties.AndroidMkStaticLibs = append(mod.Properties.AndroidMkStaticLibs, depName)
-			case cc.SharedDepTag():
+			case cc.SharedDepTag:
 				depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
 				depPaths.depFlags = append(depPaths.depFlags, "-l"+libName)
 				directSharedLibDeps = append(directSharedLibDeps, ccDep)
 				mod.Properties.AndroidMkSharedLibs = append(mod.Properties.AndroidMkSharedLibs, depName)
 				exportDep = true
-			case cc.CrtBeginDepTag():
+			case cc.CrtBeginDepTag:
 				depPaths.CrtBegin = linkFile
-			case cc.CrtEndDepTag():
+			case cc.CrtEndDepTag:
 				depPaths.CrtEnd = linkFile
 			}
 
 			// Make sure these dependencies are propagated
-			if lib, ok := mod.compiler.(*libraryDecorator); ok && (exportDep || lib.rlib()) {
+			if lib, ok := mod.compiler.(*libraryDecorator); ok && exportDep {
 				lib.linkDirs = append(lib.linkDirs, linkPath)
 				lib.depFlags = append(lib.depFlags, "-l"+libName)
 			} else if procMacro, ok := mod.compiler.(*procMacroDecorator); ok && exportDep {
@@ -457,8 +653,8 @@
 }
 func libNameFromFilePath(filepath android.Path) string {
 	libName := strings.Split(filepath.Base(), filepath.Ext())[0]
-	if strings.Contains(libName, "lib") {
-		libName = strings.Split(libName, "lib")[1]
+	if strings.HasPrefix(libName, "lib") {
+		libName = libName[3:]
 	}
 	return libName
 }
@@ -472,23 +668,37 @@
 	ctx.ctx = ctx
 
 	deps := mod.deps(ctx)
-
-	actx.AddVariationDependencies([]blueprint.Variation{{Mutator: "rust_libraries", Variation: "rlib"}}, rlibDepTag, deps.Rlibs...)
-	actx.AddVariationDependencies([]blueprint.Variation{{Mutator: "rust_libraries", Variation: "dylib"}}, dylibDepTag, deps.Dylibs...)
-
-	ccDepVariations := []blueprint.Variation{}
-	ccDepVariations = append(ccDepVariations, blueprint.Variation{Mutator: "version", Variation: ""})
+	commonDepVariations := []blueprint.Variation{}
+	commonDepVariations = append(commonDepVariations,
+		blueprint.Variation{Mutator: "version", Variation: ""})
 	if !mod.Host() {
-		ccDepVariations = append(ccDepVariations, blueprint.Variation{Mutator: "image", Variation: "core"})
+		commonDepVariations = append(commonDepVariations,
+			blueprint.Variation{Mutator: "image", Variation: "core"})
 	}
-	actx.AddVariationDependencies(append(ccDepVariations, blueprint.Variation{Mutator: "link", Variation: "shared"}), cc.SharedDepTag(), deps.SharedLibs...)
-	actx.AddVariationDependencies(append(ccDepVariations, blueprint.Variation{Mutator: "link", Variation: "static"}), cc.StaticDepTag(), deps.StaticLibs...)
+
+	actx.AddVariationDependencies(
+		append(commonDepVariations, []blueprint.Variation{
+			{Mutator: "rust_libraries", Variation: "rlib"},
+			{Mutator: "link", Variation: ""}}...),
+		rlibDepTag, deps.Rlibs...)
+	actx.AddVariationDependencies(
+		append(commonDepVariations, []blueprint.Variation{
+			{Mutator: "rust_libraries", Variation: "dylib"},
+			{Mutator: "link", Variation: ""}}...),
+		dylibDepTag, deps.Dylibs...)
+
+	actx.AddVariationDependencies(append(commonDepVariations,
+		blueprint.Variation{Mutator: "link", Variation: "shared"}),
+		cc.SharedDepTag, deps.SharedLibs...)
+	actx.AddVariationDependencies(append(commonDepVariations,
+		blueprint.Variation{Mutator: "link", Variation: "static"}),
+		cc.StaticDepTag, deps.StaticLibs...)
 
 	if deps.CrtBegin != "" {
-		actx.AddVariationDependencies(ccDepVariations, cc.CrtBeginDepTag(), deps.CrtBegin)
+		actx.AddVariationDependencies(commonDepVariations, cc.CrtBeginDepTag, deps.CrtBegin)
 	}
 	if deps.CrtEnd != "" {
-		actx.AddVariationDependencies(ccDepVariations, cc.CrtEndDepTag(), deps.CrtEnd)
+		actx.AddVariationDependencies(commonDepVariations, cc.CrtEndDepTag, deps.CrtEnd)
 	}
 
 	// proc_macros are compiler plugins, and so we need the host arch variant as a dependendcy.
diff --git a/rust/rust_test.go b/rust/rust_test.go
index 0c8d355..599af09 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -101,12 +101,20 @@
 
 // Test that we can extract the lib name from a lib path.
 func TestLibNameFromFilePath(t *testing.T) {
-	barPath := android.PathForTesting("out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/libbar.so")
-	libName := libNameFromFilePath(barPath)
-	expectedResult := "bar"
+	libBarPath := android.PathForTesting("out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/libbar.so")
+	libLibPath := android.PathForTesting("out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/liblib.dylib.so")
 
-	if libName != expectedResult {
-		t.Errorf("libNameFromFilePath returned the wrong name; expected '%#v', got '%#v'", expectedResult, libName)
+	libBarName := libNameFromFilePath(libBarPath)
+	libLibName := libNameFromFilePath(libLibPath)
+
+	expectedResult := "bar"
+	if libBarName != expectedResult {
+		t.Errorf("libNameFromFilePath returned the wrong name; expected '%#v', got '%#v'", expectedResult, libBarName)
+	}
+
+	expectedResult = "lib.dylib"
+	if libLibName != expectedResult {
+		t.Errorf("libNameFromFilePath returned the wrong name; expected '%#v', got '%#v'", expectedResult, libLibPath)
 	}
 }
 
@@ -121,53 +129,52 @@
 	}
 }
 
-// Test default crate names from module names are generated correctly.
-func TestDefaultCrateName(t *testing.T) {
-	ctx := testRust(t, `
-		rust_library_host_dylib {
-			name: "fizz-buzz",
-			srcs: ["foo.rs"],
-		}`)
-	module := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64_dylib").Module().(*Module)
-	crateName := module.CrateName()
-	expectedResult := "fizz_buzz"
-
-	if crateName != expectedResult {
-		t.Errorf("CrateName() returned the wrong default crate name; expected '%#v', got '%#v'", expectedResult, crateName)
-	}
-}
-
 // Test to make sure dependencies are being picked up correctly.
 func TestDepsTracking(t *testing.T) {
 	ctx := testRust(t, `
-		rust_library_host_dylib {
-			name: "libfoo",
+		rust_library_host_static {
+			name: "libstatic",
 			srcs: ["foo.rs"],
+			crate_name: "static",
+		}
+		rust_library_host_shared {
+			name: "libshared",
+			srcs: ["foo.rs"],
+			crate_name: "shared",
+		}
+		rust_library_host_dylib {
+			name: "libdylib",
+			srcs: ["foo.rs"],
+			crate_name: "dylib",
 		}
 		rust_library_host_rlib {
-			name: "libbar",
+			name: "librlib",
 			srcs: ["foo.rs"],
+			crate_name: "rlib",
 		}
 		rust_proc_macro {
 			name: "libpm",
 			srcs: ["foo.rs"],
+			crate_name: "pm",
 		}
 		rust_binary_host {
 			name: "fizz-buzz",
-			dylibs: ["libfoo"],
-			rlibs: ["libbar"],
+			dylibs: ["libdylib"],
+			rlibs: ["librlib"],
 			proc_macros: ["libpm"],
+			static_libs: ["libstatic"],
+			shared_libs: ["libshared"],
 			srcs: ["foo.rs"],
 		}
 	`)
 	module := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module)
 
 	// Since dependencies are added to AndroidMk* properties, we can check these to see if they've been picked up.
-	if !android.InList("libfoo", module.Properties.AndroidMkDylibs) {
+	if !android.InList("libdylib", module.Properties.AndroidMkDylibs) {
 		t.Errorf("Dylib dependency not detected (dependency missing from AndroidMkDylibs)")
 	}
 
-	if !android.InList("libbar", module.Properties.AndroidMkRlibs) {
+	if !android.InList("librlib", module.Properties.AndroidMkRlibs) {
 		t.Errorf("Rlib dependency not detected (dependency missing from AndroidMkRlibs)")
 	}
 
@@ -175,6 +182,13 @@
 		t.Errorf("Proc_macro dependency not detected (dependency missing from AndroidMkProcMacroLibs)")
 	}
 
+	if !android.InList("libshared", module.Properties.AndroidMkSharedLibs) {
+		t.Errorf("Shared library dependency not detected (dependency missing from AndroidMkSharedLibs)")
+	}
+
+	if !android.InList("libstatic", module.Properties.AndroidMkStaticLibs) {
+		t.Errorf("Static library dependency not detected (dependency missing from AndroidMkStaticLibs)")
+	}
 }
 
 // Test to make sure proc_macros use host variants when building device modules.
@@ -183,11 +197,13 @@
 		rust_library_host_rlib {
 			name: "libbar",
 			srcs: ["foo.rs"],
+			crate_name: "bar",
 		}
 		rust_proc_macro {
 			name: "libpm",
 			rlibs: ["libbar"],
 			srcs: ["foo.rs"],
+			crate_name: "pm",
 		}
 		rust_binary {
 			name: "fizz-buzz",
diff --git a/rust/test.go b/rust/test.go
new file mode 100644
index 0000000..816e3c7
--- /dev/null
+++ b/rust/test.go
@@ -0,0 +1,116 @@
+// Copyright 2019 The Android Open Source Project
+//
+// 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 rust
+
+import (
+	"path/filepath"
+	"strings"
+
+	"android/soong/android"
+)
+
+// A test module is a binary module with extra --test compiler flag
+// and different default installation directory.
+// In golang, inheriance is written as a component.
+type testBinaryDecorator struct {
+	*binaryDecorator
+}
+
+func NewRustTest(hod android.HostOrDeviceSupported) (*Module, *testBinaryDecorator) {
+	module := newModule(hod, android.MultilibFirst)
+
+	test := &testBinaryDecorator{
+		binaryDecorator: &binaryDecorator{
+			// TODO(chh): set up dir64?
+			baseCompiler: NewBaseCompiler("testcases", ""),
+		},
+	}
+
+	module.compiler = test
+
+	return module, test
+}
+
+func (test *testBinaryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags {
+	flags = test.binaryDecorator.compilerFlags(ctx, flags)
+	flags.RustFlags = append(flags.RustFlags, "--test")
+	return flags
+}
+
+func init() {
+	// Rust tests are binary files built with --test.
+	android.RegisterModuleType("rust_test", RustTestFactory)
+	android.RegisterModuleType("rust_test_host", RustTestHostFactory)
+}
+
+func RustTestFactory() android.Module {
+	module, _ := NewRustTest(android.HostAndDeviceSupported)
+	return module.Init()
+}
+
+func RustTestHostFactory() android.Module {
+	module, _ := NewRustTest(android.HostSupported)
+	return module.Init()
+}
+
+func (test *testBinaryDecorator) testPerSrc() bool {
+	return true
+}
+
+func (test *testBinaryDecorator) srcs() []string {
+	return test.Properties.Srcs
+}
+
+func (test *testBinaryDecorator) setSrc(name, src string) {
+	test.Properties.Srcs = []string{src}
+	test.baseCompiler.Properties.Stem = StringPtr(name)
+}
+
+func (test *testBinaryDecorator) unsetSrc() {
+	test.Properties.Srcs = nil
+	test.baseCompiler.Properties.Stem = StringPtr("")
+}
+
+type testPerSrc interface {
+	testPerSrc() bool
+	srcs() []string
+	setSrc(string, string)
+	unsetSrc()
+}
+
+var _ testPerSrc = (*testBinaryDecorator)(nil)
+
+func TestPerSrcMutator(mctx android.BottomUpMutatorContext) {
+	if m, ok := mctx.Module().(*Module); ok {
+		if test, ok := m.compiler.(testPerSrc); ok {
+			numTests := len(test.srcs())
+			if test.testPerSrc() && numTests > 0 {
+				if duplicate, found := android.CheckDuplicate(test.srcs()); found {
+					mctx.PropertyErrorf("srcs", "found a duplicate entry %q", duplicate)
+					return
+				}
+				testNames := make([]string, numTests)
+				for i, src := range test.srcs() {
+					testNames[i] = strings.TrimSuffix(filepath.Base(src), filepath.Ext(src))
+				}
+				// TODO(chh): Add an "all tests" variation like cc/test.go?
+				tests := mctx.CreateLocalVariations(testNames...)
+				for i, src := range test.srcs() {
+					tests[i].(*Module).compiler.(testPerSrc).setSrc(testNames[i], src)
+				}
+			}
+		}
+	}
+}
diff --git a/rust/test_test.go b/rust/test_test.go
new file mode 100644
index 0000000..aa4c3c8
--- /dev/null
+++ b/rust/test_test.go
@@ -0,0 +1,43 @@
+// Copyright 2019 The Android Open Source Project
+//
+// 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 rust
+
+import (
+	"strings"
+	"testing"
+)
+
+// Check if rust_test_host accepts multiple source files and applies --test flag.
+func TestRustTest(t *testing.T) {
+	ctx := testRust(t, `
+		rust_test_host {
+			name: "my_test",
+			srcs: ["foo.rs", "src/bar.rs"],
+			relative_install_path: "rust/my-test",
+		}`)
+
+	for _, name := range []string{"foo", "bar"} {
+		testingModule := ctx.ModuleForTests("my_test", "linux_glibc_x86_64_"+name)
+		testingBuildParams := testingModule.Output(name)
+		rustcFlags := testingBuildParams.Args["rustcFlags"]
+		if !strings.Contains(rustcFlags, "--test") {
+			t.Errorf("%v missing --test flag, rustcFlags: %#v", name, rustcFlags)
+		}
+		outPath := "/my_test/linux_glibc_x86_64_" + name + "/" + name
+		if !strings.Contains(testingBuildParams.Output.String(), outPath) {
+			t.Errorf("wrong output: %v  expect: %v", testingBuildParams.Output, outPath)
+		}
+	}
+}
diff --git a/rust/testing.go b/rust/testing.go
index 92347f1..24defa6 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -168,24 +168,32 @@
 	ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(cc.ObjectFactory))
 	ctx.RegisterModuleType("rust_binary", android.ModuleFactoryAdaptor(RustBinaryFactory))
 	ctx.RegisterModuleType("rust_binary_host", android.ModuleFactoryAdaptor(RustBinaryHostFactory))
+	ctx.RegisterModuleType("rust_test", android.ModuleFactoryAdaptor(RustTestFactory))
+	ctx.RegisterModuleType("rust_test_host", android.ModuleFactoryAdaptor(RustTestHostFactory))
 	ctx.RegisterModuleType("rust_library", android.ModuleFactoryAdaptor(RustLibraryFactory))
 	ctx.RegisterModuleType("rust_library_host", android.ModuleFactoryAdaptor(RustLibraryHostFactory))
 	ctx.RegisterModuleType("rust_library_host_rlib", android.ModuleFactoryAdaptor(RustLibraryRlibHostFactory))
 	ctx.RegisterModuleType("rust_library_host_dylib", android.ModuleFactoryAdaptor(RustLibraryDylibHostFactory))
 	ctx.RegisterModuleType("rust_library_rlib", android.ModuleFactoryAdaptor(RustLibraryRlibFactory))
 	ctx.RegisterModuleType("rust_library_dylib", android.ModuleFactoryAdaptor(RustLibraryDylibFactory))
+	ctx.RegisterModuleType("rust_library_shared", android.ModuleFactoryAdaptor(RustLibrarySharedFactory))
+	ctx.RegisterModuleType("rust_library_static", android.ModuleFactoryAdaptor(RustLibraryStaticFactory))
+	ctx.RegisterModuleType("rust_library_host_shared", android.ModuleFactoryAdaptor(RustLibrarySharedHostFactory))
+	ctx.RegisterModuleType("rust_library_host_static", android.ModuleFactoryAdaptor(RustLibraryStaticHostFactory))
 	ctx.RegisterModuleType("rust_proc_macro", android.ModuleFactoryAdaptor(ProcMacroFactory))
 	ctx.RegisterModuleType("rust_prebuilt_dylib", android.ModuleFactoryAdaptor(PrebuiltDylibFactory))
 	ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(cc.ToolchainLibraryFactory))
 	ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
-		ctx.BottomUp("rust_libraries", LibraryMutator).Parallel()
-
+		// cc mutators
 		ctx.BottomUp("image", cc.ImageMutator).Parallel()
 		ctx.BottomUp("link", cc.LinkageMutator).Parallel()
 		ctx.BottomUp("version", cc.VersionMutator).Parallel()
 		ctx.BottomUp("begin", cc.BeginMutator).Parallel()
-	})
 
+		// rust mutators
+		ctx.BottomUp("rust_libraries", LibraryMutator).Parallel()
+		ctx.BottomUp("rust_unit_tests", TestPerSrcMutator).Parallel()
+	})
 	bp = bp + GatherRequiredDepsForTest()
 
 	mockFS := map[string][]byte{
diff --git a/scripts/archive_repack.sh b/scripts/archive_repack.sh
new file mode 100755
index 0000000..f09372d
--- /dev/null
+++ b/scripts/archive_repack.sh
@@ -0,0 +1,87 @@
+#!/bin/bash -e
+
+# 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.
+
+# Script to extract and repack an archive with specified object files.
+# Inputs:
+#  Environment:
+#   CLANG_BIN: path to the clang bin directory
+#  Arguments:
+#   -i ${file}: input file
+#   -o ${file}: output file
+#   -d ${file}: deps file
+
+set -o pipefail
+
+OPTSTRING=d:i:o:
+
+usage() {
+    cat <<EOF
+Usage: archive_repack.sh [options] <objects to repack>
+
+OPTIONS:
+    -i <file>: input file
+    -o <file>: output file
+    -d <file>: deps file
+EOF
+    exit 1
+}
+
+while getopts $OPTSTRING opt; do
+    case "$opt" in
+        d) depsfile="${OPTARG}" ;;
+        i) infile="${OPTARG}" ;;
+        o) outfile="${OPTARG}" ;;
+        ?) usage ;;
+    esac
+done
+shift "$(($OPTIND -1))"
+
+if [ -z "${infile}" ]; then
+    echo "-i argument is required"
+    usage
+fi
+
+if [ -z "${outfile}" ]; then
+    echo "-o argument is required"
+    usage
+fi
+
+# Produce deps file
+if [ ! -z "${depsfile}" ]; then
+    cat <<EOF > "${depsfile}"
+${outfile}: ${infile} ${CLANG_BIN}/llvm-ar
+EOF
+fi
+
+# Get absolute path for outfile and llvm-ar.
+LLVM_AR="${PWD}/${CLANG_BIN}/llvm-ar"
+if [[ "$outfile" != /* ]]; then
+    outfile="${PWD}/${outfile}"
+fi
+
+tempdir="${outfile}.tmp"
+
+# Clean up any previous temporary files.
+rm -f "${outfile}"
+rm -rf "${tempdir}"
+
+# Do repack
+# We have to change working directory since ar only allows extracting to CWD.
+mkdir "${tempdir}"
+cp "${infile}" "${tempdir}/archive"
+cd "${tempdir}"
+"${LLVM_AR}" x "archive"
+"${LLVM_AR}" --format=gnu qc "${outfile}" "$@"
diff --git a/sdk/sdk.go b/sdk/sdk.go
index d189043..4eb3665 100644
--- a/sdk/sdk.go
+++ b/sdk/sdk.go
@@ -19,14 +19,17 @@
 	"strconv"
 
 	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
 	// This package doesn't depend on the apex package, but import it to make its mutators to be
 	// registered before mutators in this package. See RegisterPostDepsMutators for more details.
 	_ "android/soong/apex"
+	"android/soong/cc"
 )
 
 func init() {
+	pctx.Import("android/soong/android")
 	android.RegisterModuleType("sdk", ModuleFactory)
 	android.RegisterModuleType("sdk_snapshot", SnapshotModuleFactory)
 	android.PreDepsMutators(RegisterPreDepsMutators)
@@ -39,8 +42,7 @@
 
 	properties sdkProperties
 
-	updateScript android.OutputPath
-	freezeScript android.OutputPath
+	snapshotFile android.OptionalPath
 }
 
 type sdkProperties struct {
@@ -59,6 +61,13 @@
 	s.AddProperties(&s.properties)
 	android.InitAndroidMultiTargetsArchModule(s, android.HostAndDeviceSupported, android.MultilibCommon)
 	android.InitDefaultableModule(s)
+	android.AddLoadHook(s, func(ctx android.LoadHookContext) {
+		type props struct {
+			Compile_multilib *string
+		}
+		p := &props{Compile_multilib: proptools.StringPtr("both")}
+		ctx.AppendProperties(p)
+	})
 	return s
 }
 
@@ -95,11 +104,24 @@
 }
 
 func (s *sdk) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	s.buildSnapshotGenerationScripts(ctx)
+	if !s.snapshot() {
+		// We don't need to create a snapshot out of sdk_snapshot.
+		// That doesn't make sense. We need a snapshot to create sdk_snapshot.
+		s.snapshotFile = android.OptionalPathForPath(s.buildSnapshot(ctx))
+	}
 }
 
 func (s *sdk) AndroidMkEntries() android.AndroidMkEntries {
-	return s.androidMkEntriesForScript()
+	if !s.snapshotFile.Valid() {
+		return android.AndroidMkEntries{}
+	}
+
+	return android.AndroidMkEntries{
+		Class:      "FAKE",
+		OutputFile: s.snapshotFile,
+		DistFile:   s.snapshotFile,
+		Include:    "$(BUILD_PHONY_PACKAGE)",
+	}
 }
 
 // RegisterPreDepsMutators registers pre-deps mutators to support modules implementing SdkAware
@@ -148,10 +170,17 @@
 
 		targets := mctx.MultiTargets()
 		for _, target := range targets {
-			mctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
-				{Mutator: "image", Variation: "core"},
-				{Mutator: "link", Variation: "shared"},
-			}...), sdkMemberDepTag, m.properties.Native_shared_libs...)
+			for _, lib := range m.properties.Native_shared_libs {
+				name, version := cc.StubsLibNameAndVersion(lib)
+				if version == "" {
+					version = cc.LatestStubsVersionFor(mctx.Config(), name)
+				}
+				mctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
+					{Mutator: "image", Variation: "core"},
+					{Mutator: "link", Variation: "shared"},
+					{Mutator: "version", Variation: version},
+				}...), sdkMemberDepTag, name)
+			}
 		}
 	}
 }
diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go
index 664bb7c..3471bc9 100644
--- a/sdk/sdk_test.go
+++ b/sdk/sdk_test.go
@@ -17,6 +17,7 @@
 import (
 	"io/ioutil"
 	"os"
+	"path/filepath"
 	"strings"
 	"testing"
 
@@ -100,6 +101,8 @@
 		"myapex.pk8":                                 nil,
 		"Test.java":                                  nil,
 		"Test.cpp":                                   nil,
+		"include/Test.h":                             nil,
+		"aidl/foo/bar/Test.aidl":                     nil,
 		"libfoo.so":                                  nil,
 	})
 
@@ -377,6 +380,100 @@
 	`)
 }
 
+func TestSdkIsCompileMultilibBoth(t *testing.T) {
+	ctx, _ := testSdk(t, `
+		sdk {
+			name: "mysdk",
+			native_shared_libs: ["sdkmember"],
+		}
+
+		cc_library_shared {
+			name: "sdkmember",
+			srcs: ["Test.cpp"],
+			system_shared_libs: [],
+			stl: "none",
+		}
+	`)
+
+	armOutput := ctx.ModuleForTests("sdkmember", "android_arm_armv7-a-neon_core_shared").Module().(*cc.Module).OutputFile()
+	arm64Output := ctx.ModuleForTests("sdkmember", "android_arm64_armv8-a_core_shared").Module().(*cc.Module).OutputFile()
+
+	var inputs []string
+	buildParams := ctx.ModuleForTests("mysdk", "android_common").Module().BuildParamsForTests()
+	for _, bp := range buildParams {
+		if bp.Input != nil {
+			inputs = append(inputs, bp.Input.String())
+		}
+	}
+
+	// ensure that both 32/64 outputs are inputs of the sdk snapshot
+	ensureListContains(t, inputs, armOutput.String())
+	ensureListContains(t, inputs, arm64Output.String())
+}
+
+func TestSnapshot(t *testing.T) {
+	ctx, config := testSdk(t, `
+		sdk {
+			name: "mysdk",
+			java_libs: ["myjavalib"],
+			native_shared_libs: ["mynativelib"],
+		}
+
+		java_library {
+			name: "myjavalib",
+			srcs: ["Test.java"],
+			aidl: {
+				export_include_dirs: ["aidl"],
+			},
+			system_modules: "none",
+			sdk_version: "none",
+			compile_dex: true,
+			host_supported: true,
+		}
+
+		cc_library_shared {
+			name: "mynativelib",
+			srcs: [
+				"Test.cpp",
+				"aidl/foo/bar/Test.aidl",
+			],
+			export_include_dirs: ["include"],
+			aidl: {
+				export_aidl_headers: true,
+			},
+			system_shared_libs: [],
+			stl: "none",
+		}
+	`)
+
+	var copySrcs []string
+	var copyDests []string
+	buildParams := ctx.ModuleForTests("mysdk", "android_common").Module().BuildParamsForTests()
+	for _, bp := range buildParams {
+		if bp.Rule.String() == "android/soong/android.Cp" {
+			copySrcs = append(copySrcs, bp.Input.String())
+			copyDests = append(copyDests, bp.Output.Rel()) // rooted at the snapshot root
+		}
+	}
+
+	buildDir := config.BuildDir()
+	ensureListContains(t, copySrcs, "aidl/foo/bar/Test.aidl")
+	ensureListContains(t, copySrcs, "include/Test.h")
+	ensureListContains(t, copySrcs, filepath.Join(buildDir, ".intermediates/mynativelib/android_arm64_armv8-a_core_shared/gen/aidl/aidl/foo/bar/BnTest.h"))
+	ensureListContains(t, copySrcs, filepath.Join(buildDir, ".intermediates/mynativelib/android_arm64_armv8-a_core_shared/gen/aidl/aidl/foo/bar/BpTest.h"))
+	ensureListContains(t, copySrcs, filepath.Join(buildDir, ".intermediates/mynativelib/android_arm64_armv8-a_core_shared/gen/aidl/aidl/foo/bar/Test.h"))
+	ensureListContains(t, copySrcs, filepath.Join(buildDir, ".intermediates/myjavalib/android_common/turbine-combined/myjavalib.jar"))
+	ensureListContains(t, copySrcs, filepath.Join(buildDir, ".intermediates/mynativelib/android_arm64_armv8-a_core_shared/mynativelib.so"))
+
+	ensureListContains(t, copyDests, "aidl/aidl/foo/bar/Test.aidl")
+	ensureListContains(t, copyDests, "arm64/include/include/Test.h")
+	ensureListContains(t, copyDests, "arm64/include_gen/mynativelib/aidl/foo/bar/BnTest.h")
+	ensureListContains(t, copyDests, "arm64/include_gen/mynativelib/aidl/foo/bar/BpTest.h")
+	ensureListContains(t, copyDests, "arm64/include_gen/mynativelib/aidl/foo/bar/Test.h")
+	ensureListContains(t, copyDests, "java/myjavalib.jar")
+	ensureListContains(t, copyDests, "arm64/lib/mynativelib.so")
+}
+
 var buildDir string
 
 func setUp() {
diff --git a/sdk/update.go b/sdk/update.go
index 5235c9e..171bb3f 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -16,14 +16,13 @@
 
 import (
 	"fmt"
-	"io"
 	"path/filepath"
-	"strconv"
 	"strings"
 
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
+	"android/soong/cc"
 	"android/soong/java"
 )
 
@@ -32,21 +31,31 @@
 // generatedFile abstracts operations for writing contents into a file and emit a build rule
 // for the file.
 type generatedFile struct {
-	path    android.OutputPath
-	content strings.Builder
+	path        android.OutputPath
+	content     strings.Builder
+	indentLevel int
 }
 
-func newGeneratedFile(ctx android.ModuleContext, name string) *generatedFile {
+func newGeneratedFile(ctx android.ModuleContext, path ...string) *generatedFile {
 	return &generatedFile{
-		path: android.PathForModuleOut(ctx, name).OutputPath,
+		path:        android.PathForModuleOut(ctx, path...).OutputPath,
+		indentLevel: 0,
 	}
 }
 
+func (gf *generatedFile) indent() {
+	gf.indentLevel++
+}
+
+func (gf *generatedFile) dedent() {
+	gf.indentLevel--
+}
+
 func (gf *generatedFile) printfln(format string, args ...interface{}) {
 	// ninja consumes newline characters in rspfile_content. Prevent it by
 	// escaping the backslash in the newline character. The extra backshash
 	// is removed when the rspfile is written to the actual script file
-	fmt.Fprintf(&(gf.content), format+"\\n", args...)
+	fmt.Fprintf(&(gf.content), strings.Repeat("    ", gf.indentLevel)+format+"\\n", args...)
 }
 
 func (gf *generatedFile) build(pctx android.PackageContext, ctx android.BuilderContext, implicits android.Paths) {
@@ -61,34 +70,186 @@
 	rb.Build(pctx, ctx, gf.path.Base(), "Build "+gf.path.Base())
 }
 
-func (s *sdk) javaMemberNames(ctx android.ModuleContext) []string {
-	result := []string{}
+func (s *sdk) javaLibs(ctx android.ModuleContext) []*java.Library {
+	result := []*java.Library{}
 	ctx.VisitDirectDeps(func(m android.Module) {
-		if _, ok := m.(*java.Library); ok {
-			result = append(result, m.Name())
+		if j, ok := m.(*java.Library); ok {
+			result = append(result, j)
 		}
 	})
 	return result
 }
 
-// buildAndroidBp creates the blueprint file that defines prebuilt modules for each of
-// the SDK members, and the sdk_snapshot module for the specified version
-func (s *sdk) buildAndroidBp(ctx android.ModuleContext, version string) android.OutputPath {
-	bp := newGeneratedFile(ctx, "blueprint-"+version+".sh")
+// archSpecificNativeLibInfo represents an arch-specific variant of a native lib
+type archSpecificNativeLibInfo struct {
+	name                      string
+	archType                  string
+	exportedIncludeDirs       android.Paths
+	exportedSystemIncludeDirs android.Paths
+	exportedFlags             []string
+	exportedDeps              android.Paths
+	outputFile                android.Path
+}
 
-	makePrebuiltName := func(name string) string {
-		return ctx.ModuleName() + "_" + name + string(android.SdkVersionSeparator) + version
+func (lib *archSpecificNativeLibInfo) signature() string {
+	return fmt.Sprintf("%v %v %v %v",
+		lib.name,
+		lib.exportedIncludeDirs.Strings(),
+		lib.exportedSystemIncludeDirs.Strings(),
+		lib.exportedFlags)
+}
+
+// nativeLibInfo represents a collection of arch-specific modules having the same name
+type nativeLibInfo struct {
+	name         string
+	archVariants []archSpecificNativeLibInfo
+	// hasArchSpecificFlags is set to true if modules for each architecture all have the same
+	// include dirs, flags, etc, in which case only those of the first arch is selected.
+	hasArchSpecificFlags bool
+}
+
+// nativeMemberInfos collects all cc.Modules that are member of an SDK.
+func (s *sdk) nativeMemberInfos(ctx android.ModuleContext) []*nativeLibInfo {
+	infoMap := make(map[string]*nativeLibInfo)
+
+	// Collect cc.Modules
+	ctx.VisitDirectDeps(func(m android.Module) {
+		ccModule, ok := m.(*cc.Module)
+		if !ok {
+			return
+		}
+		depName := ctx.OtherModuleName(m)
+
+		if _, ok := infoMap[depName]; !ok {
+			infoMap[depName] = &nativeLibInfo{name: depName}
+		}
+
+		info := infoMap[depName]
+		info.archVariants = append(info.archVariants, archSpecificNativeLibInfo{
+			name:                      ccModule.BaseModuleName(),
+			archType:                  ccModule.Target().Arch.ArchType.String(),
+			exportedIncludeDirs:       ccModule.ExportedIncludeDirs(),
+			exportedSystemIncludeDirs: ccModule.ExportedSystemIncludeDirs(),
+			exportedFlags:             ccModule.ExportedFlags(),
+			exportedDeps:              ccModule.ExportedDeps(),
+			outputFile:                ccModule.OutputFile().Path(),
+		})
+	})
+
+	// Determine if include dirs and flags for each module are different across arch-specific
+	// modules or not. And set hasArchSpecificFlags accordingly
+	for _, info := range infoMap {
+		// by default, include paths and flags are assumed to be the same across arches
+		info.hasArchSpecificFlags = false
+		oldSignature := ""
+		for _, av := range info.archVariants {
+			newSignature := av.signature()
+			if oldSignature == "" {
+				oldSignature = newSignature
+			}
+			if oldSignature != newSignature {
+				info.hasArchSpecificFlags = true
+				break
+			}
+		}
 	}
 
-	javaLibs := s.javaMemberNames(ctx)
-	for _, name := range javaLibs {
-		prebuiltName := makePrebuiltName(name)
-		jar := filepath.Join("java", name, "stub.jar")
+	var list []*nativeLibInfo
+	for _, v := range infoMap {
+		list = append(list, v)
+	}
+	return list
+}
 
+// SDK directory structure
+// <sdk_root>/
+//     Android.bp   : definition of a 'sdk' module is here. This is a hand-made one.
+//     <api_ver>/   : below this directory are all auto-generated
+//         Android.bp   : definition of 'sdk_snapshot' module is here
+//         aidl/
+//            frameworks/base/core/..../IFoo.aidl   : an exported AIDL file
+//         java/
+//            <module_name>.jar    : the stub jar for a java library 'module_name'
+//         include/
+//            bionic/libc/include/stdlib.h   : an exported header file
+//         include_gen/
+//            <module_name>/com/android/.../IFoo.h : a generated header file
+//         <arch>/include/   : arch-specific exported headers
+//         <arch>/include_gen/   : arch-specific generated headers
+//         <arch>/lib/
+//            libFoo.so   : a stub library
+
+const (
+	aidlIncludeDir            = "aidl"
+	javaStubDir               = "java"
+	javaStubFileSuffix        = ".jar"
+	nativeIncludeDir          = "include"
+	nativeGeneratedIncludeDir = "include_gen"
+	nativeStubDir             = "lib"
+	nativeStubFileSuffix      = ".so"
+)
+
+// path to the stub file of a java library. Relative to <sdk_root>/<api_dir>
+func javaStubFilePathFor(javaLib *java.Library) string {
+	return filepath.Join(javaStubDir, javaLib.Name()+javaStubFileSuffix)
+}
+
+// path to the stub file of a native shared library. Relative to <sdk_root>/<api_dir>
+func nativeStubFilePathFor(lib archSpecificNativeLibInfo) string {
+	return filepath.Join(lib.archType,
+		nativeStubDir, lib.name+nativeStubFileSuffix)
+}
+
+// paths to the include dirs of a native shared library. Relative to <sdk_root>/<api_dir>
+func nativeIncludeDirPathsFor(ctx android.ModuleContext, lib archSpecificNativeLibInfo,
+	systemInclude bool, archSpecific bool) []string {
+	var result []string
+	var includeDirs []android.Path
+	if !systemInclude {
+		includeDirs = lib.exportedIncludeDirs
+	} else {
+		includeDirs = lib.exportedSystemIncludeDirs
+	}
+	for _, dir := range includeDirs {
+		var path string
+		if _, gen := dir.(android.WritablePath); gen {
+			path = filepath.Join(nativeGeneratedIncludeDir, lib.name)
+		} else {
+			path = filepath.Join(nativeIncludeDir, dir.String())
+		}
+		if archSpecific {
+			path = filepath.Join(lib.archType, path)
+		}
+		result = append(result, path)
+	}
+	return result
+}
+
+// A name that uniquely identifies a prebuilt SDK member for a version of SDK snapshot
+// This isn't visible to users, so could be changed in future.
+func versionedSdkMemberName(ctx android.ModuleContext, memberName string, version string) string {
+	return ctx.ModuleName() + "_" + memberName + string(android.SdkVersionSeparator) + version
+}
+
+// buildAndroidBp creates the blueprint file that defines prebuilt modules for each of
+// the SDK members, and the entire sdk_snapshot module for the specified version
+// TODO(jiyong): create a meta info file (e.g. json, protobuf, etc.) instead, and convert it to
+// Android.bp in the (presumably old) branch where the snapshots will be used. This will give us
+// some flexibility to introduce backwards incompatible changes in soong.
+func (s *sdk) buildAndroidBp(ctx android.ModuleContext, version string) android.OutputPath {
+	bp := newGeneratedFile(ctx, "snapshot", "Android.bp")
+	bp.printfln("// This is auto-generated. DO NOT EDIT.")
+	bp.printfln("")
+
+	javaLibModules := s.javaLibs(ctx)
+	for _, m := range javaLibModules {
+		name := m.Name()
 		bp.printfln("java_import {")
-		bp.printfln("    name: %q,", prebuiltName)
-		bp.printfln("    jars: [%q],", jar)
-		bp.printfln("    sdk_member_name: %q,", name)
+		bp.indent()
+		bp.printfln("name: %q,", versionedSdkMemberName(ctx, name, version))
+		bp.printfln("sdk_member_name: %q,", name)
+		bp.printfln("jars: [%q],", javaStubFilePathFor(m))
+		bp.dedent()
 		bp.printfln("}")
 		bp.printfln("")
 
@@ -96,133 +257,201 @@
 		// doesn't exist (i.e. building in an unbundled tree). "prefer:" is set to false
 		// so that this module does not eclipse the unversioned module if it exists.
 		bp.printfln("java_import {")
-		bp.printfln("    name: %q,", name)
-		bp.printfln("    jars: [%q],", jar)
-		bp.printfln("    prefer: false,")
+		bp.indent()
+		bp.printfln("name: %q,", name)
+		bp.printfln("jars: [%q],", javaStubFilePathFor(m))
+		bp.printfln("prefer: false,")
+		bp.dedent()
 		bp.printfln("}")
 		bp.printfln("")
-
 	}
 
-	// TODO(jiyong): emit cc_prebuilt_library_shared for the native libs
+	nativeLibInfos := s.nativeMemberInfos(ctx)
+	for _, info := range nativeLibInfos {
+		bp.printfln("cc_prebuilt_library_shared {")
+		bp.indent()
+		bp.printfln("name: %q,", versionedSdkMemberName(ctx, info.name, version))
+		bp.printfln("sdk_member_name: %q,", info.name)
+
+		// a function for emitting include dirs
+		printExportedDirsForNativeLibs := func(lib archSpecificNativeLibInfo, systemInclude bool) {
+			includeDirs := nativeIncludeDirPathsFor(ctx, lib, systemInclude, info.hasArchSpecificFlags)
+			if len(includeDirs) == 0 {
+				return
+			}
+			if !systemInclude {
+				bp.printfln("export_include_dirs: [")
+			} else {
+				bp.printfln("export_system_include_dirs: [")
+			}
+			bp.indent()
+			for _, dir := range includeDirs {
+				bp.printfln("%q,", dir)
+			}
+			bp.dedent()
+			bp.printfln("],")
+		}
+
+		if !info.hasArchSpecificFlags {
+			printExportedDirsForNativeLibs(info.archVariants[0], false /*systemInclude*/)
+			printExportedDirsForNativeLibs(info.archVariants[0], true /*systemInclude*/)
+		}
+
+		bp.printfln("arch: {")
+		bp.indent()
+		for _, av := range info.archVariants {
+			bp.printfln("%s: {", av.archType)
+			bp.indent()
+			bp.printfln("srcs: [%q],", nativeStubFilePathFor(av))
+			if info.hasArchSpecificFlags {
+				// export_* properties are added inside the arch: {<arch>: {...}} block
+				printExportedDirsForNativeLibs(av, false /*systemInclude*/)
+				printExportedDirsForNativeLibs(av, true /*systemInclude*/)
+			}
+			bp.dedent()
+			bp.printfln("},") // <arch>
+		}
+		bp.dedent()
+		bp.printfln("},") // arch
+		bp.printfln("stl: \"none\",")
+		bp.printfln("system_shared_libs: [],")
+		bp.dedent()
+		bp.printfln("}") // cc_prebuilt_library_shared
+		bp.printfln("")
+	}
 
 	bp.printfln("sdk_snapshot {")
-	bp.printfln("    name: %q,", ctx.ModuleName()+string(android.SdkVersionSeparator)+version)
-	bp.printfln("    java_libs: [")
-	for _, n := range javaLibs {
-		bp.printfln("        %q,", makePrebuiltName(n))
+	bp.indent()
+	bp.printfln("name: %q,", ctx.ModuleName()+string(android.SdkVersionSeparator)+version)
+	if len(javaLibModules) > 0 {
+		bp.printfln("java_libs: [")
+		bp.indent()
+		for _, m := range javaLibModules {
+			bp.printfln("%q,", versionedSdkMemberName(ctx, m.Name(), version))
+		}
+		bp.dedent()
+		bp.printfln("],") // java_libs
 	}
-	bp.printfln("    ],")
-	// TODO(jiyong): emit native_shared_libs
-	bp.printfln("}")
+	if len(nativeLibInfos) > 0 {
+		bp.printfln("native_shared_libs: [")
+		bp.indent()
+		for _, info := range nativeLibInfos {
+			bp.printfln("%q,", versionedSdkMemberName(ctx, info.name, version))
+		}
+		bp.dedent()
+		bp.printfln("],") // native_shared_libs
+	}
+	bp.dedent()
+	bp.printfln("}") // sdk_snapshot
 	bp.printfln("")
 
 	bp.build(pctx, ctx, nil)
 	return bp.path
 }
 
-func (s *sdk) buildScript(ctx android.ModuleContext, version string) android.OutputPath {
-	sh := newGeneratedFile(ctx, "update_prebuilt-"+version+".sh")
+// buildSnapshot is the main function in this source file. It creates rules to copy
+// the contents (header files, stub libraries, etc) into the zip file.
+func (s *sdk) buildSnapshot(ctx android.ModuleContext) android.OutputPath {
+	snapshotPath := func(paths ...string) android.OutputPath {
+		return android.PathForModuleOut(ctx, "snapshot").Join(ctx, paths...)
+	}
 
-	snapshotRoot := filepath.Join(ctx.ModuleDir(), version)
-	aidlIncludeDir := filepath.Join(snapshotRoot, "aidl")
-	javaStubsDir := filepath.Join(snapshotRoot, "java")
+	var filesToZip android.Paths
+	// copy src to dest and add the dest to the zip
+	copy := func(src android.Path, dest android.OutputPath) {
+		ctx.Build(pctx, android.BuildParams{
+			Rule:   android.Cp,
+			Input:  src,
+			Output: dest,
+		})
+		filesToZip = append(filesToZip, dest)
+	}
 
-	sh.printfln("#!/bin/bash")
-	sh.printfln("echo Updating snapshot of %s in %s", ctx.ModuleName(), snapshotRoot)
-	sh.printfln("pushd $ANDROID_BUILD_TOP > /dev/null")
-	sh.printfln("rm -rf %s", snapshotRoot)
-	sh.printfln("mkdir -p %s", aidlIncludeDir)
-	sh.printfln("mkdir -p %s", javaStubsDir)
-	// TODO(jiyong): mkdir the 'native' dir
+	// copy exported AIDL files and stub jar files
+	for _, m := range s.javaLibs(ctx) {
+		headerJars := m.HeaderJars()
+		if len(headerJars) != 1 {
+			panic(fmt.Errorf("there must be only one header jar from %q", m.Name()))
+		}
+		copy(headerJars[0], snapshotPath(javaStubFilePathFor(m)))
 
-	var implicits android.Paths
-	ctx.VisitDirectDeps(func(m android.Module) {
-		if javaLib, ok := m.(*java.Library); ok {
-			headerJars := javaLib.HeaderJars()
-			if len(headerJars) != 1 {
-				panic(fmt.Errorf("there must be only one header jar from %q", m.Name()))
+		for _, dir := range m.AidlIncludeDirs() {
+			// TODO(jiyong): copy parcelable declarations only
+			aidlFiles, _ := ctx.GlobWithDeps(dir.String()+"/**/*.aidl", nil)
+			for _, file := range aidlFiles {
+				copy(android.PathForSource(ctx, file), snapshotPath(aidlIncludeDir, file))
 			}
-			implicits = append(implicits, headerJars...)
+		}
+	}
 
-			exportedAidlIncludeDirs := javaLib.AidlIncludeDirs()
-			for _, dir := range exportedAidlIncludeDirs {
-				// Using tar to copy with the directory structure
-				// TODO(jiyong): copy parcelable declarations only
-				sh.printfln("find %s -name \"*.aidl\" | tar cf - -T - | (cd %s; tar xf -)",
-					dir.String(), aidlIncludeDir)
+	// copy exported header files and stub *.so files
+	nativeLibInfos := s.nativeMemberInfos(ctx)
+	for _, info := range nativeLibInfos {
+
+		// a function for emitting include dirs
+		printExportedDirCopyCommandsForNativeLibs := func(lib archSpecificNativeLibInfo) {
+			includeDirs := lib.exportedIncludeDirs
+			includeDirs = append(includeDirs, lib.exportedSystemIncludeDirs...)
+			if len(includeDirs) == 0 {
+				return
+			}
+			for _, dir := range includeDirs {
+				if _, gen := dir.(android.WritablePath); gen {
+					// generated headers are copied via exportedDeps. See below.
+					continue
+				}
+				targetDir := nativeIncludeDir
+				if info.hasArchSpecificFlags {
+					targetDir = filepath.Join(lib.archType, targetDir)
+				}
+
+				// TODO(jiyong) copy headers having other suffixes
+				headers, _ := ctx.GlobWithDeps(dir.String()+"/**/*.h", nil)
+				for _, file := range headers {
+					src := android.PathForSource(ctx, file)
+					dest := snapshotPath(targetDir, file)
+					copy(src, dest)
+				}
 			}
 
-			copiedHeaderJar := filepath.Join(javaStubsDir, m.Name(), "stub.jar")
-			sh.printfln("mkdir -p $(dirname %s) && cp %s %s",
-				copiedHeaderJar, headerJars[0].String(), copiedHeaderJar)
+			genHeaders := lib.exportedDeps
+			for _, file := range genHeaders {
+				targetDir := nativeGeneratedIncludeDir
+				if info.hasArchSpecificFlags {
+					targetDir = filepath.Join(lib.archType, targetDir)
+				}
+				dest := snapshotPath(targetDir, lib.name, file.Rel())
+				copy(file, dest)
+			}
 		}
-		// TODO(jiyong): emit the commands for copying the headers and stub libraries for native libs
-	})
 
-	bp := s.buildAndroidBp(ctx, version)
-	implicits = append(implicits, bp)
-	sh.printfln("cp %s %s", bp.String(), filepath.Join(snapshotRoot, "Android.bp"))
-
-	sh.printfln("popd > /dev/null")
-	sh.printfln("rm -- \"$0\"") // self deleting so that stale script is not used
-	sh.printfln("echo Done")
-
-	sh.build(pctx, ctx, implicits)
-	return sh.path
-}
-
-func (s *sdk) buildSnapshotGenerationScripts(ctx android.ModuleContext) {
-	if s.snapshot() {
-		// we don't need a script for sdk_snapshot.. as they are frozen
-		return
-	}
-
-	// script to update the 'current' snapshot
-	s.updateScript = s.buildScript(ctx, "current")
-
-	versions := s.frozenVersions(ctx)
-	newVersion := "1"
-	if len(versions) >= 1 {
-		lastVersion := versions[len(versions)-1]
-		lastVersionNum, err := strconv.Atoi(lastVersion)
-		if err != nil {
-			panic(err)
-			return
+		if !info.hasArchSpecificFlags {
+			printExportedDirCopyCommandsForNativeLibs(info.archVariants[0])
 		}
-		newVersion = strconv.Itoa(lastVersionNum + 1)
-	}
-	// script to create a new frozen version of snapshot
-	s.freezeScript = s.buildScript(ctx, newVersion)
-}
 
-func (s *sdk) androidMkEntriesForScript() android.AndroidMkEntries {
-	if s.snapshot() {
-		// we don't need a script for sdk_snapshot.. as they are frozen
-		return android.AndroidMkEntries{}
+		// for each architecture
+		for _, av := range info.archVariants {
+			copy(av.outputFile, snapshotPath(nativeStubFilePathFor(av)))
+
+			if info.hasArchSpecificFlags {
+				printExportedDirCopyCommandsForNativeLibs(av)
+			}
+		}
 	}
 
-	entries := android.AndroidMkEntries{
-		Class: "FAKE",
-		// TODO(jiyong): remove this? but androidmk.go expects OutputFile to be specified anyway
-		OutputFile: android.OptionalPathForPath(s.updateScript),
-		Include:    "$(BUILD_SYSTEM)/base_rules.mk",
-		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
-			func(entries *android.AndroidMkEntries) {
-				entries.AddStrings("LOCAL_ADDITIONAL_DEPENDENCIES",
-					s.updateScript.String(), s.freezeScript.String())
-			},
-		},
-		ExtraFooters: []android.AndroidMkExtraFootersFunc{
-			func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
-				fmt.Fprintln(w, "$(LOCAL_BUILT_MODULE): $(LOCAL_ADDITIONAL_DEPENDENCIES)")
-				fmt.Fprintln(w, "	touch $@")
-				fmt.Fprintln(w, "	echo ##################################################")
-				fmt.Fprintln(w, "	echo To update current SDK: execute", s.updateScript.String())
-				fmt.Fprintln(w, "	echo To freeze current SDK: execute", s.freezeScript.String())
-				fmt.Fprintln(w, "	echo ##################################################")
-			},
-		},
-	}
-	return entries
+	// generate Android.bp
+	bp := s.buildAndroidBp(ctx, "current")
+	filesToZip = append(filesToZip, bp)
+
+	// zip them all
+	zipFile := android.PathForModuleOut(ctx, ctx.ModuleName()+"-current.zip").OutputPath
+	rb := android.NewRuleBuilder()
+	rb.Command().
+		BuiltTool(ctx, "soong_zip").
+		FlagWithArg("-C ", snapshotPath().String()).
+		FlagWithRspFileInputList("-l ", filesToZip).
+		FlagWithOutput("-o ", zipFile)
+	rb.Build(pctx, ctx, "snapshot", "Building snapshot for "+ctx.ModuleName())
+
+	return zipFile
 }
diff --git a/ui/build/config.go b/ui/build/config.go
index 919b9ce..92aee4d 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -219,10 +219,10 @@
 		if override, ok := ret.environ.Get("OVERRIDE_ANDROID_JAVA_HOME"); ok {
 			return override
 		}
-		if toolchain11, ok := ret.environ.Get("EXPERIMENTAL_USE_OPENJDK11_TOOLCHAIN"); ok && toolchain11 == "true" {
-			return java11Home
+		if toolchain11, ok := ret.environ.Get("EXPERIMENTAL_USE_OPENJDK11_TOOLCHAIN"); ok && toolchain11 != "true" {
+			ctx.Fatalln("The environment variable EXPERIMENTAL_USE_OPENJDK11_TOOLCHAIN is no longer supported. An OpenJDK 11 toolchain is now the global default.")
 		}
-		return java9Home
+		return java11Home
 	}()
 	absJavaHome := absPath(ctx, javaHome)
 
diff --git a/ui/terminal/smart_status.go b/ui/terminal/smart_status.go
index efcfd43..6bdf140 100644
--- a/ui/terminal/smart_status.go
+++ b/ui/terminal/smart_status.go
@@ -170,6 +170,13 @@
 }
 
 func (s *smartStatusOutput) Flush() {
+	if s.tableMode {
+		// Stop the action table tick outside of the lock to avoid lock ordering issues between s.done and
+		// s.lock, the goroutine in startActionTableTick can get blocked on the lock and be unable to read
+		// from the channel.
+		s.stopActionTableTick()
+	}
+
 	s.lock.Lock()
 	defer s.lock.Unlock()
 
@@ -180,8 +187,6 @@
 	s.runningActions = nil
 
 	if s.tableMode {
-		s.stopActionTableTick()
-
 		// Update the table after clearing runningActions to clear it
 		s.actionTable()
 
diff --git a/zip/zip.go b/zip/zip.go
index 707c4ef..3c710a7 100644
--- a/zip/zip.go
+++ b/zip/zip.go
@@ -145,7 +145,7 @@
 	}
 
 	arg := b.state
-	arg.SourceFiles = strings.Split(string(list), "\n")
+	arg.SourceFiles = strings.Fields(string(list))
 	b.fileArgs = append(b.fileArgs, arg)
 	return b
 }
diff --git a/zip/zip_test.go b/zip/zip_test.go
index 84317d1..9705d6c 100644
--- a/zip/zip_test.go
+++ b/zip/zip_test.go
@@ -46,7 +46,8 @@
 	"dangling -> missing": nil,
 	"a/a/d -> b":          nil,
 	"c":                   fileC,
-	"l":                   []byte("a/a/a\na/a/b\nc\n"),
+	"l_nl":                []byte("a/a/a\na/a/b\nc\n"),
+	"l_sp":                []byte("a/a/a a/a/b c"),
 	"l2":                  []byte("missing\n"),
 	"manifest.txt":        fileCustomManifest,
 })
@@ -224,7 +225,19 @@
 		{
 			name: "list",
 			args: fileArgsBuilder().
-				List("l"),
+				List("l_nl"),
+			compressionLevel: 9,
+
+			files: []zip.FileHeader{
+				fh("a/a/a", fileA, zip.Deflate),
+				fh("a/a/b", fileB, zip.Deflate),
+				fh("c", fileC, zip.Deflate),
+			},
+		},
+		{
+			name: "list",
+			args: fileArgsBuilder().
+				List("l_sp"),
 			compressionLevel: 9,
 
 			files: []zip.FileHeader{