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 "java_writer_vendor.h"
18
19 #include <stdio.h>
20
21 #include <algorithm>
22 #include <map>
23 #include <memory>
24 #include <set>
25 #include <string>
26 #include <vector>
27
28 #include "Collation.h"
29 #include "utils.h"
30
31 namespace android {
32 namespace stats_log_api_gen {
33
write_vendor_annotation_int(FILE * out,const string & annotationName,int value,const char * indent)34 static void write_vendor_annotation_int(FILE* out, const string& annotationName, int value,
35 const char* indent) {
36 fprintf(out, "%s{\n", indent);
37 fprintf(out, "%s Annotation annotation = new Annotation();\n", indent);
38 fprintf(out, "%s annotation.annotationId = %s;\n", indent, annotationName.c_str());
39 fprintf(out, "%s annotation.value = AnnotationValue.intValue(%d);\n", indent, value);
40 fprintf(out, "%s annotations[annotationIdx] = annotation;\n", indent);
41 fprintf(out, "%s annotationIdx++;\n", indent);
42 fprintf(out, "%s}\n", indent);
43 }
44
write_vendor_annotation_int_constant(FILE * out,const string & annotationName,const string & constantName,const char * indent)45 static void write_vendor_annotation_int_constant(FILE* out, const string& annotationName,
46 const string& constantName, const char* indent) {
47 fprintf(out, "%s{\n", indent);
48 fprintf(out, "%s Annotation annotation = new Annotation();\n", indent);
49 fprintf(out, "%s annotation.annotationId = %s;\n", indent, annotationName.c_str());
50 fprintf(out, "%s annotation.value = AnnotationValue.intValue(%s);\n", indent,
51 constantName.c_str());
52 fprintf(out, "%s annotations[annotationIdx] = annotation;\n", indent);
53 fprintf(out, "%s annotationIdx++;\n", indent);
54 fprintf(out, "%s}\n", indent);
55 }
56
write_vendor_annotation_bool(FILE * out,const string & annotationName,bool value,const char * indent)57 static void write_vendor_annotation_bool(FILE* out, const string& annotationName, bool value,
58 const char* indent) {
59 fprintf(out, "%s{\n", indent);
60 fprintf(out, "%s Annotation annotation = new Annotation();\n", indent);
61 fprintf(out, "%s annotation.annotationId = %s;\n", indent, annotationName.c_str());
62 fprintf(out, "%s annotation.value = AnnotationValue.boolValue(%s);\n", indent,
63 value ? "true" : "false");
64 fprintf(out, "%s annotations[annotationIdx] = annotation;\n", indent);
65 fprintf(out, "%s annotationIdx++;\n", indent);
66 fprintf(out, "%s}\n", indent);
67 }
68
write_value_annotations_array_init(FILE * out,const AtomDeclSet & atomDeclSet,set<string> & processedAtomNames)69 static bool write_value_annotations_array_init(FILE* out, const AtomDeclSet& atomDeclSet,
70 set<string>& processedAtomNames) {
71 const char* indent = " ";
72
73 for (const shared_ptr<AtomDecl>& atomDecl : atomDeclSet) {
74 const string atomConstant = make_constant_name(atomDecl->name);
75 if (processedAtomNames.find(atomConstant) != processedAtomNames.end()) {
76 continue;
77 }
78 processedAtomNames.insert(atomConstant);
79 fprintf(out, "%sif (%s == atomId) {\n", indent, atomConstant.c_str());
80 fprintf(out, "%s fieldsAnnotations = new ArrayList<AnnotationSet>();\n", indent);
81 fprintf(out, "%s}\n", indent);
82 }
83 return true;
84 }
85
write_annotations_vendor_for_field(FILE * out,int argIndex,const AtomDeclSet & atomDeclSet)86 static bool write_annotations_vendor_for_field(FILE* out, int argIndex,
87 const AtomDeclSet& atomDeclSet) {
88 const char* indent = " ";
89 const char* indent2 = " ";
90 const char* indent3 = " ";
91
92 const map<AnnotationId, AnnotationStruct>& annotationIdConstants =
93 get_annotation_id_constants(ANNOTATION_CONSTANT_NAME_VENDOR_PREFIX);
94
95 for (const shared_ptr<AtomDecl>& atomDecl : atomDeclSet) {
96 const string atomConstant = make_constant_name(atomDecl->name);
97 fprintf(out, "%sif (%s == atomId) {\n", indent, atomConstant.c_str());
98
99 const AnnotationSet& annotations = atomDecl->fieldNumberToAnnotations.at(argIndex);
100 // calculate annotations amount upfront
101 // search for a trigger reset state & default state annotation
102 int resetState = -1;
103 int defaultState = -1;
104 for (const shared_ptr<Annotation>& annotation : annotations) {
105 switch (annotation->type) {
106 case ANNOTATION_TYPE_INT:
107 if (ANNOTATION_ID_TRIGGER_STATE_RESET == annotation->annotationId) {
108 resetState = annotation->value.intValue;
109 } else if (ANNOTATION_ID_DEFAULT_STATE == annotation->annotationId) {
110 defaultState = annotation->value.intValue;
111 }
112 break;
113 default:
114 break;
115 }
116 }
117
118 const int annotationsCount = std::count_if(
119 annotations.begin(), annotations.end(),
120 [](const shared_ptr<Annotation>& annotation) {
121 return (annotation->type == ANNOTATION_TYPE_INT &&
122 (ANNOTATION_ID_TRIGGER_STATE_RESET != annotation->annotationId &&
123 ANNOTATION_ID_DEFAULT_STATE != annotation->annotationId)) ||
124 annotation->type == ANNOTATION_TYPE_BOOL;
125 });
126
127 fprintf(out, "%sint annotationsCount = %d;\n", indent2, annotationsCount);
128 if (defaultState != -1 && resetState != -1) {
129 fprintf(out, "%sif (arg%d == %d) {\n", indent2, argIndex, resetState);
130 fprintf(out, "%s annotationsCount++;\n", indent2);
131 fprintf(out, "%s}\n", indent2);
132 }
133 fprintf(out, "%sAnnotation[] annotations = new Annotation[annotationsCount];\n", indent2);
134 fprintf(out, "%sint annotationIdx = 0;\n", indent2);
135
136 for (const shared_ptr<Annotation>& annotation : annotations) {
137 const AnnotationStruct& annotationConstant =
138 annotationIdConstants.at(annotation->annotationId);
139 switch (annotation->type) {
140 case ANNOTATION_TYPE_INT:
141 if (ANNOTATION_ID_RESTRICTION_CATEGORY == annotation->annotationId) {
142 write_vendor_annotation_int_constant(
143 out, annotationConstant.name,
144 get_restriction_category_str(annotation->value.intValue), indent2);
145 } else if (ANNOTATION_ID_TRIGGER_STATE_RESET != annotation->annotationId &&
146 ANNOTATION_ID_DEFAULT_STATE != annotation->annotationId) {
147 write_vendor_annotation_int(out, annotationConstant.name,
148 annotation->value.intValue, indent2);
149 }
150 break;
151 case ANNOTATION_TYPE_BOOL:
152 write_vendor_annotation_bool(out, annotationConstant.name,
153 annotation->value.boolValue, indent2);
154 break;
155 default:
156 break;
157 }
158 }
159 if (defaultState != -1 && resetState != -1) {
160 const AnnotationStruct& annotationConstant =
161 annotationIdConstants.at(ANNOTATION_ID_TRIGGER_STATE_RESET);
162 fprintf(out, "%sif (arg%d == %d)", indent2, argIndex, resetState);
163 write_vendor_annotation_int(out, annotationConstant.name, defaultState, indent2);
164 }
165
166 if (argIndex == ATOM_ID_FIELD_NUMBER) {
167 fprintf(out, "%satomAnnotations = annotations;\n", indent2);
168 } else {
169 const int valueIndex = argIndex - 2;
170 fprintf(out, "%sif (annotationsCount > 0) {\n", indent2);
171 fprintf(out, "%sAnnotationSet field%dAnnotations = new AnnotationSet();\n", indent3,
172 valueIndex);
173 fprintf(out, "%sfield%dAnnotations.valueIndex = %d;\n", indent3, valueIndex,
174 valueIndex);
175 fprintf(out, "%sfield%dAnnotations.annotations = annotations;\n", indent3, valueIndex);
176 fprintf(out, "%sfieldsAnnotations.add(field%dAnnotations);\n", indent3, valueIndex);
177 fprintf(out, "%s}\n", indent2);
178 }
179 fprintf(out, "%s}\n", indent);
180 }
181
182 return true;
183 }
184
write_method_body_vendor(FILE * out,const vector<java_type_t> & signature,const FieldNumberToAtomDeclSet & fieldNumberToAtomDeclSet)185 static int write_method_body_vendor(FILE* out, const vector<java_type_t>& signature,
186 const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet) {
187 const char* indent = " ";
188
189 // Write atom code.
190 fprintf(out, "%sVendorAtom atom = new VendorAtom();\n", indent);
191 fprintf(out, "%satom.reverseDomainName = arg1;\n", indent);
192 fprintf(out, "%satom.atomId = atomId;\n", indent);
193 fprintf(out, "%satom.values = new VendorAtomValue[%ld];\n", indent, signature.size() - 1);
194
195 for (int argIndex = 2; argIndex <= signature.size(); argIndex++) {
196 const java_type_t& argType = signature[argIndex - 1];
197 const int atomValueIndex = argIndex - 2;
198 switch (argType) {
199 case JAVA_TYPE_ATTRIBUTION_CHAIN: {
200 fprintf(stderr, "Found attribution chain - not supported.\n");
201 return 1;
202 }
203 case JAVA_TYPE_BYTE_ARRAY:
204 fprintf(out, "%satom.values[%d] = VendorAtomValue.byteArrayValue(arg%d);\n", indent,
205 atomValueIndex, argIndex);
206 break;
207 case JAVA_TYPE_BOOLEAN:
208 fprintf(out, "%satom.values[%d] = VendorAtomValue.boolValue(arg%d);\n", indent,
209 atomValueIndex, argIndex);
210 break;
211 case JAVA_TYPE_INT:
212 [[fallthrough]];
213 case JAVA_TYPE_ENUM:
214 fprintf(out, "%satom.values[%d] = VendorAtomValue.intValue(arg%d);\n", indent,
215 atomValueIndex, argIndex);
216 break;
217 case JAVA_TYPE_FLOAT:
218 fprintf(out, "%satom.values[%d] = VendorAtomValue.floatValue(arg%d);\n", indent,
219 atomValueIndex, argIndex);
220 break;
221 case JAVA_TYPE_LONG:
222 fprintf(out, "%satom.values[%d] = VendorAtomValue.longValue(arg%d);\n", indent,
223 atomValueIndex, argIndex);
224 break;
225 case JAVA_TYPE_STRING:
226 fprintf(out, "%satom.values[%d] = VendorAtomValue.stringValue(arg%d);\n", indent,
227 atomValueIndex, argIndex);
228 break;
229 case JAVA_TYPE_BOOLEAN_ARRAY:
230 fprintf(out, "%satom.values[%d] = VendorAtomValue.repeatedBoolValue(arg%d);\n",
231 indent, atomValueIndex, argIndex);
232 break;
233 case JAVA_TYPE_INT_ARRAY:
234 [[fallthrough]];
235 case JAVA_TYPE_ENUM_ARRAY:
236 fprintf(out, "%satom.values[%d] = VendorAtomValue.repeatedIntValue(arg%d);\n",
237 indent, atomValueIndex, argIndex);
238 break;
239 case JAVA_TYPE_FLOAT_ARRAY:
240 fprintf(out, "%satom.values[%d] = VendorAtomValue.repeatedFloatValue(arg%d);\n",
241 indent, atomValueIndex, argIndex);
242 break;
243 case JAVA_TYPE_LONG_ARRAY:
244 fprintf(out, "%satom.values[%d] = VendorAtomValue.repeatedLongValue(arg%d);\n",
245 indent, atomValueIndex, argIndex);
246 break;
247 case JAVA_TYPE_STRING_ARRAY:
248 fprintf(out, "%satom.values[%d] = VendorAtomValue.repeatedStringValue(arg%d);\n",
249 indent, atomValueIndex, argIndex);
250 break;
251 default:
252 // Unsupported types: OBJECT, DOUBLE
253 fprintf(stderr, "Encountered unsupported type.\n");
254 return 1;
255 }
256 }
257
258 // check will be there an atom for this signature with atom level annotations
259 const AtomDeclSet atomAnnotations =
260 get_annotations(ATOM_ID_FIELD_NUMBER, fieldNumberToAtomDeclSet);
261 if (atomAnnotations.size()) {
262 fprintf(out, "%sAnnotation[] atomAnnotations = null;\n", indent);
263 write_annotations_vendor_for_field(out, ATOM_ID_FIELD_NUMBER, atomAnnotations);
264 fprintf(out, "%sif (atomAnnotations != null && atomAnnotations.length > 0) {\n", indent);
265 fprintf(out, "%s atom.atomAnnotations = atomAnnotations;\n", indent);
266 fprintf(out, "%s}\n", indent);
267 }
268
269 // Create fieldsAnnotations instance only in case if there is an atom fields with annotation
270 // for this signature
271 bool atomWithFieldsAnnotation = false;
272 for (int argIndex = 2; argIndex <= signature.size(); argIndex++) {
273 if (get_annotations(argIndex, fieldNumberToAtomDeclSet).size() > 0) {
274 atomWithFieldsAnnotation = true;
275 break;
276 }
277 }
278
279 if (atomWithFieldsAnnotation) {
280 fprintf(out, "%sArrayList<AnnotationSet> fieldsAnnotations = null;\n", indent);
281 set<string> processedAtomNames;
282 for (int argIndex = 2; argIndex <= signature.size(); argIndex++) {
283 const AtomDeclSet fieldAnnotations =
284 get_annotations(argIndex, fieldNumberToAtomDeclSet);
285 write_value_annotations_array_init(out, fieldAnnotations, processedAtomNames);
286 }
287
288 for (int argIndex = 2; argIndex <= signature.size(); argIndex++) {
289 const AtomDeclSet fieldAnnotations =
290 get_annotations(argIndex, fieldNumberToAtomDeclSet);
291 write_annotations_vendor_for_field(out, argIndex, fieldAnnotations);
292 }
293 fprintf(out, "%sif (fieldsAnnotations != null && fieldsAnnotations.size() > 0) {\n",
294 indent);
295 // Converting ArrayList<AnnotationSet> to annotationSet[]
296 fprintf(out,
297 "%s atom.valuesAnnotations = new AnnotationSet[fieldsAnnotations.size()];\n",
298 indent);
299 fprintf(out,
300 "%s atom.valuesAnnotations = "
301 "fieldsAnnotations.toArray(atom.valuesAnnotations);\n",
302 indent);
303 fprintf(out, "%s}\n", indent);
304 }
305
306 fprintf(out, "%sreturn atom;\n", indent);
307
308 return 0;
309 }
310
write_java_pushed_methods_vendor(FILE * out,const SignatureInfoMap & signatureInfoMap)311 static int write_java_pushed_methods_vendor(FILE* out, const SignatureInfoMap& signatureInfoMap) {
312 for (auto signatureInfoMapIt = signatureInfoMap.begin();
313 signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
314 // Print method signature.
315 fprintf(out, " public static VendorAtom createVendorAtom(int atomId");
316 const vector<java_type_t>& signature = signatureInfoMapIt->first;
317 const AtomDecl emptyAttributionDecl;
318 int ret = write_java_method_signature(out, signature, emptyAttributionDecl);
319 if (ret != 0) {
320 return ret;
321 }
322 fprintf(out, ") {\n");
323
324 // Print method body.
325 const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet = signatureInfoMapIt->second;
326 ret = write_method_body_vendor(out, signature, fieldNumberToAtomDeclSet);
327 if (ret != 0) {
328 return ret;
329 }
330
331 fprintf(out, " }\n"); // method
332 fprintf(out, "\n");
333 }
334 return 0;
335 }
336
write_java_enum_values_vendor(FILE * out,const Atoms & atoms)337 static void write_java_enum_values_vendor(FILE* out, const Atoms& atoms) {
338 set<string> processedEnums;
339
340 fprintf(out, " // Constants for enum values.\n\n");
341 for (AtomDeclSet::const_iterator atomIt = atoms.decls.begin(); atomIt != atoms.decls.end();
342 atomIt++) {
343 for (vector<AtomField>::const_iterator field = (*atomIt)->fields.begin();
344 field != (*atomIt)->fields.end(); field++) {
345 if (field->javaType == JAVA_TYPE_ENUM || field->javaType == JAVA_TYPE_ENUM_ARRAY) {
346 // There might be N fields with the same enum type
347 // Avoiding duplication definitions
348 // enum type name == [atom_message_type_name]__[enum_type_name]
349 const string full_enum_type_name = (*atomIt)->message + "__" + field->enumTypeName;
350
351 if (processedEnums.find(full_enum_type_name) != processedEnums.end()) {
352 continue;
353 }
354 processedEnums.insert(full_enum_type_name);
355
356 fprintf(out, " // Values for %s.%s\n", (*atomIt)->message.c_str(),
357 field->name.c_str());
358 for (map<int, string>::const_iterator value = field->enumValues.begin();
359 value != field->enumValues.end(); value++) {
360 fprintf(out, " public static final int %s__%s = %d;\n",
361 make_constant_name(full_enum_type_name).c_str(),
362 make_constant_name(value->second).c_str(), value->first);
363 }
364 fprintf(out, "\n");
365 }
366 }
367 }
368 }
369
write_stats_log_java_vendor(FILE * out,const Atoms & atoms,const string & javaClass,const string & javaPackage)370 int write_stats_log_java_vendor(FILE* out, const Atoms& atoms, const string& javaClass,
371 const string& javaPackage) {
372 // Print prelude
373 fprintf(out, "// This file is autogenerated\n");
374 fprintf(out, "\n");
375 fprintf(out, "package %s;\n", javaPackage.c_str());
376 fprintf(out, "\n");
377
378 fprintf(out, "import android.frameworks.stats.VendorAtom;\n");
379 fprintf(out, "import android.frameworks.stats.VendorAtomValue;\n");
380 fprintf(out, "import android.frameworks.stats.AnnotationValue;\n");
381 fprintf(out, "import android.frameworks.stats.Annotation;\n");
382 fprintf(out, "import android.frameworks.stats.AnnotationId;\n");
383 fprintf(out, "import android.frameworks.stats.AnnotationSet;\n");
384
385 fprintf(out, "import java.util.ArrayList;\n");
386
387 fprintf(out, "\n");
388 fprintf(out, "/**\n");
389 fprintf(out, " * Utility class for logging statistics events.\n");
390 fprintf(out, " */\n");
391 fprintf(out, "public final class %s {\n", javaClass.c_str());
392
393 write_java_atom_codes(out, atoms);
394 write_java_enum_values_vendor(out, atoms);
395
396 // Print write methods.
397 fprintf(out, " // Write methods\n");
398 const int errors = write_java_pushed_methods_vendor(out, atoms.signatureInfoMap);
399
400 fprintf(out, "}\n");
401
402 return errors;
403 }
404
405 } // namespace stats_log_api_gen
406 } // namespace android
407