Merge "Use ctx.Fatalln instead of log.Fatalln for absolute path errors"
diff --git a/Android.bp b/Android.bp
index 89a1711..afbae17 100644
--- a/Android.bp
+++ b/Android.bp
@@ -67,6 +67,7 @@
         "android/proto.go",
         "android/register.go",
         "android/rule_builder.go",
+        "android/sdk.go",
         "android/sh_binary.go",
         "android/singleton.go",
         "android/testing.go",
@@ -332,6 +333,8 @@
         "soong-cc-config",
     ],
     srcs: [
+        "rust/config/arm_device.go",
+        "rust/config/arm64_device.go",
         "rust/config/global.go",
         "rust/config/toolchain.go",
         "rust/config/whitelist.go",
@@ -475,6 +478,26 @@
     pluginFor: ["soong_build"],
 }
 
+bootstrap_go_package {
+    name: "soong-sdk",
+    pkgPath: "android/soong/sdk",
+    deps: [
+        "blueprint",
+        "soong",
+        "soong-android",
+        "soong-apex",
+        "soong-cc",
+        "soong-java",
+    ],
+    srcs: [
+        "sdk/sdk.go",
+    ],
+    testSrcs: [
+        "sdk/sdk_test.go",
+    ],
+    pluginFor: ["soong_build"],
+}
+
 //
 // Defaults to enable various configurations of host bionic
 //
diff --git a/OWNERS b/OWNERS
index 9f0fcf2..797229f 100644
--- a/OWNERS
+++ b/OWNERS
@@ -4,4 +4,4 @@
 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 = ivanlozano@google.com, jeffv@google.com, jgalenson@google.com, srhines@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/sdk.go b/android/sdk.go
new file mode 100644
index 0000000..52c392f
--- /dev/null
+++ b/android/sdk.go
@@ -0,0 +1,146 @@
+// Copyright (C) 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 android
+
+import (
+	"strings"
+
+	"github.com/google/blueprint/proptools"
+)
+
+// SdkAware is the interface that must be supported by any module to become a member of SDK or to be
+// built with SDK
+type SdkAware interface {
+	Module
+	sdkBase() *SdkBase
+	MakeMemberOf(sdk SdkRef)
+	IsInAnySdk() bool
+	ContainingSdk() SdkRef
+	MemberName() string
+	BuildWithSdks(sdks SdkRefs)
+	RequiredSdks() SdkRefs
+}
+
+// SdkRef refers to a version of an SDK
+type SdkRef struct {
+	Name    string
+	Version string
+}
+
+const (
+	// currentVersion refers to the in-development version of an SDK
+	currentVersion = "current"
+)
+
+// IsCurrentVersion determines if the SdkRef is referencing to an in-development version of an SDK
+func (s SdkRef) IsCurrentVersion() bool {
+	return s.Version == currentVersion
+}
+
+// IsCurrentVersionOf determines if the SdkRef is referencing to an in-development version of the
+// specified SDK
+func (s SdkRef) IsCurrentVersionOf(name string) bool {
+	return s.Name == name && s.IsCurrentVersion()
+}
+
+// ParseSdkRef parses a `name#version` style string into a corresponding SdkRef struct
+func ParseSdkRef(ctx BaseModuleContext, str string, property string) SdkRef {
+	tokens := strings.Split(str, "#")
+	if len(tokens) < 1 || len(tokens) > 2 {
+		ctx.PropertyErrorf(property, "%q does not follow name#version syntax", str)
+		return SdkRef{Name: "invalid sdk name", Version: "invalid sdk version"}
+	}
+
+	name := tokens[0]
+
+	version := currentVersion // If version is omitted, defaults to "current"
+	if len(tokens) == 2 {
+		version = tokens[1]
+	}
+
+	return SdkRef{Name: name, Version: version}
+}
+
+type SdkRefs []SdkRef
+
+func (refs SdkRefs) Contains(s SdkRef) bool {
+	for _, r := range refs {
+		if r == s {
+			return true
+		}
+	}
+	return false
+}
+
+type sdkProperties struct {
+	// The SDK that this module is a member of. nil if it is not a member of any SDK
+	ContainingSdk *SdkRef `blueprint:"mutated"`
+
+	// The list of SDK names and versions that are used to build this module
+	RequiredSdks SdkRefs `blueprint:"mutated"`
+
+	// Name of the module that this sdk member is representing
+	Sdk_member_name *string
+}
+
+// SdkBase is a struct that is expected to be included in module types to implement the SdkAware
+// interface. InitSdkAwareModule should be called to initialize this struct.
+type SdkBase struct {
+	properties sdkProperties
+}
+
+func (s *SdkBase) sdkBase() *SdkBase {
+	return s
+}
+
+// MakeMemberof sets this module to be a member of a specific SDK
+func (s *SdkBase) MakeMemberOf(sdk SdkRef) {
+	s.properties.ContainingSdk = &sdk
+}
+
+// IsInAnySdk returns true if this module is a member of any SDK
+func (s *SdkBase) IsInAnySdk() bool {
+	return s.properties.ContainingSdk != nil
+}
+
+// ContainingSdk returns the SDK that this module is a member of
+func (s *SdkBase) ContainingSdk() SdkRef {
+	if s.properties.ContainingSdk != nil {
+		return *s.properties.ContainingSdk
+	}
+	return SdkRef{Name: "", Version: currentVersion}
+}
+
+// Membername returns the name of the module that this SDK member is overriding
+func (s *SdkBase) MemberName() string {
+	return proptools.String(s.properties.Sdk_member_name)
+}
+
+// BuildWithSdks is used to mark that this module has to be built with the given SDK(s).
+func (s *SdkBase) BuildWithSdks(sdks SdkRefs) {
+	s.properties.RequiredSdks = sdks
+}
+
+// RequiredSdks returns the SDK(s) that this module has to be built with
+func (s *SdkBase) RequiredSdks() SdkRefs {
+	return s.properties.RequiredSdks
+}
+
+// InitSdkAwareModule initializes the SdkBase struct. This must be called by all modules including
+// SdkBase.
+func InitSdkAwareModule(m SdkAware) {
+	base := m.sdkBase()
+	m.AddProperties(&base.properties)
+}
diff --git a/apex/apex.go b/apex/apex.go
index c3f6a74..4e72d09 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -150,7 +150,6 @@
 var (
 	whitelistNoApex = map[string][]string{
 		"apex_test_build_features":       []string{"libbinder"},
-		"com.android.neuralnetworks":     []string{"libbinder"},
 		"com.android.media":              []string{"libbinder"},
 		"com.android.media.swcodec":      []string{"libbinder"},
 		"test_com.android.media.swcodec": []string{"libbinder"},
@@ -185,7 +184,7 @@
 	pctx.HostBinToolVariable("zipalign", "zipalign")
 	pctx.HostBinToolVariable("jsonmodify", "jsonmodify")
 
-	android.RegisterModuleType("apex", apexBundleFactory)
+	android.RegisterModuleType("apex", BundleFactory)
 	android.RegisterModuleType("apex_test", testApexBundleFactory)
 	android.RegisterModuleType("apex_vndk", vndkApexBundleFactory)
 	android.RegisterModuleType("apex_defaults", defaultsFactory)
@@ -195,12 +194,14 @@
 		ctx.TopDown("apex_vndk_gather", apexVndkGatherMutator).Parallel()
 		ctx.BottomUp("apex_vndk_add_deps", apexVndkAddDepsMutator).Parallel()
 	})
-	android.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
-		ctx.TopDown("apex_deps", apexDepsMutator)
-		ctx.BottomUp("apex", apexMutator).Parallel()
-		ctx.BottomUp("apex_flattened", apexFlattenedMutator).Parallel()
-		ctx.BottomUp("apex_uses", apexUsesMutator).Parallel()
-	})
+	android.PostDepsMutators(RegisterPostDepsMutators)
+}
+
+func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) {
+	ctx.TopDown("apex_deps", apexDepsMutator)
+	ctx.BottomUp("apex", apexMutator).Parallel()
+	ctx.BottomUp("apex_flattened", apexFlattenedMutator).Parallel()
+	ctx.BottomUp("apex_uses", apexUsesMutator).Parallel()
 }
 
 var (
@@ -287,11 +288,14 @@
 }
 
 func apexFlattenedMutator(mctx android.BottomUpMutatorContext) {
-	if _, ok := mctx.Module().(*apexBundle); ok {
+	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()
 		}
 	}
 }
@@ -407,9 +411,19 @@
 	// List of APKs to package inside APEX
 	Apps []string
 
-	// To distinguish between flattened and non-flattened variants.
-	// if set true, then this variant is flattened variant.
+	// 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"`
+
+	// List of SDKs that are used to build this APEX. A reference to an SDK should be either
+	// `name#version` or `name` which is an alias for `name#current`. If left empty, `platform#current`
+	// is implied. This value affects all modules included in this APEX. In other words, they are
+	// also built with the SDKs specified here.
+	Uses_sdks []string
 }
 
 type apexTargetBundleProperties struct {
@@ -536,6 +550,7 @@
 type apexBundle struct {
 	android.ModuleBase
 	android.DefaultableModuleBase
+	android.SdkBase
 
 	properties       apexBundleProperties
 	targetProperties apexTargetBundleProperties
@@ -567,9 +582,6 @@
 
 	// intermediate path for apex_manifest.json
 	manifestOut android.WritablePath
-
-	// A config value of (TARGET_FLATTEN_APEX && !TARGET_BUILD_APPS)
-	flattenedConfigValue bool
 }
 
 func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext,
@@ -738,6 +750,16 @@
 	if cert != "" {
 		ctx.AddDependency(ctx.Module(), certificateTag, cert)
 	}
+
+	// TODO(jiyong): ensure that all apexes are with non-empty uses_sdks
+	if len(a.properties.Uses_sdks) > 0 {
+		sdkRefs := []android.SdkRef{}
+		for _, str := range a.properties.Uses_sdks {
+			parsed := android.ParseSdkRef(ctx, str, "uses_sdks")
+			sdkRefs = append(sdkRefs, parsed)
+		}
+		a.BuildWithSdks(sdkRefs)
+	}
 }
 
 func (a *apexBundle) getCertString(ctx android.BaseModuleContext) string {
@@ -820,6 +842,20 @@
 	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.
@@ -1133,6 +1169,8 @@
 					}
 				} else if am.CanHaveApexVariants() && am.IsInstallableToApex() {
 					ctx.ModuleErrorf("unexpected tag %q for indirect dependency %q", depTag, depName)
+				} else if depTag == android.DefaultsDepTag {
+					return false
 				} else if am.NoApex() && !android.InList(depName, whitelistNoApex[ctx.ModuleName()]) {
 					ctx.ModuleErrorf("tries to include no_apex module %s", depName)
 				}
@@ -1141,10 +1179,6 @@
 		return false
 	})
 
-	a.flattenedConfigValue = ctx.Config().FlattenApex() && !ctx.Config().UnbundledBuild()
-	if a.flattenedConfigValue {
-		a.properties.Flattened = true
-	}
 	if a.private_key_file == nil {
 		ctx.PropertyErrorf("key", "private_key for %q could not be found", String(a.properties.Key))
 		return
@@ -1483,7 +1517,7 @@
 	})
 
 	// Install to $OUT/soong/{target,host}/.../apex
-	if a.installable() && (!ctx.Config().FlattenApex() || apexType.zip()) && (!a.properties.Flattened || a.flattenedConfigValue) {
+	if a.installable() && (!ctx.Config().FlattenApex() || apexType.zip()) && !a.isFlattenedVariant() {
 		ctx.InstallFile(a.installDir, ctx.ModuleName()+suffix, a.outputFiles[apexType])
 	}
 }
@@ -1548,7 +1582,7 @@
 		}
 
 		var suffix string
-		if a.properties.Flattened && !a.flattenedConfigValue {
+		if a.isFlattenedVariant() {
 			suffix = ".flattened"
 		}
 
@@ -1566,7 +1600,7 @@
 			// /system/apex/<name>/{lib|framework|...}
 			fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", filepath.Join("$(OUT_DIR)",
 				a.installDir.RelPathString(), name, fi.installDir))
-			if a.flattenedConfigValue {
+			if !a.isFlattenedVariant() {
 				fmt.Fprintln(w, "LOCAL_SOONG_SYMBOL_PATH :=", pathWhenActivated)
 			}
 			if len(fi.symlinks) > 0 {
@@ -1648,7 +1682,7 @@
 				moduleNames = a.androidMkForFiles(w, name, moduleDir, apexType)
 			}
 
-			if a.properties.Flattened && !a.flattenedConfigValue {
+			if a.isFlattenedVariant() {
 				name = name + ".flattened"
 			}
 
@@ -1663,7 +1697,7 @@
 				fmt.Fprintln(w, "include $(BUILD_PHONY_PACKAGE)")
 				fmt.Fprintln(w, "$(LOCAL_INSTALLED_MODULE): .KATI_IMPLICIT_OUTPUTS :=", a.flattenedOutput.String())
 
-			} else if !a.properties.Flattened || a.flattenedConfigValue {
+			} 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 {
@@ -1707,6 +1741,7 @@
 	})
 	android.InitAndroidMultiTargetsArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
 	android.InitDefaultableModule(module)
+	android.InitSdkAwareModule(module)
 	return module
 }
 
@@ -1722,7 +1757,7 @@
 	return bundle
 }
 
-func apexBundleFactory() android.Module {
+func BundleFactory() android.Module {
 	return newApexBundle()
 }
 
diff --git a/apex/apex_test.go b/apex/apex_test.go
index d16917d..91c6426 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -95,13 +95,16 @@
 	config.TestProductVariables.Platform_vndk_version = proptools.StringPtr("VER")
 
 	ctx := android.NewTestArchContext()
-	ctx.RegisterModuleType("apex", android.ModuleFactoryAdaptor(apexBundleFactory))
+	ctx.RegisterModuleType("apex", android.ModuleFactoryAdaptor(BundleFactory))
 	ctx.RegisterModuleType("apex_test", android.ModuleFactoryAdaptor(testApexBundleFactory))
 	ctx.RegisterModuleType("apex_vndk", android.ModuleFactoryAdaptor(vndkApexBundleFactory))
-	ctx.RegisterModuleType("apex_key", android.ModuleFactoryAdaptor(apexKeyFactory))
+	ctx.RegisterModuleType("apex_key", android.ModuleFactoryAdaptor(ApexKeyFactory))
 	ctx.RegisterModuleType("apex_defaults", android.ModuleFactoryAdaptor(defaultsFactory))
 	ctx.RegisterModuleType("prebuilt_apex", android.ModuleFactoryAdaptor(PrebuiltFactory))
 
+	ctx.RegisterModuleType("cc_defaults", android.ModuleFactoryAdaptor(func() android.Module {
+		return cc.DefaultsFactory()
+	}))
 	ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(cc.LibraryFactory))
 	ctx.RegisterModuleType("cc_library_shared", android.ModuleFactoryAdaptor(cc.LibrarySharedFactory))
 	ctx.RegisterModuleType("cc_library_headers", android.ModuleFactoryAdaptor(cc.LibraryHeaderFactory))
@@ -2127,6 +2130,7 @@
 }
 
 func TestApexUsesFailsIfUseNoApex(t *testing.T) {
+	// 'no_apex' prevents a module to be included in an apex
 	testApexError(t, `tries to include no_apex module mylib2`, `
 		apex {
 			name: "commonapex",
@@ -2157,6 +2161,7 @@
 		}
 	`)
 
+	// respect 'no_apex' even with static link
 	testApexError(t, `tries to include no_apex module mylib2`, `
 		apex {
 			name: "commonapex",
@@ -2187,6 +2192,86 @@
 		}
 	`)
 
+	// 'no_apex' can be applied via defaults
+	testApexError(t, `tries to include no_apex module mylib2`, `
+		apex {
+			name: "commonapex",
+			key: "myapex.key",
+			native_shared_libs: ["mylib"],
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		cc_library {
+			name: "mylib",
+			srcs: ["mylib.cpp"],
+			static_libs: ["mylib2"],
+			system_shared_libs: [],
+			stl: "none",
+		}
+
+		cc_defaults {
+			name: "mylib2_defaults",
+			system_shared_libs: [],
+			stl: "none",
+			no_apex: true,
+		}
+
+		cc_library {
+			name: "mylib2",
+			srcs: ["mylib.cpp"],
+			defaults: ["mylib2_defaults"],
+		}
+	`)
+}
+
+func TestNoApexWorksWithWhitelist(t *testing.T) {
+
+	testApex(t, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			native_shared_libs: ["mylib"],
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		cc_library {
+			name: "mylib",
+			srcs: ["mylib.cpp"],
+			shared_libs: ["mylib2"],
+			system_shared_libs: [],
+			stl: "none",
+		}
+
+		cc_defaults {
+			name: "mylib2_defaults",
+			system_shared_libs: [],
+			stl: "none",
+			no_apex: true,
+		}
+
+		cc_library {
+			name: "mylib2",
+			srcs: ["mylib.cpp"],
+			defaults: ["mylib2_defaults"],
+		}
+	`, func(fs map[string][]byte, config android.Config) {
+		whitelistNoApex = map[string][]string{
+			"myapex": []string{"mylib2"},
+		}
+	})
+}
+
+func TestNoApexCanBeDependedOnViaStubs(t *testing.T) {
 	ctx, _ := testApex(t, `
 		apex {
 			name: "myapex",
@@ -2219,6 +2304,7 @@
 			},
 		}
 
+		// this won't be included in "myapex", so 'no_apex' is still valid in this case.
 		cc_library {
 			name: "mylib3",
 			srcs: ["mylib.cpp"],
@@ -2235,7 +2321,6 @@
 	ensureContains(t, copyCmds, "image.apex/lib64/mylib.so")
 	ensureNotContains(t, copyCmds, "image.apex/lib64/mylib2.so")
 	ensureNotContains(t, copyCmds, "image.apex/lib64/mylib3.so")
-
 }
 
 func TestErrorsIfDepsAreNotEnabled(t *testing.T) {
diff --git a/apex/key.go b/apex/key.go
index 08cd45e..ffde315 100644
--- a/apex/key.go
+++ b/apex/key.go
@@ -27,7 +27,7 @@
 var String = proptools.String
 
 func init() {
-	android.RegisterModuleType("apex_key", apexKeyFactory)
+	android.RegisterModuleType("apex_key", ApexKeyFactory)
 	android.RegisterSingletonType("apex_keys_text", apexKeysTextFactory)
 }
 
@@ -53,7 +53,7 @@
 	Installable *bool
 }
 
-func apexKeyFactory() android.Module {
+func ApexKeyFactory() android.Module {
 	module := &apexKey{}
 	module.AddProperties(&module.properties)
 	android.InitAndroidArchModule(module, android.HostAndDeviceDefault, android.MultilibCommon)
diff --git a/build_kzip.bash b/build_kzip.bash
index 5364e7f..c1d09f7 100755
--- a/build_kzip.bash
+++ b/build_kzip.bash
@@ -3,16 +3,22 @@
 # Build kzip files (source files for the indexing pipeline) for the given configuration,
 # merge them and place the resulting all.kzip into $DIST_DIR.
 # It is assumed that the current directory is the top of the source tree.
-# The following enviromnet variables affect the result:
-#   TARGET_PRODUCT        target device name, e.g., `aosp_blueline`
+# The following environment variables affect the result:
+#   TARGET_PRODUCT        target device name, e.g., 'aosp_blueline'
 #   TARGET_BUILD_VARIANT  variant, e.g., `userdebug`
-#   OUT_DIR               where the build is happening (./out if not specified)
+#   OUT_DIR               absolute path  where the build is happening ($PWD/out if not specified})
 #   DIST_DIR              where the resulting all.kzip will be placed
-#   XREF_CORPUS           source code repository URI, e.g.,
-#                        `android.googlesource.com/platform/superproject`
+#   XREF_CORPUS           source code repository URI, e.g., 'android.googlesource.com/platform/superproject'
+#   BUILD_NUMBER          build number, used to generate unique ID (will use UUID if not set)
+
+# If OUT_DIR is not set, the build will use out/ as output directory, which is
+# a relative path. Make it absolute, otherwise the indexer will not know that it
+# contains only generated files.
+: ${OUT_DIR:=$PWD/out}
+[[ "$OUT_DIR" =~ ^/ ]] || { echo "$OUT_DIR is not an absolute path"; exit 1; }
 
 # The extraction might fail for some source files, so run with -k
-build/soong/soong_ui.bash --build-mode --all-modules --dir=$PWD -k merge_zips xref_cxx xref_java
+OUT_DIR=$OUT_DIR build/soong/soong_ui.bash --build-mode --all-modules --dir=$PWD -k merge_zips xref_cxx xref_java
 
 # We build with -k, so check that we have generated at least 100K files
 # (the actual number is 180K+)
@@ -22,4 +28,5 @@
 # Pack
 # TODO(asmundak): this should be done by soong.
 declare -r allkzip=all.kzip
-"${OUT_DIR:-out}/soong/host/linux-x86/bin/merge_zips" "$DIST_DIR/$allkzip" @<(find $OUT_DIR -name '*.kzip')
+"$OUT_DIR/soong/host/linux-x86/bin/merge_zips" "$DIST_DIR/$allkzip" @<(find $OUT_DIR -name '*.kzip')
+echo "${BUILD_NUMBER:-$(uuidgen)}" >"$DIST_DIR/revision.txt"
diff --git a/cc/cc.go b/cc/cc.go
index b255a14..744e0cb 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -401,6 +401,14 @@
 	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
@@ -408,6 +416,7 @@
 	android.ModuleBase
 	android.DefaultableModuleBase
 	android.ApexModuleBase
+	android.SdkBase
 
 	Properties       BaseProperties
 	VendorProperties VendorProperties
@@ -543,10 +552,9 @@
 		}
 	})
 	android.InitAndroidArchModule(c, c.hod, c.multilib)
-
-	android.InitDefaultableModule(c)
-
 	android.InitApexModule(c)
+	android.InitDefaultableModule(c)
+	android.InitSdkAwareModule(c)
 
 	return c
 }
@@ -2219,8 +2227,8 @@
 		&android.ProtoProperties{},
 	)
 
-	android.InitDefaultsModule(module)
 	android.InitApexModule(module)
+	android.InitDefaultsModule(module)
 
 	return module
 }
diff --git a/cc/config/clang.go b/cc/config/clang.go
index 3636ae9..e59aa37 100644
--- a/cc/config/clang.go
+++ b/cc/config/clang.go
@@ -115,10 +115,6 @@
 		// TODO: can we remove this now?
 		"-Wno-reserved-id-macro",
 
-		// Disable overly aggressive warning for format strings.
-		// Bug: 20148343
-		"-Wno-format-pedantic",
-
 		// Workaround for ccache with clang.
 		// See http://petereisentraut.blogspot.com/2011/05/ccache-and-clang.html.
 		"-Wno-unused-command-line-argument",
diff --git a/cc/config/global.go b/cc/config/global.go
index 1bbc6f0..0943126 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -108,6 +108,7 @@
 	noOverrideGlobalCflags = []string{
 		"-Werror=int-to-pointer-cast",
 		"-Werror=pointer-to-int-cast",
+		"-Werror=fortify-source",
 	}
 
 	IllegalFlags = []string{
diff --git a/cc/fuzz.go b/cc/fuzz.go
index 325be63..7806e83 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -17,6 +17,7 @@
 import (
 	"path/filepath"
 
+	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
@@ -33,6 +34,7 @@
 
 func init() {
 	android.RegisterModuleType("cc_fuzz", FuzzFactory)
+	android.RegisterSingletonType("cc_fuzz_packaging", fuzzPackagingFactory)
 }
 
 // cc_fuzz creates a host/device fuzzer binary. Host binaries can be found at
@@ -155,3 +157,96 @@
 
 	return module
 }
+
+// Responsible for generating GNU Make rules that package fuzz targets into
+// their architecture & target/host specific zip file.
+type fuzzPackager struct {
+}
+
+func fuzzPackagingFactory() android.Singleton {
+	return &fuzzPackager{}
+}
+
+type fileToZip struct {
+	SourceFilePath        android.Path
+	DestinationPathPrefix string
+}
+
+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)
+
+	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
+		}
+
+		// Discard vendor-NDK-linked modules, they're duplicates of fuzz targets
+		// we're going to package anyway.
+		if ccModule.useVndk() || !ccModule.Enabled() {
+			return
+		}
+
+		hostOrTargetString := "target"
+		if ccModule.Host() {
+			hostOrTargetString = "host"
+		}
+
+		archString := ccModule.Arch().ArchType.String()
+		archDir := android.PathForIntermediates(ctx, "fuzz", hostOrTargetString, archString)
+
+		// The executable.
+		archDirs[archDir] = append(archDirs[archDir],
+			fileToZip{ccModule.outputFile.Path(), ccModule.Name()})
+
+		// The corpora.
+		for _, corpusEntry := range fuzzModule.corpus {
+			archDirs[archDir] = append(archDirs[archDir],
+				fileToZip{corpusEntry, ccModule.Name() + "/corpus/" + corpusEntry.Base()})
+		}
+
+		// The dictionary.
+		if fuzzModule.dictionary != nil {
+			archDirs[archDir] = append(archDirs[archDir],
+				fileToZip{fuzzModule.dictionary, ccModule.Name()})
+		}
+	})
+
+	// List of architecture + host/device specific packages to build via. 'make fuzz'.
+	var archDirTargets android.Paths
+
+	for archDir, filesToZip := range archDirs {
+		arch := archDir.Base()
+		hostOrTarget := filepath.Base(filepath.Dir(archDir.String()))
+		builder := android.NewRuleBuilder()
+		outputFile := android.PathForOutput(ctx, "fuzz-"+hostOrTarget+"-"+arch+".zip")
+		archDirTargets = append(archDirTargets, outputFile)
+
+		command := builder.Command().BuiltTool(ctx, "soong_zip").
+			Flag("-j").
+			FlagWithOutput("-o ", outputFile)
+
+		for _, fileToZip := range filesToZip {
+			command.FlagWithArg("-P ", fileToZip.DestinationPathPrefix).
+				FlagWithInput("-f ", fileToZip.SourceFilePath)
+		}
+
+		builder.Build(pctx, ctx, "create-fuzz-package-"+arch+"-"+hostOrTarget,
+			"Create fuzz target packages for "+arch+"-"+hostOrTarget)
+	}
+
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        blueprint.Phony,
+		Output:      android.PathForPhony(ctx, "fuzz"),
+		Implicits:   archDirTargets,
+		Description: "Build all Android fuzz targets, and create packages.",
+	})
+}
diff --git a/cc/gen.go b/cc/gen.go
index 42b0cbe..17ab45f 100644
--- a/cc/gen.go
+++ b/cc/gen.go
@@ -113,7 +113,14 @@
 
 	aidlPackage := strings.TrimSuffix(aidlFile.Rel(), aidlFile.Base())
 	baseName := strings.TrimSuffix(aidlFile.Base(), aidlFile.Ext())
-	shortName := strings.TrimPrefix(baseName, "I")
+	shortName := baseName
+	// TODO(b/111362593): aidl_to_cpp_common.cpp uses heuristics to figure out if
+	//   an interface name has a leading I. Those same heuristics have been
+	//   moved here.
+	if len(baseName) >= 2 && baseName[0] == 'I' &&
+		strings.ToUpper(baseName)[1] == baseName[1] {
+		shortName = strings.TrimPrefix(baseName, "I")
+	}
 
 	outDir := android.PathForModuleGen(ctx, "aidl")
 	headerI := outDir.Join(ctx, aidlPackage, baseName+".h")
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index 8c72b69..4e6cdd7 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -152,6 +152,7 @@
 
 	// Prebuilt libraries can be included in APEXes
 	android.InitApexModule(module)
+	android.InitSdkAwareModule(module)
 
 	return module, library
 }
@@ -176,6 +177,7 @@
 	module.AddProperties(&prebuilt.properties)
 
 	android.InitPrebuiltModule(module, &prebuilt.properties.Srcs)
+	android.InitSdkAwareModule(module)
 	return module, library
 }
 
diff --git a/genrule/genrule.go b/genrule/genrule.go
index cf0b484..b8b0e01 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -437,7 +437,7 @@
 		phonyFile := android.PathForModuleGen(ctx, "genrule-phony")
 
 		ctx.Build(pctx, android.BuildParams{
-			Rule:   android.Phony,
+			Rule:   blueprint.Phony,
 			Output: phonyFile,
 			Inputs: g.outputFiles,
 		})
diff --git a/java/androidmk.go b/java/androidmk.go
index 0e8e422..f006705 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -155,7 +155,7 @@
 }
 
 func (prebuilt *Import) AndroidMk() android.AndroidMkData {
-	if !prebuilt.IsForPlatform() {
+	if !prebuilt.IsForPlatform() || !prebuilt.ContainingSdk().IsCurrentVersion() {
 		return android.AndroidMkData{
 			Disabled: true,
 		}
diff --git a/java/gen.go b/java/gen.go
index a69e9a2..b840b60 100644
--- a/java/gen.go
+++ b/java/gen.go
@@ -23,7 +23,6 @@
 )
 
 func init() {
-	pctx.HostBinToolVariable("syspropCmd", "sysprop_java")
 	pctx.SourcePathVariable("logtagsCmd", "build/make/tools/java-event-log-tags.py")
 	pctx.SourcePathVariable("mergeLogtagsCmd", "build/make/tools/merge-event-log-tags.py")
 	pctx.SourcePathVariable("logtagsLib", "build/make/tools/event_log_tags.py")
@@ -48,17 +47,6 @@
 			Command:     "$mergeLogtagsCmd -o $out $in",
 			CommandDeps: []string{"$mergeLogtagsCmd", "$logtagsLib"},
 		})
-
-	sysprop = pctx.AndroidStaticRule("sysprop",
-		blueprint.RuleParams{
-			Command: `rm -rf $out.tmp && mkdir -p $out.tmp && ` +
-				`$syspropCmd --scope $scope --java-output-dir $out.tmp $in && ` +
-				`${config.SoongZipCmd} -jar -o $out -C $out.tmp -D $out.tmp && rm -rf $out.tmp`,
-			CommandDeps: []string{
-				"$syspropCmd",
-				"${config.SoongZipCmd}",
-			},
-		}, "scope")
 )
 
 func genAidl(ctx android.ModuleContext, aidlFile android.Path, aidlFlags string, deps android.Paths) android.Path {
@@ -93,22 +81,6 @@
 	return javaFile
 }
 
-func genSysprop(ctx android.ModuleContext, syspropFile android.Path, scope string) android.Path {
-	srcJarFile := android.GenPathWithExt(ctx, "sysprop", syspropFile, "srcjar")
-
-	ctx.Build(pctx, android.BuildParams{
-		Rule:        sysprop,
-		Description: "sysprop_java " + syspropFile.Rel(),
-		Output:      srcJarFile,
-		Input:       syspropFile,
-		Args: map[string]string{
-			"scope": scope,
-		},
-	})
-
-	return srcJarFile
-}
-
 func genAidlIncludeFlags(srcFiles android.Paths) string {
 	var baseDirs []string
 	for _, srcFile := range srcFiles {
@@ -141,29 +113,6 @@
 		case ".proto":
 			srcJarFile := genProto(ctx, srcFile, flags.proto)
 			outSrcFiles = append(outSrcFiles, srcJarFile)
-		case ".sysprop":
-			// internal scope contains all properties
-			// public scope only contains public properties
-			// use public if the owner is different from client
-			scope := "internal"
-			if j.properties.Sysprop.Platform != nil {
-				isProduct := ctx.ProductSpecific()
-				isVendor := ctx.SocSpecific()
-				isOwnerPlatform := Bool(j.properties.Sysprop.Platform)
-
-				if isProduct {
-					// product can't own any sysprop_library now, so product must use public scope
-					scope = "public"
-				} else if isVendor && !isOwnerPlatform {
-					// vendor and odm can't use system's internal property.
-					scope = "public"
-				}
-
-				// We don't care about clients under system.
-				// They can't use sysprop_library owned by other partitions.
-			}
-			srcJarFile := genSysprop(ctx, srcFile, scope)
-			outSrcFiles = append(outSrcFiles, srcJarFile)
 		default:
 			outSrcFiles = append(outSrcFiles, srcFile)
 		}
diff --git a/java/java.go b/java/java.go
index b0fc9db..4dd6a49 100644
--- a/java/java.go
+++ b/java/java.go
@@ -184,10 +184,6 @@
 		Output_params []string
 	}
 
-	Sysprop struct {
-		Platform *bool
-	} `blueprint:"mutated"`
-
 	Instrument bool `blueprint:"mutated"`
 
 	// List of files to include in the META-INF/services folder of the resulting jar.
@@ -290,6 +286,7 @@
 	android.ModuleBase
 	android.DefaultableModuleBase
 	android.ApexModuleBase
+	android.SdkBase
 
 	properties       CompilerProperties
 	protoProperties  android.ProtoProperties
@@ -535,7 +532,9 @@
 			ctx.PropertyErrorf("sdk_version",
 				`system_modules is required to be set when sdk_version is "none", did you mean "core_platform"`)
 		} else if *j.deviceProperties.System_modules != "none" {
+			// Add the system modules to both the system modules and bootclasspath.
 			ctx.AddVariationDependencies(nil, systemModulesTag, *j.deviceProperties.System_modules)
+			ctx.AddVariationDependencies(nil, bootClasspathTag, *j.deviceProperties.System_modules)
 		}
 		if ctx.ModuleName() == "android_stubs_current" ||
 			ctx.ModuleName() == "android_system_stubs_current" ||
@@ -848,6 +847,12 @@
 			}
 		default:
 			switch tag {
+			case bootClasspathTag:
+				// If a system modules dependency has been added to the bootclasspath
+				// then add its libs to the bootclasspath.
+				sm := module.(*SystemModules)
+				deps.bootClasspath = append(deps.bootClasspath, sm.headerJars...)
+
 			case systemModulesTag:
 				if deps.systemModules != nil {
 					panic("Found two system module dependencies")
@@ -1633,6 +1638,7 @@
 
 	InitJavaModule(module, android.HostAndDeviceSupported)
 	android.InitApexModule(module)
+	android.InitSdkAwareModule(module)
 	return module
 }
 
@@ -1913,6 +1919,7 @@
 	android.DefaultableModuleBase
 	android.ApexModuleBase
 	prebuilt android.Prebuilt
+	android.SdkBase
 
 	properties ImportProperties
 
@@ -2069,6 +2076,7 @@
 	android.InitPrebuiltModule(module, &module.properties.Jars)
 	InitJavaModule(module, android.HostAndDeviceSupported)
 	android.InitApexModule(module)
+	android.InitSdkAwareModule(module)
 	return module
 }
 
diff --git a/java/sdk_test.go b/java/sdk_test.go
index 6be17eb..88e21d7 100644
--- a/java/sdk_test.go
+++ b/java/sdk_test.go
@@ -124,7 +124,7 @@
 			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{`""`},
+			bootclasspath: []string{"core-platform-api-stubs-system-modules-lib"},
 			classpath:     []string{},
 		},
 		{
diff --git a/java/system_modules.go b/java/system_modules.go
index c616249..43e4e11 100644
--- a/java/system_modules.go
+++ b/java/system_modules.go
@@ -101,6 +101,9 @@
 
 	properties SystemModulesProperties
 
+	// The aggregated header jars from all jars specified in the libs property.
+	// Used when system module is added as a dependency to bootclasspath.
+	headerJars android.Paths
 	outputDir  android.Path
 	outputDeps android.Paths
 }
@@ -118,6 +121,8 @@
 		jars = append(jars, dep.HeaderJars()...)
 	})
 
+	system.headerJars = jars
+
 	system.outputDir, system.outputDeps = TransformJarsToSystemModules(ctx, "java.base", jars)
 }
 
diff --git a/java/testing.go b/java/testing.go
index a37c0a9..5315b85 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -114,7 +114,13 @@
 	for _, extra := range systemModules {
 		bp += fmt.Sprintf(`
 			java_system_modules {
-				name: "%s",
+				name: "%[1]s",
+				libs: ["%[1]s-lib"],
+			}
+			java_library {
+				name: "%[1]s-lib",
+				sdk_version: "none",
+				system_modules: "none",
 			}
 		`, extra)
 	}
diff --git a/rust/binary.go b/rust/binary.go
index 279c6f5..52f840e 100644
--- a/rust/binary.go
+++ b/rust/binary.go
@@ -71,6 +71,15 @@
 
 func (binary *binaryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags {
 	flags = binary.baseCompiler.compilerFlags(ctx, flags)
+
+	if ctx.toolchain().Bionic() {
+		// no-undefined-version breaks dylib compilation since __rust_*alloc* functions aren't defined, but we can apply this to binaries.
+		flags.LinkFlags = append(flags.LinkFlags,
+			"-Wl,--gc-sections",
+			"-Wl,-z,nocopyreloc",
+			"-Wl,--no-undefined-version")
+	}
+
 	if binary.preferDynamic() {
 		flags.RustFlags = append(flags.RustFlags, "-C prefer-dynamic")
 	}
@@ -86,6 +95,12 @@
 		}
 	}
 
+	if ctx.toolchain().Bionic() {
+		deps = binary.baseCompiler.bionicDeps(ctx, deps)
+		deps.CrtBegin = "crtbegin_dynamic"
+		deps.CrtEnd = "crtend_android"
+	}
+
 	return deps
 }
 
diff --git a/rust/builder.go b/rust/builder.go
index 64e387b..6611492 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -28,14 +28,14 @@
 		blueprint.RuleParams{
 			Command: "$rustcCmd " +
 				"-C linker=${config.RustLinker} " +
-				"-C link-args=\"${config.RustLinkerArgs} ${linkFlags}\" " +
+				"-C link-args=\"${crtBegin} ${config.RustLinkerArgs} ${linkFlags} ${crtEnd}\" " +
 				"-o $out $in ${libFlags} $rustcFlags " +
 				"&& $rustcCmd --emit=dep-info -o $out.d $in ${libFlags} $rustcFlags",
 			CommandDeps: []string{"$rustcCmd"},
 			Depfile:     "$out.d",
 			Deps:        blueprint.DepsGCC, // Rustc deps-info writes out make compatible dep files: https://github.com/rust-lang/rust/issues/7633
 		},
-		"rustcFlags", "linkFlags", "libFlags")
+		"rustcFlags", "linkFlags", "libFlags", "crtBegin", "crtEnd")
 )
 
 func init() {
@@ -43,28 +43,19 @@
 }
 
 func TransformSrcToBinary(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags, outputFile android.WritablePath, includeDirs []string) {
-	targetTriple := ctx.(ModuleContext).toolchain().RustTriple()
-
-	transformSrctoCrate(ctx, mainSrc, deps.RLibs, deps.DyLibs, deps.ProcMacros, deps.StaticLibs, deps.SharedLibs, flags, outputFile, "bin", includeDirs, targetTriple)
+	transformSrctoCrate(ctx, mainSrc, deps.RLibs, deps.DyLibs, deps.ProcMacros, deps.StaticLibs, deps.SharedLibs, deps.CrtBegin, deps.CrtEnd, flags, outputFile, "bin", includeDirs)
 }
 
 func TransformSrctoRlib(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags, outputFile android.WritablePath, includeDirs []string) {
-	targetTriple := ctx.(ModuleContext).toolchain().RustTriple()
-
-	transformSrctoCrate(ctx, mainSrc, deps.RLibs, deps.DyLibs, deps.ProcMacros, deps.StaticLibs, deps.SharedLibs, flags, outputFile, "rlib", includeDirs, targetTriple)
+	transformSrctoCrate(ctx, mainSrc, deps.RLibs, deps.DyLibs, deps.ProcMacros, deps.StaticLibs, deps.SharedLibs, deps.CrtBegin, deps.CrtEnd, flags, outputFile, "rlib", includeDirs)
 }
 
 func TransformSrctoDylib(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags, outputFile android.WritablePath, includeDirs []string) {
-	targetTriple := ctx.(ModuleContext).toolchain().RustTriple()
-
-	transformSrctoCrate(ctx, mainSrc, deps.RLibs, deps.DyLibs, deps.ProcMacros, deps.StaticLibs, deps.SharedLibs, flags, outputFile, "dylib", includeDirs, targetTriple)
+	transformSrctoCrate(ctx, mainSrc, deps.RLibs, deps.DyLibs, deps.ProcMacros, deps.StaticLibs, deps.SharedLibs, deps.CrtBegin, deps.CrtEnd, flags, outputFile, "dylib", includeDirs)
 }
 
 func TransformSrctoProcMacro(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags, outputFile android.WritablePath, includeDirs []string) {
-	// Proc macros are compiler plugins, and thus should target the host compiler
-	targetTriple := ""
-
-	transformSrctoCrate(ctx, mainSrc, deps.RLibs, deps.DyLibs, deps.ProcMacros, deps.StaticLibs, deps.SharedLibs, flags, outputFile, "proc-macro", includeDirs, targetTriple)
+	transformSrctoCrate(ctx, mainSrc, deps.RLibs, deps.DyLibs, deps.ProcMacros, deps.StaticLibs, deps.SharedLibs, deps.CrtBegin, deps.CrtEnd, flags, outputFile, "proc-macro", includeDirs)
 }
 
 func rustLibsToPaths(libs RustLibraries) android.Paths {
@@ -76,23 +67,28 @@
 }
 
 func transformSrctoCrate(ctx android.ModuleContext, main android.Path,
-	rlibs, dylibs, proc_macros RustLibraries, static_libs, shared_libs android.Paths, flags Flags, outputFile android.WritablePath, crate_type string, includeDirs []string, targetTriple string) {
+	rlibs, dylibs, proc_macros RustLibraries, static_libs, shared_libs android.Paths, crtBegin, crtEnd android.OptionalPath, flags Flags, outputFile android.WritablePath, crate_type string, includeDirs []string) {
 
 	var inputs android.Paths
 	var deps android.Paths
-	var libFlags, rustcFlags []string
+	var libFlags, rustcFlags, linkFlags []string
 	crate_name := ctx.(ModuleContext).CrateName()
+	targetTriple := ctx.(ModuleContext).toolchain().RustTriple()
 
 	inputs = append(inputs, main)
 
 	// Collect rustc flags
-	rustcFlags = append(rustcFlags, flags.GlobalFlags...)
+	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 targetTriple != "" {
 		rustcFlags = append(rustcFlags, "--target="+targetTriple)
+		linkFlags = append(linkFlags, "-target "+targetTriple)
 	}
+	// Collect linker flags
+	linkFlags = append(linkFlags, flags.GlobalLinkFlags...)
+	linkFlags = append(linkFlags, flags.LinkFlags...)
 
 	// Collect library/crate flags
 	for _, lib := range rlibs {
@@ -115,6 +111,9 @@
 	deps = append(deps, rustLibsToPaths(proc_macros)...)
 	deps = append(deps, static_libs...)
 	deps = append(deps, shared_libs...)
+	if crtBegin.Valid() {
+		deps = append(deps, crtBegin.Path(), crtEnd.Path())
+	}
 
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        rustc,
@@ -124,8 +123,10 @@
 		Implicits:   deps,
 		Args: map[string]string{
 			"rustcFlags": strings.Join(rustcFlags, " "),
-			"linkFlags":  strings.Join(flags.LinkFlags, " "),
+			"linkFlags":  strings.Join(linkFlags, " "),
 			"libFlags":   strings.Join(libFlags, " "),
+			"crtBegin":   crtBegin.String(),
+			"crtEnd":     crtEnd.String(),
 		},
 	})
 
diff --git a/rust/compiler.go b/rust/compiler.go
index 87cf08b..f45744b 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -113,7 +113,8 @@
 	flags.RustFlags = append(flags.RustFlags, compiler.featuresToFlags(compiler.Properties.Features)...)
 	flags.RustFlags = append(flags.RustFlags, "--edition="+*compiler.Properties.Edition)
 	flags.LinkFlags = append(flags.LinkFlags, compiler.Properties.Ld_flags...)
-	flags.GlobalFlags = append(flags.GlobalFlags, ctx.toolchain().ToolchainRustFlags())
+	flags.GlobalRustFlags = append(flags.GlobalRustFlags, ctx.toolchain().ToolchainRustFlags())
+	flags.GlobalLinkFlags = append(flags.GlobalLinkFlags, ctx.toolchain().ToolchainLinkFlags())
 
 	if ctx.Host() && !ctx.Windows() {
 		rpath_prefix := `\$$ORIGIN/`
@@ -148,6 +149,18 @@
 	return deps
 }
 
+func (compiler *baseCompiler) bionicDeps(ctx DepsContext, deps Deps) Deps {
+	deps.SharedLibs = append(deps.SharedLibs, "liblog")
+	deps.SharedLibs = append(deps.SharedLibs, "libc")
+	deps.SharedLibs = append(deps.SharedLibs, "libm")
+	deps.SharedLibs = append(deps.SharedLibs, "libdl")
+
+	//TODO(b/141331117) libstd requires libgcc on Android
+	deps.StaticLibs = append(deps.StaticLibs, "libgcc")
+
+	return deps
+}
+
 func (compiler *baseCompiler) crateName() string {
 	return compiler.Properties.Crate_name
 }
diff --git a/rust/compiler_test.go b/rust/compiler_test.go
index 5369096..bbf9f8d 100644
--- a/rust/compiler_test.go
+++ b/rust/compiler_test.go
@@ -64,7 +64,6 @@
 		rust_proc_macro {
 			name: "foo-bar-proc-macro",
 			srcs: ["foo.rs", "src/bar.rs"],
-			host_supported: true,
 		}`)
 
 	// Test prebuilts
diff --git a/rust/config/arm64_device.go b/rust/config/arm64_device.go
new file mode 100644
index 0000000..0264052
--- /dev/null
+++ b/rust/config/arm64_device.go
@@ -0,0 +1,92 @@
+// 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 config
+
+import (
+	"strings"
+
+	"android/soong/android"
+)
+
+var (
+	Arm64RustFlags            = []string{}
+	Arm64ArchFeatureRustFlags = map[string][]string{}
+	Arm64LinkFlags            = []string{
+		"-Wl,--icf=safe",
+		"-Wl,-z,max-page-size=4096",
+
+		"-Wl,-execute-only",
+	}
+
+	Arm64ArchVariantRustFlags = map[string][]string{
+		"armv8-a":  []string{},
+		"armv8-2a": []string{},
+	}
+)
+
+func init() {
+	registerToolchainFactory(android.Android, android.Arm64, Arm64ToolchainFactory)
+
+	pctx.StaticVariable("Arm64ToolchainRustFlags", strings.Join(Arm64RustFlags, " "))
+	pctx.StaticVariable("Arm64ToolchainLinkFlags", strings.Join(Arm64LinkFlags, " "))
+
+	for variant, rustFlags := range Arm64ArchVariantRustFlags {
+		pctx.StaticVariable("Arm64"+variant+"VariantRustFlags",
+			strings.Join(rustFlags, " "))
+	}
+
+}
+
+type toolchainArm64 struct {
+	toolchain64Bit
+	toolchainRustFlags string
+}
+
+func (t *toolchainArm64) RustTriple() string {
+	return "aarch64-linux-android"
+}
+
+func (t *toolchainArm64) ToolchainLinkFlags() string {
+	return "${config.DeviceGlobalLinkFlags} ${config.Arm64ToolchainLinkFlags}"
+}
+
+func (t *toolchainArm64) ToolchainRustFlags() string {
+	return t.toolchainRustFlags
+}
+
+func (t *toolchainArm64) RustFlags() string {
+	return "${config.Arm64ToolchainRustFlags}"
+}
+
+func (t *toolchainArm64) Supported() bool {
+	return true
+}
+
+func Arm64ToolchainFactory(arch android.Arch) Toolchain {
+	toolchainRustFlags := []string{
+		"${config.Arm64ToolchainRustFlags}",
+		"${config.Arm64" + arch.ArchVariant + "VariantRustFlags}",
+	}
+
+	toolchainRustFlags = append(toolchainRustFlags, deviceGlobalRustFlags...)
+
+	for _, feature := range arch.ArchFeatures {
+		toolchainRustFlags = append(toolchainRustFlags, Arm64ArchFeatureRustFlags[feature]...)
+	}
+
+	return &toolchainArm64{
+		toolchainRustFlags: strings.Join(toolchainRustFlags, " "),
+	}
+}
diff --git a/rust/config/arm_device.go b/rust/config/arm_device.go
new file mode 100644
index 0000000..aedb42b
--- /dev/null
+++ b/rust/config/arm_device.go
@@ -0,0 +1,92 @@
+// 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 config
+
+import (
+	"strings"
+
+	"android/soong/android"
+)
+
+var (
+	ArmRustFlags            = []string{}
+	ArmArchFeatureRustFlags = map[string][]string{}
+	ArmLinkFlags            = []string{
+		"-Wl,--icf=safe",
+		"-Wl,-m,armelf",
+	}
+
+	ArmArchVariantRustFlags = map[string][]string{
+		"armv7-a":      []string{},
+		"armv7-a-neon": []string{},
+		"armv8-a":      []string{},
+		"armv8-2a":     []string{},
+	}
+)
+
+func init() {
+	registerToolchainFactory(android.Android, android.Arm, ArmToolchainFactory)
+
+	pctx.StaticVariable("ArmToolchainRustFlags", strings.Join(ArmRustFlags, " "))
+	pctx.StaticVariable("ArmToolchainLinkFlags", strings.Join(ArmLinkFlags, " "))
+
+	for variant, rustFlags := range ArmArchVariantRustFlags {
+		pctx.StaticVariable("Arm"+variant+"VariantRustFlags",
+			strings.Join(rustFlags, " "))
+	}
+
+}
+
+type toolchainArm struct {
+	toolchain64Bit
+	toolchainRustFlags string
+}
+
+func (t *toolchainArm) RustTriple() string {
+	return "arm-linux-androideabi"
+}
+
+func (t *toolchainArm) ToolchainLinkFlags() string {
+	return "${config.DeviceGlobalLinkFlags} ${config.ArmToolchainLinkFlags}"
+}
+
+func (t *toolchainArm) ToolchainRustFlags() string {
+	return t.toolchainRustFlags
+}
+
+func (t *toolchainArm) RustFlags() string {
+	return "${config.ArmToolchainRustFlags}"
+}
+
+func (t *toolchainArm) Supported() bool {
+	return true
+}
+
+func ArmToolchainFactory(arch android.Arch) Toolchain {
+	toolchainRustFlags := []string{
+		"${config.ArmToolchainRustFlags}",
+		"${config.Arm" + arch.ArchVariant + "VariantRustFlags}",
+	}
+
+	toolchainRustFlags = append(toolchainRustFlags, deviceGlobalRustFlags...)
+
+	for _, feature := range arch.ArchFeatures {
+		toolchainRustFlags = append(toolchainRustFlags, ArmArchFeatureRustFlags[feature]...)
+	}
+
+	return &toolchainArm{
+		toolchainRustFlags: strings.Join(toolchainRustFlags, " "),
+	}
+}
diff --git a/rust/config/global.go b/rust/config/global.go
index 7f9f993..cec5a74 100644
--- a/rust/config/global.go
+++ b/rust/config/global.go
@@ -15,6 +15,8 @@
 package config
 
 import (
+	"strings"
+
 	"android/soong/android"
 	_ "android/soong/cc/config"
 )
@@ -26,15 +28,27 @@
 	RustDefaultBase    = "prebuilts/rust/"
 	DefaultEdition     = "2018"
 	Stdlibs            = []string{
-		"libarena",
-		"libfmt_macros",
-		"libgraphviz",
-		"libserialize",
 		"libstd",
-		"libsyntax",
-		"libsyntax_ext",
-		"libsyntax_pos",
 		"libterm",
+		"libtest",
+	}
+
+	deviceGlobalRustFlags = []string{}
+
+	deviceGlobalLinkFlags = []string{
+		"-Bdynamic",
+		"-nostdlib",
+		"-Wl,-z,noexecstack",
+		"-Wl,-z,relro",
+		"-Wl,-z,now",
+		"-Wl,--build-id=md5",
+		"-Wl,--warn-shared-textrel",
+		"-Wl,--fatal-warnings",
+
+		"-Wl,--pack-dyn-relocs=android+relr",
+		"-Wl,--use-android-relr-tags",
+		"-Wl,--no-undefined",
+		"-Wl,--hash-style=gnu",
 	}
 )
 
@@ -62,4 +76,7 @@
 	pctx.ImportAs("ccConfig", "android/soong/cc/config")
 	pctx.StaticVariable("RustLinker", "${ccConfig.ClangBin}/clang++")
 	pctx.StaticVariable("RustLinkerArgs", "-B ${ccConfig.ClangBin} -fuse-ld=lld")
+
+	pctx.StaticVariable("DeviceGlobalLinkFlags", strings.Join(deviceGlobalLinkFlags, " "))
+
 }
diff --git a/rust/config/toolchain.go b/rust/config/toolchain.go
index a36d61b..328bca3 100644
--- a/rust/config/toolchain.go
+++ b/rust/config/toolchain.go
@@ -32,6 +32,8 @@
 
 	Is64Bit() bool
 	Supported() bool
+
+	Bionic() bool
 }
 
 type toolchainBase struct {
@@ -53,6 +55,10 @@
 	panic("toolchainBase cannot determine datapath width.")
 }
 
+func (toolchainBase) Bionic() bool {
+	return true
+}
+
 type toolchain64Bit struct {
 	toolchainBase
 }
diff --git a/rust/config/x86_linux_host.go b/rust/config/x86_linux_host.go
index cb6bf1a..5376e5b 100644
--- a/rust/config/x86_linux_host.go
+++ b/rust/config/x86_linux_host.go
@@ -61,6 +61,10 @@
 	return true
 }
 
+func (toolchainLinuxX8664) Bionic() bool {
+	return false
+}
+
 func (t *toolchainLinuxX8664) Name() string {
 	return "x86_64"
 }
@@ -85,6 +89,10 @@
 	return true
 }
 
+func (toolchainLinuxX86) Bionic() bool {
+	return false
+}
+
 func (t *toolchainLinuxX86) Name() string {
 	return "x86"
 }
diff --git a/rust/library.go b/rust/library.go
index 5cf8ac7..c831727 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -191,6 +191,16 @@
 		&library.MutatedProperties)
 }
 
+func (library *libraryDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps {
+	deps = library.baseCompiler.compilerDeps(ctx, deps)
+
+	if ctx.toolchain().Bionic() && library.dylib() {
+		deps = library.baseCompiler.bionicDeps(ctx, deps)
+	}
+
+	return deps
+}
+
 func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path {
 	var outputFile android.WritablePath
 
diff --git a/rust/prebuilt.go b/rust/prebuilt.go
index d4e631b..fa69fbb 100644
--- a/rust/prebuilt.go
+++ b/rust/prebuilt.go
@@ -63,3 +63,8 @@
 
 	return srcPath
 }
+
+func (prebuilt *prebuiltLibraryDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps {
+	deps = prebuilt.baseCompiler.compilerDeps(ctx, deps)
+	return deps
+}
diff --git a/rust/proc_macro.go b/rust/proc_macro.go
index 4acb06f..1a247d9 100644
--- a/rust/proc_macro.go
+++ b/rust/proc_macro.go
@@ -45,7 +45,7 @@
 var _ compiler = (*procMacroDecorator)(nil)
 
 func ProcMacroFactory() android.Module {
-	module, _ := NewProcMacro(android.HostAndDeviceSupported)
+	module, _ := NewProcMacro(android.HostSupportedNoCross)
 	return module.Init()
 }
 
diff --git a/rust/rust.go b/rust/rust.go
index 2120916..61b51e5 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -43,11 +43,12 @@
 }
 
 type Flags struct {
-	GlobalFlags   []string      // Flags that apply globally
-	RustFlags     []string      // Flags that apply to rust
-	LinkFlags     []string      // Flags that apply to linker
-	RustFlagsDeps android.Paths // Files depended on by compiler flags
-	Toolchain     config.Toolchain
+	GlobalRustFlags []string      // Flags that apply globally to rust
+	GlobalLinkFlags []string      // Flags that apply globally to linker
+	RustFlags       []string      // Flags that apply to rust
+	LinkFlags       []string      // Flags that apply to linker
+	RustFlagsDeps   android.Paths // Files depended on by compiler flags
+	Toolchain       config.Toolchain
 }
 
 type BaseProperties struct {
@@ -92,6 +93,9 @@
 	linkDirs   []string
 	depFlags   []string
 	//ReexportedDeps android.Paths
+
+	CrtBegin android.OptionalPath
+	CrtEnd   android.OptionalPath
 }
 
 type RustLibraries []RustLibrary
@@ -321,15 +325,6 @@
 		if rustDep, ok := dep.(*Module); ok {
 			//Handle Rust Modules
 
-			if rustDep.Target().Os != ctx.Os() {
-				ctx.ModuleErrorf("OS mismatch between %q and %q", ctx.ModuleName(), depName)
-				return
-			}
-			if rustDep.Target().Arch.ArchType != ctx.Arch().ArchType {
-				ctx.ModuleErrorf("Arch mismatch between %q and %q", ctx.ModuleName(), depName)
-				return
-			}
-
 			linkFile := rustDep.outputFile
 			if !linkFile.Valid() {
 				ctx.ModuleErrorf("Invalid output file when adding dep %q to %q", depName, ctx.ModuleName())
@@ -361,9 +356,6 @@
 			if lib, ok := rustDep.compiler.(*libraryDecorator); ok {
 				depPaths.linkDirs = append(depPaths.linkDirs, lib.exportedDirs()...)
 				depPaths.depFlags = append(depPaths.depFlags, lib.exportedDepFlags()...)
-			} else if procMacro, ok := rustDep.compiler.(*libraryDecorator); ok {
-				depPaths.linkDirs = append(depPaths.linkDirs, procMacro.exportedDirs()...)
-				depPaths.depFlags = append(depPaths.depFlags, procMacro.exportedDepFlags()...)
 			}
 
 			// Append this dependencies output to this mod's linkDirs so they can be exported to dependencies
@@ -410,6 +402,10 @@
 				directSharedLibDeps = append(directSharedLibDeps, ccDep)
 				mod.Properties.AndroidMkSharedLibs = append(mod.Properties.AndroidMkSharedLibs, depName)
 				exportDep = true
+			case cc.CrtBeginDepTag():
+				depPaths.CrtBegin = linkFile
+			case cc.CrtEndDepTag():
+				depPaths.CrtEnd = linkFile
 			}
 
 			// Make sure these dependencies are propagated
@@ -491,7 +487,16 @@
 	}
 	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.AddDependency(mod, procMacroDepTag, deps.ProcMacros...)
+
+	if deps.CrtBegin != "" {
+		actx.AddVariationDependencies(ccDepVariations, cc.CrtBeginDepTag(), deps.CrtBegin)
+	}
+	if deps.CrtEnd != "" {
+		actx.AddVariationDependencies(ccDepVariations, cc.CrtEndDepTag(), deps.CrtEnd)
+	}
+
+	// proc_macros are compiler plugins, and so we need the host arch variant as a dependendcy.
+	actx.AddFarVariationDependencies([]blueprint.Variation{{Mutator: "arch", Variation: ctx.Config().BuildOsVariant}}, procMacroDepTag, deps.ProcMacros...)
 }
 
 func (mod *Module) Name() string {
diff --git a/rust/rust_test.go b/rust/rust_test.go
index f7c96dd..0c8d355 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -18,6 +18,7 @@
 	"io/ioutil"
 	"os"
 	"runtime"
+	"strings"
 	"testing"
 
 	"android/soong/android"
@@ -150,7 +151,6 @@
 		rust_proc_macro {
 			name: "libpm",
 			srcs: ["foo.rs"],
-			host_supported: true,
 		}
 		rust_binary_host {
 			name: "fizz-buzz",
@@ -176,3 +176,28 @@
 	}
 
 }
+
+// Test to make sure proc_macros use host variants when building device modules.
+func TestProcMacroDeviceDeps(t *testing.T) {
+	ctx := testRust(t, `
+		rust_library_host_rlib {
+			name: "libbar",
+			srcs: ["foo.rs"],
+		}
+		rust_proc_macro {
+			name: "libpm",
+			rlibs: ["libbar"],
+			srcs: ["foo.rs"],
+		}
+		rust_binary {
+			name: "fizz-buzz",
+			proc_macros: ["libpm"],
+			srcs: ["foo.rs"],
+		}
+	`)
+	rustc := ctx.ModuleForTests("libpm", "linux_glibc_x86_64").Rule("rustc")
+
+	if !strings.Contains(rustc.Args["libFlags"], "libbar/linux_glibc_x86_64") {
+		t.Errorf("Proc_macro is not using host variant of dependent modules.")
+	}
+}
diff --git a/rust/testing.go b/rust/testing.go
index a38697f..92347f1 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -16,6 +16,7 @@
 
 import (
 	"android/soong/android"
+	"android/soong/cc"
 )
 
 func GatherRequiredDepsForTest() string {
@@ -70,12 +71,101 @@
 				srcs: [""],
 				host_supported: true,
 		}
+
+		//////////////////////////////
+		// Device module requirements
+
+		toolchain_library {
+			name: "libgcc",
+			no_libcrt: true,
+			nocrt: true,
+			src: "",
+			system_shared_libs: [],
+		}
+		cc_library {
+			name: "libc",
+			no_libcrt: true,
+			nocrt: true,
+			system_shared_libs: [],
+		}
+		cc_library {
+			name: "libm",
+			no_libcrt: true,
+			nocrt: true,
+			system_shared_libs: [],
+		}
+		cc_library {
+			name: "libdl",
+			no_libcrt: true,
+			nocrt: true,
+			system_shared_libs: [],
+		}
+		cc_object {
+			name: "crtbegin_dynamic",
+		}
+
+		cc_object {
+			name: "crtend_android",
+		}
+		cc_library {
+			name: "liblog",
+			no_libcrt: true,
+			nocrt: true,
+			system_shared_libs: [],
+		}
+
+		//////////////////////////////
+		// cc module requirements
+
+		toolchain_library {
+			name: "libatomic",
+			src: "",
+		}
+		toolchain_library {
+			name: "libclang_rt.builtins-aarch64-android",
+			src: "",
+		}
+		toolchain_library {
+			name: "libgcc_stripped",
+			src: "",
+		}
+		cc_library {
+			name: "libc++_static",
+			no_libcrt: true,
+			nocrt: true,
+			system_shared_libs: [],
+			stl: "none",
+		}
+		cc_library {
+			name: "libc++demangle",
+			no_libcrt: true,
+			nocrt: true,
+			system_shared_libs: [],
+			stl: "none",
+			host_supported: false,
+		}
+		cc_library {
+			name: "libc++",
+			no_libcrt: true,
+			nocrt: true,
+			system_shared_libs: [],
+			stl: "none",
+		}
+		cc_library {
+			name: "libunwind_llvm",
+			no_libcrt: true,
+			nocrt: true,
+			system_shared_libs: [],
+			stl: "none",
+		}
 		`
 	return bp
 }
 
 func CreateTestContext(bp string) *android.TestContext {
 	ctx := android.NewTestArchContext()
+	ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(cc.LibraryFactory))
+	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_library", android.ModuleFactoryAdaptor(RustLibraryFactory))
@@ -86,9 +176,16 @@
 	ctx.RegisterModuleType("rust_library_dylib", android.ModuleFactoryAdaptor(RustLibraryDylibFactory))
 	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()
+
+		ctx.BottomUp("image", cc.ImageMutator).Parallel()
+		ctx.BottomUp("link", cc.LinkageMutator).Parallel()
+		ctx.BottomUp("version", cc.VersionMutator).Parallel()
+		ctx.BottomUp("begin", cc.BeginMutator).Parallel()
 	})
+
 	bp = bp + GatherRequiredDepsForTest()
 
 	mockFS := map[string][]byte{
diff --git a/sdk/sdk.go b/sdk/sdk.go
new file mode 100644
index 0000000..fcb3fb7
--- /dev/null
+++ b/sdk/sdk.go
@@ -0,0 +1,172 @@
+// Copyright (C) 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 sdk
+
+import (
+	"github.com/google/blueprint"
+
+	"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"
+)
+
+func init() {
+	android.RegisterModuleType("sdk", ModuleFactory)
+	android.PreDepsMutators(RegisterPreDepsMutators)
+	android.PostDepsMutators(RegisterPostDepsMutators)
+}
+
+type sdk struct {
+	android.ModuleBase
+	android.DefaultableModuleBase
+
+	properties sdkProperties
+}
+
+type sdkProperties struct {
+	// The list of java_import modules that provide Java stubs for this SDK
+	Java_libs          []string
+	Native_shared_libs []string
+}
+
+// sdk defines an SDK which is a logical group of modules (e.g. native libs, headers, java libs, etc.)
+// which Mainline modules like APEX can choose to build with.
+func ModuleFactory() android.Module {
+	s := &sdk{}
+	s.AddProperties(&s.properties)
+	android.InitAndroidMultiTargetsArchModule(s, android.HostAndDeviceSupported, android.MultilibCommon)
+	android.InitDefaultableModule(s)
+	return s
+}
+
+func (s *sdk) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	// TODO(jiyong): add build rules for creating stubs from members of this SDK
+}
+
+// RegisterPreDepsMutators registers pre-deps mutators to support modules implementing SdkAware
+// interface and the sdk module type. This function has been made public to be called by tests
+// outside of the sdk package
+func RegisterPreDepsMutators(ctx android.RegisterMutatorsContext) {
+	ctx.BottomUp("SdkMember", memberMutator).Parallel()
+	ctx.TopDown("SdkMember_deps", memberDepsMutator).Parallel()
+	ctx.BottomUp("SdkMemberInterVersion", memberInterVersionMutator).Parallel()
+}
+
+// RegisterPostDepshMutators registers post-deps mutators to support modules implementing SdkAware
+// interface and the sdk module type. This function has been made public to be called by tests
+// outside of the sdk package
+func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) {
+	// These must run AFTER apexMutator. Note that the apex package is imported even though there is
+	// no direct dependency to the package here. sdkDepsMutator sets the SDK requirements from an
+	// APEX to its dependents. Since different versions of the same SDK can be used by different
+	// APEXes, the apex and its dependents (which includes the dependencies to the sdk members)
+	// should have been mutated for the apex before the SDK requirements are set.
+	ctx.TopDown("SdkDepsMutator", sdkDepsMutator).Parallel()
+	ctx.BottomUp("SdkDepsReplaceMutator", sdkDepsReplaceMutator).Parallel()
+}
+
+type dependencyTag struct {
+	blueprint.BaseDependencyTag
+}
+
+// For dependencies from an SDK module to its members
+// e.g. mysdk -> libfoo and libbar
+var sdkMemberDepTag dependencyTag
+
+// For dependencies from an in-development version of an SDK member to frozen versions of the same member
+// e.g. libfoo -> libfoo.mysdk.11 and libfoo.mysdk.12
+type sdkMemberVesionedDepTag struct {
+	dependencyTag
+	member  string
+	version string
+}
+
+// Step 1: create dependencies from an SDK module to its members.
+func memberMutator(mctx android.BottomUpMutatorContext) {
+	if m, ok := mctx.Module().(*sdk); ok {
+		mctx.AddVariationDependencies(nil, sdkMemberDepTag, m.properties.Java_libs...)
+
+		targets := mctx.MultiTargets()
+		for _, target := range targets {
+			mctx.AddFarVariationDependencies([]blueprint.Variation{
+				{Mutator: "arch", Variation: target.String()},
+				{Mutator: "image", Variation: "core"},
+				{Mutator: "link", Variation: "shared"},
+			}, sdkMemberDepTag, m.properties.Native_shared_libs...)
+		}
+	}
+}
+
+// Step 2: record that dependencies of SDK modules are members of the SDK modules
+func memberDepsMutator(mctx android.TopDownMutatorContext) {
+	if _, ok := mctx.Module().(*sdk); ok {
+		mySdkRef := android.ParseSdkRef(mctx, mctx.ModuleName(), "name")
+		mctx.VisitDirectDeps(func(child android.Module) {
+			if member, ok := child.(android.SdkAware); ok {
+				member.MakeMemberOf(mySdkRef)
+			}
+		})
+	}
+}
+
+// Step 3: create dependencies from the in-development version of an SDK member to frozen versions
+// of the same member. By having these dependencies, they are mutated for multiple Mainline modules
+// (apex and apk), each of which might want different sdks to be built with. For example, if both
+// apex A and B are referencing libfoo which is a member of sdk 'mysdk', the two APEXes can be
+// built with libfoo.mysdk.11 and libfoo.mysdk.12, respectively depending on which sdk they are
+// using.
+func memberInterVersionMutator(mctx android.BottomUpMutatorContext) {
+	if m, ok := mctx.Module().(android.SdkAware); ok && m.IsInAnySdk() {
+		if !m.ContainingSdk().IsCurrentVersion() {
+			memberName := m.MemberName()
+			tag := sdkMemberVesionedDepTag{member: memberName, version: m.ContainingSdk().Version}
+			mctx.AddReverseDependency(mctx.Module(), tag, memberName)
+		}
+	}
+}
+
+// Step 4: transitively ripple down the SDK requirements from the root modules like APEX to its
+// descendants
+func sdkDepsMutator(mctx android.TopDownMutatorContext) {
+	if m, ok := mctx.Module().(android.SdkAware); ok {
+		// Module types for Mainline modules (e.g. APEX) are expected to implement RequiredSdks()
+		// by reading its own properties like `uses_sdks`.
+		requiredSdks := m.RequiredSdks()
+		if len(requiredSdks) > 0 {
+			mctx.VisitDirectDeps(func(m android.Module) {
+				if dep, ok := m.(android.SdkAware); ok {
+					dep.BuildWithSdks(requiredSdks)
+				}
+			})
+		}
+	}
+}
+
+// Step 5: if libfoo.mysdk.11 is in the context where version 11 of mysdk is requested, the
+// versioned module is used instead of the un-versioned (in-development) module libfoo
+func sdkDepsReplaceMutator(mctx android.BottomUpMutatorContext) {
+	if m, ok := mctx.Module().(android.SdkAware); ok && m.IsInAnySdk() {
+		if sdk := m.ContainingSdk(); !sdk.IsCurrentVersion() {
+			if m.RequiredSdks().Contains(sdk) {
+				// Note that this replacement is done only for the modules that have the same
+				// variations as the current module. Since current module is already mutated for
+				// apex references in other APEXes are not affected by this replacement.
+				memberName := m.MemberName()
+				mctx.ReplaceDependencies(memberName)
+			}
+		}
+	}
+}
diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go
new file mode 100644
index 0000000..9eca72f
--- /dev/null
+++ b/sdk/sdk_test.go
@@ -0,0 +1,318 @@
+// Copyright 2019 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package sdk
+
+import (
+	"io/ioutil"
+	"os"
+	"strings"
+	"testing"
+
+	"android/soong/android"
+	"android/soong/apex"
+	"android/soong/cc"
+	"android/soong/java"
+)
+
+func testSdkContext(t *testing.T, bp string) (*android.TestContext, android.Config) {
+	config := android.TestArchConfig(buildDir, nil)
+	ctx := android.NewTestArchContext()
+
+	// from android package
+	ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
+	ctx.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
+		ctx.BottomUp("prebuilts", android.PrebuiltMutator).Parallel()
+	})
+	ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
+		ctx.TopDown("prebuilt_select", android.PrebuiltSelectModuleMutator).Parallel()
+		ctx.BottomUp("prebuilt_postdeps", android.PrebuiltPostDepsMutator).Parallel()
+	})
+
+	// from java package
+	ctx.RegisterModuleType("android_app_certificate", android.ModuleFactoryAdaptor(java.AndroidAppCertificateFactory))
+	ctx.RegisterModuleType("java_library", android.ModuleFactoryAdaptor(java.LibraryFactory))
+	ctx.RegisterModuleType("java_import", android.ModuleFactoryAdaptor(java.ImportFactory))
+
+	// from cc package
+	ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(cc.LibraryFactory))
+	ctx.RegisterModuleType("cc_library_shared", android.ModuleFactoryAdaptor(cc.LibrarySharedFactory))
+	ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(cc.ObjectFactory))
+	ctx.RegisterModuleType("cc_prebuilt_library_shared", android.ModuleFactoryAdaptor(cc.PrebuiltSharedLibraryFactory))
+	ctx.RegisterModuleType("cc_prebuilt_library_static", android.ModuleFactoryAdaptor(cc.PrebuiltStaticLibraryFactory))
+	ctx.RegisterModuleType("llndk_library", android.ModuleFactoryAdaptor(cc.LlndkLibraryFactory))
+	ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(cc.ToolchainLibraryFactory))
+	ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
+		ctx.BottomUp("image", cc.ImageMutator).Parallel()
+		ctx.BottomUp("link", cc.LinkageMutator).Parallel()
+		ctx.BottomUp("vndk", cc.VndkMutator).Parallel()
+		ctx.BottomUp("test_per_src", cc.TestPerSrcMutator).Parallel()
+		ctx.BottomUp("version", cc.VersionMutator).Parallel()
+		ctx.BottomUp("begin", cc.BeginMutator).Parallel()
+	})
+
+	// from apex package
+	ctx.RegisterModuleType("apex", android.ModuleFactoryAdaptor(apex.BundleFactory))
+	ctx.RegisterModuleType("apex_key", android.ModuleFactoryAdaptor(apex.ApexKeyFactory))
+	ctx.PostDepsMutators(apex.RegisterPostDepsMutators)
+
+	// from this package
+	ctx.RegisterModuleType("sdk", android.ModuleFactoryAdaptor(ModuleFactory))
+	ctx.PreDepsMutators(RegisterPreDepsMutators)
+	ctx.PostDepsMutators(RegisterPostDepsMutators)
+
+	ctx.Register()
+
+	bp = bp + `
+		apex_key {
+			name: "myapex.key",
+			public_key: "myapex.avbpubkey",
+			private_key: "myapex.pem",
+		}
+
+		android_app_certificate {
+			name: "myapex.cert",
+			certificate: "myapex",
+		}
+	` + cc.GatherRequiredDepsForTest(android.Android)
+
+	ctx.MockFileSystem(map[string][]byte{
+		"Android.bp":                                 []byte(bp),
+		"build/make/target/product/security":         nil,
+		"apex_manifest.json":                         nil,
+		"system/sepolicy/apex/myapex-file_contexts":  nil,
+		"system/sepolicy/apex/myapex2-file_contexts": nil,
+		"myapex.avbpubkey":                           nil,
+		"myapex.pem":                                 nil,
+		"myapex.x509.pem":                            nil,
+		"myapex.pk8":                                 nil,
+		"Test.java":                                  nil,
+		"Test.cpp":                                   nil,
+		"libfoo.so":                                  nil,
+	})
+
+	return ctx, config
+}
+
+func testSdk(t *testing.T, bp string) (*android.TestContext, android.Config) {
+	ctx, config := testSdkContext(t, bp)
+	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+	android.FailIfErrored(t, errs)
+	_, errs = ctx.PrepareBuildActions(config)
+	android.FailIfErrored(t, errs)
+	return ctx, config
+}
+
+// ensure that 'result' contains 'expected'
+func ensureContains(t *testing.T, result string, expected string) {
+	t.Helper()
+	if !strings.Contains(result, expected) {
+		t.Errorf("%q is not found in %q", expected, result)
+	}
+}
+
+// ensures that 'result' does not contain 'notExpected'
+func ensureNotContains(t *testing.T, result string, notExpected string) {
+	t.Helper()
+	if strings.Contains(result, notExpected) {
+		t.Errorf("%q is found in %q", notExpected, result)
+	}
+}
+
+func ensureListContains(t *testing.T, result []string, expected string) {
+	t.Helper()
+	if !android.InList(expected, result) {
+		t.Errorf("%q is not found in %v", expected, result)
+	}
+}
+
+func ensureListNotContains(t *testing.T, result []string, notExpected string) {
+	t.Helper()
+	if android.InList(notExpected, result) {
+		t.Errorf("%q is found in %v", notExpected, result)
+	}
+}
+
+func pathsToStrings(paths android.Paths) []string {
+	ret := []string{}
+	for _, p := range paths {
+		ret = append(ret, p.String())
+	}
+	return ret
+}
+
+func TestBasicSdkWithJava(t *testing.T) {
+	ctx, _ := testSdk(t, `
+		sdk {
+			name: "mysdk#1",
+			java_libs: ["sdkmember_mysdk_1"],
+		}
+
+		sdk {
+			name: "mysdk#2",
+			java_libs: ["sdkmember_mysdk_2"],
+		}
+
+		java_import {
+			name: "sdkmember",
+			prefer: false,
+			host_supported: true,
+		}
+
+		java_import {
+			name: "sdkmember_mysdk_1",
+			sdk_member_name: "sdkmember",
+			host_supported: true,
+		}
+
+		java_import {
+			name: "sdkmember_mysdk_2",
+			sdk_member_name: "sdkmember",
+			host_supported: true,
+		}
+
+		java_library {
+			name: "myjavalib",
+			srcs: ["Test.java"],
+			libs: ["sdkmember"],
+			system_modules: "none",
+			sdk_version: "none",
+			compile_dex: true,
+			host_supported: true,
+		}
+
+		apex {
+			name: "myapex",
+			java_libs: ["myjavalib"],
+			uses_sdks: ["mysdk#1"],
+			key: "myapex.key",
+			certificate: ":myapex.cert",
+		}
+
+		apex {
+			name: "myapex2",
+			java_libs: ["myjavalib"],
+			uses_sdks: ["mysdk#2"],
+			key: "myapex.key",
+			certificate: ":myapex.cert",
+		}
+	`)
+
+	sdkMemberV1 := ctx.ModuleForTests("sdkmember_mysdk_1", "android_common_myapex").Rule("combineJar").Output
+	sdkMemberV2 := ctx.ModuleForTests("sdkmember_mysdk_2", "android_common_myapex2").Rule("combineJar").Output
+
+	javalibForMyApex := ctx.ModuleForTests("myjavalib", "android_common_myapex")
+	javalibForMyApex2 := ctx.ModuleForTests("myjavalib", "android_common_myapex2")
+
+	// Depending on the uses_sdks value, different libs are linked
+	ensureListContains(t, pathsToStrings(javalibForMyApex.Rule("javac").Implicits), sdkMemberV1.String())
+	ensureListContains(t, pathsToStrings(javalibForMyApex2.Rule("javac").Implicits), sdkMemberV2.String())
+}
+
+func TestBasicSdkWithCc(t *testing.T) {
+	ctx, _ := testSdk(t, `
+		sdk {
+			name: "mysdk#1",
+			native_shared_libs: ["sdkmember_mysdk_1"],
+		}
+
+		sdk {
+			name: "mysdk#2",
+			native_shared_libs: ["sdkmember_mysdk_2"],
+		}
+
+		cc_prebuilt_library_shared {
+			name: "sdkmember",
+			srcs: ["libfoo.so"],
+			prefer: false,
+			system_shared_libs: [],
+			stl: "none",
+		}
+
+		cc_prebuilt_library_shared {
+			name: "sdkmember_mysdk_1",
+			sdk_member_name: "sdkmember",
+			srcs: ["libfoo.so"],
+			system_shared_libs: [],
+			stl: "none",
+		}
+
+		cc_prebuilt_library_shared {
+			name: "sdkmember_mysdk_2",
+			sdk_member_name: "sdkmember",
+			srcs: ["libfoo.so"],
+			system_shared_libs: [],
+			stl: "none",
+		}
+
+		cc_library_shared {
+			name: "mycpplib",
+			srcs: ["Test.cpp"],
+			shared_libs: ["sdkmember"],
+			system_shared_libs: [],
+			stl: "none",
+		}
+
+		apex {
+			name: "myapex",
+			native_shared_libs: ["mycpplib"],
+			uses_sdks: ["mysdk#1"],
+			key: "myapex.key",
+			certificate: ":myapex.cert",
+		}
+
+		apex {
+			name: "myapex2",
+			native_shared_libs: ["mycpplib"],
+			uses_sdks: ["mysdk#2"],
+			key: "myapex.key",
+			certificate: ":myapex.cert",
+		}
+	`)
+
+	sdkMemberV1 := ctx.ModuleForTests("sdkmember_mysdk_1", "android_arm64_armv8-a_core_shared_myapex").Rule("toc").Output
+	sdkMemberV2 := ctx.ModuleForTests("sdkmember_mysdk_2", "android_arm64_armv8-a_core_shared_myapex2").Rule("toc").Output
+
+	cpplibForMyApex := ctx.ModuleForTests("mycpplib", "android_arm64_armv8-a_core_shared_myapex")
+	cpplibForMyApex2 := ctx.ModuleForTests("mycpplib", "android_arm64_armv8-a_core_shared_myapex2")
+
+	// Depending on the uses_sdks value, different libs are linked
+	ensureListContains(t, pathsToStrings(cpplibForMyApex.Rule("ld").Implicits), sdkMemberV1.String())
+	ensureListContains(t, pathsToStrings(cpplibForMyApex2.Rule("ld").Implicits), sdkMemberV2.String())
+}
+
+var buildDir string
+
+func setUp() {
+	var err error
+	buildDir, err = ioutil.TempDir("", "soong_sdk_test")
+	if err != nil {
+		panic(err)
+	}
+}
+
+func tearDown() {
+	os.RemoveAll(buildDir)
+}
+
+func TestMain(m *testing.M) {
+	run := func() int {
+		setUp()
+		defer tearDown()
+
+		return m.Run()
+	}
+
+	os.Exit(run())
+}
diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go
index c7669bd..5eb7fa9 100644
--- a/sysprop/sysprop_library.go
+++ b/sysprop/sysprop_library.go
@@ -32,6 +32,86 @@
 	name string
 }
 
+type syspropGenProperties struct {
+	Srcs  []string `android:"path"`
+	Scope string
+}
+
+type syspropJavaGenRule struct {
+	android.ModuleBase
+
+	properties syspropGenProperties
+
+	genSrcjars android.Paths
+}
+
+var _ android.OutputFileProducer = (*syspropJavaGenRule)(nil)
+
+var (
+	syspropJava = pctx.AndroidStaticRule("syspropJava",
+		blueprint.RuleParams{
+			Command: `rm -rf $out.tmp && mkdir -p $out.tmp && ` +
+				`$syspropJavaCmd --scope $scope --java-output-dir $out.tmp $in && ` +
+				`$soongZipCmd -jar -o $out -C $out.tmp -D $out.tmp && rm -rf $out.tmp`,
+			CommandDeps: []string{
+				"$syspropJavaCmd",
+				"$soongZipCmd",
+			},
+		}, "scope")
+)
+
+func init() {
+	pctx.HostBinToolVariable("soongZipCmd", "soong_zip")
+	pctx.HostBinToolVariable("syspropJavaCmd", "sysprop_java")
+
+	android.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
+		ctx.BottomUp("sysprop_deps", syspropDepsMutator).Parallel()
+	})
+}
+
+func (g *syspropJavaGenRule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	var checkApiFileTimeStamp android.WritablePath
+
+	ctx.VisitDirectDeps(func(dep android.Module) {
+		if m, ok := dep.(*syspropLibrary); ok {
+			checkApiFileTimeStamp = m.checkApiFileTimeStamp
+		}
+	})
+
+	for _, syspropFile := range android.PathsForModuleSrc(ctx, g.properties.Srcs) {
+		srcJarFile := android.GenPathWithExt(ctx, "sysprop", syspropFile, "srcjar")
+
+		ctx.Build(pctx, android.BuildParams{
+			Rule:        syspropJava,
+			Description: "sysprop_java " + syspropFile.Rel(),
+			Output:      srcJarFile,
+			Input:       syspropFile,
+			Implicit:    checkApiFileTimeStamp,
+			Args: map[string]string{
+				"scope": g.properties.Scope,
+			},
+		})
+
+		g.genSrcjars = append(g.genSrcjars, srcJarFile)
+	}
+}
+
+func (g *syspropJavaGenRule) OutputFiles(tag string) (android.Paths, error) {
+	switch tag {
+	case "":
+		return g.genSrcjars, nil
+	default:
+		return nil, fmt.Errorf("unsupported module reference tag %q", tag)
+	}
+}
+
+func syspropJavaGenFactory() android.Module {
+	g := &syspropJavaGenRule{}
+	g.AddProperties(&g.properties)
+	android.InitAndroidModule(g)
+	return g
+}
+
 type syspropLibrary struct {
 	android.ModuleBase
 
@@ -81,13 +161,29 @@
 	return "lib" + m.BaseModuleName()
 }
 
+func (m *syspropLibrary) javaGenModuleName() string {
+	return m.BaseModuleName() + "_java_gen"
+}
+
 func (m *syspropLibrary) BaseModuleName() string {
 	return m.ModuleBase.Name()
 }
 
 func (m *syspropLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	m.currentApiFile = android.PathForSource(ctx, ctx.ModuleDir(), "api", m.BaseModuleName()+"-current.txt")
-	m.latestApiFile = android.PathForSource(ctx, ctx.ModuleDir(), "api", m.BaseModuleName()+"-latest.txt")
+	baseModuleName := m.BaseModuleName()
+
+	for _, syspropFile := range android.PathsForModuleSrc(ctx, m.properties.Srcs) {
+		if syspropFile.Ext() != ".sysprop" {
+			ctx.PropertyErrorf("srcs", "srcs contains non-sysprop file %q", syspropFile.String())
+		}
+	}
+
+	if ctx.Failed() {
+		return
+	}
+
+	m.currentApiFile = android.PathForSource(ctx, ctx.ModuleDir(), "api", baseModuleName+"-current.txt")
+	m.latestApiFile = android.PathForSource(ctx, ctx.ModuleDir(), "api", baseModuleName+"-latest.txt")
 
 	// dump API rule
 	rule := android.NewRuleBuilder()
@@ -96,7 +192,7 @@
 		BuiltTool(ctx, "sysprop_api_dump").
 		Output(m.dumpedApiFile).
 		Inputs(android.PathsForModuleSrc(ctx, m.properties.Srcs))
-	rule.Build(pctx, ctx, m.BaseModuleName()+"_api_dump", m.BaseModuleName()+" api dump")
+	rule.Build(pctx, ctx, baseModuleName+"_api_dump", baseModuleName+" api dump")
 
 	// check API rule
 	rule = android.NewRuleBuilder()
@@ -105,8 +201,8 @@
 	msg := fmt.Sprintf(`\n******************************\n`+
 		`API of sysprop_library %s doesn't match with current.txt\n`+
 		`Please update current.txt by:\n`+
-		`rm -rf %q && cp -f %q %q\n`+
-		`******************************\n`, m.BaseModuleName(),
+		`m %s-dump-api && rm -rf %q && cp -f %q %q\n`+
+		`******************************\n`, baseModuleName, baseModuleName,
 		m.currentApiFile.String(), m.dumpedApiFile.String(), m.currentApiFile.String())
 
 	rule.Command().
@@ -121,7 +217,7 @@
 	msg = fmt.Sprintf(`\n******************************\n`+
 		`API of sysprop_library %s doesn't match with latest version\n`+
 		`Please fix the breakage and rebuild.\n`+
-		`******************************\n`, m.BaseModuleName())
+		`******************************\n`, baseModuleName)
 
 	rule.Command().
 		Text("( ").
@@ -138,7 +234,7 @@
 		Text("touch").
 		Output(m.checkApiFileTimeStamp)
 
-	rule.Build(pctx, ctx, m.BaseModuleName()+"_check_api", m.BaseModuleName()+" check api")
+	rule.Build(pctx, ctx, baseModuleName+"_check_api", baseModuleName+" check api")
 }
 
 func (m *syspropLibrary) AndroidMk() android.AndroidMkData {
@@ -153,13 +249,13 @@
 			fmt.Fprintf(w, "include $(BUILD_SYSTEM)/base_rules.mk\n\n")
 			fmt.Fprintf(w, "$(LOCAL_BUILT_MODULE): %s\n", m.checkApiFileTimeStamp.String())
 			fmt.Fprintf(w, "\ttouch $@\n\n")
-			fmt.Fprintf(w, ".PHONY: %s-check-api\n\n", name)
+			fmt.Fprintf(w, ".PHONY: %s-check-api %s-dump-api\n\n", name, name)
+
+			// dump API rule
+			fmt.Fprintf(w, "%s-dump-api: %s\n\n", name, m.dumpedApiFile.String())
 
 			// check API rule
 			fmt.Fprintf(w, "%s-check-api: %s\n\n", name, m.checkApiFileTimeStamp.String())
-
-			// "make {sysprop_library}" should also build the C++ library
-			fmt.Fprintf(w, "%s: %s\n\n", name, m.CcModuleName())
 		}}
 }
 
@@ -263,42 +359,65 @@
 	ccProps.Sysprop.Platform = proptools.BoolPtr(owner == "Platform")
 	ccProps.Header_libs = []string{"libbase_headers"}
 	ccProps.Shared_libs = []string{"liblog"}
-
-	// add sysprop_library module to perform check API
-	ccProps.Required = []string{m.Name()}
-	ccProps.Sysprop.Platform = proptools.BoolPtr(owner == "Platform")
 	ccProps.Recovery_available = m.properties.Recovery_available
 	ccProps.Vendor_available = m.properties.Vendor_available
 
 	ctx.CreateModule(android.ModuleFactoryAdaptor(cc.LibraryFactory), &ccProps)
 
+	// internal scope contains all properties
+	// public scope only contains public properties
+	// use public if the owner is different from client
+	scope := "internal"
+	isProduct := ctx.ProductSpecific()
+	isVendor := ctx.SocSpecific()
+	isOwnerPlatform := owner == "Platform"
+
+	if isProduct {
+		// product can't own any sysprop_library now, so product must use public scope
+		scope = "public"
+	} else if isVendor && !isOwnerPlatform {
+		// vendor and odm can't use system's internal property.
+		scope = "public"
+	}
+
+	javaGenProps := struct {
+		Srcs  []string
+		Scope string
+		Name  *string
+	}{
+		Srcs:  m.properties.Srcs,
+		Scope: scope,
+		Name:  proptools.StringPtr(m.javaGenModuleName()),
+	}
+
+	ctx.CreateModule(android.ModuleFactoryAdaptor(syspropJavaGenFactory), &javaGenProps)
+
 	javaProps := struct {
 		Name             *string
 		Srcs             []string
 		Soc_specific     *bool
 		Device_specific  *bool
 		Product_specific *bool
-		Sysprop          struct {
-			Platform *bool
-		}
-		Required    []string
-		Sdk_version *string
-		Installable *bool
-		Libs        []string
+		Required         []string
+		Sdk_version      *string
+		Installable      *bool
+		Libs             []string
 	}{}
 
 	javaProps.Name = proptools.StringPtr(m.BaseModuleName())
-	javaProps.Srcs = m.properties.Srcs
+	javaProps.Srcs = []string{":" + *javaGenProps.Name}
 	javaProps.Soc_specific = proptools.BoolPtr(socSpecific)
 	javaProps.Device_specific = proptools.BoolPtr(deviceSpecific)
 	javaProps.Product_specific = proptools.BoolPtr(productSpecific)
 	javaProps.Installable = m.properties.Installable
-
-	// add sysprop_library module to perform check API
-	javaProps.Required = []string{m.Name()}
 	javaProps.Sdk_version = proptools.StringPtr("core_current")
-	javaProps.Sysprop.Platform = proptools.BoolPtr(owner == "Platform")
 	javaProps.Libs = []string{stub}
 
 	ctx.CreateModule(android.ModuleFactoryAdaptor(java.LibraryFactory), &javaProps)
 }
+
+func syspropDepsMutator(ctx android.BottomUpMutatorContext) {
+	if m, ok := ctx.Module().(*syspropLibrary); ok {
+		ctx.AddReverseDependency(m, nil, m.javaGenModuleName())
+	}
+}
diff --git a/sysprop/sysprop_test.go b/sysprop/sysprop_test.go
index 8db6833..6b4337a 100644
--- a/sysprop/sysprop_test.go
+++ b/sysprop/sysprop_test.go
@@ -62,6 +62,9 @@
 	ctx.PreArchMutators(android.RegisterPrebuiltsPreArchMutators)
 	ctx.PreArchMutators(android.RegisterPrebuiltsPostDepsMutators)
 	ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
+	ctx.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
+		ctx.BottomUp("sysprop_deps", syspropDepsMutator).Parallel()
+	})
 
 	ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(cc.LibraryFactory))
 	ctx.RegisterModuleType("cc_library_headers", android.ModuleFactoryAdaptor(cc.LibraryHeaderFactory))