Generate constants for enum values.

Test: Builds successfully, tests pass and statsd works (it seems).

This will allow us to use those constants instead of literals.
The generated code only augmentes the java constant file.
If needed, the same can be done for the C++ file.
Some of the constant names are very long, but this is due to enum value names that are unnecessarily redundant with the enum names, i.e.
enum ENUM_NAME {
  ENUM_NAME_UNKNOWN = 0;
  ENUM_NAME_VALUE1 = 1;
  ENUM_NAME_VALUE2 = 2;
  ...
}
which can be fixed by avoiding the 'ENUM_NAME_' part in the value names above.
So, when possible, we should use shorter value names in stats_events.proto.

Change-Id: I1ad19b86e28d0df0f8c15d4c995d101423cff4c2
diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp
index 5d29268..f76196d 100644
--- a/tools/stats_log_api_gen/Collation.cpp
+++ b/tools/stats_log_api_gen/Collation.cpp
@@ -22,6 +22,7 @@
 namespace android {
 namespace stats_log_api_gen {
 
+using google::protobuf::EnumDescriptor;
 using google::protobuf::FieldDescriptor;
 using google::protobuf::FileDescriptor;
 using google::protobuf::SourceLocation;
@@ -120,7 +121,7 @@
         case FieldDescriptor::TYPE_UINT32:
             return JAVA_TYPE_INT;
         case FieldDescriptor::TYPE_ENUM:
-            return JAVA_TYPE_INT;
+            return JAVA_TYPE_ENUM;
         case FieldDescriptor::TYPE_SFIXED32:
             return JAVA_TYPE_INT;
         case FieldDescriptor::TYPE_SFIXED64:
@@ -208,7 +209,6 @@
                 errorCount++;
                 continue;
             }
-
         }
 
         // Check that if there's a WorkSource, it's at position 1.
@@ -228,15 +228,26 @@
 
         AtomDecl atomDecl(atomField->number(), atomField->name(), atom->name());
 
-        // Build the type signature
+        // Build the type signature and the atom data.
         vector<java_type_t> signature;
         for (map<int,const FieldDescriptor*>::const_iterator it = fields.begin();
                 it != fields.end(); it++) {
             const FieldDescriptor* field = it->second;
             java_type_t javaType = java_type(field);
 
-            atomDecl.fields.push_back(AtomField(field->name(), javaType));
-            signature.push_back(javaType);
+            AtomField atField(field->name(), javaType);
+            if (javaType == JAVA_TYPE_ENUM) {
+                // All enums are treated as ints when it comes to function signatures.
+                signature.push_back(JAVA_TYPE_INT);
+                const EnumDescriptor* enumDescriptor = field->enum_type();
+                for (int i = 0; i < enumDescriptor->value_count(); i++) {
+                    atField.enumValues[enumDescriptor->value(i)->number()] =
+                        enumDescriptor->value(i)->name().c_str();
+                }
+            } else {
+                signature.push_back(javaType);
+            }
+            atomDecl.fields.push_back(atField);
         }
 
         atoms->signatures.insert(signature);
@@ -261,5 +272,3 @@
 
 }  // namespace stats_log_api_gen
 }  // namespace android
-
-
diff --git a/tools/stats_log_api_gen/Collation.h b/tools/stats_log_api_gen/Collation.h
index 50af7ea..2f840d7 100644
--- a/tools/stats_log_api_gen/Collation.h
+++ b/tools/stats_log_api_gen/Collation.h
@@ -22,10 +22,12 @@
 
 #include <set>
 #include <vector>
+#include <map>
 
 namespace android {
 namespace stats_log_api_gen {
 
+using std::map;
 using std::set;
 using std::string;
 using std::vector;
@@ -44,6 +46,7 @@
     JAVA_TYPE_FLOAT = 5,
     JAVA_TYPE_DOUBLE = 6,
     JAVA_TYPE_STRING = 7,
+    JAVA_TYPE_ENUM = 8,
 
     JAVA_TYPE_OBJECT = -1,
     JAVA_TYPE_BYTE_ARRAY = -2,
@@ -57,8 +60,13 @@
     string name;
     java_type_t javaType;
 
+    // If the field is of type enum, the following map contains the list of enum values.
+    map<int /* numeric value */, string /* value name */> enumValues;
+
     inline AtomField() :name(), javaType(JAVA_TYPE_UNKNOWN) {}
-    inline AtomField(const AtomField& that) :name(that.name), javaType(that.javaType) {}
+    inline AtomField(const AtomField& that) :name(that.name),
+                                             javaType(that.javaType),
+                                             enumValues(that.enumValues) {}
     inline AtomField(string n, java_type_t jt) :name(n), javaType(jt) {}
     inline ~AtomField() {}
 };
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index aaea4f6..6350b72 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -56,6 +56,7 @@
         case JAVA_TYPE_BOOLEAN:
             return "bool";
         case JAVA_TYPE_INT:
+        case JAVA_TYPE_ENUM:
             return "int32_t";
         case JAVA_TYPE_LONG:
             return "int64_t";
@@ -77,6 +78,7 @@
         case JAVA_TYPE_BOOLEAN:
             return "boolean";
         case JAVA_TYPE_INT:
+        case JAVA_TYPE_ENUM:
             return "int";
         case JAVA_TYPE_LONG:
             return "long";
@@ -173,7 +175,7 @@
     fprintf(out, " */\n");
     fprintf(out, "\n");
     fprintf(out, "/**\n");
-    fprintf(out, " * Constants for event codes.\n");
+    fprintf(out, " * Constants for atom codes.\n");
     fprintf(out, " */\n");
     fprintf(out, "enum {\n");
 
@@ -240,9 +242,9 @@
     fprintf(out, " * @hide\n");
     fprintf(out, " */\n");
     fprintf(out, "public final class StatsLog {\n");
-    fprintf(out, "    // Constants for event codes.\n");
+    fprintf(out, "    // Constants for atom codes.\n");
 
-    // Print constants
+    // Print constants for the atom codes.
     for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
             atom != atoms.decls.end(); atom++) {
         string constant = make_constant_name(atom->name);
@@ -260,6 +262,27 @@
     }
     fprintf(out, "\n");
 
+    // Print constants for the enum values.
+    fprintf(out, "    // Constants for enum values.\n\n");
+    for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
+            atom != atoms.decls.end(); atom++) {
+        for (vector<AtomField>::const_iterator field = atom->fields.begin();
+                field != atom->fields.end(); field++) {
+          if (field->javaType == JAVA_TYPE_ENUM) {
+            fprintf(out, "    // Values for %s.%s\n", atom->message.c_str(), field->name.c_str());
+            for (map<int, string>::const_iterator value = field->enumValues.begin();
+                 value != field->enumValues.end(); value++) {
+              fprintf(out, "    public static final int %s__%s__%s = %d;\n",
+                      make_constant_name(atom->message).c_str(),
+                      make_constant_name(field->name).c_str(),
+                      make_constant_name(value->second).c_str(),
+                      value->first);
+            }
+            fprintf(out, "\n");
+          }
+        }
+    }
+
     // Print write methods
     fprintf(out, "    // Write methods\n");
     for (set<vector<java_type_t>>::const_iterator signature = atoms.signatures.begin();
@@ -286,6 +309,7 @@
         case JAVA_TYPE_BOOLEAN:
             return "jboolean";
         case JAVA_TYPE_INT:
+        case JAVA_TYPE_ENUM:
             return "jint";
         case JAVA_TYPE_LONG:
             return "jlong";
@@ -311,6 +335,7 @@
                 result += "_boolean";
                 break;
             case JAVA_TYPE_INT:
+            case JAVA_TYPE_ENUM:
                 result += "_int";
                 break;
             case JAVA_TYPE_LONG:
@@ -340,6 +365,7 @@
         case JAVA_TYPE_BOOLEAN:
             return "Z";
         case JAVA_TYPE_INT:
+        case JAVA_TYPE_ENUM:
             return "I";
         case JAVA_TYPE_LONG:
             return "J";
diff --git a/tools/stats_log_api_gen/test_collation.cpp b/tools/stats_log_api_gen/test_collation.cpp
index 1bd2e3d..073f2cf 100644
--- a/tools/stats_log_api_gen/test_collation.cpp
+++ b/tools/stats_log_api_gen/test_collation.cpp
@@ -24,6 +24,7 @@
 namespace android {
 namespace stats_log_api_gen {
 
+using std::map;
 using std::set;
 using std::vector;
 
@@ -54,6 +55,29 @@
         EXPECT_TRUE(set_contains_vector(s, count, __VA_ARGS__)); \
     } while(0)
 
+/** Expects that the provided atom has no enum values for any field. */
+#define EXPECT_NO_ENUM_FIELD(atom) \
+    do { \
+        for (vector<AtomField>::const_iterator field = atom->fields.begin(); \
+             field != atom->fields.end(); field++) { \
+            EXPECT_TRUE(field->enumValues.empty()); \
+        } \
+    } while(0)
+
+/** Expects that exactly one specific field has expected enum values. */ 
+#define EXPECT_HAS_ENUM_FIELD(atom, field_name, values)        \
+    do { \
+        for (vector<AtomField>::const_iterator field = atom->fields.begin(); \
+             field != atom->fields.end(); field++) { \
+            if (field->name == field_name) { \
+                EXPECT_EQ(field->enumValues, values); \
+            } else { \
+                EXPECT_TRUE(field->enumValues.empty()); \
+            } \
+        } \
+    } while(0)
+
+
 /**
  * Test a correct collation, with all the types.
  */
@@ -94,21 +118,28 @@
     EXPECT_EQ(1, atom->code);
     EXPECT_EQ("int_atom", atom->name);
     EXPECT_EQ("IntAtom", atom->message);
+    EXPECT_NO_ENUM_FIELD(atom);
     atom++;
 
     EXPECT_EQ(2, atom->code);
     EXPECT_EQ("out_of_order_atom", atom->name);
     EXPECT_EQ("OutOfOrderAtom", atom->message);
+    EXPECT_NO_ENUM_FIELD(atom);
     atom++;
 
     EXPECT_EQ(3, atom->code);
     EXPECT_EQ("another_int_atom", atom->name);
     EXPECT_EQ("AnotherIntAtom", atom->message);
+    EXPECT_NO_ENUM_FIELD(atom);
     atom++;
 
     EXPECT_EQ(4, atom->code);
     EXPECT_EQ("all_types_atom", atom->name);
     EXPECT_EQ("AllTypesAtom", atom->message);
+    map<int, string> enumValues;
+    enumValues[0] = "VALUE0";
+    enumValues[1] = "VALUE1";
+    EXPECT_HAS_ENUM_FIELD(atom, "enum_field", enumValues);
     atom++;
 
     EXPECT_TRUE(atom == atoms.decls.end());
@@ -125,7 +156,7 @@
 }
 
 /**
- * Test that atoms that have non-primitve types are rejected.
+ * Test that atoms that have non-primitive types are rejected.
  */
 TEST(CollationTest, FailOnBadTypes) {
     Atoms atoms;
@@ -165,7 +196,5 @@
     EXPECT_EQ(1, errorCount);
 }
 
-
 }  // namespace stats_log_api_gen
 }  // namespace android
-