Enforce apex.min_sdk_version for bundled builds

Previously, when Q-targeting apexes are bundled-built, they are built
against the latest stubs.

It was because unwinder is linked dynamically in R and APIs are provided
by libc while Q apexes should run on Q where libc doesn't provide those
APIs. To make Q apexes run on Q device, libc++ should be linked with
static unwinder. But, because libc++ with static unwinder may cause problem
on HWASAN build, Q apexes were built against the latest stubs for bundled
build.

However, Q apexes should be built against Q stubs.

Now, only for HWASAN builds, Q apexes are built against the latest stubs
(and native modules are not linked with static unwinder).

Bug: 151912436
Test: TARGET_SANITIZE=hwaddress m
      => Q apexes(media, resolv, ..) are linked with the latest stubs
      m
      => Q apexes are linked with Q stubs,
         and Q apexes' libc++ is linked with static unwinder
Merged-In: If32f1b547e6d93e3955c7521eec8aef5851f908c
Change-Id: If32f1b547e6d93e3955c7521eec8aef5851f908c
(cherry picked from commit 7406660685a9a085c433ba7081cc6984f66fa732)

Exempt-From-Owner-Approval: cp from internal
Change-Id: If32f1b547e6d93e3955c7521eec8aef5851f908c
diff --git a/android/apex.go b/android/apex.go
index eabe059..cbaf1c7 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -92,12 +92,10 @@
 	// 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
+	// Returns the highest version which is <= maxSdkVersion.
+	// For example, with maxSdkVersion is 10 and versionList is [9,11]
+	// it returns 9 as string
+	ChooseSdkVersion(versionList []string, maxSdkVersion int) (string, error)
 }
 
 type ApexProperties struct {
@@ -193,22 +191,14 @@
 	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
+func (m *ApexModuleBase) ChooseSdkVersion(versionList []string, maxSdkVersion int) (string, error) {
 	for i := range versionList {
 		ver, _ := strconv.Atoi(versionList[len(versionList)-i-1])
-		if ver <= minSdkVersion {
+		if ver <= maxSdkVersion {
 			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 <= SdkVersion_Android10)
+	return "", fmt.Errorf("not found a version(<=%d) in versionList: %v", maxSdkVersion, versionList)
 }
 
 func (m *ApexModuleBase) checkApexAvailableProperty(mctx BaseModuleContext) {
diff --git a/apex/apex_test.go b/apex/apex_test.go
index c01ba14..b97e38d 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -882,7 +882,7 @@
 		shouldNotLink []string
 	}{
 		{
-			name:          "should link to test latest",
+			name:          "should link to the latest",
 			minSdkVersion: "current",
 			shouldLink:    "30",
 			shouldNotLink: []string{"29"},
@@ -1222,7 +1222,7 @@
 	expectNoLink("libz", "shared", "libz", "shared")
 }
 
-func TestQApexesUseLatestStubsInBundledBuilds(t *testing.T) {
+func TestQApexesUseLatestStubsInBundledBuildsAndHWASAN(t *testing.T) {
 	ctx, _ := testApex(t, `
 		apex {
 			name: "myapex",
@@ -1249,16 +1249,18 @@
 				versions: ["29", "30"],
 			},
 		}
-	`)
+	`, func(fs map[string][]byte, config android.Config) {
+		config.TestProductVariables.SanitizeDevice = []string{"hwaddress"}
+	})
 	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")
+	expectLink("libx", "shared_hwasan_myapex", "libbar", "shared_30")
 }
 
-func TestQTargetApexUseStaticUnwinder(t *testing.T) {
+func TestQTargetApexUsesStaticUnwinder(t *testing.T) {
 	ctx, _ := testApex(t, `
 		apex {
 			name: "myapex",
@@ -1277,8 +1279,7 @@
 			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)
@@ -1289,7 +1290,7 @@
 }
 
 func TestInvalidMinSdkVersion(t *testing.T) {
-	testApexError(t, `"libz" .*: min_sdk_version is set 29.*`, `
+	testApexError(t, `"libz" .*: not found a version\(<=29\)`, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -1319,9 +1320,9 @@
 				versions: ["30"],
 			},
 		}
-	`, withUnbundledBuild)
+	`)
 
-	testApexError(t, `"myapex" .*: min_sdk_version: should be .*`, `
+	testApexError(t, `"myapex" .*: min_sdk_version: should be "current" or <number>`, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -1842,7 +1843,7 @@
 	// non-APEX variant does not have __ANDROID_APEX__ defined
 	mylibCFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"]
 	ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__")
-	ensureNotContains(t, mylibCFlags, "-D__ANDROID_SDK_VERSION__=10000")
+	ensureNotContains(t, mylibCFlags, "-D__ANDROID_SDK_VERSION__")
 
 	// APEX variant has __ANDROID_APEX__ and __ANDROID_APEX_SDK__ defined
 	mylibCFlags = ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_myapex").Rule("cc").Args["cFlags"]
diff --git a/cc/cc.go b/cc/cc.go
index de07229..88fede4 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -488,6 +488,9 @@
 	makeLinkType string
 	// Kythe (source file indexer) paths for this compilation module
 	kytheFiles android.Paths
+
+	// For apex variants, this is set as apex.min_sdk_version
+	apexSdkVersion int
 }
 
 func (c *Module) Toc() android.OptionalPath {
@@ -1209,7 +1212,7 @@
 }
 
 func (ctx *moduleContextImpl) apexSdkVersion() int {
-	return ctx.mod.ApexProperties.Info.MinSdkVersion
+	return ctx.mod.apexSdkVersion
 }
 
 func (ctx *moduleContextImpl) hasStubsVariants() bool {
@@ -1847,7 +1850,10 @@
 		}, depTag, lib)
 	}
 
-	if deps.StaticUnwinderIfLegacy && ctx.Config().UnbundledBuild() {
+	// staticUnwinderDep is treated as staticDep for Q apexes
+	// so that native libraries/binaries are linked with static unwinder
+	// because Q libc doesn't have unwinder APIs
+	if deps.StaticUnwinderIfLegacy {
 		actx.AddVariationDependencies([]blueprint.Variation{
 			{Mutator: "link", Variation: "static"},
 		}, staticUnwinderDepTag, staticUnwinder(actx))
@@ -2231,9 +2237,22 @@
 			}
 		}
 
+		// For the dependency from platform to apex, use the latest stubs
+		c.apexSdkVersion = android.FutureApiLevel
+		if !c.IsForPlatform() {
+			c.apexSdkVersion = c.ApexProperties.Info.MinSdkVersion
+		}
+
+		if android.InList("hwaddress", ctx.Config().SanitizeDevice()) {
+			// In hwasan build, we override apexSdkVersion to the FutureApiLevel(10000)
+			// so that even Q(29/Android10) apexes could use the dynamic unwinder by linking the newer stubs(e.g libc(R+)).
+			// (b/144430859)
+			c.apexSdkVersion = android.FutureApiLevel
+		}
+
 		if depTag == staticUnwinderDepTag {
-			// Use static unwinder for legacy (min_sdk_version = 29) apexes  (b/144430859)
-			if c.ShouldSupportAndroid10() {
+			// Use static unwinder for legacy (min_sdk_version = 29) apexes (b/144430859)
+			if c.apexSdkVersion <= android.SdkVersion_Android10 {
 				depTag = StaticDepTag
 			} else {
 				return
@@ -2287,8 +2306,7 @@
 
 				// 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)
+					versionToUse, err := c.ChooseSdkVersion(ccDep.StubsVersions(), c.apexSdkVersion)
 					if err != nil {
 						ctx.OtherModuleErrorf(dep, err.Error())
 						return
@@ -2311,8 +2329,7 @@
 						// if this is for use_vendor apex && dep has stubsVersions
 						// apply the same rule of apex sdk enforcement to choose right version
 						var err error
-						useLatest := c.ShouldSupportAndroid10() && !ctx.Config().UnbundledBuild()
-						versionToUse, err = c.ChooseSdkVersion(versions, useLatest)
+						versionToUse, err = c.ChooseSdkVersion(versions, c.apexSdkVersion)
 						if err != nil {
 							ctx.OtherModuleErrorf(dep, err.Error())
 							return
diff --git a/cc/testing.go b/cc/testing.go
index e9739ff..f85795b 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -67,6 +67,20 @@
 			src: "",
 		}
 
+		cc_prebuilt_library_shared {
+			name: "libclang_rt.hwasan-aarch64-android",
+			nocrt: true,
+			vendor_available: true,
+			recovery_available: true,
+			system_shared_libs: [],
+			stl: "none",
+			srcs: [""],
+			check_elf_files: false,
+			sanitize: {
+				never: true,
+			},
+		}
+
 		toolchain_library {
 			name: "libclang_rt.builtins-i686-android",
 			vendor_available: true,