• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 #include <google/protobuf/descriptor.h>
3 #include <google/protobuf/stubs/common.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 
8 #include <cstdlib>
9 #include <filesystem>
10 
11 #include "Collation.h"
12 #include "frameworks/proto_logging/stats/atoms.pb.h"
13 #include "frameworks/proto_logging/stats/attribution_node.pb.h"
14 #include "java_writer.h"
15 #include "native_writer.h"
16 #include "rust_writer.h"
17 #include "utils.h"
18 
19 #ifdef WITH_VENDOR
20 #include "java_writer_vendor.h"
21 #include "native_writer_vendor.h"
22 #endif
23 
24 namespace android {
25 namespace stats_log_api_gen {
26 
27 namespace fs = std::filesystem;
28 using android::os::statsd::Atom;
29 
print_usage()30 static void print_usage() {
31     fprintf(stderr, "usage: stats-log-api-gen OPTIONS\n");
32     fprintf(stderr, "\n");
33     fprintf(stderr, "OPTIONS\n");
34     fprintf(stderr, "  --cpp FILENAME       the cpp file to output for write helpers\n");
35     fprintf(stderr, "  --header FILENAME    the header file to output for write helpers\n");
36     fprintf(stderr, "  --help               this message\n");
37     fprintf(stderr, "  --java FILENAME      the java file to output\n");
38     fprintf(stderr, "  --rust FILENAME      the rust file to output\n");
39     fprintf(stderr, "  --rustHeader FILENAME the rust file to output for write helpers\n");
40     fprintf(stderr,
41             "  --rustHeaderCrate NAME        header crate to be used while "
42             "generating the code. Note: this should be the same as the crate_name "
43             "created by rust_library for the header \n");
44     fprintf(stderr, "  --module NAME        optional, module name to generate outputs for\n");
45     fprintf(stderr,
46             "  --namespace COMMA,SEP,NAMESPACE   required for cpp/header with "
47             "module\n");
48     fprintf(stderr,
49             "                                    comma separated namespace of "
50             "the files\n");
51     fprintf(stderr,
52             "  --importHeader NAME  required for cpp/jni to say which header to "
53             "import "
54             "for write helpers\n");
55     fprintf(stderr, "  --javaPackage PACKAGE             the package for the java file.\n");
56     fprintf(stderr, "                                    required for java with module\n");
57     fprintf(stderr, "  --javaClass CLASS    the class name of the java class.\n");
58     fprintf(stderr, "  --nonStatic          generate java classes with non-static methods\n");
59     fprintf(stderr, "  --minApiLevel API_LEVEL           lowest API level to support.\n");
60     fprintf(stderr, "                                    Default is \"current\".\n");
61     fprintf(stderr,
62             "  --worksource         Include support for logging WorkSource "
63             "objects.\n");
64     fprintf(stderr, "                                        Default is \"current\".\n");
65     fprintf(stderr,
66             "  --bootstrap          If this logging is from a bootstrap process. "
67             "Only supported for cpp. Do not use unless necessary.\n");
68 #ifdef WITH_VENDOR
69     fprintf(stderr,
70             "  --vendor-proto       Path to the proto file for vendor atoms logging\n"
71             "code generation.\n");
72 #endif
73 }
74 
75 /**
76  * Do the argument parsing and execute the tasks.
77  */
run(int argc,char const * const * argv)78 static int run(int argc, char const* const* argv) {
79     string cppFilename;
80     string headerFilename;
81     string javaFilename;
82     string javaPackage;
83     string javaClass;
84     string rustFilename;
85     string rustHeaderFilename;
86     string rustHeaderCrate;
87     string moduleName = DEFAULT_MODULE_NAME;
88     string cppNamespace = DEFAULT_CPP_NAMESPACE;
89     string cppHeaderImport = DEFAULT_CPP_HEADER_IMPORT;
90     string vendorProto;
91     bool supportWorkSource = false;
92     int minApiLevel = API_LEVEL_CURRENT;
93     bool bootstrap = false;
94     bool javaStaticMethods = true;
95 
96     int index = 1;
97     while (index < argc) {
98         if (0 == strcmp("--help", argv[index])) {
99             print_usage();
100             return 0;
101         } else if (0 == strcmp("--cpp", argv[index])) {
102             index++;
103             if (index >= argc) {
104                 print_usage();
105                 return 1;
106             }
107             cppFilename = argv[index];
108         } else if (0 == strcmp("--header", argv[index])) {
109             index++;
110             if (index >= argc) {
111                 print_usage();
112                 return 1;
113             }
114             headerFilename = argv[index];
115         } else if (0 == strcmp("--java", argv[index])) {
116             index++;
117             if (index >= argc) {
118                 print_usage();
119                 return 1;
120             }
121             javaFilename = argv[index];
122         } else if (0 == strcmp("--rust", argv[index])) {
123             index++;
124             if (index >= argc) {
125                 print_usage();
126                 return 1;
127             }
128             rustFilename = argv[index];
129         } else if (0 == strcmp("--rustHeader", argv[index])) {
130             index++;
131             if (index >= argc) {
132                 print_usage();
133                 return 1;
134             }
135             rustHeaderFilename = argv[index];
136         } else if (0 == strcmp("--rustHeaderCrate", argv[index])) {
137             index++;
138             if (index >= argc) {
139                 print_usage();
140                 return 1;
141             }
142             rustHeaderCrate = argv[index];
143         } else if (0 == strcmp("--module", argv[index])) {
144             index++;
145             if (index >= argc) {
146                 print_usage();
147                 return 1;
148             }
149             moduleName = argv[index];
150         } else if (0 == strcmp("--namespace", argv[index])) {
151             index++;
152             if (index >= argc) {
153                 print_usage();
154                 return 1;
155             }
156             cppNamespace = argv[index];
157         } else if (0 == strcmp("--importHeader", argv[index])) {
158             index++;
159             if (index >= argc) {
160                 print_usage();
161                 return 1;
162             }
163             cppHeaderImport = argv[index];
164         } else if (0 == strcmp("--javaPackage", argv[index])) {
165             index++;
166             if (index >= argc) {
167                 print_usage();
168                 return 1;
169             }
170             javaPackage = argv[index];
171         } else if (0 == strcmp("--javaClass", argv[index])) {
172             index++;
173             if (index >= argc) {
174                 print_usage();
175                 return 1;
176             }
177             javaClass = argv[index];
178         } else if (0 == strcmp("--nonStatic", argv[index])) {
179             javaStaticMethods = false;
180         } else if (0 == strcmp("--supportQ", argv[index])) {
181             minApiLevel = API_Q;
182         } else if (0 == strcmp("--worksource", argv[index])) {
183             supportWorkSource = true;
184         } else if (0 == strcmp("--minApiLevel", argv[index])) {
185             index++;
186             if (index >= argc) {
187                 print_usage();
188                 return 1;
189             }
190             if (0 != strcmp("current", argv[index])) {
191                 minApiLevel = atoi(argv[index]);
192             }
193         } else if (0 == strcmp("--bootstrap", argv[index])) {
194             bootstrap = true;
195 #ifdef WITH_VENDOR
196         } else if (0 == strcmp("--vendor-proto", argv[index])) {
197             index++;
198             if (index >= argc) {
199                 print_usage();
200                 return 1;
201             }
202 
203             vendorProto = argv[index];
204 #endif
205         }
206 
207         index++;
208     }
209     if (index < argc) {
210         fprintf(stderr, "Error: Unknown command line argument\n");
211         print_usage();
212         return 1;
213     }
214 
215     if (cppFilename.empty() && headerFilename.empty() && javaFilename.empty() &&
216         rustFilename.empty() && rustHeaderFilename.empty()) {
217         print_usage();
218         return 1;
219     }
220     if (DEFAULT_MODULE_NAME == moduleName && minApiLevel != API_LEVEL_CURRENT) {
221         // Default module only supports current API level.
222         fprintf(stderr, "%s cannot support older API levels\n", moduleName.c_str());
223         return 1;
224     }
225 
226     if (minApiLevel < API_Q) {
227         // Cannot support pre-Q.
228         fprintf(stderr, "minApiLevel must be %d or higher.\n", API_Q);
229         return 1;
230     }
231 
232     if (bootstrap) {
233         if (cppFilename.empty() && headerFilename.empty()) {
234             fprintf(stderr, "Bootstrap flag can only be used for cpp/header files.\n");
235             return 1;
236         }
237         if (supportWorkSource) {
238             fprintf(stderr, "Bootstrap flag does not support worksources");
239             return 1;
240         }
241         if (minApiLevel != API_LEVEL_CURRENT) {
242             fprintf(stderr, "Bootstrap flag does not support older API levels");
243             return 1;
244         }
245     }
246 
247     // Collate the parameters.
248     int errorCount = 0;
249 
250     Atoms atoms;
251 
252     MFErrorCollector errorCollector;
253     google::protobuf::compiler::DiskSourceTree sourceTree;
254     google::protobuf::compiler::Importer importer(&sourceTree, &errorCollector);
255 
256     if (vendorProto.empty()) {
257         errorCount = collate_atoms(*Atom::descriptor(), moduleName, atoms);
258     } else {
259         const google::protobuf::FileDescriptor* fileDescriptor;
260         sourceTree.MapPath("", fs::current_path().c_str());
261 
262         const char* androidBuildTop = std::getenv("ANDROID_BUILD_TOP");
263 
264         fs::path protobufSrc = androidBuildTop != nullptr ? androidBuildTop : fs::current_path();
265         protobufSrc /= "external/protobuf/src";
266         sourceTree.MapPath("", protobufSrc.c_str());
267 
268         if (androidBuildTop != nullptr) {
269             sourceTree.MapPath("", androidBuildTop);
270         }
271 
272         fileDescriptor = importer.Import(vendorProto);
273         errorCount =
274                 collate_atoms(*fileDescriptor->FindMessageTypeByName("Atom"), moduleName, atoms);
275     }
276 
277     if (errorCount != 0) {
278         return 1;
279     }
280 
281     AtomDecl attributionDecl;
282     vector<java_type_t> attributionSignature;
283     collate_atom(*android::os::statsd::AttributionNode::descriptor(), attributionDecl,
284                  attributionSignature);
285 
286     // Write the .cpp file
287     if (!cppFilename.empty()) {
288         // If this is for a specific module, the namespace must also be provided.
289         if (moduleName != DEFAULT_MODULE_NAME && cppNamespace == DEFAULT_CPP_NAMESPACE) {
290             fprintf(stderr, "Must supply --namespace if supplying a specific module\n");
291             return 1;
292         }
293         // If this is for a specific module, the header file to import must also be
294         // provided.
295         if (moduleName != DEFAULT_MODULE_NAME && cppHeaderImport == DEFAULT_CPP_HEADER_IMPORT) {
296             fprintf(stderr, "Must supply --headerImport if supplying a specific module\n");
297             return 1;
298         }
299         FILE* out = fopen(cppFilename.c_str(), "we");
300         if (out == nullptr) {
301             fprintf(stderr, "Unable to open file for write: %s\n", cppFilename.c_str());
302             return 1;
303         }
304         if (vendorProto.empty()) {
305             errorCount = android::stats_log_api_gen::write_stats_log_cpp(
306                     out, atoms, attributionDecl, cppNamespace, cppHeaderImport, minApiLevel,
307                     bootstrap);
308         } else {
309 #ifdef WITH_VENDOR
310             errorCount = android::stats_log_api_gen::write_stats_log_cpp_vendor(
311                     out, atoms, attributionDecl, cppNamespace, cppHeaderImport);
312 #endif
313         }
314         fclose(out);
315     }
316 
317     // Write the .h file
318     if (!headerFilename.empty()) {
319         // If this is for a specific module, the namespace must also be provided.
320         if (moduleName != DEFAULT_MODULE_NAME && cppNamespace == DEFAULT_CPP_NAMESPACE) {
321             fprintf(stderr, "Must supply --namespace if supplying a specific module\n");
322         }
323         FILE* out = fopen(headerFilename.c_str(), "we");
324         if (out == nullptr) {
325             fprintf(stderr, "Unable to open file for write: %s\n", headerFilename.c_str());
326             return 1;
327         }
328 
329         if (vendorProto.empty()) {
330             errorCount = android::stats_log_api_gen::write_stats_log_header(
331                     out, atoms, attributionDecl, cppNamespace, minApiLevel, bootstrap);
332         } else {
333 #ifdef WITH_VENDOR
334             errorCount = android::stats_log_api_gen::write_stats_log_header_vendor(
335                     out, atoms, attributionDecl, cppNamespace);
336 #endif
337         }
338         fclose(out);
339     }
340 
341     // Write the .java file
342     if (!javaFilename.empty()) {
343         if (javaClass.empty()) {
344             fprintf(stderr, "Must supply --javaClass if supplying a Java filename");
345             return 1;
346         }
347 
348         if (javaPackage.empty()) {
349             fprintf(stderr, "Must supply --javaPackage if supplying a Java filename");
350             return 1;
351         }
352 
353         if (moduleName.empty() || moduleName == DEFAULT_MODULE_NAME) {
354             fprintf(stderr, "Must supply --module if supplying a Java filename");
355             return 1;
356         }
357 
358         FILE* out = fopen(javaFilename.c_str(), "we");
359         if (out == nullptr) {
360             fprintf(stderr, "Unable to open file for write: %s\n", javaFilename.c_str());
361             return 1;
362         }
363 
364         if (vendorProto.empty()) {
365             errorCount = android::stats_log_api_gen::write_stats_log_java(
366                     out, atoms, attributionDecl, javaClass, javaPackage, minApiLevel,
367                     supportWorkSource, javaStaticMethods);
368         } else {
369 #ifdef WITH_VENDOR
370             if (supportWorkSource) {
371                 fprintf(stderr, "The attribution chain is not supported for vendor atoms");
372                 return 1;
373             }
374 
375             errorCount = android::stats_log_api_gen::write_stats_log_java_vendor(out, atoms,
376                     javaClass, javaPackage, javaStaticMethods);
377 #endif
378         }
379 
380         fclose(out);
381     }
382 
383     // Write the main .rs file
384     if (!rustFilename.empty()) {
385         if (rustHeaderCrate.empty()) {
386             fprintf(stderr, "rustHeaderCrate flag is either not passed or is empty");
387             return 1;
388         }
389 
390         FILE* out = fopen(rustFilename.c_str(), "we");
391         if (out == nullptr) {
392             fprintf(stderr, "Unable to open file for write: %s\n", rustFilename.c_str());
393             return 1;
394         }
395 
396         errorCount += android::stats_log_api_gen::write_stats_log_rust(
397                 out, atoms, attributionDecl, minApiLevel, rustHeaderCrate.c_str());
398 
399         fclose(out);
400     }
401 
402     // Write the header .rs file
403     if (!rustHeaderFilename.empty()) {
404         if (rustHeaderCrate.empty()) {
405             fprintf(stderr, "rustHeaderCrate flag is either not passed or is empty");
406             return 1;
407         }
408 
409         FILE* out = fopen(rustHeaderFilename.c_str(), "we");
410         if (out == nullptr) {
411             fprintf(stderr, "Unable to open file for write: %s\n", rustHeaderFilename.c_str());
412             return 1;
413         }
414 
415         android::stats_log_api_gen::write_stats_log_rust_header(out, atoms, attributionDecl,
416                                                                 rustHeaderCrate.c_str());
417 
418         fclose(out);
419     }
420 
421     return errorCount;
422 }
423 
424 }  // namespace stats_log_api_gen
425 }  // namespace android
426 
427 /**
428  * Main.
429  */
main(int argc,char const * const * argv)430 int main(int argc, char const* const* argv) {
431     GOOGLE_PROTOBUF_VERIFY_VERSION;
432 
433     return android::stats_log_api_gen::run(argc, argv);
434 }
435