xref: /aosp_15_r20/frameworks/proto_logging/stats/stats_log_api_gen/native_writer.cpp (revision 64c55175f22a2714b5ba1250098ad9bbc12ec7cd)
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