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 "native_writer_q.h"
18 #include "utils.h"
19
20 namespace android {
21 namespace stats_log_api_gen {
22
write_native_stats_write_body_q(FILE * out,const vector<java_type_t> & signature,const AtomDecl & attributionDecl,const string & indent,const string & tryMethodName)23 static void write_native_stats_write_body_q(FILE* out, const vector<java_type_t>& signature,
24 const AtomDecl& attributionDecl, const string& indent, const string& tryMethodName) {
25 fprintf(out, "%sint ret = 0;\n", indent.c_str());
26
27 fprintf(out, "%sfor(int retry = 0; retry < 2; ++retry) {\n", indent.c_str());
28 fprintf(out, "%s ret = ", indent.c_str());
29 write_native_method_call(out, tryMethodName, signature, attributionDecl);
30 fprintf(out, "%s if (ret >= 0) { break; }\n", indent.c_str());
31
32 fprintf(out, "%s {\n", indent.c_str());
33 fprintf(out, "%s std::lock_guard<std::mutex> lock(mLogdRetryMutex);\n", indent.c_str());
34 fprintf(out, "%s if ((get_elapsed_realtime_ns() - lastRetryTimestampNs) <= "
35 "kMinRetryIntervalNs) break;\n", indent.c_str());
36 fprintf(out, "%s lastRetryTimestampNs = get_elapsed_realtime_ns();\n",
37 indent.c_str());
38 fprintf(out, "%s }\n", indent.c_str());
39 fprintf(out, "%s std::this_thread::sleep_for(std::chrono::milliseconds(10));\n",
40 indent.c_str());
41 fprintf(out, "%s}\n", indent.c_str());
42 fprintf(out, "%sif (ret < 0) {\n", indent.c_str());
43 fprintf(out, "%s note_log_drop(ret, code);\n", indent.c_str());
44 fprintf(out, "%s}\n", indent.c_str());
45 fprintf(out, "%sreturn ret;\n", indent.c_str());
46 }
47
write_native_cpp_includes_q(FILE * out)48 void write_native_cpp_includes_q(FILE* out) {
49 fprintf(out, "#include <mutex>\n");
50 fprintf(out, "#include <chrono>\n");
51 fprintf(out, "#include <thread>\n");
52 fprintf(out, "#ifdef __ANDROID__\n");
53 fprintf(out, "#include <cutils/properties.h>\n");
54 fprintf(out, "#endif\n");
55 fprintf(out, "#include <stats_event_list.h>\n");
56 fprintf(out, "#include <log/log.h>\n");
57 fprintf(out, "#include <time.h>\n");
58 }
59
write_native_get_timestamp_ns_q(FILE * out)60 void write_native_get_timestamp_ns_q(FILE* out) {
61 fprintf(out, "\n");
62 fprintf(out, "static int64_t get_elapsed_realtime_ns() {\n");
63 fprintf(out, " struct timespec t;\n");
64 fprintf(out, " t.tv_sec = t.tv_nsec = 0;\n");
65 fprintf(out, " clock_gettime(CLOCK_BOOTTIME, &t);\n");
66 fprintf(out, " return (int64_t)t.tv_sec * 1000000000LL + t.tv_nsec;\n");
67 fprintf(out, "}\n");
68 }
69
write_native_stats_log_cpp_globals_q(FILE * out)70 void write_native_stats_log_cpp_globals_q(FILE* out) {
71 fprintf(out, "// the single event tag id for all stats logs\n");
72 fprintf(out, "const static int kStatsEventTag = 1937006964;\n");
73 fprintf(out, "#ifdef __ANDROID__\n");
74 fprintf(out,
75 "const static bool kStatsdEnabled = property_get_bool(\"ro.statsd.enable\", true);\n");
76 fprintf(out, "#else\n");
77 fprintf(out, "const static bool kStatsdEnabled = false;\n");
78 fprintf(out, "#endif\n");
79
80 fprintf(out, "int64_t lastRetryTimestampNs = -1;\n");
81 fprintf(out, "const int64_t kMinRetryIntervalNs = NS_PER_SEC * 60 * 20; // 20 minutes\n");
82 fprintf(out, "static std::mutex mLogdRetryMutex;\n");
83 }
84
write_native_try_stats_write_methods_q(FILE * out,const Atoms & atoms,const AtomDecl & attributionDecl,const string & moduleName)85 void write_native_try_stats_write_methods_q(FILE* out, const Atoms& atoms,
86 const AtomDecl& attributionDecl, const string& moduleName) {
87 fprintf(out, "\n");
88 for (auto signature_to_modules_it = atoms.signatures_to_modules.begin();
89 signature_to_modules_it != atoms.signatures_to_modules.end(); signature_to_modules_it++) {
90 if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) {
91 continue;
92 }
93 vector<java_type_t> signature = signature_to_modules_it->first;
94
95 write_native_method_signature(out, "static int try_stats_write", signature,
96 attributionDecl, " {");
97
98 int argIndex = 1;
99 fprintf(out, " if (kStatsdEnabled) {\n");
100 fprintf(out, " stats_event_list event(kStatsEventTag);\n");
101 fprintf(out, " event << get_elapsed_realtime_ns();\n\n");
102 fprintf(out, " event << code;\n\n");
103 for (vector<java_type_t>::const_iterator arg = signature.begin();
104 arg != signature.end(); arg++) {
105 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
106 for (const auto &chainField : attributionDecl.fields) {
107 if (chainField.javaType == JAVA_TYPE_STRING) {
108 fprintf(out, " if (%s_length != %s.size()) {\n",
109 attributionDecl.fields.front().name.c_str(), chainField.name.c_str());
110 fprintf(out, " return -EINVAL;\n");
111 fprintf(out, " }\n");
112 }
113 }
114 fprintf(out, "\n event.begin();\n");
115 fprintf(out, " for (size_t i = 0; i < %s_length; ++i) {\n",
116 attributionDecl.fields.front().name.c_str());
117 fprintf(out, " event.begin();\n");
118 for (const auto &chainField : attributionDecl.fields) {
119 if (chainField.javaType == JAVA_TYPE_STRING) {
120 fprintf(out, " if (%s[i] != NULL) {\n", chainField.name.c_str());
121 fprintf(out, " event << %s[i];\n", chainField.name.c_str());
122 fprintf(out, " } else {\n");
123 fprintf(out, " event << \"\";\n");
124 fprintf(out, " }\n");
125 } else {
126 fprintf(out, " event << %s[i];\n", chainField.name.c_str());
127 }
128 }
129 fprintf(out, " event.end();\n");
130 fprintf(out, " }\n");
131 fprintf(out, " event.end();\n\n");
132 } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
133 fprintf(out, " event.begin();\n\n");
134 fprintf(out, " for (const auto& it : arg%d_1) {\n", argIndex);
135 fprintf(out, " event.begin();\n");
136 fprintf(out, " event << it.first;\n");
137 fprintf(out, " event << it.second;\n");
138 fprintf(out, " event.end();\n");
139 fprintf(out, " }\n");
140
141 fprintf(out, " for (const auto& it : arg%d_2) {\n", argIndex);
142 fprintf(out, " event.begin();\n");
143 fprintf(out, " event << it.first;\n");
144 fprintf(out, " event << it.second;\n");
145 fprintf(out, " event.end();\n");
146 fprintf(out, " }\n");
147
148 fprintf(out, " for (const auto& it : arg%d_3) {\n", argIndex);
149 fprintf(out, " event.begin();\n");
150 fprintf(out, " event << it.first;\n");
151 fprintf(out, " event << it.second;\n");
152 fprintf(out, " event.end();\n");
153 fprintf(out, " }\n");
154
155 fprintf(out, " for (const auto& it : arg%d_4) {\n", argIndex);
156 fprintf(out, " event.begin();\n");
157 fprintf(out, " event << it.first;\n");
158 fprintf(out, " event << it.second;\n");
159 fprintf(out, " event.end();\n");
160 fprintf(out, " }\n");
161
162 fprintf(out, " event.end();\n\n");
163 } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
164 fprintf(out,
165 " event.AppendCharArray(arg%d.arg, "
166 "arg%d.arg_length);\n",
167 argIndex, argIndex);
168 } else {
169 if (*arg == JAVA_TYPE_STRING) {
170 fprintf(out, " if (arg%d == NULL) {\n", argIndex);
171 fprintf(out, " arg%d = \"\";\n", argIndex);
172 fprintf(out, " }\n");
173 }
174 fprintf(out, " event << arg%d;\n", argIndex);
175 }
176 argIndex++;
177 }
178
179 fprintf(out, " return event.write(LOG_ID_STATS);\n");
180 fprintf(out, " } else {\n");
181 fprintf(out, " return 1;\n");
182 fprintf(out, " }\n");
183 fprintf(out, "}\n");
184 fprintf(out, "\n");
185 }
186
187 }
188
write_native_stats_write_methods_q(FILE * out,const string & methodName,const Atoms & atoms,const AtomDecl & attributionDecl,const string & moduleName,const string & tryMethodName)189 void write_native_stats_write_methods_q(FILE* out, const string& methodName, const Atoms& atoms,
190 const AtomDecl& attributionDecl, const string& moduleName, const string& tryMethodName) {
191 for (auto signature_to_modules_it = atoms.signatures_to_modules.begin();
192 signature_to_modules_it != atoms.signatures_to_modules.end();
193 signature_to_modules_it++) {
194 if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) {
195 continue;
196 }
197 vector<java_type_t> signature = signature_to_modules_it->first;
198
199 write_native_method_signature(out, methodName, signature, attributionDecl, " {");
200
201 write_native_stats_write_body_q(out, signature, attributionDecl, " ", tryMethodName);
202 fprintf(out, "}\n\n");
203 }
204 }
205
write_native_stats_write_non_chained_methods_q(FILE * out,const string & methodName,const Atoms & atoms,const AtomDecl & attributionDecl,const string & moduleName,const string & tryMethodName)206 void write_native_stats_write_non_chained_methods_q(FILE* out, const string& methodName,
207 const Atoms& atoms, const AtomDecl& attributionDecl, const string& moduleName,
208 const string& tryMethodName) {
209 for (auto signature_it = atoms.non_chained_signatures_to_modules.begin();
210 signature_it != atoms.non_chained_signatures_to_modules.end(); signature_it++) {
211 if (!signature_needed_for_module(signature_it->second, moduleName)) {
212 continue;
213 }
214 vector<java_type_t> signature = signature_it->first;
215
216 write_native_method_signature(out, methodName, signature, attributionDecl, " {");
217
218 write_native_stats_write_body_q(out, signature, attributionDecl, " ", tryMethodName);
219 fprintf(out, "}\n\n");
220 }
221 }
222
write_native_try_stats_write_non_chained_methods_q(FILE * out,const Atoms & atoms,const AtomDecl & attributionDecl,const string & moduleName)223 void write_native_try_stats_write_non_chained_methods_q(FILE* out, const Atoms& atoms,
224 const AtomDecl& attributionDecl, const string& moduleName) {
225 for (auto signature_it = atoms.non_chained_signatures_to_modules.begin();
226 signature_it != atoms.non_chained_signatures_to_modules.end(); signature_it++) {
227 if (!signature_needed_for_module(signature_it->second, moduleName)) {
228 continue;
229 }
230 vector<java_type_t> signature = signature_it->first;
231
232 write_native_method_signature(out, "static int try_stats_write_non_chained", signature,
233 attributionDecl, " {");
234
235 int argIndex = 1;
236 fprintf(out, " if (kStatsdEnabled) {\n");
237 fprintf(out, " stats_event_list event(kStatsEventTag);\n");
238 fprintf(out, " event << get_elapsed_realtime_ns();\n\n");
239 fprintf(out, " event << code;\n\n");
240 for (vector<java_type_t>::const_iterator arg = signature.begin();
241 arg != signature.end(); arg++) {
242 if (argIndex == 1) {
243 fprintf(out, " event.begin();\n\n");
244 fprintf(out, " event.begin();\n");
245 }
246 if (*arg == JAVA_TYPE_STRING) {
247 fprintf(out, " if (arg%d == NULL) {\n", argIndex);
248 fprintf(out, " arg%d = \"\";\n", argIndex);
249 fprintf(out, " }\n");
250 }
251 if (*arg == JAVA_TYPE_BYTE_ARRAY) {
252 fprintf(out,
253 " event.AppendCharArray(arg%d.arg, "
254 "arg%d.arg_length);\n",
255 argIndex, argIndex);
256 } else {
257 fprintf(out, " event << arg%d;\n", argIndex);
258 }
259 if (argIndex == 2) {
260 fprintf(out, " event.end();\n\n");
261 fprintf(out, " event.end();\n\n");
262 }
263 argIndex++;
264 }
265
266 fprintf(out, " return event.write(LOG_ID_STATS);\n");
267 fprintf(out, " } else {\n");
268 fprintf(out, " return 1;\n");
269 fprintf(out, " }\n");
270 fprintf(out, "}\n");
271 fprintf(out, "\n");
272 }
273 }
274
275 } // namespace stats_log_api_gen
276 } // namespace android
277