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