Merge "Always build zipapex's unflattened."
diff --git a/android/arch.go b/android/arch.go
index ad812a4..b88b275 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -15,9 +15,11 @@
 package android
 
 import (
+	"encoding"
 	"fmt"
 	"reflect"
 	"runtime"
+	"strconv"
 	"strings"
 
 	"github.com/google/blueprint/proptools"
@@ -369,6 +371,23 @@
 	return a.Name
 }
 
+var _ encoding.TextMarshaler = ArchType{}
+
+func (a ArchType) MarshalText() ([]byte, error) {
+	return []byte(strconv.Quote(a.String())), nil
+}
+
+var _ encoding.TextUnmarshaler = &ArchType{}
+
+func (a *ArchType) UnmarshalText(text []byte) error {
+	if u, ok := archTypeMap[string(text)]; ok {
+		*a = u
+		return nil
+	}
+
+	return fmt.Errorf("unknown ArchType %q", text)
+}
+
 var BuildOs = func() OsType {
 	switch runtime.GOOS {
 	case "linux":
diff --git a/android/makevars.go b/android/makevars.go
index 366bb6b..2c2fb6f 100644
--- a/android/makevars.go
+++ b/android/makevars.go
@@ -92,10 +92,6 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-func init() {
-	RegisterSingletonType("makevars", makeVarsSingletonFunc)
-}
-
 func makeVarsSingletonFunc() Singleton {
 	return &makeVarsSingleton{}
 }
diff --git a/android/paths.go b/android/paths.go
index 0c65b83..31500ab 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -697,6 +697,16 @@
 	return p.withRel(path)
 }
 
+// ReplaceExtension creates a new OutputPath with the extension replaced with ext.
+func (p OutputPath) ReplaceExtension(ctx PathContext, ext string) OutputPath {
+	if strings.Contains(ext, "/") {
+		reportPathErrorf(ctx, "extension %q cannot contain /", ext)
+	}
+	ret := PathForOutput(ctx, pathtools.ReplaceExtension(p.path, ext))
+	ret.rel = p.rel
+	return ret
+}
+
 // PathForIntermediates returns an OutputPath representing the top-level
 // intermediates directory.
 func PathForIntermediates(ctx PathContext, paths ...string) OutputPath {
diff --git a/android/paths_test.go b/android/paths_test.go
index 1ed0734..1972591 100644
--- a/android/paths_test.go
+++ b/android/paths_test.go
@@ -691,3 +691,15 @@
 		})
 	}
 }
+
+func ExampleOutputPath_ReplaceExtension() {
+	ctx := &configErrorWrapper{
+		config: TestConfig("out", nil),
+	}
+	p := PathForOutput(ctx, "system/framework/boot.art")
+	p2 := p.ReplaceExtension(ctx, "oat")
+	fmt.Println(p, p2)
+
+	// Output:
+	// out/system/framework/boot.art out/system/framework/boot.oat
+}
diff --git a/android/register.go b/android/register.go
index 6c88af1..10e14fe 100644
--- a/android/register.go
+++ b/android/register.go
@@ -99,5 +99,9 @@
 
 	registerMutators(ctx.Context, preArch, preDeps, postDeps)
 
+	// Register makevars after other singletons so they can export values through makevars
+	ctx.RegisterSingletonType("makevars", SingletonFactoryAdaptor(makeVarsSingletonFunc))
+
+	// Register env last so that it can track all used environment variables
 	ctx.RegisterSingletonType("env", SingletonFactoryAdaptor(EnvSingleton))
 }
diff --git a/android/rule_builder.go b/android/rule_builder.go
index 38018be..468b617 100644
--- a/android/rule_builder.go
+++ b/android/rule_builder.go
@@ -294,6 +294,15 @@
 	return c.Text(flag + arg)
 }
 
+// FlagForEachArg adds the specified flag joined with each argument to the command line.  The result is identical to
+// calling FlagWithArg for argument.
+func (c *RuleBuilderCommand) FlagForEachArg(flag string, args []string) *RuleBuilderCommand {
+	for _, arg := range args {
+		c.FlagWithArg(flag, arg)
+	}
+	return c
+}
+
 // FlagWithArg adds the specified flag and list of arguments to the command line, with the arguments joined by sep
 // and no separator between the flag and arguments.  The flag and arguments should not contain input or output paths or
 // the rule will not have them listed in its dependencies or outputs.
diff --git a/android/rule_builder_test.go b/android/rule_builder_test.go
index f7577a6..53a5b48 100644
--- a/android/rule_builder_test.go
+++ b/android/rule_builder_test.go
@@ -117,6 +117,14 @@
 	// ls --sort=time
 }
 
+func ExampleRuleBuilderCommand_FlagForEachArg() {
+	fmt.Println(NewRuleBuilder().Command().
+		Tool("ls").
+		FlagForEachArg("--sort=", []string{"time", "size"}))
+	// Output:
+	// ls --sort=time --sort=size
+}
+
 func ExampleRuleBuilderCommand_FlagForEachInput() {
 	fmt.Println(NewRuleBuilder().Command().
 		Tool("turbine").
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index 319e36e..8fef010 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -17,6 +17,8 @@
 import (
 	"encoding/json"
 	"io/ioutil"
+
+	"android/soong/android"
 )
 
 // GlobalConfig stores the configuration for dex preopting set by the product
@@ -66,9 +68,9 @@
 
 	EmptyDirectory string // path to an empty directory
 
-	DefaultDexPreoptImageLocation map[string]string // default boot image location for each architecture
-	CpuVariant                    map[string]string // cpu variant for each architecture
-	InstructionSetFeatures        map[string]string // instruction set for each architecture
+	DefaultDexPreoptImage  map[android.ArchType]string // default boot image location for each architecture
+	CpuVariant             map[android.ArchType]string // cpu variant for each architecture
+	InstructionSetFeatures map[android.ArchType]string // instruction set for each architecture
 
 	Tools Tools // paths to tools possibly used by the generated commands
 }
@@ -103,8 +105,8 @@
 	UsesLibraries         []string
 	LibraryPaths          map[string]string
 
-	Archs                  []string
-	DexPreoptImageLocation string
+	Archs           []android.ArchType
+	DexPreoptImages []string
 
 	PreoptExtractedApk bool // Overrides OnlyPreoptModules
 
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index c38fbff..cd931df 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -113,12 +113,9 @@
 
 			generateDM := shouldGenerateDM(module, global)
 
-			for _, arch := range module.Archs {
-				imageLocation := module.DexPreoptImageLocation
-				if imageLocation == "" {
-					imageLocation = global.DefaultDexPreoptImageLocation[arch]
-				}
-				dexpreoptCommand(global, module, rule, profile, arch, imageLocation, appImage, generateDM)
+			for i, arch := range module.Archs {
+				image := module.DexPreoptImages[i]
+				dexpreoptCommand(global, module, rule, arch, profile, image, appImage, generateDM)
 			}
 		}
 	}
@@ -181,7 +178,7 @@
 }
 
 func dexpreoptCommand(global GlobalConfig, module ModuleConfig, rule *android.RuleBuilder,
-	profile, arch, bootImageLocation string, appImage, generateDM bool) {
+	arch android.ArchType, profile, bootImage string, appImage, generateDM bool) {
 
 	// HACK: make soname in Soong-generated .odex files match Make.
 	base := filepath.Base(module.DexLocation)
@@ -195,7 +192,7 @@
 		return filepath.Join(
 			filepath.Dir(path),
 			"oat",
-			arch,
+			arch.String(),
 			pathtools.ReplaceExtension(filepath.Base(path), "odex"))
 	}
 
@@ -213,11 +210,11 @@
 
 	invocationPath := pathtools.ReplaceExtension(odexPath, "invocation")
 
-	// bootImageLocation is $OUT/dex_bootjars/system/framework/boot.art, but dex2oat actually reads
-	// $OUT/dex_bootjars/system/framework/arm64/boot.art
-	var bootImagePath string
-	if bootImageLocation != "" {
-		bootImagePath = filepath.Join(filepath.Dir(bootImageLocation), arch, filepath.Base(bootImageLocation))
+	// bootImage is .../dex_bootjars/system/framework/arm64/boot.art, but dex2oat wants
+	// .../dex_bootjars/system/framework/boot.art on the command line
+	var bootImageLocation string
+	if bootImage != "" {
+		bootImageLocation = PathToLocation(bootImage, arch)
 	}
 
 	// Lists of used and optional libraries from the build config to be verified against the manifest in the APK
@@ -325,13 +322,13 @@
 		Flag("--runtime-arg").FlagWithArg("-Xbootclasspath-locations:", bcp_locations).
 		Flag("${class_loader_context_arg}").
 		Flag("${stored_class_loader_context_arg}").
-		FlagWithArg("--boot-image=", bootImageLocation).Implicit(bootImagePath).
+		FlagWithArg("--boot-image=", bootImageLocation).Implicit(bootImage).
 		FlagWithInput("--dex-file=", module.DexPath).
 		FlagWithArg("--dex-location=", module.DexLocation).
 		FlagWithOutput("--oat-file=", odexPath).ImplicitOutput(vdexPath).
 		// Pass an empty directory, dex2oat shouldn't be reading arbitrary files
 		FlagWithArg("--android-root=", global.EmptyDirectory).
-		FlagWithArg("--instruction-set=", arch).
+		FlagWithArg("--instruction-set=", arch.String()).
 		FlagWithArg("--instruction-set-variant=", global.CpuVariant[arch]).
 		FlagWithArg("--instruction-set-features=", global.InstructionSetFeatures[arch]).
 		Flag("--no-generate-debug-info").
@@ -521,6 +518,15 @@
 	return false
 }
 
+// PathToLocation converts .../system/framework/arm64/boot.art to .../system/framework/boot.art
+func PathToLocation(path string, arch android.ArchType) string {
+	pathArch := filepath.Base(filepath.Dir(path))
+	if pathArch != arch.String() {
+		panic(fmt.Errorf("last directory in %q must be %q", path, arch.String()))
+	}
+	return filepath.Join(filepath.Dir(filepath.Dir(path)), filepath.Base(path))
+}
+
 func pathForLibrary(module ModuleConfig, lib string) string {
 	path := module.LibraryPaths[lib]
 	if path == "" {
diff --git a/dexpreopt/dexpreopt_test.go b/dexpreopt/dexpreopt_test.go
index d949852..be86190 100644
--- a/dexpreopt/dexpreopt_test.go
+++ b/dexpreopt/dexpreopt_test.go
@@ -48,7 +48,7 @@
 	Dex2oatXmx:                         "",
 	Dex2oatXms:                         "",
 	EmptyDirectory:                     "",
-	DefaultDexPreoptImageLocation:      nil,
+	DefaultDexPreoptImage:              nil,
 	CpuVariant:                         nil,
 	InstructionSetFeatures:             nil,
 	Tools: Tools{
@@ -63,28 +63,28 @@
 }
 
 var testModuleConfig = ModuleConfig{
-	Name:                   "",
-	DexLocation:            "",
-	BuildPath:              "",
-	DexPath:                "",
-	UncompressedDex:        false,
-	HasApkLibraries:        false,
-	PreoptFlags:            nil,
-	ProfileClassListing:    "",
-	ProfileIsTextListing:   false,
-	EnforceUsesLibraries:   false,
-	OptionalUsesLibraries:  nil,
-	UsesLibraries:          nil,
-	LibraryPaths:           nil,
-	Archs:                  nil,
-	DexPreoptImageLocation: "",
-	PreoptExtractedApk:     false,
-	NoCreateAppImage:       false,
-	ForceCreateAppImage:    false,
-	PresignedPrebuilt:      false,
-	NoStripping:            false,
-	StripInputPath:         "",
-	StripOutputPath:        "",
+	Name:                  "",
+	DexLocation:           "",
+	BuildPath:             "",
+	DexPath:               "",
+	UncompressedDex:       false,
+	HasApkLibraries:       false,
+	PreoptFlags:           nil,
+	ProfileClassListing:   "",
+	ProfileIsTextListing:  false,
+	EnforceUsesLibraries:  false,
+	OptionalUsesLibraries: nil,
+	UsesLibraries:         nil,
+	LibraryPaths:          nil,
+	Archs:                 []android.ArchType{android.Arm},
+	DexPreoptImages:       []string{"system/framework/arm/boot.art"},
+	PreoptExtractedApk:    false,
+	NoCreateAppImage:      false,
+	ForceCreateAppImage:   false,
+	PresignedPrebuilt:     false,
+	NoStripping:           false,
+	StripInputPath:        "",
+	StripOutputPath:       "",
 }
 
 func TestDexPreopt(t *testing.T) {
@@ -93,7 +93,6 @@
 	module.Name = "test"
 	module.DexLocation = "/system/app/test/test.apk"
 	module.BuildPath = "out/test/test.apk"
-	module.Archs = []string{"arm"}
 
 	rule, err := GenerateDexpreoptRule(global, module)
 	if err != nil {
@@ -119,7 +118,6 @@
 	module.Name = "test"
 	module.DexLocation = "/system/app/test/test.apk"
 	module.BuildPath = "out/test/test.apk"
-	module.Archs = []string{"arm"}
 
 	rule, err := GenerateDexpreoptRule(global, module)
 	if err != nil {
@@ -143,7 +141,6 @@
 	module.DexLocation = "/system/app/test/test.apk"
 	module.BuildPath = "out/test/test.apk"
 	module.ProfileClassListing = "profile"
-	module.Archs = []string{"arm"}
 
 	rule, err := GenerateDexpreoptRule(global, module)
 	if err != nil {
@@ -193,7 +190,6 @@
 			module.Name = "test"
 			module.DexLocation = "/system/app/test/test.apk"
 			module.BuildPath = "out/test/test.apk"
-			module.Archs = []string{"arm"}
 			module.StripInputPath = "$1"
 			module.StripOutputPath = "$2"
 
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index 55662cf..cb6427b 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -100,14 +100,14 @@
 		return dexpreopt.GlobalConfig{}
 	}).(dexpreopt.GlobalConfig)
 
-	var archs []string
+	var archs []android.ArchType
 	for _, a := range ctx.MultiTargets() {
-		archs = append(archs, a.Arch.ArchType.String())
+		archs = append(archs, a.Arch.ArchType)
 	}
 	if len(archs) == 0 {
 		// assume this is a java library, dexpreopt for all arches for now
 		for _, target := range ctx.Config().Targets[android.Android] {
-			archs = append(archs, target.Arch.ArchType.String())
+			archs = append(archs, target.Arch.ArchType)
 		}
 		if inList(ctx.ModuleName(), globalConfig.SystemServerJars) && !d.isSDKLibrary {
 			// If the module is not an SDK library and it's a system server jar, only preopt the primary arch.
@@ -119,6 +119,11 @@
 		archs = archs[:1]
 	}
 
+	var images []string
+	for _, arch := range archs {
+		images = append(images, globalConfig.DefaultDexPreoptImage[arch])
+	}
+
 	dexLocation := android.InstallPathToOnDevicePath(ctx, d.installPath)
 
 	strippedDexJarFile := android.PathForModuleOut(ctx, "dexpreopt", dexJarFile.Base())
@@ -161,8 +166,8 @@
 		UsesLibraries:         nil,
 		LibraryPaths:          nil,
 
-		Archs:                  archs,
-		DexPreoptImageLocation: "",
+		Archs:           archs,
+		DexPreoptImages: images,
 
 		PreoptExtractedApk: false,
 
diff --git a/java/droiddoc.go b/java/droiddoc.go
index d893c09..cbe6be6 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -630,10 +630,10 @@
 			}
 		case libTag:
 			switch dep := module.(type) {
+			case SdkLibraryDependency:
+				deps.classpath = append(deps.classpath, dep.SdkImplementationJars(ctx, j.sdkVersion())...)
 			case Dependency:
 				deps.classpath = append(deps.classpath, dep.HeaderJars()...)
-			case SdkLibraryDependency:
-				deps.classpath = append(deps.classpath, dep.ImplementationJars(ctx, j.sdkVersion())...)
 			case android.SourceFileProducer:
 				checkProducesJars(ctx, dep)
 				deps.classpath = append(deps.classpath, dep.Srcs()...)
diff --git a/java/java.go b/java/java.go
index 3d7d6ad..2c7c1f6 100644
--- a/java/java.go
+++ b/java/java.go
@@ -338,8 +338,8 @@
 }
 
 type SdkLibraryDependency interface {
-	HeaderJars(ctx android.BaseContext, sdkVersion string) android.Paths
-	ImplementationJars(ctx android.BaseContext, sdkVersion string) android.Paths
+	SdkHeaderJars(ctx android.BaseContext, sdkVersion string) android.Paths
+	SdkImplementationJars(ctx android.BaseContext, sdkVersion string) android.Paths
 }
 
 type SrcDependency interface {
@@ -698,6 +698,15 @@
 			}
 		}
 		switch dep := module.(type) {
+		case SdkLibraryDependency:
+			switch tag {
+			case libTag:
+				deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.sdkVersion())...)
+				// names of sdk libs that are directly depended are exported
+				j.exportedSdkLibs = append(j.exportedSdkLibs, otherName)
+			default:
+				ctx.ModuleErrorf("dependency on java_sdk_library %q can only be in libs", otherName)
+			}
 		case Dependency:
 			switch tag {
 			case bootClasspathTag:
@@ -748,15 +757,6 @@
 			}
 
 			deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...)
-		case SdkLibraryDependency:
-			switch tag {
-			case libTag:
-				deps.classpath = append(deps.classpath, dep.HeaderJars(ctx, j.sdkVersion())...)
-				// names of sdk libs that are directly depended are exported
-				j.exportedSdkLibs = append(j.exportedSdkLibs, otherName)
-			default:
-				ctx.ModuleErrorf("dependency on java_sdk_library %q can only be in libs", otherName)
-			}
 		case android.SourceFileProducer:
 			switch tag {
 			case libTag:
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 1b0fe75..85ce533 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -145,6 +145,9 @@
 	testApiFilePath   android.Path
 }
 
+var _ Dependency = (*sdkLibrary)(nil)
+var _ SdkLibraryDependency = (*sdkLibrary)(nil)
+
 func (module *sdkLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
 	// Add dependencies to the stubs library
 	ctx.AddVariationDependencies(nil, publicApiStubsTag, module.stubsName(apiScopePublic))
@@ -596,7 +599,7 @@
 }
 
 // to satisfy SdkLibraryDependency interface
-func (module *sdkLibrary) HeaderJars(ctx android.BaseContext, sdkVersion string) android.Paths {
+func (module *sdkLibrary) SdkHeaderJars(ctx android.BaseContext, sdkVersion string) android.Paths {
 	// This module is just a wrapper for the stubs.
 	if ctx.Config().UnbundledBuildPrebuiltSdks() {
 		return module.PrebuiltJars(ctx, sdkVersion)
@@ -612,7 +615,7 @@
 }
 
 // to satisfy SdkLibraryDependency interface
-func (module *sdkLibrary) ImplementationJars(ctx android.BaseContext, sdkVersion string) android.Paths {
+func (module *sdkLibrary) SdkImplementationJars(ctx android.BaseContext, sdkVersion string) android.Paths {
 	// This module is just a wrapper for the stubs.
 	if ctx.Config().UnbundledBuildPrebuiltSdks() {
 		return module.PrebuiltJars(ctx, sdkVersion)
diff --git a/ui/build/paths/config.go b/ui/build/paths/config.go
index 17decd0..b9713fe 100644
--- a/ui/build/paths/config.go
+++ b/ui/build/paths/config.go
@@ -74,7 +74,6 @@
 }
 
 var Configuration = map[string]PathConfig{
-	"awk":       Allowed,
 	"bash":      Allowed,
 	"bc":        Allowed,
 	"bzip2":     Allowed,
@@ -127,6 +126,7 @@
 	"pkg-config": Forbidden,
 
 	// On Linux we'll use the toybox versions of these instead.
+	"awk":       Toybox, // Strictly one-true-awk, but...
 	"basename":  Toybox,
 	"cat":       Toybox,
 	"chmod":     Toybox,