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