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 #include "native_writer_q.h"
19 #include "utils.h"
20 
21 namespace android {
22 namespace stats_log_api_gen {
23 
24 #if !defined(STATS_SCHEMA_LEGACY)
write_native_key_value_pairs_for_type(FILE * out,const int argIndex,const int typeIndex,const string & type,const string & valueFieldName)25 static void write_native_key_value_pairs_for_type(FILE* out, const int argIndex,
26         const int typeIndex, const string& type, const string& valueFieldName) {
27     fprintf(out, "    for (const auto& it : arg%d_%d) {\n", argIndex, typeIndex);
28     fprintf(out, "        pairs.push_back("
29             "{ .key = it.first, .valueType = %s, .%s = it.second });\n",
30             type.c_str(), valueFieldName.c_str());
31     fprintf(out, "    }\n");
32 
33 }
34 
write_native_stats_write_methods(FILE * out,const Atoms & atoms,const AtomDecl & attributionDecl,const string & moduleName,const bool supportQ)35 static int write_native_stats_write_methods(FILE* out, const Atoms& atoms,
36         const AtomDecl& attributionDecl, const string& moduleName, const bool supportQ) {
37     fprintf(out, "\n");
38     for (auto signature_to_modules_it = atoms.signatures_to_modules.begin();
39         signature_to_modules_it != atoms.signatures_to_modules.end(); signature_to_modules_it++) {
40         if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) {
41             continue;
42         }
43         vector<java_type_t> signature = signature_to_modules_it->first;
44 
45         write_native_method_signature(out, "int stats_write", signature,
46                 attributionDecl, " {");
47 
48         int argIndex = 1;
49         if (supportQ) {
50             fprintf(out, "    StatsEventCompat event;\n");
51             fprintf(out, "    event.setAtomId(code);\n");
52             for (vector<java_type_t>::const_iterator arg = signature.begin();
53                     arg != signature.end(); arg++) {
54                 switch (*arg) {
55                     case JAVA_TYPE_ATTRIBUTION_CHAIN: {
56                         const char* uidName = attributionDecl.fields.front().name.c_str();
57                         const char* tagName = attributionDecl.fields.back().name.c_str();
58                         fprintf(out, "    event.writeAttributionChain(%s, %s_length, %s);\n",
59                                 uidName, uidName, tagName);
60                         break;
61                     }
62                     case JAVA_TYPE_KEY_VALUE_PAIR:
63                         fprintf(out, "    event.writeKeyValuePairs("
64                                 "arg%d_1, arg%d_2, arg%d_3, arg%d_4);\n",
65                                 argIndex, argIndex, argIndex, argIndex);
66                         break;
67                     case JAVA_TYPE_BYTE_ARRAY:
68                         fprintf(out, "    event.writeByteArray(arg%d.arg, arg%d.arg_length);\n",
69                                 argIndex, argIndex);
70                         break;
71                     case JAVA_TYPE_BOOLEAN:
72                         fprintf(out, "    event.writeBool(arg%d);\n", argIndex);
73                         break;
74                     case JAVA_TYPE_INT: // Fall through.
75                     case JAVA_TYPE_ENUM:
76                         fprintf(out, "    event.writeInt32(arg%d);\n", argIndex);
77                         break;
78                     case JAVA_TYPE_FLOAT:
79                         fprintf(out, "    event.writeFloat(arg%d);\n", argIndex);
80                         break;
81                     case JAVA_TYPE_LONG:
82                         fprintf(out, "    event.writeInt64(arg%d);\n", argIndex);
83                         break;
84                     case JAVA_TYPE_STRING:
85                         fprintf(out, "    event.writeString(arg%d);\n", argIndex);
86                         break;
87                     default:
88                         // Unsupported types: OBJECT, DOUBLE.
89                         fprintf(stderr, "Encountered unsupported type.");
90                         return 1;
91                 }
92                 argIndex++;
93             }
94             fprintf(out, "    return event.writeToSocket();\n");
95         } else {
96             fprintf(out, "    struct stats_event* event = stats_event_obtain();\n");
97             fprintf(out, "    stats_event_set_atom_id(event, code);\n");
98             for (vector<java_type_t>::const_iterator arg = signature.begin();
99                     arg != signature.end(); arg++) {
100                 switch (*arg) {
101                     case JAVA_TYPE_ATTRIBUTION_CHAIN: {
102                         const char* uidName = attributionDecl.fields.front().name.c_str();
103                         const char* tagName = attributionDecl.fields.back().name.c_str();
104                         fprintf(out,
105                                 "    stats_event_write_attribution_chain(event, "
106                                 "reinterpret_cast<const uint32_t*>(%s), %s.data(), "
107                                 "static_cast<uint8_t>(%s_length));\n",
108                                 uidName, tagName, uidName);
109                         break;
110                     }
111                     case JAVA_TYPE_KEY_VALUE_PAIR:
112                         fprintf(out, "    std::vector<key_value_pair> pairs;\n");
113                         write_native_key_value_pairs_for_type(
114                                 out, argIndex, 1, "INT32_TYPE", "int32Value");
115                         write_native_key_value_pairs_for_type(
116                                 out, argIndex, 2, "INT64_TYPE", "int64Value");
117                         write_native_key_value_pairs_for_type(
118                                 out, argIndex, 3, "STRING_TYPE", "stringValue");
119                         write_native_key_value_pairs_for_type(
120                                 out, argIndex, 4, "FLOAT_TYPE", "floatValue");
121                         fprintf(out,
122                                 "    stats_event_write_key_value_pairs(event, pairs.data(), "
123                                 "static_cast<uint8_t>(pairs.size()));\n");
124                         break;
125                     case JAVA_TYPE_BYTE_ARRAY:
126                         fprintf(out,
127                                 "    stats_event_write_byte_array(event, "
128                                 "reinterpret_cast<const uint8_t*>(arg%d.arg), arg%d.arg_length);\n",
129                                 argIndex, argIndex);
130                         break;
131                     case JAVA_TYPE_BOOLEAN:
132                         fprintf(out, "    stats_event_write_bool(event, arg%d);\n", argIndex);
133                         break;
134                     case JAVA_TYPE_INT: // Fall through.
135                     case JAVA_TYPE_ENUM:
136                         fprintf(out, "    stats_event_write_int32(event, arg%d);\n", argIndex);
137                         break;
138                     case JAVA_TYPE_FLOAT:
139                         fprintf(out, "    stats_event_write_float(event, arg%d);\n", argIndex);
140                         break;
141                     case JAVA_TYPE_LONG:
142                         fprintf(out, "    stats_event_write_int64(event, arg%d);\n", argIndex);
143                         break;
144                     case JAVA_TYPE_STRING:
145                         fprintf(out, "    stats_event_write_string8(event, arg%d);\n", argIndex);
146                         break;
147                     default:
148                         // Unsupported types: OBJECT, DOUBLE.
149                         fprintf(stderr, "Encountered unsupported type.");
150                         return 1;
151                 }
152                 argIndex++;
153             }
154             fprintf(out, "    const int ret = stats_event_write(event);\n");
155             fprintf(out, "    stats_event_release(event);\n");
156             fprintf(out, "    return ret;\n");
157         }
158         fprintf(out, "}\n\n");
159     }
160     return 0;
161 }
162 
write_native_stats_write_non_chained_methods(FILE * out,const Atoms & atoms,const AtomDecl & attributionDecl,const string & moduleName)163 static void write_native_stats_write_non_chained_methods(FILE* out, const Atoms& atoms,
164         const AtomDecl& attributionDecl, const string& moduleName) {
165     fprintf(out, "\n");
166     for (auto signature_it = atoms.non_chained_signatures_to_modules.begin();
167             signature_it != atoms.non_chained_signatures_to_modules.end(); signature_it++) {
168         if (!signature_needed_for_module(signature_it->second, moduleName)) {
169             continue;
170         }
171         vector<java_type_t> signature = signature_it->first;
172 
173         write_native_method_signature(out, "int stats_write_non_chained", signature,
174                 attributionDecl, " {");
175 
176         vector<java_type_t> newSignature;
177 
178         // First two args form the attribution node so size goes down by 1.
179         newSignature.reserve(signature.size() - 1);
180 
181         // First arg is Attribution Chain.
182         newSignature.push_back(JAVA_TYPE_ATTRIBUTION_CHAIN);
183 
184         // Followed by the originial signature except the first 2 args.
185         newSignature.insert(newSignature.end(), signature.begin() + 2, signature.end());
186 
187         const char* uidName = attributionDecl.fields.front().name.c_str();
188         const char* tagName = attributionDecl.fields.back().name.c_str();
189         fprintf(out, "    const int32_t* %s = &arg1;\n", uidName);
190         fprintf(out, "    const size_t %s_length = 1;\n", uidName);
191         fprintf(out, "    const std::vector<char const*> %s(1, arg2);\n", tagName);
192         fprintf(out, "    return ");
193         write_native_method_call(out, "stats_write", newSignature, attributionDecl, 2);
194 
195         fprintf(out, "}\n\n");
196     }
197 
198 }
199 #endif
200 
write_native_method_header(FILE * out,const string & methodName,const map<vector<java_type_t>,set<string>> & signatures_to_modules,const AtomDecl & attributionDecl,const string & moduleName)201 static void write_native_method_header(
202         FILE* out,
203         const string& methodName,
204         const map<vector<java_type_t>, set<string>>& signatures_to_modules,
205         const AtomDecl &attributionDecl, const string& moduleName) {
206 
207     for (auto signature_to_modules_it = signatures_to_modules.begin();
208             signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
209         // Skip if this signature is not needed for the module.
210         if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) {
211             continue;
212         }
213 
214         vector<java_type_t> signature = signature_to_modules_it->first;
215         write_native_method_signature(out, methodName, signature, attributionDecl, ";");
216     }
217 }
218 
write_stats_log_cpp(FILE * out,const Atoms & atoms,const AtomDecl & attributionDecl,const string & moduleName,const string & cppNamespace,const string & importHeader,const bool supportQ)219 int write_stats_log_cpp(FILE *out, const Atoms &atoms, const AtomDecl &attributionDecl,
220                         const string& moduleName, const string& cppNamespace,
221                         const string& importHeader, const bool supportQ) {
222     // Print prelude
223     fprintf(out, "// This file is autogenerated\n");
224     fprintf(out, "\n");
225 
226     fprintf(out, "#include <%s>\n", importHeader.c_str());
227 #if defined(STATS_SCHEMA_LEGACY)
228     (void)supportQ; // Workaround for unused parameter error.
229     write_native_cpp_includes_q(out);
230 #else
231     if (supportQ) {
232         fprintf(out, "#include <StatsEventCompat.h>\n");
233     } else {
234         fprintf(out, "#include <stats_event.h>\n");
235     }
236 #endif
237 
238     fprintf(out, "\n");
239     write_namespace(out, cppNamespace);
240 
241 #if defined(STATS_SCHEMA_LEGACY)
242     write_native_stats_log_cpp_globals_q(out);
243     write_native_get_timestamp_ns_q(out);
244     write_native_try_stats_write_methods_q(out, atoms, attributionDecl, moduleName);
245     write_native_stats_write_methods_q(out, "int stats_write", atoms, attributionDecl, moduleName,
246             "try_stats_write");
247     write_native_try_stats_write_non_chained_methods_q(out, atoms, attributionDecl, moduleName);
248     write_native_stats_write_non_chained_methods_q(out, "int stats_write_non_chained", atoms,
249             attributionDecl, moduleName, "try_stats_write_non_chained");
250 #else
251     write_native_stats_write_methods(out, atoms, attributionDecl, moduleName, supportQ);
252     write_native_stats_write_non_chained_methods(out, atoms, attributionDecl, moduleName);
253 #endif
254 
255     // Print footer
256     fprintf(out, "\n");
257     write_closing_namespace(out, cppNamespace);
258 
259     return 0;
260 }
261 
write_stats_log_header(FILE * out,const Atoms & atoms,const AtomDecl & attributionDecl,const string & moduleName,const string & cppNamespace)262 int write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl,
263         const string& moduleName, const string& cppNamespace) {
264     // Print prelude
265     fprintf(out, "// This file is autogenerated\n");
266     fprintf(out, "\n");
267     fprintf(out, "#pragma once\n");
268     fprintf(out, "\n");
269     fprintf(out, "#include <stdint.h>\n");
270     fprintf(out, "#include <vector>\n");
271     fprintf(out, "#include <map>\n");
272     fprintf(out, "#include <set>\n");
273     fprintf(out, "\n");
274 
275     write_namespace(out, cppNamespace);
276     fprintf(out, "\n");
277     fprintf(out, "/*\n");
278     fprintf(out, " * API For logging statistics events.\n");
279     fprintf(out, " */\n");
280     fprintf(out, "\n");
281 
282     write_native_atom_constants(out, atoms, attributionDecl, moduleName);
283 
284     // Print constants for the enum values.
285     fprintf(out, "//\n");
286     fprintf(out, "// Constants for enum values\n");
287     fprintf(out, "//\n\n");
288     for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
289         atom != atoms.decls.end(); atom++) {
290         // Skip if the atom is not needed for the module.
291         if (!atom_needed_for_module(*atom, moduleName)) {
292             continue;
293         }
294 
295         for (vector<AtomField>::const_iterator field = atom->fields.begin();
296             field != atom->fields.end(); field++) {
297             if (field->javaType == JAVA_TYPE_ENUM) {
298                 fprintf(out, "// Values for %s.%s\n", atom->message.c_str(),
299                     field->name.c_str());
300                 for (map<int, string>::const_iterator value = field->enumValues.begin();
301                     value != field->enumValues.end(); value++) {
302                     fprintf(out, "const int32_t %s__%s__%s = %d;\n",
303                         make_constant_name(atom->message).c_str(),
304                         make_constant_name(field->name).c_str(),
305                         make_constant_name(value->second).c_str(),
306                         value->first);
307                 }
308                 fprintf(out, "\n");
309             }
310         }
311     }
312 
313     fprintf(out, "struct BytesField {\n");
314     fprintf(out,
315             "  BytesField(char const* array, size_t len) : arg(array), "
316             "arg_length(len) {}\n");
317     fprintf(out, "  char const* arg;\n");
318     fprintf(out, "  size_t arg_length;\n");
319     fprintf(out, "};\n");
320     fprintf(out, "\n");
321 
322     // Print write methods
323     fprintf(out, "//\n");
324     fprintf(out, "// Write methods\n");
325     fprintf(out, "//\n");
326     write_native_method_header(out, "int stats_write", atoms.signatures_to_modules, attributionDecl,
327             moduleName);
328 
329     fprintf(out, "//\n");
330     fprintf(out, "// Write flattened methods\n");
331     fprintf(out, "//\n");
332     write_native_method_header(out, "int stats_write_non_chained",
333             atoms.non_chained_signatures_to_modules, attributionDecl, moduleName);
334 
335     fprintf(out, "\n");
336     write_closing_namespace(out, cppNamespace);
337 
338     return 0;
339 }
340 
341 }  // namespace stats_log_api_gen
342 }  // namespace android
343