• 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_body(FILE * out,vector<java_type_t> & signature,const FieldNumberToAtomDeclSet & fieldNumberToAtomDeclSet,const AtomDecl & attributionDecl,const int minApiLevel)90 static int write_native_method_body(FILE* out, vector<java_type_t>& signature,
91                                     const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet,
92                                     const AtomDecl& attributionDecl, const int minApiLevel) {
93     int argIndex = 1;
94     fprintf(out, "    AStatsEvent_setAtomId(event, code);\n");
95     write_annotations(out, ATOM_ID_FIELD_NUMBER, fieldNumberToAtomDeclSet, "AStatsEvent_",
96                       "event, ", minApiLevel);
97     for (vector<java_type_t>::const_iterator arg = signature.begin();
98          arg != signature.end(); arg++) {
99         switch (*arg) {
100             case JAVA_TYPE_ATTRIBUTION_CHAIN: {
101                 const char* uidName = attributionDecl.fields.front().name.c_str();
102                 const char* tagName = attributionDecl.fields.back().name.c_str();
103                 fprintf(out,
104                         "    AStatsEvent_writeAttributionChain(event, "
105                         "reinterpret_cast<const uint32_t*>(%s), %s.data(), "
106                         "static_cast<uint8_t>(%s_length));\n",
107                         uidName, tagName, uidName);
108                 break;
109             }
110             case JAVA_TYPE_BYTE_ARRAY:
111                 fprintf(out,
112                         "    AStatsEvent_writeByteArray(event, "
113                         "reinterpret_cast<const uint8_t*>(arg%d.arg), "
114                         "arg%d.arg_length);\n",
115                         argIndex, argIndex);
116                 break;
117             case JAVA_TYPE_BOOLEAN:
118                 fprintf(out, "    AStatsEvent_writeBool(event, arg%d);\n", argIndex);
119                 break;
120             case JAVA_TYPE_INT:  // Fall through.
121             case JAVA_TYPE_ENUM:
122                 fprintf(out, "    AStatsEvent_writeInt32(event, arg%d);\n", argIndex);
123                 break;
124             case JAVA_TYPE_FLOAT:
125                 fprintf(out, "    AStatsEvent_writeFloat(event, arg%d);\n", argIndex);
126                 break;
127             case JAVA_TYPE_LONG:
128                 fprintf(out, "    AStatsEvent_writeInt64(event, arg%d);\n", argIndex);
129                 break;
130             case JAVA_TYPE_STRING:
131                 fprintf(out, "    AStatsEvent_writeString(event, arg%d);\n", argIndex);
132                 break;
133             default:
134                 // Unsupported types: OBJECT, DOUBLE, KEY_VALUE_PAIRS
135                 fprintf(stderr, "Encountered unsupported type.");
136                 return 1;
137         }
138         write_annotations(out, argIndex, fieldNumberToAtomDeclSet, "AStatsEvent_",
139                           "event, ", minApiLevel);
140         argIndex++;
141     }
142     return 0;
143 }
144 
write_native_stats_write_methods(FILE * out,const SignatureInfoMap & signatureInfoMap,const AtomDecl & attributionDecl,const int minApiLevel)145 static int write_native_stats_write_methods(FILE* out, const SignatureInfoMap& signatureInfoMap,
146                                             const AtomDecl& attributionDecl,
147                                             const int minApiLevel) {
148     fprintf(out, "\n");
149     for (auto signatureInfoMapIt = signatureInfoMap.begin();
150          signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
151         vector<java_type_t> signature = signatureInfoMapIt->first;
152         const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet = signatureInfoMapIt->second;
153         // Key value pairs not supported in native.
154         if (std::find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) !=
155             signature.end()) {
156             continue;
157         }
158         write_native_method_signature(out, "int stats_write(", signature, attributionDecl, " {");
159 
160         // Write method body.
161         if (minApiLevel == API_Q) {
162             int argIndex = 1;
163             fprintf(out, "    StatsEventCompat event;\n");
164             fprintf(out, "    event.setAtomId(code);\n");
165             write_annotations(out, ATOM_ID_FIELD_NUMBER, fieldNumberToAtomDeclSet, "event.", "",
166                     minApiLevel);
167             for (vector<java_type_t>::const_iterator arg = signature.begin();
168                  arg != signature.end(); arg++) {
169                 switch (*arg) {
170                     case JAVA_TYPE_ATTRIBUTION_CHAIN: {
171                         const char* uidName = attributionDecl.fields.front().name.c_str();
172                         const char* tagName = attributionDecl.fields.back().name.c_str();
173                         fprintf(out, "    event.writeAttributionChain(%s, %s_length, %s);\n",
174                                 uidName, uidName, tagName);
175                         break;
176                     }
177                     case JAVA_TYPE_BYTE_ARRAY:
178                         fprintf(out, "    event.writeByteArray(arg%d.arg, arg%d.arg_length);\n",
179                                 argIndex, argIndex);
180                         break;
181                     case JAVA_TYPE_BOOLEAN:
182                         fprintf(out, "    event.writeBool(arg%d);\n", argIndex);
183                         break;
184                     case JAVA_TYPE_INT:  // Fall through.
185                     case JAVA_TYPE_ENUM:
186                         fprintf(out, "    event.writeInt32(arg%d);\n", argIndex);
187                         break;
188                     case JAVA_TYPE_FLOAT:
189                         fprintf(out, "    event.writeFloat(arg%d);\n", argIndex);
190                         break;
191                     case JAVA_TYPE_LONG:
192                         fprintf(out, "    event.writeInt64(arg%d);\n", argIndex);
193                         break;
194                     case JAVA_TYPE_STRING:
195                         fprintf(out, "    event.writeString(arg%d);\n", argIndex);
196                         break;
197                     default:
198                         // Unsupported types: OBJECT, DOUBLE, KEY_VALUE_PAIRS.
199                         fprintf(stderr, "Encountered unsupported type.");
200                         return 1;
201                 }
202                 write_annotations(out, argIndex, fieldNumberToAtomDeclSet, "event.", "",
203                         minApiLevel);
204                 argIndex++;
205             }
206             fprintf(out, "    return event.writeToSocket();\n"); // end method body.
207         } else {
208             fprintf(out, "    AStatsEvent* event = AStatsEvent_obtain();\n");
209             int ret = write_native_method_body(out, signature, fieldNumberToAtomDeclSet,
210                                                attributionDecl, minApiLevel);
211             if (ret != 0) {
212                 return ret;
213             }
214             fprintf(out, "    const int ret = AStatsEvent_write(event);\n");
215             fprintf(out, "    AStatsEvent_release(event);\n");
216             fprintf(out, "    return ret;\n"); // end method body.
217         }
218         fprintf(out, "}\n\n"); // end method.
219     }
220     return 0;
221 }
222 
write_native_stats_write_non_chained_methods(FILE * out,const SignatureInfoMap & signatureInfoMap,const AtomDecl & attributionDecl)223 static void write_native_stats_write_non_chained_methods(FILE* out,
224                                                          const SignatureInfoMap& signatureInfoMap,
225                                                          const AtomDecl& attributionDecl) {
226     fprintf(out, "\n");
227     for (auto signature_it = signatureInfoMap.begin();
228          signature_it != signatureInfoMap.end(); signature_it++) {
229         vector<java_type_t> signature = signature_it->first;
230         // Key value pairs not supported in native.
231         if (std::find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) !=
232             signature.end()) {
233             continue;
234         }
235 
236         write_native_method_signature(out, "int stats_write_non_chained(", signature,
237                                       attributionDecl, " {");
238 
239         vector<java_type_t> newSignature;
240 
241         // First two args form the attribution node so size goes down by 1.
242         newSignature.reserve(signature.size() - 1);
243 
244         // First arg is Attribution Chain.
245         newSignature.push_back(JAVA_TYPE_ATTRIBUTION_CHAIN);
246 
247         // Followed by the originial signature except the first 2 args.
248         newSignature.insert(newSignature.end(), signature.begin() + 2, signature.end());
249 
250         const char* uidName = attributionDecl.fields.front().name.c_str();
251         const char* tagName = attributionDecl.fields.back().name.c_str();
252         fprintf(out, "    const int32_t* %s = &arg1;\n", uidName);
253         fprintf(out, "    const size_t %s_length = 1;\n", uidName);
254         fprintf(out, "    const std::vector<char const*> %s(1, arg2);\n", tagName);
255         fprintf(out, "    return ");
256         write_native_method_call(out, "stats_write", newSignature, attributionDecl, 2);
257 
258         fprintf(out, "}\n\n");
259     }
260 }
261 
write_native_build_stats_event_methods(FILE * out,const SignatureInfoMap & signatureInfoMap,const AtomDecl & attributionDecl,const int minApiLevel)262 static int write_native_build_stats_event_methods(FILE* out,
263                                                   const SignatureInfoMap& signatureInfoMap,
264                                                   const AtomDecl& attributionDecl,
265                                                   const int minApiLevel) {
266     fprintf(out, "\n");
267     for (auto signatureInfoMapIt = signatureInfoMap.begin();
268          signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
269         vector<java_type_t> signature = signatureInfoMapIt->first;
270         const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet = signatureInfoMapIt->second;
271         // Key value pairs not supported in native.
272         if (std::find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) !=
273             signature.end()) {
274             continue;
275         }
276         write_native_method_signature(out, "void addAStatsEvent(AStatsEventList* pulled_data, ",
277                                       signature, attributionDecl, " {");
278 
279         fprintf(out, "    AStatsEvent* event = AStatsEventList_addStatsEvent(pulled_data);\n");
280         int ret = write_native_method_body(out, signature, fieldNumberToAtomDeclSet,
281                                            attributionDecl, minApiLevel);
282         if (ret != 0) {
283             return ret;
284         }
285         fprintf(out, "    AStatsEvent_build(event);\n"); // end method body.
286 
287         fprintf(out, "}\n\n"); // end method.
288     }
289     return 0;
290 }
291 
write_native_method_header(FILE * out,const string & methodName,const SignatureInfoMap & signatureInfoMap,const AtomDecl & attributionDecl)292 static void write_native_method_header(FILE* out, const string& methodName,
293                                        const SignatureInfoMap& signatureInfoMap,
294                                        const AtomDecl& attributionDecl) {
295     for (auto signatureInfoMapIt = signatureInfoMap.begin();
296          signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
297         vector<java_type_t> signature = signatureInfoMapIt->first;
298 
299         // Key value pairs not supported in native.
300         if (std::find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) !=
301             signature.end()) {
302             continue;
303         }
304         write_native_method_signature(out, methodName, signature, attributionDecl, ";");
305     }
306 }
307 
write_stats_log_cpp(FILE * out,const Atoms & atoms,const AtomDecl & attributionDecl,const string & cppNamespace,const string & importHeader,const int minApiLevel)308 int write_stats_log_cpp(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
309                         const string& cppNamespace, const string& importHeader,
310                         const int minApiLevel) {
311     // Print prelude
312     fprintf(out, "// This file is autogenerated\n");
313     fprintf(out, "\n");
314 
315     fprintf(out, "#include <%s>\n", importHeader.c_str());
316     if (minApiLevel == API_Q) {
317         fprintf(out, "#include <StatsEventCompat.h>\n");
318     } else {
319         fprintf(out, "#include <stats_event.h>\n");
320     }
321 
322     if (minApiLevel > API_R) {
323         fprintf(out, "#include <stats_annotations.h>\n");
324     }
325 
326     if (minApiLevel > API_Q && !atoms.pulledAtomsSignatureInfoMap.empty()) {
327         fprintf(out, "#include <stats_pull_atom_callback.h>\n");
328     }
329 
330 
331 
332     fprintf(out, "\n");
333     write_namespace(out, cppNamespace);
334 
335     write_native_stats_write_methods(out, atoms.signatureInfoMap, attributionDecl, minApiLevel);
336     write_native_stats_write_non_chained_methods(out, atoms.nonChainedSignatureInfoMap,
337                                                  attributionDecl);
338     write_native_build_stats_event_methods(out, atoms.pulledAtomsSignatureInfoMap,
339                                            attributionDecl, minApiLevel);
340 
341     // Print footer
342     fprintf(out, "\n");
343     write_closing_namespace(out, cppNamespace);
344 
345     return 0;
346 }
347 
write_stats_log_header(FILE * out,const Atoms & atoms,const AtomDecl & attributionDecl,const string & cppNamespace,const int minApiLevel)348 int write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
349                            const string& cppNamespace, const int minApiLevel) {
350     // Print prelude
351     fprintf(out, "// This file is autogenerated\n");
352     fprintf(out, "\n");
353     fprintf(out, "#pragma once\n");
354     fprintf(out, "\n");
355     fprintf(out, "#include <stdint.h>\n");
356     fprintf(out, "#include <vector>\n");
357     fprintf(out, "#include <map>\n");
358     fprintf(out, "#include <set>\n");
359     if (!atoms.pulledAtomsSignatureInfoMap.empty()) {
360         fprintf(out, "#include <stats_pull_atom_callback.h>\n");
361     }
362     fprintf(out, "\n");
363 
364     write_namespace(out, cppNamespace);
365     fprintf(out, "\n");
366     fprintf(out, "/*\n");
367     fprintf(out, " * API For logging statistics events.\n");
368     fprintf(out, " */\n");
369     fprintf(out, "\n");
370 
371     write_native_atom_constants(out, atoms, attributionDecl);
372 
373     // Print constants for the enum values.
374     fprintf(out, "//\n");
375     fprintf(out, "// Constants for enum values\n");
376     fprintf(out, "//\n\n");
377     for (AtomDeclSet::const_iterator atomIt = atoms.decls.begin(); atomIt != atoms.decls.end();
378          atomIt++) {
379         for (vector<AtomField>::const_iterator field = (*atomIt)->fields.begin();
380              field != (*atomIt)->fields.end(); field++) {
381             if (field->javaType == JAVA_TYPE_ENUM) {
382                 fprintf(out, "// Values for %s.%s\n", (*atomIt)->message.c_str(),
383                         field->name.c_str());
384                 for (map<int, string>::const_iterator value = field->enumValues.begin();
385                      value != field->enumValues.end(); value++) {
386                     fprintf(out, "const int32_t %s__%s__%s = %d;\n",
387                             make_constant_name((*atomIt)->message).c_str(),
388                             make_constant_name(field->name).c_str(),
389                             make_constant_name(value->second).c_str(), value->first);
390                 }
391                 fprintf(out, "\n");
392             }
393         }
394     }
395 
396     if (minApiLevel <= API_R) {
397         write_native_annotation_constants(out);
398     }
399 
400     fprintf(out, "struct BytesField {\n");
401     fprintf(out,
402             "  BytesField(char const* array, size_t len) : arg(array), "
403             "arg_length(len) {}\n");
404     fprintf(out, "  char const* arg;\n");
405     fprintf(out, "  size_t arg_length;\n");
406     fprintf(out, "};\n");
407     fprintf(out, "\n");
408 
409     // Print write methods
410     fprintf(out, "//\n");
411     fprintf(out, "// Write methods\n");
412     fprintf(out, "//\n");
413     write_native_method_header(out, "int stats_write(", atoms.signatureInfoMap, attributionDecl);
414     fprintf(out, "\n");
415 
416     fprintf(out, "//\n");
417     fprintf(out, "// Write flattened methods\n");
418     fprintf(out, "//\n");
419     write_native_method_header(out, "int stats_write_non_chained(", atoms.nonChainedSignatureInfoMap,
420                                attributionDecl);
421     fprintf(out, "\n");
422 
423     // Print pulled atoms methods.
424     fprintf(out, "//\n");
425     fprintf(out, "// Add AStatsEvent methods\n");
426     fprintf(out, "//\n");
427     write_native_method_header(out, "void addAStatsEvent(AStatsEventList* pulled_data, ",
428                                atoms.pulledAtomsSignatureInfoMap,
429                                attributionDecl);
430 
431     fprintf(out, "\n");
432     write_closing_namespace(out, cppNamespace);
433 
434     return 0;
435 }
436 
437 }  // namespace stats_log_api_gen
438 }  // namespace android
439