Merge "Use no_libcrt property instead of hard coding projects to exclude"
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/onceper.go b/android/onceper.go
index 6160506..f06f428 100644
--- a/android/onceper.go
+++ b/android/onceper.go
@@ -20,37 +20,51 @@
 )
 
 type OncePer struct {
-	values     sync.Map
-	valuesLock sync.Mutex
+	values sync.Map
+}
+
+type onceValueWaiter chan bool
+
+func (once *OncePer) maybeWaitFor(key OnceKey, value interface{}) interface{} {
+	if wait, isWaiter := value.(onceValueWaiter); isWaiter {
+		// The entry in the map is a placeholder waiter because something else is constructing the value
+		// wait until the waiter is signalled, then load the real value.
+		<-wait
+		value, _ = once.values.Load(key)
+		if _, isWaiter := value.(onceValueWaiter); isWaiter {
+			panic(fmt.Errorf("Once() waiter completed but key is still not valid"))
+		}
+	}
+
+	return value
 }
 
 // Once computes a value the first time it is called with a given key per OncePer, and returns the
 // value without recomputing when called with the same key.  key must be hashable.
-func (once *OncePer) Once(key interface{}, value func() interface{}) interface{} {
+func (once *OncePer) Once(key OnceKey, value func() interface{}) interface{} {
 	// Fast path: check if the key is already in the map
 	if v, ok := once.values.Load(key); ok {
-		return v
+		return once.maybeWaitFor(key, v)
 	}
 
-	// Slow path: lock so that we don't call the value function twice concurrently
-	once.valuesLock.Lock()
-	defer once.valuesLock.Unlock()
-
-	// Check again with the lock held
-	if v, ok := once.values.Load(key); ok {
-		return v
+	// Slow path: create a OnceValueWrapper and attempt to insert it
+	waiter := make(onceValueWaiter)
+	if v, loaded := once.values.LoadOrStore(key, waiter); loaded {
+		// Got a value, something else inserted its own waiter or a constructed value
+		return once.maybeWaitFor(key, v)
 	}
 
-	// Still not in the map, call the value function and store it
+	// The waiter is inserted, call the value constructor, store it, and signal the waiter
 	v := value()
 	once.values.Store(key, v)
+	close(waiter)
 
 	return v
 }
 
 // Get returns the value previously computed with Once for a given key.  If Once has not been called for the given
 // key Get will panic.
-func (once *OncePer) Get(key interface{}) interface{} {
+func (once *OncePer) Get(key OnceKey) interface{} {
 	v, ok := once.values.Load(key)
 	if !ok {
 		panic(fmt.Errorf("Get() called before Once()"))
@@ -60,12 +74,12 @@
 }
 
 // OnceStringSlice is the same as Once, but returns the value cast to a []string
-func (once *OncePer) OnceStringSlice(key interface{}, value func() []string) []string {
+func (once *OncePer) OnceStringSlice(key OnceKey, value func() []string) []string {
 	return once.Once(key, func() interface{} { return value() }).([]string)
 }
 
 // OnceStringSlice is the same as Once, but returns two values cast to []string
-func (once *OncePer) Once2StringSlice(key interface{}, value func() ([]string, []string)) ([]string, []string) {
+func (once *OncePer) Once2StringSlice(key OnceKey, value func() ([]string, []string)) ([]string, []string) {
 	type twoStringSlice [2][]string
 	s := once.Once(key, func() interface{} {
 		var s twoStringSlice
diff --git a/android/onceper_test.go b/android/onceper_test.go
index d2ca9ad..f27799b 100644
--- a/android/onceper_test.go
+++ b/android/onceper_test.go
@@ -133,3 +133,14 @@
 		t.Errorf(`second call to Once with the NewCustomOnceKey from equal key should return "a": %q`, b)
 	}
 }
+
+func TestOncePerReentrant(t *testing.T) {
+	once := OncePer{}
+	key1 := NewOnceKey("key")
+	key2 := NewOnceKey("key")
+
+	a := once.Once(key1, func() interface{} { return once.Once(key2, func() interface{} { return "a" }) })
+	if a != "a" {
+		t.Errorf(`reentrant Once should return "a": %q`, a)
+	}
+}
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/apex/apex.go b/apex/apex.go
index 0337afb..e7f498a 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -212,6 +212,10 @@
 	// "apex_manifest.json"
 	Manifest *string
 
+	// AndroidManifest.xml file used for the zip container of this APEX bundle.
+	// If unspecified, a default one is automatically generated.
+	AndroidManifest *string
+
 	// Determines the file contexts file for setting security context to each file in this APEX bundle.
 	// Specifically, when this is set to <value>, /system/sepolicy/apex/<value>_file_contexts file is
 	// used.
@@ -513,12 +517,20 @@
 	}
 	ctx.AddDependency(ctx.Module(), keyTag, String(a.properties.Key))
 
-	cert := android.SrcIsModule(String(a.properties.Certificate))
+	cert := android.SrcIsModule(a.getCertString(ctx))
 	if cert != "" {
 		ctx.AddDependency(ctx.Module(), certificateTag, cert)
 	}
 }
 
+func (a *apexBundle) getCertString(ctx android.BaseContext) string {
+	certificate, overridden := ctx.DeviceConfig().OverrideCertificateFor(ctx.ModuleName())
+	if overridden {
+		return ":" + certificate
+	}
+	return String(a.properties.Certificate)
+}
+
 func (a *apexBundle) Srcs() android.Paths {
 	if file, ok := a.outputFiles[imageApex]; ok {
 		return android.Paths{file}
@@ -901,6 +913,12 @@
 			optFlags = append(optFlags, "--override_apk_package_name "+manifestPackageName)
 		}
 
+		if a.properties.AndroidManifest != nil {
+			androidManifestFile := android.PathForModuleSrc(ctx, proptools.String(a.properties.AndroidManifest))
+			implicitInputs = append(implicitInputs, androidManifestFile)
+			optFlags = append(optFlags, "--android_manifest "+androidManifestFile.String())
+		}
+
 		ctx.Build(pctx, android.BuildParams{
 			Rule:        apexRule,
 			Implicits:   implicitInputs,
@@ -966,7 +984,7 @@
 	})
 
 	// Install to $OUT/soong/{target,host}/.../apex
-	if a.installable() && !ctx.Config().FlattenApex() {
+	if a.installable() && (!ctx.Config().FlattenApex() || apexType.zip()) {
 		ctx.InstallFile(android.PathForModuleInstall(ctx, "apex"), ctx.ModuleName()+suffix, a.outputFiles[apexType])
 	}
 }
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 2c7f285..13ddb55 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -24,6 +24,7 @@
 
 	"android/soong/android"
 	"android/soong/cc"
+	"android/soong/java"
 )
 
 func testApex(t *testing.T, bp string) *android.TestContext {
@@ -51,6 +52,7 @@
 	ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(cc.ToolchainLibraryFactory))
 	ctx.RegisterModuleType("prebuilt_etc", android.ModuleFactoryAdaptor(android.PrebuiltEtcFactory))
 	ctx.RegisterModuleType("sh_binary", android.ModuleFactoryAdaptor(android.ShBinaryFactory))
+	ctx.RegisterModuleType("android_app_certificate", android.ModuleFactoryAdaptor(java.AndroidAppCertificateFactory))
 	ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
 		ctx.BottomUp("image", cc.ImageMutator).Parallel()
 		ctx.BottomUp("link", cc.LinkageMutator).Parallel()
@@ -138,18 +140,23 @@
 	`
 
 	ctx.MockFileSystem(map[string][]byte{
-		"Android.bp":                                   []byte(bp),
-		"build/target/product/security":                nil,
-		"apex_manifest.json":                           nil,
-		"system/sepolicy/apex/myapex-file_contexts":    nil,
-		"system/sepolicy/apex/otherapex-file_contexts": nil,
-		"mylib.cpp":                                    nil,
-		"myprebuilt":                                   nil,
-		"my_include":                                   nil,
-		"vendor/foo/devkeys/test.x509.pem":             nil,
-		"vendor/foo/devkeys/test.pk8":                  nil,
-		"vendor/foo/devkeys/testkey.avbpubkey":         nil,
-		"vendor/foo/devkeys/testkey.pem":               nil,
+		"Android.bp":                                        []byte(bp),
+		"build/target/product/security":                     nil,
+		"apex_manifest.json":                                nil,
+		"system/sepolicy/apex/myapex-file_contexts":         nil,
+		"system/sepolicy/apex/myapex_keytest-file_contexts": nil,
+		"system/sepolicy/apex/otherapex-file_contexts":      nil,
+		"mylib.cpp":                            nil,
+		"myprebuilt":                           nil,
+		"my_include":                           nil,
+		"vendor/foo/devkeys/test.x509.pem":     nil,
+		"vendor/foo/devkeys/test.pk8":          nil,
+		"testkey.x509.pem":                     nil,
+		"testkey.pk8":                          nil,
+		"testkey.override.x509.pem":            nil,
+		"testkey.override.pk8":                 nil,
+		"vendor/foo/devkeys/testkey.avbpubkey": nil,
+		"vendor/foo/devkeys/testkey.pem":       nil,
 	})
 	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
 	android.FailIfErrored(t, errs)
@@ -168,6 +175,7 @@
 	config = android.TestArchConfig(buildDir, nil)
 	config.TestProductVariables.DeviceVndkVersion = proptools.StringPtr("current")
 	config.TestProductVariables.DefaultAppCertificate = proptools.StringPtr("vendor/foo/devkeys/test")
+	config.TestProductVariables.CertificateOverrides = []string{"myapex_keytest:myapex.certificate.override"}
 	return
 }
 
@@ -773,8 +781,9 @@
 func TestKeys(t *testing.T) {
 	ctx := testApex(t, `
 		apex {
-			name: "myapex",
+			name: "myapex_keytest",
 			key: "myapex.key",
+			certificate: ":myapex.certificate",
 			native_shared_libs: ["mylib"],
 		}
 
@@ -791,6 +800,16 @@
 			private_key: "testkey.pem",
 		}
 
+		android_app_certificate {
+			name: "myapex.certificate",
+			certificate: "testkey",
+		}
+
+		android_app_certificate {
+			name: "myapex.certificate.override",
+			certificate: "testkey.override",
+		}
+
 	`)
 
 	// check the APEX keys
@@ -805,11 +824,11 @@
 			"vendor/foo/devkeys/testkey.pem")
 	}
 
-	// check the APK certs
-	certs := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("signapk").Args["certificates"]
-	if certs != "vendor/foo/devkeys/test.x509.pem vendor/foo/devkeys/test.pk8" {
+	// check the APK certs. It should be overridden to myapex.certificate.override
+	certs := ctx.ModuleForTests("myapex_keytest", "android_common_myapex_keytest").Rule("signapk").Args["certificates"]
+	if certs != "testkey.override.x509.pem testkey.override.pk8" {
 		t.Errorf("cert and private key %q are not %q", certs,
-			"vendor/foo/devkeys/test.x509.pem vendor/foo/devkeys/test.pk8")
+			"testkey.override.509.pem testkey.override.pk8")
 	}
 }
 
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index 319e36e..c7f0638 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
@@ -46,7 +48,8 @@
 	DefaultCompilerFilter      string // default compiler filter to pass to dex2oat, overridden by --compiler-filter= in module-specific dex2oat flags
 	SystemServerCompilerFilter string // default compiler filter to pass to dex2oat for system server jars
 
-	GenerateDMFiles bool // generate Dex Metadata files
+	GenerateDMFiles     bool // generate Dex Metadata files
+	NeverAllowStripping bool // whether stripping should not be done - used as build time check to make sure dex files are always available
 
 	NoDebugInfo                 bool // don't generate debug info by default
 	AlwaysSystemServerDebugInfo bool // always generate mini debug info for system server modules (overrides NoDebugInfo=true)
@@ -66,9 +69,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 +106,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..68bd3ea 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -68,6 +68,9 @@
 	strip := shouldStripDex(module, global)
 
 	if strip {
+		if global.NeverAllowStripping {
+			panic(fmt.Errorf("Stripping requested on %q, though the product does not allow it", module.DexLocation))
+		}
 		// Only strips if the dex files are not already uncompressed
 		rule.Command().
 			Textf(`if (zipinfo %s '*.dex' 2>/dev/null | grep -v ' stor ' >/dev/null) ; then`, module.StripInputPath).
@@ -113,12 +116,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 +181,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 +195,7 @@
 		return filepath.Join(
 			filepath.Dir(path),
 			"oat",
-			arch,
+			arch.String(),
 			pathtools.ReplaceExtension(filepath.Base(path), "odex"))
 	}
 
@@ -213,11 +213,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 +325,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").
@@ -499,7 +499,7 @@
 		contains(module.PreoptFlags, "--compiler-filter=verify")
 }
 
-func odexOnSystemOther(module ModuleConfig, global GlobalConfig) bool {
+func OdexOnSystemOtherByName(name string, dexLocation string, global GlobalConfig) bool {
 	if !global.HasSystemOther {
 		return false
 	}
@@ -508,12 +508,12 @@
 		return false
 	}
 
-	if contains(global.SpeedApps, module.Name) || contains(global.SystemServerApps, module.Name) {
+	if contains(global.SpeedApps, name) || contains(global.SystemServerApps, name) {
 		return false
 	}
 
 	for _, f := range global.PatternsOnSystemOther {
-		if makefileMatch(filepath.Join(SystemPartition, f), module.DexLocation) {
+		if makefileMatch(filepath.Join(SystemPartition, f), dexLocation) {
 			return true
 		}
 	}
@@ -521,6 +521,19 @@
 	return false
 }
 
+func odexOnSystemOther(module ModuleConfig, global GlobalConfig) bool {
+	return OdexOnSystemOtherByName(module.Name, module.DexLocation, global)
+}
+
+// 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..ecaf876 100644
--- a/dexpreopt/dexpreopt_test.go
+++ b/dexpreopt/dexpreopt_test.go
@@ -36,6 +36,7 @@
 	DefaultCompilerFilter:              "",
 	SystemServerCompilerFilter:         "",
 	GenerateDMFiles:                    false,
+	NeverAllowStripping:                false,
 	NoDebugInfo:                        false,
 	AlwaysSystemServerDebugInfo:        false,
 	NeverSystemServerDebugInfo:         false,
@@ -48,7 +49,7 @@
 	Dex2oatXmx:                         "",
 	Dex2oatXms:                         "",
 	EmptyDirectory:                     "",
-	DefaultDexPreoptImageLocation:      nil,
+	DefaultDexPreoptImage:              nil,
 	CpuVariant:                         nil,
 	InstructionSetFeatures:             nil,
 	Tools: Tools{
@@ -63,28 +64,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 +94,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 {
@@ -110,6 +110,22 @@
 	}
 }
 
+func TestDexPreoptStrip(t *testing.T) {
+	// Test that we panic if we strip in a configuration where stripping is not allowed.
+	global, module := testGlobalConfig, testModuleConfig
+
+	global.NeverAllowStripping = true
+	module.NoStripping = false
+	module.Name = "test"
+	module.DexLocation = "/system/app/test/test.apk"
+	module.BuildPath = "out/test/test.apk"
+
+	_, err := GenerateStripRule(global, module)
+	if err == nil {
+		t.Errorf("Expected an error when calling GenerateStripRule on a stripped module")
+	}
+}
+
 func TestDexPreoptSystemOther(t *testing.T) {
 	global, module := testGlobalConfig, testModuleConfig
 
@@ -119,7 +135,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 +158,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 +207,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/aar.go b/java/aar.go
index 7495bda..60fbe29 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -367,6 +367,12 @@
 	a.exportedStaticPackages = android.FirstUniquePaths(a.exportedStaticPackages)
 }
 
+// android_library builds and links sources into a `.jar` file for the device along with Android resources.
+//
+// An android_library has a single variant that produces a `.jar` file containing `.class` files that were
+// compiled against the device bootclasspath, along with a `package-res.apk` file containing  Android resources compiled
+// with aapt2.  This module is not suitable for installing on a device, but can be used as a `static_libs` dependency of
+// an android_app module.
 func AndroidLibraryFactory() android.Module {
 	module := &AndroidLibrary{}
 
@@ -584,6 +590,10 @@
 
 var _ android.PrebuiltInterface = (*Import)(nil)
 
+// android_library_import imports an `.aar` file into the build graph as if it was built with android_library.
+//
+// This module is not suitable for installing on a device, but can be used as a `static_libs` dependency of
+// an android_app module.
 func AARImportFactory() android.Module {
 	module := &AARImport{}
 
diff --git a/java/app.go b/java/app.go
index 9697582..3cb7e8e 100644
--- a/java/app.go
+++ b/java/app.go
@@ -171,9 +171,18 @@
 	}
 
 	// Uncompress dex in APKs of privileged apps, and modules used by privileged apps.
-	return ctx.Config().UncompressPrivAppDex() &&
+	if ctx.Config().UncompressPrivAppDex() &&
 		(Bool(a.appProperties.Privileged) ||
-			inList(ctx.ModuleName(), ctx.Config().ModulesLoadedByPrivilegedModules()))
+			inList(ctx.ModuleName(), ctx.Config().ModulesLoadedByPrivilegedModules())) {
+		return true
+	}
+
+	// Uncompress if the dex files is preopted on /system.
+	if !a.dexpreopter.dexpreoptDisabled(ctx) && (ctx.Host() || !odexOnSystemOther(ctx, a.dexpreopter.installPath)) {
+		return true
+	}
+
+	return false
 }
 
 func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) {
@@ -232,7 +241,6 @@
 }
 
 func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) android.Path {
-	a.deviceProperties.UncompressDex = a.shouldUncompressDex(ctx)
 
 	var installDir string
 	if ctx.ModuleName() == "framework-res" {
@@ -244,6 +252,9 @@
 		installDir = filepath.Join("app", a.installApkName)
 	}
 	a.dexpreopter.installPath = android.PathForModuleInstall(ctx, installDir, a.installApkName+".apk")
+	a.dexpreopter.isInstallable = Bool(a.properties.Installable)
+	a.dexpreopter.uncompressedDex = a.shouldUncompressDex(ctx)
+	a.deviceProperties.UncompressDex = a.dexpreopter.uncompressedDex
 
 	if ctx.ModuleName() != "framework-res" {
 		a.Module.compile(ctx, a.aaptSrcJar)
@@ -384,6 +395,7 @@
 	return String(a.appProperties.Certificate)
 }
 
+// android_app compiles sources and Android resources into an Android application package `.apk` file.
 func AndroidAppFactory() android.Module {
 	module := &AndroidApp{}
 
@@ -446,6 +458,8 @@
 	}
 }
 
+// android_test compiles test sources and Android resources into an Android application package `.apk` file and
+// creates an `AndroidTest.xml` file to allow running the test with `atest` or a `TEST_MAPPING` file.
 func AndroidTestFactory() android.Module {
 	module := &AndroidTest{}
 
@@ -483,6 +497,9 @@
 	appTestHelperAppProperties appTestHelperAppProperties
 }
 
+// android_test_helper_app compiles sources and Android resources into an Android application package `.apk` file that
+// will be used by tests, but does not produce an `AndroidTest.xml` file so the module will not be run directly as a
+// test.
 func AndroidTestHelperAppFactory() android.Module {
 	module := &AndroidTestHelperApp{}
 
@@ -517,6 +534,8 @@
 	Certificate *string
 }
 
+// android_app_certificate modules can be referenced by the certificates property of android_app modules to select
+// the signing key.
 func AndroidAppCertificateFactory() android.Module {
 	module := &AndroidAppCertificate{}
 	module.AddProperties(&module.properties)
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index 55662cf..a89731a 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -83,11 +83,7 @@
 
 var dexpreoptGlobalConfigKey = android.NewOnceKey("DexpreoptGlobalConfig")
 
-func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.ModuleOutPath) android.ModuleOutPath {
-	if d.dexpreoptDisabled(ctx) {
-		return dexJarFile
-	}
-
+func getGlobalConfig(ctx android.ModuleContext) dexpreopt.GlobalConfig {
 	globalConfig := ctx.Config().Once(dexpreoptGlobalConfigKey, func() interface{} {
 		if f := ctx.Config().DexpreoptGlobalConfig(); f != "" {
 			ctx.AddNinjaFileDeps(f)
@@ -99,15 +95,28 @@
 		}
 		return dexpreopt.GlobalConfig{}
 	}).(dexpreopt.GlobalConfig)
+	return globalConfig
+}
 
-	var archs []string
+func odexOnSystemOther(ctx android.ModuleContext, installPath android.OutputPath) bool {
+	return dexpreopt.OdexOnSystemOtherByName(ctx.ModuleName(), android.InstallPathToOnDevicePath(ctx, installPath), getGlobalConfig(ctx))
+}
+
+func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.ModuleOutPath) android.ModuleOutPath {
+	if d.dexpreoptDisabled(ctx) {
+		return dexJarFile
+	}
+
+	globalConfig := getGlobalConfig(ctx)
+
+	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 +128,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 +175,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..787c4d7 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()...)
@@ -695,14 +695,17 @@
 	j.sourcepaths = android.PathsForModuleSrc(ctx, j.properties.Local_sourcepaths)
 
 	j.argFiles = ctx.ExpandSources(j.properties.Arg_files, nil)
-	argFilesMap := map[string]android.Path{}
+	argFilesMap := map[string]string{}
+	argFileLabels := []string{}
 
-	for _, f := range j.argFiles {
-		if _, exists := argFilesMap[f.Rel()]; !exists {
-			argFilesMap[f.Rel()] = f
+	for _, label := range j.properties.Arg_files {
+		var paths = ctx.ExpandSources([]string{label}, nil)
+		if _, exists := argFilesMap[label]; !exists {
+			argFilesMap[label] = strings.Join(paths.Strings(), " ")
+			argFileLabels = append(argFileLabels, label)
 		} else {
 			ctx.ModuleErrorf("multiple arg_files for %q, %q and %q",
-				f, argFilesMap[f.Rel()], f.Rel())
+				label, argFilesMap[label], paths)
 		}
 	}
 
@@ -710,10 +713,11 @@
 	j.args, err = android.Expand(String(j.properties.Args), func(name string) (string, error) {
 		if strings.HasPrefix(name, "location ") {
 			label := strings.TrimSpace(strings.TrimPrefix(name, "location "))
-			if f, ok := argFilesMap[label]; ok {
-				return f.String(), nil
+			if paths, ok := argFilesMap[label]; ok {
+				return paths, nil
 			} else {
-				return "", fmt.Errorf("unknown location label %q", label)
+				return "", fmt.Errorf("unknown location label %q, expecting one of %q",
+					label, strings.Join(argFileLabels, ", "))
 			}
 		} else if name == "genDir" {
 			return android.PathForModuleGen(ctx).String(), nil
diff --git a/java/genrule.go b/java/genrule.go
index 8f29482..25494ec 100644
--- a/java/genrule.go
+++ b/java/genrule.go
@@ -25,8 +25,37 @@
 }
 
 // java_genrule is a genrule that can depend on other java_* objects.
-// The cmd may be run multiple times, once for each of the different host/device
-// variations.
+//
+// By default a java_genrule has a single variant that will run against the device variant of its dependencies and
+// produce an output that can be used as an input to a device java rule.
+//
+// Specifying `host_supported: true` will produce two variants, one that uses device dependencie sand one that uses
+// host dependencies.  Each variant will run the command.
+//
+// Use a java_genrule instead of a genrule when it needs to depend on or be depended on by other java modules, unless
+// the dependency is for a generated source file.
+//
+// Examples:
+//
+// Use a java_genrule to package generated java resources:
+//
+//     java_genrule {
+//     name: "generated_resources",
+//         tools: [
+//             "generator",
+//             "soong_zip",
+//         ],
+//         srcs: ["generator_inputs/**/*"],
+//         out: ["generated_android_icu4j_resources.jar"],
+//         cmd: "$(location generator) $(in) -o $(genDir) " +
+//             "&& $(location soong_zip) -o $(out) -C $(genDir)/res -D $(genDir)/res",
+//     }
+//
+//     java_library {
+//         name: "lib_with_generated_resources",
+//         srcs: ["src/**/*.java"],
+//         static_libs: ["generated_resources"],
+//     }
 func genRuleFactory() android.Module {
 	module := genrule.NewGenRule()
 
@@ -36,8 +65,9 @@
 }
 
 // java_genrule_host is a genrule that can depend on other java_* objects.
-// The cmd may be run multiple times, once for each of the different host/device
-// variations.
+//
+// A java_genrule_host has a single variant that will run against the host variant of its dependencies and
+// produce an output that can be used as an input to a host java rule.
 func genRuleFactoryHost() android.Module {
 	module := genrule.NewGenRule()
 
diff --git a/java/java.go b/java/java.go
index 3d7d6ad..c0310da 100644
--- a/java/java.go
+++ b/java/java.go
@@ -36,7 +36,7 @@
 	android.RegisterModuleType("java_defaults", defaultsFactory)
 
 	android.RegisterModuleType("java_library", LibraryFactory)
-	android.RegisterModuleType("java_library_static", LibraryFactory)
+	android.RegisterModuleType("java_library_static", LibraryStaticFactory)
 	android.RegisterModuleType("java_library_host", LibraryHostFactory)
 	android.RegisterModuleType("java_binary", BinaryFactory)
 	android.RegisterModuleType("java_binary_host", BinaryHostFactory)
@@ -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:
@@ -1239,8 +1239,6 @@
 		j.dexJarFile = dexOutputFile
 
 		// Dexpreopting
-		j.dexpreopter.isInstallable = Bool(j.properties.Installable)
-		j.dexpreopter.uncompressedDex = j.deviceProperties.UncompressDex
 		dexOutputFile = j.dexpreopt(ctx, dexOutputFile)
 
 		j.maybeStrippedDexJarFile = dexOutputFile
@@ -1417,10 +1415,13 @@
 }
 
 func (j *Library) shouldUncompressDex(ctx android.ModuleContext) bool {
-	// Store uncompressed (and do not strip) dex files from boot class path jars that are
-	// in an apex.
-	if inList(ctx.ModuleName(), ctx.Config().BootJars()) &&
-		android.DirectlyInAnyApex(ctx, ctx.ModuleName()) {
+	// Store uncompressed (and do not strip) dex files from boot class path jars.
+	if inList(ctx.ModuleName(), ctx.Config().BootJars()) {
+		return true
+	}
+
+	// Store uncompressed dex files that are preopted on /system.
+	if !j.dexpreopter.dexpreoptDisabled(ctx) && (ctx.Host() || !odexOnSystemOther(ctx, j.dexpreopter.installPath)) {
 		return true
 	}
 	if ctx.Config().UncompressPrivAppDex() &&
@@ -1434,7 +1435,9 @@
 func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	j.dexpreopter.installPath = android.PathForModuleInstall(ctx, "framework", ctx.ModuleName()+".jar")
 	j.dexpreopter.isSDKLibrary = j.deviceProperties.IsSDKLibrary
-	j.deviceProperties.UncompressDex = j.shouldUncompressDex(ctx)
+	j.dexpreopter.isInstallable = Bool(j.properties.Installable)
+	j.dexpreopter.uncompressedDex = j.shouldUncompressDex(ctx)
+	j.deviceProperties.UncompressDex = j.dexpreopter.uncompressedDex
 	j.compile(ctx)
 
 	if (Bool(j.properties.Installable) || ctx.Host()) && !android.DirectlyInAnyApex(ctx, ctx.ModuleName()) {
@@ -1447,6 +1450,17 @@
 	j.deps(ctx)
 }
 
+// java_library builds and links sources into a `.jar` file for the device, and possibly for the host as well.
+//
+// By default, a java_library has a single variant that produces a `.jar` file containing `.class` files that were
+// compiled against the device bootclasspath.  This jar is not suitable for installing on a device, but can be used
+// as a `static_libs` dependency of another module.
+//
+// Specifying `installable: true` will product a `.jar` file containing `classes.dex` files, suitable for installing on
+// a device.
+//
+// Specifying `host_supported: true` will produce two variants, one compiled against the device bootclasspath and one
+// compiled against the host bootclasspath.
 func LibraryFactory() android.Module {
 	module := &Library{}
 
@@ -1460,6 +1474,15 @@
 	return module
 }
 
+// java_library_static is an obsolete alias for java_library.
+func LibraryStaticFactory() android.Module {
+	return LibraryFactory()
+}
+
+// java_library_host builds and links sources into a `.jar` file for the host.
+//
+// A java_library_host has a single variant that produces a `.jar` file containing `.class` files that were
+// compiled against the host bootclasspath.
 func LibraryHostFactory() android.Module {
 	module := &Library{}
 
@@ -1518,6 +1541,14 @@
 	android.ExtractSourcesDeps(ctx, j.testProperties.Data)
 }
 
+// java_test builds a and links sources into a `.jar` file for the device, and possibly for the host as well, and
+// creates an `AndroidTest.xml` file to allow running the test with `atest` or a `TEST_MAPPING` file.
+//
+// By default, a java_test has a single variant that produces a `.jar` file containing `classes.dex` files that were
+// compiled against the device bootclasspath.
+//
+// Specifying `host_supported: true` will produce two variants, one compiled against the device bootclasspath and one
+// compiled against the host bootclasspath.
 func TestFactory() android.Module {
 	module := &Test{}
 
@@ -1535,6 +1566,11 @@
 	return module
 }
 
+// java_test_host builds a and links sources into a `.jar` file for the host, and creates an `AndroidTest.xml` file to
+// allow running the test with `atest` or a `TEST_MAPPING` file.
+//
+// A java_test_host has a single variant that produces a `.jar` file containing `.class` files that were
+// compiled against the host bootclasspath.
 func TestHostFactory() android.Module {
 	module := &Test{}
 
@@ -1616,6 +1652,14 @@
 	}
 }
 
+// java_binary builds a `.jar` file and a shell script that executes it for the device, and possibly for the host
+// as well.
+//
+// By default, a java_binary has a single variant that produces a `.jar` file containing `classes.dex` files that were
+// compiled against the device bootclasspath.
+//
+// Specifying `host_supported: true` will produce two variants, one compiled against the device bootclasspath and one
+// compiled against the host bootclasspath.
 func BinaryFactory() android.Module {
 	module := &Binary{}
 
@@ -1633,6 +1677,10 @@
 	return module
 }
 
+// java_binary_host builds a `.jar` file and a shell script that executes it for the host.
+//
+// A java_binary_host has a single variant that produces a `.jar` file containing `.class` files that were
+// compiled against the host bootclasspath.
 func BinaryHostFactory() android.Module {
 	module := &Binary{}
 
@@ -1814,6 +1862,13 @@
 
 var _ android.PrebuiltInterface = (*Import)(nil)
 
+// java_import imports one or more `.jar` files into the build graph as if they were built by a java_library module.
+//
+// By default, a java_import has a single variant that expects a `.jar` file containing `.class` files that were
+// compiled against an Android classpath.
+//
+// Specifying `host_supported: true` will produce two variants, one for use as a dependency of device modules and one
+// for host modules.
 func ImportFactory() android.Module {
 	module := &Import{}
 
@@ -1824,6 +1879,11 @@
 	return module
 }
 
+// java_import imports one or more `.jar` files into the build graph as if they were built by a java_library_host
+// module.
+//
+// A java_import_host has a single variant that expects a `.jar` file containing `.class` files that were
+// compiled against a host bootclasspath.
 func ImportFactoryHost() android.Module {
 	module := &Import{}
 
@@ -1845,6 +1905,37 @@
 func (*Defaults) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 }
 
+// java_defaults provides a set of properties that can be inherited by other java or android modules.
+//
+// A module can use the properties from a java_defaults module using `defaults: ["defaults_module_name"]`.  Each
+// property in the defaults module that exists in the depending module will be prepended to the depending module's
+// value for that property.
+//
+// Example:
+//
+//     java_defaults {
+//         name: "example_defaults",
+//         srcs: ["common/**/*.java"],
+//         javacflags: ["-Xlint:all"],
+//         aaptflags: ["--auto-add-overlay"],
+//     }
+//
+//     java_library {
+//         name: "example",
+//         defaults: ["example_defaults"],
+//         srcs: ["example/**/*.java"],
+//     }
+//
+// is functionally identical to:
+//
+//     java_library {
+//         name: "example",
+//         srcs: [
+//             "common/**/*.java",
+//             "example/**/*.java",
+//         ],
+//         javacflags: ["-Xlint:all"],
+//     }
 func defaultsFactory() android.Module {
 	return DefaultsFactory()
 }
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 1b0fe75..3623e7c 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -100,7 +100,13 @@
 	// list of package names that must be hidden from the API
 	Hidden_api_packages []string
 
-	// Additional droiddoc options
+	// local files that are used within user customized droiddoc options.
+	Droiddoc_option_files []string
+
+	// additional droiddoc options
+	// Available variables for substitution:
+	//
+	//  $(location <label>): the path to the droiddoc_option_files with name <label>
 	Droiddoc_options []string
 
 	// the java library (in classpath) for documentation that provides java srcs and srcjars.
@@ -145,6 +151,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))
@@ -431,6 +440,7 @@
 		Srcs_lib_whitelist_dirs          []string
 		Srcs_lib_whitelist_pkgs          []string
 		Libs                             []string
+		Arg_files                        []string
 		Args                             *string
 		Api_tag_name                     *string
 		Api_filename                     *string
@@ -478,6 +488,7 @@
 	case apiScopeTest:
 		droiddocArgs = droiddocArgs + " -showAnnotation android.annotation.TestApi"
 	}
+	props.Arg_files = module.sdkLibraryProperties.Droiddoc_option_files
 	props.Args = proptools.StringPtr(droiddocArgs)
 
 	// List of APIs identified from the provided source files are created. They are later
@@ -596,7 +607,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 +623,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,