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 "java_writer.h"
18 #include "java_writer_q.h"
19 #include "utils.h"
20
21 namespace android {
22 namespace stats_log_api_gen {
23
write_java_q_logger_class(FILE * out,const map<vector<java_type_t>,set<string>> & signatures_to_modules,const AtomDecl & attributionDecl,const string & moduleName)24 static int write_java_q_logger_class(
25 FILE* out,
26 const map<vector<java_type_t>, set<string>>& signatures_to_modules,
27 const AtomDecl &attributionDecl,
28 const string& moduleName
29 ) {
30 fprintf(out, "\n");
31 fprintf(out, " // Write logging helper methods for statsd in Q and earlier.\n");
32 fprintf(out, " private static class QLogger {\n");
33
34 write_java_q_logging_constants(out, " ");
35
36 // Print Q write methods.
37 fprintf(out, "\n");
38 fprintf(out, " // Write methods.\n");
39 write_java_methods_q_schema(
40 out, signatures_to_modules, attributionDecl, moduleName, " ");
41
42 fprintf(out, " }\n");
43 return 0;
44 }
45
46
write_java_methods(FILE * out,const map<vector<java_type_t>,set<string>> & signatures_to_modules,const AtomDecl & attributionDecl,const string & moduleName,const bool supportQ)47 static int write_java_methods(
48 FILE* out,
49 const map<vector<java_type_t>, set<string>>& signatures_to_modules,
50 const AtomDecl &attributionDecl,
51 const string& moduleName,
52 const bool supportQ
53 ) {
54 for (auto signature_to_modules_it = signatures_to_modules.begin();
55 signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
56 // Skip if this signature is not needed for the module.
57 if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) {
58 continue;
59 }
60
61 // Print method signature.
62 if (DEFAULT_MODULE_NAME == moduleName) {
63 fprintf(out, " /** @hide */\n");
64 }
65 fprintf(out, " public static void write(int code");
66 vector<java_type_t> signature = signature_to_modules_it->first;
67 int argIndex = 1;
68 for (vector<java_type_t>::const_iterator arg = signature.begin();
69 arg != signature.end(); arg++) {
70 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
71 for (auto chainField : attributionDecl.fields) {
72 fprintf(out, ", %s[] %s",
73 java_type_name(chainField.javaType), chainField.name.c_str());
74 }
75 } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
76 fprintf(out, ", android.util.SparseArray<Object> valueMap");
77 } else {
78 fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
79 }
80 argIndex++;
81 }
82 fprintf(out, ") {\n");
83
84 // Print method body.
85 string indent("");
86 if (supportQ) {
87 // TODO(b/146235828): Use just SDK_INT check once it is incremented from Q.
88 fprintf(out, " if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q\n");
89 fprintf(out, " || (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q\n");
90 fprintf(out, " && Build.VERSION.PREVIEW_SDK_INT > 0)) {\n");
91 indent = " ";
92 }
93
94 // Start StatsEvent.Builder.
95 fprintf(out, "%s final StatsEvent.Builder builder = StatsEvent.newBuilder();\n",
96 indent.c_str());
97
98 // Write atom code.
99 fprintf(out, "%s builder.setAtomId(code);\n", indent.c_str());
100
101 // Write the args.
102 argIndex = 1;
103 for (vector<java_type_t>::const_iterator arg = signature.begin();
104 arg != signature.end(); arg++) {
105 switch (*arg) {
106 case JAVA_TYPE_BOOLEAN:
107 fprintf(out, "%s builder.writeBoolean(arg%d);\n", indent.c_str(), argIndex);
108 break;
109 case JAVA_TYPE_INT:
110 case JAVA_TYPE_ENUM:
111 fprintf(out, "%s builder.writeInt(arg%d);\n", indent.c_str(), argIndex);
112 break;
113 case JAVA_TYPE_FLOAT:
114 fprintf(out, "%s builder.writeFloat(arg%d);\n", indent.c_str(), argIndex);
115 break;
116 case JAVA_TYPE_LONG:
117 fprintf(out, "%s builder.writeLong(arg%d);\n", indent.c_str(), argIndex);
118 break;
119 case JAVA_TYPE_STRING:
120 fprintf(out, "%s builder.writeString(arg%d);\n", indent.c_str(), argIndex);
121 break;
122 case JAVA_TYPE_BYTE_ARRAY:
123 fprintf(out, "%s builder.writeByteArray(null == arg%d ? new byte[0] : arg%d);\n",
124 indent.c_str(), argIndex, argIndex);
125 break;
126 case JAVA_TYPE_ATTRIBUTION_CHAIN:
127 {
128 const char* uidName = attributionDecl.fields.front().name.c_str();
129 const char* tagName = attributionDecl.fields.back().name.c_str();
130
131 fprintf(out, "%s builder.writeAttributionChain(\n", indent.c_str());
132 fprintf(out, "%s null == %s ? new int[0] : %s,\n",
133 indent.c_str(), uidName, uidName);
134 fprintf(out, "%s null == %s ? new String[0] : %s);\n",
135 indent.c_str(), tagName, tagName);
136 break;
137 }
138 case JAVA_TYPE_KEY_VALUE_PAIR:
139 fprintf(out, "\n");
140 fprintf(out,
141 "%s // Write KeyValuePairs.\n", indent.c_str());
142 fprintf(out,
143 "%s final int count = valueMap.size();\n", indent.c_str());
144 fprintf(out,
145 "%s android.util.SparseIntArray intMap = null;\n",
146 indent.c_str());
147 fprintf(out,
148 "%s android.util.SparseLongArray longMap = null;\n",
149 indent.c_str());
150 fprintf(out,
151 "%s android.util.SparseArray<String> stringMap = null;\n",
152 indent.c_str());
153 fprintf(out,
154 "%s android.util.SparseArray<Float> floatMap = null;\n",
155 indent.c_str());
156 fprintf(out,
157 "%s for (int i = 0; i < count; i++) {\n", indent.c_str());
158 fprintf(out,
159 "%s final int key = valueMap.keyAt(i);\n", indent.c_str());
160 fprintf(out,
161 "%s final Object value = valueMap.valueAt(i);\n",
162 indent.c_str());
163 fprintf(out,
164 "%s if (value instanceof Integer) {\n", indent.c_str());
165 fprintf(out,
166 "%s if (null == intMap) {\n", indent.c_str());
167 fprintf(out,
168 "%s intMap = new android.util.SparseIntArray();\n", indent.c_str());
169 fprintf(out,
170 "%s }\n", indent.c_str());
171 fprintf(out,
172 "%s intMap.put(key, (Integer) value);\n", indent.c_str());
173 fprintf(out,
174 "%s } else if (value instanceof Long) {\n", indent.c_str());
175 fprintf(out,
176 "%s if (null == longMap) {\n", indent.c_str());
177 fprintf(out,
178 "%s longMap = new android.util.SparseLongArray();\n", indent.c_str());
179 fprintf(out,
180 "%s }\n", indent.c_str());
181 fprintf(out,
182 "%s longMap.put(key, (Long) value);\n", indent.c_str());
183 fprintf(out,
184 "%s } else if (value instanceof String) {\n", indent.c_str());
185 fprintf(out,
186 "%s if (null == stringMap) {\n", indent.c_str());
187 fprintf(out,
188 "%s stringMap = new android.util.SparseArray<>();\n", indent.c_str());
189 fprintf(out,
190 "%s }\n", indent.c_str());
191 fprintf(out,
192 "%s stringMap.put(key, (String) value);\n", indent.c_str());
193 fprintf(out,
194 "%s } else if (value instanceof Float) {\n", indent.c_str());
195 fprintf(out,
196 "%s if (null == floatMap) {\n", indent.c_str());
197 fprintf(out,
198 "%s floatMap = new android.util.SparseArray<>();\n", indent.c_str());
199 fprintf(out,
200 "%s }\n", indent.c_str());
201 fprintf(out,
202 "%s floatMap.put(key, (Float) value);\n", indent.c_str());
203 fprintf(out,
204 "%s }\n", indent.c_str());
205 fprintf(out,
206 "%s }\n", indent.c_str());
207 fprintf(out,
208 "%s builder.writeKeyValuePairs("
209 "intMap, longMap, stringMap, floatMap);\n", indent.c_str());
210 break;
211 default:
212 // Unsupported types: OBJECT, DOUBLE.
213 fprintf(stderr, "Encountered unsupported type.");
214 return 1;
215 }
216 argIndex++;
217 }
218
219 fprintf(out, "\n");
220 fprintf(out, "%s builder.usePooledBuffer();\n", indent.c_str());
221 fprintf(out, "%s StatsLog.write(builder.build());\n", indent.c_str());
222
223 // Add support for writing using Q schema if this is not the default module.
224 if (supportQ) {
225 fprintf(out, " } else {\n");
226 fprintf(out, " QLogger.write(code");
227 argIndex = 1;
228 for (vector<java_type_t>::const_iterator arg = signature.begin();
229 arg != signature.end(); arg++) {
230 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
231 const char* uidName = attributionDecl.fields.front().name.c_str();
232 const char* tagName = attributionDecl.fields.back().name.c_str();
233 fprintf(out, ", %s, %s", uidName, tagName);
234 } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
235 // Module logging does not yet support key value pair.
236 fprintf(stderr, "Module logging does not yet support key value pair.\n");
237 return 1;
238 } else {
239 fprintf(out, ", arg%d", argIndex);
240 }
241 argIndex++;
242 }
243 fprintf(out, ");\n");
244 fprintf(out, " }\n"); // if
245 }
246
247 fprintf(out, " }\n"); // method
248 fprintf(out, "\n");
249 }
250 return 0;
251
252 }
253
write_stats_log_java(FILE * out,const Atoms & atoms,const AtomDecl & attributionDecl,const string & moduleName,const string & javaClass,const string & javaPackage,const bool supportQ,const bool supportWorkSource)254 int write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl,
255 const string& moduleName, const string& javaClass,
256 const string& javaPackage, const bool supportQ,
257 const bool supportWorkSource) {
258 // Print prelude
259 fprintf(out, "// This file is autogenerated\n");
260 fprintf(out, "\n");
261 fprintf(out, "package %s;\n", javaPackage.c_str());
262 fprintf(out, "\n");
263 fprintf(out, "\n");
264 if (supportQ) {
265 fprintf(out, "import android.os.Build;\n");
266 fprintf(out, "import android.os.SystemClock;\n");
267 }
268
269 fprintf(out, "import android.util.StatsEvent;\n");
270 fprintf(out, "import android.util.StatsLog;\n");
271
272 fprintf(out, "\n");
273 fprintf(out, "\n");
274 fprintf(out, "/**\n");
275 fprintf(out, " * Utility class for logging statistics events.\n");
276 if (DEFAULT_MODULE_NAME == moduleName) {
277 fprintf(out, " * @hide\n");
278 }
279 fprintf(out, " */\n");
280 fprintf(out, "public class %s {\n", javaClass.c_str());
281
282 write_java_atom_codes(out, atoms, moduleName);
283 write_java_enum_values(out, atoms, moduleName);
284
285 int errors = 0;
286
287 // Print write methods.
288 fprintf(out, " // Write methods\n");
289 errors += write_java_methods(
290 out, atoms.signatures_to_modules, attributionDecl, moduleName, supportQ);
291 errors += write_java_non_chained_methods(
292 out, atoms.non_chained_signatures_to_modules, moduleName);
293 if (supportWorkSource) {
294 errors += write_java_work_source_methods(out, atoms.signatures_to_modules, moduleName);
295 }
296
297 if (supportQ) {
298 errors += write_java_q_logger_class(
299 out, atoms.signatures_to_modules, attributionDecl, moduleName);
300 }
301
302 fprintf(out, "}\n");
303
304 return errors;
305 }
306
307 } // namespace stats_log_api_gen
308 } // namespace android
309