Generate "current" API level.

Support for using this coming in an upcoming patch.

Test: nose2
      readelf to check the following:
      * bsd_signal unversioned before current
      * bsd_signal versioned in current
      * catclose missing before current
      * catclose present and versioned in current
Bug: None
Change-Id: I861862161426d3ec5b530e3156d3a8ae96fed468
diff --git a/cc/androidmk.go b/cc/androidmk.go
index a4d7fcf..50c183e 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -18,7 +18,6 @@
 	"fmt"
 	"io"
 	"path/filepath"
-	"strconv"
 	"strings"
 
 	"android/soong/android"
@@ -217,7 +216,7 @@
 }
 
 func (c *stubDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
-	ret.SubName = "." + strconv.Itoa(c.properties.ApiLevel)
+	ret.SubName = "." + c.properties.ApiLevel
 	ret.Class = "SHARED_LIBRARIES"
 
 	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) error {
diff --git a/cc/gen_stub_libs.py b/cc/gen_stub_libs.py
index 2db8312..eb233f8 100755
--- a/cc/gen_stub_libs.py
+++ b/cc/gen_stub_libs.py
@@ -31,11 +31,30 @@
 )
 
 
+# Arbitrary magic number. We use the same one in api-level.h for this purpose.
+FUTURE_API_LEVEL = 10000
+
+
 def logger():
     """Return the main logger for this module."""
     return logging.getLogger(__name__)
 
 
+def api_level_arg(api_str):
+    """Parses an API level, handling the "current" special case.
+
+    Args:
+        api_str: (string) Either a numeric API level or "current".
+
+    Returns:
+        (int) FUTURE_API_LEVEL if `api_str` is "current", else `api_str` parsed
+        as an integer.
+    """
+    if api_str == "current":
+        return FUTURE_API_LEVEL
+    return int(api_str)
+
+
 def get_tags(line):
     """Returns a list of all tags on this line."""
     _, _, all_tags = line.strip().partition('#')
@@ -105,10 +124,7 @@
             introduced_tag = tag
             arch_specific = True
         elif tag == 'future':
-            # This symbol is not in any released API level.
-            # TODO(danalbert): These need to be emitted for api == current.
-            # That's not a construct we have yet, so just skip it for now.
-            return False
+            return api == FUTURE_API_LEVEL
 
     if introduced_tag is None:
         # We found no "introduced" tags, so the symbol has always been
@@ -310,7 +326,8 @@
     parser.add_argument('-v', '--verbose', action='count', default=0)
 
     parser.add_argument(
-        '--api', type=int, required=True, help='API level being targeted.')
+        '--api', type=api_level_arg, required=True,
+        help='API level being targeted.')
     parser.add_argument(
         '--arch', choices=ALL_ARCHITECTURES, required=True,
         help='Architecture being targeted.')
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index 94be17c..d603ad0 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -88,7 +88,7 @@
 	First_version string
 
 	// Private property for use by the mutator that splits per-API level.
-	ApiLevel int `blueprint:"mutated"`
+	ApiLevel string `blueprint:"mutated"`
 }
 
 type stubDecorator struct {
@@ -147,14 +147,15 @@
 		mctx.PropertyErrorf("first_version", err.Error())
 	}
 
-	versionStrs := make([]string, maxVersion-firstVersion+1)
+	var versionStrs []string
 	for version := firstVersion; version <= maxVersion; version++ {
-		versionStrs[version-firstVersion] = strconv.Itoa(version)
+		versionStrs = append(versionStrs, strconv.Itoa(version))
 	}
+	versionStrs = append(versionStrs, "current")
 
 	modules := mctx.CreateVariations(versionStrs...)
 	for i, module := range modules {
-		module.(*Module).compiler.(*stubDecorator).properties.ApiLevel = firstVersion + i
+		module.(*Module).compiler.(*stubDecorator).properties.ApiLevel = versionStrs[i]
 	}
 }
 
@@ -188,7 +189,7 @@
 			ndkLibrarySuffix)
 	}
 	libName := strings.TrimSuffix(ctx.ModuleName(), ndkLibrarySuffix)
-	fileBase := fmt.Sprintf("%s.%s.%d", libName, arch, c.properties.ApiLevel)
+	fileBase := fmt.Sprintf("%s.%s.%s", libName, arch, c.properties.ApiLevel)
 	stubSrcName := fileBase + ".c"
 	stubSrcPath := android.PathForModuleGen(ctx, stubSrcName)
 	versionScriptName := fileBase + ".map"
@@ -201,7 +202,7 @@
 		Input:   symbolFilePath,
 		Args: map[string]string{
 			"arch":     arch,
-			"apiLevel": strconv.Itoa(c.properties.ApiLevel),
+			"apiLevel": c.properties.ApiLevel,
 		},
 	})
 
@@ -252,7 +253,7 @@
 	}
 
 	installDir := getNdkInstallBase(ctx).Join(ctx, fmt.Sprintf(
-		"platforms/android-%d/arch-%s/usr/%s", apiLevel, arch, libDir))
+		"platforms/android-%s/arch-%s/usr/%s", apiLevel, arch, libDir))
 	stub.installPath = ctx.InstallFile(installDir, path).String()
 }
 
diff --git a/cc/test_gen_stub_libs.py b/cc/test_gen_stub_libs.py
index 2c79ded..e9e7249 100755
--- a/cc/test_gen_stub_libs.py
+++ b/cc/test_gen_stub_libs.py
@@ -75,6 +75,8 @@
             ['introduced=9', 'introduced-x86=21'], 'arm', 14))
         self.assertTrue(gsl.symbol_in_api(
             ['introduced=21', 'introduced-arm=9'], 'arm', 14))
+        self.assertTrue(gsl.symbol_in_api(
+            ['future'], 'arm', gsl.FUTURE_API_LEVEL))
 
         self.assertFalse(gsl.symbol_in_api(['introduced=14'], 'arm', 9))
         self.assertFalse(gsl.symbol_in_api(['introduced-arm=14'], 'arm', 9))