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
make_constant_name(const string & str)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*
cpp_type_name(java_type_t type)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*
java_type_name(java_type_t type)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
write_stats_log_cpp(FILE * out,const Atoms & atoms,const AtomDecl & attributionDecl)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
build_non_chained_decl_map(const Atoms & atoms,std::map<int,set<AtomDecl>::const_iterator> * decl_map)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
write_cpp_usage(FILE * out,const string & method_name,const string & atom_code_name,const AtomDecl & atom,const AtomDecl & attributionDecl)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
write_cpp_method_header(FILE * out,const string & method_name,const set<vector<java_type_t>> & signatures,const AtomDecl & attributionDecl)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
write_stats_log_header(FILE * out,const Atoms & atoms,const AtomDecl & attributionDecl)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
write_java_usage(FILE * out,const string & method_name,const string & atom_code_name,const AtomDecl & atom,const AtomDecl & attributionDecl)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
write_java_method(FILE * out,const string & method_name,const set<vector<java_type_t>> & signatures,const AtomDecl & attributionDecl)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
write_stats_log_java(FILE * out,const Atoms & atoms,const AtomDecl & attributionDecl)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*
jni_type_name(java_type_t type)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*
jni_array_type_name(java_type_t type)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
jni_function_name(const string & method_name,const vector<java_type_t> & signature)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*
java_type_signature(java_type_t type)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
jni_function_signature(const vector<java_type_t> & signature,const AtomDecl & attributionDecl)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
write_stats_log_jni(FILE * out,const string & java_method_name,const string & cpp_method_name,const set<vector<java_type_t>> & signatures,const AtomDecl & attributionDecl)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
write_jni_registration(FILE * out,const string & java_method_name,const set<vector<java_type_t>> & signatures,const AtomDecl & attributionDecl)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
write_stats_log_jni(FILE * out,const Atoms & atoms,const AtomDecl & attributionDecl)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
print_usage()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
run(int argc,char const * const * argv)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
main(int argc,char const * const * argv)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