• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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"
18 
19 #include <stdio.h>
20 
21 #include <map>
22 
23 #include "frameworks/proto_logging/stats/atoms.pb.h"
24 #include "frameworks/proto_logging/stats/attribution_node.pb.h"
25 #include "utils.h"
26 
27 namespace android {
28 namespace stats_log_api_gen {
29 
30 using google::protobuf::EnumDescriptor;
31 using google::protobuf::FieldDescriptor;
32 using google::protobuf::FileDescriptor;
33 using google::protobuf::OneofDescriptor;
34 using google::protobuf::SourceLocation;
35 using std::make_shared;
36 using std::map;
37 
38 const bool dbg = false;
39 
40 const int PLATFORM_PULLED_ATOMS_START = 10000;
41 const int PLATFORM_PULLED_ATOMS_END = 99999;
42 const int VENDOR_PULLED_ATOMS_START = 150000;
43 const int VENDOR_PULLED_ATOMS_END = 199999;
44 
45 //
46 // AtomDecl class
47 //
48 
AtomDecl()49 AtomDecl::AtomDecl() : code(0), name(), atomType(ATOM_TYPE_PUSHED) {
50 }
51 
AtomDecl(const AtomDecl & that)52 AtomDecl::AtomDecl(const AtomDecl& that)
53     : code(that.code),
54       name(that.name),
55       message(that.message),
56       fields(that.fields),
57       atomType(that.atomType),
58       fieldNumberToAnnotations(that.fieldNumberToAnnotations),
59       primaryFields(that.primaryFields),
60       exclusiveField(that.exclusiveField),
61       defaultState(that.defaultState),
62       triggerStateReset(that.triggerStateReset),
63       nested(that.nested) {
64 }
65 
AtomDecl(int c,const string & n,const string & m,AtomType a)66 AtomDecl::AtomDecl(int c, const string& n, const string& m, AtomType a)
67     : code(c), name(n), message(m), atomType(a) {
68 }
69 
~AtomDecl()70 AtomDecl::~AtomDecl() {
71 }
72 
73 /**
74  * Print an error message for a FieldDescriptor, including the file name and
75  * line number.
76  */
print_error(const FieldDescriptor * field,const char * format,...)77 static void print_error(const FieldDescriptor* field, const char* format, ...) {
78     const Descriptor* message = field->containing_type();
79     const FileDescriptor* file = message->file();
80 
81     SourceLocation loc;
82     if (field->GetSourceLocation(&loc)) {
83         // TODO(b/162454173): this will work if we can figure out how to pass
84         // --include_source_info to protoc
85         fprintf(stderr, "%s:%d: ", file->name().c_str(), loc.start_line);
86     } else {
87         fprintf(stderr, "%s: ", file->name().c_str());
88     }
89     va_list args;
90     va_start(args, format);
91     vfprintf(stderr, format, args);
92     va_end(args);
93 }
94 
95 /**
96  * Convert a protobuf type into a java type.
97  */
java_type(const FieldDescriptor * field)98 static java_type_t java_type(const FieldDescriptor* field) {
99     int protoType = field->type();
100     bool isRepeatedField = field->is_repeated();
101 
102     switch (protoType) {
103         case FieldDescriptor::TYPE_FLOAT:
104             return isRepeatedField ? JAVA_TYPE_FLOAT_ARRAY : JAVA_TYPE_FLOAT;
105         case FieldDescriptor::TYPE_INT64:
106             return isRepeatedField ? JAVA_TYPE_LONG_ARRAY : JAVA_TYPE_LONG;
107         case FieldDescriptor::TYPE_INT32:
108             return isRepeatedField ? JAVA_TYPE_INT_ARRAY : JAVA_TYPE_INT;
109         case FieldDescriptor::TYPE_BOOL:
110             return isRepeatedField ? JAVA_TYPE_BOOLEAN_ARRAY : JAVA_TYPE_BOOLEAN;
111         case FieldDescriptor::TYPE_STRING:
112             return isRepeatedField ? JAVA_TYPE_STRING_ARRAY : JAVA_TYPE_STRING;
113         case FieldDescriptor::TYPE_ENUM:
114             return isRepeatedField ? JAVA_TYPE_ENUM_ARRAY : JAVA_TYPE_ENUM;
115         case FieldDescriptor::TYPE_GROUP:
116             return JAVA_TYPE_UNKNOWN_OR_INVALID;
117         case FieldDescriptor::TYPE_MESSAGE:
118             if (field->message_type()->full_name() == "android.os.statsd.AttributionNode") {
119                 return JAVA_TYPE_ATTRIBUTION_CHAIN;
120             } else if ((field->options().GetExtension(os::statsd::log_mode) ==
121                         os::statsd::LogMode::MODE_BYTES) &&
122                        !isRepeatedField) {
123                 return JAVA_TYPE_BYTE_ARRAY;
124             } else {
125                 return isRepeatedField ? JAVA_TYPE_UNKNOWN_OR_INVALID : JAVA_TYPE_OBJECT;
126             }
127         case FieldDescriptor::TYPE_BYTES:
128             return isRepeatedField ? JAVA_TYPE_UNKNOWN_OR_INVALID : JAVA_TYPE_BYTE_ARRAY;
129         case FieldDescriptor::TYPE_UINT64:
130             return isRepeatedField ? JAVA_TYPE_UNKNOWN_OR_INVALID : JAVA_TYPE_LONG;
131         case FieldDescriptor::TYPE_UINT32:
132             return isRepeatedField ? JAVA_TYPE_UNKNOWN_OR_INVALID : JAVA_TYPE_INT;
133         default:
134             return JAVA_TYPE_UNKNOWN_OR_INVALID;
135     }
136 }
137 
138 /**
139  * Gather the enums info.
140  */
collate_enums(const EnumDescriptor & enumDescriptor,AtomField * atomField)141 void collate_enums(const EnumDescriptor& enumDescriptor, AtomField* atomField) {
142     for (int i = 0; i < enumDescriptor.value_count(); i++) {
143         atomField->enumValues[enumDescriptor.value(i)->number()] = enumDescriptor.value(i)->name();
144     }
145 }
146 
addAnnotationToAtomDecl(AtomDecl * atomDecl,const int fieldNumber,const AnnotationId annotationId,const AnnotationType annotationType,const AnnotationValue annotationValue)147 static void addAnnotationToAtomDecl(AtomDecl* atomDecl, const int fieldNumber,
148                                     const AnnotationId annotationId,
149                                     const AnnotationType annotationType,
150                                     const AnnotationValue annotationValue) {
151     if (dbg) {
152         printf("   Adding annotation to %s: [%d] = {id: %d, type: %d}\n", atomDecl->name.c_str(),
153                fieldNumber, annotationId, annotationType);
154     }
155     atomDecl->fieldNumberToAnnotations[fieldNumber].insert(
156             make_shared<Annotation>(annotationId, atomDecl->code, annotationType, annotationValue));
157 }
158 
collate_field_restricted_annotations(AtomDecl * atomDecl,const FieldDescriptor * field,const int fieldNumber)159 static int collate_field_restricted_annotations(AtomDecl* atomDecl, const FieldDescriptor* field,
160                                                 const int fieldNumber) {
161     int errorCount = 0;
162 
163     if (field->options().HasExtension(os::statsd::field_restriction_option)) {
164         if (!atomDecl->restricted) {
165             print_error(field,
166                         "field_restriction_option annotations must be from an atom with "
167                         "a restriction_category annotation: '%s'\n", atomDecl->message.c_str());
168             errorCount++;
169         }
170 
171         const os::statsd::FieldRestrictionOption& fieldRestrictionOption =
172                 field->options().GetExtension(os::statsd::field_restriction_option);
173 
174         if (fieldRestrictionOption.peripheral_device_info()) {
175             addAnnotationToAtomDecl(atomDecl, fieldNumber,
176                                     ANNOTATION_ID_FIELD_RESTRICTION_PERIPHERAL_DEVICE_INFO,
177                                     ANNOTATION_TYPE_BOOL, AnnotationValue(true));
178         }
179 
180         if (fieldRestrictionOption.app_usage()) {
181             addAnnotationToAtomDecl(atomDecl, fieldNumber,
182                                     ANNOTATION_ID_FIELD_RESTRICTION_APP_USAGE, ANNOTATION_TYPE_BOOL,
183                                     AnnotationValue(true));
184         }
185 
186         if (fieldRestrictionOption.app_activity()) {
187             addAnnotationToAtomDecl(atomDecl, fieldNumber,
188                                     ANNOTATION_ID_FIELD_RESTRICTION_APP_ACTIVITY,
189                                     ANNOTATION_TYPE_BOOL, AnnotationValue(true));
190         }
191 
192         if (fieldRestrictionOption.health_connect()) {
193             addAnnotationToAtomDecl(atomDecl, fieldNumber,
194                                     ANNOTATION_ID_FIELD_RESTRICTION_HEALTH_CONNECT,
195                                     ANNOTATION_TYPE_BOOL, AnnotationValue(true));
196         }
197 
198         if (fieldRestrictionOption.accessibility()) {
199             addAnnotationToAtomDecl(atomDecl, fieldNumber,
200                                     ANNOTATION_ID_FIELD_RESTRICTION_ACCESSIBILITY,
201                                     ANNOTATION_TYPE_BOOL, AnnotationValue(true));
202         }
203 
204         if (fieldRestrictionOption.system_search()) {
205             addAnnotationToAtomDecl(atomDecl, fieldNumber,
206                                     ANNOTATION_ID_FIELD_RESTRICTION_SYSTEM_SEARCH,
207                                     ANNOTATION_TYPE_BOOL, AnnotationValue(true));
208         }
209 
210         if (fieldRestrictionOption.user_engagement()) {
211             addAnnotationToAtomDecl(atomDecl, fieldNumber,
212                                     ANNOTATION_ID_FIELD_RESTRICTION_USER_ENGAGEMENT,
213                                     ANNOTATION_TYPE_BOOL, AnnotationValue(true));
214         }
215 
216         if (fieldRestrictionOption.ambient_sensing()) {
217             addAnnotationToAtomDecl(atomDecl, fieldNumber,
218                                     ANNOTATION_ID_FIELD_RESTRICTION_AMBIENT_SENSING,
219                                     ANNOTATION_TYPE_BOOL, AnnotationValue(true));
220         }
221 
222         if (fieldRestrictionOption.demographic_classification()) {
223             addAnnotationToAtomDecl(atomDecl, fieldNumber,
224                                     ANNOTATION_ID_FIELD_RESTRICTION_DEMOGRAPHIC_CLASSIFICATION,
225                                     ANNOTATION_TYPE_BOOL, AnnotationValue(true));
226         }
227     }
228 
229     if (field->options().HasExtension(os::statsd::restriction_category)) {
230         print_error(field,
231                     "restriction_category must be an atom-level annotation: '%s'\n",
232                     atomDecl->message.c_str());
233         errorCount++;
234     }
235 
236     return errorCount;
237 }
238 
collate_field_annotations(AtomDecl * atomDecl,const FieldDescriptor * field,const int fieldNumber,const java_type_t & javaType)239 static int collate_field_annotations(AtomDecl* atomDecl, const FieldDescriptor* field,
240                                      const int fieldNumber, const java_type_t& javaType) {
241     int errorCount = 0;
242 
243     if (field->options().HasExtension(os::statsd::state_field_option)) {
244         if (is_repeated_field(javaType)) {
245             print_error(field,
246                         "State field annotations are not allowed for repeated fields: '%s'\n",
247                         atomDecl->message.c_str());
248             errorCount++;
249             return errorCount;
250         }
251 
252         const os::statsd::StateAtomFieldOption& stateFieldOption =
253                 field->options().GetExtension(os::statsd::state_field_option);
254         const bool primaryField = stateFieldOption.primary_field();
255         const bool exclusiveState = stateFieldOption.exclusive_state();
256         const bool primaryFieldFirstUid = stateFieldOption.primary_field_first_uid();
257 
258         // Check the field is only one of primaryField, exclusiveState, or primaryFieldFirstUid.
259         if (primaryField + primaryFieldFirstUid + exclusiveState > 1) {
260             print_error(field,
261                         "Field can be max 1 of primary_field, exclusive_state, "
262                         "or primary_field_first_uid: '%s'\n",
263                         atomDecl->message.c_str());
264             errorCount++;
265         }
266 
267         if (primaryField) {
268             if (javaType == JAVA_TYPE_ATTRIBUTION_CHAIN || javaType == JAVA_TYPE_OBJECT ||
269                 javaType == JAVA_TYPE_BYTE_ARRAY) {
270                 print_error(field, "Invalid primary state field: '%s'\n",
271                             atomDecl->message.c_str());
272                 errorCount++;
273             } else {
274                 atomDecl->primaryFields.push_back(fieldNumber);
275                 addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_PRIMARY_FIELD,
276                                         ANNOTATION_TYPE_BOOL, AnnotationValue(true));
277             }
278         }
279 
280         if (primaryFieldFirstUid) {
281             if (javaType != JAVA_TYPE_ATTRIBUTION_CHAIN) {
282                 print_error(field,
283                             "PRIMARY_FIELD_FIRST_UID annotation is only for AttributionChains: "
284                             "'%s'\n",
285                             atomDecl->message.c_str());
286                 errorCount++;
287             } else {
288                 atomDecl->primaryFields.push_back(FIRST_UID_IN_CHAIN_ID);
289                 addAnnotationToAtomDecl(atomDecl, fieldNumber,
290                                         ANNOTATION_ID_PRIMARY_FIELD_FIRST_UID, ANNOTATION_TYPE_BOOL,
291                                         AnnotationValue(true));
292             }
293         }
294 
295         if (exclusiveState) {
296             if (javaType == JAVA_TYPE_ATTRIBUTION_CHAIN || javaType == JAVA_TYPE_OBJECT ||
297                 javaType == JAVA_TYPE_BYTE_ARRAY) {
298                 print_error(field, "Invalid exclusive state field: '%s'\n",
299                             atomDecl->message.c_str());
300                 errorCount++;
301             }
302 
303             if (atomDecl->exclusiveField != 0) {
304                 print_error(field,
305                             "Cannot have more than one exclusive state field in an "
306                             "atom: '%s'\n",
307                             atomDecl->message.c_str());
308                 errorCount++;
309             } else {
310                 atomDecl->exclusiveField = fieldNumber;
311                 addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_EXCLUSIVE_STATE,
312                                         ANNOTATION_TYPE_BOOL, AnnotationValue(true));
313             }
314 
315             if (stateFieldOption.has_default_state_value()) {
316                 const int defaultState = stateFieldOption.default_state_value();
317                 atomDecl->defaultState = defaultState;
318 
319                 addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_DEFAULT_STATE,
320                                         ANNOTATION_TYPE_INT, AnnotationValue(defaultState));
321             }
322 
323             if (stateFieldOption.has_trigger_state_reset_value()) {
324                 const int triggerStateReset = stateFieldOption.trigger_state_reset_value();
325 
326                 atomDecl->triggerStateReset = triggerStateReset;
327                 addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_TRIGGER_STATE_RESET,
328                                         ANNOTATION_TYPE_INT, AnnotationValue(triggerStateReset));
329             }
330 
331             if (stateFieldOption.has_nested()) {
332                 const bool nested = stateFieldOption.nested();
333                 atomDecl->nested = nested;
334 
335                 addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_STATE_NESTED,
336                                         ANNOTATION_TYPE_BOOL, AnnotationValue(nested));
337             }
338         }
339     }
340 
341     errorCount += collate_field_restricted_annotations(atomDecl, field, fieldNumber);
342 
343     if (field->options().GetExtension(os::statsd::is_uid) == true) {
344         if (javaType != JAVA_TYPE_INT && javaType != JAVA_TYPE_INT_ARRAY) {
345             print_error(field,
346                         "is_uid annotation can only be applied to int32 fields and repeated int32 "
347                         "fields: '%s'\n",
348                         atomDecl->message.c_str());
349             errorCount++;
350         }
351 
352         addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_IS_UID, ANNOTATION_TYPE_BOOL,
353                                 AnnotationValue(true));
354     }
355 
356     return errorCount;
357 }
358 
359 /**
360  * Gather the info about an atom proto.
361  */
collate_atom(const Descriptor * atom,AtomDecl * atomDecl,vector<java_type_t> * signature)362 int collate_atom(const Descriptor* atom, AtomDecl* atomDecl, vector<java_type_t>* signature) {
363     int errorCount = 0;
364 
365     // Build a sorted list of the fields. Descriptor has them in source file
366     // order.
367     map<int, const FieldDescriptor*> fields;
368     for (int j = 0; j < atom->field_count(); j++) {
369         const FieldDescriptor* field = atom->field(j);
370         fields[field->number()] = field;
371     }
372 
373     // Check that the parameters start at 1 and go up sequentially.
374     int expectedNumber = 1;
375     for (map<int, const FieldDescriptor*>::const_iterator it = fields.begin(); it != fields.end();
376          it++) {
377         const int number = it->first;
378         const FieldDescriptor* field = it->second;
379         if (number != expectedNumber) {
380             print_error(field,
381                         "Fields must be numbered consecutively starting at 1:"
382                         " '%s' is %d but should be %d\n",
383                         field->name().c_str(), number, expectedNumber);
384             errorCount++;
385             expectedNumber = number;
386             continue;
387         }
388         expectedNumber++;
389     }
390 
391     // Check that only allowed types are present. Remove any invalid ones.
392     for (map<int, const FieldDescriptor*>::const_iterator it = fields.begin(); it != fields.end();
393          it++) {
394         const FieldDescriptor* field = it->second;
395         bool isBinaryField = field->options().GetExtension(os::statsd::log_mode) ==
396                              os::statsd::LogMode::MODE_BYTES;
397 
398         java_type_t javaType = java_type(field);
399 
400         if (javaType == JAVA_TYPE_UNKNOWN_OR_INVALID) {
401             if (field->is_repeated()) {
402                 print_error(field, "Repeated field type %d is not allowed for field: %s\n",
403                             field->type(), field->name().c_str());
404             } else {
405                 print_error(field, "Field type %d is not allowed for field: %s\n", field->type(),
406                             field->name().c_str());
407             }
408             errorCount++;
409             continue;
410         } else if (javaType == JAVA_TYPE_OBJECT) {
411             // Allow attribution chain, but only at position 1.
412             print_error(field, "Message type not allowed for field without mode_bytes: %s\n",
413                         field->name().c_str());
414             errorCount++;
415             continue;
416         } else if (javaType == JAVA_TYPE_BYTE_ARRAY && !isBinaryField) {
417             print_error(field, "Raw bytes type not allowed for field: %s\n", field->name().c_str());
418             errorCount++;
419             continue;
420         }
421 
422         if (isBinaryField && javaType != JAVA_TYPE_BYTE_ARRAY) {
423             print_error(field, "Cannot mark field %s as bytes.\n", field->name().c_str());
424             errorCount++;
425             continue;
426         }
427 
428         if (atomDecl->restricted && !is_primitive_field(javaType)) {
429             print_error(field, "Restricted atom '%s' cannot have nonprimitive field: '%s'\n",
430                         atomDecl->message.c_str(), field->name().c_str());
431             errorCount++;
432             continue;
433         }
434     }
435 
436     // Check that if there's an attribution chain, it's at position 1.
437     for (map<int, const FieldDescriptor*>::const_iterator it = fields.begin(); it != fields.end();
438          it++) {
439         int number = it->first;
440         if (number != 1) {
441             const FieldDescriptor* field = it->second;
442             java_type_t javaType = java_type(field);
443             if (javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
444                 print_error(field,
445                             "AttributionChain fields must have field id 1, in message: '%s'\n",
446                             atom->name().c_str());
447                 errorCount++;
448             }
449         }
450     }
451 
452     // Build the type signature and the atom data.
453     for (map<int, const FieldDescriptor*>::const_iterator it = fields.begin(); it != fields.end();
454          it++) {
455         const FieldDescriptor* field = it->second;
456         java_type_t javaType = java_type(field);
457         bool isBinaryField = field->options().GetExtension(os::statsd::log_mode) ==
458                              os::statsd::LogMode::MODE_BYTES;
459 
460         AtomField atField(field->name(), javaType);
461 
462         if (javaType == JAVA_TYPE_ENUM || javaType == JAVA_TYPE_ENUM_ARRAY) {
463             atField.enumTypeName = field->enum_type()->name();
464             // All enums are treated as ints when it comes to function signatures.
465             collate_enums(*field->enum_type(), &atField);
466         }
467 
468         // Generate signature for atom.
469         if (javaType == JAVA_TYPE_ENUM) {
470             // All enums are treated as ints when it comes to function signatures.
471             signature->push_back(JAVA_TYPE_INT);
472         } else if (javaType == JAVA_TYPE_ENUM_ARRAY) {
473             signature->push_back(JAVA_TYPE_INT_ARRAY);
474         } else if (javaType == JAVA_TYPE_OBJECT && isBinaryField) {
475             signature->push_back(JAVA_TYPE_BYTE_ARRAY);
476         } else {
477             signature->push_back(javaType);
478         }
479 
480         atomDecl->fields.push_back(atField);
481 
482         errorCount += collate_field_annotations(atomDecl, field, it->first, javaType);
483     }
484 
485     return errorCount;
486 }
487 
488 // This function flattens the fields of the AttributionNode proto in an Atom
489 // proto and generates the corresponding atom decl and signature.
get_non_chained_node(const Descriptor * atom,AtomDecl * atomDecl,vector<java_type_t> * signature)490 bool get_non_chained_node(const Descriptor* atom, AtomDecl* atomDecl,
491                           vector<java_type_t>* signature) {
492     // Build a sorted list of the fields. Descriptor has them in source file
493     // order.
494     map<int, const FieldDescriptor*> fields;
495     for (int j = 0; j < atom->field_count(); j++) {
496         const FieldDescriptor* field = atom->field(j);
497         fields[field->number()] = field;
498     }
499 
500     AtomDecl attributionDecl;
501     vector<java_type_t> attributionSignature;
502     collate_atom(android::os::statsd::AttributionNode::descriptor(), &attributionDecl,
503                  &attributionSignature);
504 
505     // Build the type signature and the atom data.
506     bool has_attribution_node = false;
507     for (map<int, const FieldDescriptor*>::const_iterator it = fields.begin(); it != fields.end();
508          it++) {
509         const FieldDescriptor* field = it->second;
510         java_type_t javaType = java_type(field);
511         if (javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
512             atomDecl->fields.insert(atomDecl->fields.end(), attributionDecl.fields.begin(),
513                                     attributionDecl.fields.end());
514             signature->insert(signature->end(), attributionSignature.begin(),
515                               attributionSignature.end());
516             has_attribution_node = true;
517 
518         } else {
519             AtomField atField(field->name(), javaType);
520             if (javaType == JAVA_TYPE_ENUM) {
521                 // All enums are treated as ints when it comes to function signatures.
522                 signature->push_back(JAVA_TYPE_INT);
523                 collate_enums(*field->enum_type(), &atField);
524             } else {
525                 signature->push_back(javaType);
526             }
527             atomDecl->fields.push_back(atField);
528         }
529     }
530     return has_attribution_node;
531 }
532 
populateFieldNumberToAtomDeclSet(const shared_ptr<AtomDecl> & atomDecl,FieldNumberToAtomDeclSet * fieldNumberToAtomDeclSet)533 static void populateFieldNumberToAtomDeclSet(const shared_ptr<AtomDecl>& atomDecl,
534                                              FieldNumberToAtomDeclSet* fieldNumberToAtomDeclSet) {
535     for (FieldNumberToAnnotations::const_iterator it = atomDecl->fieldNumberToAnnotations.begin();
536          it != atomDecl->fieldNumberToAnnotations.end(); it++) {
537         const int fieldNumber = it->first;
538         (*fieldNumberToAtomDeclSet)[fieldNumber].insert(atomDecl);
539     }
540 }
541 
getAtomType(const FieldDescriptor * atomField)542 static AtomType getAtomType(const FieldDescriptor* atomField) {
543     const int atomId = atomField->number();
544     if ((atomId >= PLATFORM_PULLED_ATOMS_START && atomId <= PLATFORM_PULLED_ATOMS_END) ||
545         (atomId >= VENDOR_PULLED_ATOMS_START && atomId <= VENDOR_PULLED_ATOMS_END)) {
546         return ATOM_TYPE_PULLED;
547     } else {
548         return ATOM_TYPE_PUSHED;
549     }
550 }
551 
collate_from_field_descriptor(const FieldDescriptor * atomField,const string & moduleName,Atoms * atoms)552 static int collate_from_field_descriptor(const FieldDescriptor* atomField, const string& moduleName,
553                                          Atoms* atoms) {
554     int errorCount = 0;
555 
556     if (moduleName != DEFAULT_MODULE_NAME) {
557         const int moduleCount = atomField->options().ExtensionSize(os::statsd::module);
558         bool moduleFound = false;
559         for (int j = 0; j < moduleCount; ++j) {
560             const string atomModuleName = atomField->options().GetExtension(os::statsd::module, j);
561             if (atomModuleName == moduleName) {
562                 moduleFound = true;
563                 break;
564             }
565         }
566 
567         // This atom is not in the module we're interested in; skip it.
568         if (!moduleFound) {
569             if (dbg) {
570                 printf("   Skipping %s (%d)\n", atomField->name().c_str(), atomField->number());
571             }
572             return errorCount;
573         }
574     }
575 
576     if (dbg) {
577         printf("   %s (%d)\n", atomField->name().c_str(), atomField->number());
578     }
579 
580     // StatsEvent only has one oneof, which contains only messages. Don't allow
581     // other types.
582     if (atomField->type() != FieldDescriptor::TYPE_MESSAGE) {
583         print_error(atomField,
584                     "Bad type for atom. StatsEvent can only have message type "
585                     "fields: %s\n",
586                     atomField->name().c_str());
587         errorCount++;
588         return errorCount;
589     }
590 
591     const AtomType atomType = getAtomType(atomField);
592 
593     const Descriptor* atom = atomField->message_type();
594     shared_ptr<AtomDecl> atomDecl =
595             make_shared<AtomDecl>(atomField->number(), atomField->name(), atom->name(), atomType);
596 
597     if (atomField->options().GetExtension(os::statsd::truncate_timestamp)) {
598         addAnnotationToAtomDecl(atomDecl.get(), ATOM_ID_FIELD_NUMBER,
599                                 ANNOTATION_ID_TRUNCATE_TIMESTAMP, ANNOTATION_TYPE_BOOL,
600                                 AnnotationValue(true));
601         if (dbg) {
602             printf("%s can have timestamp truncated\n", atomField->name().c_str());
603         }
604     }
605 
606     if (atomField->options().HasExtension(os::statsd::restriction_category)) {
607         if (atomType == ATOM_TYPE_PULLED) {
608             print_error(atomField,
609                         "Restricted atoms cannot be pulled: '%s'\n",
610                         atomField->name().c_str());
611             errorCount++;
612             return errorCount;
613         }
614         const int restrictionCategory = atomField->options()
615                                         .GetExtension(os::statsd::restriction_category);
616         atomDecl.get()->restricted = true;
617         addAnnotationToAtomDecl(atomDecl.get(), ATOM_ID_FIELD_NUMBER,
618                                 ANNOTATION_ID_RESTRICTION_CATEGORY, ANNOTATION_TYPE_INT,
619                                 AnnotationValue(restrictionCategory));
620     }
621 
622     vector<java_type_t> signature;
623     errorCount += collate_atom(atom, atomDecl.get(), &signature);
624     if (!atomDecl->primaryFields.empty() && atomDecl->exclusiveField == 0) {
625         print_error(atomField, "Cannot have a primary field without an exclusive field: %s\n",
626                     atomField->name().c_str());
627         errorCount++;
628         return errorCount;
629     }
630 
631     FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet =
632             atomType == ATOM_TYPE_PUSHED ? atoms->signatureInfoMap[signature]
633                                          : atoms->pulledAtomsSignatureInfoMap[signature];
634     populateFieldNumberToAtomDeclSet(atomDecl, &fieldNumberToAtomDeclSet);
635 
636     atoms->decls.insert(atomDecl);
637 
638     shared_ptr<AtomDecl> nonChainedAtomDecl =
639             make_shared<AtomDecl>(atomField->number(), atomField->name(), atom->name(), atomType);
640     vector<java_type_t> nonChainedSignature;
641     if (get_non_chained_node(atom, nonChainedAtomDecl.get(), &nonChainedSignature)) {
642         FieldNumberToAtomDeclSet& nonChainedFieldNumberToAtomDeclSet =
643                 atoms->nonChainedSignatureInfoMap[nonChainedSignature];
644         populateFieldNumberToAtomDeclSet(nonChainedAtomDecl, &nonChainedFieldNumberToAtomDeclSet);
645 
646         atoms->non_chained_decls.insert(nonChainedAtomDecl);
647     }
648 
649     if (atomField->options().HasExtension(os::statsd::field_restriction_option)) {
650         print_error(atomField,
651                     "field_restriction_option must be a field-level annotation: '%s'\n",
652                     atomField->name().c_str());
653         errorCount++;
654     }
655 
656     return errorCount;
657 }
658 
659 /**
660  * Gather the info about the atoms.
661  */
collate_atoms(const Descriptor * descriptor,const string & moduleName,Atoms * atoms)662 int collate_atoms(const Descriptor* descriptor, const string& moduleName, Atoms* atoms) {
663     int errorCount = 0;
664 
665     // Regular field atoms in Atom
666     for (int i = 0; i < descriptor->field_count(); i++) {
667         const FieldDescriptor* atomField = descriptor->field(i);
668         errorCount += collate_from_field_descriptor(atomField, moduleName, atoms);
669     }
670 
671     // Extension field atoms in Atom.
672     vector<const FieldDescriptor*> extensions;
673     descriptor->file()->pool()->FindAllExtensions(descriptor, &extensions);
674     for (const FieldDescriptor* atomField : extensions) {
675         errorCount += collate_from_field_descriptor(atomField, moduleName, atoms);
676     }
677 
678     if (dbg) {
679         // Signatures for pushed atoms.
680         printf("signatures = [\n");
681         for (SignatureInfoMap::const_iterator it = atoms->signatureInfoMap.begin();
682              it != atoms->signatureInfoMap.end(); it++) {
683             printf("   ");
684             for (vector<java_type_t>::const_iterator jt = it->first.begin(); jt != it->first.end();
685                  jt++) {
686                 printf(" %d", static_cast<int>(*jt));
687             }
688             printf("\n");
689         }
690 
691         // Signatures for pull atoms.
692         for (SignatureInfoMap::const_iterator it = atoms->pulledAtomsSignatureInfoMap.begin();
693              it != atoms->pulledAtomsSignatureInfoMap.end(); it++) {
694             printf("   ");
695             for (vector<java_type_t>::const_iterator jt = it->first.begin(); jt != it->first.end();
696                  jt++) {
697                 printf(" %d", static_cast<int>(*jt));
698             }
699             printf("\n");
700         }
701         printf("]\n");
702     }
703 
704     return errorCount;
705 }
706 
707 }  // namespace stats_log_api_gen
708 }  // namespace android
709