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
is_primitive_field(java_type_t type)250 bool is_primitive_field(java_type_t type) {
251 switch (type) {
252 case JAVA_TYPE_BOOLEAN:
253 case JAVA_TYPE_INT:
254 case JAVA_TYPE_LONG:
255 case JAVA_TYPE_FLOAT:
256 case JAVA_TYPE_STRING:
257 case JAVA_TYPE_ENUM:
258 return true;
259 default:
260 return false;
261 }
262 }
263
264 // Native
265 // Writes namespaces for the cpp and header files
write_namespace(FILE * out,const string & cppNamespaces)266 void write_namespace(FILE* out, const string& cppNamespaces) {
267 const vector<string> cppNamespaceVec = Split(cppNamespaces, ",");
268 for (const string& cppNamespace : cppNamespaceVec) {
269 fprintf(out, "namespace %s {\n", cppNamespace.c_str());
270 }
271 }
272
273 // Writes namespace closing brackets for cpp and header files.
write_closing_namespace(FILE * out,const string & cppNamespaces)274 void write_closing_namespace(FILE* out, const string& cppNamespaces) {
275 vector<string> cppNamespaceVec = Split(cppNamespaces, ",");
276 for (auto it = cppNamespaceVec.rbegin(); it != cppNamespaceVec.rend(); ++it) {
277 fprintf(out, "} // namespace %s\n", it->c_str());
278 }
279 }
280
write_cpp_usage(FILE * out,const string & method_name,const string & atom_code_name,const AtomDecl & atom,const AtomDecl & attributionDecl,bool isVendorAtomLogging=false)281 static void write_cpp_usage(FILE* out, const string& method_name, const string& atom_code_name,
282 const AtomDecl& atom, const AtomDecl& attributionDecl,
283 bool isVendorAtomLogging = false) {
284 const char* delimiterStr = method_name.find('(') == string::npos ? "(" : " ";
285 fprintf(out, " * Usage: %s%s%s", method_name.c_str(), delimiterStr, atom_code_name.c_str());
286
287 for (vector<AtomField>::const_iterator field = atom.fields.begin(); field != atom.fields.end();
288 field++) {
289 if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
290 for (const auto& chainField : attributionDecl.fields) {
291 if (chainField.javaType == JAVA_TYPE_STRING) {
292 fprintf(out, ", const std::vector<%s>& %s", cpp_type_name(chainField.javaType),
293 chainField.name.c_str());
294 } else {
295 fprintf(out, ", const %s* %s, size_t %s_length",
296 cpp_type_name(chainField.javaType), chainField.name.c_str(),
297 chainField.name.c_str());
298 }
299 }
300 } else {
301 fprintf(out, ", %s %s", cpp_type_name(field->javaType, isVendorAtomLogging),
302 field->name.c_str());
303 }
304 }
305 fprintf(out, ");\n");
306 }
307
write_native_atom_constants(FILE * out,const Atoms & atoms,const AtomDecl & attributionDecl,const string & methodName,bool isVendorAtomLogging)308 void write_native_atom_constants(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
309 const string& methodName, bool isVendorAtomLogging) {
310 fprintf(out, "/**\n");
311 fprintf(out, " * Constants for atom codes.\n");
312 fprintf(out, " */\n");
313 fprintf(out, "enum {\n");
314
315 std::map<int, AtomDeclSet::const_iterator> atom_code_to_non_chained_decl_map;
316 build_non_chained_decl_map(atoms, &atom_code_to_non_chained_decl_map);
317
318 size_t i = 0;
319 // Print atom constants
320 for (AtomDeclSet::const_iterator atomIt = atoms.decls.begin(); atomIt != atoms.decls.end();
321 atomIt++) {
322 const string constant = make_constant_name((*atomIt)->name);
323 fprintf(out, "\n");
324 fprintf(out, " /**\n");
325 fprintf(out, " * %s %s\n", (*atomIt)->message.c_str(), (*atomIt)->name.c_str());
326 write_cpp_usage(out, methodName, constant, **atomIt, attributionDecl, isVendorAtomLogging);
327
328 auto non_chained_decl = atom_code_to_non_chained_decl_map.find((*atomIt)->code);
329 if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) {
330 write_cpp_usage(out, methodName + "_non_chained", constant, **non_chained_decl->second,
331 attributionDecl, isVendorAtomLogging);
332 }
333 fprintf(out, " */\n");
334 char const* const comma = (i == atoms.decls.size() - 1) ? "" : ",";
335 fprintf(out, " %s = %d%s\n", constant.c_str(), (*atomIt)->code, comma);
336 i++;
337 }
338 fprintf(out, "\n");
339 fprintf(out, "};\n");
340 fprintf(out, "\n");
341 }
342
write_native_atom_enums(FILE * out,const Atoms & atoms)343 void write_native_atom_enums(FILE* out, const Atoms& atoms) {
344 // Print constants for the enum values.
345 fprintf(out, "//\n");
346 fprintf(out, "// Constants for enum values\n");
347 fprintf(out, "//\n\n");
348 for (AtomDeclSet::const_iterator atomIt = atoms.decls.begin(); atomIt != atoms.decls.end();
349 atomIt++) {
350 for (vector<AtomField>::const_iterator field = (*atomIt)->fields.begin();
351 field != (*atomIt)->fields.end(); field++) {
352 if (field->javaType == JAVA_TYPE_ENUM || field->javaType == JAVA_TYPE_ENUM_ARRAY) {
353 fprintf(out, "// Values for %s.%s\n", (*atomIt)->message.c_str(),
354 field->name.c_str());
355 for (map<int, string>::const_iterator value = field->enumValues.begin();
356 value != field->enumValues.end(); value++) {
357 fprintf(out, "const int32_t %s__%s__%s = %d;\n",
358 make_constant_name((*atomIt)->message).c_str(),
359 make_constant_name(field->name).c_str(),
360 make_constant_name(value->second).c_str(), value->first);
361 }
362 fprintf(out, "\n");
363 }
364 }
365 }
366 }
367
write_native_method_signature(FILE * out,const string & signaturePrefix,const vector<java_type_t> & signature,const AtomDecl & attributionDecl,const string & closer,bool isVendorAtomLogging)368 void write_native_method_signature(FILE* out, const string& signaturePrefix,
369 const vector<java_type_t>& signature,
370 const AtomDecl& attributionDecl, const string& closer,
371 bool isVendorAtomLogging) {
372 fprintf(out, "%sint32_t code", signaturePrefix.c_str());
373 int argIndex = 1;
374 for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
375 arg++) {
376 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
377 for (const auto& chainField : attributionDecl.fields) {
378 if (chainField.javaType == JAVA_TYPE_STRING) {
379 fprintf(out, ", const std::vector<%s>& %s",
380 cpp_type_name(chainField.javaType, isVendorAtomLogging),
381 chainField.name.c_str());
382 } else {
383 fprintf(out, ", const %s* %s, size_t %s_length",
384 cpp_type_name(chainField.javaType, isVendorAtomLogging),
385 chainField.name.c_str(), chainField.name.c_str());
386 }
387 }
388 } else {
389 fprintf(out, ", %s arg%d", cpp_type_name(*arg, isVendorAtomLogging), argIndex);
390
391 if (*arg == JAVA_TYPE_BOOLEAN_ARRAY && !isVendorAtomLogging) {
392 fprintf(out, ", size_t arg%d_length", argIndex);
393 }
394 }
395 argIndex++;
396 }
397 fprintf(out, ")%s\n", closer.c_str());
398 }
399
write_native_method_header(FILE * out,const string & methodName,const SignatureInfoMap & signatureInfoMap,const AtomDecl & attributionDecl,bool isVendorAtomLogging)400 void write_native_method_header(FILE* out, const string& methodName,
401 const SignatureInfoMap& signatureInfoMap,
402 const AtomDecl& attributionDecl,
403 bool isVendorAtomLogging) {
404 for (const auto& [signature, _] : signatureInfoMap) {
405 write_native_method_signature(out, methodName, signature, attributionDecl, ";",
406 isVendorAtomLogging);
407 }
408 }
409
write_native_header_preamble(FILE * out,const string & cppNamespace,bool includePull,bool isVendorAtomLogging)410 void write_native_header_preamble(FILE* out, const string& cppNamespace, bool includePull,
411 bool isVendorAtomLogging) {
412 // Print prelude
413 fprintf(out, "// This file is autogenerated\n");
414 fprintf(out, "\n");
415 fprintf(out, "#pragma once\n");
416 fprintf(out, "\n");
417 fprintf(out, "#include <stdint.h>\n");
418 fprintf(out, "#include <vector>\n");
419 fprintf(out, "#include <map>\n");
420 fprintf(out, "#include <set>\n");
421 if (includePull) {
422 fprintf(out, "#include <stats_pull_atom_callback.h>\n");
423 }
424
425 if (isVendorAtomLogging) {
426 fprintf(out, "#include <aidl/android/frameworks/stats/VendorAtom.h>\n");
427 }
428
429 fprintf(out, "\n");
430
431 write_namespace(out, cppNamespace);
432 fprintf(out, "\n");
433 fprintf(out, "/*\n");
434 fprintf(out, " * API For logging statistics events.\n");
435 fprintf(out, " */\n");
436 fprintf(out, "\n");
437 }
438
write_native_header_epilogue(FILE * out,const string & cppNamespace)439 void write_native_header_epilogue(FILE* out, const string& cppNamespace) {
440 write_closing_namespace(out, cppNamespace);
441 }
442
443 // Java
write_java_atom_codes(FILE * out,const Atoms & atoms)444 void write_java_atom_codes(FILE* out, const Atoms& atoms) {
445 fprintf(out, " // Constants for atom codes.\n");
446
447 std::map<int, AtomDeclSet::const_iterator> atom_code_to_non_chained_decl_map;
448 build_non_chained_decl_map(atoms, &atom_code_to_non_chained_decl_map);
449
450 // Print constants for the atom codes.
451 for (AtomDeclSet::const_iterator atomIt = atoms.decls.begin(); atomIt != atoms.decls.end();
452 atomIt++) {
453 const string constant = make_constant_name((*atomIt)->name);
454 fprintf(out, "\n");
455 fprintf(out, " /**\n");
456 fprintf(out, " * %s %s<br>\n", (*atomIt)->message.c_str(), (*atomIt)->name.c_str());
457 write_java_usage(out, "write", constant, **atomIt);
458 auto non_chained_decl = atom_code_to_non_chained_decl_map.find((*atomIt)->code);
459 if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) {
460 write_java_usage(out, "write_non_chained", constant, **(non_chained_decl->second));
461 }
462 fprintf(out, " */\n");
463 fprintf(out, " public static final int %s = %d;\n", constant.c_str(), (*atomIt)->code);
464 }
465 fprintf(out, "\n");
466 }
467
write_java_enum_values(FILE * out,const Atoms & atoms)468 void write_java_enum_values(FILE* out, const Atoms& atoms) {
469 fprintf(out, " // Constants for enum values.\n\n");
470 for (AtomDeclSet::const_iterator atomIt = atoms.decls.begin(); atomIt != atoms.decls.end();
471 atomIt++) {
472 for (vector<AtomField>::const_iterator field = (*atomIt)->fields.begin();
473 field != (*atomIt)->fields.end(); field++) {
474 if (field->javaType == JAVA_TYPE_ENUM || field->javaType == JAVA_TYPE_ENUM_ARRAY) {
475 fprintf(out, " // Values for %s.%s\n", (*atomIt)->message.c_str(),
476 field->name.c_str());
477 for (map<int, string>::const_iterator value = field->enumValues.begin();
478 value != field->enumValues.end(); value++) {
479 fprintf(out, " public static final int %s__%s__%s = %d;\n",
480 make_constant_name((*atomIt)->message).c_str(),
481 make_constant_name(field->name).c_str(),
482 make_constant_name(value->second).c_str(), value->first);
483 }
484 fprintf(out, "\n");
485 }
486 }
487 }
488 }
489
write_java_method_signature(FILE * out,const vector<java_type_t> & signature,const AtomDecl & attributionDecl)490 int write_java_method_signature(FILE* out, const vector<java_type_t>& signature,
491 const AtomDecl& attributionDecl) {
492 int argIndex = 1;
493 for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
494 arg++) {
495 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
496 if (attributionDecl.fields.empty()) {
497 fprintf(stderr, "Encountered incompatible attribution chain atom definition");
498 return 1;
499 }
500 for (const auto& chainField : attributionDecl.fields) {
501 fprintf(out, ", %s[] %s", java_type_name(chainField.javaType),
502 chainField.name.c_str());
503 }
504 } else {
505 fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
506 }
507 argIndex++;
508 }
509 return 0;
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 static 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
contains_repeated_field(const vector<java_type_t> & signature)658 static bool contains_repeated_field(const vector<java_type_t>& signature) {
659 for (const java_type_t& javaType : signature) {
660 switch (javaType) {
661 case JAVA_TYPE_BOOLEAN_ARRAY:
662 case JAVA_TYPE_INT_ARRAY:
663 case JAVA_TYPE_FLOAT_ARRAY:
664 case JAVA_TYPE_LONG_ARRAY:
665 case JAVA_TYPE_STRING_ARRAY:
666 return true;
667 default:
668 break;
669 }
670 }
671 return false;
672 }
673
get_max_requires_api_level(int minApiLevel,const AtomDeclSet * atomDeclSet,const vector<java_type_t> & signature)674 int get_max_requires_api_level(int minApiLevel, const AtomDeclSet* atomDeclSet,
675 const vector<java_type_t>& signature) {
676 if (atomDeclSet != nullptr && contains_restricted(*atomDeclSet)) {
677 return API_U;
678 }
679 if (contains_repeated_field(signature)) {
680 return API_T;
681 }
682 if (minApiLevel <= API_Q) {
683 return API_Q; // for StatsLog.writeRaw()
684 }
685 return 0;
686 }
687
get_annotations(int argIndex,const FieldNumberToAtomDeclSet & fieldNumberToAtomDeclSet)688 AtomDeclSet get_annotations(int argIndex,
689 const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet) {
690 const FieldNumberToAtomDeclSet::const_iterator fieldNumberToAtomDeclSetIt =
691 fieldNumberToAtomDeclSet.find(argIndex);
692 if (fieldNumberToAtomDeclSet.end() == fieldNumberToAtomDeclSetIt) {
693 return AtomDeclSet();
694 }
695 return fieldNumberToAtomDeclSetIt->second;
696 }
697
698 } // namespace stats_log_api_gen
699 } // namespace android
700