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