blob: f1310db03d45866b7609ead7788a31cde7319134 [file] [log] [blame]
Yangster-mac20877162017-12-22 17:19:39 -08001/*
2 * Copyright (C) 2017 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
Yangster-mac9def8e32018-04-17 13:55:51 -070017#include "hash.h"
Yangster-mac20877162017-12-22 17:19:39 -080018#include "stats_log_util.h"
19
Yao Chen8a8d16c2018-02-08 14:50:40 -080020#include <logd/LogEvent.h>
yro59cc24d2018-02-13 20:17:32 -080021#include <private/android_filesystem_config.h>
Yao Chen8a8d16c2018-02-08 14:50:40 -080022#include <utils/Log.h>
Yangster-mac20877162017-12-22 17:19:39 -080023#include <set>
24#include <stack>
Yangster-mac330af582018-02-08 15:24:38 -080025#include <utils/Log.h>
26#include <utils/SystemClock.h>
Yangster-mac20877162017-12-22 17:19:39 -080027
Yao Chenbbdd67d2018-10-24 12:15:56 -070028using android::util::AtomsInfo;
Yangster-mac20877162017-12-22 17:19:39 -080029using android::util::FIELD_COUNT_REPEATED;
30using android::util::FIELD_TYPE_BOOL;
Yao Chenbbdd67d2018-10-24 12:15:56 -070031using android::util::FIELD_TYPE_FIXED64;
Yangster-mac20877162017-12-22 17:19:39 -080032using android::util::FIELD_TYPE_FLOAT;
33using android::util::FIELD_TYPE_INT32;
34using android::util::FIELD_TYPE_INT64;
35using android::util::FIELD_TYPE_MESSAGE;
36using android::util::FIELD_TYPE_STRING;
Yao Chenbbdd67d2018-10-24 12:15:56 -070037using android::util::FIELD_TYPE_UINT64;
Yangster-mac20877162017-12-22 17:19:39 -080038using android::util::ProtoOutputStream;
39
40namespace android {
41namespace os {
42namespace statsd {
43
44// for DimensionsValue Proto
45const int DIMENSIONS_VALUE_FIELD = 1;
46const int DIMENSIONS_VALUE_VALUE_STR = 2;
47const int DIMENSIONS_VALUE_VALUE_INT = 3;
48const int DIMENSIONS_VALUE_VALUE_LONG = 4;
Yao Chen4c959cb2018-02-13 13:27:48 -080049// const int DIMENSIONS_VALUE_VALUE_BOOL = 5; // logd doesn't have bool data type.
Yangster-mac20877162017-12-22 17:19:39 -080050const int DIMENSIONS_VALUE_VALUE_FLOAT = 6;
51const int DIMENSIONS_VALUE_VALUE_TUPLE = 7;
Yangster-mac9def8e32018-04-17 13:55:51 -070052const int DIMENSIONS_VALUE_VALUE_STR_HASH = 8;
Yangster-mac20877162017-12-22 17:19:39 -080053
Yao Chen8a8d16c2018-02-08 14:50:40 -080054const int DIMENSIONS_VALUE_TUPLE_VALUE = 1;
55
Chenjie Yub038b702017-12-18 15:15:34 -080056// for PulledAtomStats proto
57const int FIELD_ID_PULLED_ATOM_STATS = 10;
58const int FIELD_ID_PULL_ATOM_ID = 1;
59const int FIELD_ID_TOTAL_PULL = 2;
60const int FIELD_ID_TOTAL_PULL_FROM_CACHE = 3;
61const int FIELD_ID_MIN_PULL_INTERVAL_SEC = 4;
Chenjie Yu48ed1cc2018-10-31 17:36:38 -070062const int FIELD_ID_AVERAGE_PULL_TIME_NANOS = 5;
63const int FIELD_ID_MAX_PULL_TIME_NANOS = 6;
64const int FIELD_ID_AVERAGE_PULL_DELAY_NANOS = 7;
65const int FIELD_ID_MAX_PULL_DELAY_NANOS = 8;
Chenjie Yuc715b9e2018-10-19 07:52:12 -070066const int FIELD_ID_DATA_ERROR = 9;
Yangster-mac9def8e32018-04-17 13:55:51 -070067
Yao Chen8a8d16c2018-02-08 14:50:40 -080068namespace {
Chenjie Yub038b702017-12-18 15:15:34 -080069
Yao Chen8a8d16c2018-02-08 14:50:40 -080070void writeDimensionToProtoHelper(const std::vector<FieldValue>& dims, size_t* index, int depth,
Yangster-mac9def8e32018-04-17 13:55:51 -070071 int prefix, std::set<string> *str_set,
72 ProtoOutputStream* protoOutput) {
Yao Chen8a8d16c2018-02-08 14:50:40 -080073 size_t count = dims.size();
74 while (*index < count) {
75 const auto& dim = dims[*index];
76 const int valueDepth = dim.mField.getDepth();
77 const int valuePrefix = dim.mField.getPrefix(depth);
78 const int fieldNum = dim.mField.getPosAtDepth(depth);
79 if (valueDepth > 2) {
80 ALOGE("Depth > 2 not supported");
81 return;
82 }
83
84 if (depth == valueDepth && valuePrefix == prefix) {
Yi Jin5ee07872018-03-05 18:18:27 -080085 uint64_t token = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
Yao Chen8a8d16c2018-02-08 14:50:40 -080086 DIMENSIONS_VALUE_TUPLE_VALUE);
87 protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD, fieldNum);
88 switch (dim.mValue.getType()) {
89 case INT:
90 protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_VALUE_INT,
91 dim.mValue.int_value);
92 break;
93 case LONG:
94 protoOutput->write(FIELD_TYPE_INT64 | DIMENSIONS_VALUE_VALUE_LONG,
95 (long long)dim.mValue.long_value);
96 break;
97 case FLOAT:
98 protoOutput->write(FIELD_TYPE_FLOAT | DIMENSIONS_VALUE_VALUE_FLOAT,
99 dim.mValue.float_value);
100 break;
101 case STRING:
Yangster-mac9def8e32018-04-17 13:55:51 -0700102 if (str_set == nullptr) {
103 protoOutput->write(FIELD_TYPE_STRING | DIMENSIONS_VALUE_VALUE_STR,
104 dim.mValue.str_value);
105 } else {
106 str_set->insert(dim.mValue.str_value);
107 protoOutput->write(
108 FIELD_TYPE_UINT64 | DIMENSIONS_VALUE_VALUE_STR_HASH,
109 (long long)Hash64(dim.mValue.str_value));
110 }
Yao Chen8a8d16c2018-02-08 14:50:40 -0800111 break;
112 default:
113 break;
114 }
115 if (token != 0) {
116 protoOutput->end(token);
117 }
118 (*index)++;
119 } else if (valueDepth > depth && valuePrefix == prefix) {
120 // Writing the sub tree
Yi Jin5ee07872018-03-05 18:18:27 -0800121 uint64_t dimensionToken = protoOutput->start(
Yao Chen8a8d16c2018-02-08 14:50:40 -0800122 FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | DIMENSIONS_VALUE_TUPLE_VALUE);
123 protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD, fieldNum);
Yi Jin5ee07872018-03-05 18:18:27 -0800124 uint64_t tupleToken =
Yao Chen8a8d16c2018-02-08 14:50:40 -0800125 protoOutput->start(FIELD_TYPE_MESSAGE | DIMENSIONS_VALUE_VALUE_TUPLE);
126 writeDimensionToProtoHelper(dims, index, valueDepth, dim.mField.getPrefix(valueDepth),
Yangster-mac9def8e32018-04-17 13:55:51 -0700127 str_set, protoOutput);
128 protoOutput->end(tupleToken);
129 protoOutput->end(dimensionToken);
130 } else {
131 // Done with the prev sub tree
132 return;
133 }
134 }
135}
136
137void writeDimensionLeafToProtoHelper(const std::vector<FieldValue>& dims,
138 const int dimensionLeafField,
139 size_t* index, int depth,
140 int prefix, std::set<string> *str_set,
141 ProtoOutputStream* protoOutput) {
142 size_t count = dims.size();
143 while (*index < count) {
144 const auto& dim = dims[*index];
145 const int valueDepth = dim.mField.getDepth();
146 const int valuePrefix = dim.mField.getPrefix(depth);
147 if (valueDepth > 2) {
148 ALOGE("Depth > 2 not supported");
149 return;
150 }
151
152 if (depth == valueDepth && valuePrefix == prefix) {
153 uint64_t token = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
154 dimensionLeafField);
155 switch (dim.mValue.getType()) {
156 case INT:
157 protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_VALUE_INT,
158 dim.mValue.int_value);
159 break;
160 case LONG:
161 protoOutput->write(FIELD_TYPE_INT64 | DIMENSIONS_VALUE_VALUE_LONG,
162 (long long)dim.mValue.long_value);
163 break;
164 case FLOAT:
165 protoOutput->write(FIELD_TYPE_FLOAT | DIMENSIONS_VALUE_VALUE_FLOAT,
166 dim.mValue.float_value);
167 break;
168 case STRING:
169 if (str_set == nullptr) {
170 protoOutput->write(FIELD_TYPE_STRING | DIMENSIONS_VALUE_VALUE_STR,
171 dim.mValue.str_value);
172 } else {
173 str_set->insert(dim.mValue.str_value);
174 protoOutput->write(
175 FIELD_TYPE_UINT64 | DIMENSIONS_VALUE_VALUE_STR_HASH,
176 (long long)Hash64(dim.mValue.str_value));
177 }
178 break;
179 default:
180 break;
181 }
182 if (token != 0) {
183 protoOutput->end(token);
184 }
185 (*index)++;
186 } else if (valueDepth > depth && valuePrefix == prefix) {
187 writeDimensionLeafToProtoHelper(dims, dimensionLeafField,
188 index, valueDepth, dim.mField.getPrefix(valueDepth),
189 str_set, protoOutput);
190 } else {
191 // Done with the prev sub tree
192 return;
193 }
194 }
195}
196
197void writeDimensionPathToProtoHelper(const std::vector<Matcher>& fieldMatchers,
198 size_t* index, int depth, int prefix,
199 ProtoOutputStream* protoOutput) {
200 size_t count = fieldMatchers.size();
201 while (*index < count) {
202 const Field& field = fieldMatchers[*index].mMatcher;
203 const int valueDepth = field.getDepth();
204 const int valuePrefix = field.getPrefix(depth);
205 const int fieldNum = field.getPosAtDepth(depth);
206 if (valueDepth > 2) {
207 ALOGE("Depth > 2 not supported");
208 return;
209 }
210
211 if (depth == valueDepth && valuePrefix == prefix) {
212 uint64_t token = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
213 DIMENSIONS_VALUE_TUPLE_VALUE);
214 protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD, fieldNum);
215 if (token != 0) {
216 protoOutput->end(token);
217 }
218 (*index)++;
219 } else if (valueDepth > depth && valuePrefix == prefix) {
220 // Writing the sub tree
221 uint64_t dimensionToken = protoOutput->start(
222 FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | DIMENSIONS_VALUE_TUPLE_VALUE);
223 protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD, fieldNum);
224 uint64_t tupleToken =
225 protoOutput->start(FIELD_TYPE_MESSAGE | DIMENSIONS_VALUE_VALUE_TUPLE);
226 writeDimensionPathToProtoHelper(fieldMatchers, index, valueDepth,
227 field.getPrefix(valueDepth), protoOutput);
Yao Chen8a8d16c2018-02-08 14:50:40 -0800228 protoOutput->end(tupleToken);
229 protoOutput->end(dimensionToken);
230 } else {
231 // Done with the prev sub tree
232 return;
233 }
234 }
235}
236
237} // namespace
238
Yangster-mac9def8e32018-04-17 13:55:51 -0700239void writeDimensionToProto(const HashableDimensionKey& dimension, std::set<string> *str_set,
240 ProtoOutputStream* protoOutput) {
Yao Chen8a8d16c2018-02-08 14:50:40 -0800241 if (dimension.getValues().size() == 0) {
Yangster-mac93694462018-01-22 20:49:31 -0800242 return;
243 }
Yao Chen8a8d16c2018-02-08 14:50:40 -0800244 protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD,
245 dimension.getValues()[0].mField.getTag());
Yi Jin5ee07872018-03-05 18:18:27 -0800246 uint64_t topToken = protoOutput->start(FIELD_TYPE_MESSAGE | DIMENSIONS_VALUE_VALUE_TUPLE);
Yao Chen8a8d16c2018-02-08 14:50:40 -0800247 size_t index = 0;
Yangster-mac9def8e32018-04-17 13:55:51 -0700248 writeDimensionToProtoHelper(dimension.getValues(), &index, 0, 0, str_set, protoOutput);
249 protoOutput->end(topToken);
250}
251
252void writeDimensionLeafNodesToProto(const HashableDimensionKey& dimension,
253 const int dimensionLeafFieldId,
254 std::set<string> *str_set,
255 ProtoOutputStream* protoOutput) {
256 if (dimension.getValues().size() == 0) {
257 return;
258 }
259 size_t index = 0;
260 writeDimensionLeafToProtoHelper(dimension.getValues(), dimensionLeafFieldId,
261 &index, 0, 0, str_set, protoOutput);
262}
263
264void writeDimensionPathToProto(const std::vector<Matcher>& fieldMatchers,
265 ProtoOutputStream* protoOutput) {
266 if (fieldMatchers.size() == 0) {
267 return;
268 }
269 protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD,
270 fieldMatchers[0].mMatcher.getTag());
271 uint64_t topToken = protoOutput->start(FIELD_TYPE_MESSAGE | DIMENSIONS_VALUE_VALUE_TUPLE);
272 size_t index = 0;
273 writeDimensionPathToProtoHelper(fieldMatchers, &index, 0, 0, protoOutput);
Yao Chen8a8d16c2018-02-08 14:50:40 -0800274 protoOutput->end(topToken);
Yangster-mac20877162017-12-22 17:19:39 -0800275}
276
Yao Chen8a8d16c2018-02-08 14:50:40 -0800277// Supported Atoms format
278// XYZ_Atom {
279// repeated SubMsg field_1 = 1;
280// SubMsg2 field_2 = 2;
281// int32/float/string/int63 field_3 = 3;
282// }
283// logd's msg format, doesn't allow us to distinguish between the 2 cases below
284// Case (1):
285// Atom {
286// SubMsg {
287// int i = 1;
288// int j = 2;
289// }
290// repeated SubMsg
291// }
292//
293// and case (2):
294// Atom {
295// SubMsg {
296// repeated int i = 1;
297// repeated int j = 2;
298// }
299// optional SubMsg = 1;
300// }
301//
302//
Yao Chenbbdd67d2018-10-24 12:15:56 -0700303void writeFieldValueTreeToStreamHelper(int tagId, const std::vector<FieldValue>& dims,
304 size_t* index, int depth, int prefix,
305 ProtoOutputStream* protoOutput) {
Yao Chen8a8d16c2018-02-08 14:50:40 -0800306 size_t count = dims.size();
307 while (*index < count) {
308 const auto& dim = dims[*index];
309 const int valueDepth = dim.mField.getDepth();
310 const int valuePrefix = dim.mField.getPrefix(depth);
311 const int fieldNum = dim.mField.getPosAtDepth(depth);
312 if (valueDepth > 2) {
313 ALOGE("Depth > 2 not supported");
314 return;
Yangster-mac20877162017-12-22 17:19:39 -0800315 }
Yao Chen8a8d16c2018-02-08 14:50:40 -0800316
317 if (depth == valueDepth && valuePrefix == prefix) {
318 switch (dim.mValue.getType()) {
319 case INT:
320 protoOutput->write(FIELD_TYPE_INT32 | fieldNum, dim.mValue.int_value);
321 break;
322 case LONG:
323 protoOutput->write(FIELD_TYPE_INT64 | fieldNum,
324 (long long)dim.mValue.long_value);
325 break;
326 case FLOAT:
327 protoOutput->write(FIELD_TYPE_FLOAT | fieldNum, dim.mValue.float_value);
328 break;
Yao Chenbbdd67d2018-10-24 12:15:56 -0700329 case STRING: {
330 bool isBytesField = false;
331 // Bytes field is logged via string format in log_msg format. So here we check
332 // if this string field is a byte field.
333 std::map<int, std::vector<int>>::const_iterator itr;
334 if (depth == 0 && (itr = AtomsInfo::kBytesFieldAtoms.find(tagId)) !=
335 AtomsInfo::kBytesFieldAtoms.end()) {
336 const std::vector<int>& bytesFields = itr->second;
337 for (int bytesField : bytesFields) {
338 if (bytesField == fieldNum) {
339 // This is a bytes field
340 isBytesField = true;
341 break;
342 }
343 }
344 }
345 if (isBytesField) {
Yao Chen8e6f9982018-11-29 09:39:45 -0800346 if (dim.mValue.str_value.length() > 0) {
347 protoOutput->write(FIELD_TYPE_MESSAGE | fieldNum,
348 (const char*)dim.mValue.str_value.c_str(),
349 dim.mValue.str_value.length());
350 }
Yao Chenbbdd67d2018-10-24 12:15:56 -0700351 } else {
352 protoOutput->write(FIELD_TYPE_STRING | fieldNum, dim.mValue.str_value);
353 }
Yao Chen8a8d16c2018-02-08 14:50:40 -0800354 break;
Yao Chenbbdd67d2018-10-24 12:15:56 -0700355 }
Chenjie Yu12e5e672018-09-14 15:54:59 -0700356 case STORAGE:
357 protoOutput->write(FIELD_TYPE_MESSAGE | fieldNum,
358 (const char*)dim.mValue.storage_value.data(),
359 dim.mValue.storage_value.size());
360 break;
Yangster-macf5204922018-02-23 13:08:03 -0800361 default:
362 break;
Yao Chen8a8d16c2018-02-08 14:50:40 -0800363 }
364 (*index)++;
365 } else if (valueDepth > depth && valuePrefix == prefix) {
366 // Writing the sub tree
Yi Jin5ee07872018-03-05 18:18:27 -0800367 uint64_t msg_token = 0ULL;
Yao Chen8a8d16c2018-02-08 14:50:40 -0800368 if (valueDepth == depth + 2) {
369 msg_token =
370 protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | fieldNum);
371 } else if (valueDepth == depth + 1) {
372 msg_token = protoOutput->start(FIELD_TYPE_MESSAGE | fieldNum);
373 }
374 // Directly jump to the leaf value because the repeated position field is implied
375 // by the position of the sub msg in the parent field.
Yao Chenbbdd67d2018-10-24 12:15:56 -0700376 writeFieldValueTreeToStreamHelper(tagId, dims, index, valueDepth,
Yao Chen8a8d16c2018-02-08 14:50:40 -0800377 dim.mField.getPrefix(valueDepth), protoOutput);
378 if (msg_token != 0) {
379 protoOutput->end(msg_token);
380 }
381 } else {
382 // Done with the prev sub tree
383 return;
384 }
Yangster-mac20877162017-12-22 17:19:39 -0800385 }
386}
387
Yao Chen8a8d16c2018-02-08 14:50:40 -0800388void writeFieldValueTreeToStream(int tagId, const std::vector<FieldValue>& values,
Yangster-mac20877162017-12-22 17:19:39 -0800389 util::ProtoOutputStream* protoOutput) {
Yi Jin5ee07872018-03-05 18:18:27 -0800390 uint64_t atomToken = protoOutput->start(FIELD_TYPE_MESSAGE | tagId);
Yangster-mac20877162017-12-22 17:19:39 -0800391
Yao Chen8a8d16c2018-02-08 14:50:40 -0800392 size_t index = 0;
Yao Chenbbdd67d2018-10-24 12:15:56 -0700393 writeFieldValueTreeToStreamHelper(tagId, values, &index, 0, 0, protoOutput);
Yao Chen8a8d16c2018-02-08 14:50:40 -0800394 protoOutput->end(atomToken);
Yangster-macb8144812018-01-04 10:56:23 -0800395}
Yangster-mac20877162017-12-22 17:19:39 -0800396
yro59cc24d2018-02-13 20:17:32 -0800397int64_t TimeUnitToBucketSizeInMillisGuardrailed(int uid, TimeUnit unit) {
398 int64_t bucketSizeMillis = TimeUnitToBucketSizeInMillis(unit);
Chenjie Yu1a0a9412018-03-28 10:07:22 -0700399 if (bucketSizeMillis > 1000 && bucketSizeMillis < 5 * 60 * 1000LL && uid != AID_SHELL &&
400 uid != AID_ROOT) {
yro59cc24d2018-02-13 20:17:32 -0800401 bucketSizeMillis = 5 * 60 * 1000LL;
402 }
403 return bucketSizeMillis;
404}
405
Yangster-macb8144812018-01-04 10:56:23 -0800406int64_t TimeUnitToBucketSizeInMillis(TimeUnit unit) {
407 switch (unit) {
408 case ONE_MINUTE:
409 return 60 * 1000LL;
410 case FIVE_MINUTES:
411 return 5 * 60 * 1000LL;
412 case TEN_MINUTES:
413 return 10 * 60 * 1000LL;
414 case THIRTY_MINUTES:
415 return 30 * 60 * 1000LL;
416 case ONE_HOUR:
417 return 60 * 60 * 1000LL;
418 case THREE_HOURS:
419 return 3 * 60 * 60 * 1000LL;
420 case SIX_HOURS:
421 return 6 * 60 * 60 * 1000LL;
422 case TWELVE_HOURS:
423 return 12 * 60 * 60 * 1000LL;
424 case ONE_DAY:
425 return 24 * 60 * 60 * 1000LL;
426 case CTS:
427 return 1000;
428 case TIME_UNIT_UNSPECIFIED:
429 default:
430 return -1;
431 }
Yangster-mac20877162017-12-22 17:19:39 -0800432}
433
Chenjie Yub038b702017-12-18 15:15:34 -0800434void writePullerStatsToStream(const std::pair<int, StatsdStats::PulledAtomStats>& pair,
435 util::ProtoOutputStream* protoOutput) {
Yi Jin5ee07872018-03-05 18:18:27 -0800436 uint64_t token = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_PULLED_ATOM_STATS |
Chenjie Yub038b702017-12-18 15:15:34 -0800437 FIELD_COUNT_REPEATED);
438 protoOutput->write(FIELD_TYPE_INT32 | FIELD_ID_PULL_ATOM_ID, (int32_t)pair.first);
439 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_TOTAL_PULL, (long long)pair.second.totalPull);
440 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_TOTAL_PULL_FROM_CACHE,
441 (long long)pair.second.totalPullFromCache);
442 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_MIN_PULL_INTERVAL_SEC,
443 (long long)pair.second.minPullIntervalSec);
Chenjie Yu48ed1cc2018-10-31 17:36:38 -0700444 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_AVERAGE_PULL_TIME_NANOS,
445 (long long)pair.second.avgPullTimeNs);
446 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_MAX_PULL_TIME_NANOS,
447 (long long)pair.second.maxPullTimeNs);
448 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_AVERAGE_PULL_DELAY_NANOS,
449 (long long)pair.second.avgPullDelayNs);
450 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_MAX_PULL_DELAY_NANOS,
451 (long long)pair.second.maxPullDelayNs);
Chenjie Yuc715b9e2018-10-19 07:52:12 -0700452 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_DATA_ERROR, (long long)pair.second.dataError);
Chenjie Yub038b702017-12-18 15:15:34 -0800453 protoOutput->end(token);
454}
455
Yangster-mac330af582018-02-08 15:24:38 -0800456int64_t getElapsedRealtimeNs() {
457 return ::android::elapsedRealtimeNano();
458}
459
460int64_t getElapsedRealtimeSec() {
461 return ::android::elapsedRealtimeNano() / NS_PER_SEC;
462}
463
464int64_t getElapsedRealtimeMillis() {
465 return ::android::elapsedRealtime();
466}
467
468int64_t getWallClockNs() {
469 return time(nullptr) * NS_PER_SEC;
470}
471
472int64_t getWallClockSec() {
473 return time(nullptr);
474}
475
476int64_t getWallClockMillis() {
477 return time(nullptr) * MS_PER_SEC;
478}
479
Yangster-macd5c35622018-02-02 10:33:25 -0800480int64_t truncateTimestampNsToFiveMinutes(int64_t timestampNs) {
481 return timestampNs / NS_PER_SEC / (5 * 60) * NS_PER_SEC * (5 * 60);
482}
483
Yangster-mac9def8e32018-04-17 13:55:51 -0700484int64_t NanoToMillis(const int64_t nano) {
485 return nano / 1000000;
486}
487
488int64_t MillisToNano(const int64_t millis) {
489 return millis * 1000000;
490}
491
Yangster-mac20877162017-12-22 17:19:39 -0800492} // namespace statsd
493} // namespace os
yro59cc24d2018-02-13 20:17:32 -0800494} // namespace android