Enforce hidden apis usage in product(soong)

Only if PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE is set,
every app and java library in product cannot use hidden APIs anymore.

checkSdkVersion() checks if sdk_version of app and library is narrow enough,
checkLinkType() checks every library that app links agianst

Bug: 132780927
Test: m
Test: set PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE, and check whether build
error occurs.
Change-Id: Ic630503b875040f730feda4fef826ed6d71da111
diff --git a/java/aar.go b/java/aar.go
index afe860c..d8db192 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -520,7 +520,7 @@
 }
 
 func (a *AARImport) sdkVersion() string {
-	return proptools.StringDefault(a.properties.Sdk_version, defaultSdkVersion(a))
+	return String(a.properties.Sdk_version)
 }
 
 func (a *AARImport) systemModules() string {
diff --git a/java/app.go b/java/app.go
index bd8556e..ddd63f9 100644
--- a/java/app.go
+++ b/java/app.go
@@ -206,6 +206,7 @@
 
 func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	a.checkPlatformAPI(ctx)
+	a.checkSdkVersion(ctx)
 	a.generateAndroidBuildActions(ctx)
 }
 
diff --git a/java/app_test.go b/java/app_test.go
index 05ab856..ba08f58 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -666,6 +666,44 @@
 	}
 }
 
+func TestAppSdkVersionByPartition(t *testing.T) {
+	testJavaError(t, "sdk_version must have a value when the module is located at vendor or product", `
+		android_app {
+			name: "foo",
+			srcs: ["a.java"],
+			vendor: true,
+			platform_apis: true,
+		}
+	`)
+
+	testJava(t, `
+		android_app {
+			name: "bar",
+			srcs: ["b.java"],
+			platform_apis: true,
+		}
+	`)
+
+	for _, enforce := range []bool{true, false} {
+
+		config := testConfig(nil)
+		config.TestProductVariables.EnforceProductPartitionInterface = proptools.BoolPtr(enforce)
+		bp := `
+			android_app {
+				name: "foo",
+				srcs: ["a.java"],
+				product_specific: true,
+				platform_apis: true,
+			}
+		`
+		if enforce {
+			testJavaErrorWithConfig(t, "sdk_version must have a value when the module is located at vendor or product", bp, config)
+		} else {
+			testJavaWithConfig(t, bp, config)
+		}
+	}
+}
+
 func TestJNIPackaging(t *testing.T) {
 	ctx, _ := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
 		cc_library {
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 6f3b152..9a38050 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -404,7 +404,7 @@
 var _ android.OutputFileProducer = (*Javadoc)(nil)
 
 func (j *Javadoc) sdkVersion() string {
-	return proptools.StringDefault(j.properties.Sdk_version, defaultSdkVersion(j))
+	return String(j.properties.Sdk_version)
 }
 
 func (j *Javadoc) systemModules() string {
diff --git a/java/java.go b/java/java.go
index d7077d1..d043a12 100644
--- a/java/java.go
+++ b/java/java.go
@@ -54,6 +54,18 @@
 	android.RegisterSingletonType("kythe_java_extract", kytheExtractJavaFactory)
 }
 
+func (j *Module) checkSdkVersion(ctx android.ModuleContext) {
+	if j.SocSpecific() || j.DeviceSpecific() ||
+		(j.ProductSpecific() && ctx.Config().EnforceProductPartitionInterface()) {
+		if sc, ok := ctx.Module().(sdkContext); ok {
+			if sc.sdkVersion() == "" {
+				ctx.PropertyErrorf("sdk_version",
+					"sdk_version must have a value when the module is located at vendor or product(only if PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE is set).")
+			}
+		}
+	}
+}
+
 func (j *Module) checkPlatformAPI(ctx android.ModuleContext) {
 	if sc, ok := ctx.Module().(sdkContext); ok {
 		usePlatformAPI := proptools.Bool(j.deviceProperties.Platform_apis)
@@ -447,18 +459,6 @@
 	usesLibTag            = dependencyTag{name: "uses-library"}
 )
 
-func defaultSdkVersion(ctx checkVendorModuleContext) string {
-	if ctx.SocSpecific() || ctx.DeviceSpecific() {
-		return "system_current"
-	}
-	return ""
-}
-
-type checkVendorModuleContext interface {
-	SocSpecific() bool
-	DeviceSpecific() bool
-}
-
 type sdkDep struct {
 	useModule, useFiles, useDefaultLibs, invalidVersion bool
 
@@ -505,7 +505,7 @@
 }
 
 func (j *Module) sdkVersion() string {
-	return proptools.StringDefault(j.deviceProperties.Sdk_version, defaultSdkVersion(j))
+	return String(j.deviceProperties.Sdk_version)
 }
 
 func (j *Module) systemModules() string {
@@ -1635,6 +1635,7 @@
 }
 
 func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	j.checkSdkVersion(ctx)
 	j.dexpreopter.installPath = android.PathForModuleInstall(ctx, "framework", j.Stem()+".jar")
 	j.dexpreopter.isSDKLibrary = j.deviceProperties.IsSDKLibrary
 	j.dexpreopter.isInstallable = Bool(j.properties.Installable)
@@ -1978,7 +1979,7 @@
 }
 
 func (j *Import) sdkVersion() string {
-	return proptools.StringDefault(j.properties.Sdk_version, defaultSdkVersion(j))
+	return String(j.properties.Sdk_version)
 }
 
 func (j *Import) minSdkVersion() string {
diff --git a/java/java_test.go b/java/java_test.go
index a6ae503..e3e45d7 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -27,6 +27,8 @@
 	"android/soong/cc"
 	"android/soong/dexpreopt"
 	"android/soong/genrule"
+
+	"github.com/google/blueprint/proptools"
 )
 
 var buildDir string
@@ -228,9 +230,13 @@
 	android.FailIfErrored(t, errs)
 }
 
-func testJavaError(t *testing.T, pattern string, bp string) {
+func testJavaError(t *testing.T, pattern string, bp string) (*android.TestContext, android.Config) {
 	t.Helper()
-	config := testConfig(nil)
+	return testJavaErrorWithConfig(t, pattern, bp, testConfig(nil))
+}
+
+func testJavaErrorWithConfig(t *testing.T, pattern string, bp string, config android.Config) (*android.TestContext, android.Config) {
+	t.Helper()
 	ctx := testContext(bp, nil)
 
 	pathCtx := android.PathContextForTesting(config, nil)
@@ -240,20 +246,26 @@
 	_, errs := ctx.ParseBlueprintsFiles("Android.bp")
 	if len(errs) > 0 {
 		android.FailIfNoMatchingErrors(t, pattern, errs)
-		return
+		return ctx, config
 	}
 	_, errs = ctx.PrepareBuildActions(config)
 	if len(errs) > 0 {
 		android.FailIfNoMatchingErrors(t, pattern, errs)
-		return
+		return ctx, config
 	}
 
 	t.Fatalf("missing expected error %q (0 errors are returned)", pattern)
+
+	return ctx, config
 }
 
 func testJava(t *testing.T, bp string) (*android.TestContext, android.Config) {
 	t.Helper()
-	config := testConfig(nil)
+	return testJavaWithConfig(t, bp, testConfig(nil))
+}
+
+func testJavaWithConfig(t *testing.T, bp string, config android.Config) (*android.TestContext, android.Config) {
+	t.Helper()
 	ctx := testContext(bp, nil)
 	run(t, ctx, config)
 
@@ -315,29 +327,38 @@
 	}
 }
 
-func TestSdkVersion(t *testing.T) {
-	ctx, _ := testJava(t, `
+func TestSdkVersionByPartition(t *testing.T) {
+	testJavaError(t, "sdk_version must have a value when the module is located at vendor or product", `
 		java_library {
 			name: "foo",
 			srcs: ["a.java"],
 			vendor: true,
 		}
+	`)
 
+	testJava(t, `
 		java_library {
 			name: "bar",
 			srcs: ["b.java"],
 		}
 	`)
 
-	foo := ctx.ModuleForTests("foo", "android_common").Module().(*Library)
-	bar := ctx.ModuleForTests("bar", "android_common").Module().(*Library)
+	for _, enforce := range []bool{true, false} {
 
-	if foo.sdkVersion() != "system_current" {
-		t.Errorf("If sdk version of vendor module is empty, it must change to system_current.")
-	}
-
-	if bar.sdkVersion() != "" {
-		t.Errorf("If sdk version of non-vendor module is empty, it keeps empty.")
+		config := testConfig(nil)
+		config.TestProductVariables.EnforceProductPartitionInterface = proptools.BoolPtr(enforce)
+		bp := `
+			java_library {
+				name: "foo",
+				srcs: ["a.java"],
+				product_specific: true,
+			}
+		`
+		if enforce {
+			testJavaErrorWithConfig(t, "sdk_version must have a value when the module is located at vendor or product", bp, config)
+		} else {
+			testJavaWithConfig(t, bp, config)
+		}
 	}
 }