blob: 61174d99198b70a5fd8ba0dc6435e86e43124e77 [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),
Yao Chen8b71c742018-10-24 12:15:56 -070050 uidField(that.uidField),
51 binaryFields(that.binaryFields) {}
Yao Chend54f9dd2017-10-17 17:37:48 +000052
53AtomDecl::AtomDecl(int c, const string& n, const string& m)
54 :code(c),
55 name(n),
56 message(m)
57{
58}
59
60AtomDecl::~AtomDecl()
61{
62}
63
64
65/**
66 * Print an error message for a FieldDescriptor, including the file name and line number.
67 */
68static void
69print_error(const FieldDescriptor* field, const char* format, ...)
70{
71 const Descriptor* message = field->containing_type();
72 const FileDescriptor* file = message->file();
73
74 SourceLocation loc;
75 if (field->GetSourceLocation(&loc)) {
76 // TODO: this will work if we can figure out how to pass --include_source_info to protoc
77 fprintf(stderr, "%s:%d: ", file->name().c_str(), loc.start_line);
78 } else {
79 fprintf(stderr, "%s: ", file->name().c_str());
80 }
81 va_list args;
82 va_start(args, format);
83 vfprintf(stderr, format, args);
84 va_end (args);
85}
86
87/**
88 * Convert a protobuf type into a java type.
89 */
90static java_type_t
91java_type(const FieldDescriptor* field)
92{
93 int protoType = field->type();
94 switch (protoType) {
95 case FieldDescriptor::TYPE_DOUBLE:
96 return JAVA_TYPE_DOUBLE;
97 case FieldDescriptor::TYPE_FLOAT:
98 return JAVA_TYPE_FLOAT;
99 case FieldDescriptor::TYPE_INT64:
100 return JAVA_TYPE_LONG;
101 case FieldDescriptor::TYPE_UINT64:
102 return JAVA_TYPE_LONG;
103 case FieldDescriptor::TYPE_INT32:
104 return JAVA_TYPE_INT;
105 case FieldDescriptor::TYPE_FIXED64:
106 return JAVA_TYPE_LONG;
107 case FieldDescriptor::TYPE_FIXED32:
108 return JAVA_TYPE_INT;
109 case FieldDescriptor::TYPE_BOOL:
110 return JAVA_TYPE_BOOLEAN;
111 case FieldDescriptor::TYPE_STRING:
112 return JAVA_TYPE_STRING;
113 case FieldDescriptor::TYPE_GROUP:
114 return JAVA_TYPE_UNKNOWN;
115 case FieldDescriptor::TYPE_MESSAGE:
116 // TODO: not the final package name
Yangster-mac7604aea2017-12-11 22:55:49 -0800117 if (field->message_type()->full_name() ==
Yangster-mac20877162017-12-22 17:19:39 -0800118 "android.os.statsd.AttributionNode") {
Yangster-mac7604aea2017-12-11 22:55:49 -0800119 return JAVA_TYPE_ATTRIBUTION_CHAIN;
Yao Chen8b71c742018-10-24 12:15:56 -0700120 } else if (field->options().GetExtension(os::statsd::log_mode) ==
121 os::statsd::LogMode::MODE_BYTES) {
122 return JAVA_TYPE_BYTE_ARRAY;
Yao Chend54f9dd2017-10-17 17:37:48 +0000123 } else {
124 return JAVA_TYPE_OBJECT;
125 }
126 case FieldDescriptor::TYPE_BYTES:
127 return JAVA_TYPE_BYTE_ARRAY;
128 case FieldDescriptor::TYPE_UINT32:
129 return JAVA_TYPE_INT;
130 case FieldDescriptor::TYPE_ENUM:
Stefan Lafon9478f352017-10-30 21:20:20 -0700131 return JAVA_TYPE_ENUM;
Yao Chend54f9dd2017-10-17 17:37:48 +0000132 case FieldDescriptor::TYPE_SFIXED32:
133 return JAVA_TYPE_INT;
134 case FieldDescriptor::TYPE_SFIXED64:
135 return JAVA_TYPE_LONG;
136 case FieldDescriptor::TYPE_SINT32:
137 return JAVA_TYPE_INT;
138 case FieldDescriptor::TYPE_SINT64:
139 return JAVA_TYPE_LONG;
140 default:
141 return JAVA_TYPE_UNKNOWN;
142 }
143}
144
145/**
Yangster-macba5b9e42018-01-10 21:31:59 -0800146 * Gather the enums info.
147 */
148void collate_enums(const EnumDescriptor &enumDescriptor, AtomField *atomField) {
149 for (int i = 0; i < enumDescriptor.value_count(); i++) {
150 atomField->enumValues[enumDescriptor.value(i)->number()] =
151 enumDescriptor.value(i)->name().c_str();
152 }
153}
154
155/**
Yangster-mac7604aea2017-12-11 22:55:49 -0800156 * Gather the info about an atom proto.
157 */
158int collate_atom(const Descriptor *atom, AtomDecl *atomDecl,
159 vector<java_type_t> *signature) {
160
161 int errorCount = 0;
162 // Build a sorted list of the fields. Descriptor has them in source file
163 // order.
164 map<int, const FieldDescriptor *> fields;
165 for (int j = 0; j < atom->field_count(); j++) {
166 const FieldDescriptor *field = atom->field(j);
167 fields[field->number()] = field;
168 }
169
170 // Check that the parameters start at 1 and go up sequentially.
171 int expectedNumber = 1;
172 for (map<int, const FieldDescriptor *>::const_iterator it = fields.begin();
173 it != fields.end(); it++) {
174 const int number = it->first;
175 const FieldDescriptor *field = it->second;
176 if (number != expectedNumber) {
177 print_error(field,
178 "Fields must be numbered consecutively starting at 1:"
179 " '%s' is %d but should be %d\n",
180 field->name().c_str(), number, expectedNumber);
181 errorCount++;
182 expectedNumber = number;
183 continue;
184 }
185 expectedNumber++;
186 }
187
188 // Check that only allowed types are present. Remove any invalid ones.
189 for (map<int, const FieldDescriptor *>::const_iterator it = fields.begin();
190 it != fields.end(); it++) {
191 const FieldDescriptor *field = it->second;
Yao Chen8b71c742018-10-24 12:15:56 -0700192 bool isBinaryField = field->options().GetExtension(os::statsd::log_mode) ==
193 os::statsd::LogMode::MODE_BYTES;
Yangster-mac7604aea2017-12-11 22:55:49 -0800194
195 java_type_t javaType = java_type(field);
196
197 if (javaType == JAVA_TYPE_UNKNOWN) {
198 print_error(field, "Unkown type for field: %s\n", field->name().c_str());
199 errorCount++;
200 continue;
201 } else if (javaType == JAVA_TYPE_OBJECT) {
202 // Allow attribution chain, but only at position 1.
203 print_error(field, "Message type not allowed for field: %s\n",
204 field->name().c_str());
205 errorCount++;
206 continue;
Yao Chen8b71c742018-10-24 12:15:56 -0700207 } else if (javaType == JAVA_TYPE_BYTE_ARRAY && !isBinaryField) {
Yangster-mac7604aea2017-12-11 22:55:49 -0800208 print_error(field, "Raw bytes type not allowed for field: %s\n",
209 field->name().c_str());
210 errorCount++;
211 continue;
212 }
Yao Chen8b71c742018-10-24 12:15:56 -0700213
214 if (isBinaryField && javaType != JAVA_TYPE_BYTE_ARRAY) {
215 print_error(field, "Cannot mark field %s as bytes.\n",
216 field->name().c_str());
217 errorCount++;
218 continue;
219 }
Yangster-mac7604aea2017-12-11 22:55:49 -0800220 }
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);
Yao Chen8b71c742018-10-24 12:15:56 -0700244 bool isBinaryField = field->options().GetExtension(os::statsd::log_mode) ==
245 os::statsd::LogMode::MODE_BYTES;
Yangster-mac7604aea2017-12-11 22:55:49 -0800246
247 AtomField atField(field->name(), javaType);
248 if (javaType == JAVA_TYPE_ENUM) {
249 // All enums are treated as ints when it comes to function signatures.
250 signature->push_back(JAVA_TYPE_INT);
Yangster-macba5b9e42018-01-10 21:31:59 -0800251 collate_enums(*field->enum_type(), &atField);
Yao Chen8b71c742018-10-24 12:15:56 -0700252 } else if (javaType == JAVA_TYPE_OBJECT && isBinaryField) {
253 signature->push_back(JAVA_TYPE_BYTE_ARRAY);
Yangster-mac7604aea2017-12-11 22:55:49 -0800254 } else {
255 signature->push_back(javaType);
256 }
257 atomDecl->fields.push_back(atField);
Yao Chen9c1debe2018-02-19 14:39:19 -0800258
259 if (field->options().GetExtension(os::statsd::stateFieldOption).option() ==
260 os::statsd::StateField::PRIMARY) {
261 if (javaType == JAVA_TYPE_UNKNOWN ||
262 javaType == JAVA_TYPE_ATTRIBUTION_CHAIN ||
263 javaType == JAVA_TYPE_OBJECT || javaType == JAVA_TYPE_BYTE_ARRAY) {
264 errorCount++;
265 }
266 atomDecl->primaryFields.push_back(it->first);
267 }
268
269 if (field->options().GetExtension(os::statsd::stateFieldOption).option() ==
270 os::statsd::StateField::EXCLUSIVE) {
271 if (javaType == JAVA_TYPE_UNKNOWN ||
272 javaType == JAVA_TYPE_ATTRIBUTION_CHAIN ||
273 javaType == JAVA_TYPE_OBJECT || javaType == JAVA_TYPE_BYTE_ARRAY) {
274 errorCount++;
275 }
276
277 if (atomDecl->exclusiveField == 0) {
278 atomDecl->exclusiveField = it->first;
279 } else {
280 errorCount++;
281 }
282 }
Yao Chenc40a19d2018-03-15 16:48:25 -0700283
284 if (field->options().GetExtension(os::statsd::is_uid) == true) {
285 if (javaType != JAVA_TYPE_INT) {
286 errorCount++;
287 }
288
289 if (atomDecl->uidField == 0) {
290 atomDecl->uidField = it->first;
291 } else {
292 errorCount++;
293 }
294 }
Yao Chen8b71c742018-10-24 12:15:56 -0700295 // Binary field validity is already checked above.
296 if (isBinaryField) {
297 atomDecl->binaryFields.push_back(it->first);
298 }
Yangster-mac7604aea2017-12-11 22:55:49 -0800299 }
300
301 return errorCount;
302}
303
Yangster-macba5b9e42018-01-10 21:31:59 -0800304// This function flattens the fields of the AttributionNode proto in an Atom proto and generates
305// the corresponding atom decl and signature.
306bool get_non_chained_node(const Descriptor *atom, AtomDecl *atomDecl,
307 vector<java_type_t> *signature) {
308 // Build a sorted list of the fields. Descriptor has them in source file
309 // order.
310 map<int, const FieldDescriptor *> fields;
311 for (int j = 0; j < atom->field_count(); j++) {
312 const FieldDescriptor *field = atom->field(j);
313 fields[field->number()] = field;
314 }
315
316 AtomDecl attributionDecl;
317 vector<java_type_t> attributionSignature;
318 collate_atom(android::os::statsd::AttributionNode::descriptor(),
319 &attributionDecl, &attributionSignature);
320
321 // Build the type signature and the atom data.
322 bool has_attribution_node = false;
323 for (map<int, const FieldDescriptor *>::const_iterator it = fields.begin();
324 it != fields.end(); it++) {
325 const FieldDescriptor *field = it->second;
326 java_type_t javaType = java_type(field);
327 if (javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
328 atomDecl->fields.insert(
329 atomDecl->fields.end(),
330 attributionDecl.fields.begin(), attributionDecl.fields.end());
331 signature->insert(
332 signature->end(),
333 attributionSignature.begin(), attributionSignature.end());
334 has_attribution_node = true;
335
336 } else {
337 AtomField atField(field->name(), javaType);
338 if (javaType == JAVA_TYPE_ENUM) {
339 // All enums are treated as ints when it comes to function signatures.
340 signature->push_back(JAVA_TYPE_INT);
341 collate_enums(*field->enum_type(), &atField);
342 } else {
343 signature->push_back(javaType);
344 }
345 atomDecl->fields.push_back(atField);
346 }
347 }
348 return has_attribution_node;
349}
350
Yangster-mac7604aea2017-12-11 22:55:49 -0800351/**
Yao Chend54f9dd2017-10-17 17:37:48 +0000352 * Gather the info about the atoms.
353 */
Yangster-mac7604aea2017-12-11 22:55:49 -0800354int collate_atoms(const Descriptor *descriptor, Atoms *atoms) {
355 int errorCount = 0;
356 const bool dbg = false;
Yao Chend54f9dd2017-10-17 17:37:48 +0000357
Yangster-mac7604aea2017-12-11 22:55:49 -0800358 for (int i = 0; i < descriptor->field_count(); i++) {
359 const FieldDescriptor *atomField = descriptor->field(i);
Yao Chend54f9dd2017-10-17 17:37:48 +0000360
361 if (dbg) {
Yangster-mac7604aea2017-12-11 22:55:49 -0800362 printf(" %s (%d)\n", atomField->name().c_str(), atomField->number());
Yao Chend54f9dd2017-10-17 17:37:48 +0000363 }
364
Yangster-mac7604aea2017-12-11 22:55:49 -0800365 // StatsEvent only has one oneof, which contains only messages. Don't allow
366 // other types.
367 if (atomField->type() != FieldDescriptor::TYPE_MESSAGE) {
368 print_error(atomField,
369 "Bad type for atom. StatsEvent can only have message type "
370 "fields: %s\n",
371 atomField->name().c_str());
372 errorCount++;
373 continue;
374 }
375
376 const Descriptor *atom = atomField->message_type();
377 AtomDecl atomDecl(atomField->number(), atomField->name(), atom->name());
378 vector<java_type_t> signature;
379 errorCount += collate_atom(atom, &atomDecl, &signature);
Yao Chen9c1debe2018-02-19 14:39:19 -0800380 if (atomDecl.primaryFields.size() != 0 && atomDecl.exclusiveField == 0) {
381 errorCount++;
382 }
Yangster-mac7604aea2017-12-11 22:55:49 -0800383 atoms->signatures.insert(signature);
384 atoms->decls.insert(atomDecl);
Yangster-macba5b9e42018-01-10 21:31:59 -0800385
386 AtomDecl nonChainedAtomDecl(atomField->number(), atomField->name(), atom->name());
387 vector<java_type_t> nonChainedSignature;
388 if (get_non_chained_node(atom, &nonChainedAtomDecl, &nonChainedSignature)) {
389 atoms->non_chained_signatures.insert(nonChainedSignature);
390 atoms->non_chained_decls.insert(nonChainedAtomDecl);
391 }
Yangster-mac7604aea2017-12-11 22:55:49 -0800392 }
393
394 if (dbg) {
395 printf("signatures = [\n");
396 for (set<vector<java_type_t>>::const_iterator it =
397 atoms->signatures.begin();
398 it != atoms->signatures.end(); it++) {
399 printf(" ");
400 for (vector<java_type_t>::const_iterator jt = it->begin();
401 jt != it->end(); jt++) {
402 printf(" %d", (int)*jt);
403 }
404 printf("\n");
405 }
406 printf("]\n");
407 }
408
409 return errorCount;
Yao Chend54f9dd2017-10-17 17:37:48 +0000410}
411
412} // namespace stats_log_api_gen
413} // namespace android