blob: dbbcaf94f06f1b28bb259dca92bd67c278f85ff8 [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
Andy Hung37de9b72020-01-02 13:54:05 -0800134static inline bool startsWith(const std::string& s, const std::string& comp) {
135 return !strncmp(s.c_str(), comp.c_str(), comp.size() - 1);
136}
137
138/**
139 * Defers a function to run in the destructor.
140 *
141 * This helper class is used to log results on exit of a method.
142 */
143class Defer {
144public:
145 template <typename U>
146 Defer(U &&f) : mThunk(std::forward<U>(f)) {}
147 ~Defer() { mThunk(); }
148
149private:
150 const std::function<void()> mThunk;
151};
152
Andy Hung1efc9c62019-12-03 13:43:33 -0800153/**
154 * Media Metrics BaseItem
155 *
156 * A base class which contains utility static functions to write to a byte stream
157 * and access the Media Metrics service.
158 */
159
160class BaseItem {
161 friend class MediaMetricsDeathNotifier; // for dropInstance
162 // enabled 1, disabled 0
163public:
Andy Hung47e58d62019-12-06 18:40:19 -0800164 // are we collecting metrics data
Andy Hung1efc9c62019-12-03 13:43:33 -0800165 static bool isEnabled();
Andy Hung47e58d62019-12-06 18:40:19 -0800166 static sp<IMediaMetricsService> getService();
Andy Hung1efc9c62019-12-03 13:43:33 -0800167
168protected:
169 static constexpr const char * const EnabledProperty = "media.metrics.enabled";
170 static constexpr const char * const EnabledPropertyPersist = "persist.media.metrics.enabled";
171 static const int EnabledProperty_default = 1;
172
173 // let's reuse a binder connection
Ray Essickf27e9872019-12-07 06:28:46 -0800174 static sp<IMediaMetricsService> sMediaMetricsService;
Andy Hung47e58d62019-12-06 18:40:19 -0800175
Andy Hung1efc9c62019-12-03 13:43:33 -0800176 static void dropInstance();
177 static bool submitBuffer(const char *buffer, size_t len);
178
Andy Hungb7aadb32019-12-09 19:40:42 -0800179 template <typename T>
180 struct is_item_type {
181 static constexpr inline bool value =
182 std::is_same<T, int32_t>::value
183 || std::is_same<T, int64_t>::value
184 || std::is_same<T, double>::value
185 || std::is_same<T, std::pair<int64_t, int64_t>>:: value
186 || std::is_same<T, std::string>::value
187 || std::is_same<T, std::monostate>::value;
188 };
Andy Hung1efc9c62019-12-03 13:43:33 -0800189
Andy Hungb7aadb32019-12-09 19:40:42 -0800190 template <typename T>
191 struct get_type_of {
192 static_assert(is_item_type<T>::value);
193 static constexpr inline Type value =
194 std::is_same<T, int32_t>::value ? kTypeInt32
195 : std::is_same<T, int64_t>::value ? kTypeInt64
196 : std::is_same<T, double>::value ? kTypeDouble
197 : std::is_same<T, std::pair<int64_t, int64_t>>:: value ? kTypeRate
198 : std::is_same<T, std::string>::value ? kTypeCString
199 : std::is_same<T, std::monostate>::value ? kTypeNone
200 : kTypeNone;
201 };
202
203 template <typename T>
204 static size_t sizeOfByteString(const char *name, const T& value) {
205 static_assert(is_item_type<T>::value);
Andy Hung1efc9c62019-12-03 13:43:33 -0800206 return 2 + 1 + strlen(name) + 1 + sizeof(value);
207 }
Andy Hungb7aadb32019-12-09 19:40:42 -0800208 template <> // static
209 size_t sizeOfByteString(const char *name, const std::string& value) {
210 return 2 + 1 + strlen(name) + 1 + value.size() + 1;
Andy Hung1efc9c62019-12-03 13:43:33 -0800211 }
Andy Hungb7aadb32019-12-09 19:40:42 -0800212 template <> // static
213 size_t sizeOfByteString(const char *name, const std::monostate&) {
Andy Hung1efc9c62019-12-03 13:43:33 -0800214 return 2 + 1 + strlen(name) + 1;
215 }
Andy Hungb7aadb32019-12-09 19:40:42 -0800216 // for speed
217 static size_t sizeOfByteString(const char *name, const char *value) {
218 return 2 + 1 + strlen(name) + 1 + strlen(value) + 1;
219 }
220
221 template <typename T>
222 static status_t insert(const T& val, char **bufferpptr, char *bufferptrmax) {
223 static_assert(std::is_trivially_constructible<T>::value);
224 const size_t size = sizeof(val);
225 if (*bufferpptr + size > bufferptrmax) {
226 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
227 return BAD_VALUE;
228 }
229 memcpy(*bufferpptr, &val, size);
230 *bufferpptr += size;
231 return NO_ERROR;
232 }
233 template <> // static
234 status_t insert(const std::string& val, char **bufferpptr, char *bufferptrmax) {
235 const size_t size = val.size() + 1;
236 if (size > UINT16_MAX || *bufferpptr + size > bufferptrmax) {
237 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
238 return BAD_VALUE;
239 }
240 memcpy(*bufferpptr, val.c_str(), size);
241 *bufferpptr += size;
242 return NO_ERROR;
243 }
244 template <> // static
245 status_t insert(const std::pair<int64_t, int64_t>& val,
246 char **bufferpptr, char *bufferptrmax) {
247 const size_t size = sizeof(val.first) + sizeof(val.second);
248 if (*bufferpptr + size > bufferptrmax) {
249 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
250 return BAD_VALUE;
251 }
252 memcpy(*bufferpptr, &val.first, sizeof(val.first));
253 memcpy(*bufferpptr + sizeof(val.first), &val.second, sizeof(val.second));
254 *bufferpptr += size;
255 return NO_ERROR;
256 }
257 template <> // static
258 status_t insert(const std::monostate&, char **, char *) {
259 return NO_ERROR;
260 }
261 // for speed
262 static status_t insert(const char *val, char **bufferpptr, char *bufferptrmax) {
263 const size_t size = strlen(val) + 1;
264 if (size > UINT16_MAX || *bufferpptr + size > bufferptrmax) {
265 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
266 return BAD_VALUE;
267 }
268 memcpy(*bufferpptr, val, size);
269 *bufferpptr += size;
270 return NO_ERROR;
271 }
272
273 template <typename T>
274 static status_t writeToByteString(
275 const char *name, const T& value, char **bufferpptr, char *bufferptrmax) {
276 static_assert(is_item_type<T>::value);
277 const size_t len = sizeOfByteString(name, value);
278 if (len > UINT16_MAX) return BAD_VALUE;
279 return insert((uint16_t)len, bufferpptr, bufferptrmax)
280 ?: insert((uint8_t)get_type_of<T>::value, bufferpptr, bufferptrmax)
281 ?: insert(name, bufferpptr, bufferptrmax)
282 ?: insert(value, bufferpptr, bufferptrmax);
283 }
284 // for speed
285 static status_t writeToByteString(
286 const char *name, const char *value, char **bufferpptr, char *bufferptrmax) {
287 const size_t len = sizeOfByteString(name, value);
288 if (len > UINT16_MAX) return BAD_VALUE;
289 return insert((uint16_t)len, bufferpptr, bufferptrmax)
290 ?: insert((uint8_t)kTypeCString, bufferpptr, bufferptrmax)
291 ?: insert(name, bufferpptr, bufferptrmax)
292 ?: insert(value, bufferpptr, bufferptrmax);
293 }
294
295 template <typename T>
296 static void toStringBuffer(
297 const char *name, const T& value, char *buffer, size_t length) = delete;
298 template <> // static
299 void toStringBuffer(
300 const char *name, const int32_t& value, char *buffer, size_t length) {
301 snprintf(buffer, length, "%s=%d:", name, value);
302 }
303 template <> // static
304 void toStringBuffer(
305 const char *name, const int64_t& value, char *buffer, size_t length) {
306 snprintf(buffer, length, "%s=%lld:", name, (long long)value);
307 }
308 template <> // static
309 void toStringBuffer(
310 const char *name, const double& value, char *buffer, size_t length) {
311 snprintf(buffer, length, "%s=%e:", name, value);
312 }
313 template <> // static
314 void toStringBuffer(
315 const char *name, const std::pair<int64_t, int64_t>& value,
316 char *buffer, size_t length) {
317 snprintf(buffer, length, "%s=%lld/%lld:",
318 name, (long long)value.first, (long long)value.second);
319 }
320 template <> // static
321 void toStringBuffer(
322 const char *name, const std::string& value, char *buffer, size_t length) {
323 // TODO sanitize string for ':' '='
324 snprintf(buffer, length, "%s=%s:", name, value.c_str());
325 }
326 template <> // static
327 void toStringBuffer(
328 const char *name, const std::monostate&, char *buffer, size_t length) {
329 snprintf(buffer, length, "%s=():", name);
330 }
331
332 template <typename T>
333 static status_t writeToParcel(
334 const char *name, const T& value, Parcel *parcel) = delete;
335 template <> // static
336 status_t writeToParcel(
337 const char *name, const int32_t& value, Parcel *parcel) {
338 return parcel->writeCString(name)
339 ?: parcel->writeInt32(get_type_of<int32_t>::value)
340 ?: parcel->writeInt32(value);
341 }
342 template <> // static
343 status_t writeToParcel(
344 const char *name, const int64_t& value, Parcel *parcel) {
345 return parcel->writeCString(name)
346 ?: parcel->writeInt32(get_type_of<int64_t>::value)
347 ?: parcel->writeInt64(value);
348 }
349 template <> // static
350 status_t writeToParcel(
351 const char *name, const double& value, Parcel *parcel) {
352 return parcel->writeCString(name)
353 ?: parcel->writeInt32(get_type_of<double>::value)
354 ?: parcel->writeDouble(value);
355 }
356 template <> // static
357 status_t writeToParcel(
358 const char *name, const std::pair<int64_t, int64_t>& value, Parcel *parcel) {
359 return parcel->writeCString(name)
360 ?: parcel->writeInt32(get_type_of< std::pair<int64_t, int64_t>>::value)
361 ?: parcel->writeInt64(value.first)
362 ?: parcel->writeInt64(value.second);
363 }
364 template <> // static
365 status_t writeToParcel(
366 const char *name, const std::string& value, Parcel *parcel) {
367 return parcel->writeCString(name)
368 ?: parcel->writeInt32(get_type_of<std::string>::value)
369 ?: parcel->writeCString(value.c_str());
370 }
371 template <> // static
372 status_t writeToParcel(
373 const char *name, const std::monostate&, Parcel *parcel) {
374 return parcel->writeCString(name)
375 ?: parcel->writeInt32(get_type_of<std::monostate>::value);
376 }
377
378 template <typename T>
379 static status_t extract(T *val, const char **bufferpptr, const char *bufferptrmax) {
380 static_assert(std::is_trivially_constructible<T>::value);
381 const size_t size = sizeof(*val);
382 if (*bufferpptr + size > bufferptrmax) {
383 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
384 return BAD_VALUE;
385 }
386 memcpy(val, *bufferpptr, size);
387 *bufferpptr += size;
388 return NO_ERROR;
389 }
390 template <> // static
391 status_t extract(std::string *val, const char **bufferpptr, const char *bufferptrmax) {
392 const char *ptr = *bufferpptr;
393 while (*ptr != 0) {
394 if (ptr >= bufferptrmax) {
395 ALOGE("%s: buffer exceeded", __func__);
396 return BAD_VALUE;
397 }
398 ++ptr;
399 }
400 const size_t size = (ptr - *bufferpptr) + 1;
401 *val = *bufferpptr;
402 *bufferpptr += size;
403 return NO_ERROR;
404 }
405 template <> // static
406 status_t extract(std::pair<int64_t, int64_t> *val,
407 const char **bufferpptr, const char *bufferptrmax) {
408 const size_t size = sizeof(val->first) + sizeof(val->second);
409 if (*bufferpptr + size > bufferptrmax) {
410 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
411 return BAD_VALUE;
412 }
413 memcpy(&val->first, *bufferpptr, sizeof(val->first));
414 memcpy(&val->second, *bufferpptr + sizeof(val->first), sizeof(val->second));
415 *bufferpptr += size;
416 return NO_ERROR;
417 }
418 template <> // static
419 status_t extract(std::monostate *, const char **, const char *) {
420 return NO_ERROR;
421 }
Andy Hung1efc9c62019-12-03 13:43:33 -0800422};
423
424/**
425 * Media Metrics BufferedItem
426 *
427 * A base class which represents a put-only Media Metrics item, storing
428 * the Media Metrics data in a buffer with begin and end pointers.
429 *
430 * If a property key is entered twice, it will be stored in the buffer twice,
431 * and (implementation defined) the last value for that key will be used
432 * by the Media Metrics service.
433 *
434 * For realloc, a baseRealloc pointer must be passed in either explicitly
435 * or implicitly in the constructor. This will be updated with the value used on realloc.
436 */
437class BufferedItem : public BaseItem {
438public:
439 static inline constexpr uint16_t kVersion = 0;
440
441 virtual ~BufferedItem() = default;
442 BufferedItem(const BufferedItem&) = delete;
443 BufferedItem& operator=(const BufferedItem&) = delete;
444
445 BufferedItem(const std::string key, char *begin, char *end)
446 : BufferedItem(key.c_str(), begin, end) { }
447
448 BufferedItem(const char *key, char *begin, char *end)
449 : BufferedItem(key, begin, end, nullptr) { }
450
451 BufferedItem(const char *key, char **begin, char *end)
452 : BufferedItem(key, *begin, end, begin) { }
453
454 BufferedItem(const char *key, char *begin, char *end, char **baseRealloc)
455 : mBegin(begin)
456 , mEnd(end)
457 , mBaseRealloc(baseRealloc)
458 {
459 init(key);
460 }
461
462 template<typename T>
463 BufferedItem &set(const char *key, const T& value) {
464 reallocFor(sizeOfByteString(key, value));
465 if (mStatus == NO_ERROR) {
466 mStatus = BaseItem::writeToByteString(key, value, &mBptr, mEnd);
467 ++mPropCount;
468 }
469 return *this;
470 }
471
472 template<typename T>
473 BufferedItem &set(const std::string& key, const T& value) {
474 return set(key.c_str(), value);
475 }
476
477 BufferedItem &setPid(pid_t pid) {
478 if (mStatus == NO_ERROR) {
479 copyTo(mBegin + mHeaderLen - 16, (int32_t)pid);
480 }
481 return *this;
482 }
483
484 BufferedItem &setUid(uid_t uid) {
485 if (mStatus == NO_ERROR) {
486 copyTo(mBegin + mHeaderLen - 12, (int32_t)uid);
487 }
488 return *this;
489 }
490
491 BufferedItem &setTimestamp(nsecs_t timestamp) {
492 if (mStatus == NO_ERROR) {
493 copyTo(mBegin + mHeaderLen - 8, (int64_t)timestamp);
494 }
495 return *this;
496 }
497
498 bool record() {
499 return updateHeader()
500 && BaseItem::submitBuffer(getBuffer(), getLength());
501 }
502
503 bool isValid () const {
504 return mStatus == NO_ERROR;
505 }
506
507 char *getBuffer() const { return mBegin; }
508 size_t getLength() const { return mBptr - mBegin; }
509 size_t getRemaining() const { return mEnd - mBptr; }
510 size_t getCapacity() const { return mEnd - mBegin; }
511
512 bool updateHeader() {
513 if (mStatus != NO_ERROR) return false;
514 copyTo(mBegin + 0, (uint32_t)getLength());
515 copyTo(mBegin + 4, (uint32_t)mHeaderLen);
516 copyTo(mBegin + mHeaderLen, (uint32_t)mPropCount);
517 return true;
518 }
519
520protected:
521 BufferedItem() = default;
522
523 void reallocFor(size_t required) {
524 if (mStatus != NO_ERROR) return;
525 const size_t remaining = getRemaining();
526 if (required <= remaining) return;
527 if (mBaseRealloc == nullptr) {
528 mStatus = NO_MEMORY;
529 return;
530 }
531
532 const size_t current = getLength();
533 size_t minimum = current + required;
534 if (minimum > SSIZE_MAX >> 1) {
535 mStatus = NO_MEMORY;
536 return;
537 }
538 minimum <<= 1;
539 void *newptr = realloc(*mBaseRealloc, minimum);
540 if (newptr == nullptr) {
541 mStatus = NO_MEMORY;
542 return;
543 }
544 if (newptr != *mBaseRealloc) {
545 // ALOGD("base changed! current:%zu new size %zu", current, minimum);
546 if (*mBaseRealloc == nullptr) {
547 memcpy(newptr, mBegin, current);
548 }
549 mBegin = (char *)newptr;
550 *mBaseRealloc = mBegin;
551 mEnd = mBegin + minimum;
552 mBptr = mBegin + current;
553 } else {
554 // ALOGD("base kept! current:%zu new size %zu", current, minimum);
555 mEnd = mBegin + minimum;
556 }
557 }
558 template<typename T>
559 void copyTo(char *ptr, const T& value) {
560 memcpy(ptr, &value, sizeof(value));
561 }
562
563 void init(const char *key) {
564 mBptr = mBegin;
565 const size_t keylen = strlen(key) + 1;
566 mHeaderLen = 4 + 4 + 2 + 2 + keylen + 4 + 4 + 8;
567 reallocFor(mHeaderLen);
568 if (mStatus != NO_ERROR) return;
569 mBptr = mBegin + mHeaderLen + 4; // this includes propcount.
570
571 if (mEnd < mBptr || keylen > UINT16_MAX) {
572 mStatus = NO_MEMORY;
573 mBptr = mEnd;
574 return;
575 }
576 copyTo(mBegin + 8, kVersion);
577 copyTo(mBegin + 10, (uint16_t)keylen);
578 strcpy(mBegin + 12, key);
579
580 // initialize some parameters (that could be overridden)
581 setPid(-1);
582 setUid(-1);
583 setTimestamp(0);
584 }
585
586 char *mBegin = nullptr;
587 char *mEnd = nullptr;
588 char **mBaseRealloc = nullptr; // set to an address if realloc should be done.
589 // upon return, that pointer is updated with
590 // whatever needs to be freed.
591 char *mBptr = nullptr;
592 status_t mStatus = NO_ERROR;
593 uint32_t mPropCount = 0;
594 uint32_t mHeaderLen = 0;
595};
596
597/**
Andy Hung47e58d62019-12-06 18:40:19 -0800598 * MediaMetrics LogItem is a stack allocated mediametrics item used for
Andy Hung1efc9c62019-12-03 13:43:33 -0800599 * fast logging. It falls over to a malloc if needed.
600 *
601 * This is templated with a buffer size to allocate on the stack.
602 */
603template <size_t N = 4096>
Ray Essickf27e9872019-12-07 06:28:46 -0800604class LogItem : public BufferedItem {
Andy Hung1efc9c62019-12-03 13:43:33 -0800605public:
Ray Essickf27e9872019-12-07 06:28:46 -0800606 explicit LogItem(const std::string key) : LogItem(key.c_str()) { }
Andy Hung1efc9c62019-12-03 13:43:33 -0800607
608 // Since this class will not be defined before the base class, we initialize variables
609 // in our own order.
Ray Essickf27e9872019-12-07 06:28:46 -0800610 explicit LogItem(const char *key) {
Andy Hung1efc9c62019-12-03 13:43:33 -0800611 mBegin = mBuffer;
612 mEnd = mBuffer + N;
613 mBaseRealloc = &mReallocPtr;
614 init(key);
615 }
616
Ray Essickf27e9872019-12-07 06:28:46 -0800617 ~LogItem() override {
Andy Hung1efc9c62019-12-03 13:43:33 -0800618 if (mReallocPtr != nullptr) { // do the check before calling free to avoid overhead.
619 free(mReallocPtr);
620 }
621 }
622
623private:
624 char *mReallocPtr = nullptr; // set non-null by base class if realloc happened.
625 char mBuffer[N];
626};
627
Andy Hung1efc9c62019-12-03 13:43:33 -0800628
Andy Hung3253f2d2019-10-21 14:50:07 -0700629/**
Ray Essickf27e9872019-12-07 06:28:46 -0800630 * Media Metrics Item
Andy Hung3253f2d2019-10-21 14:50:07 -0700631 *
632 * A mutable item representing an event or record that will be
Andy Hung1efc9c62019-12-03 13:43:33 -0800633 * logged with the Media Metrics service. For client logging, one should
634 * use the mediametrics::Item.
Andy Hung3253f2d2019-10-21 14:50:07 -0700635 *
Ray Essickf27e9872019-12-07 06:28:46 -0800636 * The Item is designed for the service as it has getters.
Andy Hung3253f2d2019-10-21 14:50:07 -0700637 */
Andy Hung565cc482020-01-02 13:40:04 -0800638class Item final : public mediametrics::BaseItem {
Andy Hungaeef7882019-10-18 15:18:14 -0700639public:
Ray Essick3938dc62016-11-01 08:56:56 -0700640
Andy Hung2ecacc42020-01-02 13:29:50 -0800641 class Prop {
642 public:
643 using Elem = std::variant<
644 std::monostate, // kTypeNone
645 int32_t, // kTypeInt32
646 int64_t, // kTypeInt64
647 double, // kTypeDouble
648 std::string, // kTypeCString
649 std::pair<int64_t, int64_t> // kTypeRate
650 >;
651
652 Prop() = default;
653 Prop(const Prop& other) {
654 *this = other;
655 }
656 Prop& operator=(const Prop& other) {
657 mName = other.mName;
658 mElem = other.mElem;
659 return *this;
660 }
661 Prop(Prop&& other) {
662 *this = std::move(other);
663 }
664 Prop& operator=(Prop&& other) {
665 mName = std::move(other.mName);
666 mElem = std::move(other.mElem);
667 return *this;
668 }
669
670 bool operator==(const Prop& other) const {
671 return mName == other.mName && mElem == other.mElem;
672 }
673 bool operator!=(const Prop& other) const {
674 return !(*this == other);
675 }
676
677 void clear() {
678 mName.clear();
679 mElem = std::monostate{};
680 }
681 void clearValue() {
682 mElem = std::monostate{};
683 }
684
685 const char *getName() const {
686 return mName.c_str();
687 }
688
689 void swap(Prop& other) {
690 std::swap(mName, other.mName);
691 std::swap(mElem, other.mElem);
692 }
693
694 void setName(const char *name) {
695 mName = name;
696 }
697
698 bool isNamed(const char *name) const {
699 return mName == name;
700 }
701
702 template <typename T> void visit(T f) const {
703 std::visit(f, mElem);
704 }
705
706 template <typename T> bool get(T *value) const {
707 auto pval = std::get_if<T>(&mElem);
708 if (pval != nullptr) {
709 *value = *pval;
710 return true;
711 }
712 return false;
713 }
714
715 const Elem& get() const {
716 return mElem;
717 }
718
719 template <typename T> void set(const T& value) {
720 mElem = value;
721 }
722
723 template <typename T> void add(const T& value) {
724 auto pval = std::get_if<T>(&mElem);
725 if (pval != nullptr) {
726 *pval += value;
727 } else {
728 mElem = value;
729 }
730 }
731
732 template <> void add(const std::pair<int64_t, int64_t>& value) {
733 auto pval = std::get_if<std::pair<int64_t, int64_t>>(&mElem);
734 if (pval != nullptr) {
735 pval->first += value.first;
736 pval->second += value.second;
737 } else {
738 mElem = value;
739 }
740 }
741
742 status_t writeToParcel(Parcel *parcel) const {
743 return std::visit([this, parcel](auto &value) {
744 return BaseItem::writeToParcel(mName.c_str(), value, parcel);}, mElem);
745 }
746
747 void toStringBuffer(char *buffer, size_t length) const {
748 return std::visit([this, buffer, length](auto &value) {
749 BaseItem::toStringBuffer(mName.c_str(), value, buffer, length);}, mElem);
750 }
751
752 size_t getByteStringSize() const {
753 return std::visit([this](auto &value) {
754 return BaseItem::sizeOfByteString(mName.c_str(), value);}, mElem);
755 }
756
757 status_t writeToByteString(char **bufferpptr, char *bufferptrmax) const {
758 return std::visit([this, bufferpptr, bufferptrmax](auto &value) {
759 return BaseItem::writeToByteString(mName.c_str(), value, bufferpptr, bufferptrmax);
760 }, mElem);
761 }
762
763 status_t readFromParcel(const Parcel& data);
764
765 status_t readFromByteString(const char **bufferpptr, const char *bufferptrmax);
766
767 private:
768 std::string mName;
769 Elem mElem;
770 };
771
772 // Iteration of props within item
773 class iterator {
774 public:
775 iterator(const std::map<std::string, Prop>::const_iterator &_it) : it(_it) { }
776 iterator &operator++() {
777 ++it;
778 return *this;
779 }
780 bool operator!=(iterator &other) const {
781 return it != other.it;
782 }
783 const Prop &operator*() const {
784 return it->second;
785 }
786
787 private:
788 std::map<std::string, Prop>::const_iterator it;
789 };
790
791 iterator begin() const {
792 return iterator(mProps.cbegin());
793 }
794
795 iterator end() const {
796 return iterator(mProps.cend());
797 }
798
Ray Essickf65f4212017-08-31 11:41:19 -0700799 enum {
800 PROTO_V0 = 0,
801 PROTO_FIRST = PROTO_V0,
802 PROTO_V1 = 1,
803 PROTO_LAST = PROTO_V1,
804 };
805
Andy Hungaeef7882019-10-18 15:18:14 -0700806 // T must be convertible to mKey
807 template <typename T>
Ray Essickf27e9872019-12-07 06:28:46 -0800808 explicit Item(T key)
Andy Hungaeef7882019-10-18 15:18:14 -0700809 : mKey(key) { }
Ray Essickf27e9872019-12-07 06:28:46 -0800810 Item() = default;
Andy Hung3253f2d2019-10-21 14:50:07 -0700811
Andy Hung565cc482020-01-02 13:40:04 -0800812 // We enable default copy and move constructors and make this class final
813 // to prevent a derived class; this avoids possible data slicing.
814 Item(const Item& other) = default;
815 Item(Item&& other) = default;
816 Item& operator=(const Item& other) = default;
817 Item& operator=(Item&& other) = default;
818
Ray Essickf27e9872019-12-07 06:28:46 -0800819 bool operator==(const Item& other) const {
Andy Hung692870b2020-01-02 13:46:06 -0800820 return mPid == other.mPid
821 && mUid == other.mUid
822 && mPkgName == other.mPkgName
823 && mPkgVersionCode == other.mPkgVersionCode
824 && mKey == other.mKey
825 && mTimestamp == other.mTimestamp
826 && mProps == other.mProps
827 ;
Andy Hung3253f2d2019-10-21 14:50:07 -0700828 }
Ray Essickf27e9872019-12-07 06:28:46 -0800829 bool operator!=(const Item& other) const {
Andy Hung3253f2d2019-10-21 14:50:07 -0700830 return !(*this == other);
831 }
832
833 template <typename T>
Ray Essickf27e9872019-12-07 06:28:46 -0800834 static Item* create(T key) {
835 return new Item(key);
Andy Hung3253f2d2019-10-21 14:50:07 -0700836 }
Ray Essickf27e9872019-12-07 06:28:46 -0800837 static Item* create() {
838 return new Item();
Andy Hung3253f2d2019-10-21 14:50:07 -0700839 }
Ray Essickba8c4842019-01-18 11:35:33 -0800840
Ray Essickf27e9872019-12-07 06:28:46 -0800841 static Item* convert(mediametrics_handle_t);
842 static mediametrics_handle_t convert(Item *);
Ray Essickbf536ac2019-08-26 11:04:28 -0700843
Ray Essick3938dc62016-11-01 08:56:56 -0700844 // access functions for the class
Ray Essickf27e9872019-12-07 06:28:46 -0800845 ~Item();
Ray Essick3938dc62016-11-01 08:56:56 -0700846
Andy Hung47e58d62019-12-06 18:40:19 -0800847 void clear() {
848 mPid = -1;
849 mUid = -1;
850 mPkgName.clear();
851 mPkgVersionCode = 0;
852 mTimestamp = 0;
853 mKey.clear();
854 mProps.clear();
855 }
856
857 Item *dup() const { return new Item(*this); }
Ray Essick3938dc62016-11-01 08:56:56 -0700858
Ray Essickf27e9872019-12-07 06:28:46 -0800859 Item &setKey(const char *key) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700860 mKey = key;
861 return *this;
862 }
863 const std::string& getKey() const { return mKey; }
Ray Essick3938dc62016-11-01 08:56:56 -0700864
Andy Hung3253f2d2019-10-21 14:50:07 -0700865 // # of properties in the record
Andy Hung47e58d62019-12-06 18:40:19 -0800866 size_t count() const { return mProps.size(); }
Ray Essick3938dc62016-11-01 08:56:56 -0700867
Andy Hungaeef7882019-10-18 15:18:14 -0700868 template<typename S, typename T>
Ray Essickf27e9872019-12-07 06:28:46 -0800869 Item &set(S key, T value) {
Andy Hung47e58d62019-12-06 18:40:19 -0800870 findOrAllocateProp(key).set(value);
Andy Hungaeef7882019-10-18 15:18:14 -0700871 return *this;
872 }
Ray Essick3938dc62016-11-01 08:56:56 -0700873
Andy Hungaeef7882019-10-18 15:18:14 -0700874 // set values appropriately
Ray Essickf27e9872019-12-07 06:28:46 -0800875 Item &setInt32(const char *key, int32_t value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700876 return set(key, value);
877 }
Ray Essickf27e9872019-12-07 06:28:46 -0800878 Item &setInt64(const char *key, int64_t value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700879 return set(key, value);
880 }
Ray Essickf27e9872019-12-07 06:28:46 -0800881 Item &setDouble(const char *key, double value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700882 return set(key, value);
883 }
Ray Essickf27e9872019-12-07 06:28:46 -0800884 Item &setRate(const char *key, int64_t count, int64_t duration) {
Andy Hungaeef7882019-10-18 15:18:14 -0700885 return set(key, std::make_pair(count, duration));
886 }
Ray Essickf27e9872019-12-07 06:28:46 -0800887 Item &setCString(const char *key, const char *value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700888 return set(key, value);
889 }
Ray Essick3938dc62016-11-01 08:56:56 -0700890
Andy Hungaeef7882019-10-18 15:18:14 -0700891 // fused get/add/set; if attr wasn't there, it's a simple set.
892 // type-mismatch counts as "wasn't there".
893 template<typename S, typename T>
Ray Essickf27e9872019-12-07 06:28:46 -0800894 Item &add(S key, T value) {
Andy Hung47e58d62019-12-06 18:40:19 -0800895 findOrAllocateProp(key).add(value);
Andy Hungaeef7882019-10-18 15:18:14 -0700896 return *this;
897 }
898
Ray Essickf27e9872019-12-07 06:28:46 -0800899 Item &addInt32(const char *key, int32_t value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700900 return add(key, value);
901 }
Ray Essickf27e9872019-12-07 06:28:46 -0800902 Item &addInt64(const char *key, int64_t value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700903 return add(key, value);
904 }
Ray Essickf27e9872019-12-07 06:28:46 -0800905 Item &addDouble(const char *key, double value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700906 return add(key, value);
907 }
Ray Essickf27e9872019-12-07 06:28:46 -0800908 Item &addRate(const char *key, int64_t count, int64_t duration) {
Andy Hungaeef7882019-10-18 15:18:14 -0700909 return add(key, std::make_pair(count, duration));
910 }
911
912 // find & extract values
913 // return indicates whether attr exists (and thus value filled in)
914 // NULL parameter value suppresses storage of value.
915 template<typename S, typename T>
916 bool get(S key, T *value) const {
Andy Hung47e58d62019-12-06 18:40:19 -0800917 const Prop *prop = findProp(key);
Andy Hungaeef7882019-10-18 15:18:14 -0700918 return prop != nullptr && prop->get(value);
919 }
920
Andy Hung3253f2d2019-10-21 14:50:07 -0700921 bool getInt32(const char *key, int32_t *value) const {
Andy Hungaeef7882019-10-18 15:18:14 -0700922 return get(key, value);
923 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700924 bool getInt64(const char *key, int64_t *value) const {
Andy Hungaeef7882019-10-18 15:18:14 -0700925 return get(key, value);
926 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700927 bool getDouble(const char *key, double *value) const {
Andy Hungaeef7882019-10-18 15:18:14 -0700928 return get(key, value);
929 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700930 bool getRate(const char *key, int64_t *count, int64_t *duration, double *rate) const {
Andy Hungaeef7882019-10-18 15:18:14 -0700931 std::pair<int64_t, int64_t> value;
932 if (!get(key, &value)) return false;
933 if (count != nullptr) *count = value.first;
934 if (duration != nullptr) *duration = value.second;
935 if (rate != nullptr) {
936 if (value.second != 0) {
937 *rate = (double)value.first / value.second; // TODO: isn't INF OK?
938 } else {
939 *rate = 0.;
940 }
941 }
942 return true;
943 }
944 // Caller owns the returned string
Andy Hung3253f2d2019-10-21 14:50:07 -0700945 bool getCString(const char *key, char **value) const {
Andy Hungb7aadb32019-12-09 19:40:42 -0800946 std::string s;
947 if (get(key, &s)) {
948 *value = strdup(s.c_str());
Andy Hung3253f2d2019-10-21 14:50:07 -0700949 return true;
950 }
951 return false;
Andy Hungaeef7882019-10-18 15:18:14 -0700952 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700953 bool getString(const char *key, std::string *value) const {
Andy Hungaeef7882019-10-18 15:18:14 -0700954 return get(key, value);
955 }
Ray Essick3938dc62016-11-01 08:56:56 -0700956
Andy Hung692870b2020-01-02 13:46:06 -0800957 const Prop::Elem* get(const char *key) const {
958 const Prop *prop = findProp(key);
959 return prop == nullptr ? nullptr : &prop->get();
960 }
961
Andy Hunga87e69c2019-10-18 10:07:40 -0700962 // Deliver the item to MediaMetrics
Ray Essick3938dc62016-11-01 08:56:56 -0700963 bool selfrecord();
964
Andy Hung3253f2d2019-10-21 14:50:07 -0700965 // remove indicated attributes and their values
966 // filterNot() could also be called keepOnly()
967 // return value is # attributes removed
968 // XXX: perhaps 'remove' instead of 'filter'
969 // XXX: filterNot would become 'keep'
970 size_t filter(size_t count, const char *attrs[]);
971 size_t filterNot(size_t count, const char *attrs[]);
972 size_t filter(const char *attr) { return filter(1, &attr); }
Ray Essick3938dc62016-11-01 08:56:56 -0700973
974 // below here are used on server side or to talk to server
975 // clients need not worry about these.
976
977 // timestamp, pid, and uid only used on server side
Ray Essickb5fac8e2016-12-12 11:33:56 -0800978 // timestamp is in 'nanoseconds, unix time'
Ray Essickf27e9872019-12-07 06:28:46 -0800979 Item &setTimestamp(nsecs_t);
Ray Essick3938dc62016-11-01 08:56:56 -0700980 nsecs_t getTimestamp() const;
981
Ray Essickf27e9872019-12-07 06:28:46 -0800982 Item &setPid(pid_t);
Ray Essick3938dc62016-11-01 08:56:56 -0700983 pid_t getPid() const;
984
Ray Essickf27e9872019-12-07 06:28:46 -0800985 Item &setUid(uid_t);
Ray Essick3938dc62016-11-01 08:56:56 -0700986 uid_t getUid() const;
987
Ray Essickf27e9872019-12-07 06:28:46 -0800988 Item &setPkgName(const std::string &pkgName);
Ray Essick783bd0d2018-01-11 11:10:35 -0800989 std::string getPkgName() const { return mPkgName; }
Ray Essickf65f4212017-08-31 11:41:19 -0700990
Ray Essickf27e9872019-12-07 06:28:46 -0800991 Item &setPkgVersionCode(int64_t);
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800992 int64_t getPkgVersionCode() const;
Ray Essickf65f4212017-08-31 11:41:19 -0700993
Andy Hung3253f2d2019-10-21 14:50:07 -0700994 // our serialization code for binder calls
995 status_t writeToParcel(Parcel *) const;
996 status_t readFromParcel(const Parcel&);
Ray Essick3938dc62016-11-01 08:56:56 -0700997
Andy Hung3253f2d2019-10-21 14:50:07 -0700998 status_t writeToByteString(char **bufferptr, size_t *length) const;
999 status_t readFromByteString(const char *bufferptr, size_t length);
1000
Ray Essickba8c4842019-01-18 11:35:33 -08001001
Andy Hung17dbaf22019-10-11 14:06:31 -07001002 std::string toString() const;
1003 std::string toString(int version) const;
Ray Essick20147322018-11-17 09:08:39 -08001004 const char *toCString();
1005 const char *toCString(int version);
Ray Essick3938dc62016-11-01 08:56:56 -07001006
Andy Hung3253f2d2019-10-21 14:50:07 -07001007private:
1008 // handle Parcel version 0
1009 int32_t writeToParcel0(Parcel *) const;
1010 int32_t readFromParcel0(const Parcel&);
1011
Andy Hung47e58d62019-12-06 18:40:19 -08001012 const Prop *findProp(const char *key) const {
1013 auto it = mProps.find(key);
1014 return it != mProps.end() ? &it->second : nullptr;
1015 }
Andy Hungaeef7882019-10-18 15:18:14 -07001016
Andy Hung47e58d62019-12-06 18:40:19 -08001017 Prop &findOrAllocateProp(const char *key) {
1018 auto it = mProps.find(key);
1019 if (it != mProps.end()) return it->second;
1020 Prop &prop = mProps[key];
1021 prop.setName(key);
1022 return prop;
1023 }
Andy Hungaeef7882019-10-18 15:18:14 -07001024
Andy Hung565cc482020-01-02 13:40:04 -08001025 // Changes to member variables below require changes to clear().
Andy Hungaeef7882019-10-18 15:18:14 -07001026 pid_t mPid = -1;
1027 uid_t mUid = -1;
1028 std::string mPkgName;
1029 int64_t mPkgVersionCode = 0;
Andy Hung47e58d62019-12-06 18:40:19 -08001030 std::string mKey;
Andy Hungaeef7882019-10-18 15:18:14 -07001031 nsecs_t mTimestamp = 0;
Andy Hung47e58d62019-12-06 18:40:19 -08001032 std::map<std::string, Prop> mProps;
Ray Essick3938dc62016-11-01 08:56:56 -07001033};
1034
Ray Essickf27e9872019-12-07 06:28:46 -08001035} // namespace mediametrics
Ray Essick3938dc62016-11-01 08:56:56 -07001036} // namespace android
1037
Andy Hung47e58d62019-12-06 18:40:19 -08001038#endif // ANDROID_MEDIA_MEDIAMETRICSITEM_H