• 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 
25 namespace android {
26 namespace stats_log_api_gen {
27 
28 using google::protobuf::OneofDescriptor;
29 using google::protobuf::EnumDescriptor;
30 using google::protobuf::FieldDescriptor;
31 using google::protobuf::FileDescriptor;
32 using google::protobuf::SourceLocation;
33 using std::make_shared;
34 using std::map;
35 
36 const bool dbg = false;
37 
38 //
39 // AtomDecl class
40 //
41 
AtomDecl()42 AtomDecl::AtomDecl() : code(0), name() {
43 }
44 
AtomDecl(const AtomDecl & that)45 AtomDecl::AtomDecl(const AtomDecl& that)
46     : code(that.code),
47       name(that.name),
48       message(that.message),
49       fields(that.fields),
50       oneOfName(that.oneOfName),
51       fieldNumberToAnnotations(that.fieldNumberToAnnotations),
52       primaryFields(that.primaryFields),
53       exclusiveField(that.exclusiveField),
54       defaultState(that.defaultState),
55       triggerStateReset(that.triggerStateReset),
56       nested(that.nested),
57       uidField(that.uidField) {
58 }
59 
AtomDecl(int c,const string & n,const string & m,const string & o)60 AtomDecl::AtomDecl(int c, const string& n, const string& m, const string &o)
61     : code(c), name(n), message(m), oneOfName(o) {
62 }
63 
~AtomDecl()64 AtomDecl::~AtomDecl() {
65 }
66 
67 /**
68  * Print an error message for a FieldDescriptor, including the file name and
69  * line number.
70  */
print_error(const FieldDescriptor * field,const char * format,...)71 static void print_error(const FieldDescriptor* field, const char* format, ...) {
72     const Descriptor* message = field->containing_type();
73     const FileDescriptor* file = message->file();
74 
75     SourceLocation loc;
76     if (field->GetSourceLocation(&loc)) {
77         // TODO(b/162454173): this will work if we can figure out how to pass
78         // --include_source_info to protoc
79         fprintf(stderr, "%s:%d: ", file->name().c_str(), loc.start_line);
80     } else {
81         fprintf(stderr, "%s: ", file->name().c_str());
82     }
83     va_list args;
84     va_start(args, format);
85     vfprintf(stderr, format, args);
86     va_end(args);
87 }
88 
89 /**
90  * Convert a protobuf type into a java type.
91  */
java_type(const FieldDescriptor * field)92 static java_type_t java_type(const FieldDescriptor* field) {
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             if (field->message_type()->full_name() == "android.os.statsd.AttributionNode") {
117                 return JAVA_TYPE_ATTRIBUTION_CHAIN;
118             } else if (field->message_type()->full_name() == "android.os.statsd.KeyValuePair") {
119                 return JAVA_TYPE_KEY_VALUE_PAIR;
120             } else if (field->options().GetExtension(os::statsd::log_mode) ==
121                        os::statsd::LogMode::MODE_BYTES) {
122                 return JAVA_TYPE_BYTE_ARRAY;
123             } 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:
131             return JAVA_TYPE_ENUM;
132         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 /**
146  * Gather the enums info.
147  */
collate_enums(const EnumDescriptor & enumDescriptor,AtomField * atomField)148 void 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();
152     }
153 }
154 
addAnnotationToAtomDecl(AtomDecl * atomDecl,const int fieldNumber,const AnnotationId annotationId,const AnnotationType annotationType,const AnnotationValue annotationValue)155 static void addAnnotationToAtomDecl(AtomDecl* atomDecl, const int fieldNumber,
156                                     const AnnotationId annotationId,
157                                     const AnnotationType annotationType,
158                                     const AnnotationValue annotationValue) {
159     if (dbg) {
160         printf("   Adding annotation to %s: [%d] = {id: %d, type: %d}\n", atomDecl->name.c_str(),
161                fieldNumber, annotationId, annotationType);
162     }
163     atomDecl->fieldNumberToAnnotations[fieldNumber].insert(
164             make_shared<Annotation>(annotationId, atomDecl->code, annotationType, annotationValue));
165 }
166 
collate_field_annotations(AtomDecl * atomDecl,const FieldDescriptor * field,const int fieldNumber,const java_type_t & javaType)167 static int collate_field_annotations(AtomDecl* atomDecl, const FieldDescriptor* field,
168                                      const int fieldNumber, const java_type_t& javaType) {
169     int errorCount = 0;
170 
171     if (field->options().HasExtension(os::statsd::state_field_option)) {
172         const os::statsd::StateAtomFieldOption& stateFieldOption =
173                 field->options().GetExtension(os::statsd::state_field_option);
174         const bool primaryField = stateFieldOption.primary_field();
175         const bool exclusiveState = stateFieldOption.exclusive_state();
176         const bool primaryFieldFirstUid = stateFieldOption.primary_field_first_uid();
177 
178         // Check the field is only one of primaryField, exclusiveState, or primaryFieldFirstUid.
179         if (primaryField + primaryFieldFirstUid + exclusiveState > 1) {
180             print_error(field,
181                         "Field can be max 1 of primary_field, exclusive_state, "
182                         "or primary_field_first_uid: '%s'\n",
183                         atomDecl->message.c_str());
184             errorCount++;
185         }
186 
187         if (primaryField) {
188             if (javaType == JAVA_TYPE_UNKNOWN || javaType == JAVA_TYPE_ATTRIBUTION_CHAIN ||
189                 javaType == JAVA_TYPE_OBJECT || javaType == JAVA_TYPE_BYTE_ARRAY) {
190                 print_error(field, "Invalid primary state field: '%s'\n",
191                             atomDecl->message.c_str());
192                 errorCount++;
193             } else {
194                 atomDecl->primaryFields.push_back(fieldNumber);
195                 addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_PRIMARY_FIELD,
196                                         ANNOTATION_TYPE_BOOL, AnnotationValue(true));
197             }
198         }
199 
200         if (primaryFieldFirstUid) {
201             if (javaType != JAVA_TYPE_ATTRIBUTION_CHAIN) {
202                 print_error(field,
203                             "PRIMARY_FIELD_FIRST_UID annotation is only for AttributionChains: "
204                             "'%s'\n",
205                             atomDecl->message.c_str());
206                 errorCount++;
207             } else {
208                 atomDecl->primaryFields.push_back(FIRST_UID_IN_CHAIN_ID);
209                 addAnnotationToAtomDecl(atomDecl, fieldNumber,
210                                         ANNOTATION_ID_PRIMARY_FIELD_FIRST_UID, ANNOTATION_TYPE_BOOL,
211                                         AnnotationValue(true));
212             }
213         }
214 
215         if (exclusiveState) {
216             if (javaType == JAVA_TYPE_UNKNOWN || javaType == JAVA_TYPE_ATTRIBUTION_CHAIN ||
217                 javaType == JAVA_TYPE_OBJECT || javaType == JAVA_TYPE_BYTE_ARRAY) {
218                 print_error(field, "Invalid exclusive state field: '%s'\n",
219                             atomDecl->message.c_str());
220                 errorCount++;
221             }
222 
223             if (atomDecl->exclusiveField != 0) {
224                 print_error(field,
225                             "Cannot have more than one exclusive state field in an "
226                             "atom: '%s'\n",
227                             atomDecl->message.c_str());
228                 errorCount++;
229             } else {
230                 atomDecl->exclusiveField = fieldNumber;
231                 addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_EXCLUSIVE_STATE,
232                                         ANNOTATION_TYPE_BOOL, AnnotationValue(true));
233             }
234 
235             if (stateFieldOption.has_default_state_value()) {
236                 const int defaultState = stateFieldOption.default_state_value();
237                 atomDecl->defaultState = defaultState;
238 
239                 addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_DEFAULT_STATE,
240                                         ANNOTATION_TYPE_INT, AnnotationValue(defaultState));
241             }
242 
243             if (stateFieldOption.has_trigger_state_reset_value()) {
244                 const int triggerStateReset = stateFieldOption.trigger_state_reset_value();
245 
246                 atomDecl->triggerStateReset = triggerStateReset;
247                 addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_TRIGGER_STATE_RESET,
248                                         ANNOTATION_TYPE_INT, AnnotationValue(triggerStateReset));
249             }
250 
251             if (stateFieldOption.has_nested()) {
252                 const bool nested = stateFieldOption.nested();
253                 atomDecl->nested = nested;
254 
255                 addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_STATE_NESTED,
256                                         ANNOTATION_TYPE_BOOL, AnnotationValue(nested));
257             }
258         }
259     }
260 
261     if (field->options().GetExtension(os::statsd::is_uid) == true) {
262         if (javaType != JAVA_TYPE_INT) {
263             print_error(field, "is_uid annotation can only be applied to int32 fields: '%s'\n",
264                         atomDecl->message.c_str());
265             errorCount++;
266         }
267 
268         if (atomDecl->uidField == 0) {
269             atomDecl->uidField = fieldNumber;
270 
271             addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_IS_UID,
272                                     ANNOTATION_TYPE_BOOL, AnnotationValue(true));
273         } else {
274             print_error(field,
275                         "Cannot have more than one field in an atom with is_uid "
276                         "annotation: '%s'\n",
277                         atomDecl->message.c_str());
278             errorCount++;
279         }
280     }
281 
282     return errorCount;
283 }
284 
285 /**
286  * Gather the info about an atom proto.
287  */
collate_atom(const Descriptor * atom,AtomDecl * atomDecl,vector<java_type_t> * signature)288 int collate_atom(const Descriptor* atom, AtomDecl* atomDecl, vector<java_type_t>* signature) {
289     int errorCount = 0;
290 
291     // Build a sorted list of the fields. Descriptor has them in source file
292     // order.
293     map<int, const FieldDescriptor*> fields;
294     for (int j = 0; j < atom->field_count(); j++) {
295         const FieldDescriptor* field = atom->field(j);
296         fields[field->number()] = field;
297     }
298 
299     // Check that the parameters start at 1 and go up sequentially.
300     int expectedNumber = 1;
301     for (map<int, const FieldDescriptor*>::const_iterator it = fields.begin(); it != fields.end();
302          it++) {
303         const int number = it->first;
304         const FieldDescriptor* field = it->second;
305         if (number != expectedNumber) {
306             print_error(field,
307                         "Fields must be numbered consecutively starting at 1:"
308                         " '%s' is %d but should be %d\n",
309                         field->name().c_str(), number, expectedNumber);
310             errorCount++;
311             expectedNumber = number;
312             continue;
313         }
314         expectedNumber++;
315     }
316 
317     // Check that only allowed types are present. Remove any invalid ones.
318     for (map<int, const FieldDescriptor*>::const_iterator it = fields.begin(); it != fields.end();
319          it++) {
320         const FieldDescriptor* field = it->second;
321         bool isBinaryField = field->options().GetExtension(os::statsd::log_mode) ==
322                              os::statsd::LogMode::MODE_BYTES;
323 
324         java_type_t javaType = java_type(field);
325 
326         if (javaType == JAVA_TYPE_UNKNOWN) {
327             print_error(field, "Unknown type for field: %s\n", field->name().c_str());
328             errorCount++;
329             continue;
330         } else if (javaType == JAVA_TYPE_OBJECT && atomDecl->code < PULL_ATOM_START_ID) {
331             // Allow attribution chain, but only at position 1.
332             print_error(field, "Message type not allowed for field in pushed atoms: %s\n",
333                         field->name().c_str());
334             errorCount++;
335             continue;
336         } else if (javaType == JAVA_TYPE_BYTE_ARRAY && !isBinaryField) {
337             print_error(field, "Raw bytes type not allowed for field: %s\n", field->name().c_str());
338             errorCount++;
339             continue;
340         }
341 
342         if (isBinaryField && javaType != JAVA_TYPE_BYTE_ARRAY) {
343             print_error(field, "Cannot mark field %s as bytes.\n", field->name().c_str());
344             errorCount++;
345             continue;
346         }
347 
348         // Doubles are not supported yet.
349         if (javaType == JAVA_TYPE_DOUBLE) {
350             print_error(field,
351                         "Doubles are not supported in atoms. Please change field %s "
352                         "to float\n",
353                         field->name().c_str());
354             errorCount++;
355             continue;
356         }
357 
358         if (field->is_repeated() &&
359             !(javaType == JAVA_TYPE_ATTRIBUTION_CHAIN || javaType == JAVA_TYPE_KEY_VALUE_PAIR)) {
360             print_error(field,
361                         "Repeated fields are not supported in atoms. Please make "
362                         "field %s not "
363                         "repeated.\n",
364                         field->name().c_str());
365             errorCount++;
366             continue;
367         }
368     }
369 
370     // Check that if there's an attribution chain, it's at position 1.
371     for (map<int, const FieldDescriptor*>::const_iterator it = fields.begin(); it != fields.end();
372          it++) {
373         int number = it->first;
374         if (number != 1) {
375             const FieldDescriptor* field = it->second;
376             java_type_t javaType = java_type(field);
377             if (javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
378                 print_error(field,
379                             "AttributionChain fields must have field id 1, in message: '%s'\n",
380                             atom->name().c_str());
381                 errorCount++;
382             }
383         }
384     }
385 
386     // Build the type signature and the atom data.
387     for (map<int, const FieldDescriptor*>::const_iterator it = fields.begin(); it != fields.end();
388          it++) {
389         const FieldDescriptor* field = it->second;
390         java_type_t javaType = java_type(field);
391         bool isBinaryField = field->options().GetExtension(os::statsd::log_mode) ==
392                              os::statsd::LogMode::MODE_BYTES;
393 
394         AtomField atField(field->name(), javaType);
395 
396         if (javaType == JAVA_TYPE_ENUM) {
397             // All enums are treated as ints when it comes to function signatures.
398             collate_enums(*field->enum_type(), &atField);
399         }
400 
401         // Generate signature for atom.
402         if (javaType == JAVA_TYPE_ENUM) {
403             // All enums are treated as ints when it comes to function signatures.
404             signature->push_back(JAVA_TYPE_INT);
405         } else if (javaType == JAVA_TYPE_OBJECT && isBinaryField) {
406             signature->push_back(JAVA_TYPE_BYTE_ARRAY);
407         } else {
408             signature->push_back(javaType);
409         }
410 
411         atomDecl->fields.push_back(atField);
412 
413         errorCount += collate_field_annotations(atomDecl, field, it->first, javaType);
414     }
415 
416     return errorCount;
417 }
418 
419 // This function flattens the fields of the AttributionNode proto in an Atom
420 // proto and generates the corresponding atom decl and signature.
get_non_chained_node(const Descriptor * atom,AtomDecl * atomDecl,vector<java_type_t> * signature)421 bool get_non_chained_node(const Descriptor* atom, AtomDecl* atomDecl,
422                           vector<java_type_t>* signature) {
423     // Build a sorted list of the fields. Descriptor has them in source file
424     // order.
425     map<int, const FieldDescriptor*> fields;
426     for (int j = 0; j < atom->field_count(); j++) {
427         const FieldDescriptor* field = atom->field(j);
428         fields[field->number()] = field;
429     }
430 
431     AtomDecl attributionDecl;
432     vector<java_type_t> attributionSignature;
433     collate_atom(android::os::statsd::AttributionNode::descriptor(), &attributionDecl,
434                  &attributionSignature);
435 
436     // Build the type signature and the atom data.
437     bool has_attribution_node = false;
438     for (map<int, const FieldDescriptor*>::const_iterator it = fields.begin(); it != fields.end();
439          it++) {
440         const FieldDescriptor* field = it->second;
441         java_type_t javaType = java_type(field);
442         if (javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
443             atomDecl->fields.insert(atomDecl->fields.end(), attributionDecl.fields.begin(),
444                                     attributionDecl.fields.end());
445             signature->insert(signature->end(), attributionSignature.begin(),
446                               attributionSignature.end());
447             has_attribution_node = true;
448 
449         } else {
450             AtomField atField(field->name(), javaType);
451             if (javaType == JAVA_TYPE_ENUM) {
452                 // All enums are treated as ints when it comes to function signatures.
453                 signature->push_back(JAVA_TYPE_INT);
454                 collate_enums(*field->enum_type(), &atField);
455             } else {
456                 signature->push_back(javaType);
457             }
458             atomDecl->fields.push_back(atField);
459         }
460     }
461     return has_attribution_node;
462 }
463 
populateFieldNumberToAtomDeclSet(const shared_ptr<AtomDecl> & atomDecl,FieldNumberToAtomDeclSet * fieldNumberToAtomDeclSet)464 static void populateFieldNumberToAtomDeclSet(const shared_ptr<AtomDecl>& atomDecl,
465                                              FieldNumberToAtomDeclSet* fieldNumberToAtomDeclSet) {
466     for (FieldNumberToAnnotations::const_iterator it = atomDecl->fieldNumberToAnnotations.begin();
467          it != atomDecl->fieldNumberToAnnotations.end(); it++) {
468         const int fieldNumber = it->first;
469         (*fieldNumberToAtomDeclSet)[fieldNumber].insert(atomDecl);
470     }
471 }
472 
473 /**
474  * Gather the info about the atoms.
475  */
collate_atoms(const Descriptor * descriptor,const string & moduleName,Atoms * atoms)476 int collate_atoms(const Descriptor* descriptor, const string& moduleName, Atoms* atoms) {
477     int errorCount = 0;
478 
479     for (int i = 0; i < descriptor->field_count(); i++) {
480         const FieldDescriptor* atomField = descriptor->field(i);
481 
482         if (moduleName != DEFAULT_MODULE_NAME) {
483             const int moduleCount = atomField->options().ExtensionSize(os::statsd::module);
484             int j;
485             for (j = 0; j < moduleCount; ++j) {
486                 const string atomModuleName =
487                         atomField->options().GetExtension(os::statsd::module, j);
488                 if (atomModuleName == moduleName) {
489                     break;
490                 }
491             }
492 
493             // This atom is not in the module we're interested in; skip it.
494             if (moduleCount == j) {
495                 if (dbg) {
496                     printf("   Skipping %s (%d)\n", atomField->name().c_str(), atomField->number());
497                 }
498                 continue;
499             }
500         }
501 
502         if (dbg) {
503             printf("   %s (%d)\n", atomField->name().c_str(), atomField->number());
504         }
505 
506         // StatsEvent only has one oneof, which contains only messages. Don't allow
507         // other types.
508         if (atomField->type() != FieldDescriptor::TYPE_MESSAGE) {
509             print_error(atomField,
510                         "Bad type for atom. StatsEvent can only have message type "
511                         "fields: %s\n",
512                         atomField->name().c_str());
513             errorCount++;
514             continue;
515         }
516 
517         const OneofDescriptor* oneofAtom = atomField->containing_oneof();
518         if (oneofAtom == nullptr) {
519             print_error(atomField, "Atom is not declared in a `oneof` field: %s\n",
520                         atomField->name().c_str());
521             errorCount++;
522             continue;
523         }
524 
525         const Descriptor* atom = atomField->message_type();
526         shared_ptr<AtomDecl> atomDecl =
527                 make_shared<AtomDecl>(atomField->number(), atomField->name(), atom->name(),
528                                       oneofAtom->name());
529 
530         if (atomField->options().GetExtension(os::statsd::truncate_timestamp)) {
531             addAnnotationToAtomDecl(atomDecl.get(), ATOM_ID_FIELD_NUMBER,
532                                     ANNOTATION_ID_TRUNCATE_TIMESTAMP, ANNOTATION_TYPE_BOOL,
533                                     AnnotationValue(true));
534             if (dbg) {
535                 printf("%s can have timestamp truncated\n", atomField->name().c_str());
536             }
537         }
538 
539         vector<java_type_t> signature;
540         errorCount += collate_atom(atom, atomDecl.get(), &signature);
541         if (!atomDecl->primaryFields.empty() && atomDecl->exclusiveField == 0) {
542             print_error(atomField, "Cannot have a primary field without an exclusive field: %s\n",
543                         atomField->name().c_str());
544             errorCount++;
545             continue;
546         }
547 
548         if ((oneofAtom->name() != ONEOF_PUSHED_ATOM_NAME) &&
549                  (oneofAtom->name() != ONEOF_PULLED_ATOM_NAME)) {
550             print_error(atomField, "Atom is neither a pushed nor pulled atom: %s\n",
551                         atomField->name().c_str());
552             errorCount++;
553             continue;
554         }
555 
556         FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet = oneofAtom->name() ==
557             ONEOF_PUSHED_ATOM_NAME ? atoms->signatureInfoMap[signature] :
558             atoms->pulledAtomsSignatureInfoMap[signature];
559         populateFieldNumberToAtomDeclSet(atomDecl, &fieldNumberToAtomDeclSet);
560 
561         atoms->decls.insert(atomDecl);
562 
563         shared_ptr<AtomDecl> nonChainedAtomDecl =
564                 make_shared<AtomDecl>(atomField->number(), atomField->name(), atom->name(),
565                                       oneofAtom->name());
566         vector<java_type_t> nonChainedSignature;
567         if (get_non_chained_node(atom, nonChainedAtomDecl.get(), &nonChainedSignature)) {
568             FieldNumberToAtomDeclSet& nonChainedFieldNumberToAtomDeclSet =
569                     atoms->nonChainedSignatureInfoMap[nonChainedSignature];
570             populateFieldNumberToAtomDeclSet(nonChainedAtomDecl,
571                                              &nonChainedFieldNumberToAtomDeclSet);
572 
573             atoms->non_chained_decls.insert(nonChainedAtomDecl);
574         }
575     }
576 
577     if (dbg) {
578         // Signatures for pushed atoms.
579         printf("signatures = [\n");
580         for (SignatureInfoMap::const_iterator it = atoms->signatureInfoMap.begin();
581              it != atoms->signatureInfoMap.end(); it++) {
582             printf("   ");
583             for (vector<java_type_t>::const_iterator jt = it->first.begin(); jt != it->first.end();
584                  jt++) {
585                 printf(" %d", static_cast<int>(*jt));
586             }
587             printf("\n");
588         }
589 
590         // Signatures for pull atoms.
591         for (SignatureInfoMap::const_iterator it = atoms->pulledAtomsSignatureInfoMap.begin();
592              it != atoms->pulledAtomsSignatureInfoMap.end(); it++) {
593             printf("   ");
594             for (vector<java_type_t>::const_iterator jt = it->first.begin(); jt != it->first.end();
595                  jt++) {
596                 printf(" %d", static_cast<int>(*jt));
597             }
598             printf("\n");
599         }
600         printf("]\n");
601     }
602 
603     return errorCount;
604 }
605 
606 }  // namespace stats_log_api_gen
607 }  // namespace android
608