Merge "Do not explicitly link ucrt, ucrtbase"
diff --git a/android/apex.go b/android/apex.go
index 026d685..a4de6dd 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -15,7 +15,9 @@
 package android
 
 import (
+	"fmt"
 	"sort"
+	"strconv"
 	"sync"
 )
 
@@ -25,6 +27,8 @@
 
 	// Whether this apex variant needs to target Android 10
 	LegacyAndroid10Support bool
+
+	MinSdkVersion int
 }
 
 // ApexModule is the interface that a module type is expected to implement if
@@ -86,6 +90,13 @@
 	// DepIsInSameApex tests if the other module 'dep' is installed to the same
 	// APEX as this module
 	DepIsInSameApex(ctx BaseModuleContext, dep Module) bool
+
+	// Returns the highest version which is <= min_sdk_version.
+	// For example, with min_sdk_version is 10 and versionList is [9,11]
+	// it returns 9.
+	ChooseSdkVersion(versionList []string, useLatest bool) (string, error)
+
+	ShouldSupportAndroid10() bool
 }
 
 type ApexProperties struct {
@@ -181,6 +192,24 @@
 	return true
 }
 
+func (m *ApexModuleBase) ChooseSdkVersion(versionList []string, useLatest bool) (string, error) {
+	if useLatest {
+		return versionList[len(versionList)-1], nil
+	}
+	minSdkVersion := m.ApexProperties.Info.MinSdkVersion
+	for i := range versionList {
+		ver, _ := strconv.Atoi(versionList[len(versionList)-i-1])
+		if ver <= minSdkVersion {
+			return versionList[len(versionList)-i-1], nil
+		}
+	}
+	return "", fmt.Errorf("min_sdk_version is set %v, but not found in %v", minSdkVersion, versionList)
+}
+
+func (m *ApexModuleBase) ShouldSupportAndroid10() bool {
+	return !m.IsForPlatform() && (m.ApexProperties.Info.MinSdkVersion <= 29 || m.ApexProperties.Info.LegacyAndroid10Support)
+}
+
 func (m *ApexModuleBase) checkApexAvailableProperty(mctx BaseModuleContext) {
 	for _, n := range m.ApexProperties.Apex_available {
 		if n == AvailableToPlatform || n == availableToAnyApex {
diff --git a/apex/apex.go b/apex/apex.go
index bef4e42..de18e5c 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -19,6 +19,7 @@
 	"path"
 	"path/filepath"
 	"sort"
+	"strconv"
 	"strings"
 	"sync"
 
@@ -1028,7 +1029,15 @@
 	var apexBundles []android.ApexInfo
 	var directDep bool
 	if a, ok := mctx.Module().(*apexBundle); ok && !a.vndkApex {
-		apexBundles = []android.ApexInfo{{mctx.ModuleName(), proptools.Bool(a.properties.Legacy_android10_support)}}
+		minSdkVersion := a.minSdkVersion(mctx)
+
+		apexBundles = []android.ApexInfo{
+			android.ApexInfo{
+				ApexName:               mctx.ModuleName(),
+				LegacyAndroid10Support: proptools.Bool(a.properties.Legacy_android10_support),
+				MinSdkVersion:          minSdkVersion,
+			},
+		}
 		directDep = true
 	} else if am, ok := mctx.Module().(android.ApexModule); ok {
 		apexBundles = am.ApexVariations()
@@ -1967,6 +1976,18 @@
 	})
 }
 
+func (a *apexBundle) minSdkVersion(ctx android.BaseModuleContext) int {
+	ver := proptools.StringDefault(a.properties.Min_sdk_version, "current")
+	if ver != "current" {
+		minSdkVersion, err := strconv.Atoi(ver)
+		if err != nil {
+			ctx.PropertyErrorf("min_sdk_version", "should be \"current\" or <number>, but %q", ver)
+		}
+		return minSdkVersion
+	}
+	return android.FutureApiLevel
+}
+
 // Ensures that the dependencies are marked as available for this APEX
 func (a *apexBundle) checkApexAvailability(ctx android.ModuleContext) {
 	// Let's be practical. Availability for test, host, and the VNDK apex isn't important
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 674446a..2b13197 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -984,6 +984,297 @@
 	ensureContains(t, libFlags, "libdl/android_arm64_armv8-a_shared/libdl.so")
 }
 
+func TestApexUseStubsAccordingToMinSdkVersionInUnbundledBuild(t *testing.T) {
+	// there are three links between liba --> libz
+	// 1) myapex -> libx -> liba -> libz    : this should be #2 link, but fallback to #1
+	// 2) otherapex -> liby -> liba -> libz : this should be #3 link
+	// 3) (platform) -> liba -> libz        : this should be non-stub link
+	ctx, _ := testApex(t, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			native_shared_libs: ["libx"],
+			min_sdk_version: "2",
+		}
+
+		apex {
+			name: "otherapex",
+			key: "myapex.key",
+			native_shared_libs: ["liby"],
+			min_sdk_version: "3",
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		cc_library {
+			name: "libx",
+			shared_libs: ["liba"],
+			system_shared_libs: [],
+			stl: "none",
+			apex_available: [ "myapex" ],
+		}
+
+		cc_library {
+			name: "liby",
+			shared_libs: ["liba"],
+			system_shared_libs: [],
+			stl: "none",
+			apex_available: [ "otherapex" ],
+		}
+
+		cc_library {
+			name: "liba",
+			shared_libs: ["libz"],
+			system_shared_libs: [],
+			stl: "none",
+			apex_available: [
+				"//apex_available:anyapex",
+				"//apex_available:platform",
+			],
+		}
+
+		cc_library {
+			name: "libz",
+			system_shared_libs: [],
+			stl: "none",
+			stubs: {
+				versions: ["1", "3"],
+			},
+		}
+	`, withUnbundledBuild)
+
+	expectLink := func(from, from_variant, to, to_variant string) {
+		ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"]
+		ensureContains(t, ldArgs, "android_arm64_armv8-a_"+to_variant+"/"+to+".so")
+	}
+	expectNoLink := func(from, from_variant, to, to_variant string) {
+		ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"]
+		ensureNotContains(t, ldArgs, "android_arm64_armv8-a_"+to_variant+"/"+to+".so")
+	}
+	// platform liba is linked to non-stub version
+	expectLink("liba", "shared", "libz", "shared")
+	// liba in myapex is linked to #1
+	expectLink("liba", "shared_myapex", "libz", "shared_1")
+	expectNoLink("liba", "shared_myapex", "libz", "shared_3")
+	expectNoLink("liba", "shared_myapex", "libz", "shared")
+	// liba in otherapex is linked to #3
+	expectLink("liba", "shared_otherapex", "libz", "shared_3")
+	expectNoLink("liba", "shared_otherapex", "libz", "shared_1")
+	expectNoLink("liba", "shared_otherapex", "libz", "shared")
+}
+
+func TestApexMinSdkVersionDefaultsToLatest(t *testing.T) {
+	ctx, _ := testApex(t, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			native_shared_libs: ["libx"],
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		cc_library {
+			name: "libx",
+			shared_libs: ["libz"],
+			system_shared_libs: [],
+			stl: "none",
+			apex_available: [ "myapex" ],
+		}
+
+		cc_library {
+			name: "libz",
+			system_shared_libs: [],
+			stl: "none",
+			stubs: {
+				versions: ["1", "2"],
+			},
+		}
+	`)
+
+	expectLink := func(from, from_variant, to, to_variant string) {
+		ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"]
+		ensureContains(t, ldArgs, "android_arm64_armv8-a_"+to_variant+"/"+to+".so")
+	}
+	expectNoLink := func(from, from_variant, to, to_variant string) {
+		ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"]
+		ensureNotContains(t, ldArgs, "android_arm64_armv8-a_"+to_variant+"/"+to+".so")
+	}
+	expectLink("libx", "shared_myapex", "libz", "shared_2")
+	expectNoLink("libx", "shared_myapex", "libz", "shared_1")
+	expectNoLink("libx", "shared_myapex", "libz", "shared")
+}
+
+func TestPlatformUsesLatestStubsFromApexes(t *testing.T) {
+	ctx, _ := testApex(t, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			native_shared_libs: ["libx"],
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		cc_library {
+			name: "libx",
+			system_shared_libs: [],
+			stl: "none",
+			apex_available: [ "myapex" ],
+			stubs: {
+				versions: ["1", "2"],
+			},
+		}
+
+		cc_library {
+			name: "libz",
+			shared_libs: ["libx"],
+			system_shared_libs: [],
+			stl: "none",
+		}
+	`)
+
+	expectLink := func(from, from_variant, to, to_variant string) {
+		ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"]
+		ensureContains(t, ldArgs, "android_arm64_armv8-a_"+to_variant+"/"+to+".so")
+	}
+	expectNoLink := func(from, from_variant, to, to_variant string) {
+		ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"]
+		ensureNotContains(t, ldArgs, "android_arm64_armv8-a_"+to_variant+"/"+to+".so")
+	}
+	expectLink("libz", "shared", "libx", "shared_2")
+	expectNoLink("libz", "shared", "libz", "shared_1")
+	expectNoLink("libz", "shared", "libz", "shared")
+}
+
+func TestQApexesUseLatestStubsInBundledBuilds(t *testing.T) {
+	ctx, _ := testApex(t, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			native_shared_libs: ["libx"],
+			min_sdk_version: "29",
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		cc_library {
+			name: "libx",
+			shared_libs: ["libbar"],
+			apex_available: [ "myapex" ],
+		}
+
+		cc_library {
+			name: "libbar",
+			stubs: {
+				versions: ["29", "30"],
+			},
+		}
+	`)
+	expectLink := func(from, from_variant, to, to_variant string) {
+		ld := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld")
+		libFlags := ld.Args["libFlags"]
+		ensureContains(t, libFlags, "android_arm64_armv8-a_"+to_variant+"/"+to+".so")
+	}
+	expectLink("libx", "shared_myapex", "libbar", "shared_30")
+}
+
+func TestQTargetApexUseStaticUnwinder(t *testing.T) {
+	ctx, _ := testApex(t, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			native_shared_libs: ["libx"],
+			min_sdk_version: "29",
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		cc_library {
+			name: "libx",
+			apex_available: [ "myapex" ],
+		}
+
+	`, withUnbundledBuild)
+
+	// ensure apex variant of c++ is linked with static unwinder
+	cm := ctx.ModuleForTests("libc++", "android_arm64_armv8-a_shared_myapex").Module().(*cc.Module)
+	ensureListContains(t, cm.Properties.AndroidMkStaticLibs, "libgcc_stripped")
+	// note that platform variant is not.
+	cm = ctx.ModuleForTests("libc++", "android_arm64_armv8-a_shared").Module().(*cc.Module)
+	ensureListNotContains(t, cm.Properties.AndroidMkStaticLibs, "libgcc_stripped")
+
+	libFlags := ctx.ModuleForTests("libx", "android_arm64_armv8-a_shared_myapex").Rule("ld").Args["libFlags"]
+	ensureContains(t, libFlags, "android_arm64_armv8-a_shared_myapex/libc++.so")
+	ensureContains(t, libFlags, "android_arm64_armv8-a_shared_29/libc.so") // min_sdk_version applied
+}
+
+func TestInvalidMinSdkVersion(t *testing.T) {
+	testApexError(t, `"libz" .*: min_sdk_version is set 29.*`, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			native_shared_libs: ["libx"],
+			min_sdk_version: "29",
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		cc_library {
+			name: "libx",
+			shared_libs: ["libz"],
+			system_shared_libs: [],
+			stl: "none",
+			apex_available: [ "myapex" ],
+		}
+
+		cc_library {
+			name: "libz",
+			system_shared_libs: [],
+			stl: "none",
+			stubs: {
+				versions: ["30"],
+			},
+		}
+	`, withUnbundledBuild)
+
+	testApexError(t, `"myapex" .*: min_sdk_version: should be .*`, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			min_sdk_version: "R",
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+	`)
+}
+
 func TestFilesInSubDir(t *testing.T) {
 	ctx, _ := testApex(t, `
 		apex {
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 81004da..ef695b0 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -244,6 +244,9 @@
 	if library.shared() && !library.buildStubs() {
 		ctx.subAndroidMk(entries, library.baseInstaller)
 	} else {
+		if library.buildStubs() {
+			entries.SubName = "." + library.stubsVersion()
+		}
 		entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
 			entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
 			if library.buildStubs() {
@@ -254,6 +257,10 @@
 	if len(library.Properties.Stubs.Versions) > 0 &&
 		android.DirectlyInAnyApex(ctx, ctx.Name()) && !ctx.InRamdisk() && !ctx.InRecovery() && !ctx.UseVndk() &&
 		!ctx.static() {
+		if library.buildStubs() && library.isLatestStubVersion() {
+			// reference the latest version via its name without suffix when it is provided by apex
+			entries.SubName = ""
+		}
 		if !library.buildStubs() {
 			entries.SubName = ".bootstrap"
 		}
diff --git a/cc/cc.go b/cc/cc.go
index e5e724e..8b3c772 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -631,6 +631,15 @@
 	panic(fmt.Errorf("SetStubsVersions called on non-library module: %q", c.BaseModuleName()))
 }
 
+func (c *Module) StubsVersion() string {
+	if c.linker != nil {
+		if library, ok := c.linker.(*libraryDecorator); ok {
+			return library.MutatedProperties.StubsVersion
+		}
+	}
+	panic(fmt.Errorf("StubsVersion called on non-library module: %q", c.BaseModuleName()))
+}
+
 func (c *Module) SetStatic() {
 	if c.linker != nil {
 		if library, ok := c.linker.(libraryInterface); ok {
@@ -1821,16 +1830,17 @@
 		}
 		actx.AddVariationDependencies(variations, depTag, name)
 
-		// If the version is not specified, add dependency to the latest stubs library.
+		// If the version is not specified, add dependency to all stubs libraries.
 		// The stubs library will be used when the depending module is built for APEX and
 		// the dependent module is not in the same APEX.
-		latestVersion := LatestStubsVersionFor(actx.Config(), name)
-		if version == "" && latestVersion != "" && versionVariantAvail {
-			actx.AddVariationDependencies([]blueprint.Variation{
-				{Mutator: "link", Variation: "shared"},
-				{Mutator: "version", Variation: latestVersion},
-			}, depTag, name)
-			// Note that depTag.ExplicitlyVersioned is false in this case.
+		if version == "" && versionVariantAvail {
+			for _, ver := range stubsVersionsFor(actx.Config())[name] {
+				// Note that depTag.ExplicitlyVersioned is false in this case.
+				actx.AddVariationDependencies([]blueprint.Variation{
+					{Mutator: "link", Variation: "shared"},
+					{Mutator: "version", Variation: ver},
+				}, depTag, name)
+			}
 		}
 	}
 
@@ -2178,7 +2188,8 @@
 		}
 
 		if depTag == staticUnwinderDepTag {
-			if c.ApexProperties.Info.LegacyAndroid10Support {
+			// Use static unwinder for legacy (min_sdk_version = 29) apexes  (b/144430859)
+			if c.ShouldSupportAndroid10() {
 				depTag = StaticDepTag
 			} else {
 				return
@@ -2230,6 +2241,19 @@
 					useThisDep = (depInSameApex != depIsStubs)
 				}
 
+				// when to use (unspecified) stubs, check min_sdk_version and choose the right one
+				if useThisDep && depIsStubs && !explicitlyVersioned {
+					useLatest := c.IsForPlatform() || (c.ShouldSupportAndroid10() && !ctx.Config().UnbundledBuild())
+					versionToUse, err := c.ChooseSdkVersion(ccDep.StubsVersions(), useLatest)
+					if err != nil {
+						ctx.OtherModuleErrorf(dep, err.Error())
+						return
+					}
+					if versionToUse != ccDep.StubsVersion() {
+						useThisDep = false
+					}
+				}
+
 				if !useThisDep {
 					return // stop processing this dep
 				}
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 8acc817..56b36df 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -2530,6 +2530,7 @@
 }
 
 func checkStaticLibs(t *testing.T, expected []string, module *Module) {
+	t.Helper()
 	actual := module.Properties.AndroidMkStaticLibs
 	if !reflect.DeepEqual(actual, expected) {
 		t.Errorf("incorrect static_libs"+
diff --git a/cc/library.go b/cc/library.go
index 0159cee..e1d0b34 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -1273,6 +1273,11 @@
 	return library.MutatedProperties.StubsVersion
 }
 
+func (library *libraryDecorator) isLatestStubVersion() bool {
+	versions := library.Properties.Stubs.Versions
+	return versions[len(versions)-1] == library.stubsVersion()
+}
+
 func (library *libraryDecorator) availableFor(what string) bool {
 	var list []string
 	if library.static() {
@@ -1444,30 +1449,35 @@
 	return ""
 }
 
+func checkVersions(ctx android.BaseModuleContext, versions []string) {
+	numVersions := make([]int, len(versions))
+	for i, v := range versions {
+		numVer, err := strconv.Atoi(v)
+		if err != nil {
+			ctx.PropertyErrorf("versions", "%q is not a number", v)
+		}
+		numVersions[i] = numVer
+	}
+	if !sort.IsSorted(sort.IntSlice(numVersions)) {
+		ctx.PropertyErrorf("versions", "not sorted: %v", versions)
+	}
+}
+
 // Version mutator splits a module into the mandatory non-stubs variant
 // (which is unnamed) and zero or more stubs variants.
 func VersionMutator(mctx android.BottomUpMutatorContext) {
 	if library, ok := mctx.Module().(LinkableInterface); ok && !library.InRecovery() {
 		if library.CcLibrary() && library.BuildSharedVariant() && len(library.StubsVersions()) > 0 {
-			versions := []string{}
-			for _, v := range library.StubsVersions() {
-				if _, err := strconv.Atoi(v); err != nil {
-					mctx.PropertyErrorf("versions", "%q is not a number", v)
-				}
-				versions = append(versions, v)
+			versions := library.StubsVersions()
+			checkVersions(mctx, versions)
+			if mctx.Failed() {
+				return
 			}
-			sort.Slice(versions, func(i, j int) bool {
-				left, _ := strconv.Atoi(versions[i])
-				right, _ := strconv.Atoi(versions[j])
-				return left < right
-			})
 
 			// save the list of versions for later use
-			copiedVersions := make([]string, len(versions))
-			copy(copiedVersions, versions)
 			stubsVersionsLock.Lock()
 			defer stubsVersionsLock.Unlock()
-			stubsVersionsFor(mctx.Config())[mctx.ModuleName()] = copiedVersions
+			stubsVersionsFor(mctx.Config())[mctx.ModuleName()] = versions
 
 			// "" is for the non-stubs variant
 			versions = append([]string{""}, versions...)
diff --git a/cc/linkable.go b/cc/linkable.go
index e4f034c..80cd6b8 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -26,6 +26,7 @@
 	BuildStubs() bool
 	SetBuildStubs()
 	SetStubsVersions(string)
+	StubsVersion() string
 	HasStubsVariants() bool
 	SelectedStl() string
 	ApiLevel() string
diff --git a/rust/rust.go b/rust/rust.go
index de6512c..f446ef0 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -325,6 +325,10 @@
 	panic("SetStubsVersions not yet implemented for rust modules")
 }
 
+func (mod *Module) StubsVersion() string {
+	panic("SetStubsVersions not yet implemented for rust modules")
+}
+
 func (mod *Module) BuildStaticVariant() bool {
 	if mod.compiler != nil {
 		if library, ok := mod.compiler.(libraryInterface); ok {
diff --git a/ui/build/paths/config.go b/ui/build/paths/config.go
index bfe662d..5717401 100644
--- a/ui/build/paths/config.go
+++ b/ui/build/paths/config.go
@@ -74,28 +74,27 @@
 }
 
 var Configuration = map[string]PathConfig{
-	"bash":     Allowed,
-	"dd":       Allowed,
-	"diff":     Allowed,
-	"dlv":      Allowed,
-	"expr":     Allowed,
-	"fuser":    Allowed,
-	"getopt":   Allowed,
-	"git":      Allowed,
-	"hexdump":  Allowed,
-	"jar":      Allowed,
-	"java":     Allowed,
-	"javap":    Allowed,
-	"lsof":     Allowed,
-	"openssl":  Allowed,
-	"patch":    Allowed,
-	"pstree":   Allowed,
-	"python3":  Allowed,
-	"rsync":    Allowed,
-	"sh":       Allowed,
-	"tr":       Allowed,
-	"unzip":    Allowed,
-	"zip":      Allowed,
+	"bash":    Allowed,
+	"dd":      Allowed,
+	"diff":    Allowed,
+	"dlv":     Allowed,
+	"expr":    Allowed,
+	"fuser":   Allowed,
+	"getopt":  Allowed,
+	"git":     Allowed,
+	"hexdump": Allowed,
+	"jar":     Allowed,
+	"java":    Allowed,
+	"javap":   Allowed,
+	"lsof":    Allowed,
+	"openssl": Allowed,
+	"patch":   Allowed,
+	"pstree":  Allowed,
+	"rsync":   Allowed,
+	"sh":      Allowed,
+	"tr":      Allowed,
+	"unzip":   Allowed,
+	"zip":     Allowed,
 
 	// Host toolchain is removed. In-tree toolchain should be used instead.
 	// GCC also can't find cc1 with this implementation.