Merge "Add module name to sh_test install path."
diff --git a/android/arch.go b/android/arch.go
index 08c0256..9a54614 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -810,7 +810,7 @@
 // Valid multilib values include:
 //    "both": compile for all Targets supported by the OsClass (generally x86_64 and x86, or arm64 and arm).
 //    "first": compile for only a single preferred Target supported by the OsClass.  This is generally x86_64 or arm64,
-//        but may be arm for a 32-bit only build or a build with TARGET_PREFER_32_BIT=true set.
+//        but may be arm for a 32-bit only build.
 //    "32": compile for only a single 32-bit Target supported by the OsClass.
 //    "64": compile for only a single 64-bit Target supported by the OsClass.
 //    "common": compile a for a single Target that will work on all Targets suported by the OsClass (for example Java).
@@ -1026,6 +1026,7 @@
 			"Not_windows",
 			"Arm_on_x86",
 			"Arm_on_x86_64",
+			"Native_bridge",
 		}
 		for _, os := range OsTypeList {
 			targets = append(targets, os.Field)
@@ -1413,6 +1414,11 @@
 					prefix := "target.arm_on_x86_64"
 					m.appendProperties(ctx, genProps, targetProp, field, prefix)
 				}
+				if os == Android && m.Target().NativeBridge == NativeBridgeEnabled {
+					field := "Native_bridge"
+					prefix := "target.native_bridge"
+					m.appendProperties(ctx, genProps, targetProp, field, prefix)
+				}
 			}
 		}
 	}
diff --git a/android/arch_test.go b/android/arch_test.go
index b987d56..8525b03 100644
--- a/android/arch_test.go
+++ b/android/arch_test.go
@@ -383,3 +383,88 @@
 		})
 	}
 }
+
+func TestArchMutatorNativeBridge(t *testing.T) {
+	bp := `
+		// This module is only enabled for x86.
+		module {
+			name: "foo",
+		}
+
+		// This module is enabled for x86 and arm (via native bridge).
+		module {
+			name: "bar",
+			native_bridge_supported: true,
+		}
+
+		// This module is enabled for arm (native_bridge) only.
+		module {
+			name: "baz",
+			native_bridge_supported: true,
+			enabled: false,
+			target: {
+				native_bridge: {
+					enabled: true,
+				}
+			}
+		}
+	`
+
+	testCases := []struct {
+		name        string
+		config      func(Config)
+		fooVariants []string
+		barVariants []string
+		bazVariants []string
+	}{
+		{
+			name:        "normal",
+			config:      nil,
+			fooVariants: []string{"android_x86_64_silvermont", "android_x86_silvermont"},
+			barVariants: []string{"android_x86_64_silvermont", "android_native_bridge_arm64_armv8-a", "android_x86_silvermont", "android_native_bridge_arm_armv7-a-neon"},
+			bazVariants: []string{"android_native_bridge_arm64_armv8-a", "android_native_bridge_arm_armv7-a-neon"},
+		},
+	}
+
+	enabledVariants := func(ctx *TestContext, name string) []string {
+		var ret []string
+		variants := ctx.ModuleVariantsForTests(name)
+		for _, variant := range variants {
+			m := ctx.ModuleForTests(name, variant)
+			if m.Module().Enabled() {
+				ret = append(ret, variant)
+			}
+		}
+		return ret
+	}
+
+	for _, tt := range testCases {
+		t.Run(tt.name, func(t *testing.T) {
+			config := TestArchConfigNativeBridge(buildDir, nil, bp, nil)
+
+			ctx := NewTestArchContext()
+			ctx.RegisterModuleType("module", archTestModuleFactory)
+			ctx.Register(config)
+			if tt.config != nil {
+				tt.config(config)
+			}
+
+			_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+			FailIfErrored(t, errs)
+			_, errs = ctx.PrepareBuildActions(config)
+			FailIfErrored(t, errs)
+
+			if g, w := enabledVariants(ctx, "foo"), tt.fooVariants; !reflect.DeepEqual(w, g) {
+				t.Errorf("want foo variants:\n%q\ngot:\n%q\n", w, g)
+			}
+
+			if g, w := enabledVariants(ctx, "bar"), tt.barVariants; !reflect.DeepEqual(w, g) {
+				t.Errorf("want bar variants:\n%q\ngot:\n%q\n", w, g)
+			}
+
+			if g, w := enabledVariants(ctx, "baz"), tt.bazVariants; !reflect.DeepEqual(w, g) {
+				t.Errorf("want qux variants:\n%q\ngot:\n%q\n", w, g)
+			}
+		})
+	}
+}
diff --git a/android/config.go b/android/config.go
index 59118ce..675660e 100644
--- a/android/config.go
+++ b/android/config.go
@@ -732,14 +732,6 @@
 	return Bool(c.productVariables.Eng)
 }
 
-func (c *config) DevicePrefer32BitApps() bool {
-	return Bool(c.productVariables.DevicePrefer32BitApps)
-}
-
-func (c *config) DevicePrefer32BitExecutables() bool {
-	return Bool(c.productVariables.DevicePrefer32BitExecutables)
-}
-
 func (c *config) DevicePrimaryArchType() ArchType {
 	return c.Targets[Android][0].Arch.ArchType
 }
diff --git a/android/variable.go b/android/variable.go
index 3c08405..e025ae0 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -272,10 +272,6 @@
 	CoveragePaths        []string `json:",omitempty"`
 	CoverageExcludePaths []string `json:",omitempty"`
 
-	DevicePrefer32BitApps        *bool `json:",omitempty"`
-	DevicePrefer32BitExecutables *bool `json:",omitempty"`
-	HostPrefer32BitExecutables   *bool `json:",omitempty"`
-
 	SanitizeHost       []string `json:",omitempty"`
 	SanitizeDevice     []string `json:",omitempty"`
 	SanitizeDeviceDiag []string `json:",omitempty"`
diff --git a/apex/androidmk.go b/apex/androidmk.go
index 1b3a4ba..774b62d 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -180,13 +180,17 @@
 		}
 		switch fi.class {
 		case javaSharedLib:
-			javaModule := fi.module.(java.Dependency)
 			// soong_java_prebuilt.mk sets LOCAL_MODULE_SUFFIX := .jar  Therefore
 			// we need to remove the suffix from LOCAL_MODULE_STEM, otherwise
 			// we will have foo.jar.jar
 			fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", strings.TrimSuffix(fi.Stem(), ".jar"))
-			fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", javaModule.ImplementationAndResourcesJars()[0].String())
-			fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", javaModule.HeaderJars()[0].String())
+			if javaModule, ok := fi.module.(java.Dependency); ok {
+				fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", javaModule.ImplementationAndResourcesJars()[0].String())
+				fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", javaModule.HeaderJars()[0].String())
+			} else {
+				fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", fi.builtFile.String())
+				fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", fi.builtFile.String())
+			}
 			fmt.Fprintln(w, "LOCAL_SOONG_DEX_JAR :=", fi.builtFile.String())
 			fmt.Fprintln(w, "LOCAL_DEX_PREOPT := false")
 			fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_java_prebuilt.mk")
diff --git a/apex/apex.go b/apex/apex.go
index 2f7b2e5..d45dd6f 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -2280,9 +2280,6 @@
 	module.AddProperties(&module.properties)
 	module.AddProperties(&module.targetProperties)
 	module.AddProperties(&module.overridableProperties)
-	module.Prefer32(func(ctx android.BaseModuleContext, base *android.ModuleBase, class android.OsClass) bool {
-		return class == android.Device && ctx.Config().DevicePrefer32BitExecutables()
-	})
 	android.InitAndroidMultiTargetsArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
 	android.InitDefaultableModule(module)
 	android.InitSdkAwareModule(module)
diff --git a/apex/apex_test.go b/apex/apex_test.go
index d6a5d09..7bd0374 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -329,7 +329,7 @@
 
 // Minimal test
 func TestBasicApex(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx, config := testApex(t, `
 		apex_defaults {
 			name: "myapex-defaults",
 			manifest: ":myapex.manifest",
@@ -484,6 +484,16 @@
 
 	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule")
 
+	// Make sure that Android.mk is created
+	ab := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+	data := android.AndroidMkDataForTest(t, config, "", ab)
+	var builder strings.Builder
+	data.Custom(&builder, ab.BaseModuleName(), "TARGET_", "", data)
+
+	androidMk := builder.String()
+	ensureContains(t, androidMk, "LOCAL_MODULE := mylib.myapex\n")
+	ensureNotContains(t, androidMk, "LOCAL_MODULE := mylib.com.android.myapex\n")
+
 	optFlags := apexRule.Args["opt_flags"]
 	ensureContains(t, optFlags, "--pubkey vendor/foo/devkeys/testkey.avbpubkey")
 	// Ensure that the NOTICE output is being packaged as an asset.
diff --git a/cc/cc.go b/cc/cc.go
index 8eabff5..770391a 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -825,15 +825,8 @@
 	}
 
 	c.Prefer32(func(ctx android.BaseModuleContext, base *android.ModuleBase, class android.OsClass) bool {
-		switch class {
-		case android.Device:
-			return ctx.Config().DevicePrefer32BitExecutables()
-		case android.HostCross:
-			// Windows builds always prefer 32-bit
-			return true
-		default:
-			return false
-		}
+		// Windows builds always prefer 32-bit
+		return class == android.HostCross
 	})
 	android.InitAndroidArchModule(c, c.hod, c.multilib)
 	android.InitApexModule(c)
diff --git a/cc/config/global.go b/cc/config/global.go
index 1dd8a2d..7b651bc 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -128,8 +128,8 @@
 
 	// prebuilts/clang default settings.
 	ClangDefaultBase         = "prebuilts/clang/host"
-	ClangDefaultVersion      = "clang-r383902"
-	ClangDefaultShortVersion = "11.0.1"
+	ClangDefaultVersion      = "clang-r383902b"
+	ClangDefaultShortVersion = "11.0.2"
 
 	// Directories with warnings from Android.bp files.
 	WarningAllowedProjects = []string{
diff --git a/cc/linker.go b/cc/linker.go
index 57a0c01..c9cbd9b 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -177,7 +177,10 @@
 	Version_script *string `android:"path,arch_variant"`
 
 	// list of static libs that should not be used to build this module
-	Exclude_static_libs []string
+	Exclude_static_libs []string `android:"arch_variant"`
+
+	// list of shared libs that should not be used to build this module
+	Exclude_shared_libs []string `android:"arch_variant"`
 }
 
 func NewBaseLinker(sanitize *sanitize) *baseLinker {
@@ -223,6 +226,8 @@
 	deps.ReexportSharedLibHeaders = append(deps.ReexportSharedLibHeaders, linker.Properties.Export_shared_lib_headers...)
 	deps.ReexportGeneratedHeaders = append(deps.ReexportGeneratedHeaders, linker.Properties.Export_generated_headers...)
 
+	deps.SharedLibs = removeListFromList(deps.SharedLibs, linker.Properties.Exclude_shared_libs)
+	deps.StaticLibs = removeListFromList(deps.StaticLibs, linker.Properties.Exclude_static_libs)
 	deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Exclude_static_libs)
 
 	if Bool(linker.Properties.Use_version_lib) {
diff --git a/cc/sdk.go b/cc/sdk.go
index d05a04a..a6f94af 100644
--- a/cc/sdk.go
+++ b/cc/sdk.go
@@ -43,6 +43,7 @@
 
 			if ctx.Config().UnbundledBuild() {
 				modules[0].(*Module).Properties.HideFromMake = true
+				modules[0].(*Module).Properties.PreventInstall = true
 			} else {
 				modules[1].(*Module).Properties.SdkAndPlatformVariantVisibleToMake = true
 				modules[1].(*Module).Properties.PreventInstall = true
diff --git a/java/aar.go b/java/aar.go
index 7413c80..28e388a 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -734,6 +734,10 @@
 	return nil
 }
 
+func (a *AARImport) DexJarInstallPath() android.Path {
+	return nil
+}
+
 func (a *AARImport) AidlIncludeDirs() android.Paths {
 	return nil
 }
diff --git a/java/app.go b/java/app.go
index 24dde79..7a109be 100755
--- a/java/app.go
+++ b/java/app.go
@@ -973,10 +973,6 @@
 		&module.overridableAppProperties,
 		&module.usesLibrary.usesLibraryProperties)
 
-	module.Prefer32(func(ctx android.BaseModuleContext, base *android.ModuleBase, class android.OsClass) bool {
-		return class == android.Device && ctx.Config().DevicePrefer32BitApps()
-	})
-
 	android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
 	android.InitDefaultableModule(module)
 	android.InitOverridableModule(module, &module.appProperties.Overrides)
@@ -1887,16 +1883,22 @@
 		ctx.VisitDirectDepsWithTag(usesLibTag, func(m android.Module) {
 			dep := ctx.OtherModuleName(m)
 			if lib, ok := m.(Dependency); ok {
-				if dexJar := lib.DexJarBuildPath(); dexJar != nil {
-					usesLibPaths[dep] = &dexpreopt.LibraryPath{
-						dexJar,
-						// TODO(b/132357300): propagate actual install paths here.
-						filepath.Join("/system/framework", dep+".jar"),
-					}
-				} else {
+				buildPath := lib.DexJarBuildPath()
+				if buildPath == nil {
 					ctx.ModuleErrorf("module %q in uses_libs or optional_uses_libs must"+
 						" produce a dex jar, does it have installable: true?", dep)
+					return
 				}
+
+				var devicePath string
+				installPath := lib.DexJarInstallPath()
+				if installPath == nil {
+					devicePath = filepath.Join("/system/framework", dep+".jar")
+				} else {
+					devicePath = android.InstallPathToOnDevicePath(ctx, installPath.(android.InstallPath))
+				}
+
+				usesLibPaths[dep] = &dexpreopt.LibraryPath{buildPath, devicePath}
 			} else if ctx.Config().AllowMissingDependencies() {
 				ctx.AddMissingDependencies([]string{dep})
 			} else {
diff --git a/java/device_host_converter.go b/java/device_host_converter.go
index 1ffb13f..877fd8a 100644
--- a/java/device_host_converter.go
+++ b/java/device_host_converter.go
@@ -154,6 +154,10 @@
 	return nil
 }
 
+func (d *DeviceHostConverter) DexJarInstallPath() android.Path {
+	return nil
+}
+
 func (d *DeviceHostConverter) AidlIncludeDirs() android.Paths {
 	return nil
 }
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index 2911fd9..c33415e 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -77,10 +77,6 @@
 		return true
 	}
 
-	if ctx.Config().UnbundledBuild() {
-		return true
-	}
-
 	if d.isTest {
 		return true
 	}
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 9d93838..4120559 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -179,15 +179,7 @@
 }
 
 func skipDexpreoptBootJars(ctx android.PathContext) bool {
-	if dexpreopt.GetGlobalConfig(ctx).DisablePreopt {
-		return true
-	}
-
-	if ctx.Config().UnbundledBuild() {
-		return true
-	}
-
-	return false
+	return dexpreopt.GetGlobalConfig(ctx).DisablePreopt
 }
 
 type dexpreoptBootJars struct {
@@ -340,10 +332,12 @@
 	bootFrameworkProfileRule(ctx, image, missingDeps)
 	updatableBcpPackagesRule(ctx, image, missingDeps)
 
-	var allFiles android.Paths
+	var zipFiles android.Paths
 	for _, variant := range image.variants {
 		files := buildBootImageVariant(ctx, variant, profile, missingDeps)
-		allFiles = append(allFiles, files.Paths()...)
+		if variant.target.Os == android.Android {
+			zipFiles = append(zipFiles, files.Paths()...)
+		}
 	}
 
 	if image.zip != nil {
@@ -351,8 +345,8 @@
 		rule.Command().
 			BuiltTool(ctx, "soong_zip").
 			FlagWithOutput("-o ", image.zip).
-			FlagWithArg("-C ", image.dir.String()).
-			FlagWithInputList("-f ", allFiles, " -f ")
+			FlagWithArg("-C ", image.dir.Join(ctx, android.Android.String()).String()).
+			FlagWithInputList("-f ", zipFiles, " -f ")
 
 		rule.Build(pctx, ctx, "zip_"+image.name, "zip "+image.name+" image")
 	}
diff --git a/java/dexpreopt_bootjars_test.go b/java/dexpreopt_bootjars_test.go
index e9704dc..9670c7f 100644
--- a/java/dexpreopt_bootjars_test.go
+++ b/java/dexpreopt_bootjars_test.go
@@ -118,7 +118,7 @@
 
 	ctx := android.PathContextForTesting(testConfig(nil, "", nil))
 	expectedInputs := []string{}
-	for _, target := range dexpreoptTargets(ctx) {
+	for _, target := range ctx.Config().Targets[android.Android] {
 		for _, ext := range []string{".art", ".oat", ".vdex"} {
 			for _, jar := range []string{"foo", "bar", "baz"} {
 				expectedInputs = append(expectedInputs,
diff --git a/java/java.go b/java/java.go
index af68e56..5f8ad03 100644
--- a/java/java.go
+++ b/java/java.go
@@ -502,6 +502,7 @@
 	ResourceJars() android.Paths
 	ImplementationAndResourcesJars() android.Paths
 	DexJarBuildPath() android.Path
+	DexJarInstallPath() android.Path
 	AidlIncludeDirs() android.Paths
 	ExportedSdkLibs() []string
 	ExportedPlugins() (android.Paths, []string)
@@ -1749,6 +1750,10 @@
 	return j.dexJarFile
 }
 
+func (j *Module) DexJarInstallPath() android.Path {
+	return j.installFile
+}
+
 func (j *Module) ResourceJars() android.Paths {
 	if j.resourceJar == nil {
 		return nil
@@ -2575,6 +2580,10 @@
 	return nil
 }
 
+func (j *Import) DexJarInstallPath() android.Path {
+	return nil
+}
+
 func (j *Import) AidlIncludeDirs() android.Paths {
 	return j.exportAidlIncludeDirs
 }
@@ -2754,8 +2763,10 @@
 
 	j.maybeStrippedDexJarFile = dexOutputFile
 
-	ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"),
-		j.Stem()+".jar", dexOutputFile)
+	if j.IsForPlatform() {
+		ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"),
+			j.Stem()+".jar", dexOutputFile)
+	}
 }
 
 func (j *DexImport) DexJarBuildPath() android.Path {
diff --git a/python/androidmk.go b/python/androidmk.go
index d293d52..247b80d 100644
--- a/python/androidmk.go
+++ b/python/androidmk.go
@@ -66,15 +66,9 @@
 			fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE :=",
 				strings.Join(p.binaryDecorator.binaryProperties.Test_suites, " "))
 		}
-		// If the test config has an explicit config specified use it.
-		if p.testProperties.Test_config != nil {
-			fmt.Fprintln(w, "LOCAL_TEST_CONFIG :=",
-				*p.testProperties.Test_config)
-		} else {
-			if p.testConfig != nil {
-				fmt.Fprintln(w, "LOCAL_FULL_TEST_CONFIG :=",
-					p.testConfig.String())
-			}
+		if p.testConfig != nil {
+			fmt.Fprintln(w, "LOCAL_FULL_TEST_CONFIG :=",
+				p.testConfig.String())
 		}
 
 		if !BoolDefault(p.binaryProperties.Auto_gen_config, true) {
diff --git a/python/test.go b/python/test.go
index f684fd5..a669c73 100644
--- a/python/test.go
+++ b/python/test.go
@@ -29,11 +29,11 @@
 type TestProperties struct {
 	// the name of the test configuration (for example "AndroidTest.xml") that should be
 	// installed with the module.
-	Test_config *string `android:"arch_variant"`
+	Test_config *string `android:"path,arch_variant"`
 
 	// the name of the test configuration template (for example "AndroidTestTemplate.xml") that
 	// should be installed with the module.
-	Test_config_template *string `android:"arch_variant"`
+	Test_config_template *string `android:"path,arch_variant"`
 }
 
 type testDecorator struct {
diff --git a/rust/Android.bp b/rust/Android.bp
index 684db0b..b06ea8e 100644
--- a/rust/Android.bp
+++ b/rust/Android.bp
@@ -16,6 +16,7 @@
         "library.go",
         "prebuilt.go",
         "proc_macro.go",
+	"project_json.go",
         "rust.go",
         "test.go",
         "testing.go",
@@ -25,6 +26,7 @@
         "compiler_test.go",
         "coverage_test.go",
         "library_test.go",
+	"project_json_test.go",
         "rust_test.go",
         "test_test.go",
     ],
diff --git a/rust/library.go b/rust/library.go
index 8aa033c..2e51266 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -329,12 +329,21 @@
 
 	return deps
 }
+
+func (library *libraryDecorator) sharedLibFilename(ctx ModuleContext) string {
+	return library.getStem(ctx) + ctx.toolchain().SharedLibSuffix()
+}
+
 func (library *libraryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags {
 	flags.RustFlags = append(flags.RustFlags, "-C metadata="+ctx.baseModuleName())
 	flags = library.baseCompiler.compilerFlags(ctx, flags)
 	if library.shared() || library.static() {
 		library.includeDirs = append(library.includeDirs, android.PathsForModuleSrc(ctx, library.Properties.Include_dirs)...)
 	}
+	if library.shared() {
+		flags.LinkFlags = append(flags.LinkFlags, "-Wl,-soname="+library.sharedLibFilename(ctx))
+	}
+
 	return flags
 }
 
@@ -371,7 +380,7 @@
 		outputs := TransformSrctoStatic(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
 		library.coverageFile = outputs.coverageFile
 	} else if library.shared() {
-		fileName := library.getStem(ctx) + ctx.toolchain().SharedLibSuffix()
+		fileName := library.sharedLibFilename(ctx)
 		outputFile = android.PathForModuleOut(ctx, fileName)
 
 		outputs := TransformSrctoShared(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
diff --git a/rust/library_test.go b/rust/library_test.go
index 9f9f374..37dd541 100644
--- a/rust/library_test.go
+++ b/rust/library_test.go
@@ -114,3 +114,17 @@
 			}`)
 
 }
+
+func TestSharedLibraryFlags(t *testing.T) {
+	ctx := testRust(t, `
+		rust_library_host {
+			name: "libfoo",
+			srcs: ["foo.rs"],
+			crate_name: "foo",
+		}`)
+
+	libfooShared := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_shared").Output("libfoo.so")
+	if !strings.Contains(libfooShared.Args["linkFlags"], "-Wl,-soname=libfoo.so") {
+		t.Errorf("missing expected -Wl,-soname linker flag for libfoo shared lib, linkFlags: %#v", libfooShared.Args["linkFlags"])
+	}
+}
diff --git a/rust/project_json.go b/rust/project_json.go
new file mode 100644
index 0000000..909aebc
--- /dev/null
+++ b/rust/project_json.go
@@ -0,0 +1,161 @@
+// 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 rust
+
+import (
+	"encoding/json"
+	"fmt"
+	"path"
+
+	"android/soong/android"
+)
+
+// This singleton collects Rust crate definitions and generates a JSON file
+// (${OUT_DIR}/soong/rust-project.json) which can be use by external tools,
+// such as rust-analyzer. It does so when either make, mm, mma, mmm or mmma is
+// called.  This singleton is enabled only if SOONG_GEN_RUST_PROJECT is set.
+// For example,
+//
+//   $ SOONG_GEN_RUST_PROJECT=1 m nothing
+
+func init() {
+	android.RegisterSingletonType("rust_project_generator", rustProjectGeneratorSingleton)
+}
+
+func rustProjectGeneratorSingleton() android.Singleton {
+	return &projectGeneratorSingleton{}
+}
+
+type projectGeneratorSingleton struct{}
+
+const (
+	// Environment variables used to control the behavior of this singleton.
+	envVariableCollectRustDeps = "SOONG_GEN_RUST_PROJECT"
+	rustProjectJsonFileName    = "rust-project.json"
+)
+
+// The format of rust-project.json is not yet finalized. A current description is available at:
+// https://github.com/rust-analyzer/rust-analyzer/blob/master/docs/user/manual.adoc#non-cargo-based-projects
+type rustProjectDep struct {
+	Crate int    `json:"crate"`
+	Name  string `json:"name"`
+}
+
+type rustProjectCrate struct {
+	RootModule string           `json:"root_module"`
+	Edition    string           `json:"edition,omitempty"`
+	Deps       []rustProjectDep `json:"deps"`
+	Cfgs       []string         `json:"cfgs"`
+}
+
+type rustProjectJson struct {
+	Roots  []string           `json:"roots"`
+	Crates []rustProjectCrate `json:"crates"`
+}
+
+// crateInfo is used during the processing to keep track of the known crates.
+type crateInfo struct {
+	ID   int
+	Deps map[string]int
+}
+
+func mergeDependencies(ctx android.SingletonContext, project *rustProjectJson,
+	knownCrates map[string]crateInfo, module android.Module,
+	crate *rustProjectCrate, deps map[string]int) {
+
+	//TODO(tweek): The stdlib dependencies do not appear here. We need to manually add them.
+	ctx.VisitDirectDeps(module, func(child android.Module) {
+		childId, childName, ok := appendLibraryAndDeps(ctx, project, knownCrates, child)
+		if !ok {
+			return
+		}
+		if _, ok = deps[childName]; ok {
+			return
+		}
+		crate.Deps = append(crate.Deps, rustProjectDep{Crate: childId, Name: childName})
+		deps[childName] = childId
+	})
+}
+
+// appendLibraryAndDeps creates a rustProjectCrate for the module argument and
+// appends it to the rustProjectJson struct.  It visits the dependencies of the
+// module depth-first. If the current module is already in knownCrates, its
+// its dependencies are merged. Returns a tuple (id, crate_name, ok).
+func appendLibraryAndDeps(ctx android.SingletonContext, project *rustProjectJson,
+	knownCrates map[string]crateInfo, module android.Module) (int, string, bool) {
+	rModule, ok := module.(*Module)
+	if !ok {
+		return 0, "", false
+	}
+	if rModule.compiler == nil {
+		return 0, "", false
+	}
+	rustLib, ok := rModule.compiler.(*libraryDecorator)
+	if !ok {
+		return 0, "", false
+	}
+	crateName := rModule.CrateName()
+	if cInfo, ok := knownCrates[crateName]; ok {
+		// We have seen this crate already; merge any new dependencies.
+		crate := project.Crates[cInfo.ID]
+		mergeDependencies(ctx, project, knownCrates, module, &crate, cInfo.Deps)
+		return cInfo.ID, crateName, true
+	}
+	crate := rustProjectCrate{Deps: make([]rustProjectDep, 0), Cfgs: make([]string, 0)}
+	src := rustLib.Properties.Srcs[0]
+	crate.RootModule = path.Join(ctx.ModuleDir(rModule), src)
+	crate.Edition = getEdition(rustLib.baseCompiler)
+
+	deps := make(map[string]int)
+	mergeDependencies(ctx, project, knownCrates, module, &crate, deps)
+
+	id := len(project.Crates)
+	knownCrates[crateName] = crateInfo{ID: id, Deps: deps}
+	project.Crates = append(project.Crates, crate)
+	// rust-analyzer requires that all crates belong to at least one root:
+	// https://github.com/rust-analyzer/rust-analyzer/issues/4735.
+	project.Roots = append(project.Roots, path.Dir(crate.RootModule))
+	return id, crateName, true
+}
+
+func (r *projectGeneratorSingleton) GenerateBuildActions(ctx android.SingletonContext) {
+	if !ctx.Config().IsEnvTrue(envVariableCollectRustDeps) {
+		return
+	}
+
+	project := rustProjectJson{}
+	knownCrates := make(map[string]crateInfo)
+	ctx.VisitAllModules(func(module android.Module) {
+		appendLibraryAndDeps(ctx, &project, knownCrates, module)
+	})
+
+	path := android.PathForOutput(ctx, rustProjectJsonFileName)
+	err := createJsonFile(project, path)
+	if err != nil {
+		ctx.Errorf(err.Error())
+	}
+}
+
+func createJsonFile(project rustProjectJson, rustProjectPath android.WritablePath) error {
+	buf, err := json.MarshalIndent(project, "", "  ")
+	if err != nil {
+		return fmt.Errorf("JSON marshal of rustProjectJson failed: %s", err)
+	}
+	err = android.WriteFileToOutputDir(rustProjectPath, buf, 0666)
+	if err != nil {
+		return fmt.Errorf("Writing rust-project to %s failed: %s", rustProjectPath.String(), err)
+	}
+	return nil
+}
diff --git a/rust/project_json_test.go b/rust/project_json_test.go
new file mode 100644
index 0000000..6786e72
--- /dev/null
+++ b/rust/project_json_test.go
@@ -0,0 +1,55 @@
+// 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 rust
+
+import (
+	"io/ioutil"
+	"path/filepath"
+	"testing"
+
+	"android/soong/android"
+	"android/soong/cc"
+)
+
+func TestProjectJson(t *testing.T) {
+	bp := `rust_library {
+		  name: "liba",
+		  srcs: ["src/lib.rs"],
+		  crate_name: "a"
+		}` + GatherRequiredDepsForTest()
+	env := map[string]string{"SOONG_GEN_RUST_PROJECT": "1"}
+	fs := map[string][]byte{
+		"foo.rs":     nil,
+		"src/lib.rs": nil,
+	}
+
+	cc.GatherRequiredFilesForTest(fs)
+
+	config := android.TestArchConfig(buildDir, env, bp, fs)
+	ctx := CreateTestContext()
+	ctx.Register(config)
+	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+	android.FailIfErrored(t, errs)
+	_, errs = ctx.PrepareBuildActions(config)
+	android.FailIfErrored(t, errs)
+
+	// The JSON file is generated via WriteFileToOutputDir. Therefore, it
+	// won't appear in the Output of the TestingSingleton. Manually verify
+	// it exists.
+	_, err := ioutil.ReadFile(filepath.Join(buildDir, "rust-project.json"))
+	if err != nil {
+		t.Errorf("rust-project.json has not been generated")
+	}
+}
diff --git a/rust/test.go b/rust/test.go
index 94568c1..10c2785 100644
--- a/rust/test.go
+++ b/rust/test.go
@@ -25,11 +25,11 @@
 type TestProperties struct {
 	// the name of the test configuration (for example "AndroidTest.xml") that should be
 	// installed with the module.
-	Test_config *string `android:"arch_variant"`
+	Test_config *string `android:"path,arch_variant"`
 
 	// the name of the test configuration template (for example "AndroidTestTemplate.xml") that
 	// should be installed with the module.
-	Test_config_template *string `android:"arch_variant"`
+	Test_config_template *string `android:"path,arch_variant"`
 
 	// list of compatibility suites (for example "cts", "vts") that the module should be
 	// installed into.
diff --git a/rust/testing.go b/rust/testing.go
index 09008a8..f94af71 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -100,6 +100,7 @@
 		ctx.BottomUp("rust_unit_tests", TestPerSrcMutator).Parallel()
 		ctx.BottomUp("rust_begin", BeginMutator).Parallel()
 	})
+	ctx.RegisterSingletonType("rust_project_generator", rustProjectGeneratorSingleton)
 
 	return ctx
 }
diff --git a/sh/sh_binary.go b/sh/sh_binary.go
index 37e8253..ae653fd 100644
--- a/sh/sh_binary.go
+++ b/sh/sh_binary.go
@@ -70,7 +70,7 @@
 
 	// the name of the test configuration (for example "AndroidTest.xml") that should be
 	// installed with the module.
-	Test_config *string `android:"arch_variant"`
+	Test_config *string `android:"path,arch_variant"`
 
 	// list of files or filegroup modules that provide data that should be installed alongside
 	// the test.
@@ -234,12 +234,8 @@
 
 				entries.SetPath("LOCAL_MODULE_PATH", s.installDir.ToMakePath())
 				entries.AddStrings("LOCAL_COMPATIBILITY_SUITE", s.testProperties.Test_suites...)
-				if s.testProperties.Test_config != nil {
-					entries.SetString("LOCAL_TEST_CONFIG", proptools.String(s.testProperties.Test_config))
-				} else {
-					if s.testConfig != nil {
-						entries.SetString("LOCAL_FULL_TEST_CONFIG", s.testConfig.String())
-					}
+				if s.testConfig != nil {
+					entries.SetPath("LOCAL_FULL_TEST_CONFIG", s.testConfig)
 				}
 				for _, d := range s.data {
 					rel := d.Rel()
@@ -263,9 +259,6 @@
 // executable binary to <partition>/bin.
 func ShBinaryFactory() android.Module {
 	module := &ShBinary{}
-	module.Prefer32(func(ctx android.BaseModuleContext, base *android.ModuleBase, class android.OsClass) bool {
-		return class == android.Device && ctx.Config().DevicePrefer32BitExecutables()
-	})
 	InitShBinaryModule(module)
 	android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibFirst)
 	return module
diff --git a/ui/build/config.go b/ui/build/config.go
index 49f506e..c4bbad7 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -592,6 +592,7 @@
 	c.environ.Set("TARGET_BUILD_VARIANT", variant)
 	c.environ.Set("TARGET_BUILD_TYPE", "release")
 	c.environ.Unset("TARGET_BUILD_APPS")
+	c.environ.Unset("TARGET_BUILD_UNBUNDLED")
 }
 
 // Tapas configures the environment to build one or more unbundled apps,
diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go
index 7dc4915..e229856 100644
--- a/ui/build/dumpvars.go
+++ b/ui/build/dumpvars.go
@@ -143,6 +143,7 @@
 	"TARGET_BUILD_VARIANT",
 	"TARGET_BUILD_TYPE",
 	"TARGET_BUILD_APPS",
+	"TARGET_BUILD_UNBUNDLED",
 	"TARGET_ARCH",
 	"TARGET_ARCH_VARIANT",
 	"TARGET_CPU_VARIANT",
@@ -187,6 +188,7 @@
 		"TARGET_PRODUCT",
 		"TARGET_BUILD_VARIANT",
 		"TARGET_BUILD_APPS",
+		"TARGET_BUILD_UNBUNDLED",
 
 		// compiler wrappers set up by make
 		"CC_WRAPPER",