Allow java_sdk_library in an APEX to have higher min_sdk_version.

Inidividual boot or system server jars may have higher min_sdk_version
than the contianing apex, since the runtime respects the values of
min/max_sdk_version; e.g. runtime would not load a boot jar with
higher min_sdk_version. This allows shipping new boot jars via apexes
that target older platforms.

Bug: 190818041
Test: presubmit
Change-Id: I08ec0b4463a17bc8265b948fe09da55eb4e52ac3
diff --git a/android/apex.go b/android/apex.go
index 567d5c6..cf1bcfe 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -945,6 +945,14 @@
 		if am, ok := from.(DepIsInSameApex); ok && !am.DepIsInSameApex(ctx, to) {
 			return false
 		}
+		if m, ok := to.(ModuleWithMinSdkVersionCheck); ok {
+			// This dependency performs its own min_sdk_version check, just make sure it sets min_sdk_version
+			// to trigger the check.
+			if !m.MinSdkVersion(ctx).Specified() {
+				ctx.OtherModuleErrorf(m, "must set min_sdk_version")
+			}
+			return false
+		}
 		if err := to.ShouldSupportSdkVersion(ctx, minSdkVersion); err != nil {
 			toName := ctx.OtherModuleName(to)
 			if ver, ok := minSdkVersionAllowlist[toName]; !ok || ver.GreaterThan(minSdkVersion) {
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 2f7dce5..3b9b13a 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -8410,6 +8410,184 @@
 	ensureContains(t, androidMk, "LOCAL_REQUIRED_MODULES += otherapex")
 }
 
+func TestSdkLibraryCanHaveHigherMinSdkVersion(t *testing.T) {
+	preparer := android.GroupFixturePreparers(
+		PrepareForTestWithApexBuildComponents,
+		prepareForTestWithMyapex,
+		java.PrepareForTestWithJavaSdkLibraryFiles,
+		java.PrepareForTestWithJavaDefaultModules,
+		android.PrepareForTestWithAndroidBuildComponents,
+		dexpreopt.FixtureSetApexBootJars("myapex:mybootclasspathlib"),
+		dexpreopt.FixtureSetApexSystemServerJars("myapex:mysystemserverclasspathlib"),
+	)
+
+	// Test java_sdk_library in bootclasspath_fragment may define higher min_sdk_version than the apex
+	t.Run("bootclasspath_fragment jar has higher min_sdk_version than apex", func(t *testing.T) {
+		preparer.RunTestWithBp(t, `
+			apex {
+				name: "myapex",
+				key: "myapex.key",
+				bootclasspath_fragments: ["mybootclasspathfragment"],
+				min_sdk_version: "30",
+				updatable: false,
+			}
+
+			apex_key {
+				name: "myapex.key",
+				public_key: "testkey.avbpubkey",
+				private_key: "testkey.pem",
+			}
+
+			bootclasspath_fragment {
+				name: "mybootclasspathfragment",
+				contents: ["mybootclasspathlib"],
+				apex_available: ["myapex"],
+			}
+
+			java_sdk_library {
+				name: "mybootclasspathlib",
+				srcs: ["mybootclasspathlib.java"],
+				apex_available: ["myapex"],
+				compile_dex: true,
+				unsafe_ignore_missing_latest_api: true,
+				min_sdk_version: "31",
+				static_libs: ["util"],
+			}
+
+			java_library {
+				name: "util",
+                srcs: ["a.java"],
+				apex_available: ["myapex"],
+				min_sdk_version: "31",
+				static_libs: ["another_util"],
+			}
+
+			java_library {
+				name: "another_util",
+                srcs: ["a.java"],
+				min_sdk_version: "31",
+				apex_available: ["myapex"],
+			}
+		`)
+	})
+
+	// Test java_sdk_library in systemserverclasspath_fragment may define higher min_sdk_version than the apex
+	t.Run("systemserverclasspath_fragment jar has higher min_sdk_version than apex", func(t *testing.T) {
+		preparer.RunTestWithBp(t, `
+			apex {
+				name: "myapex",
+				key: "myapex.key",
+				systemserverclasspath_fragments: ["mysystemserverclasspathfragment"],
+				min_sdk_version: "30",
+				updatable: false,
+			}
+
+			apex_key {
+				name: "myapex.key",
+				public_key: "testkey.avbpubkey",
+				private_key: "testkey.pem",
+			}
+
+			systemserverclasspath_fragment {
+				name: "mysystemserverclasspathfragment",
+				contents: ["mysystemserverclasspathlib"],
+				apex_available: ["myapex"],
+			}
+
+			java_sdk_library {
+				name: "mysystemserverclasspathlib",
+				srcs: ["mysystemserverclasspathlib.java"],
+				apex_available: ["myapex"],
+				compile_dex: true,
+				min_sdk_version: "32",
+				unsafe_ignore_missing_latest_api: true,
+				static_libs: ["util"],
+			}
+
+			java_library {
+				name: "util",
+                srcs: ["a.java"],
+				apex_available: ["myapex"],
+				min_sdk_version: "31",
+				static_libs: ["another_util"],
+			}
+
+			java_library {
+				name: "another_util",
+                srcs: ["a.java"],
+				min_sdk_version: "31",
+				apex_available: ["myapex"],
+			}
+		`)
+	})
+
+	t.Run("bootclasspath_fragment jar must set min_sdk_version", func(t *testing.T) {
+		preparer.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "mybootclasspathlib".*must set min_sdk_version`)).
+			RunTestWithBp(t, `
+				apex {
+					name: "myapex",
+					key: "myapex.key",
+					bootclasspath_fragments: ["mybootclasspathfragment"],
+					min_sdk_version: "30",
+					updatable: false,
+				}
+
+				apex_key {
+					name: "myapex.key",
+					public_key: "testkey.avbpubkey",
+					private_key: "testkey.pem",
+				}
+
+				bootclasspath_fragment {
+					name: "mybootclasspathfragment",
+					contents: ["mybootclasspathlib"],
+					apex_available: ["myapex"],
+				}
+
+				java_sdk_library {
+					name: "mybootclasspathlib",
+					srcs: ["mybootclasspathlib.java"],
+					apex_available: ["myapex"],
+					compile_dex: true,
+					unsafe_ignore_missing_latest_api: true,
+				}
+		`)
+	})
+
+	t.Run("systemserverclasspath_fragment jar must set min_sdk_version", func(t *testing.T) {
+		preparer.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "mysystemserverclasspathlib".*must set min_sdk_version`)).
+			RunTestWithBp(t, `
+				apex {
+					name: "myapex",
+					key: "myapex.key",
+					systemserverclasspath_fragments: ["mysystemserverclasspathfragment"],
+					min_sdk_version: "30",
+					updatable: false,
+				}
+
+				apex_key {
+					name: "myapex.key",
+					public_key: "testkey.avbpubkey",
+					private_key: "testkey.pem",
+				}
+
+				systemserverclasspath_fragment {
+					name: "mysystemserverclasspathfragment",
+					contents: ["mysystemserverclasspathlib"],
+					apex_available: ["myapex"],
+				}
+
+				java_sdk_library {
+					name: "mysystemserverclasspathlib",
+					srcs: ["mysystemserverclasspathlib.java"],
+					apex_available: ["myapex"],
+					compile_dex: true,
+					unsafe_ignore_missing_latest_api: true,
+				}
+		`)
+	})
+}
+
 func TestMain(m *testing.M) {
 	os.Exit(m.Run())
 }
diff --git a/java/base.go b/java/base.go
index 2f90db2..c0da215 100644
--- a/java/base.go
+++ b/java/base.go
@@ -1643,8 +1643,7 @@
 }
 
 // Implements android.ApexModule
-func (j *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext,
-	sdkVersion android.ApiLevel) error {
+func (j *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion android.ApiLevel) error {
 	sdkSpec := j.MinSdkVersion(ctx)
 	if !sdkSpec.Specified() {
 		return fmt.Errorf("min_sdk_version is not specified")
diff --git a/java/sdk_library.go b/java/sdk_library.go
index fec0000..52ab06e 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -1129,6 +1129,8 @@
 	return generatedScopes
 }
 
+var _ android.ModuleWithMinSdkVersionCheck = (*SdkLibrary)(nil)
+
 func (module *SdkLibrary) CheckMinSdkVersion(ctx android.ModuleContext) {
 	android.CheckMinSdkVersion(ctx, module.MinSdkVersion(ctx).ApiLevel, func(c android.ModuleContext, do android.PayloadDepsCallback) {
 		ctx.WalkDeps(func(child android.Module, parent android.Module) bool {