Introduce module type 'sdk'

This change introduces a new module type named 'sdk'. It is a logical
group of prebuilt modules that together provide a context (e.g. APIs)
in which Mainline modules (such as APEXes) are built.

A prebuilt module (e.g. java_import) can join an sdk by adding it to the
sdk module as shown below:

sdk {
    name: "mysdk#20",
    java_libs: ["myjavalib_mysdk_20"],
}

java_import {
    name: "myjavalib_mysdk_20",
    srcs: ["myjavalib-v20.jar"],
    sdk_member_name: "myjavalib",
}

sdk {
    name: "mysdk#21",
    java_libs: ["myjavalib_mysdk_21"],
}

java_import {
    name: "myjavalib_mysdk_21",
    srcs: ["myjavalib-v21.jar"],
    sdk_member_name: "myjavalib",
}

java_library {
    name: "myjavalib",
    srcs: ["**/*/*.java"],
}

An APEX can specify the SDK(s) that it wants to build with via the new
'uses_sdks' property.

apex {
    name: "myapex",
    java_libs: ["libX", "libY"],
    uses_sdks: ["mysdk#20"],
}

With this, libX, libY, and their transitive dependencies are all built
with the version 20 of myjavalib (the first java_import module) instead
of the other one (which is for version 21) and java_library having the
same name (which is for ToT).

Bug: 138182343
Test: m (sdk_test.go added)
Change-Id: I7e14c524a7d6a0d9f575fb20822080f39818c01e
diff --git a/apex/apex.go b/apex/apex.go
index 4f79c42..4383876 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -185,7 +185,7 @@
 	pctx.HostBinToolVariable("zipalign", "zipalign")
 	pctx.HostBinToolVariable("jsonmodify", "jsonmodify")
 
-	android.RegisterModuleType("apex", apexBundleFactory)
+	android.RegisterModuleType("apex", BundleFactory)
 	android.RegisterModuleType("apex_test", testApexBundleFactory)
 	android.RegisterModuleType("apex_vndk", vndkApexBundleFactory)
 	android.RegisterModuleType("apex_defaults", defaultsFactory)
@@ -195,12 +195,14 @@
 		ctx.TopDown("apex_vndk_gather", apexVndkGatherMutator).Parallel()
 		ctx.BottomUp("apex_vndk_add_deps", apexVndkAddDepsMutator).Parallel()
 	})
-	android.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
-		ctx.TopDown("apex_deps", apexDepsMutator)
-		ctx.BottomUp("apex", apexMutator).Parallel()
-		ctx.BottomUp("apex_flattened", apexFlattenedMutator).Parallel()
-		ctx.BottomUp("apex_uses", apexUsesMutator).Parallel()
-	})
+	android.PostDepsMutators(RegisterPostDepsMutators)
+}
+
+func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) {
+	ctx.TopDown("apex_deps", apexDepsMutator)
+	ctx.BottomUp("apex", apexMutator).Parallel()
+	ctx.BottomUp("apex_flattened", apexFlattenedMutator).Parallel()
+	ctx.BottomUp("apex_uses", apexUsesMutator).Parallel()
 }
 
 var (
@@ -409,6 +411,12 @@
 	// To distinguish between flattened and non-flattened variants.
 	// if set true, then this variant is flattened variant.
 	Flattened bool `blueprint:"mutated"`
+
+	// List of SDKs that are used to build this APEX. A reference to an SDK should be either
+	// `name#version` or `name` which is an alias for `name#current`. If left empty, `platform#current`
+	// is implied. This value affects all modules included in this APEX. In other words, they are
+	// also built with the SDKs specified here.
+	Uses_sdks []string
 }
 
 type apexTargetBundleProperties struct {
@@ -535,6 +543,7 @@
 type apexBundle struct {
 	android.ModuleBase
 	android.DefaultableModuleBase
+	android.SdkBase
 
 	properties       apexBundleProperties
 	targetProperties apexTargetBundleProperties
@@ -737,6 +746,16 @@
 	if cert != "" {
 		ctx.AddDependency(ctx.Module(), certificateTag, cert)
 	}
+
+	// TODO(jiyong): ensure that all apexes are with non-empty uses_sdks
+	if len(a.properties.Uses_sdks) > 0 {
+		sdkRefs := []android.SdkRef{}
+		for _, str := range a.properties.Uses_sdks {
+			parsed := android.ParseSdkRef(ctx, str, "uses_sdks")
+			sdkRefs = append(sdkRefs, parsed)
+		}
+		a.BuildWithSdks(sdkRefs)
+	}
 }
 
 func (a *apexBundle) getCertString(ctx android.BaseModuleContext) string {
@@ -1706,6 +1725,7 @@
 	})
 	android.InitAndroidMultiTargetsArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
 	android.InitDefaultableModule(module)
+	android.InitSdkAwareModule(module)
 	return module
 }
 
@@ -1721,7 +1741,7 @@
 	return bundle
 }
 
-func apexBundleFactory() android.Module {
+func BundleFactory() android.Module {
 	return newApexBundle()
 }