• 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, 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_signature(FILE * out,const string & signaturePrefix,const vector<java_type_t> & signature,const AtomDecl & attributionDecl,const string & closer)90 static void write_native_method_signature(FILE* out, const string& signaturePrefix,
91                                           const vector<java_type_t>& signature,
92                                           const AtomDecl& attributionDecl, const string& closer) {
93     fprintf(out, "%sint32_t code", signaturePrefix.c_str());
94     int argIndex = 1;
95     for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
96          arg++) {
97         if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
98             for (const auto& chainField : attributionDecl.fields) {
99                 if (chainField.javaType == JAVA_TYPE_STRING) {
100                     fprintf(out, ", const std::vector<%s>& %s", cpp_type_name(chainField.javaType),
101                             chainField.name.c_str());
102                 } else {
103                     fprintf(out, ", const %s* %s, size_t %s_length",
104                             cpp_type_name(chainField.javaType), chainField.name.c_str(),
105                             chainField.name.c_str());
106                 }
107             }
108         } else {
109             fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
110 
111             if (*arg == JAVA_TYPE_BOOLEAN_ARRAY) {
112                 fprintf(out, ", size_t arg%d_length", argIndex);
113             }
114         }
115         argIndex++;
116     }
117     fprintf(out, ")%s\n", closer.c_str());
118 }
119 
write_native_method_body(FILE * out,vector<java_type_t> & signature,const FieldNumberToAtomDeclSet & fieldNumberToAtomDeclSet,const AtomDecl & attributionDecl,const int minApiLevel)120 static int write_native_method_body(FILE* out, vector<java_type_t>& signature,
121                                     const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet,
122                                     const AtomDecl& attributionDecl, const int minApiLevel) {
123     int argIndex = 1;
124     fprintf(out, "    AStatsEvent_setAtomId(event, code);\n");
125     write_annotations(out, ATOM_ID_FIELD_NUMBER, fieldNumberToAtomDeclSet, "AStatsEvent_",
126                       "event, ", minApiLevel);
127     for (vector<java_type_t>::const_iterator arg = signature.begin();
128          arg != signature.end(); arg++) {
129         if (minApiLevel < API_T && is_repeated_field(*arg)) {
130             fprintf(stderr, "Found repeated field type with min api level < T.");
131             return 1;
132         }
133         switch (*arg) {
134             case JAVA_TYPE_ATTRIBUTION_CHAIN: {
135                 const char* uidName = attributionDecl.fields.front().name.c_str();
136                 const char* tagName = attributionDecl.fields.back().name.c_str();
137                 fprintf(out,
138                         "    AStatsEvent_writeAttributionChain(event, "
139                         "reinterpret_cast<const uint32_t*>(%s), %s.data(), "
140                         "static_cast<uint8_t>(%s_length));\n",
141                         uidName, tagName, uidName);
142                 break;
143             }
144             case JAVA_TYPE_BYTE_ARRAY:
145                 fprintf(out,
146                         "    AStatsEvent_writeByteArray(event, "
147                         "reinterpret_cast<const uint8_t*>(arg%d.arg), "
148                         "arg%d.arg_length);\n",
149                         argIndex, argIndex);
150                 break;
151             case JAVA_TYPE_BOOLEAN:
152                 fprintf(out, "    AStatsEvent_writeBool(event, arg%d);\n", argIndex);
153                 break;
154             case JAVA_TYPE_INT:
155                 [[fallthrough]];
156             case JAVA_TYPE_ENUM:
157                 fprintf(out, "    AStatsEvent_writeInt32(event, arg%d);\n", argIndex);
158                 break;
159             case JAVA_TYPE_FLOAT:
160                 fprintf(out, "    AStatsEvent_writeFloat(event, arg%d);\n", argIndex);
161                 break;
162             case JAVA_TYPE_LONG:
163                 fprintf(out, "    AStatsEvent_writeInt64(event, arg%d);\n", argIndex);
164                 break;
165             case JAVA_TYPE_STRING:
166                 fprintf(out, "    AStatsEvent_writeString(event, arg%d);\n", argIndex);
167                 break;
168             case JAVA_TYPE_BOOLEAN_ARRAY:
169                 fprintf(out, "    AStatsEvent_writeBoolArray(event, arg%d, arg%d_length);\n",
170                         argIndex, argIndex);
171                 break;
172             case JAVA_TYPE_INT_ARRAY:
173                 [[fallthrough]];
174             case JAVA_TYPE_ENUM_ARRAY:
175                 fprintf(out,
176                         "    AStatsEvent_writeInt32Array(event, arg%d.data(), arg%d.size());\n",
177                         argIndex, argIndex);
178                 break;
179             case JAVA_TYPE_FLOAT_ARRAY:
180                 fprintf(out,
181                         "    AStatsEvent_writeFloatArray(event, arg%d.data(), arg%d.size());\n",
182                         argIndex, argIndex);
183                 break;
184             case JAVA_TYPE_LONG_ARRAY:
185                 fprintf(out,
186                         "    AStatsEvent_writeInt64Array(event, arg%d.data(), arg%d.size());\n",
187                         argIndex, argIndex);
188                 break;
189             case JAVA_TYPE_STRING_ARRAY:
190                 fprintf(out,
191                         "    AStatsEvent_writeStringArray(event, arg%d.data(), arg%d.size());\n",
192                         argIndex, argIndex);
193                 break;
194 
195             default:
196                 // Unsupported types: OBJECT, DOUBLE
197                 fprintf(stderr, "Encountered unsupported type.\n");
198                 return 1;
199         }
200         write_annotations(out, argIndex, fieldNumberToAtomDeclSet, "AStatsEvent_",
201                           "event, ", minApiLevel);
202         argIndex++;
203     }
204     return 0;
205 }
206 
write_native_method_call(FILE * out,const string & methodName,const vector<java_type_t> & signature,const AtomDecl & attributionDecl,int argIndex)207 static void write_native_method_call(FILE* out, const string& methodName,
208                                      const vector<java_type_t>& signature,
209                                      const AtomDecl& attributionDecl, int argIndex) {
210     fprintf(out, "%s(code", methodName.c_str());
211     for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
212          arg++) {
213         if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
214             for (const auto& chainField : attributionDecl.fields) {
215                 if (chainField.javaType == JAVA_TYPE_STRING) {
216                     fprintf(out, ", %s", chainField.name.c_str());
217                 } else {
218                     fprintf(out, ",  %s,  %s_length", chainField.name.c_str(),
219                             chainField.name.c_str());
220                 }
221             }
222         } else {
223             fprintf(out, ", arg%d", argIndex);
224 
225             if (*arg == JAVA_TYPE_BOOLEAN_ARRAY) {
226                 fprintf(out, ", arg%d_length", argIndex);
227             }
228         }
229         argIndex++;
230     }
231     fprintf(out, ");\n");
232 }
233 
write_native_stats_write_methods(FILE * out,const SignatureInfoMap & signatureInfoMap,const AtomDecl & attributionDecl,const int minApiLevel,bool bootstrap)234 static int write_native_stats_write_methods(FILE* out, const SignatureInfoMap& signatureInfoMap,
235                                             const AtomDecl& attributionDecl, const int minApiLevel,
236                                             bool bootstrap) {
237     fprintf(out, "\n");
238     for (auto signatureInfoMapIt = signatureInfoMap.begin();
239          signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
240         vector<java_type_t> signature = signatureInfoMapIt->first;
241         const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet = signatureInfoMapIt->second;
242         write_native_method_signature(out, "int stats_write(", signature, attributionDecl, " {");
243 
244         // Write method body.
245         if (bootstrap) {
246             fprintf(out, "    ::android::os::StatsBootstrapAtom atom;\n");
247             fprintf(out, "    atom.atomId = code;\n");
248             FieldNumberToAtomDeclSet::const_iterator fieldNumberToAtomDeclSetIt =
249                     fieldNumberToAtomDeclSet.find(ATOM_ID_FIELD_NUMBER);
250             if (fieldNumberToAtomDeclSet.end() != fieldNumberToAtomDeclSetIt) {
251                 fprintf(stderr, "Bootstrap atoms do not support annotations\n");
252                 return 1;
253             }
254             int argIndex = 1;
255             const char* atomVal = "::android::os::StatsBootstrapAtomValue::";
256             for (vector<java_type_t>::const_iterator arg = signature.begin();
257                  arg != signature.end(); arg++) {
258                 switch (*arg) {
259                     case JAVA_TYPE_BYTE_ARRAY:
260                         fprintf(out,
261                                 "    const uint8_t* arg%dbyte = reinterpret_cast<const "
262                                 "uint8_t*>(arg%d.arg);\n",
263                                 argIndex, argIndex);
264                         fprintf(out,
265                                 "    "
266                                 "atom.values.push_back(%smake<%sbytesValue>(std::vector(arg%dbyte, "
267                                 "arg%dbyte + arg%d.arg_length)));\n",
268                                 atomVal, atomVal, argIndex, argIndex, argIndex);
269                         break;
270                     case JAVA_TYPE_BOOLEAN:
271                         fprintf(out, "    atom.values.push_back(%smake<%sboolValue>(arg%d));\n",
272                                 atomVal, atomVal, argIndex);
273                         break;
274                     case JAVA_TYPE_INT:  // Fall through.
275                     case JAVA_TYPE_ENUM:
276                         fprintf(out, "    atom.values.push_back(%smake<%sintValue>(arg%d));\n",
277                                 atomVal, atomVal, argIndex);
278                         break;
279                     case JAVA_TYPE_FLOAT:
280                         fprintf(out, "    atom.values.push_back(%smake<%sfloatValue>(arg%d));\n",
281                                 atomVal, atomVal, argIndex);
282                         break;
283                     case JAVA_TYPE_LONG:
284                         fprintf(out, "    atom.values.push_back(%smake<%slongValue>(arg%d));\n",
285                                 atomVal, atomVal, argIndex);
286                         break;
287                     case JAVA_TYPE_STRING:
288                         fprintf(out,
289                                 "    atom.values.push_back(%smake<%sstringValue>("
290                                 "::android::String16(arg%d)));\n",
291                                 atomVal, atomVal, argIndex);
292                         break;
293                     default:
294                         // Unsupported types: OBJECT, DOUBLE, ATTRIBUTION_CHAIN,
295                         // and all repeated fields
296                         fprintf(stderr, "Encountered unsupported type.\n");
297                         return 1;
298                 }
299                 FieldNumberToAtomDeclSet::const_iterator fieldNumberToAtomDeclSetIt =
300                         fieldNumberToAtomDeclSet.find(argIndex);
301                 if (fieldNumberToAtomDeclSet.end() != fieldNumberToAtomDeclSetIt) {
302                     fprintf(stderr, "Bootstrap atoms do not support annotations\n");
303                     return 1;
304                 }
305                 argIndex++;
306             }
307             fprintf(out,
308                     "    bool success = "
309                     "::android::os::stats::StatsBootstrapAtomClient::reportBootstrapAtom(atom);\n");
310             fprintf(out, "    return success? 0 : -1;\n");
311 
312         } else if (minApiLevel == API_Q) {
313             int argIndex = 1;
314             fprintf(out, "    StatsEventCompat event;\n");
315             fprintf(out, "    event.setAtomId(code);\n");
316             write_annotations(out, ATOM_ID_FIELD_NUMBER, fieldNumberToAtomDeclSet, "event.", "",
317                     minApiLevel);
318             for (vector<java_type_t>::const_iterator arg = signature.begin();
319                  arg != signature.end(); arg++) {
320                 switch (*arg) {
321                     case JAVA_TYPE_ATTRIBUTION_CHAIN: {
322                         const char* uidName = attributionDecl.fields.front().name.c_str();
323                         const char* tagName = attributionDecl.fields.back().name.c_str();
324                         fprintf(out, "    event.writeAttributionChain(%s, %s_length, %s);\n",
325                                 uidName, uidName, tagName);
326                         break;
327                     }
328                     case JAVA_TYPE_BYTE_ARRAY:
329                         fprintf(out, "    event.writeByteArray(arg%d.arg, arg%d.arg_length);\n",
330                                 argIndex, argIndex);
331                         break;
332                     case JAVA_TYPE_BOOLEAN:
333                         fprintf(out, "    event.writeBool(arg%d);\n", argIndex);
334                         break;
335                     case JAVA_TYPE_INT:  // Fall through.
336                     case JAVA_TYPE_ENUM:
337                         fprintf(out, "    event.writeInt32(arg%d);\n", argIndex);
338                         break;
339                     case JAVA_TYPE_FLOAT:
340                         fprintf(out, "    event.writeFloat(arg%d);\n", argIndex);
341                         break;
342                     case JAVA_TYPE_LONG:
343                         fprintf(out, "    event.writeInt64(arg%d);\n", argIndex);
344                         break;
345                     case JAVA_TYPE_STRING:
346                         fprintf(out, "    event.writeString(arg%d);\n", argIndex);
347                         break;
348                     default:
349                         // Unsupported types: OBJECT, DOUBLE, and all repeated
350                         // fields.
351                         fprintf(stderr, "Encountered unsupported type.\n");
352                         return 1;
353                 }
354                 write_annotations(out, argIndex, fieldNumberToAtomDeclSet, "event.", "",
355                         minApiLevel);
356                 argIndex++;
357             }
358             fprintf(out, "    return event.writeToSocket();\n"); // end method body.
359         } else {
360             fprintf(out, "    AStatsEvent* event = AStatsEvent_obtain();\n");
361             int ret = write_native_method_body(out, signature, fieldNumberToAtomDeclSet,
362                                                attributionDecl, minApiLevel);
363             if (ret != 0) {
364                 return ret;
365             }
366             fprintf(out, "    const int ret = AStatsEvent_write(event);\n");
367             fprintf(out, "    AStatsEvent_release(event);\n");
368             fprintf(out, "    return ret;\n"); // end method body.
369         }
370         fprintf(out, "}\n\n"); // end method.
371     }
372     return 0;
373 }
374 
write_native_stats_write_non_chained_methods(FILE * out,const SignatureInfoMap & signatureInfoMap,const AtomDecl & attributionDecl)375 static void write_native_stats_write_non_chained_methods(FILE* out,
376                                                          const SignatureInfoMap& signatureInfoMap,
377                                                          const AtomDecl& attributionDecl) {
378     fprintf(out, "\n");
379     for (auto signature_it = signatureInfoMap.begin();
380          signature_it != signatureInfoMap.end(); signature_it++) {
381         vector<java_type_t> signature = signature_it->first;
382 
383         write_native_method_signature(out, "int stats_write_non_chained(", signature,
384                                       attributionDecl, " {");
385 
386         vector<java_type_t> newSignature;
387 
388         // First two args form the attribution node so size goes down by 1.
389         newSignature.reserve(signature.size() - 1);
390 
391         // First arg is Attribution Chain.
392         newSignature.push_back(JAVA_TYPE_ATTRIBUTION_CHAIN);
393 
394         // Followed by the originial signature except the first 2 args.
395         newSignature.insert(newSignature.end(), signature.begin() + 2, signature.end());
396 
397         const char* uidName = attributionDecl.fields.front().name.c_str();
398         const char* tagName = attributionDecl.fields.back().name.c_str();
399         fprintf(out, "    const int32_t* %s = &arg1;\n", uidName);
400         fprintf(out, "    const size_t %s_length = 1;\n", uidName);
401         fprintf(out, "    const std::vector<char const*> %s(1, arg2);\n", tagName);
402         fprintf(out, "    return ");
403         write_native_method_call(out, "stats_write", newSignature, attributionDecl, 2);
404 
405         fprintf(out, "}\n\n");
406     }
407 }
408 
write_native_build_stats_event_methods(FILE * out,const SignatureInfoMap & signatureInfoMap,const AtomDecl & attributionDecl,const int minApiLevel)409 static int write_native_build_stats_event_methods(FILE* out,
410                                                   const SignatureInfoMap& signatureInfoMap,
411                                                   const AtomDecl& attributionDecl,
412                                                   const int minApiLevel) {
413     fprintf(out, "\n");
414     for (auto signatureInfoMapIt = signatureInfoMap.begin();
415          signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
416         vector<java_type_t> signature = signatureInfoMapIt->first;
417         const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet = signatureInfoMapIt->second;
418         write_native_method_signature(out, "void addAStatsEvent(AStatsEventList* pulled_data, ",
419                                       signature, attributionDecl, " {");
420 
421         fprintf(out, "    AStatsEvent* event = AStatsEventList_addStatsEvent(pulled_data);\n");
422         int ret = write_native_method_body(out, signature, fieldNumberToAtomDeclSet,
423                                            attributionDecl, minApiLevel);
424         if (ret != 0) {
425             return ret;
426         }
427         fprintf(out, "    AStatsEvent_build(event);\n"); // end method body.
428 
429         fprintf(out, "}\n\n"); // end method.
430     }
431     return 0;
432 }
433 
write_native_method_header(FILE * out,const string & methodName,const SignatureInfoMap & signatureInfoMap,const AtomDecl & attributionDecl)434 static void write_native_method_header(FILE* out, const string& methodName,
435                                        const SignatureInfoMap& signatureInfoMap,
436                                        const AtomDecl& attributionDecl) {
437     for (auto signatureInfoMapIt = signatureInfoMap.begin();
438          signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
439         vector<java_type_t> signature = signatureInfoMapIt->first;
440 
441         write_native_method_signature(out, methodName, signature, attributionDecl, ";");
442     }
443 }
444 
write_stats_log_cpp(FILE * out,const Atoms & atoms,const AtomDecl & attributionDecl,const string & cppNamespace,const string & importHeader,const int minApiLevel,bool bootstrap)445 int write_stats_log_cpp(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
446                         const string& cppNamespace, const string& importHeader,
447                         const int minApiLevel, bool bootstrap) {
448     // Print prelude
449     fprintf(out, "// This file is autogenerated\n");
450     fprintf(out, "\n");
451 
452     fprintf(out, "#include <%s>\n", importHeader.c_str());
453     if (!bootstrap) {
454         if (minApiLevel == API_Q) {
455             fprintf(out, "#include <StatsEventCompat.h>\n");
456         } else {
457             fprintf(out, "#include <stats_event.h>\n");
458         }
459 
460         if (minApiLevel > API_R) {
461             fprintf(out, "#include <stats_annotations.h>\n");
462         }
463 
464         if (minApiLevel > API_Q && !atoms.pulledAtomsSignatureInfoMap.empty()) {
465             fprintf(out, "#include <stats_pull_atom_callback.h>\n");
466         }
467     } else {
468         fprintf(out, "#include <StatsBootstrapAtomClient.h>\n");
469         fprintf(out, "#include <android/os/StatsBootstrapAtom.h>\n");
470         fprintf(out, "#include <utils/String16.h>\n");
471     }
472 
473     fprintf(out, "\n");
474     write_namespace(out, cppNamespace);
475 
476     int ret = write_native_stats_write_methods(out, atoms.signatureInfoMap, attributionDecl,
477                                                minApiLevel, bootstrap);
478     if (ret != 0) {
479         return ret;
480     }
481     if (!bootstrap) {
482         write_native_stats_write_non_chained_methods(out, atoms.nonChainedSignatureInfoMap,
483                                                      attributionDecl);
484         ret = write_native_build_stats_event_methods(out, atoms.pulledAtomsSignatureInfoMap,
485                                                      attributionDecl, minApiLevel);
486         if (ret != 0) {
487             return ret;
488         }
489     }
490 
491     // Print footer
492     fprintf(out, "\n");
493     write_closing_namespace(out, cppNamespace);
494 
495     return 0;
496 }
497 
write_stats_log_header(FILE * out,const Atoms & atoms,const AtomDecl & attributionDecl,const string & cppNamespace,const int minApiLevel,bool bootstrap)498 int write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
499                            const string& cppNamespace, const int minApiLevel, bool bootstrap) {
500     // Print prelude
501     fprintf(out, "// This file is autogenerated\n");
502     fprintf(out, "\n");
503     fprintf(out, "#pragma once\n");
504     fprintf(out, "\n");
505     fprintf(out, "#include <stdint.h>\n");
506     fprintf(out, "#include <vector>\n");
507     fprintf(out, "#include <map>\n");
508     fprintf(out, "#include <set>\n");
509     if (!atoms.pulledAtomsSignatureInfoMap.empty() && !bootstrap) {
510         fprintf(out, "#include <stats_pull_atom_callback.h>\n");
511     }
512     fprintf(out, "\n");
513 
514     write_namespace(out, cppNamespace);
515     fprintf(out, "\n");
516     fprintf(out, "/*\n");
517     fprintf(out, " * API For logging statistics events.\n");
518     fprintf(out, " */\n");
519     fprintf(out, "\n");
520 
521     write_native_atom_constants(out, atoms, attributionDecl);
522 
523     // Print constants for the enum values.
524     fprintf(out, "//\n");
525     fprintf(out, "// Constants for enum values\n");
526     fprintf(out, "//\n\n");
527     for (AtomDeclSet::const_iterator atomIt = atoms.decls.begin(); atomIt != atoms.decls.end();
528          atomIt++) {
529         for (vector<AtomField>::const_iterator field = (*atomIt)->fields.begin();
530              field != (*atomIt)->fields.end(); field++) {
531             if (field->javaType == JAVA_TYPE_ENUM) {
532                 fprintf(out, "// Values for %s.%s\n", (*atomIt)->message.c_str(),
533                         field->name.c_str());
534                 for (map<int, string>::const_iterator value = field->enumValues.begin();
535                      value != field->enumValues.end(); value++) {
536                     fprintf(out, "const int32_t %s__%s__%s = %d;\n",
537                             make_constant_name((*atomIt)->message).c_str(),
538                             make_constant_name(field->name).c_str(),
539                             make_constant_name(value->second).c_str(), value->first);
540                 }
541                 fprintf(out, "\n");
542             }
543         }
544     }
545 
546     if (minApiLevel <= API_R) {
547         write_native_annotation_constants(out);
548     }
549 
550     fprintf(out, "struct BytesField {\n");
551     fprintf(out,
552             "  BytesField(char const* array, size_t len) : arg(array), "
553             "arg_length(len) {}\n");
554     fprintf(out, "  char const* arg;\n");
555     fprintf(out, "  size_t arg_length;\n");
556     fprintf(out, "};\n");
557     fprintf(out, "\n");
558 
559     // Print write methods
560     fprintf(out, "//\n");
561     fprintf(out, "// Write methods\n");
562     fprintf(out, "//\n");
563     write_native_method_header(out, "int stats_write(", atoms.signatureInfoMap, attributionDecl);
564     fprintf(out, "\n");
565 
566     // Attribution chains and pulled atoms are not supported for bootstrap processes.
567     if (!bootstrap) {
568         fprintf(out, "//\n");
569         fprintf(out, "// Write flattened methods\n");
570         fprintf(out, "//\n");
571         write_native_method_header(out, "int stats_write_non_chained(",
572                                    atoms.nonChainedSignatureInfoMap, attributionDecl);
573         fprintf(out, "\n");
574 
575         // Print pulled atoms methods.
576         fprintf(out, "//\n");
577         fprintf(out, "// Add AStatsEvent methods\n");
578         fprintf(out, "//\n");
579         write_native_method_header(out, "void addAStatsEvent(AStatsEventList* pulled_data, ",
580                                    atoms.pulledAtomsSignatureInfoMap, attributionDecl);
581         fprintf(out, "\n");
582     }
583 
584     write_closing_namespace(out, cppNamespace);
585 
586     return 0;
587 }
588 
589 }  // namespace stats_log_api_gen
590 }  // namespace android
591