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 <stdio.h>
20
21 #include "Collation.h"
22 #include "utils.h"
23
24 namespace android {
25 namespace stats_log_api_gen {
26
write_native_annotation_constants(FILE * out)27 static void write_native_annotation_constants(FILE* out) {
28 fprintf(out, "// Annotation constants.\n");
29
30 const map<AnnotationId, AnnotationStruct>& ANNOTATION_ID_CONSTANTS =
31 get_annotation_id_constants(ANNOTATION_CONSTANT_NAME_PREFIX);
32 for (const auto& [id, annotation] : ANNOTATION_ID_CONSTANTS) {
33 fprintf(out, "const uint8_t %s = %hhu;\n", annotation.name.c_str(), id);
34 }
35 fprintf(out, "\n");
36 }
37
write_annotations(FILE * out,int argIndex,const FieldNumberToAtomDeclSet & fieldNumberToAtomDeclSet,const string & methodPrefix,const string & methodSuffix,const int minApiLevel)38 static void write_annotations(FILE* out, int argIndex,
39 const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet,
40 const string& methodPrefix, const string& methodSuffix,
41 const int minApiLevel) {
42 const FieldNumberToAtomDeclSet::const_iterator fieldNumberToAtomDeclSetIt =
43 fieldNumberToAtomDeclSet.find(argIndex);
44 if (fieldNumberToAtomDeclSet.end() == fieldNumberToAtomDeclSetIt) {
45 return;
46 }
47 const AtomDeclSet& atomDeclSet = fieldNumberToAtomDeclSetIt->second;
48 const map<AnnotationId, AnnotationStruct>& ANNOTATION_ID_CONSTANTS =
49 get_annotation_id_constants(ANNOTATION_CONSTANT_NAME_PREFIX);
50 const string constantPrefix = minApiLevel > API_R ? "ASTATSLOG_" : "";
51 for (const shared_ptr<AtomDecl>& atomDecl : atomDeclSet) {
52 const string atomConstant = make_constant_name(atomDecl->name);
53 fprintf(out, " if (%s == code) {\n", atomConstant.c_str());
54 const AnnotationSet& annotations = atomDecl->fieldNumberToAnnotations.at(argIndex);
55 int resetState = -1;
56 int defaultState = -1;
57 for (const shared_ptr<Annotation>& annotation : annotations) {
58 const string& annotationConstant =
59 ANNOTATION_ID_CONSTANTS.at(annotation->annotationId).name;
60 switch (annotation->type) {
61 case ANNOTATION_TYPE_INT:
62 if (ANNOTATION_ID_TRIGGER_STATE_RESET == annotation->annotationId) {
63 resetState = annotation->value.intValue;
64 } else if (ANNOTATION_ID_DEFAULT_STATE == annotation->annotationId) {
65 defaultState = annotation->value.intValue;
66 } else if (ANNOTATION_ID_RESTRICTION_CATEGORY == annotation->annotationId) {
67 fprintf(out, " %saddInt32Annotation(%s%s%s,\n",
68 methodPrefix.c_str(), methodSuffix.c_str(), constantPrefix.c_str(),
69 annotationConstant.c_str());
70 fprintf(out, " %s%s);\n",
71 constantPrefix.c_str(),
72 get_restriction_category_str(annotation->value.intValue).c_str());
73 } else {
74 fprintf(out, " %saddInt32Annotation(%s%s%s, %d);\n",
75 methodPrefix.c_str(), methodSuffix.c_str(), constantPrefix.c_str(),
76 annotationConstant.c_str(), annotation->value.intValue);
77 }
78 break;
79 case ANNOTATION_TYPE_BOOL:
80 fprintf(out, " %saddBoolAnnotation(%s%s%s, %s);\n", methodPrefix.c_str(),
81 methodSuffix.c_str(), constantPrefix.c_str(),
82 annotationConstant.c_str(),
83 annotation->value.boolValue ? "true" : "false");
84 break;
85 default:
86 break;
87 }
88 }
89 if (defaultState != -1 && resetState != -1) {
90 const string& annotationConstant =
91 ANNOTATION_ID_CONSTANTS.at(ANNOTATION_ID_TRIGGER_STATE_RESET).name;
92 fprintf(out, " if (arg%d == %d) {\n", argIndex, resetState);
93 fprintf(out, " %saddInt32Annotation(%s%s%s, %d);\n", methodPrefix.c_str(),
94 methodSuffix.c_str(), constantPrefix.c_str(), annotationConstant.c_str(),
95 defaultState);
96 fprintf(out, " }\n");
97 }
98 fprintf(out, " }\n");
99 }
100 }
101
write_native_method_body(FILE * out,const vector<java_type_t> & signature,const FieldNumberToAtomDeclSet & fieldNumberToAtomDeclSet,const AtomDecl & attributionDecl,const int minApiLevel)102 static int write_native_method_body(FILE* out, const vector<java_type_t>& signature,
103 const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet,
104 const AtomDecl& attributionDecl, const int minApiLevel) {
105 int argIndex = 1;
106 fprintf(out, " AStatsEvent_setAtomId(event, code);\n");
107 write_annotations(out, ATOM_ID_FIELD_NUMBER, fieldNumberToAtomDeclSet, "AStatsEvent_",
108 "event, ", minApiLevel);
109 for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
110 arg++) {
111 if (minApiLevel < API_T && is_repeated_field(*arg)) {
112 fprintf(stderr, "Found repeated field type with min api level < T.");
113 return 1;
114 }
115 switch (*arg) {
116 case JAVA_TYPE_ATTRIBUTION_CHAIN: {
117 const char* uidName = attributionDecl.fields.front().name.c_str();
118 const char* tagName = attributionDecl.fields.back().name.c_str();
119 fprintf(out,
120 " AStatsEvent_writeAttributionChain(event, "
121 "reinterpret_cast<const uint32_t*>(%s), %s.data(), "
122 "static_cast<uint8_t>(%s_length));\n",
123 uidName, tagName, uidName);
124 break;
125 }
126 case JAVA_TYPE_BYTE_ARRAY:
127 fprintf(out,
128 " AStatsEvent_writeByteArray(event, "
129 "reinterpret_cast<const uint8_t*>(arg%d.arg), "
130 "arg%d.arg_length);\n",
131 argIndex, argIndex);
132 break;
133 case JAVA_TYPE_BOOLEAN:
134 fprintf(out, " AStatsEvent_writeBool(event, arg%d);\n", argIndex);
135 break;
136 case JAVA_TYPE_INT:
137 [[fallthrough]];
138 case JAVA_TYPE_ENUM:
139 fprintf(out, " AStatsEvent_writeInt32(event, arg%d);\n", argIndex);
140 break;
141 case JAVA_TYPE_FLOAT:
142 fprintf(out, " AStatsEvent_writeFloat(event, arg%d);\n", argIndex);
143 break;
144 case JAVA_TYPE_LONG:
145 fprintf(out, " AStatsEvent_writeInt64(event, arg%d);\n", argIndex);
146 break;
147 case JAVA_TYPE_STRING:
148 fprintf(out, " AStatsEvent_writeString(event, arg%d);\n", argIndex);
149 break;
150 case JAVA_TYPE_BOOLEAN_ARRAY:
151 fprintf(out, " AStatsEvent_writeBoolArray(event, arg%d, arg%d_length);\n",
152 argIndex, argIndex);
153 break;
154 case JAVA_TYPE_INT_ARRAY:
155 [[fallthrough]];
156 case JAVA_TYPE_ENUM_ARRAY:
157 fprintf(out,
158 " AStatsEvent_writeInt32Array(event, arg%d.data(), arg%d.size());\n",
159 argIndex, argIndex);
160 break;
161 case JAVA_TYPE_FLOAT_ARRAY:
162 fprintf(out,
163 " AStatsEvent_writeFloatArray(event, arg%d.data(), arg%d.size());\n",
164 argIndex, argIndex);
165 break;
166 case JAVA_TYPE_LONG_ARRAY:
167 fprintf(out,
168 " AStatsEvent_writeInt64Array(event, arg%d.data(), arg%d.size());\n",
169 argIndex, argIndex);
170 break;
171 case JAVA_TYPE_STRING_ARRAY:
172 fprintf(out,
173 " AStatsEvent_writeStringArray(event, arg%d.data(), arg%d.size());\n",
174 argIndex, argIndex);
175 break;
176
177 default:
178 // Unsupported types: OBJECT, DOUBLE
179 fprintf(stderr, "Encountered unsupported type.\n");
180 return 1;
181 }
182 write_annotations(out, argIndex, fieldNumberToAtomDeclSet, "AStatsEvent_", "event, ",
183 minApiLevel);
184 argIndex++;
185 }
186 return 0;
187 }
188
write_native_method_call(FILE * out,const string & methodName,const vector<java_type_t> & signature,const AtomDecl & attributionDecl,int argIndex)189 static void write_native_method_call(FILE* out, const string& methodName,
190 const vector<java_type_t>& signature,
191 const AtomDecl& attributionDecl, int argIndex) {
192 fprintf(out, "%s(code", methodName.c_str());
193 for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
194 arg++) {
195 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
196 for (const auto& chainField : attributionDecl.fields) {
197 if (chainField.javaType == JAVA_TYPE_STRING) {
198 fprintf(out, ", %s", chainField.name.c_str());
199 } else {
200 fprintf(out, ", %s, %s_length", chainField.name.c_str(),
201 chainField.name.c_str());
202 }
203 }
204 } else {
205 fprintf(out, ", arg%d", argIndex);
206
207 if (*arg == JAVA_TYPE_BOOLEAN_ARRAY) {
208 fprintf(out, ", arg%d_length", argIndex);
209 }
210 }
211 argIndex++;
212 }
213 fprintf(out, ");\n");
214 }
215
write_native_stats_write_methods(FILE * out,const SignatureInfoMap & signatureInfoMap,const AtomDecl & attributionDecl,const int minApiLevel,bool bootstrap)216 static int write_native_stats_write_methods(FILE* out, const SignatureInfoMap& signatureInfoMap,
217 const AtomDecl& attributionDecl, const int minApiLevel,
218 bool bootstrap) {
219 fprintf(out, "\n");
220 for (const auto& [signature, fieldNumberToAtomDeclSet] : signatureInfoMap) {
221 write_native_method_signature(out, "int stats_write(", signature, attributionDecl, " {");
222
223 // Write method body.
224 if (bootstrap) {
225 fprintf(out, " ::android::os::StatsBootstrapAtom atom;\n");
226 fprintf(out, " atom.atomId = code;\n");
227 const FieldNumberToAtomDeclSet::const_iterator fieldNumberToAtomDeclSetIt =
228 fieldNumberToAtomDeclSet.find(ATOM_ID_FIELD_NUMBER);
229 if (fieldNumberToAtomDeclSet.end() != fieldNumberToAtomDeclSetIt) {
230 fprintf(stderr, "Top-level bootstrap atoms do not support annotations\n");
231 return 1;
232 }
233 int argIndex = 1;
234 const char* atomVal = "::android::os::StatsBootstrapAtomValue";
235 const char* primitiveVal = "::android::os::StatsBootstrapAtomValue::Primitive::";
236 const char* annotationVal = "::android::os::StatsBootstrapAtomValue::Annotation";
237 const char* annotationIdVal =
238 "::android::os::StatsBootstrapAtomValue::Annotation::Id::";
239 const char* annotationPrimitiveVal =
240 "::android::os::StatsBootstrapAtomValue::Annotation::Primitive::";
241 for (vector<java_type_t>::const_iterator arg = signature.begin();
242 arg != signature.end(); arg++) {
243 fprintf(out, " %s value%d;\n", atomVal, argIndex);
244 switch (*arg) {
245 case JAVA_TYPE_BYTE_ARRAY:
246 fprintf(out,
247 " const uint8_t* arg%dbyte = reinterpret_cast<const "
248 "uint8_t*>(arg%d.arg);\n",
249 argIndex, argIndex);
250 fprintf(out,
251 " value%d.value = %smake<%sbytesValue>(std::vector(arg%dbyte, "
252 "arg%dbyte + arg%d.arg_length));\n",
253 argIndex, primitiveVal, primitiveVal, argIndex, argIndex, argIndex);
254 break;
255 case JAVA_TYPE_BOOLEAN:
256 fprintf(out, " value%d.value = %smake<%sboolValue>(arg%d);\n", argIndex,
257 primitiveVal, primitiveVal, argIndex);
258 break;
259 case JAVA_TYPE_INT: // Fall through.
260 case JAVA_TYPE_ENUM:
261 fprintf(out, " value%d.value = %smake<%sintValue>(arg%d);\n", argIndex,
262 primitiveVal, primitiveVal, argIndex);
263 break;
264 case JAVA_TYPE_FLOAT:
265 fprintf(out, " value%d.value = %smake<%sfloatValue>(arg%d);\n", argIndex,
266 primitiveVal, primitiveVal, argIndex);
267 break;
268 case JAVA_TYPE_LONG:
269 fprintf(out, " value%d.value = %smake<%slongValue>(arg%d);\n", argIndex,
270 primitiveVal, primitiveVal, argIndex);
271 break;
272 case JAVA_TYPE_STRING:
273 fprintf(out,
274 " value%d.value = %smake<%sstringValue>("
275 "::android::String16(arg%d));\n",
276 argIndex, primitiveVal, primitiveVal, argIndex);
277 break;
278 case JAVA_TYPE_STRING_ARRAY:
279 fprintf(out,
280 " value%d.value = %smake<%sstringArrayValue>("
281 "arg%d.begin(), arg%d.end());\n",
282 argIndex, primitiveVal, primitiveVal, argIndex, argIndex);
283 break;
284 default:
285 // Unsupported types: OBJECT, DOUBLE, ATTRIBUTION_CHAIN,
286 // and all repeated fields
287 fprintf(stderr, "Encountered unsupported type. %d, %d\n", *arg, argIndex);
288 return 1;
289 }
290 const FieldNumberToAtomDeclSet::const_iterator fieldNumberToAtomDeclSetIt =
291 fieldNumberToAtomDeclSet.find(argIndex);
292 // Scrub for any annotations that aren't UIDs
293 if (fieldNumberToAtomDeclSet.end() != fieldNumberToAtomDeclSetIt) {
294 const AtomDeclSet& atomDeclSet = fieldNumberToAtomDeclSetIt->second;
295 for (const shared_ptr<AtomDecl>& atomDecl : atomDeclSet) {
296 const string atomConstant = make_constant_name(atomDecl->name);
297 fprintf(out, " if (%s == code) {\n", atomConstant.c_str());
298 int32_t annotationIndex = 0;
299 for (const shared_ptr<Annotation>& annotation :
300 atomDecl->fieldNumberToAnnotations.at(argIndex)) {
301 if (annotation->annotationId != ANNOTATION_ID_IS_UID) {
302 fprintf(stderr,
303 "Bootstrap atom fields do not support non-UID "
304 "annotations\n");
305 return 1;
306 }
307
308 if (annotationIndex >= 1) {
309 fprintf(stderr,
310 "Bootstrap atom fields do not support multiple "
311 "annotations\n");
312 return 1;
313 }
314
315 fprintf(out, " %s annotation%d;\n", annotationVal,
316 annotationIndex);
317 fprintf(out, " annotation%d.id = %sIS_UID;\n", annotationIndex,
318 annotationIdVal);
319 fprintf(out,
320 " annotation%d.value = "
321 "%smake<%sboolValue>(true);\n",
322 annotationIndex, annotationPrimitiveVal,
323 annotationPrimitiveVal);
324 fprintf(out, " value%d.annotations.push_back(annotation%d);\n",
325 argIndex, annotationIndex);
326 annotationIndex++;
327 }
328 fprintf(out, " }\n");
329 }
330 }
331 fprintf(out, " atom.values.push_back(value%d);\n", argIndex);
332 argIndex++;
333 }
334 fprintf(out,
335 " bool success = "
336 "::android::os::stats::StatsBootstrapAtomClient::reportBootstrapAtom(atom);\n");
337 fprintf(out, " return success ? 0 : -1;\n");
338
339 } else if (minApiLevel == API_Q) {
340 int argIndex = 1;
341 fprintf(out, " StatsEventCompat event;\n");
342 fprintf(out, " event.setAtomId(code);\n");
343 write_annotations(out, ATOM_ID_FIELD_NUMBER, fieldNumberToAtomDeclSet, "event.", "",
344 minApiLevel);
345 for (vector<java_type_t>::const_iterator arg = signature.begin();
346 arg != signature.end(); arg++) {
347 switch (*arg) {
348 case JAVA_TYPE_ATTRIBUTION_CHAIN: {
349 const char* uidName = attributionDecl.fields.front().name.c_str();
350 const char* tagName = attributionDecl.fields.back().name.c_str();
351 fprintf(out, " event.writeAttributionChain(%s, %s_length, %s);\n",
352 uidName, uidName, tagName);
353 break;
354 }
355 case JAVA_TYPE_BYTE_ARRAY:
356 fprintf(out, " event.writeByteArray(arg%d.arg, arg%d.arg_length);\n",
357 argIndex, argIndex);
358 break;
359 case JAVA_TYPE_BOOLEAN:
360 fprintf(out, " event.writeBool(arg%d);\n", argIndex);
361 break;
362 case JAVA_TYPE_INT: // Fall through.
363 case JAVA_TYPE_ENUM:
364 fprintf(out, " event.writeInt32(arg%d);\n", argIndex);
365 break;
366 case JAVA_TYPE_FLOAT:
367 fprintf(out, " event.writeFloat(arg%d);\n", argIndex);
368 break;
369 case JAVA_TYPE_LONG:
370 fprintf(out, " event.writeInt64(arg%d);\n", argIndex);
371 break;
372 case JAVA_TYPE_STRING:
373 fprintf(out, " event.writeString(arg%d);\n", argIndex);
374 break;
375 default:
376 // Unsupported types: OBJECT, DOUBLE, and all repeated
377 // fields.
378 fprintf(stderr, "Encountered unsupported type.\n");
379 return 1;
380 }
381 write_annotations(out, argIndex, fieldNumberToAtomDeclSet, "event.", "",
382 minApiLevel);
383 argIndex++;
384 }
385 fprintf(out, " return event.writeToSocket();\n"); // end method body.
386 } else {
387 fprintf(out, " AStatsEvent* event = AStatsEvent_obtain();\n");
388 const int ret = write_native_method_body(out, signature, fieldNumberToAtomDeclSet,
389 attributionDecl, minApiLevel);
390 if (ret != 0) {
391 return ret;
392 }
393 fprintf(out, " const int ret = AStatsEvent_write(event);\n");
394 fprintf(out, " AStatsEvent_release(event);\n");
395 fprintf(out, " return ret;\n"); // end method body.
396 }
397 fprintf(out, "}\n\n"); // end method.
398 }
399 return 0;
400 }
401
write_native_stats_write_non_chained_methods(FILE * out,const SignatureInfoMap & signatureInfoMap,const AtomDecl & attributionDecl)402 static void write_native_stats_write_non_chained_methods(FILE* out,
403 const SignatureInfoMap& signatureInfoMap,
404 const AtomDecl& attributionDecl) {
405 fprintf(out, "\n");
406 for (const auto& [signature, _] : signatureInfoMap) {
407 write_native_method_signature(out, "int stats_write_non_chained(", signature,
408 attributionDecl, " {");
409
410 vector<java_type_t> newSignature;
411
412 // First two args form the attribution node so size goes down by 1.
413 newSignature.reserve(signature.size() - 1);
414
415 // First arg is Attribution Chain.
416 newSignature.push_back(JAVA_TYPE_ATTRIBUTION_CHAIN);
417
418 // Followed by the originial signature except the first 2 args.
419 newSignature.insert(newSignature.end(), signature.begin() + 2, signature.end());
420
421 const char* uidName = attributionDecl.fields.front().name.c_str();
422 const char* tagName = attributionDecl.fields.back().name.c_str();
423 fprintf(out, " const int32_t* %s = &arg1;\n", uidName);
424 fprintf(out, " const size_t %s_length = 1;\n", uidName);
425 fprintf(out, " const std::vector<char const*> %s(1, arg2);\n", tagName);
426 fprintf(out, " return ");
427 write_native_method_call(out, "stats_write", newSignature, attributionDecl, 2);
428
429 fprintf(out, "}\n\n");
430 }
431 }
432
write_native_build_stats_event_methods(FILE * out,const SignatureInfoMap & signatureInfoMap,const AtomDecl & attributionDecl,const int minApiLevel)433 static int write_native_build_stats_event_methods(FILE* out,
434 const SignatureInfoMap& signatureInfoMap,
435 const AtomDecl& attributionDecl,
436 const int minApiLevel) {
437 fprintf(out, "\n");
438 for (const auto& [signature, fieldNumberToAtomDeclSet] : signatureInfoMap) {
439 write_native_method_signature(out, "void addAStatsEvent(AStatsEventList* pulled_data, ",
440 signature, attributionDecl, " {");
441
442 fprintf(out, " AStatsEvent* event = AStatsEventList_addStatsEvent(pulled_data);\n");
443 const int ret = write_native_method_body(out, signature, fieldNumberToAtomDeclSet,
444 attributionDecl, minApiLevel);
445 if (ret != 0) {
446 return ret;
447 }
448 fprintf(out, " AStatsEvent_build(event);\n"); // end method body.
449
450 fprintf(out, "}\n\n"); // end method.
451 }
452 return 0;
453 }
454
write_stats_log_cpp(FILE * out,const Atoms & atoms,const AtomDecl & attributionDecl,const string & cppNamespace,const string & importHeader,const int minApiLevel,bool bootstrap)455 int write_stats_log_cpp(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
456 const string& cppNamespace, const string& importHeader,
457 const int minApiLevel, bool bootstrap) {
458 // Print prelude
459 fprintf(out, "// This file is autogenerated\n");
460 fprintf(out, "\n");
461
462 fprintf(out, "#include <%s>\n", importHeader.c_str());
463 if (!bootstrap) {
464 if (minApiLevel == API_Q) {
465 fprintf(out, "#include <StatsEventCompat.h>\n");
466 } else {
467 fprintf(out, "#include <stats_event.h>\n");
468 }
469
470 if (minApiLevel > API_R) {
471 fprintf(out, "#include <stats_annotations.h>\n");
472 }
473
474 if (minApiLevel > API_Q && !atoms.pulledAtomsSignatureInfoMap.empty()) {
475 fprintf(out, "#include <stats_pull_atom_callback.h>\n");
476 }
477 } else {
478 fprintf(out, "#include <StatsBootstrapAtomClient.h>\n");
479 fprintf(out, "#include <android/os/StatsBootstrapAtom.h>\n");
480 fprintf(out, "#include <utils/String16.h>\n");
481 }
482
483 fprintf(out, "\n");
484 write_namespace(out, cppNamespace);
485
486 int ret = write_native_stats_write_methods(out, atoms.signatureInfoMap, attributionDecl,
487 minApiLevel, bootstrap);
488 if (ret != 0) {
489 return ret;
490 }
491 if (!bootstrap) {
492 write_native_stats_write_non_chained_methods(out, atoms.nonChainedSignatureInfoMap,
493 attributionDecl);
494 ret = write_native_build_stats_event_methods(out, atoms.pulledAtomsSignatureInfoMap,
495 attributionDecl, minApiLevel);
496 if (ret != 0) {
497 return ret;
498 }
499 }
500
501 // Print footer
502 fprintf(out, "\n");
503 write_closing_namespace(out, cppNamespace);
504
505 return 0;
506 }
507
write_stats_log_header(FILE * out,const Atoms & atoms,const AtomDecl & attributionDecl,const string & cppNamespace,const int minApiLevel,bool bootstrap)508 int write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
509 const string& cppNamespace, const int minApiLevel, bool bootstrap) {
510 const bool includePull = !atoms.pulledAtomsSignatureInfoMap.empty() && !bootstrap;
511 write_native_header_preamble(out, cppNamespace, includePull, bootstrap);
512 write_native_atom_constants(out, atoms, attributionDecl);
513 write_native_atom_enums(out, atoms);
514
515 if (minApiLevel <= API_R) {
516 write_native_annotation_constants(out);
517 }
518
519 fprintf(out, "struct BytesField {\n");
520 fprintf(out,
521 " BytesField(char const* array, size_t len) : arg(array), "
522 "arg_length(len) {}\n");
523 fprintf(out, " char const* arg;\n");
524 fprintf(out, " size_t arg_length;\n");
525 fprintf(out, "};\n");
526 fprintf(out, "\n");
527
528 // Print write methods
529 fprintf(out, "//\n");
530 fprintf(out, "// Write methods\n");
531 fprintf(out, "//\n");
532 write_native_method_header(out, "int stats_write(", atoms.signatureInfoMap, attributionDecl);
533 fprintf(out, "\n");
534
535 // Attribution chains and pulled atoms are not supported for bootstrap processes.
536 if (!bootstrap) {
537 fprintf(out, "//\n");
538 fprintf(out, "// Write flattened methods\n");
539 fprintf(out, "//\n");
540 write_native_method_header(out, "int stats_write_non_chained(",
541 atoms.nonChainedSignatureInfoMap, attributionDecl);
542 fprintf(out, "\n");
543
544 // Print pulled atoms methods.
545 fprintf(out, "//\n");
546 fprintf(out, "// Add AStatsEvent methods\n");
547 fprintf(out, "//\n");
548 write_native_method_header(out, "void addAStatsEvent(AStatsEventList* pulled_data, ",
549 atoms.pulledAtomsSignatureInfoMap, attributionDecl);
550 fprintf(out, "\n");
551 }
552
553 write_native_header_epilogue(out, cppNamespace);
554
555 return 0;
556 }
557
558 } // namespace stats_log_api_gen
559 } // namespace android
560