• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019, 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 "utils.h"
18 
19 namespace android {
20 namespace stats_log_api_gen {
21 
22 /**
23  * Inlining this method because "android-base/strings.h" is not available on
24  * google3.
25  */
Split(const string & s,const string & delimiters)26 static vector<string> Split(const string& s, const string& delimiters) {
27     GOOGLE_CHECK_NE(delimiters.size(), 0U);
28 
29     vector<string> result;
30 
31     size_t base = 0;
32     size_t found;
33     while (true) {
34         found = s.find_first_of(delimiters, base);
35         result.push_back(s.substr(base, found - base));
36         if (found == s.npos) break;
37         base = found + 1;
38     }
39 
40     return result;
41 }
42 
build_non_chained_decl_map(const Atoms & atoms,std::map<int,AtomDeclSet::const_iterator> * decl_map)43 void build_non_chained_decl_map(const Atoms& atoms,
44                                 std::map<int, AtomDeclSet::const_iterator>* decl_map) {
45     for (AtomDeclSet::const_iterator atomIt = atoms.non_chained_decls.begin();
46          atomIt != atoms.non_chained_decls.end(); atomIt++) {
47         decl_map->insert(std::make_pair((*atomIt)->code, atomIt));
48     }
49 }
50 
get_annotation_id_constants()51 const map<AnnotationId, AnnotationStruct>& get_annotation_id_constants() {
52     static const map<AnnotationId, AnnotationStruct>* ANNOTATION_ID_CONSTANTS =
53             new map<AnnotationId, AnnotationStruct>{
54             {ANNOTATION_ID_IS_UID,
55              AnnotationStruct("ANNOTATION_ID_IS_UID", API_S)},
56             {ANNOTATION_ID_TRUNCATE_TIMESTAMP,
57              AnnotationStruct("ANNOTATION_ID_TRUNCATE_TIMESTAMP", API_S)},
58             {ANNOTATION_ID_PRIMARY_FIELD,
59              AnnotationStruct("ANNOTATION_ID_PRIMARY_FIELD", API_S)},
60             {ANNOTATION_ID_EXCLUSIVE_STATE,
61              AnnotationStruct("ANNOTATION_ID_EXCLUSIVE_STATE", API_S)},
62             {ANNOTATION_ID_PRIMARY_FIELD_FIRST_UID,
63              AnnotationStruct("ANNOTATION_ID_PRIMARY_FIELD_FIRST_UID", API_S)},
64             {ANNOTATION_ID_DEFAULT_STATE,
65              AnnotationStruct("ANNOTATION_ID_DEFAULT_STATE", API_S)},
66             {ANNOTATION_ID_TRIGGER_STATE_RESET,
67              AnnotationStruct("ANNOTATION_ID_TRIGGER_STATE_RESET", API_S)},
68             {ANNOTATION_ID_STATE_NESTED,
69              AnnotationStruct("ANNOTATION_ID_STATE_NESTED", API_S)},
70             {ANNOTATION_ID_RESTRICTION_CATEGORY,
71              AnnotationStruct("ANNOTATION_ID_RESTRICTION_CATEGORY", API_U)},
72             {ANNOTATION_ID_FIELD_RESTRICTION_PERIPHERAL_DEVICE_INFO,
73              AnnotationStruct("ANNOTATION_ID_FIELD_RESTRICTION_PERIPHERAL_DEVICE_INFO", API_U)},
74             {ANNOTATION_ID_FIELD_RESTRICTION_APP_USAGE,
75              AnnotationStruct("ANNOTATION_ID_FIELD_RESTRICTION_APP_USAGE", API_U)},
76             {ANNOTATION_ID_FIELD_RESTRICTION_APP_ACTIVITY,
77              AnnotationStruct("ANNOTATION_ID_FIELD_RESTRICTION_APP_ACTIVITY", API_U)},
78             {ANNOTATION_ID_FIELD_RESTRICTION_HEALTH_CONNECT,
79              AnnotationStruct("ANNOTATION_ID_FIELD_RESTRICTION_HEALTH_CONNECT", API_U)},
80             {ANNOTATION_ID_FIELD_RESTRICTION_ACCESSIBILITY,
81              AnnotationStruct("ANNOTATION_ID_FIELD_RESTRICTION_ACCESSIBILITY", API_U)},
82             {ANNOTATION_ID_FIELD_RESTRICTION_SYSTEM_SEARCH,
83              AnnotationStruct("ANNOTATION_ID_FIELD_RESTRICTION_SYSTEM_SEARCH", API_U)},
84             {ANNOTATION_ID_FIELD_RESTRICTION_USER_ENGAGEMENT,
85              AnnotationStruct("ANNOTATION_ID_FIELD_RESTRICTION_USER_ENGAGEMENT", API_U)},
86             {ANNOTATION_ID_FIELD_RESTRICTION_AMBIENT_SENSING,
87              AnnotationStruct("ANNOTATION_ID_FIELD_RESTRICTION_AMBIENT_SENSING", API_U)},
88             {ANNOTATION_ID_FIELD_RESTRICTION_DEMOGRAPHIC_CLASSIFICATION,
89              AnnotationStruct("ANNOTATION_ID_FIELD_RESTRICTION_DEMOGRAPHIC_CLASSIFICATION", API_U)},
90     };
91 
92     return *ANNOTATION_ID_CONSTANTS;
93 }
94 
get_java_build_version_code(int minApiLevel)95 string get_java_build_version_code(int minApiLevel) {
96     switch (minApiLevel) {
97         case API_Q:
98             return "Build.VERSION_CODES.Q";
99         case API_R:
100             return "Build.VERSION_CODES.R";
101         case API_S:
102             return "Build.VERSION_CODES.S";
103         case API_S_V2:
104             return "Build.VERSION_CODES.S_V2";
105         case API_T:
106             return "Build.VERSION_CODES.TIRAMISU";
107         case API_U:
108             return "Build.VERSION_CODES.UPSIDE_DOWN_CAKE";
109         default:
110             return "Build.VERSION_CODES.CUR_DEVELOPMENT";
111     }
112 }
113 
get_restriction_category_str(int annotationValue)114 string get_restriction_category_str(int annotationValue) {
115     switch (annotationValue) {
116         case os::statsd::RestrictionCategory::RESTRICTION_DIAGNOSTIC:
117             return "RESTRICTION_CATEGORY_DIAGNOSTIC";
118         case os::statsd::RestrictionCategory::RESTRICTION_SYSTEM_INTELLIGENCE:
119             return "RESTRICTION_CATEGORY_SYSTEM_INTELLIGENCE";
120         case os::statsd::RestrictionCategory::RESTRICTION_AUTHENTICATION:
121             return "RESTRICTION_CATEGORY_AUTHENTICATION";
122         case os::statsd::RestrictionCategory::RESTRICTION_FRAUD_AND_ABUSE:
123             return "RESTRICTION_CATEGORY_FRAUD_AND_ABUSE";
124         default:
125             return "";
126     }
127 }
128 
129 /**
130  * Turn lower and camel case into upper case with underscores.
131  */
make_constant_name(const string & str)132 string make_constant_name(const string& str) {
133     string result;
134     const int N = str.size();
135     bool underscore_next = false;
136     for (int i = 0; i < N; i++) {
137         char c = str[i];
138         if (c >= 'A' && c <= 'Z') {
139             if (underscore_next) {
140                 result += '_';
141                 underscore_next = false;
142             }
143         } else if (c >= 'a' && c <= 'z') {
144             c = 'A' + c - 'a';
145             underscore_next = true;
146         } else if (c == '_') {
147             underscore_next = false;
148         }
149         result += c;
150     }
151     return result;
152 }
153 
cpp_type_name(java_type_t type,bool isVendorAtomLogging)154 const char* cpp_type_name(java_type_t type, bool isVendorAtomLogging) {
155     switch (type) {
156         case JAVA_TYPE_BOOLEAN:
157             return "bool";
158         case JAVA_TYPE_INT:  // Fallthrough.
159         case JAVA_TYPE_ENUM:
160             return "int32_t";
161         case JAVA_TYPE_LONG:
162             return "int64_t";
163         case JAVA_TYPE_FLOAT:
164             return "float";
165         case JAVA_TYPE_DOUBLE:
166             return "double";
167         case JAVA_TYPE_STRING:
168             return "char const*";
169         case JAVA_TYPE_BYTE_ARRAY:
170             return isVendorAtomLogging ? "const std::vector<uint8_t>&" : "const BytesField&";
171         case JAVA_TYPE_BOOLEAN_ARRAY:
172             return isVendorAtomLogging ? "const std::vector<bool>&" : "const bool*";
173         case JAVA_TYPE_INT_ARRAY:  // Fallthrough.
174         case JAVA_TYPE_ENUM_ARRAY:
175             return "const std::vector<int32_t>&";
176         case JAVA_TYPE_LONG_ARRAY:
177             return "const std::vector<int64_t>&";
178         case JAVA_TYPE_FLOAT_ARRAY:
179             return "const std::vector<float>&";
180         case JAVA_TYPE_STRING_ARRAY:
181             return "const std::vector<char const*>&";
182         case JAVA_TYPE_DOUBLE_ARRAY:
183             return "const std::vector<double>&";
184         default:
185             return "UNKNOWN";
186     }
187 }
188 
java_type_name(java_type_t type)189 const char* java_type_name(java_type_t type) {
190     switch (type) {
191         case JAVA_TYPE_BOOLEAN:
192             return "boolean";
193         case JAVA_TYPE_INT:  // Fallthrough.
194         case JAVA_TYPE_ENUM:
195             return "int";
196         case JAVA_TYPE_LONG:
197             return "long";
198         case JAVA_TYPE_FLOAT:
199             return "float";
200         case JAVA_TYPE_DOUBLE:
201             return "double";
202         case JAVA_TYPE_STRING:
203             return "java.lang.String";
204         case JAVA_TYPE_BYTE_ARRAY:
205             return "byte[]";
206         case JAVA_TYPE_BOOLEAN_ARRAY:
207             return "boolean[]";
208         case JAVA_TYPE_INT_ARRAY:  // Fallthrough.
209         case JAVA_TYPE_ENUM_ARRAY:
210             return "int[]";
211         case JAVA_TYPE_LONG_ARRAY:
212             return "long[]";
213         case JAVA_TYPE_FLOAT_ARRAY:
214             return "float[]";
215         case JAVA_TYPE_STRING_ARRAY:
216             return "java.lang.String[]";
217         case JAVA_TYPE_DOUBLE_ARRAY:
218             return "double[]";
219         default:
220             return "UNKNOWN";
221     }
222 }
223 
224 // Does not include AttributionChain type.
is_repeated_field(java_type_t type)225 bool is_repeated_field(java_type_t type) {
226     switch (type) {
227         case JAVA_TYPE_BOOLEAN_ARRAY:
228         case JAVA_TYPE_INT_ARRAY:
229         case JAVA_TYPE_FLOAT_ARRAY:
230         case JAVA_TYPE_LONG_ARRAY:
231         case JAVA_TYPE_STRING_ARRAY:
232         case JAVA_TYPE_ENUM_ARRAY:
233             return true;
234         default:
235             return false;
236     }
237 }
238 
is_primitive_field(java_type_t type)239 bool is_primitive_field(java_type_t type) {
240     switch (type) {
241         case JAVA_TYPE_BOOLEAN:
242         case JAVA_TYPE_INT:
243         case JAVA_TYPE_LONG:
244         case JAVA_TYPE_FLOAT:
245         case JAVA_TYPE_STRING:
246         case JAVA_TYPE_ENUM:
247             return true;
248         default:
249             return false;
250     }
251 }
252 
253 // Native
254 // Writes namespaces for the cpp and header files
write_namespace(FILE * out,const string & cppNamespaces)255 void write_namespace(FILE* out, const string& cppNamespaces) {
256     vector<string> cppNamespaceVec = Split(cppNamespaces, ",");
257     for (const string& cppNamespace : cppNamespaceVec) {
258         fprintf(out, "namespace %s {\n", cppNamespace.c_str());
259     }
260 }
261 
262 // Writes namespace closing brackets for cpp and header files.
write_closing_namespace(FILE * out,const string & cppNamespaces)263 void write_closing_namespace(FILE* out, const string& cppNamespaces) {
264     vector<string> cppNamespaceVec = Split(cppNamespaces, ",");
265     for (auto it = cppNamespaceVec.rbegin(); it != cppNamespaceVec.rend(); ++it) {
266         fprintf(out, "} // namespace %s\n", it->c_str());
267     }
268 }
269 
write_cpp_usage(FILE * out,const string & method_name,const string & atom_code_name,const shared_ptr<AtomDecl> atom,const AtomDecl & attributionDecl,bool isVendorAtomLogging=false)270 static void write_cpp_usage(FILE* out, const string& method_name, const string& atom_code_name,
271                             const shared_ptr<AtomDecl> atom, const AtomDecl& attributionDecl,
272                             bool isVendorAtomLogging = false) {
273     const char* delimiterStr = method_name.find('(') == string::npos ? "(" : " ";
274     fprintf(out, "     * Usage: %s%s%s", method_name.c_str(), delimiterStr, atom_code_name.c_str());
275 
276     for (vector<AtomField>::const_iterator field = atom->fields.begin();
277          field != atom->fields.end(); field++) {
278         if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
279             for (const auto& chainField : attributionDecl.fields) {
280                 if (chainField.javaType == JAVA_TYPE_STRING) {
281                     fprintf(out, ", const std::vector<%s>& %s", cpp_type_name(chainField.javaType),
282                             chainField.name.c_str());
283                 } else {
284                     fprintf(out, ", const %s* %s, size_t %s_length",
285                             cpp_type_name(chainField.javaType), chainField.name.c_str(),
286                             chainField.name.c_str());
287                 }
288             }
289         } else {
290             fprintf(out, ", %s %s", cpp_type_name(field->javaType, isVendorAtomLogging),
291                     field->name.c_str());
292         }
293     }
294     fprintf(out, ");\n");
295 }
296 
write_native_atom_constants(FILE * out,const Atoms & atoms,const AtomDecl & attributionDecl,const string & methodName,bool isVendorAtomLogging)297 void write_native_atom_constants(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
298                                  const string& methodName, bool isVendorAtomLogging) {
299     fprintf(out, "/**\n");
300     fprintf(out, " * Constants for atom codes.\n");
301     fprintf(out, " */\n");
302     fprintf(out, "enum {\n");
303 
304     std::map<int, AtomDeclSet::const_iterator> atom_code_to_non_chained_decl_map;
305     build_non_chained_decl_map(atoms, &atom_code_to_non_chained_decl_map);
306 
307     size_t i = 0;
308     // Print atom constants
309     for (AtomDeclSet::const_iterator atomIt = atoms.decls.begin(); atomIt != atoms.decls.end();
310          atomIt++) {
311         string constant = make_constant_name((*atomIt)->name);
312         fprintf(out, "\n");
313         fprintf(out, "    /**\n");
314         fprintf(out, "     * %s %s\n", (*atomIt)->message.c_str(), (*atomIt)->name.c_str());
315         write_cpp_usage(out, methodName, constant, *atomIt, attributionDecl, isVendorAtomLogging);
316 
317         auto non_chained_decl = atom_code_to_non_chained_decl_map.find((*atomIt)->code);
318         if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) {
319             write_cpp_usage(out, methodName + "_non_chained", constant, *non_chained_decl->second,
320                             attributionDecl, isVendorAtomLogging);
321         }
322         fprintf(out, "     */\n");
323         char const* const comma = (i == atoms.decls.size() - 1) ? "" : ",";
324         fprintf(out, "    %s = %d%s\n", constant.c_str(), (*atomIt)->code, comma);
325         i++;
326     }
327     fprintf(out, "\n");
328     fprintf(out, "};\n");
329     fprintf(out, "\n");
330 }
331 
write_native_atom_enums(FILE * out,const Atoms & atoms)332 void write_native_atom_enums(FILE* out, const Atoms& atoms) {
333     // Print constants for the enum values.
334     fprintf(out, "//\n");
335     fprintf(out, "// Constants for enum values\n");
336     fprintf(out, "//\n\n");
337     for (AtomDeclSet::const_iterator atomIt = atoms.decls.begin(); atomIt != atoms.decls.end();
338          atomIt++) {
339         for (vector<AtomField>::const_iterator field = (*atomIt)->fields.begin();
340              field != (*atomIt)->fields.end(); field++) {
341             if (field->javaType == JAVA_TYPE_ENUM || field->javaType == JAVA_TYPE_ENUM_ARRAY) {
342                 fprintf(out, "// Values for %s.%s\n", (*atomIt)->message.c_str(),
343                         field->name.c_str());
344                 for (map<int, string>::const_iterator value = field->enumValues.begin();
345                      value != field->enumValues.end(); value++) {
346                     fprintf(out, "const int32_t %s__%s__%s = %d;\n",
347                             make_constant_name((*atomIt)->message).c_str(),
348                             make_constant_name(field->name).c_str(),
349                             make_constant_name(value->second).c_str(), value->first);
350                 }
351                 fprintf(out, "\n");
352             }
353         }
354     }
355 }
356 
write_native_method_signature(FILE * out,const string & signaturePrefix,const vector<java_type_t> & signature,const AtomDecl & attributionDecl,const string & closer,bool isVendorAtomLogging)357 void write_native_method_signature(FILE* out, const string& signaturePrefix,
358                                           const vector<java_type_t>& signature,
359                                           const AtomDecl& attributionDecl, const string& closer,
360                                           bool isVendorAtomLogging) {
361     fprintf(out, "%sint32_t code", signaturePrefix.c_str());
362     int argIndex = 1;
363     for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
364          arg++) {
365         if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
366             for (const auto& chainField : attributionDecl.fields) {
367                 if (chainField.javaType == JAVA_TYPE_STRING) {
368                     fprintf(out, ", const std::vector<%s>& %s",
369                             cpp_type_name(chainField.javaType, isVendorAtomLogging),
370                             chainField.name.c_str());
371                 } else {
372                     fprintf(out, ", const %s* %s, size_t %s_length",
373                             cpp_type_name(chainField.javaType, isVendorAtomLogging),
374                             chainField.name.c_str(), chainField.name.c_str());
375                 }
376             }
377         } else {
378             fprintf(out, ", %s arg%d", cpp_type_name(*arg, isVendorAtomLogging), argIndex);
379 
380             if (*arg == JAVA_TYPE_BOOLEAN_ARRAY && !isVendorAtomLogging) {
381                 fprintf(out, ", size_t arg%d_length", argIndex);
382             }
383         }
384         argIndex++;
385     }
386     fprintf(out, ")%s\n", closer.c_str());
387 }
388 
write_native_method_header(FILE * out,const string & methodName,const SignatureInfoMap & signatureInfoMap,const AtomDecl & attributionDecl,bool isVendorAtomLogging)389 void write_native_method_header(FILE* out, const string& methodName,
390                                        const SignatureInfoMap& signatureInfoMap,
391                                        const AtomDecl& attributionDecl,
392                                        bool isVendorAtomLogging) {
393     for (const auto& [signature, _] : signatureInfoMap) {
394         write_native_method_signature(out, methodName, signature, attributionDecl, ";",
395                                       isVendorAtomLogging);
396     }
397 }
398 
write_native_header_preamble(FILE * out,const string & cppNamespace,bool includePull,bool isVendorAtomLogging)399 void write_native_header_preamble(FILE* out, const string& cppNamespace, bool includePull,
400                                      bool isVendorAtomLogging) {
401     // Print prelude
402     fprintf(out, "// This file is autogenerated\n");
403     fprintf(out, "\n");
404     fprintf(out, "#pragma once\n");
405     fprintf(out, "\n");
406     fprintf(out, "#include <stdint.h>\n");
407     fprintf(out, "#include <vector>\n");
408     fprintf(out, "#include <map>\n");
409     fprintf(out, "#include <set>\n");
410     if (includePull) {
411         fprintf(out, "#include <stats_pull_atom_callback.h>\n");
412     }
413 
414     if (isVendorAtomLogging) {
415         fprintf(out, "#include <aidl/android/frameworks/stats/VendorAtom.h>\n");
416     }
417 
418     fprintf(out, "\n");
419 
420     write_namespace(out, cppNamespace);
421     fprintf(out, "\n");
422     fprintf(out, "/*\n");
423     fprintf(out, " * API For logging statistics events.\n");
424     fprintf(out, " */\n");
425     fprintf(out, "\n");
426 }
427 
write_native_header_epilogue(FILE * out,const string & cppNamespace)428 void write_native_header_epilogue(FILE* out, const string& cppNamespace) {
429     write_closing_namespace(out, cppNamespace);
430 }
431 
432 // Java
write_java_atom_codes(FILE * out,const Atoms & atoms)433 void write_java_atom_codes(FILE* out, const Atoms& atoms) {
434     fprintf(out, "    // Constants for atom codes.\n");
435 
436     std::map<int, AtomDeclSet::const_iterator> atom_code_to_non_chained_decl_map;
437     build_non_chained_decl_map(atoms, &atom_code_to_non_chained_decl_map);
438 
439     // Print constants for the atom codes.
440     for (AtomDeclSet::const_iterator atomIt = atoms.decls.begin(); atomIt != atoms.decls.end();
441          atomIt++) {
442         string constant = make_constant_name((*atomIt)->name);
443         fprintf(out, "\n");
444         fprintf(out, "    /**\n");
445         fprintf(out, "     * %s %s<br>\n", (*atomIt)->message.c_str(), (*atomIt)->name.c_str());
446         write_java_usage(out, "write", constant, **atomIt);
447         auto non_chained_decl = atom_code_to_non_chained_decl_map.find((*atomIt)->code);
448         if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) {
449             write_java_usage(out, "write_non_chained", constant, **(non_chained_decl->second));
450         }
451         fprintf(out, "     */\n");
452         fprintf(out, "    public static final int %s = %d;\n", constant.c_str(), (*atomIt)->code);
453     }
454     fprintf(out, "\n");
455 }
456 
write_java_enum_values(FILE * out,const Atoms & atoms)457 void write_java_enum_values(FILE* out, const Atoms& atoms) {
458     fprintf(out, "    // Constants for enum values.\n\n");
459     for (AtomDeclSet::const_iterator atomIt = atoms.decls.begin(); atomIt != atoms.decls.end();
460          atomIt++) {
461         for (vector<AtomField>::const_iterator field = (*atomIt)->fields.begin();
462              field != (*atomIt)->fields.end(); field++) {
463             if (field->javaType == JAVA_TYPE_ENUM || field->javaType == JAVA_TYPE_ENUM_ARRAY) {
464                 fprintf(out, "    // Values for %s.%s\n", (*atomIt)->message.c_str(),
465                         field->name.c_str());
466                 for (map<int, string>::const_iterator value = field->enumValues.begin();
467                      value != field->enumValues.end(); value++) {
468                     fprintf(out, "    public static final int %s__%s__%s = %d;\n",
469                             make_constant_name((*atomIt)->message).c_str(),
470                             make_constant_name(field->name).c_str(),
471                             make_constant_name(value->second).c_str(), value->first);
472                 }
473                 fprintf(out, "\n");
474             }
475         }
476     }
477 }
478 
write_java_enum_values_vendor(FILE * out,const Atoms & atoms)479 void write_java_enum_values_vendor(FILE* out, const Atoms& atoms) {
480     set<string> processedEnums;
481 
482     fprintf(out, "    // Constants for enum values.\n\n");
483     for (AtomDeclSet::const_iterator atomIt = atoms.decls.begin(); atomIt != atoms.decls.end();
484          atomIt++) {
485         for (vector<AtomField>::const_iterator field = (*atomIt)->fields.begin();
486              field != (*atomIt)->fields.end(); field++) {
487             if (field->javaType == JAVA_TYPE_ENUM || field->javaType == JAVA_TYPE_ENUM_ARRAY) {
488                 // there might be N fields with the same enum type
489                 // avoid duplication definitions
490                 // enum type name == [atom_message_type_name]__[enum_type_name]
491                 const string full_enum_type_name = (*atomIt)->message + "__" + field->enumTypeName;
492 
493                 if (processedEnums.find(full_enum_type_name) != processedEnums.end()) {
494                     continue;
495                 }
496                 processedEnums.insert(full_enum_type_name);
497 
498                 fprintf(out, "    // Values for %s.%s\n", (*atomIt)->message.c_str(),
499                         field->name.c_str());
500                 for (map<int, string>::const_iterator value = field->enumValues.begin();
501                      value != field->enumValues.end(); value++) {
502                     fprintf(out, "    public static final int %s__%s = %d;\n",
503                             make_constant_name(full_enum_type_name).c_str(),
504                             make_constant_name(value->second).c_str(), value->first);
505                 }
506                 fprintf(out, "\n");
507             }
508         }
509     }
510 }
511 
write_java_usage(FILE * out,const string & method_name,const string & atom_code_name,const AtomDecl & atom)512 void write_java_usage(FILE* out, const string& method_name, const string& atom_code_name,
513                       const AtomDecl& atom) {
514     fprintf(out, "     * Usage: StatsLog.%s(StatsLog.%s", method_name.c_str(),
515             atom_code_name.c_str());
516     for (vector<AtomField>::const_iterator field = atom.fields.begin(); field != atom.fields.end();
517          field++) {
518         if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
519             fprintf(out, ", android.os.WorkSource workSource");
520         } else if (field->javaType == JAVA_TYPE_BYTE_ARRAY) {
521             fprintf(out, ", byte[] %s", field->name.c_str());
522         } else {
523             fprintf(out, ", %s %s", java_type_name(field->javaType), field->name.c_str());
524         }
525     }
526     fprintf(out, ");<br>\n");
527 }
528 
write_java_non_chained_methods(FILE * out,const SignatureInfoMap & signatureInfoMap)529 int write_java_non_chained_methods(FILE* out, const SignatureInfoMap& signatureInfoMap) {
530     for (auto signatureInfoMapIt = signatureInfoMap.begin();
531          signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
532         // Print method signature.
533         fprintf(out, "    public static void write_non_chained(int code");
534         vector<java_type_t> signature = signatureInfoMapIt->first;
535         int argIndex = 1;
536         for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
537              arg++) {
538             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
539                 fprintf(stderr, "Non chained signatures should not have attribution chains.\n");
540                 return 1;
541             } else {
542                 fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
543             }
544             argIndex++;
545         }
546         fprintf(out, ") {\n");
547 
548         fprintf(out, "        write(code");
549         argIndex = 1;
550         for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
551              arg++) {
552             // First two args are uid and tag of attribution chain.
553             if (argIndex == 1) {
554                 fprintf(out, ", new int[] {arg%d}", argIndex);
555             } else if (argIndex == 2) {
556                 fprintf(out, ", new java.lang.String[] {arg%d}", argIndex);
557             } else {
558                 fprintf(out, ", arg%d", argIndex);
559             }
560             argIndex++;
561         }
562         fprintf(out, ");\n");
563         fprintf(out, "    }\n");
564         fprintf(out, "\n");
565     }
566     return 0;
567 }
568 
write_java_work_source_methods(FILE * out,const SignatureInfoMap & signatureInfoMap)569 int write_java_work_source_methods(FILE* out, const SignatureInfoMap& signatureInfoMap) {
570     fprintf(out, "    // WorkSource methods.\n");
571     for (auto signatureInfoMapIt = signatureInfoMap.begin();
572          signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
573         vector<java_type_t> signature = signatureInfoMapIt->first;
574         // Determine if there is Attribution in this signature.
575         int attributionArg = -1;
576         int argIndexMax = 0;
577         for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
578              arg++) {
579             argIndexMax++;
580             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
581                 if (attributionArg > -1) {
582                     fprintf(stderr, "An atom contains multiple AttributionNode fields.\n");
583                     fprintf(stderr, "This is not supported. Aborting WorkSource method writing.\n");
584                     fprintf(out,
585                             "\n// Invalid for WorkSource: more than one attribution "
586                             "chain.\n");
587                     return 1;
588                 }
589                 attributionArg = argIndexMax;
590             }
591         }
592         if (attributionArg < 0) {
593             continue;
594         }
595 
596         fprintf(out, "\n");
597         // Method header (signature)
598         fprintf(out, "    public static void write(int code");
599         int argIndex = 1;
600         for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
601              arg++) {
602             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
603                 fprintf(out, ", android.os.WorkSource ws");
604             } else {
605                 fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
606             }
607             argIndex++;
608         }
609         fprintf(out, ") {\n");
610 
611         // write_non_chained() component. TODO: Remove when flat uids are no longer
612         // needed.
613         fprintf(out, "        for (int i = 0; i < ws.size(); ++i) {\n");
614         fprintf(out, "            write_non_chained(code");
615         for (int argIndex = 1; argIndex <= argIndexMax; argIndex++) {
616             if (argIndex == attributionArg) {
617                 fprintf(out, ", ws.getUid(i), ws.getPackageName(i)");
618             } else {
619                 fprintf(out, ", arg%d", argIndex);
620             }
621         }
622         fprintf(out, ");\n");
623         fprintf(out, "        }\n");  // close for-loop
624 
625         // write() component.
626         fprintf(out,
627                 "        java.util.List<android.os.WorkSource.WorkChain> workChains = "
628                 "ws.getWorkChains();\n");
629         fprintf(out, "        if (workChains != null) {\n");
630         fprintf(out,
631                 "            for (android.os.WorkSource.WorkChain wc : workChains) "
632                 "{\n");
633         fprintf(out, "                write(code");
634         for (int argIndex = 1; argIndex <= argIndexMax; argIndex++) {
635             if (argIndex == attributionArg) {
636                 fprintf(out, ", wc.getUids(), wc.getTags()");
637             } else {
638                 fprintf(out, ", arg%d", argIndex);
639             }
640         }
641         fprintf(out, ");\n");
642         fprintf(out, "            }\n");  // close for-loop
643         fprintf(out, "        }\n");      // close if
644         fprintf(out, "    }\n");          // close method
645     }
646     return 0;
647 }
648 
contains_restricted(const AtomDeclSet & atomDeclSet)649 bool contains_restricted(const AtomDeclSet& atomDeclSet) {
650     for (const auto& decl : atomDeclSet) {
651         if (decl->restricted) {
652             return true;
653         }
654     }
655     return false;
656 }
657 
requires_api_needed(const AtomDeclSet & atomDeclSet)658 bool requires_api_needed(const AtomDeclSet& atomDeclSet) {
659     return contains_restricted(atomDeclSet);
660 }
661 
get_min_api_level(const AtomDeclSet & atomDeclSet)662 int get_min_api_level(const AtomDeclSet& atomDeclSet) {
663     if (requires_api_needed(atomDeclSet)) {
664         if (contains_restricted(atomDeclSet)) {
665             return API_U;
666         }
667     }
668     return API_LEVEL_CURRENT;
669 }
670 
671 }  // namespace stats_log_api_gen
672 }  // namespace android
673