blob: 1f13cc274efa5fd59a64764359bc01ee03448a56 [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-macca5c0862018-04-09 22:39:53 -0700104 fprintf(out, "#include <mutex>\n");
Yangster-macb8382a12018-04-04 10:39:12 -0700105 fprintf(out, "#include <chrono>\n");
106 fprintf(out, "#include <thread>\n");
Yao Chenf7bc6ab2018-04-18 13:45:48 -0700107 fprintf(out, "#include <stats_event_list.h>\n");
Yao Chend54f9dd2017-10-17 17:37:48 +0000108 fprintf(out, "#include <log/log.h>\n");
109 fprintf(out, "#include <statslog.h>\n");
Yangster-mac330af582018-02-08 15:24:38 -0800110 fprintf(out, "#include <utils/SystemClock.h>\n");
Yao Chend54f9dd2017-10-17 17:37:48 +0000111 fprintf(out, "\n");
112
113 fprintf(out, "namespace android {\n");
114 fprintf(out, "namespace util {\n");
Yao Chen80235402017-11-13 20:42:25 -0800115 fprintf(out, "// the single event tag id for all stats logs\n");
116 fprintf(out, "const static int kStatsEventTag = 1937006964;\n");
Yao Chend54f9dd2017-10-17 17:37:48 +0000117
Yao Chenc40a19d2018-03-15 16:48:25 -0700118 std::set<string> kTruncatingAtomNames = {"mobile_radio_power_state_changed",
119 "audio_state_changed",
120 "call_state_changed",
121 "phone_signal_strength_changed",
122 "mobile_bytes_transfer_by_fg_bg",
123 "mobile_bytes_transfer"};
124 fprintf(out,
125 "const std::set<int> "
126 "AtomsInfo::kNotTruncatingTimestampAtomWhiteList = {\n");
127 for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
128 atom != atoms.decls.end(); atom++) {
129 if (kTruncatingAtomNames.find(atom->name) ==
130 kTruncatingAtomNames.end()) {
131 string constant = make_constant_name(atom->name);
132 fprintf(out, " %s,\n", constant.c_str());
133 }
134 }
135 fprintf(out, "};\n");
136 fprintf(out, "\n");
137
138 fprintf(out,
139 "const std::set<int> AtomsInfo::kAtomsWithAttributionChain = {\n");
140 for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
141 atom != atoms.decls.end(); atom++) {
142 for (vector<AtomField>::const_iterator field = atom->fields.begin();
143 field != atom->fields.end(); field++) {
144 if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
145 string constant = make_constant_name(atom->name);
146 fprintf(out, " %s,\n", constant.c_str());
147 break;
148 }
149 }
150 }
151 fprintf(out, "};\n");
152 fprintf(out, "\n");
153
Yangster-macca5c0862018-04-09 22:39:53 -0700154 fprintf(out, "static std::map<int, int> getAtomUidField() {\n");
Yao Chenc40a19d2018-03-15 16:48:25 -0700155 fprintf(out, " std::map<int, int> uidField;\n");
156 for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
157 atom != atoms.decls.end(); atom++) {
158 if (atom->uidField == 0) {
159 continue;
160 }
161 fprintf(out,
162 "\n // Adding uid field for atom "
163 "(%d)%s\n",
164 atom->code, atom->name.c_str());
165 fprintf(out, " uidField[static_cast<int>(%s)] = %d;\n",
166 make_constant_name(atom->name).c_str(), atom->uidField);
167 }
168
169 fprintf(out, " return uidField;\n");
170 fprintf(out, "};\n");
171
172 fprintf(out,
173 "const std::map<int, int> AtomsInfo::kAtomsWithUidField = "
174 "getAtomUidField();\n");
175
176 fprintf(out,
177 "static std::map<int, StateAtomFieldOptions> "
178 "getStateAtomFieldOptions() {\n");
179 fprintf(out, " std::map<int, StateAtomFieldOptions> options;\n");
180 fprintf(out, " StateAtomFieldOptions opt;\n");
181 for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
182 atom != atoms.decls.end(); atom++) {
183 if (atom->primaryFields.size() == 0 && atom->exclusiveField == 0) {
184 continue;
185 }
186 fprintf(out,
187 "\n // Adding primary and exclusive fields for atom "
188 "(%d)%s\n",
189 atom->code, atom->name.c_str());
190 fprintf(out, " opt.primaryFields.clear();\n");
191 for (const auto& field : atom->primaryFields) {
192 fprintf(out, " opt.primaryFields.push_back(%d);\n", field);
193 }
194
195 fprintf(out, " opt.exclusiveField = %d;\n", atom->exclusiveField);
196 fprintf(out, " options[static_cast<int>(%s)] = opt;\n",
197 make_constant_name(atom->name).c_str());
198 }
199
200 fprintf(out, " return options;\n");
201 fprintf(out, " }\n");
202
203 fprintf(out,
204 "const std::map<int, StateAtomFieldOptions> "
205 "AtomsInfo::kStateAtomsFieldOptions = "
206 "getStateAtomFieldOptions();\n");
207
Yangster-macca5c0862018-04-09 22:39:53 -0700208
209 fprintf(out, "int64_t lastRetryTimestampNs = -1;\n");
210 fprintf(out, "const int64_t kMinRetryIntervalNs = NS_PER_SEC * 60 * 20; // 20 minutes\n");
211 fprintf(out, "static std::mutex mLogdRetryMutex;\n");
212
Yao Chend54f9dd2017-10-17 17:37:48 +0000213 // Print write methods
214 fprintf(out, "\n");
215 for (set<vector<java_type_t>>::const_iterator signature = atoms.signatures.begin();
Yangster-mac7604aea2017-12-11 22:55:49 -0800216 signature != atoms.signatures.end(); signature++) {
Yao Chend54f9dd2017-10-17 17:37:48 +0000217 int argIndex;
218
Yao Chen97e21ec2018-03-29 11:00:38 -0700219 fprintf(out, "int\n");
Yangster-macb8382a12018-04-04 10:39:12 -0700220 fprintf(out, "try_stats_write(int32_t code");
Yao Chend54f9dd2017-10-17 17:37:48 +0000221 argIndex = 1;
222 for (vector<java_type_t>::const_iterator arg = signature->begin();
Yangster-mac7604aea2017-12-11 22:55:49 -0800223 arg != signature->end(); arg++) {
224 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
225 for (auto chainField : attributionDecl.fields) {
226 if (chainField.javaType == JAVA_TYPE_STRING) {
227 fprintf(out, ", const std::vector<%s>& %s",
228 cpp_type_name(chainField.javaType),
229 chainField.name.c_str());
230 } else {
231 fprintf(out, ", const %s* %s, size_t %s_length",
232 cpp_type_name(chainField.javaType),
233 chainField.name.c_str(), chainField.name.c_str());
234 }
235 }
236 } else {
237 fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
238 }
Yao Chend54f9dd2017-10-17 17:37:48 +0000239 argIndex++;
240 }
241 fprintf(out, ")\n");
242
243 fprintf(out, "{\n");
244 argIndex = 1;
Yao Chenf7bc6ab2018-04-18 13:45:48 -0700245 fprintf(out, " stats_event_list event(kStatsEventTag);\n");
Yangster-mac330af582018-02-08 15:24:38 -0800246 fprintf(out, " event << android::elapsedRealtimeNano();\n\n");
Yangster-mac7604aea2017-12-11 22:55:49 -0800247 fprintf(out, " event << code;\n\n");
Yao Chend54f9dd2017-10-17 17:37:48 +0000248 for (vector<java_type_t>::const_iterator arg = signature->begin();
Yangster-mac7604aea2017-12-11 22:55:49 -0800249 arg != signature->end(); arg++) {
250 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
251 for (const auto &chainField : attributionDecl.fields) {
252 if (chainField.javaType == JAVA_TYPE_STRING) {
253 fprintf(out, " if (%s_length != %s.size()) {\n",
254 attributionDecl.fields.front().name.c_str(), chainField.name.c_str());
Yao Chen97e21ec2018-03-29 11:00:38 -0700255 fprintf(out, " return -EINVAL;\n");
Yangster-mac7604aea2017-12-11 22:55:49 -0800256 fprintf(out, " }\n");
257 }
258 }
259 fprintf(out, "\n event.begin();\n");
260 fprintf(out, " for (size_t i = 0; i < %s_length; ++i) {\n",
261 attributionDecl.fields.front().name.c_str());
262 fprintf(out, " event.begin();\n");
263 for (const auto &chainField : attributionDecl.fields) {
Yangster-mac20ac9442018-01-08 14:54:48 -0800264 if (chainField.javaType == JAVA_TYPE_STRING) {
265 fprintf(out, " if (%s[i] != NULL) {\n", chainField.name.c_str());
266 fprintf(out, " event << %s[i];\n", chainField.name.c_str());
267 fprintf(out, " } else {\n");
268 fprintf(out, " event << \"\";\n");
269 fprintf(out, " }\n");
270 } else {
271 fprintf(out, " event << %s[i];\n", chainField.name.c_str());
272 }
Yangster-mac7604aea2017-12-11 22:55:49 -0800273 }
274 fprintf(out, " event.end();\n");
Yao Chend54f9dd2017-10-17 17:37:48 +0000275 fprintf(out, " }\n");
Yangster-mac7604aea2017-12-11 22:55:49 -0800276 fprintf(out, " event.end();\n\n");
277 } else {
278 if (*arg == JAVA_TYPE_STRING) {
279 fprintf(out, " if (arg%d == NULL) {\n", argIndex);
280 fprintf(out, " arg%d = \"\";\n", argIndex);
281 fprintf(out, " }\n");
282 }
283 fprintf(out, " event << arg%d;\n", argIndex);
Yao Chend54f9dd2017-10-17 17:37:48 +0000284 }
Yao Chend54f9dd2017-10-17 17:37:48 +0000285 argIndex++;
286 }
287
Yao Chen97e21ec2018-03-29 11:00:38 -0700288 fprintf(out, " return event.write(LOG_ID_STATS);\n");
Yao Chend54f9dd2017-10-17 17:37:48 +0000289 fprintf(out, "}\n");
290 fprintf(out, "\n");
291 }
292
Yangster-macb8382a12018-04-04 10:39:12 -0700293 for (set<vector<java_type_t>>::const_iterator signature = atoms.signatures.begin();
294 signature != atoms.signatures.end(); signature++) {
295 int argIndex;
296
297 fprintf(out, "int \n");
298 fprintf(out, "stats_write(int32_t code");
299 argIndex = 1;
300 for (vector<java_type_t>::const_iterator arg = signature->begin();
301 arg != signature->end(); arg++) {
302 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
303 for (auto chainField : attributionDecl.fields) {
304 if (chainField.javaType == JAVA_TYPE_STRING) {
305 fprintf(out, ", const std::vector<%s>& %s",
306 cpp_type_name(chainField.javaType),
307 chainField.name.c_str());
308 } else {
309 fprintf(out, ", const %s* %s, size_t %s_length",
310 cpp_type_name(chainField.javaType),
311 chainField.name.c_str(), chainField.name.c_str());
312 }
313 }
314 } else {
315 fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
316 }
317 argIndex++;
318 }
319 fprintf(out, ")\n");
320
321 fprintf(out, "{\n");
322 fprintf(out, " int ret = 0;\n");
323
Yangster-macca5c0862018-04-09 22:39:53 -0700324 fprintf(out, " for(int retry = 0; retry < 2; ++retry) {\n");
Yangster-macb8382a12018-04-04 10:39:12 -0700325 fprintf(out, " ret = try_stats_write(code");
326
327 argIndex = 1;
328 for (vector<java_type_t>::const_iterator arg = signature->begin();
329 arg != signature->end(); arg++) {
330 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
331 for (auto chainField : attributionDecl.fields) {
332 if (chainField.javaType == JAVA_TYPE_STRING) {
333 fprintf(out, ", %s",
334 chainField.name.c_str());
335 } else {
336 fprintf(out, ", %s, %s_length",
337 chainField.name.c_str(), chainField.name.c_str());
338 }
339 }
340 } else {
341 fprintf(out, ", arg%d", argIndex);
342 }
343 argIndex++;
344 }
345 fprintf(out, ");\n");
346 fprintf(out, " if (ret >= 0) { return retry; }\n");
Yangster-macca5c0862018-04-09 22:39:53 -0700347
348
349 fprintf(out, " {\n");
350 fprintf(out, " std::lock_guard<std::mutex> lock(mLogdRetryMutex);\n");
351 fprintf(out, " if ((android::elapsedRealtimeNano() - lastRetryTimestampNs) <= "
352 "kMinRetryIntervalNs) break;\n");
353 fprintf(out, " lastRetryTimestampNs = android::elapsedRealtimeNano();\n");
354 fprintf(out, " }\n");
355 fprintf(out, " std::this_thread::sleep_for(std::chrono::milliseconds(10));\n");
Yangster-macb8382a12018-04-04 10:39:12 -0700356 fprintf(out, " }\n");
357 fprintf(out, " return ret;\n");
358 fprintf(out, "}\n");
359 fprintf(out, "\n");
360 }
361
Yangster-macba5b9e42018-01-10 21:31:59 -0800362 for (set<vector<java_type_t>>::const_iterator signature = atoms.non_chained_signatures.begin();
363 signature != atoms.non_chained_signatures.end(); signature++) {
364 int argIndex;
365
Yao Chen97e21ec2018-03-29 11:00:38 -0700366 fprintf(out, "int\n");
Yangster-macb8382a12018-04-04 10:39:12 -0700367 fprintf(out, "try_stats_write_non_chained(int32_t code");
Yangster-macba5b9e42018-01-10 21:31:59 -0800368 argIndex = 1;
369 for (vector<java_type_t>::const_iterator arg = signature->begin();
370 arg != signature->end(); arg++) {
371 fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
372 argIndex++;
373 }
374 fprintf(out, ")\n");
375
376 fprintf(out, "{\n");
377 argIndex = 1;
Yao Chenf7bc6ab2018-04-18 13:45:48 -0700378 fprintf(out, " stats_event_list event(kStatsEventTag);\n");
Yangster-mac31ddcde2018-02-14 16:09:35 -0800379 fprintf(out, " event << android::elapsedRealtimeNano();\n\n");
Yangster-macba5b9e42018-01-10 21:31:59 -0800380 fprintf(out, " event << code;\n\n");
381 for (vector<java_type_t>::const_iterator arg = signature->begin();
382 arg != signature->end(); arg++) {
383 if (argIndex == 1) {
384 fprintf(out, " event.begin();\n\n");
385 fprintf(out, " event.begin();\n");
386 }
387 if (*arg == JAVA_TYPE_STRING) {
388 fprintf(out, " if (arg%d == NULL) {\n", argIndex);
389 fprintf(out, " arg%d = \"\";\n", argIndex);
390 fprintf(out, " }\n");
391 }
392 fprintf(out, " event << arg%d;\n", argIndex);
393 if (argIndex == 2) {
394 fprintf(out, " event.end();\n\n");
395 fprintf(out, " event.end();\n\n");
396 }
397 argIndex++;
398 }
399
Yao Chen97e21ec2018-03-29 11:00:38 -0700400 fprintf(out, " return event.write(LOG_ID_STATS);\n");
Yangster-macba5b9e42018-01-10 21:31:59 -0800401 fprintf(out, "}\n");
402 fprintf(out, "\n");
403 }
Yangster-macb8382a12018-04-04 10:39:12 -0700404
405 for (set<vector<java_type_t>>::const_iterator signature = atoms.non_chained_signatures.begin();
406 signature != atoms.non_chained_signatures.end(); signature++) {
407 int argIndex;
408
409 fprintf(out, "int\n");
410 fprintf(out, "stats_write_non_chained(int32_t code");
411 argIndex = 1;
412 for (vector<java_type_t>::const_iterator arg = signature->begin();
413 arg != signature->end(); arg++) {
414 fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
415 argIndex++;
416 }
417 fprintf(out, ")\n");
418
419 fprintf(out, "{\n");
420
421 fprintf(out, " int ret = 0;\n");
Yangster-macca5c0862018-04-09 22:39:53 -0700422 fprintf(out, " for(int retry = 0; retry < 2; ++retry) {\n");
Yangster-macb8382a12018-04-04 10:39:12 -0700423 fprintf(out, " ret = try_stats_write_non_chained(code");
424
425 argIndex = 1;
426 for (vector<java_type_t>::const_iterator arg = signature->begin();
427 arg != signature->end(); arg++) {
428 fprintf(out, ", arg%d", argIndex);
429 argIndex++;
430 }
431 fprintf(out, ");\n");
432 fprintf(out, " if (ret >= 0) { return retry; }\n");
Yangster-macca5c0862018-04-09 22:39:53 -0700433
434 fprintf(out, " {\n");
435 fprintf(out, " std::lock_guard<std::mutex> lock(mLogdRetryMutex);\n");
436 fprintf(out, " if ((android::elapsedRealtimeNano() - lastRetryTimestampNs) <= "
437 "kMinRetryIntervalNs) break;\n");
438 fprintf(out, " lastRetryTimestampNs = android::elapsedRealtimeNano();\n");
439 fprintf(out, " }\n");
440
441 fprintf(out, " std::this_thread::sleep_for(std::chrono::milliseconds(10));\n");
Yangster-macb8382a12018-04-04 10:39:12 -0700442 fprintf(out, " }\n");
443 fprintf(out, " return ret;\n");
444 fprintf(out, "}\n");
445
446 fprintf(out, "\n");
447 }
448
449
Yao Chend54f9dd2017-10-17 17:37:48 +0000450 // Print footer
451 fprintf(out, "\n");
452 fprintf(out, "} // namespace util\n");
453 fprintf(out, "} // namespace android\n");
454
455 return 0;
456}
457
Yangster-macba5b9e42018-01-10 21:31:59 -0800458void build_non_chained_decl_map(const Atoms& atoms,
459 std::map<int, set<AtomDecl>::const_iterator>* decl_map){
460 for (set<AtomDecl>::const_iterator atom = atoms.non_chained_decls.begin();
461 atom != atoms.non_chained_decls.end(); atom++) {
462 decl_map->insert(std::make_pair(atom->code, atom));
463 }
464}
465
466static void write_cpp_usage(
467 FILE* out, const string& method_name, const string& atom_code_name,
468 const AtomDecl& atom, const AtomDecl &attributionDecl) {
469 fprintf(out, " * Usage: %s(StatsLog.%s", method_name.c_str(), atom_code_name.c_str());
470 for (vector<AtomField>::const_iterator field = atom.fields.begin();
471 field != atom.fields.end(); field++) {
472 if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
473 for (auto chainField : attributionDecl.fields) {
474 if (chainField.javaType == JAVA_TYPE_STRING) {
475 fprintf(out, ", const std::vector<%s>& %s",
476 cpp_type_name(chainField.javaType),
477 chainField.name.c_str());
478 } else {
479 fprintf(out, ", const %s* %s, size_t %s_length",
480 cpp_type_name(chainField.javaType),
481 chainField.name.c_str(), chainField.name.c_str());
482 }
483 }
484 } else {
485 fprintf(out, ", %s %s", cpp_type_name(field->javaType), field->name.c_str());
486 }
487 }
488 fprintf(out, ");\n");
489}
490
491static void write_cpp_method_header(
492 FILE* out, const string& method_name, const set<vector<java_type_t>>& signatures,
493 const AtomDecl &attributionDecl) {
494 for (set<vector<java_type_t>>::const_iterator signature = signatures.begin();
495 signature != signatures.end(); signature++) {
Yao Chen97e21ec2018-03-29 11:00:38 -0700496 fprintf(out, "int %s(int32_t code ", method_name.c_str());
Yangster-macba5b9e42018-01-10 21:31:59 -0800497 int argIndex = 1;
498 for (vector<java_type_t>::const_iterator arg = signature->begin();
499 arg != signature->end(); arg++) {
500 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
501 for (auto chainField : attributionDecl.fields) {
502 if (chainField.javaType == JAVA_TYPE_STRING) {
503 fprintf(out, ", const std::vector<%s>& %s",
504 cpp_type_name(chainField.javaType), chainField.name.c_str());
505 } else {
506 fprintf(out, ", const %s* %s, size_t %s_length",
507 cpp_type_name(chainField.javaType),
508 chainField.name.c_str(), chainField.name.c_str());
509 }
510 }
511 } else {
512 fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
513 }
514 argIndex++;
515 }
516 fprintf(out, ");\n");
517
518 }
519}
Yao Chend54f9dd2017-10-17 17:37:48 +0000520
521static int
Yangster-mac7604aea2017-12-11 22:55:49 -0800522write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl)
Yao Chend54f9dd2017-10-17 17:37:48 +0000523{
Yao Chend54f9dd2017-10-17 17:37:48 +0000524 // Print prelude
525 fprintf(out, "// This file is autogenerated\n");
526 fprintf(out, "\n");
527 fprintf(out, "#pragma once\n");
528 fprintf(out, "\n");
529 fprintf(out, "#include <stdint.h>\n");
Yangster-mac7604aea2017-12-11 22:55:49 -0800530 fprintf(out, "#include <vector>\n");
Yao Chen9c1debe2018-02-19 14:39:19 -0800531 fprintf(out, "#include <map>\n");
Yangster-mac68985802018-01-21 10:05:09 -0800532 fprintf(out, "#include <set>\n");
Yao Chend54f9dd2017-10-17 17:37:48 +0000533 fprintf(out, "\n");
534
535 fprintf(out, "namespace android {\n");
536 fprintf(out, "namespace util {\n");
537 fprintf(out, "\n");
538 fprintf(out, "/*\n");
539 fprintf(out, " * API For logging statistics events.\n");
540 fprintf(out, " */\n");
541 fprintf(out, "\n");
542 fprintf(out, "/**\n");
Stefan Lafon9478f352017-10-30 21:20:20 -0700543 fprintf(out, " * Constants for atom codes.\n");
Yao Chend54f9dd2017-10-17 17:37:48 +0000544 fprintf(out, " */\n");
545 fprintf(out, "enum {\n");
546
Yangster-macba5b9e42018-01-10 21:31:59 -0800547 std::map<int, set<AtomDecl>::const_iterator> atom_code_to_non_chained_decl_map;
548 build_non_chained_decl_map(atoms, &atom_code_to_non_chained_decl_map);
549
Yao Chend54f9dd2017-10-17 17:37:48 +0000550 size_t i = 0;
551 // Print constants
552 for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
Yangster-mac7604aea2017-12-11 22:55:49 -0800553 atom != atoms.decls.end(); atom++) {
Yao Chend54f9dd2017-10-17 17:37:48 +0000554 string constant = make_constant_name(atom->name);
555 fprintf(out, "\n");
556 fprintf(out, " /**\n");
557 fprintf(out, " * %s %s\n", atom->message.c_str(), atom->name.c_str());
Yangster-macba5b9e42018-01-10 21:31:59 -0800558 write_cpp_usage(out, "stats_write", constant, *atom, attributionDecl);
559
560 auto non_chained_decl = atom_code_to_non_chained_decl_map.find(atom->code);
561 if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) {
562 write_cpp_usage(out, "stats_write_non_chained", constant, *non_chained_decl->second,
563 attributionDecl);
Yao Chend54f9dd2017-10-17 17:37:48 +0000564 }
Yao Chend54f9dd2017-10-17 17:37:48 +0000565 fprintf(out, " */\n");
566 char const* const comma = (i == atoms.decls.size() - 1) ? "" : ",";
567 fprintf(out, " %s = %d%s\n", constant.c_str(), atom->code, comma);
Yao Chenb3561512017-11-21 18:07:17 -0800568 if (atom->code < PULL_ATOM_START_ID && atom->code > maxPushedAtomId) {
569 maxPushedAtomId = atom->code;
570 }
Yao Chend54f9dd2017-10-17 17:37:48 +0000571 i++;
572 }
573 fprintf(out, "\n");
574 fprintf(out, "};\n");
575 fprintf(out, "\n");
576
Yao Chen9c1debe2018-02-19 14:39:19 -0800577 fprintf(out, "struct StateAtomFieldOptions {\n");
578 fprintf(out, " std::vector<int> primaryFields;\n");
579 fprintf(out, " int exclusiveField;\n");
Yao Chenc40a19d2018-03-15 16:48:25 -0700580 fprintf(out, "};\n");
Yao Chen9c1debe2018-02-19 14:39:19 -0800581 fprintf(out, "\n");
Yao Chenc40a19d2018-03-15 16:48:25 -0700582
583 fprintf(out, "struct AtomsInfo {\n");
Yao Chen9c1debe2018-02-19 14:39:19 -0800584 fprintf(out,
Yao Chenc40a19d2018-03-15 16:48:25 -0700585 " const static std::set<int> "
586 "kNotTruncatingTimestampAtomWhiteList;\n");
587 fprintf(out, " const static std::map<int, int> kAtomsWithUidField;\n");
588 fprintf(out,
589 " const static std::set<int> kAtomsWithAttributionChain;\n");
590 fprintf(out,
591 " const static std::map<int, StateAtomFieldOptions> "
592 "kStateAtomsFieldOptions;\n");
Yao Chen9c1debe2018-02-19 14:39:19 -0800593 fprintf(out, "};\n");
594
Yao Chenc40a19d2018-03-15 16:48:25 -0700595 fprintf(out, "const static int kMaxPushedAtomId = %d;\n\n",
596 maxPushedAtomId);
Yao Chen9c1debe2018-02-19 14:39:19 -0800597
Yao Chend54f9dd2017-10-17 17:37:48 +0000598 // Print write methods
599 fprintf(out, "//\n");
600 fprintf(out, "// Write methods\n");
601 fprintf(out, "//\n");
Yangster-macba5b9e42018-01-10 21:31:59 -0800602 write_cpp_method_header(out, "stats_write", atoms.signatures, attributionDecl);
603
604 fprintf(out, "//\n");
605 fprintf(out, "// Write flattened methods\n");
606 fprintf(out, "//\n");
607 write_cpp_method_header(out, "stats_write_non_chained", atoms.non_chained_signatures,
608 attributionDecl);
Yao Chend54f9dd2017-10-17 17:37:48 +0000609
610 fprintf(out, "\n");
611 fprintf(out, "} // namespace util\n");
612 fprintf(out, "} // namespace android\n");
613
614 return 0;
615}
616
Bookatz0bd97202018-06-05 12:42:37 -0700617static void write_java_usage(FILE* out, const string& method_name, const string& atom_code_name,
618 const AtomDecl& atom) {
Yangster-macba5b9e42018-01-10 21:31:59 -0800619 fprintf(out, " * Usage: StatsLog.%s(StatsLog.%s",
620 method_name.c_str(), atom_code_name.c_str());
621 for (vector<AtomField>::const_iterator field = atom.fields.begin();
622 field != atom.fields.end(); field++) {
623 if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
Bookatz0bd97202018-06-05 12:42:37 -0700624 fprintf(out, ", android.os.WorkSource workSource");
Yangster-macba5b9e42018-01-10 21:31:59 -0800625 } else {
626 fprintf(out, ", %s %s", java_type_name(field->javaType), field->name.c_str());
627 }
628 }
Bookatz0bd97202018-06-05 12:42:37 -0700629 fprintf(out, ");<br>\n");
Yangster-macba5b9e42018-01-10 21:31:59 -0800630}
631
632static void write_java_method(
633 FILE* out, const string& method_name, const set<vector<java_type_t>>& signatures,
634 const AtomDecl &attributionDecl) {
635 for (set<vector<java_type_t>>::const_iterator signature = signatures.begin();
636 signature != signatures.end(); signature++) {
Yao Chen97e21ec2018-03-29 11:00:38 -0700637 fprintf(out, " public static native int %s(int code", method_name.c_str());
Yangster-macba5b9e42018-01-10 21:31:59 -0800638 int argIndex = 1;
639 for (vector<java_type_t>::const_iterator arg = signature->begin();
640 arg != signature->end(); arg++) {
641 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
642 for (auto chainField : attributionDecl.fields) {
643 fprintf(out, ", %s[] %s",
644 java_type_name(chainField.javaType), chainField.name.c_str());
645 }
646 } else {
647 fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
648 }
649 argIndex++;
650 }
651 fprintf(out, ");\n");
652 }
653}
654
Bookatz0bd97202018-06-05 12:42:37 -0700655static void write_java_work_source_method(FILE* out, const set<vector<java_type_t>>& signatures) {
656 fprintf(out, "\n // WorkSource methods.\n");
657 for (set<vector<java_type_t>>::const_iterator signature = signatures.begin();
658 signature != signatures.end(); signature++) {
659 // Determine if there is Attribution in this signature.
660 int attributionArg = -1;
661 int argIndexMax = 0;
662 for (vector<java_type_t>::const_iterator arg = signature->begin();
663 arg != signature->end(); arg++) {
664 argIndexMax++;
665 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
666 if (attributionArg > -1) {
667 fprintf(stderr, "An atom contains multiple AttributionNode fields.\n");
668 fprintf(stderr, "This is not supported. Aborting WorkSource method writing.\n");
669 fprintf(out, "\n// Invalid for WorkSource: more than one attribution chain.\n");
670 return;
671 }
672 attributionArg = argIndexMax;
673 }
674 }
675 if (attributionArg < 0) {
676 continue;
677 }
678
679 // Method header (signature)
680 fprintf(out, " public static void write(int code");
681 int argIndex = 1;
682 for (vector<java_type_t>::const_iterator arg = signature->begin();
683 arg != signature->end(); arg++) {
684 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
685 fprintf(out, ", WorkSource ws");
686 } else {
687 fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
688 }
689 argIndex++;
690 }
691 fprintf(out, ") {\n");
692
693 // write_non_chained() component. TODO: Remove when flat uids are no longer needed.
694 fprintf(out, " for (int i = 0; i < ws.size(); ++i) {\n");
695 fprintf(out, " write_non_chained(code");
696 for (int argIndex = 1; argIndex <= argIndexMax; argIndex++) {
697 if (argIndex == attributionArg) {
698 fprintf(out, ", ws.get(i), ws.getName(i)");
699 } else {
700 fprintf(out, ", arg%d", argIndex);
701 }
702 }
703 fprintf(out, ");\n");
704 fprintf(out, " }\n"); // close flor-loop
705
706 // write() component.
707 fprintf(out, " ArrayList<WorkSource.WorkChain> workChains = ws.getWorkChains();\n");
708 fprintf(out, " if (workChains != null) {\n");
709 fprintf(out, " for (WorkSource.WorkChain wc : workChains) {\n");
710 fprintf(out, " write(code");
711 for (int argIndex = 1; argIndex <= argIndexMax; argIndex++) {
712 if (argIndex == attributionArg) {
713 fprintf(out, ", wc.getUids(), wc.getTags()");
714 } else {
715 fprintf(out, ", arg%d", argIndex);
716 }
717 }
718 fprintf(out, ");\n");
719 fprintf(out, " }\n"); // close for-loop
720 fprintf(out, " }\n"); // close if
721 fprintf(out, " }\n"); // close method
722 }
723}
Yangster-macba5b9e42018-01-10 21:31:59 -0800724
Yao Chend54f9dd2017-10-17 17:37:48 +0000725static int
Yangster-mac7604aea2017-12-11 22:55:49 -0800726write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl)
Yao Chend54f9dd2017-10-17 17:37:48 +0000727{
Yao Chend54f9dd2017-10-17 17:37:48 +0000728 // Print prelude
729 fprintf(out, "// This file is autogenerated\n");
730 fprintf(out, "\n");
731 fprintf(out, "package android.util;\n");
732 fprintf(out, "\n");
Bookatz0bd97202018-06-05 12:42:37 -0700733 fprintf(out, "import android.os.WorkSource;\n");
734 fprintf(out, "import java.util.ArrayList;\n");
735 fprintf(out, "\n");
Yao Chend54f9dd2017-10-17 17:37:48 +0000736 fprintf(out, "\n");
737 fprintf(out, "/**\n");
738 fprintf(out, " * API For logging statistics events.\n");
739 fprintf(out, " * @hide\n");
740 fprintf(out, " */\n");
David Chen0a368b22017-12-06 16:28:16 -0800741 fprintf(out, "public class StatsLogInternal {\n");
Stefan Lafon9478f352017-10-30 21:20:20 -0700742 fprintf(out, " // Constants for atom codes.\n");
Yao Chend54f9dd2017-10-17 17:37:48 +0000743
Yangster-macba5b9e42018-01-10 21:31:59 -0800744 std::map<int, set<AtomDecl>::const_iterator> atom_code_to_non_chained_decl_map;
745 build_non_chained_decl_map(atoms, &atom_code_to_non_chained_decl_map);
746
Stefan Lafon9478f352017-10-30 21:20:20 -0700747 // Print constants for the atom codes.
Yao Chend54f9dd2017-10-17 17:37:48 +0000748 for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
749 atom != atoms.decls.end(); atom++) {
750 string constant = make_constant_name(atom->name);
751 fprintf(out, "\n");
752 fprintf(out, " /**\n");
Bookatz0bd97202018-06-05 12:42:37 -0700753 fprintf(out, " * %s %s<br>\n", atom->message.c_str(), atom->name.c_str());
754 write_java_usage(out, "write", constant, *atom);
Yangster-macba5b9e42018-01-10 21:31:59 -0800755 auto non_chained_decl = atom_code_to_non_chained_decl_map.find(atom->code);
756 if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) {
Bookatz0bd97202018-06-05 12:42:37 -0700757 write_java_usage(out, "write_non_chained", constant, *non_chained_decl->second);
Yao Chend54f9dd2017-10-17 17:37:48 +0000758 }
Yao Chend54f9dd2017-10-17 17:37:48 +0000759 fprintf(out, " */\n");
760 fprintf(out, " public static final int %s = %d;\n", constant.c_str(), atom->code);
761 }
762 fprintf(out, "\n");
763
Stefan Lafon9478f352017-10-30 21:20:20 -0700764 // Print constants for the enum values.
765 fprintf(out, " // Constants for enum values.\n\n");
766 for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
Yangster-mac7604aea2017-12-11 22:55:49 -0800767 atom != atoms.decls.end(); atom++) {
Stefan Lafon9478f352017-10-30 21:20:20 -0700768 for (vector<AtomField>::const_iterator field = atom->fields.begin();
Yangster-mac7604aea2017-12-11 22:55:49 -0800769 field != atom->fields.end(); field++) {
770 if (field->javaType == JAVA_TYPE_ENUM) {
771 fprintf(out, " // Values for %s.%s\n", atom->message.c_str(),
772 field->name.c_str());
773 for (map<int, string>::const_iterator value = field->enumValues.begin();
774 value != field->enumValues.end(); value++) {
775 fprintf(out, " public static final int %s__%s__%s = %d;\n",
776 make_constant_name(atom->message).c_str(),
777 make_constant_name(field->name).c_str(),
778 make_constant_name(value->second).c_str(),
779 value->first);
780 }
781 fprintf(out, "\n");
Stefan Lafon9478f352017-10-30 21:20:20 -0700782 }
Stefan Lafon9478f352017-10-30 21:20:20 -0700783 }
784 }
785
Yao Chend54f9dd2017-10-17 17:37:48 +0000786 // Print write methods
787 fprintf(out, " // Write methods\n");
Yangster-macba5b9e42018-01-10 21:31:59 -0800788 write_java_method(out, "write", atoms.signatures, attributionDecl);
789 write_java_method(out, "write_non_chained", atoms.non_chained_signatures, attributionDecl);
Bookatz0bd97202018-06-05 12:42:37 -0700790 write_java_work_source_method(out, atoms.signatures);
Yao Chend54f9dd2017-10-17 17:37:48 +0000791
792 fprintf(out, "}\n");
793
794 return 0;
795}
796
797static const char*
798jni_type_name(java_type_t type)
799{
800 switch (type) {
801 case JAVA_TYPE_BOOLEAN:
802 return "jboolean";
803 case JAVA_TYPE_INT:
Stefan Lafon9478f352017-10-30 21:20:20 -0700804 case JAVA_TYPE_ENUM:
Yao Chend54f9dd2017-10-17 17:37:48 +0000805 return "jint";
806 case JAVA_TYPE_LONG:
807 return "jlong";
808 case JAVA_TYPE_FLOAT:
809 return "jfloat";
810 case JAVA_TYPE_DOUBLE:
811 return "jdouble";
812 case JAVA_TYPE_STRING:
813 return "jstring";
814 default:
815 return "UNKNOWN";
816 }
817}
818
Yangster-mac7604aea2017-12-11 22:55:49 -0800819static const char*
820jni_array_type_name(java_type_t type)
821{
822 switch (type) {
823 case JAVA_TYPE_INT:
824 return "jintArray";
825 case JAVA_TYPE_STRING:
826 return "jobjectArray";
827 default:
828 return "UNKNOWN";
829 }
830}
831
Yao Chend54f9dd2017-10-17 17:37:48 +0000832static string
Yangster-macba5b9e42018-01-10 21:31:59 -0800833jni_function_name(const string& method_name, const vector<java_type_t>& signature)
Yao Chend54f9dd2017-10-17 17:37:48 +0000834{
Yangster-macba5b9e42018-01-10 21:31:59 -0800835 string result("StatsLog_" + method_name);
Yao Chend54f9dd2017-10-17 17:37:48 +0000836 for (vector<java_type_t>::const_iterator arg = signature.begin();
Yangster-mac7604aea2017-12-11 22:55:49 -0800837 arg != signature.end(); arg++) {
Yao Chend54f9dd2017-10-17 17:37:48 +0000838 switch (*arg) {
839 case JAVA_TYPE_BOOLEAN:
840 result += "_boolean";
841 break;
842 case JAVA_TYPE_INT:
Stefan Lafon9478f352017-10-30 21:20:20 -0700843 case JAVA_TYPE_ENUM:
Yao Chend54f9dd2017-10-17 17:37:48 +0000844 result += "_int";
845 break;
846 case JAVA_TYPE_LONG:
847 result += "_long";
848 break;
849 case JAVA_TYPE_FLOAT:
850 result += "_float";
851 break;
852 case JAVA_TYPE_DOUBLE:
853 result += "_double";
854 break;
855 case JAVA_TYPE_STRING:
856 result += "_String";
857 break;
Yangster-mac7604aea2017-12-11 22:55:49 -0800858 case JAVA_TYPE_ATTRIBUTION_CHAIN:
859 result += "_AttributionChain";
860 break;
Yao Chend54f9dd2017-10-17 17:37:48 +0000861 default:
862 result += "_UNKNOWN";
863 break;
864 }
865 }
866 return result;
867}
868
869static const char*
870java_type_signature(java_type_t type)
871{
872 switch (type) {
873 case JAVA_TYPE_BOOLEAN:
874 return "Z";
875 case JAVA_TYPE_INT:
Stefan Lafon9478f352017-10-30 21:20:20 -0700876 case JAVA_TYPE_ENUM:
Yao Chend54f9dd2017-10-17 17:37:48 +0000877 return "I";
878 case JAVA_TYPE_LONG:
879 return "J";
880 case JAVA_TYPE_FLOAT:
881 return "F";
882 case JAVA_TYPE_DOUBLE:
883 return "D";
884 case JAVA_TYPE_STRING:
885 return "Ljava/lang/String;";
886 default:
887 return "UNKNOWN";
888 }
889}
890
891static string
Yangster-mac7604aea2017-12-11 22:55:49 -0800892jni_function_signature(const vector<java_type_t>& signature, const AtomDecl &attributionDecl)
Yao Chend54f9dd2017-10-17 17:37:48 +0000893{
894 string result("(I");
895 for (vector<java_type_t>::const_iterator arg = signature.begin();
Yangster-mac7604aea2017-12-11 22:55:49 -0800896 arg != signature.end(); arg++) {
897 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
898 for (auto chainField : attributionDecl.fields) {
899 result += "[";
900 result += java_type_signature(chainField.javaType);
901 }
902 } else {
903 result += java_type_signature(*arg);
904 }
Yao Chend54f9dd2017-10-17 17:37:48 +0000905 }
Yao Chen97e21ec2018-03-29 11:00:38 -0700906 result += ")I";
Yao Chend54f9dd2017-10-17 17:37:48 +0000907 return result;
908}
909
910static int
Yangster-macba5b9e42018-01-10 21:31:59 -0800911write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp_method_name,
912 const set<vector<java_type_t>>& signatures, const AtomDecl &attributionDecl)
Yao Chend54f9dd2017-10-17 17:37:48 +0000913{
Yao Chend54f9dd2017-10-17 17:37:48 +0000914 // Print write methods
Yangster-macba5b9e42018-01-10 21:31:59 -0800915 for (set<vector<java_type_t>>::const_iterator signature = signatures.begin();
916 signature != signatures.end(); signature++) {
Yao Chend54f9dd2017-10-17 17:37:48 +0000917 int argIndex;
918
Yao Chen97e21ec2018-03-29 11:00:38 -0700919 fprintf(out, "static int\n");
Yao Chend54f9dd2017-10-17 17:37:48 +0000920 fprintf(out, "%s(JNIEnv* env, jobject clazz UNUSED, jint code",
Yangster-macba5b9e42018-01-10 21:31:59 -0800921 jni_function_name(java_method_name, *signature).c_str());
Yao Chend54f9dd2017-10-17 17:37:48 +0000922 argIndex = 1;
923 for (vector<java_type_t>::const_iterator arg = signature->begin();
924 arg != signature->end(); arg++) {
Yangster-mac7604aea2017-12-11 22:55:49 -0800925 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
926 for (auto chainField : attributionDecl.fields) {
927 fprintf(out, ", %s %s", jni_array_type_name(chainField.javaType),
928 chainField.name.c_str());
929 }
930 } else {
931 fprintf(out, ", %s arg%d", jni_type_name(*arg), argIndex);
932 }
Yao Chend54f9dd2017-10-17 17:37:48 +0000933 argIndex++;
934 }
935 fprintf(out, ")\n");
936
937 fprintf(out, "{\n");
938
939 // Prepare strings
940 argIndex = 1;
Yangster-mac7604aea2017-12-11 22:55:49 -0800941 bool hadStringOrChain = false;
Yao Chend54f9dd2017-10-17 17:37:48 +0000942 for (vector<java_type_t>::const_iterator arg = signature->begin();
943 arg != signature->end(); arg++) {
944 if (*arg == JAVA_TYPE_STRING) {
Yangster-mac7604aea2017-12-11 22:55:49 -0800945 hadStringOrChain = true;
Yao Chend54f9dd2017-10-17 17:37:48 +0000946 fprintf(out, " const char* str%d;\n", argIndex);
947 fprintf(out, " if (arg%d != NULL) {\n", argIndex);
948 fprintf(out, " str%d = env->GetStringUTFChars(arg%d, NULL);\n",
949 argIndex, argIndex);
950 fprintf(out, " } else {\n");
951 fprintf(out, " str%d = NULL;\n", argIndex);
952 fprintf(out, " }\n");
Yangster-mac7604aea2017-12-11 22:55:49 -0800953 } else if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
954 hadStringOrChain = true;
955 for (auto chainField : attributionDecl.fields) {
956 fprintf(out, " size_t %s_length = env->GetArrayLength(%s);\n",
957 chainField.name.c_str(), chainField.name.c_str());
958 if (chainField.name != attributionDecl.fields.front().name) {
959 fprintf(out, " if (%s_length != %s_length) {\n",
960 chainField.name.c_str(),
961 attributionDecl.fields.front().name.c_str());
Yao Chen97e21ec2018-03-29 11:00:38 -0700962 fprintf(out, " return -EINVAL;\n");
Yangster-mac7604aea2017-12-11 22:55:49 -0800963 fprintf(out, " }\n");
964 }
965 if (chainField.javaType == JAVA_TYPE_INT) {
966 fprintf(out, " jint* %s_array = env->GetIntArrayElements(%s, NULL);\n",
967 chainField.name.c_str(), chainField.name.c_str());
968 } else if (chainField.javaType == JAVA_TYPE_STRING) {
969 fprintf(out, " std::vector<%s> %s_vec;\n",
970 cpp_type_name(chainField.javaType), chainField.name.c_str());
971 fprintf(out, " std::vector<ScopedUtfChars*> scoped_%s_vec;\n",
972 chainField.name.c_str());
973 fprintf(out, " for (size_t i = 0; i < %s_length; ++i) {\n",
974 chainField.name.c_str());
975 fprintf(out, " jstring jstr = "
976 "(jstring)env->GetObjectArrayElement(%s, i);\n",
977 chainField.name.c_str());
Yangster-mac20ac9442018-01-08 14:54:48 -0800978 fprintf(out, " if (jstr == NULL) {\n");
979 fprintf(out, " %s_vec.push_back(NULL);\n",
980 chainField.name.c_str());
981 fprintf(out, " } else {\n");
982 fprintf(out, " ScopedUtfChars* scoped_%s = "
Yangster-mac7604aea2017-12-11 22:55:49 -0800983 "new ScopedUtfChars(env, jstr);\n",
984 chainField.name.c_str());
Yangster-mac20ac9442018-01-08 14:54:48 -0800985 fprintf(out, " %s_vec.push_back(scoped_%s->c_str());\n",
Yangster-mac7604aea2017-12-11 22:55:49 -0800986 chainField.name.c_str(), chainField.name.c_str());
Yangster-mac20ac9442018-01-08 14:54:48 -0800987 fprintf(out, " scoped_%s_vec.push_back(scoped_%s);\n",
Yangster-mac7604aea2017-12-11 22:55:49 -0800988 chainField.name.c_str(), chainField.name.c_str());
Yangster-mac20ac9442018-01-08 14:54:48 -0800989 fprintf(out, " }\n");
Yangster-mac7604aea2017-12-11 22:55:49 -0800990 fprintf(out, " }\n");
991 }
992 fprintf(out, "\n");
993 }
Yao Chend54f9dd2017-10-17 17:37:48 +0000994 }
995 argIndex++;
996 }
Yangster-mac7604aea2017-12-11 22:55:49 -0800997 // Emit this to quiet the unused parameter warning if there were no strings or attribution
998 // chains.
999 if (!hadStringOrChain) {
Yao Chend54f9dd2017-10-17 17:37:48 +00001000 fprintf(out, " (void)env;\n");
1001 }
1002
1003 // stats_write call
1004 argIndex = 1;
Yao Chen97e21ec2018-03-29 11:00:38 -07001005 fprintf(out, " int ret = android::util::%s(code", cpp_method_name.c_str());
Yao Chend54f9dd2017-10-17 17:37:48 +00001006 for (vector<java_type_t>::const_iterator arg = signature->begin();
1007 arg != signature->end(); arg++) {
Yangster-mac7604aea2017-12-11 22:55:49 -08001008 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
1009 for (auto chainField : attributionDecl.fields) {
1010 if (chainField.javaType == JAVA_TYPE_INT) {
1011 fprintf(out, ", (const %s*)%s_array, %s_length",
1012 cpp_type_name(chainField.javaType),
1013 chainField.name.c_str(), chainField.name.c_str());
1014 } else if (chainField.javaType == JAVA_TYPE_STRING) {
1015 fprintf(out, ", %s_vec", chainField.name.c_str());
1016 }
1017 }
1018 } else {
1019 const char *argName = (*arg == JAVA_TYPE_STRING) ? "str" : "arg";
1020 fprintf(out, ", (%s)%s%d", cpp_type_name(*arg), argName, argIndex);
1021 }
Yao Chend54f9dd2017-10-17 17:37:48 +00001022 argIndex++;
1023 }
1024 fprintf(out, ");\n");
Yangster-mac7604aea2017-12-11 22:55:49 -08001025 fprintf(out, "\n");
Yao Chend54f9dd2017-10-17 17:37:48 +00001026
1027 // Clean up strings
1028 argIndex = 1;
1029 for (vector<java_type_t>::const_iterator arg = signature->begin();
1030 arg != signature->end(); arg++) {
1031 if (*arg == JAVA_TYPE_STRING) {
1032 fprintf(out, " if (str%d != NULL) {\n", argIndex);
1033 fprintf(out, " env->ReleaseStringUTFChars(arg%d, str%d);\n",
1034 argIndex, argIndex);
1035 fprintf(out, " }\n");
Yangster-mac7604aea2017-12-11 22:55:49 -08001036 } else if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
1037 for (auto chainField : attributionDecl.fields) {
1038 if (chainField.javaType == JAVA_TYPE_INT) {
1039 fprintf(out, " env->ReleaseIntArrayElements(%s, %s_array, 0);\n",
1040 chainField.name.c_str(), chainField.name.c_str());
1041 } else if (chainField.javaType == JAVA_TYPE_STRING) {
Yangster-mac20ac9442018-01-08 14:54:48 -08001042 fprintf(out, " for (size_t i = 0; i < scoped_%s_vec.size(); ++i) {\n",
Yangster-mac7604aea2017-12-11 22:55:49 -08001043 chainField.name.c_str());
1044 fprintf(out, " delete scoped_%s_vec[i];\n", chainField.name.c_str());
1045 fprintf(out, " }\n");
1046 }
1047 }
Yao Chend54f9dd2017-10-17 17:37:48 +00001048 }
1049 argIndex++;
1050 }
Yao Chen97e21ec2018-03-29 11:00:38 -07001051 fprintf(out, " return ret;\n");
Yao Chend54f9dd2017-10-17 17:37:48 +00001052
1053 fprintf(out, "}\n");
1054 fprintf(out, "\n");
1055 }
1056
Yangster-macba5b9e42018-01-10 21:31:59 -08001057
1058 return 0;
1059}
1060
1061void write_jni_registration(FILE* out, const string& java_method_name,
1062 const set<vector<java_type_t>>& signatures, const AtomDecl &attributionDecl) {
1063 for (set<vector<java_type_t>>::const_iterator signature = signatures.begin();
1064 signature != signatures.end(); signature++) {
1065 fprintf(out, " { \"%s\", \"%s\", (void*)%s },\n",
1066 java_method_name.c_str(),
1067 jni_function_signature(*signature, attributionDecl).c_str(),
1068 jni_function_name(java_method_name, *signature).c_str());
1069 }
1070}
1071
1072static int
1073write_stats_log_jni(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl)
1074{
1075 // Print prelude
1076 fprintf(out, "// This file is autogenerated\n");
1077 fprintf(out, "\n");
1078
1079 fprintf(out, "#include <statslog.h>\n");
1080 fprintf(out, "\n");
1081 fprintf(out, "#include <nativehelper/JNIHelp.h>\n");
1082 fprintf(out, "#include <nativehelper/ScopedUtfChars.h>\n");
1083 fprintf(out, "#include <utils/Vector.h>\n");
1084 fprintf(out, "#include \"core_jni_helpers.h\"\n");
1085 fprintf(out, "#include \"jni.h\"\n");
1086 fprintf(out, "\n");
1087 fprintf(out, "#define UNUSED __attribute__((__unused__))\n");
1088 fprintf(out, "\n");
1089
1090 fprintf(out, "namespace android {\n");
1091 fprintf(out, "\n");
1092
1093 write_stats_log_jni(out, "write", "stats_write", atoms.signatures, attributionDecl);
1094 write_stats_log_jni(out, "write_non_chained", "stats_write_non_chained",
1095 atoms.non_chained_signatures, attributionDecl);
1096
Yao Chend54f9dd2017-10-17 17:37:48 +00001097 // Print registration function table
1098 fprintf(out, "/*\n");
1099 fprintf(out, " * JNI registration.\n");
1100 fprintf(out, " */\n");
1101 fprintf(out, "static const JNINativeMethod gRegisterMethods[] = {\n");
Yangster-macba5b9e42018-01-10 21:31:59 -08001102 write_jni_registration(out, "write", atoms.signatures, attributionDecl);
1103 write_jni_registration(out, "write_non_chained", atoms.non_chained_signatures, attributionDecl);
Yao Chend54f9dd2017-10-17 17:37:48 +00001104 fprintf(out, "};\n");
1105 fprintf(out, "\n");
1106
1107 // Print registration function
1108 fprintf(out, "int register_android_util_StatsLog(JNIEnv* env) {\n");
1109 fprintf(out, " return RegisterMethodsOrDie(\n");
1110 fprintf(out, " env,\n");
1111 fprintf(out, " \"android/util/StatsLog\",\n");
1112 fprintf(out, " gRegisterMethods, NELEM(gRegisterMethods));\n");
1113 fprintf(out, "}\n");
1114
1115 fprintf(out, "\n");
1116 fprintf(out, "} // namespace android\n");
Yao Chend54f9dd2017-10-17 17:37:48 +00001117 return 0;
1118}
1119
Yao Chend54f9dd2017-10-17 17:37:48 +00001120static void
1121print_usage()
1122{
1123 fprintf(stderr, "usage: stats-log-api-gen OPTIONS\n");
1124 fprintf(stderr, "\n");
1125 fprintf(stderr, "OPTIONS\n");
1126 fprintf(stderr, " --cpp FILENAME the header file to output\n");
1127 fprintf(stderr, " --header FILENAME the cpp file to output\n");
1128 fprintf(stderr, " --help this message\n");
1129 fprintf(stderr, " --java FILENAME the java file to output\n");
1130 fprintf(stderr, " --jni FILENAME the jni file to output\n");
1131}
1132
1133/**
1134 * Do the argument parsing and execute the tasks.
1135 */
1136static int
1137run(int argc, char const*const* argv)
1138{
1139 string cppFilename;
1140 string headerFilename;
1141 string javaFilename;
1142 string jniFilename;
1143
1144 int index = 1;
1145 while (index < argc) {
1146 if (0 == strcmp("--help", argv[index])) {
1147 print_usage();
1148 return 0;
1149 } else if (0 == strcmp("--cpp", argv[index])) {
1150 index++;
1151 if (index >= argc) {
1152 print_usage();
1153 return 1;
1154 }
1155 cppFilename = argv[index];
1156 } else if (0 == strcmp("--header", argv[index])) {
1157 index++;
1158 if (index >= argc) {
1159 print_usage();
1160 return 1;
1161 }
1162 headerFilename = argv[index];
1163 } else if (0 == strcmp("--java", argv[index])) {
1164 index++;
1165 if (index >= argc) {
1166 print_usage();
1167 return 1;
1168 }
1169 javaFilename = argv[index];
1170 } else if (0 == strcmp("--jni", argv[index])) {
1171 index++;
1172 if (index >= argc) {
1173 print_usage();
1174 return 1;
1175 }
1176 jniFilename = argv[index];
1177 }
1178 index++;
1179 }
1180
1181 if (cppFilename.size() == 0
1182 && headerFilename.size() == 0
1183 && javaFilename.size() == 0
1184 && jniFilename.size() == 0) {
1185 print_usage();
1186 return 1;
1187 }
1188
1189 // Collate the parameters
1190 Atoms atoms;
Stefan Lafonae2df012017-11-14 09:17:21 -08001191 int errorCount = collate_atoms(Atom::descriptor(), &atoms);
Yao Chend54f9dd2017-10-17 17:37:48 +00001192 if (errorCount != 0) {
1193 return 1;
1194 }
1195
Yangster-mac7604aea2017-12-11 22:55:49 -08001196 AtomDecl attributionDecl;
1197 vector<java_type_t> attributionSignature;
Yangster-mac20877162017-12-22 17:19:39 -08001198 collate_atom(android::os::statsd::AttributionNode::descriptor(),
Yangster-mac7604aea2017-12-11 22:55:49 -08001199 &attributionDecl, &attributionSignature);
1200
Yao Chend54f9dd2017-10-17 17:37:48 +00001201 // Write the .cpp file
1202 if (cppFilename.size() != 0) {
1203 FILE* out = fopen(cppFilename.c_str(), "w");
1204 if (out == NULL) {
1205 fprintf(stderr, "Unable to open file for write: %s\n", cppFilename.c_str());
1206 return 1;
1207 }
Yangster-mac7604aea2017-12-11 22:55:49 -08001208 errorCount = android::stats_log_api_gen::write_stats_log_cpp(
1209 out, atoms, attributionDecl);
Yao Chend54f9dd2017-10-17 17:37:48 +00001210 fclose(out);
1211 }
1212
1213 // Write the .h file
1214 if (headerFilename.size() != 0) {
1215 FILE* out = fopen(headerFilename.c_str(), "w");
1216 if (out == NULL) {
1217 fprintf(stderr, "Unable to open file for write: %s\n", headerFilename.c_str());
1218 return 1;
1219 }
Yangster-mac7604aea2017-12-11 22:55:49 -08001220 errorCount = android::stats_log_api_gen::write_stats_log_header(
1221 out, atoms, attributionDecl);
Yao Chend54f9dd2017-10-17 17:37:48 +00001222 fclose(out);
1223 }
1224
1225 // Write the .java file
1226 if (javaFilename.size() != 0) {
1227 FILE* out = fopen(javaFilename.c_str(), "w");
1228 if (out == NULL) {
1229 fprintf(stderr, "Unable to open file for write: %s\n", javaFilename.c_str());
1230 return 1;
1231 }
Yangster-mac7604aea2017-12-11 22:55:49 -08001232 errorCount = android::stats_log_api_gen::write_stats_log_java(
1233 out, atoms, attributionDecl);
Yao Chend54f9dd2017-10-17 17:37:48 +00001234 fclose(out);
1235 }
1236
1237 // Write the jni file
1238 if (jniFilename.size() != 0) {
1239 FILE* out = fopen(jniFilename.c_str(), "w");
1240 if (out == NULL) {
1241 fprintf(stderr, "Unable to open file for write: %s\n", jniFilename.c_str());
1242 return 1;
1243 }
Yangster-mac7604aea2017-12-11 22:55:49 -08001244 errorCount = android::stats_log_api_gen::write_stats_log_jni(
1245 out, atoms, attributionDecl);
Yao Chend54f9dd2017-10-17 17:37:48 +00001246 fclose(out);
1247 }
1248
1249 return 0;
1250}
1251
1252}
1253}
1254
1255/**
1256 * Main.
1257 */
1258int
1259main(int argc, char const*const* argv)
1260{
1261 GOOGLE_PROTOBUF_VERIFY_VERSION;
1262
1263 return android::stats_log_api_gen::run(argc, argv);
Yangster-mac7604aea2017-12-11 22:55:49 -08001264}