1
2
3 #include "Collation.h"
4 #include "atoms_info_writer.h"
5 #if !defined(STATS_SCHEMA_LEGACY)
6 #include "java_writer.h"
7 #endif
8 #include "java_writer_q.h"
9 #include "native_writer.h"
10 #include "utils.h"
11
12 #include "frameworks/base/cmds/statsd/src/atoms.pb.h"
13
14 #include <map>
15 #include <set>
16 #include <vector>
17
18 #include <getopt.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22
23 using namespace google::protobuf;
24 using namespace std;
25
26 namespace android {
27 namespace stats_log_api_gen {
28
29 using android::os::statsd::Atom;
30
31 // Hide the JNI write helpers that are not used in the new schema.
32 // TODO(b/145100015): Remove this and other JNI related functionality once StatsEvent migration is
33 // complete.
34 #if defined(STATS_SCHEMA_LEGACY)
35 // JNI helpers.
36 static const char*
jni_type_name(java_type_t type)37 jni_type_name(java_type_t type)
38 {
39 switch (type) {
40 case JAVA_TYPE_BOOLEAN:
41 return "jboolean";
42 case JAVA_TYPE_INT:
43 case JAVA_TYPE_ENUM:
44 return "jint";
45 case JAVA_TYPE_LONG:
46 return "jlong";
47 case JAVA_TYPE_FLOAT:
48 return "jfloat";
49 case JAVA_TYPE_DOUBLE:
50 return "jdouble";
51 case JAVA_TYPE_STRING:
52 return "jstring";
53 case JAVA_TYPE_BYTE_ARRAY:
54 return "jbyteArray";
55 default:
56 return "UNKNOWN";
57 }
58 }
59
60 static const char*
jni_array_type_name(java_type_t type)61 jni_array_type_name(java_type_t type)
62 {
63 switch (type) {
64 case JAVA_TYPE_INT:
65 return "jintArray";
66 case JAVA_TYPE_FLOAT:
67 return "jfloatArray";
68 case JAVA_TYPE_STRING:
69 return "jobjectArray";
70 default:
71 return "UNKNOWN";
72 }
73 }
74
75 static string
jni_function_name(const string & method_name,const vector<java_type_t> & signature)76 jni_function_name(const string& method_name, const vector<java_type_t>& signature)
77 {
78 string result("StatsLog_" + method_name);
79 for (vector<java_type_t>::const_iterator arg = signature.begin();
80 arg != signature.end(); arg++) {
81 switch (*arg) {
82 case JAVA_TYPE_BOOLEAN:
83 result += "_boolean";
84 break;
85 case JAVA_TYPE_INT:
86 case JAVA_TYPE_ENUM:
87 result += "_int";
88 break;
89 case JAVA_TYPE_LONG:
90 result += "_long";
91 break;
92 case JAVA_TYPE_FLOAT:
93 result += "_float";
94 break;
95 case JAVA_TYPE_DOUBLE:
96 result += "_double";
97 break;
98 case JAVA_TYPE_STRING:
99 result += "_String";
100 break;
101 case JAVA_TYPE_ATTRIBUTION_CHAIN:
102 result += "_AttributionChain";
103 break;
104 case JAVA_TYPE_KEY_VALUE_PAIR:
105 result += "_KeyValuePairs";
106 break;
107 case JAVA_TYPE_BYTE_ARRAY:
108 result += "_bytes";
109 break;
110 default:
111 result += "_UNKNOWN";
112 break;
113 }
114 }
115 return result;
116 }
117
118 static const char*
java_type_signature(java_type_t type)119 java_type_signature(java_type_t type)
120 {
121 switch (type) {
122 case JAVA_TYPE_BOOLEAN:
123 return "Z";
124 case JAVA_TYPE_INT:
125 case JAVA_TYPE_ENUM:
126 return "I";
127 case JAVA_TYPE_LONG:
128 return "J";
129 case JAVA_TYPE_FLOAT:
130 return "F";
131 case JAVA_TYPE_DOUBLE:
132 return "D";
133 case JAVA_TYPE_STRING:
134 return "Ljava/lang/String;";
135 case JAVA_TYPE_BYTE_ARRAY:
136 return "[B";
137 default:
138 return "UNKNOWN";
139 }
140 }
141
142 static string
jni_function_signature(const vector<java_type_t> & signature,const AtomDecl & attributionDecl)143 jni_function_signature(const vector<java_type_t>& signature, const AtomDecl &attributionDecl)
144 {
145 string result("(I");
146 for (vector<java_type_t>::const_iterator arg = signature.begin();
147 arg != signature.end(); arg++) {
148 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
149 for (auto chainField : attributionDecl.fields) {
150 result += "[";
151 result += java_type_signature(chainField.javaType);
152 }
153 } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
154 result += "Landroid/util/SparseArray;";
155 } else {
156 result += java_type_signature(*arg);
157 }
158 }
159 result += ")I";
160 return result;
161 }
162
write_key_value_map_jni(FILE * out)163 static void write_key_value_map_jni(FILE* out) {
164 fprintf(out, " std::map<int, int32_t> int32_t_map;\n");
165 fprintf(out, " std::map<int, int64_t> int64_t_map;\n");
166 fprintf(out, " std::map<int, float> float_map;\n");
167 fprintf(out, " std::map<int, char const*> string_map;\n\n");
168
169 fprintf(out, " jclass jmap_class = env->FindClass(\"android/util/SparseArray\");\n");
170
171 fprintf(out, " jmethodID jget_size_method = env->GetMethodID(jmap_class, \"size\", \"()I\");\n");
172 fprintf(out, " jmethodID jget_key_method = env->GetMethodID(jmap_class, \"keyAt\", \"(I)I\");\n");
173 fprintf(out, " jmethodID jget_value_method = env->GetMethodID(jmap_class, \"valueAt\", \"(I)Ljava/lang/Object;\");\n\n");
174
175
176 fprintf(out, " std::vector<std::unique_ptr<ScopedUtfChars>> scoped_ufs;\n\n");
177
178 fprintf(out, " jclass jint_class = env->FindClass(\"java/lang/Integer\");\n");
179 fprintf(out, " jclass jlong_class = env->FindClass(\"java/lang/Long\");\n");
180 fprintf(out, " jclass jfloat_class = env->FindClass(\"java/lang/Float\");\n");
181 fprintf(out, " jclass jstring_class = env->FindClass(\"java/lang/String\");\n");
182 fprintf(out, " jmethodID jget_int_method = env->GetMethodID(jint_class, \"intValue\", \"()I\");\n");
183 fprintf(out, " jmethodID jget_long_method = env->GetMethodID(jlong_class, \"longValue\", \"()J\");\n");
184 fprintf(out, " jmethodID jget_float_method = env->GetMethodID(jfloat_class, \"floatValue\", \"()F\");\n\n");
185
186 fprintf(out, " jint jsize = env->CallIntMethod(value_map, jget_size_method);\n");
187 fprintf(out, " for(int i = 0; i < jsize; i++) {\n");
188 fprintf(out, " jint key = env->CallIntMethod(value_map, jget_key_method, i);\n");
189 fprintf(out, " jobject jvalue_obj = env->CallObjectMethod(value_map, jget_value_method, i);\n");
190 fprintf(out, " if (jvalue_obj == NULL) { continue; }\n");
191 fprintf(out, " if (env->IsInstanceOf(jvalue_obj, jint_class)) {\n");
192 fprintf(out, " int32_t_map[key] = env->CallIntMethod(jvalue_obj, jget_int_method);\n");
193 fprintf(out, " } else if (env->IsInstanceOf(jvalue_obj, jlong_class)) {\n");
194 fprintf(out, " int64_t_map[key] = env->CallLongMethod(jvalue_obj, jget_long_method);\n");
195 fprintf(out, " } else if (env->IsInstanceOf(jvalue_obj, jfloat_class)) {\n");
196 fprintf(out, " float_map[key] = env->CallFloatMethod(jvalue_obj, jget_float_method);\n");
197 fprintf(out, " } else if (env->IsInstanceOf(jvalue_obj, jstring_class)) {\n");
198 fprintf(out, " std::unique_ptr<ScopedUtfChars> utf(new ScopedUtfChars(env, (jstring)jvalue_obj));\n");
199 fprintf(out, " if (utf->c_str() != NULL) { string_map[key] = utf->c_str(); }\n");
200 fprintf(out, " scoped_ufs.push_back(std::move(utf));\n");
201 fprintf(out, " }\n");
202 fprintf(out, " }\n");
203 }
204
205 static int
write_stats_log_jni_method(FILE * out,const string & java_method_name,const string & cpp_method_name,const map<vector<java_type_t>,set<string>> & signatures_to_modules,const AtomDecl & attributionDecl)206 write_stats_log_jni_method(FILE* out, const string& java_method_name, const string& cpp_method_name,
207 const map<vector<java_type_t>, set<string>>& signatures_to_modules,
208 const AtomDecl &attributionDecl) {
209 // Print write methods
210 for (auto signature_to_modules_it = signatures_to_modules.begin();
211 signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
212 vector<java_type_t> signature = signature_to_modules_it->first;
213 int argIndex;
214
215 fprintf(out, "static int\n");
216 fprintf(out, "%s(JNIEnv* env, jobject clazz UNUSED, jint code",
217 jni_function_name(java_method_name, signature).c_str());
218 argIndex = 1;
219 for (vector<java_type_t>::const_iterator arg = signature.begin();
220 arg != signature.end(); arg++) {
221 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
222 for (auto chainField : attributionDecl.fields) {
223 fprintf(out, ", %s %s", jni_array_type_name(chainField.javaType),
224 chainField.name.c_str());
225 }
226 } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
227 fprintf(out, ", jobject value_map");
228 } else {
229 fprintf(out, ", %s arg%d", jni_type_name(*arg), argIndex);
230 }
231 argIndex++;
232 }
233 fprintf(out, ")\n");
234
235 fprintf(out, "{\n");
236
237 // Prepare strings
238 argIndex = 1;
239 bool hadStringOrChain = false;
240 bool isKeyValuePairAtom = false;
241 for (vector<java_type_t>::const_iterator arg = signature.begin();
242 arg != signature.end(); arg++) {
243 if (*arg == JAVA_TYPE_STRING) {
244 hadStringOrChain = true;
245 fprintf(out, " const char* str%d;\n", argIndex);
246 fprintf(out, " if (arg%d != NULL) {\n", argIndex);
247 fprintf(out, " str%d = env->GetStringUTFChars(arg%d, NULL);\n",
248 argIndex, argIndex);
249 fprintf(out, " } else {\n");
250 fprintf(out, " str%d = NULL;\n", argIndex);
251 fprintf(out, " }\n");
252 } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
253 hadStringOrChain = true;
254 fprintf(out, " jbyte* jbyte_array%d;\n", argIndex);
255 fprintf(out, " const char* str%d;\n", argIndex);
256 fprintf(out, " int str%d_length = 0;\n", argIndex);
257 fprintf(out,
258 " if (arg%d != NULL && env->GetArrayLength(arg%d) > "
259 "0) {\n",
260 argIndex, argIndex);
261 fprintf(out,
262 " jbyte_array%d = "
263 "env->GetByteArrayElements(arg%d, NULL);\n",
264 argIndex, argIndex);
265 fprintf(out,
266 " str%d_length = env->GetArrayLength(arg%d);\n",
267 argIndex, argIndex);
268 fprintf(out,
269 " str%d = "
270 "reinterpret_cast<char*>(env->GetByteArrayElements(arg%"
271 "d, NULL));\n",
272 argIndex, argIndex);
273 fprintf(out, " } else {\n");
274 fprintf(out, " jbyte_array%d = NULL;\n", argIndex);
275 fprintf(out, " str%d = NULL;\n", argIndex);
276 fprintf(out, " }\n");
277
278 fprintf(out,
279 " android::util::BytesField bytesField%d(str%d, "
280 "str%d_length);",
281 argIndex, argIndex, argIndex);
282
283 } else if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
284 hadStringOrChain = true;
285 for (auto chainField : attributionDecl.fields) {
286 fprintf(out, " size_t %s_length = env->GetArrayLength(%s);\n",
287 chainField.name.c_str(), chainField.name.c_str());
288 if (chainField.name != attributionDecl.fields.front().name) {
289 fprintf(out, " if (%s_length != %s_length) {\n",
290 chainField.name.c_str(),
291 attributionDecl.fields.front().name.c_str());
292 fprintf(out, " return -EINVAL;\n");
293 fprintf(out, " }\n");
294 }
295 if (chainField.javaType == JAVA_TYPE_INT) {
296 fprintf(out, " jint* %s_array = env->GetIntArrayElements(%s, NULL);\n",
297 chainField.name.c_str(), chainField.name.c_str());
298 } else if (chainField.javaType == JAVA_TYPE_STRING) {
299 fprintf(out, " std::vector<%s> %s_vec;\n",
300 cpp_type_name(chainField.javaType), chainField.name.c_str());
301 fprintf(out, " std::vector<ScopedUtfChars*> scoped_%s_vec;\n",
302 chainField.name.c_str());
303 fprintf(out, " for (size_t i = 0; i < %s_length; ++i) {\n",
304 chainField.name.c_str());
305 fprintf(out, " jstring jstr = "
306 "(jstring)env->GetObjectArrayElement(%s, i);\n",
307 chainField.name.c_str());
308 fprintf(out, " if (jstr == NULL) {\n");
309 fprintf(out, " %s_vec.push_back(NULL);\n",
310 chainField.name.c_str());
311 fprintf(out, " } else {\n");
312 fprintf(out, " ScopedUtfChars* scoped_%s = "
313 "new ScopedUtfChars(env, jstr);\n",
314 chainField.name.c_str());
315 fprintf(out, " %s_vec.push_back(scoped_%s->c_str());\n",
316 chainField.name.c_str(), chainField.name.c_str());
317 fprintf(out, " scoped_%s_vec.push_back(scoped_%s);\n",
318 chainField.name.c_str(), chainField.name.c_str());
319 fprintf(out, " }\n");
320 fprintf(out, " }\n");
321 }
322 fprintf(out, "\n");
323 }
324 } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
325 isKeyValuePairAtom = true;
326 }
327 argIndex++;
328 }
329 // Emit this to quiet the unused parameter warning if there were no strings or attribution
330 // chains.
331 if (!hadStringOrChain && !isKeyValuePairAtom) {
332 fprintf(out, " (void)env;\n");
333 }
334 if (isKeyValuePairAtom) {
335 write_key_value_map_jni(out);
336 }
337
338 // stats_write call
339 argIndex = 1;
340 fprintf(out, "\n int ret = android::util::%s(code",
341 cpp_method_name.c_str());
342 for (vector<java_type_t>::const_iterator arg = signature.begin();
343 arg != signature.end(); arg++) {
344 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
345 for (auto chainField : attributionDecl.fields) {
346 if (chainField.javaType == JAVA_TYPE_INT) {
347 fprintf(out, ", (const %s*)%s_array, %s_length",
348 cpp_type_name(chainField.javaType),
349 chainField.name.c_str(), chainField.name.c_str());
350 } else if (chainField.javaType == JAVA_TYPE_STRING) {
351 fprintf(out, ", %s_vec", chainField.name.c_str());
352 }
353 }
354 } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
355 fprintf(out, ", int32_t_map, int64_t_map, string_map, float_map");
356 } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
357 fprintf(out, ", bytesField%d", argIndex);
358 } else {
359 const char* argName =
360 (*arg == JAVA_TYPE_STRING) ? "str" : "arg";
361 fprintf(out, ", (%s)%s%d", cpp_type_name(*arg), argName, argIndex);
362 }
363 argIndex++;
364 }
365 fprintf(out, ");\n");
366 fprintf(out, "\n");
367
368 // Clean up strings
369 argIndex = 1;
370 for (vector<java_type_t>::const_iterator arg = signature.begin();
371 arg != signature.end(); arg++) {
372 if (*arg == JAVA_TYPE_STRING) {
373 fprintf(out, " if (str%d != NULL) {\n", argIndex);
374 fprintf(out, " env->ReleaseStringUTFChars(arg%d, str%d);\n",
375 argIndex, argIndex);
376 fprintf(out, " }\n");
377 } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
378 fprintf(out, " if (str%d != NULL) { \n", argIndex);
379 fprintf(out,
380 " env->ReleaseByteArrayElements(arg%d, "
381 "jbyte_array%d, 0);\n",
382 argIndex, argIndex);
383 fprintf(out, " }\n");
384 } else if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
385 for (auto chainField : attributionDecl.fields) {
386 if (chainField.javaType == JAVA_TYPE_INT) {
387 fprintf(out, " env->ReleaseIntArrayElements(%s, %s_array, 0);\n",
388 chainField.name.c_str(), chainField.name.c_str());
389 } else if (chainField.javaType == JAVA_TYPE_STRING) {
390 fprintf(out, " for (size_t i = 0; i < scoped_%s_vec.size(); ++i) {\n",
391 chainField.name.c_str());
392 fprintf(out, " delete scoped_%s_vec[i];\n", chainField.name.c_str());
393 fprintf(out, " }\n");
394 }
395 }
396 }
397 argIndex++;
398 }
399
400 fprintf(out, " return ret;\n");
401
402 fprintf(out, "}\n");
403 fprintf(out, "\n");
404 }
405
406
407 return 0;
408 }
409
write_jni_registration(FILE * out,const string & java_method_name,const map<vector<java_type_t>,set<string>> & signatures_to_modules,const AtomDecl & attributionDecl)410 void write_jni_registration(FILE* out, const string& java_method_name,
411 const map<vector<java_type_t>, set<string>>& signatures_to_modules,
412 const AtomDecl &attributionDecl) {
413 for (auto signature_to_modules_it = signatures_to_modules.begin();
414 signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
415 vector<java_type_t> signature = signature_to_modules_it->first;
416 fprintf(out, " { \"%s\", \"%s\", (void*)%s },\n",
417 java_method_name.c_str(),
418 jni_function_signature(signature, attributionDecl).c_str(),
419 jni_function_name(java_method_name, signature).c_str());
420 }
421 }
422 #endif // JNI helpers.
423
424 static int
425 #if defined(STATS_SCHEMA_LEGACY)
write_stats_log_jni(FILE * out,const Atoms & atoms,const AtomDecl & attributionDecl)426 write_stats_log_jni(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl)
427 #else
428 // Write empty JNI file that doesn't contain any JNI methods.
429 // TODO(b/145100015): remove this function and all JNI autogen code once StatsEvent migration is
430 // complete.
431 write_stats_log_jni(FILE* out)
432 #endif
433 {
434 // Print prelude
435 fprintf(out, "// This file is autogenerated\n");
436 fprintf(out, "\n");
437
438 #if defined(STATS_SCHEMA_LEGACY)
439 fprintf(out, "#include <statslog.h>\n");
440 fprintf(out, "\n");
441 fprintf(out, "#include <nativehelper/JNIHelp.h>\n");
442 fprintf(out, "#include <nativehelper/ScopedUtfChars.h>\n");
443 fprintf(out, "#include <utils/Vector.h>\n");
444 #endif
445 fprintf(out, "#include \"core_jni_helpers.h\"\n");
446 fprintf(out, "#include \"jni.h\"\n");
447 fprintf(out, "\n");
448 #if defined(STATS_SCHEMA_LEGACY)
449 fprintf(out, "#define UNUSED __attribute__((__unused__))\n");
450 fprintf(out, "\n");
451 #endif
452
453 fprintf(out, "namespace android {\n");
454 fprintf(out, "\n");
455
456 #if defined(STATS_SCHEMA_LEGACY)
457 write_stats_log_jni_method(out, "write", "stats_write", atoms.signatures_to_modules, attributionDecl);
458 write_stats_log_jni_method(out, "write_non_chained", "stats_write_non_chained",
459 atoms.non_chained_signatures_to_modules, attributionDecl);
460 #endif
461
462 // Print registration function table
463 fprintf(out, "/*\n");
464 fprintf(out, " * JNI registration.\n");
465 fprintf(out, " */\n");
466 fprintf(out, "static const JNINativeMethod gRegisterMethods[] = {\n");
467 #if defined(STATS_SCHEMA_LEGACY)
468 write_jni_registration(out, "write", atoms.signatures_to_modules, attributionDecl);
469 write_jni_registration(out, "write_non_chained", atoms.non_chained_signatures_to_modules,
470 attributionDecl);
471 #endif
472 fprintf(out, "};\n");
473 fprintf(out, "\n");
474
475 // Print registration function
476 fprintf(out, "int register_android_util_StatsLogInternal(JNIEnv* env) {\n");
477 fprintf(out, " return RegisterMethodsOrDie(\n");
478 fprintf(out, " env,\n");
479 fprintf(out, " \"android/util/StatsLogInternal\",\n");
480 fprintf(out, " gRegisterMethods, NELEM(gRegisterMethods));\n");
481 fprintf(out, "}\n");
482
483 fprintf(out, "\n");
484 fprintf(out, "} // namespace android\n");
485 return 0;
486 }
487
488 static void
print_usage()489 print_usage()
490 {
491 fprintf(stderr, "usage: stats-log-api-gen OPTIONS\n");
492 fprintf(stderr, "\n");
493 fprintf(stderr, "OPTIONS\n");
494 fprintf(stderr, " --cpp FILENAME the header file to output for write helpers\n");
495 fprintf(stderr, " --header FILENAME the cpp file to output for write helpers\n");
496 fprintf(stderr,
497 " --atomsInfoCpp FILENAME the header file to output for statsd metadata\n");
498 fprintf(stderr, " --atomsInfoHeader FILENAME the cpp file to output for statsd metadata\n");
499 fprintf(stderr, " --help this message\n");
500 fprintf(stderr, " --java FILENAME the java file to output\n");
501 fprintf(stderr, " --jni FILENAME the jni file to output\n");
502 fprintf(stderr, " --module NAME optional, module name to generate outputs for\n");
503 fprintf(stderr, " --namespace COMMA,SEP,NAMESPACE required for cpp/header with module\n");
504 fprintf(stderr, " comma separated namespace of the files\n");
505 fprintf(stderr," --importHeader NAME required for cpp/jni to say which header to import "
506 "for write helpers\n");
507 fprintf(stderr," --atomsInfoImportHeader NAME required for cpp to say which header to import "
508 "for statsd metadata\n");
509 fprintf(stderr, " --javaPackage PACKAGE the package for the java file.\n");
510 fprintf(stderr, " required for java with module\n");
511 fprintf(stderr, " --javaClass CLASS the class name of the java class.\n");
512 fprintf(stderr, " Optional for Java with module.\n");
513 fprintf(stderr, " Default is \"StatsLogInternal\"\n");
514 fprintf(stderr, " --supportQ Include runtime support for Android Q.\n");
515 fprintf(stderr, " --worksource Include support for logging WorkSource objects.\n");
516 fprintf(stderr, " --compileQ Include compile-time support for Android Q "
517 "(Java only).\n");
518 }
519
520 /**
521 * Do the argument parsing and execute the tasks.
522 */
523 static int
run(int argc,char const * const * argv)524 run(int argc, char const*const* argv)
525 {
526 string cppFilename;
527 string headerFilename;
528 string javaFilename;
529 string jniFilename;
530 string atomsInfoCppFilename;
531 string atomsInfoHeaderFilename;
532
533 string moduleName = DEFAULT_MODULE_NAME;
534 string cppNamespace = DEFAULT_CPP_NAMESPACE;
535 string cppHeaderImport = DEFAULT_CPP_HEADER_IMPORT;
536 string atomsInfoCppHeaderImport = DEFAULT_ATOMS_INFO_CPP_HEADER_IMPORT;
537 string javaPackage = DEFAULT_JAVA_PACKAGE;
538 string javaClass = DEFAULT_JAVA_CLASS;
539 bool supportQ = false;
540 bool supportWorkSource = false;
541 bool compileQ = false;
542
543 int index = 1;
544 while (index < argc) {
545 if (0 == strcmp("--help", argv[index])) {
546 print_usage();
547 return 0;
548 } else if (0 == strcmp("--cpp", argv[index])) {
549 index++;
550 if (index >= argc) {
551 print_usage();
552 return 1;
553 }
554 cppFilename = argv[index];
555 } else if (0 == strcmp("--header", argv[index])) {
556 index++;
557 if (index >= argc) {
558 print_usage();
559 return 1;
560 }
561 headerFilename = argv[index];
562 } else if (0 == strcmp("--java", argv[index])) {
563 index++;
564 if (index >= argc) {
565 print_usage();
566 return 1;
567 }
568 javaFilename = argv[index];
569 } else if (0 == strcmp("--jni", argv[index])) {
570 index++;
571 if (index >= argc) {
572 print_usage();
573 return 1;
574 }
575 jniFilename = argv[index];
576 } else if (0 == strcmp("--module", argv[index])) {
577 index++;
578 if (index >= argc) {
579 print_usage();
580 return 1;
581 }
582 moduleName = argv[index];
583 } else if (0 == strcmp("--namespace", argv[index])) {
584 index++;
585 if (index >= argc) {
586 print_usage();
587 return 1;
588 }
589 cppNamespace = argv[index];
590 } else if (0 == strcmp("--importHeader", argv[index])) {
591 index++;
592 if (index >= argc) {
593 print_usage();
594 return 1;
595 }
596 cppHeaderImport = argv[index];
597 } else if (0 == strcmp("--javaPackage", argv[index])) {
598 index++;
599 if (index >= argc) {
600 print_usage();
601 return 1;
602 }
603 javaPackage = argv[index];
604 } else if (0 == strcmp("--javaClass", argv[index])) {
605 index++;
606 if (index >= argc) {
607 print_usage();
608 return 1;
609 }
610 javaClass = argv[index];
611 } else if (0 == strcmp("--atomsInfoHeader", argv[index])) {
612 index++;
613 if (index >= argc) {
614 print_usage();
615 return 1;
616 }
617 atomsInfoHeaderFilename = argv[index];
618 } else if (0 == strcmp("--atomsInfoCpp", argv[index])) {
619 index++;
620 if (index >= argc) {
621 print_usage();
622 return 1;
623 }
624 atomsInfoCppFilename = argv[index];
625 } else if (0 == strcmp("--atomsInfoImportHeader", argv[index])) {
626 index++;
627 if (index >= argc) {
628 print_usage();
629 return 1;
630 }
631 atomsInfoCppHeaderImport = argv[index];
632 } else if (0 == strcmp("--supportQ", argv[index])) {
633 supportQ = true;
634 } else if (0 == strcmp("--worksource", argv[index])) {
635 supportWorkSource = true;
636 } else if (0 == strcmp("--compileQ", argv[index])) {
637 compileQ = true;
638 }
639
640 index++;
641 }
642
643 if (cppFilename.size() == 0
644 && headerFilename.size() == 0
645 && javaFilename.size() == 0
646 && jniFilename.size() == 0
647 && atomsInfoHeaderFilename.size() == 0
648 && atomsInfoCppFilename.size() == 0) {
649 print_usage();
650 return 1;
651 }
652
653 if (DEFAULT_MODULE_NAME == moduleName && (supportQ || compileQ)) {
654 // Support for Q schema is not needed for default module.
655 fprintf(stderr, "%s cannot support Q schema\n", moduleName.c_str());
656 return 1;
657 }
658
659 if (supportQ && compileQ) {
660 // Runtime Q support is redundant if compile-time Q support is required.
661 fprintf(stderr, "Cannot specify compileQ and supportQ simultaneously.\n");
662 return 1;
663 }
664
665 // Collate the parameters
666 Atoms atoms;
667 int errorCount = collate_atoms(Atom::descriptor(), &atoms);
668 if (errorCount != 0) {
669 return 1;
670 }
671
672 AtomDecl attributionDecl;
673 vector<java_type_t> attributionSignature;
674 collate_atom(android::os::statsd::AttributionNode::descriptor(),
675 &attributionDecl, &attributionSignature);
676
677 // Write the atoms info .cpp file
678 if (atomsInfoCppFilename.size() != 0) {
679 FILE* out = fopen(atomsInfoCppFilename.c_str(), "w");
680 if (out == NULL) {
681 fprintf(stderr, "Unable to open file for write: %s\n", atomsInfoCppFilename.c_str());
682 return 1;
683 }
684 errorCount = android::stats_log_api_gen::write_atoms_info_cpp(
685 out, atoms, cppNamespace, atomsInfoCppHeaderImport, cppHeaderImport);
686 fclose(out);
687 }
688
689 // Write the atoms info .h file
690 if (atomsInfoHeaderFilename.size() != 0) {
691 FILE* out = fopen(atomsInfoHeaderFilename.c_str(), "w");
692 if (out == NULL) {
693 fprintf(stderr, "Unable to open file for write: %s\n", atomsInfoHeaderFilename.c_str());
694 return 1;
695 }
696 errorCount = android::stats_log_api_gen::write_atoms_info_header(out, atoms, cppNamespace);
697 fclose(out);
698 }
699
700
701 // Write the .cpp file
702 if (cppFilename.size() != 0) {
703 FILE* out = fopen(cppFilename.c_str(), "w");
704 if (out == NULL) {
705 fprintf(stderr, "Unable to open file for write: %s\n", cppFilename.c_str());
706 return 1;
707 }
708 // If this is for a specific module, the namespace must also be provided.
709 if (moduleName != DEFAULT_MODULE_NAME && cppNamespace == DEFAULT_CPP_NAMESPACE) {
710 fprintf(stderr, "Must supply --namespace if supplying a specific module\n");
711 return 1;
712 }
713 // If this is for a specific module, the header file to import must also be provided.
714 if (moduleName != DEFAULT_MODULE_NAME && cppHeaderImport == DEFAULT_CPP_HEADER_IMPORT) {
715 fprintf(stderr, "Must supply --headerImport if supplying a specific module\n");
716 return 1;
717 }
718 errorCount = android::stats_log_api_gen::write_stats_log_cpp(
719 out, atoms, attributionDecl, moduleName, cppNamespace, cppHeaderImport, supportQ);
720 fclose(out);
721 }
722
723 // Write the .h file
724 if (headerFilename.size() != 0) {
725 FILE* out = fopen(headerFilename.c_str(), "w");
726 if (out == NULL) {
727 fprintf(stderr, "Unable to open file for write: %s\n", headerFilename.c_str());
728 return 1;
729 }
730 // If this is for a specific module, the namespace must also be provided.
731 if (moduleName != DEFAULT_MODULE_NAME && cppNamespace == DEFAULT_CPP_NAMESPACE) {
732 fprintf(stderr, "Must supply --namespace if supplying a specific module\n");
733 }
734 errorCount = android::stats_log_api_gen::write_stats_log_header(
735 out, atoms, attributionDecl, moduleName, cppNamespace);
736 fclose(out);
737 }
738
739 // Write the .java file
740 if (javaFilename.size() != 0) {
741 FILE* out = fopen(javaFilename.c_str(), "w");
742 if (out == NULL) {
743 fprintf(stderr, "Unable to open file for write: %s\n", javaFilename.c_str());
744 return 1;
745 }
746
747 #if defined(STATS_SCHEMA_LEGACY)
748 if (moduleName == DEFAULT_MODULE_NAME) {
749 errorCount = android::stats_log_api_gen::write_stats_log_java_q(
750 out, atoms, attributionDecl, supportWorkSource);
751 } else {
752 errorCount = android::stats_log_api_gen::write_stats_log_java_q_for_module(
753 out, atoms, attributionDecl, moduleName, javaClass, javaPackage,
754 supportWorkSource);
755
756 }
757 #else
758 if (moduleName == DEFAULT_MODULE_NAME) {
759 javaClass = "StatsLogInternal";
760 javaPackage = "android.util";
761 }
762 if (compileQ) {
763 errorCount = android::stats_log_api_gen::write_stats_log_java_q_for_module(
764 out, atoms, attributionDecl, moduleName, javaClass, javaPackage,
765 supportWorkSource);
766 } else {
767 errorCount = android::stats_log_api_gen::write_stats_log_java(
768 out, atoms, attributionDecl, moduleName, javaClass, javaPackage, supportQ,
769 supportWorkSource);
770 }
771 #endif
772
773 fclose(out);
774 }
775
776 // Write the jni file
777 if (jniFilename.size() != 0) {
778 FILE* out = fopen(jniFilename.c_str(), "w");
779 if (out == NULL) {
780 fprintf(stderr, "Unable to open file for write: %s\n", jniFilename.c_str());
781 return 1;
782 }
783
784 #if defined(STATS_SCHEMA_LEGACY)
785 errorCount = android::stats_log_api_gen::write_stats_log_jni(
786 out, atoms, attributionDecl);
787 #else
788 errorCount = android::stats_log_api_gen::write_stats_log_jni(out);
789 #endif
790
791 fclose(out);
792 }
793
794 return errorCount;
795 }
796
797 } // namespace stats_log_api_gen
798 } // namespace android
799
800 /**
801 * Main.
802 */
803 int
main(int argc,char const * const * argv)804 main(int argc, char const*const* argv)
805 {
806 GOOGLE_PROTOBUF_VERIFY_VERSION;
807
808 return android::stats_log_api_gen::run(argc, argv);
809 }
810