Generate stub libraries for unreleased API levels.

Generating released API levels and android-current is not sufficient
in a trunk-stable world. One branch will have the stable APIs and
possibly multiple unreleased API levels. We need to generate stubs
for each unreleased API level up to our current target.

I still need to add support for things like `# introduced=O` before
this is really done.

Whether or not we still need something like "current" that would map
to the absolute latest even it hasn't been assigned a code name yet
is uncertain.

Test: make ndk
Bug: None
Change-Id: I282be1347ab39c56fa887d4d71c03bb12c300dc5
diff --git a/cc/gen_stub_libs.py b/cc/gen_stub_libs.py
index 7c70406..8a4f21e 100755
--- a/cc/gen_stub_libs.py
+++ b/cc/gen_stub_libs.py
@@ -16,6 +16,7 @@
 #
 """Generates source for stub shared libraries for the NDK."""
 import argparse
+import json
 import logging
 import os
 import re
@@ -326,6 +327,27 @@
                 self.version_script.write('}' + base + ';\n')
 
 
+def decode_api_level(api, api_map):
+    """Decodes the API level argument into the API level number.
+
+    For the average case, this just decodes the integer value from the string,
+    but for unreleased APIs we need to translate from the API codename (like
+    "O") to the future API level for that codename.
+    """
+    try:
+        return int(api)
+    except ValueError:
+        pass
+
+    if api == "current":
+        return FUTURE_API_LEVEL
+
+    with open(api_map) as map_file:
+        api_levels = json.load(map_file)
+
+    return api_levels[api]
+
+
 def parse_args():
     """Parses and returns command line arguments."""
     parser = argparse.ArgumentParser()
@@ -333,8 +355,7 @@
     parser.add_argument('-v', '--verbose', action='count', default=0)
 
     parser.add_argument(
-        '--api', type=api_level_arg, required=True,
-        help='API level being targeted.')
+        '--api', required=True, help='API level being targeted.')
     parser.add_argument(
         '--arch', choices=ALL_ARCHITECTURES, required=True,
         help='Architecture being targeted.')
@@ -342,6 +363,10 @@
         '--vndk', action='store_true', help='Use the VNDK variant.')
 
     parser.add_argument(
+        '--api-map', type=os.path.realpath, required=True,
+        help='Path to the API level map JSON file.')
+
+    parser.add_argument(
         'symbol_file', type=os.path.realpath, help='Path to symbol file.')
     parser.add_argument(
         'stub_src', type=os.path.realpath,
@@ -357,6 +382,8 @@
     """Program entry point."""
     args = parse_args()
 
+    api = decode_api_level(args.api, args.api_map)
+
     verbose_map = (logging.WARNING, logging.INFO, logging.DEBUG)
     verbosity = args.verbose
     if verbosity > 2:
@@ -368,7 +395,7 @@
 
     with open(args.stub_src, 'w') as src_file:
         with open(args.version_script, 'w') as version_file:
-            generator = Generator(src_file, version_file, args.arch, args.api,
+            generator = Generator(src_file, version_file, args.arch, api,
                                   args.vndk)
             generator.write(versions)
 
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index d769fea..1bd63a9 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -30,10 +30,11 @@
 
 	genStubSrc = pctx.AndroidStaticRule("genStubSrc",
 		blueprint.RuleParams{
-			Command:     "$toolPath --arch $arch --api $apiLevel $vndk $in $out",
+			Command: "$toolPath --arch $arch --api $apiLevel --api-map " +
+				"$apiMap $vndk $in $out",
 			Description: "genStubSrc $out",
 			CommandDeps: []string{"$toolPath"},
-		}, "arch", "apiLevel", "vndk")
+		}, "arch", "apiLevel", "apiMap", "vndk")
 
 	ndkLibrarySuffix = ".ndk"
 
@@ -205,6 +206,7 @@
 	for version := firstGenVersion; version <= platformVersion; version++ {
 		versionStrs = append(versionStrs, strconv.Itoa(version))
 	}
+	versionStrs = append(versionStrs, mctx.AConfig().PlatformVersionAllCodenames()...)
 	versionStrs = append(versionStrs, "current")
 
 	modules := mctx.CreateVariations(versionStrs...)
@@ -247,13 +249,16 @@
 	stubSrcPath := android.PathForModuleGen(ctx, "stub.c")
 	versionScriptPath := android.PathForModuleGen(ctx, "stub.map")
 	symbolFilePath := android.PathForModuleSrc(ctx, symbolFile)
+	apiLevelsJson := android.GetApiLevelsJson(ctx)
 	ctx.ModuleBuild(pctx, android.ModuleBuildParams{
-		Rule:    genStubSrc,
-		Outputs: []android.WritablePath{stubSrcPath, versionScriptPath},
-		Input:   symbolFilePath,
+		Rule:      genStubSrc,
+		Outputs:   []android.WritablePath{stubSrcPath, versionScriptPath},
+		Input:     symbolFilePath,
+		Implicits: []android.Path{apiLevelsJson},
 		Args: map[string]string{
 			"arch":     arch,
 			"apiLevel": apiLevel,
+			"apiMap":   apiLevelsJson.String(),
 			"vndk":     vndk,
 		},
 	})