blob: 35a0b550211f9e56d89570b030920198d3a454b9 [file] [log] [blame]
Ray Essick3938dc62016-11-01 08:56:56 -07001/*
2 * Copyright (C) 2016 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
Andy Hung47e58d62019-12-06 18:40:19 -080017#ifndef ANDROID_MEDIA_MEDIAMETRICSITEM_H
18#define ANDROID_MEDIA_MEDIAMETRICSITEM_H
Ray Essick3938dc62016-11-01 08:56:56 -070019
Ray Essickbf536ac2019-08-26 11:04:28 -070020#include "MediaMetrics.h"
21
Andy Hung3253f2d2019-10-21 14:50:07 -070022#include <algorithm>
Andy Hung47e58d62019-12-06 18:40:19 -080023#include <map>
Ray Essick783bd0d2018-01-11 11:10:35 -080024#include <string>
Ray Essick3938dc62016-11-01 08:56:56 -070025#include <sys/types.h>
Andy Hungb7aadb32019-12-09 19:40:42 -080026#include <variant>
Ray Essickba8c4842019-01-18 11:35:33 -080027
Andy Hungb7aadb32019-12-09 19:40:42 -080028#include <binder/Parcel.h>
Ray Essickba8c4842019-01-18 11:35:33 -080029#include <cutils/properties.h>
Ray Essick3938dc62016-11-01 08:56:56 -070030#include <utils/Errors.h>
31#include <utils/KeyedVector.h>
32#include <utils/RefBase.h>
33#include <utils/StrongPointer.h>
34#include <utils/Timers.h>
35
Ray Essick3938dc62016-11-01 08:56:56 -070036namespace android {
37
Ray Essickf27e9872019-12-07 06:28:46 -080038class IMediaMetricsService;
Ray Essick783bd0d2018-01-11 11:10:35 -080039class Parcel;
Ray Essick3938dc62016-11-01 08:56:56 -070040
Andy Hung3253f2d2019-10-21 14:50:07 -070041/*
Andy Hung1efc9c62019-12-03 13:43:33 -080042 * MediaMetrics Item
Andy Hung3253f2d2019-10-21 14:50:07 -070043 *
Andy Hung1efc9c62019-12-03 13:43:33 -080044 * Byte string format.
45 *
46 * For Java
47 * int64 corresponds to long
48 * int32, uint32 corresponds to int
49 * uint16 corresponds to char
50 * uint8, int8 corresponds to byte
51 *
52 * Hence uint8 and uint32 values are limited to INT8_MAX and INT32_MAX.
53 *
54 * Physical layout of integers and doubles within the MediaMetrics byte string
55 * is in Native / host order, which is nearly always little endian.
56 *
57 * -- begin of item
58 * -- begin of header
59 * (uint32) item size: including the item size field
60 * (uint32) header size, including the item size and header size fields.
61 * (uint16) version: exactly 0
62 * (uint16) key size, that is key strlen + 1 for zero termination.
63 * (int8)+ key string which is 0 terminated
Andy Hung3253f2d2019-10-21 14:50:07 -070064 * (int32) pid
65 * (int32) uid
66 * (int64) timestamp
Andy Hung1efc9c62019-12-03 13:43:33 -080067 * -- end of header
68 * -- begin body
69 * (uint32) number of properties
70 * -- repeat for number of properties
71 * (uint16) property size, including property size field itself
Andy Hung3253f2d2019-10-21 14:50:07 -070072 * (uint8) type of property
73 * (int8)+ key string, including 0 termination
Andy Hung1efc9c62019-12-03 13:43:33 -080074 * based on type of property (given above), one of:
Andy Hung3253f2d2019-10-21 14:50:07 -070075 * (int32)
76 * (int64)
77 * (double)
78 * (int8)+ for cstring, including 0 termination
79 * (int64, int64) for rate
Andy Hung1efc9c62019-12-03 13:43:33 -080080 * -- end body
81 * -- end of item
Andy Hung3253f2d2019-10-21 14:50:07 -070082 */
83
Andy Hung1efc9c62019-12-03 13:43:33 -080084namespace mediametrics {
85
86// Type must match MediaMetrics.java
87enum Type {
88 kTypeNone = 0,
89 kTypeInt32 = 1,
90 kTypeInt64 = 2,
91 kTypeDouble = 3,
92 kTypeCString = 4,
93 kTypeRate = 5,
94};
95
96template<size_t N>
97static inline bool startsWith(const std::string &s, const char (&comp)[N]) {
98 return !strncmp(s.c_str(), comp, N-1);
99}
100
101/**
102 * Media Metrics BaseItem
103 *
104 * A base class which contains utility static functions to write to a byte stream
105 * and access the Media Metrics service.
106 */
107
108class BaseItem {
109 friend class MediaMetricsDeathNotifier; // for dropInstance
110 // enabled 1, disabled 0
111public:
Andy Hung47e58d62019-12-06 18:40:19 -0800112 // are we collecting metrics data
Andy Hung1efc9c62019-12-03 13:43:33 -0800113 static bool isEnabled();
Andy Hung47e58d62019-12-06 18:40:19 -0800114 static sp<IMediaMetricsService> getService();
Andy Hung1efc9c62019-12-03 13:43:33 -0800115
116protected:
117 static constexpr const char * const EnabledProperty = "media.metrics.enabled";
118 static constexpr const char * const EnabledPropertyPersist = "persist.media.metrics.enabled";
119 static const int EnabledProperty_default = 1;
120
121 // let's reuse a binder connection
Ray Essickf27e9872019-12-07 06:28:46 -0800122 static sp<IMediaMetricsService> sMediaMetricsService;
Andy Hung47e58d62019-12-06 18:40:19 -0800123
Andy Hung1efc9c62019-12-03 13:43:33 -0800124 static void dropInstance();
125 static bool submitBuffer(const char *buffer, size_t len);
126
Andy Hungb7aadb32019-12-09 19:40:42 -0800127 template <typename T>
128 struct is_item_type {
129 static constexpr inline bool value =
130 std::is_same<T, int32_t>::value
131 || std::is_same<T, int64_t>::value
132 || std::is_same<T, double>::value
133 || std::is_same<T, std::pair<int64_t, int64_t>>:: value
134 || std::is_same<T, std::string>::value
135 || std::is_same<T, std::monostate>::value;
136 };
Andy Hung1efc9c62019-12-03 13:43:33 -0800137
Andy Hungb7aadb32019-12-09 19:40:42 -0800138 template <typename T>
139 struct get_type_of {
140 static_assert(is_item_type<T>::value);
141 static constexpr inline Type value =
142 std::is_same<T, int32_t>::value ? kTypeInt32
143 : std::is_same<T, int64_t>::value ? kTypeInt64
144 : std::is_same<T, double>::value ? kTypeDouble
145 : std::is_same<T, std::pair<int64_t, int64_t>>:: value ? kTypeRate
146 : std::is_same<T, std::string>::value ? kTypeCString
147 : std::is_same<T, std::monostate>::value ? kTypeNone
148 : kTypeNone;
149 };
150
151 template <typename T>
152 static size_t sizeOfByteString(const char *name, const T& value) {
153 static_assert(is_item_type<T>::value);
Andy Hung1efc9c62019-12-03 13:43:33 -0800154 return 2 + 1 + strlen(name) + 1 + sizeof(value);
155 }
Andy Hungb7aadb32019-12-09 19:40:42 -0800156 template <> // static
157 size_t sizeOfByteString(const char *name, const std::string& value) {
158 return 2 + 1 + strlen(name) + 1 + value.size() + 1;
Andy Hung1efc9c62019-12-03 13:43:33 -0800159 }
Andy Hungb7aadb32019-12-09 19:40:42 -0800160 template <> // static
161 size_t sizeOfByteString(const char *name, const std::monostate&) {
Andy Hung1efc9c62019-12-03 13:43:33 -0800162 return 2 + 1 + strlen(name) + 1;
163 }
Andy Hungb7aadb32019-12-09 19:40:42 -0800164 // for speed
165 static size_t sizeOfByteString(const char *name, const char *value) {
166 return 2 + 1 + strlen(name) + 1 + strlen(value) + 1;
167 }
168
169 template <typename T>
170 static status_t insert(const T& val, char **bufferpptr, char *bufferptrmax) {
171 static_assert(std::is_trivially_constructible<T>::value);
172 const size_t size = sizeof(val);
173 if (*bufferpptr + size > bufferptrmax) {
174 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
175 return BAD_VALUE;
176 }
177 memcpy(*bufferpptr, &val, size);
178 *bufferpptr += size;
179 return NO_ERROR;
180 }
181 template <> // static
182 status_t insert(const std::string& val, char **bufferpptr, char *bufferptrmax) {
183 const size_t size = val.size() + 1;
184 if (size > UINT16_MAX || *bufferpptr + size > bufferptrmax) {
185 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
186 return BAD_VALUE;
187 }
188 memcpy(*bufferpptr, val.c_str(), size);
189 *bufferpptr += size;
190 return NO_ERROR;
191 }
192 template <> // static
193 status_t insert(const std::pair<int64_t, int64_t>& val,
194 char **bufferpptr, char *bufferptrmax) {
195 const size_t size = sizeof(val.first) + sizeof(val.second);
196 if (*bufferpptr + size > bufferptrmax) {
197 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
198 return BAD_VALUE;
199 }
200 memcpy(*bufferpptr, &val.first, sizeof(val.first));
201 memcpy(*bufferpptr + sizeof(val.first), &val.second, sizeof(val.second));
202 *bufferpptr += size;
203 return NO_ERROR;
204 }
205 template <> // static
206 status_t insert(const std::monostate&, char **, char *) {
207 return NO_ERROR;
208 }
209 // for speed
210 static status_t insert(const char *val, char **bufferpptr, char *bufferptrmax) {
211 const size_t size = strlen(val) + 1;
212 if (size > UINT16_MAX || *bufferpptr + size > bufferptrmax) {
213 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
214 return BAD_VALUE;
215 }
216 memcpy(*bufferpptr, val, size);
217 *bufferpptr += size;
218 return NO_ERROR;
219 }
220
221 template <typename T>
222 static status_t writeToByteString(
223 const char *name, const T& value, char **bufferpptr, char *bufferptrmax) {
224 static_assert(is_item_type<T>::value);
225 const size_t len = sizeOfByteString(name, value);
226 if (len > UINT16_MAX) return BAD_VALUE;
227 return insert((uint16_t)len, bufferpptr, bufferptrmax)
228 ?: insert((uint8_t)get_type_of<T>::value, bufferpptr, bufferptrmax)
229 ?: insert(name, bufferpptr, bufferptrmax)
230 ?: insert(value, bufferpptr, bufferptrmax);
231 }
232 // for speed
233 static status_t writeToByteString(
234 const char *name, const char *value, char **bufferpptr, char *bufferptrmax) {
235 const size_t len = sizeOfByteString(name, value);
236 if (len > UINT16_MAX) return BAD_VALUE;
237 return insert((uint16_t)len, bufferpptr, bufferptrmax)
238 ?: insert((uint8_t)kTypeCString, bufferpptr, bufferptrmax)
239 ?: insert(name, bufferpptr, bufferptrmax)
240 ?: insert(value, bufferpptr, bufferptrmax);
241 }
242
243 template <typename T>
244 static void toStringBuffer(
245 const char *name, const T& value, char *buffer, size_t length) = delete;
246 template <> // static
247 void toStringBuffer(
248 const char *name, const int32_t& value, char *buffer, size_t length) {
249 snprintf(buffer, length, "%s=%d:", name, value);
250 }
251 template <> // static
252 void toStringBuffer(
253 const char *name, const int64_t& value, char *buffer, size_t length) {
254 snprintf(buffer, length, "%s=%lld:", name, (long long)value);
255 }
256 template <> // static
257 void toStringBuffer(
258 const char *name, const double& value, char *buffer, size_t length) {
259 snprintf(buffer, length, "%s=%e:", name, value);
260 }
261 template <> // static
262 void toStringBuffer(
263 const char *name, const std::pair<int64_t, int64_t>& value,
264 char *buffer, size_t length) {
265 snprintf(buffer, length, "%s=%lld/%lld:",
266 name, (long long)value.first, (long long)value.second);
267 }
268 template <> // static
269 void toStringBuffer(
270 const char *name, const std::string& value, char *buffer, size_t length) {
271 // TODO sanitize string for ':' '='
272 snprintf(buffer, length, "%s=%s:", name, value.c_str());
273 }
274 template <> // static
275 void toStringBuffer(
276 const char *name, const std::monostate&, char *buffer, size_t length) {
277 snprintf(buffer, length, "%s=():", name);
278 }
279
280 template <typename T>
281 static status_t writeToParcel(
282 const char *name, const T& value, Parcel *parcel) = delete;
283 template <> // static
284 status_t writeToParcel(
285 const char *name, const int32_t& value, Parcel *parcel) {
286 return parcel->writeCString(name)
287 ?: parcel->writeInt32(get_type_of<int32_t>::value)
288 ?: parcel->writeInt32(value);
289 }
290 template <> // static
291 status_t writeToParcel(
292 const char *name, const int64_t& value, Parcel *parcel) {
293 return parcel->writeCString(name)
294 ?: parcel->writeInt32(get_type_of<int64_t>::value)
295 ?: parcel->writeInt64(value);
296 }
297 template <> // static
298 status_t writeToParcel(
299 const char *name, const double& value, Parcel *parcel) {
300 return parcel->writeCString(name)
301 ?: parcel->writeInt32(get_type_of<double>::value)
302 ?: parcel->writeDouble(value);
303 }
304 template <> // static
305 status_t writeToParcel(
306 const char *name, const std::pair<int64_t, int64_t>& value, Parcel *parcel) {
307 return parcel->writeCString(name)
308 ?: parcel->writeInt32(get_type_of< std::pair<int64_t, int64_t>>::value)
309 ?: parcel->writeInt64(value.first)
310 ?: parcel->writeInt64(value.second);
311 }
312 template <> // static
313 status_t writeToParcel(
314 const char *name, const std::string& value, Parcel *parcel) {
315 return parcel->writeCString(name)
316 ?: parcel->writeInt32(get_type_of<std::string>::value)
317 ?: parcel->writeCString(value.c_str());
318 }
319 template <> // static
320 status_t writeToParcel(
321 const char *name, const std::monostate&, Parcel *parcel) {
322 return parcel->writeCString(name)
323 ?: parcel->writeInt32(get_type_of<std::monostate>::value);
324 }
325
326 template <typename T>
327 static status_t extract(T *val, const char **bufferpptr, const char *bufferptrmax) {
328 static_assert(std::is_trivially_constructible<T>::value);
329 const size_t size = sizeof(*val);
330 if (*bufferpptr + size > bufferptrmax) {
331 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
332 return BAD_VALUE;
333 }
334 memcpy(val, *bufferpptr, size);
335 *bufferpptr += size;
336 return NO_ERROR;
337 }
338 template <> // static
339 status_t extract(std::string *val, const char **bufferpptr, const char *bufferptrmax) {
340 const char *ptr = *bufferpptr;
341 while (*ptr != 0) {
342 if (ptr >= bufferptrmax) {
343 ALOGE("%s: buffer exceeded", __func__);
344 return BAD_VALUE;
345 }
346 ++ptr;
347 }
348 const size_t size = (ptr - *bufferpptr) + 1;
349 *val = *bufferpptr;
350 *bufferpptr += size;
351 return NO_ERROR;
352 }
353 template <> // static
354 status_t extract(std::pair<int64_t, int64_t> *val,
355 const char **bufferpptr, const char *bufferptrmax) {
356 const size_t size = sizeof(val->first) + sizeof(val->second);
357 if (*bufferpptr + size > bufferptrmax) {
358 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
359 return BAD_VALUE;
360 }
361 memcpy(&val->first, *bufferpptr, sizeof(val->first));
362 memcpy(&val->second, *bufferpptr + sizeof(val->first), sizeof(val->second));
363 *bufferpptr += size;
364 return NO_ERROR;
365 }
366 template <> // static
367 status_t extract(std::monostate *, const char **, const char *) {
368 return NO_ERROR;
369 }
Andy Hung1efc9c62019-12-03 13:43:33 -0800370};
371
372/**
373 * Media Metrics BufferedItem
374 *
375 * A base class which represents a put-only Media Metrics item, storing
376 * the Media Metrics data in a buffer with begin and end pointers.
377 *
378 * If a property key is entered twice, it will be stored in the buffer twice,
379 * and (implementation defined) the last value for that key will be used
380 * by the Media Metrics service.
381 *
382 * For realloc, a baseRealloc pointer must be passed in either explicitly
383 * or implicitly in the constructor. This will be updated with the value used on realloc.
384 */
385class BufferedItem : public BaseItem {
386public:
387 static inline constexpr uint16_t kVersion = 0;
388
389 virtual ~BufferedItem() = default;
390 BufferedItem(const BufferedItem&) = delete;
391 BufferedItem& operator=(const BufferedItem&) = delete;
392
393 BufferedItem(const std::string key, char *begin, char *end)
394 : BufferedItem(key.c_str(), begin, end) { }
395
396 BufferedItem(const char *key, char *begin, char *end)
397 : BufferedItem(key, begin, end, nullptr) { }
398
399 BufferedItem(const char *key, char **begin, char *end)
400 : BufferedItem(key, *begin, end, begin) { }
401
402 BufferedItem(const char *key, char *begin, char *end, char **baseRealloc)
403 : mBegin(begin)
404 , mEnd(end)
405 , mBaseRealloc(baseRealloc)
406 {
407 init(key);
408 }
409
410 template<typename T>
411 BufferedItem &set(const char *key, const T& value) {
412 reallocFor(sizeOfByteString(key, value));
413 if (mStatus == NO_ERROR) {
414 mStatus = BaseItem::writeToByteString(key, value, &mBptr, mEnd);
415 ++mPropCount;
416 }
417 return *this;
418 }
419
420 template<typename T>
421 BufferedItem &set(const std::string& key, const T& value) {
422 return set(key.c_str(), value);
423 }
424
425 BufferedItem &setPid(pid_t pid) {
426 if (mStatus == NO_ERROR) {
427 copyTo(mBegin + mHeaderLen - 16, (int32_t)pid);
428 }
429 return *this;
430 }
431
432 BufferedItem &setUid(uid_t uid) {
433 if (mStatus == NO_ERROR) {
434 copyTo(mBegin + mHeaderLen - 12, (int32_t)uid);
435 }
436 return *this;
437 }
438
439 BufferedItem &setTimestamp(nsecs_t timestamp) {
440 if (mStatus == NO_ERROR) {
441 copyTo(mBegin + mHeaderLen - 8, (int64_t)timestamp);
442 }
443 return *this;
444 }
445
446 bool record() {
447 return updateHeader()
448 && BaseItem::submitBuffer(getBuffer(), getLength());
449 }
450
451 bool isValid () const {
452 return mStatus == NO_ERROR;
453 }
454
455 char *getBuffer() const { return mBegin; }
456 size_t getLength() const { return mBptr - mBegin; }
457 size_t getRemaining() const { return mEnd - mBptr; }
458 size_t getCapacity() const { return mEnd - mBegin; }
459
460 bool updateHeader() {
461 if (mStatus != NO_ERROR) return false;
462 copyTo(mBegin + 0, (uint32_t)getLength());
463 copyTo(mBegin + 4, (uint32_t)mHeaderLen);
464 copyTo(mBegin + mHeaderLen, (uint32_t)mPropCount);
465 return true;
466 }
467
468protected:
469 BufferedItem() = default;
470
471 void reallocFor(size_t required) {
472 if (mStatus != NO_ERROR) return;
473 const size_t remaining = getRemaining();
474 if (required <= remaining) return;
475 if (mBaseRealloc == nullptr) {
476 mStatus = NO_MEMORY;
477 return;
478 }
479
480 const size_t current = getLength();
481 size_t minimum = current + required;
482 if (minimum > SSIZE_MAX >> 1) {
483 mStatus = NO_MEMORY;
484 return;
485 }
486 minimum <<= 1;
487 void *newptr = realloc(*mBaseRealloc, minimum);
488 if (newptr == nullptr) {
489 mStatus = NO_MEMORY;
490 return;
491 }
492 if (newptr != *mBaseRealloc) {
493 // ALOGD("base changed! current:%zu new size %zu", current, minimum);
494 if (*mBaseRealloc == nullptr) {
495 memcpy(newptr, mBegin, current);
496 }
497 mBegin = (char *)newptr;
498 *mBaseRealloc = mBegin;
499 mEnd = mBegin + minimum;
500 mBptr = mBegin + current;
501 } else {
502 // ALOGD("base kept! current:%zu new size %zu", current, minimum);
503 mEnd = mBegin + minimum;
504 }
505 }
506 template<typename T>
507 void copyTo(char *ptr, const T& value) {
508 memcpy(ptr, &value, sizeof(value));
509 }
510
511 void init(const char *key) {
512 mBptr = mBegin;
513 const size_t keylen = strlen(key) + 1;
514 mHeaderLen = 4 + 4 + 2 + 2 + keylen + 4 + 4 + 8;
515 reallocFor(mHeaderLen);
516 if (mStatus != NO_ERROR) return;
517 mBptr = mBegin + mHeaderLen + 4; // this includes propcount.
518
519 if (mEnd < mBptr || keylen > UINT16_MAX) {
520 mStatus = NO_MEMORY;
521 mBptr = mEnd;
522 return;
523 }
524 copyTo(mBegin + 8, kVersion);
525 copyTo(mBegin + 10, (uint16_t)keylen);
526 strcpy(mBegin + 12, key);
527
528 // initialize some parameters (that could be overridden)
529 setPid(-1);
530 setUid(-1);
531 setTimestamp(0);
532 }
533
534 char *mBegin = nullptr;
535 char *mEnd = nullptr;
536 char **mBaseRealloc = nullptr; // set to an address if realloc should be done.
537 // upon return, that pointer is updated with
538 // whatever needs to be freed.
539 char *mBptr = nullptr;
540 status_t mStatus = NO_ERROR;
541 uint32_t mPropCount = 0;
542 uint32_t mHeaderLen = 0;
543};
544
545/**
Andy Hung47e58d62019-12-06 18:40:19 -0800546 * MediaMetrics LogItem is a stack allocated mediametrics item used for
Andy Hung1efc9c62019-12-03 13:43:33 -0800547 * fast logging. It falls over to a malloc if needed.
548 *
549 * This is templated with a buffer size to allocate on the stack.
550 */
551template <size_t N = 4096>
Ray Essickf27e9872019-12-07 06:28:46 -0800552class LogItem : public BufferedItem {
Andy Hung1efc9c62019-12-03 13:43:33 -0800553public:
Ray Essickf27e9872019-12-07 06:28:46 -0800554 explicit LogItem(const std::string key) : LogItem(key.c_str()) { }
Andy Hung1efc9c62019-12-03 13:43:33 -0800555
556 // Since this class will not be defined before the base class, we initialize variables
557 // in our own order.
Ray Essickf27e9872019-12-07 06:28:46 -0800558 explicit LogItem(const char *key) {
Andy Hung1efc9c62019-12-03 13:43:33 -0800559 mBegin = mBuffer;
560 mEnd = mBuffer + N;
561 mBaseRealloc = &mReallocPtr;
562 init(key);
563 }
564
Ray Essickf27e9872019-12-07 06:28:46 -0800565 ~LogItem() override {
Andy Hung1efc9c62019-12-03 13:43:33 -0800566 if (mReallocPtr != nullptr) { // do the check before calling free to avoid overhead.
567 free(mReallocPtr);
568 }
569 }
570
571private:
572 char *mReallocPtr = nullptr; // set non-null by base class if realloc happened.
573 char mBuffer[N];
574};
575
Andy Hung1efc9c62019-12-03 13:43:33 -0800576
Andy Hung3253f2d2019-10-21 14:50:07 -0700577/**
Ray Essickf27e9872019-12-07 06:28:46 -0800578 * Media Metrics Item
Andy Hung3253f2d2019-10-21 14:50:07 -0700579 *
580 * A mutable item representing an event or record that will be
Andy Hung1efc9c62019-12-03 13:43:33 -0800581 * logged with the Media Metrics service. For client logging, one should
582 * use the mediametrics::Item.
Andy Hung3253f2d2019-10-21 14:50:07 -0700583 *
Ray Essickf27e9872019-12-07 06:28:46 -0800584 * The Item is designed for the service as it has getters.
Andy Hung3253f2d2019-10-21 14:50:07 -0700585 */
Ray Essickf27e9872019-12-07 06:28:46 -0800586class Item : public mediametrics::BaseItem {
Andy Hungaeef7882019-10-18 15:18:14 -0700587public:
Ray Essick3938dc62016-11-01 08:56:56 -0700588
Ray Essickf65f4212017-08-31 11:41:19 -0700589 enum {
590 PROTO_V0 = 0,
591 PROTO_FIRST = PROTO_V0,
592 PROTO_V1 = 1,
593 PROTO_LAST = PROTO_V1,
594 };
595
Andy Hungaeef7882019-10-18 15:18:14 -0700596 // T must be convertible to mKey
597 template <typename T>
Ray Essickf27e9872019-12-07 06:28:46 -0800598 explicit Item(T key)
Andy Hungaeef7882019-10-18 15:18:14 -0700599 : mKey(key) { }
Ray Essickf27e9872019-12-07 06:28:46 -0800600 Item() = default;
Andy Hung3253f2d2019-10-21 14:50:07 -0700601
Ray Essickf27e9872019-12-07 06:28:46 -0800602 bool operator==(const Item& other) const {
Andy Hung47e58d62019-12-06 18:40:19 -0800603 if (mPid != other.mPid
Andy Hung3253f2d2019-10-21 14:50:07 -0700604 || mUid != other.mUid
605 || mPkgName != other.mPkgName
606 || mPkgVersionCode != other.mPkgVersionCode
607 || mKey != other.mKey
Andy Hung47e58d62019-12-06 18:40:19 -0800608 || mTimestamp != other.mTimestamp
609 || mProps != other.mProps) return false;
Andy Hung3253f2d2019-10-21 14:50:07 -0700610 return true;
611 }
Ray Essickf27e9872019-12-07 06:28:46 -0800612 bool operator!=(const Item& other) const {
Andy Hung3253f2d2019-10-21 14:50:07 -0700613 return !(*this == other);
614 }
615
616 template <typename T>
Ray Essickf27e9872019-12-07 06:28:46 -0800617 static Item* create(T key) {
618 return new Item(key);
Andy Hung3253f2d2019-10-21 14:50:07 -0700619 }
Ray Essickf27e9872019-12-07 06:28:46 -0800620 static Item* create() {
621 return new Item();
Andy Hung3253f2d2019-10-21 14:50:07 -0700622 }
Ray Essickba8c4842019-01-18 11:35:33 -0800623
Ray Essickf27e9872019-12-07 06:28:46 -0800624 static Item* convert(mediametrics_handle_t);
625 static mediametrics_handle_t convert(Item *);
Ray Essickbf536ac2019-08-26 11:04:28 -0700626
Ray Essick3938dc62016-11-01 08:56:56 -0700627 // access functions for the class
Ray Essickf27e9872019-12-07 06:28:46 -0800628 ~Item();
Ray Essick3938dc62016-11-01 08:56:56 -0700629
Andy Hung47e58d62019-12-06 18:40:19 -0800630 void clear() {
631 mPid = -1;
632 mUid = -1;
633 mPkgName.clear();
634 mPkgVersionCode = 0;
635 mTimestamp = 0;
636 mKey.clear();
637 mProps.clear();
638 }
639
640 Item *dup() const { return new Item(*this); }
Ray Essick3938dc62016-11-01 08:56:56 -0700641
Ray Essickf27e9872019-12-07 06:28:46 -0800642 Item &setKey(const char *key) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700643 mKey = key;
644 return *this;
645 }
646 const std::string& getKey() const { return mKey; }
Ray Essick3938dc62016-11-01 08:56:56 -0700647
Andy Hung3253f2d2019-10-21 14:50:07 -0700648 // # of properties in the record
Andy Hung47e58d62019-12-06 18:40:19 -0800649 size_t count() const { return mProps.size(); }
Ray Essick3938dc62016-11-01 08:56:56 -0700650
Andy Hungaeef7882019-10-18 15:18:14 -0700651 template<typename S, typename T>
Ray Essickf27e9872019-12-07 06:28:46 -0800652 Item &set(S key, T value) {
Andy Hung47e58d62019-12-06 18:40:19 -0800653 findOrAllocateProp(key).set(value);
Andy Hungaeef7882019-10-18 15:18:14 -0700654 return *this;
655 }
Ray Essick3938dc62016-11-01 08:56:56 -0700656
Andy Hungaeef7882019-10-18 15:18:14 -0700657 // set values appropriately
Ray Essickf27e9872019-12-07 06:28:46 -0800658 Item &setInt32(const char *key, int32_t value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700659 return set(key, value);
660 }
Ray Essickf27e9872019-12-07 06:28:46 -0800661 Item &setInt64(const char *key, int64_t value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700662 return set(key, value);
663 }
Ray Essickf27e9872019-12-07 06:28:46 -0800664 Item &setDouble(const char *key, double value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700665 return set(key, value);
666 }
Ray Essickf27e9872019-12-07 06:28:46 -0800667 Item &setRate(const char *key, int64_t count, int64_t duration) {
Andy Hungaeef7882019-10-18 15:18:14 -0700668 return set(key, std::make_pair(count, duration));
669 }
Ray Essickf27e9872019-12-07 06:28:46 -0800670 Item &setCString(const char *key, const char *value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700671 return set(key, value);
672 }
Ray Essick3938dc62016-11-01 08:56:56 -0700673
Andy Hungaeef7882019-10-18 15:18:14 -0700674 // fused get/add/set; if attr wasn't there, it's a simple set.
675 // type-mismatch counts as "wasn't there".
676 template<typename S, typename T>
Ray Essickf27e9872019-12-07 06:28:46 -0800677 Item &add(S key, T value) {
Andy Hung47e58d62019-12-06 18:40:19 -0800678 findOrAllocateProp(key).add(value);
Andy Hungaeef7882019-10-18 15:18:14 -0700679 return *this;
680 }
681
Ray Essickf27e9872019-12-07 06:28:46 -0800682 Item &addInt32(const char *key, int32_t value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700683 return add(key, value);
684 }
Ray Essickf27e9872019-12-07 06:28:46 -0800685 Item &addInt64(const char *key, int64_t value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700686 return add(key, value);
687 }
Ray Essickf27e9872019-12-07 06:28:46 -0800688 Item &addDouble(const char *key, double value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700689 return add(key, value);
690 }
Ray Essickf27e9872019-12-07 06:28:46 -0800691 Item &addRate(const char *key, int64_t count, int64_t duration) {
Andy Hungaeef7882019-10-18 15:18:14 -0700692 return add(key, std::make_pair(count, duration));
693 }
694
695 // find & extract values
696 // return indicates whether attr exists (and thus value filled in)
697 // NULL parameter value suppresses storage of value.
698 template<typename S, typename T>
699 bool get(S key, T *value) const {
Andy Hung47e58d62019-12-06 18:40:19 -0800700 const Prop *prop = findProp(key);
Andy Hungaeef7882019-10-18 15:18:14 -0700701 return prop != nullptr && prop->get(value);
702 }
703
Andy Hung3253f2d2019-10-21 14:50:07 -0700704 bool getInt32(const char *key, int32_t *value) const {
Andy Hungaeef7882019-10-18 15:18:14 -0700705 return get(key, value);
706 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700707 bool getInt64(const char *key, int64_t *value) const {
Andy Hungaeef7882019-10-18 15:18:14 -0700708 return get(key, value);
709 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700710 bool getDouble(const char *key, double *value) const {
Andy Hungaeef7882019-10-18 15:18:14 -0700711 return get(key, value);
712 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700713 bool getRate(const char *key, int64_t *count, int64_t *duration, double *rate) const {
Andy Hungaeef7882019-10-18 15:18:14 -0700714 std::pair<int64_t, int64_t> value;
715 if (!get(key, &value)) return false;
716 if (count != nullptr) *count = value.first;
717 if (duration != nullptr) *duration = value.second;
718 if (rate != nullptr) {
719 if (value.second != 0) {
720 *rate = (double)value.first / value.second; // TODO: isn't INF OK?
721 } else {
722 *rate = 0.;
723 }
724 }
725 return true;
726 }
727 // Caller owns the returned string
Andy Hung3253f2d2019-10-21 14:50:07 -0700728 bool getCString(const char *key, char **value) const {
Andy Hungb7aadb32019-12-09 19:40:42 -0800729 std::string s;
730 if (get(key, &s)) {
731 *value = strdup(s.c_str());
Andy Hung3253f2d2019-10-21 14:50:07 -0700732 return true;
733 }
734 return false;
Andy Hungaeef7882019-10-18 15:18:14 -0700735 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700736 bool getString(const char *key, std::string *value) const {
Andy Hungaeef7882019-10-18 15:18:14 -0700737 return get(key, value);
738 }
Ray Essick3938dc62016-11-01 08:56:56 -0700739
Andy Hunga87e69c2019-10-18 10:07:40 -0700740 // Deliver the item to MediaMetrics
Ray Essick3938dc62016-11-01 08:56:56 -0700741 bool selfrecord();
742
Andy Hung3253f2d2019-10-21 14:50:07 -0700743 // remove indicated attributes and their values
744 // filterNot() could also be called keepOnly()
745 // return value is # attributes removed
746 // XXX: perhaps 'remove' instead of 'filter'
747 // XXX: filterNot would become 'keep'
748 size_t filter(size_t count, const char *attrs[]);
749 size_t filterNot(size_t count, const char *attrs[]);
750 size_t filter(const char *attr) { return filter(1, &attr); }
Ray Essick3938dc62016-11-01 08:56:56 -0700751
752 // below here are used on server side or to talk to server
753 // clients need not worry about these.
754
755 // timestamp, pid, and uid only used on server side
Ray Essickb5fac8e2016-12-12 11:33:56 -0800756 // timestamp is in 'nanoseconds, unix time'
Ray Essickf27e9872019-12-07 06:28:46 -0800757 Item &setTimestamp(nsecs_t);
Ray Essick3938dc62016-11-01 08:56:56 -0700758 nsecs_t getTimestamp() const;
759
Ray Essickf27e9872019-12-07 06:28:46 -0800760 Item &setPid(pid_t);
Ray Essick3938dc62016-11-01 08:56:56 -0700761 pid_t getPid() const;
762
Ray Essickf27e9872019-12-07 06:28:46 -0800763 Item &setUid(uid_t);
Ray Essick3938dc62016-11-01 08:56:56 -0700764 uid_t getUid() const;
765
Ray Essickf27e9872019-12-07 06:28:46 -0800766 Item &setPkgName(const std::string &pkgName);
Ray Essick783bd0d2018-01-11 11:10:35 -0800767 std::string getPkgName() const { return mPkgName; }
Ray Essickf65f4212017-08-31 11:41:19 -0700768
Ray Essickf27e9872019-12-07 06:28:46 -0800769 Item &setPkgVersionCode(int64_t);
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800770 int64_t getPkgVersionCode() const;
Ray Essickf65f4212017-08-31 11:41:19 -0700771
Andy Hung3253f2d2019-10-21 14:50:07 -0700772 // our serialization code for binder calls
773 status_t writeToParcel(Parcel *) const;
774 status_t readFromParcel(const Parcel&);
Ray Essick3938dc62016-11-01 08:56:56 -0700775
Andy Hung3253f2d2019-10-21 14:50:07 -0700776 status_t writeToByteString(char **bufferptr, size_t *length) const;
777 status_t readFromByteString(const char *bufferptr, size_t length);
778
Ray Essickba8c4842019-01-18 11:35:33 -0800779
Andy Hung17dbaf22019-10-11 14:06:31 -0700780 std::string toString() const;
781 std::string toString(int version) const;
Ray Essick20147322018-11-17 09:08:39 -0800782 const char *toCString();
783 const char *toCString(int version);
Ray Essick3938dc62016-11-01 08:56:56 -0700784
Andy Hung3253f2d2019-10-21 14:50:07 -0700785private:
786 // handle Parcel version 0
787 int32_t writeToParcel0(Parcel *) const;
788 int32_t readFromParcel0(const Parcel&);
789
Andy Hung3253f2d2019-10-21 14:50:07 -0700790public:
Andy Hungb7aadb32019-12-09 19:40:42 -0800791
Andy Hungaeef7882019-10-18 15:18:14 -0700792 class Prop {
Andy Hungaeef7882019-10-18 15:18:14 -0700793 public:
Andy Hungb7aadb32019-12-09 19:40:42 -0800794 using Elem = std::variant<
795 std::monostate, // kTypeNone
796 int32_t, // kTypeInt32
797 int64_t, // kTypeInt64
798 double, // kTypeDouble
799 std::string, // kTypeCString
800 std::pair<int64_t, int64_t> // kTypeRate
801 >;
802
Andy Hungaeef7882019-10-18 15:18:14 -0700803 Prop() = default;
804 Prop(const Prop& other) {
805 *this = other;
806 }
807 Prop& operator=(const Prop& other) {
Andy Hung47e58d62019-12-06 18:40:19 -0800808 mName = other.mName;
Andy Hungb7aadb32019-12-09 19:40:42 -0800809 mElem = other.mElem;
Andy Hungaeef7882019-10-18 15:18:14 -0700810 return *this;
811 }
Andy Hung47e58d62019-12-06 18:40:19 -0800812 Prop(Prop&& other) {
813 *this = std::move(other);
814 }
815 Prop& operator=(Prop&& other) {
816 mName = std::move(other.mName);
Andy Hungb7aadb32019-12-09 19:40:42 -0800817 mElem = std::move(other.mElem);
Andy Hung47e58d62019-12-06 18:40:19 -0800818 return *this;
819 }
820
Andy Hung3253f2d2019-10-21 14:50:07 -0700821 bool operator==(const Prop& other) const {
Andy Hungb7aadb32019-12-09 19:40:42 -0800822 return mName == other.mName && mElem == other.mElem;
Andy Hung3253f2d2019-10-21 14:50:07 -0700823 }
824 bool operator!=(const Prop& other) const {
825 return !(*this == other);
826 }
Ray Essick3938dc62016-11-01 08:56:56 -0700827
Andy Hungaeef7882019-10-18 15:18:14 -0700828 void clear() {
Andy Hung47e58d62019-12-06 18:40:19 -0800829 mName.clear();
Andy Hungb7aadb32019-12-09 19:40:42 -0800830 mElem = std::monostate{};
Andy Hungaeef7882019-10-18 15:18:14 -0700831 }
832 void clearValue() {
Andy Hungb7aadb32019-12-09 19:40:42 -0800833 mElem = std::monostate{};
Andy Hungaeef7882019-10-18 15:18:14 -0700834 }
Ray Essick3938dc62016-11-01 08:56:56 -0700835
Andy Hungaeef7882019-10-18 15:18:14 -0700836 const char *getName() const {
Andy Hung47e58d62019-12-06 18:40:19 -0800837 return mName.c_str();
Andy Hungaeef7882019-10-18 15:18:14 -0700838 }
Ray Essick3938dc62016-11-01 08:56:56 -0700839
Andy Hungaeef7882019-10-18 15:18:14 -0700840 void swap(Prop& other) {
841 std::swap(mName, other.mName);
Andy Hungb7aadb32019-12-09 19:40:42 -0800842 std::swap(mElem, other.mElem);
Andy Hungaeef7882019-10-18 15:18:14 -0700843 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800844
Andy Hung3253f2d2019-10-21 14:50:07 -0700845 void setName(const char *name) {
Andy Hung47e58d62019-12-06 18:40:19 -0800846 mName = name;
Andy Hungaeef7882019-10-18 15:18:14 -0700847 }
848
Andy Hungaeef7882019-10-18 15:18:14 -0700849 bool isNamed(const char *name) const {
Andy Hung47e58d62019-12-06 18:40:19 -0800850 return mName == name;
Andy Hung1efc9c62019-12-03 13:43:33 -0800851 }
852
853 template <typename T> void visit(T f) const {
Andy Hungb7aadb32019-12-09 19:40:42 -0800854 std::visit(f, mElem);
855 }
856
857 template <typename T> bool get(T *value) const {
858 auto pval = std::get_if<T>(&mElem);
859 if (pval != nullptr) {
860 *value = *pval;
861 return true;
862 }
863 return false;
864 }
865
866 template <typename T> void set(const T& value) {
867 mElem = value;
868 }
869
870 template <typename T> void add(const T& value) {
871 auto pval = std::get_if<T>(&mElem);
872 if (pval != nullptr) {
873 *pval += value;
874 } else {
875 mElem = value;
Andy Hung1efc9c62019-12-03 13:43:33 -0800876 }
Andy Hungaeef7882019-10-18 15:18:14 -0700877 }
878
Andy Hungb7aadb32019-12-09 19:40:42 -0800879 template <> void add(const std::pair<int64_t, int64_t>& value) {
880 auto pval = std::get_if<std::pair<int64_t, int64_t>>(&mElem);
881 if (pval != nullptr) {
882 pval->first += value.first;
883 pval->second += value.second;
Andy Hungaeef7882019-10-18 15:18:14 -0700884 } else {
Andy Hungb7aadb32019-12-09 19:40:42 -0800885 mElem = value;
Andy Hungaeef7882019-10-18 15:18:14 -0700886 }
887 }
888
Andy Hungb7aadb32019-12-09 19:40:42 -0800889 status_t writeToParcel(Parcel *parcel) const {
890 return std::visit([this, parcel](auto &value) {
891 return BaseItem::writeToParcel(mName.c_str(), value, parcel);}, mElem);
892 }
893
894 void toStringBuffer(char *buffer, size_t length) const {
895 return std::visit([this, buffer, length](auto &value) {
896 BaseItem::toStringBuffer(mName.c_str(), value, buffer, length);}, mElem);
897 }
898
899 size_t getByteStringSize() const {
900 return std::visit([this](auto &value) {
901 return BaseItem::sizeOfByteString(mName.c_str(), value);}, mElem);
902 }
903
904 status_t writeToByteString(char **bufferpptr, char *bufferptrmax) const {
905 return std::visit([this, bufferpptr, bufferptrmax](auto &value) {
906 return BaseItem::writeToByteString(mName.c_str(), value, bufferpptr, bufferptrmax);
907 }, mElem);
908 }
909
Andy Hung3253f2d2019-10-21 14:50:07 -0700910 status_t readFromParcel(const Parcel& data);
Andy Hungb7aadb32019-12-09 19:40:42 -0800911
Andy Hung3253f2d2019-10-21 14:50:07 -0700912 status_t readFromByteString(const char **bufferpptr, const char *bufferptrmax);
Andy Hungaeef7882019-10-18 15:18:14 -0700913
Andy Hung47e58d62019-12-06 18:40:19 -0800914 private:
915 std::string mName;
Andy Hungb7aadb32019-12-09 19:40:42 -0800916 Elem mElem;
Andy Hungaeef7882019-10-18 15:18:14 -0700917 };
918
Andy Hung47e58d62019-12-06 18:40:19 -0800919 // Iteration of props within item
Andy Hung3253f2d2019-10-21 14:50:07 -0700920 class iterator {
921 public:
Andy Hung47e58d62019-12-06 18:40:19 -0800922 iterator(const std::map<std::string, Prop>::const_iterator &_it) : it(_it) { }
923 iterator &operator++() {
924 ++it;
925 return *this;
926 }
927 bool operator!=(iterator &other) const {
928 return it != other.it;
929 }
930 const Prop &operator*() const {
931 return it->second;
932 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700933
934 private:
Andy Hung47e58d62019-12-06 18:40:19 -0800935 std::map<std::string, Prop>::const_iterator it;
Andy Hung3253f2d2019-10-21 14:50:07 -0700936 };
937
938 iterator begin() const {
Andy Hung47e58d62019-12-06 18:40:19 -0800939 return iterator(mProps.cbegin());
Andy Hung3253f2d2019-10-21 14:50:07 -0700940 }
Andy Hung47e58d62019-12-06 18:40:19 -0800941
Andy Hung3253f2d2019-10-21 14:50:07 -0700942 iterator end() const {
Andy Hung47e58d62019-12-06 18:40:19 -0800943 return iterator(mProps.cend());
Andy Hung3253f2d2019-10-21 14:50:07 -0700944 }
945
946private:
947
Andy Hung47e58d62019-12-06 18:40:19 -0800948 const Prop *findProp(const char *key) const {
949 auto it = mProps.find(key);
950 return it != mProps.end() ? &it->second : nullptr;
951 }
Andy Hungaeef7882019-10-18 15:18:14 -0700952
Andy Hung47e58d62019-12-06 18:40:19 -0800953 Prop &findOrAllocateProp(const char *key) {
954 auto it = mProps.find(key);
955 if (it != mProps.end()) return it->second;
956 Prop &prop = mProps[key];
957 prop.setName(key);
958 return prop;
959 }
Andy Hungaeef7882019-10-18 15:18:14 -0700960
961 pid_t mPid = -1;
962 uid_t mUid = -1;
963 std::string mPkgName;
964 int64_t mPkgVersionCode = 0;
Andy Hung47e58d62019-12-06 18:40:19 -0800965 std::string mKey;
Andy Hungaeef7882019-10-18 15:18:14 -0700966 nsecs_t mTimestamp = 0;
Andy Hung47e58d62019-12-06 18:40:19 -0800967 std::map<std::string, Prop> mProps;
Ray Essick3938dc62016-11-01 08:56:56 -0700968};
969
Ray Essickf27e9872019-12-07 06:28:46 -0800970} // namespace mediametrics
Ray Essick3938dc62016-11-01 08:56:56 -0700971} // namespace android
972
Andy Hung47e58d62019-12-06 18:40:19 -0800973#endif // ANDROID_MEDIA_MEDIAMETRICSITEM_H