blob: 257043b3070498e0b2560e19219f7b384035fa4a [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 Chenbbdd67d2018-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;
Yangster-mac48b3d622018-08-18 12:38:11 -0700120 } else if (field->message_type()->full_name() ==
121 "android.os.statsd.KeyValuePair") {
122 return JAVA_TYPE_KEY_VALUE_PAIR;
Yao Chenbbdd67d2018-10-24 12:15:56 -0700123 } else if (field->options().GetExtension(os::statsd::log_mode) ==
124 os::statsd::LogMode::MODE_BYTES) {
125 return JAVA_TYPE_BYTE_ARRAY;
Yao Chend54f9dd2017-10-17 17:37:48 +0000126 } else {
127 return JAVA_TYPE_OBJECT;
128 }
129 case FieldDescriptor::TYPE_BYTES:
130 return JAVA_TYPE_BYTE_ARRAY;
131 case FieldDescriptor::TYPE_UINT32:
132 return JAVA_TYPE_INT;
133 case FieldDescriptor::TYPE_ENUM:
Stefan Lafon9478f352017-10-30 21:20:20 -0700134 return JAVA_TYPE_ENUM;
Yao Chend54f9dd2017-10-17 17:37:48 +0000135 case FieldDescriptor::TYPE_SFIXED32:
136 return JAVA_TYPE_INT;
137 case FieldDescriptor::TYPE_SFIXED64:
138 return JAVA_TYPE_LONG;
139 case FieldDescriptor::TYPE_SINT32:
140 return JAVA_TYPE_INT;
141 case FieldDescriptor::TYPE_SINT64:
142 return JAVA_TYPE_LONG;
143 default:
144 return JAVA_TYPE_UNKNOWN;
145 }
146}
147
148/**
Yangster-macba5b9e42018-01-10 21:31:59 -0800149 * Gather the enums info.
150 */
151void collate_enums(const EnumDescriptor &enumDescriptor, AtomField *atomField) {
152 for (int i = 0; i < enumDescriptor.value_count(); i++) {
153 atomField->enumValues[enumDescriptor.value(i)->number()] =
154 enumDescriptor.value(i)->name().c_str();
155 }
156}
157
158/**
Yangster-mac7604aea2017-12-11 22:55:49 -0800159 * Gather the info about an atom proto.
160 */
161int collate_atom(const Descriptor *atom, AtomDecl *atomDecl,
162 vector<java_type_t> *signature) {
163
164 int errorCount = 0;
165 // Build a sorted list of the fields. Descriptor has them in source file
166 // order.
167 map<int, const FieldDescriptor *> fields;
168 for (int j = 0; j < atom->field_count(); j++) {
169 const FieldDescriptor *field = atom->field(j);
170 fields[field->number()] = field;
171 }
172
173 // Check that the parameters start at 1 and go up sequentially.
174 int expectedNumber = 1;
175 for (map<int, const FieldDescriptor *>::const_iterator it = fields.begin();
176 it != fields.end(); it++) {
177 const int number = it->first;
178 const FieldDescriptor *field = it->second;
179 if (number != expectedNumber) {
180 print_error(field,
181 "Fields must be numbered consecutively starting at 1:"
182 " '%s' is %d but should be %d\n",
183 field->name().c_str(), number, expectedNumber);
184 errorCount++;
185 expectedNumber = number;
186 continue;
187 }
188 expectedNumber++;
189 }
190
191 // Check that only allowed types are present. Remove any invalid ones.
192 for (map<int, const FieldDescriptor *>::const_iterator it = fields.begin();
193 it != fields.end(); it++) {
194 const FieldDescriptor *field = it->second;
Yao Chenbbdd67d2018-10-24 12:15:56 -0700195 bool isBinaryField = field->options().GetExtension(os::statsd::log_mode) ==
196 os::statsd::LogMode::MODE_BYTES;
Yangster-mac7604aea2017-12-11 22:55:49 -0800197
198 java_type_t javaType = java_type(field);
199
200 if (javaType == JAVA_TYPE_UNKNOWN) {
201 print_error(field, "Unkown type for field: %s\n", field->name().c_str());
202 errorCount++;
203 continue;
Chenjie Yu159e4f82018-08-29 11:49:11 -0700204 } else if (javaType == JAVA_TYPE_OBJECT &&
205 atomDecl->code < PULL_ATOM_START_ID) {
Yao Chenbbdd67d2018-10-24 12:15:56 -0700206 // Allow attribution chain, but only at position 1.
207 print_error(field,
208 "Message type not allowed for field in pushed atoms: %s\n",
209 field->name().c_str());
210 errorCount++;
211 continue;
212 } else if (javaType == JAVA_TYPE_BYTE_ARRAY && !isBinaryField) {
213 print_error(field, "Raw bytes type not allowed for field: %s\n",
214 field->name().c_str());
215 errorCount++;
216 continue;
217 }
218
219 if (isBinaryField && javaType != JAVA_TYPE_BYTE_ARRAY) {
220 print_error(field, "Cannot mark field %s as bytes.\n",
221 field->name().c_str());
222 errorCount++;
223 continue;
Yangster-mac7604aea2017-12-11 22:55:49 -0800224 }
225 }
226
227 // Check that if there's an attribution chain, it's at position 1.
228 for (map<int, const FieldDescriptor *>::const_iterator it = fields.begin();
229 it != fields.end(); it++) {
230 int number = it->first;
231 if (number != 1) {
232 const FieldDescriptor *field = it->second;
233 java_type_t javaType = java_type(field);
234 if (javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
235 print_error(
236 field,
237 "AttributionChain fields must have field id 1, in message: '%s'\n",
238 atom->name().c_str());
239 errorCount++;
240 }
241 }
242 }
243
244 // Build the type signature and the atom data.
245 for (map<int, const FieldDescriptor *>::const_iterator it = fields.begin();
246 it != fields.end(); it++) {
247 const FieldDescriptor *field = it->second;
248 java_type_t javaType = java_type(field);
Yao Chenbbdd67d2018-10-24 12:15:56 -0700249 bool isBinaryField = field->options().GetExtension(os::statsd::log_mode) ==
250 os::statsd::LogMode::MODE_BYTES;
Yangster-mac7604aea2017-12-11 22:55:49 -0800251
252 AtomField atField(field->name(), javaType);
Chenjie Yu159e4f82018-08-29 11:49:11 -0700253 // Generate signature for pushed atoms
254 if (atomDecl->code < PULL_ATOM_START_ID) {
255 if (javaType == JAVA_TYPE_ENUM) {
256 // All enums are treated as ints when it comes to function signatures.
257 signature->push_back(JAVA_TYPE_INT);
258 collate_enums(*field->enum_type(), &atField);
Yao Chenbbdd67d2018-10-24 12:15:56 -0700259 } else if (javaType == JAVA_TYPE_OBJECT && isBinaryField) {
260 signature->push_back(JAVA_TYPE_BYTE_ARRAY);
Chenjie Yu159e4f82018-08-29 11:49:11 -0700261 } else {
Yao Chenbbdd67d2018-10-24 12:15:56 -0700262 signature->push_back(javaType);
Chenjie Yu159e4f82018-08-29 11:49:11 -0700263 }
264 }
Yangster-mac7604aea2017-12-11 22:55:49 -0800265 if (javaType == JAVA_TYPE_ENUM) {
266 // All enums are treated as ints when it comes to function signatures.
Yangster-macba5b9e42018-01-10 21:31:59 -0800267 collate_enums(*field->enum_type(), &atField);
Yangster-mac7604aea2017-12-11 22:55:49 -0800268 }
269 atomDecl->fields.push_back(atField);
Yao Chen9c1debe2018-02-19 14:39:19 -0800270
Yangster-macb6b77c62018-10-12 19:33:24 -0700271 if (field->options().GetExtension(os::statsd::state_field_option).option() ==
Yao Chen9c1debe2018-02-19 14:39:19 -0800272 os::statsd::StateField::PRIMARY) {
273 if (javaType == JAVA_TYPE_UNKNOWN ||
274 javaType == JAVA_TYPE_ATTRIBUTION_CHAIN ||
275 javaType == JAVA_TYPE_OBJECT || javaType == JAVA_TYPE_BYTE_ARRAY) {
276 errorCount++;
277 }
278 atomDecl->primaryFields.push_back(it->first);
279 }
280
Yangster-macb6b77c62018-10-12 19:33:24 -0700281 if (field->options().GetExtension(os::statsd::state_field_option).option() ==
Yao Chen9c1debe2018-02-19 14:39:19 -0800282 os::statsd::StateField::EXCLUSIVE) {
283 if (javaType == JAVA_TYPE_UNKNOWN ||
284 javaType == JAVA_TYPE_ATTRIBUTION_CHAIN ||
285 javaType == JAVA_TYPE_OBJECT || javaType == JAVA_TYPE_BYTE_ARRAY) {
286 errorCount++;
287 }
288
289 if (atomDecl->exclusiveField == 0) {
290 atomDecl->exclusiveField = it->first;
291 } else {
292 errorCount++;
293 }
294 }
Yao Chenc40a19d2018-03-15 16:48:25 -0700295
296 if (field->options().GetExtension(os::statsd::is_uid) == true) {
297 if (javaType != JAVA_TYPE_INT) {
298 errorCount++;
299 }
300
301 if (atomDecl->uidField == 0) {
302 atomDecl->uidField = it->first;
303 } else {
304 errorCount++;
305 }
306 }
Yao Chenbbdd67d2018-10-24 12:15:56 -0700307 // Binary field validity is already checked above.
308 if (isBinaryField) {
309 atomDecl->binaryFields.push_back(it->first);
310 }
Yangster-mac7604aea2017-12-11 22:55:49 -0800311 }
312
313 return errorCount;
314}
315
Yangster-macba5b9e42018-01-10 21:31:59 -0800316// This function flattens the fields of the AttributionNode proto in an Atom proto and generates
317// the corresponding atom decl and signature.
318bool get_non_chained_node(const Descriptor *atom, AtomDecl *atomDecl,
319 vector<java_type_t> *signature) {
320 // Build a sorted list of the fields. Descriptor has them in source file
321 // order.
322 map<int, const FieldDescriptor *> fields;
323 for (int j = 0; j < atom->field_count(); j++) {
324 const FieldDescriptor *field = atom->field(j);
325 fields[field->number()] = field;
326 }
327
328 AtomDecl attributionDecl;
329 vector<java_type_t> attributionSignature;
330 collate_atom(android::os::statsd::AttributionNode::descriptor(),
331 &attributionDecl, &attributionSignature);
332
333 // Build the type signature and the atom data.
334 bool has_attribution_node = false;
335 for (map<int, const FieldDescriptor *>::const_iterator it = fields.begin();
336 it != fields.end(); it++) {
337 const FieldDescriptor *field = it->second;
338 java_type_t javaType = java_type(field);
339 if (javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
340 atomDecl->fields.insert(
341 atomDecl->fields.end(),
342 attributionDecl.fields.begin(), attributionDecl.fields.end());
343 signature->insert(
344 signature->end(),
345 attributionSignature.begin(), attributionSignature.end());
346 has_attribution_node = true;
347
348 } else {
349 AtomField atField(field->name(), javaType);
350 if (javaType == JAVA_TYPE_ENUM) {
351 // All enums are treated as ints when it comes to function signatures.
352 signature->push_back(JAVA_TYPE_INT);
353 collate_enums(*field->enum_type(), &atField);
354 } else {
355 signature->push_back(javaType);
356 }
357 atomDecl->fields.push_back(atField);
358 }
359 }
360 return has_attribution_node;
361}
362
Yangster-mac7604aea2017-12-11 22:55:49 -0800363/**
Yao Chend54f9dd2017-10-17 17:37:48 +0000364 * Gather the info about the atoms.
365 */
Yangster-mac7604aea2017-12-11 22:55:49 -0800366int collate_atoms(const Descriptor *descriptor, Atoms *atoms) {
367 int errorCount = 0;
368 const bool dbg = false;
Yao Chend54f9dd2017-10-17 17:37:48 +0000369
Yangster-mac7604aea2017-12-11 22:55:49 -0800370 for (int i = 0; i < descriptor->field_count(); i++) {
371 const FieldDescriptor *atomField = descriptor->field(i);
Yao Chend54f9dd2017-10-17 17:37:48 +0000372
373 if (dbg) {
Yangster-mac7604aea2017-12-11 22:55:49 -0800374 printf(" %s (%d)\n", atomField->name().c_str(), atomField->number());
Yao Chend54f9dd2017-10-17 17:37:48 +0000375 }
376
Yangster-mac7604aea2017-12-11 22:55:49 -0800377 // StatsEvent only has one oneof, which contains only messages. Don't allow
378 // other types.
379 if (atomField->type() != FieldDescriptor::TYPE_MESSAGE) {
380 print_error(atomField,
381 "Bad type for atom. StatsEvent can only have message type "
382 "fields: %s\n",
383 atomField->name().c_str());
384 errorCount++;
385 continue;
386 }
387
388 const Descriptor *atom = atomField->message_type();
389 AtomDecl atomDecl(atomField->number(), atomField->name(), atom->name());
390 vector<java_type_t> signature;
391 errorCount += collate_atom(atom, &atomDecl, &signature);
Yao Chen9c1debe2018-02-19 14:39:19 -0800392 if (atomDecl.primaryFields.size() != 0 && atomDecl.exclusiveField == 0) {
393 errorCount++;
394 }
Yangster-mac7604aea2017-12-11 22:55:49 -0800395 atoms->signatures.insert(signature);
396 atoms->decls.insert(atomDecl);
Yangster-macba5b9e42018-01-10 21:31:59 -0800397
398 AtomDecl nonChainedAtomDecl(atomField->number(), atomField->name(), atom->name());
399 vector<java_type_t> nonChainedSignature;
400 if (get_non_chained_node(atom, &nonChainedAtomDecl, &nonChainedSignature)) {
401 atoms->non_chained_signatures.insert(nonChainedSignature);
402 atoms->non_chained_decls.insert(nonChainedAtomDecl);
403 }
Yangster-mac7604aea2017-12-11 22:55:49 -0800404 }
405
406 if (dbg) {
407 printf("signatures = [\n");
408 for (set<vector<java_type_t>>::const_iterator it =
409 atoms->signatures.begin();
410 it != atoms->signatures.end(); it++) {
411 printf(" ");
412 for (vector<java_type_t>::const_iterator jt = it->begin();
413 jt != it->end(); jt++) {
414 printf(" %d", (int)*jt);
415 }
416 printf("\n");
417 }
418 printf("]\n");
419 }
420
421 return errorCount;
Yao Chend54f9dd2017-10-17 17:37:48 +0000422}
423
424} // namespace stats_log_api_gen
425} // namespace android