blob: eb29150fc9f93c9027ae327000844c86b7ce63e5 [file] [log] [blame]
Yao Chend54f9dd2017-10-17 17:37:48 +00001
2
3#include "Collation.h"
4
Stefan Lafonae2df012017-11-14 09:17:21 -08005#include "frameworks/base/cmds/statsd/src/atoms.pb.h"
Yao Chend54f9dd2017-10-17 17:37:48 +00006
7#include <set>
8#include <vector>
9
10#include <getopt.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14
15using namespace google::protobuf;
16using namespace std;
17
18namespace android {
19namespace stats_log_api_gen {
20
Stefan Lafonae2df012017-11-14 09:17:21 -080021using android::os::statsd::Atom;
Yao Chend54f9dd2017-10-17 17:37:48 +000022
23// TODO: Support WorkSources
24
25/**
26 * Turn lower and camel case into upper case with underscores.
27 */
28static string
29make_constant_name(const string& str)
30{
31 string result;
32 const int N = str.size();
33 bool underscore_next = false;
34 for (int i=0; i<N; i++) {
35 char c = str[i];
36 if (c >= 'A' && c <= 'Z') {
37 if (underscore_next) {
38 result += '_';
39 underscore_next = false;
40 }
41 } else if (c >= 'a' && c <= 'z') {
42 c = 'A' + c - 'a';
43 underscore_next = true;
44 } else if (c == '_') {
45 underscore_next = false;
46 }
47 result += c;
48 }
49 return result;
50}
51
52static const char*
53cpp_type_name(java_type_t type)
54{
55 switch (type) {
56 case JAVA_TYPE_BOOLEAN:
57 return "bool";
58 case JAVA_TYPE_INT:
Stefan Lafon9478f352017-10-30 21:20:20 -070059 case JAVA_TYPE_ENUM:
Yao Chend54f9dd2017-10-17 17:37:48 +000060 return "int32_t";
61 case JAVA_TYPE_LONG:
62 return "int64_t";
63 case JAVA_TYPE_FLOAT:
64 return "float";
65 case JAVA_TYPE_DOUBLE:
66 return "double";
67 case JAVA_TYPE_STRING:
68 return "char const*";
69 default:
70 return "UNKNOWN";
71 }
72}
73
74static const char*
75java_type_name(java_type_t type)
76{
77 switch (type) {
78 case JAVA_TYPE_BOOLEAN:
79 return "boolean";
80 case JAVA_TYPE_INT:
Stefan Lafon9478f352017-10-30 21:20:20 -070081 case JAVA_TYPE_ENUM:
Yao Chend54f9dd2017-10-17 17:37:48 +000082 return "int";
83 case JAVA_TYPE_LONG:
84 return "long";
85 case JAVA_TYPE_FLOAT:
86 return "float";
87 case JAVA_TYPE_DOUBLE:
88 return "double";
89 case JAVA_TYPE_STRING:
90 return "java.lang.String";
91 default:
92 return "UNKNOWN";
93 }
94}
95
96static int
97write_stats_log_cpp(FILE* out, const Atoms& atoms)
98{
99 int errorCount;
100
101 // Print prelude
102 fprintf(out, "// This file is autogenerated\n");
103 fprintf(out, "\n");
104
105 fprintf(out, "#include <log/log_event_list.h>\n");
106 fprintf(out, "#include <log/log.h>\n");
107 fprintf(out, "#include <statslog.h>\n");
108 fprintf(out, "\n");
109
110 fprintf(out, "namespace android {\n");
111 fprintf(out, "namespace util {\n");
112
113 // Print write methods
114 fprintf(out, "\n");
115 for (set<vector<java_type_t>>::const_iterator signature = atoms.signatures.begin();
116 signature != atoms.signatures.end(); signature++) {
117 int argIndex;
118
119 fprintf(out, "void\n");
120 fprintf(out, "stats_write(int code");
121 argIndex = 1;
122 for (vector<java_type_t>::const_iterator arg = signature->begin();
123 arg != signature->end(); arg++) {
124 fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
125 argIndex++;
126 }
127 fprintf(out, ")\n");
128
129 fprintf(out, "{\n");
130 argIndex = 1;
131 fprintf(out, " android_log_event_list event(code);\n");
132 for (vector<java_type_t>::const_iterator arg = signature->begin();
133 arg != signature->end(); arg++) {
134 if (*arg == JAVA_TYPE_STRING) {
135 fprintf(out, " if (arg%d == NULL) {\n", argIndex);
136 fprintf(out, " arg%d = \"\";\n", argIndex);
137 fprintf(out, " }\n");
138 }
139 fprintf(out, " event << arg%d;\n", argIndex);
140 argIndex++;
141 }
142
143 fprintf(out, " event.write(LOG_ID_STATS);\n");
144 fprintf(out, "}\n");
145 fprintf(out, "\n");
146 }
147
148 // Print footer
149 fprintf(out, "\n");
150 fprintf(out, "} // namespace util\n");
151 fprintf(out, "} // namespace android\n");
152
153 return 0;
154}
155
156
157static int
158write_stats_log_header(FILE* out, const Atoms& atoms)
159{
160 int errorCount;
161
162 // Print prelude
163 fprintf(out, "// This file is autogenerated\n");
164 fprintf(out, "\n");
165 fprintf(out, "#pragma once\n");
166 fprintf(out, "\n");
167 fprintf(out, "#include <stdint.h>\n");
168 fprintf(out, "\n");
169
170 fprintf(out, "namespace android {\n");
171 fprintf(out, "namespace util {\n");
172 fprintf(out, "\n");
173 fprintf(out, "/*\n");
174 fprintf(out, " * API For logging statistics events.\n");
175 fprintf(out, " */\n");
176 fprintf(out, "\n");
177 fprintf(out, "/**\n");
Stefan Lafon9478f352017-10-30 21:20:20 -0700178 fprintf(out, " * Constants for atom codes.\n");
Yao Chend54f9dd2017-10-17 17:37:48 +0000179 fprintf(out, " */\n");
180 fprintf(out, "enum {\n");
181
182 size_t i = 0;
183 // Print constants
184 for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
185 atom != atoms.decls.end(); atom++) {
186 string constant = make_constant_name(atom->name);
187 fprintf(out, "\n");
188 fprintf(out, " /**\n");
189 fprintf(out, " * %s %s\n", atom->message.c_str(), atom->name.c_str());
190 fprintf(out, " * Usage: stats_write(StatsLog.%s", constant.c_str());
191 for (vector<AtomField>::const_iterator field = atom->fields.begin();
192 field != atom->fields.end(); field++) {
193 fprintf(out, ", %s %s", cpp_type_name(field->javaType), field->name.c_str());
194 }
195 fprintf(out, ");\n");
196 fprintf(out, " */\n");
197 char const* const comma = (i == atoms.decls.size() - 1) ? "" : ",";
198 fprintf(out, " %s = %d%s\n", constant.c_str(), atom->code, comma);
199 i++;
200 }
201 fprintf(out, "\n");
202 fprintf(out, "};\n");
203 fprintf(out, "\n");
204
205 // Print write methods
206 fprintf(out, "//\n");
207 fprintf(out, "// Write methods\n");
208 fprintf(out, "//\n");
209 for (set<vector<java_type_t>>::const_iterator signature = atoms.signatures.begin();
210 signature != atoms.signatures.end(); signature++) {
211
212 fprintf(out, "void stats_write(int code");
213 int argIndex = 1;
214 for (vector<java_type_t>::const_iterator arg = signature->begin();
215 arg != signature->end(); arg++) {
216 fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
217 argIndex++;
218 }
219 fprintf(out, ");\n");
220 }
221
222 fprintf(out, "\n");
223 fprintf(out, "} // namespace util\n");
224 fprintf(out, "} // namespace android\n");
225
226 return 0;
227}
228
229static int
230write_stats_log_java(FILE* out, const Atoms& atoms)
231{
232 int errorCount;
233
234 // Print prelude
235 fprintf(out, "// This file is autogenerated\n");
236 fprintf(out, "\n");
237 fprintf(out, "package android.util;\n");
238 fprintf(out, "\n");
239 fprintf(out, "\n");
240 fprintf(out, "/**\n");
241 fprintf(out, " * API For logging statistics events.\n");
242 fprintf(out, " * @hide\n");
243 fprintf(out, " */\n");
244 fprintf(out, "public final class StatsLog {\n");
Stefan Lafon9478f352017-10-30 21:20:20 -0700245 fprintf(out, " // Constants for atom codes.\n");
Yao Chend54f9dd2017-10-17 17:37:48 +0000246
Stefan Lafon9478f352017-10-30 21:20:20 -0700247 // Print constants for the atom codes.
Yao Chend54f9dd2017-10-17 17:37:48 +0000248 for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
249 atom != atoms.decls.end(); atom++) {
250 string constant = make_constant_name(atom->name);
251 fprintf(out, "\n");
252 fprintf(out, " /**\n");
253 fprintf(out, " * %s %s\n", atom->message.c_str(), atom->name.c_str());
254 fprintf(out, " * Usage: StatsLog.write(StatsLog.%s", constant.c_str());
255 for (vector<AtomField>::const_iterator field = atom->fields.begin();
256 field != atom->fields.end(); field++) {
257 fprintf(out, ", %s %s", java_type_name(field->javaType), field->name.c_str());
258 }
259 fprintf(out, ");\n");
260 fprintf(out, " */\n");
261 fprintf(out, " public static final int %s = %d;\n", constant.c_str(), atom->code);
262 }
263 fprintf(out, "\n");
264
Stefan Lafon9478f352017-10-30 21:20:20 -0700265 // Print constants for the enum values.
266 fprintf(out, " // Constants for enum values.\n\n");
267 for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
268 atom != atoms.decls.end(); atom++) {
269 for (vector<AtomField>::const_iterator field = atom->fields.begin();
270 field != atom->fields.end(); field++) {
271 if (field->javaType == JAVA_TYPE_ENUM) {
272 fprintf(out, " // Values for %s.%s\n", atom->message.c_str(), field->name.c_str());
273 for (map<int, string>::const_iterator value = field->enumValues.begin();
274 value != field->enumValues.end(); value++) {
275 fprintf(out, " public static final int %s__%s__%s = %d;\n",
276 make_constant_name(atom->message).c_str(),
277 make_constant_name(field->name).c_str(),
278 make_constant_name(value->second).c_str(),
279 value->first);
280 }
281 fprintf(out, "\n");
282 }
283 }
284 }
285
Yao Chend54f9dd2017-10-17 17:37:48 +0000286 // Print write methods
287 fprintf(out, " // Write methods\n");
288 for (set<vector<java_type_t>>::const_iterator signature = atoms.signatures.begin();
289 signature != atoms.signatures.end(); signature++) {
290 fprintf(out, " public static native void write(int code");
291 int argIndex = 1;
292 for (vector<java_type_t>::const_iterator arg = signature->begin();
293 arg != signature->end(); arg++) {
294 fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
295 argIndex++;
296 }
297 fprintf(out, ");\n");
298 }
299
300 fprintf(out, "}\n");
301
302 return 0;
303}
304
305static const char*
306jni_type_name(java_type_t type)
307{
308 switch (type) {
309 case JAVA_TYPE_BOOLEAN:
310 return "jboolean";
311 case JAVA_TYPE_INT:
Stefan Lafon9478f352017-10-30 21:20:20 -0700312 case JAVA_TYPE_ENUM:
Yao Chend54f9dd2017-10-17 17:37:48 +0000313 return "jint";
314 case JAVA_TYPE_LONG:
315 return "jlong";
316 case JAVA_TYPE_FLOAT:
317 return "jfloat";
318 case JAVA_TYPE_DOUBLE:
319 return "jdouble";
320 case JAVA_TYPE_STRING:
321 return "jstring";
322 default:
323 return "UNKNOWN";
324 }
325}
326
327static string
328jni_function_name(const vector<java_type_t>& signature)
329{
330 string result("StatsLog_write");
331 for (vector<java_type_t>::const_iterator arg = signature.begin();
332 arg != signature.end(); arg++) {
333 switch (*arg) {
334 case JAVA_TYPE_BOOLEAN:
335 result += "_boolean";
336 break;
337 case JAVA_TYPE_INT:
Stefan Lafon9478f352017-10-30 21:20:20 -0700338 case JAVA_TYPE_ENUM:
Yao Chend54f9dd2017-10-17 17:37:48 +0000339 result += "_int";
340 break;
341 case JAVA_TYPE_LONG:
342 result += "_long";
343 break;
344 case JAVA_TYPE_FLOAT:
345 result += "_float";
346 break;
347 case JAVA_TYPE_DOUBLE:
348 result += "_double";
349 break;
350 case JAVA_TYPE_STRING:
351 result += "_String";
352 break;
353 default:
354 result += "_UNKNOWN";
355 break;
356 }
357 }
358 return result;
359}
360
361static const char*
362java_type_signature(java_type_t type)
363{
364 switch (type) {
365 case JAVA_TYPE_BOOLEAN:
366 return "Z";
367 case JAVA_TYPE_INT:
Stefan Lafon9478f352017-10-30 21:20:20 -0700368 case JAVA_TYPE_ENUM:
Yao Chend54f9dd2017-10-17 17:37:48 +0000369 return "I";
370 case JAVA_TYPE_LONG:
371 return "J";
372 case JAVA_TYPE_FLOAT:
373 return "F";
374 case JAVA_TYPE_DOUBLE:
375 return "D";
376 case JAVA_TYPE_STRING:
377 return "Ljava/lang/String;";
378 default:
379 return "UNKNOWN";
380 }
381}
382
383static string
384jni_function_signature(const vector<java_type_t>& signature)
385{
386 string result("(I");
387 for (vector<java_type_t>::const_iterator arg = signature.begin();
388 arg != signature.end(); arg++) {
389 result += java_type_signature(*arg);
390 }
391 result += ")V";
392 return result;
393}
394
395static int
396write_stats_log_jni(FILE* out, const Atoms& atoms)
397{
398 int errorCount;
399
400 // Print prelude
401 fprintf(out, "// This file is autogenerated\n");
402 fprintf(out, "\n");
403
404 fprintf(out, "#include <statslog.h>\n");
405 fprintf(out, "\n");
406 fprintf(out, "#include <nativehelper/JNIHelp.h>\n");
407 fprintf(out, "#include \"core_jni_helpers.h\"\n");
408 fprintf(out, "#include \"jni.h\"\n");
409 fprintf(out, "\n");
410 fprintf(out, "#define UNUSED __attribute__((__unused__))\n");
411 fprintf(out, "\n");
412
413 fprintf(out, "namespace android {\n");
414 fprintf(out, "\n");
415
416 // Print write methods
417 for (set<vector<java_type_t>>::const_iterator signature = atoms.signatures.begin();
418 signature != atoms.signatures.end(); signature++) {
419 int argIndex;
420
421 fprintf(out, "static void\n");
422 fprintf(out, "%s(JNIEnv* env, jobject clazz UNUSED, jint code",
423 jni_function_name(*signature).c_str());
424 argIndex = 1;
425 for (vector<java_type_t>::const_iterator arg = signature->begin();
426 arg != signature->end(); arg++) {
427 fprintf(out, ", %s arg%d", jni_type_name(*arg), argIndex);
428 argIndex++;
429 }
430 fprintf(out, ")\n");
431
432 fprintf(out, "{\n");
433
434 // Prepare strings
435 argIndex = 1;
436 bool hadString = false;
437 for (vector<java_type_t>::const_iterator arg = signature->begin();
438 arg != signature->end(); arg++) {
439 if (*arg == JAVA_TYPE_STRING) {
440 fprintf(out, " const char* str%d;\n", argIndex);
441 fprintf(out, " if (arg%d != NULL) {\n", argIndex);
442 fprintf(out, " str%d = env->GetStringUTFChars(arg%d, NULL);\n",
443 argIndex, argIndex);
444 fprintf(out, " } else {\n");
445 fprintf(out, " str%d = NULL;\n", argIndex);
446 fprintf(out, " }\n");
447 hadString = true;
448 }
449 argIndex++;
450 }
451
452 // Emit this to quiet the unused parameter warning if there were no strings.
453 if (!hadString) {
454 fprintf(out, " (void)env;\n");
455 }
456
457 // stats_write call
458 argIndex = 1;
459 fprintf(out, " android::util::stats_write(code");
460 for (vector<java_type_t>::const_iterator arg = signature->begin();
461 arg != signature->end(); arg++) {
462 const char* argName = (*arg == JAVA_TYPE_STRING) ? "str" : "arg";
463 fprintf(out, ", (%s)%s%d", cpp_type_name(*arg), argName, argIndex);
464 argIndex++;
465 }
466 fprintf(out, ");\n");
467
468 // Clean up strings
469 argIndex = 1;
470 for (vector<java_type_t>::const_iterator arg = signature->begin();
471 arg != signature->end(); arg++) {
472 if (*arg == JAVA_TYPE_STRING) {
473 fprintf(out, " if (str%d != NULL) {\n", argIndex);
474 fprintf(out, " env->ReleaseStringUTFChars(arg%d, str%d);\n",
475 argIndex, argIndex);
476 fprintf(out, " }\n");
477 }
478 argIndex++;
479 }
480
481 fprintf(out, "}\n");
482 fprintf(out, "\n");
483 }
484
485 // Print registration function table
486 fprintf(out, "/*\n");
487 fprintf(out, " * JNI registration.\n");
488 fprintf(out, " */\n");
489 fprintf(out, "static const JNINativeMethod gRegisterMethods[] = {\n");
490 for (set<vector<java_type_t>>::const_iterator signature = atoms.signatures.begin();
491 signature != atoms.signatures.end(); signature++) {
492 fprintf(out, " { \"write\", \"%s\", (void*)%s },\n",
493 jni_function_signature(*signature).c_str(),
494 jni_function_name(*signature).c_str());
495 }
496 fprintf(out, "};\n");
497 fprintf(out, "\n");
498
499 // Print registration function
500 fprintf(out, "int register_android_util_StatsLog(JNIEnv* env) {\n");
501 fprintf(out, " return RegisterMethodsOrDie(\n");
502 fprintf(out, " env,\n");
503 fprintf(out, " \"android/util/StatsLog\",\n");
504 fprintf(out, " gRegisterMethods, NELEM(gRegisterMethods));\n");
505 fprintf(out, "}\n");
506
507 fprintf(out, "\n");
508 fprintf(out, "} // namespace android\n");
509
510 return 0;
511}
512
513
514static void
515print_usage()
516{
517 fprintf(stderr, "usage: stats-log-api-gen OPTIONS\n");
518 fprintf(stderr, "\n");
519 fprintf(stderr, "OPTIONS\n");
520 fprintf(stderr, " --cpp FILENAME the header file to output\n");
521 fprintf(stderr, " --header FILENAME the cpp file to output\n");
522 fprintf(stderr, " --help this message\n");
523 fprintf(stderr, " --java FILENAME the java file to output\n");
524 fprintf(stderr, " --jni FILENAME the jni file to output\n");
525}
526
527/**
528 * Do the argument parsing and execute the tasks.
529 */
530static int
531run(int argc, char const*const* argv)
532{
533 string cppFilename;
534 string headerFilename;
535 string javaFilename;
536 string jniFilename;
537
538 int index = 1;
539 while (index < argc) {
540 if (0 == strcmp("--help", argv[index])) {
541 print_usage();
542 return 0;
543 } else if (0 == strcmp("--cpp", argv[index])) {
544 index++;
545 if (index >= argc) {
546 print_usage();
547 return 1;
548 }
549 cppFilename = argv[index];
550 } else if (0 == strcmp("--header", argv[index])) {
551 index++;
552 if (index >= argc) {
553 print_usage();
554 return 1;
555 }
556 headerFilename = argv[index];
557 } else if (0 == strcmp("--java", argv[index])) {
558 index++;
559 if (index >= argc) {
560 print_usage();
561 return 1;
562 }
563 javaFilename = argv[index];
564 } else if (0 == strcmp("--jni", argv[index])) {
565 index++;
566 if (index >= argc) {
567 print_usage();
568 return 1;
569 }
570 jniFilename = argv[index];
571 }
572 index++;
573 }
574
575 if (cppFilename.size() == 0
576 && headerFilename.size() == 0
577 && javaFilename.size() == 0
578 && jniFilename.size() == 0) {
579 print_usage();
580 return 1;
581 }
582
583 // Collate the parameters
584 Atoms atoms;
Stefan Lafonae2df012017-11-14 09:17:21 -0800585 int errorCount = collate_atoms(Atom::descriptor(), &atoms);
Yao Chend54f9dd2017-10-17 17:37:48 +0000586 if (errorCount != 0) {
587 return 1;
588 }
589
590 // Write the .cpp file
591 if (cppFilename.size() != 0) {
592 FILE* out = fopen(cppFilename.c_str(), "w");
593 if (out == NULL) {
594 fprintf(stderr, "Unable to open file for write: %s\n", cppFilename.c_str());
595 return 1;
596 }
597 errorCount = android::stats_log_api_gen::write_stats_log_cpp(out, atoms);
598 fclose(out);
599 }
600
601 // Write the .h file
602 if (headerFilename.size() != 0) {
603 FILE* out = fopen(headerFilename.c_str(), "w");
604 if (out == NULL) {
605 fprintf(stderr, "Unable to open file for write: %s\n", headerFilename.c_str());
606 return 1;
607 }
608 errorCount = android::stats_log_api_gen::write_stats_log_header(out, atoms);
609 fclose(out);
610 }
611
612 // Write the .java file
613 if (javaFilename.size() != 0) {
614 FILE* out = fopen(javaFilename.c_str(), "w");
615 if (out == NULL) {
616 fprintf(stderr, "Unable to open file for write: %s\n", javaFilename.c_str());
617 return 1;
618 }
619 errorCount = android::stats_log_api_gen::write_stats_log_java(out, atoms);
620 fclose(out);
621 }
622
623 // Write the jni file
624 if (jniFilename.size() != 0) {
625 FILE* out = fopen(jniFilename.c_str(), "w");
626 if (out == NULL) {
627 fprintf(stderr, "Unable to open file for write: %s\n", jniFilename.c_str());
628 return 1;
629 }
630 errorCount = android::stats_log_api_gen::write_stats_log_jni(out, atoms);
631 fclose(out);
632 }
633
634 return 0;
635}
636
637}
638}
639
640/**
641 * Main.
642 */
643int
644main(int argc, char const*const* argv)
645{
646 GOOGLE_PROTOBUF_VERIFY_VERSION;
647
648 return android::stats_log_api_gen::run(argc, argv);
649}