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 #include "android-base/strings.h"
     16 
     17 using namespace google::protobuf;
     18 using namespace std;
     19 
     20 namespace android {
     21 namespace stats_log_api_gen {
     22 
     23 int maxPushedAtomId = 2;
     24 
     25 const string DEFAULT_MODULE_NAME = "DEFAULT";
     26 const string DEFAULT_CPP_NAMESPACE = "android,util";
     27 const string DEFAULT_CPP_HEADER_IMPORT = "statslog.h";
     28 const string DEFAULT_JAVA_PACKAGE = "android.util";
     29 const string DEFAULT_JAVA_CLASS = "StatsLogInternal";
     30 
     31 const int JAVA_MODULE_REQUIRES_FLOAT = 0x01;
     32 const int JAVA_MODULE_REQUIRES_ATTRIBUTION = 0x02;
     33 
     34 using android::os::statsd::Atom;
     35 
     36 /**
     37  * Turn lower and camel case into upper case with underscores.
     38  */
     39 static string
     40 make_constant_name(const string& str)
     41 {
     42     string result;
     43     const int N = str.size();
     44     bool underscore_next = false;
     45     for (int i=0; i<N; i++) {
     46         char c = str[i];
     47         if (c >= 'A' && c <= 'Z') {
     48             if (underscore_next) {
     49                 result += '_';
     50                 underscore_next = false;
     51             }
     52         } else if (c >= 'a' && c <= 'z') {
     53             c = 'A' + c - 'a';
     54             underscore_next = true;
     55         } else if (c == '_') {
     56             underscore_next = false;
     57         }
     58         result += c;
     59     }
     60     return result;
     61 }
     62 
     63 static const char*
     64 cpp_type_name(java_type_t type)
     65 {
     66     switch (type) {
     67         case JAVA_TYPE_BOOLEAN:
     68             return "bool";
     69         case JAVA_TYPE_INT:
     70         case JAVA_TYPE_ENUM:
     71             return "int32_t";
     72         case JAVA_TYPE_LONG:
     73             return "int64_t";
     74         case JAVA_TYPE_FLOAT:
     75             return "float";
     76         case JAVA_TYPE_DOUBLE:
     77             return "double";
     78         case JAVA_TYPE_STRING:
     79             return "char const*";
     80         case JAVA_TYPE_BYTE_ARRAY:
     81             return "const BytesField&";
     82         default:
     83             return "UNKNOWN";
     84     }
     85 }
     86 
     87 static const char*
     88 java_type_name(java_type_t type)
     89 {
     90     switch (type) {
     91         case JAVA_TYPE_BOOLEAN:
     92             return "boolean";
     93         case JAVA_TYPE_INT:
     94         case JAVA_TYPE_ENUM:
     95             return "int";
     96         case JAVA_TYPE_LONG:
     97             return "long";
     98         case JAVA_TYPE_FLOAT:
     99             return "float";
    100         case JAVA_TYPE_DOUBLE:
    101             return "double";
    102         case JAVA_TYPE_STRING:
    103             return "java.lang.String";
    104         case JAVA_TYPE_BYTE_ARRAY:
    105             return "byte[]";
    106         default:
    107             return "UNKNOWN";
    108     }
    109 }
    110 
    111 static bool atom_needed_for_module(const AtomDecl& atomDecl, const string& moduleName) {
    112     if (moduleName == DEFAULT_MODULE_NAME) {
    113         return true;
    114     }
    115     return atomDecl.hasModule && (moduleName == atomDecl.moduleName);
    116 }
    117 
    118 static bool signature_needed_for_module(const set<string>& modules, const string& moduleName) {
    119     if (moduleName == DEFAULT_MODULE_NAME) {
    120         return true;
    121     }
    122     return modules.find(moduleName) != modules.end();
    123 }
    124 
    125 static void write_atoms_info_cpp(FILE *out, const Atoms &atoms) {
    126     std::set<string> kTruncatingAtomNames = {"mobile_radio_power_state_changed",
    127                                                  "audio_state_changed",
    128                                                  "call_state_changed",
    129                                                  "phone_signal_strength_changed",
    130                                                  "mobile_bytes_transfer_by_fg_bg",
    131                                                  "mobile_bytes_transfer"};
    132     fprintf(out,
    133             "const std::set<int> "
    134             "AtomsInfo::kTruncatingTimestampAtomBlackList = {\n");
    135     for (set<string>::const_iterator blacklistedAtom = kTruncatingAtomNames.begin();
    136          blacklistedAtom != kTruncatingAtomNames.end(); blacklistedAtom++) {
    137             fprintf(out, " %s,\n", make_constant_name(*blacklistedAtom).c_str());
    138     }
    139     fprintf(out, "};\n");
    140     fprintf(out, "\n");
    141 
    142     fprintf(out,
    143             "const std::set<int> AtomsInfo::kAtomsWithAttributionChain = {\n");
    144     for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
    145          atom != atoms.decls.end(); atom++) {
    146         for (vector<AtomField>::const_iterator field = atom->fields.begin();
    147              field != atom->fields.end(); field++) {
    148             if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
    149                 string constant = make_constant_name(atom->name);
    150                 fprintf(out, " %s,\n", constant.c_str());
    151                 break;
    152             }
    153         }
    154     }
    155 
    156     fprintf(out, "};\n");
    157     fprintf(out, "\n");
    158 
    159     fprintf(out,
    160             "const std::set<int> AtomsInfo::kWhitelistedAtoms = {\n");
    161     for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
    162          atom != atoms.decls.end(); atom++) {
    163         if (atom->whitelisted) {
    164             string constant = make_constant_name(atom->name);
    165             fprintf(out, " %s,\n", constant.c_str());
    166         }
    167     }
    168 
    169     fprintf(out, "};\n");
    170     fprintf(out, "\n");
    171 
    172     fprintf(out, "static std::map<int, int> getAtomUidField() {\n");
    173     fprintf(out, "  std::map<int, int> uidField;\n");
    174     for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
    175          atom != atoms.decls.end(); atom++) {
    176         if (atom->uidField == 0) {
    177             continue;
    178         }
    179         fprintf(out,
    180                 "\n    // Adding uid field for atom "
    181                 "(%d)%s\n",
    182                 atom->code, atom->name.c_str());
    183         fprintf(out, "    uidField[static_cast<int>(%s)] = %d;\n",
    184                 make_constant_name(atom->name).c_str(), atom->uidField);
    185     }
    186 
    187     fprintf(out, "    return uidField;\n");
    188     fprintf(out, "};\n");
    189 
    190     fprintf(out,
    191             "const std::map<int, int> AtomsInfo::kAtomsWithUidField = "
    192             "getAtomUidField();\n");
    193 
    194     fprintf(out,
    195             "static std::map<int, StateAtomFieldOptions> "
    196             "getStateAtomFieldOptions() {\n");
    197     fprintf(out, "    std::map<int, StateAtomFieldOptions> options;\n");
    198     fprintf(out, "    StateAtomFieldOptions opt;\n");
    199     for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
    200          atom != atoms.decls.end(); atom++) {
    201         if (atom->primaryFields.size() == 0 && atom->exclusiveField == 0) {
    202             continue;
    203         }
    204         fprintf(out,
    205                 "\n    // Adding primary and exclusive fields for atom "
    206                 "(%d)%s\n",
    207                 atom->code, atom->name.c_str());
    208         fprintf(out, "    opt.primaryFields.clear();\n");
    209         for (const auto& field : atom->primaryFields) {
    210             fprintf(out, "    opt.primaryFields.push_back(%d);\n", field);
    211         }
    212 
    213         fprintf(out, "    opt.exclusiveField = %d;\n", atom->exclusiveField);
    214         fprintf(out, "    options[static_cast<int>(%s)] = opt;\n",
    215                 make_constant_name(atom->name).c_str());
    216     }
    217 
    218     fprintf(out, "    return options;\n");
    219     fprintf(out, "}\n");
    220 
    221     fprintf(out,
    222             "const std::map<int, StateAtomFieldOptions> "
    223             "AtomsInfo::kStateAtomsFieldOptions = "
    224             "getStateAtomFieldOptions();\n");
    225 
    226     fprintf(out,
    227             "static std::map<int, std::vector<int>> "
    228             "getBinaryFieldAtoms() {\n");
    229     fprintf(out, "    std::map<int, std::vector<int>> options;\n");
    230     for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
    231          atom != atoms.decls.end(); atom++) {
    232         if (atom->binaryFields.size() == 0) {
    233             continue;
    234         }
    235         fprintf(out,
    236                 "\n    // Adding binary fields for atom "
    237                 "(%d)%s\n",
    238                 atom->code, atom->name.c_str());
    239 
    240         for (const auto& field : atom->binaryFields) {
    241             fprintf(out, "    options[static_cast<int>(%s)].push_back(%d);\n",
    242                     make_constant_name(atom->name).c_str(), field);
    243         }
    244     }
    245 
    246     fprintf(out, "    return options;\n");
    247     fprintf(out, "}\n");
    248 
    249     fprintf(out,
    250             "const std::map<int, std::vector<int>> "
    251             "AtomsInfo::kBytesFieldAtoms = "
    252             "getBinaryFieldAtoms();\n");
    253 }
    254 
    255 // Writes namespaces for the cpp and header files, returning the number of namespaces written.
    256 void write_namespace(FILE* out, const string& cppNamespaces) {
    257     vector<string> cppNamespaceVec = android::base::Split(cppNamespaces, ",");
    258     for (string cppNamespace : cppNamespaceVec) {
    259         fprintf(out, "namespace %s {\n", cppNamespace.c_str());
    260     }
    261 }
    262 
    263 // Writes namespace closing brackets for cpp and header files.
    264 void write_closing_namespace(FILE* out, const string& cppNamespaces) {
    265     vector<string> cppNamespaceVec = android::base::Split(cppNamespaces, ",");
    266     for (auto it = cppNamespaceVec.rbegin(); it != cppNamespaceVec.rend(); ++it) {
    267         fprintf(out, "} // namespace %s\n", it->c_str());
    268     }
    269 }
    270 
    271 static int write_stats_log_cpp(FILE *out, const Atoms &atoms, const AtomDecl &attributionDecl,
    272                                const string& moduleName, const string& cppNamespace,
    273                                const string& importHeader) {
    274     // Print prelude
    275     fprintf(out, "// This file is autogenerated\n");
    276     fprintf(out, "\n");
    277 
    278     fprintf(out, "#include <mutex>\n");
    279     fprintf(out, "#include <chrono>\n");
    280     fprintf(out, "#include <thread>\n");
    281     fprintf(out, "#ifdef __ANDROID__\n");
    282     fprintf(out, "#include <cutils/properties.h>\n");
    283     fprintf(out, "#endif\n");
    284     fprintf(out, "#include <stats_event_list.h>\n");
    285     fprintf(out, "#include <log/log.h>\n");
    286     fprintf(out, "#include <%s>\n", importHeader.c_str());
    287     fprintf(out, "#include <utils/SystemClock.h>\n");
    288     fprintf(out, "\n");
    289 
    290     write_namespace(out, cppNamespace);
    291     fprintf(out, "// the single event tag id for all stats logs\n");
    292     fprintf(out, "const static int kStatsEventTag = 1937006964;\n");
    293     fprintf(out, "#ifdef __ANDROID__\n");
    294     fprintf(out, "const static bool kStatsdEnabled = property_get_bool(\"ro.statsd.enable\", true);\n");
    295     fprintf(out, "#else\n");
    296     fprintf(out, "const static bool kStatsdEnabled = false;\n");
    297     fprintf(out, "#endif\n");
    298 
    299     // AtomsInfo is only used by statsd internally and is not needed for other modules.
    300     if (moduleName == DEFAULT_MODULE_NAME) {
    301         write_atoms_info_cpp(out, atoms);
    302     }
    303 
    304     fprintf(out, "int64_t lastRetryTimestampNs = -1;\n");
    305     fprintf(out, "const int64_t kMinRetryIntervalNs = NS_PER_SEC * 60 * 20; // 20 minutes\n");
    306     fprintf(out, "static std::mutex mLogdRetryMutex;\n");
    307 
    308     // Print write methods
    309     fprintf(out, "\n");
    310     for (auto signature_to_modules_it = atoms.signatures_to_modules.begin();
    311         signature_to_modules_it != atoms.signatures_to_modules.end(); signature_to_modules_it++) {
    312         if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) {
    313             continue;
    314         }
    315         vector<java_type_t> signature = signature_to_modules_it->first;
    316         int argIndex;
    317 
    318         fprintf(out, "int\n");
    319         fprintf(out, "try_stats_write(int32_t code");
    320         argIndex = 1;
    321         for (vector<java_type_t>::const_iterator arg = signature.begin();
    322             arg != signature.end(); arg++) {
    323             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
    324                 for (auto chainField : attributionDecl.fields) {
    325                     if (chainField.javaType == JAVA_TYPE_STRING) {
    326                             fprintf(out, ", const std::vector<%s>& %s",
    327                                  cpp_type_name(chainField.javaType),
    328                                  chainField.name.c_str());
    329                     } else {
    330                             fprintf(out, ", const %s* %s, size_t %s_length",
    331                                  cpp_type_name(chainField.javaType),
    332                                  chainField.name.c_str(), chainField.name.c_str());
    333                     }
    334                 }
    335             } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
    336                 fprintf(out, ", const std::map<int, int32_t>& arg%d_1, "
    337                              "const std::map<int, int64_t>& arg%d_2, "
    338                              "const std::map<int, char const*>& arg%d_3, "
    339                              "const std::map<int, float>& arg%d_4",
    340                              argIndex, argIndex, argIndex, argIndex);
    341             } else {
    342                 fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
    343             }
    344             argIndex++;
    345         }
    346         fprintf(out, ")\n");
    347 
    348         fprintf(out, "{\n");
    349         argIndex = 1;
    350         fprintf(out, "  if (kStatsdEnabled) {\n");
    351         fprintf(out, "    stats_event_list event(kStatsEventTag);\n");
    352         fprintf(out, "    event << android::elapsedRealtimeNano();\n\n");
    353         fprintf(out, "    event << code;\n\n");
    354         for (vector<java_type_t>::const_iterator arg = signature.begin();
    355             arg != signature.end(); arg++) {
    356             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
    357                 for (const auto &chainField : attributionDecl.fields) {
    358                     if (chainField.javaType == JAVA_TYPE_STRING) {
    359                         fprintf(out, "    if (%s_length != %s.size()) {\n",
    360                             attributionDecl.fields.front().name.c_str(), chainField.name.c_str());
    361                         fprintf(out, "        return -EINVAL;\n");
    362                         fprintf(out, "    }\n");
    363                     }
    364                 }
    365                 fprintf(out, "\n    event.begin();\n");
    366                 fprintf(out, "    for (size_t i = 0; i < %s_length; ++i) {\n",
    367                     attributionDecl.fields.front().name.c_str());
    368                 fprintf(out, "        event.begin();\n");
    369                 for (const auto &chainField : attributionDecl.fields) {
    370                     if (chainField.javaType == JAVA_TYPE_STRING) {
    371                         fprintf(out, "        if (%s[i] != NULL) {\n", chainField.name.c_str());
    372                         fprintf(out, "           event << %s[i];\n", chainField.name.c_str());
    373                         fprintf(out, "        } else {\n");
    374                         fprintf(out, "           event << \"\";\n");
    375                         fprintf(out, "        }\n");
    376                     } else {
    377                         fprintf(out, "        event << %s[i];\n", chainField.name.c_str());
    378                     }
    379                 }
    380                 fprintf(out, "        event.end();\n");
    381                 fprintf(out, "    }\n");
    382                 fprintf(out, "    event.end();\n\n");
    383             } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
    384                     fprintf(out, "    event.begin();\n\n");
    385                     fprintf(out, "    for (const auto& it : arg%d_1) {\n", argIndex);
    386                     fprintf(out, "         event.begin();\n");
    387                     fprintf(out, "         event << it.first;\n");
    388                     fprintf(out, "         event << it.second;\n");
    389                     fprintf(out, "         event.end();\n");
    390                     fprintf(out, "    }\n");
    391 
    392                     fprintf(out, "    for (const auto& it : arg%d_2) {\n", argIndex);
    393                     fprintf(out, "         event.begin();\n");
    394                     fprintf(out, "         event << it.first;\n");
    395                     fprintf(out, "         event << it.second;\n");
    396                     fprintf(out, "         event.end();\n");
    397                     fprintf(out, "    }\n");
    398 
    399                     fprintf(out, "    for (const auto& it : arg%d_3) {\n", argIndex);
    400                     fprintf(out, "         event.begin();\n");
    401                     fprintf(out, "         event << it.first;\n");
    402                     fprintf(out, "         event << it.second;\n");
    403                     fprintf(out, "         event.end();\n");
    404                     fprintf(out, "    }\n");
    405 
    406                     fprintf(out, "    for (const auto& it : arg%d_4) {\n", argIndex);
    407                     fprintf(out, "         event.begin();\n");
    408                     fprintf(out, "         event << it.first;\n");
    409                     fprintf(out, "         event << it.second;\n");
    410                     fprintf(out, "         event.end();\n");
    411                     fprintf(out, "    }\n");
    412 
    413                     fprintf(out, "    event.end();\n\n");
    414             } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
    415                 fprintf(out,
    416                         "    event.AppendCharArray(arg%d.arg, "
    417                         "arg%d.arg_length);\n",
    418                         argIndex, argIndex);
    419             } else {
    420                 if (*arg == JAVA_TYPE_STRING) {
    421                     fprintf(out, "    if (arg%d == NULL) {\n", argIndex);
    422                     fprintf(out, "        arg%d = \"\";\n", argIndex);
    423                     fprintf(out, "    }\n");
    424                 }
    425                 fprintf(out, "    event << arg%d;\n", argIndex);
    426             }
    427             argIndex++;
    428         }
    429 
    430         fprintf(out, "    return event.write(LOG_ID_STATS);\n");
    431         fprintf(out, "  } else {\n");
    432         fprintf(out, "    return 1;\n");
    433         fprintf(out, "  }\n");
    434         fprintf(out, "}\n");
    435         fprintf(out, "\n");
    436     }
    437 
    438    for (auto signature_to_modules_it = atoms.signatures_to_modules.begin();
    439        signature_to_modules_it != atoms.signatures_to_modules.end(); signature_to_modules_it++) {
    440        if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) {
    441            continue;
    442        }
    443        vector<java_type_t> signature = signature_to_modules_it->first;
    444        int argIndex;
    445 
    446        fprintf(out, "int\n");
    447        fprintf(out, "stats_write(int32_t code");
    448        argIndex = 1;
    449        for (vector<java_type_t>::const_iterator arg = signature.begin();
    450            arg != signature.end(); arg++) {
    451            if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
    452                for (auto chainField : attributionDecl.fields) {
    453                    if (chainField.javaType == JAVA_TYPE_STRING) {
    454                            fprintf(out, ", const std::vector<%s>& %s",
    455                                 cpp_type_name(chainField.javaType),
    456                                 chainField.name.c_str());
    457                    } else {
    458                            fprintf(out, ", const %s* %s, size_t %s_length",
    459                                 cpp_type_name(chainField.javaType),
    460                                 chainField.name.c_str(), chainField.name.c_str());
    461                    }
    462                }
    463            } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
    464                fprintf(out,
    465                        ", const std::map<int, int32_t>& arg%d_1, "
    466                        "const std::map<int, int64_t>& arg%d_2, "
    467                        "const std::map<int, char const*>& arg%d_3, "
    468                        "const std::map<int, float>& arg%d_4",
    469                        argIndex, argIndex, argIndex, argIndex);
    470            } else {
    471                fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
    472            }
    473            argIndex++;
    474        }
    475        fprintf(out, ")\n");
    476 
    477        fprintf(out, "{\n");
    478        fprintf(out, "  int ret = 0;\n");
    479 
    480        fprintf(out, "  for(int retry = 0; retry < 2; ++retry) {\n");
    481        fprintf(out, "      ret =  try_stats_write(code");
    482 
    483        argIndex = 1;
    484        for (vector<java_type_t>::const_iterator arg = signature.begin();
    485            arg != signature.end(); arg++) {
    486            if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
    487                for (auto chainField : attributionDecl.fields) {
    488                    if (chainField.javaType == JAVA_TYPE_STRING) {
    489                            fprintf(out, ", %s",
    490                                 chainField.name.c_str());
    491                    } else {
    492                            fprintf(out, ",  %s,  %s_length",
    493                                 chainField.name.c_str(), chainField.name.c_str());
    494                    }
    495                }
    496            } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
    497                fprintf(out, ", arg%d_1, arg%d_2, arg%d_3, arg%d_4", argIndex,
    498                        argIndex, argIndex, argIndex);
    499            } else {
    500                fprintf(out, ", arg%d", argIndex);
    501            }
    502            argIndex++;
    503        }
    504        fprintf(out, ");\n");
    505        fprintf(out, "      if (ret >= 0) { break; }\n");
    506 
    507        fprintf(out, "      {\n");
    508        fprintf(out, "          std::lock_guard<std::mutex> lock(mLogdRetryMutex);\n");
    509        fprintf(out, "          if ((android::elapsedRealtimeNano() - lastRetryTimestampNs) <= "
    510                                 "kMinRetryIntervalNs) break;\n");
    511        fprintf(out, "          lastRetryTimestampNs = android::elapsedRealtimeNano();\n");
    512        fprintf(out, "      }\n");
    513        fprintf(out, "      std::this_thread::sleep_for(std::chrono::milliseconds(10));\n");
    514        fprintf(out, "  }\n");
    515        fprintf(out, "  if (ret < 0) {\n");
    516        fprintf(out, "      note_log_drop(ret, code);\n");
    517        fprintf(out, "  }\n");
    518        fprintf(out, "  return ret;\n");
    519        fprintf(out, "}\n");
    520        fprintf(out, "\n");
    521    }
    522 
    523     for (auto signature_it = atoms.non_chained_signatures_to_modules.begin();
    524             signature_it != atoms.non_chained_signatures_to_modules.end(); signature_it++) {
    525         if (!signature_needed_for_module(signature_it->second, moduleName)) {
    526             continue;
    527         }
    528         vector<java_type_t> signature = signature_it->first;
    529         int argIndex;
    530 
    531         fprintf(out, "int\n");
    532         fprintf(out, "try_stats_write_non_chained(int32_t code");
    533         argIndex = 1;
    534         for (vector<java_type_t>::const_iterator arg = signature.begin();
    535             arg != signature.end(); arg++) {
    536             fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
    537             argIndex++;
    538         }
    539         fprintf(out, ")\n");
    540 
    541         fprintf(out, "{\n");
    542         argIndex = 1;
    543         fprintf(out, "  if (kStatsdEnabled) {\n");
    544         fprintf(out, "    stats_event_list event(kStatsEventTag);\n");
    545         fprintf(out, "    event << android::elapsedRealtimeNano();\n\n");
    546         fprintf(out, "    event << code;\n\n");
    547         for (vector<java_type_t>::const_iterator arg = signature.begin();
    548             arg != signature.end(); arg++) {
    549             if (argIndex == 1) {
    550                 fprintf(out, "    event.begin();\n\n");
    551                 fprintf(out, "    event.begin();\n");
    552             }
    553             if (*arg == JAVA_TYPE_STRING) {
    554                 fprintf(out, "    if (arg%d == NULL) {\n", argIndex);
    555                 fprintf(out, "        arg%d = \"\";\n", argIndex);
    556                 fprintf(out, "    }\n");
    557             }
    558             if (*arg == JAVA_TYPE_BYTE_ARRAY) {
    559                 fprintf(out,
    560                         "    event.AppendCharArray(arg%d.arg, "
    561                         "arg%d.arg_length);",
    562                         argIndex, argIndex);
    563             } else {
    564                 fprintf(out, "    event << arg%d;\n", argIndex);
    565             }
    566             if (argIndex == 2) {
    567                 fprintf(out, "    event.end();\n\n");
    568                 fprintf(out, "    event.end();\n\n");
    569             }
    570             argIndex++;
    571         }
    572 
    573         fprintf(out, "    return event.write(LOG_ID_STATS);\n");
    574         fprintf(out, "  } else {\n");
    575         fprintf(out, "    return 1;\n");
    576         fprintf(out, "  }\n");
    577         fprintf(out, "}\n");
    578         fprintf(out, "\n");
    579     }
    580 
    581     for (auto signature_it = atoms.non_chained_signatures_to_modules.begin();
    582             signature_it != atoms.non_chained_signatures_to_modules.end(); signature_it++) {
    583        if (!signature_needed_for_module(signature_it->second, moduleName)) {
    584            continue;
    585        }
    586        vector<java_type_t> signature = signature_it->first;
    587        int argIndex;
    588 
    589        fprintf(out, "int\n");
    590        fprintf(out, "stats_write_non_chained(int32_t code");
    591        argIndex = 1;
    592        for (vector<java_type_t>::const_iterator arg = signature.begin();
    593            arg != signature.end(); arg++) {
    594            fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
    595            argIndex++;
    596        }
    597        fprintf(out, ")\n");
    598 
    599        fprintf(out, "{\n");
    600 
    601        fprintf(out, "  int ret = 0;\n");
    602        fprintf(out, "  for(int retry = 0; retry < 2; ++retry) {\n");
    603        fprintf(out, "      ret =  try_stats_write_non_chained(code");
    604 
    605        argIndex = 1;
    606        for (vector<java_type_t>::const_iterator arg = signature.begin();
    607            arg != signature.end(); arg++) {
    608            fprintf(out, ", arg%d",   argIndex);
    609            argIndex++;
    610        }
    611        fprintf(out, ");\n");
    612        fprintf(out, "      if (ret >= 0) { break; }\n");
    613 
    614        fprintf(out, "      {\n");
    615        fprintf(out, "          std::lock_guard<std::mutex> lock(mLogdRetryMutex);\n");
    616        fprintf(out, "          if ((android::elapsedRealtimeNano() - lastRetryTimestampNs) <= "
    617                                 "kMinRetryIntervalNs) break;\n");
    618        fprintf(out, "          lastRetryTimestampNs = android::elapsedRealtimeNano();\n");
    619        fprintf(out, "      }\n");
    620 
    621        fprintf(out, "      std::this_thread::sleep_for(std::chrono::milliseconds(10));\n");
    622        fprintf(out, "  }\n");
    623        fprintf(out, "  if (ret < 0) {\n");
    624        fprintf(out, "      note_log_drop(ret, code);\n");
    625        fprintf(out, "  }\n");
    626        fprintf(out, "  return ret;\n\n");
    627        fprintf(out, "}\n");
    628 
    629        fprintf(out, "\n");
    630    }
    631 
    632 
    633     // Print footer
    634     fprintf(out, "\n");
    635     write_closing_namespace(out, cppNamespace);
    636 
    637     return 0;
    638 }
    639 
    640 void build_non_chained_decl_map(const Atoms& atoms,
    641                                 std::map<int, set<AtomDecl>::const_iterator>* decl_map){
    642     for (set<AtomDecl>::const_iterator atom = atoms.non_chained_decls.begin();
    643         atom != atoms.non_chained_decls.end(); atom++) {
    644         decl_map->insert(std::make_pair(atom->code, atom));
    645     }
    646 }
    647 
    648 static void write_cpp_usage(
    649     FILE* out, const string& method_name, const string& atom_code_name,
    650     const AtomDecl& atom, const AtomDecl &attributionDecl) {
    651     fprintf(out, "     * Usage: %s(StatsLog.%s", method_name.c_str(),
    652             atom_code_name.c_str());
    653 
    654     for (vector<AtomField>::const_iterator field = atom.fields.begin();
    655             field != atom.fields.end(); field++) {
    656         if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
    657             for (auto chainField : attributionDecl.fields) {
    658                 if (chainField.javaType == JAVA_TYPE_STRING) {
    659                     fprintf(out, ", const std::vector<%s>& %s",
    660                          cpp_type_name(chainField.javaType),
    661                          chainField.name.c_str());
    662                 } else {
    663                     fprintf(out, ", const %s* %s, size_t %s_length",
    664                          cpp_type_name(chainField.javaType),
    665                          chainField.name.c_str(), chainField.name.c_str());
    666                 }
    667             }
    668         } else if (field->javaType == JAVA_TYPE_KEY_VALUE_PAIR) {
    669             fprintf(out, ", const std::map<int, int32_t>& %s_int"
    670                          ", const std::map<int, int64_t>& %s_long"
    671                          ", const std::map<int, char const*>& %s_str"
    672                          ", const std::map<int, float>& %s_float",
    673                          field->name.c_str(),
    674                          field->name.c_str(),
    675                          field->name.c_str(),
    676                          field->name.c_str());
    677         } else {
    678             fprintf(out, ", %s %s", cpp_type_name(field->javaType), field->name.c_str());
    679         }
    680     }
    681     fprintf(out, ");\n");
    682 }
    683 
    684 static void write_cpp_method_header(
    685         FILE* out,
    686         const string& method_name,
    687         const map<vector<java_type_t>, set<string>>& signatures_to_modules,
    688         const AtomDecl &attributionDecl, const string& moduleName) {
    689 
    690     for (auto signature_to_modules_it = signatures_to_modules.begin();
    691             signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
    692         // Skip if this signature is not needed for the module.
    693         if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) {
    694             continue;
    695         }
    696 
    697         vector<java_type_t> signature = signature_to_modules_it->first;
    698         fprintf(out, "int %s(int32_t code", method_name.c_str());
    699         int argIndex = 1;
    700         for (vector<java_type_t>::const_iterator arg = signature.begin();
    701                 arg != signature.end(); arg++) {
    702             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
    703                 for (auto chainField : attributionDecl.fields) {
    704                     if (chainField.javaType == JAVA_TYPE_STRING) {
    705                         fprintf(out, ", const std::vector<%s>& %s",
    706                             cpp_type_name(chainField.javaType), chainField.name.c_str());
    707                     } else {
    708                         fprintf(out, ", const %s* %s, size_t %s_length",
    709                             cpp_type_name(chainField.javaType),
    710                             chainField.name.c_str(), chainField.name.c_str());
    711                     }
    712                 }
    713             } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
    714                 fprintf(out, ", const std::map<int, int32_t>& arg%d_1, "
    715                              "const std::map<int, int64_t>& arg%d_2, "
    716                              "const std::map<int, char const*>& arg%d_3, "
    717                              "const std::map<int, float>& arg%d_4",
    718                              argIndex, argIndex, argIndex, argIndex);
    719             } else {
    720                 fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
    721             }
    722             argIndex++;
    723         }
    724         fprintf(out, ");\n");
    725 
    726     }
    727 }
    728 
    729 static int
    730 write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl,
    731         const string& moduleName, const string& cppNamespace)
    732 {
    733     // Print prelude
    734     fprintf(out, "// This file is autogenerated\n");
    735     fprintf(out, "\n");
    736     fprintf(out, "#pragma once\n");
    737     fprintf(out, "\n");
    738     fprintf(out, "#include <stdint.h>\n");
    739     fprintf(out, "#include <vector>\n");
    740     fprintf(out, "#include <map>\n");
    741     fprintf(out, "#include <set>\n");
    742     fprintf(out, "\n");
    743 
    744     write_namespace(out, cppNamespace);
    745     fprintf(out, "\n");
    746     fprintf(out, "/*\n");
    747     fprintf(out, " * API For logging statistics events.\n");
    748     fprintf(out, " */\n");
    749     fprintf(out, "\n");
    750     fprintf(out, "/**\n");
    751     fprintf(out, " * Constants for atom codes.\n");
    752     fprintf(out, " */\n");
    753     fprintf(out, "enum {\n");
    754 
    755     std::map<int, set<AtomDecl>::const_iterator> atom_code_to_non_chained_decl_map;
    756     build_non_chained_decl_map(atoms, &atom_code_to_non_chained_decl_map);
    757 
    758     size_t i = 0;
    759     // Print atom constants
    760     for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
    761         atom != atoms.decls.end(); atom++) {
    762         // Skip if the atom is not needed for the module.
    763         if (!atom_needed_for_module(*atom, moduleName)) {
    764             continue;
    765         }
    766         string constant = make_constant_name(atom->name);
    767         fprintf(out, "\n");
    768         fprintf(out, "    /**\n");
    769         fprintf(out, "     * %s %s\n", atom->message.c_str(), atom->name.c_str());
    770         write_cpp_usage(out, "stats_write", constant, *atom, attributionDecl);
    771 
    772         auto non_chained_decl = atom_code_to_non_chained_decl_map.find(atom->code);
    773         if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) {
    774             write_cpp_usage(out, "stats_write_non_chained", constant, *non_chained_decl->second,
    775                 attributionDecl);
    776         }
    777         fprintf(out, "     */\n");
    778         char const* const comma = (i == atoms.decls.size() - 1) ? "" : ",";
    779         fprintf(out, "    %s = %d%s\n", constant.c_str(), atom->code, comma);
    780         if (atom->code < PULL_ATOM_START_ID && atom->code > maxPushedAtomId) {
    781             maxPushedAtomId = atom->code;
    782         }
    783         i++;
    784     }
    785     fprintf(out, "\n");
    786     fprintf(out, "};\n");
    787     fprintf(out, "\n");
    788 
    789     // Print constants for the enum values.
    790     fprintf(out, "//\n");
    791     fprintf(out, "// Constants for enum values\n");
    792     fprintf(out, "//\n\n");
    793     for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
    794         atom != atoms.decls.end(); atom++) {
    795         // Skip if the atom is not needed for the module.
    796         if (!atom_needed_for_module(*atom, moduleName)) {
    797             continue;
    798         }
    799 
    800         for (vector<AtomField>::const_iterator field = atom->fields.begin();
    801             field != atom->fields.end(); field++) {
    802             if (field->javaType == JAVA_TYPE_ENUM) {
    803                 fprintf(out, "// Values for %s.%s\n", atom->message.c_str(),
    804                     field->name.c_str());
    805                 for (map<int, string>::const_iterator value = field->enumValues.begin();
    806                     value != field->enumValues.end(); value++) {
    807                     fprintf(out, "const int32_t %s__%s__%s = %d;\n",
    808                         make_constant_name(atom->message).c_str(),
    809                         make_constant_name(field->name).c_str(),
    810                         make_constant_name(value->second).c_str(),
    811                         value->first);
    812                 }
    813                 fprintf(out, "\n");
    814             }
    815         }
    816     }
    817 
    818     fprintf(out, "struct BytesField {\n");
    819     fprintf(out,
    820             "  BytesField(char const* array, size_t len) : arg(array), "
    821             "arg_length(len) {}\n");
    822     fprintf(out, "  char const* arg;\n");
    823     fprintf(out, "  size_t arg_length;\n");
    824     fprintf(out, "};\n");
    825     fprintf(out, "\n");
    826 
    827     // This metadata is only used by statsd, which uses the default libstatslog.
    828     if (moduleName == DEFAULT_MODULE_NAME) {
    829 
    830         fprintf(out, "struct StateAtomFieldOptions {\n");
    831         fprintf(out, "  std::vector<int> primaryFields;\n");
    832         fprintf(out, "  int exclusiveField;\n");
    833         fprintf(out, "};\n");
    834         fprintf(out, "\n");
    835 
    836         fprintf(out, "struct AtomsInfo {\n");
    837         fprintf(out,
    838                 "  const static std::set<int> "
    839                 "kTruncatingTimestampAtomBlackList;\n");
    840         fprintf(out, "  const static std::map<int, int> kAtomsWithUidField;\n");
    841         fprintf(out,
    842                 "  const static std::set<int> kAtomsWithAttributionChain;\n");
    843         fprintf(out,
    844                 "  const static std::map<int, StateAtomFieldOptions> "
    845                 "kStateAtomsFieldOptions;\n");
    846         fprintf(out,
    847                 "  const static std::map<int, std::vector<int>> "
    848                 "kBytesFieldAtoms;");
    849         fprintf(out,
    850                 "  const static std::set<int> kWhitelistedAtoms;\n");
    851         fprintf(out, "};\n");
    852 
    853         fprintf(out, "const static int kMaxPushedAtomId = %d;\n\n",
    854                 maxPushedAtomId);
    855     }
    856 
    857     // Print write methods
    858     fprintf(out, "//\n");
    859     fprintf(out, "// Write methods\n");
    860     fprintf(out, "//\n");
    861     write_cpp_method_header(out, "stats_write", atoms.signatures_to_modules, attributionDecl,
    862             moduleName);
    863 
    864     fprintf(out, "//\n");
    865     fprintf(out, "// Write flattened methods\n");
    866     fprintf(out, "//\n");
    867     write_cpp_method_header(out, "stats_write_non_chained", atoms.non_chained_signatures_to_modules,
    868         attributionDecl, moduleName);
    869 
    870     fprintf(out, "\n");
    871     write_closing_namespace(out, cppNamespace);
    872 
    873     return 0;
    874 }
    875 
    876 static void write_java_usage(FILE* out, const string& method_name, const string& atom_code_name,
    877         const AtomDecl& atom) {
    878     fprintf(out, "     * Usage: StatsLog.%s(StatsLog.%s",
    879         method_name.c_str(), atom_code_name.c_str());
    880     for (vector<AtomField>::const_iterator field = atom.fields.begin();
    881         field != atom.fields.end(); field++) {
    882         if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
    883             fprintf(out, ", android.os.WorkSource workSource");
    884         } else if (field->javaType == JAVA_TYPE_KEY_VALUE_PAIR) {
    885             fprintf(out, ", SparseArray<Object> value_map");
    886         } else if (field->javaType == JAVA_TYPE_BYTE_ARRAY) {
    887             fprintf(out, ", byte[] %s", field->name.c_str());
    888         } else {
    889             fprintf(out, ", %s %s", java_type_name(field->javaType), field->name.c_str());
    890         }
    891     }
    892     fprintf(out, ");<br>\n");
    893 }
    894 
    895 static void write_java_method(
    896         FILE* out,
    897         const string& method_name,
    898         const map<vector<java_type_t>, set<string>>& signatures_to_modules,
    899         const AtomDecl &attributionDecl) {
    900 
    901     for (auto signature_to_modules_it = signatures_to_modules.begin();
    902             signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
    903         vector<java_type_t> signature = signature_to_modules_it->first;
    904         fprintf(out, "    /** @hide */\n");
    905         fprintf(out, "    public static native int %s(int code", method_name.c_str());
    906         int argIndex = 1;
    907         for (vector<java_type_t>::const_iterator arg = signature.begin();
    908             arg != signature.end(); arg++) {
    909             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
    910                 for (auto chainField : attributionDecl.fields) {
    911                     fprintf(out, ", %s[] %s",
    912                         java_type_name(chainField.javaType), chainField.name.c_str());
    913                 }
    914             } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
    915                 fprintf(out, ", SparseArray<Object> value_map");
    916             } else {
    917                 fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
    918             }
    919             argIndex++;
    920         }
    921         fprintf(out, ");\n");
    922     }
    923 }
    924 
    925 static void write_java_helpers_for_module(
    926         FILE * out,
    927         const AtomDecl &attributionDecl,
    928         const int requiredHelpers) {
    929     fprintf(out, "    private static void copyInt(byte[] buff, int pos, int val) {\n");
    930     fprintf(out, "        buff[pos] = (byte) (val);\n");
    931     fprintf(out, "        buff[pos + 1] = (byte) (val >> 8);\n");
    932     fprintf(out, "        buff[pos + 2] = (byte) (val >> 16);\n");
    933     fprintf(out, "        buff[pos + 3] = (byte) (val >> 24);\n");
    934     fprintf(out, "        return;\n");
    935     fprintf(out, "    }\n");
    936     fprintf(out, "\n");
    937 
    938     fprintf(out, "    private static void copyLong(byte[] buff, int pos, long val) {\n");
    939     fprintf(out, "        buff[pos] = (byte) (val);\n");
    940     fprintf(out, "        buff[pos + 1] = (byte) (val >> 8);\n");
    941     fprintf(out, "        buff[pos + 2] = (byte) (val >> 16);\n");
    942     fprintf(out, "        buff[pos + 3] = (byte) (val >> 24);\n");
    943     fprintf(out, "        buff[pos + 4] = (byte) (val >> 32);\n");
    944     fprintf(out, "        buff[pos + 5] = (byte) (val >> 40);\n");
    945     fprintf(out, "        buff[pos + 6] = (byte) (val >> 48);\n");
    946     fprintf(out, "        buff[pos + 7] = (byte) (val >> 56);\n");
    947     fprintf(out, "        return;\n");
    948     fprintf(out, "    }\n");
    949     fprintf(out, "\n");
    950 
    951     if (requiredHelpers & JAVA_MODULE_REQUIRES_FLOAT) {
    952         fprintf(out, "    private static void copyFloat(byte[] buff, int pos, float val) {\n");
    953         fprintf(out, "        copyInt(buff, pos, Float.floatToIntBits(val));\n");
    954         fprintf(out, "        return;\n");
    955         fprintf(out, "    }\n");
    956         fprintf(out, "\n");
    957     }
    958 
    959     if (requiredHelpers & JAVA_MODULE_REQUIRES_ATTRIBUTION) {
    960         fprintf(out, "    private static void writeAttributionChain(byte[] buff, int pos");
    961         for (auto chainField : attributionDecl.fields) {
    962             fprintf(out, ", %s[] %s",
    963                 java_type_name(chainField.javaType), chainField.name.c_str());
    964         }
    965         fprintf(out, ") {\n");
    966 
    967         const char* uidName = attributionDecl.fields.front().name.c_str();
    968         const char* tagName = attributionDecl.fields.back().name.c_str();
    969 
    970         // Write the first list begin.
    971         fprintf(out, "        buff[pos] = LIST_TYPE;\n");
    972         fprintf(out, "        buff[pos + 1] = (byte) (%s.length);\n", tagName);
    973         fprintf(out, "        pos += LIST_TYPE_OVERHEAD;\n");
    974 
    975         // Iterate through the attribution chain and write the nodes.
    976         fprintf(out, "        for (int i = 0; i < %s.length; i++) {\n", tagName);
    977         // Write the list begin.
    978         fprintf(out, "            buff[pos] = LIST_TYPE;\n");
    979         fprintf(out, "            buff[pos + 1] = %lu;\n", attributionDecl.fields.size());
    980         fprintf(out, "            pos += LIST_TYPE_OVERHEAD;\n");
    981 
    982         // Write the uid.
    983         fprintf(out, "            buff[pos] = INT_TYPE;\n");
    984         fprintf(out, "            copyInt(buff, pos + 1, %s[i]);\n", uidName);
    985         fprintf(out, "            pos += INT_TYPE_SIZE;\n");
    986 
    987         // Write the tag.
    988         fprintf(out, "            String %sStr = (%s[i] == null) ? \"\" : %s[i];\n",
    989                 tagName, tagName, tagName);
    990         fprintf(out, "            byte[] %sByte = %sStr.getBytes(UTF_8);\n", tagName, tagName);
    991         fprintf(out, "            buff[pos] = STRING_TYPE;\n");
    992         fprintf(out, "            copyInt(buff, pos + 1, %sByte.length);\n", tagName);
    993         fprintf(out, "            System.arraycopy("
    994                 "%sByte, 0, buff, pos + STRING_TYPE_OVERHEAD, %sByte.length);\n",
    995                 tagName, tagName);
    996         fprintf(out, "            pos += STRING_TYPE_OVERHEAD + %sByte.length;\n", tagName);
    997         fprintf(out, "        }\n");
    998         fprintf(out, "    }\n");
    999         fprintf(out, "\n");
   1000     }
   1001 }
   1002 
   1003 
   1004 static int write_java_non_chained_method_for_module(
   1005         FILE* out,
   1006         const map<vector<java_type_t>, set<string>>& signatures_to_modules,
   1007         const string& moduleName
   1008         ) {
   1009     for (auto signature_to_modules_it = signatures_to_modules.begin();
   1010             signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
   1011         // Skip if this signature is not needed for the module.
   1012         if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) {
   1013             continue;
   1014         }
   1015 
   1016         // Print method signature.
   1017         vector<java_type_t> signature = signature_to_modules_it->first;
   1018         fprintf(out, "    public static void write_non_chained(int code");
   1019         int argIndex = 1;
   1020         for (vector<java_type_t>::const_iterator arg = signature.begin();
   1021                 arg != signature.end(); arg++) {
   1022             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
   1023                 // Non chained signatures should not have attribution chains.
   1024                 return 1;
   1025             } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
   1026                 // Module logging does not yet support key value pair.
   1027                 return 1;
   1028             } else {
   1029                 fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
   1030             }
   1031             argIndex++;
   1032         }
   1033         fprintf(out, ") {\n");
   1034 
   1035         fprintf(out, "        write(code");
   1036         argIndex = 1;
   1037         for (vector<java_type_t>::const_iterator arg = signature.begin();
   1038                 arg != signature.end(); arg++) {
   1039             // First two args are uid and tag of attribution chain.
   1040             if (argIndex == 1) {
   1041                 fprintf(out, ", new int[] {arg%d}", argIndex);
   1042             } else if (argIndex == 2) {
   1043                 fprintf(out, ", new java.lang.String[] {arg%d}", argIndex);
   1044             } else {
   1045                 fprintf(out, ", arg%d", argIndex);
   1046             }
   1047             argIndex++;
   1048         }
   1049         fprintf(out, ");\n");
   1050         fprintf(out, "    }\n");
   1051         fprintf(out, "\n");
   1052     }
   1053     return 0;
   1054 }
   1055 
   1056 static int write_java_method_for_module(
   1057         FILE* out,
   1058         const map<vector<java_type_t>, set<string>>& signatures_to_modules,
   1059         const AtomDecl &attributionDecl,
   1060         const string& moduleName,
   1061         int* requiredHelpers
   1062         ) {
   1063 
   1064     for (auto signature_to_modules_it = signatures_to_modules.begin();
   1065             signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
   1066         // Skip if this signature is not needed for the module.
   1067         if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) {
   1068             continue;
   1069         }
   1070 
   1071         // Print method signature.
   1072         vector<java_type_t> signature = signature_to_modules_it->first;
   1073         fprintf(out, "    public static void write(int code");
   1074         int argIndex = 1;
   1075         for (vector<java_type_t>::const_iterator arg = signature.begin();
   1076                 arg != signature.end(); arg++) {
   1077             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
   1078                 for (auto chainField : attributionDecl.fields) {
   1079                     fprintf(out, ", %s[] %s",
   1080                         java_type_name(chainField.javaType), chainField.name.c_str());
   1081                 }
   1082             } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
   1083                 // Module logging does not yet support key value pair.
   1084                 return 1;
   1085             } else {
   1086                 fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
   1087             }
   1088             argIndex++;
   1089         }
   1090         fprintf(out, ") {\n");
   1091 
   1092         // Calculate the size of the buffer.
   1093         fprintf(out, "        // Initial overhead of the list, timestamp, and atom tag.\n");
   1094         fprintf(out, "        int needed = LIST_TYPE_OVERHEAD + LONG_TYPE_SIZE + INT_TYPE_SIZE;\n");
   1095         argIndex = 1;
   1096         for (vector<java_type_t>::const_iterator arg = signature.begin();
   1097                 arg != signature.end(); arg++) {
   1098             switch (*arg) {
   1099             case JAVA_TYPE_BOOLEAN:
   1100             case JAVA_TYPE_INT:
   1101             case JAVA_TYPE_FLOAT:
   1102             case JAVA_TYPE_ENUM:
   1103                 fprintf(out, "        needed += INT_TYPE_SIZE;\n");
   1104                 break;
   1105             case JAVA_TYPE_LONG:
   1106                 // Longs take 9 bytes, 1 for the type and 8 for the value.
   1107                 fprintf(out, "        needed += LONG_TYPE_SIZE;\n");
   1108                 break;
   1109             case JAVA_TYPE_STRING:
   1110                 // Strings take 5 metadata bytes + length of byte encoded string.
   1111                 fprintf(out, "        if (arg%d == null) {\n", argIndex);
   1112                 fprintf(out, "            arg%d = \"\";\n", argIndex);
   1113                 fprintf(out, "        }\n");
   1114                 fprintf(out, "        byte[] arg%dBytes= arg%d.getBytes(UTF_8);\n",
   1115                         argIndex, argIndex);
   1116                 fprintf(out, "        needed += STRING_TYPE_OVERHEAD + arg%dBytes.length;\n",
   1117                         argIndex);
   1118                 break;
   1119             case JAVA_TYPE_BYTE_ARRAY:
   1120                 // Byte arrays take 5 metadata bytes + length of byte array.
   1121                 fprintf(out, "        if (arg%d == null) {\n", argIndex);
   1122                 fprintf(out, "            arg%d = new byte[0];\n", argIndex);
   1123                 fprintf(out, "        }\n");
   1124                 fprintf(out, "        needed += STRING_TYPE_OVERHEAD + arg%d.length;\n", argIndex);
   1125                 break;
   1126             case JAVA_TYPE_ATTRIBUTION_CHAIN:
   1127             {
   1128                 const char* uidName = attributionDecl.fields.front().name.c_str();
   1129                 const char* tagName = attributionDecl.fields.back().name.c_str();
   1130                 // Null checks on the params.
   1131                 fprintf(out, "        if (%s == null) {\n", uidName);
   1132                 fprintf(out, "            %s = new %s[0];\n", uidName,
   1133                         java_type_name(attributionDecl.fields.front().javaType));
   1134                 fprintf(out, "        }\n");
   1135                 fprintf(out, "        if (%s == null) {\n", tagName);
   1136                 fprintf(out, "            %s = new %s[0];\n", tagName,
   1137                         java_type_name(attributionDecl.fields.back().javaType));
   1138                 fprintf(out, "        }\n");
   1139 
   1140                 // First check that the lengths of the uid and tag arrays are the same.
   1141                 fprintf(out, "        if (%s.length != %s.length) {\n", uidName, tagName);
   1142                 fprintf(out, "            return;\n");
   1143                 fprintf(out, "        }\n");
   1144                 fprintf(out, "        int attrSize = LIST_TYPE_OVERHEAD;\n");
   1145                 fprintf(out, "        for (int i = 0; i < %s.length; i++) {\n", tagName);
   1146                 fprintf(out, "            String str%d = (%s[i] == null) ? \"\" : %s[i];\n",
   1147                         argIndex, tagName, tagName);
   1148                 fprintf(out, "            int str%dlen = str%d.getBytes(UTF_8).length;\n",
   1149                         argIndex, argIndex);
   1150                 fprintf(out,
   1151                         "            attrSize += "
   1152                         "LIST_TYPE_OVERHEAD + INT_TYPE_SIZE + STRING_TYPE_OVERHEAD + str%dlen;\n",
   1153                         argIndex);
   1154                 fprintf(out, "        }\n");
   1155                 fprintf(out, "        needed += attrSize;\n");
   1156                 break;
   1157             }
   1158             default:
   1159                 // Unsupported types: OBJECT, DOUBLE, KEY_VALUE_PAIR.
   1160                 return 1;
   1161             }
   1162             argIndex++;
   1163         }
   1164 
   1165         // Now we have the size that is needed. Check for overflow and return if needed.
   1166         fprintf(out, "        if (needed > MAX_EVENT_PAYLOAD) {\n");
   1167         fprintf(out, "            return;\n");
   1168         fprintf(out, "        }\n");
   1169 
   1170         // Create new buffer, and associated data types.
   1171         fprintf(out, "        byte[] buff = new byte[needed];\n");
   1172         fprintf(out, "        int pos = 0;\n");
   1173 
   1174         // Initialize the buffer with list data type.
   1175         fprintf(out, "        buff[pos] = LIST_TYPE;\n");
   1176         fprintf(out, "        buff[pos + 1] = %zu;\n", signature.size() + 2);
   1177         fprintf(out, "        pos += LIST_TYPE_OVERHEAD;\n");
   1178 
   1179         // Write timestamp.
   1180         fprintf(out, "        long elapsedRealtime = SystemClock.elapsedRealtimeNanos();\n");
   1181         fprintf(out, "        buff[pos] = LONG_TYPE;\n");
   1182         fprintf(out, "        copyLong(buff, pos + 1, elapsedRealtime);\n");
   1183         fprintf(out, "        pos += LONG_TYPE_SIZE;\n");
   1184 
   1185         // Write atom code.
   1186         fprintf(out, "        buff[pos] = INT_TYPE;\n");
   1187         fprintf(out, "        copyInt(buff, pos + 1, code);\n");
   1188         fprintf(out, "        pos += INT_TYPE_SIZE;\n");
   1189 
   1190         // Write the args.
   1191         argIndex = 1;
   1192         for (vector<java_type_t>::const_iterator arg = signature.begin();
   1193                 arg != signature.end(); arg++) {
   1194             switch (*arg) {
   1195             case JAVA_TYPE_BOOLEAN:
   1196                 fprintf(out, "        buff[pos] = INT_TYPE;\n");
   1197                 fprintf(out, "        copyInt(buff, pos + 1, arg%d? 1 : 0);\n", argIndex);
   1198                 fprintf(out, "        pos += INT_TYPE_SIZE;\n");
   1199                 break;
   1200             case JAVA_TYPE_INT:
   1201             case JAVA_TYPE_ENUM:
   1202                 fprintf(out, "        buff[pos] = INT_TYPE;\n");
   1203                 fprintf(out, "        copyInt(buff, pos + 1, arg%d);\n", argIndex);
   1204                 fprintf(out, "        pos += INT_TYPE_SIZE;\n");
   1205                 break;
   1206             case JAVA_TYPE_FLOAT:
   1207                 *requiredHelpers |= JAVA_MODULE_REQUIRES_FLOAT;
   1208                 fprintf(out, "        buff[pos] = FLOAT_TYPE;\n");
   1209                 fprintf(out, "        copyFloat(buff, pos + 1, arg%d);\n", argIndex);
   1210                 fprintf(out, "        pos += FLOAT_TYPE_SIZE;\n");
   1211                 break;
   1212             case JAVA_TYPE_LONG:
   1213                 fprintf(out, "        buff[pos] = LONG_TYPE;\n");
   1214                 fprintf(out, "        copyLong(buff, pos + 1, arg%d);\n", argIndex);
   1215                 fprintf(out, "        pos += LONG_TYPE_SIZE;\n");
   1216                 break;
   1217             case JAVA_TYPE_STRING:
   1218                 fprintf(out, "        buff[pos] = STRING_TYPE;\n");
   1219                 fprintf(out, "        copyInt(buff, pos + 1, arg%dBytes.length);\n", argIndex);
   1220                 fprintf(out, "        System.arraycopy("
   1221                         "arg%dBytes, 0, buff, pos + STRING_TYPE_OVERHEAD, arg%dBytes.length);\n",
   1222                         argIndex, argIndex);
   1223                 fprintf(out, "        pos += STRING_TYPE_OVERHEAD + arg%dBytes.length;\n",
   1224                         argIndex);
   1225                 break;
   1226             case JAVA_TYPE_BYTE_ARRAY:
   1227                 fprintf(out, "        buff[pos] = STRING_TYPE;\n");
   1228                 fprintf(out, "        copyInt(buff, pos + 1, arg%d.length);\n", argIndex);
   1229                 fprintf(out, "        System.arraycopy("
   1230                         "arg%d, 0, buff, pos + STRING_TYPE_OVERHEAD, arg%d.length);\n",
   1231                         argIndex, argIndex);
   1232                 fprintf(out, "        pos += STRING_TYPE_OVERHEAD + arg%d.length;\n", argIndex);
   1233                 break;
   1234             case JAVA_TYPE_ATTRIBUTION_CHAIN:
   1235             {
   1236                 *requiredHelpers |= JAVA_MODULE_REQUIRES_ATTRIBUTION;
   1237                 const char* uidName = attributionDecl.fields.front().name.c_str();
   1238                 const char* tagName = attributionDecl.fields.back().name.c_str();
   1239 
   1240                 fprintf(out, "        writeAttributionChain(buff, pos, %s, %s);\n",
   1241                         uidName, tagName);
   1242                 fprintf(out, "        pos += attrSize;\n");
   1243                 break;
   1244             }
   1245             default:
   1246                 // Unsupported types: OBJECT, DOUBLE, KEY_VALUE_PAIR.
   1247                 return 1;
   1248             }
   1249             argIndex++;
   1250         }
   1251 
   1252         fprintf(out, "        StatsLog.writeRaw(buff, pos);\n");
   1253         fprintf(out, "    }\n");
   1254         fprintf(out, "\n");
   1255     }
   1256     return 0;
   1257 }
   1258 
   1259 static void write_java_work_source_method(FILE* out,
   1260         const map<vector<java_type_t>, set<string>>& signatures_to_modules,
   1261         const string& moduleName) {
   1262     fprintf(out, "\n    // WorkSource methods.\n");
   1263     for (auto signature_to_modules_it = signatures_to_modules.begin();
   1264             signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
   1265         // Skip if this signature is not needed for the module.
   1266         if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) {
   1267             continue;
   1268         }
   1269         vector<java_type_t> signature = signature_to_modules_it->first;
   1270         // Determine if there is Attribution in this signature.
   1271         int attributionArg = -1;
   1272         int argIndexMax = 0;
   1273         for (vector<java_type_t>::const_iterator arg = signature.begin();
   1274                 arg != signature.end(); arg++) {
   1275             argIndexMax++;
   1276             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
   1277                 if (attributionArg > -1) {
   1278                     fprintf(stderr, "An atom contains multiple AttributionNode fields.\n");
   1279                     fprintf(stderr, "This is not supported. Aborting WorkSource method writing.\n");
   1280                     fprintf(out, "\n// Invalid for WorkSource: more than one attribution chain.\n");
   1281                     return;
   1282                 }
   1283                 attributionArg = argIndexMax;
   1284             }
   1285         }
   1286         if (attributionArg < 0) {
   1287             continue;
   1288         }
   1289 
   1290         // Method header (signature)
   1291         if (moduleName == DEFAULT_MODULE_NAME) {
   1292             fprintf(out, "    /** @hide */\n");
   1293         }
   1294         fprintf(out, "    public static void write(int code");
   1295         int argIndex = 1;
   1296         for (vector<java_type_t>::const_iterator arg = signature.begin();
   1297                 arg != signature.end(); arg++) {
   1298             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
   1299                 fprintf(out, ", WorkSource ws");
   1300             } else {
   1301                 fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
   1302             }
   1303             argIndex++;
   1304         }
   1305         fprintf(out, ") {\n");
   1306 
   1307         // write_non_chained() component. TODO: Remove when flat uids are no longer needed.
   1308         fprintf(out, "        for (int i = 0; i < ws.size(); ++i) {\n");
   1309         fprintf(out, "            write_non_chained(code");
   1310         for (int argIndex = 1; argIndex <= argIndexMax; argIndex++) {
   1311             if (argIndex == attributionArg) {
   1312                 fprintf(out, ", ws.get(i), ws.getName(i)");
   1313             } else {
   1314                fprintf(out, ", arg%d", argIndex);
   1315             }
   1316         }
   1317         fprintf(out, ");\n");
   1318         fprintf(out, "        }\n"); // close for-loop
   1319 
   1320         // write() component.
   1321         fprintf(out, "        ArrayList<WorkSource.WorkChain> workChains = ws.getWorkChains();\n");
   1322         fprintf(out, "        if (workChains != null) {\n");
   1323         fprintf(out, "            for (WorkSource.WorkChain wc : workChains) {\n");
   1324         fprintf(out, "                write(code");
   1325         for (int argIndex = 1; argIndex <= argIndexMax; argIndex++) {
   1326             if (argIndex == attributionArg) {
   1327                 fprintf(out, ", wc.getUids(), wc.getTags()");
   1328             } else {
   1329                fprintf(out, ", arg%d", argIndex);
   1330             }
   1331         }
   1332         fprintf(out, ");\n");
   1333         fprintf(out, "            }\n"); // close for-loop
   1334         fprintf(out, "        }\n"); // close if
   1335         fprintf(out, "    }\n"); // close method
   1336     }
   1337 }
   1338 
   1339 static void write_java_atom_codes(FILE* out, const Atoms& atoms, const string& moduleName) {
   1340     fprintf(out, "    // Constants for atom codes.\n");
   1341 
   1342     std::map<int, set<AtomDecl>::const_iterator> atom_code_to_non_chained_decl_map;
   1343     build_non_chained_decl_map(atoms, &atom_code_to_non_chained_decl_map);
   1344 
   1345     // Print constants for the atom codes.
   1346     for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
   1347             atom != atoms.decls.end(); atom++) {
   1348         // Skip if the atom is not needed for the module.
   1349         if (!atom_needed_for_module(*atom, moduleName)) {
   1350             continue;
   1351         }
   1352         string constant = make_constant_name(atom->name);
   1353         fprintf(out, "\n");
   1354         fprintf(out, "    /**\n");
   1355         fprintf(out, "     * %s %s<br>\n", atom->message.c_str(), atom->name.c_str());
   1356         write_java_usage(out, "write", constant, *atom);
   1357         auto non_chained_decl = atom_code_to_non_chained_decl_map.find(atom->code);
   1358         if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) {
   1359             write_java_usage(out, "write_non_chained", constant, *non_chained_decl->second);
   1360         }
   1361         if (moduleName == DEFAULT_MODULE_NAME) {
   1362             fprintf(out, "     * @hide\n");
   1363         }
   1364         fprintf(out, "     */\n");
   1365         fprintf(out, "    public static final int %s = %d;\n", constant.c_str(), atom->code);
   1366     }
   1367     fprintf(out, "\n");
   1368 }
   1369 
   1370 static void write_java_enum_values(FILE* out, const Atoms& atoms, const string& moduleName) {
   1371     fprintf(out, "    // Constants for enum values.\n\n");
   1372     for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
   1373         atom != atoms.decls.end(); atom++) {
   1374         // Skip if the atom is not needed for the module.
   1375         if (!atom_needed_for_module(*atom, moduleName)) {
   1376             continue;
   1377         }
   1378         for (vector<AtomField>::const_iterator field = atom->fields.begin();
   1379             field != atom->fields.end(); field++) {
   1380             if (field->javaType == JAVA_TYPE_ENUM) {
   1381                 fprintf(out, "    // Values for %s.%s\n", atom->message.c_str(),
   1382                     field->name.c_str());
   1383                 for (map<int, string>::const_iterator value = field->enumValues.begin();
   1384                     value != field->enumValues.end(); value++) {
   1385                     if (moduleName == DEFAULT_MODULE_NAME) {
   1386                         fprintf(out, "    /** @hide */\n");
   1387                     }
   1388                     fprintf(out, "    public static final int %s__%s__%s = %d;\n",
   1389                         make_constant_name(atom->message).c_str(),
   1390                         make_constant_name(field->name).c_str(),
   1391                         make_constant_name(value->second).c_str(),
   1392                         value->first);
   1393                 }
   1394                 fprintf(out, "\n");
   1395             }
   1396         }
   1397     }
   1398 }
   1399 
   1400 static int
   1401 write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl)
   1402 {
   1403     // Print prelude
   1404     fprintf(out, "// This file is autogenerated\n");
   1405     fprintf(out, "\n");
   1406     fprintf(out, "package android.util;\n");
   1407     fprintf(out, "\n");
   1408     fprintf(out, "import android.os.WorkSource;\n");
   1409     fprintf(out, "import android.util.SparseArray;\n");
   1410     fprintf(out, "import java.util.ArrayList;\n");
   1411     fprintf(out, "\n");
   1412     fprintf(out, "\n");
   1413     fprintf(out, "/**\n");
   1414     fprintf(out, " * API For logging statistics events.\n");
   1415     fprintf(out, " * @hide\n");
   1416     fprintf(out, " */\n");
   1417     fprintf(out, "public class StatsLogInternal {\n");
   1418     write_java_atom_codes(out, atoms, DEFAULT_MODULE_NAME);
   1419 
   1420     write_java_enum_values(out, atoms, DEFAULT_MODULE_NAME);
   1421 
   1422     // Print write methods
   1423     fprintf(out, "    // Write methods\n");
   1424     write_java_method(out, "write", atoms.signatures_to_modules, attributionDecl);
   1425     write_java_method(out, "write_non_chained", atoms.non_chained_signatures_to_modules,
   1426             attributionDecl);
   1427     write_java_work_source_method(out, atoms.signatures_to_modules, DEFAULT_MODULE_NAME);
   1428 
   1429     fprintf(out, "}\n");
   1430 
   1431     return 0;
   1432 }
   1433 
   1434 // TODO: Merge this with write_stats_log_java so that we can get rid of StatsLogInternal JNI.
   1435 static int
   1436 write_stats_log_java_for_module(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl,
   1437                      const string& moduleName, const string& javaClass, const string& javaPackage)
   1438 {
   1439     // Print prelude
   1440     fprintf(out, "// This file is autogenerated\n");
   1441     fprintf(out, "\n");
   1442     fprintf(out, "package %s;\n", javaPackage.c_str());
   1443     fprintf(out, "\n");
   1444     fprintf(out, "import static java.nio.charset.StandardCharsets.UTF_8;\n");
   1445     fprintf(out, "\n");
   1446     fprintf(out, "import android.util.StatsLog;\n");
   1447     fprintf(out, "import android.os.SystemClock;\n");
   1448     fprintf(out, "\n");
   1449     fprintf(out, "import java.util.ArrayList;\n");
   1450     fprintf(out, "\n");
   1451     fprintf(out, "\n");
   1452     fprintf(out, "/**\n");
   1453     fprintf(out, " * Utility class for logging statistics events.\n");
   1454     fprintf(out, " */\n");
   1455     fprintf(out, "public class %s {\n", javaClass.c_str());
   1456 
   1457     // TODO: ideally these match with the native values (and automatically change if they change).
   1458     fprintf(out, "    private static final int LOGGER_ENTRY_MAX_PAYLOAD = 4068;\n");
   1459     fprintf(out,
   1460             "    private static final int MAX_EVENT_PAYLOAD = LOGGER_ENTRY_MAX_PAYLOAD - 4;\n");
   1461     // Value types. Must match with EventLog.java and log.h.
   1462     fprintf(out, "    private static final byte INT_TYPE = 0;\n");
   1463     fprintf(out, "    private static final byte LONG_TYPE = 1;\n");
   1464     fprintf(out, "    private static final byte STRING_TYPE = 2;\n");
   1465     fprintf(out, "    private static final byte LIST_TYPE = 3;\n");
   1466     fprintf(out, "    private static final byte FLOAT_TYPE = 4;\n");
   1467 
   1468     // Size of each value type.
   1469     // Booleans, ints, floats, and enums take 5 bytes, 1 for the type and 4 for the value.
   1470     fprintf(out, "    private static final int INT_TYPE_SIZE = 5;\n");
   1471     fprintf(out, "    private static final int FLOAT_TYPE_SIZE = 5;\n");
   1472     // Longs take 9 bytes, 1 for the type and 8 for the value.
   1473     fprintf(out, "    private static final int LONG_TYPE_SIZE = 9;\n");
   1474     // Strings take 5 metadata bytes: 1 byte is for the type, 4 are for the length.
   1475     fprintf(out, "    private static final int STRING_TYPE_OVERHEAD = 5;\n");
   1476     fprintf(out, "    private static final int LIST_TYPE_OVERHEAD = 2;\n");
   1477 
   1478     write_java_atom_codes(out, atoms, moduleName);
   1479 
   1480     write_java_enum_values(out, atoms, moduleName);
   1481 
   1482     int errors = 0;
   1483     int requiredHelpers = 0;
   1484     // Print write methods
   1485     fprintf(out, "    // Write methods\n");
   1486     errors += write_java_method_for_module(out, atoms.signatures_to_modules, attributionDecl,
   1487             moduleName, &requiredHelpers);
   1488     errors += write_java_non_chained_method_for_module(out, atoms.non_chained_signatures_to_modules,
   1489             moduleName);
   1490 
   1491     fprintf(out, "    // Helper methods for copying primitives\n");
   1492     write_java_helpers_for_module(out, attributionDecl, requiredHelpers);
   1493 
   1494     fprintf(out, "}\n");
   1495 
   1496     return errors;
   1497 }
   1498 
   1499 static const char*
   1500 jni_type_name(java_type_t type)
   1501 {
   1502     switch (type) {
   1503         case JAVA_TYPE_BOOLEAN:
   1504             return "jboolean";
   1505         case JAVA_TYPE_INT:
   1506         case JAVA_TYPE_ENUM:
   1507             return "jint";
   1508         case JAVA_TYPE_LONG:
   1509             return "jlong";
   1510         case JAVA_TYPE_FLOAT:
   1511             return "jfloat";
   1512         case JAVA_TYPE_DOUBLE:
   1513             return "jdouble";
   1514         case JAVA_TYPE_STRING:
   1515             return "jstring";
   1516         case JAVA_TYPE_BYTE_ARRAY:
   1517             return "jbyteArray";
   1518         default:
   1519             return "UNKNOWN";
   1520     }
   1521 }
   1522 
   1523 static const char*
   1524 jni_array_type_name(java_type_t type)
   1525 {
   1526     switch (type) {
   1527         case JAVA_TYPE_INT:
   1528             return "jintArray";
   1529         case JAVA_TYPE_FLOAT:
   1530             return "jfloatArray";
   1531         case JAVA_TYPE_STRING:
   1532             return "jobjectArray";
   1533         default:
   1534             return "UNKNOWN";
   1535     }
   1536 }
   1537 
   1538 static string
   1539 jni_function_name(const string& method_name, const vector<java_type_t>& signature)
   1540 {
   1541     string result("StatsLog_" + method_name);
   1542     for (vector<java_type_t>::const_iterator arg = signature.begin();
   1543         arg != signature.end(); arg++) {
   1544         switch (*arg) {
   1545             case JAVA_TYPE_BOOLEAN:
   1546                 result += "_boolean";
   1547                 break;
   1548             case JAVA_TYPE_INT:
   1549             case JAVA_TYPE_ENUM:
   1550                 result += "_int";
   1551                 break;
   1552             case JAVA_TYPE_LONG:
   1553                 result += "_long";
   1554                 break;
   1555             case JAVA_TYPE_FLOAT:
   1556                 result += "_float";
   1557                 break;
   1558             case JAVA_TYPE_DOUBLE:
   1559                 result += "_double";
   1560                 break;
   1561             case JAVA_TYPE_STRING:
   1562                 result += "_String";
   1563                 break;
   1564             case JAVA_TYPE_ATTRIBUTION_CHAIN:
   1565               result += "_AttributionChain";
   1566               break;
   1567             case JAVA_TYPE_KEY_VALUE_PAIR:
   1568               result += "_KeyValuePairs";
   1569               break;
   1570             case JAVA_TYPE_BYTE_ARRAY:
   1571                 result += "_bytes";
   1572                 break;
   1573             default:
   1574                 result += "_UNKNOWN";
   1575                 break;
   1576         }
   1577     }
   1578     return result;
   1579 }
   1580 
   1581 static const char*
   1582 java_type_signature(java_type_t type)
   1583 {
   1584     switch (type) {
   1585         case JAVA_TYPE_BOOLEAN:
   1586             return "Z";
   1587         case JAVA_TYPE_INT:
   1588         case JAVA_TYPE_ENUM:
   1589             return "I";
   1590         case JAVA_TYPE_LONG:
   1591             return "J";
   1592         case JAVA_TYPE_FLOAT:
   1593             return "F";
   1594         case JAVA_TYPE_DOUBLE:
   1595             return "D";
   1596         case JAVA_TYPE_STRING:
   1597             return "Ljava/lang/String;";
   1598         case JAVA_TYPE_BYTE_ARRAY:
   1599             return "[B";
   1600         default:
   1601             return "UNKNOWN";
   1602     }
   1603 }
   1604 
   1605 static string
   1606 jni_function_signature(const vector<java_type_t>& signature, const AtomDecl &attributionDecl)
   1607 {
   1608     string result("(I");
   1609     for (vector<java_type_t>::const_iterator arg = signature.begin();
   1610         arg != signature.end(); arg++) {
   1611         if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
   1612             for (auto chainField : attributionDecl.fields) {
   1613                 result += "[";
   1614                 result += java_type_signature(chainField.javaType);
   1615             }
   1616         } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
   1617             result += "Landroid/util/SparseArray;";
   1618         } else {
   1619             result += java_type_signature(*arg);
   1620         }
   1621     }
   1622     result += ")I";
   1623     return result;
   1624 }
   1625 
   1626 static void write_key_value_map_jni(FILE* out) {
   1627    fprintf(out, "    std::map<int, int32_t> int32_t_map;\n");
   1628    fprintf(out, "    std::map<int, int64_t> int64_t_map;\n");
   1629    fprintf(out, "    std::map<int, float> float_map;\n");
   1630    fprintf(out, "    std::map<int, char const*> string_map;\n\n");
   1631 
   1632    fprintf(out, "    jclass jmap_class = env->FindClass(\"android/util/SparseArray\");\n");
   1633 
   1634    fprintf(out, "    jmethodID jget_size_method = env->GetMethodID(jmap_class, \"size\", \"()I\");\n");
   1635    fprintf(out, "    jmethodID jget_key_method = env->GetMethodID(jmap_class, \"keyAt\", \"(I)I\");\n");
   1636    fprintf(out, "    jmethodID jget_value_method = env->GetMethodID(jmap_class, \"valueAt\", \"(I)Ljava/lang/Object;\");\n\n");
   1637 
   1638 
   1639    fprintf(out, "    std::vector<std::unique_ptr<ScopedUtfChars>> scoped_ufs;\n\n");
   1640 
   1641    fprintf(out, "    jclass jint_class = env->FindClass(\"java/lang/Integer\");\n");
   1642    fprintf(out, "    jclass jlong_class = env->FindClass(\"java/lang/Long\");\n");
   1643    fprintf(out, "    jclass jfloat_class = env->FindClass(\"java/lang/Float\");\n");
   1644    fprintf(out, "    jclass jstring_class = env->FindClass(\"java/lang/String\");\n");
   1645    fprintf(out, "    jmethodID jget_int_method = env->GetMethodID(jint_class, \"intValue\", \"()I\");\n");
   1646    fprintf(out, "    jmethodID jget_long_method = env->GetMethodID(jlong_class, \"longValue\", \"()J\");\n");
   1647    fprintf(out, "    jmethodID jget_float_method = env->GetMethodID(jfloat_class, \"floatValue\", \"()F\");\n\n");
   1648 
   1649    fprintf(out, "    jint jsize = env->CallIntMethod(value_map, jget_size_method);\n");
   1650    fprintf(out, "    for(int i = 0; i < jsize; i++) {\n");
   1651    fprintf(out, "        jint key = env->CallIntMethod(value_map, jget_key_method, i);\n");
   1652    fprintf(out, "        jobject jvalue_obj = env->CallObjectMethod(value_map, jget_value_method, i);\n");
   1653    fprintf(out, "        if (jvalue_obj == NULL) { continue; }\n");
   1654    fprintf(out, "        if (env->IsInstanceOf(jvalue_obj, jint_class)) {\n");
   1655    fprintf(out, "            int32_t_map[key] = env->CallIntMethod(jvalue_obj, jget_int_method);\n");
   1656    fprintf(out, "        } else if (env->IsInstanceOf(jvalue_obj, jlong_class)) {\n");
   1657    fprintf(out, "            int64_t_map[key] = env->CallLongMethod(jvalue_obj, jget_long_method);\n");
   1658    fprintf(out, "        } else if (env->IsInstanceOf(jvalue_obj, jfloat_class)) {\n");
   1659    fprintf(out, "            float_map[key] = env->CallFloatMethod(jvalue_obj, jget_float_method);\n");
   1660    fprintf(out, "        } else if (env->IsInstanceOf(jvalue_obj, jstring_class)) {\n");
   1661    fprintf(out, "            std::unique_ptr<ScopedUtfChars> utf(new ScopedUtfChars(env, (jstring)jvalue_obj));\n");
   1662    fprintf(out, "            if (utf->c_str() != NULL) { string_map[key] = utf->c_str(); }\n");
   1663    fprintf(out, "            scoped_ufs.push_back(std::move(utf));\n");
   1664    fprintf(out, "        }\n");
   1665    fprintf(out, "    }\n");
   1666 }
   1667 
   1668 static int
   1669 write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp_method_name,
   1670         const map<vector<java_type_t>, set<string>>& signatures_to_modules,
   1671         const AtomDecl &attributionDecl) {
   1672     // Print write methods
   1673     for (auto signature_to_modules_it = signatures_to_modules.begin();
   1674             signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
   1675         vector<java_type_t> signature = signature_to_modules_it->first;
   1676         int argIndex;
   1677 
   1678         fprintf(out, "static int\n");
   1679         fprintf(out, "%s(JNIEnv* env, jobject clazz UNUSED, jint code",
   1680                 jni_function_name(java_method_name, signature).c_str());
   1681         argIndex = 1;
   1682         for (vector<java_type_t>::const_iterator arg = signature.begin();
   1683                 arg != signature.end(); arg++) {
   1684             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
   1685                 for (auto chainField : attributionDecl.fields) {
   1686                     fprintf(out, ", %s %s", jni_array_type_name(chainField.javaType),
   1687                         chainField.name.c_str());
   1688                 }
   1689             } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
   1690                 fprintf(out, ", jobject value_map");
   1691             } else {
   1692                 fprintf(out, ", %s arg%d", jni_type_name(*arg), argIndex);
   1693             }
   1694             argIndex++;
   1695         }
   1696         fprintf(out, ")\n");
   1697 
   1698         fprintf(out, "{\n");
   1699 
   1700         // Prepare strings
   1701         argIndex = 1;
   1702         bool hadStringOrChain = false;
   1703         bool isKeyValuePairAtom = false;
   1704         for (vector<java_type_t>::const_iterator arg = signature.begin();
   1705                 arg != signature.end(); arg++) {
   1706             if (*arg == JAVA_TYPE_STRING) {
   1707                 hadStringOrChain = true;
   1708                 fprintf(out, "    const char* str%d;\n", argIndex);
   1709                 fprintf(out, "    if (arg%d != NULL) {\n", argIndex);
   1710                 fprintf(out, "        str%d = env->GetStringUTFChars(arg%d, NULL);\n",
   1711                         argIndex, argIndex);
   1712                 fprintf(out, "    } else {\n");
   1713                 fprintf(out, "        str%d = NULL;\n", argIndex);
   1714                 fprintf(out, "    }\n");
   1715             } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
   1716                 hadStringOrChain = true;
   1717                 fprintf(out, "    jbyte* jbyte_array%d;\n", argIndex);
   1718                 fprintf(out, "    const char* str%d;\n", argIndex);
   1719                 fprintf(out, "    int str%d_length = 0;\n", argIndex);
   1720                 fprintf(out,
   1721                         "    if (arg%d != NULL && env->GetArrayLength(arg%d) > "
   1722                         "0) {\n",
   1723                         argIndex, argIndex);
   1724                 fprintf(out,
   1725                         "        jbyte_array%d = "
   1726                         "env->GetByteArrayElements(arg%d, NULL);\n",
   1727                         argIndex, argIndex);
   1728                 fprintf(out,
   1729                         "        str%d_length = env->GetArrayLength(arg%d);\n",
   1730                         argIndex, argIndex);
   1731                 fprintf(out,
   1732                         "        str%d = "
   1733                         "reinterpret_cast<char*>(env->GetByteArrayElements(arg%"
   1734                         "d, NULL));\n",
   1735                         argIndex, argIndex);
   1736                 fprintf(out, "    } else {\n");
   1737                 fprintf(out, "        jbyte_array%d = NULL;\n", argIndex);
   1738                 fprintf(out, "        str%d = NULL;\n", argIndex);
   1739                 fprintf(out, "    }\n");
   1740 
   1741                 fprintf(out,
   1742                         "    android::util::BytesField bytesField%d(str%d, "
   1743                         "str%d_length);",
   1744                         argIndex, argIndex, argIndex);
   1745 
   1746             } else if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
   1747                 hadStringOrChain = true;
   1748                 for (auto chainField : attributionDecl.fields) {
   1749                     fprintf(out, "    size_t %s_length = env->GetArrayLength(%s);\n",
   1750                         chainField.name.c_str(), chainField.name.c_str());
   1751                     if (chainField.name != attributionDecl.fields.front().name) {
   1752                         fprintf(out, "    if (%s_length != %s_length) {\n",
   1753                             chainField.name.c_str(),
   1754                             attributionDecl.fields.front().name.c_str());
   1755                         fprintf(out, "        return -EINVAL;\n");
   1756                         fprintf(out, "    }\n");
   1757                     }
   1758                     if (chainField.javaType == JAVA_TYPE_INT) {
   1759                         fprintf(out, "    jint* %s_array = env->GetIntArrayElements(%s, NULL);\n",
   1760                             chainField.name.c_str(), chainField.name.c_str());
   1761                     } else if (chainField.javaType == JAVA_TYPE_STRING) {
   1762                         fprintf(out, "    std::vector<%s> %s_vec;\n",
   1763                             cpp_type_name(chainField.javaType), chainField.name.c_str());
   1764                         fprintf(out, "    std::vector<ScopedUtfChars*> scoped_%s_vec;\n",
   1765                             chainField.name.c_str());
   1766                         fprintf(out, "    for (size_t i = 0; i < %s_length; ++i) {\n",
   1767                             chainField.name.c_str());
   1768                         fprintf(out, "        jstring jstr = "
   1769                             "(jstring)env->GetObjectArrayElement(%s, i);\n",
   1770                              chainField.name.c_str());
   1771                         fprintf(out, "        if (jstr == NULL) {\n");
   1772                         fprintf(out, "            %s_vec.push_back(NULL);\n",
   1773                             chainField.name.c_str());
   1774                         fprintf(out, "        } else {\n");
   1775                         fprintf(out, "            ScopedUtfChars* scoped_%s = "
   1776                             "new ScopedUtfChars(env, jstr);\n",
   1777                              chainField.name.c_str());
   1778                         fprintf(out, "            %s_vec.push_back(scoped_%s->c_str());\n",
   1779                                 chainField.name.c_str(), chainField.name.c_str());
   1780                         fprintf(out, "            scoped_%s_vec.push_back(scoped_%s);\n",
   1781                                 chainField.name.c_str(), chainField.name.c_str());
   1782                         fprintf(out, "        }\n");
   1783                         fprintf(out, "    }\n");
   1784                     }
   1785                     fprintf(out, "\n");
   1786                 }
   1787             } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
   1788                 isKeyValuePairAtom = true;
   1789             }
   1790             argIndex++;
   1791         }
   1792         // Emit this to quiet the unused parameter warning if there were no strings or attribution
   1793         // chains.
   1794         if (!hadStringOrChain && !isKeyValuePairAtom) {
   1795             fprintf(out, "    (void)env;\n");
   1796         }
   1797         if (isKeyValuePairAtom) {
   1798             write_key_value_map_jni(out);
   1799         }
   1800 
   1801         // stats_write call
   1802         argIndex = 1;
   1803         fprintf(out, "\n    int ret =  android::util::%s(code",
   1804                 cpp_method_name.c_str());
   1805         for (vector<java_type_t>::const_iterator arg = signature.begin();
   1806                 arg != signature.end(); arg++) {
   1807             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
   1808                 for (auto chainField : attributionDecl.fields) {
   1809                     if (chainField.javaType == JAVA_TYPE_INT) {
   1810                         fprintf(out, ", (const %s*)%s_array, %s_length",
   1811                             cpp_type_name(chainField.javaType),
   1812                             chainField.name.c_str(), chainField.name.c_str());
   1813                     } else if (chainField.javaType == JAVA_TYPE_STRING) {
   1814                         fprintf(out, ", %s_vec", chainField.name.c_str());
   1815                     }
   1816                 }
   1817             } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
   1818                 fprintf(out, ", int32_t_map, int64_t_map, string_map, float_map");
   1819             } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
   1820                 fprintf(out, ", bytesField%d", argIndex);
   1821             } else {
   1822                 const char* argName =
   1823                         (*arg == JAVA_TYPE_STRING) ? "str" : "arg";
   1824                 fprintf(out, ", (%s)%s%d", cpp_type_name(*arg), argName, argIndex);
   1825             }
   1826             argIndex++;
   1827         }
   1828         fprintf(out, ");\n");
   1829         fprintf(out, "\n");
   1830 
   1831         // Clean up strings
   1832         argIndex = 1;
   1833         for (vector<java_type_t>::const_iterator arg = signature.begin();
   1834                 arg != signature.end(); arg++) {
   1835             if (*arg == JAVA_TYPE_STRING) {
   1836                 fprintf(out, "    if (str%d != NULL) {\n", argIndex);
   1837                 fprintf(out, "        env->ReleaseStringUTFChars(arg%d, str%d);\n",
   1838                         argIndex, argIndex);
   1839                 fprintf(out, "    }\n");
   1840             } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
   1841                 fprintf(out, "    if (str%d != NULL) { \n", argIndex);
   1842                 fprintf(out,
   1843                         "        env->ReleaseByteArrayElements(arg%d, "
   1844                         "jbyte_array%d, 0);\n",
   1845                         argIndex, argIndex);
   1846                 fprintf(out, "    }\n");
   1847             } else if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
   1848                 for (auto chainField : attributionDecl.fields) {
   1849                     if (chainField.javaType == JAVA_TYPE_INT) {
   1850                         fprintf(out, "    env->ReleaseIntArrayElements(%s, %s_array, 0);\n",
   1851                             chainField.name.c_str(), chainField.name.c_str());
   1852                     } else if (chainField.javaType == JAVA_TYPE_STRING) {
   1853                         fprintf(out, "    for (size_t i = 0; i < scoped_%s_vec.size(); ++i) {\n",
   1854                             chainField.name.c_str());
   1855                         fprintf(out, "        delete scoped_%s_vec[i];\n", chainField.name.c_str());
   1856                         fprintf(out, "    }\n");
   1857                     }
   1858                 }
   1859             }
   1860             argIndex++;
   1861         }
   1862 
   1863         fprintf(out, "    return ret;\n");
   1864 
   1865         fprintf(out, "}\n");
   1866         fprintf(out, "\n");
   1867     }
   1868 
   1869 
   1870     return 0;
   1871 }
   1872 
   1873 void write_jni_registration(FILE* out, const string& java_method_name,
   1874         const map<vector<java_type_t>, set<string>>& signatures_to_modules,
   1875         const AtomDecl &attributionDecl) {
   1876     for (auto signature_to_modules_it = signatures_to_modules.begin();
   1877             signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
   1878         vector<java_type_t> signature = signature_to_modules_it->first;
   1879         fprintf(out, "    { \"%s\", \"%s\", (void*)%s },\n",
   1880             java_method_name.c_str(),
   1881             jni_function_signature(signature, attributionDecl).c_str(),
   1882             jni_function_name(java_method_name, signature).c_str());
   1883     }
   1884 }
   1885 
   1886 static int
   1887 write_stats_log_jni(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl)
   1888 {
   1889     // Print prelude
   1890     fprintf(out, "// This file is autogenerated\n");
   1891     fprintf(out, "\n");
   1892 
   1893     fprintf(out, "#include <statslog.h>\n");
   1894     fprintf(out, "\n");
   1895     fprintf(out, "#include <nativehelper/JNIHelp.h>\n");
   1896     fprintf(out, "#include <nativehelper/ScopedUtfChars.h>\n");
   1897     fprintf(out, "#include <utils/Vector.h>\n");
   1898     fprintf(out, "#include \"core_jni_helpers.h\"\n");
   1899     fprintf(out, "#include \"jni.h\"\n");
   1900     fprintf(out, "\n");
   1901     fprintf(out, "#define UNUSED  __attribute__((__unused__))\n");
   1902     fprintf(out, "\n");
   1903 
   1904     fprintf(out, "namespace android {\n");
   1905     fprintf(out, "\n");
   1906 
   1907     write_stats_log_jni(out, "write", "stats_write", atoms.signatures_to_modules, attributionDecl);
   1908     write_stats_log_jni(out, "write_non_chained", "stats_write_non_chained",
   1909             atoms.non_chained_signatures_to_modules, attributionDecl);
   1910 
   1911     // Print registration function table
   1912     fprintf(out, "/*\n");
   1913     fprintf(out, " * JNI registration.\n");
   1914     fprintf(out, " */\n");
   1915     fprintf(out, "static const JNINativeMethod gRegisterMethods[] = {\n");
   1916     write_jni_registration(out, "write", atoms.signatures_to_modules, attributionDecl);
   1917     write_jni_registration(out, "write_non_chained", atoms.non_chained_signatures_to_modules,
   1918             attributionDecl);
   1919     fprintf(out, "};\n");
   1920     fprintf(out, "\n");
   1921 
   1922     // Print registration function
   1923     fprintf(out, "int register_android_util_StatsLogInternal(JNIEnv* env) {\n");
   1924     fprintf(out, "    return RegisterMethodsOrDie(\n");
   1925     fprintf(out, "            env,\n");
   1926     fprintf(out, "            \"android/util/StatsLogInternal\",\n");
   1927     fprintf(out, "            gRegisterMethods, NELEM(gRegisterMethods));\n");
   1928     fprintf(out, "}\n");
   1929 
   1930     fprintf(out, "\n");
   1931     fprintf(out, "} // namespace android\n");
   1932     return 0;
   1933 }
   1934 
   1935 static void
   1936 print_usage()
   1937 {
   1938     fprintf(stderr, "usage: stats-log-api-gen OPTIONS\n");
   1939     fprintf(stderr, "\n");
   1940     fprintf(stderr, "OPTIONS\n");
   1941     fprintf(stderr, "  --cpp FILENAME       the header file to output\n");
   1942     fprintf(stderr, "  --header FILENAME    the cpp file to output\n");
   1943     fprintf(stderr, "  --help               this message\n");
   1944     fprintf(stderr, "  --java FILENAME      the java file to output\n");
   1945     fprintf(stderr, "  --jni FILENAME       the jni file to output\n");
   1946     fprintf(stderr, "  --module NAME        optional, module name to generate outputs for\n");
   1947     fprintf(stderr, "  --namespace COMMA,SEP,NAMESPACE   required for cpp/header with module\n");
   1948     fprintf(stderr, "                                    comma separated namespace of the files\n");
   1949     fprintf(stderr, "  --importHeader NAME  required for cpp/jni to say which header to import\n");
   1950     fprintf(stderr, "  --javaPackage PACKAGE             the package for the java file.\n");
   1951     fprintf(stderr, "                                    required for java with module\n");
   1952     fprintf(stderr, "  --javaClass CLASS    the class name of the java class.\n");
   1953     fprintf(stderr, "                       Optional for Java with module.\n");
   1954     fprintf(stderr, "                       Default is \"StatsLogInternal\"\n");}
   1955 
   1956 /**
   1957  * Do the argument parsing and execute the tasks.
   1958  */
   1959 static int
   1960 run(int argc, char const*const* argv)
   1961 {
   1962     string cppFilename;
   1963     string headerFilename;
   1964     string javaFilename;
   1965     string jniFilename;
   1966 
   1967     string moduleName = DEFAULT_MODULE_NAME;
   1968     string cppNamespace = DEFAULT_CPP_NAMESPACE;
   1969     string cppHeaderImport = DEFAULT_CPP_HEADER_IMPORT;
   1970     string javaPackage = DEFAULT_JAVA_PACKAGE;
   1971     string javaClass = DEFAULT_JAVA_CLASS;
   1972 
   1973     int index = 1;
   1974     while (index < argc) {
   1975         if (0 == strcmp("--help", argv[index])) {
   1976             print_usage();
   1977             return 0;
   1978         } else if (0 == strcmp("--cpp", argv[index])) {
   1979             index++;
   1980             if (index >= argc) {
   1981                 print_usage();
   1982                 return 1;
   1983             }
   1984             cppFilename = argv[index];
   1985         } else if (0 == strcmp("--header", argv[index])) {
   1986             index++;
   1987             if (index >= argc) {
   1988                 print_usage();
   1989                 return 1;
   1990             }
   1991             headerFilename = argv[index];
   1992         } else if (0 == strcmp("--java", argv[index])) {
   1993             index++;
   1994             if (index >= argc) {
   1995                 print_usage();
   1996                 return 1;
   1997             }
   1998             javaFilename = argv[index];
   1999         } else if (0 == strcmp("--jni", argv[index])) {
   2000             index++;
   2001             if (index >= argc) {
   2002                 print_usage();
   2003                 return 1;
   2004             }
   2005             jniFilename = argv[index];
   2006         } else if (0 == strcmp("--module", argv[index])) {
   2007             index++;
   2008             if (index >= argc) {
   2009                 print_usage();
   2010                 return 1;
   2011             }
   2012             moduleName = argv[index];
   2013         } else if (0 == strcmp("--namespace", argv[index])) {
   2014             index++;
   2015             if (index >= argc) {
   2016                 print_usage();
   2017                 return 1;
   2018             }
   2019             cppNamespace = argv[index];
   2020         } else if (0 == strcmp("--importHeader", argv[index])) {
   2021             index++;
   2022             if (index >= argc) {
   2023                 print_usage();
   2024                 return 1;
   2025             }
   2026             cppHeaderImport = argv[index];
   2027         } else if (0 == strcmp("--javaPackage", argv[index])) {
   2028             index++;
   2029             if (index >= argc) {
   2030                 print_usage();
   2031                 return 1;
   2032             }
   2033             javaPackage = argv[index];
   2034         } else if (0 == strcmp("--javaClass", argv[index])) {
   2035             index++;
   2036             if (index >= argc) {
   2037                 print_usage();
   2038                 return 1;
   2039             }
   2040             javaClass = argv[index];
   2041         }
   2042         index++;
   2043     }
   2044 
   2045     if (cppFilename.size() == 0
   2046             && headerFilename.size() == 0
   2047             && javaFilename.size() == 0
   2048             && jniFilename.size() == 0) {
   2049         print_usage();
   2050         return 1;
   2051     }
   2052 
   2053     // Collate the parameters
   2054     Atoms atoms;
   2055     int errorCount = collate_atoms(Atom::descriptor(), &atoms);
   2056     if (errorCount != 0) {
   2057         return 1;
   2058     }
   2059 
   2060     AtomDecl attributionDecl;
   2061     vector<java_type_t> attributionSignature;
   2062     collate_atom(android::os::statsd::AttributionNode::descriptor(),
   2063                  &attributionDecl, &attributionSignature);
   2064 
   2065     // Write the .cpp file
   2066     if (cppFilename.size() != 0) {
   2067         FILE* out = fopen(cppFilename.c_str(), "w");
   2068         if (out == NULL) {
   2069             fprintf(stderr, "Unable to open file for write: %s\n", cppFilename.c_str());
   2070             return 1;
   2071         }
   2072         // If this is for a specific module, the namespace must also be provided.
   2073         if (moduleName != DEFAULT_MODULE_NAME && cppNamespace == DEFAULT_CPP_NAMESPACE) {
   2074             fprintf(stderr, "Must supply --namespace if supplying a specific module\n");
   2075             return 1;
   2076         }
   2077         // If this is for a specific module, the header file to import must also be provided.
   2078         if (moduleName != DEFAULT_MODULE_NAME && cppHeaderImport == DEFAULT_CPP_HEADER_IMPORT) {
   2079             fprintf(stderr, "Must supply --headerImport if supplying a specific module\n");
   2080             return 1;
   2081         }
   2082         errorCount = android::stats_log_api_gen::write_stats_log_cpp(
   2083             out, atoms, attributionDecl, moduleName, cppNamespace, cppHeaderImport);
   2084         fclose(out);
   2085     }
   2086 
   2087     // Write the .h file
   2088     if (headerFilename.size() != 0) {
   2089         FILE* out = fopen(headerFilename.c_str(), "w");
   2090         if (out == NULL) {
   2091             fprintf(stderr, "Unable to open file for write: %s\n", headerFilename.c_str());
   2092             return 1;
   2093         }
   2094         // If this is for a specific module, the namespace must also be provided.
   2095         if (moduleName != DEFAULT_MODULE_NAME && cppNamespace == DEFAULT_CPP_NAMESPACE) {
   2096             fprintf(stderr, "Must supply --namespace if supplying a specific module\n");
   2097         }
   2098         errorCount = android::stats_log_api_gen::write_stats_log_header(
   2099             out, atoms, attributionDecl, moduleName, cppNamespace);
   2100         fclose(out);
   2101     }
   2102 
   2103     // Write the .java file
   2104     if (javaFilename.size() != 0) {
   2105         FILE* out = fopen(javaFilename.c_str(), "w");
   2106         if (out == NULL) {
   2107             fprintf(stderr, "Unable to open file for write: %s\n", javaFilename.c_str());
   2108             return 1;
   2109         }
   2110         // If this is for a specific module, the java package must also be provided.
   2111         if (moduleName != DEFAULT_MODULE_NAME && javaPackage== DEFAULT_JAVA_PACKAGE) {
   2112             fprintf(stderr, "Must supply --javaPackage if supplying a specific module\n");
   2113             return 1;
   2114         }
   2115         if (moduleName == DEFAULT_MODULE_NAME) {
   2116             errorCount = android::stats_log_api_gen::write_stats_log_java(
   2117                     out, atoms, attributionDecl);
   2118         } else {
   2119             errorCount = android::stats_log_api_gen::write_stats_log_java_for_module(
   2120                     out, atoms, attributionDecl, moduleName, javaClass, javaPackage);
   2121         }
   2122         fclose(out);
   2123     }
   2124 
   2125     // Write the jni file
   2126     if (jniFilename.size() != 0) {
   2127         FILE* out = fopen(jniFilename.c_str(), "w");
   2128         if (out == NULL) {
   2129             fprintf(stderr, "Unable to open file for write: %s\n", jniFilename.c_str());
   2130             return 1;
   2131         }
   2132         errorCount = android::stats_log_api_gen::write_stats_log_jni(
   2133             out, atoms, attributionDecl);
   2134         fclose(out);
   2135     }
   2136 
   2137     return errorCount;
   2138 }
   2139 
   2140 }
   2141 }
   2142 
   2143 /**
   2144  * Main.
   2145  */
   2146 int
   2147 main(int argc, char const*const* argv)
   2148 {
   2149     GOOGLE_PROTOBUF_VERIFY_VERSION;
   2150 
   2151     return android::stats_log_api_gen::run(argc, argv);
   2152 }
   2153