blob: 5765dc55567c45e6275d727c32e86442b71f3e72 [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 Hung611268d2019-12-19 13:54:02 -080044 * The MediaMetrics Item allows get/set operations and recording to the service.
45 *
46 * The MediaMetrics LogItem is a faster logging variant. It allows set operations only,
47 * and then recording to the service.
48 *
49 * The Byte String format is as follows:
Andy Hung1efc9c62019-12-03 13:43:33 -080050 *
51 * For Java
52 * int64 corresponds to long
53 * int32, uint32 corresponds to int
54 * uint16 corresponds to char
55 * uint8, int8 corresponds to byte
56 *
Andy Hung611268d2019-12-19 13:54:02 -080057 * For items transmitted from Java, uint8 and uint32 values are limited
58 * to INT8_MAX and INT32_MAX. This constrains the size of large items
59 * to 2GB, which is consistent with ByteBuffer max size. A native item
60 * can conceivably have size of 4GB.
Andy Hung1efc9c62019-12-03 13:43:33 -080061 *
62 * Physical layout of integers and doubles within the MediaMetrics byte string
Andy Hung611268d2019-12-19 13:54:02 -080063 * is in Native / host order, which is usually little endian.
64 *
65 * Note that primitive data (ints, doubles) within a Byte String has
66 * no extra padding or alignment requirements, like ByteBuffer.
Andy Hung1efc9c62019-12-03 13:43:33 -080067 *
68 * -- begin of item
69 * -- begin of header
70 * (uint32) item size: including the item size field
71 * (uint32) header size, including the item size and header size fields.
72 * (uint16) version: exactly 0
73 * (uint16) key size, that is key strlen + 1 for zero termination.
Andy Hung611268d2019-12-19 13:54:02 -080074 * (int8)+ key, a string which is 0 terminated (UTF-8).
Andy Hung3253f2d2019-10-21 14:50:07 -070075 * (int32) pid
76 * (int32) uid
77 * (int64) timestamp
Andy Hung1efc9c62019-12-03 13:43:33 -080078 * -- end of header
79 * -- begin body
80 * (uint32) number of properties
81 * -- repeat for number of properties
82 * (uint16) property size, including property size field itself
Andy Hung3253f2d2019-10-21 14:50:07 -070083 * (uint8) type of property
84 * (int8)+ key string, including 0 termination
Andy Hung1efc9c62019-12-03 13:43:33 -080085 * based on type of property (given above), one of:
Andy Hung3253f2d2019-10-21 14:50:07 -070086 * (int32)
87 * (int64)
88 * (double)
Andy Hung611268d2019-12-19 13:54:02 -080089 * (int8)+ for TYPE_CSTRING, including 0 termination
Andy Hung3253f2d2019-10-21 14:50:07 -070090 * (int64, int64) for rate
Andy Hung1efc9c62019-12-03 13:43:33 -080091 * -- end body
92 * -- end of item
Andy Hung611268d2019-12-19 13:54:02 -080093 *
94 * The Byte String format must match MediaMetrics.java.
Andy Hung3253f2d2019-10-21 14:50:07 -070095 */
96
Andy Hung1efc9c62019-12-03 13:43:33 -080097namespace mediametrics {
98
99// Type must match MediaMetrics.java
100enum Type {
101 kTypeNone = 0,
102 kTypeInt32 = 1,
103 kTypeInt64 = 2,
104 kTypeDouble = 3,
105 kTypeCString = 4,
106 kTypeRate = 5,
107};
108
Andy Hung611268d2019-12-19 13:54:02 -0800109/**
110 * The MediaMetrics Item has special Item properties,
111 * derived internally or through dedicated setters.
112 *
113 * For consistency we use the following keys to represent
114 * these special Item properties when in a generic Bundle
115 * or in a std::map.
116 *
117 * These values must match MediaMetrics.java
118 */
119static inline constexpr const char *BUNDLE_TOTAL_SIZE = "_totalSize";
120static inline constexpr const char *BUNDLE_HEADER_SIZE = "_headerSize";
121static inline constexpr const char *BUNDLE_VERSION = "_version";
122static inline constexpr const char *BUNDLE_KEY_SIZE = "_keySize";
123static inline constexpr const char *BUNDLE_KEY = "_key";
124static inline constexpr const char *BUNDLE_PID = "_pid";
125static inline constexpr const char *BUNDLE_UID = "_uid";
126static inline constexpr const char *BUNDLE_TIMESTAMP = "_timestamp";
127static inline constexpr const char *BUNDLE_PROPERTY_COUNT = "_propertyCount";
128
Andy Hung1efc9c62019-12-03 13:43:33 -0800129template<size_t N>
130static inline bool startsWith(const std::string &s, const char (&comp)[N]) {
Andy Hung692870b2020-01-02 13:46:06 -0800131 return !strncmp(s.c_str(), comp, N - 1);
Andy Hung1efc9c62019-12-03 13:43:33 -0800132}
133
134/**
135 * Media Metrics BaseItem
136 *
137 * A base class which contains utility static functions to write to a byte stream
138 * and access the Media Metrics service.
139 */
140
141class BaseItem {
142 friend class MediaMetricsDeathNotifier; // for dropInstance
143 // enabled 1, disabled 0
144public:
Andy Hung47e58d62019-12-06 18:40:19 -0800145 // are we collecting metrics data
Andy Hung1efc9c62019-12-03 13:43:33 -0800146 static bool isEnabled();
Andy Hung47e58d62019-12-06 18:40:19 -0800147 static sp<IMediaMetricsService> getService();
Andy Hung1efc9c62019-12-03 13:43:33 -0800148
149protected:
150 static constexpr const char * const EnabledProperty = "media.metrics.enabled";
151 static constexpr const char * const EnabledPropertyPersist = "persist.media.metrics.enabled";
152 static const int EnabledProperty_default = 1;
153
154 // let's reuse a binder connection
Ray Essickf27e9872019-12-07 06:28:46 -0800155 static sp<IMediaMetricsService> sMediaMetricsService;
Andy Hung47e58d62019-12-06 18:40:19 -0800156
Andy Hung1efc9c62019-12-03 13:43:33 -0800157 static void dropInstance();
158 static bool submitBuffer(const char *buffer, size_t len);
159
Andy Hungb7aadb32019-12-09 19:40:42 -0800160 template <typename T>
161 struct is_item_type {
162 static constexpr inline bool value =
163 std::is_same<T, int32_t>::value
164 || std::is_same<T, int64_t>::value
165 || std::is_same<T, double>::value
166 || std::is_same<T, std::pair<int64_t, int64_t>>:: value
167 || std::is_same<T, std::string>::value
168 || std::is_same<T, std::monostate>::value;
169 };
Andy Hung1efc9c62019-12-03 13:43:33 -0800170
Andy Hungb7aadb32019-12-09 19:40:42 -0800171 template <typename T>
172 struct get_type_of {
173 static_assert(is_item_type<T>::value);
174 static constexpr inline Type value =
175 std::is_same<T, int32_t>::value ? kTypeInt32
176 : std::is_same<T, int64_t>::value ? kTypeInt64
177 : std::is_same<T, double>::value ? kTypeDouble
178 : std::is_same<T, std::pair<int64_t, int64_t>>:: value ? kTypeRate
179 : std::is_same<T, std::string>::value ? kTypeCString
180 : std::is_same<T, std::monostate>::value ? kTypeNone
181 : kTypeNone;
182 };
183
184 template <typename T>
185 static size_t sizeOfByteString(const char *name, const T& value) {
186 static_assert(is_item_type<T>::value);
Andy Hung1efc9c62019-12-03 13:43:33 -0800187 return 2 + 1 + strlen(name) + 1 + sizeof(value);
188 }
Andy Hungb7aadb32019-12-09 19:40:42 -0800189 template <> // static
190 size_t sizeOfByteString(const char *name, const std::string& value) {
191 return 2 + 1 + strlen(name) + 1 + value.size() + 1;
Andy Hung1efc9c62019-12-03 13:43:33 -0800192 }
Andy Hungb7aadb32019-12-09 19:40:42 -0800193 template <> // static
194 size_t sizeOfByteString(const char *name, const std::monostate&) {
Andy Hung1efc9c62019-12-03 13:43:33 -0800195 return 2 + 1 + strlen(name) + 1;
196 }
Andy Hungb7aadb32019-12-09 19:40:42 -0800197 // for speed
198 static size_t sizeOfByteString(const char *name, const char *value) {
199 return 2 + 1 + strlen(name) + 1 + strlen(value) + 1;
200 }
201
202 template <typename T>
203 static status_t insert(const T& val, char **bufferpptr, char *bufferptrmax) {
204 static_assert(std::is_trivially_constructible<T>::value);
205 const size_t size = sizeof(val);
206 if (*bufferpptr + size > bufferptrmax) {
207 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
208 return BAD_VALUE;
209 }
210 memcpy(*bufferpptr, &val, size);
211 *bufferpptr += size;
212 return NO_ERROR;
213 }
214 template <> // static
215 status_t insert(const std::string& val, char **bufferpptr, char *bufferptrmax) {
216 const size_t size = val.size() + 1;
217 if (size > UINT16_MAX || *bufferpptr + size > bufferptrmax) {
218 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
219 return BAD_VALUE;
220 }
221 memcpy(*bufferpptr, val.c_str(), size);
222 *bufferpptr += size;
223 return NO_ERROR;
224 }
225 template <> // static
226 status_t insert(const std::pair<int64_t, int64_t>& val,
227 char **bufferpptr, char *bufferptrmax) {
228 const size_t size = sizeof(val.first) + sizeof(val.second);
229 if (*bufferpptr + size > bufferptrmax) {
230 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
231 return BAD_VALUE;
232 }
233 memcpy(*bufferpptr, &val.first, sizeof(val.first));
234 memcpy(*bufferpptr + sizeof(val.first), &val.second, sizeof(val.second));
235 *bufferpptr += size;
236 return NO_ERROR;
237 }
238 template <> // static
239 status_t insert(const std::monostate&, char **, char *) {
240 return NO_ERROR;
241 }
242 // for speed
243 static status_t insert(const char *val, char **bufferpptr, char *bufferptrmax) {
244 const size_t size = strlen(val) + 1;
245 if (size > UINT16_MAX || *bufferpptr + size > bufferptrmax) {
246 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
247 return BAD_VALUE;
248 }
249 memcpy(*bufferpptr, val, size);
250 *bufferpptr += size;
251 return NO_ERROR;
252 }
253
254 template <typename T>
255 static status_t writeToByteString(
256 const char *name, const T& value, char **bufferpptr, char *bufferptrmax) {
257 static_assert(is_item_type<T>::value);
258 const size_t len = sizeOfByteString(name, value);
259 if (len > UINT16_MAX) return BAD_VALUE;
260 return insert((uint16_t)len, bufferpptr, bufferptrmax)
261 ?: insert((uint8_t)get_type_of<T>::value, bufferpptr, bufferptrmax)
262 ?: insert(name, bufferpptr, bufferptrmax)
263 ?: insert(value, bufferpptr, bufferptrmax);
264 }
265 // for speed
266 static status_t writeToByteString(
267 const char *name, const char *value, char **bufferpptr, char *bufferptrmax) {
268 const size_t len = sizeOfByteString(name, value);
269 if (len > UINT16_MAX) return BAD_VALUE;
270 return insert((uint16_t)len, bufferpptr, bufferptrmax)
271 ?: insert((uint8_t)kTypeCString, bufferpptr, bufferptrmax)
272 ?: insert(name, bufferpptr, bufferptrmax)
273 ?: insert(value, bufferpptr, bufferptrmax);
274 }
275
276 template <typename T>
277 static void toStringBuffer(
278 const char *name, const T& value, char *buffer, size_t length) = delete;
279 template <> // static
280 void toStringBuffer(
281 const char *name, const int32_t& value, char *buffer, size_t length) {
282 snprintf(buffer, length, "%s=%d:", name, value);
283 }
284 template <> // static
285 void toStringBuffer(
286 const char *name, const int64_t& value, char *buffer, size_t length) {
287 snprintf(buffer, length, "%s=%lld:", name, (long long)value);
288 }
289 template <> // static
290 void toStringBuffer(
291 const char *name, const double& value, char *buffer, size_t length) {
292 snprintf(buffer, length, "%s=%e:", name, value);
293 }
294 template <> // static
295 void toStringBuffer(
296 const char *name, const std::pair<int64_t, int64_t>& value,
297 char *buffer, size_t length) {
298 snprintf(buffer, length, "%s=%lld/%lld:",
299 name, (long long)value.first, (long long)value.second);
300 }
301 template <> // static
302 void toStringBuffer(
303 const char *name, const std::string& value, char *buffer, size_t length) {
304 // TODO sanitize string for ':' '='
305 snprintf(buffer, length, "%s=%s:", name, value.c_str());
306 }
307 template <> // static
308 void toStringBuffer(
309 const char *name, const std::monostate&, char *buffer, size_t length) {
310 snprintf(buffer, length, "%s=():", name);
311 }
312
313 template <typename T>
314 static status_t writeToParcel(
315 const char *name, const T& value, Parcel *parcel) = delete;
316 template <> // static
317 status_t writeToParcel(
318 const char *name, const int32_t& value, Parcel *parcel) {
319 return parcel->writeCString(name)
320 ?: parcel->writeInt32(get_type_of<int32_t>::value)
321 ?: parcel->writeInt32(value);
322 }
323 template <> // static
324 status_t writeToParcel(
325 const char *name, const int64_t& value, Parcel *parcel) {
326 return parcel->writeCString(name)
327 ?: parcel->writeInt32(get_type_of<int64_t>::value)
328 ?: parcel->writeInt64(value);
329 }
330 template <> // static
331 status_t writeToParcel(
332 const char *name, const double& value, Parcel *parcel) {
333 return parcel->writeCString(name)
334 ?: parcel->writeInt32(get_type_of<double>::value)
335 ?: parcel->writeDouble(value);
336 }
337 template <> // static
338 status_t writeToParcel(
339 const char *name, const std::pair<int64_t, int64_t>& value, Parcel *parcel) {
340 return parcel->writeCString(name)
341 ?: parcel->writeInt32(get_type_of< std::pair<int64_t, int64_t>>::value)
342 ?: parcel->writeInt64(value.first)
343 ?: parcel->writeInt64(value.second);
344 }
345 template <> // static
346 status_t writeToParcel(
347 const char *name, const std::string& value, Parcel *parcel) {
348 return parcel->writeCString(name)
349 ?: parcel->writeInt32(get_type_of<std::string>::value)
350 ?: parcel->writeCString(value.c_str());
351 }
352 template <> // static
353 status_t writeToParcel(
354 const char *name, const std::monostate&, Parcel *parcel) {
355 return parcel->writeCString(name)
356 ?: parcel->writeInt32(get_type_of<std::monostate>::value);
357 }
358
359 template <typename T>
360 static status_t extract(T *val, const char **bufferpptr, const char *bufferptrmax) {
361 static_assert(std::is_trivially_constructible<T>::value);
362 const size_t size = sizeof(*val);
363 if (*bufferpptr + size > bufferptrmax) {
364 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
365 return BAD_VALUE;
366 }
367 memcpy(val, *bufferpptr, size);
368 *bufferpptr += size;
369 return NO_ERROR;
370 }
371 template <> // static
372 status_t extract(std::string *val, const char **bufferpptr, const char *bufferptrmax) {
373 const char *ptr = *bufferpptr;
374 while (*ptr != 0) {
375 if (ptr >= bufferptrmax) {
376 ALOGE("%s: buffer exceeded", __func__);
377 return BAD_VALUE;
378 }
379 ++ptr;
380 }
381 const size_t size = (ptr - *bufferpptr) + 1;
382 *val = *bufferpptr;
383 *bufferpptr += size;
384 return NO_ERROR;
385 }
386 template <> // static
387 status_t extract(std::pair<int64_t, int64_t> *val,
388 const char **bufferpptr, const char *bufferptrmax) {
389 const size_t size = sizeof(val->first) + sizeof(val->second);
390 if (*bufferpptr + size > bufferptrmax) {
391 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
392 return BAD_VALUE;
393 }
394 memcpy(&val->first, *bufferpptr, sizeof(val->first));
395 memcpy(&val->second, *bufferpptr + sizeof(val->first), sizeof(val->second));
396 *bufferpptr += size;
397 return NO_ERROR;
398 }
399 template <> // static
400 status_t extract(std::monostate *, const char **, const char *) {
401 return NO_ERROR;
402 }
Andy Hung1efc9c62019-12-03 13:43:33 -0800403};
404
405/**
406 * Media Metrics BufferedItem
407 *
408 * A base class which represents a put-only Media Metrics item, storing
409 * the Media Metrics data in a buffer with begin and end pointers.
410 *
411 * If a property key is entered twice, it will be stored in the buffer twice,
412 * and (implementation defined) the last value for that key will be used
413 * by the Media Metrics service.
414 *
415 * For realloc, a baseRealloc pointer must be passed in either explicitly
416 * or implicitly in the constructor. This will be updated with the value used on realloc.
417 */
418class BufferedItem : public BaseItem {
419public:
420 static inline constexpr uint16_t kVersion = 0;
421
422 virtual ~BufferedItem() = default;
423 BufferedItem(const BufferedItem&) = delete;
424 BufferedItem& operator=(const BufferedItem&) = delete;
425
426 BufferedItem(const std::string key, char *begin, char *end)
427 : BufferedItem(key.c_str(), begin, end) { }
428
429 BufferedItem(const char *key, char *begin, char *end)
430 : BufferedItem(key, begin, end, nullptr) { }
431
432 BufferedItem(const char *key, char **begin, char *end)
433 : BufferedItem(key, *begin, end, begin) { }
434
435 BufferedItem(const char *key, char *begin, char *end, char **baseRealloc)
436 : mBegin(begin)
437 , mEnd(end)
438 , mBaseRealloc(baseRealloc)
439 {
440 init(key);
441 }
442
443 template<typename T>
444 BufferedItem &set(const char *key, const T& value) {
445 reallocFor(sizeOfByteString(key, value));
446 if (mStatus == NO_ERROR) {
447 mStatus = BaseItem::writeToByteString(key, value, &mBptr, mEnd);
448 ++mPropCount;
449 }
450 return *this;
451 }
452
453 template<typename T>
454 BufferedItem &set(const std::string& key, const T& value) {
455 return set(key.c_str(), value);
456 }
457
458 BufferedItem &setPid(pid_t pid) {
459 if (mStatus == NO_ERROR) {
460 copyTo(mBegin + mHeaderLen - 16, (int32_t)pid);
461 }
462 return *this;
463 }
464
465 BufferedItem &setUid(uid_t uid) {
466 if (mStatus == NO_ERROR) {
467 copyTo(mBegin + mHeaderLen - 12, (int32_t)uid);
468 }
469 return *this;
470 }
471
472 BufferedItem &setTimestamp(nsecs_t timestamp) {
473 if (mStatus == NO_ERROR) {
474 copyTo(mBegin + mHeaderLen - 8, (int64_t)timestamp);
475 }
476 return *this;
477 }
478
479 bool record() {
480 return updateHeader()
481 && BaseItem::submitBuffer(getBuffer(), getLength());
482 }
483
484 bool isValid () const {
485 return mStatus == NO_ERROR;
486 }
487
488 char *getBuffer() const { return mBegin; }
489 size_t getLength() const { return mBptr - mBegin; }
490 size_t getRemaining() const { return mEnd - mBptr; }
491 size_t getCapacity() const { return mEnd - mBegin; }
492
493 bool updateHeader() {
494 if (mStatus != NO_ERROR) return false;
495 copyTo(mBegin + 0, (uint32_t)getLength());
496 copyTo(mBegin + 4, (uint32_t)mHeaderLen);
497 copyTo(mBegin + mHeaderLen, (uint32_t)mPropCount);
498 return true;
499 }
500
501protected:
502 BufferedItem() = default;
503
504 void reallocFor(size_t required) {
505 if (mStatus != NO_ERROR) return;
506 const size_t remaining = getRemaining();
507 if (required <= remaining) return;
508 if (mBaseRealloc == nullptr) {
509 mStatus = NO_MEMORY;
510 return;
511 }
512
513 const size_t current = getLength();
514 size_t minimum = current + required;
515 if (minimum > SSIZE_MAX >> 1) {
516 mStatus = NO_MEMORY;
517 return;
518 }
519 minimum <<= 1;
520 void *newptr = realloc(*mBaseRealloc, minimum);
521 if (newptr == nullptr) {
522 mStatus = NO_MEMORY;
523 return;
524 }
525 if (newptr != *mBaseRealloc) {
526 // ALOGD("base changed! current:%zu new size %zu", current, minimum);
527 if (*mBaseRealloc == nullptr) {
528 memcpy(newptr, mBegin, current);
529 }
530 mBegin = (char *)newptr;
531 *mBaseRealloc = mBegin;
532 mEnd = mBegin + minimum;
533 mBptr = mBegin + current;
534 } else {
535 // ALOGD("base kept! current:%zu new size %zu", current, minimum);
536 mEnd = mBegin + minimum;
537 }
538 }
539 template<typename T>
540 void copyTo(char *ptr, const T& value) {
541 memcpy(ptr, &value, sizeof(value));
542 }
543
544 void init(const char *key) {
545 mBptr = mBegin;
546 const size_t keylen = strlen(key) + 1;
547 mHeaderLen = 4 + 4 + 2 + 2 + keylen + 4 + 4 + 8;
548 reallocFor(mHeaderLen);
549 if (mStatus != NO_ERROR) return;
550 mBptr = mBegin + mHeaderLen + 4; // this includes propcount.
551
552 if (mEnd < mBptr || keylen > UINT16_MAX) {
553 mStatus = NO_MEMORY;
554 mBptr = mEnd;
555 return;
556 }
557 copyTo(mBegin + 8, kVersion);
558 copyTo(mBegin + 10, (uint16_t)keylen);
559 strcpy(mBegin + 12, key);
560
561 // initialize some parameters (that could be overridden)
562 setPid(-1);
563 setUid(-1);
564 setTimestamp(0);
565 }
566
567 char *mBegin = nullptr;
568 char *mEnd = nullptr;
569 char **mBaseRealloc = nullptr; // set to an address if realloc should be done.
570 // upon return, that pointer is updated with
571 // whatever needs to be freed.
572 char *mBptr = nullptr;
573 status_t mStatus = NO_ERROR;
574 uint32_t mPropCount = 0;
575 uint32_t mHeaderLen = 0;
576};
577
578/**
Andy Hung47e58d62019-12-06 18:40:19 -0800579 * MediaMetrics LogItem is a stack allocated mediametrics item used for
Andy Hung1efc9c62019-12-03 13:43:33 -0800580 * fast logging. It falls over to a malloc if needed.
581 *
582 * This is templated with a buffer size to allocate on the stack.
583 */
584template <size_t N = 4096>
Ray Essickf27e9872019-12-07 06:28:46 -0800585class LogItem : public BufferedItem {
Andy Hung1efc9c62019-12-03 13:43:33 -0800586public:
Ray Essickf27e9872019-12-07 06:28:46 -0800587 explicit LogItem(const std::string key) : LogItem(key.c_str()) { }
Andy Hung1efc9c62019-12-03 13:43:33 -0800588
589 // Since this class will not be defined before the base class, we initialize variables
590 // in our own order.
Ray Essickf27e9872019-12-07 06:28:46 -0800591 explicit LogItem(const char *key) {
Andy Hung1efc9c62019-12-03 13:43:33 -0800592 mBegin = mBuffer;
593 mEnd = mBuffer + N;
594 mBaseRealloc = &mReallocPtr;
595 init(key);
596 }
597
Ray Essickf27e9872019-12-07 06:28:46 -0800598 ~LogItem() override {
Andy Hung1efc9c62019-12-03 13:43:33 -0800599 if (mReallocPtr != nullptr) { // do the check before calling free to avoid overhead.
600 free(mReallocPtr);
601 }
602 }
603
604private:
605 char *mReallocPtr = nullptr; // set non-null by base class if realloc happened.
606 char mBuffer[N];
607};
608
Andy Hung1efc9c62019-12-03 13:43:33 -0800609
Andy Hung3253f2d2019-10-21 14:50:07 -0700610/**
Ray Essickf27e9872019-12-07 06:28:46 -0800611 * Media Metrics Item
Andy Hung3253f2d2019-10-21 14:50:07 -0700612 *
613 * A mutable item representing an event or record that will be
Andy Hung1efc9c62019-12-03 13:43:33 -0800614 * logged with the Media Metrics service. For client logging, one should
615 * use the mediametrics::Item.
Andy Hung3253f2d2019-10-21 14:50:07 -0700616 *
Ray Essickf27e9872019-12-07 06:28:46 -0800617 * The Item is designed for the service as it has getters.
Andy Hung3253f2d2019-10-21 14:50:07 -0700618 */
Andy Hung565cc482020-01-02 13:40:04 -0800619class Item final : public mediametrics::BaseItem {
Andy Hungaeef7882019-10-18 15:18:14 -0700620public:
Ray Essick3938dc62016-11-01 08:56:56 -0700621
Andy Hung2ecacc42020-01-02 13:29:50 -0800622 class Prop {
623 public:
624 using Elem = std::variant<
625 std::monostate, // kTypeNone
626 int32_t, // kTypeInt32
627 int64_t, // kTypeInt64
628 double, // kTypeDouble
629 std::string, // kTypeCString
630 std::pair<int64_t, int64_t> // kTypeRate
631 >;
632
633 Prop() = default;
634 Prop(const Prop& other) {
635 *this = other;
636 }
637 Prop& operator=(const Prop& other) {
638 mName = other.mName;
639 mElem = other.mElem;
640 return *this;
641 }
642 Prop(Prop&& other) {
643 *this = std::move(other);
644 }
645 Prop& operator=(Prop&& other) {
646 mName = std::move(other.mName);
647 mElem = std::move(other.mElem);
648 return *this;
649 }
650
651 bool operator==(const Prop& other) const {
652 return mName == other.mName && mElem == other.mElem;
653 }
654 bool operator!=(const Prop& other) const {
655 return !(*this == other);
656 }
657
658 void clear() {
659 mName.clear();
660 mElem = std::monostate{};
661 }
662 void clearValue() {
663 mElem = std::monostate{};
664 }
665
666 const char *getName() const {
667 return mName.c_str();
668 }
669
670 void swap(Prop& other) {
671 std::swap(mName, other.mName);
672 std::swap(mElem, other.mElem);
673 }
674
675 void setName(const char *name) {
676 mName = name;
677 }
678
679 bool isNamed(const char *name) const {
680 return mName == name;
681 }
682
683 template <typename T> void visit(T f) const {
684 std::visit(f, mElem);
685 }
686
687 template <typename T> bool get(T *value) const {
688 auto pval = std::get_if<T>(&mElem);
689 if (pval != nullptr) {
690 *value = *pval;
691 return true;
692 }
693 return false;
694 }
695
696 const Elem& get() const {
697 return mElem;
698 }
699
700 template <typename T> void set(const T& value) {
701 mElem = value;
702 }
703
704 template <typename T> void add(const T& value) {
705 auto pval = std::get_if<T>(&mElem);
706 if (pval != nullptr) {
707 *pval += value;
708 } else {
709 mElem = value;
710 }
711 }
712
713 template <> void add(const std::pair<int64_t, int64_t>& value) {
714 auto pval = std::get_if<std::pair<int64_t, int64_t>>(&mElem);
715 if (pval != nullptr) {
716 pval->first += value.first;
717 pval->second += value.second;
718 } else {
719 mElem = value;
720 }
721 }
722
723 status_t writeToParcel(Parcel *parcel) const {
724 return std::visit([this, parcel](auto &value) {
725 return BaseItem::writeToParcel(mName.c_str(), value, parcel);}, mElem);
726 }
727
728 void toStringBuffer(char *buffer, size_t length) const {
729 return std::visit([this, buffer, length](auto &value) {
730 BaseItem::toStringBuffer(mName.c_str(), value, buffer, length);}, mElem);
731 }
732
733 size_t getByteStringSize() const {
734 return std::visit([this](auto &value) {
735 return BaseItem::sizeOfByteString(mName.c_str(), value);}, mElem);
736 }
737
738 status_t writeToByteString(char **bufferpptr, char *bufferptrmax) const {
739 return std::visit([this, bufferpptr, bufferptrmax](auto &value) {
740 return BaseItem::writeToByteString(mName.c_str(), value, bufferpptr, bufferptrmax);
741 }, mElem);
742 }
743
744 status_t readFromParcel(const Parcel& data);
745
746 status_t readFromByteString(const char **bufferpptr, const char *bufferptrmax);
747
748 private:
749 std::string mName;
750 Elem mElem;
751 };
752
753 // Iteration of props within item
754 class iterator {
755 public:
756 iterator(const std::map<std::string, Prop>::const_iterator &_it) : it(_it) { }
757 iterator &operator++() {
758 ++it;
759 return *this;
760 }
761 bool operator!=(iterator &other) const {
762 return it != other.it;
763 }
764 const Prop &operator*() const {
765 return it->second;
766 }
767
768 private:
769 std::map<std::string, Prop>::const_iterator it;
770 };
771
772 iterator begin() const {
773 return iterator(mProps.cbegin());
774 }
775
776 iterator end() const {
777 return iterator(mProps.cend());
778 }
779
Ray Essickf65f4212017-08-31 11:41:19 -0700780 enum {
781 PROTO_V0 = 0,
782 PROTO_FIRST = PROTO_V0,
783 PROTO_V1 = 1,
784 PROTO_LAST = PROTO_V1,
785 };
786
Andy Hungaeef7882019-10-18 15:18:14 -0700787 // T must be convertible to mKey
788 template <typename T>
Ray Essickf27e9872019-12-07 06:28:46 -0800789 explicit Item(T key)
Andy Hungaeef7882019-10-18 15:18:14 -0700790 : mKey(key) { }
Ray Essickf27e9872019-12-07 06:28:46 -0800791 Item() = default;
Andy Hung3253f2d2019-10-21 14:50:07 -0700792
Andy Hung565cc482020-01-02 13:40:04 -0800793 // We enable default copy and move constructors and make this class final
794 // to prevent a derived class; this avoids possible data slicing.
795 Item(const Item& other) = default;
796 Item(Item&& other) = default;
797 Item& operator=(const Item& other) = default;
798 Item& operator=(Item&& other) = default;
799
Ray Essickf27e9872019-12-07 06:28:46 -0800800 bool operator==(const Item& other) const {
Andy Hung692870b2020-01-02 13:46:06 -0800801 return mPid == other.mPid
802 && mUid == other.mUid
803 && mPkgName == other.mPkgName
804 && mPkgVersionCode == other.mPkgVersionCode
805 && mKey == other.mKey
806 && mTimestamp == other.mTimestamp
807 && mProps == other.mProps
808 ;
Andy Hung3253f2d2019-10-21 14:50:07 -0700809 }
Ray Essickf27e9872019-12-07 06:28:46 -0800810 bool operator!=(const Item& other) const {
Andy Hung3253f2d2019-10-21 14:50:07 -0700811 return !(*this == other);
812 }
813
814 template <typename T>
Ray Essickf27e9872019-12-07 06:28:46 -0800815 static Item* create(T key) {
816 return new Item(key);
Andy Hung3253f2d2019-10-21 14:50:07 -0700817 }
Ray Essickf27e9872019-12-07 06:28:46 -0800818 static Item* create() {
819 return new Item();
Andy Hung3253f2d2019-10-21 14:50:07 -0700820 }
Ray Essickba8c4842019-01-18 11:35:33 -0800821
Ray Essickf27e9872019-12-07 06:28:46 -0800822 static Item* convert(mediametrics_handle_t);
823 static mediametrics_handle_t convert(Item *);
Ray Essickbf536ac2019-08-26 11:04:28 -0700824
Ray Essick3938dc62016-11-01 08:56:56 -0700825 // access functions for the class
Ray Essickf27e9872019-12-07 06:28:46 -0800826 ~Item();
Ray Essick3938dc62016-11-01 08:56:56 -0700827
Andy Hung47e58d62019-12-06 18:40:19 -0800828 void clear() {
829 mPid = -1;
830 mUid = -1;
831 mPkgName.clear();
832 mPkgVersionCode = 0;
833 mTimestamp = 0;
834 mKey.clear();
835 mProps.clear();
836 }
837
838 Item *dup() const { return new Item(*this); }
Ray Essick3938dc62016-11-01 08:56:56 -0700839
Ray Essickf27e9872019-12-07 06:28:46 -0800840 Item &setKey(const char *key) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700841 mKey = key;
842 return *this;
843 }
844 const std::string& getKey() const { return mKey; }
Ray Essick3938dc62016-11-01 08:56:56 -0700845
Andy Hung3253f2d2019-10-21 14:50:07 -0700846 // # of properties in the record
Andy Hung47e58d62019-12-06 18:40:19 -0800847 size_t count() const { return mProps.size(); }
Ray Essick3938dc62016-11-01 08:56:56 -0700848
Andy Hungaeef7882019-10-18 15:18:14 -0700849 template<typename S, typename T>
Ray Essickf27e9872019-12-07 06:28:46 -0800850 Item &set(S key, T value) {
Andy Hung47e58d62019-12-06 18:40:19 -0800851 findOrAllocateProp(key).set(value);
Andy Hungaeef7882019-10-18 15:18:14 -0700852 return *this;
853 }
Ray Essick3938dc62016-11-01 08:56:56 -0700854
Andy Hungaeef7882019-10-18 15:18:14 -0700855 // set values appropriately
Ray Essickf27e9872019-12-07 06:28:46 -0800856 Item &setInt32(const char *key, int32_t value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700857 return set(key, value);
858 }
Ray Essickf27e9872019-12-07 06:28:46 -0800859 Item &setInt64(const char *key, int64_t value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700860 return set(key, value);
861 }
Ray Essickf27e9872019-12-07 06:28:46 -0800862 Item &setDouble(const char *key, double value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700863 return set(key, value);
864 }
Ray Essickf27e9872019-12-07 06:28:46 -0800865 Item &setRate(const char *key, int64_t count, int64_t duration) {
Andy Hungaeef7882019-10-18 15:18:14 -0700866 return set(key, std::make_pair(count, duration));
867 }
Ray Essickf27e9872019-12-07 06:28:46 -0800868 Item &setCString(const char *key, const char *value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700869 return set(key, value);
870 }
Ray Essick3938dc62016-11-01 08:56:56 -0700871
Andy Hungaeef7882019-10-18 15:18:14 -0700872 // fused get/add/set; if attr wasn't there, it's a simple set.
873 // type-mismatch counts as "wasn't there".
874 template<typename S, typename T>
Ray Essickf27e9872019-12-07 06:28:46 -0800875 Item &add(S key, T value) {
Andy Hung47e58d62019-12-06 18:40:19 -0800876 findOrAllocateProp(key).add(value);
Andy Hungaeef7882019-10-18 15:18:14 -0700877 return *this;
878 }
879
Ray Essickf27e9872019-12-07 06:28:46 -0800880 Item &addInt32(const char *key, int32_t value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700881 return add(key, value);
882 }
Ray Essickf27e9872019-12-07 06:28:46 -0800883 Item &addInt64(const char *key, int64_t value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700884 return add(key, value);
885 }
Ray Essickf27e9872019-12-07 06:28:46 -0800886 Item &addDouble(const char *key, double value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700887 return add(key, value);
888 }
Ray Essickf27e9872019-12-07 06:28:46 -0800889 Item &addRate(const char *key, int64_t count, int64_t duration) {
Andy Hungaeef7882019-10-18 15:18:14 -0700890 return add(key, std::make_pair(count, duration));
891 }
892
893 // find & extract values
894 // return indicates whether attr exists (and thus value filled in)
895 // NULL parameter value suppresses storage of value.
896 template<typename S, typename T>
897 bool get(S key, T *value) const {
Andy Hung47e58d62019-12-06 18:40:19 -0800898 const Prop *prop = findProp(key);
Andy Hungaeef7882019-10-18 15:18:14 -0700899 return prop != nullptr && prop->get(value);
900 }
901
Andy Hung3253f2d2019-10-21 14:50:07 -0700902 bool getInt32(const char *key, int32_t *value) const {
Andy Hungaeef7882019-10-18 15:18:14 -0700903 return get(key, value);
904 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700905 bool getInt64(const char *key, int64_t *value) const {
Andy Hungaeef7882019-10-18 15:18:14 -0700906 return get(key, value);
907 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700908 bool getDouble(const char *key, double *value) const {
Andy Hungaeef7882019-10-18 15:18:14 -0700909 return get(key, value);
910 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700911 bool getRate(const char *key, int64_t *count, int64_t *duration, double *rate) const {
Andy Hungaeef7882019-10-18 15:18:14 -0700912 std::pair<int64_t, int64_t> value;
913 if (!get(key, &value)) return false;
914 if (count != nullptr) *count = value.first;
915 if (duration != nullptr) *duration = value.second;
916 if (rate != nullptr) {
917 if (value.second != 0) {
918 *rate = (double)value.first / value.second; // TODO: isn't INF OK?
919 } else {
920 *rate = 0.;
921 }
922 }
923 return true;
924 }
925 // Caller owns the returned string
Andy Hung3253f2d2019-10-21 14:50:07 -0700926 bool getCString(const char *key, char **value) const {
Andy Hungb7aadb32019-12-09 19:40:42 -0800927 std::string s;
928 if (get(key, &s)) {
929 *value = strdup(s.c_str());
Andy Hung3253f2d2019-10-21 14:50:07 -0700930 return true;
931 }
932 return false;
Andy Hungaeef7882019-10-18 15:18:14 -0700933 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700934 bool getString(const char *key, std::string *value) const {
Andy Hungaeef7882019-10-18 15:18:14 -0700935 return get(key, value);
936 }
Ray Essick3938dc62016-11-01 08:56:56 -0700937
Andy Hung692870b2020-01-02 13:46:06 -0800938 const Prop::Elem* get(const char *key) const {
939 const Prop *prop = findProp(key);
940 return prop == nullptr ? nullptr : &prop->get();
941 }
942
Andy Hunga87e69c2019-10-18 10:07:40 -0700943 // Deliver the item to MediaMetrics
Ray Essick3938dc62016-11-01 08:56:56 -0700944 bool selfrecord();
945
Andy Hung3253f2d2019-10-21 14:50:07 -0700946 // remove indicated attributes and their values
947 // filterNot() could also be called keepOnly()
948 // return value is # attributes removed
949 // XXX: perhaps 'remove' instead of 'filter'
950 // XXX: filterNot would become 'keep'
951 size_t filter(size_t count, const char *attrs[]);
952 size_t filterNot(size_t count, const char *attrs[]);
953 size_t filter(const char *attr) { return filter(1, &attr); }
Ray Essick3938dc62016-11-01 08:56:56 -0700954
955 // below here are used on server side or to talk to server
956 // clients need not worry about these.
957
958 // timestamp, pid, and uid only used on server side
Ray Essickb5fac8e2016-12-12 11:33:56 -0800959 // timestamp is in 'nanoseconds, unix time'
Ray Essickf27e9872019-12-07 06:28:46 -0800960 Item &setTimestamp(nsecs_t);
Ray Essick3938dc62016-11-01 08:56:56 -0700961 nsecs_t getTimestamp() const;
962
Ray Essickf27e9872019-12-07 06:28:46 -0800963 Item &setPid(pid_t);
Ray Essick3938dc62016-11-01 08:56:56 -0700964 pid_t getPid() const;
965
Ray Essickf27e9872019-12-07 06:28:46 -0800966 Item &setUid(uid_t);
Ray Essick3938dc62016-11-01 08:56:56 -0700967 uid_t getUid() const;
968
Ray Essickf27e9872019-12-07 06:28:46 -0800969 Item &setPkgName(const std::string &pkgName);
Ray Essick783bd0d2018-01-11 11:10:35 -0800970 std::string getPkgName() const { return mPkgName; }
Ray Essickf65f4212017-08-31 11:41:19 -0700971
Ray Essickf27e9872019-12-07 06:28:46 -0800972 Item &setPkgVersionCode(int64_t);
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800973 int64_t getPkgVersionCode() const;
Ray Essickf65f4212017-08-31 11:41:19 -0700974
Andy Hung3253f2d2019-10-21 14:50:07 -0700975 // our serialization code for binder calls
976 status_t writeToParcel(Parcel *) const;
977 status_t readFromParcel(const Parcel&);
Ray Essick3938dc62016-11-01 08:56:56 -0700978
Andy Hung3253f2d2019-10-21 14:50:07 -0700979 status_t writeToByteString(char **bufferptr, size_t *length) const;
980 status_t readFromByteString(const char *bufferptr, size_t length);
981
Ray Essickba8c4842019-01-18 11:35:33 -0800982
Andy Hung17dbaf22019-10-11 14:06:31 -0700983 std::string toString() const;
984 std::string toString(int version) const;
Ray Essick20147322018-11-17 09:08:39 -0800985 const char *toCString();
986 const char *toCString(int version);
Ray Essick3938dc62016-11-01 08:56:56 -0700987
Andy Hung3253f2d2019-10-21 14:50:07 -0700988private:
989 // handle Parcel version 0
990 int32_t writeToParcel0(Parcel *) const;
991 int32_t readFromParcel0(const Parcel&);
992
Andy Hung47e58d62019-12-06 18:40:19 -0800993 const Prop *findProp(const char *key) const {
994 auto it = mProps.find(key);
995 return it != mProps.end() ? &it->second : nullptr;
996 }
Andy Hungaeef7882019-10-18 15:18:14 -0700997
Andy Hung47e58d62019-12-06 18:40:19 -0800998 Prop &findOrAllocateProp(const char *key) {
999 auto it = mProps.find(key);
1000 if (it != mProps.end()) return it->second;
1001 Prop &prop = mProps[key];
1002 prop.setName(key);
1003 return prop;
1004 }
Andy Hungaeef7882019-10-18 15:18:14 -07001005
Andy Hung565cc482020-01-02 13:40:04 -08001006 // Changes to member variables below require changes to clear().
Andy Hungaeef7882019-10-18 15:18:14 -07001007 pid_t mPid = -1;
1008 uid_t mUid = -1;
1009 std::string mPkgName;
1010 int64_t mPkgVersionCode = 0;
Andy Hung47e58d62019-12-06 18:40:19 -08001011 std::string mKey;
Andy Hungaeef7882019-10-18 15:18:14 -07001012 nsecs_t mTimestamp = 0;
Andy Hung47e58d62019-12-06 18:40:19 -08001013 std::map<std::string, Prop> mProps;
Ray Essick3938dc62016-11-01 08:56:56 -07001014};
1015
Ray Essickf27e9872019-12-07 06:28:46 -08001016} // namespace mediametrics
Ray Essick3938dc62016-11-01 08:56:56 -07001017} // namespace android
1018
Andy Hung47e58d62019-12-06 18:40:19 -08001019#endif // ANDROID_MEDIA_MEDIAMETRICSITEM_H