Merge "Fix and generate vndk snapshot entirely in Soong"
diff --git a/java/androidmk.go b/java/androidmk.go
index 9e9b277..cd91b46 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -52,6 +52,7 @@
 		if r := library.deviceProperties.Target.Hostdex.Required; len(r) > 0 {
 			fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES +=", strings.Join(r, " "))
 		}
+		fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", library.Stem()+"-hostdex")
 		fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_java_prebuilt.mk")
 	}
 }
@@ -102,6 +103,7 @@
 				if library.proguardDictionary != nil {
 					entries.SetPath("LOCAL_SOONG_PROGUARD_DICT", library.proguardDictionary)
 				}
+				entries.SetString("LOCAL_MODULE_STEM", library.Stem())
 			},
 		},
 		ExtraFooters: []android.AndroidMkExtraFootersFunc{
@@ -160,6 +162,7 @@
 				entries.SetPath("LOCAL_SOONG_HEADER_JAR", prebuilt.combinedClasspathFile)
 				entries.SetPath("LOCAL_SOONG_CLASSES_JAR", prebuilt.combinedClasspathFile)
 				entries.SetString("LOCAL_SDK_VERSION", prebuilt.sdkVersion())
+				entries.SetString("LOCAL_MODULE_STEM", prebuilt.Stem())
 			},
 		},
 	}
@@ -187,6 +190,7 @@
 				if len(prebuilt.dexpreopter.builtInstalled) > 0 {
 					entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", prebuilt.dexpreopter.builtInstalled)
 				}
+				entries.SetString("LOCAL_MODULE_STEM", prebuilt.Stem())
 			},
 		},
 	}
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 2a142ba..74ef667 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -73,7 +73,7 @@
 	for i, m := range image.modules {
 		name := image.name
 		if i != 0 {
-			name += "-" + m
+			name += "-" + stemOf(m)
 		}
 
 		for _, ext := range exts {
@@ -123,6 +123,10 @@
 }
 
 func skipDexpreoptBootJars(ctx android.PathContext) bool {
+	if dexpreoptGlobalConfig(ctx).DisablePreopt {
+		return true
+	}
+
 	if ctx.Config().UnbundledBuild() {
 		return true
 	}
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index 429bbdb..b3b1317 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -96,6 +96,16 @@
 	return targets
 }
 
+func stemOf(moduleName string) string {
+	// b/139391334: the stem of framework-minus-apex is framework
+	// This is hard coded here until we find a good way to query the stem
+	// of a module before any other mutators are run
+	if moduleName == "framework-minus-apex" {
+		return "framework"
+	}
+	return moduleName
+}
+
 func getBootImageConfig(ctx android.PathContext, key android.OnceKey, name string,
 	needZip bool) bootImageConfig {
 	return ctx.Config().Once(key, func() interface{} {
@@ -110,18 +120,18 @@
 
 		for _, m := range artModules {
 			bootLocations = append(bootLocations,
-				filepath.Join("/apex/com.android.art/javalib", m+".jar"))
+				filepath.Join("/apex/com.android.art/javalib", stemOf(m)+".jar"))
 		}
 
 		for _, m := range frameworkModules {
 			bootLocations = append(bootLocations,
-				filepath.Join("/system/framework", m+".jar"))
+				filepath.Join("/system/framework", stemOf(m)+".jar"))
 		}
 
 		// The path to bootclasspath dex files needs to be known at module GenerateAndroidBuildAction time, before
 		// the bootclasspath modules have been compiled.  Set up known paths for them, the singleton rules will copy
 		// them there.
-		// TODO: use module dependencies instead
+		// TODO(b/143682396): use module dependencies instead
 		var bootDexPaths android.WritablePaths
 		for _, m := range imageModules {
 			bootDexPaths = append(bootDexPaths,
diff --git a/java/java.go b/java/java.go
index 947aa8c..d7077d1 100644
--- a/java/java.go
+++ b/java/java.go
@@ -1602,6 +1602,10 @@
 	return depTag == staticLibTag
 }
 
+func (j *Module) Stem() string {
+	return proptools.StringDefault(j.deviceProperties.Stem, j.Name())
+}
+
 //
 // Java libraries (.jar file)
 //
@@ -1631,8 +1635,7 @@
 }
 
 func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	j.dexpreopter.installPath = android.PathForModuleInstall(ctx, "framework",
-		proptools.StringDefault(j.deviceProperties.Stem, ctx.ModuleName())+".jar")
+	j.dexpreopter.installPath = android.PathForModuleInstall(ctx, "framework", j.Stem()+".jar")
 	j.dexpreopter.isSDKLibrary = j.deviceProperties.IsSDKLibrary
 	j.dexpreopter.isInstallable = Bool(j.properties.Installable)
 	j.dexpreopter.uncompressedDex = shouldUncompressDex(ctx, &j.dexpreopter)
@@ -1994,6 +1997,10 @@
 	return j.prebuilt.Name(j.ModuleBase.Name())
 }
 
+func (j *Import) Stem() string {
+	return proptools.StringDefault(j.properties.Stem, j.ModuleBase.Name())
+}
+
 func (j *Import) DepsMutator(ctx android.BottomUpMutatorContext) {
 	ctx.AddVariationDependencies(nil, libTag, j.properties.Libs...)
 }
@@ -2001,7 +2008,7 @@
 func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	jars := android.PathsForModuleSrc(ctx, j.properties.Jars)
 
-	jarName := proptools.StringDefault(j.properties.Stem, ctx.ModuleName()) + ".jar"
+	jarName := j.Stem() + ".jar"
 	outputFile := android.PathForModuleOut(ctx, "combined", jarName)
 	TransformJarsToJar(ctx, outputFile, "for prebuilts", jars, android.OptionalPath{},
 		false, j.properties.Exclude_files, j.properties.Exclude_dirs)
@@ -2178,13 +2185,16 @@
 	return j.prebuilt.Name(j.ModuleBase.Name())
 }
 
+func (j *DexImport) Stem() string {
+	return proptools.StringDefault(j.properties.Stem, j.ModuleBase.Name())
+}
+
 func (j *DexImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	if len(j.properties.Jars) != 1 {
 		ctx.PropertyErrorf("jars", "exactly one jar must be provided")
 	}
 
-	j.dexpreopter.installPath = android.PathForModuleInstall(ctx, "framework",
-		proptools.StringDefault(j.properties.Stem, ctx.ModuleName())+".jar")
+	j.dexpreopter.installPath = android.PathForModuleInstall(ctx, "framework", j.Stem()+".jar")
 	j.dexpreopter.isInstallable = true
 	j.dexpreopter.uncompressedDex = shouldUncompressDex(ctx, &j.dexpreopter)
 
diff --git a/rust/builder.go b/rust/builder.go
index 2a7643d..d9e36db 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -88,7 +88,9 @@
 	rustcFlags = append(rustcFlags, flags.GlobalRustFlags...)
 	rustcFlags = append(rustcFlags, flags.RustFlags...)
 	rustcFlags = append(rustcFlags, "--crate-type="+crate_type)
-	rustcFlags = append(rustcFlags, "--crate-name="+crate_name)
+	if crate_name != "" {
+		rustcFlags = append(rustcFlags, "--crate-name="+crate_name)
+	}
 	if targetTriple != "" {
 		rustcFlags = append(rustcFlags, "--target="+targetTriple)
 		linkFlags = append(linkFlags, "-target "+targetTriple)
diff --git a/rust/compiler.go b/rust/compiler.go
index 3f02835..85e8ba6 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -18,9 +18,10 @@
 	"fmt"
 	"path/filepath"
 
+	"github.com/google/blueprint/proptools"
+
 	"android/soong/android"
 	"android/soong/rust/config"
-	"github.com/google/blueprint/proptools"
 )
 
 func getEdition(compiler *baseCompiler) string {
@@ -64,7 +65,7 @@
 	// list of C static library dependencies
 	Static_libs []string `android:"arch_variant"`
 
-	// crate name (defaults to module name); if library, this must be the expected extern crate name
+	// crate name, required for libraries. This must be the expected extern crate name used in source
 	Crate_name string `android:"arch_variant"`
 
 	// list of features to enable for this crate
@@ -207,6 +208,7 @@
 
 	return stem
 }
+
 func (compiler *baseCompiler) relativeInstallPath() string {
 	return String(compiler.Properties.Relative_install_path)
 }
diff --git a/rust/library.go b/rust/library.go
index 273a3ce..adf6e95 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -15,6 +15,9 @@
 package rust
 
 import (
+	"regexp"
+	"strings"
+
 	"android/soong/android"
 )
 
@@ -354,6 +357,33 @@
 	return outputFile
 }
 
+func (library *libraryDecorator) getStem(ctx ModuleContext) string {
+	stem := library.baseCompiler.getStemWithoutSuffix(ctx)
+	validateLibraryStem(ctx, stem, library.crateName())
+
+	return stem + String(library.baseCompiler.Properties.Suffix)
+}
+
+var validCrateName = regexp.MustCompile("[^a-zA-Z0-9_]+")
+
+func validateLibraryStem(ctx BaseModuleContext, filename string, crate_name string) {
+	if crate_name == "" {
+		ctx.PropertyErrorf("crate_name", "crate_name must be defined.")
+	}
+
+	// crate_names are used for the library output file, and rustc expects these
+	// to be alphanumeric with underscores allowed.
+	if validCrateName.MatchString(crate_name) {
+		ctx.PropertyErrorf("crate_name",
+			"library crate_names must be alphanumeric with underscores allowed")
+	}
+
+	// Libraries are expected to begin with "lib" followed by the crate_name
+	if !strings.HasPrefix(filename, "lib"+crate_name) {
+		ctx.ModuleErrorf("Invalid name or stem property; library filenames must start with lib<crate_name>")
+	}
+}
+
 func LibraryMutator(mctx android.BottomUpMutatorContext) {
 	if m, ok := mctx.Module().(*Module); ok && m.compiler != nil {
 		switch library := m.compiler.(type) {
diff --git a/rust/library_test.go b/rust/library_test.go
index 66bcd20..9f9f374 100644
--- a/rust/library_test.go
+++ b/rust/library_test.go
@@ -77,3 +77,40 @@
 		t.Errorf("missing prefer-dynamic flag for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"])
 	}
 }
+
+func TestValidateLibraryStem(t *testing.T) {
+	testRustError(t, "crate_name must be defined.", `
+			rust_library_host {
+				name: "libfoo",
+				srcs: ["foo.rs"],
+			}`)
+
+	testRustError(t, "library crate_names must be alphanumeric with underscores allowed", `
+			rust_library_host {
+				name: "libfoo-bar",
+				srcs: ["foo.rs"],
+				crate_name: "foo-bar"
+			}`)
+
+	testRustError(t, "Invalid name or stem property; library filenames must start with lib<crate_name>", `
+			rust_library_host {
+				name: "foobar",
+				srcs: ["foo.rs"],
+				crate_name: "foo_bar"
+			}`)
+	testRustError(t, "Invalid name or stem property; library filenames must start with lib<crate_name>", `
+			rust_library_host {
+				name: "foobar",
+				stem: "libfoo",
+				srcs: ["foo.rs"],
+				crate_name: "foo_bar"
+			}`)
+	testRustError(t, "Invalid name or stem property; library filenames must start with lib<crate_name>", `
+			rust_library_host {
+				name: "foobar",
+				stem: "foo_bar",
+				srcs: ["foo.rs"],
+				crate_name: "foo_bar"
+			}`)
+
+}
diff --git a/rust/proc_macro.go b/rust/proc_macro.go
index 1a247d9..0da87da 100644
--- a/rust/proc_macro.go
+++ b/rust/proc_macro.go
@@ -77,3 +77,10 @@
 	TransformSrctoProcMacro(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
 	return outputFile
 }
+
+func (procMacro *procMacroDecorator) getStem(ctx ModuleContext) string {
+	stem := procMacro.baseCompiler.getStemWithoutSuffix(ctx)
+	validateLibraryStem(ctx, stem, procMacro.crateName())
+
+	return stem + String(procMacro.baseCompiler.Properties.Suffix)
+}
diff --git a/rust/rust.go b/rust/rust.go
index ec3b590..612e257 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -225,11 +225,7 @@
 }
 
 func (mod *Module) CrateName() string {
-	if mod.compiler != nil && mod.compiler.crateName() != "" {
-		return mod.compiler.crateName()
-	}
-	// Default crate names replace '-' in the name to '_'
-	return strings.Replace(mod.BaseModuleName(), "-", "_", -1)
+	return mod.compiler.crateName()
 }
 
 func (mod *Module) CcLibrary() bool {
diff --git a/rust/rust_test.go b/rust/rust_test.go
index eb04e72..599af09 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -129,44 +129,33 @@
 	}
 }
 
-// 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_static {
 			name: "libstatic",
 			srcs: ["foo.rs"],
+			crate_name: "static",
 		}
 		rust_library_host_shared {
 			name: "libshared",
 			srcs: ["foo.rs"],
+			crate_name: "shared",
 		}
 		rust_library_host_dylib {
 			name: "libdylib",
 			srcs: ["foo.rs"],
+			crate_name: "dylib",
 		}
 		rust_library_host_rlib {
 			name: "librlib",
 			srcs: ["foo.rs"],
+			crate_name: "rlib",
 		}
 		rust_proc_macro {
 			name: "libpm",
 			srcs: ["foo.rs"],
+			crate_name: "pm",
 		}
 		rust_binary_host {
 			name: "fizz-buzz",
@@ -208,11 +197,13 @@
 		rust_library_host_rlib {
 			name: "libbar",
 			srcs: ["foo.rs"],
+			crate_name: "bar",
 		}
 		rust_proc_macro {
 			name: "libpm",
 			rlibs: ["libbar"],
 			srcs: ["foo.rs"],
+			crate_name: "pm",
 		}
 		rust_binary {
 			name: "fizz-buzz",
diff --git a/zip/zip.go b/zip/zip.go
index 707c4ef..3c710a7 100644
--- a/zip/zip.go
+++ b/zip/zip.go
@@ -145,7 +145,7 @@
 	}
 
 	arg := b.state
-	arg.SourceFiles = strings.Split(string(list), "\n")
+	arg.SourceFiles = strings.Fields(string(list))
 	b.fileArgs = append(b.fileArgs, arg)
 	return b
 }
diff --git a/zip/zip_test.go b/zip/zip_test.go
index 84317d1..9705d6c 100644
--- a/zip/zip_test.go
+++ b/zip/zip_test.go
@@ -46,7 +46,8 @@
 	"dangling -> missing": nil,
 	"a/a/d -> b":          nil,
 	"c":                   fileC,
-	"l":                   []byte("a/a/a\na/a/b\nc\n"),
+	"l_nl":                []byte("a/a/a\na/a/b\nc\n"),
+	"l_sp":                []byte("a/a/a a/a/b c"),
 	"l2":                  []byte("missing\n"),
 	"manifest.txt":        fileCustomManifest,
 })
@@ -224,7 +225,19 @@
 		{
 			name: "list",
 			args: fileArgsBuilder().
-				List("l"),
+				List("l_nl"),
+			compressionLevel: 9,
+
+			files: []zip.FileHeader{
+				fh("a/a/a", fileA, zip.Deflate),
+				fh("a/a/b", fileB, zip.Deflate),
+				fh("c", fileC, zip.Deflate),
+			},
+		},
+		{
+			name: "list",
+			args: fileArgsBuilder().
+				List("l_sp"),
 			compressionLevel: 9,
 
 			files: []zip.FileHeader{