blob: 40ee490fc186fd3adb1d32b106f47fd6a906879a [file] [log] [blame]
Yao Chend54f9dd2017-10-17 17:37:48 +00001/*
2 * Copyright (C) 2017, 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 "Collation.h"
Yangster-macba5b9e42018-01-10 21:31:59 -080018#include "frameworks/base/cmds/statsd/src/atoms.pb.h"
Yao Chend54f9dd2017-10-17 17:37:48 +000019
20#include <stdio.h>
21#include <map>
22
23namespace android {
24namespace stats_log_api_gen {
25
Stefan Lafon9478f352017-10-30 21:20:20 -070026using google::protobuf::EnumDescriptor;
Yao Chend54f9dd2017-10-17 17:37:48 +000027using google::protobuf::FieldDescriptor;
28using google::protobuf::FileDescriptor;
29using google::protobuf::SourceLocation;
30using std::map;
31
32
33//
34// AtomDecl class
35//
36
37AtomDecl::AtomDecl()
38 :code(0),
39 name()
40{
41}
42
43AtomDecl::AtomDecl(const AtomDecl& that)
Yao Chen9c1debe2018-02-19 14:39:19 -080044 : code(that.code),
45 name(that.name),
46 message(that.message),
47 fields(that.fields),
48 primaryFields(that.primaryFields),
Yao Chenc40a19d2018-03-15 16:48:25 -070049 exclusiveField(that.exclusiveField),
50 uidField(that.uidField) {}
Yao Chend54f9dd2017-10-17 17:37:48 +000051
52AtomDecl::AtomDecl(int c, const string& n, const string& m)
53 :code(c),
54 name(n),
55 message(m)
56{
57}
58
59AtomDecl::~AtomDecl()
60{
61}
62
63
64/**
65 * Print an error message for a FieldDescriptor, including the file name and line number.
66 */
67static void
68print_error(const FieldDescriptor* field, const char* format, ...)
69{
70 const Descriptor* message = field->containing_type();
71 const FileDescriptor* file = message->file();
72
73 SourceLocation loc;
74 if (field->GetSourceLocation(&loc)) {
75 // TODO: this will work if we can figure out how to pass --include_source_info to protoc
76 fprintf(stderr, "%s:%d: ", file->name().c_str(), loc.start_line);
77 } else {
78 fprintf(stderr, "%s: ", file->name().c_str());
79 }
80 va_list args;
81 va_start(args, format);
82 vfprintf(stderr, format, args);
83 va_end (args);
84}
85
86/**
87 * Convert a protobuf type into a java type.
88 */
89static java_type_t
90java_type(const FieldDescriptor* field)
91{
92 int protoType = field->type();
93 switch (protoType) {
94 case FieldDescriptor::TYPE_DOUBLE:
95 return JAVA_TYPE_DOUBLE;
96 case FieldDescriptor::TYPE_FLOAT:
97 return JAVA_TYPE_FLOAT;
98 case FieldDescriptor::TYPE_INT64:
99 return JAVA_TYPE_LONG;
100 case FieldDescriptor::TYPE_UINT64:
101 return JAVA_TYPE_LONG;
102 case FieldDescriptor::TYPE_INT32:
103 return JAVA_TYPE_INT;
104 case FieldDescriptor::TYPE_FIXED64:
105 return JAVA_TYPE_LONG;
106 case FieldDescriptor::TYPE_FIXED32:
107 return JAVA_TYPE_INT;
108 case FieldDescriptor::TYPE_BOOL:
109 return JAVA_TYPE_BOOLEAN;
110 case FieldDescriptor::TYPE_STRING:
111 return JAVA_TYPE_STRING;
112 case FieldDescriptor::TYPE_GROUP:
113 return JAVA_TYPE_UNKNOWN;
114 case FieldDescriptor::TYPE_MESSAGE:
115 // TODO: not the final package name
Yangster-mac7604aea2017-12-11 22:55:49 -0800116 if (field->message_type()->full_name() ==
Yangster-mac20877162017-12-22 17:19:39 -0800117 "android.os.statsd.AttributionNode") {
Yangster-mac7604aea2017-12-11 22:55:49 -0800118 return JAVA_TYPE_ATTRIBUTION_CHAIN;
Yangster-mac48b3d622018-08-18 12:38:11 -0700119 } else if (field->message_type()->full_name() ==
120 "android.os.statsd.KeyValuePair") {
121 return JAVA_TYPE_KEY_VALUE_PAIR;
Yao Chend54f9dd2017-10-17 17:37:48 +0000122 } else {
123 return JAVA_TYPE_OBJECT;
124 }
125 case FieldDescriptor::TYPE_BYTES:
126 return JAVA_TYPE_BYTE_ARRAY;
127 case FieldDescriptor::TYPE_UINT32:
128 return JAVA_TYPE_INT;
129 case FieldDescriptor::TYPE_ENUM:
Stefan Lafon9478f352017-10-30 21:20:20 -0700130 return JAVA_TYPE_ENUM;
Yao Chend54f9dd2017-10-17 17:37:48 +0000131 case FieldDescriptor::TYPE_SFIXED32:
132 return JAVA_TYPE_INT;
133 case FieldDescriptor::TYPE_SFIXED64:
134 return JAVA_TYPE_LONG;
135 case FieldDescriptor::TYPE_SINT32:
136 return JAVA_TYPE_INT;
137 case FieldDescriptor::TYPE_SINT64:
138 return JAVA_TYPE_LONG;
139 default:
140 return JAVA_TYPE_UNKNOWN;
141 }
142}
143
144/**
Yangster-macba5b9e42018-01-10 21:31:59 -0800145 * Gather the enums info.
146 */
147void collate_enums(const EnumDescriptor &enumDescriptor, AtomField *atomField) {
148 for (int i = 0; i < enumDescriptor.value_count(); i++) {
149 atomField->enumValues[enumDescriptor.value(i)->number()] =
150 enumDescriptor.value(i)->name().c_str();
151 }
152}
153
154/**
Yangster-mac7604aea2017-12-11 22:55:49 -0800155 * Gather the info about an atom proto.
156 */
157int collate_atom(const Descriptor *atom, AtomDecl *atomDecl,
158 vector<java_type_t> *signature) {
159
160 int errorCount = 0;
161 // Build a sorted list of the fields. Descriptor has them in source file
162 // order.
163 map<int, const FieldDescriptor *> fields;
164 for (int j = 0; j < atom->field_count(); j++) {
165 const FieldDescriptor *field = atom->field(j);
166 fields[field->number()] = field;
167 }
168
169 // Check that the parameters start at 1 and go up sequentially.
170 int expectedNumber = 1;
171 for (map<int, const FieldDescriptor *>::const_iterator it = fields.begin();
172 it != fields.end(); it++) {
173 const int number = it->first;
174 const FieldDescriptor *field = it->second;
175 if (number != expectedNumber) {
176 print_error(field,
177 "Fields must be numbered consecutively starting at 1:"
178 " '%s' is %d but should be %d\n",
179 field->name().c_str(), number, expectedNumber);
180 errorCount++;
181 expectedNumber = number;
182 continue;
183 }
184 expectedNumber++;
185 }
186
Yangster-mac48b3d622018-08-18 12:38:11 -0700187 // Skips the key value pair atom.
188 for (map<int, const FieldDescriptor *>::const_iterator it = fields.begin();
189 it != fields.end(); it++) {
190 const FieldDescriptor *field = it->second;
191 java_type_t javaType = java_type(field);
192 if (javaType == JAVA_TYPE_KEY_VALUE_PAIR) {
193 return 0;
194 }
195 }
196
Yangster-mac7604aea2017-12-11 22:55:49 -0800197 // Check that only allowed types are present. Remove any invalid ones.
198 for (map<int, const FieldDescriptor *>::const_iterator it = fields.begin();
199 it != fields.end(); it++) {
200 const FieldDescriptor *field = it->second;
201
202 java_type_t javaType = java_type(field);
203
204 if (javaType == JAVA_TYPE_UNKNOWN) {
205 print_error(field, "Unkown type for field: %s\n", field->name().c_str());
206 errorCount++;
207 continue;
208 } else if (javaType == JAVA_TYPE_OBJECT) {
209 // Allow attribution chain, but only at position 1.
210 print_error(field, "Message type not allowed for field: %s\n",
211 field->name().c_str());
212 errorCount++;
213 continue;
214 } else if (javaType == JAVA_TYPE_BYTE_ARRAY) {
215 print_error(field, "Raw bytes type not allowed for field: %s\n",
216 field->name().c_str());
217 errorCount++;
218 continue;
219 }
220 }
221
222 // Check that if there's an attribution chain, it's at position 1.
223 for (map<int, const FieldDescriptor *>::const_iterator it = fields.begin();
224 it != fields.end(); it++) {
225 int number = it->first;
226 if (number != 1) {
227 const FieldDescriptor *field = it->second;
228 java_type_t javaType = java_type(field);
229 if (javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
230 print_error(
231 field,
232 "AttributionChain fields must have field id 1, in message: '%s'\n",
233 atom->name().c_str());
234 errorCount++;
235 }
236 }
237 }
238
239 // Build the type signature and the atom data.
240 for (map<int, const FieldDescriptor *>::const_iterator it = fields.begin();
241 it != fields.end(); it++) {
242 const FieldDescriptor *field = it->second;
243 java_type_t javaType = java_type(field);
244
245 AtomField atField(field->name(), javaType);
246 if (javaType == JAVA_TYPE_ENUM) {
247 // All enums are treated as ints when it comes to function signatures.
248 signature->push_back(JAVA_TYPE_INT);
Yangster-macba5b9e42018-01-10 21:31:59 -0800249 collate_enums(*field->enum_type(), &atField);
Yangster-mac7604aea2017-12-11 22:55:49 -0800250 } else {
251 signature->push_back(javaType);
252 }
253 atomDecl->fields.push_back(atField);
Yao Chen9c1debe2018-02-19 14:39:19 -0800254
255 if (field->options().GetExtension(os::statsd::stateFieldOption).option() ==
256 os::statsd::StateField::PRIMARY) {
257 if (javaType == JAVA_TYPE_UNKNOWN ||
258 javaType == JAVA_TYPE_ATTRIBUTION_CHAIN ||
259 javaType == JAVA_TYPE_OBJECT || javaType == JAVA_TYPE_BYTE_ARRAY) {
260 errorCount++;
261 }
262 atomDecl->primaryFields.push_back(it->first);
263 }
264
265 if (field->options().GetExtension(os::statsd::stateFieldOption).option() ==
266 os::statsd::StateField::EXCLUSIVE) {
267 if (javaType == JAVA_TYPE_UNKNOWN ||
268 javaType == JAVA_TYPE_ATTRIBUTION_CHAIN ||
269 javaType == JAVA_TYPE_OBJECT || javaType == JAVA_TYPE_BYTE_ARRAY) {
270 errorCount++;
271 }
272
273 if (atomDecl->exclusiveField == 0) {
274 atomDecl->exclusiveField = it->first;
275 } else {
276 errorCount++;
277 }
278 }
Yao Chenc40a19d2018-03-15 16:48:25 -0700279
280 if (field->options().GetExtension(os::statsd::is_uid) == true) {
281 if (javaType != JAVA_TYPE_INT) {
282 errorCount++;
283 }
284
285 if (atomDecl->uidField == 0) {
286 atomDecl->uidField = it->first;
287 } else {
288 errorCount++;
289 }
290 }
Yangster-mac7604aea2017-12-11 22:55:49 -0800291 }
292
293 return errorCount;
294}
295
Yangster-macba5b9e42018-01-10 21:31:59 -0800296// This function flattens the fields of the AttributionNode proto in an Atom proto and generates
297// the corresponding atom decl and signature.
298bool get_non_chained_node(const Descriptor *atom, AtomDecl *atomDecl,
299 vector<java_type_t> *signature) {
300 // Build a sorted list of the fields. Descriptor has them in source file
301 // order.
302 map<int, const FieldDescriptor *> fields;
303 for (int j = 0; j < atom->field_count(); j++) {
304 const FieldDescriptor *field = atom->field(j);
305 fields[field->number()] = field;
306 }
307
308 AtomDecl attributionDecl;
309 vector<java_type_t> attributionSignature;
310 collate_atom(android::os::statsd::AttributionNode::descriptor(),
311 &attributionDecl, &attributionSignature);
312
313 // Build the type signature and the atom data.
314 bool has_attribution_node = false;
315 for (map<int, const FieldDescriptor *>::const_iterator it = fields.begin();
316 it != fields.end(); it++) {
317 const FieldDescriptor *field = it->second;
318 java_type_t javaType = java_type(field);
319 if (javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
320 atomDecl->fields.insert(
321 atomDecl->fields.end(),
322 attributionDecl.fields.begin(), attributionDecl.fields.end());
323 signature->insert(
324 signature->end(),
325 attributionSignature.begin(), attributionSignature.end());
326 has_attribution_node = true;
327
328 } else {
329 AtomField atField(field->name(), javaType);
330 if (javaType == JAVA_TYPE_ENUM) {
331 // All enums are treated as ints when it comes to function signatures.
332 signature->push_back(JAVA_TYPE_INT);
333 collate_enums(*field->enum_type(), &atField);
334 } else {
335 signature->push_back(javaType);
336 }
337 atomDecl->fields.push_back(atField);
338 }
339 }
340 return has_attribution_node;
341}
342
Yangster-mac7604aea2017-12-11 22:55:49 -0800343/**
Yao Chend54f9dd2017-10-17 17:37:48 +0000344 * Gather the info about the atoms.
345 */
Yangster-mac7604aea2017-12-11 22:55:49 -0800346int collate_atoms(const Descriptor *descriptor, Atoms *atoms) {
347 int errorCount = 0;
348 const bool dbg = false;
Yao Chend54f9dd2017-10-17 17:37:48 +0000349
Yangster-mac7604aea2017-12-11 22:55:49 -0800350 for (int i = 0; i < descriptor->field_count(); i++) {
351 const FieldDescriptor *atomField = descriptor->field(i);
Yao Chend54f9dd2017-10-17 17:37:48 +0000352
353 if (dbg) {
Yangster-mac7604aea2017-12-11 22:55:49 -0800354 printf(" %s (%d)\n", atomField->name().c_str(), atomField->number());
Yao Chend54f9dd2017-10-17 17:37:48 +0000355 }
356
Yangster-mac7604aea2017-12-11 22:55:49 -0800357 // StatsEvent only has one oneof, which contains only messages. Don't allow
358 // other types.
359 if (atomField->type() != FieldDescriptor::TYPE_MESSAGE) {
360 print_error(atomField,
361 "Bad type for atom. StatsEvent can only have message type "
362 "fields: %s\n",
363 atomField->name().c_str());
364 errorCount++;
365 continue;
366 }
367
368 const Descriptor *atom = atomField->message_type();
369 AtomDecl atomDecl(atomField->number(), atomField->name(), atom->name());
370 vector<java_type_t> signature;
371 errorCount += collate_atom(atom, &atomDecl, &signature);
Yao Chen9c1debe2018-02-19 14:39:19 -0800372 if (atomDecl.primaryFields.size() != 0 && atomDecl.exclusiveField == 0) {
373 errorCount++;
374 }
Yangster-mac7604aea2017-12-11 22:55:49 -0800375 atoms->signatures.insert(signature);
376 atoms->decls.insert(atomDecl);
Yangster-macba5b9e42018-01-10 21:31:59 -0800377
378 AtomDecl nonChainedAtomDecl(atomField->number(), atomField->name(), atom->name());
379 vector<java_type_t> nonChainedSignature;
380 if (get_non_chained_node(atom, &nonChainedAtomDecl, &nonChainedSignature)) {
381 atoms->non_chained_signatures.insert(nonChainedSignature);
382 atoms->non_chained_decls.insert(nonChainedAtomDecl);
383 }
Yangster-mac7604aea2017-12-11 22:55:49 -0800384 }
385
386 if (dbg) {
387 printf("signatures = [\n");
388 for (set<vector<java_type_t>>::const_iterator it =
389 atoms->signatures.begin();
390 it != atoms->signatures.end(); it++) {
391 printf(" ");
392 for (vector<java_type_t>::const_iterator jt = it->begin();
393 jt != it->end(); jt++) {
394 printf(" %d", (int)*jt);
395 }
396 printf("\n");
397 }
398 printf("]\n");
399 }
400
401 return errorCount;
Yao Chend54f9dd2017-10-17 17:37:48 +0000402}
403
404} // namespace stats_log_api_gen
405} // namespace android