Merge "Add option disable_framework for auto-generated test config"
diff --git a/Android.bp b/Android.bp
index 4e44a0d..d63921a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -204,6 +204,7 @@
         "cc/gen_test.go",
         "cc/genrule_test.go",
         "cc/library_test.go",
+        "cc/object_test.go",
         "cc/prebuilt_test.go",
         "cc/proto_test.go",
         "cc/test_data_test.go",
@@ -325,6 +326,50 @@
 }
 
 bootstrap_go_package {
+    name: "soong-rust-config",
+    pkgPath: "android/soong/rust/config",
+    deps: [
+        "soong-android",
+        "soong-cc-config",
+    ],
+    srcs: [
+        "rust/config/global.go",
+        "rust/config/toolchain.go",
+        "rust/config/x86_linux_host.go",
+        "rust/config/x86_64_device.go",
+    ],
+}
+
+bootstrap_go_package {
+    name: "soong-rust",
+    pkgPath: "android/soong/rust",
+    deps: [
+        "soong",
+        "soong-android",
+        "soong-cc",
+        "soong-rust-config",
+    ],
+    srcs: [
+        "rust/androidmk.go",
+        "rust/compiler.go",
+        "rust/binary.go",
+        "rust/builder.go",
+        "rust/library.go",
+        "rust/prebuilt.go",
+        "rust/proc_macro.go",
+        "rust/rust.go",
+        "rust/testing.go",
+    ],
+    testSrcs: [
+        "rust/binary_test.go",
+        "rust/compiler_test.go",
+        "rust/library_test.go",
+        "rust/rust_test.go",
+    ],
+    pluginFor: ["soong_build"],
+}
+
+bootstrap_go_package {
     name: "soong-python",
     pkgPath: "android/soong/python",
     deps: [
diff --git a/android/androidmk.go b/android/androidmk.go
index 1f1bd70..124523f 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -79,12 +79,14 @@
 	header bytes.Buffer
 	footer bytes.Buffer
 
-	AddCustomEntries func(name, prefix, moduleDir string, entries *AndroidMkEntries)
+	ExtraEntries []AndroidMkExtraEntriesFunc
 
 	EntryMap   map[string][]string
 	entryOrder []string
 }
 
+type AndroidMkExtraEntriesFunc func(entries *AndroidMkEntries)
+
 func (a *AndroidMkEntries) SetString(name, value string) {
 	if _, ok := a.EntryMap[name]; !ok {
 		a.entryOrder = append(a.entryOrder, name)
@@ -246,9 +248,8 @@
 			prefix = "2ND_" + prefix
 		}
 	}
-	blueprintDir := filepath.Dir(bpPath)
-	if a.AddCustomEntries != nil {
-		a.AddCustomEntries(name, prefix, blueprintDir, a)
+	for _, extra := range a.ExtraEntries {
+		extra(a)
 	}
 
 	// Write to footer.
diff --git a/android/apex.go b/android/apex.go
index 17df762..99b13ab 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -19,6 +19,7 @@
 	"sync"
 
 	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
 )
 
 // ApexModule is the interface that a module type is expected to implement if
@@ -74,9 +75,15 @@
 	// Sets the name of the apex variant of this module. Called inside
 	// CreateApexVariations.
 	setApexName(apexName string)
+
+	// Return the no_apex property
+	NoApex() bool
 }
 
 type ApexProperties struct {
+	// Whether this module should not be part of any APEX. Default is false.
+	No_apex *bool
+
 	// Name of the apex variant that this module is mutated into
 	ApexName string `blueprint:"mutated"`
 }
@@ -125,6 +132,10 @@
 	return false
 }
 
+func (m *ApexModuleBase) NoApex() bool {
+	return proptools.Bool(m.ApexProperties.No_apex)
+}
+
 func (m *ApexModuleBase) CreateApexVariations(mctx BottomUpMutatorContext) []blueprint.Module {
 	if len(m.apexVariations) > 0 {
 		sort.Strings(m.apexVariations)
diff --git a/android/module.go b/android/module.go
index 0ab9be7..dda526f 100644
--- a/android/module.go
+++ b/android/module.go
@@ -1038,6 +1038,13 @@
 	}
 
 	if m.Enabled() {
+		// ensure all direct android.Module deps are enabled
+		ctx.VisitDirectDepsBlueprint(func(bm blueprint.Module) {
+			if _, ok := bm.(Module); ok {
+				ctx.validateAndroidModule(bm, ctx.baseModuleContext.strictVisitDeps)
+			}
+		})
+
 		notice := proptools.StringDefault(m.commonProperties.Notice, "NOTICE")
 		if module := SrcIsModule(notice); module != "" {
 			m.noticeFile = ctx.ExpandOptionalSource(&notice, "notice")
diff --git a/android/module_test.go b/android/module_test.go
index c790a68..6dca29f 100644
--- a/android/module_test.go
+++ b/android/module_test.go
@@ -14,7 +14,9 @@
 
 package android
 
-import "testing"
+import (
+	"testing"
+)
 
 func TestSrcIsModule(t *testing.T) {
 	type args struct {
@@ -139,3 +141,55 @@
 		})
 	}
 }
+
+type depsModule struct {
+	ModuleBase
+	props struct {
+		Deps []string
+	}
+}
+
+func (m *depsModule) GenerateAndroidBuildActions(ctx ModuleContext) {
+}
+
+func (m *depsModule) DepsMutator(ctx BottomUpMutatorContext) {
+	ctx.AddDependency(ctx.Module(), nil, m.props.Deps...)
+}
+
+func depsModuleFactory() Module {
+	m := &depsModule{}
+	m.AddProperties(&m.props)
+	InitAndroidModule(m)
+	return m
+}
+
+func TestErrorDependsOnDisabledModule(t *testing.T) {
+	ctx := NewTestContext()
+	ctx.RegisterModuleType("deps", ModuleFactoryAdaptor(depsModuleFactory))
+
+	bp := `
+		deps {
+			name: "foo",
+			deps: ["bar"],
+		}
+		deps {
+			name: "bar",
+			enabled: false,
+		}
+	`
+
+	mockFS := map[string][]byte{
+		"Android.bp": []byte(bp),
+	}
+
+	ctx.MockFileSystem(mockFS)
+
+	ctx.Register()
+
+	config := TestConfig(buildDir, nil)
+
+	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+	FailIfErrored(t, errs)
+	_, errs = ctx.PrepareBuildActions(config)
+	FailIfNoMatchingErrors(t, `module "foo": depends on disabled module "bar"`, errs)
+}
diff --git a/android/paths.go b/android/paths.go
index 5110617..0d64a61 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -989,6 +989,10 @@
 
 var _ Path = ModuleOutPath{}
 
+func (p ModuleOutPath) objPathWithExt(ctx ModuleContext, subdir, ext string) ModuleObjPath {
+	return PathForModuleObj(ctx, subdir, pathtools.ReplaceExtension(p.path, ext))
+}
+
 func pathForModule(ctx ModuleContext) OutputPath {
 	return PathForOutput(ctx, ".intermediates", ctx.ModuleDir(), ctx.ModuleName(), ctx.ModuleSubDir())
 }
diff --git a/android/prebuilt_etc.go b/android/prebuilt_etc.go
index 9722a25..d29ed16 100644
--- a/android/prebuilt_etc.go
+++ b/android/prebuilt_etc.go
@@ -155,16 +155,18 @@
 		Class:      "ETC",
 		SubName:    nameSuffix,
 		OutputFile: OptionalPathForPath(p.outputFilePath),
-		AddCustomEntries: func(name, prefix, moduleDir string, entries *AndroidMkEntries) {
-			entries.SetString("LOCAL_MODULE_TAGS", "optional")
-			entries.SetString("LOCAL_MODULE_PATH", "$(OUT_DIR)/"+p.installDirPath.RelPathString())
-			entries.SetString("LOCAL_INSTALLED_MODULE_STEM", p.outputFilePath.Base())
-			entries.SetString("LOCAL_UNINSTALLABLE_MODULE", strconv.FormatBool(!p.Installable()))
-			if p.additionalDependencies != nil {
-				for _, path := range *p.additionalDependencies {
-					entries.SetString("LOCAL_ADDITIONAL_DEPENDENCIES", path.String())
+		ExtraEntries: []AndroidMkExtraEntriesFunc{
+			func(entries *AndroidMkEntries) {
+				entries.SetString("LOCAL_MODULE_TAGS", "optional")
+				entries.SetString("LOCAL_MODULE_PATH", "$(OUT_DIR)/"+p.installDirPath.RelPathString())
+				entries.SetString("LOCAL_INSTALLED_MODULE_STEM", p.outputFilePath.Base())
+				entries.SetString("LOCAL_UNINSTALLABLE_MODULE", strconv.FormatBool(!p.Installable()))
+				if p.additionalDependencies != nil {
+					for _, path := range *p.additionalDependencies {
+						entries.SetString("LOCAL_ADDITIONAL_DEPENDENCIES", path.String())
+					}
 				}
-			}
+			},
 		},
 	}
 }
diff --git a/android/sh_binary.go b/android/sh_binary.go
index 2855aa0..ba0c8be 100644
--- a/android/sh_binary.go
+++ b/android/sh_binary.go
@@ -133,8 +133,10 @@
 		Class:      "EXECUTABLES",
 		OutputFile: OptionalPathForPath(s.outputFilePath),
 		Include:    "$(BUILD_SYSTEM)/soong_cc_prebuilt.mk",
-		AddCustomEntries: func(name, prefix, moduleDir string, entries *AndroidMkEntries) {
-			s.customAndroidMkEntries(entries)
+		ExtraEntries: []AndroidMkExtraEntriesFunc{
+			func(entries *AndroidMkEntries) {
+				s.customAndroidMkEntries(entries)
+			},
 		},
 	}
 }
@@ -156,20 +158,22 @@
 		Class:      "NATIVE_TESTS",
 		OutputFile: OptionalPathForPath(s.outputFilePath),
 		Include:    "$(BUILD_SYSTEM)/soong_cc_prebuilt.mk",
-		AddCustomEntries: func(name, prefix, moduleDir string, entries *AndroidMkEntries) {
-			s.customAndroidMkEntries(entries)
+		ExtraEntries: []AndroidMkExtraEntriesFunc{
+			func(entries *AndroidMkEntries) {
+				s.customAndroidMkEntries(entries)
 
-			entries.AddStrings("LOCAL_COMPATIBILITY_SUITE", s.testProperties.Test_suites...)
-			entries.SetString("LOCAL_TEST_CONFIG", String(s.testProperties.Test_config))
-			for _, d := range s.data {
-				rel := d.Rel()
-				path := d.String()
-				if !strings.HasSuffix(path, rel) {
-					panic(fmt.Errorf("path %q does not end with %q", path, rel))
+				entries.AddStrings("LOCAL_COMPATIBILITY_SUITE", s.testProperties.Test_suites...)
+				entries.SetString("LOCAL_TEST_CONFIG", String(s.testProperties.Test_config))
+				for _, d := range s.data {
+					rel := d.Rel()
+					path := d.String()
+					if !strings.HasSuffix(path, rel) {
+						panic(fmt.Errorf("path %q does not end with %q", path, rel))
+					}
+					path = strings.TrimSuffix(path, rel)
+					entries.AddStrings("LOCAL_TEST_DATA", path+":"+rel)
 				}
-				path = strings.TrimSuffix(path, rel)
-				entries.AddStrings("LOCAL_TEST_DATA", path+":"+rel)
-			}
+			},
 		},
 	}
 }
diff --git a/apex/apex.go b/apex/apex.go
index 574604b..832188d 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -126,6 +126,16 @@
 	usesTag        = dependencyTag{name: "uses"}
 )
 
+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"},
+	}
+)
+
 func init() {
 	pctx.Import("android/soong/android")
 	pctx.Import("android/soong/java")
@@ -932,7 +942,7 @@
 			}
 		} else {
 			// indirect dependencies
-			if am, ok := child.(android.ApexModule); ok && am.CanHaveApexVariants() && am.IsInstallableToApex() {
+			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) {
@@ -972,8 +982,10 @@
 						filesInfo = append(filesInfo, apexFile{fileToCopy, moduleName, dirInApex, nativeTest, cc, nil})
 						return true
 					}
-				} else {
+				} else if am.CanHaveApexVariants() && am.IsInstallableToApex() {
 					ctx.ModuleErrorf("unexpected tag %q for indirect dependency %q", depTag, depName)
+				} else if am.NoApex() && !android.InList(depName, whitelistNoApex[ctx.ModuleName()]) {
+					ctx.ModuleErrorf("tries to include no_apex module %s", depName)
 				}
 			}
 		}
@@ -1005,6 +1017,16 @@
 		return filesInfo[i].builtFile.String() < filesInfo[j].builtFile.String()
 	})
 
+	// check no_apex modules
+	whitelist := whitelistNoApex[ctx.ModuleName()]
+	for i := range filesInfo {
+		if am, ok := filesInfo[i].module.(android.ApexModule); ok {
+			if am.NoApex() && !android.InList(filesInfo[i].moduleName, whitelist) {
+				ctx.ModuleErrorf("tries to include no_apex module %s", filesInfo[i].moduleName)
+			}
+		}
+	}
+
 	// 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 {
@@ -1191,6 +1213,13 @@
 			optFlags = append(optFlags, "--assets_dir "+filepath.Dir(noticeFile.String()))
 		}
 
+		if !ctx.Config().UnbundledBuild() && a.installable() {
+			// Apexes which are supposed to be installed in builtin dirs(/system, etc)
+			// don't need hashtree for activation. Therefore, by removing hashtree from
+			// apex bundle (filesystem image in it, to be specific), we can save storage.
+			optFlags = append(optFlags, "--no_hashtree")
+		}
+
 		ctx.Build(pctx, android.BuildParams{
 			Rule:        apexRule,
 			Implicits:   implicitInputs,
@@ -1658,11 +1687,13 @@
 		Class:      "ETC",
 		OutputFile: android.OptionalPathForPath(p.inputApex),
 		Include:    "$(BUILD_PREBUILT)",
-		AddCustomEntries: func(name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
-			entries.SetString("LOCAL_MODULE_PATH", filepath.Join("$(OUT_DIR)", p.installDir.RelPathString()))
-			entries.SetString("LOCAL_MODULE_STEM", p.installFilename)
-			entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", !p.installable())
-			entries.AddStrings("LOCAL_OVERRIDES_PACKAGES", p.properties.Overrides...)
+		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+			func(entries *android.AndroidMkEntries) {
+				entries.SetString("LOCAL_MODULE_PATH", filepath.Join("$(OUT_DIR)", p.installDir.RelPathString()))
+				entries.SetString("LOCAL_MODULE_STEM", p.installFilename)
+				entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", !p.installable())
+				entries.AddStrings("LOCAL_OVERRIDES_PACKAGES", p.properties.Overrides...)
+			},
 		},
 	}
 }
diff --git a/apex/apex_test.go b/apex/apex_test.go
index e06c193..8de4cef 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -714,6 +714,58 @@
 
 }
 
+func TestApexDependencyToLLNDK(t *testing.T) {
+	ctx, _ := testApex(t, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			use_vendor: true,
+			native_shared_libs: ["mylib"],
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		cc_library {
+			name: "mylib",
+			srcs: ["mylib.cpp"],
+			vendor_available: true,
+			shared_libs: ["libbar"],
+			system_shared_libs: [],
+			stl: "none",
+		}
+
+		cc_library {
+			name: "libbar",
+			srcs: ["mylib.cpp"],
+			system_shared_libs: [],
+			stl: "none",
+		}
+
+		llndk_library {
+			name: "libbar",
+			symbol_file: "",
+		}
+
+	`)
+
+	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
+	copyCmds := apexRule.Args["copy_commands"]
+
+	// Ensure that LLNDK dep is not included
+	ensureNotContains(t, copyCmds, "image.apex/lib64/libbar.so")
+
+	injectRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("injectApexDependency")
+	ensureListEmpty(t, names(injectRule.Args["provideNativeLibs"]))
+
+	// Ensure that LLNDK dep is required
+	ensureListContains(t, names(injectRule.Args["requireNativeLibs"]), "libbar.so")
+
+}
+
 func TestApexWithSystemLibsStubs(t *testing.T) {
 	ctx, _ := testApex(t, `
 		apex {
@@ -1768,6 +1820,163 @@
 	`)
 }
 
+func TestApexUsesFailsIfUseNoApex(t *testing.T) {
+	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"],
+			shared_libs: ["mylib2"],
+			system_shared_libs: [],
+			stl: "none",
+		}
+
+		cc_library {
+			name: "mylib2",
+			srcs: ["mylib.cpp"],
+			system_shared_libs: [],
+			stl: "none",
+			no_apex: true,
+		}
+	`)
+
+	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_library {
+			name: "mylib2",
+			srcs: ["mylib.cpp"],
+			system_shared_libs: [],
+			stl: "none",
+			no_apex: true,
+		}
+	`)
+
+	ctx, _ := 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_library {
+			name: "mylib2",
+			srcs: ["mylib.cpp"],
+			shared_libs: ["mylib3"],
+			system_shared_libs: [],
+			stl: "none",
+			stubs: {
+				versions: ["1", "2", "3"],
+			},
+		}
+
+		cc_library {
+			name: "mylib3",
+			srcs: ["mylib.cpp"],
+			system_shared_libs: [],
+			stl: "none",
+			no_apex: true,
+		}
+	`)
+
+	module := ctx.ModuleForTests("myapex", "android_common_myapex")
+	apexRule := module.Rule("apexRule")
+	copyCmds := apexRule.Args["copy_commands"]
+
+	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) {
+	testApexError(t, `module "myapex" .* depends on disabled module "libfoo"`, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			native_shared_libs: ["libfoo"],
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		cc_library {
+			name: "libfoo",
+			stl: "none",
+			system_shared_libs: [],
+			enabled: false,
+		}
+	`)
+	testApexError(t, `module "myapex" .* depends on disabled module "myjar"`, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			java_libs: ["myjar"],
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		java_library {
+			name: "myjar",
+			srcs: ["foo/bar/MyClass.java"],
+			sdk_version: "none",
+			system_modules: "none",
+			compile_dex: true,
+			enabled: false,
+		}
+	`)
+}
+
 func TestMain(m *testing.M) {
 	run := func() int {
 		setUp()
diff --git a/cc/builder.go b/cc/builder.go
index 3d89770..554706c 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -65,14 +65,14 @@
 	ld = pctx.AndroidStaticRule("ld",
 		blueprint.RuleParams{
 			Command: "$ldCmd ${crtBegin} @${out}.rsp " +
-				"${libFlags} ${crtEnd} -o ${out} ${ldFlags}",
+				"${libFlags} ${crtEnd} -o ${out} ${ldFlags} ${extraLibFlags}",
 			CommandDeps:    []string{"$ldCmd"},
 			Rspfile:        "${out}.rsp",
 			RspfileContent: "${in}",
 			// clang -Wl,--out-implib doesn't update its output file if it hasn't changed.
 			Restat: true,
 		},
-		"ldCmd", "crtBegin", "libFlags", "crtEnd", "ldFlags")
+		"ldCmd", "crtBegin", "libFlags", "crtEnd", "ldFlags", "extraLibFlags")
 
 	partialLd = pctx.AndroidStaticRule("partialLd",
 		blueprint.RuleParams{
@@ -259,6 +259,7 @@
 	cppFlags        string
 	ldFlags         string
 	libFlags        string
+	extraLibFlags   string
 	tidyFlags       string
 	sAbiFlags       string
 	yasmFlags       string
@@ -270,6 +271,8 @@
 	sAbiDump        bool
 	emitXrefs       bool
 
+	assemblerWithCpp bool
+
 	systemIncludeFlags string
 
 	groupStaticLibs bool
@@ -411,6 +414,9 @@
 				},
 			})
 			continue
+		case ".o":
+			objFiles[i] = srcFile
+			continue
 		}
 
 		var moduleCflags string
@@ -424,7 +430,9 @@
 
 		switch srcFile.Ext() {
 		case ".s":
-			rule = ccNoDeps
+			if !flags.assemblerWithCpp {
+				rule = ccNoDeps
+			}
 			fallthrough
 		case ".S":
 			ccCmd = "clang"
@@ -627,11 +635,12 @@
 		Inputs:          objFiles,
 		Implicits:       deps,
 		Args: map[string]string{
-			"ldCmd":    ldCmd,
-			"crtBegin": crtBegin.String(),
-			"libFlags": strings.Join(libFlagsList, " "),
-			"ldFlags":  flags.ldFlags,
-			"crtEnd":   crtEnd.String(),
+			"ldCmd":         ldCmd,
+			"crtBegin":      crtBegin.String(),
+			"libFlags":      strings.Join(libFlagsList, " "),
+			"extraLibFlags": flags.extraLibFlags,
+			"ldFlags":       flags.ldFlags,
+			"crtEnd":        crtEnd.String(),
 		},
 	})
 }
diff --git a/cc/cc.go b/cc/cc.go
index c853e67..2ff3434 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -153,6 +153,7 @@
 	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
@@ -173,7 +174,8 @@
 	CFlagsDeps  android.Paths // Files depended on by compiler flags
 	LdFlagsDeps android.Paths // Files depended on by linker flags
 
-	GroupStaticLibs bool
+	AssemblerWithCpp bool
+	GroupStaticLibs  bool
 
 	proto            android.ProtoFlags
 	protoC           bool // Whether to use C instead of C++
@@ -182,17 +184,6 @@
 	Yacc *YaccProperties
 }
 
-type ObjectLinkerProperties struct {
-	// list of modules that should only provide headers for this module.
-	Header_libs []string `android:"arch_variant,variant_prepend"`
-
-	// names of other cc_object modules to link into this module using partial linking
-	Objs []string `android:"arch_variant"`
-
-	// if set, add an extra objcopy --prefix-symbols= step
-	Prefix_symbols *string
-}
-
 // Properties used to compile all C or C++ modules
 type BaseProperties struct {
 	// Deprecated. true is the default, false is invalid.
@@ -401,6 +392,14 @@
 	return ok && ccDepTag == testPerSrcDepTag
 }
 
+func SharedDepTag() dependencyTag {
+	return sharedDepTag
+}
+
+func StaticDepTag() dependencyTag {
+	return staticDepTag
+}
+
 // 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
@@ -1063,6 +1062,9 @@
 	if c.sabi != nil {
 		flags = c.sabi.flags(ctx, flags)
 	}
+
+	flags.AssemblerWithCpp = inList("-xassembler-with-cpp", flags.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, " "))
diff --git a/cc/cc_test.go b/cc/cc_test.go
index c4799e9..c9eb421 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -2203,7 +2203,7 @@
 	ctx := testCc(t, `
 		cc_binary {
 			name: "static_test",
-			srcs: ["foo.c"],
+			srcs: ["foo.c", "baz.o"],
 			static_executable: true,
 		}`)
 
@@ -2264,6 +2264,24 @@
 	}
 }
 
+func TestErrorsIfAModuleDependsOnDisabled(t *testing.T) {
+	testCcError(t, `module "libA" .* depends on disabled module "libB"`, `
+		cc_library {
+			name: "libA",
+			srcs: ["foo.c"],
+			shared_libs: ["libB"],
+			stl: "none",
+		}
+
+		cc_library {
+			name: "libB",
+			srcs: ["foo.c"],
+			enabled: false,
+			stl: "none",
+		}
+	`)
+}
+
 // Simple smoke test for the cc_fuzz target that ensures the rule compiles
 // correctly.
 func TestFuzzTarget(t *testing.T) {
diff --git a/cc/config/global.go b/cc/config/global.go
index 9ce6896..d873494 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -46,6 +46,8 @@
 		"-g",
 
 		"-fno-strict-aliasing",
+
+		"-Werror=date-time",
 	}
 
 	commonGlobalConlyflags = []string{}
@@ -67,7 +69,6 @@
 		"-Werror=non-virtual-dtor",
 		"-Werror=address",
 		"-Werror=sequence-point",
-		"-Werror=date-time",
 		"-Werror=format-security",
 	}
 
@@ -122,8 +123,8 @@
 
 	// prebuilts/clang default settings.
 	ClangDefaultBase         = "prebuilts/clang/host"
-	ClangDefaultVersion      = "clang-r353983d"
-	ClangDefaultShortVersion = "9.0.4"
+	ClangDefaultVersion      = "clang-r365631"
+	ClangDefaultShortVersion = "9.0.6"
 
 	// Directories with warnings from Android.bp files.
 	WarningAllowedProjects = []string{
diff --git a/cc/fuzz.go b/cc/fuzz.go
index c1754b2..d44c02d 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -17,6 +17,7 @@
 import (
 	"android/soong/android"
 	"android/soong/cc/config"
+	"github.com/google/blueprint/proptools"
 )
 
 func init() {
@@ -120,5 +121,16 @@
 		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 {
+			Stl *string
+		}{}
+
+		staticStlLinkage.Stl = proptools.StringPtr("libc++_static")
+		ctx.AppendProperties(&staticStlLinkage)
+	})
+
 	return module
 }
diff --git a/cc/library.go b/cc/library.go
index 0869727..6564fa1 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -113,6 +113,9 @@
 
 	// Order symbols in .bss section by their sizes.  Only useful for shared libraries.
 	Sort_bss_symbols_by_size *bool
+
+	// Inject boringssl hash into the shared library.  This is only intended for use by external/boringssl.
+	Inject_bssl_hash *bool `android:"arch_variant"`
 }
 
 type LibraryMutatedProperties struct {
@@ -766,9 +769,21 @@
 		outputFile = android.PathForModuleOut(ctx, "unstripped", fileName)
 		library.stripper.stripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile, builderFlags)
 	}
-
 	library.unstrippedOutputFile = outputFile
 
+	// TODO(b/137267623): Remove this in favor of a cc_genrule when they support operating on shared libraries.
+	if Bool(library.Properties.Inject_bssl_hash) {
+		hashedOutputfile := outputFile
+		outputFile = android.PathForModuleOut(ctx, "unhashed", fileName)
+
+		rule := android.NewRuleBuilder()
+		rule.Command().
+			BuiltTool(ctx, "bssl_inject_hash").
+			FlagWithInput("-in-object ", outputFile).
+			FlagWithOutput("-o ", hashedOutputfile)
+		rule.Build(pctx, ctx, "injectCryptoHash", "inject crypto hash")
+	}
+
 	if Bool(library.baseLinker.Properties.Use_version_lib) {
 		if ctx.Host() {
 			versionedOutputFile := outputFile
@@ -937,9 +952,7 @@
 			isVendor := ctx.useVndk()
 			isOwnerPlatform := Bool(library.Properties.Sysprop.Platform)
 
-			usePublic := isProduct || (isOwnerPlatform == isVendor)
-
-			if usePublic {
+			if !ctx.inRecovery() && (isProduct || (isOwnerPlatform == isVendor)) {
 				dir = android.PathForModuleGen(ctx, "sysprop/public", "include").String()
 			}
 		}
diff --git a/cc/library_test.go b/cc/library_test.go
index 859b05a..2acae35 100644
--- a/cc/library_test.go
+++ b/cc/library_test.go
@@ -24,23 +24,26 @@
 		ctx := testCc(t, `
 		cc_library {
 			name: "libfoo",
-			srcs: ["foo.c"],
+			srcs: ["foo.c", "baz.o"],
 		}`)
 
 		libfooShared := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_core_shared").Rule("ld")
 		libfooStatic := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_core_static").Output("libfoo.a")
 
-		if len(libfooShared.Inputs) != 1 {
+		if len(libfooShared.Inputs) != 2 {
 			t.Fatalf("unexpected inputs to libfoo shared: %#v", libfooShared.Inputs.Strings())
 		}
 
-		if len(libfooStatic.Inputs) != 1 {
+		if len(libfooStatic.Inputs) != 2 {
 			t.Fatalf("unexpected inputs to libfoo static: %#v", libfooStatic.Inputs.Strings())
 		}
 
 		if libfooShared.Inputs[0] != libfooStatic.Inputs[0] {
 			t.Errorf("static object not reused for shared library")
 		}
+		if libfooShared.Inputs[1] != libfooStatic.Inputs[1] {
+			t.Errorf("static object not reused for shared library")
+		}
 	})
 
 	t.Run("extra static source", func(t *testing.T) {
diff --git a/cc/object.go b/cc/object.go
index 15272eb..1a2711d 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -33,6 +33,20 @@
 	Properties ObjectLinkerProperties
 }
 
+type ObjectLinkerProperties struct {
+	// list of modules that should only provide headers for this module.
+	Header_libs []string `android:"arch_variant,variant_prepend"`
+
+	// names of other cc_object modules to link into this module using partial linking
+	Objs []string `android:"arch_variant"`
+
+	// if set, add an extra objcopy --prefix-symbols= step
+	Prefix_symbols *string
+
+	// if set, the path to a linker script to pass to ld -r when combining multiple object files.
+	Linker_script *string `android:"path,arch_variant"`
+}
+
 // cc_object runs the compiler without running the linker. It is rarely
 // necessary, but sometimes used to generate .s files from .c files to use as
 // input to a cc_genrule module.
@@ -71,9 +85,13 @@
 	return deps
 }
 
-func (*objectLinker) linkerFlags(ctx ModuleContext, flags Flags) Flags {
+func (object *objectLinker) linkerFlags(ctx ModuleContext, flags Flags) Flags {
 	flags.LdFlags = append(flags.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.LdFlagsDeps = append(flags.LdFlagsDeps, lds.Path())
+	}
 	return flags
 }
 
diff --git a/cc/object_test.go b/cc/object_test.go
new file mode 100644
index 0000000..6ff8a00
--- /dev/null
+++ b/cc/object_test.go
@@ -0,0 +1,31 @@
+// 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 cc
+
+import (
+	"testing"
+)
+
+func TestLinkerScript(t *testing.T) {
+	t.Run("script", func(t *testing.T) {
+		testCc(t, `
+		cc_object {
+			name: "foo",
+			srcs: ["baz.o"],
+			linker_script: "foo.lds",
+		}`)
+	})
+
+}
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 4687782..192b8d9 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -37,11 +37,7 @@
 	}
 	asanLdflags = []string{"-Wl,-u,__asan_preinit"}
 
-	// TODO(pcc): Stop passing -hwasan-allow-ifunc here once it has been made
-	// the default.
 	hwasanCflags = []string{"-fno-omit-frame-pointer", "-Wno-frame-larger-than=",
-		"-mllvm", "-hwasan-create-frame-descriptions=0",
-		"-mllvm", "-hwasan-allow-ifunc",
 		"-fsanitize-hwaddress-abi=platform",
 		"-fno-experimental-new-pass-manager"}
 
diff --git a/cc/stl.go b/cc/stl.go
index d7feb6f..458129c 100644
--- a/cc/stl.go
+++ b/cc/stl.go
@@ -207,8 +207,6 @@
 func (stl *stl) flags(ctx ModuleContext, flags Flags) Flags {
 	switch stl.Properties.SelectedStl {
 	case "libc++", "libc++_static":
-		flags.CFlags = append(flags.CFlags, "-D_USING_LIBCXX")
-
 		if ctx.Darwin() {
 			// libc++'s headers are annotated with availability macros that
 			// indicate which version of Mac OS was the first to ship with a
@@ -223,11 +221,11 @@
 
 		if !ctx.toolchain().Bionic() {
 			flags.CppFlags = append(flags.CppFlags, "-nostdinc++")
-			flags.LdFlags = append(flags.LdFlags, "-nodefaultlibs")
+			flags.extraLibFlags = append(flags.extraLibFlags, "-nodefaultlibs")
 			if ctx.staticBinary() {
-				flags.LdFlags = append(flags.LdFlags, hostStaticGccLibs[ctx.Os()]...)
+				flags.extraLibFlags = append(flags.extraLibFlags, hostStaticGccLibs[ctx.Os()]...)
 			} else {
-				flags.LdFlags = append(flags.LdFlags, hostDynamicGccLibs[ctx.Os()]...)
+				flags.extraLibFlags = append(flags.extraLibFlags, hostDynamicGccLibs[ctx.Os()]...)
 			}
 			if ctx.Windows() {
 				// Use SjLj exceptions for 32-bit.  libgcc_eh implements SjLj
@@ -262,11 +260,11 @@
 		// None or error.
 		if !ctx.toolchain().Bionic() {
 			flags.CppFlags = append(flags.CppFlags, "-nostdinc++")
-			flags.LdFlags = append(flags.LdFlags, "-nodefaultlibs")
+			flags.extraLibFlags = append(flags.extraLibFlags, "-nodefaultlibs")
 			if ctx.staticBinary() {
-				flags.LdFlags = append(flags.LdFlags, hostStaticGccLibs[ctx.Os()]...)
+				flags.extraLibFlags = append(flags.extraLibFlags, hostStaticGccLibs[ctx.Os()]...)
 			} else {
-				flags.LdFlags = append(flags.LdFlags, hostDynamicGccLibs[ctx.Os()]...)
+				flags.extraLibFlags = append(flags.extraLibFlags, hostDynamicGccLibs[ctx.Os()]...)
 			}
 		}
 	default:
diff --git a/cc/sysprop.go b/cc/sysprop.go
index 656f79f..6cac7fb 100644
--- a/cc/sysprop.go
+++ b/cc/sysprop.go
@@ -21,6 +21,7 @@
 )
 
 type syspropLibraryInterface interface {
+	BaseModuleName() string
 	CcModuleName() string
 }
 
@@ -42,6 +43,6 @@
 		syspropImplLibrariesLock.Lock()
 		defer syspropImplLibrariesLock.Unlock()
 
-		syspropImplLibraries[mctx.ModuleName()] = m.CcModuleName()
+		syspropImplLibraries[m.BaseModuleName()] = m.CcModuleName()
 	}
 }
diff --git a/cc/testing.go b/cc/testing.go
index e69b774..5a3993c 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -272,7 +272,9 @@
 	mockFS := map[string][]byte{
 		"Android.bp":  []byte(bp),
 		"foo.c":       nil,
+		"foo.lds":     nil,
 		"bar.c":       nil,
+		"baz.o":       nil,
 		"a.proto":     nil,
 		"b.aidl":      nil,
 		"sub/c.aidl":  nil,
diff --git a/cc/util.go b/cc/util.go
index 0d1b2f0..7b8ad18 100644
--- a/cc/util.go
+++ b/cc/util.go
@@ -67,6 +67,7 @@
 		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, " "),
@@ -78,7 +79,8 @@
 
 		systemIncludeFlags: strings.Join(in.SystemIncludeFlags, " "),
 
-		groupStaticLibs: in.GroupStaticLibs,
+		assemblerWithCpp: in.AssemblerWithCpp,
+		groupStaticLibs:  in.GroupStaticLibs,
 
 		proto:            in.proto,
 		protoC:           in.protoC,
diff --git a/java/androidmk.go b/java/androidmk.go
index c00e070..0e8e422 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -122,6 +122,15 @@
 	}
 }
 
+func testSuiteComponentEntries(entries *android.AndroidMkEntries, test_suites []string) {
+	entries.SetString("LOCAL_MODULE_TAGS", "tests")
+	if len(test_suites) > 0 {
+		entries.AddStrings("LOCAL_COMPATIBILITY_SUITE", test_suites...)
+	} else {
+		entries.SetString("LOCAL_COMPATIBILITY_SUITE", "null-suite")
+	}
+}
+
 func (j *Test) AndroidMk() android.AndroidMkData {
 	data := j.Library.AndroidMk()
 	data.Extra = append(data.Extra, func(w io.Writer, outputFile android.Path) {
@@ -614,22 +623,33 @@
 		Class:      "APPS",
 		OutputFile: android.OptionalPathForPath(a.outputFile),
 		Include:    "$(BUILD_SYSTEM)/soong_app_prebuilt.mk",
-		AddCustomEntries: func(name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
-			entries.SetBoolIfTrue("LOCAL_PRIVILEGED_MODULE", Bool(a.properties.Privileged))
-			if a.certificate != nil {
-				entries.SetString("LOCAL_CERTIFICATE", a.certificate.Pem.String())
-			} else {
-				entries.SetString("LOCAL_CERTIFICATE", "PRESIGNED")
-			}
-			entries.AddStrings("LOCAL_OVERRIDES_PACKAGES", a.properties.Overrides...)
-			if len(a.dexpreopter.builtInstalled) > 0 {
-				entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", a.dexpreopter.builtInstalled)
-			}
-			entries.AddStrings("LOCAL_INSTALLED_MODULE_STEM", a.installPath.Rel())
+		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+			func(entries *android.AndroidMkEntries) {
+				entries.SetBoolIfTrue("LOCAL_PRIVILEGED_MODULE", Bool(a.properties.Privileged))
+				if a.certificate != nil {
+					entries.SetString("LOCAL_CERTIFICATE", a.certificate.Pem.String())
+				} else {
+					entries.SetString("LOCAL_CERTIFICATE", "PRESIGNED")
+				}
+				entries.AddStrings("LOCAL_OVERRIDES_PACKAGES", a.properties.Overrides...)
+				if len(a.dexpreopter.builtInstalled) > 0 {
+					entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", a.dexpreopter.builtInstalled)
+				}
+				entries.AddStrings("LOCAL_INSTALLED_MODULE_STEM", a.installPath.Rel())
+			},
 		},
 	}
 }
 
+func (a *AndroidTestImport) AndroidMkEntries() android.AndroidMkEntries {
+	entries := a.AndroidAppImport.AndroidMkEntries()
+	entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+		testSuiteComponentEntries(entries, a.testProperties.Test_suites)
+		androidMkEntriesWriteTestData(a.data, entries)
+	})
+	return entries
+}
+
 func androidMkWriteTestData(data android.Paths, ret *android.AndroidMkData) {
 	var testFiles []string
 	for _, d := range data {
@@ -641,3 +661,11 @@
 		})
 	}
 }
+
+func androidMkEntriesWriteTestData(data android.Paths, entries *android.AndroidMkEntries) {
+	var testFiles []string
+	for _, d := range data {
+		testFiles = append(testFiles, d.String()+":"+d.Rel())
+	}
+	entries.AddStrings("LOCAL_COMPATIBILITY_SUPPORT_FILES", testFiles...)
+}
diff --git a/java/app.go b/java/app.go
index 31f07d3..7df4358 100644
--- a/java/app.go
+++ b/java/app.go
@@ -39,6 +39,7 @@
 	android.RegisterModuleType("android_app_certificate", AndroidAppCertificateFactory)
 	android.RegisterModuleType("override_android_app", OverrideAndroidAppModuleFactory)
 	android.RegisterModuleType("android_app_import", AndroidAppImportFactory)
+	android.RegisterModuleType("android_test_import", AndroidTestImportFactory)
 
 	initAndroidAppImportVariantGroupTypes()
 }
@@ -751,14 +752,18 @@
 	// A prebuilt apk to import
 	Apk *string
 
-	// The name of a certificate in the default certificate directory, blank to use the default
-	// product certificate, or an android_app_certificate module name in the form ":module".
+	// The name of a certificate in the default certificate directory or an android_app_certificate
+	// module name in the form ":module". Should be empty if presigned or default_dev_cert is set.
 	Certificate *string
 
 	// Set this flag to true if the prebuilt apk is already signed. The certificate property must not
 	// be set for presigned modules.
 	Presigned *bool
 
+	// Sign with the default system dev certificate. Must be used judiciously. Most imported apps
+	// need to either specify a specific certificate or be presigned.
+	Default_dev_cert *bool
+
 	// Specifies that this app should be installed to the priv-app directory,
 	// where the system will grant it additional privileges not available to
 	// normal apps.
@@ -862,11 +867,22 @@
 }
 
 func (a *AndroidAppImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	if String(a.properties.Certificate) == "" && !Bool(a.properties.Presigned) {
-		ctx.PropertyErrorf("certificate", "No certificate specified for prebuilt")
+	a.generateAndroidBuildActions(ctx)
+}
+
+func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext) {
+	numCertPropsSet := 0
+	if String(a.properties.Certificate) != "" {
+		numCertPropsSet++
 	}
-	if String(a.properties.Certificate) != "" && Bool(a.properties.Presigned) {
-		ctx.PropertyErrorf("certificate", "Certificate can't be specified for presigned modules")
+	if Bool(a.properties.Presigned) {
+		numCertPropsSet++
+	}
+	if Bool(a.properties.Default_dev_cert) {
+		numCertPropsSet++
+	}
+	if numCertPropsSet != 1 {
+		ctx.ModuleErrorf("One and only one of certficate, presigned, and default_dev_cert properties must be set")
 	}
 
 	_, certificates := collectAppDeps(ctx)
@@ -907,7 +923,9 @@
 	// Sign or align the package
 	// TODO: Handle EXTERNAL
 	if !Bool(a.properties.Presigned) {
-		certificates = processMainCert(a.ModuleBase, *a.properties.Certificate, certificates, ctx)
+		// If the certificate property is empty at this point, default_dev_cert must be set to true.
+		// Which makes processMainCert's behavior for the empty cert string WAI.
+		certificates = processMainCert(a.ModuleBase, String(a.properties.Certificate), certificates, ctx)
 		if len(certificates) != 1 {
 			ctx.ModuleErrorf("Unexpected number of certificates were extracted: %q", certificates)
 		}
@@ -1011,6 +1029,39 @@
 	return module
 }
 
+type AndroidTestImport struct {
+	AndroidAppImport
+
+	testProperties testProperties
+
+	data android.Paths
+}
+
+func (a *AndroidTestImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	a.generateAndroidBuildActions(ctx)
+
+	a.data = android.PathsForModuleSrc(ctx, a.testProperties.Data)
+}
+
+// android_test_import imports a prebuilt test apk with additional processing specified in the
+// module. DPI or arch variant configurations can be made as with android_app_import.
+func AndroidTestImportFactory() android.Module {
+	module := &AndroidTestImport{}
+	module.AddProperties(&module.properties)
+	module.AddProperties(&module.dexpreoptProperties)
+	module.AddProperties(&module.usesLibrary.usesLibraryProperties)
+	module.AddProperties(&module.testProperties)
+	module.populateAllVariantStructs()
+	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
+		module.processVariants(ctx)
+	})
+
+	InitJavaModule(module, android.DeviceSupported)
+	android.InitSingleSourcePrebuiltModule(module, &module.properties, "Apk")
+
+	return module
+}
+
 type UsesLibraryProperties struct {
 	// A list of shared library modules that will be listed in uses-library tags in the AndroidManifest.xml file.
 	Uses_libs []string
diff --git a/java/app_test.go b/java/app_test.go
index 564211c..f2aaec3 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -1164,6 +1164,35 @@
 	}
 }
 
+func TestAndroidAppImport_DefaultDevCert(t *testing.T) {
+	ctx, _ := testJava(t, `
+		android_app_import {
+			name: "foo",
+			apk: "prebuilts/apk/app.apk",
+			default_dev_cert: true,
+			dex_preopt: {
+				enabled: true,
+			},
+		}
+		`)
+
+	variant := ctx.ModuleForTests("foo", "android_common")
+
+	// Check dexpreopt outputs.
+	if variant.MaybeOutput("dexpreopt/oat/arm64/package.vdex").Rule == nil ||
+		variant.MaybeOutput("dexpreopt/oat/arm64/package.odex").Rule == nil {
+		t.Errorf("can't find dexpreopt outputs")
+	}
+
+	// Check cert signing flag.
+	signedApk := variant.Output("signed/foo.apk")
+	signingFlag := signedApk.Args["certificates"]
+	expected := "build/make/target/product/security/testkey.x509.pem build/make/target/product/security/testkey.pk8"
+	if expected != signingFlag {
+		t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected, signingFlag)
+	}
+}
+
 func TestAndroidAppImport_DpiVariants(t *testing.T) {
 	bp := `
 		android_app_import {
@@ -1177,7 +1206,7 @@
 					apk: "prebuilts/apk/app_xxhdpi.apk",
 				},
 			},
-			certificate: "PRESIGNED",
+			presigned: true,
 			dex_preopt: {
 				enabled: true,
 			},
@@ -1307,7 +1336,7 @@
 							apk: "prebuilts/apk/app_arm64.apk",
 						},
 					},
-					certificate: "PRESIGNED",
+					presigned: true,
 					dex_preopt: {
 						enabled: true,
 					},
@@ -1326,7 +1355,7 @@
 							apk: "prebuilts/apk/app_arm.apk",
 						},
 					},
-					certificate: "PRESIGNED",
+					presigned: true,
 					dex_preopt: {
 						enabled: true,
 					},
@@ -1352,6 +1381,34 @@
 	}
 }
 
+func TestAndroidTestImport(t *testing.T) {
+	ctx, config := testJava(t, `
+		android_test_import {
+			name: "foo",
+			apk: "prebuilts/apk/app.apk",
+			presigned: true,
+			data: [
+				"testdata/data",
+			],
+		}
+		`)
+
+	test := ctx.ModuleForTests("foo", "android_common").Module().(*AndroidTestImport)
+
+	// Check android mks.
+	entries := android.AndroidMkEntriesForTest(t, config, "", test)
+	expected := []string{"tests"}
+	actual := entries.EntryMap["LOCAL_MODULE_TAGS"]
+	if !reflect.DeepEqual(expected, actual) {
+		t.Errorf("Unexpected module tags - expected: %q, actual: %q", expected, actual)
+	}
+	expected = []string{"testdata/data:testdata/data"}
+	actual = entries.EntryMap["LOCAL_COMPATIBILITY_SUPPORT_FILES"]
+	if !reflect.DeepEqual(expected, actual) {
+		t.Errorf("Unexpected test data - expected: %q, actual: %q", expected, actual)
+	}
+}
+
 func TestStl(t *testing.T) {
 	ctx, _ := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
 		cc_library {
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 9956270..8b15e0f 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -64,10 +64,7 @@
 	// the java library (in classpath) for documentation that provides java srcs and srcjars.
 	Srcs_lib *string
 
-	// the base dirs under srcs_lib will be scanned for java srcs.
-	Srcs_lib_whitelist_dirs []string
-
-	// the sub dirs under srcs_lib_whitelist_dirs will be scanned for java srcs.
+	// List of packages to document from srcs_lib
 	Srcs_lib_whitelist_pkgs []string
 
 	// If set to false, don't allow this module(-docs.zip) to be exported. Defaults to true.
@@ -362,6 +359,8 @@
 	switch tag {
 	case "":
 		return android.Paths{j.stubsSrcJar}, nil
+	case ".docs.zip":
+		return android.Paths{j.docZip}, nil
 	default:
 		return nil, fmt.Errorf("unsupported module reference tag %q", tag)
 	}
@@ -428,19 +427,6 @@
 	}
 }
 
-func (j *Javadoc) genWhitelistPathPrefixes(whitelistPathPrefixes map[string]bool) {
-	for _, dir := range j.properties.Srcs_lib_whitelist_dirs {
-		for _, pkg := range j.properties.Srcs_lib_whitelist_pkgs {
-			// convert foo.bar.baz to foo/bar/baz
-			pkgAsPath := filepath.Join(strings.Split(pkg, ".")...)
-			prefix := filepath.Join(dir, pkgAsPath)
-			if _, found := whitelistPathPrefixes[prefix]; !found {
-				whitelistPathPrefixes[prefix] = true
-			}
-		}
-	}
-}
-
 func (j *Javadoc) collectAidlFlags(ctx android.ModuleContext, deps deps) droiddocBuilderFlags {
 	var flags droiddocBuilderFlags
 
@@ -474,18 +460,21 @@
 	return strings.Join(flags, " "), deps
 }
 
+// TODO: remove the duplication between this and the one in gen.go
 func (j *Javadoc) genSources(ctx android.ModuleContext, srcFiles android.Paths,
 	flags droiddocBuilderFlags) android.Paths {
 
 	outSrcFiles := make(android.Paths, 0, len(srcFiles))
 
+	aidlIncludeFlags := genAidlIncludeFlags(srcFiles)
+
 	for _, srcFile := range srcFiles {
 		switch srcFile.Ext() {
 		case ".aidl":
-			javaFile := genAidl(ctx, srcFile, flags.aidlFlags, flags.aidlDeps)
+			javaFile := genAidl(ctx, srcFile, flags.aidlFlags+aidlIncludeFlags, flags.aidlDeps)
 			outSrcFiles = append(outSrcFiles, javaFile)
-		case ".sysprop":
-			javaFile := genSysprop(ctx, srcFile)
+		case ".logtags":
+			javaFile := genLogtags(ctx, srcFile)
 			outSrcFiles = append(outSrcFiles, javaFile)
 		default:
 			outSrcFiles = append(outSrcFiles, srcFile)
@@ -533,14 +522,13 @@
 			switch dep := module.(type) {
 			case Dependency:
 				srcs := dep.(SrcDependency).CompiledSrcs()
-				whitelistPathPrefixes := make(map[string]bool)
-				j.genWhitelistPathPrefixes(whitelistPathPrefixes)
 				for _, src := range srcs {
 					if _, ok := src.(android.WritablePath); ok { // generated sources
 						deps.srcs = append(deps.srcs, src)
 					} else { // select source path for documentation based on whitelist path prefixs.
-						for k := range whitelistPathPrefixes {
-							if strings.HasPrefix(src.Rel(), k) {
+						for _, pkg := range j.properties.Srcs_lib_whitelist_pkgs {
+							pkgAsPath := filepath.Join(strings.Split(pkg, ".")...)
+							if strings.HasPrefix(src.Rel(), pkgAsPath) {
 								deps.srcs = append(deps.srcs, src)
 								break
 							}
diff --git a/java/gen.go b/java/gen.go
index 69965ec..532a22c 100644
--- a/java/gen.go
+++ b/java/gen.go
@@ -53,22 +53,18 @@
 	sysprop = pctx.AndroidStaticRule("sysprop",
 		blueprint.RuleParams{
 			Command: `rm -rf $out.tmp && mkdir -p $out.tmp && ` +
-				`$syspropCmd --java-output-dir $out.tmp $in && ` +
+				`$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 {
 	javaFile := android.GenPathWithExt(ctx, "aidl", aidlFile, "java")
 	depFile := javaFile.String() + ".d"
-	baseDir := strings.TrimSuffix(aidlFile.String(), aidlFile.Rel())
-	if baseDir != "" {
-		aidlFlags += " -I" + baseDir
-	}
 
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        aidl,
@@ -98,7 +94,7 @@
 	return javaFile
 }
 
-func genSysprop(ctx android.ModuleContext, syspropFile android.Path) android.Path {
+func genSysprop(ctx android.ModuleContext, syspropFile android.Path, scope string) android.Path {
 	srcJarFile := android.GenPathWithExt(ctx, "sysprop", syspropFile, "srcjar")
 
 	ctx.Build(pctx, android.BuildParams{
@@ -106,20 +102,38 @@
 		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 {
+		if srcFile.Ext() == ".aidl" {
+			baseDir := strings.TrimSuffix(srcFile.String(), srcFile.Rel())
+			if baseDir != "" && !android.InList(baseDir, baseDirs) {
+				baseDirs = append(baseDirs, baseDir)
+			}
+		}
+	}
+	return android.JoinWithPrefix(baseDirs, " -I")
+}
+
 func (j *Module) genSources(ctx android.ModuleContext, srcFiles android.Paths,
 	flags javaBuilderFlags) android.Paths {
 
 	outSrcFiles := make(android.Paths, 0, len(srcFiles))
 
+	aidlIncludeFlags := genAidlIncludeFlags(srcFiles)
+
 	for _, srcFile := range srcFiles {
 		switch srcFile.Ext() {
 		case ".aidl":
-			javaFile := genAidl(ctx, srcFile, flags.aidlFlags, flags.aidlDeps)
+			javaFile := genAidl(ctx, srcFile, flags.aidlFlags+aidlIncludeFlags, flags.aidlDeps)
 			outSrcFiles = append(outSrcFiles, javaFile)
 		case ".logtags":
 			j.logtagsSrcs = append(j.logtagsSrcs, srcFile)
@@ -129,7 +143,27 @@
 			srcJarFile := genProto(ctx, srcFile, flags.proto)
 			outSrcFiles = append(outSrcFiles, srcJarFile)
 		case ".sysprop":
-			srcJarFile := genSysprop(ctx, srcFile)
+			// 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 afb1218..2193a2b 100644
--- a/java/java.go
+++ b/java/java.go
@@ -183,6 +183,10 @@
 		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.
@@ -1017,7 +1021,6 @@
 }
 
 func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {
-
 	j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.deviceProperties.Aidl.Export_include_dirs)
 
 	deps := j.collectDeps(ctx)
diff --git a/java/java_test.go b/java/java_test.go
index 5fcdf96..c55e325 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -66,6 +66,7 @@
 	ctx.RegisterModuleType("android_library", android.ModuleFactoryAdaptor(AndroidLibraryFactory))
 	ctx.RegisterModuleType("android_test", android.ModuleFactoryAdaptor(AndroidTestFactory))
 	ctx.RegisterModuleType("android_test_helper_app", android.ModuleFactoryAdaptor(AndroidTestHelperAppFactory))
+	ctx.RegisterModuleType("android_test_import", android.ModuleFactoryAdaptor(AndroidTestImportFactory))
 	ctx.RegisterModuleType("java_binary", android.ModuleFactoryAdaptor(BinaryFactory))
 	ctx.RegisterModuleType("java_binary_host", android.ModuleFactoryAdaptor(BinaryHostFactory))
 	ctx.RegisterModuleType("java_device_for_host", android.ModuleFactoryAdaptor(DeviceForHostFactory))
@@ -200,6 +201,8 @@
 
 		"cert/new_cert.x509.pem": nil,
 		"cert/new_cert.pk8":      nil,
+
+		"testdata/data": nil,
 	}
 
 	for k, v := range fs {
diff --git a/java/platform_compat_config.go b/java/platform_compat_config.go
index 792edf3..f1da203 100644
--- a/java/platform_compat_config.go
+++ b/java/platform_compat_config.go
@@ -77,9 +77,11 @@
 		Class:      "ETC",
 		OutputFile: android.OptionalPathForPath(p.configFile),
 		Include:    "$(BUILD_PREBUILT)",
-		AddCustomEntries: func(name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
-			entries.SetString("LOCAL_MODULE_PATH", "$(OUT_DIR)/"+p.installDirPath.RelPathString())
-			entries.SetString("LOCAL_INSTALLED_MODULE_STEM", p.configFile.Base())
+		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+			func(entries *android.AndroidMkEntries) {
+				entries.SetString("LOCAL_MODULE_PATH", "$(OUT_DIR)/"+p.installDirPath.RelPathString())
+				entries.SetString("LOCAL_INSTALLED_MODULE_STEM", p.configFile.Base())
+			},
 		},
 	}
 }
diff --git a/java/sdk_library.go b/java/sdk_library.go
index d38088d..56b30b2 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -103,11 +103,7 @@
 	// the java library (in classpath) for documentation that provides java srcs and srcjars.
 	Srcs_lib *string
 
-	// the base dirs under srcs_lib will be scanned for java srcs.
-	Srcs_lib_whitelist_dirs []string
-
-	// the sub dirs under srcs_lib_whitelist_dirs will be scanned for java srcs.
-	// Defaults to "android.annotation".
+	// list of packages to document from srcs_lib. Defaults to "android.annotation".
 	Srcs_lib_whitelist_pkgs []string
 
 	// a list of top-level directories containing files to merge qualifier annotations
@@ -443,7 +439,6 @@
 		Srcs                             []string
 		Installable                      *bool
 		Srcs_lib                         *string
-		Srcs_lib_whitelist_dirs          []string
 		Srcs_lib_whitelist_pkgs          []string
 		Sdk_version                      *string
 		Libs                             []string
@@ -535,7 +530,6 @@
 		module.latestRemovedApiFilegroupName(apiScope))
 	props.Check_api.Ignore_missing_latest_api = proptools.BoolPtr(true)
 	props.Srcs_lib = module.sdkLibraryProperties.Srcs_lib
-	props.Srcs_lib_whitelist_dirs = module.sdkLibraryProperties.Srcs_lib_whitelist_dirs
 	props.Srcs_lib_whitelist_pkgs = module.sdkLibraryProperties.Srcs_lib_whitelist_pkgs
 
 	mctx.CreateModule(android.ModuleFactoryAdaptor(DroidstubsFactory), &props)
@@ -550,9 +544,9 @@
      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.
diff --git a/rust/androidmk.go b/rust/androidmk.go
new file mode 100644
index 0000000..c9056e1
--- /dev/null
+++ b/rust/androidmk.go
@@ -0,0 +1,155 @@
+// 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 (
+	"fmt"
+	"io"
+	"path/filepath"
+	"regexp"
+	"strings"
+
+	"android/soong/android"
+)
+
+type AndroidMkContext interface {
+	Name() string
+	Target() android.Target
+	subAndroidMk(*android.AndroidMkData, interface{})
+}
+
+type subAndroidMkProvider interface {
+	AndroidMk(AndroidMkContext, *android.AndroidMkData)
+}
+
+func (mod *Module) subAndroidMk(data *android.AndroidMkData, obj interface{}) {
+	if mod.subAndroidMkOnce == nil {
+		mod.subAndroidMkOnce = make(map[subAndroidMkProvider]bool)
+	}
+	if androidmk, ok := obj.(subAndroidMkProvider); ok {
+		if !mod.subAndroidMkOnce[androidmk] {
+			mod.subAndroidMkOnce[androidmk] = true
+			androidmk.AndroidMk(mod, data)
+		}
+	}
+}
+
+func (mod *Module) AndroidMk() android.AndroidMkData {
+	ret := android.AndroidMkData{
+		OutputFile: mod.outputFile,
+		Include:    "$(BUILD_SYSTEM)/soong_rust_prebuilt.mk",
+		Extra: []android.AndroidMkExtraFunc{
+			func(w io.Writer, outputFile android.Path) {
+				if len(mod.Properties.AndroidMkRlibs) > 0 {
+					fmt.Fprintln(w, "LOCAL_RLIB_LIBRARIES := "+strings.Join(mod.Properties.AndroidMkRlibs, " "))
+				}
+				if len(mod.Properties.AndroidMkDylibs) > 0 {
+					fmt.Fprintln(w, "LOCAL_DYLIB_LIBRARIES := "+strings.Join(mod.Properties.AndroidMkDylibs, " "))
+				}
+				if len(mod.Properties.AndroidMkProcMacroLibs) > 0 {
+					fmt.Fprintln(w, "LOCAL_PROC_MACRO_LIBRARIES := "+strings.Join(mod.Properties.AndroidMkProcMacroLibs, " "))
+				}
+				if len(mod.Properties.AndroidMkSharedLibs) > 0 {
+					fmt.Fprintln(w, "LOCAL_SHARED_LIBRARIES := "+strings.Join(mod.Properties.AndroidMkSharedLibs, " "))
+				}
+				if len(mod.Properties.AndroidMkStaticLibs) > 0 {
+					fmt.Fprintln(w, "LOCAL_STATIC_LIBRARIES := "+strings.Join(mod.Properties.AndroidMkStaticLibs, " "))
+				}
+			},
+		},
+	}
+
+	mod.subAndroidMk(&ret, mod.compiler)
+
+	return ret
+}
+
+func (binary *binaryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+	ctx.subAndroidMk(ret, binary.baseCompiler)
+
+	ret.Class = "EXECUTABLES"
+	ret.DistFile = binary.distFile
+	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
+		fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", binary.unstrippedOutputFile.String())
+	})
+}
+
+func (library *libraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+	ctx.subAndroidMk(ret, library.baseCompiler)
+
+	if library.rlib() {
+		ret.Class = "RLIB_LIBRARIES"
+	} else if library.dylib() {
+		ret.Class = "DYLIB_LIBRARIES"
+	}
+	ret.DistFile = library.distFile
+	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
+		if !library.rlib() {
+			fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", library.unstrippedOutputFile.String())
+		}
+	})
+}
+
+func (procMacro *procMacroDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+	ctx.subAndroidMk(ret, procMacro.baseCompiler)
+
+	ret.Class = "PROC_MACRO_LIBRARIES"
+	ret.DistFile = procMacro.distFile
+
+}
+
+func (compiler *baseCompiler) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+	// Soong installation is only supported for host modules. Have Make
+	// installation trigger Soong installation.
+	if ctx.Target().Os.Class == android.Host {
+		ret.OutputFile = android.OptionalPathForPath(compiler.path)
+	}
+	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
+		path := compiler.path.RelPathString()
+		dir, file := filepath.Split(path)
+		stem, suffix, _ := splitFileExt(file)
+		fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := "+suffix)
+		fmt.Fprintln(w, "LOCAL_MODULE_PATH := $(OUT_DIR)/"+filepath.Clean(dir))
+		fmt.Fprintln(w, "LOCAL_MODULE_STEM := "+stem)
+	})
+}
+
+//TODO: splitFileExt copied from cc/util.go; move this to android/util.go and refactor usages.
+
+// splitFileExt splits a file name into root, suffix and ext. root stands for the file name without
+// the file extension and the version number (e.g. "libexample"). suffix stands for the
+// concatenation of the file extension and the version number (e.g. ".so.1.0"). ext stands for the
+// file extension after the version numbers are trimmed (e.g. ".so").
+var shlibVersionPattern = regexp.MustCompile("(?:\\.\\d+(?:svn)?)+")
+
+func splitFileExt(name string) (string, string, string) {
+	// Extract and trim the shared lib version number if the file name ends with dot digits.
+	suffix := ""
+	matches := shlibVersionPattern.FindAllStringIndex(name, -1)
+	if len(matches) > 0 {
+		lastMatch := matches[len(matches)-1]
+		if lastMatch[1] == len(name) {
+			suffix = name[lastMatch[0]:lastMatch[1]]
+			name = name[0:lastMatch[0]]
+		}
+	}
+
+	// Extract the file name root and the file extension.
+	ext := filepath.Ext(name)
+	root := strings.TrimSuffix(name, ext)
+	suffix = ext + suffix
+
+	return root, suffix, ext
+}
diff --git a/rust/binary.go b/rust/binary.go
new file mode 100644
index 0000000..279c6f5
--- /dev/null
+++ b/rust/binary.go
@@ -0,0 +1,110 @@
+// 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 (
+	"android/soong/android"
+	"android/soong/rust/config"
+)
+
+func init() {
+	android.RegisterModuleType("rust_binary", RustBinaryFactory)
+	android.RegisterModuleType("rust_binary_host", RustBinaryHostFactory)
+}
+
+type BinaryCompilerProperties struct {
+	// path to the main source file that contains the program entry point (e.g. src/main.rs)
+	Srcs []string `android:"path,arch_variant"`
+
+	// passes -C prefer-dynamic to rustc, which tells it to dynamically link the stdlib (assuming it has no dylib dependencies already)
+	Prefer_dynamic *bool
+}
+
+type binaryDecorator struct {
+	*baseCompiler
+
+	Properties           BinaryCompilerProperties
+	distFile             android.OptionalPath
+	unstrippedOutputFile android.Path
+}
+
+var _ compiler = (*binaryDecorator)(nil)
+
+// rust_binary produces a binary that is runnable on a device.
+func RustBinaryFactory() android.Module {
+	module, _ := NewRustBinary(android.HostAndDeviceSupported)
+	return module.Init()
+}
+
+func RustBinaryHostFactory() android.Module {
+	module, _ := NewRustBinary(android.HostSupported)
+	return module.Init()
+}
+
+func NewRustBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecorator) {
+	module := newModule(hod, android.MultilibFirst)
+
+	binary := &binaryDecorator{
+		baseCompiler: NewBaseCompiler("bin", ""),
+	}
+
+	module.compiler = binary
+
+	return module, binary
+}
+
+func (binary *binaryDecorator) preferDynamic() bool {
+	return Bool(binary.Properties.Prefer_dynamic)
+}
+
+func (binary *binaryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags {
+	flags = binary.baseCompiler.compilerFlags(ctx, flags)
+	if binary.preferDynamic() {
+		flags.RustFlags = append(flags.RustFlags, "-C prefer-dynamic")
+	}
+	return flags
+}
+
+func (binary *binaryDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps {
+	deps = binary.baseCompiler.compilerDeps(ctx, deps)
+
+	if binary.preferDynamic() || len(deps.Dylibs) > 0 {
+		for _, stdlib := range config.Stdlibs {
+			deps.Dylibs = append(deps.Dylibs, stdlib+"_"+ctx.toolchain().RustTriple())
+		}
+	}
+
+	return deps
+}
+
+func (binary *binaryDecorator) compilerProps() []interface{} {
+	return append(binary.baseCompiler.compilerProps(),
+		&binary.Properties)
+}
+
+func (binary *binaryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path {
+	fileName := binary.getStem(ctx) + ctx.toolchain().ExecutableSuffix()
+
+	srcPath := srcPathFromModuleSrcs(ctx, binary.Properties.Srcs)
+
+	outputFile := android.PathForModuleOut(ctx, fileName)
+	binary.unstrippedOutputFile = outputFile
+
+	flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
+
+	TransformSrcToBinary(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
+
+	return outputFile
+}
diff --git a/rust/binary_test.go b/rust/binary_test.go
new file mode 100644
index 0000000..cd41fcf
--- /dev/null
+++ b/rust/binary_test.go
@@ -0,0 +1,46 @@
+// 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"
+)
+
+// Test that the prefer_dynamic property is handled correctly.
+func TestPreferDynamicBinary(t *testing.T) {
+	ctx := testRust(t, `
+		rust_binary_host {
+			name: "fizz-buzz-dynamic",
+			srcs: ["foo.rs"],
+			prefer_dynamic: true,
+		}
+
+		rust_binary_host {
+			name: "fizz-buzz",
+			srcs: ["foo.rs"],
+		}`)
+
+	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"])
+	}
+
+	if strings.Contains(fizzBuzz.Args["rustcFlags"], "prefer-dynamic") {
+		t.Errorf("unexpected prefer-dynamic flag, rustcFlags: %#v", fizzBuzz.Args["rustcFlags"])
+	}
+}
diff --git a/rust/builder.go b/rust/builder.go
new file mode 100644
index 0000000..64e387b
--- /dev/null
+++ b/rust/builder.go
@@ -0,0 +1,132 @@
+// 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"
+
+	"github.com/google/blueprint"
+
+	"android/soong/android"
+)
+
+var (
+	_     = pctx.SourcePathVariable("rustcCmd", "${config.RustBin}/rustc")
+	rustc = pctx.AndroidStaticRule("rustc",
+		blueprint.RuleParams{
+			Command: "$rustcCmd " +
+				"-C linker=${config.RustLinker} " +
+				"-C link-args=\"${config.RustLinkerArgs} ${linkFlags}\" " +
+				"-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")
+)
+
+func init() {
+
+}
+
+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)
+}
+
+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)
+}
+
+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)
+}
+
+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)
+}
+
+func rustLibsToPaths(libs RustLibraries) android.Paths {
+	var paths android.Paths
+	for _, lib := range libs {
+		paths = append(paths, lib.Path)
+	}
+	return paths
+}
+
+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) {
+
+	var inputs android.Paths
+	var deps android.Paths
+	var libFlags, rustcFlags []string
+	crate_name := ctx.(ModuleContext).CrateName()
+
+	inputs = append(inputs, main)
+
+	// Collect rustc flags
+	rustcFlags = append(rustcFlags, flags.GlobalFlags...)
+	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)
+	}
+
+	// Collect library/crate flags
+	for _, lib := range rlibs {
+		libFlags = append(libFlags, "--extern "+lib.CrateName+"="+lib.Path.String())
+	}
+	for _, lib := range dylibs {
+		libFlags = append(libFlags, "--extern "+lib.CrateName+"="+lib.Path.String())
+	}
+	for _, proc_macro := range proc_macros {
+		libFlags = append(libFlags, "--extern "+proc_macro.CrateName+"="+proc_macro.Path.String())
+	}
+
+	for _, path := range includeDirs {
+		libFlags = append(libFlags, "-L "+path)
+	}
+
+	// Collect dependencies
+	deps = append(deps, rustLibsToPaths(rlibs)...)
+	deps = append(deps, rustLibsToPaths(dylibs)...)
+	deps = append(deps, rustLibsToPaths(proc_macros)...)
+	deps = append(deps, static_libs...)
+	deps = append(deps, shared_libs...)
+
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        rustc,
+		Description: "rustc " + main.Rel(),
+		Output:      outputFile,
+		Inputs:      inputs,
+		Implicits:   deps,
+		Args: map[string]string{
+			"rustcFlags": strings.Join(rustcFlags, " "),
+			"linkFlags":  strings.Join(flags.LinkFlags, " "),
+			"libFlags":   strings.Join(libFlags, " "),
+		},
+	})
+
+}
diff --git a/rust/compiler.go b/rust/compiler.go
new file mode 100644
index 0000000..87cf08b
--- /dev/null
+++ b/rust/compiler.go
@@ -0,0 +1,193 @@
+// 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 (
+	"fmt"
+	"path/filepath"
+
+	"android/soong/android"
+	"android/soong/rust/config"
+)
+
+func NewBaseCompiler(dir, dir64 string) *baseCompiler {
+	return &baseCompiler{
+		Properties: BaseCompilerProperties{
+			Edition: &config.DefaultEdition,
+		},
+		dir:   dir,
+		dir64: dir64,
+	}
+}
+
+type BaseCompilerProperties struct {
+	// flags to pass to rustc
+	Flags []string `android:"path,arch_variant"`
+
+	// flags to pass to the linker
+	Ld_flags []string `android:"path,arch_variant"`
+
+	// list of rust rlib crate dependencies
+	Rlibs []string `android:"arch_variant"`
+
+	// list of rust dylib crate dependencies
+	Dylibs []string `android:"arch_variant"`
+
+	// list of rust proc_macro crate dependencies
+	Proc_macros []string `android:"arch_variant"`
+
+	// list of C shared library dependencies
+	Shared_libs []string `android:"arch_variant"`
+
+	// 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 string `android:"arch_variant"`
+
+	// list of features to enable for this crate
+	Features []string `android:"arch_variant"`
+
+	// specific rust edition that should be used if the default version is not desired
+	Edition *string `android:"arch_variant"`
+
+	// sets name of the output
+	Stem *string `android:"arch_variant"`
+
+	// append to name of output
+	Suffix *string `android:"arch_variant"`
+
+	// install to a subdirectory of the default install path for the module
+	Relative_install_path *string `android:"arch_variant"`
+}
+
+type baseCompiler struct {
+	Properties    BaseCompilerProperties
+	pathDeps      android.Paths
+	rustFlagsDeps android.Paths
+	linkFlagsDeps android.Paths
+	flags         string
+	linkFlags     string
+	depFlags      []string
+	linkDirs      []string
+	edition       string
+	src           android.Path //rustc takes a single src file
+
+	// Install related
+	dir      string
+	dir64    string
+	subDir   string
+	relative string
+	path     android.OutputPath
+}
+
+var _ compiler = (*baseCompiler)(nil)
+
+func (compiler *baseCompiler) compilerProps() []interface{} {
+	return []interface{}{&compiler.Properties}
+}
+
+func (compiler *baseCompiler) featuresToFlags(features []string) []string {
+	flags := []string{}
+	for _, feature := range features {
+		flags = append(flags, "--cfg 'feature=\""+feature+"\"'")
+	}
+	return flags
+}
+
+func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags) Flags {
+
+	flags.RustFlags = append(flags.RustFlags, compiler.Properties.Flags...)
+	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())
+
+	if ctx.Host() && !ctx.Windows() {
+		rpath_prefix := `\$$ORIGIN/`
+		if ctx.Darwin() {
+			rpath_prefix = "@loader_path/"
+		}
+
+		var rpath string
+		if ctx.toolchain().Is64Bit() {
+			rpath = "lib64"
+		} else {
+			rpath = "lib"
+		}
+		flags.LinkFlags = append(flags.LinkFlags, "-Wl,-rpath,"+rpath_prefix+rpath)
+		flags.LinkFlags = append(flags.LinkFlags, "-Wl,-rpath,"+rpath_prefix+"../"+rpath)
+	}
+
+	return flags
+}
+
+func (compiler *baseCompiler) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path {
+	panic(fmt.Errorf("baseCrater doesn't know how to crate things!"))
+}
+
+func (compiler *baseCompiler) compilerDeps(ctx DepsContext, deps Deps) Deps {
+	deps.Rlibs = append(deps.Rlibs, compiler.Properties.Rlibs...)
+	deps.Dylibs = append(deps.Dylibs, compiler.Properties.Dylibs...)
+	deps.ProcMacros = append(deps.ProcMacros, compiler.Properties.Proc_macros...)
+	deps.StaticLibs = append(deps.StaticLibs, compiler.Properties.Static_libs...)
+	deps.SharedLibs = append(deps.SharedLibs, compiler.Properties.Shared_libs...)
+
+	return deps
+}
+
+func (compiler *baseCompiler) crateName() string {
+	return compiler.Properties.Crate_name
+}
+
+func (compiler *baseCompiler) installDir(ctx ModuleContext) android.OutputPath {
+	dir := compiler.dir
+	if ctx.toolchain().Is64Bit() && compiler.dir64 != "" {
+		dir = compiler.dir64
+	}
+	if (!ctx.Host() && !ctx.Arch().Native) || ctx.Target().NativeBridge == android.NativeBridgeEnabled {
+		dir = filepath.Join(dir, ctx.Arch().ArchType.String())
+	}
+	return android.PathForModuleInstall(ctx, dir, compiler.subDir,
+		compiler.relativeInstallPath(), compiler.relative)
+}
+
+func (compiler *baseCompiler) install(ctx ModuleContext, file android.Path) {
+	compiler.path = ctx.InstallFile(compiler.installDir(ctx), file.Base(), file)
+}
+
+func (compiler *baseCompiler) getStem(ctx ModuleContext) string {
+	return compiler.getStemWithoutSuffix(ctx) + String(compiler.Properties.Suffix)
+}
+
+func (compiler *baseCompiler) getStemWithoutSuffix(ctx BaseModuleContext) string {
+	stem := ctx.baseModuleName()
+	if String(compiler.Properties.Stem) != "" {
+		stem = String(compiler.Properties.Stem)
+	}
+
+	return stem
+}
+func (compiler *baseCompiler) relativeInstallPath() string {
+	return String(compiler.Properties.Relative_install_path)
+}
+
+func srcPathFromModuleSrcs(ctx ModuleContext, srcs []string) android.Path {
+	srcPaths := android.PathsForModuleSrc(ctx, srcs)
+	if len(srcPaths) != 1 {
+		ctx.PropertyErrorf("srcs", "srcs can only contain one path for rust modules")
+	}
+	return srcPaths[0]
+}
diff --git a/rust/compiler_test.go b/rust/compiler_test.go
new file mode 100644
index 0000000..5369096
--- /dev/null
+++ b/rust/compiler_test.go
@@ -0,0 +1,77 @@
+// 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"
+)
+
+// Test that feature flags are being correctly generated.
+func TestFeaturesToFlags(t *testing.T) {
+	ctx := testRust(t, `
+		rust_library_host_dylib {
+			name: "libfoo",
+			srcs: ["foo.rs"],
+			crate_name: "foo",
+			features: [
+				"fizz",
+				"buzz"
+			],
+		}`)
+
+	libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc")
+
+	if !strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'feature=\"fizz\"'") ||
+		!strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'feature=\"buzz\"'") {
+		t.Fatalf("missing fizz and buzz feature flags for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"])
+	}
+}
+
+// Test that we reject multiple source files.
+func TestEnforceSingleSourceFile(t *testing.T) {
+
+	singleSrcError := "srcs can only contain one path for rust modules"
+
+	// Test libraries
+	testRustError(t, singleSrcError, `
+		rust_library_host {
+			name: "foo-bar-library",
+			srcs: ["foo.rs", "src/bar.rs"],
+		}`)
+
+	// Test binaries
+	testRustError(t, singleSrcError, `
+			rust_binary_host {
+				name: "foo-bar-binary",
+				srcs: ["foo.rs", "src/bar.rs"],
+			}`)
+
+	// Test proc_macros
+	testRustError(t, singleSrcError, `
+		rust_proc_macro {
+			name: "foo-bar-proc-macro",
+			srcs: ["foo.rs", "src/bar.rs"],
+			host_supported: true,
+		}`)
+
+	// Test prebuilts
+	testRustError(t, singleSrcError, `
+		rust_prebuilt_dylib {
+			name: "foo-bar-prebuilt",
+			srcs: ["liby.so", "libz.so"],
+		  host_supported: true,
+		}`)
+}
diff --git a/rust/config/global.go b/rust/config/global.go
new file mode 100644
index 0000000..2e08a8c
--- /dev/null
+++ b/rust/config/global.go
@@ -0,0 +1,65 @@
+// 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 (
+	"android/soong/android"
+	_ "android/soong/cc/config"
+)
+
+var pctx = android.NewPackageContext("android/soong/rust/config")
+
+var (
+	RustDefaultVersion = "1.35.0"
+	RustDefaultBase    = "prebuilts/rust/"
+	DefaultEdition     = "2018"
+	Stdlibs            = []string{
+		"libarena",
+		"libfmt_macros",
+		"libgraphviz",
+		"libserialize",
+		"libstd",
+		"libsyntax",
+		"libsyntax_ext",
+		"libsyntax_pos",
+		"libterm",
+	}
+)
+
+func init() {
+	pctx.SourcePathVariable("RustDefaultBase", RustDefaultBase)
+	pctx.VariableConfigMethod("HostPrebuiltTag", android.Config.PrebuiltOS)
+
+	pctx.VariableFunc("RustBase", func(ctx android.PackageVarContext) string {
+		if override := ctx.Config().Getenv("RUST_PREBUILTS_BASE"); override != "" {
+			return override
+		}
+		return "${RustDefaultBase}"
+	})
+
+	pctx.VariableFunc("RustVersion", func(ctx android.PackageVarContext) string {
+		if override := ctx.Config().Getenv("RUST_PREBUILTS_VERSION"); override != "" {
+			return override
+		}
+		return RustDefaultVersion
+	})
+
+	pctx.StaticVariable("RustPath", "${RustBase}/${HostPrebuiltTag}/${RustVersion}")
+	pctx.StaticVariable("RustBin", "${RustPath}/bin")
+
+	pctx.ImportAs("ccConfig", "android/soong/cc/config")
+	pctx.StaticVariable("RustLinker", "${ccConfig.ClangBin}/clang++")
+	pctx.StaticVariable("RustLinkerArgs", "-B ${ccConfig.ClangBin} -fuse-ld=lld")
+}
diff --git a/rust/config/toolchain.go b/rust/config/toolchain.go
new file mode 100644
index 0000000..a36d61b
--- /dev/null
+++ b/rust/config/toolchain.go
@@ -0,0 +1,124 @@
+// 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 (
+	"android/soong/android"
+)
+
+type Toolchain interface {
+	RustTriple() string
+	ToolchainRustFlags() string
+	ToolchainLinkFlags() string
+
+	SharedLibSuffix() string
+	StaticLibSuffix() string
+	RlibSuffix() string
+	DylibSuffix() string
+	ProcMacroSuffix() string
+	ExecutableSuffix() string
+
+	Is64Bit() bool
+	Supported() bool
+}
+
+type toolchainBase struct {
+}
+
+func (toolchainBase) RustTriple() string {
+	panic("toolchainBase does not define a triple.")
+}
+
+func (toolchainBase) ToolchainRustFlags() string {
+	panic("toolchainBase does not provide rust flags.")
+}
+
+func (toolchainBase) ToolchainLinkFlags() string {
+	panic("toolchainBase does not provide link flags.")
+}
+
+func (toolchainBase) Is64Bit() bool {
+	panic("toolchainBase cannot determine datapath width.")
+}
+
+type toolchain64Bit struct {
+	toolchainBase
+}
+
+func (toolchain64Bit) Is64Bit() bool {
+	return true
+}
+
+type toolchain32Bit struct {
+	toolchainBase
+}
+
+func (toolchain32Bit) Is64Bit() bool {
+	return false
+}
+
+func (toolchain32Bit) Bionic() bool {
+	return true
+}
+
+func (toolchainBase) ExecutableSuffix() string {
+	return ""
+}
+
+func (toolchainBase) SharedLibSuffix() string {
+	return ".so"
+}
+
+func (toolchainBase) StaticLibSuffix() string {
+	return ".a"
+}
+
+func (toolchainBase) RlibSuffix() string {
+	return ".rlib"
+}
+func (toolchainBase) DylibSuffix() string {
+	return ".so"
+}
+
+func (toolchainBase) ProcMacroSuffix() string {
+	return ".so"
+}
+
+func (toolchainBase) Supported() bool {
+	return false
+}
+
+func toolchainBaseFactory() Toolchain {
+	return &toolchainBase{}
+}
+
+type toolchainFactory func(arch android.Arch) Toolchain
+
+var toolchainFactories = make(map[android.OsType]map[android.ArchType]toolchainFactory)
+
+func registerToolchainFactory(os android.OsType, arch android.ArchType, factory toolchainFactory) {
+	if toolchainFactories[os] == nil {
+		toolchainFactories[os] = make(map[android.ArchType]toolchainFactory)
+	}
+	toolchainFactories[os][arch] = factory
+}
+
+func FindToolchain(os android.OsType, arch android.Arch) Toolchain {
+	factory := toolchainFactories[os][arch.ArchType]
+	if factory == nil {
+		return toolchainBaseFactory()
+	}
+	return factory(arch)
+}
diff --git a/rust/config/x86_64_device.go b/rust/config/x86_64_device.go
new file mode 100644
index 0000000..2aca56a
--- /dev/null
+++ b/rust/config/x86_64_device.go
@@ -0,0 +1,88 @@
+// 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 (
+	x86_64RustFlags            = []string{}
+	x86_64ArchFeatureRustFlags = map[string][]string{}
+	x86_64LinkFlags            = []string{}
+
+	x86_64ArchVariantRustFlags = map[string][]string{
+		"":            []string{},
+		"broadwell":   []string{"-C target-cpu=broadwell"},
+		"haswell":     []string{"-C target-cpu=haswell"},
+		"ivybridge":   []string{"-C target-cpu=ivybridge"},
+		"sandybridge": []string{"-C target-cpu=sandybridge"},
+		"silvermont":  []string{"-C target-cpu=silvermont"},
+		"skylake":     []string{"-C target-cpu=skylake"},
+		//TODO: Add target-cpu=stoneyridge when rustc supports it.
+		"stoneyridge": []string{""},
+	}
+)
+
+func init() {
+	registerToolchainFactory(android.Android, android.X86_64, x86_64ToolchainFactory)
+
+	pctx.StaticVariable("x86_64ToolchainRustFlags", strings.Join(x86_64RustFlags, " "))
+	pctx.StaticVariable("x86_64ToolchainLinkFlags", strings.Join(x86_64LinkFlags, " "))
+
+	for variant, rustFlags := range x86_64ArchVariantRustFlags {
+		pctx.StaticVariable("X86_64"+variant+"VariantRustFlags",
+			strings.Join(rustFlags, " "))
+	}
+
+}
+
+type toolchainX86_64 struct {
+	toolchain64Bit
+	toolchainRustFlags string
+}
+
+func (t *toolchainX86_64) RustTriple() string {
+	return "x86_64-unknown-linux-gnu"
+}
+
+func (t *toolchainX86_64) ToolchainLinkFlags() string {
+	return "${config.x86_64ToolchainLinkFlags}"
+}
+
+func (t *toolchainX86_64) ToolchainRustFlags() string {
+	return t.toolchainRustFlags
+}
+
+func (t *toolchainX86_64) RustFlags() string {
+	return "${config.x86_64ToolchainRustFlags}"
+}
+
+func x86_64ToolchainFactory(arch android.Arch) Toolchain {
+	toolchainRustFlags := []string{
+		"${config.x86_64ToolchainRustFlags}",
+		"${config.X86_64" + arch.ArchVariant + "VariantRustFlags}",
+	}
+
+	for _, feature := range arch.ArchFeatures {
+		toolchainRustFlags = append(toolchainRustFlags, x86_64ArchFeatureRustFlags[feature]...)
+	}
+
+	return &toolchainX86_64{
+		toolchainRustFlags: strings.Join(toolchainRustFlags, " "),
+	}
+}
diff --git a/rust/config/x86_linux_host.go b/rust/config/x86_linux_host.go
new file mode 100644
index 0000000..cb6bf1a
--- /dev/null
+++ b/rust/config/x86_linux_host.go
@@ -0,0 +1,109 @@
+// 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 (
+	LinuxRustFlags      = []string{}
+	LinuxRustLinkFlags  = []string{}
+	linuxX86Rustflags   = []string{}
+	linuxX86Linkflags   = []string{}
+	linuxX8664Rustflags = []string{}
+	linuxX8664Linkflags = []string{}
+)
+
+func init() {
+	registerToolchainFactory(android.Linux, android.X86_64, linuxX8664ToolchainFactory)
+	registerToolchainFactory(android.Linux, android.X86, linuxX86ToolchainFactory)
+
+	pctx.StaticVariable("LinuxToolchainRustFlags", strings.Join(LinuxRustFlags, " "))
+	pctx.StaticVariable("LinuxToolchainLinkFlags", strings.Join(LinuxRustLinkFlags, " "))
+	pctx.StaticVariable("LinuxToolchainX86RustFlags", strings.Join(linuxX86Rustflags, " "))
+	pctx.StaticVariable("LinuxToolchainX86LinkFlags", strings.Join(linuxX86Linkflags, " "))
+	pctx.StaticVariable("LinuxToolchainX8664RustFlags", strings.Join(linuxX8664Rustflags, " "))
+	pctx.StaticVariable("LinuxToolchainX8664LinkFlags", strings.Join(linuxX8664Linkflags, " "))
+
+}
+
+type toolchainLinux struct {
+	toolchainRustFlags string
+	toolchainLinkFlags string
+}
+
+type toolchainLinuxX86 struct {
+	toolchain32Bit
+	toolchainLinux
+}
+
+type toolchainLinuxX8664 struct {
+	toolchain64Bit
+	toolchainLinux
+}
+
+func (toolchainLinuxX8664) Supported() bool {
+	return true
+}
+
+func (t *toolchainLinuxX8664) Name() string {
+	return "x86_64"
+}
+
+func (t *toolchainLinuxX8664) RustTriple() string {
+	return "x86_64-unknown-linux-gnu"
+}
+
+func (t *toolchainLinuxX8664) ToolchainLinkFlags() string {
+	return "${config.LinuxToolchainLinkFlags} ${config.LinuxToolchainX8664LinkFlags}"
+}
+
+func (t *toolchainLinuxX8664) ToolchainRustFlags() string {
+	return "${config.LinuxToolchainRustFlags} ${config.LinuxToolchainX8664RustFlags}"
+}
+
+func linuxX8664ToolchainFactory(arch android.Arch) Toolchain {
+	return toolchainLinuxX8664Singleton
+}
+
+func (toolchainLinuxX86) Supported() bool {
+	return true
+}
+
+func (t *toolchainLinuxX86) Name() string {
+	return "x86"
+}
+
+func (t *toolchainLinuxX86) RustTriple() string {
+	return "i686-unknown-linux-gnu"
+}
+
+func (t *toolchainLinuxX86) ToolchainLinkFlags() string {
+	return "${config.LinuxToolchainLinkFlags} ${config.LinuxToolchainX86LinkFlags}"
+}
+
+func (t *toolchainLinuxX86) ToolchainRustFlags() string {
+	return "${config.LinuxToolchainRustFlags} ${config.LinuxToolchainX86RustFlags}"
+}
+
+func linuxX86ToolchainFactory(arch android.Arch) Toolchain {
+	return toolchainLinuxX86Singleton
+}
+
+var toolchainLinuxX8664Singleton Toolchain = &toolchainLinuxX8664{}
+var toolchainLinuxX86Singleton Toolchain = &toolchainLinuxX86{}
diff --git a/rust/library.go b/rust/library.go
new file mode 100644
index 0000000..5cf8ac7
--- /dev/null
+++ b/rust/library.go
@@ -0,0 +1,245 @@
+// 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 (
+	"android/soong/android"
+)
+
+func init() {
+	android.RegisterModuleType("rust_library", RustLibraryFactory)
+	android.RegisterModuleType("rust_library_dylib", RustLibraryDylibFactory)
+	android.RegisterModuleType("rust_library_rlib", RustLibraryRlibFactory)
+	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.
+}
+
+type VariantLibraryProperties struct {
+	Enabled *bool `android:"arch_variant"`
+}
+
+type LibraryCompilerProperties struct {
+	Rlib  VariantLibraryProperties `android:"arch_variant"`
+	Dylib 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"`
+}
+
+type LibraryMutatedProperties struct {
+	VariantName string `blueprint:"mutated"`
+
+	// Build a dylib variant
+	BuildDylib bool `blueprint:"mutated"`
+	// Build an rlib variant
+	BuildRlib bool `blueprint:"mutated"`
+
+	// This variant is a dylib
+	VariantIsDylib bool `blueprint:"mutated"`
+	// This variant is an rlib
+	VariantIsRlib bool `blueprint:"mutated"`
+}
+
+type libraryDecorator struct {
+	*baseCompiler
+
+	Properties           LibraryCompilerProperties
+	MutatedProperties    LibraryMutatedProperties
+	distFile             android.OptionalPath
+	unstrippedOutputFile android.Path
+}
+
+type libraryInterface interface {
+	rlib() bool
+	dylib() bool
+
+	// Returns true if the build options for the module have selected a particular build type
+	buildRlib() bool
+	buildDylib() bool
+
+	// Sets a particular variant type
+	setRlib()
+	setDylib()
+}
+
+func (library *libraryDecorator) exportedDirs() []string {
+	return library.linkDirs
+}
+
+func (library *libraryDecorator) exportedDepFlags() []string {
+	return library.depFlags
+}
+
+func (library *libraryDecorator) reexportDirs(dirs ...string) {
+	library.linkDirs = android.FirstUniqueStrings(append(library.linkDirs, dirs...))
+}
+
+func (library *libraryDecorator) reexportDepFlags(flags ...string) {
+	library.depFlags = android.FirstUniqueStrings(append(library.depFlags, flags...))
+}
+
+func (library *libraryDecorator) rlib() bool {
+	return library.MutatedProperties.VariantIsRlib
+}
+
+func (library *libraryDecorator) dylib() bool {
+	return library.MutatedProperties.VariantIsDylib
+}
+
+func (library *libraryDecorator) buildRlib() bool {
+	return library.MutatedProperties.BuildRlib && BoolDefault(library.Properties.Rlib.Enabled, true)
+}
+
+func (library *libraryDecorator) buildDylib() bool {
+	return library.MutatedProperties.BuildDylib && BoolDefault(library.Properties.Dylib.Enabled, true)
+}
+
+func (library *libraryDecorator) setRlib() {
+	library.MutatedProperties.VariantIsRlib = true
+	library.MutatedProperties.VariantIsDylib = false
+}
+
+func (library *libraryDecorator) setDylib() {
+	library.MutatedProperties.VariantIsRlib = false
+	library.MutatedProperties.VariantIsDylib = true
+}
+
+var _ compiler = (*libraryDecorator)(nil)
+
+// rust_library produces all variants.
+func RustLibraryFactory() android.Module {
+	module, _ := NewRustLibrary(android.HostAndDeviceSupported)
+	return module.Init()
+}
+
+// rust_library_dylib produces a dylib.
+func RustLibraryDylibFactory() android.Module {
+	module, library := NewRustLibrary(android.HostAndDeviceSupported)
+	library.BuildOnlyDylib()
+	return module.Init()
+}
+
+// rust_library_rlib produces an rlib.
+func RustLibraryRlibFactory() android.Module {
+	module, library := NewRustLibrary(android.HostAndDeviceSupported)
+	library.BuildOnlyRlib()
+	return module.Init()
+}
+
+// rust_library_host produces all variants.
+func RustLibraryHostFactory() android.Module {
+	module, _ := NewRustLibrary(android.HostSupported)
+	return module.Init()
+}
+
+// rust_library_dylib_host produces a dylib.
+func RustLibraryDylibHostFactory() android.Module {
+	module, library := NewRustLibrary(android.HostSupported)
+	library.BuildOnlyDylib()
+	return module.Init()
+}
+
+// rust_library_rlib_host produces an rlib.
+func RustLibraryRlibHostFactory() android.Module {
+	module, library := NewRustLibrary(android.HostSupported)
+	library.BuildOnlyRlib()
+	return module.Init()
+}
+
+func (library *libraryDecorator) BuildOnlyDylib() {
+	library.MutatedProperties.BuildRlib = false
+}
+
+func (library *libraryDecorator) BuildOnlyRlib() {
+	library.MutatedProperties.BuildDylib = false
+}
+
+func NewRustLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorator) {
+	module := newModule(hod, android.MultilibFirst)
+
+	library := &libraryDecorator{
+		MutatedProperties: LibraryMutatedProperties{
+			BuildDylib: true,
+			BuildRlib:  true,
+		},
+		baseCompiler: NewBaseCompiler("lib", "lib64"),
+	}
+
+	module.compiler = library
+
+	return module, library
+}
+
+func (library *libraryDecorator) compilerProps() []interface{} {
+	return append(library.baseCompiler.compilerProps(),
+		&library.Properties,
+		&library.MutatedProperties)
+}
+
+func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path {
+	var outputFile android.WritablePath
+
+	srcPath := srcPathFromModuleSrcs(ctx, library.Properties.Srcs)
+
+	flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
+
+	if library.rlib() {
+		fileName := library.getStem(ctx) + ctx.toolchain().RlibSuffix()
+		outputFile = android.PathForModuleOut(ctx, fileName)
+
+		TransformSrctoRlib(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
+	} else if library.dylib() {
+		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)
+	}
+
+	library.reexportDirs(deps.linkDirs...)
+	library.reexportDepFlags(deps.depFlags...)
+	library.unstrippedOutputFile = outputFile
+
+	return outputFile
+}
+
+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()
+			}
+		}
+	}
+}
diff --git a/rust/library_test.go b/rust/library_test.go
new file mode 100644
index 0000000..bf8643e
--- /dev/null
+++ b/rust/library_test.go
@@ -0,0 +1,61 @@
+// 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"
+)
+
+// Test that variants are being generated correctly, and that crate-types are correct.
+func TestLibraryVariants(t *testing.T) {
+
+	ctx := testRust(t, `
+		rust_library_host {
+			name: "libfoo",
+			srcs: ["foo.rs"],
+			crate_name: "foo",
+		}`)
+
+	// Test both 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")
+
+	// 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"])
+	}
+
+	// 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"])
+	}
+}
+
+// Test that dylibs are not statically linking the standard library.
+func TestDylibPreferDynamic(t *testing.T) {
+	ctx := testRust(t, `
+		rust_library_host_dylib {
+			name: "libfoo",
+			srcs: ["foo.rs"],
+			crate_name: "foo",
+		}`)
+
+	libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Output("libfoo.so")
+
+	if !strings.Contains(libfooDylib.Args["rustcFlags"], "prefer-dynamic") {
+		t.Errorf("missing prefer-dynamic flag for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"])
+	}
+}
diff --git a/rust/prebuilt.go b/rust/prebuilt.go
new file mode 100644
index 0000000..d4e631b
--- /dev/null
+++ b/rust/prebuilt.go
@@ -0,0 +1,65 @@
+// 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 (
+	"android/soong/android"
+)
+
+func init() {
+	android.RegisterModuleType("rust_prebuilt_dylib", PrebuiltDylibFactory)
+}
+
+type PrebuiltProperties struct {
+	// path to the prebuilt file
+	Srcs []string `android:"path,arch_variant"`
+}
+
+type prebuiltLibraryDecorator struct {
+	*libraryDecorator
+	Properties PrebuiltProperties
+}
+
+var _ compiler = (*prebuiltLibraryDecorator)(nil)
+
+func PrebuiltDylibFactory() android.Module {
+	module, _ := NewPrebuiltDylib(android.HostAndDeviceSupported)
+	return module.Init()
+}
+
+func NewPrebuiltDylib(hod android.HostOrDeviceSupported) (*Module, *prebuiltLibraryDecorator) {
+	module, library := NewRustLibrary(hod)
+	library.BuildOnlyDylib()
+	library.setDylib()
+	prebuilt := &prebuiltLibraryDecorator{
+		libraryDecorator: library,
+	}
+	module.compiler = prebuilt
+	module.AddProperties(&library.Properties)
+	return module, prebuilt
+}
+
+func (prebuilt *prebuiltLibraryDecorator) compilerProps() []interface{} {
+	return append(prebuilt.baseCompiler.compilerProps(),
+		&prebuilt.Properties)
+}
+
+func (prebuilt *prebuiltLibraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path {
+	srcPath := srcPathFromModuleSrcs(ctx, prebuilt.Properties.Srcs)
+
+	prebuilt.unstrippedOutputFile = srcPath
+
+	return srcPath
+}
diff --git a/rust/proc_macro.go b/rust/proc_macro.go
new file mode 100644
index 0000000..4acb06f
--- /dev/null
+++ b/rust/proc_macro.go
@@ -0,0 +1,79 @@
+// 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 (
+	"android/soong/android"
+)
+
+func init() {
+	android.RegisterModuleType("rust_proc_macro", ProcMacroFactory)
+}
+
+type ProcMacroCompilerProperties struct {
+	// 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"`
+
+	// set name of the procMacro
+	Stem   *string `android:"arch_variant"`
+	Suffix *string `android:"arch_variant"`
+}
+
+type procMacroDecorator struct {
+	*baseCompiler
+
+	Properties           ProcMacroCompilerProperties
+	distFile             android.OptionalPath
+	unstrippedOutputFile android.Path
+}
+
+type procMacroInterface interface {
+}
+
+var _ compiler = (*procMacroDecorator)(nil)
+
+func ProcMacroFactory() android.Module {
+	module, _ := NewProcMacro(android.HostAndDeviceSupported)
+	return module.Init()
+}
+
+func NewProcMacro(hod android.HostOrDeviceSupported) (*Module, *procMacroDecorator) {
+	module := newModule(hod, android.MultilibFirst)
+
+	procMacro := &procMacroDecorator{
+		baseCompiler: NewBaseCompiler("lib", "lib64"),
+	}
+
+	module.compiler = procMacro
+
+	return module, procMacro
+}
+
+func (procMacro *procMacroDecorator) compilerProps() []interface{} {
+	return append(procMacro.baseCompiler.compilerProps(),
+		&procMacro.Properties)
+}
+
+func (procMacro *procMacroDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path {
+	fileName := procMacro.getStem(ctx) + ctx.toolchain().ProcMacroSuffix()
+	outputFile := android.PathForModuleOut(ctx, fileName)
+
+	srcPath := srcPathFromModuleSrcs(ctx, procMacro.Properties.Srcs)
+
+	procMacro.unstrippedOutputFile = outputFile
+
+	TransformSrctoProcMacro(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
+	return outputFile
+}
diff --git a/rust/rust.go b/rust/rust.go
new file mode 100644
index 0000000..5a2514e
--- /dev/null
+++ b/rust/rust.go
@@ -0,0 +1,498 @@
+// 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"
+
+	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
+
+	"android/soong/android"
+	"android/soong/cc"
+	"android/soong/rust/config"
+)
+
+var pctx = android.NewPackageContext("android/soong/rust")
+
+func init() {
+	// Only allow rust modules to be defined for certain projects
+	rustModuleTypes := []string{
+		"rust_binary",
+		"rust_binary_host",
+		"rust_library",
+		"rust_library_dylib",
+		"rust_library_rlib",
+		"rust_library_host",
+		"rust_library_host_dylib",
+		"rust_library_host_rlib",
+		"rust_proc_macro",
+	}
+
+	rustAllowedPaths := []string{
+		"external/rust/crates",
+		"external/crosvm",
+		"external/adhd",
+	}
+
+	android.AddNeverAllowRules(
+		android.NeverAllow().
+			NotIn(rustAllowedPaths...).
+			ModuleType(rustModuleTypes...))
+
+	android.RegisterModuleType("rust_defaults", defaultsFactory)
+	android.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
+		ctx.BottomUp("rust_libraries", LibraryMutator).Parallel()
+	})
+	pctx.Import("android/soong/rust/config")
+}
+
+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
+}
+
+type BaseProperties struct {
+	AndroidMkRlibs         []string
+	AndroidMkDylibs        []string
+	AndroidMkProcMacroLibs []string
+	AndroidMkSharedLibs    []string
+	AndroidMkStaticLibs    []string
+}
+
+type Module struct {
+	android.ModuleBase
+	android.DefaultableModuleBase
+
+	Properties BaseProperties
+
+	hod      android.HostOrDeviceSupported
+	multilib android.Multilib
+
+	compiler         compiler
+	cachedToolchain  config.Toolchain
+	subAndroidMkOnce map[subAndroidMkProvider]bool
+	outputFile       android.OptionalPath
+}
+
+type Deps struct {
+	Dylibs     []string
+	Rlibs      []string
+	ProcMacros []string
+	SharedLibs []string
+	StaticLibs []string
+
+	CrtBegin, CrtEnd string
+}
+
+type PathDeps struct {
+	DyLibs     RustLibraries
+	RLibs      RustLibraries
+	SharedLibs android.Paths
+	StaticLibs android.Paths
+	ProcMacros RustLibraries
+	linkDirs   []string
+	depFlags   []string
+	//ReexportedDeps android.Paths
+}
+
+type RustLibraries []RustLibrary
+
+type RustLibrary struct {
+	Path      android.Path
+	CrateName string
+}
+
+type compiler interface {
+	compilerFlags(ctx ModuleContext, flags Flags) Flags
+	compilerProps() []interface{}
+	compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path
+	compilerDeps(ctx DepsContext, deps Deps) Deps
+	crateName() string
+
+	install(ctx ModuleContext, path android.Path)
+	relativeInstallPath() string
+}
+
+func defaultsFactory() android.Module {
+	return DefaultsFactory()
+}
+
+type Defaults struct {
+	android.ModuleBase
+	android.DefaultsModuleBase
+}
+
+func DefaultsFactory(props ...interface{}) android.Module {
+	module := &Defaults{}
+
+	module.AddProperties(props...)
+	module.AddProperties(
+		&BaseProperties{},
+		&BaseCompilerProperties{},
+		&BinaryCompilerProperties{},
+		&LibraryCompilerProperties{},
+		&ProcMacroCompilerProperties{},
+		&PrebuiltProperties{},
+	)
+
+	android.InitDefaultsModule(module)
+	return module
+}
+
+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)
+}
+
+func (mod *Module) Init() android.Module {
+	mod.AddProperties(&mod.Properties)
+
+	if mod.compiler != nil {
+		mod.AddProperties(mod.compiler.compilerProps()...)
+	}
+	android.InitAndroidArchModule(mod, mod.hod, mod.multilib)
+
+	android.InitDefaultableModule(mod)
+
+	return mod
+}
+
+func newBaseModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Module {
+	return &Module{
+		hod:      hod,
+		multilib: multilib,
+	}
+}
+func newModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Module {
+	module := newBaseModule(hod, multilib)
+	return module
+}
+
+type ModuleContext interface {
+	android.ModuleContext
+	ModuleContextIntf
+}
+
+type BaseModuleContext interface {
+	android.BaseModuleContext
+	ModuleContextIntf
+}
+
+type DepsContext interface {
+	android.BottomUpMutatorContext
+	ModuleContextIntf
+}
+
+type ModuleContextIntf interface {
+	toolchain() config.Toolchain
+	baseModuleName() string
+	CrateName() string
+}
+
+type depsContext struct {
+	android.BottomUpMutatorContext
+	moduleContextImpl
+}
+
+type moduleContext struct {
+	android.ModuleContext
+	moduleContextImpl
+}
+
+type moduleContextImpl struct {
+	mod *Module
+	ctx BaseModuleContext
+}
+
+func (ctx *moduleContextImpl) toolchain() config.Toolchain {
+	return ctx.mod.toolchain(ctx.ctx)
+}
+
+func (mod *Module) toolchain(ctx android.BaseModuleContext) config.Toolchain {
+	if mod.cachedToolchain == nil {
+		mod.cachedToolchain = config.FindToolchain(ctx.Os(), ctx.Arch())
+	}
+	return mod.cachedToolchain
+}
+
+func (d *Defaults) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+}
+
+func (mod *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
+	ctx := &moduleContext{
+		ModuleContext: actx,
+		moduleContextImpl: moduleContextImpl{
+			mod: mod,
+		},
+	}
+	ctx.ctx = ctx
+
+	toolchain := mod.toolchain(ctx)
+
+	if !toolchain.Supported() {
+		// This toolchain's unsupported, there's nothing to do for this mod.
+		return
+	}
+
+	deps := mod.depsToPaths(ctx)
+	flags := Flags{
+		Toolchain: toolchain,
+	}
+
+	if mod.compiler != nil {
+		flags = mod.compiler.compilerFlags(ctx, flags)
+		outputFile := mod.compiler.compile(ctx, flags, deps)
+		mod.outputFile = android.OptionalPathForPath(outputFile)
+		mod.compiler.install(ctx, mod.outputFile.Path())
+	}
+}
+
+func (mod *Module) deps(ctx DepsContext) Deps {
+	deps := Deps{}
+
+	if mod.compiler != nil {
+		deps = mod.compiler.compilerDeps(ctx, deps)
+	}
+
+	deps.Rlibs = android.LastUniqueStrings(deps.Rlibs)
+	deps.Dylibs = android.LastUniqueStrings(deps.Dylibs)
+	deps.ProcMacros = android.LastUniqueStrings(deps.ProcMacros)
+	deps.SharedLibs = android.LastUniqueStrings(deps.SharedLibs)
+	deps.StaticLibs = android.LastUniqueStrings(deps.StaticLibs)
+
+	return deps
+
+}
+
+func (ctx *moduleContextImpl) baseModuleName() string {
+	return ctx.mod.ModuleBase.BaseModuleName()
+}
+
+func (ctx *moduleContextImpl) CrateName() string {
+	return ctx.mod.CrateName()
+}
+
+type dependencyTag struct {
+	blueprint.BaseDependencyTag
+	name       string
+	library    bool
+	proc_macro bool
+}
+
+var (
+	rlibDepTag      = dependencyTag{name: "rlibTag", library: true}
+	dylibDepTag     = dependencyTag{name: "dylib", library: true}
+	procMacroDepTag = dependencyTag{name: "procMacro", proc_macro: true}
+)
+
+func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
+	var depPaths PathDeps
+
+	directRlibDeps := []*Module{}
+	directDylibDeps := []*Module{}
+	directProcMacroDeps := []*Module{}
+	directSharedLibDeps := []*(cc.Module){}
+	directStaticLibDeps := []*(cc.Module){}
+
+	ctx.VisitDirectDeps(func(dep android.Module) {
+		depName := ctx.OtherModuleName(dep)
+		depTag := ctx.OtherModuleDependencyTag(dep)
+		if dep.Target().Os != ctx.Os() {
+			ctx.ModuleErrorf("OS mismatch between %q and %q", ctx.ModuleName(), depName)
+			return
+		}
+		if dep.Target().Arch.ArchType != ctx.Arch().ArchType {
+			ctx.ModuleErrorf("Arch mismatch between %q and %q", ctx.ModuleName(), depName)
+			return
+		}
+
+		if rustDep, ok := dep.(*Module); ok {
+			//Handle Rust Modules
+			linkFile := rustDep.outputFile
+			if !linkFile.Valid() {
+				ctx.ModuleErrorf("Invalid output file when adding dep %q to %q", depName, ctx.ModuleName())
+			}
+
+			switch depTag {
+			case dylibDepTag:
+				dylib, ok := rustDep.compiler.(libraryInterface)
+				if !ok || !dylib.dylib() {
+					ctx.ModuleErrorf("mod %q not an dylib library", depName)
+					return
+				}
+				directDylibDeps = append(directDylibDeps, rustDep)
+				mod.Properties.AndroidMkDylibs = append(mod.Properties.AndroidMkDylibs, depName)
+			case rlibDepTag:
+				rlib, ok := rustDep.compiler.(libraryInterface)
+				if !ok || !rlib.rlib() {
+					ctx.ModuleErrorf("mod %q not an rlib library", depName)
+					return
+				}
+				directRlibDeps = append(directRlibDeps, rustDep)
+				mod.Properties.AndroidMkRlibs = append(mod.Properties.AndroidMkRlibs, depName)
+			case procMacroDepTag:
+				directProcMacroDeps = append(directProcMacroDeps, rustDep)
+				mod.Properties.AndroidMkProcMacroLibs = append(mod.Properties.AndroidMkProcMacroLibs, depName)
+			}
+
+			//Append the dependencies exportedDirs
+			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
+			// This can be probably be refactored by defining a common exporter interface similar to cc's
+			if depTag == dylibDepTag || depTag == rlibDepTag || depTag == procMacroDepTag {
+				linkDir := linkPathFromFilePath(linkFile.Path())
+				if lib, ok := mod.compiler.(*libraryDecorator); ok {
+					lib.linkDirs = append(lib.linkDirs, linkDir)
+				} else if procMacro, ok := mod.compiler.(*procMacroDecorator); ok {
+					procMacro.linkDirs = append(procMacro.linkDirs, linkDir)
+				}
+			}
+
+		} else if ccDep, ok := dep.(*cc.Module); ok {
+
+			//Handle C dependencies
+			linkFile := ccDep.OutputFile()
+			linkPath := linkPathFromFilePath(linkFile.Path())
+			libName := libNameFromFilePath(linkFile.Path())
+			if !linkFile.Valid() {
+				ctx.ModuleErrorf("Invalid output file when adding dep %q to %q", depName, ctx.ModuleName())
+			}
+
+			exportDep := false
+
+			switch depTag {
+			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():
+				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
+			}
+
+			// Make sure these dependencies are propagated
+			if lib, ok := mod.compiler.(*libraryDecorator); ok && (exportDep || lib.rlib()) {
+				lib.linkDirs = append(lib.linkDirs, linkPath)
+				lib.depFlags = append(lib.depFlags, "-l"+libName)
+			} else if procMacro, ok := mod.compiler.(*procMacroDecorator); ok && exportDep {
+				procMacro.linkDirs = append(procMacro.linkDirs, linkPath)
+				procMacro.depFlags = append(procMacro.depFlags, "-l"+libName)
+			}
+
+		}
+	})
+
+	var rlibDepFiles RustLibraries
+	for _, dep := range directRlibDeps {
+		rlibDepFiles = append(rlibDepFiles, RustLibrary{Path: dep.outputFile.Path(), CrateName: dep.CrateName()})
+	}
+	var dylibDepFiles RustLibraries
+	for _, dep := range directDylibDeps {
+		dylibDepFiles = append(dylibDepFiles, RustLibrary{Path: dep.outputFile.Path(), CrateName: dep.CrateName()})
+	}
+	var procMacroDepFiles RustLibraries
+	for _, dep := range directProcMacroDeps {
+		procMacroDepFiles = append(procMacroDepFiles, RustLibrary{Path: dep.outputFile.Path(), CrateName: dep.CrateName()})
+	}
+
+	var staticLibDepFiles android.Paths
+	for _, dep := range directStaticLibDeps {
+		staticLibDepFiles = append(staticLibDepFiles, dep.OutputFile().Path())
+	}
+
+	var sharedLibDepFiles android.Paths
+	for _, dep := range directSharedLibDeps {
+		sharedLibDepFiles = append(sharedLibDepFiles, dep.OutputFile().Path())
+	}
+
+	depPaths.RLibs = append(depPaths.RLibs, rlibDepFiles...)
+	depPaths.DyLibs = append(depPaths.DyLibs, dylibDepFiles...)
+	depPaths.SharedLibs = append(depPaths.SharedLibs, sharedLibDepFiles...)
+	depPaths.StaticLibs = append(depPaths.StaticLibs, staticLibDepFiles...)
+	depPaths.ProcMacros = append(depPaths.ProcMacros, procMacroDepFiles...)
+
+	// Dedup exported flags from dependencies
+	depPaths.linkDirs = android.FirstUniqueStrings(depPaths.linkDirs)
+	depPaths.depFlags = android.FirstUniqueStrings(depPaths.depFlags)
+
+	return depPaths
+}
+
+func linkPathFromFilePath(filepath android.Path) string {
+	return strings.Split(filepath.String(), filepath.Base())[0]
+}
+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]
+	}
+	return libName
+}
+func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) {
+	ctx := &depsContext{
+		BottomUpMutatorContext: actx,
+		moduleContextImpl: moduleContextImpl{
+			mod: mod,
+		},
+	}
+	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: ""})
+	if !mod.Host() {
+		ccDepVariations = append(ccDepVariations, 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.AddDependency(mod, procMacroDepTag, deps.ProcMacros...)
+}
+
+func (mod *Module) Name() string {
+	name := mod.ModuleBase.Name()
+	if p, ok := mod.compiler.(interface {
+		Name(string) string
+	}); ok {
+		name = p.Name(name)
+	}
+	return name
+}
+
+var Bool = proptools.Bool
+var BoolDefault = proptools.BoolDefault
+var String = proptools.String
+var StringPtr = proptools.StringPtr
diff --git a/rust/rust_test.go b/rust/rust_test.go
new file mode 100644
index 0000000..c68cfe7
--- /dev/null
+++ b/rust/rust_test.go
@@ -0,0 +1,167 @@
+// 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 (
+	"io/ioutil"
+	"os"
+	"testing"
+
+	"android/soong/android"
+)
+
+var (
+	buildDir string
+)
+
+func setUp() {
+	var err error
+	buildDir, err = ioutil.TempDir("", "soong_rust_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())
+}
+
+func testRust(t *testing.T, bp string) *android.TestContext {
+	t.Helper()
+	config := android.TestArchConfig(buildDir, nil)
+
+	t.Helper()
+	ctx := CreateTestContext(bp)
+	ctx.Register()
+
+	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+	android.FailIfErrored(t, errs)
+	_, errs = ctx.PrepareBuildActions(config)
+	android.FailIfErrored(t, errs)
+
+	return ctx
+}
+
+func testRustError(t *testing.T, pattern string, bp string) {
+	t.Helper()
+	config := android.TestArchConfig(buildDir, nil)
+
+	ctx := CreateTestContext(bp)
+	ctx.Register()
+
+	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+	if len(errs) > 0 {
+		android.FailIfNoMatchingErrors(t, pattern, errs)
+		return
+	}
+
+	_, errs = ctx.PrepareBuildActions(config)
+	if len(errs) > 0 {
+		android.FailIfNoMatchingErrors(t, pattern, errs)
+		return
+	}
+
+	t.Fatalf("missing expected error %q (0 errors are returned)", pattern)
+}
+
+// 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"
+
+	if libName != expectedResult {
+		t.Errorf("libNameFromFilePath returned the wrong name; expected '%#v', got '%#v'", expectedResult, libName)
+	}
+}
+
+// Test that we can extract the link path from a lib path.
+func TestLinkPathFromFilePath(t *testing.T) {
+	barPath := android.PathForTesting("out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/libbar.so")
+	libName := linkPathFromFilePath(barPath)
+	expectedResult := "out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/"
+
+	if libName != expectedResult {
+		t.Errorf("libNameFromFilePath returned the wrong name; expected '%#v', got '%#v'", expectedResult, libName)
+	}
+}
+
+// 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",
+			srcs: ["foo.rs"],
+		}
+		rust_library_host_rlib {
+			name: "libbar",
+			srcs: ["foo.rs"],
+		}
+		rust_proc_macro {
+			name: "libpm",
+			srcs: ["foo.rs"],
+			host_supported: true,
+		}
+		rust_binary_host {
+			name: "fizz-buzz",
+			dylibs: ["libfoo"],
+			rlibs: ["libbar"],
+			proc_macros: ["libpm"],
+			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) {
+		t.Errorf("Dylib dependency not detected (dependency missing from AndroidMkDylibs)")
+	}
+
+	if !android.InList("libbar", module.Properties.AndroidMkRlibs) {
+		t.Errorf("Rlib dependency not detected (dependency missing from AndroidMkRlibs)")
+	}
+
+	if !android.InList("libpm", module.Properties.AndroidMkProcMacroLibs) {
+		t.Errorf("Proc_macro dependency not detected (dependency missing from AndroidMkProcMacroLibs)")
+	}
+
+}
diff --git a/rust/testing.go b/rust/testing.go
new file mode 100644
index 0000000..a38697f
--- /dev/null
+++ b/rust/testing.go
@@ -0,0 +1,105 @@
+// 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 rust
+
+import (
+	"android/soong/android"
+)
+
+func GatherRequiredDepsForTest() string {
+	bp := `
+		rust_prebuilt_dylib {
+				name: "libarena_x86_64-unknown-linux-gnu",
+				srcs: [""],
+				host_supported: true,
+		}
+		rust_prebuilt_dylib {
+				name: "libfmt_macros_x86_64-unknown-linux-gnu",
+				srcs: [""],
+				host_supported: true,
+		}
+		rust_prebuilt_dylib {
+				name: "libgraphviz_x86_64-unknown-linux-gnu",
+				srcs: [""],
+				host_supported: true,
+		}
+		rust_prebuilt_dylib {
+				name: "libserialize_x86_64-unknown-linux-gnu",
+				srcs: [""],
+				host_supported: true,
+		}
+		rust_prebuilt_dylib {
+				name: "libstd_x86_64-unknown-linux-gnu",
+				srcs: [""],
+				host_supported: true,
+		}
+		rust_prebuilt_dylib {
+				name: "libsyntax_x86_64-unknown-linux-gnu",
+				srcs: [""],
+				host_supported: true,
+		}
+		rust_prebuilt_dylib {
+				name: "libsyntax_ext_x86_64-unknown-linux-gnu",
+				srcs: [""],
+				host_supported: true,
+		}
+		rust_prebuilt_dylib {
+				name: "libsyntax_pos_x86_64-unknown-linux-gnu",
+				srcs: [""],
+				host_supported: true,
+		}
+		rust_prebuilt_dylib {
+				name: "libterm_x86_64-unknown-linux-gnu",
+				srcs: [""],
+				host_supported: true,
+		}
+		rust_prebuilt_dylib {
+				name: "libtest_x86_64-unknown-linux-gnu",
+				srcs: [""],
+				host_supported: true,
+		}
+		`
+	return bp
+}
+
+func CreateTestContext(bp string) *android.TestContext {
+	ctx := android.NewTestArchContext()
+	ctx.RegisterModuleType("rust_binary", android.ModuleFactoryAdaptor(RustBinaryFactory))
+	ctx.RegisterModuleType("rust_binary_host", android.ModuleFactoryAdaptor(RustBinaryHostFactory))
+	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_proc_macro", android.ModuleFactoryAdaptor(ProcMacroFactory))
+	ctx.RegisterModuleType("rust_prebuilt_dylib", android.ModuleFactoryAdaptor(PrebuiltDylibFactory))
+	ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
+		ctx.BottomUp("rust_libraries", LibraryMutator).Parallel()
+	})
+	bp = bp + GatherRequiredDepsForTest()
+
+	mockFS := map[string][]byte{
+		"Android.bp": []byte(bp),
+		"foo.rs":     nil,
+		"src/bar.rs": nil,
+		"liby.so":    nil,
+		"libz.so":    nil,
+	}
+
+	ctx.MockFileSystem(mockFS)
+
+	return ctx
+}
diff --git a/scripts/freeze-sysprop-api-files.sh b/scripts/freeze-sysprop-api-files.sh
new file mode 100755
index 0000000..1b2ff7c
--- /dev/null
+++ b/scripts/freeze-sysprop-api-files.sh
@@ -0,0 +1,39 @@
+#!/bin/bash -e
+
+# 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.
+
+# This script freezes APIs of a sysprop_library after checking compatibility
+# between latest API and current API.
+#
+# Usage: freeze-sysprop-api-files.sh <modulePath> <moduleName>
+#
+# <modulePath>: the directory, either relative or absolute, which holds the
+# Android.bp file defining sysprop_library.
+#
+# <moduleName>: the name of sysprop_library to freeze API.
+#
+# Example:
+# $ . build/envsetup.sh && lunch aosp_arm64-user
+# $ . build/soong/scripts/freeze-sysprop-api-files.sh \
+#       system/libsysprop/srcs PlatformProperties
+
+if [[ -z "$1" || -z "$2" ]]; then
+  echo "usage: $0 <modulePath> <moduleName>" >&2
+  exit 1
+fi
+
+api_dir=$1/api
+
+m "$2-check-api" && cp -f "${api_dir}/$2-current.txt" "${api_dir}/$2-latest.txt"
diff --git a/scripts/gen-sysprop-api-files.sh b/scripts/gen-sysprop-api-files.sh
new file mode 100755
index 0000000..a4cb506
--- /dev/null
+++ b/scripts/gen-sysprop-api-files.sh
@@ -0,0 +1,26 @@
+#!/bin/bash -e
+
+# 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.
+
+if [[ -z "$1" || -z "$2" ]]; then
+  echo "usage: $0 <modulePath> <moduleName>" >&2
+  exit 1
+fi
+
+api_dir=$1/api
+
+mkdir -p "$api_dir"
+touch "${api_dir}/$2-current.txt"
+touch "${api_dir}/$2-latest.txt"
diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go
index 86061c6..c7669bd 100644
--- a/sysprop/sysprop_library.go
+++ b/sysprop/sysprop_library.go
@@ -15,12 +15,16 @@
 package sysprop
 
 import (
-	"android/soong/android"
-	"android/soong/cc"
-	"android/soong/java"
+	"fmt"
+	"io"
+	"path"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
+
+	"android/soong/android"
+	"android/soong/cc"
+	"android/soong/java"
 )
 
 type dependencyTag struct {
@@ -29,10 +33,14 @@
 }
 
 type syspropLibrary struct {
-	java.SdkLibrary
+	android.ModuleBase
 
-	commonProperties         commonProperties
-	syspropLibraryProperties syspropLibraryProperties
+	properties syspropLibraryProperties
+
+	checkApiFileTimeStamp android.WritablePath
+	latestApiFile         android.Path
+	currentApiFile        android.Path
+	dumpedApiFile         android.WritablePath
 }
 
 type syspropLibraryProperties struct {
@@ -42,17 +50,22 @@
 
 	// list of package names that will be documented and publicized as API
 	Api_packages []string
-}
 
-type commonProperties struct {
-	Srcs               []string
-	Recovery           *bool
+	// If set to true, allow this module to be dexed and installed on devices.
+	Installable *bool
+
+	// Make this module available when building for recovery
 	Recovery_available *bool
-	Vendor_available   *bool
+
+	// Make this module available when building for vendor
+	Vendor_available *bool
+
+	// list of .sysprop files which defines the properties.
+	Srcs []string `android:"path"`
 }
 
 var (
-	Bool         = proptools.Bool
+	pctx         = android.NewPackageContext("android/soong/sysprop")
 	syspropCcTag = dependencyTag{name: "syspropCc"}
 )
 
@@ -60,56 +73,166 @@
 	android.RegisterModuleType("sysprop_library", syspropLibraryFactory)
 }
 
-func (m *syspropLibrary) CcModuleName() string {
-	return "lib" + m.Name()
+func (m *syspropLibrary) Name() string {
+	return m.BaseModuleName() + "_sysprop_library"
 }
 
+func (m *syspropLibrary) CcModuleName() string {
+	return "lib" + m.BaseModuleName()
+}
+
+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")
+
+	// dump API rule
+	rule := android.NewRuleBuilder()
+	m.dumpedApiFile = android.PathForModuleOut(ctx, "api-dump.txt")
+	rule.Command().
+		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")
+
+	// check API rule
+	rule = android.NewRuleBuilder()
+
+	// 1. current.txt <-> api_dump.txt
+	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.currentApiFile.String(), m.dumpedApiFile.String(), m.currentApiFile.String())
+
+	rule.Command().
+		Text("( cmp").Flag("-s").
+		Input(m.dumpedApiFile).
+		Input(m.currentApiFile).
+		Text("|| ( echo").Flag("-e").
+		Flag(`"` + msg + `"`).
+		Text("; exit 38) )")
+
+	// 2. current.txt <-> latest.txt
+	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())
+
+	rule.Command().
+		Text("( ").
+		BuiltTool(ctx, "sysprop_api_checker").
+		Input(m.latestApiFile).
+		Input(m.currentApiFile).
+		Text(" || ( echo").Flag("-e").
+		Flag(`"` + msg + `"`).
+		Text("; exit 38) )")
+
+	m.checkApiFileTimeStamp = android.PathForModuleOut(ctx, "check_api.timestamp")
+
+	rule.Command().
+		Text("touch").
+		Output(m.checkApiFileTimeStamp)
+
+	rule.Build(pctx, ctx, m.BaseModuleName()+"_check_api", m.BaseModuleName()+" check api")
+}
+
+func (m *syspropLibrary) AndroidMk() android.AndroidMkData {
+	return android.AndroidMkData{
+		Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
+			// sysprop_library module itself is defined as a FAKE module to perform API check.
+			// Actual implementation libraries are created on LoadHookMutator
+			fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)")
+			fmt.Fprintf(w, "LOCAL_MODULE := %s\n", m.Name())
+			fmt.Fprintf(w, "LOCAL_MODULE_CLASS := FAKE\n")
+			fmt.Fprintf(w, "LOCAL_MODULE_TAGS := optional\n")
+			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)
+
+			// 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())
+		}}
+}
+
+// sysprop_library creates schematized APIs from sysprop description files (.sysprop).
+// Both Java and C++ modules can link against sysprop_library, and API stability check
+// against latest APIs (see build/soong/scripts/freeze-sysprop-api-files.sh)
+// is performed.
 func syspropLibraryFactory() android.Module {
 	m := &syspropLibrary{}
 
 	m.AddProperties(
-		&m.commonProperties,
-		&m.syspropLibraryProperties,
+		&m.properties,
 	)
-	m.InitSdkLibraryProperties()
-	m.SetNoDist()
-	android.InitAndroidMultiTargetsArchModule(m, android.DeviceSupported, "common")
+	android.InitAndroidModule(m)
 	android.AddLoadHook(m, func(ctx android.LoadHookContext) { syspropLibraryHook(ctx, m) })
-	android.AddLoadHook(m, func(ctx android.LoadHookContext) { m.SdkLibrary.CreateInternalModules(ctx) })
 	return m
 }
 
 func syspropLibraryHook(ctx android.LoadHookContext, m *syspropLibrary) {
-	if len(m.commonProperties.Srcs) == 0 {
+	if len(m.properties.Srcs) == 0 {
 		ctx.PropertyErrorf("srcs", "sysprop_library must specify srcs")
 	}
 
-	if len(m.syspropLibraryProperties.Api_packages) == 0 {
-		ctx.PropertyErrorf("api_packages", "sysprop_library must specify api_packages")
+	missing_api := false
+
+	for _, txt := range []string{"-current.txt", "-latest.txt"} {
+		path := path.Join(ctx.ModuleDir(), "api", m.BaseModuleName()+txt)
+		file := android.ExistentPathForSource(ctx, path)
+		if !file.Valid() {
+			ctx.ModuleErrorf("API file %#v doesn't exist", path)
+			missing_api = true
+		}
+	}
+
+	if missing_api {
+		script := "build/soong/scripts/gen-sysprop-api-files.sh"
+		p := android.ExistentPathForSource(ctx, script)
+
+		if !p.Valid() {
+			panic(fmt.Sprintf("script file %s doesn't exist", script))
+		}
+
+		ctx.ModuleErrorf("One or more api files are missing. "+
+			"You can create them by:\n"+
+			"%s %q %q", script, ctx.ModuleDir(), m.BaseModuleName())
+		return
 	}
 
 	socSpecific := ctx.SocSpecific()
 	deviceSpecific := ctx.DeviceSpecific()
 	productSpecific := ctx.ProductSpecific()
 
-	owner := m.syspropLibraryProperties.Property_owner
+	owner := m.properties.Property_owner
+	stub := "sysprop-library-stub-"
 
 	switch owner {
 	case "Platform":
 		// Every partition can access platform-defined properties
-		break
+		stub += "platform"
 	case "Vendor":
 		// System can't access vendor's properties
 		if !socSpecific && !deviceSpecific && !productSpecific {
 			ctx.ModuleErrorf("None of soc_specific, device_specific, product_specific is true. " +
 				"System can't access sysprop_library owned by Vendor")
 		}
+		stub += "vendor"
 	case "Odm":
 		// Only vendor can access Odm-defined properties
 		if !socSpecific && !deviceSpecific {
 			ctx.ModuleErrorf("Neither soc_speicifc nor device_specific is true. " +
 				"Odm-defined properties should be accessed only in Vendor or Odm")
 		}
+		stub += "vendor"
 	default:
 		ctx.PropertyErrorf("property_owner",
 			"Unknown value %s: must be one of Platform, Vendor or Odm", owner)
@@ -117,17 +240,23 @@
 
 	ccProps := struct {
 		Name             *string
+		Srcs             []string
 		Soc_specific     *bool
 		Device_specific  *bool
 		Product_specific *bool
 		Sysprop          struct {
 			Platform *bool
 		}
-		Header_libs []string
-		Shared_libs []string
+		Header_libs        []string
+		Shared_libs        []string
+		Required           []string
+		Recovery           *bool
+		Recovery_available *bool
+		Vendor_available   *bool
 	}{}
 
 	ccProps.Name = proptools.StringPtr(m.CcModuleName())
+	ccProps.Srcs = m.properties.Srcs
 	ccProps.Soc_specific = proptools.BoolPtr(socSpecific)
 	ccProps.Device_specific = proptools.BoolPtr(deviceSpecific)
 	ccProps.Product_specific = proptools.BoolPtr(productSpecific)
@@ -135,5 +264,41 @@
 	ccProps.Header_libs = []string{"libbase_headers"}
 	ccProps.Shared_libs = []string{"liblog"}
 
-	ctx.CreateModule(android.ModuleFactoryAdaptor(cc.LibraryFactory), &m.commonProperties, &ccProps)
+	// 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)
+
+	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
+	}{}
+
+	javaProps.Name = proptools.StringPtr(m.BaseModuleName())
+	javaProps.Srcs = m.properties.Srcs
+	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)
 }
diff --git a/sysprop/sysprop_test.go b/sysprop/sysprop_test.go
index 0566036..5345770 100644
--- a/sysprop/sysprop_test.go
+++ b/sysprop/sysprop_test.go
@@ -57,16 +57,11 @@
 
 	ctx := android.NewTestArchContext()
 	ctx.RegisterModuleType("android_app", android.ModuleFactoryAdaptor(java.AndroidAppFactory))
-	ctx.RegisterModuleType("droiddoc_template", android.ModuleFactoryAdaptor(java.ExportedDroiddocDirFactory))
 	ctx.RegisterModuleType("java_library", android.ModuleFactoryAdaptor(java.LibraryFactory))
 	ctx.RegisterModuleType("java_system_modules", android.ModuleFactoryAdaptor(java.SystemModulesFactory))
-	ctx.RegisterModuleType("prebuilt_apis", android.ModuleFactoryAdaptor(java.PrebuiltApisFactory))
 	ctx.PreArchMutators(android.RegisterPrebuiltsPreArchMutators)
 	ctx.PreArchMutators(android.RegisterPrebuiltsPostDepsMutators)
 	ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
-	ctx.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
-		ctx.TopDown("prebuilt_apis", java.PrebuiltApisMutator).Parallel()
-	})
 
 	ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(cc.LibraryFactory))
 	ctx.RegisterModuleType("cc_library_headers", android.ModuleFactoryAdaptor(cc.LibraryHeaderFactory))
@@ -91,45 +86,20 @@
 	bp += cc.GatherRequiredDepsForTest(android.Android)
 
 	mockFS := map[string][]byte{
-		"Android.bp":             []byte(bp),
-		"a.java":                 nil,
-		"b.java":                 nil,
-		"c.java":                 nil,
-		"d.cpp":                  nil,
-		"api/current.txt":        nil,
-		"api/removed.txt":        nil,
-		"api/system-current.txt": nil,
-		"api/system-removed.txt": nil,
-		"api/test-current.txt":   nil,
-		"api/test-removed.txt":   nil,
-		"framework/aidl/a.aidl":  nil,
-
-		"prebuilts/sdk/current/core/android.jar":                              nil,
-		"prebuilts/sdk/current/public/android.jar":                            nil,
-		"prebuilts/sdk/current/public/framework.aidl":                         nil,
-		"prebuilts/sdk/current/public/core.jar":                               nil,
-		"prebuilts/sdk/current/system/android.jar":                            nil,
-		"prebuilts/sdk/current/test/android.jar":                              nil,
-		"prebuilts/sdk/28/public/api/sysprop-platform.txt":                    nil,
-		"prebuilts/sdk/28/system/api/sysprop-platform.txt":                    nil,
-		"prebuilts/sdk/28/test/api/sysprop-platform.txt":                      nil,
-		"prebuilts/sdk/28/public/api/sysprop-platform-removed.txt":            nil,
-		"prebuilts/sdk/28/system/api/sysprop-platform-removed.txt":            nil,
-		"prebuilts/sdk/28/test/api/sysprop-platform-removed.txt":              nil,
-		"prebuilts/sdk/28/public/api/sysprop-platform-on-product.txt":         nil,
-		"prebuilts/sdk/28/system/api/sysprop-platform-on-product.txt":         nil,
-		"prebuilts/sdk/28/test/api/sysprop-platform-on-product.txt":           nil,
-		"prebuilts/sdk/28/public/api/sysprop-platform-on-product-removed.txt": nil,
-		"prebuilts/sdk/28/system/api/sysprop-platform-on-product-removed.txt": nil,
-		"prebuilts/sdk/28/test/api/sysprop-platform-on-product-removed.txt":   nil,
-		"prebuilts/sdk/28/public/api/sysprop-vendor.txt":                      nil,
-		"prebuilts/sdk/28/system/api/sysprop-vendor.txt":                      nil,
-		"prebuilts/sdk/28/test/api/sysprop-vendor.txt":                        nil,
-		"prebuilts/sdk/28/public/api/sysprop-vendor-removed.txt":              nil,
-		"prebuilts/sdk/28/system/api/sysprop-vendor-removed.txt":              nil,
-		"prebuilts/sdk/28/test/api/sysprop-vendor-removed.txt":                nil,
-		"prebuilts/sdk/tools/core-lambda-stubs.jar":                           nil,
-		"prebuilts/sdk/Android.bp":                                            []byte(`prebuilt_apis { name: "sdk", api_dirs: ["28", "current"],}`),
+		"Android.bp":                       []byte(bp),
+		"a.java":                           nil,
+		"b.java":                           nil,
+		"c.java":                           nil,
+		"d.cpp":                            nil,
+		"api/sysprop-platform-current.txt": nil,
+		"api/sysprop-platform-latest.txt":  nil,
+		"api/sysprop-platform-on-product-current.txt": nil,
+		"api/sysprop-platform-on-product-latest.txt":  nil,
+		"api/sysprop-vendor-current.txt":              nil,
+		"api/sysprop-vendor-latest.txt":               nil,
+		"api/sysprop-odm-current.txt":                 nil,
+		"api/sysprop-odm-latest.txt":                  nil,
+		"framework/aidl/a.aidl":                       nil,
 
 		// For framework-res, which is an implicit dependency for framework
 		"AndroidManifest.xml":                        nil,
@@ -155,6 +125,7 @@
 
 		"android/sysprop/PlatformProperties.sysprop": nil,
 		"com/android/VendorProperties.sysprop":       nil,
+		"com/android2/OdmProperties.sysprop":         nil,
 	}
 
 	for k, v := range fs {
@@ -168,7 +139,7 @@
 
 func run(t *testing.T, ctx *android.TestContext, config android.Config) {
 	t.Helper()
-	_, errs := ctx.ParseFileList(".", []string{"Android.bp", "prebuilts/sdk/Android.bp"})
+	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
 	android.FailIfErrored(t, errs)
 	_, errs = ctx.PrepareBuildActions(config)
 	android.FailIfErrored(t, errs)
@@ -221,6 +192,14 @@
 			vendor_available: true,
 		}
 
+		sysprop_library {
+			name: "sysprop-odm",
+			srcs: ["com/android2/OdmProperties.sysprop"],
+			api_packages: ["com.android2"],
+			property_owner: "Odm",
+			device_specific: true,
+		}
+
 		java_library {
 			name: "java-platform",
 			srcs: ["c.java"],
@@ -288,20 +267,40 @@
 			name: "liblog",
 			symbol_file: "",
 		}
+
+		java_library {
+			name: "sysprop-library-stub-platform",
+			sdk_version: "core_current",
+		}
+
+		java_library {
+			name: "sysprop-library-stub-vendor",
+			soc_specific: true,
+			sdk_version: "core_current",
+		}
 		`)
 
+	// Check for generated cc_library
+	for _, variant := range []string{
+		"android_arm_armv7-a-neon_vendor_shared",
+		"android_arm_armv7-a-neon_vendor_static",
+		"android_arm64_armv8-a_vendor_shared",
+		"android_arm64_armv8-a_vendor_static",
+	} {
+		ctx.ModuleForTests("libsysprop-platform", variant)
+		ctx.ModuleForTests("libsysprop-vendor", variant)
+		ctx.ModuleForTests("libsysprop-odm", variant)
+	}
+
 	for _, variant := range []string{
 		"android_arm_armv7-a-neon_core_shared",
 		"android_arm_armv7-a-neon_core_static",
-		"android_arm_armv7-a-neon_vendor_shared",
-		"android_arm_armv7-a-neon_vendor_static",
 		"android_arm64_armv8-a_core_shared",
 		"android_arm64_armv8-a_core_static",
-		"android_arm64_armv8-a_vendor_shared",
-		"android_arm64_armv8-a_vendor_static",
 	} {
-		// Check for generated cc_library
 		ctx.ModuleForTests("libsysprop-platform", variant)
+
+		// core variant of vendor-owned sysprop_library is for product
 		ctx.ModuleForTests("libsysprop-vendor", variant)
 	}
 
diff --git a/ui/build/cleanbuild.go b/ui/build/cleanbuild.go
index 8e7f96a..bfe2c36 100644
--- a/ui/build/cleanbuild.go
+++ b/ui/build/cleanbuild.go
@@ -99,6 +99,7 @@
 		productOut("*.img"),
 		productOut("*.zip"),
 		productOut("android-info.txt"),
+		productOut("apex"),
 		productOut("kernel"),
 		productOut("data"),
 		productOut("skin"),
diff --git a/ui/build/paths/config.go b/ui/build/paths/config.go
index 100cc65..738ef40 100644
--- a/ui/build/paths/config.go
+++ b/ui/build/paths/config.go
@@ -118,67 +118,19 @@
 	"ld.gold":    Forbidden,
 	"pkg-config": Forbidden,
 
-	// On Linux we'll use the toybox versions of these instead.
-	"basename":  LinuxOnlyPrebuilt,
-	"cat":       LinuxOnlyPrebuilt,
-	"chmod":     LinuxOnlyPrebuilt,
-	"cmp":       LinuxOnlyPrebuilt,
-	"cp":        LinuxOnlyPrebuilt,
-	"comm":      LinuxOnlyPrebuilt,
-	"cut":       LinuxOnlyPrebuilt,
-	"date":      LinuxOnlyPrebuilt,
-	"dirname":   LinuxOnlyPrebuilt,
-	"du":        LinuxOnlyPrebuilt,
-	"echo":      LinuxOnlyPrebuilt,
-	"egrep":     LinuxOnlyPrebuilt,
-	"env":       LinuxOnlyPrebuilt,
-	"getconf":   LinuxOnlyPrebuilt,
-	"grep":      LinuxOnlyPrebuilt,
-	"head":      LinuxOnlyPrebuilt,
-	"hostname":  LinuxOnlyPrebuilt,
-	"id":        LinuxOnlyPrebuilt,
-	"ln":        LinuxOnlyPrebuilt,
-	"ls":        LinuxOnlyPrebuilt,
-	"md5sum":    LinuxOnlyPrebuilt,
-	"mkdir":     LinuxOnlyPrebuilt,
-	"mktemp":    LinuxOnlyPrebuilt,
-	"mv":        LinuxOnlyPrebuilt,
-	"od":        LinuxOnlyPrebuilt,
-	"paste":     LinuxOnlyPrebuilt,
-	"pgrep":     LinuxOnlyPrebuilt,
-	"pkill":     LinuxOnlyPrebuilt,
-	"ps":        LinuxOnlyPrebuilt,
-	"pwd":       LinuxOnlyPrebuilt,
-	"readlink":  LinuxOnlyPrebuilt,
-	"rm":        LinuxOnlyPrebuilt,
-	"rmdir":     LinuxOnlyPrebuilt,
-	"sed":       LinuxOnlyPrebuilt,
-	"seq":       LinuxOnlyPrebuilt,
-	"setsid":    LinuxOnlyPrebuilt,
-	"sha1sum":   LinuxOnlyPrebuilt,
-	"sha256sum": LinuxOnlyPrebuilt,
-	"sha512sum": LinuxOnlyPrebuilt,
-	"sleep":     LinuxOnlyPrebuilt,
-	"sort":      LinuxOnlyPrebuilt,
-	"stat":      LinuxOnlyPrebuilt,
-	"tail":      LinuxOnlyPrebuilt,
-	"tar":       LinuxOnlyPrebuilt,
-	"tee":       LinuxOnlyPrebuilt,
-	"timeout":   LinuxOnlyPrebuilt,
-	"touch":     LinuxOnlyPrebuilt,
-	"true":      LinuxOnlyPrebuilt,
-	"uname":     LinuxOnlyPrebuilt,
-	"uniq":      LinuxOnlyPrebuilt,
-	"unix2dos":  LinuxOnlyPrebuilt,
-	"wc":        LinuxOnlyPrebuilt,
-	"whoami":    LinuxOnlyPrebuilt,
-	"which":     LinuxOnlyPrebuilt,
-	"xargs":     LinuxOnlyPrebuilt,
-	"xxd":       LinuxOnlyPrebuilt,
+	// These are currently Linux-only toybox tools (but can be switched now).
+	"date": LinuxOnlyPrebuilt,
+	"stat": LinuxOnlyPrebuilt,
+
+	// These are toybox tools that only work on Linux.
+	"pgrep": LinuxOnlyPrebuilt,
+	"pkill": LinuxOnlyPrebuilt,
+	"ps":    LinuxOnlyPrebuilt,
 }
 
 func init() {
 	if runtime.GOOS == "darwin" {
+		// TODO: move Darwin off md5 and onto our md5sum prebuilt.
 		Configuration["md5"] = Allowed
 		Configuration["sw_vers"] = Allowed
 		Configuration["xcrun"] = Allowed