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)