blob: e519909aa0263dc6fa76c29f7c7c65db656fc197 [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 Chencf3829a2018-06-05 14:20:35 -0700107 fprintf(out, "#include <cutils/properties.h>\n");
Yao Chenf7bc6ab2018-04-18 13:45:48 -0700108 fprintf(out, "#include <stats_event_list.h>\n");
Yao Chend54f9dd2017-10-17 17:37:48 +0000109 fprintf(out, "#include <log/log.h>\n");
110 fprintf(out, "#include <statslog.h>\n");
Yangster-mac330af582018-02-08 15:24:38 -0800111 fprintf(out, "#include <utils/SystemClock.h>\n");
Yao Chend54f9dd2017-10-17 17:37:48 +0000112 fprintf(out, "\n");
113
114 fprintf(out, "namespace android {\n");
115 fprintf(out, "namespace util {\n");
Yao Chen80235402017-11-13 20:42:25 -0800116 fprintf(out, "// the single event tag id for all stats logs\n");
117 fprintf(out, "const static int kStatsEventTag = 1937006964;\n");
Yao Chencf3829a2018-06-05 14:20:35 -0700118 fprintf(out, "const static bool kStatsdEnabled = property_get_bool(\"ro.statsd.enable\", true);\n");
Yao Chend54f9dd2017-10-17 17:37:48 +0000119
Yao Chenc40a19d2018-03-15 16:48:25 -0700120 std::set<string> kTruncatingAtomNames = {"mobile_radio_power_state_changed",
121 "audio_state_changed",
122 "call_state_changed",
123 "phone_signal_strength_changed",
124 "mobile_bytes_transfer_by_fg_bg",
125 "mobile_bytes_transfer"};
126 fprintf(out,
127 "const std::set<int> "
128 "AtomsInfo::kNotTruncatingTimestampAtomWhiteList = {\n");
129 for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
130 atom != atoms.decls.end(); atom++) {
131 if (kTruncatingAtomNames.find(atom->name) ==
132 kTruncatingAtomNames.end()) {
133 string constant = make_constant_name(atom->name);
134 fprintf(out, " %s,\n", constant.c_str());
135 }
136 }
137 fprintf(out, "};\n");
138 fprintf(out, "\n");
139
140 fprintf(out,
141 "const std::set<int> AtomsInfo::kAtomsWithAttributionChain = {\n");
142 for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
143 atom != atoms.decls.end(); atom++) {
144 for (vector<AtomField>::const_iterator field = atom->fields.begin();
145 field != atom->fields.end(); field++) {
146 if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
147 string constant = make_constant_name(atom->name);
148 fprintf(out, " %s,\n", constant.c_str());
149 break;
150 }
151 }
152 }
153 fprintf(out, "};\n");
154 fprintf(out, "\n");
155
Yangster-macca5c0862018-04-09 22:39:53 -0700156 fprintf(out, "static std::map<int, int> getAtomUidField() {\n");
Yao Chenc40a19d2018-03-15 16:48:25 -0700157 fprintf(out, " std::map<int, int> uidField;\n");
158 for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
159 atom != atoms.decls.end(); atom++) {
160 if (atom->uidField == 0) {
161 continue;
162 }
163 fprintf(out,
164 "\n // Adding uid field for atom "
165 "(%d)%s\n",
166 atom->code, atom->name.c_str());
167 fprintf(out, " uidField[static_cast<int>(%s)] = %d;\n",
168 make_constant_name(atom->name).c_str(), atom->uidField);
169 }
170
171 fprintf(out, " return uidField;\n");
172 fprintf(out, "};\n");
173
174 fprintf(out,
175 "const std::map<int, int> AtomsInfo::kAtomsWithUidField = "
176 "getAtomUidField();\n");
177
178 fprintf(out,
179 "static std::map<int, StateAtomFieldOptions> "
180 "getStateAtomFieldOptions() {\n");
181 fprintf(out, " std::map<int, StateAtomFieldOptions> options;\n");
182 fprintf(out, " StateAtomFieldOptions opt;\n");
183 for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
184 atom != atoms.decls.end(); atom++) {
185 if (atom->primaryFields.size() == 0 && atom->exclusiveField == 0) {
186 continue;
187 }
188 fprintf(out,
189 "\n // Adding primary and exclusive fields for atom "
190 "(%d)%s\n",
191 atom->code, atom->name.c_str());
192 fprintf(out, " opt.primaryFields.clear();\n");
193 for (const auto& field : atom->primaryFields) {
194 fprintf(out, " opt.primaryFields.push_back(%d);\n", field);
195 }
196
197 fprintf(out, " opt.exclusiveField = %d;\n", atom->exclusiveField);
198 fprintf(out, " options[static_cast<int>(%s)] = opt;\n",
199 make_constant_name(atom->name).c_str());
200 }
201
202 fprintf(out, " return options;\n");
203 fprintf(out, " }\n");
204
205 fprintf(out,
206 "const std::map<int, StateAtomFieldOptions> "
207 "AtomsInfo::kStateAtomsFieldOptions = "
208 "getStateAtomFieldOptions();\n");
209
Yangster-macca5c0862018-04-09 22:39:53 -0700210
211 fprintf(out, "int64_t lastRetryTimestampNs = -1;\n");
212 fprintf(out, "const int64_t kMinRetryIntervalNs = NS_PER_SEC * 60 * 20; // 20 minutes\n");
213 fprintf(out, "static std::mutex mLogdRetryMutex;\n");
214
Yao Chend54f9dd2017-10-17 17:37:48 +0000215 // Print write methods
216 fprintf(out, "\n");
217 for (set<vector<java_type_t>>::const_iterator signature = atoms.signatures.begin();
Yangster-mac7604aea2017-12-11 22:55:49 -0800218 signature != atoms.signatures.end(); signature++) {
Yao Chend54f9dd2017-10-17 17:37:48 +0000219 int argIndex;
220
Yao Chen97e21ec2018-03-29 11:00:38 -0700221 fprintf(out, "int\n");
Yangster-macb8382a12018-04-04 10:39:12 -0700222 fprintf(out, "try_stats_write(int32_t code");
Yao Chend54f9dd2017-10-17 17:37:48 +0000223 argIndex = 1;
224 for (vector<java_type_t>::const_iterator arg = signature->begin();
Yangster-mac7604aea2017-12-11 22:55:49 -0800225 arg != signature->end(); arg++) {
226 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
227 for (auto chainField : attributionDecl.fields) {
228 if (chainField.javaType == JAVA_TYPE_STRING) {
229 fprintf(out, ", const std::vector<%s>& %s",
230 cpp_type_name(chainField.javaType),
231 chainField.name.c_str());
232 } else {
233 fprintf(out, ", const %s* %s, size_t %s_length",
234 cpp_type_name(chainField.javaType),
235 chainField.name.c_str(), chainField.name.c_str());
236 }
237 }
238 } else {
239 fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
240 }
Yao Chend54f9dd2017-10-17 17:37:48 +0000241 argIndex++;
242 }
243 fprintf(out, ")\n");
244
245 fprintf(out, "{\n");
246 argIndex = 1;
Yao Chencf3829a2018-06-05 14:20:35 -0700247 fprintf(out, " if (kStatsdEnabled) {\n");
Yao Chenf7bc6ab2018-04-18 13:45:48 -0700248 fprintf(out, " stats_event_list event(kStatsEventTag);\n");
Yangster-mac330af582018-02-08 15:24:38 -0800249 fprintf(out, " event << android::elapsedRealtimeNano();\n\n");
Yangster-mac7604aea2017-12-11 22:55:49 -0800250 fprintf(out, " event << code;\n\n");
Yao Chend54f9dd2017-10-17 17:37:48 +0000251 for (vector<java_type_t>::const_iterator arg = signature->begin();
Yangster-mac7604aea2017-12-11 22:55:49 -0800252 arg != signature->end(); arg++) {
253 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
254 for (const auto &chainField : attributionDecl.fields) {
255 if (chainField.javaType == JAVA_TYPE_STRING) {
256 fprintf(out, " if (%s_length != %s.size()) {\n",
257 attributionDecl.fields.front().name.c_str(), chainField.name.c_str());
Yao Chen97e21ec2018-03-29 11:00:38 -0700258 fprintf(out, " return -EINVAL;\n");
Yangster-mac7604aea2017-12-11 22:55:49 -0800259 fprintf(out, " }\n");
260 }
261 }
262 fprintf(out, "\n event.begin();\n");
263 fprintf(out, " for (size_t i = 0; i < %s_length; ++i) {\n",
264 attributionDecl.fields.front().name.c_str());
265 fprintf(out, " event.begin();\n");
266 for (const auto &chainField : attributionDecl.fields) {
Yangster-mac20ac9442018-01-08 14:54:48 -0800267 if (chainField.javaType == JAVA_TYPE_STRING) {
268 fprintf(out, " if (%s[i] != NULL) {\n", chainField.name.c_str());
269 fprintf(out, " event << %s[i];\n", chainField.name.c_str());
270 fprintf(out, " } else {\n");
271 fprintf(out, " event << \"\";\n");
272 fprintf(out, " }\n");
273 } else {
274 fprintf(out, " event << %s[i];\n", chainField.name.c_str());
275 }
Yangster-mac7604aea2017-12-11 22:55:49 -0800276 }
277 fprintf(out, " event.end();\n");
Yao Chend54f9dd2017-10-17 17:37:48 +0000278 fprintf(out, " }\n");
Yangster-mac7604aea2017-12-11 22:55:49 -0800279 fprintf(out, " event.end();\n\n");
280 } else {
281 if (*arg == JAVA_TYPE_STRING) {
282 fprintf(out, " if (arg%d == NULL) {\n", argIndex);
283 fprintf(out, " arg%d = \"\";\n", argIndex);
284 fprintf(out, " }\n");
285 }
286 fprintf(out, " event << arg%d;\n", argIndex);
Yao Chend54f9dd2017-10-17 17:37:48 +0000287 }
Yao Chend54f9dd2017-10-17 17:37:48 +0000288 argIndex++;
289 }
290
Yao Chen97e21ec2018-03-29 11:00:38 -0700291 fprintf(out, " return event.write(LOG_ID_STATS);\n");
Yao Chencf3829a2018-06-05 14:20:35 -0700292 fprintf(out, " } else {\n");
293 fprintf(out, " return 1;\n");
294 fprintf(out, " }\n");
Yao Chend54f9dd2017-10-17 17:37:48 +0000295 fprintf(out, "}\n");
296 fprintf(out, "\n");
297 }
298
Yangster-macb8382a12018-04-04 10:39:12 -0700299 for (set<vector<java_type_t>>::const_iterator signature = atoms.signatures.begin();
300 signature != atoms.signatures.end(); signature++) {
301 int argIndex;
302
303 fprintf(out, "int \n");
304 fprintf(out, "stats_write(int32_t code");
305 argIndex = 1;
306 for (vector<java_type_t>::const_iterator arg = signature->begin();
307 arg != signature->end(); arg++) {
308 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
309 for (auto chainField : attributionDecl.fields) {
310 if (chainField.javaType == JAVA_TYPE_STRING) {
311 fprintf(out, ", const std::vector<%s>& %s",
312 cpp_type_name(chainField.javaType),
313 chainField.name.c_str());
314 } else {
315 fprintf(out, ", const %s* %s, size_t %s_length",
316 cpp_type_name(chainField.javaType),
317 chainField.name.c_str(), chainField.name.c_str());
318 }
319 }
320 } else {
321 fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
322 }
323 argIndex++;
324 }
325 fprintf(out, ")\n");
326
327 fprintf(out, "{\n");
328 fprintf(out, " int ret = 0;\n");
329
Yangster-macca5c0862018-04-09 22:39:53 -0700330 fprintf(out, " for(int retry = 0; retry < 2; ++retry) {\n");
Yangster-macb8382a12018-04-04 10:39:12 -0700331 fprintf(out, " ret = try_stats_write(code");
332
333 argIndex = 1;
334 for (vector<java_type_t>::const_iterator arg = signature->begin();
335 arg != signature->end(); arg++) {
336 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
337 for (auto chainField : attributionDecl.fields) {
338 if (chainField.javaType == JAVA_TYPE_STRING) {
339 fprintf(out, ", %s",
340 chainField.name.c_str());
341 } else {
342 fprintf(out, ", %s, %s_length",
343 chainField.name.c_str(), chainField.name.c_str());
344 }
345 }
346 } else {
347 fprintf(out, ", arg%d", argIndex);
348 }
349 argIndex++;
350 }
351 fprintf(out, ");\n");
352 fprintf(out, " if (ret >= 0) { return retry; }\n");
Yangster-macca5c0862018-04-09 22:39:53 -0700353
354
355 fprintf(out, " {\n");
356 fprintf(out, " std::lock_guard<std::mutex> lock(mLogdRetryMutex);\n");
357 fprintf(out, " if ((android::elapsedRealtimeNano() - lastRetryTimestampNs) <= "
358 "kMinRetryIntervalNs) break;\n");
359 fprintf(out, " lastRetryTimestampNs = android::elapsedRealtimeNano();\n");
360 fprintf(out, " }\n");
361 fprintf(out, " std::this_thread::sleep_for(std::chrono::milliseconds(10));\n");
Yangster-macb8382a12018-04-04 10:39:12 -0700362 fprintf(out, " }\n");
363 fprintf(out, " return ret;\n");
364 fprintf(out, "}\n");
365 fprintf(out, "\n");
366 }
367
Yangster-macba5b9e42018-01-10 21:31:59 -0800368 for (set<vector<java_type_t>>::const_iterator signature = atoms.non_chained_signatures.begin();
369 signature != atoms.non_chained_signatures.end(); signature++) {
370 int argIndex;
371
Yao Chen97e21ec2018-03-29 11:00:38 -0700372 fprintf(out, "int\n");
Yangster-macb8382a12018-04-04 10:39:12 -0700373 fprintf(out, "try_stats_write_non_chained(int32_t code");
Yangster-macba5b9e42018-01-10 21:31:59 -0800374 argIndex = 1;
375 for (vector<java_type_t>::const_iterator arg = signature->begin();
376 arg != signature->end(); arg++) {
377 fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
378 argIndex++;
379 }
380 fprintf(out, ")\n");
381
382 fprintf(out, "{\n");
383 argIndex = 1;
Yao Chencf3829a2018-06-05 14:20:35 -0700384 fprintf(out, " if (kStatsdEnabled) {\n");
Yao Chenf7bc6ab2018-04-18 13:45:48 -0700385 fprintf(out, " stats_event_list event(kStatsEventTag);\n");
Yangster-mac31ddcde2018-02-14 16:09:35 -0800386 fprintf(out, " event << android::elapsedRealtimeNano();\n\n");
Yangster-macba5b9e42018-01-10 21:31:59 -0800387 fprintf(out, " event << code;\n\n");
388 for (vector<java_type_t>::const_iterator arg = signature->begin();
389 arg != signature->end(); arg++) {
390 if (argIndex == 1) {
391 fprintf(out, " event.begin();\n\n");
392 fprintf(out, " event.begin();\n");
393 }
394 if (*arg == JAVA_TYPE_STRING) {
395 fprintf(out, " if (arg%d == NULL) {\n", argIndex);
396 fprintf(out, " arg%d = \"\";\n", argIndex);
397 fprintf(out, " }\n");
398 }
399 fprintf(out, " event << arg%d;\n", argIndex);
400 if (argIndex == 2) {
401 fprintf(out, " event.end();\n\n");
402 fprintf(out, " event.end();\n\n");
403 }
404 argIndex++;
405 }
406
Yao Chen97e21ec2018-03-29 11:00:38 -0700407 fprintf(out, " return event.write(LOG_ID_STATS);\n");
Yao Chencf3829a2018-06-05 14:20:35 -0700408 fprintf(out, " } else {\n");
409 fprintf(out, " return 1;\n");
410 fprintf(out, " }\n");
Yangster-macba5b9e42018-01-10 21:31:59 -0800411 fprintf(out, "}\n");
412 fprintf(out, "\n");
413 }
Yangster-macb8382a12018-04-04 10:39:12 -0700414
415 for (set<vector<java_type_t>>::const_iterator signature = atoms.non_chained_signatures.begin();
416 signature != atoms.non_chained_signatures.end(); signature++) {
417 int argIndex;
418
419 fprintf(out, "int\n");
420 fprintf(out, "stats_write_non_chained(int32_t code");
421 argIndex = 1;
422 for (vector<java_type_t>::const_iterator arg = signature->begin();
423 arg != signature->end(); arg++) {
424 fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
425 argIndex++;
426 }
427 fprintf(out, ")\n");
428
429 fprintf(out, "{\n");
430
431 fprintf(out, " int ret = 0;\n");
Yangster-macca5c0862018-04-09 22:39:53 -0700432 fprintf(out, " for(int retry = 0; retry < 2; ++retry) {\n");
Yangster-macb8382a12018-04-04 10:39:12 -0700433 fprintf(out, " ret = try_stats_write_non_chained(code");
434
435 argIndex = 1;
436 for (vector<java_type_t>::const_iterator arg = signature->begin();
437 arg != signature->end(); arg++) {
438 fprintf(out, ", arg%d", argIndex);
439 argIndex++;
440 }
441 fprintf(out, ");\n");
442 fprintf(out, " if (ret >= 0) { return retry; }\n");
Yangster-macca5c0862018-04-09 22:39:53 -0700443
444 fprintf(out, " {\n");
445 fprintf(out, " std::lock_guard<std::mutex> lock(mLogdRetryMutex);\n");
446 fprintf(out, " if ((android::elapsedRealtimeNano() - lastRetryTimestampNs) <= "
447 "kMinRetryIntervalNs) break;\n");
448 fprintf(out, " lastRetryTimestampNs = android::elapsedRealtimeNano();\n");
449 fprintf(out, " }\n");
450
451 fprintf(out, " std::this_thread::sleep_for(std::chrono::milliseconds(10));\n");
Yangster-macb8382a12018-04-04 10:39:12 -0700452 fprintf(out, " }\n");
453 fprintf(out, " return ret;\n");
454 fprintf(out, "}\n");
455
456 fprintf(out, "\n");
457 }
458
459
Yao Chend54f9dd2017-10-17 17:37:48 +0000460 // Print footer
461 fprintf(out, "\n");
462 fprintf(out, "} // namespace util\n");
463 fprintf(out, "} // namespace android\n");
464
465 return 0;
466}
467
Yangster-macba5b9e42018-01-10 21:31:59 -0800468void build_non_chained_decl_map(const Atoms& atoms,
469 std::map<int, set<AtomDecl>::const_iterator>* decl_map){
470 for (set<AtomDecl>::const_iterator atom = atoms.non_chained_decls.begin();
471 atom != atoms.non_chained_decls.end(); atom++) {
472 decl_map->insert(std::make_pair(atom->code, atom));
473 }
474}
475
476static void write_cpp_usage(
477 FILE* out, const string& method_name, const string& atom_code_name,
478 const AtomDecl& atom, const AtomDecl &attributionDecl) {
479 fprintf(out, " * Usage: %s(StatsLog.%s", method_name.c_str(), atom_code_name.c_str());
480 for (vector<AtomField>::const_iterator field = atom.fields.begin();
481 field != atom.fields.end(); field++) {
482 if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
483 for (auto chainField : attributionDecl.fields) {
484 if (chainField.javaType == JAVA_TYPE_STRING) {
485 fprintf(out, ", const std::vector<%s>& %s",
486 cpp_type_name(chainField.javaType),
487 chainField.name.c_str());
488 } else {
489 fprintf(out, ", const %s* %s, size_t %s_length",
490 cpp_type_name(chainField.javaType),
491 chainField.name.c_str(), chainField.name.c_str());
492 }
493 }
494 } else {
495 fprintf(out, ", %s %s", cpp_type_name(field->javaType), field->name.c_str());
496 }
497 }
498 fprintf(out, ");\n");
499}
500
501static void write_cpp_method_header(
502 FILE* out, const string& method_name, const set<vector<java_type_t>>& signatures,
503 const AtomDecl &attributionDecl) {
504 for (set<vector<java_type_t>>::const_iterator signature = signatures.begin();
505 signature != signatures.end(); signature++) {
Yao Chen97e21ec2018-03-29 11:00:38 -0700506 fprintf(out, "int %s(int32_t code ", method_name.c_str());
Yangster-macba5b9e42018-01-10 21:31:59 -0800507 int argIndex = 1;
508 for (vector<java_type_t>::const_iterator arg = signature->begin();
509 arg != signature->end(); arg++) {
510 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
511 for (auto chainField : attributionDecl.fields) {
512 if (chainField.javaType == JAVA_TYPE_STRING) {
513 fprintf(out, ", const std::vector<%s>& %s",
514 cpp_type_name(chainField.javaType), chainField.name.c_str());
515 } else {
516 fprintf(out, ", const %s* %s, size_t %s_length",
517 cpp_type_name(chainField.javaType),
518 chainField.name.c_str(), chainField.name.c_str());
519 }
520 }
521 } else {
522 fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
523 }
524 argIndex++;
525 }
526 fprintf(out, ");\n");
527
528 }
529}
Yao Chend54f9dd2017-10-17 17:37:48 +0000530
531static int
Yangster-mac7604aea2017-12-11 22:55:49 -0800532write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl)
Yao Chend54f9dd2017-10-17 17:37:48 +0000533{
Yao Chend54f9dd2017-10-17 17:37:48 +0000534 // Print prelude
535 fprintf(out, "// This file is autogenerated\n");
536 fprintf(out, "\n");
537 fprintf(out, "#pragma once\n");
538 fprintf(out, "\n");
539 fprintf(out, "#include <stdint.h>\n");
Yangster-mac7604aea2017-12-11 22:55:49 -0800540 fprintf(out, "#include <vector>\n");
Yao Chen9c1debe2018-02-19 14:39:19 -0800541 fprintf(out, "#include <map>\n");
Yangster-mac68985802018-01-21 10:05:09 -0800542 fprintf(out, "#include <set>\n");
Yao Chend54f9dd2017-10-17 17:37:48 +0000543 fprintf(out, "\n");
544
545 fprintf(out, "namespace android {\n");
546 fprintf(out, "namespace util {\n");
547 fprintf(out, "\n");
548 fprintf(out, "/*\n");
549 fprintf(out, " * API For logging statistics events.\n");
550 fprintf(out, " */\n");
551 fprintf(out, "\n");
552 fprintf(out, "/**\n");
Stefan Lafon9478f352017-10-30 21:20:20 -0700553 fprintf(out, " * Constants for atom codes.\n");
Yao Chend54f9dd2017-10-17 17:37:48 +0000554 fprintf(out, " */\n");
555 fprintf(out, "enum {\n");
556
Yangster-macba5b9e42018-01-10 21:31:59 -0800557 std::map<int, set<AtomDecl>::const_iterator> atom_code_to_non_chained_decl_map;
558 build_non_chained_decl_map(atoms, &atom_code_to_non_chained_decl_map);
559
Yao Chend54f9dd2017-10-17 17:37:48 +0000560 size_t i = 0;
561 // Print constants
562 for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
Yangster-mac7604aea2017-12-11 22:55:49 -0800563 atom != atoms.decls.end(); atom++) {
Yao Chend54f9dd2017-10-17 17:37:48 +0000564 string constant = make_constant_name(atom->name);
565 fprintf(out, "\n");
566 fprintf(out, " /**\n");
567 fprintf(out, " * %s %s\n", atom->message.c_str(), atom->name.c_str());
Yangster-macba5b9e42018-01-10 21:31:59 -0800568 write_cpp_usage(out, "stats_write", constant, *atom, attributionDecl);
569
570 auto non_chained_decl = atom_code_to_non_chained_decl_map.find(atom->code);
571 if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) {
572 write_cpp_usage(out, "stats_write_non_chained", constant, *non_chained_decl->second,
573 attributionDecl);
Yao Chend54f9dd2017-10-17 17:37:48 +0000574 }
Yao Chend54f9dd2017-10-17 17:37:48 +0000575 fprintf(out, " */\n");
576 char const* const comma = (i == atoms.decls.size() - 1) ? "" : ",";
577 fprintf(out, " %s = %d%s\n", constant.c_str(), atom->code, comma);
Yao Chenb3561512017-11-21 18:07:17 -0800578 if (atom->code < PULL_ATOM_START_ID && atom->code > maxPushedAtomId) {
579 maxPushedAtomId = atom->code;
580 }
Yao Chend54f9dd2017-10-17 17:37:48 +0000581 i++;
582 }
583 fprintf(out, "\n");
584 fprintf(out, "};\n");
585 fprintf(out, "\n");
586
Yao Chen9c1debe2018-02-19 14:39:19 -0800587 fprintf(out, "struct StateAtomFieldOptions {\n");
588 fprintf(out, " std::vector<int> primaryFields;\n");
589 fprintf(out, " int exclusiveField;\n");
Yao Chenc40a19d2018-03-15 16:48:25 -0700590 fprintf(out, "};\n");
Yao Chen9c1debe2018-02-19 14:39:19 -0800591 fprintf(out, "\n");
Yao Chenc40a19d2018-03-15 16:48:25 -0700592
593 fprintf(out, "struct AtomsInfo {\n");
Yao Chen9c1debe2018-02-19 14:39:19 -0800594 fprintf(out,
Yao Chenc40a19d2018-03-15 16:48:25 -0700595 " const static std::set<int> "
596 "kNotTruncatingTimestampAtomWhiteList;\n");
597 fprintf(out, " const static std::map<int, int> kAtomsWithUidField;\n");
598 fprintf(out,
599 " const static std::set<int> kAtomsWithAttributionChain;\n");
600 fprintf(out,
601 " const static std::map<int, StateAtomFieldOptions> "
602 "kStateAtomsFieldOptions;\n");
Yao Chen9c1debe2018-02-19 14:39:19 -0800603 fprintf(out, "};\n");
604
Yao Chenc40a19d2018-03-15 16:48:25 -0700605 fprintf(out, "const static int kMaxPushedAtomId = %d;\n\n",
606 maxPushedAtomId);
Yao Chen9c1debe2018-02-19 14:39:19 -0800607
Yao Chend54f9dd2017-10-17 17:37:48 +0000608 // Print write methods
609 fprintf(out, "//\n");
610 fprintf(out, "// Write methods\n");
611 fprintf(out, "//\n");
Yangster-macba5b9e42018-01-10 21:31:59 -0800612 write_cpp_method_header(out, "stats_write", atoms.signatures, attributionDecl);
613
614 fprintf(out, "//\n");
615 fprintf(out, "// Write flattened methods\n");
616 fprintf(out, "//\n");
617 write_cpp_method_header(out, "stats_write_non_chained", atoms.non_chained_signatures,
618 attributionDecl);
Yao Chend54f9dd2017-10-17 17:37:48 +0000619
620 fprintf(out, "\n");
621 fprintf(out, "} // namespace util\n");
622 fprintf(out, "} // namespace android\n");
623
624 return 0;
625}
626
Bookatz0bd97202018-06-05 12:42:37 -0700627static void write_java_usage(FILE* out, const string& method_name, const string& atom_code_name,
628 const AtomDecl& atom) {
Yangster-macba5b9e42018-01-10 21:31:59 -0800629 fprintf(out, " * Usage: StatsLog.%s(StatsLog.%s",
630 method_name.c_str(), atom_code_name.c_str());
631 for (vector<AtomField>::const_iterator field = atom.fields.begin();
632 field != atom.fields.end(); field++) {
633 if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
Bookatz0bd97202018-06-05 12:42:37 -0700634 fprintf(out, ", android.os.WorkSource workSource");
Yangster-macba5b9e42018-01-10 21:31:59 -0800635 } else {
636 fprintf(out, ", %s %s", java_type_name(field->javaType), field->name.c_str());
637 }
638 }
Bookatz0bd97202018-06-05 12:42:37 -0700639 fprintf(out, ");<br>\n");
Yangster-macba5b9e42018-01-10 21:31:59 -0800640}
641
642static void write_java_method(
643 FILE* out, const string& method_name, const set<vector<java_type_t>>& signatures,
644 const AtomDecl &attributionDecl) {
645 for (set<vector<java_type_t>>::const_iterator signature = signatures.begin();
646 signature != signatures.end(); signature++) {
Yao Chen97e21ec2018-03-29 11:00:38 -0700647 fprintf(out, " public static native int %s(int code", method_name.c_str());
Yangster-macba5b9e42018-01-10 21:31:59 -0800648 int argIndex = 1;
649 for (vector<java_type_t>::const_iterator arg = signature->begin();
650 arg != signature->end(); arg++) {
651 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
652 for (auto chainField : attributionDecl.fields) {
653 fprintf(out, ", %s[] %s",
654 java_type_name(chainField.javaType), chainField.name.c_str());
655 }
656 } else {
657 fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
658 }
659 argIndex++;
660 }
661 fprintf(out, ");\n");
662 }
663}
664
Bookatz0bd97202018-06-05 12:42:37 -0700665static void write_java_work_source_method(FILE* out, const set<vector<java_type_t>>& signatures) {
666 fprintf(out, "\n // WorkSource methods.\n");
667 for (set<vector<java_type_t>>::const_iterator signature = signatures.begin();
668 signature != signatures.end(); signature++) {
669 // Determine if there is Attribution in this signature.
670 int attributionArg = -1;
671 int argIndexMax = 0;
672 for (vector<java_type_t>::const_iterator arg = signature->begin();
673 arg != signature->end(); arg++) {
674 argIndexMax++;
675 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
676 if (attributionArg > -1) {
677 fprintf(stderr, "An atom contains multiple AttributionNode fields.\n");
678 fprintf(stderr, "This is not supported. Aborting WorkSource method writing.\n");
679 fprintf(out, "\n// Invalid for WorkSource: more than one attribution chain.\n");
680 return;
681 }
682 attributionArg = argIndexMax;
683 }
684 }
685 if (attributionArg < 0) {
686 continue;
687 }
688
689 // Method header (signature)
690 fprintf(out, " public static void write(int code");
691 int argIndex = 1;
692 for (vector<java_type_t>::const_iterator arg = signature->begin();
693 arg != signature->end(); arg++) {
694 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
695 fprintf(out, ", WorkSource ws");
696 } else {
697 fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
698 }
699 argIndex++;
700 }
701 fprintf(out, ") {\n");
702
703 // write_non_chained() component. TODO: Remove when flat uids are no longer needed.
704 fprintf(out, " for (int i = 0; i < ws.size(); ++i) {\n");
705 fprintf(out, " write_non_chained(code");
706 for (int argIndex = 1; argIndex <= argIndexMax; argIndex++) {
707 if (argIndex == attributionArg) {
708 fprintf(out, ", ws.get(i), ws.getName(i)");
709 } else {
710 fprintf(out, ", arg%d", argIndex);
711 }
712 }
713 fprintf(out, ");\n");
714 fprintf(out, " }\n"); // close flor-loop
715
716 // write() component.
717 fprintf(out, " ArrayList<WorkSource.WorkChain> workChains = ws.getWorkChains();\n");
718 fprintf(out, " if (workChains != null) {\n");
719 fprintf(out, " for (WorkSource.WorkChain wc : workChains) {\n");
720 fprintf(out, " write(code");
721 for (int argIndex = 1; argIndex <= argIndexMax; argIndex++) {
722 if (argIndex == attributionArg) {
723 fprintf(out, ", wc.getUids(), wc.getTags()");
724 } else {
725 fprintf(out, ", arg%d", argIndex);
726 }
727 }
728 fprintf(out, ");\n");
729 fprintf(out, " }\n"); // close for-loop
730 fprintf(out, " }\n"); // close if
731 fprintf(out, " }\n"); // close method
732 }
733}
Yangster-macba5b9e42018-01-10 21:31:59 -0800734
Yao Chend54f9dd2017-10-17 17:37:48 +0000735static int
Yangster-mac7604aea2017-12-11 22:55:49 -0800736write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl)
Yao Chend54f9dd2017-10-17 17:37:48 +0000737{
Yao Chend54f9dd2017-10-17 17:37:48 +0000738 // Print prelude
739 fprintf(out, "// This file is autogenerated\n");
740 fprintf(out, "\n");
741 fprintf(out, "package android.util;\n");
742 fprintf(out, "\n");
Bookatz0bd97202018-06-05 12:42:37 -0700743 fprintf(out, "import android.os.WorkSource;\n");
744 fprintf(out, "import java.util.ArrayList;\n");
745 fprintf(out, "\n");
Yao Chend54f9dd2017-10-17 17:37:48 +0000746 fprintf(out, "\n");
747 fprintf(out, "/**\n");
748 fprintf(out, " * API For logging statistics events.\n");
749 fprintf(out, " * @hide\n");
750 fprintf(out, " */\n");
David Chen0a368b22017-12-06 16:28:16 -0800751 fprintf(out, "public class StatsLogInternal {\n");
Stefan Lafon9478f352017-10-30 21:20:20 -0700752 fprintf(out, " // Constants for atom codes.\n");
Yao Chend54f9dd2017-10-17 17:37:48 +0000753
Yangster-macba5b9e42018-01-10 21:31:59 -0800754 std::map<int, set<AtomDecl>::const_iterator> atom_code_to_non_chained_decl_map;
755 build_non_chained_decl_map(atoms, &atom_code_to_non_chained_decl_map);
756
Stefan Lafon9478f352017-10-30 21:20:20 -0700757 // Print constants for the atom codes.
Yao Chend54f9dd2017-10-17 17:37:48 +0000758 for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
759 atom != atoms.decls.end(); atom++) {
760 string constant = make_constant_name(atom->name);
761 fprintf(out, "\n");
762 fprintf(out, " /**\n");
Bookatz0bd97202018-06-05 12:42:37 -0700763 fprintf(out, " * %s %s<br>\n", atom->message.c_str(), atom->name.c_str());
764 write_java_usage(out, "write", constant, *atom);
Yangster-macba5b9e42018-01-10 21:31:59 -0800765 auto non_chained_decl = atom_code_to_non_chained_decl_map.find(atom->code);
766 if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) {
Bookatz0bd97202018-06-05 12:42:37 -0700767 write_java_usage(out, "write_non_chained", constant, *non_chained_decl->second);
Yao Chend54f9dd2017-10-17 17:37:48 +0000768 }
Yao Chend54f9dd2017-10-17 17:37:48 +0000769 fprintf(out, " */\n");
770 fprintf(out, " public static final int %s = %d;\n", constant.c_str(), atom->code);
771 }
772 fprintf(out, "\n");
773
Stefan Lafon9478f352017-10-30 21:20:20 -0700774 // Print constants for the enum values.
775 fprintf(out, " // Constants for enum values.\n\n");
776 for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
Yangster-mac7604aea2017-12-11 22:55:49 -0800777 atom != atoms.decls.end(); atom++) {
Stefan Lafon9478f352017-10-30 21:20:20 -0700778 for (vector<AtomField>::const_iterator field = atom->fields.begin();
Yangster-mac7604aea2017-12-11 22:55:49 -0800779 field != atom->fields.end(); field++) {
780 if (field->javaType == JAVA_TYPE_ENUM) {
781 fprintf(out, " // Values for %s.%s\n", atom->message.c_str(),
782 field->name.c_str());
783 for (map<int, string>::const_iterator value = field->enumValues.begin();
784 value != field->enumValues.end(); value++) {
785 fprintf(out, " public static final int %s__%s__%s = %d;\n",
786 make_constant_name(atom->message).c_str(),
787 make_constant_name(field->name).c_str(),
788 make_constant_name(value->second).c_str(),
789 value->first);
790 }
791 fprintf(out, "\n");
Stefan Lafon9478f352017-10-30 21:20:20 -0700792 }
Stefan Lafon9478f352017-10-30 21:20:20 -0700793 }
794 }
795
Yao Chend54f9dd2017-10-17 17:37:48 +0000796 // Print write methods
797 fprintf(out, " // Write methods\n");
Yangster-macba5b9e42018-01-10 21:31:59 -0800798 write_java_method(out, "write", atoms.signatures, attributionDecl);
799 write_java_method(out, "write_non_chained", atoms.non_chained_signatures, attributionDecl);
Bookatz0bd97202018-06-05 12:42:37 -0700800 write_java_work_source_method(out, atoms.signatures);
Yao Chend54f9dd2017-10-17 17:37:48 +0000801
802 fprintf(out, "}\n");
803
804 return 0;
805}
806
807static const char*
808jni_type_name(java_type_t type)
809{
810 switch (type) {
811 case JAVA_TYPE_BOOLEAN:
812 return "jboolean";
813 case JAVA_TYPE_INT:
Stefan Lafon9478f352017-10-30 21:20:20 -0700814 case JAVA_TYPE_ENUM:
Yao Chend54f9dd2017-10-17 17:37:48 +0000815 return "jint";
816 case JAVA_TYPE_LONG:
817 return "jlong";
818 case JAVA_TYPE_FLOAT:
819 return "jfloat";
820 case JAVA_TYPE_DOUBLE:
821 return "jdouble";
822 case JAVA_TYPE_STRING:
823 return "jstring";
824 default:
825 return "UNKNOWN";
826 }
827}
828
Yangster-mac7604aea2017-12-11 22:55:49 -0800829static const char*
830jni_array_type_name(java_type_t type)
831{
832 switch (type) {
833 case JAVA_TYPE_INT:
834 return "jintArray";
835 case JAVA_TYPE_STRING:
836 return "jobjectArray";
837 default:
838 return "UNKNOWN";
839 }
840}
841
Yao Chend54f9dd2017-10-17 17:37:48 +0000842static string
Yangster-macba5b9e42018-01-10 21:31:59 -0800843jni_function_name(const string& method_name, const vector<java_type_t>& signature)
Yao Chend54f9dd2017-10-17 17:37:48 +0000844{
Yangster-macba5b9e42018-01-10 21:31:59 -0800845 string result("StatsLog_" + method_name);
Yao Chend54f9dd2017-10-17 17:37:48 +0000846 for (vector<java_type_t>::const_iterator arg = signature.begin();
Yangster-mac7604aea2017-12-11 22:55:49 -0800847 arg != signature.end(); arg++) {
Yao Chend54f9dd2017-10-17 17:37:48 +0000848 switch (*arg) {
849 case JAVA_TYPE_BOOLEAN:
850 result += "_boolean";
851 break;
852 case JAVA_TYPE_INT:
Stefan Lafon9478f352017-10-30 21:20:20 -0700853 case JAVA_TYPE_ENUM:
Yao Chend54f9dd2017-10-17 17:37:48 +0000854 result += "_int";
855 break;
856 case JAVA_TYPE_LONG:
857 result += "_long";
858 break;
859 case JAVA_TYPE_FLOAT:
860 result += "_float";
861 break;
862 case JAVA_TYPE_DOUBLE:
863 result += "_double";
864 break;
865 case JAVA_TYPE_STRING:
866 result += "_String";
867 break;
Yangster-mac7604aea2017-12-11 22:55:49 -0800868 case JAVA_TYPE_ATTRIBUTION_CHAIN:
869 result += "_AttributionChain";
870 break;
Yao Chend54f9dd2017-10-17 17:37:48 +0000871 default:
872 result += "_UNKNOWN";
873 break;
874 }
875 }
876 return result;
877}
878
879static const char*
880java_type_signature(java_type_t type)
881{
882 switch (type) {
883 case JAVA_TYPE_BOOLEAN:
884 return "Z";
885 case JAVA_TYPE_INT:
Stefan Lafon9478f352017-10-30 21:20:20 -0700886 case JAVA_TYPE_ENUM:
Yao Chend54f9dd2017-10-17 17:37:48 +0000887 return "I";
888 case JAVA_TYPE_LONG:
889 return "J";
890 case JAVA_TYPE_FLOAT:
891 return "F";
892 case JAVA_TYPE_DOUBLE:
893 return "D";
894 case JAVA_TYPE_STRING:
895 return "Ljava/lang/String;";
896 default:
897 return "UNKNOWN";
898 }
899}
900
901static string
Yangster-mac7604aea2017-12-11 22:55:49 -0800902jni_function_signature(const vector<java_type_t>& signature, const AtomDecl &attributionDecl)
Yao Chend54f9dd2017-10-17 17:37:48 +0000903{
904 string result("(I");
905 for (vector<java_type_t>::const_iterator arg = signature.begin();
Yangster-mac7604aea2017-12-11 22:55:49 -0800906 arg != signature.end(); arg++) {
907 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
908 for (auto chainField : attributionDecl.fields) {
909 result += "[";
910 result += java_type_signature(chainField.javaType);
911 }
912 } else {
913 result += java_type_signature(*arg);
914 }
Yao Chend54f9dd2017-10-17 17:37:48 +0000915 }
Yao Chen97e21ec2018-03-29 11:00:38 -0700916 result += ")I";
Yao Chend54f9dd2017-10-17 17:37:48 +0000917 return result;
918}
919
920static int
Yangster-macba5b9e42018-01-10 21:31:59 -0800921write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp_method_name,
922 const set<vector<java_type_t>>& signatures, const AtomDecl &attributionDecl)
Yao Chend54f9dd2017-10-17 17:37:48 +0000923{
Yao Chend54f9dd2017-10-17 17:37:48 +0000924 // Print write methods
Yangster-macba5b9e42018-01-10 21:31:59 -0800925 for (set<vector<java_type_t>>::const_iterator signature = signatures.begin();
926 signature != signatures.end(); signature++) {
Yao Chend54f9dd2017-10-17 17:37:48 +0000927 int argIndex;
928
Yao Chen97e21ec2018-03-29 11:00:38 -0700929 fprintf(out, "static int\n");
Yao Chend54f9dd2017-10-17 17:37:48 +0000930 fprintf(out, "%s(JNIEnv* env, jobject clazz UNUSED, jint code",
Yangster-macba5b9e42018-01-10 21:31:59 -0800931 jni_function_name(java_method_name, *signature).c_str());
Yao Chend54f9dd2017-10-17 17:37:48 +0000932 argIndex = 1;
933 for (vector<java_type_t>::const_iterator arg = signature->begin();
934 arg != signature->end(); arg++) {
Yangster-mac7604aea2017-12-11 22:55:49 -0800935 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
936 for (auto chainField : attributionDecl.fields) {
937 fprintf(out, ", %s %s", jni_array_type_name(chainField.javaType),
938 chainField.name.c_str());
939 }
940 } else {
941 fprintf(out, ", %s arg%d", jni_type_name(*arg), argIndex);
942 }
Yao Chend54f9dd2017-10-17 17:37:48 +0000943 argIndex++;
944 }
945 fprintf(out, ")\n");
946
947 fprintf(out, "{\n");
948
949 // Prepare strings
950 argIndex = 1;
Yangster-mac7604aea2017-12-11 22:55:49 -0800951 bool hadStringOrChain = false;
Yao Chend54f9dd2017-10-17 17:37:48 +0000952 for (vector<java_type_t>::const_iterator arg = signature->begin();
953 arg != signature->end(); arg++) {
954 if (*arg == JAVA_TYPE_STRING) {
Yangster-mac7604aea2017-12-11 22:55:49 -0800955 hadStringOrChain = true;
Yao Chend54f9dd2017-10-17 17:37:48 +0000956 fprintf(out, " const char* str%d;\n", argIndex);
957 fprintf(out, " if (arg%d != NULL) {\n", argIndex);
958 fprintf(out, " str%d = env->GetStringUTFChars(arg%d, NULL);\n",
959 argIndex, argIndex);
960 fprintf(out, " } else {\n");
961 fprintf(out, " str%d = NULL;\n", argIndex);
962 fprintf(out, " }\n");
Yangster-mac7604aea2017-12-11 22:55:49 -0800963 } else if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
964 hadStringOrChain = true;
965 for (auto chainField : attributionDecl.fields) {
966 fprintf(out, " size_t %s_length = env->GetArrayLength(%s);\n",
967 chainField.name.c_str(), chainField.name.c_str());
968 if (chainField.name != attributionDecl.fields.front().name) {
969 fprintf(out, " if (%s_length != %s_length) {\n",
970 chainField.name.c_str(),
971 attributionDecl.fields.front().name.c_str());
Yao Chen97e21ec2018-03-29 11:00:38 -0700972 fprintf(out, " return -EINVAL;\n");
Yangster-mac7604aea2017-12-11 22:55:49 -0800973 fprintf(out, " }\n");
974 }
975 if (chainField.javaType == JAVA_TYPE_INT) {
976 fprintf(out, " jint* %s_array = env->GetIntArrayElements(%s, NULL);\n",
977 chainField.name.c_str(), chainField.name.c_str());
978 } else if (chainField.javaType == JAVA_TYPE_STRING) {
979 fprintf(out, " std::vector<%s> %s_vec;\n",
980 cpp_type_name(chainField.javaType), chainField.name.c_str());
981 fprintf(out, " std::vector<ScopedUtfChars*> scoped_%s_vec;\n",
982 chainField.name.c_str());
983 fprintf(out, " for (size_t i = 0; i < %s_length; ++i) {\n",
984 chainField.name.c_str());
985 fprintf(out, " jstring jstr = "
986 "(jstring)env->GetObjectArrayElement(%s, i);\n",
987 chainField.name.c_str());
Yangster-mac20ac9442018-01-08 14:54:48 -0800988 fprintf(out, " if (jstr == NULL) {\n");
989 fprintf(out, " %s_vec.push_back(NULL);\n",
990 chainField.name.c_str());
991 fprintf(out, " } else {\n");
992 fprintf(out, " ScopedUtfChars* scoped_%s = "
Yangster-mac7604aea2017-12-11 22:55:49 -0800993 "new ScopedUtfChars(env, jstr);\n",
994 chainField.name.c_str());
Yangster-mac20ac9442018-01-08 14:54:48 -0800995 fprintf(out, " %s_vec.push_back(scoped_%s->c_str());\n",
Yangster-mac7604aea2017-12-11 22:55:49 -0800996 chainField.name.c_str(), chainField.name.c_str());
Yangster-mac20ac9442018-01-08 14:54:48 -0800997 fprintf(out, " scoped_%s_vec.push_back(scoped_%s);\n",
Yangster-mac7604aea2017-12-11 22:55:49 -0800998 chainField.name.c_str(), chainField.name.c_str());
Yangster-mac20ac9442018-01-08 14:54:48 -0800999 fprintf(out, " }\n");
Yangster-mac7604aea2017-12-11 22:55:49 -08001000 fprintf(out, " }\n");
1001 }
1002 fprintf(out, "\n");
1003 }
Yao Chend54f9dd2017-10-17 17:37:48 +00001004 }
1005 argIndex++;
1006 }
Yangster-mac7604aea2017-12-11 22:55:49 -08001007 // Emit this to quiet the unused parameter warning if there were no strings or attribution
1008 // chains.
1009 if (!hadStringOrChain) {
Yao Chend54f9dd2017-10-17 17:37:48 +00001010 fprintf(out, " (void)env;\n");
1011 }
1012
1013 // stats_write call
1014 argIndex = 1;
Yao Chen97e21ec2018-03-29 11:00:38 -07001015 fprintf(out, " int ret = android::util::%s(code", cpp_method_name.c_str());
Yao Chend54f9dd2017-10-17 17:37:48 +00001016 for (vector<java_type_t>::const_iterator arg = signature->begin();
1017 arg != signature->end(); arg++) {
Yangster-mac7604aea2017-12-11 22:55:49 -08001018 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
1019 for (auto chainField : attributionDecl.fields) {
1020 if (chainField.javaType == JAVA_TYPE_INT) {
1021 fprintf(out, ", (const %s*)%s_array, %s_length",
1022 cpp_type_name(chainField.javaType),
1023 chainField.name.c_str(), chainField.name.c_str());
1024 } else if (chainField.javaType == JAVA_TYPE_STRING) {
1025 fprintf(out, ", %s_vec", chainField.name.c_str());
1026 }
1027 }
1028 } else {
1029 const char *argName = (*arg == JAVA_TYPE_STRING) ? "str" : "arg";
1030 fprintf(out, ", (%s)%s%d", cpp_type_name(*arg), argName, argIndex);
1031 }
Yao Chend54f9dd2017-10-17 17:37:48 +00001032 argIndex++;
1033 }
1034 fprintf(out, ");\n");
Yangster-mac7604aea2017-12-11 22:55:49 -08001035 fprintf(out, "\n");
Yao Chend54f9dd2017-10-17 17:37:48 +00001036
1037 // Clean up strings
1038 argIndex = 1;
1039 for (vector<java_type_t>::const_iterator arg = signature->begin();
1040 arg != signature->end(); arg++) {
1041 if (*arg == JAVA_TYPE_STRING) {
1042 fprintf(out, " if (str%d != NULL) {\n", argIndex);
1043 fprintf(out, " env->ReleaseStringUTFChars(arg%d, str%d);\n",
1044 argIndex, argIndex);
1045 fprintf(out, " }\n");
Yangster-mac7604aea2017-12-11 22:55:49 -08001046 } else if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
1047 for (auto chainField : attributionDecl.fields) {
1048 if (chainField.javaType == JAVA_TYPE_INT) {
1049 fprintf(out, " env->ReleaseIntArrayElements(%s, %s_array, 0);\n",
1050 chainField.name.c_str(), chainField.name.c_str());
1051 } else if (chainField.javaType == JAVA_TYPE_STRING) {
Yangster-mac20ac9442018-01-08 14:54:48 -08001052 fprintf(out, " for (size_t i = 0; i < scoped_%s_vec.size(); ++i) {\n",
Yangster-mac7604aea2017-12-11 22:55:49 -08001053 chainField.name.c_str());
1054 fprintf(out, " delete scoped_%s_vec[i];\n", chainField.name.c_str());
1055 fprintf(out, " }\n");
1056 }
1057 }
Yao Chend54f9dd2017-10-17 17:37:48 +00001058 }
1059 argIndex++;
1060 }
Yao Chen97e21ec2018-03-29 11:00:38 -07001061 fprintf(out, " return ret;\n");
Yao Chend54f9dd2017-10-17 17:37:48 +00001062
1063 fprintf(out, "}\n");
1064 fprintf(out, "\n");
1065 }
1066
Yangster-macba5b9e42018-01-10 21:31:59 -08001067
1068 return 0;
1069}
1070
1071void write_jni_registration(FILE* out, const string& java_method_name,
1072 const set<vector<java_type_t>>& signatures, const AtomDecl &attributionDecl) {
1073 for (set<vector<java_type_t>>::const_iterator signature = signatures.begin();
1074 signature != signatures.end(); signature++) {
1075 fprintf(out, " { \"%s\", \"%s\", (void*)%s },\n",
1076 java_method_name.c_str(),
1077 jni_function_signature(*signature, attributionDecl).c_str(),
1078 jni_function_name(java_method_name, *signature).c_str());
1079 }
1080}
1081
1082static int
1083write_stats_log_jni(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl)
1084{
1085 // Print prelude
1086 fprintf(out, "// This file is autogenerated\n");
1087 fprintf(out, "\n");
1088
1089 fprintf(out, "#include <statslog.h>\n");
1090 fprintf(out, "\n");
1091 fprintf(out, "#include <nativehelper/JNIHelp.h>\n");
1092 fprintf(out, "#include <nativehelper/ScopedUtfChars.h>\n");
1093 fprintf(out, "#include <utils/Vector.h>\n");
1094 fprintf(out, "#include \"core_jni_helpers.h\"\n");
1095 fprintf(out, "#include \"jni.h\"\n");
1096 fprintf(out, "\n");
1097 fprintf(out, "#define UNUSED __attribute__((__unused__))\n");
1098 fprintf(out, "\n");
1099
1100 fprintf(out, "namespace android {\n");
1101 fprintf(out, "\n");
1102
1103 write_stats_log_jni(out, "write", "stats_write", atoms.signatures, attributionDecl);
1104 write_stats_log_jni(out, "write_non_chained", "stats_write_non_chained",
1105 atoms.non_chained_signatures, attributionDecl);
1106
Yao Chend54f9dd2017-10-17 17:37:48 +00001107 // Print registration function table
1108 fprintf(out, "/*\n");
1109 fprintf(out, " * JNI registration.\n");
1110 fprintf(out, " */\n");
1111 fprintf(out, "static const JNINativeMethod gRegisterMethods[] = {\n");
Yangster-macba5b9e42018-01-10 21:31:59 -08001112 write_jni_registration(out, "write", atoms.signatures, attributionDecl);
1113 write_jni_registration(out, "write_non_chained", atoms.non_chained_signatures, attributionDecl);
Yao Chend54f9dd2017-10-17 17:37:48 +00001114 fprintf(out, "};\n");
1115 fprintf(out, "\n");
1116
1117 // Print registration function
1118 fprintf(out, "int register_android_util_StatsLog(JNIEnv* env) {\n");
1119 fprintf(out, " return RegisterMethodsOrDie(\n");
1120 fprintf(out, " env,\n");
1121 fprintf(out, " \"android/util/StatsLog\",\n");
1122 fprintf(out, " gRegisterMethods, NELEM(gRegisterMethods));\n");
1123 fprintf(out, "}\n");
1124
1125 fprintf(out, "\n");
1126 fprintf(out, "} // namespace android\n");
Yao Chend54f9dd2017-10-17 17:37:48 +00001127 return 0;
1128}
1129
Yao Chend54f9dd2017-10-17 17:37:48 +00001130static void
1131print_usage()
1132{
1133 fprintf(stderr, "usage: stats-log-api-gen OPTIONS\n");
1134 fprintf(stderr, "\n");
1135 fprintf(stderr, "OPTIONS\n");
1136 fprintf(stderr, " --cpp FILENAME the header file to output\n");
1137 fprintf(stderr, " --header FILENAME the cpp file to output\n");
1138 fprintf(stderr, " --help this message\n");
1139 fprintf(stderr, " --java FILENAME the java file to output\n");
1140 fprintf(stderr, " --jni FILENAME the jni file to output\n");
1141}
1142
1143/**
1144 * Do the argument parsing and execute the tasks.
1145 */
1146static int
1147run(int argc, char const*const* argv)
1148{
1149 string cppFilename;
1150 string headerFilename;
1151 string javaFilename;
1152 string jniFilename;
1153
1154 int index = 1;
1155 while (index < argc) {
1156 if (0 == strcmp("--help", argv[index])) {
1157 print_usage();
1158 return 0;
1159 } else if (0 == strcmp("--cpp", argv[index])) {
1160 index++;
1161 if (index >= argc) {
1162 print_usage();
1163 return 1;
1164 }
1165 cppFilename = argv[index];
1166 } else if (0 == strcmp("--header", argv[index])) {
1167 index++;
1168 if (index >= argc) {
1169 print_usage();
1170 return 1;
1171 }
1172 headerFilename = argv[index];
1173 } else if (0 == strcmp("--java", argv[index])) {
1174 index++;
1175 if (index >= argc) {
1176 print_usage();
1177 return 1;
1178 }
1179 javaFilename = argv[index];
1180 } else if (0 == strcmp("--jni", argv[index])) {
1181 index++;
1182 if (index >= argc) {
1183 print_usage();
1184 return 1;
1185 }
1186 jniFilename = argv[index];
1187 }
1188 index++;
1189 }
1190
1191 if (cppFilename.size() == 0
1192 && headerFilename.size() == 0
1193 && javaFilename.size() == 0
1194 && jniFilename.size() == 0) {
1195 print_usage();
1196 return 1;
1197 }
1198
1199 // Collate the parameters
1200 Atoms atoms;
Stefan Lafonae2df012017-11-14 09:17:21 -08001201 int errorCount = collate_atoms(Atom::descriptor(), &atoms);
Yao Chend54f9dd2017-10-17 17:37:48 +00001202 if (errorCount != 0) {
1203 return 1;
1204 }
1205
Yangster-mac7604aea2017-12-11 22:55:49 -08001206 AtomDecl attributionDecl;
1207 vector<java_type_t> attributionSignature;
Yangster-mac20877162017-12-22 17:19:39 -08001208 collate_atom(android::os::statsd::AttributionNode::descriptor(),
Yangster-mac7604aea2017-12-11 22:55:49 -08001209 &attributionDecl, &attributionSignature);
1210
Yao Chend54f9dd2017-10-17 17:37:48 +00001211 // Write the .cpp file
1212 if (cppFilename.size() != 0) {
1213 FILE* out = fopen(cppFilename.c_str(), "w");
1214 if (out == NULL) {
1215 fprintf(stderr, "Unable to open file for write: %s\n", cppFilename.c_str());
1216 return 1;
1217 }
Yangster-mac7604aea2017-12-11 22:55:49 -08001218 errorCount = android::stats_log_api_gen::write_stats_log_cpp(
1219 out, atoms, attributionDecl);
Yao Chend54f9dd2017-10-17 17:37:48 +00001220 fclose(out);
1221 }
1222
1223 // Write the .h file
1224 if (headerFilename.size() != 0) {
1225 FILE* out = fopen(headerFilename.c_str(), "w");
1226 if (out == NULL) {
1227 fprintf(stderr, "Unable to open file for write: %s\n", headerFilename.c_str());
1228 return 1;
1229 }
Yangster-mac7604aea2017-12-11 22:55:49 -08001230 errorCount = android::stats_log_api_gen::write_stats_log_header(
1231 out, atoms, attributionDecl);
Yao Chend54f9dd2017-10-17 17:37:48 +00001232 fclose(out);
1233 }
1234
1235 // Write the .java file
1236 if (javaFilename.size() != 0) {
1237 FILE* out = fopen(javaFilename.c_str(), "w");
1238 if (out == NULL) {
1239 fprintf(stderr, "Unable to open file for write: %s\n", javaFilename.c_str());
1240 return 1;
1241 }
Yangster-mac7604aea2017-12-11 22:55:49 -08001242 errorCount = android::stats_log_api_gen::write_stats_log_java(
1243 out, atoms, attributionDecl);
Yao Chend54f9dd2017-10-17 17:37:48 +00001244 fclose(out);
1245 }
1246
1247 // Write the jni file
1248 if (jniFilename.size() != 0) {
1249 FILE* out = fopen(jniFilename.c_str(), "w");
1250 if (out == NULL) {
1251 fprintf(stderr, "Unable to open file for write: %s\n", jniFilename.c_str());
1252 return 1;
1253 }
Yangster-mac7604aea2017-12-11 22:55:49 -08001254 errorCount = android::stats_log_api_gen::write_stats_log_jni(
1255 out, atoms, attributionDecl);
Yao Chend54f9dd2017-10-17 17:37:48 +00001256 fclose(out);
1257 }
1258
1259 return 0;
1260}
1261
1262}
1263}
1264
1265/**
1266 * Main.
1267 */
1268int
1269main(int argc, char const*const* argv)
1270{
1271 GOOGLE_PROTOBUF_VERIFY_VERSION;
1272
1273 return android::stats_log_api_gen::run(argc, argv);
Yao Chencf3829a2018-06-05 14:20:35 -07001274}