Home | History | Annotate | Download | only in stats_log_api_gen
      1 
      2 
      3 #include "Collation.h"
      4 
      5 #include "frameworks/base/cmds/statsd/src/atoms.pb.h"
      6 
      7 #include <set>
      8 #include <vector>
      9 
     10 #include <getopt.h>
     11 #include <stdio.h>
     12 #include <stdlib.h>
     13 #include <string.h>
     14 
     15 using namespace google::protobuf;
     16 using namespace std;
     17 
     18 namespace android {
     19 namespace stats_log_api_gen {
     20 
     21 const int PULL_ATOM_START_ID = 1000;
     22 
     23 int maxPushedAtomId = 2;
     24 
     25 using android::os::statsd::Atom;
     26 
     27 /**
     28  * Turn lower and camel case into upper case with underscores.
     29  */
     30 static string
     31 make_constant_name(const string& str)
     32 {
     33     string result;
     34     const int N = str.size();
     35     bool underscore_next = false;
     36     for (int i=0; i<N; i++) {
     37         char c = str[i];
     38         if (c >= 'A' && c <= 'Z') {
     39             if (underscore_next) {
     40                 result += '_';
     41                 underscore_next = false;
     42             }
     43         } else if (c >= 'a' && c <= 'z') {
     44             c = 'A' + c - 'a';
     45             underscore_next = true;
     46         } else if (c == '_') {
     47             underscore_next = false;
     48         }
     49         result += c;
     50     }
     51     return result;
     52 }
     53 
     54 static const char*
     55 cpp_type_name(java_type_t type)
     56 {
     57     switch (type) {
     58         case JAVA_TYPE_BOOLEAN:
     59             return "bool";
     60         case JAVA_TYPE_INT:
     61         case JAVA_TYPE_ENUM:
     62             return "int32_t";
     63         case JAVA_TYPE_LONG:
     64             return "int64_t";
     65         case JAVA_TYPE_FLOAT:
     66             return "float";
     67         case JAVA_TYPE_DOUBLE:
     68             return "double";
     69         case JAVA_TYPE_STRING:
     70             return "char const*";
     71         default:
     72             return "UNKNOWN";
     73     }
     74 }
     75 
     76 static const char*
     77 java_type_name(java_type_t type)
     78 {
     79     switch (type) {
     80         case JAVA_TYPE_BOOLEAN:
     81             return "boolean";
     82         case JAVA_TYPE_INT:
     83         case JAVA_TYPE_ENUM:
     84             return "int";
     85         case JAVA_TYPE_LONG:
     86             return "long";
     87         case JAVA_TYPE_FLOAT:
     88             return "float";
     89         case JAVA_TYPE_DOUBLE:
     90             return "double";
     91         case JAVA_TYPE_STRING:
     92             return "java.lang.String";
     93         default:
     94             return "UNKNOWN";
     95     }
     96 }
     97 
     98 static int write_stats_log_cpp(FILE *out, const Atoms &atoms,
     99                                const AtomDecl &attributionDecl) {
    100     // Print prelude
    101     fprintf(out, "// This file is autogenerated\n");
    102     fprintf(out, "\n");
    103 
    104     fprintf(out, "#include <mutex>\n");
    105     fprintf(out, "#include <chrono>\n");
    106     fprintf(out, "#include <thread>\n");
    107     fprintf(out, "#include <cutils/properties.h>\n");
    108     fprintf(out, "#include <stats_event_list.h>\n");
    109     fprintf(out, "#include <log/log.h>\n");
    110     fprintf(out, "#include <statslog.h>\n");
    111     fprintf(out, "#include <utils/SystemClock.h>\n");
    112     fprintf(out, "\n");
    113 
    114     fprintf(out, "namespace android {\n");
    115     fprintf(out, "namespace util {\n");
    116     fprintf(out, "// the single event tag id for all stats logs\n");
    117     fprintf(out, "const static int kStatsEventTag = 1937006964;\n");
    118     fprintf(out, "const static bool kStatsdEnabled = property_get_bool(\"ro.statsd.enable\", true);\n");
    119 
    120     std::set<string> kTruncatingAtomNames = {"mobile_radio_power_state_changed",
    121                                              "audio_state_changed",
    122                                              "call_state_changed",
    123                                              "phone_signal_strength_changed",
    124                                              "mobile_bytes_transfer_by_fg_bg",
    125                                              "mobile_bytes_transfer"};
    126     fprintf(out,
    127             "const std::set<int> "
    128             "AtomsInfo::kNotTruncatingTimestampAtomWhiteList = {\n");
    129     for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
    130          atom != atoms.decls.end(); atom++) {
    131         if (kTruncatingAtomNames.find(atom->name) ==
    132             kTruncatingAtomNames.end()) {
    133             string constant = make_constant_name(atom->name);
    134             fprintf(out, " %s,\n", constant.c_str());
    135         }
    136     }
    137     fprintf(out, "};\n");
    138     fprintf(out, "\n");
    139 
    140     fprintf(out,
    141             "const std::set<int> AtomsInfo::kAtomsWithAttributionChain = {\n");
    142     for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
    143          atom != atoms.decls.end(); atom++) {
    144         for (vector<AtomField>::const_iterator field = atom->fields.begin();
    145              field != atom->fields.end(); field++) {
    146             if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
    147                 string constant = make_constant_name(atom->name);
    148                 fprintf(out, " %s,\n", constant.c_str());
    149                 break;
    150             }
    151         }
    152     }
    153     fprintf(out, "};\n");
    154     fprintf(out, "\n");
    155 
    156     fprintf(out, "static std::map<int, int> getAtomUidField() {\n");
    157     fprintf(out, "  std::map<int, int> uidField;\n");
    158     for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
    159          atom != atoms.decls.end(); atom++) {
    160         if (atom->uidField == 0) {
    161             continue;
    162         }
    163         fprintf(out,
    164                 "\n    // Adding uid field for atom "
    165                 "(%d)%s\n",
    166                 atom->code, atom->name.c_str());
    167         fprintf(out, "    uidField[static_cast<int>(%s)] = %d;\n",
    168                 make_constant_name(atom->name).c_str(), atom->uidField);
    169     }
    170 
    171     fprintf(out, "    return uidField;\n");
    172     fprintf(out, "};\n");
    173 
    174     fprintf(out,
    175             "const std::map<int, int> AtomsInfo::kAtomsWithUidField = "
    176             "getAtomUidField();\n");
    177 
    178     fprintf(out,
    179             "static std::map<int, StateAtomFieldOptions> "
    180             "getStateAtomFieldOptions() {\n");
    181     fprintf(out, "    std::map<int, StateAtomFieldOptions> options;\n");
    182     fprintf(out, "    StateAtomFieldOptions opt;\n");
    183     for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
    184          atom != atoms.decls.end(); atom++) {
    185         if (atom->primaryFields.size() == 0 && atom->exclusiveField == 0) {
    186             continue;
    187         }
    188         fprintf(out,
    189                 "\n    // Adding primary and exclusive fields for atom "
    190                 "(%d)%s\n",
    191                 atom->code, atom->name.c_str());
    192         fprintf(out, "    opt.primaryFields.clear();\n");
    193         for (const auto& field : atom->primaryFields) {
    194             fprintf(out, "    opt.primaryFields.push_back(%d);\n", field);
    195         }
    196 
    197         fprintf(out, "    opt.exclusiveField = %d;\n", atom->exclusiveField);
    198         fprintf(out, "    options[static_cast<int>(%s)] = opt;\n",
    199                 make_constant_name(atom->name).c_str());
    200     }
    201 
    202     fprintf(out, "    return options;\n");
    203     fprintf(out, "  }\n");
    204 
    205     fprintf(out,
    206             "const std::map<int, StateAtomFieldOptions> "
    207             "AtomsInfo::kStateAtomsFieldOptions = "
    208             "getStateAtomFieldOptions();\n");
    209 
    210 
    211     fprintf(out, "int64_t lastRetryTimestampNs = -1;\n");
    212     fprintf(out, "const int64_t kMinRetryIntervalNs = NS_PER_SEC * 60 * 20; // 20 minutes\n");
    213     fprintf(out, "static std::mutex mLogdRetryMutex;\n");
    214 
    215     // Print write methods
    216     fprintf(out, "\n");
    217     for (set<vector<java_type_t>>::const_iterator signature = atoms.signatures.begin();
    218         signature != atoms.signatures.end(); signature++) {
    219         int argIndex;
    220 
    221         fprintf(out, "int\n");
    222         fprintf(out, "try_stats_write(int32_t code");
    223         argIndex = 1;
    224         for (vector<java_type_t>::const_iterator arg = signature->begin();
    225             arg != signature->end(); arg++) {
    226             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
    227                 for (auto chainField : attributionDecl.fields) {
    228                     if (chainField.javaType == JAVA_TYPE_STRING) {
    229                             fprintf(out, ", const std::vector<%s>& %s",
    230                                  cpp_type_name(chainField.javaType),
    231                                  chainField.name.c_str());
    232                     } else {
    233                             fprintf(out, ", const %s* %s, size_t %s_length",
    234                                  cpp_type_name(chainField.javaType),
    235                                  chainField.name.c_str(), chainField.name.c_str());
    236                     }
    237                 }
    238             } else {
    239                 fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
    240             }
    241             argIndex++;
    242         }
    243         fprintf(out, ")\n");
    244 
    245         fprintf(out, "{\n");
    246         argIndex = 1;
    247         fprintf(out, "  if (kStatsdEnabled) {\n");
    248         fprintf(out, "    stats_event_list event(kStatsEventTag);\n");
    249         fprintf(out, "    event << android::elapsedRealtimeNano();\n\n");
    250         fprintf(out, "    event << code;\n\n");
    251         for (vector<java_type_t>::const_iterator arg = signature->begin();
    252             arg != signature->end(); arg++) {
    253             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
    254                 for (const auto &chainField : attributionDecl.fields) {
    255                     if (chainField.javaType == JAVA_TYPE_STRING) {
    256                         fprintf(out, "    if (%s_length != %s.size()) {\n",
    257                             attributionDecl.fields.front().name.c_str(), chainField.name.c_str());
    258                         fprintf(out, "        return -EINVAL;\n");
    259                         fprintf(out, "    }\n");
    260                     }
    261                 }
    262                 fprintf(out, "\n    event.begin();\n");
    263                 fprintf(out, "    for (size_t i = 0; i < %s_length; ++i) {\n",
    264                     attributionDecl.fields.front().name.c_str());
    265                 fprintf(out, "        event.begin();\n");
    266                 for (const auto &chainField : attributionDecl.fields) {
    267                     if (chainField.javaType == JAVA_TYPE_STRING) {
    268                         fprintf(out, "        if (%s[i] != NULL) {\n", chainField.name.c_str());
    269                         fprintf(out, "           event << %s[i];\n", chainField.name.c_str());
    270                         fprintf(out, "        } else {\n");
    271                         fprintf(out, "           event << \"\";\n");
    272                         fprintf(out, "        }\n");
    273                     } else {
    274                         fprintf(out, "        event << %s[i];\n", chainField.name.c_str());
    275                     }
    276                 }
    277                 fprintf(out, "        event.end();\n");
    278                 fprintf(out, "    }\n");
    279                 fprintf(out, "    event.end();\n\n");
    280             } else {
    281                 if (*arg == JAVA_TYPE_STRING) {
    282                     fprintf(out, "    if (arg%d == NULL) {\n", argIndex);
    283                     fprintf(out, "        arg%d = \"\";\n", argIndex);
    284                     fprintf(out, "    }\n");
    285                 }
    286                 fprintf(out, "    event << arg%d;\n", argIndex);
    287             }
    288             argIndex++;
    289         }
    290 
    291         fprintf(out, "    return event.write(LOG_ID_STATS);\n");
    292         fprintf(out, "  } else {\n");
    293         fprintf(out, "    return 1;\n");
    294         fprintf(out, "  }\n");
    295         fprintf(out, "}\n");
    296         fprintf(out, "\n");
    297     }
    298 
    299    for (set<vector<java_type_t>>::const_iterator signature = atoms.signatures.begin();
    300        signature != atoms.signatures.end(); signature++) {
    301        int argIndex;
    302 
    303        fprintf(out, "int \n");
    304        fprintf(out, "stats_write(int32_t code");
    305        argIndex = 1;
    306        for (vector<java_type_t>::const_iterator arg = signature->begin();
    307            arg != signature->end(); arg++) {
    308            if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
    309                for (auto chainField : attributionDecl.fields) {
    310                    if (chainField.javaType == JAVA_TYPE_STRING) {
    311                            fprintf(out, ", const std::vector<%s>& %s",
    312                                 cpp_type_name(chainField.javaType),
    313                                 chainField.name.c_str());
    314                    } else {
    315                            fprintf(out, ", const %s* %s, size_t %s_length",
    316                                 cpp_type_name(chainField.javaType),
    317                                 chainField.name.c_str(), chainField.name.c_str());
    318                    }
    319                }
    320            } else {
    321                fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
    322            }
    323            argIndex++;
    324        }
    325        fprintf(out, ")\n");
    326 
    327        fprintf(out, "{\n");
    328        fprintf(out, "  int ret = 0;\n");
    329 
    330        fprintf(out, "  for(int retry = 0; retry < 2; ++retry) {\n");
    331        fprintf(out, "      ret =  try_stats_write(code");
    332 
    333        argIndex = 1;
    334        for (vector<java_type_t>::const_iterator arg = signature->begin();
    335            arg != signature->end(); arg++) {
    336            if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
    337                for (auto chainField : attributionDecl.fields) {
    338                    if (chainField.javaType == JAVA_TYPE_STRING) {
    339                            fprintf(out, ", %s",
    340                                 chainField.name.c_str());
    341                    } else {
    342                            fprintf(out, ",  %s,  %s_length",
    343                                 chainField.name.c_str(), chainField.name.c_str());
    344                    }
    345                }
    346            } else {
    347                fprintf(out, ", arg%d", argIndex);
    348            }
    349            argIndex++;
    350        }
    351        fprintf(out, ");\n");
    352        fprintf(out, "      if (ret >= 0) { return retry; }\n");
    353 
    354 
    355        fprintf(out, "      {\n");
    356        fprintf(out, "          std::lock_guard<std::mutex> lock(mLogdRetryMutex);\n");
    357        fprintf(out, "          if ((android::elapsedRealtimeNano() - lastRetryTimestampNs) <= "
    358                                 "kMinRetryIntervalNs) break;\n");
    359        fprintf(out, "          lastRetryTimestampNs = android::elapsedRealtimeNano();\n");
    360        fprintf(out, "      }\n");
    361        fprintf(out, "      std::this_thread::sleep_for(std::chrono::milliseconds(10));\n");
    362        fprintf(out, "  }\n");
    363        fprintf(out, "  return ret;\n");
    364        fprintf(out, "}\n");
    365        fprintf(out, "\n");
    366    }
    367 
    368     for (set<vector<java_type_t>>::const_iterator signature = atoms.non_chained_signatures.begin();
    369         signature != atoms.non_chained_signatures.end(); signature++) {
    370         int argIndex;
    371 
    372         fprintf(out, "int\n");
    373         fprintf(out, "try_stats_write_non_chained(int32_t code");
    374         argIndex = 1;
    375         for (vector<java_type_t>::const_iterator arg = signature->begin();
    376             arg != signature->end(); arg++) {
    377             fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
    378             argIndex++;
    379         }
    380         fprintf(out, ")\n");
    381 
    382         fprintf(out, "{\n");
    383         argIndex = 1;
    384         fprintf(out, "  if (kStatsdEnabled) {\n");
    385         fprintf(out, "    stats_event_list event(kStatsEventTag);\n");
    386         fprintf(out, "    event << android::elapsedRealtimeNano();\n\n");
    387         fprintf(out, "    event << code;\n\n");
    388         for (vector<java_type_t>::const_iterator arg = signature->begin();
    389             arg != signature->end(); arg++) {
    390             if (argIndex == 1) {
    391                 fprintf(out, "    event.begin();\n\n");
    392                 fprintf(out, "    event.begin();\n");
    393             }
    394             if (*arg == JAVA_TYPE_STRING) {
    395                 fprintf(out, "    if (arg%d == NULL) {\n", argIndex);
    396                 fprintf(out, "        arg%d = \"\";\n", argIndex);
    397                 fprintf(out, "    }\n");
    398             }
    399             fprintf(out, "    event << arg%d;\n", argIndex);
    400             if (argIndex == 2) {
    401                 fprintf(out, "    event.end();\n\n");
    402                 fprintf(out, "    event.end();\n\n");
    403             }
    404             argIndex++;
    405         }
    406 
    407         fprintf(out, "    return event.write(LOG_ID_STATS);\n");
    408         fprintf(out, "  } else {\n");
    409         fprintf(out, "    return 1;\n");
    410         fprintf(out, "  }\n");
    411         fprintf(out, "}\n");
    412         fprintf(out, "\n");
    413     }
    414 
    415    for (set<vector<java_type_t>>::const_iterator signature = atoms.non_chained_signatures.begin();
    416        signature != atoms.non_chained_signatures.end(); signature++) {
    417        int argIndex;
    418 
    419        fprintf(out, "int\n");
    420        fprintf(out, "stats_write_non_chained(int32_t code");
    421        argIndex = 1;
    422        for (vector<java_type_t>::const_iterator arg = signature->begin();
    423            arg != signature->end(); arg++) {
    424            fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
    425            argIndex++;
    426        }
    427        fprintf(out, ")\n");
    428 
    429        fprintf(out, "{\n");
    430 
    431        fprintf(out, "  int ret = 0;\n");
    432        fprintf(out, "  for(int retry = 0; retry < 2; ++retry) {\n");
    433        fprintf(out, "      ret =  try_stats_write_non_chained(code");
    434 
    435        argIndex = 1;
    436        for (vector<java_type_t>::const_iterator arg = signature->begin();
    437            arg != signature->end(); arg++) {
    438            fprintf(out, ", arg%d",   argIndex);
    439            argIndex++;
    440        }
    441        fprintf(out, ");\n");
    442        fprintf(out, "      if (ret >= 0) { return retry; }\n");
    443 
    444        fprintf(out, "      {\n");
    445        fprintf(out, "          std::lock_guard<std::mutex> lock(mLogdRetryMutex);\n");
    446        fprintf(out, "          if ((android::elapsedRealtimeNano() - lastRetryTimestampNs) <= "
    447                                 "kMinRetryIntervalNs) break;\n");
    448        fprintf(out, "          lastRetryTimestampNs = android::elapsedRealtimeNano();\n");
    449        fprintf(out, "      }\n");
    450 
    451        fprintf(out, "      std::this_thread::sleep_for(std::chrono::milliseconds(10));\n");
    452        fprintf(out, "  }\n");
    453        fprintf(out, "  return ret;\n");
    454        fprintf(out, "}\n");
    455 
    456        fprintf(out, "\n");
    457    }
    458 
    459 
    460     // Print footer
    461     fprintf(out, "\n");
    462     fprintf(out, "} // namespace util\n");
    463     fprintf(out, "} // namespace android\n");
    464 
    465     return 0;
    466 }
    467 
    468 void build_non_chained_decl_map(const Atoms& atoms,
    469                                 std::map<int, set<AtomDecl>::const_iterator>* decl_map){
    470     for (set<AtomDecl>::const_iterator atom = atoms.non_chained_decls.begin();
    471         atom != atoms.non_chained_decls.end(); atom++) {
    472         decl_map->insert(std::make_pair(atom->code, atom));
    473     }
    474 }
    475 
    476 static void write_cpp_usage(
    477     FILE* out, const string& method_name, const string& atom_code_name,
    478     const AtomDecl& atom, const AtomDecl &attributionDecl) {
    479     fprintf(out, "     * Usage: %s(StatsLog.%s", method_name.c_str(), atom_code_name.c_str());
    480     for (vector<AtomField>::const_iterator field = atom.fields.begin();
    481             field != atom.fields.end(); field++) {
    482         if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
    483             for (auto chainField : attributionDecl.fields) {
    484                 if (chainField.javaType == JAVA_TYPE_STRING) {
    485                     fprintf(out, ", const std::vector<%s>& %s",
    486                          cpp_type_name(chainField.javaType),
    487                          chainField.name.c_str());
    488                 } else {
    489                     fprintf(out, ", const %s* %s, size_t %s_length",
    490                          cpp_type_name(chainField.javaType),
    491                          chainField.name.c_str(), chainField.name.c_str());
    492                 }
    493             }
    494         } else {
    495             fprintf(out, ", %s %s", cpp_type_name(field->javaType), field->name.c_str());
    496         }
    497     }
    498     fprintf(out, ");\n");
    499 }
    500 
    501 static void write_cpp_method_header(
    502     FILE* out, const string& method_name, const set<vector<java_type_t>>& signatures,
    503     const AtomDecl &attributionDecl) {
    504     for (set<vector<java_type_t>>::const_iterator signature = signatures.begin();
    505             signature != signatures.end(); signature++) {
    506         fprintf(out, "int %s(int32_t code ", method_name.c_str());
    507         int argIndex = 1;
    508         for (vector<java_type_t>::const_iterator arg = signature->begin();
    509             arg != signature->end(); arg++) {
    510             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
    511                 for (auto chainField : attributionDecl.fields) {
    512                     if (chainField.javaType == JAVA_TYPE_STRING) {
    513                         fprintf(out, ", const std::vector<%s>& %s",
    514                             cpp_type_name(chainField.javaType), chainField.name.c_str());
    515                     } else {
    516                         fprintf(out, ", const %s* %s, size_t %s_length",
    517                             cpp_type_name(chainField.javaType),
    518                             chainField.name.c_str(), chainField.name.c_str());
    519                     }
    520                 }
    521             } else {
    522                 fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
    523             }
    524             argIndex++;
    525         }
    526         fprintf(out, ");\n");
    527 
    528     }
    529 }
    530 
    531 static int
    532 write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl)
    533 {
    534     // Print prelude
    535     fprintf(out, "// This file is autogenerated\n");
    536     fprintf(out, "\n");
    537     fprintf(out, "#pragma once\n");
    538     fprintf(out, "\n");
    539     fprintf(out, "#include <stdint.h>\n");
    540     fprintf(out, "#include <vector>\n");
    541     fprintf(out, "#include <map>\n");
    542     fprintf(out, "#include <set>\n");
    543     fprintf(out, "\n");
    544 
    545     fprintf(out, "namespace android {\n");
    546     fprintf(out, "namespace util {\n");
    547     fprintf(out, "\n");
    548     fprintf(out, "/*\n");
    549     fprintf(out, " * API For logging statistics events.\n");
    550     fprintf(out, " */\n");
    551     fprintf(out, "\n");
    552     fprintf(out, "/**\n");
    553     fprintf(out, " * Constants for atom codes.\n");
    554     fprintf(out, " */\n");
    555     fprintf(out, "enum {\n");
    556 
    557     std::map<int, set<AtomDecl>::const_iterator> atom_code_to_non_chained_decl_map;
    558     build_non_chained_decl_map(atoms, &atom_code_to_non_chained_decl_map);
    559 
    560     size_t i = 0;
    561     // Print constants
    562     for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
    563         atom != atoms.decls.end(); atom++) {
    564         string constant = make_constant_name(atom->name);
    565         fprintf(out, "\n");
    566         fprintf(out, "    /**\n");
    567         fprintf(out, "     * %s %s\n", atom->message.c_str(), atom->name.c_str());
    568         write_cpp_usage(out, "stats_write", constant, *atom, attributionDecl);
    569 
    570         auto non_chained_decl = atom_code_to_non_chained_decl_map.find(atom->code);
    571         if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) {
    572             write_cpp_usage(out, "stats_write_non_chained", constant, *non_chained_decl->second,
    573                 attributionDecl);
    574         }
    575         fprintf(out, "     */\n");
    576         char const* const comma = (i == atoms.decls.size() - 1) ? "" : ",";
    577         fprintf(out, "    %s = %d%s\n", constant.c_str(), atom->code, comma);
    578         if (atom->code < PULL_ATOM_START_ID && atom->code > maxPushedAtomId) {
    579             maxPushedAtomId = atom->code;
    580         }
    581         i++;
    582     }
    583     fprintf(out, "\n");
    584     fprintf(out, "};\n");
    585     fprintf(out, "\n");
    586 
    587     fprintf(out, "struct StateAtomFieldOptions {\n");
    588     fprintf(out, "  std::vector<int> primaryFields;\n");
    589     fprintf(out, "  int exclusiveField;\n");
    590     fprintf(out, "};\n");
    591     fprintf(out, "\n");
    592 
    593     fprintf(out, "struct AtomsInfo {\n");
    594     fprintf(out,
    595             "  const static std::set<int> "
    596             "kNotTruncatingTimestampAtomWhiteList;\n");
    597     fprintf(out, "  const static std::map<int, int> kAtomsWithUidField;\n");
    598     fprintf(out,
    599             "  const static std::set<int> kAtomsWithAttributionChain;\n");
    600     fprintf(out,
    601             "  const static std::map<int, StateAtomFieldOptions> "
    602             "kStateAtomsFieldOptions;\n");
    603     fprintf(out, "};\n");
    604 
    605     fprintf(out, "const static int kMaxPushedAtomId = %d;\n\n",
    606             maxPushedAtomId);
    607 
    608     // Print write methods
    609     fprintf(out, "//\n");
    610     fprintf(out, "// Write methods\n");
    611     fprintf(out, "//\n");
    612     write_cpp_method_header(out, "stats_write", atoms.signatures, attributionDecl);
    613 
    614     fprintf(out, "//\n");
    615     fprintf(out, "// Write flattened methods\n");
    616     fprintf(out, "//\n");
    617     write_cpp_method_header(out, "stats_write_non_chained", atoms.non_chained_signatures,
    618         attributionDecl);
    619 
    620     fprintf(out, "\n");
    621     fprintf(out, "} // namespace util\n");
    622     fprintf(out, "} // namespace android\n");
    623 
    624     return 0;
    625 }
    626 
    627 static void write_java_usage(
    628     FILE* out, const string& method_name, const string& atom_code_name,
    629     const AtomDecl& atom, const AtomDecl &attributionDecl) {
    630     fprintf(out, "     * Usage: StatsLog.%s(StatsLog.%s",
    631         method_name.c_str(), atom_code_name.c_str());
    632     for (vector<AtomField>::const_iterator field = atom.fields.begin();
    633         field != atom.fields.end(); field++) {
    634         if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
    635             for (auto chainField : attributionDecl.fields) {
    636                 fprintf(out, ", %s[] %s",
    637                     java_type_name(chainField.javaType), chainField.name.c_str());
    638             }
    639         } else {
    640             fprintf(out, ", %s %s", java_type_name(field->javaType), field->name.c_str());
    641         }
    642     }
    643     fprintf(out, ");\n");
    644 }
    645 
    646 static void write_java_method(
    647     FILE* out, const string& method_name, const set<vector<java_type_t>>& signatures,
    648     const AtomDecl &attributionDecl) {
    649     for (set<vector<java_type_t>>::const_iterator signature = signatures.begin();
    650         signature != signatures.end(); signature++) {
    651         fprintf(out, "    public static native int %s(int code", method_name.c_str());
    652         int argIndex = 1;
    653         for (vector<java_type_t>::const_iterator arg = signature->begin();
    654             arg != signature->end(); arg++) {
    655             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
    656                 for (auto chainField : attributionDecl.fields) {
    657                     fprintf(out, ", %s[] %s",
    658                         java_type_name(chainField.javaType), chainField.name.c_str());
    659                 }
    660             } else {
    661                 fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
    662             }
    663             argIndex++;
    664         }
    665         fprintf(out, ");\n");
    666     }
    667 }
    668 
    669 
    670 static int
    671 write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl)
    672 {
    673     // Print prelude
    674     fprintf(out, "// This file is autogenerated\n");
    675     fprintf(out, "\n");
    676     fprintf(out, "package android.util;\n");
    677     fprintf(out, "\n");
    678     fprintf(out, "\n");
    679     fprintf(out, "/**\n");
    680     fprintf(out, " * API For logging statistics events.\n");
    681     fprintf(out, " * @hide\n");
    682     fprintf(out, " */\n");
    683     fprintf(out, "public class StatsLogInternal {\n");
    684     fprintf(out, "    // Constants for atom codes.\n");
    685 
    686     std::map<int, set<AtomDecl>::const_iterator> atom_code_to_non_chained_decl_map;
    687     build_non_chained_decl_map(atoms, &atom_code_to_non_chained_decl_map);
    688 
    689     // Print constants for the atom codes.
    690     for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
    691             atom != atoms.decls.end(); atom++) {
    692         string constant = make_constant_name(atom->name);
    693         fprintf(out, "\n");
    694         fprintf(out, "    /**\n");
    695         fprintf(out, "     * %s %s\n", atom->message.c_str(), atom->name.c_str());
    696         write_java_usage(out, "write", constant, *atom, attributionDecl);
    697         auto non_chained_decl = atom_code_to_non_chained_decl_map.find(atom->code);
    698         if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) {
    699             write_java_usage(out, "write_non_chained", constant, *non_chained_decl->second,
    700              attributionDecl);
    701         }
    702         fprintf(out, "     */\n");
    703         fprintf(out, "    public static final int %s = %d;\n", constant.c_str(), atom->code);
    704     }
    705     fprintf(out, "\n");
    706 
    707     // Print constants for the enum values.
    708     fprintf(out, "    // Constants for enum values.\n\n");
    709     for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
    710         atom != atoms.decls.end(); atom++) {
    711         for (vector<AtomField>::const_iterator field = atom->fields.begin();
    712             field != atom->fields.end(); field++) {
    713             if (field->javaType == JAVA_TYPE_ENUM) {
    714                 fprintf(out, "    // Values for %s.%s\n", atom->message.c_str(),
    715                     field->name.c_str());
    716                 for (map<int, string>::const_iterator value = field->enumValues.begin();
    717                     value != field->enumValues.end(); value++) {
    718                     fprintf(out, "    public static final int %s__%s__%s = %d;\n",
    719                         make_constant_name(atom->message).c_str(),
    720                         make_constant_name(field->name).c_str(),
    721                         make_constant_name(value->second).c_str(),
    722                         value->first);
    723                 }
    724                 fprintf(out, "\n");
    725             }
    726         }
    727     }
    728 
    729     // Print write methods
    730     fprintf(out, "    // Write methods\n");
    731     write_java_method(out, "write", atoms.signatures, attributionDecl);
    732     write_java_method(out, "write_non_chained", atoms.non_chained_signatures, attributionDecl);
    733 
    734     fprintf(out, "}\n");
    735 
    736     return 0;
    737 }
    738 
    739 static const char*
    740 jni_type_name(java_type_t type)
    741 {
    742     switch (type) {
    743         case JAVA_TYPE_BOOLEAN:
    744             return "jboolean";
    745         case JAVA_TYPE_INT:
    746         case JAVA_TYPE_ENUM:
    747             return "jint";
    748         case JAVA_TYPE_LONG:
    749             return "jlong";
    750         case JAVA_TYPE_FLOAT:
    751             return "jfloat";
    752         case JAVA_TYPE_DOUBLE:
    753             return "jdouble";
    754         case JAVA_TYPE_STRING:
    755             return "jstring";
    756         default:
    757             return "UNKNOWN";
    758     }
    759 }
    760 
    761 static const char*
    762 jni_array_type_name(java_type_t type)
    763 {
    764     switch (type) {
    765         case JAVA_TYPE_INT:
    766             return "jintArray";
    767         case JAVA_TYPE_STRING:
    768             return "jobjectArray";
    769         default:
    770             return "UNKNOWN";
    771     }
    772 }
    773 
    774 static string
    775 jni_function_name(const string& method_name, const vector<java_type_t>& signature)
    776 {
    777     string result("StatsLog_" + method_name);
    778     for (vector<java_type_t>::const_iterator arg = signature.begin();
    779         arg != signature.end(); arg++) {
    780         switch (*arg) {
    781             case JAVA_TYPE_BOOLEAN:
    782                 result += "_boolean";
    783                 break;
    784             case JAVA_TYPE_INT:
    785             case JAVA_TYPE_ENUM:
    786                 result += "_int";
    787                 break;
    788             case JAVA_TYPE_LONG:
    789                 result += "_long";
    790                 break;
    791             case JAVA_TYPE_FLOAT:
    792                 result += "_float";
    793                 break;
    794             case JAVA_TYPE_DOUBLE:
    795                 result += "_double";
    796                 break;
    797             case JAVA_TYPE_STRING:
    798                 result += "_String";
    799                 break;
    800             case JAVA_TYPE_ATTRIBUTION_CHAIN:
    801               result += "_AttributionChain";
    802               break;
    803             default:
    804                 result += "_UNKNOWN";
    805                 break;
    806         }
    807     }
    808     return result;
    809 }
    810 
    811 static const char*
    812 java_type_signature(java_type_t type)
    813 {
    814     switch (type) {
    815         case JAVA_TYPE_BOOLEAN:
    816             return "Z";
    817         case JAVA_TYPE_INT:
    818         case JAVA_TYPE_ENUM:
    819             return "I";
    820         case JAVA_TYPE_LONG:
    821             return "J";
    822         case JAVA_TYPE_FLOAT:
    823             return "F";
    824         case JAVA_TYPE_DOUBLE:
    825             return "D";
    826         case JAVA_TYPE_STRING:
    827             return "Ljava/lang/String;";
    828         default:
    829             return "UNKNOWN";
    830     }
    831 }
    832 
    833 static string
    834 jni_function_signature(const vector<java_type_t>& signature, const AtomDecl &attributionDecl)
    835 {
    836     string result("(I");
    837     for (vector<java_type_t>::const_iterator arg = signature.begin();
    838         arg != signature.end(); arg++) {
    839         if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
    840             for (auto chainField : attributionDecl.fields) {
    841                 result += "[";
    842                 result += java_type_signature(chainField.javaType);
    843             }
    844         } else {
    845             result += java_type_signature(*arg);
    846         }
    847     }
    848     result += ")I";
    849     return result;
    850 }
    851 
    852 static int
    853 write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp_method_name,
    854     const set<vector<java_type_t>>& signatures, const AtomDecl &attributionDecl)
    855 {
    856     // Print write methods
    857     for (set<vector<java_type_t>>::const_iterator signature = signatures.begin();
    858         signature != signatures.end(); signature++) {
    859         int argIndex;
    860 
    861         fprintf(out, "static int\n");
    862         fprintf(out, "%s(JNIEnv* env, jobject clazz UNUSED, jint code",
    863                 jni_function_name(java_method_name, *signature).c_str());
    864         argIndex = 1;
    865         for (vector<java_type_t>::const_iterator arg = signature->begin();
    866                 arg != signature->end(); arg++) {
    867             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
    868                 for (auto chainField : attributionDecl.fields) {
    869                     fprintf(out, ", %s %s", jni_array_type_name(chainField.javaType),
    870                         chainField.name.c_str());
    871                 }
    872             } else {
    873                 fprintf(out, ", %s arg%d", jni_type_name(*arg), argIndex);
    874             }
    875             argIndex++;
    876         }
    877         fprintf(out, ")\n");
    878 
    879         fprintf(out, "{\n");
    880 
    881         // Prepare strings
    882         argIndex = 1;
    883         bool hadStringOrChain = false;
    884         for (vector<java_type_t>::const_iterator arg = signature->begin();
    885                 arg != signature->end(); arg++) {
    886             if (*arg == JAVA_TYPE_STRING) {
    887                 hadStringOrChain = true;
    888                 fprintf(out, "    const char* str%d;\n", argIndex);
    889                 fprintf(out, "    if (arg%d != NULL) {\n", argIndex);
    890                 fprintf(out, "        str%d = env->GetStringUTFChars(arg%d, NULL);\n",
    891                         argIndex, argIndex);
    892                 fprintf(out, "    } else {\n");
    893                 fprintf(out, "        str%d = NULL;\n", argIndex);
    894                 fprintf(out, "    }\n");
    895             } else if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
    896                 hadStringOrChain = true;
    897                 for (auto chainField : attributionDecl.fields) {
    898                     fprintf(out, "    size_t %s_length = env->GetArrayLength(%s);\n",
    899                         chainField.name.c_str(), chainField.name.c_str());
    900                     if (chainField.name != attributionDecl.fields.front().name) {
    901                         fprintf(out, "    if (%s_length != %s_length) {\n",
    902                             chainField.name.c_str(),
    903                             attributionDecl.fields.front().name.c_str());
    904                         fprintf(out, "        return -EINVAL;\n");
    905                         fprintf(out, "    }\n");
    906                     }
    907                     if (chainField.javaType == JAVA_TYPE_INT) {
    908                         fprintf(out, "    jint* %s_array = env->GetIntArrayElements(%s, NULL);\n",
    909                             chainField.name.c_str(), chainField.name.c_str());
    910                     } else if (chainField.javaType == JAVA_TYPE_STRING) {
    911                         fprintf(out, "    std::vector<%s> %s_vec;\n",
    912                             cpp_type_name(chainField.javaType), chainField.name.c_str());
    913                         fprintf(out, "    std::vector<ScopedUtfChars*> scoped_%s_vec;\n",
    914                             chainField.name.c_str());
    915                         fprintf(out, "    for (size_t i = 0; i < %s_length; ++i) {\n",
    916                             chainField.name.c_str());
    917                         fprintf(out, "        jstring jstr = "
    918                             "(jstring)env->GetObjectArrayElement(%s, i);\n",
    919                              chainField.name.c_str());
    920                         fprintf(out, "        if (jstr == NULL) {\n");
    921                         fprintf(out, "            %s_vec.push_back(NULL);\n",
    922                             chainField.name.c_str());
    923                         fprintf(out, "        } else {\n");
    924                         fprintf(out, "            ScopedUtfChars* scoped_%s = "
    925                             "new ScopedUtfChars(env, jstr);\n",
    926                              chainField.name.c_str());
    927                         fprintf(out, "            %s_vec.push_back(scoped_%s->c_str());\n",
    928                                 chainField.name.c_str(), chainField.name.c_str());
    929                         fprintf(out, "            scoped_%s_vec.push_back(scoped_%s);\n",
    930                                 chainField.name.c_str(), chainField.name.c_str());
    931                         fprintf(out, "        }\n");
    932                         fprintf(out, "    }\n");
    933                     }
    934                     fprintf(out, "\n");
    935                 }
    936             }
    937             argIndex++;
    938         }
    939         // Emit this to quiet the unused parameter warning if there were no strings or attribution
    940         // chains.
    941         if (!hadStringOrChain) {
    942             fprintf(out, "    (void)env;\n");
    943         }
    944 
    945         // stats_write call
    946         argIndex = 1;
    947         fprintf(out, "   int ret =  android::util::%s(code", cpp_method_name.c_str());
    948         for (vector<java_type_t>::const_iterator arg = signature->begin();
    949                 arg != signature->end(); arg++) {
    950             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
    951                 for (auto chainField : attributionDecl.fields) {
    952                     if (chainField.javaType == JAVA_TYPE_INT) {
    953                         fprintf(out, ", (const %s*)%s_array, %s_length",
    954                             cpp_type_name(chainField.javaType),
    955                             chainField.name.c_str(), chainField.name.c_str());
    956                     } else if (chainField.javaType == JAVA_TYPE_STRING) {
    957                         fprintf(out, ", %s_vec", chainField.name.c_str());
    958                     }
    959                 }
    960             } else {
    961                 const char *argName = (*arg == JAVA_TYPE_STRING) ? "str" : "arg";
    962                 fprintf(out, ", (%s)%s%d", cpp_type_name(*arg), argName, argIndex);
    963             }
    964             argIndex++;
    965         }
    966         fprintf(out, ");\n");
    967         fprintf(out, "\n");
    968 
    969         // Clean up strings
    970         argIndex = 1;
    971         for (vector<java_type_t>::const_iterator arg = signature->begin();
    972                 arg != signature->end(); arg++) {
    973             if (*arg == JAVA_TYPE_STRING) {
    974                 fprintf(out, "    if (str%d != NULL) {\n", argIndex);
    975                 fprintf(out, "        env->ReleaseStringUTFChars(arg%d, str%d);\n",
    976                         argIndex, argIndex);
    977                 fprintf(out, "    }\n");
    978             } else if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
    979                 for (auto chainField : attributionDecl.fields) {
    980                     if (chainField.javaType == JAVA_TYPE_INT) {
    981                         fprintf(out, "    env->ReleaseIntArrayElements(%s, %s_array, 0);\n",
    982                             chainField.name.c_str(), chainField.name.c_str());
    983                     } else if (chainField.javaType == JAVA_TYPE_STRING) {
    984                         fprintf(out, "    for (size_t i = 0; i < scoped_%s_vec.size(); ++i) {\n",
    985                             chainField.name.c_str());
    986                         fprintf(out, "        delete scoped_%s_vec[i];\n", chainField.name.c_str());
    987                         fprintf(out, "    }\n");
    988                     }
    989                 }
    990             }
    991             argIndex++;
    992         }
    993         fprintf(out, "    return ret;\n");
    994 
    995         fprintf(out, "}\n");
    996         fprintf(out, "\n");
    997     }
    998 
    999 
   1000     return 0;
   1001 }
   1002 
   1003 void write_jni_registration(FILE* out, const string& java_method_name,
   1004     const set<vector<java_type_t>>& signatures, const AtomDecl &attributionDecl) {
   1005     for (set<vector<java_type_t>>::const_iterator signature = signatures.begin();
   1006             signature != signatures.end(); signature++) {
   1007         fprintf(out, "    { \"%s\", \"%s\", (void*)%s },\n",
   1008             java_method_name.c_str(),
   1009             jni_function_signature(*signature, attributionDecl).c_str(),
   1010             jni_function_name(java_method_name, *signature).c_str());
   1011     }
   1012 }
   1013 
   1014 static int
   1015 write_stats_log_jni(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl)
   1016 {
   1017     // Print prelude
   1018     fprintf(out, "// This file is autogenerated\n");
   1019     fprintf(out, "\n");
   1020 
   1021     fprintf(out, "#include <statslog.h>\n");
   1022     fprintf(out, "\n");
   1023     fprintf(out, "#include <nativehelper/JNIHelp.h>\n");
   1024     fprintf(out, "#include <nativehelper/ScopedUtfChars.h>\n");
   1025     fprintf(out, "#include <utils/Vector.h>\n");
   1026     fprintf(out, "#include \"core_jni_helpers.h\"\n");
   1027     fprintf(out, "#include \"jni.h\"\n");
   1028     fprintf(out, "\n");
   1029     fprintf(out, "#define UNUSED  __attribute__((__unused__))\n");
   1030     fprintf(out, "\n");
   1031 
   1032     fprintf(out, "namespace android {\n");
   1033     fprintf(out, "\n");
   1034 
   1035     write_stats_log_jni(out, "write", "stats_write", atoms.signatures, attributionDecl);
   1036     write_stats_log_jni(out, "write_non_chained", "stats_write_non_chained",
   1037         atoms.non_chained_signatures, attributionDecl);
   1038 
   1039     // Print registration function table
   1040     fprintf(out, "/*\n");
   1041     fprintf(out, " * JNI registration.\n");
   1042     fprintf(out, " */\n");
   1043     fprintf(out, "static const JNINativeMethod gRegisterMethods[] = {\n");
   1044     write_jni_registration(out, "write", atoms.signatures, attributionDecl);
   1045     write_jni_registration(out, "write_non_chained", atoms.non_chained_signatures, attributionDecl);
   1046     fprintf(out, "};\n");
   1047     fprintf(out, "\n");
   1048 
   1049     // Print registration function
   1050     fprintf(out, "int register_android_util_StatsLog(JNIEnv* env) {\n");
   1051     fprintf(out, "    return RegisterMethodsOrDie(\n");
   1052     fprintf(out, "            env,\n");
   1053     fprintf(out, "            \"android/util/StatsLog\",\n");
   1054     fprintf(out, "            gRegisterMethods, NELEM(gRegisterMethods));\n");
   1055     fprintf(out, "}\n");
   1056 
   1057     fprintf(out, "\n");
   1058     fprintf(out, "} // namespace android\n");
   1059     return 0;
   1060 }
   1061 
   1062 static void
   1063 print_usage()
   1064 {
   1065     fprintf(stderr, "usage: stats-log-api-gen OPTIONS\n");
   1066     fprintf(stderr, "\n");
   1067     fprintf(stderr, "OPTIONS\n");
   1068     fprintf(stderr, "  --cpp FILENAME       the header file to output\n");
   1069     fprintf(stderr, "  --header FILENAME    the cpp file to output\n");
   1070     fprintf(stderr, "  --help               this message\n");
   1071     fprintf(stderr, "  --java FILENAME      the java file to output\n");
   1072     fprintf(stderr, "  --jni FILENAME       the jni file to output\n");
   1073 }
   1074 
   1075 /**
   1076  * Do the argument parsing and execute the tasks.
   1077  */
   1078 static int
   1079 run(int argc, char const*const* argv)
   1080 {
   1081     string cppFilename;
   1082     string headerFilename;
   1083     string javaFilename;
   1084     string jniFilename;
   1085 
   1086     int index = 1;
   1087     while (index < argc) {
   1088         if (0 == strcmp("--help", argv[index])) {
   1089             print_usage();
   1090             return 0;
   1091         } else if (0 == strcmp("--cpp", argv[index])) {
   1092             index++;
   1093             if (index >= argc) {
   1094                 print_usage();
   1095                 return 1;
   1096             }
   1097             cppFilename = argv[index];
   1098         } else if (0 == strcmp("--header", argv[index])) {
   1099             index++;
   1100             if (index >= argc) {
   1101                 print_usage();
   1102                 return 1;
   1103             }
   1104             headerFilename = argv[index];
   1105         } else if (0 == strcmp("--java", argv[index])) {
   1106             index++;
   1107             if (index >= argc) {
   1108                 print_usage();
   1109                 return 1;
   1110             }
   1111             javaFilename = argv[index];
   1112         } else if (0 == strcmp("--jni", argv[index])) {
   1113             index++;
   1114             if (index >= argc) {
   1115                 print_usage();
   1116                 return 1;
   1117             }
   1118             jniFilename = argv[index];
   1119         }
   1120         index++;
   1121     }
   1122 
   1123     if (cppFilename.size() == 0
   1124             && headerFilename.size() == 0
   1125             && javaFilename.size() == 0
   1126             && jniFilename.size() == 0) {
   1127         print_usage();
   1128         return 1;
   1129     }
   1130 
   1131     // Collate the parameters
   1132     Atoms atoms;
   1133     int errorCount = collate_atoms(Atom::descriptor(), &atoms);
   1134     if (errorCount != 0) {
   1135         return 1;
   1136     }
   1137 
   1138     AtomDecl attributionDecl;
   1139     vector<java_type_t> attributionSignature;
   1140     collate_atom(android::os::statsd::AttributionNode::descriptor(),
   1141                  &attributionDecl, &attributionSignature);
   1142 
   1143     // Write the .cpp file
   1144     if (cppFilename.size() != 0) {
   1145         FILE* out = fopen(cppFilename.c_str(), "w");
   1146         if (out == NULL) {
   1147             fprintf(stderr, "Unable to open file for write: %s\n", cppFilename.c_str());
   1148             return 1;
   1149         }
   1150         errorCount = android::stats_log_api_gen::write_stats_log_cpp(
   1151             out, atoms, attributionDecl);
   1152         fclose(out);
   1153     }
   1154 
   1155     // Write the .h file
   1156     if (headerFilename.size() != 0) {
   1157         FILE* out = fopen(headerFilename.c_str(), "w");
   1158         if (out == NULL) {
   1159             fprintf(stderr, "Unable to open file for write: %s\n", headerFilename.c_str());
   1160             return 1;
   1161         }
   1162         errorCount = android::stats_log_api_gen::write_stats_log_header(
   1163             out, atoms, attributionDecl);
   1164         fclose(out);
   1165     }
   1166 
   1167     // Write the .java file
   1168     if (javaFilename.size() != 0) {
   1169         FILE* out = fopen(javaFilename.c_str(), "w");
   1170         if (out == NULL) {
   1171             fprintf(stderr, "Unable to open file for write: %s\n", javaFilename.c_str());
   1172             return 1;
   1173         }
   1174         errorCount = android::stats_log_api_gen::write_stats_log_java(
   1175             out, atoms, attributionDecl);
   1176         fclose(out);
   1177     }
   1178 
   1179     // Write the jni file
   1180     if (jniFilename.size() != 0) {
   1181         FILE* out = fopen(jniFilename.c_str(), "w");
   1182         if (out == NULL) {
   1183             fprintf(stderr, "Unable to open file for write: %s\n", jniFilename.c_str());
   1184             return 1;
   1185         }
   1186         errorCount = android::stats_log_api_gen::write_stats_log_jni(
   1187             out, atoms, attributionDecl);
   1188         fclose(out);
   1189     }
   1190 
   1191     return 0;
   1192 }
   1193 
   1194 }
   1195 }
   1196 
   1197 /**
   1198  * Main.
   1199  */
   1200 int
   1201 main(int argc, char const*const* argv)
   1202 {
   1203     GOOGLE_PROTOBUF_VERIFY_VERSION;
   1204 
   1205     return android::stats_log_api_gen::run(argc, argv);
   1206 }
   1207