blob: 6141b3610a8a14a17b52287b2cca8e85a2f830f5 [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
Andy Hungea186fa2020-01-09 18:13:15 -080038/*
39 * MediaMetrics Keys and Properties for Audio.
40 *
41 * C/C++ friendly constants that ensure
42 * 1) Compilation error on misspelling
43 * 2) Consistent behavior and documentation.
44 *
45 * TODO: Move to separate header file.
46 */
47
48// Taxonomy of audio keys
49
50// Key Prefixes are used for MediaMetrics Item Keys and ends with a ".".
51// They must be appended with another value to make a key.
52#define AMEDIAMETRICS_KEY_PREFIX_AUDIO "audio."
53
54// The AudioRecord key appends the "trackId" to the prefix.
55#define AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD AMEDIAMETRICS_KEY_PREFIX_AUDIO "record."
56
57// The AudioThread key appends the "threadId" to the prefix.
58#define AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD AMEDIAMETRICS_KEY_PREFIX_AUDIO "thread."
59
60// The AudioTrack key appends the "trackId" to the prefix.
61#define AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK AMEDIAMETRICS_KEY_PREFIX_AUDIO "track."
62
63// Keys are strings used for MediaMetrics Item Keys
64#define AMEDIAMETRICS_KEY_AUDIO_FLINGER AMEDIAMETRICS_KEY_PREFIX_AUDIO "flinger"
65#define AMEDIAMETRICS_KEY_AUDIO_POLICY AMEDIAMETRICS_KEY_PREFIX_AUDIO "policy"
66
67// Props are properties allowed for Mediametrics Items.
68#define AMEDIAMETRICS_PROP_EVENT "event" // string value (often func name)
69#define AMEDIAMETRICS_PROP_LATENCYMS "latencyMs" // double value
70#define AMEDIAMETRICS_PROP_OUTPUTDEVICES "outputDevices" // string value
71#define AMEDIAMETRICS_PROP_STARTUPMS "startupMs" // double value
72#define AMEDIAMETRICS_PROP_THREADID "threadId" // int32 value io handle
73
74// Values are strings accepted for a given property.
75
76// An event is a general description, which often is a function name.
77#define AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR "ctor"
78#define AMEDIAMETRICS_PROP_EVENT_VALUE_DTOR "dtor"
79#define AMEDIAMETRICS_PROP_EVENT_VALUE_UNDERRUN "underrun" // from Thread
80
Ray Essickf27e9872019-12-07 06:28:46 -080081class IMediaMetricsService;
Ray Essick783bd0d2018-01-11 11:10:35 -080082class Parcel;
Ray Essick3938dc62016-11-01 08:56:56 -070083
Andy Hung3253f2d2019-10-21 14:50:07 -070084/*
Andy Hung1efc9c62019-12-03 13:43:33 -080085 * MediaMetrics Item
Andy Hung3253f2d2019-10-21 14:50:07 -070086 *
Andy Hung611268d2019-12-19 13:54:02 -080087 * The MediaMetrics Item allows get/set operations and recording to the service.
88 *
89 * The MediaMetrics LogItem is a faster logging variant. It allows set operations only,
90 * and then recording to the service.
91 *
92 * The Byte String format is as follows:
Andy Hung1efc9c62019-12-03 13:43:33 -080093 *
94 * For Java
95 * int64 corresponds to long
96 * int32, uint32 corresponds to int
97 * uint16 corresponds to char
98 * uint8, int8 corresponds to byte
99 *
Andy Hung611268d2019-12-19 13:54:02 -0800100 * For items transmitted from Java, uint8 and uint32 values are limited
101 * to INT8_MAX and INT32_MAX. This constrains the size of large items
102 * to 2GB, which is consistent with ByteBuffer max size. A native item
103 * can conceivably have size of 4GB.
Andy Hung1efc9c62019-12-03 13:43:33 -0800104 *
105 * Physical layout of integers and doubles within the MediaMetrics byte string
Andy Hung611268d2019-12-19 13:54:02 -0800106 * is in Native / host order, which is usually little endian.
107 *
108 * Note that primitive data (ints, doubles) within a Byte String has
109 * no extra padding or alignment requirements, like ByteBuffer.
Andy Hung1efc9c62019-12-03 13:43:33 -0800110 *
111 * -- begin of item
112 * -- begin of header
113 * (uint32) item size: including the item size field
114 * (uint32) header size, including the item size and header size fields.
115 * (uint16) version: exactly 0
116 * (uint16) key size, that is key strlen + 1 for zero termination.
Andy Hung611268d2019-12-19 13:54:02 -0800117 * (int8)+ key, a string which is 0 terminated (UTF-8).
Andy Hung3253f2d2019-10-21 14:50:07 -0700118 * (int32) pid
119 * (int32) uid
120 * (int64) timestamp
Andy Hung1efc9c62019-12-03 13:43:33 -0800121 * -- end of header
122 * -- begin body
123 * (uint32) number of properties
124 * -- repeat for number of properties
125 * (uint16) property size, including property size field itself
Andy Hung3253f2d2019-10-21 14:50:07 -0700126 * (uint8) type of property
127 * (int8)+ key string, including 0 termination
Andy Hung1efc9c62019-12-03 13:43:33 -0800128 * based on type of property (given above), one of:
Andy Hung3253f2d2019-10-21 14:50:07 -0700129 * (int32)
130 * (int64)
131 * (double)
Andy Hung611268d2019-12-19 13:54:02 -0800132 * (int8)+ for TYPE_CSTRING, including 0 termination
Andy Hung3253f2d2019-10-21 14:50:07 -0700133 * (int64, int64) for rate
Andy Hung1efc9c62019-12-03 13:43:33 -0800134 * -- end body
135 * -- end of item
Andy Hung611268d2019-12-19 13:54:02 -0800136 *
137 * The Byte String format must match MediaMetrics.java.
Andy Hung3253f2d2019-10-21 14:50:07 -0700138 */
139
Andy Hung1efc9c62019-12-03 13:43:33 -0800140namespace mediametrics {
141
142// Type must match MediaMetrics.java
143enum Type {
144 kTypeNone = 0,
145 kTypeInt32 = 1,
146 kTypeInt64 = 2,
147 kTypeDouble = 3,
148 kTypeCString = 4,
149 kTypeRate = 5,
150};
151
Andy Hung611268d2019-12-19 13:54:02 -0800152/**
153 * The MediaMetrics Item has special Item properties,
154 * derived internally or through dedicated setters.
155 *
156 * For consistency we use the following keys to represent
157 * these special Item properties when in a generic Bundle
158 * or in a std::map.
159 *
160 * These values must match MediaMetrics.java
161 */
162static inline constexpr const char *BUNDLE_TOTAL_SIZE = "_totalSize";
163static inline constexpr const char *BUNDLE_HEADER_SIZE = "_headerSize";
164static inline constexpr const char *BUNDLE_VERSION = "_version";
165static inline constexpr const char *BUNDLE_KEY_SIZE = "_keySize";
166static inline constexpr const char *BUNDLE_KEY = "_key";
167static inline constexpr const char *BUNDLE_PID = "_pid";
168static inline constexpr const char *BUNDLE_UID = "_uid";
169static inline constexpr const char *BUNDLE_TIMESTAMP = "_timestamp";
170static inline constexpr const char *BUNDLE_PROPERTY_COUNT = "_propertyCount";
171
Andy Hung1efc9c62019-12-03 13:43:33 -0800172template<size_t N>
173static inline bool startsWith(const std::string &s, const char (&comp)[N]) {
Andy Hung692870b2020-01-02 13:46:06 -0800174 return !strncmp(s.c_str(), comp, N - 1);
Andy Hung1efc9c62019-12-03 13:43:33 -0800175}
176
Andy Hung37de9b72020-01-02 13:54:05 -0800177static inline bool startsWith(const std::string& s, const std::string& comp) {
178 return !strncmp(s.c_str(), comp.c_str(), comp.size() - 1);
179}
180
181/**
182 * Defers a function to run in the destructor.
183 *
184 * This helper class is used to log results on exit of a method.
185 */
186class Defer {
187public:
188 template <typename U>
189 Defer(U &&f) : mThunk(std::forward<U>(f)) {}
190 ~Defer() { mThunk(); }
191
192private:
193 const std::function<void()> mThunk;
194};
195
Andy Hung1efc9c62019-12-03 13:43:33 -0800196/**
197 * Media Metrics BaseItem
198 *
199 * A base class which contains utility static functions to write to a byte stream
200 * and access the Media Metrics service.
201 */
202
203class BaseItem {
204 friend class MediaMetricsDeathNotifier; // for dropInstance
205 // enabled 1, disabled 0
206public:
Andy Hung47e58d62019-12-06 18:40:19 -0800207 // are we collecting metrics data
Andy Hung1efc9c62019-12-03 13:43:33 -0800208 static bool isEnabled();
Andy Hung47e58d62019-12-06 18:40:19 -0800209 static sp<IMediaMetricsService> getService();
Andy Hung1efc9c62019-12-03 13:43:33 -0800210
211protected:
212 static constexpr const char * const EnabledProperty = "media.metrics.enabled";
213 static constexpr const char * const EnabledPropertyPersist = "persist.media.metrics.enabled";
214 static const int EnabledProperty_default = 1;
215
216 // let's reuse a binder connection
Ray Essickf27e9872019-12-07 06:28:46 -0800217 static sp<IMediaMetricsService> sMediaMetricsService;
Andy Hung47e58d62019-12-06 18:40:19 -0800218
Andy Hung1efc9c62019-12-03 13:43:33 -0800219 static void dropInstance();
220 static bool submitBuffer(const char *buffer, size_t len);
221
Andy Hungb7aadb32019-12-09 19:40:42 -0800222 template <typename T>
223 struct is_item_type {
224 static constexpr inline bool value =
225 std::is_same<T, int32_t>::value
226 || std::is_same<T, int64_t>::value
227 || std::is_same<T, double>::value
228 || std::is_same<T, std::pair<int64_t, int64_t>>:: value
229 || std::is_same<T, std::string>::value
230 || std::is_same<T, std::monostate>::value;
231 };
Andy Hung1efc9c62019-12-03 13:43:33 -0800232
Andy Hungb7aadb32019-12-09 19:40:42 -0800233 template <typename T>
234 struct get_type_of {
235 static_assert(is_item_type<T>::value);
236 static constexpr inline Type value =
237 std::is_same<T, int32_t>::value ? kTypeInt32
238 : std::is_same<T, int64_t>::value ? kTypeInt64
239 : std::is_same<T, double>::value ? kTypeDouble
240 : std::is_same<T, std::pair<int64_t, int64_t>>:: value ? kTypeRate
241 : std::is_same<T, std::string>::value ? kTypeCString
242 : std::is_same<T, std::monostate>::value ? kTypeNone
243 : kTypeNone;
244 };
245
246 template <typename T>
247 static size_t sizeOfByteString(const char *name, const T& value) {
248 static_assert(is_item_type<T>::value);
Andy Hung1efc9c62019-12-03 13:43:33 -0800249 return 2 + 1 + strlen(name) + 1 + sizeof(value);
250 }
Andy Hungb7aadb32019-12-09 19:40:42 -0800251 template <> // static
252 size_t sizeOfByteString(const char *name, const std::string& value) {
253 return 2 + 1 + strlen(name) + 1 + value.size() + 1;
Andy Hung1efc9c62019-12-03 13:43:33 -0800254 }
Andy Hungb7aadb32019-12-09 19:40:42 -0800255 template <> // static
256 size_t sizeOfByteString(const char *name, const std::monostate&) {
Andy Hung1efc9c62019-12-03 13:43:33 -0800257 return 2 + 1 + strlen(name) + 1;
258 }
Andy Hungb7aadb32019-12-09 19:40:42 -0800259 // for speed
260 static size_t sizeOfByteString(const char *name, const char *value) {
261 return 2 + 1 + strlen(name) + 1 + strlen(value) + 1;
262 }
263
264 template <typename T>
265 static status_t insert(const T& val, char **bufferpptr, char *bufferptrmax) {
266 static_assert(std::is_trivially_constructible<T>::value);
267 const size_t size = sizeof(val);
268 if (*bufferpptr + size > bufferptrmax) {
269 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
270 return BAD_VALUE;
271 }
272 memcpy(*bufferpptr, &val, size);
273 *bufferpptr += size;
274 return NO_ERROR;
275 }
276 template <> // static
277 status_t insert(const std::string& val, char **bufferpptr, char *bufferptrmax) {
278 const size_t size = val.size() + 1;
279 if (size > UINT16_MAX || *bufferpptr + size > bufferptrmax) {
280 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
281 return BAD_VALUE;
282 }
283 memcpy(*bufferpptr, val.c_str(), size);
284 *bufferpptr += size;
285 return NO_ERROR;
286 }
287 template <> // static
288 status_t insert(const std::pair<int64_t, int64_t>& val,
289 char **bufferpptr, char *bufferptrmax) {
290 const size_t size = sizeof(val.first) + sizeof(val.second);
291 if (*bufferpptr + size > bufferptrmax) {
292 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
293 return BAD_VALUE;
294 }
295 memcpy(*bufferpptr, &val.first, sizeof(val.first));
296 memcpy(*bufferpptr + sizeof(val.first), &val.second, sizeof(val.second));
297 *bufferpptr += size;
298 return NO_ERROR;
299 }
300 template <> // static
301 status_t insert(const std::monostate&, char **, char *) {
302 return NO_ERROR;
303 }
304 // for speed
305 static status_t insert(const char *val, char **bufferpptr, char *bufferptrmax) {
306 const size_t size = strlen(val) + 1;
307 if (size > UINT16_MAX || *bufferpptr + size > bufferptrmax) {
308 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
309 return BAD_VALUE;
310 }
311 memcpy(*bufferpptr, val, size);
312 *bufferpptr += size;
313 return NO_ERROR;
314 }
315
316 template <typename T>
317 static status_t writeToByteString(
318 const char *name, const T& value, char **bufferpptr, char *bufferptrmax) {
319 static_assert(is_item_type<T>::value);
320 const size_t len = sizeOfByteString(name, value);
321 if (len > UINT16_MAX) return BAD_VALUE;
322 return insert((uint16_t)len, bufferpptr, bufferptrmax)
323 ?: insert((uint8_t)get_type_of<T>::value, bufferpptr, bufferptrmax)
324 ?: insert(name, bufferpptr, bufferptrmax)
325 ?: insert(value, bufferpptr, bufferptrmax);
326 }
327 // for speed
328 static status_t writeToByteString(
329 const char *name, const char *value, char **bufferpptr, char *bufferptrmax) {
330 const size_t len = sizeOfByteString(name, value);
331 if (len > UINT16_MAX) return BAD_VALUE;
332 return insert((uint16_t)len, bufferpptr, bufferptrmax)
333 ?: insert((uint8_t)kTypeCString, bufferpptr, bufferptrmax)
334 ?: insert(name, bufferpptr, bufferptrmax)
335 ?: insert(value, bufferpptr, bufferptrmax);
336 }
337
338 template <typename T>
339 static void toStringBuffer(
340 const char *name, const T& value, char *buffer, size_t length) = delete;
341 template <> // static
342 void toStringBuffer(
343 const char *name, const int32_t& value, char *buffer, size_t length) {
344 snprintf(buffer, length, "%s=%d:", name, value);
345 }
346 template <> // static
347 void toStringBuffer(
348 const char *name, const int64_t& value, char *buffer, size_t length) {
349 snprintf(buffer, length, "%s=%lld:", name, (long long)value);
350 }
351 template <> // static
352 void toStringBuffer(
353 const char *name, const double& value, char *buffer, size_t length) {
354 snprintf(buffer, length, "%s=%e:", name, value);
355 }
356 template <> // static
357 void toStringBuffer(
358 const char *name, const std::pair<int64_t, int64_t>& value,
359 char *buffer, size_t length) {
360 snprintf(buffer, length, "%s=%lld/%lld:",
361 name, (long long)value.first, (long long)value.second);
362 }
363 template <> // static
364 void toStringBuffer(
365 const char *name, const std::string& value, char *buffer, size_t length) {
366 // TODO sanitize string for ':' '='
367 snprintf(buffer, length, "%s=%s:", name, value.c_str());
368 }
369 template <> // static
370 void toStringBuffer(
371 const char *name, const std::monostate&, char *buffer, size_t length) {
372 snprintf(buffer, length, "%s=():", name);
373 }
374
375 template <typename T>
376 static status_t writeToParcel(
377 const char *name, const T& value, Parcel *parcel) = delete;
378 template <> // static
379 status_t writeToParcel(
380 const char *name, const int32_t& value, Parcel *parcel) {
381 return parcel->writeCString(name)
382 ?: parcel->writeInt32(get_type_of<int32_t>::value)
383 ?: parcel->writeInt32(value);
384 }
385 template <> // static
386 status_t writeToParcel(
387 const char *name, const int64_t& value, Parcel *parcel) {
388 return parcel->writeCString(name)
389 ?: parcel->writeInt32(get_type_of<int64_t>::value)
390 ?: parcel->writeInt64(value);
391 }
392 template <> // static
393 status_t writeToParcel(
394 const char *name, const double& value, Parcel *parcel) {
395 return parcel->writeCString(name)
396 ?: parcel->writeInt32(get_type_of<double>::value)
397 ?: parcel->writeDouble(value);
398 }
399 template <> // static
400 status_t writeToParcel(
401 const char *name, const std::pair<int64_t, int64_t>& value, Parcel *parcel) {
402 return parcel->writeCString(name)
403 ?: parcel->writeInt32(get_type_of< std::pair<int64_t, int64_t>>::value)
404 ?: parcel->writeInt64(value.first)
405 ?: parcel->writeInt64(value.second);
406 }
407 template <> // static
408 status_t writeToParcel(
409 const char *name, const std::string& value, Parcel *parcel) {
410 return parcel->writeCString(name)
411 ?: parcel->writeInt32(get_type_of<std::string>::value)
412 ?: parcel->writeCString(value.c_str());
413 }
414 template <> // static
415 status_t writeToParcel(
416 const char *name, const std::monostate&, Parcel *parcel) {
417 return parcel->writeCString(name)
418 ?: parcel->writeInt32(get_type_of<std::monostate>::value);
419 }
420
421 template <typename T>
422 static status_t extract(T *val, const char **bufferpptr, const char *bufferptrmax) {
423 static_assert(std::is_trivially_constructible<T>::value);
424 const size_t size = sizeof(*val);
425 if (*bufferpptr + size > bufferptrmax) {
426 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
427 return BAD_VALUE;
428 }
429 memcpy(val, *bufferpptr, size);
430 *bufferpptr += size;
431 return NO_ERROR;
432 }
433 template <> // static
434 status_t extract(std::string *val, const char **bufferpptr, const char *bufferptrmax) {
435 const char *ptr = *bufferpptr;
436 while (*ptr != 0) {
437 if (ptr >= bufferptrmax) {
438 ALOGE("%s: buffer exceeded", __func__);
439 return BAD_VALUE;
440 }
441 ++ptr;
442 }
443 const size_t size = (ptr - *bufferpptr) + 1;
444 *val = *bufferpptr;
445 *bufferpptr += size;
446 return NO_ERROR;
447 }
448 template <> // static
449 status_t extract(std::pair<int64_t, int64_t> *val,
450 const char **bufferpptr, const char *bufferptrmax) {
451 const size_t size = sizeof(val->first) + sizeof(val->second);
452 if (*bufferpptr + size > bufferptrmax) {
453 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
454 return BAD_VALUE;
455 }
456 memcpy(&val->first, *bufferpptr, sizeof(val->first));
457 memcpy(&val->second, *bufferpptr + sizeof(val->first), sizeof(val->second));
458 *bufferpptr += size;
459 return NO_ERROR;
460 }
461 template <> // static
462 status_t extract(std::monostate *, const char **, const char *) {
463 return NO_ERROR;
464 }
Andy Hung1efc9c62019-12-03 13:43:33 -0800465};
466
467/**
468 * Media Metrics BufferedItem
469 *
470 * A base class which represents a put-only Media Metrics item, storing
471 * the Media Metrics data in a buffer with begin and end pointers.
472 *
473 * If a property key is entered twice, it will be stored in the buffer twice,
474 * and (implementation defined) the last value for that key will be used
475 * by the Media Metrics service.
476 *
477 * For realloc, a baseRealloc pointer must be passed in either explicitly
478 * or implicitly in the constructor. This will be updated with the value used on realloc.
479 */
480class BufferedItem : public BaseItem {
481public:
482 static inline constexpr uint16_t kVersion = 0;
483
484 virtual ~BufferedItem() = default;
485 BufferedItem(const BufferedItem&) = delete;
486 BufferedItem& operator=(const BufferedItem&) = delete;
487
488 BufferedItem(const std::string key, char *begin, char *end)
489 : BufferedItem(key.c_str(), begin, end) { }
490
491 BufferedItem(const char *key, char *begin, char *end)
492 : BufferedItem(key, begin, end, nullptr) { }
493
494 BufferedItem(const char *key, char **begin, char *end)
495 : BufferedItem(key, *begin, end, begin) { }
496
497 BufferedItem(const char *key, char *begin, char *end, char **baseRealloc)
498 : mBegin(begin)
499 , mEnd(end)
500 , mBaseRealloc(baseRealloc)
501 {
502 init(key);
503 }
504
505 template<typename T>
506 BufferedItem &set(const char *key, const T& value) {
507 reallocFor(sizeOfByteString(key, value));
508 if (mStatus == NO_ERROR) {
509 mStatus = BaseItem::writeToByteString(key, value, &mBptr, mEnd);
510 ++mPropCount;
511 }
512 return *this;
513 }
514
515 template<typename T>
516 BufferedItem &set(const std::string& key, const T& value) {
517 return set(key.c_str(), value);
518 }
519
520 BufferedItem &setPid(pid_t pid) {
521 if (mStatus == NO_ERROR) {
522 copyTo(mBegin + mHeaderLen - 16, (int32_t)pid);
523 }
524 return *this;
525 }
526
527 BufferedItem &setUid(uid_t uid) {
528 if (mStatus == NO_ERROR) {
529 copyTo(mBegin + mHeaderLen - 12, (int32_t)uid);
530 }
531 return *this;
532 }
533
534 BufferedItem &setTimestamp(nsecs_t timestamp) {
535 if (mStatus == NO_ERROR) {
536 copyTo(mBegin + mHeaderLen - 8, (int64_t)timestamp);
537 }
538 return *this;
539 }
540
541 bool record() {
542 return updateHeader()
543 && BaseItem::submitBuffer(getBuffer(), getLength());
544 }
545
546 bool isValid () const {
547 return mStatus == NO_ERROR;
548 }
549
550 char *getBuffer() const { return mBegin; }
551 size_t getLength() const { return mBptr - mBegin; }
552 size_t getRemaining() const { return mEnd - mBptr; }
553 size_t getCapacity() const { return mEnd - mBegin; }
554
555 bool updateHeader() {
556 if (mStatus != NO_ERROR) return false;
557 copyTo(mBegin + 0, (uint32_t)getLength());
558 copyTo(mBegin + 4, (uint32_t)mHeaderLen);
559 copyTo(mBegin + mHeaderLen, (uint32_t)mPropCount);
560 return true;
561 }
562
563protected:
564 BufferedItem() = default;
565
566 void reallocFor(size_t required) {
567 if (mStatus != NO_ERROR) return;
568 const size_t remaining = getRemaining();
569 if (required <= remaining) return;
570 if (mBaseRealloc == nullptr) {
571 mStatus = NO_MEMORY;
572 return;
573 }
574
575 const size_t current = getLength();
576 size_t minimum = current + required;
577 if (minimum > SSIZE_MAX >> 1) {
578 mStatus = NO_MEMORY;
579 return;
580 }
581 minimum <<= 1;
582 void *newptr = realloc(*mBaseRealloc, minimum);
583 if (newptr == nullptr) {
584 mStatus = NO_MEMORY;
585 return;
586 }
587 if (newptr != *mBaseRealloc) {
588 // ALOGD("base changed! current:%zu new size %zu", current, minimum);
589 if (*mBaseRealloc == nullptr) {
590 memcpy(newptr, mBegin, current);
591 }
592 mBegin = (char *)newptr;
593 *mBaseRealloc = mBegin;
594 mEnd = mBegin + minimum;
595 mBptr = mBegin + current;
596 } else {
597 // ALOGD("base kept! current:%zu new size %zu", current, minimum);
598 mEnd = mBegin + minimum;
599 }
600 }
601 template<typename T>
602 void copyTo(char *ptr, const T& value) {
603 memcpy(ptr, &value, sizeof(value));
604 }
605
606 void init(const char *key) {
607 mBptr = mBegin;
608 const size_t keylen = strlen(key) + 1;
609 mHeaderLen = 4 + 4 + 2 + 2 + keylen + 4 + 4 + 8;
610 reallocFor(mHeaderLen);
611 if (mStatus != NO_ERROR) return;
612 mBptr = mBegin + mHeaderLen + 4; // this includes propcount.
613
614 if (mEnd < mBptr || keylen > UINT16_MAX) {
615 mStatus = NO_MEMORY;
616 mBptr = mEnd;
617 return;
618 }
619 copyTo(mBegin + 8, kVersion);
620 copyTo(mBegin + 10, (uint16_t)keylen);
621 strcpy(mBegin + 12, key);
622
623 // initialize some parameters (that could be overridden)
624 setPid(-1);
625 setUid(-1);
626 setTimestamp(0);
627 }
628
629 char *mBegin = nullptr;
630 char *mEnd = nullptr;
631 char **mBaseRealloc = nullptr; // set to an address if realloc should be done.
632 // upon return, that pointer is updated with
633 // whatever needs to be freed.
634 char *mBptr = nullptr;
635 status_t mStatus = NO_ERROR;
636 uint32_t mPropCount = 0;
637 uint32_t mHeaderLen = 0;
638};
639
640/**
Andy Hung47e58d62019-12-06 18:40:19 -0800641 * MediaMetrics LogItem is a stack allocated mediametrics item used for
Andy Hung1efc9c62019-12-03 13:43:33 -0800642 * fast logging. It falls over to a malloc if needed.
643 *
644 * This is templated with a buffer size to allocate on the stack.
645 */
646template <size_t N = 4096>
Ray Essickf27e9872019-12-07 06:28:46 -0800647class LogItem : public BufferedItem {
Andy Hung1efc9c62019-12-03 13:43:33 -0800648public:
Ray Essickf27e9872019-12-07 06:28:46 -0800649 explicit LogItem(const std::string key) : LogItem(key.c_str()) { }
Andy Hung1efc9c62019-12-03 13:43:33 -0800650
651 // Since this class will not be defined before the base class, we initialize variables
652 // in our own order.
Ray Essickf27e9872019-12-07 06:28:46 -0800653 explicit LogItem(const char *key) {
Andy Hung1efc9c62019-12-03 13:43:33 -0800654 mBegin = mBuffer;
655 mEnd = mBuffer + N;
656 mBaseRealloc = &mReallocPtr;
657 init(key);
658 }
659
Ray Essickf27e9872019-12-07 06:28:46 -0800660 ~LogItem() override {
Andy Hung1efc9c62019-12-03 13:43:33 -0800661 if (mReallocPtr != nullptr) { // do the check before calling free to avoid overhead.
662 free(mReallocPtr);
663 }
664 }
665
666private:
667 char *mReallocPtr = nullptr; // set non-null by base class if realloc happened.
668 char mBuffer[N];
669};
670
Andy Hung1efc9c62019-12-03 13:43:33 -0800671
Andy Hung3253f2d2019-10-21 14:50:07 -0700672/**
Ray Essickf27e9872019-12-07 06:28:46 -0800673 * Media Metrics Item
Andy Hung3253f2d2019-10-21 14:50:07 -0700674 *
675 * A mutable item representing an event or record that will be
Andy Hung1efc9c62019-12-03 13:43:33 -0800676 * logged with the Media Metrics service. For client logging, one should
677 * use the mediametrics::Item.
Andy Hung3253f2d2019-10-21 14:50:07 -0700678 *
Ray Essickf27e9872019-12-07 06:28:46 -0800679 * The Item is designed for the service as it has getters.
Andy Hung3253f2d2019-10-21 14:50:07 -0700680 */
Andy Hung565cc482020-01-02 13:40:04 -0800681class Item final : public mediametrics::BaseItem {
Andy Hungaeef7882019-10-18 15:18:14 -0700682public:
Ray Essick3938dc62016-11-01 08:56:56 -0700683
Andy Hung2ecacc42020-01-02 13:29:50 -0800684 class Prop {
685 public:
686 using Elem = std::variant<
687 std::monostate, // kTypeNone
688 int32_t, // kTypeInt32
689 int64_t, // kTypeInt64
690 double, // kTypeDouble
691 std::string, // kTypeCString
692 std::pair<int64_t, int64_t> // kTypeRate
693 >;
694
695 Prop() = default;
696 Prop(const Prop& other) {
697 *this = other;
698 }
699 Prop& operator=(const Prop& other) {
700 mName = other.mName;
701 mElem = other.mElem;
702 return *this;
703 }
704 Prop(Prop&& other) {
705 *this = std::move(other);
706 }
707 Prop& operator=(Prop&& other) {
708 mName = std::move(other.mName);
709 mElem = std::move(other.mElem);
710 return *this;
711 }
712
713 bool operator==(const Prop& other) const {
714 return mName == other.mName && mElem == other.mElem;
715 }
716 bool operator!=(const Prop& other) const {
717 return !(*this == other);
718 }
719
720 void clear() {
721 mName.clear();
722 mElem = std::monostate{};
723 }
724 void clearValue() {
725 mElem = std::monostate{};
726 }
727
728 const char *getName() const {
729 return mName.c_str();
730 }
731
732 void swap(Prop& other) {
733 std::swap(mName, other.mName);
734 std::swap(mElem, other.mElem);
735 }
736
737 void setName(const char *name) {
738 mName = name;
739 }
740
741 bool isNamed(const char *name) const {
742 return mName == name;
743 }
744
745 template <typename T> void visit(T f) const {
746 std::visit(f, mElem);
747 }
748
749 template <typename T> bool get(T *value) const {
750 auto pval = std::get_if<T>(&mElem);
751 if (pval != nullptr) {
752 *value = *pval;
753 return true;
754 }
755 return false;
756 }
757
758 const Elem& get() const {
759 return mElem;
760 }
761
762 template <typename T> void set(const T& value) {
763 mElem = value;
764 }
765
766 template <typename T> void add(const T& value) {
767 auto pval = std::get_if<T>(&mElem);
768 if (pval != nullptr) {
769 *pval += value;
770 } else {
771 mElem = value;
772 }
773 }
774
775 template <> void add(const std::pair<int64_t, int64_t>& value) {
776 auto pval = std::get_if<std::pair<int64_t, int64_t>>(&mElem);
777 if (pval != nullptr) {
778 pval->first += value.first;
779 pval->second += value.second;
780 } else {
781 mElem = value;
782 }
783 }
784
785 status_t writeToParcel(Parcel *parcel) const {
786 return std::visit([this, parcel](auto &value) {
787 return BaseItem::writeToParcel(mName.c_str(), value, parcel);}, mElem);
788 }
789
790 void toStringBuffer(char *buffer, size_t length) const {
791 return std::visit([this, buffer, length](auto &value) {
792 BaseItem::toStringBuffer(mName.c_str(), value, buffer, length);}, mElem);
793 }
794
795 size_t getByteStringSize() const {
796 return std::visit([this](auto &value) {
797 return BaseItem::sizeOfByteString(mName.c_str(), value);}, mElem);
798 }
799
800 status_t writeToByteString(char **bufferpptr, char *bufferptrmax) const {
801 return std::visit([this, bufferpptr, bufferptrmax](auto &value) {
802 return BaseItem::writeToByteString(mName.c_str(), value, bufferpptr, bufferptrmax);
803 }, mElem);
804 }
805
806 status_t readFromParcel(const Parcel& data);
807
808 status_t readFromByteString(const char **bufferpptr, const char *bufferptrmax);
809
810 private:
811 std::string mName;
812 Elem mElem;
813 };
814
815 // Iteration of props within item
816 class iterator {
817 public:
818 iterator(const std::map<std::string, Prop>::const_iterator &_it) : it(_it) { }
819 iterator &operator++() {
820 ++it;
821 return *this;
822 }
823 bool operator!=(iterator &other) const {
824 return it != other.it;
825 }
826 const Prop &operator*() const {
827 return it->second;
828 }
829
830 private:
831 std::map<std::string, Prop>::const_iterator it;
832 };
833
834 iterator begin() const {
835 return iterator(mProps.cbegin());
836 }
837
838 iterator end() const {
839 return iterator(mProps.cend());
840 }
841
Ray Essickf65f4212017-08-31 11:41:19 -0700842 enum {
843 PROTO_V0 = 0,
844 PROTO_FIRST = PROTO_V0,
845 PROTO_V1 = 1,
846 PROTO_LAST = PROTO_V1,
847 };
848
Andy Hungaeef7882019-10-18 15:18:14 -0700849 // T must be convertible to mKey
850 template <typename T>
Ray Essickf27e9872019-12-07 06:28:46 -0800851 explicit Item(T key)
Andy Hungaeef7882019-10-18 15:18:14 -0700852 : mKey(key) { }
Ray Essickf27e9872019-12-07 06:28:46 -0800853 Item() = default;
Andy Hung3253f2d2019-10-21 14:50:07 -0700854
Andy Hung565cc482020-01-02 13:40:04 -0800855 // We enable default copy and move constructors and make this class final
856 // to prevent a derived class; this avoids possible data slicing.
857 Item(const Item& other) = default;
858 Item(Item&& other) = default;
859 Item& operator=(const Item& other) = default;
860 Item& operator=(Item&& other) = default;
861
Ray Essickf27e9872019-12-07 06:28:46 -0800862 bool operator==(const Item& other) const {
Andy Hung692870b2020-01-02 13:46:06 -0800863 return mPid == other.mPid
864 && mUid == other.mUid
865 && mPkgName == other.mPkgName
866 && mPkgVersionCode == other.mPkgVersionCode
867 && mKey == other.mKey
868 && mTimestamp == other.mTimestamp
869 && mProps == other.mProps
870 ;
Andy Hung3253f2d2019-10-21 14:50:07 -0700871 }
Ray Essickf27e9872019-12-07 06:28:46 -0800872 bool operator!=(const Item& other) const {
Andy Hung3253f2d2019-10-21 14:50:07 -0700873 return !(*this == other);
874 }
875
876 template <typename T>
Ray Essickf27e9872019-12-07 06:28:46 -0800877 static Item* create(T key) {
878 return new Item(key);
Andy Hung3253f2d2019-10-21 14:50:07 -0700879 }
Ray Essickf27e9872019-12-07 06:28:46 -0800880 static Item* create() {
881 return new Item();
Andy Hung3253f2d2019-10-21 14:50:07 -0700882 }
Ray Essickba8c4842019-01-18 11:35:33 -0800883
Ray Essickf27e9872019-12-07 06:28:46 -0800884 static Item* convert(mediametrics_handle_t);
885 static mediametrics_handle_t convert(Item *);
Ray Essickbf536ac2019-08-26 11:04:28 -0700886
Ray Essick3938dc62016-11-01 08:56:56 -0700887 // access functions for the class
Ray Essickf27e9872019-12-07 06:28:46 -0800888 ~Item();
Ray Essick3938dc62016-11-01 08:56:56 -0700889
Andy Hung47e58d62019-12-06 18:40:19 -0800890 void clear() {
891 mPid = -1;
892 mUid = -1;
893 mPkgName.clear();
894 mPkgVersionCode = 0;
895 mTimestamp = 0;
896 mKey.clear();
897 mProps.clear();
898 }
899
900 Item *dup() const { return new Item(*this); }
Ray Essick3938dc62016-11-01 08:56:56 -0700901
Ray Essickf27e9872019-12-07 06:28:46 -0800902 Item &setKey(const char *key) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700903 mKey = key;
904 return *this;
905 }
906 const std::string& getKey() const { return mKey; }
Ray Essick3938dc62016-11-01 08:56:56 -0700907
Andy Hung3253f2d2019-10-21 14:50:07 -0700908 // # of properties in the record
Andy Hung47e58d62019-12-06 18:40:19 -0800909 size_t count() const { return mProps.size(); }
Ray Essick3938dc62016-11-01 08:56:56 -0700910
Andy Hungaeef7882019-10-18 15:18:14 -0700911 template<typename S, typename T>
Ray Essickf27e9872019-12-07 06:28:46 -0800912 Item &set(S key, T value) {
Andy Hung47e58d62019-12-06 18:40:19 -0800913 findOrAllocateProp(key).set(value);
Andy Hungaeef7882019-10-18 15:18:14 -0700914 return *this;
915 }
Ray Essick3938dc62016-11-01 08:56:56 -0700916
Andy Hungaeef7882019-10-18 15:18:14 -0700917 // set values appropriately
Ray Essickf27e9872019-12-07 06:28:46 -0800918 Item &setInt32(const char *key, int32_t value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700919 return set(key, value);
920 }
Ray Essickf27e9872019-12-07 06:28:46 -0800921 Item &setInt64(const char *key, int64_t value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700922 return set(key, value);
923 }
Ray Essickf27e9872019-12-07 06:28:46 -0800924 Item &setDouble(const char *key, double value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700925 return set(key, value);
926 }
Ray Essickf27e9872019-12-07 06:28:46 -0800927 Item &setRate(const char *key, int64_t count, int64_t duration) {
Andy Hungaeef7882019-10-18 15:18:14 -0700928 return set(key, std::make_pair(count, duration));
929 }
Ray Essickf27e9872019-12-07 06:28:46 -0800930 Item &setCString(const char *key, const char *value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700931 return set(key, value);
932 }
Ray Essick3938dc62016-11-01 08:56:56 -0700933
Andy Hungaeef7882019-10-18 15:18:14 -0700934 // fused get/add/set; if attr wasn't there, it's a simple set.
935 // type-mismatch counts as "wasn't there".
936 template<typename S, typename T>
Ray Essickf27e9872019-12-07 06:28:46 -0800937 Item &add(S key, T value) {
Andy Hung47e58d62019-12-06 18:40:19 -0800938 findOrAllocateProp(key).add(value);
Andy Hungaeef7882019-10-18 15:18:14 -0700939 return *this;
940 }
941
Ray Essickf27e9872019-12-07 06:28:46 -0800942 Item &addInt32(const char *key, int32_t value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700943 return add(key, value);
944 }
Ray Essickf27e9872019-12-07 06:28:46 -0800945 Item &addInt64(const char *key, int64_t value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700946 return add(key, value);
947 }
Ray Essickf27e9872019-12-07 06:28:46 -0800948 Item &addDouble(const char *key, double value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700949 return add(key, value);
950 }
Ray Essickf27e9872019-12-07 06:28:46 -0800951 Item &addRate(const char *key, int64_t count, int64_t duration) {
Andy Hungaeef7882019-10-18 15:18:14 -0700952 return add(key, std::make_pair(count, duration));
953 }
954
955 // find & extract values
956 // return indicates whether attr exists (and thus value filled in)
957 // NULL parameter value suppresses storage of value.
958 template<typename S, typename T>
959 bool get(S key, T *value) const {
Andy Hung47e58d62019-12-06 18:40:19 -0800960 const Prop *prop = findProp(key);
Andy Hungaeef7882019-10-18 15:18:14 -0700961 return prop != nullptr && prop->get(value);
962 }
963
Andy Hung3253f2d2019-10-21 14:50:07 -0700964 bool getInt32(const char *key, int32_t *value) const {
Andy Hungaeef7882019-10-18 15:18:14 -0700965 return get(key, value);
966 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700967 bool getInt64(const char *key, int64_t *value) const {
Andy Hungaeef7882019-10-18 15:18:14 -0700968 return get(key, value);
969 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700970 bool getDouble(const char *key, double *value) const {
Andy Hungaeef7882019-10-18 15:18:14 -0700971 return get(key, value);
972 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700973 bool getRate(const char *key, int64_t *count, int64_t *duration, double *rate) const {
Andy Hungaeef7882019-10-18 15:18:14 -0700974 std::pair<int64_t, int64_t> value;
975 if (!get(key, &value)) return false;
976 if (count != nullptr) *count = value.first;
977 if (duration != nullptr) *duration = value.second;
978 if (rate != nullptr) {
979 if (value.second != 0) {
980 *rate = (double)value.first / value.second; // TODO: isn't INF OK?
981 } else {
982 *rate = 0.;
983 }
984 }
985 return true;
986 }
987 // Caller owns the returned string
Andy Hung3253f2d2019-10-21 14:50:07 -0700988 bool getCString(const char *key, char **value) const {
Andy Hungb7aadb32019-12-09 19:40:42 -0800989 std::string s;
990 if (get(key, &s)) {
991 *value = strdup(s.c_str());
Andy Hung3253f2d2019-10-21 14:50:07 -0700992 return true;
993 }
994 return false;
Andy Hungaeef7882019-10-18 15:18:14 -0700995 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700996 bool getString(const char *key, std::string *value) const {
Andy Hungaeef7882019-10-18 15:18:14 -0700997 return get(key, value);
998 }
Ray Essick3938dc62016-11-01 08:56:56 -0700999
Andy Hung692870b2020-01-02 13:46:06 -08001000 const Prop::Elem* get(const char *key) const {
1001 const Prop *prop = findProp(key);
1002 return prop == nullptr ? nullptr : &prop->get();
1003 }
1004
Andy Hunga87e69c2019-10-18 10:07:40 -07001005 // Deliver the item to MediaMetrics
Ray Essick3938dc62016-11-01 08:56:56 -07001006 bool selfrecord();
1007
Andy Hung3253f2d2019-10-21 14:50:07 -07001008 // remove indicated attributes and their values
1009 // filterNot() could also be called keepOnly()
1010 // return value is # attributes removed
1011 // XXX: perhaps 'remove' instead of 'filter'
1012 // XXX: filterNot would become 'keep'
1013 size_t filter(size_t count, const char *attrs[]);
1014 size_t filterNot(size_t count, const char *attrs[]);
1015 size_t filter(const char *attr) { return filter(1, &attr); }
Ray Essick3938dc62016-11-01 08:56:56 -07001016
1017 // below here are used on server side or to talk to server
1018 // clients need not worry about these.
1019
1020 // timestamp, pid, and uid only used on server side
Ray Essickb5fac8e2016-12-12 11:33:56 -08001021 // timestamp is in 'nanoseconds, unix time'
Ray Essickf27e9872019-12-07 06:28:46 -08001022 Item &setTimestamp(nsecs_t);
Ray Essick3938dc62016-11-01 08:56:56 -07001023 nsecs_t getTimestamp() const;
1024
Ray Essickf27e9872019-12-07 06:28:46 -08001025 Item &setPid(pid_t);
Ray Essick3938dc62016-11-01 08:56:56 -07001026 pid_t getPid() const;
1027
Ray Essickf27e9872019-12-07 06:28:46 -08001028 Item &setUid(uid_t);
Ray Essick3938dc62016-11-01 08:56:56 -07001029 uid_t getUid() const;
1030
Ray Essickf27e9872019-12-07 06:28:46 -08001031 Item &setPkgName(const std::string &pkgName);
Ray Essick783bd0d2018-01-11 11:10:35 -08001032 std::string getPkgName() const { return mPkgName; }
Ray Essickf65f4212017-08-31 11:41:19 -07001033
Ray Essickf27e9872019-12-07 06:28:46 -08001034 Item &setPkgVersionCode(int64_t);
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -08001035 int64_t getPkgVersionCode() const;
Ray Essickf65f4212017-08-31 11:41:19 -07001036
Andy Hung3253f2d2019-10-21 14:50:07 -07001037 // our serialization code for binder calls
1038 status_t writeToParcel(Parcel *) const;
1039 status_t readFromParcel(const Parcel&);
Ray Essick3938dc62016-11-01 08:56:56 -07001040
Andy Hung3253f2d2019-10-21 14:50:07 -07001041 status_t writeToByteString(char **bufferptr, size_t *length) const;
1042 status_t readFromByteString(const char *bufferptr, size_t length);
1043
Ray Essickba8c4842019-01-18 11:35:33 -08001044
Andy Hung17dbaf22019-10-11 14:06:31 -07001045 std::string toString() const;
1046 std::string toString(int version) const;
Ray Essick20147322018-11-17 09:08:39 -08001047 const char *toCString();
1048 const char *toCString(int version);
Ray Essick3938dc62016-11-01 08:56:56 -07001049
Andy Hung0f7ad8c2020-01-03 13:24:34 -08001050 /**
1051 * Returns true if the item has a property with a target value.
1052 *
1053 * If propName is nullptr, hasPropElem() returns false.
1054 *
1055 * \param propName is the property name.
1056 * \param elem is the value to match. std::monostate matches any.
1057 */
1058 bool hasPropElem(const char *propName, const Prop::Elem& elem) const {
1059 if (propName == nullptr) return false;
1060 const Prop::Elem *e = get(propName);
1061 return e != nullptr && (std::holds_alternative<std::monostate>(elem) || elem == *e);
1062 }
1063
1064 /**
1065 * Returns -2, -1, 0 (success) if the item has a property (wildcard matched) with a
1066 * target value.
1067 *
1068 * The enum RecursiveWildcardCheck designates the meaning of the returned value.
1069 *
1070 * RECURSIVE_WILDCARD_CHECK_NO_MATCH_NO_WILDCARD = -2,
1071 * RECURSIVE_WILDCARD_CHECK_NO_MATCH_WILDCARD_FOUND = -1,
1072 * RECURSIVE_WILDCARD_CHECK_MATCH_FOUND = 0.
1073 *
1074 * If url is nullptr, RECURSIVE_WILDCARD_CHECK_NO_MATCH_NO_WILDCARD is returned.
1075 *
1076 * \param url is the full item + property name, which may have wildcards '*'
1077 * denoting an arbitrary sequence of 0 or more characters.
1078 * \param elem is the target property value to match. std::monostate matches any.
1079 * \return 0 if the property was matched,
1080 * -1 if the property was not matched and a wildcard char was encountered,
1081 * -2 if the property was not matched with no wildcard char encountered.
1082 */
1083 enum RecursiveWildcardCheck {
1084 RECURSIVE_WILDCARD_CHECK_NO_MATCH_NO_WILDCARD = -2,
1085 RECURSIVE_WILDCARD_CHECK_NO_MATCH_WILDCARD_FOUND = -1,
1086 RECURSIVE_WILDCARD_CHECK_MATCH_FOUND = 0,
1087 };
1088
1089 enum RecursiveWildcardCheck recursiveWildcardCheckElem(
1090 const char *url, const Prop::Elem& elem) const {
1091 if (url == nullptr) return RECURSIVE_WILDCARD_CHECK_NO_MATCH_NO_WILDCARD;
1092 return recursiveWildcardCheckElem(getKey().c_str(), url, elem);
1093 }
1094
Andy Hung3253f2d2019-10-21 14:50:07 -07001095private:
Andy Hung0f7ad8c2020-01-03 13:24:34 -08001096
1097 enum RecursiveWildcardCheck recursiveWildcardCheckElem(
1098 const char *itemKeyPtr, const char *url, const Prop::Elem& elem) const {
1099 for (; *url && *itemKeyPtr; ++url, ++itemKeyPtr) {
1100 if (*url != *itemKeyPtr) {
1101 if (*url == '*') { // wildcard
1102 ++url;
1103 while (true) {
1104 if (recursiveWildcardCheckElem(itemKeyPtr, url, elem)
1105 == RECURSIVE_WILDCARD_CHECK_MATCH_FOUND) {
1106 return RECURSIVE_WILDCARD_CHECK_MATCH_FOUND;
1107 }
1108 if (*itemKeyPtr == 0) break;
1109 ++itemKeyPtr;
1110 }
1111 return RECURSIVE_WILDCARD_CHECK_NO_MATCH_WILDCARD_FOUND;
1112 }
1113 return RECURSIVE_WILDCARD_CHECK_NO_MATCH_NO_WILDCARD;
1114 }
1115 }
1116 if (itemKeyPtr[0] != 0 || url[0] != '.') {
1117 return RECURSIVE_WILDCARD_CHECK_NO_MATCH_NO_WILDCARD;
1118 }
1119 const char *propName = url + 1; // skip the '.'
1120 return hasPropElem(propName, elem)
1121 ? RECURSIVE_WILDCARD_CHECK_MATCH_FOUND
1122 : RECURSIVE_WILDCARD_CHECK_NO_MATCH_NO_WILDCARD;
1123 }
1124
Andy Hung3253f2d2019-10-21 14:50:07 -07001125 // handle Parcel version 0
1126 int32_t writeToParcel0(Parcel *) const;
1127 int32_t readFromParcel0(const Parcel&);
1128
Andy Hung47e58d62019-12-06 18:40:19 -08001129 const Prop *findProp(const char *key) const {
1130 auto it = mProps.find(key);
1131 return it != mProps.end() ? &it->second : nullptr;
1132 }
Andy Hungaeef7882019-10-18 15:18:14 -07001133
Andy Hung47e58d62019-12-06 18:40:19 -08001134 Prop &findOrAllocateProp(const char *key) {
1135 auto it = mProps.find(key);
1136 if (it != mProps.end()) return it->second;
1137 Prop &prop = mProps[key];
1138 prop.setName(key);
1139 return prop;
1140 }
Andy Hungaeef7882019-10-18 15:18:14 -07001141
Andy Hung565cc482020-01-02 13:40:04 -08001142 // Changes to member variables below require changes to clear().
Andy Hungaeef7882019-10-18 15:18:14 -07001143 pid_t mPid = -1;
1144 uid_t mUid = -1;
1145 std::string mPkgName;
1146 int64_t mPkgVersionCode = 0;
Andy Hung47e58d62019-12-06 18:40:19 -08001147 std::string mKey;
Andy Hungaeef7882019-10-18 15:18:14 -07001148 nsecs_t mTimestamp = 0;
Andy Hung47e58d62019-12-06 18:40:19 -08001149 std::map<std::string, Prop> mProps;
Ray Essick3938dc62016-11-01 08:56:56 -07001150};
1151
Ray Essickf27e9872019-12-07 06:28:46 -08001152} // namespace mediametrics
Ray Essick3938dc62016-11-01 08:56:56 -07001153} // namespace android
1154
Andy Hung47e58d62019-12-06 18:40:19 -08001155#endif // ANDROID_MEDIA_MEDIAMETRICSITEM_H