blob: 83a66312b4255e4843fc3f3e09a8a6a5c59993b8 [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 }
Yangster-mace124e422018-08-16 10:30:28 -0700238 } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
239 fprintf(out, ", const std::map<int, int64_t>& arg%d_1, "
240 "const std::map<int, char const*>& arg%d_2, "
241 "const std::map<int, float>& arg%d_3", argIndex, argIndex, argIndex);
Yangster-mac7604aea2017-12-11 22:55:49 -0800242 } else {
243 fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
244 }
Yao Chend54f9dd2017-10-17 17:37:48 +0000245 argIndex++;
246 }
247 fprintf(out, ")\n");
248
249 fprintf(out, "{\n");
250 argIndex = 1;
Yao Chencf3829a2018-06-05 14:20:35 -0700251 fprintf(out, " if (kStatsdEnabled) {\n");
Yao Chenf7bc6ab2018-04-18 13:45:48 -0700252 fprintf(out, " stats_event_list event(kStatsEventTag);\n");
Yangster-mac330af582018-02-08 15:24:38 -0800253 fprintf(out, " event << android::elapsedRealtimeNano();\n\n");
Yangster-mac7604aea2017-12-11 22:55:49 -0800254 fprintf(out, " event << code;\n\n");
Yao Chend54f9dd2017-10-17 17:37:48 +0000255 for (vector<java_type_t>::const_iterator arg = signature->begin();
Yangster-mac7604aea2017-12-11 22:55:49 -0800256 arg != signature->end(); arg++) {
257 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
258 for (const auto &chainField : attributionDecl.fields) {
259 if (chainField.javaType == JAVA_TYPE_STRING) {
260 fprintf(out, " if (%s_length != %s.size()) {\n",
261 attributionDecl.fields.front().name.c_str(), chainField.name.c_str());
Yao Chen97e21ec2018-03-29 11:00:38 -0700262 fprintf(out, " return -EINVAL;\n");
Yangster-mac7604aea2017-12-11 22:55:49 -0800263 fprintf(out, " }\n");
264 }
265 }
266 fprintf(out, "\n event.begin();\n");
267 fprintf(out, " for (size_t i = 0; i < %s_length; ++i) {\n",
268 attributionDecl.fields.front().name.c_str());
269 fprintf(out, " event.begin();\n");
270 for (const auto &chainField : attributionDecl.fields) {
Yangster-mac20ac9442018-01-08 14:54:48 -0800271 if (chainField.javaType == JAVA_TYPE_STRING) {
272 fprintf(out, " if (%s[i] != NULL) {\n", chainField.name.c_str());
273 fprintf(out, " event << %s[i];\n", chainField.name.c_str());
274 fprintf(out, " } else {\n");
275 fprintf(out, " event << \"\";\n");
276 fprintf(out, " }\n");
277 } else {
278 fprintf(out, " event << %s[i];\n", chainField.name.c_str());
279 }
Yangster-mac7604aea2017-12-11 22:55:49 -0800280 }
281 fprintf(out, " event.end();\n");
Yao Chend54f9dd2017-10-17 17:37:48 +0000282 fprintf(out, " }\n");
Yangster-mac7604aea2017-12-11 22:55:49 -0800283 fprintf(out, " event.end();\n\n");
Yangster-mace124e422018-08-16 10:30:28 -0700284 } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
285 fprintf(out, " event.begin();\n\n");
286 fprintf(out, " for (const auto& it : arg%d_1) {\n", argIndex);
287 fprintf(out, " event.begin();\n");
288 fprintf(out, " event << it.first;\n");
289 fprintf(out, " event << it.second;\n");
290 fprintf(out, " event.end();\n");
291 fprintf(out, " }\n");
292
293 fprintf(out, " for (const auto& it : arg%d_2) {\n", argIndex);
294 fprintf(out, " event.begin();\n");
295 fprintf(out, " event << it.first;\n");
296 fprintf(out, " event << it.second;\n");
297 fprintf(out, " event.end();\n");
298 fprintf(out, " }\n");
299
300 fprintf(out, " for (const auto& it : arg%d_3) {\n", argIndex);
301 fprintf(out, " event.begin();\n");
302 fprintf(out, " event << it.first;\n");
303 fprintf(out, " event << it.second;\n");
304 fprintf(out, " event.end();\n");
305 fprintf(out, " }\n");
306
307 fprintf(out, " event.end();\n\n");
Yangster-mac7604aea2017-12-11 22:55:49 -0800308 } else {
309 if (*arg == JAVA_TYPE_STRING) {
310 fprintf(out, " if (arg%d == NULL) {\n", argIndex);
311 fprintf(out, " arg%d = \"\";\n", argIndex);
312 fprintf(out, " }\n");
313 }
314 fprintf(out, " event << arg%d;\n", argIndex);
Yao Chend54f9dd2017-10-17 17:37:48 +0000315 }
Yao Chend54f9dd2017-10-17 17:37:48 +0000316 argIndex++;
317 }
318
Yao Chen97e21ec2018-03-29 11:00:38 -0700319 fprintf(out, " return event.write(LOG_ID_STATS);\n");
Yao Chencf3829a2018-06-05 14:20:35 -0700320 fprintf(out, " } else {\n");
321 fprintf(out, " return 1;\n");
322 fprintf(out, " }\n");
Yao Chend54f9dd2017-10-17 17:37:48 +0000323 fprintf(out, "}\n");
324 fprintf(out, "\n");
325 }
326
Yangster-macb8382a12018-04-04 10:39:12 -0700327 for (set<vector<java_type_t>>::const_iterator signature = atoms.signatures.begin();
328 signature != atoms.signatures.end(); signature++) {
329 int argIndex;
330
Yangster-mace124e422018-08-16 10:30:28 -0700331 fprintf(out, "int\n");
Yangster-macb8382a12018-04-04 10:39:12 -0700332 fprintf(out, "stats_write(int32_t code");
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, ", const std::vector<%s>& %s",
340 cpp_type_name(chainField.javaType),
341 chainField.name.c_str());
342 } else {
343 fprintf(out, ", const %s* %s, size_t %s_length",
344 cpp_type_name(chainField.javaType),
345 chainField.name.c_str(), chainField.name.c_str());
346 }
347 }
Yangster-mace124e422018-08-16 10:30:28 -0700348 } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
349 fprintf(out, ", const std::map<int, int64_t>& arg%d_1, "
350 "const std::map<int, char const*>& arg%d_2, "
351 "const std::map<int, float>& arg%d_3", argIndex, argIndex, argIndex);
Yangster-macb8382a12018-04-04 10:39:12 -0700352 } else {
353 fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
354 }
355 argIndex++;
356 }
357 fprintf(out, ")\n");
358
359 fprintf(out, "{\n");
360 fprintf(out, " int ret = 0;\n");
361
Yangster-macca5c0862018-04-09 22:39:53 -0700362 fprintf(out, " for(int retry = 0; retry < 2; ++retry) {\n");
Yangster-macb8382a12018-04-04 10:39:12 -0700363 fprintf(out, " ret = try_stats_write(code");
364
365 argIndex = 1;
366 for (vector<java_type_t>::const_iterator arg = signature->begin();
367 arg != signature->end(); arg++) {
368 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
369 for (auto chainField : attributionDecl.fields) {
370 if (chainField.javaType == JAVA_TYPE_STRING) {
371 fprintf(out, ", %s",
372 chainField.name.c_str());
373 } else {
374 fprintf(out, ", %s, %s_length",
375 chainField.name.c_str(), chainField.name.c_str());
376 }
377 }
Yangster-mace124e422018-08-16 10:30:28 -0700378 } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
379 fprintf(out, ", arg%d_1, arg%d_2, arg%d_3", argIndex, argIndex, argIndex);
Yangster-macb8382a12018-04-04 10:39:12 -0700380 } else {
381 fprintf(out, ", arg%d", argIndex);
382 }
383 argIndex++;
384 }
385 fprintf(out, ");\n");
Yao Chen0f5d6612018-08-22 14:11:51 -0700386 fprintf(out, " if (ret >= 0) { break; }\n");
Yangster-macca5c0862018-04-09 22:39:53 -0700387
388 fprintf(out, " {\n");
389 fprintf(out, " std::lock_guard<std::mutex> lock(mLogdRetryMutex);\n");
390 fprintf(out, " if ((android::elapsedRealtimeNano() - lastRetryTimestampNs) <= "
391 "kMinRetryIntervalNs) break;\n");
392 fprintf(out, " lastRetryTimestampNs = android::elapsedRealtimeNano();\n");
393 fprintf(out, " }\n");
394 fprintf(out, " std::this_thread::sleep_for(std::chrono::milliseconds(10));\n");
Yangster-macb8382a12018-04-04 10:39:12 -0700395 fprintf(out, " }\n");
Yao Chen0f5d6612018-08-22 14:11:51 -0700396 fprintf(out, " if (ret < 0) {\n");
397 fprintf(out, " note_log_drop();\n");
398 fprintf(out, " }\n");
Yangster-macb8382a12018-04-04 10:39:12 -0700399 fprintf(out, " return ret;\n");
400 fprintf(out, "}\n");
401 fprintf(out, "\n");
402 }
403
Yangster-macba5b9e42018-01-10 21:31:59 -0800404 for (set<vector<java_type_t>>::const_iterator signature = atoms.non_chained_signatures.begin();
405 signature != atoms.non_chained_signatures.end(); signature++) {
406 int argIndex;
407
Yao Chen97e21ec2018-03-29 11:00:38 -0700408 fprintf(out, "int\n");
Yangster-macb8382a12018-04-04 10:39:12 -0700409 fprintf(out, "try_stats_write_non_chained(int32_t code");
Yangster-macba5b9e42018-01-10 21:31:59 -0800410 argIndex = 1;
411 for (vector<java_type_t>::const_iterator arg = signature->begin();
412 arg != signature->end(); arg++) {
413 fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
414 argIndex++;
415 }
416 fprintf(out, ")\n");
417
418 fprintf(out, "{\n");
419 argIndex = 1;
Yao Chencf3829a2018-06-05 14:20:35 -0700420 fprintf(out, " if (kStatsdEnabled) {\n");
Yao Chenf7bc6ab2018-04-18 13:45:48 -0700421 fprintf(out, " stats_event_list event(kStatsEventTag);\n");
Yangster-mac31ddcde2018-02-14 16:09:35 -0800422 fprintf(out, " event << android::elapsedRealtimeNano();\n\n");
Yangster-macba5b9e42018-01-10 21:31:59 -0800423 fprintf(out, " event << code;\n\n");
424 for (vector<java_type_t>::const_iterator arg = signature->begin();
425 arg != signature->end(); arg++) {
426 if (argIndex == 1) {
427 fprintf(out, " event.begin();\n\n");
428 fprintf(out, " event.begin();\n");
429 }
430 if (*arg == JAVA_TYPE_STRING) {
431 fprintf(out, " if (arg%d == NULL) {\n", argIndex);
432 fprintf(out, " arg%d = \"\";\n", argIndex);
433 fprintf(out, " }\n");
434 }
435 fprintf(out, " event << arg%d;\n", argIndex);
436 if (argIndex == 2) {
437 fprintf(out, " event.end();\n\n");
438 fprintf(out, " event.end();\n\n");
439 }
440 argIndex++;
441 }
442
Yao Chen97e21ec2018-03-29 11:00:38 -0700443 fprintf(out, " return event.write(LOG_ID_STATS);\n");
Yao Chencf3829a2018-06-05 14:20:35 -0700444 fprintf(out, " } else {\n");
445 fprintf(out, " return 1;\n");
446 fprintf(out, " }\n");
Yangster-macba5b9e42018-01-10 21:31:59 -0800447 fprintf(out, "}\n");
448 fprintf(out, "\n");
449 }
Yangster-macb8382a12018-04-04 10:39:12 -0700450
451 for (set<vector<java_type_t>>::const_iterator signature = atoms.non_chained_signatures.begin();
452 signature != atoms.non_chained_signatures.end(); signature++) {
453 int argIndex;
454
455 fprintf(out, "int\n");
456 fprintf(out, "stats_write_non_chained(int32_t code");
457 argIndex = 1;
458 for (vector<java_type_t>::const_iterator arg = signature->begin();
459 arg != signature->end(); arg++) {
460 fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
461 argIndex++;
462 }
463 fprintf(out, ")\n");
464
465 fprintf(out, "{\n");
466
467 fprintf(out, " int ret = 0;\n");
Yangster-macca5c0862018-04-09 22:39:53 -0700468 fprintf(out, " for(int retry = 0; retry < 2; ++retry) {\n");
Yangster-macb8382a12018-04-04 10:39:12 -0700469 fprintf(out, " ret = try_stats_write_non_chained(code");
470
471 argIndex = 1;
472 for (vector<java_type_t>::const_iterator arg = signature->begin();
473 arg != signature->end(); arg++) {
474 fprintf(out, ", arg%d", argIndex);
475 argIndex++;
476 }
477 fprintf(out, ");\n");
Yao Chen0f5d6612018-08-22 14:11:51 -0700478 fprintf(out, " if (ret >= 0) { break; }\n");
Yangster-macca5c0862018-04-09 22:39:53 -0700479
480 fprintf(out, " {\n");
481 fprintf(out, " std::lock_guard<std::mutex> lock(mLogdRetryMutex);\n");
482 fprintf(out, " if ((android::elapsedRealtimeNano() - lastRetryTimestampNs) <= "
483 "kMinRetryIntervalNs) break;\n");
484 fprintf(out, " lastRetryTimestampNs = android::elapsedRealtimeNano();\n");
485 fprintf(out, " }\n");
486
487 fprintf(out, " std::this_thread::sleep_for(std::chrono::milliseconds(10));\n");
Yangster-macb8382a12018-04-04 10:39:12 -0700488 fprintf(out, " }\n");
Yao Chen0f5d6612018-08-22 14:11:51 -0700489 fprintf(out, " if (ret < 0) {\n");
490 fprintf(out, " note_log_drop();\n");
491 fprintf(out, " }\n");
492 fprintf(out, " return ret;\n\n");
Yangster-macb8382a12018-04-04 10:39:12 -0700493 fprintf(out, "}\n");
494
495 fprintf(out, "\n");
496 }
497
498
Yao Chend54f9dd2017-10-17 17:37:48 +0000499 // Print footer
500 fprintf(out, "\n");
501 fprintf(out, "} // namespace util\n");
502 fprintf(out, "} // namespace android\n");
503
504 return 0;
505}
506
Yangster-macba5b9e42018-01-10 21:31:59 -0800507void build_non_chained_decl_map(const Atoms& atoms,
508 std::map<int, set<AtomDecl>::const_iterator>* decl_map){
509 for (set<AtomDecl>::const_iterator atom = atoms.non_chained_decls.begin();
510 atom != atoms.non_chained_decls.end(); atom++) {
511 decl_map->insert(std::make_pair(atom->code, atom));
512 }
513}
514
515static void write_cpp_usage(
516 FILE* out, const string& method_name, const string& atom_code_name,
517 const AtomDecl& atom, const AtomDecl &attributionDecl) {
518 fprintf(out, " * Usage: %s(StatsLog.%s", method_name.c_str(), atom_code_name.c_str());
519 for (vector<AtomField>::const_iterator field = atom.fields.begin();
520 field != atom.fields.end(); field++) {
521 if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
522 for (auto chainField : attributionDecl.fields) {
523 if (chainField.javaType == JAVA_TYPE_STRING) {
524 fprintf(out, ", const std::vector<%s>& %s",
525 cpp_type_name(chainField.javaType),
526 chainField.name.c_str());
527 } else {
528 fprintf(out, ", const %s* %s, size_t %s_length",
529 cpp_type_name(chainField.javaType),
530 chainField.name.c_str(), chainField.name.c_str());
531 }
532 }
Yangster-mace124e422018-08-16 10:30:28 -0700533 } else if (field->javaType == JAVA_TYPE_KEY_VALUE_PAIR) {
534 fprintf(out, ", const std::map<int, int64_t>& %s_int"
535 ", const std::map<int, char const*>& %s_str"
536 ", const std::map<int, float>& %s_float",
537 field->name.c_str(), field->name.c_str(), field->name.c_str());
Yangster-macba5b9e42018-01-10 21:31:59 -0800538 } else {
539 fprintf(out, ", %s %s", cpp_type_name(field->javaType), field->name.c_str());
540 }
541 }
542 fprintf(out, ");\n");
543}
544
545static void write_cpp_method_header(
546 FILE* out, const string& method_name, const set<vector<java_type_t>>& signatures,
547 const AtomDecl &attributionDecl) {
548 for (set<vector<java_type_t>>::const_iterator signature = signatures.begin();
549 signature != signatures.end(); signature++) {
Yangster-mace124e422018-08-16 10:30:28 -0700550 fprintf(out, "int %s(int32_t code", method_name.c_str());
Yangster-macba5b9e42018-01-10 21:31:59 -0800551 int argIndex = 1;
552 for (vector<java_type_t>::const_iterator arg = signature->begin();
553 arg != signature->end(); arg++) {
554 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
555 for (auto chainField : attributionDecl.fields) {
556 if (chainField.javaType == JAVA_TYPE_STRING) {
557 fprintf(out, ", const std::vector<%s>& %s",
558 cpp_type_name(chainField.javaType), chainField.name.c_str());
559 } else {
560 fprintf(out, ", const %s* %s, size_t %s_length",
561 cpp_type_name(chainField.javaType),
562 chainField.name.c_str(), chainField.name.c_str());
563 }
564 }
Yangster-mace124e422018-08-16 10:30:28 -0700565 } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
566 fprintf(out, ", const std::map<int, int64_t>& arg%d_1, "
567 "const std::map<int, char const*>& arg%d_2, "
568 "const std::map<int, float>& arg%d_3", argIndex, argIndex, argIndex);
Yangster-macba5b9e42018-01-10 21:31:59 -0800569 } else {
570 fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
571 }
572 argIndex++;
573 }
574 fprintf(out, ");\n");
575
576 }
577}
Yao Chend54f9dd2017-10-17 17:37:48 +0000578
579static int
Yangster-mac7604aea2017-12-11 22:55:49 -0800580write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl)
Yao Chend54f9dd2017-10-17 17:37:48 +0000581{
Yao Chend54f9dd2017-10-17 17:37:48 +0000582 // Print prelude
583 fprintf(out, "// This file is autogenerated\n");
584 fprintf(out, "\n");
585 fprintf(out, "#pragma once\n");
586 fprintf(out, "\n");
587 fprintf(out, "#include <stdint.h>\n");
Yangster-mac7604aea2017-12-11 22:55:49 -0800588 fprintf(out, "#include <vector>\n");
Yao Chen9c1debe2018-02-19 14:39:19 -0800589 fprintf(out, "#include <map>\n");
Yangster-mac68985802018-01-21 10:05:09 -0800590 fprintf(out, "#include <set>\n");
Yao Chend54f9dd2017-10-17 17:37:48 +0000591 fprintf(out, "\n");
592
593 fprintf(out, "namespace android {\n");
594 fprintf(out, "namespace util {\n");
595 fprintf(out, "\n");
596 fprintf(out, "/*\n");
597 fprintf(out, " * API For logging statistics events.\n");
598 fprintf(out, " */\n");
599 fprintf(out, "\n");
600 fprintf(out, "/**\n");
Stefan Lafon9478f352017-10-30 21:20:20 -0700601 fprintf(out, " * Constants for atom codes.\n");
Yao Chend54f9dd2017-10-17 17:37:48 +0000602 fprintf(out, " */\n");
603 fprintf(out, "enum {\n");
604
Yangster-macba5b9e42018-01-10 21:31:59 -0800605 std::map<int, set<AtomDecl>::const_iterator> atom_code_to_non_chained_decl_map;
606 build_non_chained_decl_map(atoms, &atom_code_to_non_chained_decl_map);
607
Yao Chend54f9dd2017-10-17 17:37:48 +0000608 size_t i = 0;
609 // Print constants
610 for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
Yangster-mac7604aea2017-12-11 22:55:49 -0800611 atom != atoms.decls.end(); atom++) {
Yao Chend54f9dd2017-10-17 17:37:48 +0000612 string constant = make_constant_name(atom->name);
613 fprintf(out, "\n");
614 fprintf(out, " /**\n");
615 fprintf(out, " * %s %s\n", atom->message.c_str(), atom->name.c_str());
Yangster-macba5b9e42018-01-10 21:31:59 -0800616 write_cpp_usage(out, "stats_write", constant, *atom, attributionDecl);
617
618 auto non_chained_decl = atom_code_to_non_chained_decl_map.find(atom->code);
619 if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) {
620 write_cpp_usage(out, "stats_write_non_chained", constant, *non_chained_decl->second,
621 attributionDecl);
Yao Chend54f9dd2017-10-17 17:37:48 +0000622 }
Yao Chend54f9dd2017-10-17 17:37:48 +0000623 fprintf(out, " */\n");
624 char const* const comma = (i == atoms.decls.size() - 1) ? "" : ",";
625 fprintf(out, " %s = %d%s\n", constant.c_str(), atom->code, comma);
Yao Chenb3561512017-11-21 18:07:17 -0800626 if (atom->code < PULL_ATOM_START_ID && atom->code > maxPushedAtomId) {
627 maxPushedAtomId = atom->code;
628 }
Yao Chend54f9dd2017-10-17 17:37:48 +0000629 i++;
630 }
631 fprintf(out, "\n");
632 fprintf(out, "};\n");
633 fprintf(out, "\n");
634
Yao Chen9c1debe2018-02-19 14:39:19 -0800635 fprintf(out, "struct StateAtomFieldOptions {\n");
636 fprintf(out, " std::vector<int> primaryFields;\n");
637 fprintf(out, " int exclusiveField;\n");
Yao Chenc40a19d2018-03-15 16:48:25 -0700638 fprintf(out, "};\n");
Yao Chen9c1debe2018-02-19 14:39:19 -0800639 fprintf(out, "\n");
Yao Chenc40a19d2018-03-15 16:48:25 -0700640
641 fprintf(out, "struct AtomsInfo {\n");
Yao Chen9c1debe2018-02-19 14:39:19 -0800642 fprintf(out,
Yao Chenc40a19d2018-03-15 16:48:25 -0700643 " const static std::set<int> "
644 "kNotTruncatingTimestampAtomWhiteList;\n");
645 fprintf(out, " const static std::map<int, int> kAtomsWithUidField;\n");
646 fprintf(out,
647 " const static std::set<int> kAtomsWithAttributionChain;\n");
648 fprintf(out,
649 " const static std::map<int, StateAtomFieldOptions> "
650 "kStateAtomsFieldOptions;\n");
Yao Chen9c1debe2018-02-19 14:39:19 -0800651 fprintf(out, "};\n");
652
Yao Chenc40a19d2018-03-15 16:48:25 -0700653 fprintf(out, "const static int kMaxPushedAtomId = %d;\n\n",
654 maxPushedAtomId);
Yao Chen9c1debe2018-02-19 14:39:19 -0800655
Yao Chend54f9dd2017-10-17 17:37:48 +0000656 // Print write methods
657 fprintf(out, "//\n");
658 fprintf(out, "// Write methods\n");
659 fprintf(out, "//\n");
Yangster-macba5b9e42018-01-10 21:31:59 -0800660 write_cpp_method_header(out, "stats_write", atoms.signatures, attributionDecl);
661
662 fprintf(out, "//\n");
663 fprintf(out, "// Write flattened methods\n");
664 fprintf(out, "//\n");
665 write_cpp_method_header(out, "stats_write_non_chained", atoms.non_chained_signatures,
666 attributionDecl);
Yao Chend54f9dd2017-10-17 17:37:48 +0000667
668 fprintf(out, "\n");
669 fprintf(out, "} // namespace util\n");
670 fprintf(out, "} // namespace android\n");
671
672 return 0;
673}
674
Bookatz0bd97202018-06-05 12:42:37 -0700675static void write_java_usage(FILE* out, const string& method_name, const string& atom_code_name,
676 const AtomDecl& atom) {
Yangster-macba5b9e42018-01-10 21:31:59 -0800677 fprintf(out, " * Usage: StatsLog.%s(StatsLog.%s",
678 method_name.c_str(), atom_code_name.c_str());
679 for (vector<AtomField>::const_iterator field = atom.fields.begin();
680 field != atom.fields.end(); field++) {
681 if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
Bookatz0bd97202018-06-05 12:42:37 -0700682 fprintf(out, ", android.os.WorkSource workSource");
Yangster-mace124e422018-08-16 10:30:28 -0700683 } else if (field->javaType == JAVA_TYPE_KEY_VALUE_PAIR) {
684 fprintf(out, ", SparseArray<Object> value_map");
Yangster-macba5b9e42018-01-10 21:31:59 -0800685 } else {
686 fprintf(out, ", %s %s", java_type_name(field->javaType), field->name.c_str());
687 }
688 }
Bookatz0bd97202018-06-05 12:42:37 -0700689 fprintf(out, ");<br>\n");
Yangster-macba5b9e42018-01-10 21:31:59 -0800690}
691
692static void write_java_method(
693 FILE* out, const string& method_name, const set<vector<java_type_t>>& signatures,
694 const AtomDecl &attributionDecl) {
695 for (set<vector<java_type_t>>::const_iterator signature = signatures.begin();
696 signature != signatures.end(); signature++) {
Yao Chen97e21ec2018-03-29 11:00:38 -0700697 fprintf(out, " public static native int %s(int code", method_name.c_str());
Yangster-macba5b9e42018-01-10 21:31:59 -0800698 int argIndex = 1;
699 for (vector<java_type_t>::const_iterator arg = signature->begin();
700 arg != signature->end(); arg++) {
701 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
702 for (auto chainField : attributionDecl.fields) {
703 fprintf(out, ", %s[] %s",
704 java_type_name(chainField.javaType), chainField.name.c_str());
705 }
Yangster-mace124e422018-08-16 10:30:28 -0700706 } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
707 fprintf(out, ", SparseArray<Object> value_map");
Yangster-macba5b9e42018-01-10 21:31:59 -0800708 } else {
709 fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
710 }
711 argIndex++;
712 }
713 fprintf(out, ");\n");
714 }
715}
716
Bookatz0bd97202018-06-05 12:42:37 -0700717static void write_java_work_source_method(FILE* out, const set<vector<java_type_t>>& signatures) {
718 fprintf(out, "\n // WorkSource methods.\n");
719 for (set<vector<java_type_t>>::const_iterator signature = signatures.begin();
720 signature != signatures.end(); signature++) {
721 // Determine if there is Attribution in this signature.
722 int attributionArg = -1;
723 int argIndexMax = 0;
724 for (vector<java_type_t>::const_iterator arg = signature->begin();
725 arg != signature->end(); arg++) {
726 argIndexMax++;
727 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
728 if (attributionArg > -1) {
729 fprintf(stderr, "An atom contains multiple AttributionNode fields.\n");
730 fprintf(stderr, "This is not supported. Aborting WorkSource method writing.\n");
731 fprintf(out, "\n// Invalid for WorkSource: more than one attribution chain.\n");
732 return;
733 }
734 attributionArg = argIndexMax;
735 }
736 }
737 if (attributionArg < 0) {
738 continue;
739 }
740
741 // Method header (signature)
742 fprintf(out, " public static void write(int code");
743 int argIndex = 1;
744 for (vector<java_type_t>::const_iterator arg = signature->begin();
745 arg != signature->end(); arg++) {
746 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
747 fprintf(out, ", WorkSource ws");
748 } else {
749 fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
750 }
751 argIndex++;
752 }
753 fprintf(out, ") {\n");
754
755 // write_non_chained() component. TODO: Remove when flat uids are no longer needed.
756 fprintf(out, " for (int i = 0; i < ws.size(); ++i) {\n");
757 fprintf(out, " write_non_chained(code");
758 for (int argIndex = 1; argIndex <= argIndexMax; argIndex++) {
759 if (argIndex == attributionArg) {
760 fprintf(out, ", ws.get(i), ws.getName(i)");
761 } else {
762 fprintf(out, ", arg%d", argIndex);
763 }
764 }
765 fprintf(out, ");\n");
766 fprintf(out, " }\n"); // close flor-loop
767
768 // write() component.
769 fprintf(out, " ArrayList<WorkSource.WorkChain> workChains = ws.getWorkChains();\n");
770 fprintf(out, " if (workChains != null) {\n");
771 fprintf(out, " for (WorkSource.WorkChain wc : workChains) {\n");
772 fprintf(out, " write(code");
773 for (int argIndex = 1; argIndex <= argIndexMax; argIndex++) {
774 if (argIndex == attributionArg) {
775 fprintf(out, ", wc.getUids(), wc.getTags()");
776 } else {
777 fprintf(out, ", arg%d", argIndex);
778 }
779 }
780 fprintf(out, ");\n");
781 fprintf(out, " }\n"); // close for-loop
782 fprintf(out, " }\n"); // close if
783 fprintf(out, " }\n"); // close method
784 }
785}
Yangster-macba5b9e42018-01-10 21:31:59 -0800786
Yao Chend54f9dd2017-10-17 17:37:48 +0000787static int
Yangster-mac7604aea2017-12-11 22:55:49 -0800788write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl)
Yao Chend54f9dd2017-10-17 17:37:48 +0000789{
Yao Chend54f9dd2017-10-17 17:37:48 +0000790 // Print prelude
791 fprintf(out, "// This file is autogenerated\n");
792 fprintf(out, "\n");
793 fprintf(out, "package android.util;\n");
794 fprintf(out, "\n");
Bookatz0bd97202018-06-05 12:42:37 -0700795 fprintf(out, "import android.os.WorkSource;\n");
Yangster-mace124e422018-08-16 10:30:28 -0700796 fprintf(out, "import android.util.SparseArray;\n");
Bookatz0bd97202018-06-05 12:42:37 -0700797 fprintf(out, "import java.util.ArrayList;\n");
798 fprintf(out, "\n");
Yao Chend54f9dd2017-10-17 17:37:48 +0000799 fprintf(out, "\n");
800 fprintf(out, "/**\n");
801 fprintf(out, " * API For logging statistics events.\n");
802 fprintf(out, " * @hide\n");
803 fprintf(out, " */\n");
David Chen0a368b22017-12-06 16:28:16 -0800804 fprintf(out, "public class StatsLogInternal {\n");
Stefan Lafon9478f352017-10-30 21:20:20 -0700805 fprintf(out, " // Constants for atom codes.\n");
Yao Chend54f9dd2017-10-17 17:37:48 +0000806
Yangster-macba5b9e42018-01-10 21:31:59 -0800807 std::map<int, set<AtomDecl>::const_iterator> atom_code_to_non_chained_decl_map;
808 build_non_chained_decl_map(atoms, &atom_code_to_non_chained_decl_map);
809
Stefan Lafon9478f352017-10-30 21:20:20 -0700810 // Print constants for the atom codes.
Yao Chend54f9dd2017-10-17 17:37:48 +0000811 for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
812 atom != atoms.decls.end(); atom++) {
813 string constant = make_constant_name(atom->name);
814 fprintf(out, "\n");
815 fprintf(out, " /**\n");
Bookatz0bd97202018-06-05 12:42:37 -0700816 fprintf(out, " * %s %s<br>\n", atom->message.c_str(), atom->name.c_str());
817 write_java_usage(out, "write", constant, *atom);
Yangster-macba5b9e42018-01-10 21:31:59 -0800818 auto non_chained_decl = atom_code_to_non_chained_decl_map.find(atom->code);
819 if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) {
Bookatz0bd97202018-06-05 12:42:37 -0700820 write_java_usage(out, "write_non_chained", constant, *non_chained_decl->second);
Yao Chend54f9dd2017-10-17 17:37:48 +0000821 }
Yao Chend54f9dd2017-10-17 17:37:48 +0000822 fprintf(out, " */\n");
823 fprintf(out, " public static final int %s = %d;\n", constant.c_str(), atom->code);
824 }
825 fprintf(out, "\n");
826
Stefan Lafon9478f352017-10-30 21:20:20 -0700827 // Print constants for the enum values.
828 fprintf(out, " // Constants for enum values.\n\n");
829 for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
Yangster-mac7604aea2017-12-11 22:55:49 -0800830 atom != atoms.decls.end(); atom++) {
Stefan Lafon9478f352017-10-30 21:20:20 -0700831 for (vector<AtomField>::const_iterator field = atom->fields.begin();
Yangster-mac7604aea2017-12-11 22:55:49 -0800832 field != atom->fields.end(); field++) {
833 if (field->javaType == JAVA_TYPE_ENUM) {
834 fprintf(out, " // Values for %s.%s\n", atom->message.c_str(),
835 field->name.c_str());
836 for (map<int, string>::const_iterator value = field->enumValues.begin();
837 value != field->enumValues.end(); value++) {
838 fprintf(out, " public static final int %s__%s__%s = %d;\n",
839 make_constant_name(atom->message).c_str(),
840 make_constant_name(field->name).c_str(),
841 make_constant_name(value->second).c_str(),
842 value->first);
843 }
844 fprintf(out, "\n");
Stefan Lafon9478f352017-10-30 21:20:20 -0700845 }
Stefan Lafon9478f352017-10-30 21:20:20 -0700846 }
847 }
848
Yao Chend54f9dd2017-10-17 17:37:48 +0000849 // Print write methods
850 fprintf(out, " // Write methods\n");
Yangster-macba5b9e42018-01-10 21:31:59 -0800851 write_java_method(out, "write", atoms.signatures, attributionDecl);
852 write_java_method(out, "write_non_chained", atoms.non_chained_signatures, attributionDecl);
Bookatz0bd97202018-06-05 12:42:37 -0700853 write_java_work_source_method(out, atoms.signatures);
Yao Chend54f9dd2017-10-17 17:37:48 +0000854
855 fprintf(out, "}\n");
856
857 return 0;
858}
859
860static const char*
861jni_type_name(java_type_t type)
862{
863 switch (type) {
864 case JAVA_TYPE_BOOLEAN:
865 return "jboolean";
866 case JAVA_TYPE_INT:
Stefan Lafon9478f352017-10-30 21:20:20 -0700867 case JAVA_TYPE_ENUM:
Yao Chend54f9dd2017-10-17 17:37:48 +0000868 return "jint";
869 case JAVA_TYPE_LONG:
870 return "jlong";
871 case JAVA_TYPE_FLOAT:
872 return "jfloat";
873 case JAVA_TYPE_DOUBLE:
874 return "jdouble";
875 case JAVA_TYPE_STRING:
876 return "jstring";
877 default:
878 return "UNKNOWN";
879 }
880}
881
Yangster-mac7604aea2017-12-11 22:55:49 -0800882static const char*
883jni_array_type_name(java_type_t type)
884{
885 switch (type) {
886 case JAVA_TYPE_INT:
887 return "jintArray";
Yangster-mace124e422018-08-16 10:30:28 -0700888 case JAVA_TYPE_FLOAT:
889 return "jfloatArray";
Yangster-mac7604aea2017-12-11 22:55:49 -0800890 case JAVA_TYPE_STRING:
891 return "jobjectArray";
892 default:
893 return "UNKNOWN";
894 }
895}
896
Yao Chend54f9dd2017-10-17 17:37:48 +0000897static string
Yangster-macba5b9e42018-01-10 21:31:59 -0800898jni_function_name(const string& method_name, const vector<java_type_t>& signature)
Yao Chend54f9dd2017-10-17 17:37:48 +0000899{
Yangster-macba5b9e42018-01-10 21:31:59 -0800900 string result("StatsLog_" + method_name);
Yao Chend54f9dd2017-10-17 17:37:48 +0000901 for (vector<java_type_t>::const_iterator arg = signature.begin();
Yangster-mac7604aea2017-12-11 22:55:49 -0800902 arg != signature.end(); arg++) {
Yao Chend54f9dd2017-10-17 17:37:48 +0000903 switch (*arg) {
904 case JAVA_TYPE_BOOLEAN:
905 result += "_boolean";
906 break;
907 case JAVA_TYPE_INT:
Stefan Lafon9478f352017-10-30 21:20:20 -0700908 case JAVA_TYPE_ENUM:
Yao Chend54f9dd2017-10-17 17:37:48 +0000909 result += "_int";
910 break;
911 case JAVA_TYPE_LONG:
912 result += "_long";
913 break;
914 case JAVA_TYPE_FLOAT:
915 result += "_float";
916 break;
917 case JAVA_TYPE_DOUBLE:
918 result += "_double";
919 break;
920 case JAVA_TYPE_STRING:
921 result += "_String";
922 break;
Yangster-mac7604aea2017-12-11 22:55:49 -0800923 case JAVA_TYPE_ATTRIBUTION_CHAIN:
924 result += "_AttributionChain";
925 break;
Yangster-mace124e422018-08-16 10:30:28 -0700926 case JAVA_TYPE_KEY_VALUE_PAIR:
927 result += "_KeyValuePairs";
928 break;
Yao Chend54f9dd2017-10-17 17:37:48 +0000929 default:
930 result += "_UNKNOWN";
931 break;
932 }
933 }
934 return result;
935}
936
937static const char*
938java_type_signature(java_type_t type)
939{
940 switch (type) {
941 case JAVA_TYPE_BOOLEAN:
942 return "Z";
943 case JAVA_TYPE_INT:
Stefan Lafon9478f352017-10-30 21:20:20 -0700944 case JAVA_TYPE_ENUM:
Yao Chend54f9dd2017-10-17 17:37:48 +0000945 return "I";
946 case JAVA_TYPE_LONG:
947 return "J";
948 case JAVA_TYPE_FLOAT:
949 return "F";
950 case JAVA_TYPE_DOUBLE:
951 return "D";
952 case JAVA_TYPE_STRING:
953 return "Ljava/lang/String;";
954 default:
955 return "UNKNOWN";
956 }
957}
958
959static string
Yangster-mac7604aea2017-12-11 22:55:49 -0800960jni_function_signature(const vector<java_type_t>& signature, const AtomDecl &attributionDecl)
Yao Chend54f9dd2017-10-17 17:37:48 +0000961{
962 string result("(I");
963 for (vector<java_type_t>::const_iterator arg = signature.begin();
Yangster-mac7604aea2017-12-11 22:55:49 -0800964 arg != signature.end(); arg++) {
965 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
966 for (auto chainField : attributionDecl.fields) {
967 result += "[";
968 result += java_type_signature(chainField.javaType);
969 }
Yangster-mace124e422018-08-16 10:30:28 -0700970 } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
971 result += "Landroid/util/SparseArray;";
Yangster-mac7604aea2017-12-11 22:55:49 -0800972 } else {
973 result += java_type_signature(*arg);
974 }
Yao Chend54f9dd2017-10-17 17:37:48 +0000975 }
Yao Chen97e21ec2018-03-29 11:00:38 -0700976 result += ")I";
Yao Chend54f9dd2017-10-17 17:37:48 +0000977 return result;
978}
979
Yangster-mace124e422018-08-16 10:30:28 -0700980static void write_key_value_map_jni(FILE* out) {
981 fprintf(out, " std::map<int, int64_t> int64_t_map;\n");
982 fprintf(out, " std::map<int, float> float_map;\n");
983 fprintf(out, " std::map<int, char const*> string_map;\n\n");
984
985 fprintf(out, " jclass jmap_class = env->FindClass(\"android/util/SparseArray\");\n");
986
987 fprintf(out, " jmethodID jget_size_method = env->GetMethodID(jmap_class, \"size\", \"()I\");\n");
988 fprintf(out, " jmethodID jget_key_method = env->GetMethodID(jmap_class, \"keyAt\", \"(I)I\");\n");
989 fprintf(out, " jmethodID jget_value_method = env->GetMethodID(jmap_class, \"valueAt\", \"(I)Ljava/lang/Object;\");\n\n");
990
991
992 fprintf(out, " std::vector<std::unique_ptr<ScopedUtfChars>> scoped_ufs;\n\n");
993
994 fprintf(out, " jclass jlong_class = env->FindClass(\"java/lang/Long\");\n");
995 fprintf(out, " jclass jfloat_class = env->FindClass(\"java/lang/Float\");\n");
996 fprintf(out, " jclass jstring_class = env->FindClass(\"java/lang/String\");\n");
997 fprintf(out, " jmethodID jget_long_method = env->GetMethodID(jlong_class, \"longValue\", \"()J\");\n");
998 fprintf(out, " jmethodID jget_float_method = env->GetMethodID(jfloat_class, \"floatValue\", \"()F\");\n\n");
999
1000 fprintf(out, " jint jsize = env->CallIntMethod(value_map, jget_size_method);\n");
1001 fprintf(out, " for(int i = 0; i < jsize; i++) {\n");
1002 fprintf(out, " jint key = env->CallIntMethod(value_map, jget_key_method, i);\n");
1003 fprintf(out, " jobject jvalue_obj = env->CallObjectMethod(value_map, jget_value_method, i);\n");
1004 fprintf(out, " if (jvalue_obj == NULL) { continue; }\n");
1005 fprintf(out, " if (env->IsInstanceOf(jvalue_obj, jlong_class)) {\n");
1006 fprintf(out, " int64_t_map[key] = env->CallLongMethod(jvalue_obj, jget_long_method);\n");
1007 fprintf(out, " } else if (env->IsInstanceOf(jvalue_obj, jfloat_class)) {\n");
1008 fprintf(out, " float_map[key] = env->CallFloatMethod(jvalue_obj, jget_float_method);\n");
1009 fprintf(out, " } else if (env->IsInstanceOf(jvalue_obj, jstring_class)) {\n");
1010 fprintf(out, " std::unique_ptr<ScopedUtfChars> utf(new ScopedUtfChars(env, (jstring)jvalue_obj));\n");
1011 fprintf(out, " if (utf->c_str() != NULL) { string_map[key] = utf->c_str(); }\n");
1012 fprintf(out, " scoped_ufs.push_back(std::move(utf));\n");
1013 fprintf(out, " }\n");
1014 fprintf(out, " }\n");
1015}
1016
Yao Chend54f9dd2017-10-17 17:37:48 +00001017static int
Yangster-macba5b9e42018-01-10 21:31:59 -08001018write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp_method_name,
1019 const set<vector<java_type_t>>& signatures, const AtomDecl &attributionDecl)
Yao Chend54f9dd2017-10-17 17:37:48 +00001020{
Yao Chend54f9dd2017-10-17 17:37:48 +00001021 // Print write methods
Yangster-macba5b9e42018-01-10 21:31:59 -08001022 for (set<vector<java_type_t>>::const_iterator signature = signatures.begin();
1023 signature != signatures.end(); signature++) {
Yao Chend54f9dd2017-10-17 17:37:48 +00001024 int argIndex;
1025
Yao Chen97e21ec2018-03-29 11:00:38 -07001026 fprintf(out, "static int\n");
Yao Chend54f9dd2017-10-17 17:37:48 +00001027 fprintf(out, "%s(JNIEnv* env, jobject clazz UNUSED, jint code",
Yangster-macba5b9e42018-01-10 21:31:59 -08001028 jni_function_name(java_method_name, *signature).c_str());
Yao Chend54f9dd2017-10-17 17:37:48 +00001029 argIndex = 1;
1030 for (vector<java_type_t>::const_iterator arg = signature->begin();
1031 arg != signature->end(); arg++) {
Yangster-mac7604aea2017-12-11 22:55:49 -08001032 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
1033 for (auto chainField : attributionDecl.fields) {
1034 fprintf(out, ", %s %s", jni_array_type_name(chainField.javaType),
1035 chainField.name.c_str());
1036 }
Yangster-mace124e422018-08-16 10:30:28 -07001037 } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
1038 fprintf(out, ", jobject value_map");
Yangster-mac7604aea2017-12-11 22:55:49 -08001039 } else {
1040 fprintf(out, ", %s arg%d", jni_type_name(*arg), argIndex);
1041 }
Yao Chend54f9dd2017-10-17 17:37:48 +00001042 argIndex++;
1043 }
1044 fprintf(out, ")\n");
1045
1046 fprintf(out, "{\n");
1047
1048 // Prepare strings
1049 argIndex = 1;
Yangster-mac7604aea2017-12-11 22:55:49 -08001050 bool hadStringOrChain = false;
Yangster-mace124e422018-08-16 10:30:28 -07001051 bool isKeyValuePairAtom = false;
Yao Chend54f9dd2017-10-17 17:37:48 +00001052 for (vector<java_type_t>::const_iterator arg = signature->begin();
1053 arg != signature->end(); arg++) {
1054 if (*arg == JAVA_TYPE_STRING) {
Yangster-mac7604aea2017-12-11 22:55:49 -08001055 hadStringOrChain = true;
Yao Chend54f9dd2017-10-17 17:37:48 +00001056 fprintf(out, " const char* str%d;\n", argIndex);
1057 fprintf(out, " if (arg%d != NULL) {\n", argIndex);
1058 fprintf(out, " str%d = env->GetStringUTFChars(arg%d, NULL);\n",
1059 argIndex, argIndex);
1060 fprintf(out, " } else {\n");
1061 fprintf(out, " str%d = NULL;\n", argIndex);
1062 fprintf(out, " }\n");
Yangster-mac7604aea2017-12-11 22:55:49 -08001063 } else if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
1064 hadStringOrChain = true;
1065 for (auto chainField : attributionDecl.fields) {
1066 fprintf(out, " size_t %s_length = env->GetArrayLength(%s);\n",
1067 chainField.name.c_str(), chainField.name.c_str());
1068 if (chainField.name != attributionDecl.fields.front().name) {
1069 fprintf(out, " if (%s_length != %s_length) {\n",
1070 chainField.name.c_str(),
1071 attributionDecl.fields.front().name.c_str());
Yao Chen97e21ec2018-03-29 11:00:38 -07001072 fprintf(out, " return -EINVAL;\n");
Yangster-mac7604aea2017-12-11 22:55:49 -08001073 fprintf(out, " }\n");
1074 }
1075 if (chainField.javaType == JAVA_TYPE_INT) {
1076 fprintf(out, " jint* %s_array = env->GetIntArrayElements(%s, NULL);\n",
1077 chainField.name.c_str(), chainField.name.c_str());
1078 } else if (chainField.javaType == JAVA_TYPE_STRING) {
1079 fprintf(out, " std::vector<%s> %s_vec;\n",
1080 cpp_type_name(chainField.javaType), chainField.name.c_str());
1081 fprintf(out, " std::vector<ScopedUtfChars*> scoped_%s_vec;\n",
1082 chainField.name.c_str());
1083 fprintf(out, " for (size_t i = 0; i < %s_length; ++i) {\n",
1084 chainField.name.c_str());
1085 fprintf(out, " jstring jstr = "
1086 "(jstring)env->GetObjectArrayElement(%s, i);\n",
1087 chainField.name.c_str());
Yangster-mac20ac9442018-01-08 14:54:48 -08001088 fprintf(out, " if (jstr == NULL) {\n");
1089 fprintf(out, " %s_vec.push_back(NULL);\n",
1090 chainField.name.c_str());
1091 fprintf(out, " } else {\n");
1092 fprintf(out, " ScopedUtfChars* scoped_%s = "
Yangster-mac7604aea2017-12-11 22:55:49 -08001093 "new ScopedUtfChars(env, jstr);\n",
1094 chainField.name.c_str());
Yangster-mac20ac9442018-01-08 14:54:48 -08001095 fprintf(out, " %s_vec.push_back(scoped_%s->c_str());\n",
Yangster-mac7604aea2017-12-11 22:55:49 -08001096 chainField.name.c_str(), chainField.name.c_str());
Yangster-mac20ac9442018-01-08 14:54:48 -08001097 fprintf(out, " scoped_%s_vec.push_back(scoped_%s);\n",
Yangster-mac7604aea2017-12-11 22:55:49 -08001098 chainField.name.c_str(), chainField.name.c_str());
Yangster-mac20ac9442018-01-08 14:54:48 -08001099 fprintf(out, " }\n");
Yangster-mac7604aea2017-12-11 22:55:49 -08001100 fprintf(out, " }\n");
1101 }
1102 fprintf(out, "\n");
1103 }
Yangster-mace124e422018-08-16 10:30:28 -07001104 } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
1105 isKeyValuePairAtom = true;
Yao Chend54f9dd2017-10-17 17:37:48 +00001106 }
1107 argIndex++;
1108 }
Yangster-mac7604aea2017-12-11 22:55:49 -08001109 // Emit this to quiet the unused parameter warning if there were no strings or attribution
1110 // chains.
Yangster-mace124e422018-08-16 10:30:28 -07001111 if (!hadStringOrChain && !isKeyValuePairAtom) {
Yao Chend54f9dd2017-10-17 17:37:48 +00001112 fprintf(out, " (void)env;\n");
1113 }
Yangster-mace124e422018-08-16 10:30:28 -07001114 if (isKeyValuePairAtom) {
1115 write_key_value_map_jni(out);
1116 }
Yao Chend54f9dd2017-10-17 17:37:48 +00001117
1118 // stats_write call
1119 argIndex = 1;
Yangster-mace124e422018-08-16 10:30:28 -07001120 fprintf(out, "\n int ret = android::util::%s(code", cpp_method_name.c_str());
Yao Chend54f9dd2017-10-17 17:37:48 +00001121 for (vector<java_type_t>::const_iterator arg = signature->begin();
1122 arg != signature->end(); arg++) {
Yangster-mac7604aea2017-12-11 22:55:49 -08001123 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
1124 for (auto chainField : attributionDecl.fields) {
1125 if (chainField.javaType == JAVA_TYPE_INT) {
1126 fprintf(out, ", (const %s*)%s_array, %s_length",
1127 cpp_type_name(chainField.javaType),
1128 chainField.name.c_str(), chainField.name.c_str());
1129 } else if (chainField.javaType == JAVA_TYPE_STRING) {
1130 fprintf(out, ", %s_vec", chainField.name.c_str());
1131 }
1132 }
Yangster-mace124e422018-08-16 10:30:28 -07001133 } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
1134 fprintf(out, ", int64_t_map, string_map, float_map");
Yangster-mac7604aea2017-12-11 22:55:49 -08001135 } else {
1136 const char *argName = (*arg == JAVA_TYPE_STRING) ? "str" : "arg";
1137 fprintf(out, ", (%s)%s%d", cpp_type_name(*arg), argName, argIndex);
1138 }
Yao Chend54f9dd2017-10-17 17:37:48 +00001139 argIndex++;
1140 }
1141 fprintf(out, ");\n");
Yangster-mac7604aea2017-12-11 22:55:49 -08001142 fprintf(out, "\n");
Yao Chend54f9dd2017-10-17 17:37:48 +00001143
1144 // Clean up strings
1145 argIndex = 1;
1146 for (vector<java_type_t>::const_iterator arg = signature->begin();
1147 arg != signature->end(); arg++) {
1148 if (*arg == JAVA_TYPE_STRING) {
1149 fprintf(out, " if (str%d != NULL) {\n", argIndex);
1150 fprintf(out, " env->ReleaseStringUTFChars(arg%d, str%d);\n",
1151 argIndex, argIndex);
1152 fprintf(out, " }\n");
Yangster-mac7604aea2017-12-11 22:55:49 -08001153 } else if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
1154 for (auto chainField : attributionDecl.fields) {
1155 if (chainField.javaType == JAVA_TYPE_INT) {
1156 fprintf(out, " env->ReleaseIntArrayElements(%s, %s_array, 0);\n",
1157 chainField.name.c_str(), chainField.name.c_str());
1158 } else if (chainField.javaType == JAVA_TYPE_STRING) {
Yangster-mac20ac9442018-01-08 14:54:48 -08001159 fprintf(out, " for (size_t i = 0; i < scoped_%s_vec.size(); ++i) {\n",
Yangster-mac7604aea2017-12-11 22:55:49 -08001160 chainField.name.c_str());
1161 fprintf(out, " delete scoped_%s_vec[i];\n", chainField.name.c_str());
1162 fprintf(out, " }\n");
1163 }
1164 }
Yao Chend54f9dd2017-10-17 17:37:48 +00001165 }
1166 argIndex++;
1167 }
Yangster-mace124e422018-08-16 10:30:28 -07001168
Yao Chen97e21ec2018-03-29 11:00:38 -07001169 fprintf(out, " return ret;\n");
Yao Chend54f9dd2017-10-17 17:37:48 +00001170
1171 fprintf(out, "}\n");
1172 fprintf(out, "\n");
1173 }
1174
Yangster-macba5b9e42018-01-10 21:31:59 -08001175
1176 return 0;
1177}
1178
1179void write_jni_registration(FILE* out, const string& java_method_name,
1180 const set<vector<java_type_t>>& signatures, const AtomDecl &attributionDecl) {
1181 for (set<vector<java_type_t>>::const_iterator signature = signatures.begin();
1182 signature != signatures.end(); signature++) {
1183 fprintf(out, " { \"%s\", \"%s\", (void*)%s },\n",
1184 java_method_name.c_str(),
1185 jni_function_signature(*signature, attributionDecl).c_str(),
1186 jni_function_name(java_method_name, *signature).c_str());
1187 }
1188}
1189
1190static int
1191write_stats_log_jni(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl)
1192{
1193 // Print prelude
1194 fprintf(out, "// This file is autogenerated\n");
1195 fprintf(out, "\n");
1196
1197 fprintf(out, "#include <statslog.h>\n");
1198 fprintf(out, "\n");
1199 fprintf(out, "#include <nativehelper/JNIHelp.h>\n");
1200 fprintf(out, "#include <nativehelper/ScopedUtfChars.h>\n");
1201 fprintf(out, "#include <utils/Vector.h>\n");
1202 fprintf(out, "#include \"core_jni_helpers.h\"\n");
1203 fprintf(out, "#include \"jni.h\"\n");
1204 fprintf(out, "\n");
1205 fprintf(out, "#define UNUSED __attribute__((__unused__))\n");
1206 fprintf(out, "\n");
1207
1208 fprintf(out, "namespace android {\n");
1209 fprintf(out, "\n");
1210
1211 write_stats_log_jni(out, "write", "stats_write", atoms.signatures, attributionDecl);
1212 write_stats_log_jni(out, "write_non_chained", "stats_write_non_chained",
1213 atoms.non_chained_signatures, attributionDecl);
1214
Yao Chend54f9dd2017-10-17 17:37:48 +00001215 // Print registration function table
1216 fprintf(out, "/*\n");
1217 fprintf(out, " * JNI registration.\n");
1218 fprintf(out, " */\n");
1219 fprintf(out, "static const JNINativeMethod gRegisterMethods[] = {\n");
Yangster-macba5b9e42018-01-10 21:31:59 -08001220 write_jni_registration(out, "write", atoms.signatures, attributionDecl);
1221 write_jni_registration(out, "write_non_chained", atoms.non_chained_signatures, attributionDecl);
Yao Chend54f9dd2017-10-17 17:37:48 +00001222 fprintf(out, "};\n");
1223 fprintf(out, "\n");
1224
1225 // Print registration function
1226 fprintf(out, "int register_android_util_StatsLog(JNIEnv* env) {\n");
1227 fprintf(out, " return RegisterMethodsOrDie(\n");
1228 fprintf(out, " env,\n");
1229 fprintf(out, " \"android/util/StatsLog\",\n");
1230 fprintf(out, " gRegisterMethods, NELEM(gRegisterMethods));\n");
1231 fprintf(out, "}\n");
1232
1233 fprintf(out, "\n");
1234 fprintf(out, "} // namespace android\n");
Yao Chend54f9dd2017-10-17 17:37:48 +00001235 return 0;
1236}
1237
Yao Chend54f9dd2017-10-17 17:37:48 +00001238static void
1239print_usage()
1240{
1241 fprintf(stderr, "usage: stats-log-api-gen OPTIONS\n");
1242 fprintf(stderr, "\n");
1243 fprintf(stderr, "OPTIONS\n");
1244 fprintf(stderr, " --cpp FILENAME the header file to output\n");
1245 fprintf(stderr, " --header FILENAME the cpp file to output\n");
1246 fprintf(stderr, " --help this message\n");
1247 fprintf(stderr, " --java FILENAME the java file to output\n");
1248 fprintf(stderr, " --jni FILENAME the jni file to output\n");
1249}
1250
1251/**
1252 * Do the argument parsing and execute the tasks.
1253 */
1254static int
1255run(int argc, char const*const* argv)
1256{
1257 string cppFilename;
1258 string headerFilename;
1259 string javaFilename;
1260 string jniFilename;
1261
1262 int index = 1;
1263 while (index < argc) {
1264 if (0 == strcmp("--help", argv[index])) {
1265 print_usage();
1266 return 0;
1267 } else if (0 == strcmp("--cpp", argv[index])) {
1268 index++;
1269 if (index >= argc) {
1270 print_usage();
1271 return 1;
1272 }
1273 cppFilename = argv[index];
1274 } else if (0 == strcmp("--header", argv[index])) {
1275 index++;
1276 if (index >= argc) {
1277 print_usage();
1278 return 1;
1279 }
1280 headerFilename = argv[index];
1281 } else if (0 == strcmp("--java", argv[index])) {
1282 index++;
1283 if (index >= argc) {
1284 print_usage();
1285 return 1;
1286 }
1287 javaFilename = argv[index];
1288 } else if (0 == strcmp("--jni", argv[index])) {
1289 index++;
1290 if (index >= argc) {
1291 print_usage();
1292 return 1;
1293 }
1294 jniFilename = argv[index];
1295 }
1296 index++;
1297 }
1298
1299 if (cppFilename.size() == 0
1300 && headerFilename.size() == 0
1301 && javaFilename.size() == 0
1302 && jniFilename.size() == 0) {
1303 print_usage();
1304 return 1;
1305 }
1306
1307 // Collate the parameters
1308 Atoms atoms;
Stefan Lafonae2df012017-11-14 09:17:21 -08001309 int errorCount = collate_atoms(Atom::descriptor(), &atoms);
Yao Chend54f9dd2017-10-17 17:37:48 +00001310 if (errorCount != 0) {
1311 return 1;
1312 }
1313
Yangster-mac7604aea2017-12-11 22:55:49 -08001314 AtomDecl attributionDecl;
1315 vector<java_type_t> attributionSignature;
Yangster-mac20877162017-12-22 17:19:39 -08001316 collate_atom(android::os::statsd::AttributionNode::descriptor(),
Yangster-mac7604aea2017-12-11 22:55:49 -08001317 &attributionDecl, &attributionSignature);
1318
Yao Chend54f9dd2017-10-17 17:37:48 +00001319 // Write the .cpp file
1320 if (cppFilename.size() != 0) {
1321 FILE* out = fopen(cppFilename.c_str(), "w");
1322 if (out == NULL) {
1323 fprintf(stderr, "Unable to open file for write: %s\n", cppFilename.c_str());
1324 return 1;
1325 }
Yangster-mac7604aea2017-12-11 22:55:49 -08001326 errorCount = android::stats_log_api_gen::write_stats_log_cpp(
1327 out, atoms, attributionDecl);
Yao Chend54f9dd2017-10-17 17:37:48 +00001328 fclose(out);
1329 }
1330
1331 // Write the .h file
1332 if (headerFilename.size() != 0) {
1333 FILE* out = fopen(headerFilename.c_str(), "w");
1334 if (out == NULL) {
1335 fprintf(stderr, "Unable to open file for write: %s\n", headerFilename.c_str());
1336 return 1;
1337 }
Yangster-mac7604aea2017-12-11 22:55:49 -08001338 errorCount = android::stats_log_api_gen::write_stats_log_header(
1339 out, atoms, attributionDecl);
Yao Chend54f9dd2017-10-17 17:37:48 +00001340 fclose(out);
1341 }
1342
1343 // Write the .java file
1344 if (javaFilename.size() != 0) {
1345 FILE* out = fopen(javaFilename.c_str(), "w");
1346 if (out == NULL) {
1347 fprintf(stderr, "Unable to open file for write: %s\n", javaFilename.c_str());
1348 return 1;
1349 }
Yangster-mac7604aea2017-12-11 22:55:49 -08001350 errorCount = android::stats_log_api_gen::write_stats_log_java(
1351 out, atoms, attributionDecl);
Yao Chend54f9dd2017-10-17 17:37:48 +00001352 fclose(out);
1353 }
1354
1355 // Write the jni file
1356 if (jniFilename.size() != 0) {
1357 FILE* out = fopen(jniFilename.c_str(), "w");
1358 if (out == NULL) {
1359 fprintf(stderr, "Unable to open file for write: %s\n", jniFilename.c_str());
1360 return 1;
1361 }
Yangster-mac7604aea2017-12-11 22:55:49 -08001362 errorCount = android::stats_log_api_gen::write_stats_log_jni(
1363 out, atoms, attributionDecl);
Yao Chend54f9dd2017-10-17 17:37:48 +00001364 fclose(out);
1365 }
1366
1367 return 0;
1368}
1369
1370}
1371}
1372
1373/**
1374 * Main.
1375 */
1376int
1377main(int argc, char const*const* argv)
1378{
1379 GOOGLE_PROTOBUF_VERIFY_VERSION;
1380
1381 return android::stats_log_api_gen::run(argc, argv);
Yao Chencf3829a2018-06-05 14:20:35 -07001382}