• 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, "  --module NAME        optional, module name to generate outputs for\n");
35     fprintf(stderr,
36             "  --namespace COMMA,SEP,NAMESPACE   required for cpp/header with "
37             "module\n");
38     fprintf(stderr,
39             "                                    comma separated namespace of "
40             "the files\n");
41     fprintf(stderr,
42             "  --importHeader NAME  required for cpp/jni to say which header to "
43             "import "
44             "for write helpers\n");
45     fprintf(stderr, "  --javaPackage PACKAGE             the package for the java file.\n");
46     fprintf(stderr, "                                    required for java with module\n");
47     fprintf(stderr, "  --javaClass CLASS    the class name of the java class.\n");
48     fprintf(stderr, "  --minApiLevel API_LEVEL           lowest API level to support.\n");
49     fprintf(stderr, "                                    Default is \"current\".\n");
50     fprintf(stderr,
51             "  --worksource         Include support for logging WorkSource "
52             "objects.\n");
53     fprintf(stderr,
54             "  --compileApiLevel API_LEVEL           specify which API level generated code is "
55             "compiled against. (Java only).\n");
56     fprintf(stderr,
57             "                                        Default is \"current\".\n");
58 }
59 
60 /**
61  * Do the argument parsing and execute the tasks.
62  */
run(int argc,char const * const * argv)63 static int run(int argc, char const* const* argv) {
64     string cppFilename;
65     string headerFilename;
66     string javaFilename;
67     string javaPackage;
68     string javaClass;
69     string rustFilename;
70     string rustHeaderFilename;
71 
72     string moduleName = DEFAULT_MODULE_NAME;
73     string cppNamespace = DEFAULT_CPP_NAMESPACE;
74     string cppHeaderImport = DEFAULT_CPP_HEADER_IMPORT;
75     bool supportWorkSource = false;
76     int minApiLevel = API_LEVEL_CURRENT;
77     int compileApiLevel = API_LEVEL_CURRENT;
78 
79     int index = 1;
80     while (index < argc) {
81         if (0 == strcmp("--help", argv[index])) {
82             print_usage();
83             return 0;
84         } else if (0 == strcmp("--cpp", argv[index])) {
85             index++;
86             if (index >= argc) {
87                 print_usage();
88                 return 1;
89             }
90             cppFilename = argv[index];
91         } else if (0 == strcmp("--header", argv[index])) {
92             index++;
93             if (index >= argc) {
94                 print_usage();
95                 return 1;
96             }
97             headerFilename = argv[index];
98         } else if (0 == strcmp("--java", argv[index])) {
99             index++;
100             if (index >= argc) {
101                 print_usage();
102                 return 1;
103             }
104             javaFilename = argv[index];
105         } else if (0 == strcmp("--rust", argv[index])) {
106             index++;
107             if (index >= argc) {
108                 print_usage();
109                 return 1;
110             }
111             rustFilename = argv[index];
112         } else if (0 == strcmp("--rustHeader", argv[index])) {
113             index++;
114             if (index >= argc) {
115                 print_usage();
116                 return 1;
117             }
118             rustHeaderFilename = argv[index];
119         } else if (0 == strcmp("--module", argv[index])) {
120             index++;
121             if (index >= argc) {
122                 print_usage();
123                 return 1;
124             }
125             moduleName = argv[index];
126         } else if (0 == strcmp("--namespace", argv[index])) {
127             index++;
128             if (index >= argc) {
129                 print_usage();
130                 return 1;
131             }
132             cppNamespace = argv[index];
133         } else if (0 == strcmp("--importHeader", argv[index])) {
134             index++;
135             if (index >= argc) {
136                 print_usage();
137                 return 1;
138             }
139             cppHeaderImport = argv[index];
140         } else if (0 == strcmp("--javaPackage", argv[index])) {
141             index++;
142             if (index >= argc) {
143                 print_usage();
144                 return 1;
145             }
146             javaPackage = argv[index];
147         } else if (0 == strcmp("--javaClass", argv[index])) {
148             index++;
149             if (index >= argc) {
150                 print_usage();
151                 return 1;
152             }
153             javaClass = argv[index];
154         } else if (0 == strcmp("--supportQ", argv[index])) {
155             minApiLevel = API_Q;
156         } else if (0 == strcmp("--worksource", argv[index])) {
157             supportWorkSource = true;
158         } else if (0 == strcmp("--minApiLevel", argv[index])) {
159             index++;
160             if (index >= argc) {
161                 print_usage();
162                 return 1;
163             }
164             if (0 != strcmp("current", argv[index])) {
165                 minApiLevel = atoi(argv[index]);
166             }
167         } else if (0 == strcmp("--compileApiLevel", argv[index])) {
168             index++;
169             if (index >= argc) {
170                 print_usage();
171                 return 1;
172             }
173             if (0 != strcmp("current", argv[index])) {
174                 compileApiLevel = atoi(argv[index]);
175             }
176         }
177 
178         index++;
179     }
180 
181     if (cppFilename.empty() && headerFilename.empty()
182         && javaFilename.empty() && rustFilename.empty()
183         && rustHeaderFilename.empty()) {
184         print_usage();
185         return 1;
186     }
187     if (DEFAULT_MODULE_NAME == moduleName &&
188             (minApiLevel != API_LEVEL_CURRENT || compileApiLevel != API_LEVEL_CURRENT)) {
189         // Default module only supports current API level.
190         fprintf(stderr, "%s cannot support older API levels\n", moduleName.c_str());
191         return 1;
192     }
193 
194     if (compileApiLevel < API_R) {
195         // Cannot compile against pre-R.
196         fprintf(stderr, "compileApiLevel must be %d or higher.\n", API_R);
197         return 1;
198     }
199 
200     if (minApiLevel < API_Q) {
201         // Cannot support pre-Q.
202         fprintf(stderr, "minApiLevel must be %d or higher.\n", API_Q);
203         return 1;
204     }
205 
206     if (minApiLevel == API_LEVEL_CURRENT) {
207         if (minApiLevel > compileApiLevel) {
208             // If minApiLevel is not specified, assume it is not higher than compileApiLevel.
209             minApiLevel = compileApiLevel;
210         }
211     } else {
212         if (minApiLevel > compileApiLevel) {
213             // If specified, minApiLevel should always be lower than compileApiLevel.
214             fprintf(stderr, "Invalid minApiLevel or compileApiLevel. If minApiLevel and"
215                     " compileApiLevel are specified, minApiLevel should not be higher"
216                     " than compileApiLevel.\n");
217             return 1;
218         }
219     }
220 
221     // Collate the parameters
222     Atoms atoms;
223     int errorCount = collate_atoms(Atom::descriptor(), moduleName, &atoms);
224     if (errorCount != 0) {
225         return 1;
226     }
227 
228     AtomDecl attributionDecl;
229     vector<java_type_t> attributionSignature;
230     collate_atom(android::os::statsd::AttributionNode::descriptor(), &attributionDecl,
231                  &attributionSignature);
232 
233     // Write the .cpp file
234     if (!cppFilename.empty()) {
235         FILE* out = fopen(cppFilename.c_str(), "w");
236         if (out == nullptr) {
237             fprintf(stderr, "Unable to open file for write: %s\n", cppFilename.c_str());
238             return 1;
239         }
240         // If this is for a specific module, the namespace must also be provided.
241         if (moduleName != DEFAULT_MODULE_NAME && cppNamespace == DEFAULT_CPP_NAMESPACE) {
242             fprintf(stderr, "Must supply --namespace if supplying a specific module\n");
243             return 1;
244         }
245         // If this is for a specific module, the header file to import must also be
246         // provided.
247         if (moduleName != DEFAULT_MODULE_NAME && cppHeaderImport == DEFAULT_CPP_HEADER_IMPORT) {
248             fprintf(stderr, "Must supply --headerImport if supplying a specific module\n");
249             return 1;
250         }
251         errorCount = android::stats_log_api_gen::write_stats_log_cpp(
252                 out, atoms, attributionDecl, cppNamespace, cppHeaderImport, minApiLevel);
253         fclose(out);
254     }
255 
256     // Write the .h file
257     if (!headerFilename.empty()) {
258         FILE* out = fopen(headerFilename.c_str(), "w");
259         if (out == nullptr) {
260             fprintf(stderr, "Unable to open file for write: %s\n", headerFilename.c_str());
261             return 1;
262         }
263         // If this is for a specific module, the namespace must also be provided.
264         if (moduleName != DEFAULT_MODULE_NAME && cppNamespace == DEFAULT_CPP_NAMESPACE) {
265             fprintf(stderr, "Must supply --namespace if supplying a specific module\n");
266         }
267         errorCount = android::stats_log_api_gen::write_stats_log_header(out, atoms, attributionDecl,
268                                                                         cppNamespace, minApiLevel);
269         fclose(out);
270     }
271 
272     // Write the .java file
273     if (!javaFilename.empty()) {
274         if (javaClass.empty()) {
275             fprintf(stderr, "Must supply --javaClass if supplying a Java filename");
276             return 1;
277         }
278 
279         if (javaPackage.empty()) {
280             fprintf(stderr, "Must supply --javaPackage if supplying a Java filename");
281             return 1;
282         }
283 
284         if (moduleName.empty()) {
285             fprintf(stderr, "Must supply --module if supplying a Java filename");
286             return 1;
287         }
288 
289         FILE* out = fopen(javaFilename.c_str(), "w");
290         if (out == nullptr) {
291             fprintf(stderr, "Unable to open file for write: %s\n", javaFilename.c_str());
292             return 1;
293         }
294 
295         errorCount = android::stats_log_api_gen::write_stats_log_java(
296                 out, atoms, attributionDecl, javaClass, javaPackage, minApiLevel, compileApiLevel,
297                 supportWorkSource);
298 
299         fclose(out);
300     }
301 
302     // Write the main .rs file
303     if (!rustFilename.empty()) {
304         FILE* out = fopen(rustFilename.c_str(), "w");
305         if (out == nullptr) {
306             fprintf(stderr, "Unable to open file for write: %s\n", rustFilename.c_str());
307             return 1;
308         }
309 
310         errorCount += android::stats_log_api_gen::write_stats_log_rust(
311                 out, atoms, attributionDecl, minApiLevel);
312 
313         fclose(out);
314     }
315 
316     // Write the header .rs file
317     if (!rustHeaderFilename.empty()) {
318         FILE* out = fopen(rustHeaderFilename.c_str(), "w");
319         if (out == nullptr) {
320             fprintf(stderr, "Unable to open file for write: %s\n", rustHeaderFilename.c_str());
321             return 1;
322         }
323 
324         android::stats_log_api_gen::write_stats_log_rust_header(
325                 out, atoms, attributionDecl);
326 
327         fclose(out);
328     }
329 
330     return errorCount;
331 }
332 
333 }  // namespace stats_log_api_gen
334 }  // namespace android
335 
336 /**
337  * Main.
338  */
main(int argc,char const * const * argv)339 int main(int argc, char const* const* argv) {
340     GOOGLE_PROTOBUF_VERIFY_VERSION;
341 
342     return android::stats_log_api_gen::run(argc, argv);
343 }
344