Merge "Make java_sdk_library implement Dependency"
diff --git a/README.md b/README.md
index 74d49bb..44a98f3 100644
--- a/README.md
+++ b/README.md
@@ -34,7 +34,7 @@
 all Android.bp files.
 
 For a list of valid module types and their properties see
-[$OUT_DIR/soong/.bootstrap/docs/soong_build.html](http://go/Android.bp).
+[$OUT_DIR/soong/docs/soong_build.html](http://go/Android.bp).
 
 ### Globs
 
diff --git a/android/onceper.go b/android/onceper.go
index 5fefb71..f06f428 100644
--- a/android/onceper.go
+++ b/android/onceper.go
@@ -20,8 +20,23 @@
 )
 
 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
@@ -29,21 +44,20 @@
 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
 }
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/prebuilt_etc.go b/android/prebuilt_etc.go
index 33647d7..8af08c1 100644
--- a/android/prebuilt_etc.go
+++ b/android/prebuilt_etc.go
@@ -25,7 +25,7 @@
 
 func init() {
 	RegisterModuleType("prebuilt_etc", PrebuiltEtcFactory)
-	RegisterModuleType("prebuilt_etc_host", prebuiltEtcHostFactory)
+	RegisterModuleType("prebuilt_etc_host", PrebuiltEtcHostFactory)
 
 	PreDepsMutators(func(ctx RegisterMutatorsContext) {
 		ctx.BottomUp("prebuilt_etc", prebuiltEtcMutator).Parallel()
@@ -182,7 +182,7 @@
 	return module
 }
 
-func prebuiltEtcHostFactory() Module {
+func PrebuiltEtcHostFactory() Module {
 	module := &PrebuiltEtc{}
 	InitPrebuiltEtcModule(module)
 	// This module is host-only
diff --git a/android/prebuilt_etc_test.go b/android/prebuilt_etc_test.go
index f31fc9e..d0961a7 100644
--- a/android/prebuilt_etc_test.go
+++ b/android/prebuilt_etc_test.go
@@ -28,7 +28,7 @@
 	defer tearDown(buildDir)
 	ctx := NewTestArchContext()
 	ctx.RegisterModuleType("prebuilt_etc", ModuleFactoryAdaptor(PrebuiltEtcFactory))
-	ctx.RegisterModuleType("prebuilt_etc_host", ModuleFactoryAdaptor(prebuiltEtcHostFactory))
+	ctx.RegisterModuleType("prebuilt_etc_host", ModuleFactoryAdaptor(PrebuiltEtcHostFactory))
 	ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
 		ctx.BottomUp("prebuilt_etc", prebuiltEtcMutator).Parallel()
 	})
diff --git a/androidmk/cmd/androidmk/android.go b/androidmk/cmd/androidmk/android.go
index abe7917..1ecda2d 100644
--- a/androidmk/cmd/androidmk/android.go
+++ b/androidmk/cmd/androidmk/android.go
@@ -189,6 +189,7 @@
 			"LOCAL_PRIVILEGED_MODULE":          "privileged",
 			"LOCAL_AAPT_INCLUDE_ALL_RESOURCES": "aapt_include_all_resources",
 			"LOCAL_USE_EMBEDDED_NATIVE_LIBS":   "use_embedded_native_libs",
+			"LOCAL_USE_EMBEDDED_DEX":           "use_embedded_dex",
 
 			"LOCAL_DEX_PREOPT":                  "dex_preopt.enabled",
 			"LOCAL_DEX_PREOPT_APP_IMAGE":        "dex_preopt.app_image",
diff --git a/apex/apex.go b/apex/apex.go
index 95cee0c..0337afb 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -252,6 +252,19 @@
 	Ignore_system_library_special_case *bool
 
 	Multilib apexMultilibProperties
+
+	Prefer_sanitize struct {
+		// Prefer native libraries with asan if available
+		Address *bool
+		// Prefer native libraries with hwasan if available
+		Hwaddress *bool
+		// Prefer native libraries with tsan if available
+		Thread *bool
+		// Prefer native libraries with integer_overflow if available
+		Integer_overflow *bool
+		// Prefer native libraries with cfi if available
+		Cfi *bool
+	}
 }
 
 type apexTargetBundleProperties struct {
@@ -527,6 +540,31 @@
 }
 
 func (a *apexBundle) IsSanitizerEnabled(ctx android.BaseModuleContext, sanitizerName string) bool {
+	// If this APEX is configured to prefer a sanitizer, use it
+	switch sanitizerName {
+	case "asan":
+		if proptools.Bool(a.properties.Prefer_sanitize.Address) {
+			return true
+		}
+	case "hwasan":
+		if proptools.Bool(a.properties.Prefer_sanitize.Hwaddress) {
+			return true
+		}
+	case "tsan":
+		if proptools.Bool(a.properties.Prefer_sanitize.Thread) {
+			return true
+		}
+	case "cfi":
+		if proptools.Bool(a.properties.Prefer_sanitize.Cfi) {
+			return true
+		}
+	case "integer_overflow":
+		if proptools.Bool(a.properties.Prefer_sanitize.Integer_overflow) {
+			return true
+		}
+	}
+
+	// Then follow the global setting
 	globalSanitizerNames := []string{}
 	if a.Host() {
 		globalSanitizerNames = ctx.Config().SanitizeHost()
diff --git a/cc/cc.go b/cc/cc.go
index c09a2f3..01577bc 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -348,6 +348,7 @@
 	linkerFlagsDepTag     = dependencyTag{name: "linker flags file"}
 	dynamicLinkerDepTag   = dependencyTag{name: "dynamic linker"}
 	reuseObjTag           = dependencyTag{name: "reuse objects"}
+	staticVariantTag      = dependencyTag{name: "static variant"}
 	ndkStubDepTag         = dependencyTag{name: "ndk stub", library: true}
 	ndkLateStubDepTag     = dependencyTag{name: "ndk late stub", library: true}
 	vndkExtDepTag         = dependencyTag{name: "vndk extends", library: true}
@@ -1536,6 +1537,13 @@
 			}
 		}
 
+		if depTag == staticVariantTag {
+			if _, ok := ccDep.compiler.(libraryInterface); ok {
+				c.staticVariant = ccDep
+				return
+			}
+		}
+
 		// Extract explicitlyVersioned field from the depTag and reset it inside the struct.
 		// Otherwise, sharedDepTag and lateSharedDepTag with explicitlyVersioned set to true
 		// won't be matched to sharedDepTag and lateSharedDepTag.
diff --git a/cc/cc_test.go b/cc/cc_test.go
index dc23620..9d370c1 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -215,6 +215,7 @@
 	ctx.RegisterModuleType("cc_binary", android.ModuleFactoryAdaptor(BinaryFactory))
 	ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(LibraryFactory))
 	ctx.RegisterModuleType("cc_library_shared", android.ModuleFactoryAdaptor(LibrarySharedFactory))
+	ctx.RegisterModuleType("cc_library_static", android.ModuleFactoryAdaptor(LibraryStaticFactory))
 	ctx.RegisterModuleType("cc_library_headers", android.ModuleFactoryAdaptor(LibraryHeaderFactory))
 	ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(ToolchainLibraryFactory))
 	ctx.RegisterModuleType("llndk_library", android.ModuleFactoryAdaptor(LlndkLibraryFactory))
@@ -1966,3 +1967,43 @@
 		}
 	}
 }
+
+func TestStaticDepsOrderWithStubs(t *testing.T) {
+	ctx := testCc(t, `
+		cc_binary {
+			name: "mybin",
+			srcs: ["foo.c"],
+			static_libs: ["libB"],
+			static_executable: true,
+			stl: "none",
+		}
+
+		cc_library {
+			name: "libB",
+			srcs: ["foo.c"],
+			shared_libs: ["libC"],
+			stl: "none",
+		}
+
+		cc_library {
+			name: "libC",
+			srcs: ["foo.c"],
+			stl: "none",
+			stubs: {
+				versions: ["1"],
+			},
+		}`)
+
+	mybin := ctx.ModuleForTests("mybin", "android_arm64_armv8-a_core").Module().(*Module)
+	actual := mybin.depsInLinkOrder
+	expected := getOutputPaths(ctx, "android_arm64_armv8-a_core_static", []string{"libB", "libC"})
+
+	if !reflect.DeepEqual(actual, expected) {
+		t.Errorf("staticDeps orderings were not propagated correctly"+
+			"\nactual:   %v"+
+			"\nexpected: %v",
+			actual,
+			expected,
+		)
+	}
+}
diff --git a/cc/library.go b/cc/library.go
index b4b89d2..a6c7bc8 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -1032,6 +1032,9 @@
 				sharedCompiler.baseCompiler.Properties.Srcs
 			sharedCompiler.baseCompiler.Properties.Srcs = nil
 			sharedCompiler.baseCompiler.Properties.Generated_sources = nil
+		} else {
+			// This dep is just to reference static variant from shared variant
+			mctx.AddInterVariantDependency(staticVariantTag, shared, static)
 		}
 	}
 }
diff --git a/java/aar.go b/java/aar.go
index f6a3d3a..7495bda 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -76,6 +76,7 @@
 	extraAaptPackagesFile android.Path
 	isLibrary             bool
 	uncompressedJNI       bool
+	useEmbeddedDex        bool
 
 	aaptProperties aaptProperties
 }
@@ -182,7 +183,8 @@
 	manifestFile := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml")
 	manifestSrcPath := android.PathForModuleSrc(ctx, manifestFile)
 
-	manifestPath := manifestMerger(ctx, manifestSrcPath, sdkContext, staticLibManifests, a.isLibrary, a.uncompressedJNI)
+	manifestPath := manifestMerger(ctx, manifestSrcPath, sdkContext, staticLibManifests, a.isLibrary,
+		a.uncompressedJNI, a.useEmbeddedDex)
 
 	linkFlags, linkDeps, resDirs, overlayDirs, rroDirs := a.aapt2Flags(ctx, sdkContext, manifestPath)
 
diff --git a/java/android_manifest.go b/java/android_manifest.go
index 6d4399d..e63fb80 100644
--- a/java/android_manifest.go
+++ b/java/android_manifest.go
@@ -44,7 +44,7 @@
 	"libs")
 
 func manifestMerger(ctx android.ModuleContext, manifest android.Path, sdkContext sdkContext,
-	staticLibManifests android.Paths, isLibrary bool, uncompressedJNI bool) android.Path {
+	staticLibManifests android.Paths, isLibrary bool, uncompressedJNI, useEmbeddedDex bool) android.Path {
 
 	var args []string
 	if isLibrary {
@@ -62,6 +62,10 @@
 		}
 	}
 
+	if useEmbeddedDex {
+		args = append(args, "--use-embedded-dex=true")
+	}
+
 	// Inject minSdkVersion into the manifest
 	fixedManifest := android.PathForModuleOut(ctx, "manifest_fixer", "AndroidManifest.xml")
 	ctx.Build(pctx, android.BuildParams{
diff --git a/java/app.go b/java/app.go
index 47f4f0d..9697582 100644
--- a/java/app.go
+++ b/java/app.go
@@ -73,6 +73,10 @@
 	// sdk_version or min_sdk_version is set to a version that doesn't support it (<23), defaults to false for other
 	// module types where the native libraries are generally preinstalled outside the APK.
 	Use_embedded_native_libs *bool
+
+	// Store dex files uncompressed in the APK and set the android:useEmbeddedDex="true" manifest attribute so that
+	// they are used from inside the APK at runtime.
+	Use_embedded_dex *bool
 }
 
 type AndroidApp struct {
@@ -141,6 +145,7 @@
 
 func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	a.aapt.uncompressedJNI = a.shouldUncompressJNI(ctx)
+	a.aapt.useEmbeddedDex = Bool(a.appProperties.Use_embedded_dex)
 	a.generateAndroidBuildActions(ctx)
 }
 
@@ -157,6 +162,10 @@
 
 // Returns whether this module should have the dex file stored uncompressed in the APK.
 func (a *AndroidApp) shouldUncompressDex(ctx android.ModuleContext) bool {
+	if Bool(a.appProperties.Use_embedded_dex) {
+		return true
+	}
+
 	if ctx.Config().UnbundledBuild() {
 		return false
 	}
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,