blob: f69de7ad4558f92150ded252bc25cc66c3dc1059 [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>
Ray Essickba8c4842019-01-18 11:35:33 -080026
27#include <cutils/properties.h>
Ray Essick3938dc62016-11-01 08:56:56 -070028#include <utils/Errors.h>
29#include <utils/KeyedVector.h>
30#include <utils/RefBase.h>
31#include <utils/StrongPointer.h>
32#include <utils/Timers.h>
33
Ray Essick3938dc62016-11-01 08:56:56 -070034namespace android {
35
Ray Essickf27e9872019-12-07 06:28:46 -080036class IMediaMetricsService;
Ray Essick783bd0d2018-01-11 11:10:35 -080037class Parcel;
Ray Essick3938dc62016-11-01 08:56:56 -070038
Andy Hung3253f2d2019-10-21 14:50:07 -070039/*
Andy Hung1efc9c62019-12-03 13:43:33 -080040 * MediaMetrics Item
Andy Hung3253f2d2019-10-21 14:50:07 -070041 *
Andy Hung1efc9c62019-12-03 13:43:33 -080042 * Byte string format.
43 *
44 * For Java
45 * int64 corresponds to long
46 * int32, uint32 corresponds to int
47 * uint16 corresponds to char
48 * uint8, int8 corresponds to byte
49 *
50 * Hence uint8 and uint32 values are limited to INT8_MAX and INT32_MAX.
51 *
52 * Physical layout of integers and doubles within the MediaMetrics byte string
53 * is in Native / host order, which is nearly always little endian.
54 *
55 * -- begin of item
56 * -- begin of header
57 * (uint32) item size: including the item size field
58 * (uint32) header size, including the item size and header size fields.
59 * (uint16) version: exactly 0
60 * (uint16) key size, that is key strlen + 1 for zero termination.
61 * (int8)+ key string which is 0 terminated
Andy Hung3253f2d2019-10-21 14:50:07 -070062 * (int32) pid
63 * (int32) uid
64 * (int64) timestamp
Andy Hung1efc9c62019-12-03 13:43:33 -080065 * -- end of header
66 * -- begin body
67 * (uint32) number of properties
68 * -- repeat for number of properties
69 * (uint16) property size, including property size field itself
Andy Hung3253f2d2019-10-21 14:50:07 -070070 * (uint8) type of property
71 * (int8)+ key string, including 0 termination
Andy Hung1efc9c62019-12-03 13:43:33 -080072 * based on type of property (given above), one of:
Andy Hung3253f2d2019-10-21 14:50:07 -070073 * (int32)
74 * (int64)
75 * (double)
76 * (int8)+ for cstring, including 0 termination
77 * (int64, int64) for rate
Andy Hung1efc9c62019-12-03 13:43:33 -080078 * -- end body
79 * -- end of item
Andy Hung3253f2d2019-10-21 14:50:07 -070080 */
81
Andy Hung1efc9c62019-12-03 13:43:33 -080082namespace mediametrics {
83
84// Type must match MediaMetrics.java
85enum Type {
86 kTypeNone = 0,
87 kTypeInt32 = 1,
88 kTypeInt64 = 2,
89 kTypeDouble = 3,
90 kTypeCString = 4,
91 kTypeRate = 5,
92};
93
94template<size_t N>
95static inline bool startsWith(const std::string &s, const char (&comp)[N]) {
96 return !strncmp(s.c_str(), comp, N-1);
97}
98
99/**
100 * Media Metrics BaseItem
101 *
102 * A base class which contains utility static functions to write to a byte stream
103 * and access the Media Metrics service.
104 */
105
106class BaseItem {
107 friend class MediaMetricsDeathNotifier; // for dropInstance
108 // enabled 1, disabled 0
109public:
Andy Hung47e58d62019-12-06 18:40:19 -0800110 // are we collecting metrics data
Andy Hung1efc9c62019-12-03 13:43:33 -0800111 static bool isEnabled();
Andy Hung47e58d62019-12-06 18:40:19 -0800112 static sp<IMediaMetricsService> getService();
Andy Hung1efc9c62019-12-03 13:43:33 -0800113
114protected:
115 static constexpr const char * const EnabledProperty = "media.metrics.enabled";
116 static constexpr const char * const EnabledPropertyPersist = "persist.media.metrics.enabled";
117 static const int EnabledProperty_default = 1;
118
119 // let's reuse a binder connection
Ray Essickf27e9872019-12-07 06:28:46 -0800120 static sp<IMediaMetricsService> sMediaMetricsService;
Andy Hung47e58d62019-12-06 18:40:19 -0800121
Andy Hung1efc9c62019-12-03 13:43:33 -0800122 static void dropInstance();
123 static bool submitBuffer(const char *buffer, size_t len);
124
125 static status_t writeToByteString(
126 const char *name, int32_t value, char **bufferpptr, char *bufferptrmax);
127 static status_t writeToByteString(
128 const char *name, int64_t value, char **bufferpptr, char *bufferptrmax);
129 static status_t writeToByteString(
130 const char *name, double value, char **bufferpptr, char *bufferptrmax);
131 static status_t writeToByteString(
132 const char *name, const std::pair<int64_t, int64_t> &value,
133 char **bufferpptr, char *bufferptrmax);
134 static status_t writeToByteString(
135 const char *name, char * const &value, char **bufferpptr, char *bufferptrmax);
136 static status_t writeToByteString(
137 const char *name, const char * const &value, char **bufferpptr, char *bufferptrmax);
Andy Hung47e58d62019-12-06 18:40:19 -0800138 struct none_t {}; // for mediametrics::kTypeNone
Andy Hung1efc9c62019-12-03 13:43:33 -0800139 static status_t writeToByteString(
140 const char *name, const none_t &, char **bufferpptr, char *bufferptrmax);
141
142 template<typename T>
143 static status_t sizeOfByteString(const char *name, const T& value) {
144 return 2 + 1 + strlen(name) + 1 + sizeof(value);
145 }
146 template<> // static
147 status_t sizeOfByteString(const char *name, char * const &value) {
148 return 2 + 1 + strlen(name) + 1 + strlen(value) + 1;
149 }
150 template<> // static
151 status_t sizeOfByteString(const char *name, const char * const &value) {
152 return 2 + 1 + strlen(name) + 1 + strlen(value) + 1;
153 }
154 template<> // static
155 status_t sizeOfByteString(const char *name, const none_t &) {
156 return 2 + 1 + strlen(name) + 1;
157 }
158};
159
160/**
161 * Media Metrics BufferedItem
162 *
163 * A base class which represents a put-only Media Metrics item, storing
164 * the Media Metrics data in a buffer with begin and end pointers.
165 *
166 * If a property key is entered twice, it will be stored in the buffer twice,
167 * and (implementation defined) the last value for that key will be used
168 * by the Media Metrics service.
169 *
170 * For realloc, a baseRealloc pointer must be passed in either explicitly
171 * or implicitly in the constructor. This will be updated with the value used on realloc.
172 */
173class BufferedItem : public BaseItem {
174public:
175 static inline constexpr uint16_t kVersion = 0;
176
177 virtual ~BufferedItem() = default;
178 BufferedItem(const BufferedItem&) = delete;
179 BufferedItem& operator=(const BufferedItem&) = delete;
180
181 BufferedItem(const std::string key, char *begin, char *end)
182 : BufferedItem(key.c_str(), begin, end) { }
183
184 BufferedItem(const char *key, char *begin, char *end)
185 : BufferedItem(key, begin, end, nullptr) { }
186
187 BufferedItem(const char *key, char **begin, char *end)
188 : BufferedItem(key, *begin, end, begin) { }
189
190 BufferedItem(const char *key, char *begin, char *end, char **baseRealloc)
191 : mBegin(begin)
192 , mEnd(end)
193 , mBaseRealloc(baseRealloc)
194 {
195 init(key);
196 }
197
198 template<typename T>
199 BufferedItem &set(const char *key, const T& value) {
200 reallocFor(sizeOfByteString(key, value));
201 if (mStatus == NO_ERROR) {
202 mStatus = BaseItem::writeToByteString(key, value, &mBptr, mEnd);
203 ++mPropCount;
204 }
205 return *this;
206 }
207
208 template<typename T>
209 BufferedItem &set(const std::string& key, const T& value) {
210 return set(key.c_str(), value);
211 }
212
213 BufferedItem &setPid(pid_t pid) {
214 if (mStatus == NO_ERROR) {
215 copyTo(mBegin + mHeaderLen - 16, (int32_t)pid);
216 }
217 return *this;
218 }
219
220 BufferedItem &setUid(uid_t uid) {
221 if (mStatus == NO_ERROR) {
222 copyTo(mBegin + mHeaderLen - 12, (int32_t)uid);
223 }
224 return *this;
225 }
226
227 BufferedItem &setTimestamp(nsecs_t timestamp) {
228 if (mStatus == NO_ERROR) {
229 copyTo(mBegin + mHeaderLen - 8, (int64_t)timestamp);
230 }
231 return *this;
232 }
233
234 bool record() {
235 return updateHeader()
236 && BaseItem::submitBuffer(getBuffer(), getLength());
237 }
238
239 bool isValid () const {
240 return mStatus == NO_ERROR;
241 }
242
243 char *getBuffer() const { return mBegin; }
244 size_t getLength() const { return mBptr - mBegin; }
245 size_t getRemaining() const { return mEnd - mBptr; }
246 size_t getCapacity() const { return mEnd - mBegin; }
247
248 bool updateHeader() {
249 if (mStatus != NO_ERROR) return false;
250 copyTo(mBegin + 0, (uint32_t)getLength());
251 copyTo(mBegin + 4, (uint32_t)mHeaderLen);
252 copyTo(mBegin + mHeaderLen, (uint32_t)mPropCount);
253 return true;
254 }
255
256protected:
257 BufferedItem() = default;
258
259 void reallocFor(size_t required) {
260 if (mStatus != NO_ERROR) return;
261 const size_t remaining = getRemaining();
262 if (required <= remaining) return;
263 if (mBaseRealloc == nullptr) {
264 mStatus = NO_MEMORY;
265 return;
266 }
267
268 const size_t current = getLength();
269 size_t minimum = current + required;
270 if (minimum > SSIZE_MAX >> 1) {
271 mStatus = NO_MEMORY;
272 return;
273 }
274 minimum <<= 1;
275 void *newptr = realloc(*mBaseRealloc, minimum);
276 if (newptr == nullptr) {
277 mStatus = NO_MEMORY;
278 return;
279 }
280 if (newptr != *mBaseRealloc) {
281 // ALOGD("base changed! current:%zu new size %zu", current, minimum);
282 if (*mBaseRealloc == nullptr) {
283 memcpy(newptr, mBegin, current);
284 }
285 mBegin = (char *)newptr;
286 *mBaseRealloc = mBegin;
287 mEnd = mBegin + minimum;
288 mBptr = mBegin + current;
289 } else {
290 // ALOGD("base kept! current:%zu new size %zu", current, minimum);
291 mEnd = mBegin + minimum;
292 }
293 }
294 template<typename T>
295 void copyTo(char *ptr, const T& value) {
296 memcpy(ptr, &value, sizeof(value));
297 }
298
299 void init(const char *key) {
300 mBptr = mBegin;
301 const size_t keylen = strlen(key) + 1;
302 mHeaderLen = 4 + 4 + 2 + 2 + keylen + 4 + 4 + 8;
303 reallocFor(mHeaderLen);
304 if (mStatus != NO_ERROR) return;
305 mBptr = mBegin + mHeaderLen + 4; // this includes propcount.
306
307 if (mEnd < mBptr || keylen > UINT16_MAX) {
308 mStatus = NO_MEMORY;
309 mBptr = mEnd;
310 return;
311 }
312 copyTo(mBegin + 8, kVersion);
313 copyTo(mBegin + 10, (uint16_t)keylen);
314 strcpy(mBegin + 12, key);
315
316 // initialize some parameters (that could be overridden)
317 setPid(-1);
318 setUid(-1);
319 setTimestamp(0);
320 }
321
322 char *mBegin = nullptr;
323 char *mEnd = nullptr;
324 char **mBaseRealloc = nullptr; // set to an address if realloc should be done.
325 // upon return, that pointer is updated with
326 // whatever needs to be freed.
327 char *mBptr = nullptr;
328 status_t mStatus = NO_ERROR;
329 uint32_t mPropCount = 0;
330 uint32_t mHeaderLen = 0;
331};
332
333/**
Andy Hung47e58d62019-12-06 18:40:19 -0800334 * MediaMetrics LogItem is a stack allocated mediametrics item used for
Andy Hung1efc9c62019-12-03 13:43:33 -0800335 * fast logging. It falls over to a malloc if needed.
336 *
337 * This is templated with a buffer size to allocate on the stack.
338 */
339template <size_t N = 4096>
Ray Essickf27e9872019-12-07 06:28:46 -0800340class LogItem : public BufferedItem {
Andy Hung1efc9c62019-12-03 13:43:33 -0800341public:
Ray Essickf27e9872019-12-07 06:28:46 -0800342 explicit LogItem(const std::string key) : LogItem(key.c_str()) { }
Andy Hung1efc9c62019-12-03 13:43:33 -0800343
344 // Since this class will not be defined before the base class, we initialize variables
345 // in our own order.
Ray Essickf27e9872019-12-07 06:28:46 -0800346 explicit LogItem(const char *key) {
Andy Hung1efc9c62019-12-03 13:43:33 -0800347 mBegin = mBuffer;
348 mEnd = mBuffer + N;
349 mBaseRealloc = &mReallocPtr;
350 init(key);
351 }
352
Ray Essickf27e9872019-12-07 06:28:46 -0800353 ~LogItem() override {
Andy Hung1efc9c62019-12-03 13:43:33 -0800354 if (mReallocPtr != nullptr) { // do the check before calling free to avoid overhead.
355 free(mReallocPtr);
356 }
357 }
358
359private:
360 char *mReallocPtr = nullptr; // set non-null by base class if realloc happened.
361 char mBuffer[N];
362};
363
Andy Hung1efc9c62019-12-03 13:43:33 -0800364
Andy Hung3253f2d2019-10-21 14:50:07 -0700365/**
Ray Essickf27e9872019-12-07 06:28:46 -0800366 * Media Metrics Item
Andy Hung3253f2d2019-10-21 14:50:07 -0700367 *
368 * A mutable item representing an event or record that will be
Andy Hung1efc9c62019-12-03 13:43:33 -0800369 * logged with the Media Metrics service. For client logging, one should
370 * use the mediametrics::Item.
Andy Hung3253f2d2019-10-21 14:50:07 -0700371 *
Ray Essickf27e9872019-12-07 06:28:46 -0800372 * The Item is designed for the service as it has getters.
Andy Hung3253f2d2019-10-21 14:50:07 -0700373 */
Ray Essickf27e9872019-12-07 06:28:46 -0800374class Item : public mediametrics::BaseItem {
Andy Hungaeef7882019-10-18 15:18:14 -0700375public:
Ray Essick3938dc62016-11-01 08:56:56 -0700376
Ray Essickf65f4212017-08-31 11:41:19 -0700377 enum {
378 PROTO_V0 = 0,
379 PROTO_FIRST = PROTO_V0,
380 PROTO_V1 = 1,
381 PROTO_LAST = PROTO_V1,
382 };
383
Andy Hungaeef7882019-10-18 15:18:14 -0700384 // T must be convertible to mKey
385 template <typename T>
Ray Essickf27e9872019-12-07 06:28:46 -0800386 explicit Item(T key)
Andy Hungaeef7882019-10-18 15:18:14 -0700387 : mKey(key) { }
Ray Essickf27e9872019-12-07 06:28:46 -0800388 Item() = default;
Andy Hung3253f2d2019-10-21 14:50:07 -0700389
Ray Essickf27e9872019-12-07 06:28:46 -0800390 bool operator==(const Item& other) const {
Andy Hung47e58d62019-12-06 18:40:19 -0800391 if (mPid != other.mPid
Andy Hung3253f2d2019-10-21 14:50:07 -0700392 || mUid != other.mUid
393 || mPkgName != other.mPkgName
394 || mPkgVersionCode != other.mPkgVersionCode
395 || mKey != other.mKey
Andy Hung47e58d62019-12-06 18:40:19 -0800396 || mTimestamp != other.mTimestamp
397 || mProps != other.mProps) return false;
Andy Hung3253f2d2019-10-21 14:50:07 -0700398 return true;
399 }
Ray Essickf27e9872019-12-07 06:28:46 -0800400 bool operator!=(const Item& other) const {
Andy Hung3253f2d2019-10-21 14:50:07 -0700401 return !(*this == other);
402 }
403
404 template <typename T>
Ray Essickf27e9872019-12-07 06:28:46 -0800405 static Item* create(T key) {
406 return new Item(key);
Andy Hung3253f2d2019-10-21 14:50:07 -0700407 }
Ray Essickf27e9872019-12-07 06:28:46 -0800408 static Item* create() {
409 return new Item();
Andy Hung3253f2d2019-10-21 14:50:07 -0700410 }
Ray Essickba8c4842019-01-18 11:35:33 -0800411
Ray Essickf27e9872019-12-07 06:28:46 -0800412 static Item* convert(mediametrics_handle_t);
413 static mediametrics_handle_t convert(Item *);
Ray Essickbf536ac2019-08-26 11:04:28 -0700414
Ray Essick3938dc62016-11-01 08:56:56 -0700415 // access functions for the class
Ray Essickf27e9872019-12-07 06:28:46 -0800416 ~Item();
Ray Essick3938dc62016-11-01 08:56:56 -0700417
Andy Hung47e58d62019-12-06 18:40:19 -0800418 void clear() {
419 mPid = -1;
420 mUid = -1;
421 mPkgName.clear();
422 mPkgVersionCode = 0;
423 mTimestamp = 0;
424 mKey.clear();
425 mProps.clear();
426 }
427
428 Item *dup() const { return new Item(*this); }
Ray Essick3938dc62016-11-01 08:56:56 -0700429
Ray Essickf27e9872019-12-07 06:28:46 -0800430 Item &setKey(const char *key) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700431 mKey = key;
432 return *this;
433 }
434 const std::string& getKey() const { return mKey; }
Ray Essick3938dc62016-11-01 08:56:56 -0700435
Andy Hung3253f2d2019-10-21 14:50:07 -0700436 // # of properties in the record
Andy Hung47e58d62019-12-06 18:40:19 -0800437 size_t count() const { return mProps.size(); }
Ray Essick3938dc62016-11-01 08:56:56 -0700438
Andy Hungaeef7882019-10-18 15:18:14 -0700439 template<typename S, typename T>
Ray Essickf27e9872019-12-07 06:28:46 -0800440 Item &set(S key, T value) {
Andy Hung47e58d62019-12-06 18:40:19 -0800441 findOrAllocateProp(key).set(value);
Andy Hungaeef7882019-10-18 15:18:14 -0700442 return *this;
443 }
Ray Essick3938dc62016-11-01 08:56:56 -0700444
Andy Hungaeef7882019-10-18 15:18:14 -0700445 // set values appropriately
Ray Essickf27e9872019-12-07 06:28:46 -0800446 Item &setInt32(const char *key, int32_t value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700447 return set(key, value);
448 }
Ray Essickf27e9872019-12-07 06:28:46 -0800449 Item &setInt64(const char *key, int64_t value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700450 return set(key, value);
451 }
Ray Essickf27e9872019-12-07 06:28:46 -0800452 Item &setDouble(const char *key, double value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700453 return set(key, value);
454 }
Ray Essickf27e9872019-12-07 06:28:46 -0800455 Item &setRate(const char *key, int64_t count, int64_t duration) {
Andy Hungaeef7882019-10-18 15:18:14 -0700456 return set(key, std::make_pair(count, duration));
457 }
Ray Essickf27e9872019-12-07 06:28:46 -0800458 Item &setCString(const char *key, const char *value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700459 return set(key, value);
460 }
Ray Essick3938dc62016-11-01 08:56:56 -0700461
Andy Hungaeef7882019-10-18 15:18:14 -0700462 // fused get/add/set; if attr wasn't there, it's a simple set.
463 // type-mismatch counts as "wasn't there".
464 template<typename S, typename T>
Ray Essickf27e9872019-12-07 06:28:46 -0800465 Item &add(S key, T value) {
Andy Hung47e58d62019-12-06 18:40:19 -0800466 findOrAllocateProp(key).add(value);
Andy Hungaeef7882019-10-18 15:18:14 -0700467 return *this;
468 }
469
Ray Essickf27e9872019-12-07 06:28:46 -0800470 Item &addInt32(const char *key, int32_t value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700471 return add(key, value);
472 }
Ray Essickf27e9872019-12-07 06:28:46 -0800473 Item &addInt64(const char *key, int64_t value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700474 return add(key, value);
475 }
Ray Essickf27e9872019-12-07 06:28:46 -0800476 Item &addDouble(const char *key, double value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700477 return add(key, value);
478 }
Ray Essickf27e9872019-12-07 06:28:46 -0800479 Item &addRate(const char *key, int64_t count, int64_t duration) {
Andy Hungaeef7882019-10-18 15:18:14 -0700480 return add(key, std::make_pair(count, duration));
481 }
482
483 // find & extract values
484 // return indicates whether attr exists (and thus value filled in)
485 // NULL parameter value suppresses storage of value.
486 template<typename S, typename T>
487 bool get(S key, T *value) const {
Andy Hung47e58d62019-12-06 18:40:19 -0800488 const Prop *prop = findProp(key);
Andy Hungaeef7882019-10-18 15:18:14 -0700489 return prop != nullptr && prop->get(value);
490 }
491
Andy Hung3253f2d2019-10-21 14:50:07 -0700492 bool getInt32(const char *key, int32_t *value) const {
Andy Hungaeef7882019-10-18 15:18:14 -0700493 return get(key, value);
494 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700495 bool getInt64(const char *key, int64_t *value) const {
Andy Hungaeef7882019-10-18 15:18:14 -0700496 return get(key, value);
497 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700498 bool getDouble(const char *key, double *value) const {
Andy Hungaeef7882019-10-18 15:18:14 -0700499 return get(key, value);
500 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700501 bool getRate(const char *key, int64_t *count, int64_t *duration, double *rate) const {
Andy Hungaeef7882019-10-18 15:18:14 -0700502 std::pair<int64_t, int64_t> value;
503 if (!get(key, &value)) return false;
504 if (count != nullptr) *count = value.first;
505 if (duration != nullptr) *duration = value.second;
506 if (rate != nullptr) {
507 if (value.second != 0) {
508 *rate = (double)value.first / value.second; // TODO: isn't INF OK?
509 } else {
510 *rate = 0.;
511 }
512 }
513 return true;
514 }
515 // Caller owns the returned string
Andy Hung3253f2d2019-10-21 14:50:07 -0700516 bool getCString(const char *key, char **value) const {
517 const char *cs;
518 if (get(key, &cs)) {
519 *value = cs != nullptr ? strdup(cs) : nullptr;
520 return true;
521 }
522 return false;
Andy Hungaeef7882019-10-18 15:18:14 -0700523 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700524 bool getString(const char *key, std::string *value) const {
Andy Hungaeef7882019-10-18 15:18:14 -0700525 return get(key, value);
526 }
Ray Essick3938dc62016-11-01 08:56:56 -0700527
Andy Hunga87e69c2019-10-18 10:07:40 -0700528 // Deliver the item to MediaMetrics
Ray Essick3938dc62016-11-01 08:56:56 -0700529 bool selfrecord();
530
Andy Hung3253f2d2019-10-21 14:50:07 -0700531 // remove indicated attributes and their values
532 // filterNot() could also be called keepOnly()
533 // return value is # attributes removed
534 // XXX: perhaps 'remove' instead of 'filter'
535 // XXX: filterNot would become 'keep'
536 size_t filter(size_t count, const char *attrs[]);
537 size_t filterNot(size_t count, const char *attrs[]);
538 size_t filter(const char *attr) { return filter(1, &attr); }
Ray Essick3938dc62016-11-01 08:56:56 -0700539
540 // below here are used on server side or to talk to server
541 // clients need not worry about these.
542
543 // timestamp, pid, and uid only used on server side
Ray Essickb5fac8e2016-12-12 11:33:56 -0800544 // timestamp is in 'nanoseconds, unix time'
Ray Essickf27e9872019-12-07 06:28:46 -0800545 Item &setTimestamp(nsecs_t);
Ray Essick3938dc62016-11-01 08:56:56 -0700546 nsecs_t getTimestamp() const;
547
Ray Essickf27e9872019-12-07 06:28:46 -0800548 Item &setPid(pid_t);
Ray Essick3938dc62016-11-01 08:56:56 -0700549 pid_t getPid() const;
550
Ray Essickf27e9872019-12-07 06:28:46 -0800551 Item &setUid(uid_t);
Ray Essick3938dc62016-11-01 08:56:56 -0700552 uid_t getUid() const;
553
Ray Essickf27e9872019-12-07 06:28:46 -0800554 Item &setPkgName(const std::string &pkgName);
Ray Essick783bd0d2018-01-11 11:10:35 -0800555 std::string getPkgName() const { return mPkgName; }
Ray Essickf65f4212017-08-31 11:41:19 -0700556
Ray Essickf27e9872019-12-07 06:28:46 -0800557 Item &setPkgVersionCode(int64_t);
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800558 int64_t getPkgVersionCode() const;
Ray Essickf65f4212017-08-31 11:41:19 -0700559
Andy Hung3253f2d2019-10-21 14:50:07 -0700560 // our serialization code for binder calls
561 status_t writeToParcel(Parcel *) const;
562 status_t readFromParcel(const Parcel&);
Ray Essick3938dc62016-11-01 08:56:56 -0700563
Andy Hung3253f2d2019-10-21 14:50:07 -0700564 status_t writeToByteString(char **bufferptr, size_t *length) const;
565 status_t readFromByteString(const char *bufferptr, size_t length);
566
Ray Essickba8c4842019-01-18 11:35:33 -0800567
Andy Hung17dbaf22019-10-11 14:06:31 -0700568 std::string toString() const;
569 std::string toString(int version) const;
Ray Essick20147322018-11-17 09:08:39 -0800570 const char *toCString();
571 const char *toCString(int version);
Ray Essick3938dc62016-11-01 08:56:56 -0700572
Andy Hung3253f2d2019-10-21 14:50:07 -0700573private:
574 // handle Parcel version 0
575 int32_t writeToParcel0(Parcel *) const;
576 int32_t readFromParcel0(const Parcel&);
577
Andy Hung3253f2d2019-10-21 14:50:07 -0700578 // checks equality even with nullptr.
579 static bool stringEquals(const char *a, const char *b) {
580 if (a == nullptr) {
581 return b == nullptr;
582 } else {
583 return b != nullptr && strcmp(a, b) == 0;
584 }
585 }
586
587public:
Andy Hungaeef7882019-10-18 15:18:14 -0700588 class Prop {
Andy Hungaeef7882019-10-18 15:18:14 -0700589 public:
590 Prop() = default;
591 Prop(const Prop& other) {
592 *this = other;
593 }
594 Prop& operator=(const Prop& other) {
Andy Hung47e58d62019-12-06 18:40:19 -0800595 mName = other.mName;
Andy Hungaeef7882019-10-18 15:18:14 -0700596 mType = other.mType;
597 switch (mType) {
Andy Hung47e58d62019-12-06 18:40:19 -0800598 case mediametrics::kTypeInt32:
Andy Hungaeef7882019-10-18 15:18:14 -0700599 u.int32Value = other.u.int32Value;
600 break;
Andy Hung47e58d62019-12-06 18:40:19 -0800601 case mediametrics::kTypeInt64:
Andy Hungaeef7882019-10-18 15:18:14 -0700602 u.int64Value = other.u.int64Value;
603 break;
Andy Hung47e58d62019-12-06 18:40:19 -0800604 case mediametrics::kTypeDouble:
Andy Hungaeef7882019-10-18 15:18:14 -0700605 u.doubleValue = other.u.doubleValue;
606 break;
Andy Hung47e58d62019-12-06 18:40:19 -0800607 case mediametrics::kTypeCString:
Andy Hungaeef7882019-10-18 15:18:14 -0700608 u.CStringValue = strdup(other.u.CStringValue);
609 break;
Andy Hung47e58d62019-12-06 18:40:19 -0800610 case mediametrics::kTypeRate:
Andy Hung3253f2d2019-10-21 14:50:07 -0700611 u.rate = other.u.rate;
Andy Hungaeef7882019-10-18 15:18:14 -0700612 break;
Andy Hung47e58d62019-12-06 18:40:19 -0800613 case mediametrics::kTypeNone:
Andy Hungaeef7882019-10-18 15:18:14 -0700614 break;
615 default:
616 // abort?
617 break;
618 }
619 return *this;
620 }
Andy Hung47e58d62019-12-06 18:40:19 -0800621 Prop(Prop&& other) {
622 *this = std::move(other);
623 }
624 Prop& operator=(Prop&& other) {
625 mName = std::move(other.mName);
626 mType = other.mType;
627 switch (mType) {
628 case mediametrics::kTypeInt32:
629 u.int32Value = other.u.int32Value;
630 break;
631 case mediametrics::kTypeInt64:
632 u.int64Value = other.u.int64Value;
633 break;
634 case mediametrics::kTypeDouble:
635 u.doubleValue = other.u.doubleValue;
636 break;
637 case mediametrics::kTypeCString:
638 u.CStringValue = other.u.CStringValue;
639 break;
640 case mediametrics::kTypeRate:
641 u.rate = other.u.rate;
642 break;
643 case mediametrics::kTypeNone:
644 break;
645 default:
646 // abort?
647 break;
648 }
649 other.mType = mediametrics::kTypeNone;
650 return *this;
651 }
652
Andy Hung3253f2d2019-10-21 14:50:07 -0700653 bool operator==(const Prop& other) const {
Andy Hung47e58d62019-12-06 18:40:19 -0800654 if (mName != other.mName
Andy Hung3253f2d2019-10-21 14:50:07 -0700655 || mType != other.mType) return false;
656 switch (mType) {
Andy Hung47e58d62019-12-06 18:40:19 -0800657 case mediametrics::kTypeInt32:
Andy Hung3253f2d2019-10-21 14:50:07 -0700658 return u.int32Value == other.u.int32Value;
Andy Hung47e58d62019-12-06 18:40:19 -0800659 case mediametrics::kTypeInt64:
Andy Hung3253f2d2019-10-21 14:50:07 -0700660 return u.int64Value == other.u.int64Value;
Andy Hung47e58d62019-12-06 18:40:19 -0800661 case mediametrics::kTypeDouble:
Andy Hung3253f2d2019-10-21 14:50:07 -0700662 return u.doubleValue == other.u.doubleValue;
Andy Hung47e58d62019-12-06 18:40:19 -0800663 case mediametrics::kTypeCString:
Andy Hung3253f2d2019-10-21 14:50:07 -0700664 return stringEquals(u.CStringValue, other.u.CStringValue);
Andy Hung47e58d62019-12-06 18:40:19 -0800665 case mediametrics::kTypeRate:
Andy Hung3253f2d2019-10-21 14:50:07 -0700666 return u.rate == other.u.rate;
Andy Hung47e58d62019-12-06 18:40:19 -0800667 case mediametrics::kTypeNone:
Andy Hung3253f2d2019-10-21 14:50:07 -0700668 default:
669 return true;
670 }
671 }
672 bool operator!=(const Prop& other) const {
673 return !(*this == other);
674 }
Ray Essick3938dc62016-11-01 08:56:56 -0700675
Andy Hungaeef7882019-10-18 15:18:14 -0700676 void clear() {
Andy Hung47e58d62019-12-06 18:40:19 -0800677 mName.clear();
Andy Hungaeef7882019-10-18 15:18:14 -0700678 clearValue();
679 }
680 void clearValue() {
Andy Hung47e58d62019-12-06 18:40:19 -0800681 if (mType == mediametrics::kTypeCString) {
Andy Hungaeef7882019-10-18 15:18:14 -0700682 free(u.CStringValue);
683 u.CStringValue = nullptr;
684 }
Andy Hung47e58d62019-12-06 18:40:19 -0800685 mType = mediametrics::kTypeNone;
Andy Hungaeef7882019-10-18 15:18:14 -0700686 }
Ray Essick3938dc62016-11-01 08:56:56 -0700687
Andy Hung47e58d62019-12-06 18:40:19 -0800688 mediametrics::Type getType() const {
Andy Hungaeef7882019-10-18 15:18:14 -0700689 return mType;
690 }
Ray Essick3938dc62016-11-01 08:56:56 -0700691
Andy Hungaeef7882019-10-18 15:18:14 -0700692 const char *getName() const {
Andy Hung47e58d62019-12-06 18:40:19 -0800693 return mName.c_str();
Andy Hungaeef7882019-10-18 15:18:14 -0700694 }
Ray Essick3938dc62016-11-01 08:56:56 -0700695
Andy Hungaeef7882019-10-18 15:18:14 -0700696 void swap(Prop& other) {
697 std::swap(mName, other.mName);
Andy Hungaeef7882019-10-18 15:18:14 -0700698 std::swap(mType, other.mType);
699 std::swap(u, other.u);
700 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800701
Andy Hung3253f2d2019-10-21 14:50:07 -0700702 void setName(const char *name) {
Andy Hung47e58d62019-12-06 18:40:19 -0800703 mName = name;
Andy Hungaeef7882019-10-18 15:18:14 -0700704 }
705
Andy Hungaeef7882019-10-18 15:18:14 -0700706 bool isNamed(const char *name) const {
Andy Hung47e58d62019-12-06 18:40:19 -0800707 return mName == name;
Andy Hung1efc9c62019-12-03 13:43:33 -0800708 }
709
710 template <typename T> void visit(T f) const {
711 switch (mType) {
Andy Hung47e58d62019-12-06 18:40:19 -0800712 case mediametrics::kTypeInt32:
Andy Hung1efc9c62019-12-03 13:43:33 -0800713 f(u.int32Value);
714 return;
Andy Hung47e58d62019-12-06 18:40:19 -0800715 case mediametrics::kTypeInt64:
Andy Hung1efc9c62019-12-03 13:43:33 -0800716 f(u.int64Value);
717 return;
Andy Hung47e58d62019-12-06 18:40:19 -0800718 case mediametrics::kTypeDouble:
Andy Hung1efc9c62019-12-03 13:43:33 -0800719 f(u.doubleValue);
720 return;
Andy Hung47e58d62019-12-06 18:40:19 -0800721 case mediametrics::kTypeRate:
Andy Hung1efc9c62019-12-03 13:43:33 -0800722 f(u.rate);
723 return;
Andy Hung47e58d62019-12-06 18:40:19 -0800724 case mediametrics::kTypeCString:
Andy Hung1efc9c62019-12-03 13:43:33 -0800725 f(u.CStringValue);
726 return;
727 default:
728 return;
729 }
Andy Hungaeef7882019-10-18 15:18:14 -0700730 }
731
732 template <typename T> bool get(T *value) const = delete;
733 template <>
734 bool get(int32_t *value) const {
Andy Hung47e58d62019-12-06 18:40:19 -0800735 if (mType != mediametrics::kTypeInt32) return false;
Andy Hungaeef7882019-10-18 15:18:14 -0700736 if (value != nullptr) *value = u.int32Value;
737 return true;
738 }
739 template <>
740 bool get(int64_t *value) const {
Andy Hung47e58d62019-12-06 18:40:19 -0800741 if (mType != mediametrics::kTypeInt64) return false;
Andy Hungaeef7882019-10-18 15:18:14 -0700742 if (value != nullptr) *value = u.int64Value;
743 return true;
744 }
745 template <>
746 bool get(double *value) const {
Andy Hung47e58d62019-12-06 18:40:19 -0800747 if (mType != mediametrics::kTypeDouble) return false;
Andy Hungaeef7882019-10-18 15:18:14 -0700748 if (value != nullptr) *value = u.doubleValue;
749 return true;
750 }
751 template <>
Andy Hung3253f2d2019-10-21 14:50:07 -0700752 bool get(const char** value) const {
Andy Hung47e58d62019-12-06 18:40:19 -0800753 if (mType != mediametrics::kTypeCString) return false;
Andy Hung3253f2d2019-10-21 14:50:07 -0700754 if (value != nullptr) *value = u.CStringValue;
Andy Hungaeef7882019-10-18 15:18:14 -0700755 return true;
756 }
757 template <>
758 bool get(std::string* value) const {
Andy Hung47e58d62019-12-06 18:40:19 -0800759 if (mType != mediametrics::kTypeCString) return false;
Andy Hungaeef7882019-10-18 15:18:14 -0700760 if (value != nullptr) *value = u.CStringValue;
761 return true;
762 }
763 template <>
764 bool get(std::pair<int64_t, int64_t> *value) const {
Andy Hung47e58d62019-12-06 18:40:19 -0800765 if (mType != mediametrics::kTypeRate) return false;
Andy Hungaeef7882019-10-18 15:18:14 -0700766 if (value != nullptr) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700767 *value = u.rate;
Andy Hungaeef7882019-10-18 15:18:14 -0700768 }
769 return true;
770 }
771
772 template <typename T> void set(const T& value) = delete;
773 template <>
774 void set(const int32_t& value) {
Andy Hung47e58d62019-12-06 18:40:19 -0800775 mType = mediametrics::kTypeInt32;
Andy Hungaeef7882019-10-18 15:18:14 -0700776 u.int32Value = value;
777 }
778 template <>
779 void set(const int64_t& value) {
Andy Hung47e58d62019-12-06 18:40:19 -0800780 mType = mediametrics::kTypeInt64;
Andy Hungaeef7882019-10-18 15:18:14 -0700781 u.int64Value = value;
782 }
783 template <>
784 void set(const double& value) {
Andy Hung47e58d62019-12-06 18:40:19 -0800785 mType = mediametrics::kTypeDouble;
Andy Hungaeef7882019-10-18 15:18:14 -0700786 u.doubleValue = value;
787 }
788 template <>
789 void set(const char* const& value) {
Andy Hung47e58d62019-12-06 18:40:19 -0800790 if (mType == mediametrics::kTypeCString) {
Andy Hungaeef7882019-10-18 15:18:14 -0700791 free(u.CStringValue);
792 } else {
Andy Hung47e58d62019-12-06 18:40:19 -0800793 mType = mediametrics::kTypeCString;
Andy Hungaeef7882019-10-18 15:18:14 -0700794 }
795 if (value == nullptr) {
796 u.CStringValue = nullptr;
797 } else {
Andy Hung3253f2d2019-10-21 14:50:07 -0700798 size_t len = strlen(value);
799 if (len > UINT16_MAX - 1) {
800 len = UINT16_MAX - 1;
801 }
802 u.CStringValue = (char *)malloc(len + 1);
803 strncpy(u.CStringValue, value, len);
804 u.CStringValue[len] = 0;
Andy Hungaeef7882019-10-18 15:18:14 -0700805 }
806 }
807 template <>
808 void set(const std::pair<int64_t, int64_t> &value) {
Andy Hung47e58d62019-12-06 18:40:19 -0800809 mType = mediametrics::kTypeRate;
Andy Hungaeef7882019-10-18 15:18:14 -0700810 u.rate = {value.first, value.second};
811 }
812
813 template <typename T> void add(const T& value) = delete;
814 template <>
815 void add(const int32_t& value) {
Andy Hung47e58d62019-12-06 18:40:19 -0800816 if (mType == mediametrics::kTypeInt32) {
Andy Hungaeef7882019-10-18 15:18:14 -0700817 u.int32Value += value;
818 } else {
Andy Hung47e58d62019-12-06 18:40:19 -0800819 mType = mediametrics::kTypeInt32;
Andy Hungaeef7882019-10-18 15:18:14 -0700820 u.int32Value = value;
821 }
822 }
823 template <>
824 void add(const int64_t& value) {
Andy Hung47e58d62019-12-06 18:40:19 -0800825 if (mType == mediametrics::kTypeInt64) {
Andy Hungaeef7882019-10-18 15:18:14 -0700826 u.int64Value += value;
827 } else {
Andy Hung47e58d62019-12-06 18:40:19 -0800828 mType = mediametrics::kTypeInt64;
Andy Hungaeef7882019-10-18 15:18:14 -0700829 u.int64Value = value;
830 }
831 }
832 template <>
833 void add(const double& value) {
Andy Hung47e58d62019-12-06 18:40:19 -0800834 if (mType == mediametrics::kTypeDouble) {
Andy Hungaeef7882019-10-18 15:18:14 -0700835 u.doubleValue += value;
836 } else {
Andy Hung47e58d62019-12-06 18:40:19 -0800837 mType = mediametrics::kTypeDouble;
Andy Hungaeef7882019-10-18 15:18:14 -0700838 u.doubleValue = value;
839 }
840 }
841 template <>
842 void add(const std::pair<int64_t, int64_t>& value) {
Andy Hung47e58d62019-12-06 18:40:19 -0800843 if (mType == mediametrics::kTypeRate) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700844 u.rate.first += value.first;
845 u.rate.second += value.second;
Andy Hungaeef7882019-10-18 15:18:14 -0700846 } else {
Andy Hung47e58d62019-12-06 18:40:19 -0800847 mType = mediametrics::kTypeRate;
Andy Hung3253f2d2019-10-21 14:50:07 -0700848 u.rate = value;
Andy Hungaeef7882019-10-18 15:18:14 -0700849 }
850 }
851
Andy Hung3253f2d2019-10-21 14:50:07 -0700852 status_t writeToParcel(Parcel *data) const;
853 status_t readFromParcel(const Parcel& data);
Andy Hungaeef7882019-10-18 15:18:14 -0700854 void toString(char *buffer, size_t length) const;
Andy Hung3253f2d2019-10-21 14:50:07 -0700855 size_t getByteStringSize() const;
856 status_t writeToByteString(char **bufferpptr, char *bufferptrmax) const;
857 status_t readFromByteString(const char **bufferpptr, const char *bufferptrmax);
Andy Hungaeef7882019-10-18 15:18:14 -0700858
Andy Hung47e58d62019-12-06 18:40:19 -0800859 // TODO: consider converting to std::variant
860 private:
861 std::string mName;
862 mediametrics::Type mType = mediametrics::kTypeNone;
Andy Hung3253f2d2019-10-21 14:50:07 -0700863 union u__ {
864 u__() { zero(); }
865 u__(u__ &&other) {
866 *this = std::move(other);
867 }
868 u__& operator=(u__ &&other) {
869 memcpy(this, &other, sizeof(*this));
870 other.zero();
871 return *this;
872 }
873 void zero() { memset(this, 0, sizeof(*this)); }
874
Andy Hungaeef7882019-10-18 15:18:14 -0700875 int32_t int32Value;
876 int64_t int64Value;
877 double doubleValue;
878 char *CStringValue;
Andy Hung3253f2d2019-10-21 14:50:07 -0700879 std::pair<int64_t, int64_t> rate;
Andy Hungaeef7882019-10-18 15:18:14 -0700880 } u;
881 };
882
Andy Hung47e58d62019-12-06 18:40:19 -0800883 // Iteration of props within item
Andy Hung3253f2d2019-10-21 14:50:07 -0700884 class iterator {
885 public:
Andy Hung47e58d62019-12-06 18:40:19 -0800886 iterator(const std::map<std::string, Prop>::const_iterator &_it) : it(_it) { }
887 iterator &operator++() {
888 ++it;
889 return *this;
890 }
891 bool operator!=(iterator &other) const {
892 return it != other.it;
893 }
894 const Prop &operator*() const {
895 return it->second;
896 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700897
898 private:
Andy Hung47e58d62019-12-06 18:40:19 -0800899 std::map<std::string, Prop>::const_iterator it;
Andy Hung3253f2d2019-10-21 14:50:07 -0700900 };
901
902 iterator begin() const {
Andy Hung47e58d62019-12-06 18:40:19 -0800903 return iterator(mProps.cbegin());
Andy Hung3253f2d2019-10-21 14:50:07 -0700904 }
Andy Hung47e58d62019-12-06 18:40:19 -0800905
Andy Hung3253f2d2019-10-21 14:50:07 -0700906 iterator end() const {
Andy Hung47e58d62019-12-06 18:40:19 -0800907 return iterator(mProps.cend());
Andy Hung3253f2d2019-10-21 14:50:07 -0700908 }
909
910private:
911
Andy Hung47e58d62019-12-06 18:40:19 -0800912 const Prop *findProp(const char *key) const {
913 auto it = mProps.find(key);
914 return it != mProps.end() ? &it->second : nullptr;
915 }
Andy Hungaeef7882019-10-18 15:18:14 -0700916
Andy Hung47e58d62019-12-06 18:40:19 -0800917 Prop &findOrAllocateProp(const char *key) {
918 auto it = mProps.find(key);
919 if (it != mProps.end()) return it->second;
920 Prop &prop = mProps[key];
921 prop.setName(key);
922 return prop;
923 }
Andy Hungaeef7882019-10-18 15:18:14 -0700924
925 pid_t mPid = -1;
926 uid_t mUid = -1;
927 std::string mPkgName;
928 int64_t mPkgVersionCode = 0;
Andy Hung47e58d62019-12-06 18:40:19 -0800929 std::string mKey;
Andy Hungaeef7882019-10-18 15:18:14 -0700930 nsecs_t mTimestamp = 0;
Andy Hung47e58d62019-12-06 18:40:19 -0800931 std::map<std::string, Prop> mProps;
Ray Essick3938dc62016-11-01 08:56:56 -0700932};
933
Ray Essickf27e9872019-12-07 06:28:46 -0800934} // namespace mediametrics
Ray Essick3938dc62016-11-01 08:56:56 -0700935} // namespace android
936
Andy Hung47e58d62019-12-06 18:40:19 -0800937#endif // ANDROID_MEDIA_MEDIAMETRICSITEM_H