• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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