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