Merge "Generate module lib API and scope together"
diff --git a/android/Android.bp b/android/Android.bp
index 977345b..6ddcc14 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -46,6 +46,7 @@
         "sdk.go",
         "singleton.go",
         "soong_config_modules.go",
+        "test_suites.go",
         "testing.go",
         "util.go",
         "variable.go",
diff --git a/android/sdk.go b/android/sdk.go
index 8115b69..2c38f56 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -466,8 +466,7 @@
 
 // Base structure for all implementations of SdkMemberProperties.
 //
-// Contains common properties that apply across many different member types. These
-// are not affected by the optimization to extract common values.
+// Contains common properties that apply across many different member types.
 type SdkMemberPropertiesBase struct {
 	// The number of unique os types supported by the member variants.
 	//
@@ -489,9 +488,7 @@
 	Os OsType `sdk:"keep"`
 
 	// The setting to use for the compile_multilib property.
-	//
-	// This property is set after optimization so there is no point in trying to optimize it.
-	Compile_multilib string `sdk:"keep"`
+	Compile_multilib string `android:"arch_variant"`
 }
 
 // The os prefix to use for any file paths in the sdk.
diff --git a/android/test_suites.go b/android/test_suites.go
new file mode 100644
index 0000000..7b2d7dc
--- /dev/null
+++ b/android/test_suites.go
@@ -0,0 +1,75 @@
+// Copyright 2020 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package android
+
+func init() {
+	RegisterSingletonType("testsuites", testSuiteFilesFactory)
+}
+
+func testSuiteFilesFactory() Singleton {
+	return &testSuiteFiles{}
+}
+
+type testSuiteFiles struct {
+	robolectric WritablePath
+}
+
+type TestSuiteModule interface {
+	Module
+	TestSuites() []string
+}
+
+func (t *testSuiteFiles) GenerateBuildActions(ctx SingletonContext) {
+	files := make(map[string]map[string]InstallPaths)
+
+	ctx.VisitAllModules(func(m Module) {
+		if tsm, ok := m.(TestSuiteModule); ok {
+			for _, testSuite := range tsm.TestSuites() {
+				if files[testSuite] == nil {
+					files[testSuite] = make(map[string]InstallPaths)
+				}
+				name := ctx.ModuleName(m)
+				files[testSuite][name] = append(files[testSuite][name], tsm.filesToInstall()...)
+			}
+		}
+	})
+
+	t.robolectric = robolectricTestSuite(ctx, files["robolectric-tests"])
+
+	ctx.Phony("robolectric-tests", t.robolectric)
+}
+
+func (t *testSuiteFiles) MakeVars(ctx MakeVarsContext) {
+	ctx.DistForGoal("robolectric-tests", t.robolectric)
+}
+
+func robolectricTestSuite(ctx SingletonContext, files map[string]InstallPaths) WritablePath {
+	var installedPaths InstallPaths
+	for _, module := range SortedStringKeys(files) {
+		installedPaths = append(installedPaths, files[module]...)
+	}
+	testCasesDir := pathForInstall(ctx, BuildOs, "testcases", false).ToMakePath()
+
+	outputFile := PathForOutput(ctx, "packaging", "robolectric-tests.zip")
+	rule := NewRuleBuilder()
+	rule.Command().BuiltTool(ctx, "soong_zip").
+		FlagWithOutput("-o ", outputFile).
+		FlagWithArg("-P ", "host/testcases").
+		FlagWithArg("-C ", testCasesDir.String()).
+		FlagWithRspFileInputList("-l ", installedPaths.Paths())
+	rule.Build(pctx, ctx, "robolectric_tests_zip", "robolectric-tests.zip")
+
+	return outputFile
+}
diff --git a/cc/binary_sdk_member.go b/cc/binary_sdk_member.go
index 372a72e..51d8b4e 100644
--- a/cc/binary_sdk_member.go
+++ b/cc/binary_sdk_member.go
@@ -140,10 +140,6 @@
 }
 
 func (p *nativeBinaryInfoProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
-	if p.Compile_multilib != "" {
-		propertySet.AddProperty("compile_multilib", p.Compile_multilib)
-	}
-
 	builder := ctx.SnapshotBuilder()
 	if p.outputFile != nil {
 		propertySet.AddProperty("srcs", []string{nativeBinaryPathFor(*p)})
diff --git a/java/android_manifest.go b/java/android_manifest.go
index 8280cb1..84dee16 100644
--- a/java/android_manifest.go
+++ b/java/android_manifest.go
@@ -130,7 +130,7 @@
 		},
 	})
 
-	return fixedManifest
+	return fixedManifest.WithoutRel()
 }
 
 func manifestMerger(ctx android.ModuleContext, manifest android.Path, staticLibManifests android.Paths,
@@ -155,5 +155,5 @@
 		},
 	})
 
-	return mergedManifest
+	return mergedManifest.WithoutRel()
 }
diff --git a/java/lint.go b/java/lint.go
index 20a7dc4..5d2c4f6 100644
--- a/java/lint.go
+++ b/java/lint.go
@@ -17,6 +17,7 @@
 import (
 	"fmt"
 	"sort"
+	"strings"
 
 	"android/soong/android"
 )
@@ -104,7 +105,16 @@
 		return
 	}
 
-	ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), extraLintCheckTag, l.properties.Lint.Extra_check_modules...)
+	extraCheckModules := l.properties.Lint.Extra_check_modules
+
+	if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" {
+		if checkOnlyModules := ctx.Config().Getenv("ANDROID_LINT_CHECK_EXTRA_MODULES"); checkOnlyModules != "" {
+			extraCheckModules = strings.Split(checkOnlyModules, ",")
+		}
+	}
+
+	ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(),
+		extraLintCheckTag, extraCheckModules...)
 }
 
 func (l *linter) writeLintProjectXML(ctx android.ModuleContext,
@@ -262,7 +272,7 @@
 		apiVersionsXMLPath = copiedAPIVersionsXmlPath(ctx)
 	}
 
-	rule.Command().
+	cmd := rule.Command().
 		Text("(").
 		Flag("JAVA_OPTS=-Xmx2048m").
 		FlagWithArg("ANDROID_SDK_HOME=", homeDir.String()).
@@ -282,9 +292,13 @@
 		FlagWithArg("--url ", fmt.Sprintf(".=.,%s=out", android.PathForOutput(ctx).String())).
 		Flag("--exitcode").
 		Flags(l.properties.Lint.Flags).
-		Implicits(deps).
-		Text("|| (").Text("cat").Input(text).Text("; exit 7)").
-		Text(")")
+		Implicits(deps)
+
+	if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" {
+		cmd.FlagWithArg("--check ", checkOnly)
+	}
+
+	cmd.Text("|| (").Text("cat").Input(text).Text("; exit 7)").Text(")")
 
 	rule.Command().Text("rm -rf").Flag(cacheDir.String()).Flag(homeDir.String())
 
diff --git a/java/robolectric.go b/java/robolectric.go
index c6b07a1..4d68fd9 100644
--- a/java/robolectric.go
+++ b/java/robolectric.go
@@ -21,10 +21,13 @@
 	"strings"
 
 	"android/soong/android"
+	"android/soong/java/config"
+	"android/soong/tradefed"
 )
 
 func init() {
 	android.RegisterModuleType("android_robolectric_test", RobolectricTestFactory)
+	android.RegisterModuleType("android_robolectric_runtimes", robolectricRuntimesFactory)
 }
 
 var robolectricDefaultLibs = []string{
@@ -32,10 +35,13 @@
 	"Robolectric_all-target",
 	"mockito-robolectric-prebuilt",
 	"truth-prebuilt",
+	// TODO(ccross): this is not needed at link time
+	"junitxml",
 }
 
 var (
-	roboCoverageLibsTag = dependencyTag{name: "roboSrcs"}
+	roboCoverageLibsTag = dependencyTag{name: "roboCoverageLibs"}
+	roboRuntimesTag     = dependencyTag{name: "roboRuntimes"}
 )
 
 type robolectricProperties struct {
@@ -58,13 +64,28 @@
 	Library
 
 	robolectricProperties robolectricProperties
+	testProperties        testProperties
 
 	libs  []string
 	tests []string
 
+	manifest    android.Path
+	resourceApk android.Path
+
+	combinedJar android.WritablePath
+
 	roboSrcJar android.Path
+
+	testConfig android.Path
+	data       android.Paths
 }
 
+func (r *robolectricTest) TestSuites() []string {
+	return r.testProperties.Test_suites
+}
+
+var _ android.TestSuiteModule = (*robolectricTest)(nil)
+
 func (r *robolectricTest) DepsMutator(ctx android.BottomUpMutatorContext) {
 	r.Library.DepsMutator(ctx)
 
@@ -77,9 +98,16 @@
 	ctx.AddVariationDependencies(nil, libTag, robolectricDefaultLibs...)
 
 	ctx.AddVariationDependencies(nil, roboCoverageLibsTag, r.robolectricProperties.Coverage_libs...)
+
+	ctx.AddVariationDependencies(nil, roboRuntimesTag, "robolectric-android-all-prebuilts")
 }
 
 func (r *robolectricTest) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	r.testConfig = tradefed.AutoGenRobolectricTestConfig(ctx, r.testProperties.Test_config,
+		r.testProperties.Test_config_template, r.testProperties.Test_suites,
+		r.testProperties.Auto_gen_config)
+	r.data = android.PathsForModuleSrc(ctx, r.testProperties.Data)
+
 	roboTestConfig := android.PathForModuleGen(ctx, "robolectric").
 		Join(ctx, "com/android/tools/test_config.properties")
 
@@ -95,6 +123,9 @@
 		ctx.PropertyErrorf("instrumentation_for", "dependency must be an android_app")
 	}
 
+	r.manifest = instrumentedApp.mergedManifestFile
+	r.resourceApk = instrumentedApp.outputFile
+
 	generateRoboTestConfig(ctx, roboTestConfig, instrumentedApp)
 	r.extraResources = android.Paths{roboTestConfig}
 
@@ -104,10 +135,30 @@
 	r.generateRoboSrcJar(ctx, roboSrcJar, instrumentedApp)
 	r.roboSrcJar = roboSrcJar
 
-	for _, dep := range ctx.GetDirectDepsWithTag(libTag) {
-		r.libs = append(r.libs, dep.(Dependency).BaseModuleName())
+	roboTestConfigJar := android.PathForModuleOut(ctx, "robolectric_samedir", "samedir_config.jar")
+	generateSameDirRoboTestConfigJar(ctx, roboTestConfigJar)
+
+	combinedJarJars := android.Paths{
+		// roboTestConfigJar comes first so that its com/android/tools/test_config.properties
+		// overrides the one from r.extraResources.  The r.extraResources one can be removed
+		// once the Make test runner is removed.
+		roboTestConfigJar,
+		r.outputFile,
+		instrumentedApp.implementationAndResourcesJar,
 	}
 
+	for _, dep := range ctx.GetDirectDepsWithTag(libTag) {
+		m := dep.(Dependency)
+		r.libs = append(r.libs, m.BaseModuleName())
+		if !android.InList(m.BaseModuleName(), config.FrameworkLibraries) {
+			combinedJarJars = append(combinedJarJars, m.ImplementationAndResourcesJars()...)
+		}
+	}
+
+	r.combinedJar = android.PathForModuleOut(ctx, "robolectric_combined", r.outputFile.Base())
+	TransformJarsToJar(ctx, r.combinedJar, "combine jars", combinedJarJars, android.OptionalPath{},
+		false, nil, nil)
+
 	// TODO: this could all be removed if tradefed was used as the test runner, it will find everything
 	// annotated as a test and run it.
 	for _, src := range r.compiledJavaSrcs {
@@ -121,14 +172,38 @@
 		}
 		r.tests = append(r.tests, s)
 	}
+
+	r.data = append(r.data, r.manifest, r.resourceApk)
+
+	runtimes := ctx.GetDirectDepWithTag("robolectric-android-all-prebuilts", roboRuntimesTag)
+
+	installPath := android.PathForModuleInstall(ctx, r.BaseModuleName())
+
+	installedResourceApk := ctx.InstallFile(installPath, ctx.ModuleName()+".apk", r.resourceApk)
+	installedManifest := ctx.InstallFile(installPath, ctx.ModuleName()+"-AndroidManifest.xml", r.manifest)
+	installedConfig := ctx.InstallFile(installPath, ctx.ModuleName()+".config", r.testConfig)
+
+	var installDeps android.Paths
+	for _, runtime := range runtimes.(*robolectricRuntimes).runtimes {
+		installDeps = append(installDeps, runtime)
+	}
+	installDeps = append(installDeps, installedResourceApk, installedManifest, installedConfig)
+
+	for _, data := range android.PathsForModuleSrc(ctx, r.testProperties.Data) {
+		installedData := ctx.InstallFile(installPath, data.Rel(), data)
+		installDeps = append(installDeps, installedData)
+	}
+
+	ctx.InstallFile(installPath, ctx.ModuleName()+".jar", r.combinedJar, installDeps...)
 }
 
-func generateRoboTestConfig(ctx android.ModuleContext, outputFile android.WritablePath, instrumentedApp *AndroidApp) {
+func generateRoboTestConfig(ctx android.ModuleContext, outputFile android.WritablePath,
+	instrumentedApp *AndroidApp) {
+	rule := android.NewRuleBuilder()
+
 	manifest := instrumentedApp.mergedManifestFile
 	resourceApk := instrumentedApp.outputFile
 
-	rule := android.NewRuleBuilder()
-
 	rule.Command().Text("rm -f").Output(outputFile)
 	rule.Command().
 		Textf(`echo "android_merged_manifest=%s" >>`, manifest.String()).Output(outputFile).Text("&&").
@@ -141,6 +216,28 @@
 	rule.Build(pctx, ctx, "generate_test_config", "generate test_config.properties")
 }
 
+func generateSameDirRoboTestConfigJar(ctx android.ModuleContext, outputFile android.ModuleOutPath) {
+	rule := android.NewRuleBuilder()
+
+	outputDir := outputFile.InSameDir(ctx)
+	configFile := outputDir.Join(ctx, "com/android/tools/test_config.properties")
+	rule.Temporary(configFile)
+	rule.Command().Text("rm -f").Output(outputFile).Output(configFile)
+	rule.Command().Textf("mkdir -p $(dirname %s)", configFile.String())
+	rule.Command().
+		Text("(").
+		Textf(`echo "android_merged_manifest=%s-AndroidManifest.xml" &&`, ctx.ModuleName()).
+		Textf(`echo "android_resource_apk=%s.apk"`, ctx.ModuleName()).
+		Text(") >>").Output(configFile)
+	rule.Command().
+		BuiltTool(ctx, "soong_zip").
+		FlagWithArg("-C ", outputDir.String()).
+		FlagWithInput("-f ", configFile).
+		FlagWithOutput("-o ", outputFile)
+
+	rule.Build(pctx, ctx, "generate_test_config_samedir", "generate test_config.properties")
+}
+
 func (r *robolectricTest) generateRoboSrcJar(ctx android.ModuleContext, outputFile android.WritablePath,
 	instrumentedApp *AndroidApp) {
 
@@ -202,7 +299,6 @@
 		fmt.Fprintln(w, "LOCAL_ROBOTEST_TIMEOUT :=", *t)
 	}
 	fmt.Fprintln(w, "-include external/robolectric-shadows/run_robotests.mk")
-
 }
 
 // An android_robolectric_test module compiles tests against the Robolectric framework that can run on the local host
@@ -218,11 +314,74 @@
 	module.addHostProperties()
 	module.AddProperties(
 		&module.Module.deviceProperties,
-		&module.robolectricProperties)
+		&module.robolectricProperties,
+		&module.testProperties)
 
 	module.Module.dexpreopter.isTest = true
 	module.Module.linter.test = true
 
+	module.testProperties.Test_suites = []string{"robolectric-tests"}
+
 	InitJavaModule(module, android.DeviceSupported)
 	return module
 }
+
+func (r *robolectricTest) InstallBypassMake() bool         { return true }
+func (r *robolectricTest) InstallInTestcases() bool        { return true }
+func (r *robolectricTest) InstallForceOS() *android.OsType { return &android.BuildOs }
+
+func robolectricRuntimesFactory() android.Module {
+	module := &robolectricRuntimes{}
+	module.AddProperties(&module.props)
+	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+	return module
+}
+
+type robolectricRuntimesProperties struct {
+	Jars []string `android:"path"`
+	Lib  *string
+}
+
+type robolectricRuntimes struct {
+	android.ModuleBase
+
+	props robolectricRuntimesProperties
+
+	runtimes []android.InstallPath
+}
+
+func (r *robolectricRuntimes) TestSuites() []string {
+	return []string{"robolectric-tests"}
+}
+
+var _ android.TestSuiteModule = (*robolectricRuntimes)(nil)
+
+func (r *robolectricRuntimes) DepsMutator(ctx android.BottomUpMutatorContext) {
+	if !ctx.Config().UnbundledBuildUsePrebuiltSdks() && r.props.Lib != nil {
+		ctx.AddVariationDependencies(nil, libTag, String(r.props.Lib))
+	}
+}
+
+func (r *robolectricRuntimes) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	files := android.PathsForModuleSrc(ctx, r.props.Jars)
+
+	androidAllDir := android.PathForModuleInstall(ctx, "android-all")
+	for _, from := range files {
+		installedRuntime := ctx.InstallFile(androidAllDir, from.Base(), from)
+		r.runtimes = append(r.runtimes, installedRuntime)
+	}
+
+	if !ctx.Config().UnbundledBuildUsePrebuiltSdks() && r.props.Lib != nil {
+		runtimeFromSourceModule := ctx.GetDirectDepWithTag(String(r.props.Lib), libTag)
+		runtimeFromSourceJar := android.OutputFileForModule(ctx, runtimeFromSourceModule, "")
+
+		runtimeName := fmt.Sprintf("android-all-%s-robolectric-r0.jar",
+			ctx.Config().PlatformSdkCodename())
+		installedRuntime := ctx.InstallFile(androidAllDir, runtimeName, runtimeFromSourceJar)
+		r.runtimes = append(r.runtimes, installedRuntime)
+	}
+}
+
+func (r *robolectricRuntimes) InstallBypassMake() bool         { return true }
+func (r *robolectricRuntimes) InstallInTestcases() bool        { return true }
+func (r *robolectricRuntimes) InstallForceOS() *android.OsType { return &android.BuildOs }
diff --git a/rust/Android.bp b/rust/Android.bp
index d56de87..26a5a08 100644
--- a/rust/Android.bp
+++ b/rust/Android.bp
@@ -10,6 +10,7 @@
     srcs: [
         "androidmk.go",
         "binary.go",
+        "bindgen.go",
         "builder.go",
         "clippy.go",
         "compiler.go",
@@ -19,11 +20,13 @@
         "proc_macro.go",
         "project_json.go",
         "rust.go",
+        "source_provider.go",
         "test.go",
         "testing.go",
     ],
     testSrcs: [
         "binary_test.go",
+        "bindgen_test.go",
         "clippy_test.go",
         "compiler_test.go",
         "coverage_test.go",
diff --git a/rust/androidmk.go b/rust/androidmk.go
index aea899b..babbf91 100644
--- a/rust/androidmk.go
+++ b/rust/androidmk.go
@@ -55,6 +55,7 @@
 	ret := android.AndroidMkData{
 		OutputFile: mod.outputFile,
 		Include:    "$(BUILD_SYSTEM)/soong_rust_prebuilt.mk",
+		SubName:    mod.subName,
 		Extra: []android.AndroidMkExtraFunc{
 			func(w io.Writer, outputFile android.Path) {
 				if len(mod.Properties.AndroidMkRlibs) > 0 {
@@ -75,9 +76,11 @@
 			},
 		},
 	}
-
-	mod.subAndroidMk(&ret, mod.compiler)
-
+	if mod.compiler != nil {
+		mod.subAndroidMk(&ret, mod.compiler)
+	} else if mod.sourceProvider != nil {
+		mod.subAndroidMk(&ret, mod.sourceProvider)
+	}
 	ret.SubName += mod.Properties.SubName
 
 	return ret
@@ -155,6 +158,25 @@
 
 }
 
+func (sourceProvider *baseSourceProvider) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+	outFile := sourceProvider.outputFile
+	ret.Class = "ETC"
+	ret.OutputFile = android.OptionalPathForPath(outFile)
+	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
+		_, file := filepath.Split(outFile.String())
+		stem, suffix, _ := android.SplitFileExt(file)
+		fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := "+suffix)
+		fmt.Fprintln(w, "LOCAL_MODULE_STEM := "+stem)
+	})
+}
+
+func (bindgen *bindgenDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+	ctx.subAndroidMk(ret, bindgen.baseSourceProvider)
+	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
+		fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
+	})
+}
+
 func (compiler *baseCompiler) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
 	// Soong installation is only supported for host modules. Have Make
 	// installation trigger Soong installation.
diff --git a/rust/binary.go b/rust/binary.go
index 9fc52cd..48f51db 100644
--- a/rust/binary.go
+++ b/rust/binary.go
@@ -107,7 +107,7 @@
 	fileName := binary.getStem(ctx) + ctx.toolchain().ExecutableSuffix()
 
 	srcPath, paths := srcPathFromModuleSrcs(ctx, binary.baseCompiler.Properties.Srcs)
-	deps.SrcDeps = paths
+	deps.SrcDeps = append(deps.SrcDeps, paths...)
 
 	outputFile := android.PathForModuleOut(ctx, fileName)
 	binary.unstrippedOutputFile = outputFile
diff --git a/rust/bindgen.go b/rust/bindgen.go
new file mode 100644
index 0000000..859223a
--- /dev/null
+++ b/rust/bindgen.go
@@ -0,0 +1,172 @@
+// Copyright 2020 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 (
+	"github.com/google/blueprint"
+	"strings"
+
+	"android/soong/android"
+	"android/soong/cc"
+	ccConfig "android/soong/cc/config"
+)
+
+var (
+	defaultBindgenFlags = []string{"--no-rustfmt-bindings"}
+
+	// bindgen should specify its own Clang revision so updating Clang isn't potentially blocked on bindgen failures.
+	bindgenClangVersion  = "clang-r383902c"
+	bindgenLibClangSoGit = "11git"
+
+	//TODO(b/160803703) Use a prebuilt bindgen instead of the built bindgen.
+	_ = pctx.SourcePathVariable("bindgenCmd", "out/host/${config.HostPrebuiltTag}/bin/bindgen")
+	_ = pctx.SourcePathVariable("bindgenClang",
+		"${ccConfig.ClangBase}/${config.HostPrebuiltTag}/"+bindgenClangVersion+"/bin/clang")
+	_ = pctx.SourcePathVariable("bindgenLibClang",
+		"${ccConfig.ClangBase}/${config.HostPrebuiltTag}/"+bindgenClangVersion+"/lib64/libclang.so."+bindgenLibClangSoGit)
+
+	//TODO(ivanlozano) Switch this to RuleBuilder
+	bindgen = pctx.AndroidStaticRule("bindgen",
+		blueprint.RuleParams{
+			Command:     "CLANG_PATH=$bindgenClang LIBCLANG_PATH=$bindgenLibClang $bindgenCmd $flags $in -o $out -- $cflags",
+			CommandDeps: []string{"$bindgenCmd"},
+		},
+		"flags", "cflags")
+)
+
+func init() {
+	android.RegisterModuleType("rust_bindgen", RustBindgenFactory)
+}
+
+var _ SourceProvider = (*bindgenDecorator)(nil)
+
+type BindgenProperties struct {
+	// The wrapper header file
+	Wrapper_src *string `android:"path,arch_variant"`
+
+	// list of bindgen-specific flags and options
+	Flags []string `android:"arch_variant"`
+
+	// list of clang flags required to correctly interpret the headers.
+	Cflags []string `android:"arch_variant"`
+
+	// list of directories relative to the Blueprints file that will
+	// be added to the include path using -I
+	Local_include_dirs []string `android:"arch_variant,variant_prepend"`
+
+	// list of static libraries that provide headers for this binding.
+	Static_libs []string `android:"arch_variant,variant_prepend"`
+
+	// list of shared libraries that provide headers for this binding.
+	Shared_libs []string `android:"arch_variant"`
+
+	//TODO(b/161141999) Add support for headers from cc_library_header modules.
+}
+
+type bindgenDecorator struct {
+	*baseSourceProvider
+
+	Properties BindgenProperties
+}
+
+func (b *bindgenDecorator) libraryExports(ctx android.ModuleContext) (android.Paths, []string) {
+	var libraryPaths android.Paths
+	var libraryFlags []string
+
+	for _, static_lib := range b.Properties.Static_libs {
+		if dep, ok := ctx.GetDirectDepWithTag(static_lib, cc.StaticDepTag).(*cc.Module); ok {
+			libraryPaths = append(libraryPaths, dep.ExportedIncludeDirs()...)
+			libraryFlags = append(libraryFlags, dep.ExportedFlags()...)
+		}
+	}
+	for _, shared_lib := range b.Properties.Shared_libs {
+		if dep, ok := ctx.GetDirectDepWithTag(shared_lib, cc.SharedDepTag).(*cc.Module); ok {
+			libraryPaths = append(libraryPaths, dep.ExportedIncludeDirs()...)
+			libraryFlags = append(libraryFlags, dep.ExportedFlags()...)
+		}
+	}
+
+	return libraryPaths, libraryFlags
+}
+
+func (b *bindgenDecorator) generateSource(ctx android.ModuleContext) android.Path {
+	ccToolchain := ccConfig.FindToolchain(ctx.Os(), ctx.Arch())
+	includes, exportedFlags := b.libraryExports(ctx)
+
+	var cflags []string
+	cflags = append(cflags, b.Properties.Cflags...)
+	cflags = append(cflags, "-target "+ccToolchain.ClangTriple())
+	cflags = append(cflags, strings.ReplaceAll(ccToolchain.ToolchainClangCflags(), "${config.", "${ccConfig."))
+	cflags = append(cflags, exportedFlags...)
+	for _, include := range includes {
+		cflags = append(cflags, "-I"+include.String())
+	}
+	for _, include := range b.Properties.Local_include_dirs {
+		cflags = append(cflags, "-I"+android.PathForModuleSrc(ctx, include).String())
+	}
+
+	bindgenFlags := defaultBindgenFlags
+	bindgenFlags = append(bindgenFlags, strings.Join(b.Properties.Flags, " "))
+
+	wrapperFile := android.OptionalPathForModuleSrc(ctx, b.Properties.Wrapper_src)
+	if !wrapperFile.Valid() {
+		ctx.PropertyErrorf("wrapper_src", "invalid path to wrapper source")
+	}
+
+	outputFile := android.PathForModuleOut(ctx, b.baseSourceProvider.getStem(ctx)+".rs")
+
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        bindgen,
+		Description: "bindgen " + wrapperFile.Path().Rel(),
+		Output:      outputFile,
+		Input:       wrapperFile.Path(),
+		Implicits:   includes,
+		Args: map[string]string{
+			"flags":  strings.Join(bindgenFlags, " "),
+			"cflags": strings.Join(cflags, " "),
+		},
+	})
+	b.baseSourceProvider.outputFile = outputFile
+	return outputFile
+}
+
+func (b *bindgenDecorator) sourceProviderProps() []interface{} {
+	return append(b.baseSourceProvider.sourceProviderProps(),
+		&b.Properties)
+}
+
+func RustBindgenFactory() android.Module {
+	module, _ := NewRustBindgen(android.HostAndDeviceSupported)
+	return module.Init()
+}
+
+func NewRustBindgen(hod android.HostOrDeviceSupported) (*Module, *bindgenDecorator) {
+	module := newModule(hod, android.MultilibBoth)
+
+	bindgen := &bindgenDecorator{
+		baseSourceProvider: NewSourceProvider(),
+		Properties:         BindgenProperties{},
+	}
+	module.sourceProvider = bindgen
+
+	return module, bindgen
+}
+
+func (b *bindgenDecorator) sourceProviderDeps(ctx DepsContext, deps Deps) Deps {
+	deps = b.baseSourceProvider.sourceProviderDeps(ctx, deps)
+	deps.SharedLibs = append(deps.SharedLibs, b.Properties.Shared_libs...)
+	deps.StaticLibs = append(deps.StaticLibs, b.Properties.Static_libs...)
+	return deps
+}
diff --git a/rust/bindgen_test.go b/rust/bindgen_test.go
new file mode 100644
index 0000000..18e188f
--- /dev/null
+++ b/rust/bindgen_test.go
@@ -0,0 +1,56 @@
+// Copyright 2020 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"
+)
+
+func TestRustBindgen(t *testing.T) {
+	ctx := testRust(t, `
+		rust_bindgen {
+			name: "libbindgen",
+			wrapper_src: "src/any.h",
+			stem: "bindings",
+			flags: ["--bindgen-flag"],
+			cflags: ["--clang-flag"],
+			shared_libs: ["libfoo_shared"],
+			static_libs: ["libfoo_static"],
+		}
+		cc_library_shared {
+			name: "libfoo_shared",
+			export_include_dirs: ["shared_include"],
+		}
+		cc_library_static {
+			name: "libfoo_static",
+			export_include_dirs: ["static_include"],
+		}
+
+	`)
+	libbindgen := ctx.ModuleForTests("libbindgen", "android_arm64_armv8-a").Output("bindings.rs")
+	if !strings.Contains(libbindgen.Args["flags"], "--bindgen-flag") {
+		t.Errorf("missing bindgen flags in rust_bindgen rule: flags %#v", libbindgen.Args["flags"])
+	}
+	if !strings.Contains(libbindgen.Args["cflags"], "--clang-flag") {
+		t.Errorf("missing clang cflags in rust_bindgen rule: cflags %#v", libbindgen.Args["cflags"])
+	}
+	if !strings.Contains(libbindgen.Args["cflags"], "-Ishared_include") {
+		t.Errorf("missing clang cflags in rust_bindgen rule: cflags %#v", libbindgen.Args["cflags"])
+	}
+	if !strings.Contains(libbindgen.Args["cflags"], "-Istatic_include") {
+		t.Errorf("missing clang cflags in rust_bindgen rule: cflags %#v", libbindgen.Args["cflags"])
+	}
+}
diff --git a/rust/builder.go b/rust/builder.go
index 7f94bb5..d1d1012 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -28,7 +28,7 @@
 	_     = pctx.SourcePathVariable("rustcCmd", "${config.RustBin}/rustc")
 	rustc = pctx.AndroidStaticRule("rustc",
 		blueprint.RuleParams{
-			Command: "$rustcCmd " +
+			Command: "$envVars $rustcCmd " +
 				"-C linker=${config.RustLinker} " +
 				"-C link-args=\"${crtBegin} ${config.RustLinkerArgs} ${linkFlags} ${crtEnd}\" " +
 				"--emit link -o $out --emit dep-info=$out.d $in ${libFlags} $rustcFlags",
@@ -37,7 +37,7 @@
 			Deps:    blueprint.DepsGCC,
 			Depfile: "$out.d",
 		},
-		"rustcFlags", "linkFlags", "libFlags", "crtBegin", "crtEnd")
+		"rustcFlags", "linkFlags", "libFlags", "crtBegin", "crtEnd", "envVars")
 
 	_            = pctx.SourcePathVariable("clippyCmd", "${config.RustBin}/clippy-driver")
 	clippyDriver = pctx.AndroidStaticRule("clippy",
@@ -58,6 +58,14 @@
 			Rspfile:        "$out.rsp",
 			RspfileContent: "$in",
 		})
+
+	cp = pctx.AndroidStaticRule("cp",
+		blueprint.RuleParams{
+			Command:        "cp `cat $outDir.rsp` $outDir",
+			Rspfile:        "${outDir}.rsp",
+			RspfileContent: "$in",
+		},
+		"outDir")
 )
 
 type buildOutput struct {
@@ -116,6 +124,7 @@
 
 	var inputs android.Paths
 	var implicits android.Paths
+	var envVars []string
 	var output buildOutput
 	var libFlags, rustcFlags, linkFlags []string
 	var implicitOutputs android.WritablePaths
@@ -166,7 +175,7 @@
 	implicits = append(implicits, rustLibsToPaths(deps.ProcMacros)...)
 	implicits = append(implicits, deps.StaticLibs...)
 	implicits = append(implicits, deps.SharedLibs...)
-	implicits = append(implicits, deps.SrcDeps...)
+
 	if deps.CrtBegin.Valid() {
 		implicits = append(implicits, deps.CrtBegin.Path(), deps.CrtEnd.Path())
 	}
@@ -209,6 +218,31 @@
 		implicits = append(implicits, clippyFile)
 	}
 
+	if len(deps.SrcDeps) > 0 {
+		moduleGenDir := android.PathForModuleOut(ctx, "out/")
+		var outputs android.WritablePaths
+
+		for _, genSrc := range deps.SrcDeps {
+			if android.SuffixInList(outputs.Strings(), "out/"+genSrc.Base()) {
+				ctx.PropertyErrorf("srcs",
+					"multiple source providers generate the same filename output: "+genSrc.Base())
+			}
+			outputs = append(outputs, android.PathForModuleOut(ctx, "out/"+genSrc.Base()))
+		}
+
+		ctx.Build(pctx, android.BuildParams{
+			Rule:        cp,
+			Description: "cp " + moduleGenDir.Rel(),
+			Outputs:     outputs,
+			Inputs:      deps.SrcDeps,
+			Args: map[string]string{
+				"outDir": moduleGenDir.String(),
+			},
+		})
+		implicits = append(implicits, outputs.Paths()...)
+		envVars = append(envVars, "OUT_DIR=$$PWD/"+moduleGenDir.String())
+	}
+
 	ctx.Build(pctx, android.BuildParams{
 		Rule:            rustc,
 		Description:     "rustc " + main.Rel(),
@@ -222,6 +256,7 @@
 			"libFlags":   strings.Join(libFlags, " "),
 			"crtBegin":   deps.CrtBegin.String(),
 			"crtEnd":     deps.CrtEnd.String(),
+			"envVars":    strings.Join(envVars, " "),
 		},
 	})
 
diff --git a/rust/compiler.go b/rust/compiler.go
index c20179b..ab3d2f4 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -46,6 +46,8 @@
 const (
 	InstallInSystem installLocation = 0
 	InstallInData                   = iota
+
+	incorrectSourcesError = "srcs can only contain one path for a rust file and source providers prefixed by \":\""
 )
 
 type BaseCompilerProperties struct {
@@ -253,6 +255,7 @@
 	return String(compiler.Properties.Relative_install_path)
 }
 
+// Returns the Path for the main source file along with Paths for generated source files from modules listed in srcs.
 func srcPathFromModuleSrcs(ctx ModuleContext, srcs []string) (android.Path, android.Paths) {
 	// The srcs can contain strings with prefix ":".
 	// They are dependent modules of this module, with android.SourceDepTag.
@@ -266,11 +269,11 @@
 		}
 	}
 	if numSrcs != 1 {
-		ctx.PropertyErrorf("srcs", "srcs can only contain one path for a rust file")
+		ctx.PropertyErrorf("srcs", incorrectSourcesError)
 	}
 	if srcIndex != 0 {
 		ctx.PropertyErrorf("srcs", "main source file must be the first in srcs")
 	}
 	paths := android.PathsForModuleSrc(ctx, srcs)
-	return paths[srcIndex], paths
+	return paths[srcIndex], paths[1:]
 }
diff --git a/rust/compiler_test.go b/rust/compiler_test.go
index 58ca52a..b853196 100644
--- a/rust/compiler_test.go
+++ b/rust/compiler_test.go
@@ -43,7 +43,7 @@
 // Test that we reject multiple source files.
 func TestEnforceSingleSourceFile(t *testing.T) {
 
-	singleSrcError := "srcs can only contain one path for a rust file"
+	singleSrcError := "srcs can only contain one path for a rust file and source providers prefixed by \":\""
 
 	// Test libraries
 	testRustError(t, singleSrcError, `
diff --git a/rust/library.go b/rust/library.go
index d718eb8..acca256 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -369,7 +369,7 @@
 	var outputFile android.WritablePath
 
 	srcPath, paths := srcPathFromModuleSrcs(ctx, library.baseCompiler.Properties.Srcs)
-	deps.SrcDeps = paths
+	deps.SrcDeps = append(deps.SrcDeps, paths...)
 
 	flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
 
diff --git a/rust/prebuilt.go b/rust/prebuilt.go
index 3b4f40a..3d081c1 100644
--- a/rust/prebuilt.go
+++ b/rust/prebuilt.go
@@ -96,7 +96,9 @@
 	prebuilt.exportLinkDirs(android.PathsForModuleSrc(ctx, prebuilt.Properties.Link_dirs).Strings()...)
 
 	srcPath, paths := srcPathFromModuleSrcs(ctx, prebuilt.prebuiltSrcs())
-	deps.SrcDeps = paths
+	if len(paths) > 0 {
+		ctx.PropertyErrorf("srcs", "prebuilt libraries can only have one entry in srcs (the prebuilt path)")
+	}
 
 	prebuilt.unstrippedOutputFile = srcPath
 
diff --git a/rust/proc_macro.go b/rust/proc_macro.go
index 49dbd8d..2752dc3 100644
--- a/rust/proc_macro.go
+++ b/rust/proc_macro.go
@@ -66,7 +66,7 @@
 	outputFile := android.PathForModuleOut(ctx, fileName)
 
 	srcPath, paths := srcPathFromModuleSrcs(ctx, procMacro.baseCompiler.Properties.Srcs)
-	deps.SrcDeps = paths
+	deps.SrcDeps = append(deps.SrcDeps, paths...)
 
 	procMacro.unstrippedOutputFile = outputFile
 
diff --git a/rust/rust.go b/rust/rust.go
index 7a98c64..28f8e1a 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -42,6 +42,7 @@
 		ctx.BottomUp("rust_begin", BeginMutator).Parallel()
 	})
 	pctx.Import("android/soong/rust/config")
+	pctx.ImportAs("ccConfig", "android/soong/cc/config")
 }
 
 type Flags struct {
@@ -61,9 +62,10 @@
 	AndroidMkProcMacroLibs []string
 	AndroidMkSharedLibs    []string
 	AndroidMkStaticLibs    []string
-	SubName                string `blueprint:"mutated"`
-	PreventInstall         bool
-	HideFromMake           bool
+
+	SubName        string `blueprint:"mutated"`
+	PreventInstall bool
+	HideFromMake   bool
 }
 
 type Module struct {
@@ -79,8 +81,27 @@
 	coverage         *coverage
 	clippy           *clippy
 	cachedToolchain  config.Toolchain
+	sourceProvider   SourceProvider
 	subAndroidMkOnce map[subAndroidMkProvider]bool
 	outputFile       android.OptionalPath
+
+	subName string
+}
+
+func (mod *Module) OutputFiles(tag string) (android.Paths, error) {
+	switch tag {
+	case "":
+		if mod.sourceProvider != nil {
+			return mod.sourceProvider.Srcs(), nil
+		} else {
+			if mod.outputFile.Valid() {
+				return android.Paths{mod.outputFile.Path()}, nil
+			}
+			return android.Paths{}, nil
+		}
+	default:
+		return nil, fmt.Errorf("unsupported module reference tag %q", tag)
+	}
 }
 
 var _ android.ImageInterface = (*Module)(nil)
@@ -348,6 +369,7 @@
 		&LibraryCompilerProperties{},
 		&ProcMacroCompilerProperties{},
 		&PrebuiltProperties{},
+		&SourceProviderProperties{},
 		&TestProperties{},
 		&cc.CoverageProperties{},
 		&ClippyProperties{},
@@ -507,6 +529,9 @@
 	if mod.clippy != nil {
 		mod.AddProperties(mod.clippy.props()...)
 	}
+	if mod.sourceProvider != nil {
+		mod.AddProperties(mod.sourceProvider.sourceProviderProps()...)
+	}
 
 	android.InitAndroidArchModule(mod, mod.hod, mod.multilib)
 
@@ -645,6 +670,10 @@
 		if !mod.Properties.PreventInstall {
 			mod.compiler.install(ctx, mod.outputFile.Path())
 		}
+	} else if mod.sourceProvider != nil {
+		outputFile := mod.sourceProvider.generateSource(ctx)
+		mod.outputFile = android.OptionalPathForPath(outputFile)
+		mod.subName = ctx.ModuleSubDir()
 	}
 }
 
@@ -653,6 +682,8 @@
 
 	if mod.compiler != nil {
 		deps = mod.compiler.compilerDeps(ctx, deps)
+	} else if mod.sourceProvider != nil {
+		deps = mod.sourceProvider.sourceProviderDeps(ctx, deps)
 	}
 
 	if mod.coverage != nil {
@@ -846,7 +877,6 @@
 	// Dedup exported flags from dependencies
 	depPaths.linkDirs = android.FirstUniqueStrings(depPaths.linkDirs)
 	depPaths.depFlags = android.FirstUniqueStrings(depPaths.depFlags)
-	depPaths.SrcDeps = android.FirstUniquePaths(depPaths.SrcDeps)
 
 	return depPaths
 }
@@ -963,3 +993,5 @@
 var BoolDefault = proptools.BoolDefault
 var String = proptools.String
 var StringPtr = proptools.StringPtr
+
+var _ android.OutputFileProducer = (*Module)(nil)
diff --git a/rust/rust_test.go b/rust/rust_test.go
index e803925..89dfb67 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -182,7 +182,7 @@
 		}
 		rust_library_host_rlib {
 			name: "librlib",
-			srcs: ["foo.rs", ":my_generator"],
+			srcs: ["foo.rs"],
 			crate_name: "rlib",
 		}
 		rust_proc_macro {
@@ -190,38 +190,17 @@
 			srcs: ["foo.rs"],
 			crate_name: "pm",
 		}
-		genrule {
-			name: "my_generator",
-			tools: ["any_rust_binary"],
-			cmd: "$(location) -o $(out) $(in)",
-			srcs: ["src/any.h"],
-			out: ["src/any.rs"],
-		}
 		rust_binary_host {
-			name: "fizz-buzz-dep",
+			name: "fizz-buzz",
 			dylibs: ["libdylib"],
 			rlibs: ["librlib"],
 			proc_macros: ["libpm"],
 			static_libs: ["libstatic"],
 			shared_libs: ["libshared"],
-			srcs: [
-				"foo.rs",
-				":my_generator",
-			],
+			srcs: ["foo.rs"],
 		}
 	`)
-	module := ctx.ModuleForTests("fizz-buzz-dep", "linux_glibc_x86_64").Module().(*Module)
-	rlibmodule := ctx.ModuleForTests("librlib", "linux_glibc_x86_64_rlib").Module().(*Module)
-
-	srcs := module.compiler.(*binaryDecorator).baseCompiler.Properties.Srcs
-	if len(srcs) != 2 || !android.InList(":my_generator", srcs) {
-		t.Errorf("missing module dependency in fizz-buzz)")
-	}
-
-	srcs = rlibmodule.compiler.(*libraryDecorator).baseCompiler.Properties.Srcs
-	if len(srcs) != 2 || !android.InList(":my_generator", srcs) {
-		t.Errorf("missing module dependency in rlib")
-	}
+	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("libdylib", module.Properties.AndroidMkDylibs) {
@@ -245,6 +224,73 @@
 	}
 }
 
+func TestSourceProviderDeps(t *testing.T) {
+	ctx := testRust(t, `
+		rust_binary {
+			name: "fizz-buzz-dep",
+			srcs: [
+				"foo.rs",
+				":my_generator",
+				":libbindings",
+			],
+		}
+		rust_proc_macro {
+			name: "libprocmacro",
+			srcs: [
+				"foo.rs",
+				":my_generator",
+				":libbindings",
+			],
+			crate_name: "procmacro",
+		}
+		rust_library {
+			name: "libfoo",
+			srcs: [
+				"foo.rs",
+				":my_generator",
+				":libbindings"],
+			crate_name: "foo",
+		}
+		genrule {
+			name: "my_generator",
+			tools: ["any_rust_binary"],
+			cmd: "$(location) -o $(out) $(in)",
+			srcs: ["src/any.h"],
+			out: ["src/any.rs"],
+		}
+		rust_bindgen {
+			name: "libbindings",
+			stem: "bindings",
+			host_supported: true,
+			wrapper_src: "src/any.h",
+        }
+	`)
+
+	libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib").Rule("rustc")
+	if !android.SuffixInList(libfoo.Implicits.Strings(), "/out/bindings.rs") {
+		t.Errorf("rust_bindgen generated source not included as implicit input for libfoo; Implicits %#v", libfoo.Implicits.Strings())
+	}
+	if !android.SuffixInList(libfoo.Implicits.Strings(), "/out/any.rs") {
+		t.Errorf("genrule generated source not included as implicit input for libfoo; Implicits %#v", libfoo.Implicits.Strings())
+	}
+
+	fizzBuzz := ctx.ModuleForTests("fizz-buzz-dep", "android_arm64_armv8-a").Rule("rustc")
+	if !android.SuffixInList(fizzBuzz.Implicits.Strings(), "/out/bindings.rs") {
+		t.Errorf("rust_bindgen generated source not included as implicit input for fizz-buzz-dep; Implicits %#v", libfoo.Implicits.Strings())
+	}
+	if !android.SuffixInList(fizzBuzz.Implicits.Strings(), "/out/any.rs") {
+		t.Errorf("genrule generated source not included as implicit input for fizz-buzz-dep; Implicits %#v", libfoo.Implicits.Strings())
+	}
+
+	libprocmacro := ctx.ModuleForTests("libprocmacro", "linux_glibc_x86_64").Rule("rustc")
+	if !android.SuffixInList(libprocmacro.Implicits.Strings(), "/out/bindings.rs") {
+		t.Errorf("rust_bindgen generated source not included as implicit input for libprocmacro; Implicits %#v", libfoo.Implicits.Strings())
+	}
+	if !android.SuffixInList(libprocmacro.Implicits.Strings(), "/out/any.rs") {
+		t.Errorf("genrule generated source not included as implicit input for libprocmacro; Implicits %#v", libfoo.Implicits.Strings())
+	}
+}
+
 // Test to make sure proc_macros use host variants when building device modules.
 func TestProcMacroDeviceDeps(t *testing.T) {
 	ctx := testRust(t, `
diff --git a/rust/source_provider.go b/rust/source_provider.go
new file mode 100644
index 0000000..e034d2c
--- /dev/null
+++ b/rust/source_provider.go
@@ -0,0 +1,70 @@
+// Copyright 2020 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"
+)
+
+type SourceProviderProperties struct {
+	// sets name of the output
+	Stem *string `android:"arch_variant"`
+}
+
+type baseSourceProvider struct {
+	Properties SourceProviderProperties
+
+	outputFile       android.Path
+	subAndroidMkOnce map[subAndroidMkProvider]bool
+}
+
+var _ SourceProvider = (*baseSourceProvider)(nil)
+
+type SourceProvider interface {
+	generateSource(ctx android.ModuleContext) android.Path
+	Srcs() android.Paths
+	sourceProviderProps() []interface{}
+	sourceProviderDeps(ctx DepsContext, deps Deps) Deps
+}
+
+func (sp *baseSourceProvider) Srcs() android.Paths {
+	return android.Paths{sp.outputFile}
+}
+
+func (sp *baseSourceProvider) generateSource(ctx android.ModuleContext) android.Path {
+	panic("baseSourceProviderModule does not implement generateSource()")
+}
+
+func (sp *baseSourceProvider) sourceProviderProps() []interface{} {
+	return []interface{}{&sp.Properties}
+}
+
+func NewSourceProvider() *baseSourceProvider {
+	return &baseSourceProvider{
+		Properties: SourceProviderProperties{},
+	}
+}
+
+func (sp *baseSourceProvider) getStem(ctx android.ModuleContext) string {
+	stem := ctx.ModuleName()
+	if String(sp.Properties.Stem) != "" {
+		stem = String(sp.Properties.Stem)
+	}
+	return stem
+}
+
+func (sp *baseSourceProvider) sourceProviderDeps(ctx DepsContext, deps Deps) Deps {
+	return deps
+}
diff --git a/rust/testing.go b/rust/testing.go
index 430b40b..f2d4c5e 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -81,6 +81,7 @@
 	ctx.RegisterModuleType("genrule", genrule.GenRuleFactory)
 	ctx.RegisterModuleType("rust_binary", RustBinaryFactory)
 	ctx.RegisterModuleType("rust_binary_host", RustBinaryHostFactory)
+	ctx.RegisterModuleType("rust_bindgen", RustBindgenFactory)
 	ctx.RegisterModuleType("rust_test", RustTestFactory)
 	ctx.RegisterModuleType("rust_test_host", RustTestHostFactory)
 	ctx.RegisterModuleType("rust_library", RustLibraryFactory)
diff --git a/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go
index 935d348..497f14b 100644
--- a/sdk/cc_sdk_test.go
+++ b/sdk/cc_sdk_test.go
@@ -73,12 +73,16 @@
 	result := testSdkWithCc(t, `
 		sdk {
 			name: "mysdk",
+			device_supported: false,
+			host_supported: true,
 			native_shared_libs: ["sdkmember"],
 			compile_multilib: "64",
 		}
 
 		cc_library_shared {
 			name: "sdkmember",
+			device_supported: false,
+			host_supported: true,
 			srcs: ["Test.cpp"],
 			stl: "none",
 			compile_multilib: "64",
@@ -86,8 +90,52 @@
 	`)
 
 	result.CheckSnapshot("mysdk", "",
+		checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library_shared {
+    name: "mysdk_sdkmember@current",
+    sdk_member_name: "sdkmember",
+    device_supported: false,
+    host_supported: true,
+    installable: false,
+    stl: "none",
+    compile_multilib: "64",
+    arch: {
+        x86_64: {
+            srcs: ["x86_64/lib/sdkmember.so"],
+        },
+    },
+}
+
+cc_prebuilt_library_shared {
+    name: "sdkmember",
+    prefer: false,
+    device_supported: false,
+    host_supported: true,
+    stl: "none",
+    compile_multilib: "64",
+    arch: {
+        x86_64: {
+            srcs: ["x86_64/lib/sdkmember.so"],
+        },
+    },
+}
+
+sdk_snapshot {
+    name: "mysdk@current",
+    device_supported: false,
+    host_supported: true,
+    native_shared_libs: ["mysdk_sdkmember@current"],
+    target: {
+        linux_glibc: {
+            compile_multilib: "64",
+        },
+    },
+}
+`),
 		checkAllCopyRules(`
-.intermediates/sdkmember/android_arm64_armv8-a_shared/sdkmember.so -> arm64/lib/sdkmember.so
+.intermediates/sdkmember/linux_glibc_x86_64_shared/sdkmember.so -> x86_64/lib/sdkmember.so
 `))
 }
 
@@ -271,6 +319,7 @@
     name: "mysdk_crtobj@current",
     sdk_member_name: "crtobj",
     stl: "none",
+    compile_multilib: "both",
     arch: {
         arm64: {
             srcs: ["arm64/lib/crtobj.o"],
@@ -285,6 +334,7 @@
     name: "crtobj",
     prefer: false,
     stl: "none",
+    compile_multilib: "both",
     arch: {
         arm64: {
             srcs: ["arm64/lib/crtobj.o"],
@@ -378,6 +428,7 @@
     sdk_member_name: "mynativelib",
     installable: false,
     stl: "none",
+    compile_multilib: "both",
     export_include_dirs: ["include/include"],
     arch: {
         arm64: {
@@ -394,6 +445,7 @@
     name: "mynativelib",
     prefer: false,
     stl: "none",
+    compile_multilib: "both",
     export_include_dirs: ["include/include"],
     arch: {
         arm64: {
@@ -621,9 +673,9 @@
     host_supported: true,
     installable: false,
     stl: "none",
+    compile_multilib: "both",
     static_executable: true,
     nocrt: true,
-    compile_multilib: "both",
     arch: {
         x86_64: {
             srcs: ["x86_64/bin/linker"],
@@ -640,9 +692,9 @@
     device_supported: false,
     host_supported: true,
     stl: "none",
+    compile_multilib: "both",
     static_executable: true,
     nocrt: true,
-    compile_multilib: "both",
     arch: {
         x86_64: {
             srcs: ["x86_64/bin/linker"],
@@ -702,6 +754,7 @@
     ],
     installable: false,
     stl: "none",
+    compile_multilib: "both",
     export_include_dirs: ["include/include"],
     arch: {
         arm64: {
@@ -723,6 +776,7 @@
         "apex2",
     ],
     stl: "none",
+    compile_multilib: "both",
     export_include_dirs: ["include/include"],
     arch: {
         arm64: {
@@ -824,6 +878,7 @@
     sdk_member_name: "mynativelib",
     installable: false,
     stl: "none",
+    compile_multilib: "both",
     shared_libs: [
         "mysdk_myothernativelib@current",
         "libc",
@@ -842,6 +897,7 @@
     name: "mynativelib",
     prefer: false,
     stl: "none",
+    compile_multilib: "both",
     shared_libs: [
         "myothernativelib",
         "libc",
@@ -861,6 +917,7 @@
     sdk_member_name: "myothernativelib",
     installable: false,
     stl: "none",
+    compile_multilib: "both",
     system_shared_libs: ["libm"],
     arch: {
         arm64: {
@@ -876,6 +933,7 @@
     name: "myothernativelib",
     prefer: false,
     stl: "none",
+    compile_multilib: "both",
     system_shared_libs: ["libm"],
     arch: {
         arm64: {
@@ -892,6 +950,7 @@
     sdk_member_name: "mysystemnativelib",
     installable: false,
     stl: "none",
+    compile_multilib: "both",
     arch: {
         arm64: {
             srcs: ["arm64/lib/mysystemnativelib.so"],
@@ -906,6 +965,7 @@
     name: "mysystemnativelib",
     prefer: false,
     stl: "none",
+    compile_multilib: "both",
     arch: {
         arm64: {
             srcs: ["arm64/lib/mysystemnativelib.so"],
@@ -974,6 +1034,7 @@
     installable: false,
     sdk_version: "minimum",
     stl: "none",
+    compile_multilib: "both",
     export_include_dirs: ["include/include"],
     arch: {
         x86_64: {
@@ -994,6 +1055,7 @@
     host_supported: true,
     sdk_version: "minimum",
     stl: "none",
+    compile_multilib: "both",
     export_include_dirs: ["include/include"],
     arch: {
         x86_64: {
@@ -1070,12 +1132,18 @@
     installable: false,
     stl: "none",
     target: {
+        linux_glibc: {
+            compile_multilib: "both",
+        },
         linux_glibc_x86_64: {
             srcs: ["linux_glibc/x86_64/lib/mynativelib.so"],
         },
         linux_glibc_x86: {
             srcs: ["linux_glibc/x86/lib/mynativelib.so"],
         },
+        windows: {
+            compile_multilib: "64",
+        },
         windows_x86_64: {
             srcs: ["windows/x86_64/lib/mynativelib.dll"],
         },
@@ -1089,12 +1157,18 @@
     host_supported: true,
     stl: "none",
     target: {
+        linux_glibc: {
+            compile_multilib: "both",
+        },
         linux_glibc_x86_64: {
             srcs: ["linux_glibc/x86_64/lib/mynativelib.so"],
         },
         linux_glibc_x86: {
             srcs: ["linux_glibc/x86/lib/mynativelib.so"],
         },
+        windows: {
+            compile_multilib: "64",
+        },
         windows_x86_64: {
             srcs: ["windows/x86_64/lib/mynativelib.dll"],
         },
@@ -1151,6 +1225,7 @@
     sdk_member_name: "mynativelib",
     installable: false,
     stl: "none",
+    compile_multilib: "both",
     export_include_dirs: ["include/include"],
     arch: {
         arm64: {
@@ -1168,6 +1243,7 @@
     name: "mynativelib",
     prefer: false,
     stl: "none",
+    compile_multilib: "both",
     export_include_dirs: ["include/include"],
     arch: {
         arm64: {
@@ -1236,6 +1312,7 @@
     host_supported: true,
     installable: false,
     stl: "none",
+    compile_multilib: "both",
     export_include_dirs: ["include/include"],
     arch: {
         x86_64: {
@@ -1255,6 +1332,7 @@
     device_supported: false,
     host_supported: true,
     stl: "none",
+    compile_multilib: "both",
     export_include_dirs: ["include/include"],
     arch: {
         x86_64: {
@@ -1315,6 +1393,7 @@
     sdk_member_name: "mynativelib",
     installable: false,
     stl: "none",
+    compile_multilib: "both",
     export_include_dirs: ["include/include"],
     arch: {
         arm64: {
@@ -1340,6 +1419,7 @@
     name: "mynativelib",
     prefer: false,
     stl: "none",
+    compile_multilib: "both",
     export_include_dirs: ["include/include"],
     arch: {
         arm64: {
@@ -1416,6 +1496,7 @@
     host_supported: true,
     installable: false,
     stl: "none",
+    compile_multilib: "64",
     export_include_dirs: ["include/include"],
     arch: {
         x86_64: {
@@ -1431,6 +1512,7 @@
     device_supported: false,
     host_supported: true,
     stl: "none",
+    compile_multilib: "64",
     export_include_dirs: ["include/include"],
     arch: {
         x86_64: {
@@ -1483,6 +1565,7 @@
     name: "mysdk_mynativeheaders@current",
     sdk_member_name: "mynativeheaders",
     stl: "none",
+    compile_multilib: "both",
     export_include_dirs: ["include/include"],
 }
 
@@ -1490,6 +1573,7 @@
     name: "mynativeheaders",
     prefer: false,
     stl: "none",
+    compile_multilib: "both",
     export_include_dirs: ["include/include"],
 }
 
@@ -1532,6 +1616,7 @@
     device_supported: false,
     host_supported: true,
     stl: "none",
+    compile_multilib: "both",
     export_include_dirs: ["include/include"],
 }
 
@@ -1541,6 +1626,7 @@
     device_supported: false,
     host_supported: true,
     stl: "none",
+    compile_multilib: "both",
     export_include_dirs: ["include/include"],
 }
 
@@ -1590,6 +1676,7 @@
     sdk_member_name: "mynativeheaders",
     host_supported: true,
     stl: "none",
+    compile_multilib: "both",
     export_system_include_dirs: ["common_os/include/include"],
     target: {
         android: {
@@ -1606,6 +1693,7 @@
     prefer: false,
     host_supported: true,
     stl: "none",
+    compile_multilib: "both",
     export_system_include_dirs: ["common_os/include/include"],
     target: {
         android: {
@@ -1662,6 +1750,7 @@
     name: "mysdk_sslnil@current",
     sdk_member_name: "sslnil",
     installable: false,
+    compile_multilib: "both",
     arch: {
         arm64: {
             srcs: ["arm64/lib/sslnil.so"],
@@ -1675,6 +1764,7 @@
 cc_prebuilt_library_shared {
     name: "sslnil",
     prefer: false,
+    compile_multilib: "both",
     arch: {
         arm64: {
             srcs: ["arm64/lib/sslnil.so"],
@@ -1689,6 +1779,7 @@
     name: "mysdk_sslempty@current",
     sdk_member_name: "sslempty",
     installable: false,
+    compile_multilib: "both",
     system_shared_libs: [],
     arch: {
         arm64: {
@@ -1703,6 +1794,7 @@
 cc_prebuilt_library_shared {
     name: "sslempty",
     prefer: false,
+    compile_multilib: "both",
     system_shared_libs: [],
     arch: {
         arm64: {
@@ -1718,6 +1810,7 @@
     name: "mysdk_sslnonempty@current",
     sdk_member_name: "sslnonempty",
     installable: false,
+    compile_multilib: "both",
     system_shared_libs: ["mysdk_sslnil@current"],
     arch: {
         arm64: {
@@ -1732,6 +1825,7 @@
 cc_prebuilt_library_shared {
     name: "sslnonempty",
     prefer: false,
+    compile_multilib: "both",
     system_shared_libs: ["sslnil"],
     arch: {
         arm64: {
@@ -1780,6 +1874,7 @@
     sdk_member_name: "sslvariants",
     host_supported: true,
     installable: false,
+    compile_multilib: "both",
     target: {
         android: {
             system_shared_libs: [],
@@ -1803,6 +1898,7 @@
     name: "sslvariants",
     prefer: false,
     host_supported: true,
+    compile_multilib: "both",
     target: {
         android: {
             system_shared_libs: [],
@@ -1859,6 +1955,7 @@
     name: "mysdk_stubslib@current",
     sdk_member_name: "stubslib",
     installable: false,
+    compile_multilib: "both",
     stubs: {
         versions: ["3"],
     },
@@ -1875,6 +1972,7 @@
 cc_prebuilt_library_shared {
     name: "stubslib",
     prefer: false,
+    compile_multilib: "both",
     stubs: {
         versions: ["3"],
     },
@@ -1928,6 +2026,7 @@
     sdk_member_name: "stubslib",
     host_supported: true,
     installable: false,
+    compile_multilib: "both",
     stubs: {
         versions: ["3"],
     },
@@ -1951,6 +2050,7 @@
     name: "stubslib",
     prefer: false,
     host_supported: true,
+    compile_multilib: "both",
     stubs: {
         versions: ["3"],
     },
@@ -2003,6 +2103,7 @@
     host_supported: true,
     installable: false,
     unique_host_soname: true,
+    compile_multilib: "both",
     target: {
         android_arm64: {
             srcs: ["android/arm64/lib/mylib.so"],
@@ -2024,6 +2125,7 @@
     prefer: false,
     host_supported: true,
     unique_host_soname: true,
+    compile_multilib: "both",
     target: {
         android_arm64: {
             srcs: ["android/arm64/lib/mylib.so"],
diff --git a/sdk/update.go b/sdk/update.go
index cf25008..b8d73c6 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -794,6 +794,17 @@
 	return !ok
 }
 
+// Add the properties from the given SdkMemberProperties to the blueprint
+// property set. This handles common properties in SdkMemberPropertiesBase and
+// calls the member-specific AddToPropertySet for the rest.
+func addSdkMemberPropertiesToSet(ctx *memberContext, memberProperties android.SdkMemberProperties, targetPropertySet android.BpPropertySet) {
+	if memberProperties.Base().Compile_multilib != "" {
+		targetPropertySet.AddProperty("compile_multilib", memberProperties.Base().Compile_multilib)
+	}
+
+	memberProperties.AddToPropertySet(ctx, targetPropertySet)
+}
+
 type sdkMemberRef struct {
 	memberType android.SdkMemberType
 	variant    android.SdkAware
@@ -1009,7 +1020,7 @@
 	}
 
 	// Add the os specific but arch independent properties to the module.
-	osInfo.Properties.AddToPropertySet(ctx, osPropertySet)
+	addSdkMemberPropertiesToSet(ctx, osInfo.Properties, osPropertySet)
 
 	// Add arch (and possibly os) specific sections for each set of arch (and possibly
 	// os) specific properties.
@@ -1111,11 +1122,11 @@
 func (archInfo *archTypeSpecificInfo) addToPropertySet(ctx *memberContext, archPropertySet android.BpPropertySet, archOsPrefix string) {
 	archTypeName := archInfo.archType.Name
 	archTypePropertySet := archPropertySet.AddPropertySet(archOsPrefix + archTypeName)
-	archInfo.Properties.AddToPropertySet(ctx, archTypePropertySet)
+	addSdkMemberPropertiesToSet(ctx, archInfo.Properties, archTypePropertySet)
 
 	for _, linkInfo := range archInfo.linkInfos {
 		linkPropertySet := archTypePropertySet.AddPropertySet(linkInfo.linkType)
-		linkInfo.Properties.AddToPropertySet(ctx, linkPropertySet)
+		addSdkMemberPropertiesToSet(ctx, linkInfo.Properties, linkPropertySet)
 	}
 }
 
@@ -1221,7 +1232,7 @@
 	extractCommonProperties(ctx.sdkMemberContext, commonValueExtractor, commonProperties, osSpecificPropertiesContainers)
 
 	// Add the common properties to the module.
-	commonProperties.AddToPropertySet(ctx, bpModule)
+	addSdkMemberPropertiesToSet(ctx, commonProperties, bpModule)
 
 	// Create a target property set into which target specific properties can be
 	// added.
diff --git a/tradefed/autogen.go b/tradefed/autogen.go
index 1cb874d..798fc40 100644
--- a/tradefed/autogen.go
+++ b/tradefed/autogen.go
@@ -239,6 +239,21 @@
 	return path
 }
 
+func AutoGenRobolectricTestConfig(ctx android.ModuleContext, testConfigProp *string, testConfigTemplateProp *string,
+	testSuites []string, autoGenConfig *bool) android.Path {
+	path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp)
+	if autogenPath != nil {
+		templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
+		if templatePath.Valid() {
+			autogenTemplate(ctx, autogenPath, templatePath.String(), nil)
+		} else {
+			autogenTemplate(ctx, autogenPath, "${RobolectricTestConfigTemplate}", nil)
+		}
+		return autogenPath
+	}
+	return path
+}
+
 var autogenInstrumentationTest = pctx.StaticRule("autogenInstrumentationTest", blueprint.RuleParams{
 	Command: "${AutoGenTestConfigScript} $out $in ${EmptyTestConfig} $template ${extraConfigs}",
 	CommandDeps: []string{
diff --git a/tradefed/config.go b/tradefed/config.go
index 34195c3..f7e8349 100644
--- a/tradefed/config.go
+++ b/tradefed/config.go
@@ -33,6 +33,7 @@
 	pctx.SourcePathVariable("PythonBinaryHostTestConfigTemplate", "build/make/core/python_binary_host_test_config_template.xml")
 	pctx.SourcePathVariable("RustDeviceTestConfigTemplate", "build/make/core/rust_device_test_config_template.xml")
 	pctx.SourcePathVariable("RustHostTestConfigTemplate", "build/make/core/rust_host_test_config_template.xml")
+	pctx.SourcePathVariable("RobolectricTestConfigTemplate", "build/make/core/robolectric_test_config_template.xml")
 	pctx.SourcePathVariable("ShellTestConfigTemplate", "build/make/core/shell_test_config_template.xml")
 
 	pctx.SourcePathVariable("EmptyTestConfig", "build/make/core/empty_test_config.xml")