blob: 8477f8d3672a0fd5f39025c7c5b822a02d10b3c1 [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"
Andy Hungb68f5eb2019-12-03 16:49:17 -080021#include "MediaMetricsConstants.h"
Ray Essickbf536ac2019-08-26 11:04:28 -070022
Andy Hung3253f2d2019-10-21 14:50:07 -070023#include <algorithm>
Andy Hung47e58d62019-12-06 18:40:19 -080024#include <map>
Ray Essick783bd0d2018-01-11 11:10:35 -080025#include <string>
Ray Essick3938dc62016-11-01 08:56:56 -070026#include <sys/types.h>
Andy Hungb7aadb32019-12-09 19:40:42 -080027#include <variant>
Ray Essickba8c4842019-01-18 11:35:33 -080028
Andy Hungb7aadb32019-12-09 19:40:42 -080029#include <binder/Parcel.h>
Ray Essickba8c4842019-01-18 11:35:33 -080030#include <cutils/properties.h>
Ray Essick3938dc62016-11-01 08:56:56 -070031#include <utils/Errors.h>
32#include <utils/KeyedVector.h>
33#include <utils/RefBase.h>
34#include <utils/StrongPointer.h>
35#include <utils/Timers.h>
36
Ray Essick3938dc62016-11-01 08:56:56 -070037namespace android {
38
Ray Essickf27e9872019-12-07 06:28:46 -080039class IMediaMetricsService;
Ray Essick783bd0d2018-01-11 11:10:35 -080040class Parcel;
Ray Essick3938dc62016-11-01 08:56:56 -070041
Andy Hung3253f2d2019-10-21 14:50:07 -070042/*
Andy Hung1efc9c62019-12-03 13:43:33 -080043 * MediaMetrics Item
Andy Hung3253f2d2019-10-21 14:50:07 -070044 *
Andy Hung611268d2019-12-19 13:54:02 -080045 * The MediaMetrics Item allows get/set operations and recording to the service.
46 *
47 * The MediaMetrics LogItem is a faster logging variant. It allows set operations only,
48 * and then recording to the service.
49 *
50 * The Byte String format is as follows:
Andy Hung1efc9c62019-12-03 13:43:33 -080051 *
52 * For Java
53 * int64 corresponds to long
54 * int32, uint32 corresponds to int
55 * uint16 corresponds to char
56 * uint8, int8 corresponds to byte
57 *
Andy Hung611268d2019-12-19 13:54:02 -080058 * For items transmitted from Java, uint8 and uint32 values are limited
59 * to INT8_MAX and INT32_MAX. This constrains the size of large items
60 * to 2GB, which is consistent with ByteBuffer max size. A native item
61 * can conceivably have size of 4GB.
Andy Hung1efc9c62019-12-03 13:43:33 -080062 *
63 * Physical layout of integers and doubles within the MediaMetrics byte string
Andy Hung611268d2019-12-19 13:54:02 -080064 * is in Native / host order, which is usually little endian.
65 *
66 * Note that primitive data (ints, doubles) within a Byte String has
67 * no extra padding or alignment requirements, like ByteBuffer.
Andy Hung1efc9c62019-12-03 13:43:33 -080068 *
69 * -- begin of item
70 * -- begin of header
71 * (uint32) item size: including the item size field
72 * (uint32) header size, including the item size and header size fields.
73 * (uint16) version: exactly 0
74 * (uint16) key size, that is key strlen + 1 for zero termination.
Andy Hung611268d2019-12-19 13:54:02 -080075 * (int8)+ key, a string which is 0 terminated (UTF-8).
Andy Hung3253f2d2019-10-21 14:50:07 -070076 * (int32) pid
77 * (int32) uid
78 * (int64) timestamp
Andy Hung1efc9c62019-12-03 13:43:33 -080079 * -- end of header
80 * -- begin body
81 * (uint32) number of properties
82 * -- repeat for number of properties
83 * (uint16) property size, including property size field itself
Andy Hung3253f2d2019-10-21 14:50:07 -070084 * (uint8) type of property
85 * (int8)+ key string, including 0 termination
Andy Hung1efc9c62019-12-03 13:43:33 -080086 * based on type of property (given above), one of:
Andy Hung3253f2d2019-10-21 14:50:07 -070087 * (int32)
88 * (int64)
89 * (double)
Andy Hung611268d2019-12-19 13:54:02 -080090 * (int8)+ for TYPE_CSTRING, including 0 termination
Andy Hung3253f2d2019-10-21 14:50:07 -070091 * (int64, int64) for rate
Andy Hung1efc9c62019-12-03 13:43:33 -080092 * -- end body
93 * -- end of item
Andy Hung611268d2019-12-19 13:54:02 -080094 *
95 * The Byte String format must match MediaMetrics.java.
Andy Hung3253f2d2019-10-21 14:50:07 -070096 */
97
Andy Hung1efc9c62019-12-03 13:43:33 -080098namespace mediametrics {
99
100// Type must match MediaMetrics.java
101enum Type {
102 kTypeNone = 0,
103 kTypeInt32 = 1,
104 kTypeInt64 = 2,
105 kTypeDouble = 3,
106 kTypeCString = 4,
107 kTypeRate = 5,
108};
109
Andy Hung3b4c1f02020-01-23 18:58:32 -0800110/*
111 * Time printing
112 *
113 * kPrintFormatLong time string is 19 characters (including null termination).
114 * Example Long Form: "03-27 16:47:06.187"
115 * MM DD HH MM SS MS
116 *
117 * kPrintFormatShort time string is 13 characters (including null termination).
118 * Example Short Form: "16:47:06.187"
119 * HH MM SS MS
120 */
121
122enum PrintFormat {
123 kPrintFormatLong = 0,
124 kPrintFormatShort = 1,
125};
126
127/**
128 * Converts real time in ns to a time string object, with format similar to logcat.
129 *
130 * \param ns input real time in nanoseconds to convert.
131 * \param buffer the buffer location to put the converted string.
132 * \param bufferSize the size of buffer in bytes.
133 * \param format format, from enum PrintFormat.
134 */
135void nsToString(
136 int64_t ns, char *buffer, size_t bufferSize, PrintFormat format = kPrintFormatLong);
137
138// Contains the time string
139struct time_string_t {
140 char time[19]; /* minimum size buffer */
141};
142
143/**
144 * Converts real time in ns to a time string object, with format similar to logcat.
145 *
146 * \param ns input real time in nanoseconds to convert.
147 * \param format format, from enum PrintFormat.
148 * \return a time_string_t object with the time string encoded.
149 */
150static inline time_string_t timeStringFromNs(int64_t ns, PrintFormat format = kPrintFormatLong) {
151 time_string_t ts;
152 nsToString(ns, ts.time, sizeof(ts.time), format);
153 return ts;
154}
155
156/**
157 * Finds the end of the common time prefix.
158 *
159 * This is as an option to remove the common time prefix to avoid
160 * unnecessary duplicated strings.
161 *
162 * \param time1 a time string from timeStringFromNs
163 * \param time2 a time string from timeStringFromNs
164 * \return the position where the common time prefix ends. For abbreviated
165 * printing of time2, offset the character pointer by this position.
166 */
167static inline size_t commonTimePrefixPosition(const char *time1, const char *time2) {
168 size_t i;
169
170 // Find location of the first mismatch between strings
171 for (i = 0; ; ++i) {
172 if (time1[i] != time2[i]) {
173 break;
174 }
175 if (time1[i] == 0) {
176 return i; // strings match completely
177 }
178 }
179
180 // Go backwards until we find a delimeter or space.
181 for (; i > 0
182 && isdigit(time1[i]) // still a number
183 && time1[i - 1] != ' '
184 ; --i) {
185 }
186 return i;
187}
188
Andy Hung611268d2019-12-19 13:54:02 -0800189/**
190 * The MediaMetrics Item has special Item properties,
191 * derived internally or through dedicated setters.
192 *
193 * For consistency we use the following keys to represent
194 * these special Item properties when in a generic Bundle
195 * or in a std::map.
196 *
197 * These values must match MediaMetrics.java
198 */
199static inline constexpr const char *BUNDLE_TOTAL_SIZE = "_totalSize";
200static inline constexpr const char *BUNDLE_HEADER_SIZE = "_headerSize";
201static inline constexpr const char *BUNDLE_VERSION = "_version";
202static inline constexpr const char *BUNDLE_KEY_SIZE = "_keySize";
203static inline constexpr const char *BUNDLE_KEY = "_key";
204static inline constexpr const char *BUNDLE_PID = "_pid";
205static inline constexpr const char *BUNDLE_UID = "_uid";
206static inline constexpr const char *BUNDLE_TIMESTAMP = "_timestamp";
207static inline constexpr const char *BUNDLE_PROPERTY_COUNT = "_propertyCount";
208
Andy Hung1efc9c62019-12-03 13:43:33 -0800209template<size_t N>
210static inline bool startsWith(const std::string &s, const char (&comp)[N]) {
Andy Hung709b91e2020-04-04 14:23:36 -0700211 return !strncmp(s.c_str(), comp, N - 1); // last char is null termination
Andy Hung1efc9c62019-12-03 13:43:33 -0800212}
213
Andy Hung37de9b72020-01-02 13:54:05 -0800214static inline bool startsWith(const std::string& s, const std::string& comp) {
Andy Hung709b91e2020-04-04 14:23:36 -0700215 return !strncmp(s.c_str(), comp.c_str(), comp.size());
Andy Hung37de9b72020-01-02 13:54:05 -0800216}
217
218/**
219 * Defers a function to run in the destructor.
220 *
221 * This helper class is used to log results on exit of a method.
222 */
223class Defer {
224public:
225 template <typename U>
Andy Hungb744faf2020-04-09 13:09:26 -0700226 explicit Defer(U &&f) : mThunk(std::forward<U>(f)) {}
Andy Hung37de9b72020-01-02 13:54:05 -0800227 ~Defer() { mThunk(); }
228
229private:
230 const std::function<void()> mThunk;
231};
232
Andy Hung1efc9c62019-12-03 13:43:33 -0800233/**
234 * Media Metrics BaseItem
235 *
236 * A base class which contains utility static functions to write to a byte stream
237 * and access the Media Metrics service.
238 */
239
240class BaseItem {
241 friend class MediaMetricsDeathNotifier; // for dropInstance
242 // enabled 1, disabled 0
243public:
Andy Hung47e58d62019-12-06 18:40:19 -0800244 // are we collecting metrics data
Andy Hung1efc9c62019-12-03 13:43:33 -0800245 static bool isEnabled();
Andy Hung47e58d62019-12-06 18:40:19 -0800246 static sp<IMediaMetricsService> getService();
Andy Hung1efc9c62019-12-03 13:43:33 -0800247
248protected:
249 static constexpr const char * const EnabledProperty = "media.metrics.enabled";
250 static constexpr const char * const EnabledPropertyPersist = "persist.media.metrics.enabled";
251 static const int EnabledProperty_default = 1;
252
253 // let's reuse a binder connection
Ray Essickf27e9872019-12-07 06:28:46 -0800254 static sp<IMediaMetricsService> sMediaMetricsService;
Andy Hung47e58d62019-12-06 18:40:19 -0800255
Andy Hung1efc9c62019-12-03 13:43:33 -0800256 static void dropInstance();
257 static bool submitBuffer(const char *buffer, size_t len);
258
Andy Hungb7aadb32019-12-09 19:40:42 -0800259 template <typename T>
260 struct is_item_type {
261 static constexpr inline bool value =
262 std::is_same<T, int32_t>::value
263 || std::is_same<T, int64_t>::value
264 || std::is_same<T, double>::value
265 || std::is_same<T, std::pair<int64_t, int64_t>>:: value
266 || std::is_same<T, std::string>::value
267 || std::is_same<T, std::monostate>::value;
268 };
Andy Hung1efc9c62019-12-03 13:43:33 -0800269
Andy Hungb7aadb32019-12-09 19:40:42 -0800270 template <typename T>
271 struct get_type_of {
272 static_assert(is_item_type<T>::value);
273 static constexpr inline Type value =
274 std::is_same<T, int32_t>::value ? kTypeInt32
275 : std::is_same<T, int64_t>::value ? kTypeInt64
276 : std::is_same<T, double>::value ? kTypeDouble
277 : std::is_same<T, std::pair<int64_t, int64_t>>:: value ? kTypeRate
278 : std::is_same<T, std::string>::value ? kTypeCString
279 : std::is_same<T, std::monostate>::value ? kTypeNone
280 : kTypeNone;
281 };
282
283 template <typename T>
284 static size_t sizeOfByteString(const char *name, const T& value) {
285 static_assert(is_item_type<T>::value);
Andy Hung1efc9c62019-12-03 13:43:33 -0800286 return 2 + 1 + strlen(name) + 1 + sizeof(value);
287 }
Andy Hungb7aadb32019-12-09 19:40:42 -0800288 template <> // static
289 size_t sizeOfByteString(const char *name, const std::string& value) {
290 return 2 + 1 + strlen(name) + 1 + value.size() + 1;
Andy Hung1efc9c62019-12-03 13:43:33 -0800291 }
Andy Hungb7aadb32019-12-09 19:40:42 -0800292 template <> // static
293 size_t sizeOfByteString(const char *name, const std::monostate&) {
Andy Hung1efc9c62019-12-03 13:43:33 -0800294 return 2 + 1 + strlen(name) + 1;
295 }
Andy Hungb7aadb32019-12-09 19:40:42 -0800296 // for speed
297 static size_t sizeOfByteString(const char *name, const char *value) {
298 return 2 + 1 + strlen(name) + 1 + strlen(value) + 1;
299 }
300
301 template <typename T>
302 static status_t insert(const T& val, char **bufferpptr, char *bufferptrmax) {
303 static_assert(std::is_trivially_constructible<T>::value);
304 const size_t size = sizeof(val);
305 if (*bufferpptr + size > bufferptrmax) {
306 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
307 return BAD_VALUE;
308 }
309 memcpy(*bufferpptr, &val, size);
310 *bufferpptr += size;
311 return NO_ERROR;
312 }
313 template <> // static
314 status_t insert(const std::string& val, char **bufferpptr, char *bufferptrmax) {
315 const size_t size = val.size() + 1;
316 if (size > UINT16_MAX || *bufferpptr + size > bufferptrmax) {
317 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
318 return BAD_VALUE;
319 }
320 memcpy(*bufferpptr, val.c_str(), size);
321 *bufferpptr += size;
322 return NO_ERROR;
323 }
324 template <> // static
325 status_t insert(const std::pair<int64_t, int64_t>& val,
326 char **bufferpptr, char *bufferptrmax) {
327 const size_t size = sizeof(val.first) + sizeof(val.second);
328 if (*bufferpptr + size > bufferptrmax) {
329 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
330 return BAD_VALUE;
331 }
332 memcpy(*bufferpptr, &val.first, sizeof(val.first));
333 memcpy(*bufferpptr + sizeof(val.first), &val.second, sizeof(val.second));
334 *bufferpptr += size;
335 return NO_ERROR;
336 }
337 template <> // static
338 status_t insert(const std::monostate&, char **, char *) {
339 return NO_ERROR;
340 }
341 // for speed
342 static status_t insert(const char *val, char **bufferpptr, char *bufferptrmax) {
343 const size_t size = strlen(val) + 1;
344 if (size > UINT16_MAX || *bufferpptr + size > bufferptrmax) {
345 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
346 return BAD_VALUE;
347 }
348 memcpy(*bufferpptr, val, size);
349 *bufferpptr += size;
350 return NO_ERROR;
351 }
352
353 template <typename T>
354 static status_t writeToByteString(
355 const char *name, const T& value, char **bufferpptr, char *bufferptrmax) {
356 static_assert(is_item_type<T>::value);
357 const size_t len = sizeOfByteString(name, value);
358 if (len > UINT16_MAX) return BAD_VALUE;
359 return insert((uint16_t)len, bufferpptr, bufferptrmax)
360 ?: insert((uint8_t)get_type_of<T>::value, bufferpptr, bufferptrmax)
361 ?: insert(name, bufferpptr, bufferptrmax)
362 ?: insert(value, bufferpptr, bufferptrmax);
363 }
364 // for speed
365 static status_t writeToByteString(
366 const char *name, const char *value, char **bufferpptr, char *bufferptrmax) {
367 const size_t len = sizeOfByteString(name, value);
368 if (len > UINT16_MAX) return BAD_VALUE;
369 return insert((uint16_t)len, bufferpptr, bufferptrmax)
370 ?: insert((uint8_t)kTypeCString, bufferpptr, bufferptrmax)
371 ?: insert(name, bufferpptr, bufferptrmax)
372 ?: insert(value, bufferpptr, bufferptrmax);
373 }
374
375 template <typename T>
376 static void toStringBuffer(
377 const char *name, const T& value, char *buffer, size_t length) = delete;
378 template <> // static
379 void toStringBuffer(
380 const char *name, const int32_t& value, char *buffer, size_t length) {
Andy Hung3b4c1f02020-01-23 18:58:32 -0800381 snprintf(buffer, length, "%s=%d", name, value);
Andy Hungb7aadb32019-12-09 19:40:42 -0800382 }
383 template <> // static
384 void toStringBuffer(
385 const char *name, const int64_t& value, char *buffer, size_t length) {
Andy Hung3b4c1f02020-01-23 18:58:32 -0800386 snprintf(buffer, length, "%s=%lld", name, (long long)value);
Andy Hungb7aadb32019-12-09 19:40:42 -0800387 }
388 template <> // static
389 void toStringBuffer(
390 const char *name, const double& value, char *buffer, size_t length) {
Andy Hung3b4c1f02020-01-23 18:58:32 -0800391 snprintf(buffer, length, "%s=%e", name, value);
Andy Hungb7aadb32019-12-09 19:40:42 -0800392 }
393 template <> // static
394 void toStringBuffer(
395 const char *name, const std::pair<int64_t, int64_t>& value,
396 char *buffer, size_t length) {
Andy Hung3b4c1f02020-01-23 18:58:32 -0800397 snprintf(buffer, length, "%s=%lld/%lld",
Andy Hungb7aadb32019-12-09 19:40:42 -0800398 name, (long long)value.first, (long long)value.second);
399 }
400 template <> // static
401 void toStringBuffer(
402 const char *name, const std::string& value, char *buffer, size_t length) {
403 // TODO sanitize string for ':' '='
Andy Hung3b4c1f02020-01-23 18:58:32 -0800404 snprintf(buffer, length, "%s=%s", name, value.c_str());
Andy Hungb7aadb32019-12-09 19:40:42 -0800405 }
406 template <> // static
407 void toStringBuffer(
408 const char *name, const std::monostate&, char *buffer, size_t length) {
Andy Hung3b4c1f02020-01-23 18:58:32 -0800409 snprintf(buffer, length, "%s=()", name);
Andy Hungb7aadb32019-12-09 19:40:42 -0800410 }
411
412 template <typename T>
413 static status_t writeToParcel(
414 const char *name, const T& value, Parcel *parcel) = delete;
415 template <> // static
416 status_t writeToParcel(
417 const char *name, const int32_t& value, Parcel *parcel) {
418 return parcel->writeCString(name)
419 ?: parcel->writeInt32(get_type_of<int32_t>::value)
420 ?: parcel->writeInt32(value);
421 }
422 template <> // static
423 status_t writeToParcel(
424 const char *name, const int64_t& value, Parcel *parcel) {
425 return parcel->writeCString(name)
426 ?: parcel->writeInt32(get_type_of<int64_t>::value)
427 ?: parcel->writeInt64(value);
428 }
429 template <> // static
430 status_t writeToParcel(
431 const char *name, const double& value, Parcel *parcel) {
432 return parcel->writeCString(name)
433 ?: parcel->writeInt32(get_type_of<double>::value)
434 ?: parcel->writeDouble(value);
435 }
436 template <> // static
437 status_t writeToParcel(
438 const char *name, const std::pair<int64_t, int64_t>& value, Parcel *parcel) {
439 return parcel->writeCString(name)
440 ?: parcel->writeInt32(get_type_of< std::pair<int64_t, int64_t>>::value)
441 ?: parcel->writeInt64(value.first)
442 ?: parcel->writeInt64(value.second);
443 }
444 template <> // static
445 status_t writeToParcel(
446 const char *name, const std::string& value, Parcel *parcel) {
447 return parcel->writeCString(name)
448 ?: parcel->writeInt32(get_type_of<std::string>::value)
449 ?: parcel->writeCString(value.c_str());
450 }
451 template <> // static
452 status_t writeToParcel(
453 const char *name, const std::monostate&, Parcel *parcel) {
454 return parcel->writeCString(name)
455 ?: parcel->writeInt32(get_type_of<std::monostate>::value);
456 }
457
458 template <typename T>
459 static status_t extract(T *val, const char **bufferpptr, const char *bufferptrmax) {
460 static_assert(std::is_trivially_constructible<T>::value);
461 const size_t size = sizeof(*val);
462 if (*bufferpptr + size > bufferptrmax) {
463 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
464 return BAD_VALUE;
465 }
466 memcpy(val, *bufferpptr, size);
467 *bufferpptr += size;
468 return NO_ERROR;
469 }
470 template <> // static
471 status_t extract(std::string *val, const char **bufferpptr, const char *bufferptrmax) {
472 const char *ptr = *bufferpptr;
473 while (*ptr != 0) {
474 if (ptr >= bufferptrmax) {
475 ALOGE("%s: buffer exceeded", __func__);
476 return BAD_VALUE;
477 }
478 ++ptr;
479 }
480 const size_t size = (ptr - *bufferpptr) + 1;
481 *val = *bufferpptr;
482 *bufferpptr += size;
483 return NO_ERROR;
484 }
485 template <> // static
486 status_t extract(std::pair<int64_t, int64_t> *val,
487 const char **bufferpptr, const char *bufferptrmax) {
488 const size_t size = sizeof(val->first) + sizeof(val->second);
489 if (*bufferpptr + size > bufferptrmax) {
490 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
491 return BAD_VALUE;
492 }
493 memcpy(&val->first, *bufferpptr, sizeof(val->first));
494 memcpy(&val->second, *bufferpptr + sizeof(val->first), sizeof(val->second));
495 *bufferpptr += size;
496 return NO_ERROR;
497 }
498 template <> // static
499 status_t extract(std::monostate *, const char **, const char *) {
500 return NO_ERROR;
501 }
Andy Hung1efc9c62019-12-03 13:43:33 -0800502};
503
504/**
505 * Media Metrics BufferedItem
506 *
507 * A base class which represents a put-only Media Metrics item, storing
508 * the Media Metrics data in a buffer with begin and end pointers.
509 *
510 * If a property key is entered twice, it will be stored in the buffer twice,
511 * and (implementation defined) the last value for that key will be used
512 * by the Media Metrics service.
513 *
514 * For realloc, a baseRealloc pointer must be passed in either explicitly
515 * or implicitly in the constructor. This will be updated with the value used on realloc.
516 */
517class BufferedItem : public BaseItem {
518public:
519 static inline constexpr uint16_t kVersion = 0;
520
521 virtual ~BufferedItem() = default;
522 BufferedItem(const BufferedItem&) = delete;
523 BufferedItem& operator=(const BufferedItem&) = delete;
524
Andy Hungb744faf2020-04-09 13:09:26 -0700525 BufferedItem(const std::string& key, char *begin, char *end)
Andy Hung1efc9c62019-12-03 13:43:33 -0800526 : BufferedItem(key.c_str(), begin, end) { }
527
528 BufferedItem(const char *key, char *begin, char *end)
529 : BufferedItem(key, begin, end, nullptr) { }
530
531 BufferedItem(const char *key, char **begin, char *end)
532 : BufferedItem(key, *begin, end, begin) { }
533
534 BufferedItem(const char *key, char *begin, char *end, char **baseRealloc)
535 : mBegin(begin)
536 , mEnd(end)
537 , mBaseRealloc(baseRealloc)
538 {
539 init(key);
540 }
541
542 template<typename T>
543 BufferedItem &set(const char *key, const T& value) {
544 reallocFor(sizeOfByteString(key, value));
545 if (mStatus == NO_ERROR) {
546 mStatus = BaseItem::writeToByteString(key, value, &mBptr, mEnd);
547 ++mPropCount;
548 }
549 return *this;
550 }
551
552 template<typename T>
553 BufferedItem &set(const std::string& key, const T& value) {
554 return set(key.c_str(), value);
555 }
556
557 BufferedItem &setPid(pid_t pid) {
558 if (mStatus == NO_ERROR) {
559 copyTo(mBegin + mHeaderLen - 16, (int32_t)pid);
560 }
561 return *this;
562 }
563
564 BufferedItem &setUid(uid_t uid) {
565 if (mStatus == NO_ERROR) {
566 copyTo(mBegin + mHeaderLen - 12, (int32_t)uid);
567 }
568 return *this;
569 }
570
571 BufferedItem &setTimestamp(nsecs_t timestamp) {
572 if (mStatus == NO_ERROR) {
573 copyTo(mBegin + mHeaderLen - 8, (int64_t)timestamp);
574 }
575 return *this;
576 }
577
578 bool record() {
579 return updateHeader()
580 && BaseItem::submitBuffer(getBuffer(), getLength());
581 }
582
583 bool isValid () const {
584 return mStatus == NO_ERROR;
585 }
586
587 char *getBuffer() const { return mBegin; }
588 size_t getLength() const { return mBptr - mBegin; }
589 size_t getRemaining() const { return mEnd - mBptr; }
590 size_t getCapacity() const { return mEnd - mBegin; }
591
592 bool updateHeader() {
593 if (mStatus != NO_ERROR) return false;
594 copyTo(mBegin + 0, (uint32_t)getLength());
595 copyTo(mBegin + 4, (uint32_t)mHeaderLen);
596 copyTo(mBegin + mHeaderLen, (uint32_t)mPropCount);
597 return true;
598 }
599
600protected:
601 BufferedItem() = default;
602
603 void reallocFor(size_t required) {
604 if (mStatus != NO_ERROR) return;
605 const size_t remaining = getRemaining();
606 if (required <= remaining) return;
607 if (mBaseRealloc == nullptr) {
608 mStatus = NO_MEMORY;
609 return;
610 }
611
612 const size_t current = getLength();
613 size_t minimum = current + required;
614 if (minimum > SSIZE_MAX >> 1) {
615 mStatus = NO_MEMORY;
616 return;
617 }
618 minimum <<= 1;
619 void *newptr = realloc(*mBaseRealloc, minimum);
620 if (newptr == nullptr) {
621 mStatus = NO_MEMORY;
622 return;
623 }
624 if (newptr != *mBaseRealloc) {
625 // ALOGD("base changed! current:%zu new size %zu", current, minimum);
626 if (*mBaseRealloc == nullptr) {
627 memcpy(newptr, mBegin, current);
628 }
629 mBegin = (char *)newptr;
630 *mBaseRealloc = mBegin;
631 mEnd = mBegin + minimum;
632 mBptr = mBegin + current;
633 } else {
634 // ALOGD("base kept! current:%zu new size %zu", current, minimum);
635 mEnd = mBegin + minimum;
636 }
637 }
638 template<typename T>
639 void copyTo(char *ptr, const T& value) {
640 memcpy(ptr, &value, sizeof(value));
641 }
642
643 void init(const char *key) {
644 mBptr = mBegin;
Andy Hungb68f5eb2019-12-03 16:49:17 -0800645 const size_t keylen = key == nullptr ? 0 : strlen(key) + 1;
646 if (keylen <= 1) {
647 mStatus = BAD_VALUE; // prevent null pointer or empty keys.
648 return;
649 }
Andy Hung1efc9c62019-12-03 13:43:33 -0800650 mHeaderLen = 4 + 4 + 2 + 2 + keylen + 4 + 4 + 8;
651 reallocFor(mHeaderLen);
652 if (mStatus != NO_ERROR) return;
653 mBptr = mBegin + mHeaderLen + 4; // this includes propcount.
654
655 if (mEnd < mBptr || keylen > UINT16_MAX) {
656 mStatus = NO_MEMORY;
657 mBptr = mEnd;
658 return;
659 }
660 copyTo(mBegin + 8, kVersion);
661 copyTo(mBegin + 10, (uint16_t)keylen);
662 strcpy(mBegin + 12, key);
663
664 // initialize some parameters (that could be overridden)
665 setPid(-1);
666 setUid(-1);
667 setTimestamp(0);
668 }
669
670 char *mBegin = nullptr;
671 char *mEnd = nullptr;
672 char **mBaseRealloc = nullptr; // set to an address if realloc should be done.
673 // upon return, that pointer is updated with
674 // whatever needs to be freed.
675 char *mBptr = nullptr;
676 status_t mStatus = NO_ERROR;
677 uint32_t mPropCount = 0;
678 uint32_t mHeaderLen = 0;
679};
680
681/**
Andy Hung47e58d62019-12-06 18:40:19 -0800682 * MediaMetrics LogItem is a stack allocated mediametrics item used for
Andy Hung1efc9c62019-12-03 13:43:33 -0800683 * fast logging. It falls over to a malloc if needed.
684 *
685 * This is templated with a buffer size to allocate on the stack.
686 */
687template <size_t N = 4096>
Ray Essickf27e9872019-12-07 06:28:46 -0800688class LogItem : public BufferedItem {
Andy Hung1efc9c62019-12-03 13:43:33 -0800689public:
Andy Hungb744faf2020-04-09 13:09:26 -0700690 explicit LogItem(const std::string& key) : LogItem(key.c_str()) { }
Andy Hung1efc9c62019-12-03 13:43:33 -0800691
692 // Since this class will not be defined before the base class, we initialize variables
693 // in our own order.
Ray Essickf27e9872019-12-07 06:28:46 -0800694 explicit LogItem(const char *key) {
Andy Hung1efc9c62019-12-03 13:43:33 -0800695 mBegin = mBuffer;
696 mEnd = mBuffer + N;
697 mBaseRealloc = &mReallocPtr;
698 init(key);
699 }
700
Ray Essickf27e9872019-12-07 06:28:46 -0800701 ~LogItem() override {
Andy Hung1efc9c62019-12-03 13:43:33 -0800702 if (mReallocPtr != nullptr) { // do the check before calling free to avoid overhead.
703 free(mReallocPtr);
704 }
705 }
706
707private:
708 char *mReallocPtr = nullptr; // set non-null by base class if realloc happened.
709 char mBuffer[N];
710};
711
Andy Hung1efc9c62019-12-03 13:43:33 -0800712
Andy Hung3253f2d2019-10-21 14:50:07 -0700713/**
Ray Essickf27e9872019-12-07 06:28:46 -0800714 * Media Metrics Item
Andy Hung3253f2d2019-10-21 14:50:07 -0700715 *
716 * A mutable item representing an event or record that will be
Andy Hung1efc9c62019-12-03 13:43:33 -0800717 * logged with the Media Metrics service. For client logging, one should
718 * use the mediametrics::Item.
Andy Hung3253f2d2019-10-21 14:50:07 -0700719 *
Ray Essickf27e9872019-12-07 06:28:46 -0800720 * The Item is designed for the service as it has getters.
Andy Hung3253f2d2019-10-21 14:50:07 -0700721 */
Andy Hung565cc482020-01-02 13:40:04 -0800722class Item final : public mediametrics::BaseItem {
Andy Hungaeef7882019-10-18 15:18:14 -0700723public:
Ray Essick3938dc62016-11-01 08:56:56 -0700724
Andy Hung2ecacc42020-01-02 13:29:50 -0800725 class Prop {
726 public:
727 using Elem = std::variant<
728 std::monostate, // kTypeNone
729 int32_t, // kTypeInt32
730 int64_t, // kTypeInt64
731 double, // kTypeDouble
732 std::string, // kTypeCString
733 std::pair<int64_t, int64_t> // kTypeRate
734 >;
735
736 Prop() = default;
737 Prop(const Prop& other) {
738 *this = other;
739 }
740 Prop& operator=(const Prop& other) {
741 mName = other.mName;
742 mElem = other.mElem;
743 return *this;
744 }
Andy Hungb744faf2020-04-09 13:09:26 -0700745 Prop(Prop&& other) noexcept {
Andy Hung2ecacc42020-01-02 13:29:50 -0800746 *this = std::move(other);
747 }
Andy Hungb744faf2020-04-09 13:09:26 -0700748 Prop& operator=(Prop&& other) noexcept {
Andy Hung2ecacc42020-01-02 13:29:50 -0800749 mName = std::move(other.mName);
750 mElem = std::move(other.mElem);
751 return *this;
752 }
753
754 bool operator==(const Prop& other) const {
755 return mName == other.mName && mElem == other.mElem;
756 }
757 bool operator!=(const Prop& other) const {
758 return !(*this == other);
759 }
760
761 void clear() {
762 mName.clear();
763 mElem = std::monostate{};
764 }
765 void clearValue() {
766 mElem = std::monostate{};
767 }
768
769 const char *getName() const {
770 return mName.c_str();
771 }
772
773 void swap(Prop& other) {
774 std::swap(mName, other.mName);
775 std::swap(mElem, other.mElem);
776 }
777
778 void setName(const char *name) {
779 mName = name;
780 }
781
782 bool isNamed(const char *name) const {
783 return mName == name;
784 }
785
786 template <typename T> void visit(T f) const {
787 std::visit(f, mElem);
788 }
789
790 template <typename T> bool get(T *value) const {
791 auto pval = std::get_if<T>(&mElem);
792 if (pval != nullptr) {
793 *value = *pval;
794 return true;
795 }
796 return false;
797 }
798
799 const Elem& get() const {
800 return mElem;
801 }
802
803 template <typename T> void set(const T& value) {
804 mElem = value;
805 }
806
807 template <typename T> void add(const T& value) {
808 auto pval = std::get_if<T>(&mElem);
809 if (pval != nullptr) {
810 *pval += value;
811 } else {
812 mElem = value;
813 }
814 }
815
816 template <> void add(const std::pair<int64_t, int64_t>& value) {
817 auto pval = std::get_if<std::pair<int64_t, int64_t>>(&mElem);
818 if (pval != nullptr) {
819 pval->first += value.first;
820 pval->second += value.second;
821 } else {
822 mElem = value;
823 }
824 }
825
826 status_t writeToParcel(Parcel *parcel) const {
827 return std::visit([this, parcel](auto &value) {
828 return BaseItem::writeToParcel(mName.c_str(), value, parcel);}, mElem);
829 }
830
831 void toStringBuffer(char *buffer, size_t length) const {
832 return std::visit([this, buffer, length](auto &value) {
833 BaseItem::toStringBuffer(mName.c_str(), value, buffer, length);}, mElem);
834 }
835
836 size_t getByteStringSize() const {
837 return std::visit([this](auto &value) {
838 return BaseItem::sizeOfByteString(mName.c_str(), value);}, mElem);
839 }
840
841 status_t writeToByteString(char **bufferpptr, char *bufferptrmax) const {
842 return std::visit([this, bufferpptr, bufferptrmax](auto &value) {
843 return BaseItem::writeToByteString(mName.c_str(), value, bufferpptr, bufferptrmax);
844 }, mElem);
845 }
846
847 status_t readFromParcel(const Parcel& data);
848
849 status_t readFromByteString(const char **bufferpptr, const char *bufferptrmax);
850
851 private:
852 std::string mName;
853 Elem mElem;
854 };
855
856 // Iteration of props within item
857 class iterator {
858 public:
Andy Hungb744faf2020-04-09 13:09:26 -0700859 explicit iterator(const std::map<std::string, Prop>::const_iterator &_it) : it(_it) { }
Andy Hung2ecacc42020-01-02 13:29:50 -0800860 iterator &operator++() {
861 ++it;
862 return *this;
863 }
864 bool operator!=(iterator &other) const {
865 return it != other.it;
866 }
867 const Prop &operator*() const {
868 return it->second;
869 }
870
871 private:
872 std::map<std::string, Prop>::const_iterator it;
873 };
874
875 iterator begin() const {
876 return iterator(mProps.cbegin());
877 }
878
879 iterator end() const {
880 return iterator(mProps.cend());
881 }
882
Andy Hungaeef7882019-10-18 15:18:14 -0700883 // T must be convertible to mKey
884 template <typename T>
Ray Essickf27e9872019-12-07 06:28:46 -0800885 explicit Item(T key)
Andy Hungaeef7882019-10-18 15:18:14 -0700886 : mKey(key) { }
Ray Essickf27e9872019-12-07 06:28:46 -0800887 Item() = default;
Andy Hung3253f2d2019-10-21 14:50:07 -0700888
Andy Hung565cc482020-01-02 13:40:04 -0800889 // We enable default copy and move constructors and make this class final
890 // to prevent a derived class; this avoids possible data slicing.
891 Item(const Item& other) = default;
892 Item(Item&& other) = default;
893 Item& operator=(const Item& other) = default;
894 Item& operator=(Item&& other) = default;
895
Ray Essickf27e9872019-12-07 06:28:46 -0800896 bool operator==(const Item& other) const {
Andy Hung692870b2020-01-02 13:46:06 -0800897 return mPid == other.mPid
898 && mUid == other.mUid
899 && mPkgName == other.mPkgName
900 && mPkgVersionCode == other.mPkgVersionCode
901 && mKey == other.mKey
902 && mTimestamp == other.mTimestamp
903 && mProps == other.mProps
904 ;
Andy Hung3253f2d2019-10-21 14:50:07 -0700905 }
Ray Essickf27e9872019-12-07 06:28:46 -0800906 bool operator!=(const Item& other) const {
Andy Hung3253f2d2019-10-21 14:50:07 -0700907 return !(*this == other);
908 }
909
910 template <typename T>
Ray Essickf27e9872019-12-07 06:28:46 -0800911 static Item* create(T key) {
912 return new Item(key);
Andy Hung3253f2d2019-10-21 14:50:07 -0700913 }
Ray Essickf27e9872019-12-07 06:28:46 -0800914 static Item* create() {
915 return new Item();
Andy Hung3253f2d2019-10-21 14:50:07 -0700916 }
Ray Essickba8c4842019-01-18 11:35:33 -0800917
Ray Essickf27e9872019-12-07 06:28:46 -0800918 static Item* convert(mediametrics_handle_t);
919 static mediametrics_handle_t convert(Item *);
Ray Essickbf536ac2019-08-26 11:04:28 -0700920
Ray Essick3938dc62016-11-01 08:56:56 -0700921 // access functions for the class
Ray Essickf27e9872019-12-07 06:28:46 -0800922 ~Item();
Ray Essick3938dc62016-11-01 08:56:56 -0700923
Andy Hung47e58d62019-12-06 18:40:19 -0800924 void clear() {
925 mPid = -1;
926 mUid = -1;
927 mPkgName.clear();
928 mPkgVersionCode = 0;
929 mTimestamp = 0;
930 mKey.clear();
931 mProps.clear();
932 }
933
934 Item *dup() const { return new Item(*this); }
Ray Essick3938dc62016-11-01 08:56:56 -0700935
Ray Essickf27e9872019-12-07 06:28:46 -0800936 Item &setKey(const char *key) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700937 mKey = key;
938 return *this;
939 }
940 const std::string& getKey() const { return mKey; }
Ray Essick3938dc62016-11-01 08:56:56 -0700941
Andy Hung3253f2d2019-10-21 14:50:07 -0700942 // # of properties in the record
Andy Hung47e58d62019-12-06 18:40:19 -0800943 size_t count() const { return mProps.size(); }
Ray Essick3938dc62016-11-01 08:56:56 -0700944
Andy Hungaeef7882019-10-18 15:18:14 -0700945 template<typename S, typename T>
Ray Essickf27e9872019-12-07 06:28:46 -0800946 Item &set(S key, T value) {
Andy Hung47e58d62019-12-06 18:40:19 -0800947 findOrAllocateProp(key).set(value);
Andy Hungaeef7882019-10-18 15:18:14 -0700948 return *this;
949 }
Ray Essick3938dc62016-11-01 08:56:56 -0700950
Andy Hungaeef7882019-10-18 15:18:14 -0700951 // set values appropriately
Ray Essickf27e9872019-12-07 06:28:46 -0800952 Item &setInt32(const char *key, int32_t value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700953 return set(key, value);
954 }
Ray Essickf27e9872019-12-07 06:28:46 -0800955 Item &setInt64(const char *key, int64_t value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700956 return set(key, value);
957 }
Ray Essickf27e9872019-12-07 06:28:46 -0800958 Item &setDouble(const char *key, double value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700959 return set(key, value);
960 }
Ray Essickf27e9872019-12-07 06:28:46 -0800961 Item &setRate(const char *key, int64_t count, int64_t duration) {
Andy Hungaeef7882019-10-18 15:18:14 -0700962 return set(key, std::make_pair(count, duration));
963 }
Ray Essickf27e9872019-12-07 06:28:46 -0800964 Item &setCString(const char *key, const char *value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700965 return set(key, value);
966 }
Ray Essick3938dc62016-11-01 08:56:56 -0700967
Andy Hungaeef7882019-10-18 15:18:14 -0700968 // fused get/add/set; if attr wasn't there, it's a simple set.
969 // type-mismatch counts as "wasn't there".
970 template<typename S, typename T>
Ray Essickf27e9872019-12-07 06:28:46 -0800971 Item &add(S key, T value) {
Andy Hung47e58d62019-12-06 18:40:19 -0800972 findOrAllocateProp(key).add(value);
Andy Hungaeef7882019-10-18 15:18:14 -0700973 return *this;
974 }
975
Ray Essickf27e9872019-12-07 06:28:46 -0800976 Item &addInt32(const char *key, int32_t value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700977 return add(key, value);
978 }
Ray Essickf27e9872019-12-07 06:28:46 -0800979 Item &addInt64(const char *key, int64_t value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700980 return add(key, value);
981 }
Ray Essickf27e9872019-12-07 06:28:46 -0800982 Item &addDouble(const char *key, double value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700983 return add(key, value);
984 }
Ray Essickf27e9872019-12-07 06:28:46 -0800985 Item &addRate(const char *key, int64_t count, int64_t duration) {
Andy Hungaeef7882019-10-18 15:18:14 -0700986 return add(key, std::make_pair(count, duration));
987 }
988
989 // find & extract values
990 // return indicates whether attr exists (and thus value filled in)
991 // NULL parameter value suppresses storage of value.
992 template<typename S, typename T>
993 bool get(S key, T *value) const {
Andy Hung47e58d62019-12-06 18:40:19 -0800994 const Prop *prop = findProp(key);
Andy Hungaeef7882019-10-18 15:18:14 -0700995 return prop != nullptr && prop->get(value);
996 }
997
Andy Hung3253f2d2019-10-21 14:50:07 -0700998 bool getInt32(const char *key, int32_t *value) const {
Andy Hungaeef7882019-10-18 15:18:14 -0700999 return get(key, value);
1000 }
Andy Hung3253f2d2019-10-21 14:50:07 -07001001 bool getInt64(const char *key, int64_t *value) const {
Andy Hungaeef7882019-10-18 15:18:14 -07001002 return get(key, value);
1003 }
Andy Hung3253f2d2019-10-21 14:50:07 -07001004 bool getDouble(const char *key, double *value) const {
Andy Hungaeef7882019-10-18 15:18:14 -07001005 return get(key, value);
1006 }
Andy Hung3253f2d2019-10-21 14:50:07 -07001007 bool getRate(const char *key, int64_t *count, int64_t *duration, double *rate) const {
Andy Hungaeef7882019-10-18 15:18:14 -07001008 std::pair<int64_t, int64_t> value;
1009 if (!get(key, &value)) return false;
1010 if (count != nullptr) *count = value.first;
1011 if (duration != nullptr) *duration = value.second;
1012 if (rate != nullptr) {
1013 if (value.second != 0) {
1014 *rate = (double)value.first / value.second; // TODO: isn't INF OK?
1015 } else {
1016 *rate = 0.;
1017 }
1018 }
1019 return true;
1020 }
1021 // Caller owns the returned string
Andy Hung3253f2d2019-10-21 14:50:07 -07001022 bool getCString(const char *key, char **value) const {
Andy Hungb7aadb32019-12-09 19:40:42 -08001023 std::string s;
1024 if (get(key, &s)) {
1025 *value = strdup(s.c_str());
Andy Hung3253f2d2019-10-21 14:50:07 -07001026 return true;
1027 }
1028 return false;
Andy Hungaeef7882019-10-18 15:18:14 -07001029 }
Andy Hung3253f2d2019-10-21 14:50:07 -07001030 bool getString(const char *key, std::string *value) const {
Andy Hungaeef7882019-10-18 15:18:14 -07001031 return get(key, value);
1032 }
Ray Essick3938dc62016-11-01 08:56:56 -07001033
Andy Hung692870b2020-01-02 13:46:06 -08001034 const Prop::Elem* get(const char *key) const {
1035 const Prop *prop = findProp(key);
1036 return prop == nullptr ? nullptr : &prop->get();
1037 }
1038
Andy Hunga87e69c2019-10-18 10:07:40 -07001039 // Deliver the item to MediaMetrics
Ray Essick3938dc62016-11-01 08:56:56 -07001040 bool selfrecord();
1041
Andy Hung3253f2d2019-10-21 14:50:07 -07001042 // remove indicated attributes and their values
1043 // filterNot() could also be called keepOnly()
1044 // return value is # attributes removed
1045 // XXX: perhaps 'remove' instead of 'filter'
1046 // XXX: filterNot would become 'keep'
1047 size_t filter(size_t count, const char *attrs[]);
1048 size_t filterNot(size_t count, const char *attrs[]);
1049 size_t filter(const char *attr) { return filter(1, &attr); }
Ray Essick3938dc62016-11-01 08:56:56 -07001050
1051 // below here are used on server side or to talk to server
1052 // clients need not worry about these.
1053
1054 // timestamp, pid, and uid only used on server side
Ray Essickb5fac8e2016-12-12 11:33:56 -08001055 // timestamp is in 'nanoseconds, unix time'
Ray Essickf27e9872019-12-07 06:28:46 -08001056 Item &setTimestamp(nsecs_t);
Ray Essick3938dc62016-11-01 08:56:56 -07001057 nsecs_t getTimestamp() const;
1058
Ray Essickf27e9872019-12-07 06:28:46 -08001059 Item &setPid(pid_t);
Ray Essick3938dc62016-11-01 08:56:56 -07001060 pid_t getPid() const;
1061
Ray Essickf27e9872019-12-07 06:28:46 -08001062 Item &setUid(uid_t);
Ray Essick3938dc62016-11-01 08:56:56 -07001063 uid_t getUid() const;
1064
Ray Essickf27e9872019-12-07 06:28:46 -08001065 Item &setPkgName(const std::string &pkgName);
Ray Essick783bd0d2018-01-11 11:10:35 -08001066 std::string getPkgName() const { return mPkgName; }
Ray Essickf65f4212017-08-31 11:41:19 -07001067
Ray Essickf27e9872019-12-07 06:28:46 -08001068 Item &setPkgVersionCode(int64_t);
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -08001069 int64_t getPkgVersionCode() const;
Ray Essickf65f4212017-08-31 11:41:19 -07001070
Andy Hung3253f2d2019-10-21 14:50:07 -07001071 // our serialization code for binder calls
1072 status_t writeToParcel(Parcel *) const;
1073 status_t readFromParcel(const Parcel&);
Ray Essick3938dc62016-11-01 08:56:56 -07001074
Andy Hung3253f2d2019-10-21 14:50:07 -07001075 status_t writeToByteString(char **bufferptr, size_t *length) const;
1076 status_t readFromByteString(const char *bufferptr, size_t length);
1077
Ray Essickba8c4842019-01-18 11:35:33 -08001078
Andy Hung17dbaf22019-10-11 14:06:31 -07001079 std::string toString() const;
Ray Essick20147322018-11-17 09:08:39 -08001080 const char *toCString();
Ray Essick3938dc62016-11-01 08:56:56 -07001081
Andy Hung0f7ad8c2020-01-03 13:24:34 -08001082 /**
1083 * Returns true if the item has a property with a target value.
1084 *
1085 * If propName is nullptr, hasPropElem() returns false.
1086 *
1087 * \param propName is the property name.
1088 * \param elem is the value to match. std::monostate matches any.
1089 */
1090 bool hasPropElem(const char *propName, const Prop::Elem& elem) const {
1091 if (propName == nullptr) return false;
1092 const Prop::Elem *e = get(propName);
1093 return e != nullptr && (std::holds_alternative<std::monostate>(elem) || elem == *e);
1094 }
1095
1096 /**
1097 * Returns -2, -1, 0 (success) if the item has a property (wildcard matched) with a
1098 * target value.
1099 *
1100 * The enum RecursiveWildcardCheck designates the meaning of the returned value.
1101 *
1102 * RECURSIVE_WILDCARD_CHECK_NO_MATCH_NO_WILDCARD = -2,
1103 * RECURSIVE_WILDCARD_CHECK_NO_MATCH_WILDCARD_FOUND = -1,
1104 * RECURSIVE_WILDCARD_CHECK_MATCH_FOUND = 0.
1105 *
1106 * If url is nullptr, RECURSIVE_WILDCARD_CHECK_NO_MATCH_NO_WILDCARD is returned.
1107 *
1108 * \param url is the full item + property name, which may have wildcards '*'
1109 * denoting an arbitrary sequence of 0 or more characters.
1110 * \param elem is the target property value to match. std::monostate matches any.
1111 * \return 0 if the property was matched,
1112 * -1 if the property was not matched and a wildcard char was encountered,
1113 * -2 if the property was not matched with no wildcard char encountered.
1114 */
1115 enum RecursiveWildcardCheck {
1116 RECURSIVE_WILDCARD_CHECK_NO_MATCH_NO_WILDCARD = -2,
1117 RECURSIVE_WILDCARD_CHECK_NO_MATCH_WILDCARD_FOUND = -1,
1118 RECURSIVE_WILDCARD_CHECK_MATCH_FOUND = 0,
1119 };
1120
1121 enum RecursiveWildcardCheck recursiveWildcardCheckElem(
1122 const char *url, const Prop::Elem& elem) const {
1123 if (url == nullptr) return RECURSIVE_WILDCARD_CHECK_NO_MATCH_NO_WILDCARD;
1124 return recursiveWildcardCheckElem(getKey().c_str(), url, elem);
1125 }
1126
Andy Hung3253f2d2019-10-21 14:50:07 -07001127private:
Andy Hung0f7ad8c2020-01-03 13:24:34 -08001128
1129 enum RecursiveWildcardCheck recursiveWildcardCheckElem(
1130 const char *itemKeyPtr, const char *url, const Prop::Elem& elem) const {
1131 for (; *url && *itemKeyPtr; ++url, ++itemKeyPtr) {
1132 if (*url != *itemKeyPtr) {
1133 if (*url == '*') { // wildcard
1134 ++url;
1135 while (true) {
1136 if (recursiveWildcardCheckElem(itemKeyPtr, url, elem)
1137 == RECURSIVE_WILDCARD_CHECK_MATCH_FOUND) {
1138 return RECURSIVE_WILDCARD_CHECK_MATCH_FOUND;
1139 }
1140 if (*itemKeyPtr == 0) break;
1141 ++itemKeyPtr;
1142 }
1143 return RECURSIVE_WILDCARD_CHECK_NO_MATCH_WILDCARD_FOUND;
1144 }
1145 return RECURSIVE_WILDCARD_CHECK_NO_MATCH_NO_WILDCARD;
1146 }
1147 }
1148 if (itemKeyPtr[0] != 0 || url[0] != '.') {
1149 return RECURSIVE_WILDCARD_CHECK_NO_MATCH_NO_WILDCARD;
1150 }
1151 const char *propName = url + 1; // skip the '.'
1152 return hasPropElem(propName, elem)
1153 ? RECURSIVE_WILDCARD_CHECK_MATCH_FOUND
1154 : RECURSIVE_WILDCARD_CHECK_NO_MATCH_NO_WILDCARD;
1155 }
1156
Andy Hung3253f2d2019-10-21 14:50:07 -07001157 // handle Parcel version 0
1158 int32_t writeToParcel0(Parcel *) const;
1159 int32_t readFromParcel0(const Parcel&);
1160
Andy Hung47e58d62019-12-06 18:40:19 -08001161 const Prop *findProp(const char *key) const {
1162 auto it = mProps.find(key);
1163 return it != mProps.end() ? &it->second : nullptr;
1164 }
Andy Hungaeef7882019-10-18 15:18:14 -07001165
Andy Hung47e58d62019-12-06 18:40:19 -08001166 Prop &findOrAllocateProp(const char *key) {
1167 auto it = mProps.find(key);
1168 if (it != mProps.end()) return it->second;
1169 Prop &prop = mProps[key];
1170 prop.setName(key);
1171 return prop;
1172 }
Andy Hungaeef7882019-10-18 15:18:14 -07001173
Andy Hung565cc482020-01-02 13:40:04 -08001174 // Changes to member variables below require changes to clear().
Andy Hungaeef7882019-10-18 15:18:14 -07001175 pid_t mPid = -1;
1176 uid_t mUid = -1;
1177 std::string mPkgName;
1178 int64_t mPkgVersionCode = 0;
Andy Hung47e58d62019-12-06 18:40:19 -08001179 std::string mKey;
Andy Hungaeef7882019-10-18 15:18:14 -07001180 nsecs_t mTimestamp = 0;
Andy Hung47e58d62019-12-06 18:40:19 -08001181 std::map<std::string, Prop> mProps;
Ray Essick3938dc62016-11-01 08:56:56 -07001182};
1183
Ray Essickf27e9872019-12-07 06:28:46 -08001184} // namespace mediametrics
Ray Essick3938dc62016-11-01 08:56:56 -07001185} // namespace android
1186
Andy Hung47e58d62019-12-06 18:40:19 -08001187#endif // ANDROID_MEDIA_MEDIAMETRICSITEM_H