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