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