blob: 8183a3fbe15dbb44427a23510ec0b15dcb40ae54 [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
Yao Chenb3561512017-11-21 18:07:17 -080021const int PULL_ATOM_START_ID = 1000;
22
23int maxPushedAtomId = 2;
24
Stefan Lafonae2df012017-11-14 09:17:21 -080025using android::os::statsd::Atom;
Yao Chend54f9dd2017-10-17 17:37:48 +000026
Yao Chend54f9dd2017-10-17 17:37:48 +000027/**
28 * Turn lower and camel case into upper case with underscores.
29 */
30static string
31make_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
54static const char*
55cpp_type_name(java_type_t type)
56{
57 switch (type) {
58 case JAVA_TYPE_BOOLEAN:
59 return "bool";
60 case JAVA_TYPE_INT:
Stefan Lafon9478f352017-10-30 21:20:20 -070061 case JAVA_TYPE_ENUM:
Yao Chend54f9dd2017-10-17 17:37:48 +000062 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
76static const char*
77java_type_name(java_type_t type)
78{
79 switch (type) {
80 case JAVA_TYPE_BOOLEAN:
81 return "boolean";
82 case JAVA_TYPE_INT:
Stefan Lafon9478f352017-10-30 21:20:20 -070083 case JAVA_TYPE_ENUM:
Yao Chend54f9dd2017-10-17 17:37:48 +000084 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
Yangster-mac7604aea2017-12-11 22:55:49 -080098static int write_stats_log_cpp(FILE *out, const Atoms &atoms,
99 const AtomDecl &attributionDecl) {
Yao Chend54f9dd2017-10-17 17:37:48 +0000100 // Print prelude
101 fprintf(out, "// This file is autogenerated\n");
102 fprintf(out, "\n");
103
Yangster-mac7604aea2017-12-11 22:55:49 -0800104 fprintf(out, "#include <exception>\n");
Yao Chend54f9dd2017-10-17 17:37:48 +0000105 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");
Yao Chen80235402017-11-13 20:42:25 -0800112 fprintf(out, "// the single event tag id for all stats logs\n");
113 fprintf(out, "const static int kStatsEventTag = 1937006964;\n");
Yao Chend54f9dd2017-10-17 17:37:48 +0000114
115 // Print write methods
116 fprintf(out, "\n");
117 for (set<vector<java_type_t>>::const_iterator signature = atoms.signatures.begin();
Yangster-mac7604aea2017-12-11 22:55:49 -0800118 signature != atoms.signatures.end(); signature++) {
Yao Chend54f9dd2017-10-17 17:37:48 +0000119 int argIndex;
120
121 fprintf(out, "void\n");
Yao Chen80235402017-11-13 20:42:25 -0800122 fprintf(out, "stats_write(int32_t code");
Yao Chend54f9dd2017-10-17 17:37:48 +0000123 argIndex = 1;
124 for (vector<java_type_t>::const_iterator arg = signature->begin();
Yangster-mac7604aea2017-12-11 22:55:49 -0800125 arg != signature->end(); arg++) {
126 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
127 for (auto chainField : attributionDecl.fields) {
128 if (chainField.javaType == JAVA_TYPE_STRING) {
129 fprintf(out, ", const std::vector<%s>& %s",
130 cpp_type_name(chainField.javaType),
131 chainField.name.c_str());
132 } else {
133 fprintf(out, ", const %s* %s, size_t %s_length",
134 cpp_type_name(chainField.javaType),
135 chainField.name.c_str(), chainField.name.c_str());
136 }
137 }
138 } else {
139 fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
140 }
Yao Chend54f9dd2017-10-17 17:37:48 +0000141 argIndex++;
142 }
143 fprintf(out, ")\n");
144
145 fprintf(out, "{\n");
146 argIndex = 1;
Yao Chen80235402017-11-13 20:42:25 -0800147 fprintf(out, " android_log_event_list event(kStatsEventTag);\n");
Yangster-mac7604aea2017-12-11 22:55:49 -0800148 fprintf(out, " event << code;\n\n");
Yao Chend54f9dd2017-10-17 17:37:48 +0000149 for (vector<java_type_t>::const_iterator arg = signature->begin();
Yangster-mac7604aea2017-12-11 22:55:49 -0800150 arg != signature->end(); arg++) {
151 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
152 for (const auto &chainField : attributionDecl.fields) {
153 if (chainField.javaType == JAVA_TYPE_STRING) {
154 fprintf(out, " if (%s_length != %s.size()) {\n",
155 attributionDecl.fields.front().name.c_str(), chainField.name.c_str());
156 fprintf(out, " throw std::invalid_argument(\"attribution fields with"
157 " diff length: %s vs %s\");\n",
158 attributionDecl.fields.front().name.c_str(),
159 chainField.name.c_str());
160 fprintf(out, " return;\n");
161 fprintf(out, " }\n");
162 }
163 }
164 fprintf(out, "\n event.begin();\n");
165 fprintf(out, " for (size_t i = 0; i < %s_length; ++i) {\n",
166 attributionDecl.fields.front().name.c_str());
167 fprintf(out, " event.begin();\n");
168 for (const auto &chainField : attributionDecl.fields) {
169 fprintf(out, " event << %s[i];\n", chainField.name.c_str());
170 }
171 fprintf(out, " event.end();\n");
Yao Chend54f9dd2017-10-17 17:37:48 +0000172 fprintf(out, " }\n");
Yangster-mac7604aea2017-12-11 22:55:49 -0800173 fprintf(out, " event.end();\n\n");
174 } else {
175 if (*arg == JAVA_TYPE_STRING) {
176 fprintf(out, " if (arg%d == NULL) {\n", argIndex);
177 fprintf(out, " arg%d = \"\";\n", argIndex);
178 fprintf(out, " }\n");
179 }
180 fprintf(out, " event << arg%d;\n", argIndex);
Yao Chend54f9dd2017-10-17 17:37:48 +0000181 }
Yao Chend54f9dd2017-10-17 17:37:48 +0000182 argIndex++;
183 }
184
185 fprintf(out, " event.write(LOG_ID_STATS);\n");
186 fprintf(out, "}\n");
187 fprintf(out, "\n");
188 }
189
190 // Print footer
191 fprintf(out, "\n");
192 fprintf(out, "} // namespace util\n");
193 fprintf(out, "} // namespace android\n");
194
195 return 0;
196}
197
198
199static int
Yangster-mac7604aea2017-12-11 22:55:49 -0800200write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl)
Yao Chend54f9dd2017-10-17 17:37:48 +0000201{
Yao Chend54f9dd2017-10-17 17:37:48 +0000202 // Print prelude
203 fprintf(out, "// This file is autogenerated\n");
204 fprintf(out, "\n");
205 fprintf(out, "#pragma once\n");
206 fprintf(out, "\n");
207 fprintf(out, "#include <stdint.h>\n");
Yangster-mac7604aea2017-12-11 22:55:49 -0800208 fprintf(out, "#include <vector>\n");
Yao Chend54f9dd2017-10-17 17:37:48 +0000209 fprintf(out, "\n");
210
211 fprintf(out, "namespace android {\n");
212 fprintf(out, "namespace util {\n");
213 fprintf(out, "\n");
214 fprintf(out, "/*\n");
215 fprintf(out, " * API For logging statistics events.\n");
216 fprintf(out, " */\n");
217 fprintf(out, "\n");
218 fprintf(out, "/**\n");
Stefan Lafon9478f352017-10-30 21:20:20 -0700219 fprintf(out, " * Constants for atom codes.\n");
Yao Chend54f9dd2017-10-17 17:37:48 +0000220 fprintf(out, " */\n");
221 fprintf(out, "enum {\n");
222
223 size_t i = 0;
224 // Print constants
225 for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
Yangster-mac7604aea2017-12-11 22:55:49 -0800226 atom != atoms.decls.end(); atom++) {
Yao Chend54f9dd2017-10-17 17:37:48 +0000227 string constant = make_constant_name(atom->name);
228 fprintf(out, "\n");
229 fprintf(out, " /**\n");
230 fprintf(out, " * %s %s\n", atom->message.c_str(), atom->name.c_str());
231 fprintf(out, " * Usage: stats_write(StatsLog.%s", constant.c_str());
232 for (vector<AtomField>::const_iterator field = atom->fields.begin();
233 field != atom->fields.end(); field++) {
Yangster-mac7604aea2017-12-11 22:55:49 -0800234 if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
235 for (auto chainField : attributionDecl.fields) {
236 if (chainField.javaType == JAVA_TYPE_STRING) {
237 fprintf(out, ", const std::vector<%s>& %s",
238 cpp_type_name(chainField.javaType),
239 chainField.name.c_str());
240 } else {
241 fprintf(out, ", const %s* %s, size_t %s_length",
242 cpp_type_name(chainField.javaType),
243 chainField.name.c_str(), chainField.name.c_str());
244 }
245 }
246 } else {
247 fprintf(out, ", %s %s", cpp_type_name(field->javaType), field->name.c_str());
248 }
Yao Chend54f9dd2017-10-17 17:37:48 +0000249 }
250 fprintf(out, ");\n");
251 fprintf(out, " */\n");
252 char const* const comma = (i == atoms.decls.size() - 1) ? "" : ",";
253 fprintf(out, " %s = %d%s\n", constant.c_str(), atom->code, comma);
Yao Chenb3561512017-11-21 18:07:17 -0800254 if (atom->code < PULL_ATOM_START_ID && atom->code > maxPushedAtomId) {
255 maxPushedAtomId = atom->code;
256 }
Yao Chend54f9dd2017-10-17 17:37:48 +0000257 i++;
258 }
259 fprintf(out, "\n");
260 fprintf(out, "};\n");
261 fprintf(out, "\n");
262
Yangster-mac7604aea2017-12-11 22:55:49 -0800263 fprintf(out, "const static int kMaxPushedAtomId = %d;\n\n", maxPushedAtomId);
Yao Chenb3561512017-11-21 18:07:17 -0800264
Yao Chend54f9dd2017-10-17 17:37:48 +0000265 // Print write methods
266 fprintf(out, "//\n");
267 fprintf(out, "// Write methods\n");
268 fprintf(out, "//\n");
269 for (set<vector<java_type_t>>::const_iterator signature = atoms.signatures.begin();
270 signature != atoms.signatures.end(); signature++) {
Yao Chen80235402017-11-13 20:42:25 -0800271 fprintf(out, "void stats_write(int32_t code ");
Yao Chend54f9dd2017-10-17 17:37:48 +0000272 int argIndex = 1;
273 for (vector<java_type_t>::const_iterator arg = signature->begin();
Yangster-mac7604aea2017-12-11 22:55:49 -0800274 arg != signature->end(); arg++) {
275 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
276 for (auto chainField : attributionDecl.fields) {
277 if (chainField.javaType == JAVA_TYPE_STRING) {
278 fprintf(out, ", const std::vector<%s>& %s",
279 cpp_type_name(chainField.javaType), chainField.name.c_str());
280 } else {
281 fprintf(out, ", const %s* %s, size_t %s_length",
282 cpp_type_name(chainField.javaType),
283 chainField.name.c_str(), chainField.name.c_str());
284 }
285 }
286 } else {
287 fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
288 }
Yao Chend54f9dd2017-10-17 17:37:48 +0000289 argIndex++;
290 }
291 fprintf(out, ");\n");
292 }
293
294 fprintf(out, "\n");
295 fprintf(out, "} // namespace util\n");
296 fprintf(out, "} // namespace android\n");
297
298 return 0;
299}
300
301static int
Yangster-mac7604aea2017-12-11 22:55:49 -0800302write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl)
Yao Chend54f9dd2017-10-17 17:37:48 +0000303{
Yao Chend54f9dd2017-10-17 17:37:48 +0000304 // Print prelude
305 fprintf(out, "// This file is autogenerated\n");
306 fprintf(out, "\n");
307 fprintf(out, "package android.util;\n");
308 fprintf(out, "\n");
309 fprintf(out, "\n");
310 fprintf(out, "/**\n");
311 fprintf(out, " * API For logging statistics events.\n");
312 fprintf(out, " * @hide\n");
313 fprintf(out, " */\n");
314 fprintf(out, "public final class StatsLog {\n");
Stefan Lafon9478f352017-10-30 21:20:20 -0700315 fprintf(out, " // Constants for atom codes.\n");
Yao Chend54f9dd2017-10-17 17:37:48 +0000316
Stefan Lafon9478f352017-10-30 21:20:20 -0700317 // Print constants for the atom codes.
Yao Chend54f9dd2017-10-17 17:37:48 +0000318 for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
319 atom != atoms.decls.end(); atom++) {
320 string constant = make_constant_name(atom->name);
321 fprintf(out, "\n");
322 fprintf(out, " /**\n");
323 fprintf(out, " * %s %s\n", atom->message.c_str(), atom->name.c_str());
324 fprintf(out, " * Usage: StatsLog.write(StatsLog.%s", constant.c_str());
325 for (vector<AtomField>::const_iterator field = atom->fields.begin();
Yangster-mac7604aea2017-12-11 22:55:49 -0800326 field != atom->fields.end(); field++) {
327 if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
328 for (auto chainField : attributionDecl.fields) {
329 fprintf(out, ", %s[] %s",
330 java_type_name(chainField.javaType), chainField.name.c_str());
331 }
332 } else {
333 fprintf(out, ", %s %s", java_type_name(field->javaType), field->name.c_str());
334 }
Yao Chend54f9dd2017-10-17 17:37:48 +0000335 }
336 fprintf(out, ");\n");
337 fprintf(out, " */\n");
338 fprintf(out, " public static final int %s = %d;\n", constant.c_str(), atom->code);
339 }
340 fprintf(out, "\n");
341
Stefan Lafon9478f352017-10-30 21:20:20 -0700342 // Print constants for the enum values.
343 fprintf(out, " // Constants for enum values.\n\n");
344 for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
Yangster-mac7604aea2017-12-11 22:55:49 -0800345 atom != atoms.decls.end(); atom++) {
Stefan Lafon9478f352017-10-30 21:20:20 -0700346 for (vector<AtomField>::const_iterator field = atom->fields.begin();
Yangster-mac7604aea2017-12-11 22:55:49 -0800347 field != atom->fields.end(); field++) {
348 if (field->javaType == JAVA_TYPE_ENUM) {
349 fprintf(out, " // Values for %s.%s\n", atom->message.c_str(),
350 field->name.c_str());
351 for (map<int, string>::const_iterator value = field->enumValues.begin();
352 value != field->enumValues.end(); value++) {
353 fprintf(out, " public static final int %s__%s__%s = %d;\n",
354 make_constant_name(atom->message).c_str(),
355 make_constant_name(field->name).c_str(),
356 make_constant_name(value->second).c_str(),
357 value->first);
358 }
359 fprintf(out, "\n");
Stefan Lafon9478f352017-10-30 21:20:20 -0700360 }
Stefan Lafon9478f352017-10-30 21:20:20 -0700361 }
362 }
363
Yao Chend54f9dd2017-10-17 17:37:48 +0000364 // Print write methods
365 fprintf(out, " // Write methods\n");
366 for (set<vector<java_type_t>>::const_iterator signature = atoms.signatures.begin();
Yangster-mac7604aea2017-12-11 22:55:49 -0800367 signature != atoms.signatures.end(); signature++) {
Yao Chend54f9dd2017-10-17 17:37:48 +0000368 fprintf(out, " public static native void write(int code");
369 int argIndex = 1;
370 for (vector<java_type_t>::const_iterator arg = signature->begin();
Yangster-mac7604aea2017-12-11 22:55:49 -0800371 arg != signature->end(); arg++) {
372 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
373 for (auto chainField : attributionDecl.fields) {
374 fprintf(out, ", %s[] %s",
375 java_type_name(chainField.javaType), chainField.name.c_str());
376 }
377 } else {
378 fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
379 }
Yao Chend54f9dd2017-10-17 17:37:48 +0000380 argIndex++;
381 }
382 fprintf(out, ");\n");
383 }
384
385 fprintf(out, "}\n");
386
387 return 0;
388}
389
390static const char*
391jni_type_name(java_type_t type)
392{
393 switch (type) {
394 case JAVA_TYPE_BOOLEAN:
395 return "jboolean";
396 case JAVA_TYPE_INT:
Stefan Lafon9478f352017-10-30 21:20:20 -0700397 case JAVA_TYPE_ENUM:
Yao Chend54f9dd2017-10-17 17:37:48 +0000398 return "jint";
399 case JAVA_TYPE_LONG:
400 return "jlong";
401 case JAVA_TYPE_FLOAT:
402 return "jfloat";
403 case JAVA_TYPE_DOUBLE:
404 return "jdouble";
405 case JAVA_TYPE_STRING:
406 return "jstring";
407 default:
408 return "UNKNOWN";
409 }
410}
411
Yangster-mac7604aea2017-12-11 22:55:49 -0800412static const char*
413jni_array_type_name(java_type_t type)
414{
415 switch (type) {
416 case JAVA_TYPE_INT:
417 return "jintArray";
418 case JAVA_TYPE_STRING:
419 return "jobjectArray";
420 default:
421 return "UNKNOWN";
422 }
423}
424
Yao Chend54f9dd2017-10-17 17:37:48 +0000425static string
426jni_function_name(const vector<java_type_t>& signature)
427{
428 string result("StatsLog_write");
429 for (vector<java_type_t>::const_iterator arg = signature.begin();
Yangster-mac7604aea2017-12-11 22:55:49 -0800430 arg != signature.end(); arg++) {
Yao Chend54f9dd2017-10-17 17:37:48 +0000431 switch (*arg) {
432 case JAVA_TYPE_BOOLEAN:
433 result += "_boolean";
434 break;
435 case JAVA_TYPE_INT:
Stefan Lafon9478f352017-10-30 21:20:20 -0700436 case JAVA_TYPE_ENUM:
Yao Chend54f9dd2017-10-17 17:37:48 +0000437 result += "_int";
438 break;
439 case JAVA_TYPE_LONG:
440 result += "_long";
441 break;
442 case JAVA_TYPE_FLOAT:
443 result += "_float";
444 break;
445 case JAVA_TYPE_DOUBLE:
446 result += "_double";
447 break;
448 case JAVA_TYPE_STRING:
449 result += "_String";
450 break;
Yangster-mac7604aea2017-12-11 22:55:49 -0800451 case JAVA_TYPE_ATTRIBUTION_CHAIN:
452 result += "_AttributionChain";
453 break;
Yao Chend54f9dd2017-10-17 17:37:48 +0000454 default:
455 result += "_UNKNOWN";
456 break;
457 }
458 }
459 return result;
460}
461
462static const char*
463java_type_signature(java_type_t type)
464{
465 switch (type) {
466 case JAVA_TYPE_BOOLEAN:
467 return "Z";
468 case JAVA_TYPE_INT:
Stefan Lafon9478f352017-10-30 21:20:20 -0700469 case JAVA_TYPE_ENUM:
Yao Chend54f9dd2017-10-17 17:37:48 +0000470 return "I";
471 case JAVA_TYPE_LONG:
472 return "J";
473 case JAVA_TYPE_FLOAT:
474 return "F";
475 case JAVA_TYPE_DOUBLE:
476 return "D";
477 case JAVA_TYPE_STRING:
478 return "Ljava/lang/String;";
479 default:
480 return "UNKNOWN";
481 }
482}
483
484static string
Yangster-mac7604aea2017-12-11 22:55:49 -0800485jni_function_signature(const vector<java_type_t>& signature, const AtomDecl &attributionDecl)
Yao Chend54f9dd2017-10-17 17:37:48 +0000486{
487 string result("(I");
488 for (vector<java_type_t>::const_iterator arg = signature.begin();
Yangster-mac7604aea2017-12-11 22:55:49 -0800489 arg != signature.end(); arg++) {
490 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
491 for (auto chainField : attributionDecl.fields) {
492 result += "[";
493 result += java_type_signature(chainField.javaType);
494 }
495 } else {
496 result += java_type_signature(*arg);
497 }
Yao Chend54f9dd2017-10-17 17:37:48 +0000498 }
499 result += ")V";
500 return result;
501}
502
503static int
Yangster-mac7604aea2017-12-11 22:55:49 -0800504write_stats_log_jni(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl)
Yao Chend54f9dd2017-10-17 17:37:48 +0000505{
Yao Chend54f9dd2017-10-17 17:37:48 +0000506 // Print prelude
507 fprintf(out, "// This file is autogenerated\n");
508 fprintf(out, "\n");
509
510 fprintf(out, "#include <statslog.h>\n");
511 fprintf(out, "\n");
512 fprintf(out, "#include <nativehelper/JNIHelp.h>\n");
Yangster-mac7604aea2017-12-11 22:55:49 -0800513 fprintf(out, "#include <nativehelper/ScopedUtfChars.h>\n");
514 fprintf(out, "#include <utils/Vector.h>\n");
Yao Chend54f9dd2017-10-17 17:37:48 +0000515 fprintf(out, "#include \"core_jni_helpers.h\"\n");
516 fprintf(out, "#include \"jni.h\"\n");
517 fprintf(out, "\n");
518 fprintf(out, "#define UNUSED __attribute__((__unused__))\n");
519 fprintf(out, "\n");
520
521 fprintf(out, "namespace android {\n");
522 fprintf(out, "\n");
523
524 // Print write methods
525 for (set<vector<java_type_t>>::const_iterator signature = atoms.signatures.begin();
Yangster-mac7604aea2017-12-11 22:55:49 -0800526 signature != atoms.signatures.end(); signature++) {
Yao Chend54f9dd2017-10-17 17:37:48 +0000527 int argIndex;
528
529 fprintf(out, "static void\n");
530 fprintf(out, "%s(JNIEnv* env, jobject clazz UNUSED, jint code",
531 jni_function_name(*signature).c_str());
532 argIndex = 1;
533 for (vector<java_type_t>::const_iterator arg = signature->begin();
534 arg != signature->end(); arg++) {
Yangster-mac7604aea2017-12-11 22:55:49 -0800535 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
536 for (auto chainField : attributionDecl.fields) {
537 fprintf(out, ", %s %s", jni_array_type_name(chainField.javaType),
538 chainField.name.c_str());
539 }
540 } else {
541 fprintf(out, ", %s arg%d", jni_type_name(*arg), argIndex);
542 }
Yao Chend54f9dd2017-10-17 17:37:48 +0000543 argIndex++;
544 }
545 fprintf(out, ")\n");
546
547 fprintf(out, "{\n");
548
549 // Prepare strings
550 argIndex = 1;
Yangster-mac7604aea2017-12-11 22:55:49 -0800551 bool hadStringOrChain = false;
Yao Chend54f9dd2017-10-17 17:37:48 +0000552 for (vector<java_type_t>::const_iterator arg = signature->begin();
553 arg != signature->end(); arg++) {
554 if (*arg == JAVA_TYPE_STRING) {
Yangster-mac7604aea2017-12-11 22:55:49 -0800555 hadStringOrChain = true;
Yao Chend54f9dd2017-10-17 17:37:48 +0000556 fprintf(out, " const char* str%d;\n", argIndex);
557 fprintf(out, " if (arg%d != NULL) {\n", argIndex);
558 fprintf(out, " str%d = env->GetStringUTFChars(arg%d, NULL);\n",
559 argIndex, argIndex);
560 fprintf(out, " } else {\n");
561 fprintf(out, " str%d = NULL;\n", argIndex);
562 fprintf(out, " }\n");
Yangster-mac7604aea2017-12-11 22:55:49 -0800563 } else if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
564 hadStringOrChain = true;
565 for (auto chainField : attributionDecl.fields) {
566 fprintf(out, " size_t %s_length = env->GetArrayLength(%s);\n",
567 chainField.name.c_str(), chainField.name.c_str());
568 if (chainField.name != attributionDecl.fields.front().name) {
569 fprintf(out, " if (%s_length != %s_length) {\n",
570 chainField.name.c_str(),
571 attributionDecl.fields.front().name.c_str());
572 fprintf(out, " jniThrowException(env, "
573 "\"java/lang/IllegalArgumentException\", "
574 "\"invalid attribution field(%s) length.\");\n",
575 chainField.name.c_str());
576 fprintf(out, " return;\n");
577 fprintf(out, " }\n");
578 }
579 if (chainField.javaType == JAVA_TYPE_INT) {
580 fprintf(out, " jint* %s_array = env->GetIntArrayElements(%s, NULL);\n",
581 chainField.name.c_str(), chainField.name.c_str());
582 } else if (chainField.javaType == JAVA_TYPE_STRING) {
583 fprintf(out, " std::vector<%s> %s_vec;\n",
584 cpp_type_name(chainField.javaType), chainField.name.c_str());
585 fprintf(out, " std::vector<ScopedUtfChars*> scoped_%s_vec;\n",
586 chainField.name.c_str());
587 fprintf(out, " for (size_t i = 0; i < %s_length; ++i) {\n",
588 chainField.name.c_str());
589 fprintf(out, " jstring jstr = "
590 "(jstring)env->GetObjectArrayElement(%s, i);\n",
591 chainField.name.c_str());
592 fprintf(out, " ScopedUtfChars* scoped_%s = "
593 "new ScopedUtfChars(env, jstr);\n",
594 chainField.name.c_str());
595 fprintf(out, " %s_vec.push_back(scoped_%s->c_str());\n",
596 chainField.name.c_str(), chainField.name.c_str());
597 fprintf(out, " scoped_%s_vec.push_back(scoped_%s);\n",
598 chainField.name.c_str(), chainField.name.c_str());
599 fprintf(out, " }\n");
600 }
601 fprintf(out, "\n");
602 }
Yao Chend54f9dd2017-10-17 17:37:48 +0000603 }
604 argIndex++;
605 }
Yangster-mac7604aea2017-12-11 22:55:49 -0800606 // Emit this to quiet the unused parameter warning if there were no strings or attribution
607 // chains.
608 if (!hadStringOrChain) {
Yao Chend54f9dd2017-10-17 17:37:48 +0000609 fprintf(out, " (void)env;\n");
610 }
611
612 // stats_write call
613 argIndex = 1;
614 fprintf(out, " android::util::stats_write(code");
615 for (vector<java_type_t>::const_iterator arg = signature->begin();
616 arg != signature->end(); arg++) {
Yangster-mac7604aea2017-12-11 22:55:49 -0800617 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
618 for (auto chainField : attributionDecl.fields) {
619 if (chainField.javaType == JAVA_TYPE_INT) {
620 fprintf(out, ", (const %s*)%s_array, %s_length",
621 cpp_type_name(chainField.javaType),
622 chainField.name.c_str(), chainField.name.c_str());
623 } else if (chainField.javaType == JAVA_TYPE_STRING) {
624 fprintf(out, ", %s_vec", chainField.name.c_str());
625 }
626 }
627 } else {
628 const char *argName = (*arg == JAVA_TYPE_STRING) ? "str" : "arg";
629 fprintf(out, ", (%s)%s%d", cpp_type_name(*arg), argName, argIndex);
630 }
Yao Chend54f9dd2017-10-17 17:37:48 +0000631 argIndex++;
632 }
633 fprintf(out, ");\n");
Yangster-mac7604aea2017-12-11 22:55:49 -0800634 fprintf(out, "\n");
Yao Chend54f9dd2017-10-17 17:37:48 +0000635
636 // Clean up strings
637 argIndex = 1;
638 for (vector<java_type_t>::const_iterator arg = signature->begin();
639 arg != signature->end(); arg++) {
640 if (*arg == JAVA_TYPE_STRING) {
641 fprintf(out, " if (str%d != NULL) {\n", argIndex);
642 fprintf(out, " env->ReleaseStringUTFChars(arg%d, str%d);\n",
643 argIndex, argIndex);
644 fprintf(out, " }\n");
Yangster-mac7604aea2017-12-11 22:55:49 -0800645 } else if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
646 for (auto chainField : attributionDecl.fields) {
647 if (chainField.javaType == JAVA_TYPE_INT) {
648 fprintf(out, " env->ReleaseIntArrayElements(%s, %s_array, 0);\n",
649 chainField.name.c_str(), chainField.name.c_str());
650 } else if (chainField.javaType == JAVA_TYPE_STRING) {
651 fprintf(out, " for (size_t i = 0; i < %s_length; ++i) {\n",
652 chainField.name.c_str());
653 fprintf(out, " delete scoped_%s_vec[i];\n", chainField.name.c_str());
654 fprintf(out, " }\n");
655 }
656 }
Yao Chend54f9dd2017-10-17 17:37:48 +0000657 }
658 argIndex++;
659 }
660
661 fprintf(out, "}\n");
662 fprintf(out, "\n");
663 }
664
665 // Print registration function table
666 fprintf(out, "/*\n");
667 fprintf(out, " * JNI registration.\n");
668 fprintf(out, " */\n");
669 fprintf(out, "static const JNINativeMethod gRegisterMethods[] = {\n");
670 for (set<vector<java_type_t>>::const_iterator signature = atoms.signatures.begin();
671 signature != atoms.signatures.end(); signature++) {
672 fprintf(out, " { \"write\", \"%s\", (void*)%s },\n",
Yangster-mac7604aea2017-12-11 22:55:49 -0800673 jni_function_signature(*signature, attributionDecl).c_str(),
674 jni_function_name(*signature).c_str());
Yao Chend54f9dd2017-10-17 17:37:48 +0000675 }
676 fprintf(out, "};\n");
677 fprintf(out, "\n");
678
679 // Print registration function
680 fprintf(out, "int register_android_util_StatsLog(JNIEnv* env) {\n");
681 fprintf(out, " return RegisterMethodsOrDie(\n");
682 fprintf(out, " env,\n");
683 fprintf(out, " \"android/util/StatsLog\",\n");
684 fprintf(out, " gRegisterMethods, NELEM(gRegisterMethods));\n");
685 fprintf(out, "}\n");
686
687 fprintf(out, "\n");
688 fprintf(out, "} // namespace android\n");
689
690 return 0;
691}
692
693
694static void
695print_usage()
696{
697 fprintf(stderr, "usage: stats-log-api-gen OPTIONS\n");
698 fprintf(stderr, "\n");
699 fprintf(stderr, "OPTIONS\n");
700 fprintf(stderr, " --cpp FILENAME the header file to output\n");
701 fprintf(stderr, " --header FILENAME the cpp file to output\n");
702 fprintf(stderr, " --help this message\n");
703 fprintf(stderr, " --java FILENAME the java file to output\n");
704 fprintf(stderr, " --jni FILENAME the jni file to output\n");
705}
706
707/**
708 * Do the argument parsing and execute the tasks.
709 */
710static int
711run(int argc, char const*const* argv)
712{
713 string cppFilename;
714 string headerFilename;
715 string javaFilename;
716 string jniFilename;
717
718 int index = 1;
719 while (index < argc) {
720 if (0 == strcmp("--help", argv[index])) {
721 print_usage();
722 return 0;
723 } else if (0 == strcmp("--cpp", argv[index])) {
724 index++;
725 if (index >= argc) {
726 print_usage();
727 return 1;
728 }
729 cppFilename = argv[index];
730 } else if (0 == strcmp("--header", argv[index])) {
731 index++;
732 if (index >= argc) {
733 print_usage();
734 return 1;
735 }
736 headerFilename = argv[index];
737 } else if (0 == strcmp("--java", argv[index])) {
738 index++;
739 if (index >= argc) {
740 print_usage();
741 return 1;
742 }
743 javaFilename = argv[index];
744 } else if (0 == strcmp("--jni", argv[index])) {
745 index++;
746 if (index >= argc) {
747 print_usage();
748 return 1;
749 }
750 jniFilename = argv[index];
751 }
752 index++;
753 }
754
755 if (cppFilename.size() == 0
756 && headerFilename.size() == 0
757 && javaFilename.size() == 0
758 && jniFilename.size() == 0) {
759 print_usage();
760 return 1;
761 }
762
763 // Collate the parameters
764 Atoms atoms;
Stefan Lafonae2df012017-11-14 09:17:21 -0800765 int errorCount = collate_atoms(Atom::descriptor(), &atoms);
Yao Chend54f9dd2017-10-17 17:37:48 +0000766 if (errorCount != 0) {
767 return 1;
768 }
769
Yangster-mac7604aea2017-12-11 22:55:49 -0800770 AtomDecl attributionDecl;
771 vector<java_type_t> attributionSignature;
772 collate_atom(android::os::statsd::Attribution::descriptor(),
773 &attributionDecl, &attributionSignature);
774
Yao Chend54f9dd2017-10-17 17:37:48 +0000775 // Write the .cpp file
776 if (cppFilename.size() != 0) {
777 FILE* out = fopen(cppFilename.c_str(), "w");
778 if (out == NULL) {
779 fprintf(stderr, "Unable to open file for write: %s\n", cppFilename.c_str());
780 return 1;
781 }
Yangster-mac7604aea2017-12-11 22:55:49 -0800782 errorCount = android::stats_log_api_gen::write_stats_log_cpp(
783 out, atoms, attributionDecl);
Yao Chend54f9dd2017-10-17 17:37:48 +0000784 fclose(out);
785 }
786
787 // Write the .h file
788 if (headerFilename.size() != 0) {
789 FILE* out = fopen(headerFilename.c_str(), "w");
790 if (out == NULL) {
791 fprintf(stderr, "Unable to open file for write: %s\n", headerFilename.c_str());
792 return 1;
793 }
Yangster-mac7604aea2017-12-11 22:55:49 -0800794 errorCount = android::stats_log_api_gen::write_stats_log_header(
795 out, atoms, attributionDecl);
Yao Chend54f9dd2017-10-17 17:37:48 +0000796 fclose(out);
797 }
798
799 // Write the .java file
800 if (javaFilename.size() != 0) {
801 FILE* out = fopen(javaFilename.c_str(), "w");
802 if (out == NULL) {
803 fprintf(stderr, "Unable to open file for write: %s\n", javaFilename.c_str());
804 return 1;
805 }
Yangster-mac7604aea2017-12-11 22:55:49 -0800806 errorCount = android::stats_log_api_gen::write_stats_log_java(
807 out, atoms, attributionDecl);
Yao Chend54f9dd2017-10-17 17:37:48 +0000808 fclose(out);
809 }
810
811 // Write the jni file
812 if (jniFilename.size() != 0) {
813 FILE* out = fopen(jniFilename.c_str(), "w");
814 if (out == NULL) {
815 fprintf(stderr, "Unable to open file for write: %s\n", jniFilename.c_str());
816 return 1;
817 }
Yangster-mac7604aea2017-12-11 22:55:49 -0800818 errorCount = android::stats_log_api_gen::write_stats_log_jni(
819 out, atoms, attributionDecl);
Yao Chend54f9dd2017-10-17 17:37:48 +0000820 fclose(out);
821 }
822
823 return 0;
824}
825
826}
827}
828
829/**
830 * Main.
831 */
832int
833main(int argc, char const*const* argv)
834{
835 GOOGLE_PROTOBUF_VERIFY_VERSION;
836
837 return android::stats_log_api_gen::run(argc, argv);
Yangster-mac7604aea2017-12-11 22:55:49 -0800838}