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