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