• 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     for (const auto& [id, name] : ANNOTATION_ID_CONSTANTS) {
28         fprintf(out, "const uint8_t %s = %hhu;\n", name.c_str(), id);
29     }
30     fprintf(out, "\n");
31 }
32 
write_annotations(FILE * out,int argIndex,const FieldNumberToAtomDeclSet & fieldNumberToAtomDeclSet,const string & methodPrefix,const string & methodSuffix)33 static void write_annotations(FILE* out, int argIndex,
34                               const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet,
35                               const string& methodPrefix, const string& methodSuffix) {
36     FieldNumberToAtomDeclSet::const_iterator fieldNumberToAtomDeclSetIt =
37             fieldNumberToAtomDeclSet.find(argIndex);
38     if (fieldNumberToAtomDeclSet.end() == fieldNumberToAtomDeclSetIt) {
39         return;
40     }
41     const AtomDeclSet& atomDeclSet = fieldNumberToAtomDeclSetIt->second;
42     for (const shared_ptr<AtomDecl>& atomDecl : atomDeclSet) {
43         const string atomConstant = make_constant_name(atomDecl->name);
44         fprintf(out, "    if (%s == code) {\n", atomConstant.c_str());
45         const AnnotationSet& annotations = atomDecl->fieldNumberToAnnotations.at(argIndex);
46         int resetState = -1;
47         int defaultState = -1;
48         for (const shared_ptr<Annotation>& annotation : annotations) {
49             const string& annotationConstant = ANNOTATION_ID_CONSTANTS.at(annotation->annotationId);
50             switch (annotation->type) {
51                 case ANNOTATION_TYPE_INT:
52                     if (ANNOTATION_ID_TRIGGER_STATE_RESET == annotation->annotationId) {
53                         resetState = annotation->value.intValue;
54                     } else if (ANNOTATION_ID_DEFAULT_STATE == annotation->annotationId) {
55                         defaultState = annotation->value.intValue;
56                     } else {
57                         fprintf(out, "        %saddInt32Annotation(%s%s, %d);\n",
58                                 methodPrefix.c_str(), methodSuffix.c_str(),
59                                 annotationConstant.c_str(), annotation->value.intValue);
60                     }
61                     break;
62                 case ANNOTATION_TYPE_BOOL:
63                     // TODO(b/151786433): Write annotation constant name instead of
64                     // annotation id literal.
65                     fprintf(out, "        %saddBoolAnnotation(%s%s, %s);\n", methodPrefix.c_str(),
66                             methodSuffix.c_str(), annotationConstant.c_str(),
67                             annotation->value.boolValue ? "true" : "false");
68                     break;
69                 default:
70                     break;
71             }
72         }
73         if (defaultState != -1 && resetState != -1) {
74             const string& annotationConstant =
75                     ANNOTATION_ID_CONSTANTS.at(ANNOTATION_ID_TRIGGER_STATE_RESET);
76             fprintf(out, "        if (arg%d == %d) {\n", argIndex, resetState);
77             fprintf(out, "            %saddInt32Annotation(%s%s, %d);\n", methodPrefix.c_str(),
78                     methodSuffix.c_str(), annotationConstant.c_str(), defaultState);
79             fprintf(out, "        }\n");
80         }
81         fprintf(out, "    }\n");
82     }
83 }
84 
write_native_stats_write_methods(FILE * out,const Atoms & atoms,const AtomDecl & attributionDecl,const bool supportQ)85 static int write_native_stats_write_methods(FILE* out, const Atoms& atoms,
86                                             const AtomDecl& attributionDecl, const bool supportQ) {
87     fprintf(out, "\n");
88     for (auto signatureInfoMapIt = atoms.signatureInfoMap.begin();
89          signatureInfoMapIt != atoms.signatureInfoMap.end(); signatureInfoMapIt++) {
90         vector<java_type_t> signature = signatureInfoMapIt->first;
91         const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet = signatureInfoMapIt->second;
92         // Key value pairs not supported in native.
93         if (find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) != signature.end()) {
94             continue;
95         }
96         write_native_method_signature(out, "int stats_write", signature, attributionDecl, " {");
97 
98         int argIndex = 1;
99         if (supportQ) {
100             fprintf(out, "    StatsEventCompat event;\n");
101             fprintf(out, "    event.setAtomId(code);\n");
102             write_annotations(out, ATOM_ID_FIELD_NUMBER, fieldNumberToAtomDeclSet, "event.", "");
103             for (vector<java_type_t>::const_iterator arg = signature.begin();
104                  arg != signature.end(); arg++) {
105                 switch (*arg) {
106                     case JAVA_TYPE_ATTRIBUTION_CHAIN: {
107                         const char* uidName = attributionDecl.fields.front().name.c_str();
108                         const char* tagName = attributionDecl.fields.back().name.c_str();
109                         fprintf(out, "    event.writeAttributionChain(%s, %s_length, %s);\n",
110                                 uidName, uidName, tagName);
111                         break;
112                     }
113                     case JAVA_TYPE_BYTE_ARRAY:
114                         fprintf(out, "    event.writeByteArray(arg%d.arg, arg%d.arg_length);\n",
115                                 argIndex, argIndex);
116                         break;
117                     case JAVA_TYPE_BOOLEAN:
118                         fprintf(out, "    event.writeBool(arg%d);\n", argIndex);
119                         break;
120                     case JAVA_TYPE_INT:  // Fall through.
121                     case JAVA_TYPE_ENUM:
122                         fprintf(out, "    event.writeInt32(arg%d);\n", argIndex);
123                         break;
124                     case JAVA_TYPE_FLOAT:
125                         fprintf(out, "    event.writeFloat(arg%d);\n", argIndex);
126                         break;
127                     case JAVA_TYPE_LONG:
128                         fprintf(out, "    event.writeInt64(arg%d);\n", argIndex);
129                         break;
130                     case JAVA_TYPE_STRING:
131                         fprintf(out, "    event.writeString(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, "event.", "");
139                 argIndex++;
140             }
141             fprintf(out, "    return event.writeToSocket();\n");
142         } else {
143             fprintf(out, "    AStatsEvent* event = AStatsEvent_obtain();\n");
144             fprintf(out, "    AStatsEvent_setAtomId(event, code);\n");
145             write_annotations(out, ATOM_ID_FIELD_NUMBER, fieldNumberToAtomDeclSet, "AStatsEvent_",
146                               "event, ");
147             for (vector<java_type_t>::const_iterator arg = signature.begin();
148                  arg != signature.end(); arg++) {
149                 switch (*arg) {
150                     case JAVA_TYPE_ATTRIBUTION_CHAIN: {
151                         const char* uidName = attributionDecl.fields.front().name.c_str();
152                         const char* tagName = attributionDecl.fields.back().name.c_str();
153                         fprintf(out,
154                                 "    AStatsEvent_writeAttributionChain(event, "
155                                 "reinterpret_cast<const uint32_t*>(%s), %s.data(), "
156                                 "static_cast<uint8_t>(%s_length));\n",
157                                 uidName, tagName, uidName);
158                         break;
159                     }
160                     case JAVA_TYPE_BYTE_ARRAY:
161                         fprintf(out,
162                                 "    AStatsEvent_writeByteArray(event, "
163                                 "reinterpret_cast<const uint8_t*>(arg%d.arg), "
164                                 "arg%d.arg_length);\n",
165                                 argIndex, argIndex);
166                         break;
167                     case JAVA_TYPE_BOOLEAN:
168                         fprintf(out, "    AStatsEvent_writeBool(event, arg%d);\n", argIndex);
169                         break;
170                     case JAVA_TYPE_INT:  // Fall through.
171                     case JAVA_TYPE_ENUM:
172                         fprintf(out, "    AStatsEvent_writeInt32(event, arg%d);\n", argIndex);
173                         break;
174                     case JAVA_TYPE_FLOAT:
175                         fprintf(out, "    AStatsEvent_writeFloat(event, arg%d);\n", argIndex);
176                         break;
177                     case JAVA_TYPE_LONG:
178                         fprintf(out, "    AStatsEvent_writeInt64(event, arg%d);\n", argIndex);
179                         break;
180                     case JAVA_TYPE_STRING:
181                         fprintf(out, "    AStatsEvent_writeString(event, arg%d);\n", argIndex);
182                         break;
183                     default:
184                         // Unsupported types: OBJECT, DOUBLE, KEY_VALUE_PAIRS
185                         fprintf(stderr, "Encountered unsupported type.");
186                         return 1;
187                 }
188                 write_annotations(out, argIndex, fieldNumberToAtomDeclSet, "AStatsEvent_",
189                                   "event, ");
190                 argIndex++;
191             }
192             fprintf(out, "    const int ret = AStatsEvent_write(event);\n");
193             fprintf(out, "    AStatsEvent_release(event);\n");
194             fprintf(out, "    return ret;\n");
195         }
196         fprintf(out, "}\n\n");
197     }
198     return 0;
199 }
200 
write_native_stats_write_non_chained_methods(FILE * out,const Atoms & atoms,const AtomDecl & attributionDecl)201 static void write_native_stats_write_non_chained_methods(FILE* out, const Atoms& atoms,
202                                                          const AtomDecl& attributionDecl) {
203     fprintf(out, "\n");
204     for (auto signature_it = atoms.nonChainedSignatureInfoMap.begin();
205          signature_it != atoms.nonChainedSignatureInfoMap.end(); signature_it++) {
206         vector<java_type_t> signature = signature_it->first;
207         // Key value pairs not supported in native.
208         if (find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) != signature.end()) {
209             continue;
210         }
211 
212         write_native_method_signature(out, "int stats_write_non_chained", signature,
213                                       attributionDecl, " {");
214 
215         vector<java_type_t> newSignature;
216 
217         // First two args form the attribution node so size goes down by 1.
218         newSignature.reserve(signature.size() - 1);
219 
220         // First arg is Attribution Chain.
221         newSignature.push_back(JAVA_TYPE_ATTRIBUTION_CHAIN);
222 
223         // Followed by the originial signature except the first 2 args.
224         newSignature.insert(newSignature.end(), signature.begin() + 2, signature.end());
225 
226         const char* uidName = attributionDecl.fields.front().name.c_str();
227         const char* tagName = attributionDecl.fields.back().name.c_str();
228         fprintf(out, "    const int32_t* %s = &arg1;\n", uidName);
229         fprintf(out, "    const size_t %s_length = 1;\n", uidName);
230         fprintf(out, "    const std::vector<char const*> %s(1, arg2);\n", tagName);
231         fprintf(out, "    return ");
232         write_native_method_call(out, "stats_write", newSignature, attributionDecl, 2);
233 
234         fprintf(out, "}\n\n");
235     }
236 }
237 
write_native_method_header(FILE * out,const string & methodName,const SignatureInfoMap & signatureInfoMap,const AtomDecl & attributionDecl)238 static void write_native_method_header(FILE* out, const string& methodName,
239                                        const SignatureInfoMap& signatureInfoMap,
240                                        const AtomDecl& attributionDecl) {
241     for (auto signatureInfoMapIt = signatureInfoMap.begin();
242          signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
243         vector<java_type_t> signature = signatureInfoMapIt->first;
244 
245         // Key value pairs not supported in native.
246         if (find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) != signature.end()) {
247             continue;
248         }
249         write_native_method_signature(out, methodName, signature, attributionDecl, ";");
250     }
251 }
252 
write_stats_log_cpp(FILE * out,const Atoms & atoms,const AtomDecl & attributionDecl,const string & cppNamespace,const string & importHeader,const bool supportQ)253 int write_stats_log_cpp(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
254                         const string& cppNamespace, const string& importHeader,
255                         const bool supportQ) {
256     // Print prelude
257     fprintf(out, "// This file is autogenerated\n");
258     fprintf(out, "\n");
259 
260     fprintf(out, "#include <%s>\n", importHeader.c_str());
261     if (supportQ) {
262         fprintf(out, "#include <StatsEventCompat.h>\n");
263     } else {
264         fprintf(out, "#include <stats_event.h>\n");
265     }
266 
267     fprintf(out, "\n");
268     write_namespace(out, cppNamespace);
269 
270     write_native_stats_write_methods(out, atoms, attributionDecl, supportQ);
271     write_native_stats_write_non_chained_methods(out, atoms, attributionDecl);
272 
273     // Print footer
274     fprintf(out, "\n");
275     write_closing_namespace(out, cppNamespace);
276 
277     return 0;
278 }
279 
write_stats_log_header(FILE * out,const Atoms & atoms,const AtomDecl & attributionDecl,const string & cppNamespace)280 int write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
281                            const string& cppNamespace) {
282     // Print prelude
283     fprintf(out, "// This file is autogenerated\n");
284     fprintf(out, "\n");
285     fprintf(out, "#pragma once\n");
286     fprintf(out, "\n");
287     fprintf(out, "#include <stdint.h>\n");
288     fprintf(out, "#include <vector>\n");
289     fprintf(out, "#include <map>\n");
290     fprintf(out, "#include <set>\n");
291     fprintf(out, "\n");
292 
293     write_namespace(out, cppNamespace);
294     fprintf(out, "\n");
295     fprintf(out, "/*\n");
296     fprintf(out, " * API For logging statistics events.\n");
297     fprintf(out, " */\n");
298     fprintf(out, "\n");
299 
300     write_native_atom_constants(out, atoms, attributionDecl);
301 
302     // Print constants for the enum values.
303     fprintf(out, "//\n");
304     fprintf(out, "// Constants for enum values\n");
305     fprintf(out, "//\n\n");
306     for (AtomDeclSet::const_iterator atomIt = atoms.decls.begin(); atomIt != atoms.decls.end();
307          atomIt++) {
308         for (vector<AtomField>::const_iterator field = (*atomIt)->fields.begin();
309              field != (*atomIt)->fields.end(); field++) {
310             if (field->javaType == JAVA_TYPE_ENUM) {
311                 fprintf(out, "// Values for %s.%s\n", (*atomIt)->message.c_str(),
312                         field->name.c_str());
313                 for (map<int, string>::const_iterator value = field->enumValues.begin();
314                      value != field->enumValues.end(); value++) {
315                     fprintf(out, "const int32_t %s__%s__%s = %d;\n",
316                             make_constant_name((*atomIt)->message).c_str(),
317                             make_constant_name(field->name).c_str(),
318                             make_constant_name(value->second).c_str(), value->first);
319                 }
320                 fprintf(out, "\n");
321             }
322         }
323     }
324 
325     write_native_annotation_constants(out);
326 
327     fprintf(out, "struct BytesField {\n");
328     fprintf(out,
329             "  BytesField(char const* array, size_t len) : arg(array), "
330             "arg_length(len) {}\n");
331     fprintf(out, "  char const* arg;\n");
332     fprintf(out, "  size_t arg_length;\n");
333     fprintf(out, "};\n");
334     fprintf(out, "\n");
335 
336     // Print write methods
337     fprintf(out, "//\n");
338     fprintf(out, "// Write methods\n");
339     fprintf(out, "//\n");
340     write_native_method_header(out, "int stats_write", atoms.signatureInfoMap, attributionDecl);
341 
342     fprintf(out, "//\n");
343     fprintf(out, "// Write flattened methods\n");
344     fprintf(out, "//\n");
345     write_native_method_header(out, "int stats_write_non_chained", atoms.nonChainedSignatureInfoMap,
346                                attributionDecl);
347 
348     fprintf(out, "\n");
349     write_closing_namespace(out, cppNamespace);
350 
351     return 0;
352 }
353 
354 }  // namespace stats_log_api_gen
355 }  // namespace android
356