blob: 2498d9f32d06dd673a9de3db0961fe27f2cac60e [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;
Yangster-mac9def8e32018-04-17 13:55:51 -070062
Yao Chen8a8d16c2018-02-08 14:50:40 -080063namespace {
Chenjie Yub038b702017-12-18 15:15:34 -080064
Yao Chen8a8d16c2018-02-08 14:50:40 -080065void writeDimensionToProtoHelper(const std::vector<FieldValue>& dims, size_t* index, int depth,
Yangster-mac9def8e32018-04-17 13:55:51 -070066 int prefix, std::set<string> *str_set,
67 ProtoOutputStream* protoOutput) {
Yao Chen8a8d16c2018-02-08 14:50:40 -080068 size_t count = dims.size();
69 while (*index < count) {
70 const auto& dim = dims[*index];
71 const int valueDepth = dim.mField.getDepth();
72 const int valuePrefix = dim.mField.getPrefix(depth);
73 const int fieldNum = dim.mField.getPosAtDepth(depth);
74 if (valueDepth > 2) {
75 ALOGE("Depth > 2 not supported");
76 return;
77 }
78
79 if (depth == valueDepth && valuePrefix == prefix) {
Yi Jin5ee07872018-03-05 18:18:27 -080080 uint64_t token = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
Yao Chen8a8d16c2018-02-08 14:50:40 -080081 DIMENSIONS_VALUE_TUPLE_VALUE);
82 protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD, fieldNum);
83 switch (dim.mValue.getType()) {
84 case INT:
85 protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_VALUE_INT,
86 dim.mValue.int_value);
87 break;
88 case LONG:
89 protoOutput->write(FIELD_TYPE_INT64 | DIMENSIONS_VALUE_VALUE_LONG,
90 (long long)dim.mValue.long_value);
91 break;
92 case FLOAT:
93 protoOutput->write(FIELD_TYPE_FLOAT | DIMENSIONS_VALUE_VALUE_FLOAT,
94 dim.mValue.float_value);
95 break;
96 case STRING:
Yangster-mac9def8e32018-04-17 13:55:51 -070097 if (str_set == nullptr) {
98 protoOutput->write(FIELD_TYPE_STRING | DIMENSIONS_VALUE_VALUE_STR,
99 dim.mValue.str_value);
100 } else {
101 str_set->insert(dim.mValue.str_value);
102 protoOutput->write(
103 FIELD_TYPE_UINT64 | DIMENSIONS_VALUE_VALUE_STR_HASH,
104 (long long)Hash64(dim.mValue.str_value));
105 }
Yao Chen8a8d16c2018-02-08 14:50:40 -0800106 break;
107 default:
108 break;
109 }
110 if (token != 0) {
111 protoOutput->end(token);
112 }
113 (*index)++;
114 } else if (valueDepth > depth && valuePrefix == prefix) {
115 // Writing the sub tree
Yi Jin5ee07872018-03-05 18:18:27 -0800116 uint64_t dimensionToken = protoOutput->start(
Yao Chen8a8d16c2018-02-08 14:50:40 -0800117 FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | DIMENSIONS_VALUE_TUPLE_VALUE);
118 protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD, fieldNum);
Yi Jin5ee07872018-03-05 18:18:27 -0800119 uint64_t tupleToken =
Yao Chen8a8d16c2018-02-08 14:50:40 -0800120 protoOutput->start(FIELD_TYPE_MESSAGE | DIMENSIONS_VALUE_VALUE_TUPLE);
121 writeDimensionToProtoHelper(dims, index, valueDepth, dim.mField.getPrefix(valueDepth),
Yangster-mac9def8e32018-04-17 13:55:51 -0700122 str_set, protoOutput);
123 protoOutput->end(tupleToken);
124 protoOutput->end(dimensionToken);
125 } else {
126 // Done with the prev sub tree
127 return;
128 }
129 }
130}
131
132void writeDimensionLeafToProtoHelper(const std::vector<FieldValue>& dims,
133 const int dimensionLeafField,
134 size_t* index, int depth,
135 int prefix, std::set<string> *str_set,
136 ProtoOutputStream* protoOutput) {
137 size_t count = dims.size();
138 while (*index < count) {
139 const auto& dim = dims[*index];
140 const int valueDepth = dim.mField.getDepth();
141 const int valuePrefix = dim.mField.getPrefix(depth);
142 if (valueDepth > 2) {
143 ALOGE("Depth > 2 not supported");
144 return;
145 }
146
147 if (depth == valueDepth && valuePrefix == prefix) {
148 uint64_t token = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
149 dimensionLeafField);
150 switch (dim.mValue.getType()) {
151 case INT:
152 protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_VALUE_INT,
153 dim.mValue.int_value);
154 break;
155 case LONG:
156 protoOutput->write(FIELD_TYPE_INT64 | DIMENSIONS_VALUE_VALUE_LONG,
157 (long long)dim.mValue.long_value);
158 break;
159 case FLOAT:
160 protoOutput->write(FIELD_TYPE_FLOAT | DIMENSIONS_VALUE_VALUE_FLOAT,
161 dim.mValue.float_value);
162 break;
163 case STRING:
164 if (str_set == nullptr) {
165 protoOutput->write(FIELD_TYPE_STRING | DIMENSIONS_VALUE_VALUE_STR,
166 dim.mValue.str_value);
167 } else {
168 str_set->insert(dim.mValue.str_value);
169 protoOutput->write(
170 FIELD_TYPE_UINT64 | DIMENSIONS_VALUE_VALUE_STR_HASH,
171 (long long)Hash64(dim.mValue.str_value));
172 }
173 break;
174 default:
175 break;
176 }
177 if (token != 0) {
178 protoOutput->end(token);
179 }
180 (*index)++;
181 } else if (valueDepth > depth && valuePrefix == prefix) {
182 writeDimensionLeafToProtoHelper(dims, dimensionLeafField,
183 index, valueDepth, dim.mField.getPrefix(valueDepth),
184 str_set, protoOutput);
185 } else {
186 // Done with the prev sub tree
187 return;
188 }
189 }
190}
191
192void writeDimensionPathToProtoHelper(const std::vector<Matcher>& fieldMatchers,
193 size_t* index, int depth, int prefix,
194 ProtoOutputStream* protoOutput) {
195 size_t count = fieldMatchers.size();
196 while (*index < count) {
197 const Field& field = fieldMatchers[*index].mMatcher;
198 const int valueDepth = field.getDepth();
199 const int valuePrefix = field.getPrefix(depth);
200 const int fieldNum = field.getPosAtDepth(depth);
201 if (valueDepth > 2) {
202 ALOGE("Depth > 2 not supported");
203 return;
204 }
205
206 if (depth == valueDepth && valuePrefix == prefix) {
207 uint64_t token = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
208 DIMENSIONS_VALUE_TUPLE_VALUE);
209 protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD, fieldNum);
210 if (token != 0) {
211 protoOutput->end(token);
212 }
213 (*index)++;
214 } else if (valueDepth > depth && valuePrefix == prefix) {
215 // Writing the sub tree
216 uint64_t dimensionToken = protoOutput->start(
217 FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | DIMENSIONS_VALUE_TUPLE_VALUE);
218 protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD, fieldNum);
219 uint64_t tupleToken =
220 protoOutput->start(FIELD_TYPE_MESSAGE | DIMENSIONS_VALUE_VALUE_TUPLE);
221 writeDimensionPathToProtoHelper(fieldMatchers, index, valueDepth,
222 field.getPrefix(valueDepth), protoOutput);
Yao Chen8a8d16c2018-02-08 14:50:40 -0800223 protoOutput->end(tupleToken);
224 protoOutput->end(dimensionToken);
225 } else {
226 // Done with the prev sub tree
227 return;
228 }
229 }
230}
231
232} // namespace
233
Yangster-mac9def8e32018-04-17 13:55:51 -0700234void writeDimensionToProto(const HashableDimensionKey& dimension, std::set<string> *str_set,
235 ProtoOutputStream* protoOutput) {
Yao Chen8a8d16c2018-02-08 14:50:40 -0800236 if (dimension.getValues().size() == 0) {
Yangster-mac93694462018-01-22 20:49:31 -0800237 return;
238 }
Yao Chen8a8d16c2018-02-08 14:50:40 -0800239 protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD,
240 dimension.getValues()[0].mField.getTag());
Yi Jin5ee07872018-03-05 18:18:27 -0800241 uint64_t topToken = protoOutput->start(FIELD_TYPE_MESSAGE | DIMENSIONS_VALUE_VALUE_TUPLE);
Yao Chen8a8d16c2018-02-08 14:50:40 -0800242 size_t index = 0;
Yangster-mac9def8e32018-04-17 13:55:51 -0700243 writeDimensionToProtoHelper(dimension.getValues(), &index, 0, 0, str_set, protoOutput);
244 protoOutput->end(topToken);
245}
246
247void writeDimensionLeafNodesToProto(const HashableDimensionKey& dimension,
248 const int dimensionLeafFieldId,
249 std::set<string> *str_set,
250 ProtoOutputStream* protoOutput) {
251 if (dimension.getValues().size() == 0) {
252 return;
253 }
254 size_t index = 0;
255 writeDimensionLeafToProtoHelper(dimension.getValues(), dimensionLeafFieldId,
256 &index, 0, 0, str_set, protoOutput);
257}
258
259void writeDimensionPathToProto(const std::vector<Matcher>& fieldMatchers,
260 ProtoOutputStream* protoOutput) {
261 if (fieldMatchers.size() == 0) {
262 return;
263 }
264 protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD,
265 fieldMatchers[0].mMatcher.getTag());
266 uint64_t topToken = protoOutput->start(FIELD_TYPE_MESSAGE | DIMENSIONS_VALUE_VALUE_TUPLE);
267 size_t index = 0;
268 writeDimensionPathToProtoHelper(fieldMatchers, &index, 0, 0, protoOutput);
Yao Chen8a8d16c2018-02-08 14:50:40 -0800269 protoOutput->end(topToken);
Yangster-mac20877162017-12-22 17:19:39 -0800270}
271
Yao Chen8a8d16c2018-02-08 14:50:40 -0800272// Supported Atoms format
273// XYZ_Atom {
274// repeated SubMsg field_1 = 1;
275// SubMsg2 field_2 = 2;
276// int32/float/string/int63 field_3 = 3;
277// }
278// logd's msg format, doesn't allow us to distinguish between the 2 cases below
279// Case (1):
280// Atom {
281// SubMsg {
282// int i = 1;
283// int j = 2;
284// }
285// repeated SubMsg
286// }
287//
288// and case (2):
289// Atom {
290// SubMsg {
291// repeated int i = 1;
292// repeated int j = 2;
293// }
294// optional SubMsg = 1;
295// }
296//
297//
Yao Chenbbdd67d2018-10-24 12:15:56 -0700298void writeFieldValueTreeToStreamHelper(int tagId, const std::vector<FieldValue>& dims,
299 size_t* index, int depth, int prefix,
300 ProtoOutputStream* protoOutput) {
Yao Chen8a8d16c2018-02-08 14:50:40 -0800301 size_t count = dims.size();
302 while (*index < count) {
303 const auto& dim = dims[*index];
304 const int valueDepth = dim.mField.getDepth();
305 const int valuePrefix = dim.mField.getPrefix(depth);
306 const int fieldNum = dim.mField.getPosAtDepth(depth);
307 if (valueDepth > 2) {
308 ALOGE("Depth > 2 not supported");
309 return;
Yangster-mac20877162017-12-22 17:19:39 -0800310 }
Yao Chen8a8d16c2018-02-08 14:50:40 -0800311
312 if (depth == valueDepth && valuePrefix == prefix) {
313 switch (dim.mValue.getType()) {
314 case INT:
315 protoOutput->write(FIELD_TYPE_INT32 | fieldNum, dim.mValue.int_value);
316 break;
317 case LONG:
318 protoOutput->write(FIELD_TYPE_INT64 | fieldNum,
319 (long long)dim.mValue.long_value);
320 break;
321 case FLOAT:
322 protoOutput->write(FIELD_TYPE_FLOAT | fieldNum, dim.mValue.float_value);
323 break;
Yao Chenbbdd67d2018-10-24 12:15:56 -0700324 case STRING: {
325 bool isBytesField = false;
326 // Bytes field is logged via string format in log_msg format. So here we check
327 // if this string field is a byte field.
328 std::map<int, std::vector<int>>::const_iterator itr;
329 if (depth == 0 && (itr = AtomsInfo::kBytesFieldAtoms.find(tagId)) !=
330 AtomsInfo::kBytesFieldAtoms.end()) {
331 const std::vector<int>& bytesFields = itr->second;
332 for (int bytesField : bytesFields) {
333 if (bytesField == fieldNum) {
334 // This is a bytes field
335 isBytesField = true;
336 break;
337 }
338 }
339 }
340 if (isBytesField) {
341 protoOutput->write(FIELD_TYPE_MESSAGE | fieldNum,
342 (const char*)dim.mValue.str_value.c_str(),
343 dim.mValue.str_value.length());
344 } else {
345 protoOutput->write(FIELD_TYPE_STRING | fieldNum, dim.mValue.str_value);
346 }
Yao Chen8a8d16c2018-02-08 14:50:40 -0800347 break;
Yao Chenbbdd67d2018-10-24 12:15:56 -0700348 }
Chenjie Yu12e5e672018-09-14 15:54:59 -0700349 case STORAGE:
350 protoOutput->write(FIELD_TYPE_MESSAGE | fieldNum,
351 (const char*)dim.mValue.storage_value.data(),
352 dim.mValue.storage_value.size());
353 break;
Yangster-macf5204922018-02-23 13:08:03 -0800354 default:
355 break;
Yao Chen8a8d16c2018-02-08 14:50:40 -0800356 }
357 (*index)++;
358 } else if (valueDepth > depth && valuePrefix == prefix) {
359 // Writing the sub tree
Yi Jin5ee07872018-03-05 18:18:27 -0800360 uint64_t msg_token = 0ULL;
Yao Chen8a8d16c2018-02-08 14:50:40 -0800361 if (valueDepth == depth + 2) {
362 msg_token =
363 protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | fieldNum);
364 } else if (valueDepth == depth + 1) {
365 msg_token = protoOutput->start(FIELD_TYPE_MESSAGE | fieldNum);
366 }
367 // Directly jump to the leaf value because the repeated position field is implied
368 // by the position of the sub msg in the parent field.
Yao Chenbbdd67d2018-10-24 12:15:56 -0700369 writeFieldValueTreeToStreamHelper(tagId, dims, index, valueDepth,
Yao Chen8a8d16c2018-02-08 14:50:40 -0800370 dim.mField.getPrefix(valueDepth), protoOutput);
371 if (msg_token != 0) {
372 protoOutput->end(msg_token);
373 }
374 } else {
375 // Done with the prev sub tree
376 return;
377 }
Yangster-mac20877162017-12-22 17:19:39 -0800378 }
379}
380
Yao Chen8a8d16c2018-02-08 14:50:40 -0800381void writeFieldValueTreeToStream(int tagId, const std::vector<FieldValue>& values,
Yangster-mac20877162017-12-22 17:19:39 -0800382 util::ProtoOutputStream* protoOutput) {
Yi Jin5ee07872018-03-05 18:18:27 -0800383 uint64_t atomToken = protoOutput->start(FIELD_TYPE_MESSAGE | tagId);
Yangster-mac20877162017-12-22 17:19:39 -0800384
Yao Chen8a8d16c2018-02-08 14:50:40 -0800385 size_t index = 0;
Yao Chenbbdd67d2018-10-24 12:15:56 -0700386 writeFieldValueTreeToStreamHelper(tagId, values, &index, 0, 0, protoOutput);
Yao Chen8a8d16c2018-02-08 14:50:40 -0800387 protoOutput->end(atomToken);
Yangster-macb8144812018-01-04 10:56:23 -0800388}
Yangster-mac20877162017-12-22 17:19:39 -0800389
yro59cc24d2018-02-13 20:17:32 -0800390int64_t TimeUnitToBucketSizeInMillisGuardrailed(int uid, TimeUnit unit) {
391 int64_t bucketSizeMillis = TimeUnitToBucketSizeInMillis(unit);
Chenjie Yu1a0a9412018-03-28 10:07:22 -0700392 if (bucketSizeMillis > 1000 && bucketSizeMillis < 5 * 60 * 1000LL && uid != AID_SHELL &&
393 uid != AID_ROOT) {
yro59cc24d2018-02-13 20:17:32 -0800394 bucketSizeMillis = 5 * 60 * 1000LL;
395 }
396 return bucketSizeMillis;
397}
398
Yangster-macb8144812018-01-04 10:56:23 -0800399int64_t TimeUnitToBucketSizeInMillis(TimeUnit unit) {
400 switch (unit) {
401 case ONE_MINUTE:
402 return 60 * 1000LL;
403 case FIVE_MINUTES:
404 return 5 * 60 * 1000LL;
405 case TEN_MINUTES:
406 return 10 * 60 * 1000LL;
407 case THIRTY_MINUTES:
408 return 30 * 60 * 1000LL;
409 case ONE_HOUR:
410 return 60 * 60 * 1000LL;
411 case THREE_HOURS:
412 return 3 * 60 * 60 * 1000LL;
413 case SIX_HOURS:
414 return 6 * 60 * 60 * 1000LL;
415 case TWELVE_HOURS:
416 return 12 * 60 * 60 * 1000LL;
417 case ONE_DAY:
418 return 24 * 60 * 60 * 1000LL;
419 case CTS:
420 return 1000;
421 case TIME_UNIT_UNSPECIFIED:
422 default:
423 return -1;
424 }
Yangster-mac20877162017-12-22 17:19:39 -0800425}
426
Chenjie Yub038b702017-12-18 15:15:34 -0800427void writePullerStatsToStream(const std::pair<int, StatsdStats::PulledAtomStats>& pair,
428 util::ProtoOutputStream* protoOutput) {
Yi Jin5ee07872018-03-05 18:18:27 -0800429 uint64_t token = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_PULLED_ATOM_STATS |
Chenjie Yub038b702017-12-18 15:15:34 -0800430 FIELD_COUNT_REPEATED);
431 protoOutput->write(FIELD_TYPE_INT32 | FIELD_ID_PULL_ATOM_ID, (int32_t)pair.first);
432 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_TOTAL_PULL, (long long)pair.second.totalPull);
433 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_TOTAL_PULL_FROM_CACHE,
434 (long long)pair.second.totalPullFromCache);
435 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_MIN_PULL_INTERVAL_SEC,
436 (long long)pair.second.minPullIntervalSec);
437 protoOutput->end(token);
438}
439
Yangster-mac330af582018-02-08 15:24:38 -0800440int64_t getElapsedRealtimeNs() {
441 return ::android::elapsedRealtimeNano();
442}
443
444int64_t getElapsedRealtimeSec() {
445 return ::android::elapsedRealtimeNano() / NS_PER_SEC;
446}
447
448int64_t getElapsedRealtimeMillis() {
449 return ::android::elapsedRealtime();
450}
451
452int64_t getWallClockNs() {
453 return time(nullptr) * NS_PER_SEC;
454}
455
456int64_t getWallClockSec() {
457 return time(nullptr);
458}
459
460int64_t getWallClockMillis() {
461 return time(nullptr) * MS_PER_SEC;
462}
463
Yangster-macd5c35622018-02-02 10:33:25 -0800464int64_t truncateTimestampNsToFiveMinutes(int64_t timestampNs) {
465 return timestampNs / NS_PER_SEC / (5 * 60) * NS_PER_SEC * (5 * 60);
466}
467
Yangster-mac9def8e32018-04-17 13:55:51 -0700468int64_t NanoToMillis(const int64_t nano) {
469 return nano / 1000000;
470}
471
472int64_t MillisToNano(const int64_t millis) {
473 return millis * 1000000;
474}
475
Yangster-mac20877162017-12-22 17:19:39 -0800476} // namespace statsd
477} // namespace os
yro59cc24d2018-02-13 20:17:32 -0800478} // namespace android