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 "utils.h"
20 
21 namespace android {
22 namespace stats_log_api_gen {
23 
write_native_create_vendor_atom_methods(FILE * out,const SignatureInfoMap & signatureInfoMap,const AtomDecl & attributionDecl)24 static int write_native_create_vendor_atom_methods(FILE* out,
25                                                   const SignatureInfoMap& signatureInfoMap,
26                                                   const AtomDecl& attributionDecl) {
27     fprintf(out, "\n");
28     for (const auto& [signature, fieldNumberToAtomDeclSet] : signatureInfoMap) {
29         // TODO (b/264922532): provide vendor implementation to skip arg1 for reverseDomainName
30         write_native_method_signature(out, "VendorAtom createVendorAtom(", signature,
31                                       attributionDecl, " {", /*isVendorAtomLogging=*/true);
32 
33         fprintf(out, "    VendorAtom atom;\n");
34 
35         // Write method body.
36         fprintf(out, "    atom.atomId = code;\n");
37         fprintf(out, "    atom.reverseDomainName = arg1;\n");
38 
39         FieldNumberToAtomDeclSet::const_iterator fieldNumberToAtomDeclSetIt =
40                 fieldNumberToAtomDeclSet.find(ATOM_ID_FIELD_NUMBER);
41         if (fieldNumberToAtomDeclSetIt != fieldNumberToAtomDeclSet.end()) {
42             // TODO (b/264922532): provide support to pass annotations information
43             fprintf(stderr, "Encountered field level annotation - skip\n");
44         }
45 
46         // Exclude first field - which is reverseDomainName
47         const int vendorAtomValuesCount = signature.size() - 1;
48         fprintf(out, "    vector<VendorAtomValue> values(%d);\n", vendorAtomValuesCount);
49 
50         // Use 1-based index to access signature arguments
51         for (int argIndex = 2; argIndex <= signature.size(); argIndex++) {
52             const java_type_t& argType = signature[argIndex - 1];
53 
54             const int atomValueIndex = argIndex - 2;
55 
56             switch (argType) {
57                 case JAVA_TYPE_ATTRIBUTION_CHAIN: {
58                     fprintf(stderr, "Found attribution chain - not supported.\n");
59                     return 1;
60                 }
61                 case JAVA_TYPE_BYTE_ARRAY:
62                     fprintf(out,
63                             "    "
64                             "values[%d].set<VendorAtomValue::byteArrayValue>(arg%d);\n",
65                             atomValueIndex, argIndex);
66                     break;
67                 case JAVA_TYPE_BOOLEAN:
68                     fprintf(out, "    values[%d].set<VendorAtomValue::boolValue>(arg%d);\n",
69                             atomValueIndex, argIndex);
70                     break;
71                 case JAVA_TYPE_INT:
72                     [[fallthrough]];
73                 case JAVA_TYPE_ENUM:
74                     fprintf(out, "    values[%d].set<VendorAtomValue::intValue>(arg%d);\n",
75                             atomValueIndex, argIndex);
76                     break;
77                 case JAVA_TYPE_FLOAT:
78                     fprintf(out, "    values[%d].set<VendorAtomValue::floatValue>(arg%d);\n",
79                             atomValueIndex, argIndex);
80                     break;
81                 case JAVA_TYPE_LONG:
82                     fprintf(out, "    values[%d].set<VendorAtomValue::longValue>(arg%d);\n",
83                             atomValueIndex, argIndex);
84                     break;
85                 case JAVA_TYPE_STRING:
86                     fprintf(out, "    values[%d].set<VendorAtomValue::stringValue>(arg%d);\n",
87                             atomValueIndex, argIndex);
88                     break;
89                 case JAVA_TYPE_BOOLEAN_ARRAY:
90                     fprintf(out, "    values[%d].set<VendorAtomValue::repeatedBoolValue>(arg%d);\n",
91                             atomValueIndex, argIndex);
92                     break;
93                 case JAVA_TYPE_INT_ARRAY:
94                     [[fallthrough]];
95                 case JAVA_TYPE_ENUM_ARRAY:
96                     fprintf(out, "    values[%d].set<VendorAtomValue::repeatedIntValue>(arg%d);\n",
97                             atomValueIndex, argIndex);
98                     break;
99                 case JAVA_TYPE_FLOAT_ARRAY:
100                     fprintf(out,
101                             "    values[%d].set<VendorAtomValue::repeatedFloatValue>(arg%d);\n",
102                             atomValueIndex, argIndex);
103                     break;
104                 case JAVA_TYPE_LONG_ARRAY:
105                     fprintf(out, "    values[%d].set<VendorAtomValue::repeatedLongValue>(arg%d);\n",
106                             atomValueIndex, argIndex);
107                     break;
108                 case JAVA_TYPE_STRING_ARRAY:
109                     fprintf(out, "    {\n");
110                     fprintf(out, "    vector<optional<string>> arrayValue(\n");
111                     fprintf(out, "        arg%d.begin(), arg%d.end());\n", argIndex, argIndex);
112                     fprintf(out,
113                             "    "
114                             "values[%d].set<VendorAtomValue::repeatedStringValue>(std::move("
115                             "arrayValue));\n",
116                             atomValueIndex);
117                     fprintf(out, "    }\n");
118                     break;
119                 default:
120                     // Unsupported types: OBJECT, DOUBLE
121                     fprintf(stderr, "Encountered unsupported type.\n");
122                     return 1;
123             }
124             FieldNumberToAtomDeclSet::const_iterator fieldNumberToAtomDeclSetIt =
125                     fieldNumberToAtomDeclSet.find(argIndex);
126             if (fieldNumberToAtomDeclSetIt != fieldNumberToAtomDeclSet.end()) {
127                 // TODO (b/264922532): provide support to pass annotations information
128                 fprintf(stderr, "Encountered field level annotation - skip\n");
129             }
130         }
131 
132         fprintf(out, "    atom.values = std::move(values);\n");  // end method body.
133         fprintf(out, "    // elision of copy operations is permitted on return\n");
134         fprintf(out, "    return atom;\n");
135         fprintf(out, "}\n\n");  // end method.
136     }
137     return 0;
138 }
139 
write_stats_log_cpp_vendor(FILE * out,const Atoms & atoms,const AtomDecl & attributionDecl,const string & cppNamespace,const string & importHeader)140 int write_stats_log_cpp_vendor(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
141                                const string& cppNamespace, const string& importHeader) {
142     // Print prelude
143     fprintf(out, "// This file is autogenerated\n");
144     fprintf(out, "\n");
145 
146     fprintf(out, "#include <%s>\n", importHeader.c_str());
147     fprintf(out, "#include <aidl/android/frameworks/stats/VendorAtom.h>\n");
148 
149     fprintf(out, "\n");
150     write_namespace(out, cppNamespace);
151     fprintf(out, "\n");
152     fprintf(out, "using namespace aidl::android::frameworks::stats;\n");
153     fprintf(out, "using std::make_optional;\n");
154     fprintf(out, "using std::optional;\n");
155     fprintf(out, "using std::vector;\n");
156     fprintf(out, "using std::string;\n");
157 
158     int ret = write_native_create_vendor_atom_methods(out, atoms.signatureInfoMap, attributionDecl);
159     if (ret != 0) {
160         return ret;
161     }
162     // Print footer
163     fprintf(out, "\n");
164     write_closing_namespace(out, cppNamespace);
165 
166     return 0;
167 }
168 
write_stats_log_header_vendor(FILE * out,const Atoms & atoms,const AtomDecl & attributionDecl,const string & cppNamespace)169 int write_stats_log_header_vendor(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
170                                   const string& cppNamespace) {
171     write_native_header_preamble(out, cppNamespace, false, /*isVendorAtomLogging=*/true);
172     write_native_atom_constants(out, atoms, attributionDecl, "createVendorAtom(",
173                                 /*isVendorAtomLogging=*/true);
174 
175     for (AtomDeclSet::const_iterator atomIt = atoms.decls.begin(); atomIt != atoms.decls.end();
176          atomIt++) {
177         set<string> processedEnums;
178 
179         for (vector<AtomField>::const_iterator field = (*atomIt)->fields.begin();
180              field != (*atomIt)->fields.end(); field++) {
181             if (field->javaType == JAVA_TYPE_ENUM || field->javaType == JAVA_TYPE_ENUM_ARRAY) {
182                 // There might be N fields with the same enum type
183                 // avoid duplication definitions
184                 if (processedEnums.find(field->enumTypeName) != processedEnums.end()) {
185                     continue;
186                 }
187 
188                 if (processedEnums.empty()) {
189                     fprintf(out, "class %s final {\n", (*atomIt)->message.c_str());
190                     fprintf(out, "public:\n\n");
191                 }
192 
193                 processedEnums.insert(field->enumTypeName);
194 
195                 fprintf(out, "enum %s {\n", field->enumTypeName.c_str());
196                 size_t i = 0;
197                 for (map<int, string>::const_iterator value = field->enumValues.begin();
198                      value != field->enumValues.end(); value++) {
199                     fprintf(out, "    %s = %d", make_constant_name(value->second).c_str(),
200                             value->first);
201                     char const* const comma = (i == field->enumValues.size() - 1) ? "" : ",";
202                     fprintf(out, "%s\n", comma);
203                     i++;
204                 }
205 
206                 fprintf(out, "};\n");
207             }
208         }
209         if (!processedEnums.empty()) {
210             fprintf(out, "};\n\n");
211         }
212     }
213 
214     fprintf(out, "using ::aidl::android::frameworks::stats::VendorAtom;\n");
215 
216     // Print write methods
217     fprintf(out, "//\n");
218     fprintf(out, "// Write methods\n");
219     fprintf(out, "//\n");
220     write_native_method_header(out, "VendorAtom createVendorAtom(", atoms.signatureInfoMap,
221                                attributionDecl,
222                                /*isVendorAtomLogging=*/true);
223     fprintf(out, "\n");
224 
225     write_native_header_epilogue(out, cppNamespace);
226 
227     return 0;
228 }
229 
230 }  // namespace stats_log_api_gen
231 }  // namespace android
232