1 /*
2 * Copyright (C) 2023, 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_vendor.h"
18
19 #include <stdio.h>
20
21 #include <set>
22 #include <string>
23 #include <vector>
24
25 #include "Collation.h"
26 #include "utils.h"
27
28 namespace android {
29 namespace stats_log_api_gen {
30
31 using std::string;
32
write_native_vendor_annotation_header(FILE * out,const string & annotationName,const char * indent)33 static void write_native_vendor_annotation_header(FILE* out, const string& annotationName,
34 const char* indent) {
35 fprintf(out, "%s{\n", indent);
36 fprintf(out, "%s Annotation annotation;\n", indent);
37 fprintf(out, "%s annotation.annotationId = %s;\n", indent, annotationName.c_str());
38 }
39
write_native_vendor_annotation_footer(FILE * out,const char * indent)40 static void write_native_vendor_annotation_footer(FILE* out, const char* indent) {
41 fprintf(out, "%s annotations.push_back(std::move(annotation));\n", indent);
42 fprintf(out, "%s}\n", indent);
43 }
44
write_native_vendor_annotation_int(FILE * out,const string & annotationName,int value,const char * indent)45 static void write_native_vendor_annotation_int(FILE* out, const string& annotationName, int value,
46 const char* indent) {
47 write_native_vendor_annotation_header(out, annotationName, indent);
48 fprintf(out, "%sannotation.value.set<AnnotationValue::intValue>(%d);\n", indent, value);
49 write_native_vendor_annotation_footer(out, indent);
50 }
51
write_native_vendor_annotation_int_constant(FILE * out,const string & annotationName,const string & constantName,const char * indent)52 static void write_native_vendor_annotation_int_constant(FILE* out, const string& annotationName,
53 const string& constantName,
54 const char* indent) {
55 write_native_vendor_annotation_header(out, annotationName, indent);
56 fprintf(out, "%sannotation.value.set<AnnotationValue::intValue>(%s);\n", indent,
57 constantName.c_str());
58 write_native_vendor_annotation_footer(out, indent);
59 }
60
write_native_vendor_annotation_bool(FILE * out,const string & annotationName,bool value,const char * indent)61 static void write_native_vendor_annotation_bool(FILE* out, const string& annotationName, bool value,
62 const char* indent) {
63 write_native_vendor_annotation_header(out, annotationName, indent);
64 fprintf(out, "%sannotation.value.set<AnnotationValue::boolValue>(%s);\n", indent,
65 value ? "true" : "false");
66 write_native_vendor_annotation_footer(out, indent);
67 }
68
write_native_annotations_vendor_for_field(FILE * out,int argIndex,const AtomDeclSet & atomDeclSet)69 static void write_native_annotations_vendor_for_field(FILE* out, int argIndex,
70 const AtomDeclSet& atomDeclSet) {
71 if (atomDeclSet.empty()) {
72 return;
73 }
74
75 const char* indent = " ";
76 const char* indent2 = " ";
77 const char* indent3 = " ";
78
79 const int valueIndex = argIndex - 2;
80
81 const map<AnnotationId, AnnotationStruct>& ANNOTATION_ID_CONSTANTS =
82 get_annotation_id_constants(ANNOTATION_CONSTANT_NAME_VENDOR_NATIVE_PREFIX);
83
84 for (const shared_ptr<AtomDecl>& atomDecl : atomDeclSet) {
85 const string atomConstant = make_constant_name(atomDecl->name);
86 fprintf(out, "%sif (%s == code) {\n", indent, atomConstant.c_str());
87
88 if (argIndex == ATOM_ID_FIELD_NUMBER) {
89 fprintf(out, "%sstd::vector<std::optional<Annotation>> annotations;\n", indent2);
90 } else {
91 fprintf(out, "%sstd::vector<Annotation> annotations;\n", indent2);
92 }
93
94 const AnnotationSet& annotations = atomDecl->fieldNumberToAnnotations.at(argIndex);
95 int resetState = -1;
96 int defaultState = -1;
97 for (const shared_ptr<Annotation>& annotation : annotations) {
98 const AnnotationStruct& annotationConstant =
99 ANNOTATION_ID_CONSTANTS.at(annotation->annotationId);
100 switch (annotation->type) {
101 case ANNOTATION_TYPE_INT:
102 if (ANNOTATION_ID_TRIGGER_STATE_RESET == annotation->annotationId) {
103 resetState = annotation->value.intValue;
104 } else if (ANNOTATION_ID_DEFAULT_STATE == annotation->annotationId) {
105 defaultState = annotation->value.intValue;
106 } else if (ANNOTATION_ID_RESTRICTION_CATEGORY == annotation->annotationId) {
107 fprintf(out, "%s{\n", indent2);
108 write_native_vendor_annotation_int_constant(
109 out, annotationConstant.name,
110 get_restriction_category_str(annotation->value.intValue), indent3);
111 fprintf(out, "%s}\n", indent2);
112 } else {
113 fprintf(out, "%s{\n", indent2);
114 write_native_vendor_annotation_int(out, annotationConstant.name,
115 annotation->value.intValue, indent3);
116 fprintf(out, "%s}\n", indent2);
117 }
118 break;
119 case ANNOTATION_TYPE_BOOL:
120 fprintf(out, "%s{\n", indent2);
121 write_native_vendor_annotation_bool(out, annotationConstant.name,
122 annotation->value.boolValue, indent3);
123 fprintf(out, "%s}\n", indent2);
124 break;
125 default:
126 break;
127 }
128 }
129 if (defaultState != -1 && resetState != -1) {
130 const AnnotationStruct& annotationConstant =
131 ANNOTATION_ID_CONSTANTS.at(ANNOTATION_ID_TRIGGER_STATE_RESET);
132 fprintf(out, "%sif (arg%d == %d) {\n", indent2, argIndex, resetState);
133 write_native_vendor_annotation_int(out, annotationConstant.name, defaultState, indent3);
134 fprintf(out, "%s}\n", indent2);
135 }
136
137 if (argIndex == ATOM_ID_FIELD_NUMBER) {
138 fprintf(out, "%satomAnnotations = std::move(annotations);\n", indent2);
139 } else {
140 fprintf(out, "%sif (annotations.size() > 0) {\n", indent2);
141 fprintf(out, "%sAnnotationSet field%dAnnotations;\n", indent3, valueIndex);
142 fprintf(out, "%sfield%dAnnotations.valueIndex = %d;\n", indent3, valueIndex,
143 valueIndex);
144 fprintf(out, "%sfield%dAnnotations.annotations = std::move(annotations);\n", indent3,
145 valueIndex);
146 fprintf(out, "%sfieldsAnnotations.push_back(std::move(field%dAnnotations));\n", indent3,
147 valueIndex);
148 fprintf(out, "%s}\n", indent2);
149 }
150 fprintf(out, "%s}\n", indent);
151 }
152 }
153
write_native_create_vendor_atom_methods(FILE * out,const SignatureInfoMap & signatureInfoMap,const AtomDecl & attributionDecl)154 static int write_native_create_vendor_atom_methods(FILE* out,
155 const SignatureInfoMap& signatureInfoMap,
156 const AtomDecl& attributionDecl) {
157 fprintf(out, "\n");
158 for (const auto& [signature, fieldNumberToAtomDeclSet] : signatureInfoMap) {
159 // TODO (b/264922532): provide vendor implementation to skip arg1 for reverseDomainName
160 write_native_method_signature(out, "VendorAtom createVendorAtom(", signature,
161 attributionDecl, " {", /*isVendorAtomLogging=*/true);
162
163 fprintf(out, " VendorAtom atom;\n");
164
165 // Write method body.
166 fprintf(out, " atom.atomId = code;\n");
167 fprintf(out, " atom.reverseDomainName = arg1;\n");
168
169 // Exclude first field - which is reverseDomainName
170 const int vendorAtomValuesCount = signature.size() - 1;
171 fprintf(out, " vector<VendorAtomValue> values(%d);\n", vendorAtomValuesCount);
172
173 // Use 1-based index to access signature arguments
174 for (int argIndex = 2; argIndex <= signature.size(); argIndex++) {
175 const java_type_t& argType = signature[argIndex - 1];
176
177 const int atomValueIndex = argIndex - 2;
178
179 switch (argType) {
180 case JAVA_TYPE_ATTRIBUTION_CHAIN: {
181 fprintf(stderr, "Found attribution chain - not supported.\n");
182 return 1;
183 }
184 case JAVA_TYPE_BYTE_ARRAY:
185 fprintf(out,
186 " "
187 "values[%d].set<VendorAtomValue::byteArrayValue>(arg%d);\n",
188 atomValueIndex, argIndex);
189 break;
190 case JAVA_TYPE_BOOLEAN:
191 fprintf(out, " values[%d].set<VendorAtomValue::boolValue>(arg%d);\n",
192 atomValueIndex, argIndex);
193 break;
194 case JAVA_TYPE_INT:
195 [[fallthrough]];
196 case JAVA_TYPE_ENUM:
197 fprintf(out, " values[%d].set<VendorAtomValue::intValue>(arg%d);\n",
198 atomValueIndex, argIndex);
199 break;
200 case JAVA_TYPE_FLOAT:
201 fprintf(out, " values[%d].set<VendorAtomValue::floatValue>(arg%d);\n",
202 atomValueIndex, argIndex);
203 break;
204 case JAVA_TYPE_LONG:
205 fprintf(out, " values[%d].set<VendorAtomValue::longValue>(arg%d);\n",
206 atomValueIndex, argIndex);
207 break;
208 case JAVA_TYPE_STRING:
209 fprintf(out, " values[%d].set<VendorAtomValue::stringValue>(arg%d);\n",
210 atomValueIndex, argIndex);
211 break;
212 case JAVA_TYPE_BOOLEAN_ARRAY:
213 fprintf(out, " values[%d].set<VendorAtomValue::repeatedBoolValue>(arg%d);\n",
214 atomValueIndex, argIndex);
215 break;
216 case JAVA_TYPE_INT_ARRAY:
217 [[fallthrough]];
218 case JAVA_TYPE_ENUM_ARRAY:
219 fprintf(out, " values[%d].set<VendorAtomValue::repeatedIntValue>(arg%d);\n",
220 atomValueIndex, argIndex);
221 break;
222 case JAVA_TYPE_FLOAT_ARRAY:
223 fprintf(out,
224 " values[%d].set<VendorAtomValue::repeatedFloatValue>(arg%d);\n",
225 atomValueIndex, argIndex);
226 break;
227 case JAVA_TYPE_LONG_ARRAY:
228 fprintf(out, " values[%d].set<VendorAtomValue::repeatedLongValue>(arg%d);\n",
229 atomValueIndex, argIndex);
230 break;
231 case JAVA_TYPE_STRING_ARRAY:
232 fprintf(out, " {\n");
233 fprintf(out, " vector<optional<string>> arrayValue(\n");
234 fprintf(out, " arg%d.begin(), arg%d.end());\n", argIndex, argIndex);
235 fprintf(out,
236 " "
237 "values[%d].set<VendorAtomValue::repeatedStringValue>(std::move("
238 "arrayValue));\n",
239 atomValueIndex);
240 fprintf(out, " }\n");
241 break;
242 default:
243 // Unsupported types: OBJECT, DOUBLE
244 fprintf(stderr, "Encountered unsupported type.\n");
245 return 1;
246 }
247 }
248 fprintf(out, " atom.values = std::move(values);\n"); // end method body.
249
250 // check will be there an atom for this signature with atom level annotations
251 const AtomDeclSet atomAnnotations =
252 get_annotations(ATOM_ID_FIELD_NUMBER, fieldNumberToAtomDeclSet);
253 if (atomAnnotations.size()) {
254 fprintf(out, " std::vector<std::optional<Annotation>> atomAnnotations;\n");
255 write_native_annotations_vendor_for_field(out, ATOM_ID_FIELD_NUMBER, atomAnnotations);
256 fprintf(out, " if (atomAnnotations.size() > 0) {\n");
257 fprintf(out, " atom.atomAnnotations = std::move(atomAnnotations);\n");
258 fprintf(out, " }\n\n");
259 }
260
261 // Create fieldsAnnotations instance only in case if there is an atom fields with annotation
262 // for this signature
263 bool atomWithFieldsAnnotation = false;
264 for (int argIndex = 2; argIndex <= signature.size(); argIndex++) {
265 if (get_annotations(argIndex, fieldNumberToAtomDeclSet).size() > 0) {
266 atomWithFieldsAnnotation = true;
267 break;
268 }
269 }
270
271 if (atomWithFieldsAnnotation) {
272 fprintf(out, " std::vector<std::optional<AnnotationSet>> fieldsAnnotations;\n");
273 for (int argIndex = 2; argIndex <= signature.size(); argIndex++) {
274 const AtomDeclSet fieldAnnotations =
275 get_annotations(argIndex, fieldNumberToAtomDeclSet);
276 write_native_annotations_vendor_for_field(out, argIndex, fieldAnnotations);
277 }
278 fprintf(out, " if (fieldsAnnotations.size() > 0) {\n");
279 fprintf(out, " atom.valuesAnnotations = std::move(fieldsAnnotations);\n");
280 fprintf(out, " }\n\n");
281 }
282
283 fprintf(out, " // elision of copy operations is permitted on return\n");
284 fprintf(out, " return atom;\n");
285 fprintf(out, "}\n\n"); // end method.
286 }
287 return 0;
288 }
289
write_stats_log_cpp_vendor(FILE * out,const Atoms & atoms,const AtomDecl & attributionDecl,const string & cppNamespace,const string & importHeader)290 int write_stats_log_cpp_vendor(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
291 const string& cppNamespace, const string& importHeader) {
292 // Print prelude
293 fprintf(out, "// This file is autogenerated\n");
294 fprintf(out, "\n");
295
296 fprintf(out, "#include <%s>\n", importHeader.c_str());
297 fprintf(out, "#include <aidl/android/frameworks/stats/VendorAtom.h>\n");
298
299 fprintf(out, "\n");
300 write_namespace(out, cppNamespace);
301 fprintf(out, "\n");
302 fprintf(out, "using namespace aidl::android::frameworks::stats;\n");
303 fprintf(out, "using std::make_optional;\n");
304 fprintf(out, "using std::optional;\n");
305 fprintf(out, "using std::vector;\n");
306 fprintf(out, "using std::string;\n");
307
308 const int ret =
309 write_native_create_vendor_atom_methods(out, atoms.signatureInfoMap, attributionDecl);
310 if (ret != 0) {
311 return ret;
312 }
313 // Print footer
314 fprintf(out, "\n");
315 write_closing_namespace(out, cppNamespace);
316
317 return 0;
318 }
319
write_stats_log_header_vendor(FILE * out,const Atoms & atoms,const AtomDecl & attributionDecl,const string & cppNamespace)320 int write_stats_log_header_vendor(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
321 const string& cppNamespace) {
322 write_native_header_preamble(out, cppNamespace, false, /*isVendorAtomLogging=*/true);
323 write_native_atom_constants(out, atoms, attributionDecl, "createVendorAtom(",
324 /*isVendorAtomLogging=*/true);
325
326 for (AtomDeclSet::const_iterator atomIt = atoms.decls.begin(); atomIt != atoms.decls.end();
327 atomIt++) {
328 set<string> processedEnums;
329
330 for (vector<AtomField>::const_iterator field = (*atomIt)->fields.begin();
331 field != (*atomIt)->fields.end(); field++) {
332 if (field->javaType == JAVA_TYPE_ENUM || field->javaType == JAVA_TYPE_ENUM_ARRAY) {
333 // There might be N fields with the same enum type
334 // avoid duplication definitions
335 if (processedEnums.find(field->enumTypeName) != processedEnums.end()) {
336 continue;
337 }
338
339 if (processedEnums.empty()) {
340 fprintf(out, "class %s final {\n", (*atomIt)->message.c_str());
341 fprintf(out, "public:\n\n");
342 }
343
344 processedEnums.insert(field->enumTypeName);
345
346 fprintf(out, "enum %s {\n", field->enumTypeName.c_str());
347 size_t i = 0;
348 for (map<int, string>::const_iterator value = field->enumValues.begin();
349 value != field->enumValues.end(); value++) {
350 fprintf(out, " %s = %d", make_constant_name(value->second).c_str(),
351 value->first);
352 char const* const comma = (i == field->enumValues.size() - 1) ? "" : ",";
353 fprintf(out, "%s\n", comma);
354 i++;
355 }
356
357 fprintf(out, "};\n");
358 }
359 }
360 if (!processedEnums.empty()) {
361 fprintf(out, "};\n\n");
362 }
363 }
364
365 fprintf(out, "using ::aidl::android::frameworks::stats::VendorAtom;\n");
366
367 // Print write methods
368 fprintf(out, "//\n");
369 fprintf(out, "// Write methods\n");
370 fprintf(out, "//\n");
371 write_native_method_header(out, "VendorAtom createVendorAtom(", atoms.signatureInfoMap,
372 attributionDecl,
373 /*isVendorAtomLogging=*/true);
374 fprintf(out, "\n");
375
376 write_native_header_epilogue(out, cppNamespace);
377
378 return 0;
379 }
380
381 } // namespace stats_log_api_gen
382 } // namespace android
383