1 /*
2 * Copyright (C) 2019, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "native_writer.h"
18
19 #include "utils.h"
20
21 namespace android {
22 namespace stats_log_api_gen {
23
write_native_annotation_constants(FILE * out)24 static void write_native_annotation_constants(FILE* out) {
25 fprintf(out, "// Annotation constants.\n");
26
27 const map<AnnotationId, string>& ANNOTATION_ID_CONSTANTS = get_annotation_id_constants();
28 for (const auto& [id, name] : ANNOTATION_ID_CONSTANTS) {
29 fprintf(out, "const uint8_t %s = %hhu;\n", name.c_str(), id);
30 }
31 fprintf(out, "\n");
32 }
33
write_annotations(FILE * out,int argIndex,const FieldNumberToAtomDeclSet & fieldNumberToAtomDeclSet,const string & methodPrefix,const string & methodSuffix,const int minApiLevel)34 static void write_annotations(FILE* out, int argIndex,
35 const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet,
36 const string& methodPrefix, const string& methodSuffix,
37 const int minApiLevel) {
38 FieldNumberToAtomDeclSet::const_iterator fieldNumberToAtomDeclSetIt =
39 fieldNumberToAtomDeclSet.find(argIndex);
40 if (fieldNumberToAtomDeclSet.end() == fieldNumberToAtomDeclSetIt) {
41 return;
42 }
43 const AtomDeclSet& atomDeclSet = fieldNumberToAtomDeclSetIt->second;
44 const map<AnnotationId, string>& ANNOTATION_ID_CONSTANTS = get_annotation_id_constants();
45 const string constantPrefix = minApiLevel > API_R ? "ASTATSLOG_" : "";
46 for (const shared_ptr<AtomDecl>& atomDecl : atomDeclSet) {
47 const string atomConstant = make_constant_name(atomDecl->name);
48 fprintf(out, " if (%s == code) {\n", atomConstant.c_str());
49 const AnnotationSet& annotations = atomDecl->fieldNumberToAnnotations.at(argIndex);
50 int resetState = -1;
51 int defaultState = -1;
52 for (const shared_ptr<Annotation>& annotation : annotations) {
53 const string& annotationConstant = ANNOTATION_ID_CONSTANTS.at(annotation->annotationId);
54 switch (annotation->type) {
55 case ANNOTATION_TYPE_INT:
56 if (ANNOTATION_ID_TRIGGER_STATE_RESET == annotation->annotationId) {
57 resetState = annotation->value.intValue;
58 } else if (ANNOTATION_ID_DEFAULT_STATE == annotation->annotationId) {
59 defaultState = annotation->value.intValue;
60 } else {
61 fprintf(out, " %saddInt32Annotation(%s%s%s, %d);\n",
62 methodPrefix.c_str(), methodSuffix.c_str(),
63 constantPrefix.c_str(), annotationConstant.c_str(),
64 annotation->value.intValue);
65 }
66 break;
67 case ANNOTATION_TYPE_BOOL:
68 fprintf(out, " %saddBoolAnnotation(%s%s%s, %s);\n", methodPrefix.c_str(),
69 methodSuffix.c_str(), constantPrefix.c_str(),
70 annotationConstant.c_str(),
71 annotation->value.boolValue ? "true" : "false");
72 break;
73 default:
74 break;
75 }
76 }
77 if (defaultState != -1 && resetState != -1) {
78 const string& annotationConstant =
79 ANNOTATION_ID_CONSTANTS.at(ANNOTATION_ID_TRIGGER_STATE_RESET);
80 fprintf(out, " if (arg%d == %d) {\n", argIndex, resetState);
81 fprintf(out, " %saddInt32Annotation(%s%s%s, %d);\n", methodPrefix.c_str(),
82 methodSuffix.c_str(), constantPrefix.c_str(), annotationConstant.c_str(),
83 defaultState);
84 fprintf(out, " }\n");
85 }
86 fprintf(out, " }\n");
87 }
88 }
89
write_native_method_body(FILE * out,vector<java_type_t> & signature,const FieldNumberToAtomDeclSet & fieldNumberToAtomDeclSet,const AtomDecl & attributionDecl,const int minApiLevel)90 static int write_native_method_body(FILE* out, vector<java_type_t>& signature,
91 const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet,
92 const AtomDecl& attributionDecl, const int minApiLevel) {
93 int argIndex = 1;
94 fprintf(out, " AStatsEvent_setAtomId(event, code);\n");
95 write_annotations(out, ATOM_ID_FIELD_NUMBER, fieldNumberToAtomDeclSet, "AStatsEvent_",
96 "event, ", minApiLevel);
97 for (vector<java_type_t>::const_iterator arg = signature.begin();
98 arg != signature.end(); arg++) {
99 switch (*arg) {
100 case JAVA_TYPE_ATTRIBUTION_CHAIN: {
101 const char* uidName = attributionDecl.fields.front().name.c_str();
102 const char* tagName = attributionDecl.fields.back().name.c_str();
103 fprintf(out,
104 " AStatsEvent_writeAttributionChain(event, "
105 "reinterpret_cast<const uint32_t*>(%s), %s.data(), "
106 "static_cast<uint8_t>(%s_length));\n",
107 uidName, tagName, uidName);
108 break;
109 }
110 case JAVA_TYPE_BYTE_ARRAY:
111 fprintf(out,
112 " AStatsEvent_writeByteArray(event, "
113 "reinterpret_cast<const uint8_t*>(arg%d.arg), "
114 "arg%d.arg_length);\n",
115 argIndex, argIndex);
116 break;
117 case JAVA_TYPE_BOOLEAN:
118 fprintf(out, " AStatsEvent_writeBool(event, arg%d);\n", argIndex);
119 break;
120 case JAVA_TYPE_INT: // Fall through.
121 case JAVA_TYPE_ENUM:
122 fprintf(out, " AStatsEvent_writeInt32(event, arg%d);\n", argIndex);
123 break;
124 case JAVA_TYPE_FLOAT:
125 fprintf(out, " AStatsEvent_writeFloat(event, arg%d);\n", argIndex);
126 break;
127 case JAVA_TYPE_LONG:
128 fprintf(out, " AStatsEvent_writeInt64(event, arg%d);\n", argIndex);
129 break;
130 case JAVA_TYPE_STRING:
131 fprintf(out, " AStatsEvent_writeString(event, arg%d);\n", argIndex);
132 break;
133 default:
134 // Unsupported types: OBJECT, DOUBLE, KEY_VALUE_PAIRS
135 fprintf(stderr, "Encountered unsupported type.");
136 return 1;
137 }
138 write_annotations(out, argIndex, fieldNumberToAtomDeclSet, "AStatsEvent_",
139 "event, ", minApiLevel);
140 argIndex++;
141 }
142 return 0;
143 }
144
write_native_stats_write_methods(FILE * out,const SignatureInfoMap & signatureInfoMap,const AtomDecl & attributionDecl,const int minApiLevel)145 static int write_native_stats_write_methods(FILE* out, const SignatureInfoMap& signatureInfoMap,
146 const AtomDecl& attributionDecl,
147 const int minApiLevel) {
148 fprintf(out, "\n");
149 for (auto signatureInfoMapIt = signatureInfoMap.begin();
150 signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
151 vector<java_type_t> signature = signatureInfoMapIt->first;
152 const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet = signatureInfoMapIt->second;
153 // Key value pairs not supported in native.
154 if (std::find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) !=
155 signature.end()) {
156 continue;
157 }
158 write_native_method_signature(out, "int stats_write(", signature, attributionDecl, " {");
159
160 // Write method body.
161 if (minApiLevel == API_Q) {
162 int argIndex = 1;
163 fprintf(out, " StatsEventCompat event;\n");
164 fprintf(out, " event.setAtomId(code);\n");
165 write_annotations(out, ATOM_ID_FIELD_NUMBER, fieldNumberToAtomDeclSet, "event.", "",
166 minApiLevel);
167 for (vector<java_type_t>::const_iterator arg = signature.begin();
168 arg != signature.end(); arg++) {
169 switch (*arg) {
170 case JAVA_TYPE_ATTRIBUTION_CHAIN: {
171 const char* uidName = attributionDecl.fields.front().name.c_str();
172 const char* tagName = attributionDecl.fields.back().name.c_str();
173 fprintf(out, " event.writeAttributionChain(%s, %s_length, %s);\n",
174 uidName, uidName, tagName);
175 break;
176 }
177 case JAVA_TYPE_BYTE_ARRAY:
178 fprintf(out, " event.writeByteArray(arg%d.arg, arg%d.arg_length);\n",
179 argIndex, argIndex);
180 break;
181 case JAVA_TYPE_BOOLEAN:
182 fprintf(out, " event.writeBool(arg%d);\n", argIndex);
183 break;
184 case JAVA_TYPE_INT: // Fall through.
185 case JAVA_TYPE_ENUM:
186 fprintf(out, " event.writeInt32(arg%d);\n", argIndex);
187 break;
188 case JAVA_TYPE_FLOAT:
189 fprintf(out, " event.writeFloat(arg%d);\n", argIndex);
190 break;
191 case JAVA_TYPE_LONG:
192 fprintf(out, " event.writeInt64(arg%d);\n", argIndex);
193 break;
194 case JAVA_TYPE_STRING:
195 fprintf(out, " event.writeString(arg%d);\n", argIndex);
196 break;
197 default:
198 // Unsupported types: OBJECT, DOUBLE, KEY_VALUE_PAIRS.
199 fprintf(stderr, "Encountered unsupported type.");
200 return 1;
201 }
202 write_annotations(out, argIndex, fieldNumberToAtomDeclSet, "event.", "",
203 minApiLevel);
204 argIndex++;
205 }
206 fprintf(out, " return event.writeToSocket();\n"); // end method body.
207 } else {
208 fprintf(out, " AStatsEvent* event = AStatsEvent_obtain();\n");
209 int ret = write_native_method_body(out, signature, fieldNumberToAtomDeclSet,
210 attributionDecl, minApiLevel);
211 if (ret != 0) {
212 return ret;
213 }
214 fprintf(out, " const int ret = AStatsEvent_write(event);\n");
215 fprintf(out, " AStatsEvent_release(event);\n");
216 fprintf(out, " return ret;\n"); // end method body.
217 }
218 fprintf(out, "}\n\n"); // end method.
219 }
220 return 0;
221 }
222
write_native_stats_write_non_chained_methods(FILE * out,const SignatureInfoMap & signatureInfoMap,const AtomDecl & attributionDecl)223 static void write_native_stats_write_non_chained_methods(FILE* out,
224 const SignatureInfoMap& signatureInfoMap,
225 const AtomDecl& attributionDecl) {
226 fprintf(out, "\n");
227 for (auto signature_it = signatureInfoMap.begin();
228 signature_it != signatureInfoMap.end(); signature_it++) {
229 vector<java_type_t> signature = signature_it->first;
230 // Key value pairs not supported in native.
231 if (std::find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) !=
232 signature.end()) {
233 continue;
234 }
235
236 write_native_method_signature(out, "int stats_write_non_chained(", signature,
237 attributionDecl, " {");
238
239 vector<java_type_t> newSignature;
240
241 // First two args form the attribution node so size goes down by 1.
242 newSignature.reserve(signature.size() - 1);
243
244 // First arg is Attribution Chain.
245 newSignature.push_back(JAVA_TYPE_ATTRIBUTION_CHAIN);
246
247 // Followed by the originial signature except the first 2 args.
248 newSignature.insert(newSignature.end(), signature.begin() + 2, signature.end());
249
250 const char* uidName = attributionDecl.fields.front().name.c_str();
251 const char* tagName = attributionDecl.fields.back().name.c_str();
252 fprintf(out, " const int32_t* %s = &arg1;\n", uidName);
253 fprintf(out, " const size_t %s_length = 1;\n", uidName);
254 fprintf(out, " const std::vector<char const*> %s(1, arg2);\n", tagName);
255 fprintf(out, " return ");
256 write_native_method_call(out, "stats_write", newSignature, attributionDecl, 2);
257
258 fprintf(out, "}\n\n");
259 }
260 }
261
write_native_build_stats_event_methods(FILE * out,const SignatureInfoMap & signatureInfoMap,const AtomDecl & attributionDecl,const int minApiLevel)262 static int write_native_build_stats_event_methods(FILE* out,
263 const SignatureInfoMap& signatureInfoMap,
264 const AtomDecl& attributionDecl,
265 const int minApiLevel) {
266 fprintf(out, "\n");
267 for (auto signatureInfoMapIt = signatureInfoMap.begin();
268 signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
269 vector<java_type_t> signature = signatureInfoMapIt->first;
270 const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet = signatureInfoMapIt->second;
271 // Key value pairs not supported in native.
272 if (std::find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) !=
273 signature.end()) {
274 continue;
275 }
276 write_native_method_signature(out, "void addAStatsEvent(AStatsEventList* pulled_data, ",
277 signature, attributionDecl, " {");
278
279 fprintf(out, " AStatsEvent* event = AStatsEventList_addStatsEvent(pulled_data);\n");
280 int ret = write_native_method_body(out, signature, fieldNumberToAtomDeclSet,
281 attributionDecl, minApiLevel);
282 if (ret != 0) {
283 return ret;
284 }
285 fprintf(out, " AStatsEvent_build(event);\n"); // end method body.
286
287 fprintf(out, "}\n\n"); // end method.
288 }
289 return 0;
290 }
291
write_native_method_header(FILE * out,const string & methodName,const SignatureInfoMap & signatureInfoMap,const AtomDecl & attributionDecl)292 static void write_native_method_header(FILE* out, const string& methodName,
293 const SignatureInfoMap& signatureInfoMap,
294 const AtomDecl& attributionDecl) {
295 for (auto signatureInfoMapIt = signatureInfoMap.begin();
296 signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
297 vector<java_type_t> signature = signatureInfoMapIt->first;
298
299 // Key value pairs not supported in native.
300 if (std::find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) !=
301 signature.end()) {
302 continue;
303 }
304 write_native_method_signature(out, methodName, signature, attributionDecl, ";");
305 }
306 }
307
write_stats_log_cpp(FILE * out,const Atoms & atoms,const AtomDecl & attributionDecl,const string & cppNamespace,const string & importHeader,const int minApiLevel)308 int write_stats_log_cpp(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
309 const string& cppNamespace, const string& importHeader,
310 const int minApiLevel) {
311 // Print prelude
312 fprintf(out, "// This file is autogenerated\n");
313 fprintf(out, "\n");
314
315 fprintf(out, "#include <%s>\n", importHeader.c_str());
316 if (minApiLevel == API_Q) {
317 fprintf(out, "#include <StatsEventCompat.h>\n");
318 } else {
319 fprintf(out, "#include <stats_event.h>\n");
320 }
321
322 if (minApiLevel > API_R) {
323 fprintf(out, "#include <stats_annotations.h>\n");
324 }
325
326 if (minApiLevel > API_Q && !atoms.pulledAtomsSignatureInfoMap.empty()) {
327 fprintf(out, "#include <stats_pull_atom_callback.h>\n");
328 }
329
330
331
332 fprintf(out, "\n");
333 write_namespace(out, cppNamespace);
334
335 write_native_stats_write_methods(out, atoms.signatureInfoMap, attributionDecl, minApiLevel);
336 write_native_stats_write_non_chained_methods(out, atoms.nonChainedSignatureInfoMap,
337 attributionDecl);
338 write_native_build_stats_event_methods(out, atoms.pulledAtomsSignatureInfoMap,
339 attributionDecl, minApiLevel);
340
341 // Print footer
342 fprintf(out, "\n");
343 write_closing_namespace(out, cppNamespace);
344
345 return 0;
346 }
347
write_stats_log_header(FILE * out,const Atoms & atoms,const AtomDecl & attributionDecl,const string & cppNamespace,const int minApiLevel)348 int write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
349 const string& cppNamespace, const int minApiLevel) {
350 // Print prelude
351 fprintf(out, "// This file is autogenerated\n");
352 fprintf(out, "\n");
353 fprintf(out, "#pragma once\n");
354 fprintf(out, "\n");
355 fprintf(out, "#include <stdint.h>\n");
356 fprintf(out, "#include <vector>\n");
357 fprintf(out, "#include <map>\n");
358 fprintf(out, "#include <set>\n");
359 if (!atoms.pulledAtomsSignatureInfoMap.empty()) {
360 fprintf(out, "#include <stats_pull_atom_callback.h>\n");
361 }
362 fprintf(out, "\n");
363
364 write_namespace(out, cppNamespace);
365 fprintf(out, "\n");
366 fprintf(out, "/*\n");
367 fprintf(out, " * API For logging statistics events.\n");
368 fprintf(out, " */\n");
369 fprintf(out, "\n");
370
371 write_native_atom_constants(out, atoms, attributionDecl);
372
373 // Print constants for the enum values.
374 fprintf(out, "//\n");
375 fprintf(out, "// Constants for enum values\n");
376 fprintf(out, "//\n\n");
377 for (AtomDeclSet::const_iterator atomIt = atoms.decls.begin(); atomIt != atoms.decls.end();
378 atomIt++) {
379 for (vector<AtomField>::const_iterator field = (*atomIt)->fields.begin();
380 field != (*atomIt)->fields.end(); field++) {
381 if (field->javaType == JAVA_TYPE_ENUM) {
382 fprintf(out, "// Values for %s.%s\n", (*atomIt)->message.c_str(),
383 field->name.c_str());
384 for (map<int, string>::const_iterator value = field->enumValues.begin();
385 value != field->enumValues.end(); value++) {
386 fprintf(out, "const int32_t %s__%s__%s = %d;\n",
387 make_constant_name((*atomIt)->message).c_str(),
388 make_constant_name(field->name).c_str(),
389 make_constant_name(value->second).c_str(), value->first);
390 }
391 fprintf(out, "\n");
392 }
393 }
394 }
395
396 if (minApiLevel <= API_R) {
397 write_native_annotation_constants(out);
398 }
399
400 fprintf(out, "struct BytesField {\n");
401 fprintf(out,
402 " BytesField(char const* array, size_t len) : arg(array), "
403 "arg_length(len) {}\n");
404 fprintf(out, " char const* arg;\n");
405 fprintf(out, " size_t arg_length;\n");
406 fprintf(out, "};\n");
407 fprintf(out, "\n");
408
409 // Print write methods
410 fprintf(out, "//\n");
411 fprintf(out, "// Write methods\n");
412 fprintf(out, "//\n");
413 write_native_method_header(out, "int stats_write(", atoms.signatureInfoMap, attributionDecl);
414 fprintf(out, "\n");
415
416 fprintf(out, "//\n");
417 fprintf(out, "// Write flattened methods\n");
418 fprintf(out, "//\n");
419 write_native_method_header(out, "int stats_write_non_chained(", atoms.nonChainedSignatureInfoMap,
420 attributionDecl);
421 fprintf(out, "\n");
422
423 // Print pulled atoms methods.
424 fprintf(out, "//\n");
425 fprintf(out, "// Add AStatsEvent methods\n");
426 fprintf(out, "//\n");
427 write_native_method_header(out, "void addAStatsEvent(AStatsEventList* pulled_data, ",
428 atoms.pulledAtomsSignatureInfoMap,
429 attributionDecl);
430
431 fprintf(out, "\n");
432 write_closing_namespace(out, cppNamespace);
433
434 return 0;
435 }
436
437 } // namespace stats_log_api_gen
438 } // namespace android
439