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