blob: a5b56a42bfbeaf4d9903f8c9bc65a89364514ad6 [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
Tej Singh810eeb32019-03-07 19:08:52 -080015#include "android-base/strings.h"
16
Yao Chend54f9dd2017-10-17 17:37:48 +000017using namespace google::protobuf;
18using namespace std;
19
20namespace android {
21namespace stats_log_api_gen {
22
Yao Chenb3561512017-11-21 18:07:17 -080023int maxPushedAtomId = 2;
24
Tej Singh810eeb32019-03-07 19:08:52 -080025const string DEFAULT_MODULE_NAME = "DEFAULT";
26const string DEFAULT_CPP_NAMESPACE = "android,util";
27const string DEFAULT_CPP_HEADER_IMPORT = "statslog.h";
28
Stefan Lafonae2df012017-11-14 09:17:21 -080029using android::os::statsd::Atom;
Yao Chend54f9dd2017-10-17 17:37:48 +000030
Yao Chend54f9dd2017-10-17 17:37:48 +000031/**
32 * Turn lower and camel case into upper case with underscores.
33 */
34static string
35make_constant_name(const string& str)
36{
37 string result;
38 const int N = str.size();
39 bool underscore_next = false;
40 for (int i=0; i<N; i++) {
41 char c = str[i];
42 if (c >= 'A' && c <= 'Z') {
43 if (underscore_next) {
44 result += '_';
45 underscore_next = false;
46 }
47 } else if (c >= 'a' && c <= 'z') {
48 c = 'A' + c - 'a';
49 underscore_next = true;
50 } else if (c == '_') {
51 underscore_next = false;
52 }
53 result += c;
54 }
55 return result;
56}
57
58static const char*
59cpp_type_name(java_type_t type)
60{
61 switch (type) {
62 case JAVA_TYPE_BOOLEAN:
63 return "bool";
64 case JAVA_TYPE_INT:
Stefan Lafon9478f352017-10-30 21:20:20 -070065 case JAVA_TYPE_ENUM:
Yao Chend54f9dd2017-10-17 17:37:48 +000066 return "int32_t";
67 case JAVA_TYPE_LONG:
68 return "int64_t";
69 case JAVA_TYPE_FLOAT:
70 return "float";
71 case JAVA_TYPE_DOUBLE:
72 return "double";
73 case JAVA_TYPE_STRING:
74 return "char const*";
Yao Chenbbdd67d2018-10-24 12:15:56 -070075 case JAVA_TYPE_BYTE_ARRAY:
Yao Chene89572c2019-01-09 15:41:50 -080076 return "const BytesField&";
Yao Chend54f9dd2017-10-17 17:37:48 +000077 default:
78 return "UNKNOWN";
79 }
80}
81
82static const char*
83java_type_name(java_type_t type)
84{
85 switch (type) {
86 case JAVA_TYPE_BOOLEAN:
87 return "boolean";
88 case JAVA_TYPE_INT:
Stefan Lafon9478f352017-10-30 21:20:20 -070089 case JAVA_TYPE_ENUM:
Yao Chend54f9dd2017-10-17 17:37:48 +000090 return "int";
91 case JAVA_TYPE_LONG:
92 return "long";
93 case JAVA_TYPE_FLOAT:
94 return "float";
95 case JAVA_TYPE_DOUBLE:
96 return "double";
97 case JAVA_TYPE_STRING:
98 return "java.lang.String";
Yao Chenbbdd67d2018-10-24 12:15:56 -070099 case JAVA_TYPE_BYTE_ARRAY:
100 return "byte[]";
Yao Chend54f9dd2017-10-17 17:37:48 +0000101 default:
102 return "UNKNOWN";
103 }
104}
105
Tej Singh810eeb32019-03-07 19:08:52 -0800106static bool atom_needed_for_module(const AtomDecl& atomDecl, const string& moduleName) {
107 if (moduleName == DEFAULT_MODULE_NAME) {
108 return true;
109 }
110 return atomDecl.hasModule && (moduleName == atomDecl.moduleName);
111}
Yao Chend54f9dd2017-10-17 17:37:48 +0000112
Tej Singh810eeb32019-03-07 19:08:52 -0800113static bool signature_needed_for_module(const set<string>& modules, const string& moduleName) {
114 if (moduleName == DEFAULT_MODULE_NAME) {
115 return true;
116 }
117 return modules.find(moduleName) != modules.end();
118}
Yao Chend54f9dd2017-10-17 17:37:48 +0000119
Tej Singh810eeb32019-03-07 19:08:52 -0800120static void write_atoms_info_cpp(FILE *out, const Atoms &atoms) {
Yao Chenc40a19d2018-03-15 16:48:25 -0700121 std::set<string> kTruncatingAtomNames = {"mobile_radio_power_state_changed",
Tej Singh810eeb32019-03-07 19:08:52 -0800122 "audio_state_changed",
123 "call_state_changed",
124 "phone_signal_strength_changed",
125 "mobile_bytes_transfer_by_fg_bg",
126 "mobile_bytes_transfer"};
Yao Chenc40a19d2018-03-15 16:48:25 -0700127 fprintf(out,
128 "const std::set<int> "
129 "AtomsInfo::kNotTruncatingTimestampAtomWhiteList = {\n");
130 for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
131 atom != atoms.decls.end(); atom++) {
132 if (kTruncatingAtomNames.find(atom->name) ==
133 kTruncatingAtomNames.end()) {
134 string constant = make_constant_name(atom->name);
135 fprintf(out, " %s,\n", constant.c_str());
136 }
137 }
138 fprintf(out, "};\n");
139 fprintf(out, "\n");
140
141 fprintf(out,
142 "const std::set<int> AtomsInfo::kAtomsWithAttributionChain = {\n");
143 for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
144 atom != atoms.decls.end(); atom++) {
145 for (vector<AtomField>::const_iterator field = atom->fields.begin();
146 field != atom->fields.end(); field++) {
147 if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
148 string constant = make_constant_name(atom->name);
149 fprintf(out, " %s,\n", constant.c_str());
150 break;
151 }
152 }
153 }
Andrei Oneada01ea52019-01-30 15:28:36 +0000154
155 fprintf(out, "};\n");
156 fprintf(out, "\n");
157
158 fprintf(out,
159 "const std::set<int> AtomsInfo::kWhitelistedAtoms = {\n");
160 for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
161 atom != atoms.decls.end(); atom++) {
162 if (atom->whitelisted) {
163 string constant = make_constant_name(atom->name);
164 fprintf(out, " %s,\n", constant.c_str());
165 }
166 }
167
Yao Chenc40a19d2018-03-15 16:48:25 -0700168 fprintf(out, "};\n");
169 fprintf(out, "\n");
170
Yangster-macca5c0862018-04-09 22:39:53 -0700171 fprintf(out, "static std::map<int, int> getAtomUidField() {\n");
Yao Chenc40a19d2018-03-15 16:48:25 -0700172 fprintf(out, " std::map<int, int> uidField;\n");
173 for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
174 atom != atoms.decls.end(); atom++) {
175 if (atom->uidField == 0) {
176 continue;
177 }
178 fprintf(out,
179 "\n // Adding uid field for atom "
180 "(%d)%s\n",
181 atom->code, atom->name.c_str());
182 fprintf(out, " uidField[static_cast<int>(%s)] = %d;\n",
183 make_constant_name(atom->name).c_str(), atom->uidField);
184 }
185
186 fprintf(out, " return uidField;\n");
187 fprintf(out, "};\n");
188
189 fprintf(out,
190 "const std::map<int, int> AtomsInfo::kAtomsWithUidField = "
191 "getAtomUidField();\n");
192
193 fprintf(out,
194 "static std::map<int, StateAtomFieldOptions> "
195 "getStateAtomFieldOptions() {\n");
196 fprintf(out, " std::map<int, StateAtomFieldOptions> options;\n");
197 fprintf(out, " StateAtomFieldOptions opt;\n");
198 for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
199 atom != atoms.decls.end(); atom++) {
200 if (atom->primaryFields.size() == 0 && atom->exclusiveField == 0) {
201 continue;
202 }
203 fprintf(out,
204 "\n // Adding primary and exclusive fields for atom "
205 "(%d)%s\n",
206 atom->code, atom->name.c_str());
207 fprintf(out, " opt.primaryFields.clear();\n");
208 for (const auto& field : atom->primaryFields) {
209 fprintf(out, " opt.primaryFields.push_back(%d);\n", field);
210 }
211
212 fprintf(out, " opt.exclusiveField = %d;\n", atom->exclusiveField);
213 fprintf(out, " options[static_cast<int>(%s)] = opt;\n",
214 make_constant_name(atom->name).c_str());
215 }
216
217 fprintf(out, " return options;\n");
Yao Chenbbdd67d2018-10-24 12:15:56 -0700218 fprintf(out, "}\n");
Yao Chenc40a19d2018-03-15 16:48:25 -0700219
220 fprintf(out,
221 "const std::map<int, StateAtomFieldOptions> "
222 "AtomsInfo::kStateAtomsFieldOptions = "
223 "getStateAtomFieldOptions();\n");
224
Yao Chenbbdd67d2018-10-24 12:15:56 -0700225 fprintf(out,
226 "static std::map<int, std::vector<int>> "
227 "getBinaryFieldAtoms() {\n");
228 fprintf(out, " std::map<int, std::vector<int>> options;\n");
229 for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
230 atom != atoms.decls.end(); atom++) {
231 if (atom->binaryFields.size() == 0) {
232 continue;
233 }
234 fprintf(out,
235 "\n // Adding binary fields for atom "
236 "(%d)%s\n",
237 atom->code, atom->name.c_str());
238
239 for (const auto& field : atom->binaryFields) {
240 fprintf(out, " options[static_cast<int>(%s)].push_back(%d);\n",
241 make_constant_name(atom->name).c_str(), field);
242 }
243 }
244
245 fprintf(out, " return options;\n");
246 fprintf(out, "}\n");
247
248 fprintf(out,
249 "const std::map<int, std::vector<int>> "
250 "AtomsInfo::kBytesFieldAtoms = "
251 "getBinaryFieldAtoms();\n");
Tej Singh810eeb32019-03-07 19:08:52 -0800252}
253
254// Writes namespaces for the cpp and header files, returning the number of namespaces written.
255void write_namespace(FILE* out, const string& cppNamespaces) {
256 vector<string> cppNamespaceVec = android::base::Split(cppNamespaces, ",");
257 for (string cppNamespace : cppNamespaceVec) {
258 fprintf(out, "namespace %s {\n", cppNamespace.c_str());
259 }
260}
261
262// Writes namespace closing brackets for cpp and header files.
263void write_closing_namespace(FILE* out, const string& cppNamespaces) {
264 vector<string> cppNamespaceVec = android::base::Split(cppNamespaces, ",");
265 for (auto it = cppNamespaceVec.rbegin(); it != cppNamespaceVec.rend(); ++it) {
266 fprintf(out, "} // namespace %s\n", it->c_str());
267 }
268}
269
270static int write_stats_log_cpp(FILE *out, const Atoms &atoms, const AtomDecl &attributionDecl,
271 const string& moduleName, const string& cppNamespace,
272 const string& importHeader) {
273 // Print prelude
274 fprintf(out, "// This file is autogenerated\n");
275 fprintf(out, "\n");
276
277 fprintf(out, "#include <mutex>\n");
278 fprintf(out, "#include <chrono>\n");
279 fprintf(out, "#include <thread>\n");
280 fprintf(out, "#ifdef __ANDROID__\n");
281 fprintf(out, "#include <cutils/properties.h>\n");
282 fprintf(out, "#endif\n");
283 fprintf(out, "#include <stats_event_list.h>\n");
284 fprintf(out, "#include <log/log.h>\n");
285 fprintf(out, "#include <%s>\n", importHeader.c_str());
286 fprintf(out, "#include <utils/SystemClock.h>\n");
287 fprintf(out, "\n");
288
289 write_namespace(out, cppNamespace);
290 fprintf(out, "// the single event tag id for all stats logs\n");
291 fprintf(out, "const static int kStatsEventTag = 1937006964;\n");
292 fprintf(out, "#ifdef __ANDROID__\n");
293 fprintf(out, "const static bool kStatsdEnabled = property_get_bool(\"ro.statsd.enable\", true);\n");
294 fprintf(out, "#else\n");
295 fprintf(out, "const static bool kStatsdEnabled = false;\n");
296 fprintf(out, "#endif\n");
297
298 // AtomsInfo is only used by statsd internally and is not needed for other modules.
299 if (moduleName == DEFAULT_MODULE_NAME) {
300 write_atoms_info_cpp(out, atoms);
301 }
Yangster-macca5c0862018-04-09 22:39:53 -0700302
303 fprintf(out, "int64_t lastRetryTimestampNs = -1;\n");
304 fprintf(out, "const int64_t kMinRetryIntervalNs = NS_PER_SEC * 60 * 20; // 20 minutes\n");
305 fprintf(out, "static std::mutex mLogdRetryMutex;\n");
306
Yao Chend54f9dd2017-10-17 17:37:48 +0000307 // Print write methods
308 fprintf(out, "\n");
Tej Singh810eeb32019-03-07 19:08:52 -0800309 for (auto signature_to_modules_it = atoms.signatures_to_modules.begin();
310 signature_to_modules_it != atoms.signatures_to_modules.end(); signature_to_modules_it++) {
311 if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) {
312 continue;
313 }
314 vector<java_type_t> signature = signature_to_modules_it->first;
Yao Chend54f9dd2017-10-17 17:37:48 +0000315 int argIndex;
316
Yao Chen97e21ec2018-03-29 11:00:38 -0700317 fprintf(out, "int\n");
Yangster-macb8382a12018-04-04 10:39:12 -0700318 fprintf(out, "try_stats_write(int32_t code");
Yao Chend54f9dd2017-10-17 17:37:48 +0000319 argIndex = 1;
Tej Singh810eeb32019-03-07 19:08:52 -0800320 for (vector<java_type_t>::const_iterator arg = signature.begin();
321 arg != signature.end(); arg++) {
Yangster-mac7604aea2017-12-11 22:55:49 -0800322 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
323 for (auto chainField : attributionDecl.fields) {
324 if (chainField.javaType == JAVA_TYPE_STRING) {
325 fprintf(out, ", const std::vector<%s>& %s",
326 cpp_type_name(chainField.javaType),
327 chainField.name.c_str());
328 } else {
329 fprintf(out, ", const %s* %s, size_t %s_length",
330 cpp_type_name(chainField.javaType),
331 chainField.name.c_str(), chainField.name.c_str());
332 }
333 }
Yangster-mace124e422018-08-16 10:30:28 -0700334 } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
Howard Ro4078dd42018-09-27 17:41:08 -0700335 fprintf(out, ", const std::map<int, int32_t>& arg%d_1, "
336 "const std::map<int, int64_t>& arg%d_2, "
337 "const std::map<int, char const*>& arg%d_3, "
338 "const std::map<int, float>& arg%d_4",
339 argIndex, argIndex, argIndex, argIndex);
Yangster-mac7604aea2017-12-11 22:55:49 -0800340 } else {
341 fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
342 }
Yao Chend54f9dd2017-10-17 17:37:48 +0000343 argIndex++;
344 }
345 fprintf(out, ")\n");
346
347 fprintf(out, "{\n");
348 argIndex = 1;
Yao Chencf3829a2018-06-05 14:20:35 -0700349 fprintf(out, " if (kStatsdEnabled) {\n");
Yao Chenf7bc6ab2018-04-18 13:45:48 -0700350 fprintf(out, " stats_event_list event(kStatsEventTag);\n");
Yangster-mac330af582018-02-08 15:24:38 -0800351 fprintf(out, " event << android::elapsedRealtimeNano();\n\n");
Yangster-mac7604aea2017-12-11 22:55:49 -0800352 fprintf(out, " event << code;\n\n");
Tej Singh810eeb32019-03-07 19:08:52 -0800353 for (vector<java_type_t>::const_iterator arg = signature.begin();
354 arg != signature.end(); arg++) {
Yangster-mac7604aea2017-12-11 22:55:49 -0800355 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
356 for (const auto &chainField : attributionDecl.fields) {
357 if (chainField.javaType == JAVA_TYPE_STRING) {
358 fprintf(out, " if (%s_length != %s.size()) {\n",
359 attributionDecl.fields.front().name.c_str(), chainField.name.c_str());
Yao Chen97e21ec2018-03-29 11:00:38 -0700360 fprintf(out, " return -EINVAL;\n");
Yangster-mac7604aea2017-12-11 22:55:49 -0800361 fprintf(out, " }\n");
362 }
363 }
364 fprintf(out, "\n event.begin();\n");
365 fprintf(out, " for (size_t i = 0; i < %s_length; ++i) {\n",
366 attributionDecl.fields.front().name.c_str());
367 fprintf(out, " event.begin();\n");
368 for (const auto &chainField : attributionDecl.fields) {
Yangster-mac20ac9442018-01-08 14:54:48 -0800369 if (chainField.javaType == JAVA_TYPE_STRING) {
370 fprintf(out, " if (%s[i] != NULL) {\n", chainField.name.c_str());
371 fprintf(out, " event << %s[i];\n", chainField.name.c_str());
372 fprintf(out, " } else {\n");
373 fprintf(out, " event << \"\";\n");
374 fprintf(out, " }\n");
375 } else {
376 fprintf(out, " event << %s[i];\n", chainField.name.c_str());
377 }
Yangster-mac7604aea2017-12-11 22:55:49 -0800378 }
379 fprintf(out, " event.end();\n");
Yao Chend54f9dd2017-10-17 17:37:48 +0000380 fprintf(out, " }\n");
Yangster-mac7604aea2017-12-11 22:55:49 -0800381 fprintf(out, " event.end();\n\n");
Yangster-mace124e422018-08-16 10:30:28 -0700382 } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
383 fprintf(out, " event.begin();\n\n");
384 fprintf(out, " for (const auto& it : arg%d_1) {\n", argIndex);
385 fprintf(out, " event.begin();\n");
386 fprintf(out, " event << it.first;\n");
387 fprintf(out, " event << it.second;\n");
388 fprintf(out, " event.end();\n");
389 fprintf(out, " }\n");
390
391 fprintf(out, " for (const auto& it : arg%d_2) {\n", argIndex);
392 fprintf(out, " event.begin();\n");
393 fprintf(out, " event << it.first;\n");
394 fprintf(out, " event << it.second;\n");
395 fprintf(out, " event.end();\n");
396 fprintf(out, " }\n");
397
398 fprintf(out, " for (const auto& it : arg%d_3) {\n", argIndex);
399 fprintf(out, " event.begin();\n");
400 fprintf(out, " event << it.first;\n");
401 fprintf(out, " event << it.second;\n");
402 fprintf(out, " event.end();\n");
403 fprintf(out, " }\n");
404
Howard Ro4078dd42018-09-27 17:41:08 -0700405 fprintf(out, " for (const auto& it : arg%d_4) {\n", argIndex);
406 fprintf(out, " event.begin();\n");
407 fprintf(out, " event << it.first;\n");
408 fprintf(out, " event << it.second;\n");
409 fprintf(out, " event.end();\n");
410 fprintf(out, " }\n");
411
Yangster-mace124e422018-08-16 10:30:28 -0700412 fprintf(out, " event.end();\n\n");
Yao Chen1fe9f592018-12-06 10:34:25 -0800413 } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
414 fprintf(out,
Yao Chene89572c2019-01-09 15:41:50 -0800415 " event.AppendCharArray(arg%d.arg, "
416 "arg%d.arg_length);\n",
Yao Chen1fe9f592018-12-06 10:34:25 -0800417 argIndex, argIndex);
Yangster-mac7604aea2017-12-11 22:55:49 -0800418 } else {
419 if (*arg == JAVA_TYPE_STRING) {
420 fprintf(out, " if (arg%d == NULL) {\n", argIndex);
421 fprintf(out, " arg%d = \"\";\n", argIndex);
422 fprintf(out, " }\n");
423 }
424 fprintf(out, " event << arg%d;\n", argIndex);
Yao Chend54f9dd2017-10-17 17:37:48 +0000425 }
Yao Chend54f9dd2017-10-17 17:37:48 +0000426 argIndex++;
427 }
428
Yao Chen97e21ec2018-03-29 11:00:38 -0700429 fprintf(out, " return event.write(LOG_ID_STATS);\n");
Yao Chencf3829a2018-06-05 14:20:35 -0700430 fprintf(out, " } else {\n");
431 fprintf(out, " return 1;\n");
432 fprintf(out, " }\n");
Yao Chend54f9dd2017-10-17 17:37:48 +0000433 fprintf(out, "}\n");
434 fprintf(out, "\n");
435 }
436
Tej Singh810eeb32019-03-07 19:08:52 -0800437 for (auto signature_to_modules_it = atoms.signatures_to_modules.begin();
438 signature_to_modules_it != atoms.signatures_to_modules.end(); signature_to_modules_it++) {
439 if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) {
440 continue;
441 }
442 vector<java_type_t> signature = signature_to_modules_it->first;
Yangster-macb8382a12018-04-04 10:39:12 -0700443 int argIndex;
444
Yangster-mace124e422018-08-16 10:30:28 -0700445 fprintf(out, "int\n");
Yangster-macb8382a12018-04-04 10:39:12 -0700446 fprintf(out, "stats_write(int32_t code");
447 argIndex = 1;
Tej Singh810eeb32019-03-07 19:08:52 -0800448 for (vector<java_type_t>::const_iterator arg = signature.begin();
449 arg != signature.end(); arg++) {
Yangster-macb8382a12018-04-04 10:39:12 -0700450 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
451 for (auto chainField : attributionDecl.fields) {
452 if (chainField.javaType == JAVA_TYPE_STRING) {
453 fprintf(out, ", const std::vector<%s>& %s",
454 cpp_type_name(chainField.javaType),
455 chainField.name.c_str());
456 } else {
457 fprintf(out, ", const %s* %s, size_t %s_length",
458 cpp_type_name(chainField.javaType),
459 chainField.name.c_str(), chainField.name.c_str());
460 }
461 }
Yangster-mace124e422018-08-16 10:30:28 -0700462 } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
Yao Chen1fe9f592018-12-06 10:34:25 -0800463 fprintf(out,
464 ", const std::map<int, int32_t>& arg%d_1, "
465 "const std::map<int, int64_t>& arg%d_2, "
466 "const std::map<int, char const*>& arg%d_3, "
467 "const std::map<int, float>& arg%d_4",
468 argIndex, argIndex, argIndex, argIndex);
Yangster-macb8382a12018-04-04 10:39:12 -0700469 } else {
470 fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
471 }
472 argIndex++;
473 }
474 fprintf(out, ")\n");
475
476 fprintf(out, "{\n");
477 fprintf(out, " int ret = 0;\n");
478
Yangster-macca5c0862018-04-09 22:39:53 -0700479 fprintf(out, " for(int retry = 0; retry < 2; ++retry) {\n");
Yangster-macb8382a12018-04-04 10:39:12 -0700480 fprintf(out, " ret = try_stats_write(code");
481
482 argIndex = 1;
Tej Singh810eeb32019-03-07 19:08:52 -0800483 for (vector<java_type_t>::const_iterator arg = signature.begin();
484 arg != signature.end(); arg++) {
Yangster-macb8382a12018-04-04 10:39:12 -0700485 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
486 for (auto chainField : attributionDecl.fields) {
487 if (chainField.javaType == JAVA_TYPE_STRING) {
488 fprintf(out, ", %s",
489 chainField.name.c_str());
490 } else {
491 fprintf(out, ", %s, %s_length",
492 chainField.name.c_str(), chainField.name.c_str());
493 }
494 }
Yao Chen1fe9f592018-12-06 10:34:25 -0800495 } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
496 fprintf(out, ", arg%d_1, arg%d_2, arg%d_3, arg%d_4", argIndex,
497 argIndex, argIndex, argIndex);
Yangster-macb8382a12018-04-04 10:39:12 -0700498 } else {
499 fprintf(out, ", arg%d", argIndex);
500 }
501 argIndex++;
502 }
503 fprintf(out, ");\n");
Yao Chen0f5d6612018-08-22 14:11:51 -0700504 fprintf(out, " if (ret >= 0) { break; }\n");
Yangster-macca5c0862018-04-09 22:39:53 -0700505
506 fprintf(out, " {\n");
507 fprintf(out, " std::lock_guard<std::mutex> lock(mLogdRetryMutex);\n");
508 fprintf(out, " if ((android::elapsedRealtimeNano() - lastRetryTimestampNs) <= "
509 "kMinRetryIntervalNs) break;\n");
510 fprintf(out, " lastRetryTimestampNs = android::elapsedRealtimeNano();\n");
511 fprintf(out, " }\n");
512 fprintf(out, " std::this_thread::sleep_for(std::chrono::milliseconds(10));\n");
Yangster-macb8382a12018-04-04 10:39:12 -0700513 fprintf(out, " }\n");
Yao Chen0f5d6612018-08-22 14:11:51 -0700514 fprintf(out, " if (ret < 0) {\n");
Yao Chen49d7dd72019-03-26 14:02:11 -0700515 fprintf(out, " note_log_drop(ret, code);\n");
Yao Chen0f5d6612018-08-22 14:11:51 -0700516 fprintf(out, " }\n");
Yangster-macb8382a12018-04-04 10:39:12 -0700517 fprintf(out, " return ret;\n");
518 fprintf(out, "}\n");
519 fprintf(out, "\n");
520 }
521
Tej Singh810eeb32019-03-07 19:08:52 -0800522 for (auto signature_it = atoms.non_chained_signatures_to_modules.begin();
523 signature_it != atoms.non_chained_signatures_to_modules.end(); signature_it++) {
524 if (!signature_needed_for_module(signature_it->second, moduleName)) {
525 continue;
526 }
527 vector<java_type_t> signature = signature_it->first;
Yangster-macba5b9e42018-01-10 21:31:59 -0800528 int argIndex;
529
Yao Chen97e21ec2018-03-29 11:00:38 -0700530 fprintf(out, "int\n");
Yangster-macb8382a12018-04-04 10:39:12 -0700531 fprintf(out, "try_stats_write_non_chained(int32_t code");
Yangster-macba5b9e42018-01-10 21:31:59 -0800532 argIndex = 1;
Tej Singh810eeb32019-03-07 19:08:52 -0800533 for (vector<java_type_t>::const_iterator arg = signature.begin();
534 arg != signature.end(); arg++) {
Yangster-macba5b9e42018-01-10 21:31:59 -0800535 fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
536 argIndex++;
537 }
538 fprintf(out, ")\n");
539
540 fprintf(out, "{\n");
541 argIndex = 1;
Yao Chencf3829a2018-06-05 14:20:35 -0700542 fprintf(out, " if (kStatsdEnabled) {\n");
Yao Chenf7bc6ab2018-04-18 13:45:48 -0700543 fprintf(out, " stats_event_list event(kStatsEventTag);\n");
Yangster-mac31ddcde2018-02-14 16:09:35 -0800544 fprintf(out, " event << android::elapsedRealtimeNano();\n\n");
Yangster-macba5b9e42018-01-10 21:31:59 -0800545 fprintf(out, " event << code;\n\n");
Tej Singh810eeb32019-03-07 19:08:52 -0800546 for (vector<java_type_t>::const_iterator arg = signature.begin();
547 arg != signature.end(); arg++) {
Yangster-macba5b9e42018-01-10 21:31:59 -0800548 if (argIndex == 1) {
549 fprintf(out, " event.begin();\n\n");
550 fprintf(out, " event.begin();\n");
551 }
552 if (*arg == JAVA_TYPE_STRING) {
553 fprintf(out, " if (arg%d == NULL) {\n", argIndex);
554 fprintf(out, " arg%d = \"\";\n", argIndex);
555 fprintf(out, " }\n");
556 }
Yao Chene89572c2019-01-09 15:41:50 -0800557 if (*arg == JAVA_TYPE_BYTE_ARRAY) {
558 fprintf(out,
559 " event.AppendCharArray(arg%d.arg, "
560 "arg%d.arg_length);",
561 argIndex, argIndex);
562 } else {
563 fprintf(out, " event << arg%d;\n", argIndex);
564 }
Yangster-macba5b9e42018-01-10 21:31:59 -0800565 if (argIndex == 2) {
566 fprintf(out, " event.end();\n\n");
567 fprintf(out, " event.end();\n\n");
568 }
569 argIndex++;
570 }
571
Yao Chen97e21ec2018-03-29 11:00:38 -0700572 fprintf(out, " return event.write(LOG_ID_STATS);\n");
Yao Chencf3829a2018-06-05 14:20:35 -0700573 fprintf(out, " } else {\n");
574 fprintf(out, " return 1;\n");
575 fprintf(out, " }\n");
Yangster-macba5b9e42018-01-10 21:31:59 -0800576 fprintf(out, "}\n");
577 fprintf(out, "\n");
578 }
Yangster-macb8382a12018-04-04 10:39:12 -0700579
Tej Singh810eeb32019-03-07 19:08:52 -0800580 for (auto signature_it = atoms.non_chained_signatures_to_modules.begin();
581 signature_it != atoms.non_chained_signatures_to_modules.end(); signature_it++) {
582 if (!signature_needed_for_module(signature_it->second, moduleName)) {
583 continue;
584 }
585 vector<java_type_t> signature = signature_it->first;
Yangster-macb8382a12018-04-04 10:39:12 -0700586 int argIndex;
587
588 fprintf(out, "int\n");
589 fprintf(out, "stats_write_non_chained(int32_t code");
590 argIndex = 1;
Tej Singh810eeb32019-03-07 19:08:52 -0800591 for (vector<java_type_t>::const_iterator arg = signature.begin();
592 arg != signature.end(); arg++) {
Yangster-macb8382a12018-04-04 10:39:12 -0700593 fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
594 argIndex++;
595 }
596 fprintf(out, ")\n");
597
598 fprintf(out, "{\n");
599
600 fprintf(out, " int ret = 0;\n");
Yangster-macca5c0862018-04-09 22:39:53 -0700601 fprintf(out, " for(int retry = 0; retry < 2; ++retry) {\n");
Yangster-macb8382a12018-04-04 10:39:12 -0700602 fprintf(out, " ret = try_stats_write_non_chained(code");
603
604 argIndex = 1;
Tej Singh810eeb32019-03-07 19:08:52 -0800605 for (vector<java_type_t>::const_iterator arg = signature.begin();
606 arg != signature.end(); arg++) {
Yangster-macb8382a12018-04-04 10:39:12 -0700607 fprintf(out, ", arg%d", argIndex);
608 argIndex++;
609 }
610 fprintf(out, ");\n");
Yao Chen0f5d6612018-08-22 14:11:51 -0700611 fprintf(out, " if (ret >= 0) { break; }\n");
Yangster-macca5c0862018-04-09 22:39:53 -0700612
613 fprintf(out, " {\n");
614 fprintf(out, " std::lock_guard<std::mutex> lock(mLogdRetryMutex);\n");
615 fprintf(out, " if ((android::elapsedRealtimeNano() - lastRetryTimestampNs) <= "
616 "kMinRetryIntervalNs) break;\n");
617 fprintf(out, " lastRetryTimestampNs = android::elapsedRealtimeNano();\n");
618 fprintf(out, " }\n");
619
620 fprintf(out, " std::this_thread::sleep_for(std::chrono::milliseconds(10));\n");
Yangster-macb8382a12018-04-04 10:39:12 -0700621 fprintf(out, " }\n");
Yao Chen0f5d6612018-08-22 14:11:51 -0700622 fprintf(out, " if (ret < 0) {\n");
Yao Chen49d7dd72019-03-26 14:02:11 -0700623 fprintf(out, " note_log_drop(ret, code);\n");
Yao Chen0f5d6612018-08-22 14:11:51 -0700624 fprintf(out, " }\n");
625 fprintf(out, " return ret;\n\n");
Yangster-macb8382a12018-04-04 10:39:12 -0700626 fprintf(out, "}\n");
627
628 fprintf(out, "\n");
629 }
630
631
Yao Chend54f9dd2017-10-17 17:37:48 +0000632 // Print footer
633 fprintf(out, "\n");
Tej Singh810eeb32019-03-07 19:08:52 -0800634 write_closing_namespace(out, cppNamespace);
Yao Chend54f9dd2017-10-17 17:37:48 +0000635
636 return 0;
637}
638
Yangster-macba5b9e42018-01-10 21:31:59 -0800639void build_non_chained_decl_map(const Atoms& atoms,
640 std::map<int, set<AtomDecl>::const_iterator>* decl_map){
641 for (set<AtomDecl>::const_iterator atom = atoms.non_chained_decls.begin();
642 atom != atoms.non_chained_decls.end(); atom++) {
643 decl_map->insert(std::make_pair(atom->code, atom));
644 }
645}
646
647static void write_cpp_usage(
648 FILE* out, const string& method_name, const string& atom_code_name,
649 const AtomDecl& atom, const AtomDecl &attributionDecl) {
Yao Chene89572c2019-01-09 15:41:50 -0800650 fprintf(out, " * Usage: %s(StatsLog.%s", method_name.c_str(),
651 atom_code_name.c_str());
652
Yangster-macba5b9e42018-01-10 21:31:59 -0800653 for (vector<AtomField>::const_iterator field = atom.fields.begin();
654 field != atom.fields.end(); field++) {
655 if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
656 for (auto chainField : attributionDecl.fields) {
657 if (chainField.javaType == JAVA_TYPE_STRING) {
658 fprintf(out, ", const std::vector<%s>& %s",
659 cpp_type_name(chainField.javaType),
660 chainField.name.c_str());
661 } else {
662 fprintf(out, ", const %s* %s, size_t %s_length",
663 cpp_type_name(chainField.javaType),
664 chainField.name.c_str(), chainField.name.c_str());
665 }
666 }
Yangster-mace124e422018-08-16 10:30:28 -0700667 } else if (field->javaType == JAVA_TYPE_KEY_VALUE_PAIR) {
Howard Ro4078dd42018-09-27 17:41:08 -0700668 fprintf(out, ", const std::map<int, int32_t>& %s_int"
669 ", const std::map<int, int64_t>& %s_long"
Yangster-mace124e422018-08-16 10:30:28 -0700670 ", const std::map<int, char const*>& %s_str"
671 ", const std::map<int, float>& %s_float",
Howard Ro4078dd42018-09-27 17:41:08 -0700672 field->name.c_str(),
673 field->name.c_str(),
674 field->name.c_str(),
675 field->name.c_str());
Yangster-macba5b9e42018-01-10 21:31:59 -0800676 } else {
677 fprintf(out, ", %s %s", cpp_type_name(field->javaType), field->name.c_str());
678 }
679 }
680 fprintf(out, ");\n");
681}
682
683static void write_cpp_method_header(
Tej Singh810eeb32019-03-07 19:08:52 -0800684 FILE* out,
685 const string& method_name,
686 const map<vector<java_type_t>, set<string>>& signatures_to_modules,
687 const AtomDecl &attributionDecl, const string& moduleName) {
688
689 for (auto signature_to_modules_it = signatures_to_modules.begin();
690 signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
691 // Skip if this signature is not needed for the module.
692 if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) {
693 continue;
694 }
695
696 vector<java_type_t> signature = signature_to_modules_it->first;
Yangster-mace124e422018-08-16 10:30:28 -0700697 fprintf(out, "int %s(int32_t code", method_name.c_str());
Yangster-macba5b9e42018-01-10 21:31:59 -0800698 int argIndex = 1;
Tej Singh810eeb32019-03-07 19:08:52 -0800699 for (vector<java_type_t>::const_iterator arg = signature.begin();
700 arg != signature.end(); arg++) {
Yangster-macba5b9e42018-01-10 21:31:59 -0800701 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
702 for (auto chainField : attributionDecl.fields) {
703 if (chainField.javaType == JAVA_TYPE_STRING) {
704 fprintf(out, ", const std::vector<%s>& %s",
705 cpp_type_name(chainField.javaType), chainField.name.c_str());
706 } else {
707 fprintf(out, ", const %s* %s, size_t %s_length",
708 cpp_type_name(chainField.javaType),
709 chainField.name.c_str(), chainField.name.c_str());
710 }
711 }
Yangster-mace124e422018-08-16 10:30:28 -0700712 } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
Howard Ro4078dd42018-09-27 17:41:08 -0700713 fprintf(out, ", const std::map<int, int32_t>& arg%d_1, "
714 "const std::map<int, int64_t>& arg%d_2, "
715 "const std::map<int, char const*>& arg%d_3, "
716 "const std::map<int, float>& arg%d_4",
717 argIndex, argIndex, argIndex, argIndex);
Yangster-macba5b9e42018-01-10 21:31:59 -0800718 } else {
719 fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
720 }
721 argIndex++;
722 }
723 fprintf(out, ");\n");
724
725 }
726}
Yao Chend54f9dd2017-10-17 17:37:48 +0000727
728static int
Tej Singh810eeb32019-03-07 19:08:52 -0800729write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl,
730 const string& moduleName, const string& cppNamespace)
Yao Chend54f9dd2017-10-17 17:37:48 +0000731{
Yao Chend54f9dd2017-10-17 17:37:48 +0000732 // Print prelude
733 fprintf(out, "// This file is autogenerated\n");
734 fprintf(out, "\n");
735 fprintf(out, "#pragma once\n");
736 fprintf(out, "\n");
737 fprintf(out, "#include <stdint.h>\n");
Yangster-mac7604aea2017-12-11 22:55:49 -0800738 fprintf(out, "#include <vector>\n");
Yao Chen9c1debe2018-02-19 14:39:19 -0800739 fprintf(out, "#include <map>\n");
Yangster-mac68985802018-01-21 10:05:09 -0800740 fprintf(out, "#include <set>\n");
Yao Chend54f9dd2017-10-17 17:37:48 +0000741 fprintf(out, "\n");
742
Tej Singh810eeb32019-03-07 19:08:52 -0800743 write_namespace(out, cppNamespace);
Yao Chend54f9dd2017-10-17 17:37:48 +0000744 fprintf(out, "\n");
745 fprintf(out, "/*\n");
746 fprintf(out, " * API For logging statistics events.\n");
747 fprintf(out, " */\n");
748 fprintf(out, "\n");
749 fprintf(out, "/**\n");
Stefan Lafon9478f352017-10-30 21:20:20 -0700750 fprintf(out, " * Constants for atom codes.\n");
Yao Chend54f9dd2017-10-17 17:37:48 +0000751 fprintf(out, " */\n");
752 fprintf(out, "enum {\n");
753
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
Yao Chend54f9dd2017-10-17 17:37:48 +0000757 size_t i = 0;
Muhammad Qureshidc132af2019-02-05 13:07:40 -0800758 // Print atom constants
Yao Chend54f9dd2017-10-17 17:37:48 +0000759 for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
Yangster-mac7604aea2017-12-11 22:55:49 -0800760 atom != atoms.decls.end(); atom++) {
Tej Singh810eeb32019-03-07 19:08:52 -0800761 // Skip if the atom is not needed for the module.
762 if (!atom_needed_for_module(*atom, moduleName)) {
763 continue;
764 }
Yao Chend54f9dd2017-10-17 17:37:48 +0000765 string constant = make_constant_name(atom->name);
766 fprintf(out, "\n");
767 fprintf(out, " /**\n");
768 fprintf(out, " * %s %s\n", atom->message.c_str(), atom->name.c_str());
Yangster-macba5b9e42018-01-10 21:31:59 -0800769 write_cpp_usage(out, "stats_write", constant, *atom, attributionDecl);
770
771 auto non_chained_decl = atom_code_to_non_chained_decl_map.find(atom->code);
772 if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) {
773 write_cpp_usage(out, "stats_write_non_chained", constant, *non_chained_decl->second,
774 attributionDecl);
Yao Chend54f9dd2017-10-17 17:37:48 +0000775 }
Yao Chend54f9dd2017-10-17 17:37:48 +0000776 fprintf(out, " */\n");
777 char const* const comma = (i == atoms.decls.size() - 1) ? "" : ",";
778 fprintf(out, " %s = %d%s\n", constant.c_str(), atom->code, comma);
Yao Chenb3561512017-11-21 18:07:17 -0800779 if (atom->code < PULL_ATOM_START_ID && atom->code > maxPushedAtomId) {
780 maxPushedAtomId = atom->code;
781 }
Yao Chend54f9dd2017-10-17 17:37:48 +0000782 i++;
783 }
784 fprintf(out, "\n");
785 fprintf(out, "};\n");
786 fprintf(out, "\n");
787
Muhammad Qureshidc132af2019-02-05 13:07:40 -0800788 // Print constants for the enum values.
789 fprintf(out, "//\n");
790 fprintf(out, "// Constants for enum values\n");
791 fprintf(out, "//\n\n");
792 for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
793 atom != atoms.decls.end(); atom++) {
Tej Singh810eeb32019-03-07 19:08:52 -0800794 // Skip if the atom is not needed for the module.
795 if (!atom_needed_for_module(*atom, moduleName)) {
796 continue;
797 }
798
Muhammad Qureshidc132af2019-02-05 13:07:40 -0800799 for (vector<AtomField>::const_iterator field = atom->fields.begin();
800 field != atom->fields.end(); field++) {
801 if (field->javaType == JAVA_TYPE_ENUM) {
802 fprintf(out, "// Values for %s.%s\n", atom->message.c_str(),
803 field->name.c_str());
804 for (map<int, string>::const_iterator value = field->enumValues.begin();
805 value != field->enumValues.end(); value++) {
806 fprintf(out, "const int32_t %s__%s__%s = %d;\n",
807 make_constant_name(atom->message).c_str(),
808 make_constant_name(field->name).c_str(),
809 make_constant_name(value->second).c_str(),
810 value->first);
811 }
812 fprintf(out, "\n");
813 }
814 }
815 }
816
Yao Chene89572c2019-01-09 15:41:50 -0800817 fprintf(out, "struct BytesField {\n");
818 fprintf(out,
819 " BytesField(char const* array, size_t len) : arg(array), "
820 "arg_length(len) {}\n");
821 fprintf(out, " char const* arg;\n");
822 fprintf(out, " size_t arg_length;\n");
823 fprintf(out, "};\n");
824 fprintf(out, "\n");
825
Tej Singh810eeb32019-03-07 19:08:52 -0800826 // This metadata is only used by statsd, which uses the default libstatslog.
827 if (moduleName == DEFAULT_MODULE_NAME) {
Yao Chenc40a19d2018-03-15 16:48:25 -0700828
Tej Singh810eeb32019-03-07 19:08:52 -0800829 fprintf(out, "struct StateAtomFieldOptions {\n");
830 fprintf(out, " std::vector<int> primaryFields;\n");
831 fprintf(out, " int exclusiveField;\n");
832 fprintf(out, "};\n");
833 fprintf(out, "\n");
Yao Chen9c1debe2018-02-19 14:39:19 -0800834
Tej Singh810eeb32019-03-07 19:08:52 -0800835 fprintf(out, "struct AtomsInfo {\n");
836 fprintf(out,
837 " const static std::set<int> "
838 "kNotTruncatingTimestampAtomWhiteList;\n");
839 fprintf(out, " const static std::map<int, int> kAtomsWithUidField;\n");
840 fprintf(out,
841 " const static std::set<int> kAtomsWithAttributionChain;\n");
842 fprintf(out,
843 " const static std::map<int, StateAtomFieldOptions> "
844 "kStateAtomsFieldOptions;\n");
845 fprintf(out,
846 " const static std::map<int, std::vector<int>> "
847 "kBytesFieldAtoms;");
848 fprintf(out,
849 " const static std::set<int> kWhitelistedAtoms;\n");
850 fprintf(out, "};\n");
851
852 fprintf(out, "const static int kMaxPushedAtomId = %d;\n\n",
853 maxPushedAtomId);
854 }
Yao Chen9c1debe2018-02-19 14:39:19 -0800855
Yao Chend54f9dd2017-10-17 17:37:48 +0000856 // Print write methods
857 fprintf(out, "//\n");
858 fprintf(out, "// Write methods\n");
859 fprintf(out, "//\n");
Tej Singh810eeb32019-03-07 19:08:52 -0800860 write_cpp_method_header(out, "stats_write", atoms.signatures_to_modules, attributionDecl,
861 moduleName);
Yangster-macba5b9e42018-01-10 21:31:59 -0800862
863 fprintf(out, "//\n");
864 fprintf(out, "// Write flattened methods\n");
865 fprintf(out, "//\n");
Tej Singh810eeb32019-03-07 19:08:52 -0800866 write_cpp_method_header(out, "stats_write_non_chained", atoms.non_chained_signatures_to_modules,
867 attributionDecl, moduleName);
Yao Chend54f9dd2017-10-17 17:37:48 +0000868
869 fprintf(out, "\n");
Tej Singh810eeb32019-03-07 19:08:52 -0800870 write_closing_namespace(out, cppNamespace);
Yao Chend54f9dd2017-10-17 17:37:48 +0000871
872 return 0;
873}
874
Bookatz0bd97202018-06-05 12:42:37 -0700875static void write_java_usage(FILE* out, const string& method_name, const string& atom_code_name,
876 const AtomDecl& atom) {
Yangster-macba5b9e42018-01-10 21:31:59 -0800877 fprintf(out, " * Usage: StatsLog.%s(StatsLog.%s",
878 method_name.c_str(), atom_code_name.c_str());
879 for (vector<AtomField>::const_iterator field = atom.fields.begin();
880 field != atom.fields.end(); field++) {
881 if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
Bookatz0bd97202018-06-05 12:42:37 -0700882 fprintf(out, ", android.os.WorkSource workSource");
Yangster-mace124e422018-08-16 10:30:28 -0700883 } else if (field->javaType == JAVA_TYPE_KEY_VALUE_PAIR) {
884 fprintf(out, ", SparseArray<Object> value_map");
Yao Chenbbdd67d2018-10-24 12:15:56 -0700885 } else if (field->javaType == JAVA_TYPE_BYTE_ARRAY) {
886 fprintf(out, ", byte[] %s", field->name.c_str());
Yangster-macba5b9e42018-01-10 21:31:59 -0800887 } else {
888 fprintf(out, ", %s %s", java_type_name(field->javaType), field->name.c_str());
889 }
890 }
Bookatz0bd97202018-06-05 12:42:37 -0700891 fprintf(out, ");<br>\n");
Yangster-macba5b9e42018-01-10 21:31:59 -0800892}
893
894static void write_java_method(
Tej Singh810eeb32019-03-07 19:08:52 -0800895 FILE* out,
896 const string& method_name,
897 const map<vector<java_type_t>, set<string>>& signatures_to_modules,
898 const AtomDecl &attributionDecl) {
899
900 for (auto signature_to_modules_it = signatures_to_modules.begin();
901 signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
902 vector<java_type_t> signature = signature_to_modules_it->first;
Tor Norbye0f2dc8d2019-01-08 12:07:15 -0800903 fprintf(out, " /** @hide */\n");
Yao Chen97e21ec2018-03-29 11:00:38 -0700904 fprintf(out, " public static native int %s(int code", method_name.c_str());
Yangster-macba5b9e42018-01-10 21:31:59 -0800905 int argIndex = 1;
Tej Singh810eeb32019-03-07 19:08:52 -0800906 for (vector<java_type_t>::const_iterator arg = signature.begin();
907 arg != signature.end(); arg++) {
Yangster-macba5b9e42018-01-10 21:31:59 -0800908 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
909 for (auto chainField : attributionDecl.fields) {
910 fprintf(out, ", %s[] %s",
911 java_type_name(chainField.javaType), chainField.name.c_str());
912 }
Yangster-mace124e422018-08-16 10:30:28 -0700913 } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
914 fprintf(out, ", SparseArray<Object> value_map");
Yangster-macba5b9e42018-01-10 21:31:59 -0800915 } else {
916 fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
917 }
918 argIndex++;
919 }
920 fprintf(out, ");\n");
921 }
922}
923
Tej Singh810eeb32019-03-07 19:08:52 -0800924static void write_java_work_source_method(FILE* out,
925 const map<vector<java_type_t>, set<string>>& signatures_to_modules) {
Bookatz0bd97202018-06-05 12:42:37 -0700926 fprintf(out, "\n // WorkSource methods.\n");
Tej Singh810eeb32019-03-07 19:08:52 -0800927 for (auto signature_to_modules_it = signatures_to_modules.begin();
928 signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
929 vector<java_type_t> signature = signature_to_modules_it->first;
Bookatz0bd97202018-06-05 12:42:37 -0700930 // Determine if there is Attribution in this signature.
931 int attributionArg = -1;
932 int argIndexMax = 0;
Tej Singh810eeb32019-03-07 19:08:52 -0800933 for (vector<java_type_t>::const_iterator arg = signature.begin();
934 arg != signature.end(); arg++) {
Bookatz0bd97202018-06-05 12:42:37 -0700935 argIndexMax++;
936 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
937 if (attributionArg > -1) {
938 fprintf(stderr, "An atom contains multiple AttributionNode fields.\n");
939 fprintf(stderr, "This is not supported. Aborting WorkSource method writing.\n");
940 fprintf(out, "\n// Invalid for WorkSource: more than one attribution chain.\n");
941 return;
942 }
943 attributionArg = argIndexMax;
944 }
945 }
946 if (attributionArg < 0) {
947 continue;
948 }
949
950 // Method header (signature)
Tor Norbye0f2dc8d2019-01-08 12:07:15 -0800951 fprintf(out, " /** @hide */\n");
Bookatz0bd97202018-06-05 12:42:37 -0700952 fprintf(out, " public static void write(int code");
953 int argIndex = 1;
Tej Singh810eeb32019-03-07 19:08:52 -0800954 for (vector<java_type_t>::const_iterator arg = signature.begin();
955 arg != signature.end(); arg++) {
Bookatz0bd97202018-06-05 12:42:37 -0700956 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
957 fprintf(out, ", WorkSource ws");
958 } else {
959 fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
960 }
961 argIndex++;
962 }
963 fprintf(out, ") {\n");
964
965 // write_non_chained() component. TODO: Remove when flat uids are no longer needed.
966 fprintf(out, " for (int i = 0; i < ws.size(); ++i) {\n");
967 fprintf(out, " write_non_chained(code");
968 for (int argIndex = 1; argIndex <= argIndexMax; argIndex++) {
969 if (argIndex == attributionArg) {
970 fprintf(out, ", ws.get(i), ws.getName(i)");
971 } else {
972 fprintf(out, ", arg%d", argIndex);
973 }
974 }
975 fprintf(out, ");\n");
976 fprintf(out, " }\n"); // close flor-loop
977
978 // write() component.
979 fprintf(out, " ArrayList<WorkSource.WorkChain> workChains = ws.getWorkChains();\n");
980 fprintf(out, " if (workChains != null) {\n");
981 fprintf(out, " for (WorkSource.WorkChain wc : workChains) {\n");
982 fprintf(out, " write(code");
983 for (int argIndex = 1; argIndex <= argIndexMax; argIndex++) {
984 if (argIndex == attributionArg) {
985 fprintf(out, ", wc.getUids(), wc.getTags()");
986 } else {
987 fprintf(out, ", arg%d", argIndex);
988 }
989 }
990 fprintf(out, ");\n");
991 fprintf(out, " }\n"); // close for-loop
992 fprintf(out, " }\n"); // close if
993 fprintf(out, " }\n"); // close method
994 }
995}
Yangster-macba5b9e42018-01-10 21:31:59 -0800996
Yao Chend54f9dd2017-10-17 17:37:48 +0000997static int
Yangster-mac7604aea2017-12-11 22:55:49 -0800998write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl)
Yao Chend54f9dd2017-10-17 17:37:48 +0000999{
Yao Chend54f9dd2017-10-17 17:37:48 +00001000 // Print prelude
1001 fprintf(out, "// This file is autogenerated\n");
1002 fprintf(out, "\n");
1003 fprintf(out, "package android.util;\n");
1004 fprintf(out, "\n");
Bookatz0bd97202018-06-05 12:42:37 -07001005 fprintf(out, "import android.os.WorkSource;\n");
Yangster-mace124e422018-08-16 10:30:28 -07001006 fprintf(out, "import android.util.SparseArray;\n");
Bookatz0bd97202018-06-05 12:42:37 -07001007 fprintf(out, "import java.util.ArrayList;\n");
1008 fprintf(out, "\n");
Yao Chend54f9dd2017-10-17 17:37:48 +00001009 fprintf(out, "\n");
1010 fprintf(out, "/**\n");
1011 fprintf(out, " * API For logging statistics events.\n");
1012 fprintf(out, " * @hide\n");
1013 fprintf(out, " */\n");
David Chen0a368b22017-12-06 16:28:16 -08001014 fprintf(out, "public class StatsLogInternal {\n");
Stefan Lafon9478f352017-10-30 21:20:20 -07001015 fprintf(out, " // Constants for atom codes.\n");
Yao Chend54f9dd2017-10-17 17:37:48 +00001016
Yangster-macba5b9e42018-01-10 21:31:59 -08001017 std::map<int, set<AtomDecl>::const_iterator> atom_code_to_non_chained_decl_map;
1018 build_non_chained_decl_map(atoms, &atom_code_to_non_chained_decl_map);
1019
Stefan Lafon9478f352017-10-30 21:20:20 -07001020 // Print constants for the atom codes.
Yao Chend54f9dd2017-10-17 17:37:48 +00001021 for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
1022 atom != atoms.decls.end(); atom++) {
1023 string constant = make_constant_name(atom->name);
1024 fprintf(out, "\n");
1025 fprintf(out, " /**\n");
Bookatz0bd97202018-06-05 12:42:37 -07001026 fprintf(out, " * %s %s<br>\n", atom->message.c_str(), atom->name.c_str());
1027 write_java_usage(out, "write", constant, *atom);
Yangster-macba5b9e42018-01-10 21:31:59 -08001028 auto non_chained_decl = atom_code_to_non_chained_decl_map.find(atom->code);
1029 if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) {
Bookatz0bd97202018-06-05 12:42:37 -07001030 write_java_usage(out, "write_non_chained", constant, *non_chained_decl->second);
Yao Chend54f9dd2017-10-17 17:37:48 +00001031 }
Tor Norbye0f2dc8d2019-01-08 12:07:15 -08001032 fprintf(out, " * @hide\n");
Yao Chend54f9dd2017-10-17 17:37:48 +00001033 fprintf(out, " */\n");
1034 fprintf(out, " public static final int %s = %d;\n", constant.c_str(), atom->code);
1035 }
1036 fprintf(out, "\n");
1037
Stefan Lafon9478f352017-10-30 21:20:20 -07001038 // Print constants for the enum values.
1039 fprintf(out, " // Constants for enum values.\n\n");
1040 for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
Yangster-mac7604aea2017-12-11 22:55:49 -08001041 atom != atoms.decls.end(); atom++) {
Stefan Lafon9478f352017-10-30 21:20:20 -07001042 for (vector<AtomField>::const_iterator field = atom->fields.begin();
Yangster-mac7604aea2017-12-11 22:55:49 -08001043 field != atom->fields.end(); field++) {
1044 if (field->javaType == JAVA_TYPE_ENUM) {
1045 fprintf(out, " // Values for %s.%s\n", atom->message.c_str(),
1046 field->name.c_str());
1047 for (map<int, string>::const_iterator value = field->enumValues.begin();
1048 value != field->enumValues.end(); value++) {
Tor Norbye0f2dc8d2019-01-08 12:07:15 -08001049 fprintf(out, " /** @hide */\n");
Yangster-mac7604aea2017-12-11 22:55:49 -08001050 fprintf(out, " public static final int %s__%s__%s = %d;\n",
1051 make_constant_name(atom->message).c_str(),
1052 make_constant_name(field->name).c_str(),
1053 make_constant_name(value->second).c_str(),
1054 value->first);
1055 }
1056 fprintf(out, "\n");
Stefan Lafon9478f352017-10-30 21:20:20 -07001057 }
Stefan Lafon9478f352017-10-30 21:20:20 -07001058 }
1059 }
1060
Yao Chend54f9dd2017-10-17 17:37:48 +00001061 // Print write methods
1062 fprintf(out, " // Write methods\n");
Tej Singh810eeb32019-03-07 19:08:52 -08001063 write_java_method(out, "write", atoms.signatures_to_modules, attributionDecl);
1064 write_java_method(out, "write_non_chained", atoms.non_chained_signatures_to_modules,
1065 attributionDecl);
1066 write_java_work_source_method(out, atoms.signatures_to_modules);
Yao Chend54f9dd2017-10-17 17:37:48 +00001067
1068 fprintf(out, "}\n");
1069
1070 return 0;
1071}
1072
1073static const char*
1074jni_type_name(java_type_t type)
1075{
1076 switch (type) {
1077 case JAVA_TYPE_BOOLEAN:
1078 return "jboolean";
1079 case JAVA_TYPE_INT:
Stefan Lafon9478f352017-10-30 21:20:20 -07001080 case JAVA_TYPE_ENUM:
Yao Chend54f9dd2017-10-17 17:37:48 +00001081 return "jint";
1082 case JAVA_TYPE_LONG:
1083 return "jlong";
1084 case JAVA_TYPE_FLOAT:
1085 return "jfloat";
1086 case JAVA_TYPE_DOUBLE:
1087 return "jdouble";
1088 case JAVA_TYPE_STRING:
1089 return "jstring";
Yao Chenbbdd67d2018-10-24 12:15:56 -07001090 case JAVA_TYPE_BYTE_ARRAY:
1091 return "jbyteArray";
Yao Chend54f9dd2017-10-17 17:37:48 +00001092 default:
1093 return "UNKNOWN";
1094 }
1095}
1096
Yangster-mac7604aea2017-12-11 22:55:49 -08001097static const char*
1098jni_array_type_name(java_type_t type)
1099{
1100 switch (type) {
1101 case JAVA_TYPE_INT:
1102 return "jintArray";
Yangster-mace124e422018-08-16 10:30:28 -07001103 case JAVA_TYPE_FLOAT:
1104 return "jfloatArray";
Yangster-mac7604aea2017-12-11 22:55:49 -08001105 case JAVA_TYPE_STRING:
1106 return "jobjectArray";
1107 default:
1108 return "UNKNOWN";
1109 }
1110}
1111
Yao Chend54f9dd2017-10-17 17:37:48 +00001112static string
Yangster-macba5b9e42018-01-10 21:31:59 -08001113jni_function_name(const string& method_name, const vector<java_type_t>& signature)
Yao Chend54f9dd2017-10-17 17:37:48 +00001114{
Yangster-macba5b9e42018-01-10 21:31:59 -08001115 string result("StatsLog_" + method_name);
Yao Chend54f9dd2017-10-17 17:37:48 +00001116 for (vector<java_type_t>::const_iterator arg = signature.begin();
Yangster-mac7604aea2017-12-11 22:55:49 -08001117 arg != signature.end(); arg++) {
Yao Chend54f9dd2017-10-17 17:37:48 +00001118 switch (*arg) {
1119 case JAVA_TYPE_BOOLEAN:
1120 result += "_boolean";
1121 break;
1122 case JAVA_TYPE_INT:
Stefan Lafon9478f352017-10-30 21:20:20 -07001123 case JAVA_TYPE_ENUM:
Yao Chend54f9dd2017-10-17 17:37:48 +00001124 result += "_int";
1125 break;
1126 case JAVA_TYPE_LONG:
1127 result += "_long";
1128 break;
1129 case JAVA_TYPE_FLOAT:
1130 result += "_float";
1131 break;
1132 case JAVA_TYPE_DOUBLE:
1133 result += "_double";
1134 break;
1135 case JAVA_TYPE_STRING:
1136 result += "_String";
1137 break;
Yangster-mac7604aea2017-12-11 22:55:49 -08001138 case JAVA_TYPE_ATTRIBUTION_CHAIN:
1139 result += "_AttributionChain";
1140 break;
Yangster-mace124e422018-08-16 10:30:28 -07001141 case JAVA_TYPE_KEY_VALUE_PAIR:
1142 result += "_KeyValuePairs";
1143 break;
Yao Chenbbdd67d2018-10-24 12:15:56 -07001144 case JAVA_TYPE_BYTE_ARRAY:
1145 result += "_bytes";
1146 break;
Yao Chend54f9dd2017-10-17 17:37:48 +00001147 default:
1148 result += "_UNKNOWN";
1149 break;
1150 }
1151 }
1152 return result;
1153}
1154
1155static const char*
1156java_type_signature(java_type_t type)
1157{
1158 switch (type) {
1159 case JAVA_TYPE_BOOLEAN:
1160 return "Z";
1161 case JAVA_TYPE_INT:
Stefan Lafon9478f352017-10-30 21:20:20 -07001162 case JAVA_TYPE_ENUM:
Yao Chend54f9dd2017-10-17 17:37:48 +00001163 return "I";
1164 case JAVA_TYPE_LONG:
1165 return "J";
1166 case JAVA_TYPE_FLOAT:
1167 return "F";
1168 case JAVA_TYPE_DOUBLE:
1169 return "D";
1170 case JAVA_TYPE_STRING:
1171 return "Ljava/lang/String;";
Yao Chenbbdd67d2018-10-24 12:15:56 -07001172 case JAVA_TYPE_BYTE_ARRAY:
1173 return "[B";
Yao Chend54f9dd2017-10-17 17:37:48 +00001174 default:
1175 return "UNKNOWN";
1176 }
1177}
1178
1179static string
Yangster-mac7604aea2017-12-11 22:55:49 -08001180jni_function_signature(const vector<java_type_t>& signature, const AtomDecl &attributionDecl)
Yao Chend54f9dd2017-10-17 17:37:48 +00001181{
1182 string result("(I");
1183 for (vector<java_type_t>::const_iterator arg = signature.begin();
Yangster-mac7604aea2017-12-11 22:55:49 -08001184 arg != signature.end(); arg++) {
1185 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
1186 for (auto chainField : attributionDecl.fields) {
1187 result += "[";
1188 result += java_type_signature(chainField.javaType);
1189 }
Yangster-mace124e422018-08-16 10:30:28 -07001190 } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
1191 result += "Landroid/util/SparseArray;";
Yangster-mac7604aea2017-12-11 22:55:49 -08001192 } else {
1193 result += java_type_signature(*arg);
1194 }
Yao Chend54f9dd2017-10-17 17:37:48 +00001195 }
Yao Chen97e21ec2018-03-29 11:00:38 -07001196 result += ")I";
Yao Chend54f9dd2017-10-17 17:37:48 +00001197 return result;
1198}
1199
Yangster-mace124e422018-08-16 10:30:28 -07001200static void write_key_value_map_jni(FILE* out) {
Howard Ro4078dd42018-09-27 17:41:08 -07001201 fprintf(out, " std::map<int, int32_t> int32_t_map;\n");
Yangster-mace124e422018-08-16 10:30:28 -07001202 fprintf(out, " std::map<int, int64_t> int64_t_map;\n");
1203 fprintf(out, " std::map<int, float> float_map;\n");
1204 fprintf(out, " std::map<int, char const*> string_map;\n\n");
1205
1206 fprintf(out, " jclass jmap_class = env->FindClass(\"android/util/SparseArray\");\n");
1207
1208 fprintf(out, " jmethodID jget_size_method = env->GetMethodID(jmap_class, \"size\", \"()I\");\n");
1209 fprintf(out, " jmethodID jget_key_method = env->GetMethodID(jmap_class, \"keyAt\", \"(I)I\");\n");
1210 fprintf(out, " jmethodID jget_value_method = env->GetMethodID(jmap_class, \"valueAt\", \"(I)Ljava/lang/Object;\");\n\n");
1211
1212
1213 fprintf(out, " std::vector<std::unique_ptr<ScopedUtfChars>> scoped_ufs;\n\n");
1214
Howard Ro4078dd42018-09-27 17:41:08 -07001215 fprintf(out, " jclass jint_class = env->FindClass(\"java/lang/Integer\");\n");
Yangster-mace124e422018-08-16 10:30:28 -07001216 fprintf(out, " jclass jlong_class = env->FindClass(\"java/lang/Long\");\n");
1217 fprintf(out, " jclass jfloat_class = env->FindClass(\"java/lang/Float\");\n");
1218 fprintf(out, " jclass jstring_class = env->FindClass(\"java/lang/String\");\n");
Howard Ro4078dd42018-09-27 17:41:08 -07001219 fprintf(out, " jmethodID jget_int_method = env->GetMethodID(jint_class, \"intValue\", \"()I\");\n");
Yangster-mace124e422018-08-16 10:30:28 -07001220 fprintf(out, " jmethodID jget_long_method = env->GetMethodID(jlong_class, \"longValue\", \"()J\");\n");
1221 fprintf(out, " jmethodID jget_float_method = env->GetMethodID(jfloat_class, \"floatValue\", \"()F\");\n\n");
1222
1223 fprintf(out, " jint jsize = env->CallIntMethod(value_map, jget_size_method);\n");
1224 fprintf(out, " for(int i = 0; i < jsize; i++) {\n");
1225 fprintf(out, " jint key = env->CallIntMethod(value_map, jget_key_method, i);\n");
1226 fprintf(out, " jobject jvalue_obj = env->CallObjectMethod(value_map, jget_value_method, i);\n");
1227 fprintf(out, " if (jvalue_obj == NULL) { continue; }\n");
Howard Ro4078dd42018-09-27 17:41:08 -07001228 fprintf(out, " if (env->IsInstanceOf(jvalue_obj, jint_class)) {\n");
1229 fprintf(out, " int32_t_map[key] = env->CallIntMethod(jvalue_obj, jget_int_method);\n");
1230 fprintf(out, " } else if (env->IsInstanceOf(jvalue_obj, jlong_class)) {\n");
Yangster-mace124e422018-08-16 10:30:28 -07001231 fprintf(out, " int64_t_map[key] = env->CallLongMethod(jvalue_obj, jget_long_method);\n");
1232 fprintf(out, " } else if (env->IsInstanceOf(jvalue_obj, jfloat_class)) {\n");
1233 fprintf(out, " float_map[key] = env->CallFloatMethod(jvalue_obj, jget_float_method);\n");
1234 fprintf(out, " } else if (env->IsInstanceOf(jvalue_obj, jstring_class)) {\n");
1235 fprintf(out, " std::unique_ptr<ScopedUtfChars> utf(new ScopedUtfChars(env, (jstring)jvalue_obj));\n");
1236 fprintf(out, " if (utf->c_str() != NULL) { string_map[key] = utf->c_str(); }\n");
1237 fprintf(out, " scoped_ufs.push_back(std::move(utf));\n");
1238 fprintf(out, " }\n");
1239 fprintf(out, " }\n");
1240}
1241
Yao Chend54f9dd2017-10-17 17:37:48 +00001242static int
Yangster-macba5b9e42018-01-10 21:31:59 -08001243write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp_method_name,
Tej Singh810eeb32019-03-07 19:08:52 -08001244 const map<vector<java_type_t>, set<string>>& signatures_to_modules,
1245 const AtomDecl &attributionDecl) {
Yao Chend54f9dd2017-10-17 17:37:48 +00001246 // Print write methods
Tej Singh810eeb32019-03-07 19:08:52 -08001247 for (auto signature_to_modules_it = signatures_to_modules.begin();
1248 signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
1249 vector<java_type_t> signature = signature_to_modules_it->first;
Yao Chend54f9dd2017-10-17 17:37:48 +00001250 int argIndex;
1251
Yao Chen97e21ec2018-03-29 11:00:38 -07001252 fprintf(out, "static int\n");
Yao Chend54f9dd2017-10-17 17:37:48 +00001253 fprintf(out, "%s(JNIEnv* env, jobject clazz UNUSED, jint code",
Tej Singh810eeb32019-03-07 19:08:52 -08001254 jni_function_name(java_method_name, signature).c_str());
Yao Chend54f9dd2017-10-17 17:37:48 +00001255 argIndex = 1;
Tej Singh810eeb32019-03-07 19:08:52 -08001256 for (vector<java_type_t>::const_iterator arg = signature.begin();
1257 arg != signature.end(); arg++) {
Yangster-mac7604aea2017-12-11 22:55:49 -08001258 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
1259 for (auto chainField : attributionDecl.fields) {
1260 fprintf(out, ", %s %s", jni_array_type_name(chainField.javaType),
1261 chainField.name.c_str());
1262 }
Yangster-mace124e422018-08-16 10:30:28 -07001263 } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
1264 fprintf(out, ", jobject value_map");
Yangster-mac7604aea2017-12-11 22:55:49 -08001265 } else {
1266 fprintf(out, ", %s arg%d", jni_type_name(*arg), argIndex);
1267 }
Yao Chend54f9dd2017-10-17 17:37:48 +00001268 argIndex++;
1269 }
1270 fprintf(out, ")\n");
1271
1272 fprintf(out, "{\n");
1273
1274 // Prepare strings
1275 argIndex = 1;
Yangster-mac7604aea2017-12-11 22:55:49 -08001276 bool hadStringOrChain = false;
Yangster-mace124e422018-08-16 10:30:28 -07001277 bool isKeyValuePairAtom = false;
Tej Singh810eeb32019-03-07 19:08:52 -08001278 for (vector<java_type_t>::const_iterator arg = signature.begin();
1279 arg != signature.end(); arg++) {
Yao Chend54f9dd2017-10-17 17:37:48 +00001280 if (*arg == JAVA_TYPE_STRING) {
Yangster-mac7604aea2017-12-11 22:55:49 -08001281 hadStringOrChain = true;
Yao Chend54f9dd2017-10-17 17:37:48 +00001282 fprintf(out, " const char* str%d;\n", argIndex);
1283 fprintf(out, " if (arg%d != NULL) {\n", argIndex);
1284 fprintf(out, " str%d = env->GetStringUTFChars(arg%d, NULL);\n",
1285 argIndex, argIndex);
1286 fprintf(out, " } else {\n");
1287 fprintf(out, " str%d = NULL;\n", argIndex);
1288 fprintf(out, " }\n");
Yao Chenbbdd67d2018-10-24 12:15:56 -07001289 } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
1290 hadStringOrChain = true;
1291 fprintf(out, " jbyte* jbyte_array%d;\n", argIndex);
1292 fprintf(out, " const char* str%d;\n", argIndex);
Yao Chen1fe9f592018-12-06 10:34:25 -08001293 fprintf(out, " int str%d_length = 0;\n", argIndex);
Yao Chen8e6f9982018-11-29 09:39:45 -08001294 fprintf(out,
1295 " if (arg%d != NULL && env->GetArrayLength(arg%d) > "
1296 "0) {\n",
1297 argIndex, argIndex);
Yao Chenbbdd67d2018-10-24 12:15:56 -07001298 fprintf(out,
1299 " jbyte_array%d = "
1300 "env->GetByteArrayElements(arg%d, NULL);\n",
1301 argIndex, argIndex);
1302 fprintf(out,
Yao Chen1fe9f592018-12-06 10:34:25 -08001303 " str%d_length = env->GetArrayLength(arg%d);\n",
1304 argIndex, argIndex);
1305 fprintf(out,
Yao Chenbbdd67d2018-10-24 12:15:56 -07001306 " str%d = "
1307 "reinterpret_cast<char*>(env->GetByteArrayElements(arg%"
1308 "d, NULL));\n",
1309 argIndex, argIndex);
1310 fprintf(out, " } else {\n");
1311 fprintf(out, " jbyte_array%d = NULL;\n", argIndex);
1312 fprintf(out, " str%d = NULL;\n", argIndex);
1313 fprintf(out, " }\n");
1314
Yao Chene89572c2019-01-09 15:41:50 -08001315 fprintf(out,
1316 " android::util::BytesField bytesField%d(str%d, "
1317 "str%d_length);",
1318 argIndex, argIndex, argIndex);
1319
Yangster-mac7604aea2017-12-11 22:55:49 -08001320 } else if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
1321 hadStringOrChain = true;
1322 for (auto chainField : attributionDecl.fields) {
1323 fprintf(out, " size_t %s_length = env->GetArrayLength(%s);\n",
1324 chainField.name.c_str(), chainField.name.c_str());
1325 if (chainField.name != attributionDecl.fields.front().name) {
1326 fprintf(out, " if (%s_length != %s_length) {\n",
1327 chainField.name.c_str(),
1328 attributionDecl.fields.front().name.c_str());
Yao Chen97e21ec2018-03-29 11:00:38 -07001329 fprintf(out, " return -EINVAL;\n");
Yangster-mac7604aea2017-12-11 22:55:49 -08001330 fprintf(out, " }\n");
1331 }
1332 if (chainField.javaType == JAVA_TYPE_INT) {
1333 fprintf(out, " jint* %s_array = env->GetIntArrayElements(%s, NULL);\n",
1334 chainField.name.c_str(), chainField.name.c_str());
1335 } else if (chainField.javaType == JAVA_TYPE_STRING) {
1336 fprintf(out, " std::vector<%s> %s_vec;\n",
1337 cpp_type_name(chainField.javaType), chainField.name.c_str());
1338 fprintf(out, " std::vector<ScopedUtfChars*> scoped_%s_vec;\n",
1339 chainField.name.c_str());
1340 fprintf(out, " for (size_t i = 0; i < %s_length; ++i) {\n",
1341 chainField.name.c_str());
1342 fprintf(out, " jstring jstr = "
1343 "(jstring)env->GetObjectArrayElement(%s, i);\n",
1344 chainField.name.c_str());
Yangster-mac20ac9442018-01-08 14:54:48 -08001345 fprintf(out, " if (jstr == NULL) {\n");
1346 fprintf(out, " %s_vec.push_back(NULL);\n",
1347 chainField.name.c_str());
1348 fprintf(out, " } else {\n");
1349 fprintf(out, " ScopedUtfChars* scoped_%s = "
Yangster-mac7604aea2017-12-11 22:55:49 -08001350 "new ScopedUtfChars(env, jstr);\n",
1351 chainField.name.c_str());
Yangster-mac20ac9442018-01-08 14:54:48 -08001352 fprintf(out, " %s_vec.push_back(scoped_%s->c_str());\n",
Yangster-mac7604aea2017-12-11 22:55:49 -08001353 chainField.name.c_str(), chainField.name.c_str());
Yangster-mac20ac9442018-01-08 14:54:48 -08001354 fprintf(out, " scoped_%s_vec.push_back(scoped_%s);\n",
Yangster-mac7604aea2017-12-11 22:55:49 -08001355 chainField.name.c_str(), chainField.name.c_str());
Yangster-mac20ac9442018-01-08 14:54:48 -08001356 fprintf(out, " }\n");
Yangster-mac7604aea2017-12-11 22:55:49 -08001357 fprintf(out, " }\n");
1358 }
1359 fprintf(out, "\n");
1360 }
Yangster-mace124e422018-08-16 10:30:28 -07001361 } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
1362 isKeyValuePairAtom = true;
Yao Chend54f9dd2017-10-17 17:37:48 +00001363 }
1364 argIndex++;
1365 }
Yangster-mac7604aea2017-12-11 22:55:49 -08001366 // Emit this to quiet the unused parameter warning if there were no strings or attribution
1367 // chains.
Yangster-mace124e422018-08-16 10:30:28 -07001368 if (!hadStringOrChain && !isKeyValuePairAtom) {
Yao Chend54f9dd2017-10-17 17:37:48 +00001369 fprintf(out, " (void)env;\n");
1370 }
Yangster-mace124e422018-08-16 10:30:28 -07001371 if (isKeyValuePairAtom) {
1372 write_key_value_map_jni(out);
1373 }
Yao Chend54f9dd2017-10-17 17:37:48 +00001374
1375 // stats_write call
1376 argIndex = 1;
Yao Chene89572c2019-01-09 15:41:50 -08001377 fprintf(out, "\n int ret = android::util::%s(code",
1378 cpp_method_name.c_str());
Tej Singh810eeb32019-03-07 19:08:52 -08001379 for (vector<java_type_t>::const_iterator arg = signature.begin();
1380 arg != signature.end(); arg++) {
Yangster-mac7604aea2017-12-11 22:55:49 -08001381 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
1382 for (auto chainField : attributionDecl.fields) {
1383 if (chainField.javaType == JAVA_TYPE_INT) {
1384 fprintf(out, ", (const %s*)%s_array, %s_length",
1385 cpp_type_name(chainField.javaType),
1386 chainField.name.c_str(), chainField.name.c_str());
1387 } else if (chainField.javaType == JAVA_TYPE_STRING) {
1388 fprintf(out, ", %s_vec", chainField.name.c_str());
1389 }
1390 }
Yangster-mace124e422018-08-16 10:30:28 -07001391 } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
Howard Ro4078dd42018-09-27 17:41:08 -07001392 fprintf(out, ", int32_t_map, int64_t_map, string_map, float_map");
Yao Chene89572c2019-01-09 15:41:50 -08001393 } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
1394 fprintf(out, ", bytesField%d", argIndex);
Yangster-mac7604aea2017-12-11 22:55:49 -08001395 } else {
Yao Chene89572c2019-01-09 15:41:50 -08001396 const char* argName =
1397 (*arg == JAVA_TYPE_STRING) ? "str" : "arg";
Yangster-mac7604aea2017-12-11 22:55:49 -08001398 fprintf(out, ", (%s)%s%d", cpp_type_name(*arg), argName, argIndex);
1399 }
Yao Chend54f9dd2017-10-17 17:37:48 +00001400 argIndex++;
1401 }
1402 fprintf(out, ");\n");
Yangster-mac7604aea2017-12-11 22:55:49 -08001403 fprintf(out, "\n");
Yao Chend54f9dd2017-10-17 17:37:48 +00001404
1405 // Clean up strings
1406 argIndex = 1;
Tej Singh810eeb32019-03-07 19:08:52 -08001407 for (vector<java_type_t>::const_iterator arg = signature.begin();
1408 arg != signature.end(); arg++) {
Yao Chend54f9dd2017-10-17 17:37:48 +00001409 if (*arg == JAVA_TYPE_STRING) {
1410 fprintf(out, " if (str%d != NULL) {\n", argIndex);
1411 fprintf(out, " env->ReleaseStringUTFChars(arg%d, str%d);\n",
1412 argIndex, argIndex);
1413 fprintf(out, " }\n");
Yao Chenbbdd67d2018-10-24 12:15:56 -07001414 } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
1415 fprintf(out, " if (str%d != NULL) { \n", argIndex);
1416 fprintf(out,
1417 " env->ReleaseByteArrayElements(arg%d, "
1418 "jbyte_array%d, 0);\n",
1419 argIndex, argIndex);
1420 fprintf(out, " }\n");
Yangster-mac7604aea2017-12-11 22:55:49 -08001421 } else if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
1422 for (auto chainField : attributionDecl.fields) {
1423 if (chainField.javaType == JAVA_TYPE_INT) {
1424 fprintf(out, " env->ReleaseIntArrayElements(%s, %s_array, 0);\n",
1425 chainField.name.c_str(), chainField.name.c_str());
1426 } else if (chainField.javaType == JAVA_TYPE_STRING) {
Yangster-mac20ac9442018-01-08 14:54:48 -08001427 fprintf(out, " for (size_t i = 0; i < scoped_%s_vec.size(); ++i) {\n",
Yangster-mac7604aea2017-12-11 22:55:49 -08001428 chainField.name.c_str());
1429 fprintf(out, " delete scoped_%s_vec[i];\n", chainField.name.c_str());
1430 fprintf(out, " }\n");
1431 }
1432 }
Yao Chend54f9dd2017-10-17 17:37:48 +00001433 }
1434 argIndex++;
1435 }
Yangster-mace124e422018-08-16 10:30:28 -07001436
Yao Chen97e21ec2018-03-29 11:00:38 -07001437 fprintf(out, " return ret;\n");
Yao Chend54f9dd2017-10-17 17:37:48 +00001438
1439 fprintf(out, "}\n");
1440 fprintf(out, "\n");
1441 }
1442
Yangster-macba5b9e42018-01-10 21:31:59 -08001443
1444 return 0;
1445}
1446
1447void write_jni_registration(FILE* out, const string& java_method_name,
Tej Singh810eeb32019-03-07 19:08:52 -08001448 const map<vector<java_type_t>, set<string>>& signatures_to_modules,
1449 const AtomDecl &attributionDecl) {
1450 for (auto signature_to_modules_it = signatures_to_modules.begin();
1451 signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
1452 vector<java_type_t> signature = signature_to_modules_it->first;
Yangster-macba5b9e42018-01-10 21:31:59 -08001453 fprintf(out, " { \"%s\", \"%s\", (void*)%s },\n",
1454 java_method_name.c_str(),
Tej Singh810eeb32019-03-07 19:08:52 -08001455 jni_function_signature(signature, attributionDecl).c_str(),
1456 jni_function_name(java_method_name, signature).c_str());
Yangster-macba5b9e42018-01-10 21:31:59 -08001457 }
1458}
1459
1460static int
1461write_stats_log_jni(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl)
1462{
1463 // Print prelude
1464 fprintf(out, "// This file is autogenerated\n");
1465 fprintf(out, "\n");
1466
1467 fprintf(out, "#include <statslog.h>\n");
1468 fprintf(out, "\n");
1469 fprintf(out, "#include <nativehelper/JNIHelp.h>\n");
1470 fprintf(out, "#include <nativehelper/ScopedUtfChars.h>\n");
1471 fprintf(out, "#include <utils/Vector.h>\n");
1472 fprintf(out, "#include \"core_jni_helpers.h\"\n");
1473 fprintf(out, "#include \"jni.h\"\n");
1474 fprintf(out, "\n");
1475 fprintf(out, "#define UNUSED __attribute__((__unused__))\n");
1476 fprintf(out, "\n");
1477
1478 fprintf(out, "namespace android {\n");
1479 fprintf(out, "\n");
1480
Tej Singh810eeb32019-03-07 19:08:52 -08001481 write_stats_log_jni(out, "write", "stats_write", atoms.signatures_to_modules, attributionDecl);
Yangster-macba5b9e42018-01-10 21:31:59 -08001482 write_stats_log_jni(out, "write_non_chained", "stats_write_non_chained",
Tej Singh810eeb32019-03-07 19:08:52 -08001483 atoms.non_chained_signatures_to_modules, attributionDecl);
Yangster-macba5b9e42018-01-10 21:31:59 -08001484
Yao Chend54f9dd2017-10-17 17:37:48 +00001485 // Print registration function table
1486 fprintf(out, "/*\n");
1487 fprintf(out, " * JNI registration.\n");
1488 fprintf(out, " */\n");
1489 fprintf(out, "static const JNINativeMethod gRegisterMethods[] = {\n");
Tej Singh810eeb32019-03-07 19:08:52 -08001490 write_jni_registration(out, "write", atoms.signatures_to_modules, attributionDecl);
1491 write_jni_registration(out, "write_non_chained", atoms.non_chained_signatures_to_modules,
1492 attributionDecl);
Yao Chend54f9dd2017-10-17 17:37:48 +00001493 fprintf(out, "};\n");
1494 fprintf(out, "\n");
1495
1496 // Print registration function
Tej Singhbe0482b2019-03-19 22:01:57 -07001497 fprintf(out, "int register_android_util_StatsLogInternal(JNIEnv* env) {\n");
Yao Chend54f9dd2017-10-17 17:37:48 +00001498 fprintf(out, " return RegisterMethodsOrDie(\n");
1499 fprintf(out, " env,\n");
Tej Singhbe0482b2019-03-19 22:01:57 -07001500 fprintf(out, " \"android/util/StatsLogInternal\",\n");
Yao Chend54f9dd2017-10-17 17:37:48 +00001501 fprintf(out, " gRegisterMethods, NELEM(gRegisterMethods));\n");
1502 fprintf(out, "}\n");
1503
1504 fprintf(out, "\n");
1505 fprintf(out, "} // namespace android\n");
Yao Chend54f9dd2017-10-17 17:37:48 +00001506 return 0;
1507}
1508
Yao Chend54f9dd2017-10-17 17:37:48 +00001509static void
1510print_usage()
1511{
1512 fprintf(stderr, "usage: stats-log-api-gen OPTIONS\n");
1513 fprintf(stderr, "\n");
1514 fprintf(stderr, "OPTIONS\n");
1515 fprintf(stderr, " --cpp FILENAME the header file to output\n");
1516 fprintf(stderr, " --header FILENAME the cpp file to output\n");
1517 fprintf(stderr, " --help this message\n");
1518 fprintf(stderr, " --java FILENAME the java file to output\n");
1519 fprintf(stderr, " --jni FILENAME the jni file to output\n");
Tej Singh810eeb32019-03-07 19:08:52 -08001520 fprintf(stderr, " --module NAME optional, module name to generate outputs for\n");
1521 fprintf(stderr, " --namespace COMMA,SEP,NAMESPACE required for cpp/header with module\n");
1522 fprintf(stderr, " comma separated namespace of the files\n");
1523 fprintf(stderr, " --importHeader NAME required for cpp/jni to say which header to import\n");
Yao Chend54f9dd2017-10-17 17:37:48 +00001524}
1525
1526/**
1527 * Do the argument parsing and execute the tasks.
1528 */
1529static int
1530run(int argc, char const*const* argv)
1531{
1532 string cppFilename;
1533 string headerFilename;
1534 string javaFilename;
1535 string jniFilename;
1536
Tej Singh810eeb32019-03-07 19:08:52 -08001537 string moduleName = DEFAULT_MODULE_NAME;
1538 string cppNamespace = DEFAULT_CPP_NAMESPACE;
1539 string cppHeaderImport = DEFAULT_CPP_HEADER_IMPORT;
1540
Yao Chend54f9dd2017-10-17 17:37:48 +00001541 int index = 1;
1542 while (index < argc) {
1543 if (0 == strcmp("--help", argv[index])) {
1544 print_usage();
1545 return 0;
1546 } else if (0 == strcmp("--cpp", argv[index])) {
1547 index++;
1548 if (index >= argc) {
1549 print_usage();
1550 return 1;
1551 }
1552 cppFilename = argv[index];
1553 } else if (0 == strcmp("--header", argv[index])) {
1554 index++;
1555 if (index >= argc) {
1556 print_usage();
1557 return 1;
1558 }
1559 headerFilename = argv[index];
1560 } else if (0 == strcmp("--java", argv[index])) {
1561 index++;
1562 if (index >= argc) {
1563 print_usage();
1564 return 1;
1565 }
1566 javaFilename = argv[index];
1567 } else if (0 == strcmp("--jni", argv[index])) {
1568 index++;
1569 if (index >= argc) {
1570 print_usage();
1571 return 1;
1572 }
1573 jniFilename = argv[index];
Tej Singh810eeb32019-03-07 19:08:52 -08001574 } else if (0 == strcmp("--module", argv[index])) {
1575 index++;
1576 if (index >= argc) {
1577 print_usage();
1578 return 1;
1579 }
1580 moduleName = argv[index];
1581 } else if (0 == strcmp("--namespace", argv[index])) {
1582 index++;
1583 if (index >= argc) {
1584 print_usage();
1585 return 1;
1586 }
1587 cppNamespace = argv[index];
1588 } else if (0 == strcmp("--importHeader", argv[index])) {
1589 index++;
1590 if (index >= argc) {
1591 print_usage();
1592 return 1;
1593 }
1594 cppHeaderImport = argv[index];
Yao Chend54f9dd2017-10-17 17:37:48 +00001595 }
1596 index++;
1597 }
1598
1599 if (cppFilename.size() == 0
1600 && headerFilename.size() == 0
1601 && javaFilename.size() == 0
1602 && jniFilename.size() == 0) {
1603 print_usage();
1604 return 1;
1605 }
1606
1607 // Collate the parameters
1608 Atoms atoms;
Stefan Lafonae2df012017-11-14 09:17:21 -08001609 int errorCount = collate_atoms(Atom::descriptor(), &atoms);
Yao Chend54f9dd2017-10-17 17:37:48 +00001610 if (errorCount != 0) {
1611 return 1;
1612 }
1613
Yangster-mac7604aea2017-12-11 22:55:49 -08001614 AtomDecl attributionDecl;
1615 vector<java_type_t> attributionSignature;
Yangster-mac20877162017-12-22 17:19:39 -08001616 collate_atom(android::os::statsd::AttributionNode::descriptor(),
Yangster-mac7604aea2017-12-11 22:55:49 -08001617 &attributionDecl, &attributionSignature);
1618
Yao Chend54f9dd2017-10-17 17:37:48 +00001619 // Write the .cpp file
1620 if (cppFilename.size() != 0) {
1621 FILE* out = fopen(cppFilename.c_str(), "w");
1622 if (out == NULL) {
1623 fprintf(stderr, "Unable to open file for write: %s\n", cppFilename.c_str());
1624 return 1;
1625 }
Tej Singh810eeb32019-03-07 19:08:52 -08001626 // If this is for a specific module, the namespace must also be provided.
1627 if (moduleName != DEFAULT_MODULE_NAME && cppNamespace == DEFAULT_CPP_NAMESPACE) {
1628 fprintf(stderr, "Must supply --namespace if supplying a specific module\n");
1629 return 1;
1630 }
1631 // If this is for a specific module, the header file to import must also be provided.
1632 if (moduleName != DEFAULT_MODULE_NAME && cppHeaderImport == DEFAULT_CPP_HEADER_IMPORT) {
1633 fprintf(stderr, "Must supply --headerImport if supplying a specific module\n");
1634 return 1;
1635 }
Yangster-mac7604aea2017-12-11 22:55:49 -08001636 errorCount = android::stats_log_api_gen::write_stats_log_cpp(
Tej Singh810eeb32019-03-07 19:08:52 -08001637 out, atoms, attributionDecl, moduleName, cppNamespace, cppHeaderImport);
Yao Chend54f9dd2017-10-17 17:37:48 +00001638 fclose(out);
1639 }
1640
1641 // Write the .h file
1642 if (headerFilename.size() != 0) {
1643 FILE* out = fopen(headerFilename.c_str(), "w");
1644 if (out == NULL) {
1645 fprintf(stderr, "Unable to open file for write: %s\n", headerFilename.c_str());
1646 return 1;
1647 }
Tej Singh810eeb32019-03-07 19:08:52 -08001648 // If this is for a specific module, the namespace must also be provided.
1649 if (moduleName != DEFAULT_MODULE_NAME && cppNamespace == DEFAULT_CPP_NAMESPACE) {
1650 fprintf(stderr, "Must supply --namespace if supplying a specific module\n");
1651 }
Yangster-mac7604aea2017-12-11 22:55:49 -08001652 errorCount = android::stats_log_api_gen::write_stats_log_header(
Tej Singh810eeb32019-03-07 19:08:52 -08001653 out, atoms, attributionDecl, moduleName, cppNamespace);
Yao Chend54f9dd2017-10-17 17:37:48 +00001654 fclose(out);
1655 }
1656
1657 // Write the .java file
1658 if (javaFilename.size() != 0) {
1659 FILE* out = fopen(javaFilename.c_str(), "w");
1660 if (out == NULL) {
1661 fprintf(stderr, "Unable to open file for write: %s\n", javaFilename.c_str());
1662 return 1;
1663 }
Yangster-mac7604aea2017-12-11 22:55:49 -08001664 errorCount = android::stats_log_api_gen::write_stats_log_java(
1665 out, atoms, attributionDecl);
Yao Chend54f9dd2017-10-17 17:37:48 +00001666 fclose(out);
1667 }
1668
1669 // Write the jni file
1670 if (jniFilename.size() != 0) {
1671 FILE* out = fopen(jniFilename.c_str(), "w");
1672 if (out == NULL) {
1673 fprintf(stderr, "Unable to open file for write: %s\n", jniFilename.c_str());
1674 return 1;
1675 }
Yangster-mac7604aea2017-12-11 22:55:49 -08001676 errorCount = android::stats_log_api_gen::write_stats_log_jni(
1677 out, atoms, attributionDecl);
Yao Chend54f9dd2017-10-17 17:37:48 +00001678 fclose(out);
1679 }
1680
1681 return 0;
1682}
1683
1684}
1685}
1686
1687/**
1688 * Main.
1689 */
1690int
1691main(int argc, char const*const* argv)
1692{
1693 GOOGLE_PROTOBUF_VERIFY_VERSION;
1694
1695 return android::stats_log_api_gen::run(argc, argv);
Yao Chencf3829a2018-06-05 14:20:35 -07001696}