hiddenapi: Prevent libraries for Q/R from include S+ flags.

The Q and R runtimes can handle Q/R flags but not S flags. So, this
change verifies that any library that can run on Q/R
(min_sdk_version <= R) by adding --max-hiddenapi-level=max-target-r
to the "hiddenapi encode" command. That will cause a failure if any
S+ flags are found in the flags to encode.

Bug: 172453495
Test: m droid && launch_cvd
      Cherry pick changes in https://r.android.com/q/topic:max-target-s
      Add @UnsupportedAppUsage maxTargetSdk=S in classes in framework-permission (for r/q)
      and framework-permission-s (nominally for S+). I had to incresed the min_sdk_version
      in the latter to 31 (S) as it was still set at 30 (R).
Change-Id: Ie0f68482603adc7b4e3d7a5c81bf203d81a84a9e
diff --git a/java/hiddenapi.go b/java/hiddenapi.go
index 3af5f1c..cf9c7ad 100644
--- a/java/hiddenapi.go
+++ b/java/hiddenapi.go
@@ -65,6 +65,8 @@
 type hiddenAPIModule interface {
 	android.Module
 	hiddenAPIIntf
+
+	MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec
 }
 
 type hiddenAPIIntf interface {
@@ -148,7 +150,7 @@
 	// Create a copy of the dex jar which has been encoded with hiddenapi flags.
 	flagsCSV := hiddenAPISingletonPaths(ctx).flags
 	outputDir := android.PathForModuleOut(ctx, "hiddenapi").OutputPath
-	encodedDex := hiddenAPIEncodeDex(ctx, dexJar, flagsCSV, uncompressDex, outputDir)
+	encodedDex := hiddenAPIEncodeDex(ctx, dexJar, flagsCSV, uncompressDex, android.SdkSpecNone, outputDir)
 
 	// Use the encoded dex jar from here onwards.
 	return encodedDex
@@ -246,7 +248,7 @@
 // The encode dex rule requires unzipping, encoding and rezipping the classes.dex files along with
 // all the resources from the input jar. It also ensures that if it was uncompressed in the input
 // it stays uncompressed in the output.
-func hiddenAPIEncodeDex(ctx android.ModuleContext, dexInput, flagsCSV android.Path, uncompressDex bool, outputDir android.OutputPath) android.OutputPath {
+func hiddenAPIEncodeDex(ctx android.ModuleContext, dexInput, flagsCSV android.Path, uncompressDex bool, minSdkVersion android.SdkSpec, outputDir android.OutputPath) android.OutputPath {
 
 	// The output file has the same name as the input file and is in the output directory.
 	output := outputDir.Join(ctx, dexInput.Base())
@@ -274,6 +276,15 @@
 		hiddenapiFlags = "--no-force-assign-all"
 	}
 
+	// If the library is targeted for Q and/or R then make sure that they do not
+	// have any S+ flags encoded as that will break the runtime.
+	minApiLevel := minSdkVersion.ApiLevel
+	if !minApiLevel.IsNone() {
+		if minApiLevel.LessThanOrEqualTo(android.ApiLevelOrPanic(ctx, "R")) {
+			hiddenapiFlags = hiddenapiFlags + " --max-hiddenapi-level=max-target-r"
+		}
+	}
+
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        hiddenAPIEncodeDexRule,
 		Description: "hiddenapi encode dex",