blob: 5f33650be33ff3ade792f7ab50bfe3e1c7f3403b [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
17#ifndef ANDROID_MEDIA_MEDIAANALYTICSITEM_H
18#define ANDROID_MEDIA_MEDIAANALYTICSITEM_H
19
Ray Essickbf536ac2019-08-26 11:04:28 -070020#include "MediaMetrics.h"
21
Andy Hung3253f2d2019-10-21 14:50:07 -070022#include <algorithm>
Ray Essick783bd0d2018-01-11 11:10:35 -080023#include <string>
Ray Essick3938dc62016-11-01 08:56:56 -070024#include <sys/types.h>
Ray Essickba8c4842019-01-18 11:35:33 -080025
26#include <cutils/properties.h>
Ray Essick3938dc62016-11-01 08:56:56 -070027#include <utils/Errors.h>
28#include <utils/KeyedVector.h>
29#include <utils/RefBase.h>
30#include <utils/StrongPointer.h>
31#include <utils/Timers.h>
32
Ray Essick3938dc62016-11-01 08:56:56 -070033namespace android {
34
Ray Essickf27e9872019-12-07 06:28:46 -080035class IMediaMetricsService;
Ray Essick783bd0d2018-01-11 11:10:35 -080036class Parcel;
Ray Essick3938dc62016-11-01 08:56:56 -070037
Andy Hung3253f2d2019-10-21 14:50:07 -070038/*
Andy Hung1efc9c62019-12-03 13:43:33 -080039 * MediaMetrics Item
Andy Hung3253f2d2019-10-21 14:50:07 -070040 *
Andy Hung1efc9c62019-12-03 13:43:33 -080041 * Byte string format.
42 *
43 * For Java
44 * int64 corresponds to long
45 * int32, uint32 corresponds to int
46 * uint16 corresponds to char
47 * uint8, int8 corresponds to byte
48 *
49 * Hence uint8 and uint32 values are limited to INT8_MAX and INT32_MAX.
50 *
51 * Physical layout of integers and doubles within the MediaMetrics byte string
52 * is in Native / host order, which is nearly always little endian.
53 *
54 * -- begin of item
55 * -- begin of header
56 * (uint32) item size: including the item size field
57 * (uint32) header size, including the item size and header size fields.
58 * (uint16) version: exactly 0
59 * (uint16) key size, that is key strlen + 1 for zero termination.
60 * (int8)+ key string which is 0 terminated
Andy Hung3253f2d2019-10-21 14:50:07 -070061 * (int32) pid
62 * (int32) uid
63 * (int64) timestamp
Andy Hung1efc9c62019-12-03 13:43:33 -080064 * -- end of header
65 * -- begin body
66 * (uint32) number of properties
67 * -- repeat for number of properties
68 * (uint16) property size, including property size field itself
Andy Hung3253f2d2019-10-21 14:50:07 -070069 * (uint8) type of property
70 * (int8)+ key string, including 0 termination
Andy Hung1efc9c62019-12-03 13:43:33 -080071 * based on type of property (given above), one of:
Andy Hung3253f2d2019-10-21 14:50:07 -070072 * (int32)
73 * (int64)
74 * (double)
75 * (int8)+ for cstring, including 0 termination
76 * (int64, int64) for rate
Andy Hung1efc9c62019-12-03 13:43:33 -080077 * -- end body
78 * -- end of item
Andy Hung3253f2d2019-10-21 14:50:07 -070079 */
80
Andy Hung1efc9c62019-12-03 13:43:33 -080081namespace mediametrics {
82
83// Type must match MediaMetrics.java
84enum Type {
85 kTypeNone = 0,
86 kTypeInt32 = 1,
87 kTypeInt64 = 2,
88 kTypeDouble = 3,
89 kTypeCString = 4,
90 kTypeRate = 5,
91};
92
93template<size_t N>
94static inline bool startsWith(const std::string &s, const char (&comp)[N]) {
95 return !strncmp(s.c_str(), comp, N-1);
96}
97
98/**
99 * Media Metrics BaseItem
100 *
101 * A base class which contains utility static functions to write to a byte stream
102 * and access the Media Metrics service.
103 */
104
105class BaseItem {
106 friend class MediaMetricsDeathNotifier; // for dropInstance
107 // enabled 1, disabled 0
108public:
109 // are we collecting analytics data
110 static bool isEnabled();
111
112protected:
113 static constexpr const char * const EnabledProperty = "media.metrics.enabled";
114 static constexpr const char * const EnabledPropertyPersist = "persist.media.metrics.enabled";
115 static const int EnabledProperty_default = 1;
116
117 // let's reuse a binder connection
Ray Essickf27e9872019-12-07 06:28:46 -0800118 static sp<IMediaMetricsService> sMediaMetricsService;
119 static sp<IMediaMetricsService> getInstance();
Andy Hung1efc9c62019-12-03 13:43:33 -0800120 static void dropInstance();
121 static bool submitBuffer(const char *buffer, size_t len);
122
123 static status_t writeToByteString(
124 const char *name, int32_t value, char **bufferpptr, char *bufferptrmax);
125 static status_t writeToByteString(
126 const char *name, int64_t value, char **bufferpptr, char *bufferptrmax);
127 static status_t writeToByteString(
128 const char *name, double value, char **bufferpptr, char *bufferptrmax);
129 static status_t writeToByteString(
130 const char *name, const std::pair<int64_t, int64_t> &value,
131 char **bufferpptr, char *bufferptrmax);
132 static status_t writeToByteString(
133 const char *name, char * const &value, char **bufferpptr, char *bufferptrmax);
134 static status_t writeToByteString(
135 const char *name, const char * const &value, char **bufferpptr, char *bufferptrmax);
136 struct none_t {}; // for kTypeNone
137 static status_t writeToByteString(
138 const char *name, const none_t &, char **bufferpptr, char *bufferptrmax);
139
140 template<typename T>
141 static status_t sizeOfByteString(const char *name, const T& value) {
142 return 2 + 1 + strlen(name) + 1 + sizeof(value);
143 }
144 template<> // static
145 status_t sizeOfByteString(const char *name, char * const &value) {
146 return 2 + 1 + strlen(name) + 1 + strlen(value) + 1;
147 }
148 template<> // static
149 status_t sizeOfByteString(const char *name, const char * const &value) {
150 return 2 + 1 + strlen(name) + 1 + strlen(value) + 1;
151 }
152 template<> // static
153 status_t sizeOfByteString(const char *name, const none_t &) {
154 return 2 + 1 + strlen(name) + 1;
155 }
156};
157
158/**
159 * Media Metrics BufferedItem
160 *
161 * A base class which represents a put-only Media Metrics item, storing
162 * the Media Metrics data in a buffer with begin and end pointers.
163 *
164 * If a property key is entered twice, it will be stored in the buffer twice,
165 * and (implementation defined) the last value for that key will be used
166 * by the Media Metrics service.
167 *
168 * For realloc, a baseRealloc pointer must be passed in either explicitly
169 * or implicitly in the constructor. This will be updated with the value used on realloc.
170 */
171class BufferedItem : public BaseItem {
172public:
173 static inline constexpr uint16_t kVersion = 0;
174
175 virtual ~BufferedItem() = default;
176 BufferedItem(const BufferedItem&) = delete;
177 BufferedItem& operator=(const BufferedItem&) = delete;
178
179 BufferedItem(const std::string key, char *begin, char *end)
180 : BufferedItem(key.c_str(), begin, end) { }
181
182 BufferedItem(const char *key, char *begin, char *end)
183 : BufferedItem(key, begin, end, nullptr) { }
184
185 BufferedItem(const char *key, char **begin, char *end)
186 : BufferedItem(key, *begin, end, begin) { }
187
188 BufferedItem(const char *key, char *begin, char *end, char **baseRealloc)
189 : mBegin(begin)
190 , mEnd(end)
191 , mBaseRealloc(baseRealloc)
192 {
193 init(key);
194 }
195
196 template<typename T>
197 BufferedItem &set(const char *key, const T& value) {
198 reallocFor(sizeOfByteString(key, value));
199 if (mStatus == NO_ERROR) {
200 mStatus = BaseItem::writeToByteString(key, value, &mBptr, mEnd);
201 ++mPropCount;
202 }
203 return *this;
204 }
205
206 template<typename T>
207 BufferedItem &set(const std::string& key, const T& value) {
208 return set(key.c_str(), value);
209 }
210
211 BufferedItem &setPid(pid_t pid) {
212 if (mStatus == NO_ERROR) {
213 copyTo(mBegin + mHeaderLen - 16, (int32_t)pid);
214 }
215 return *this;
216 }
217
218 BufferedItem &setUid(uid_t uid) {
219 if (mStatus == NO_ERROR) {
220 copyTo(mBegin + mHeaderLen - 12, (int32_t)uid);
221 }
222 return *this;
223 }
224
225 BufferedItem &setTimestamp(nsecs_t timestamp) {
226 if (mStatus == NO_ERROR) {
227 copyTo(mBegin + mHeaderLen - 8, (int64_t)timestamp);
228 }
229 return *this;
230 }
231
232 bool record() {
233 return updateHeader()
234 && BaseItem::submitBuffer(getBuffer(), getLength());
235 }
236
237 bool isValid () const {
238 return mStatus == NO_ERROR;
239 }
240
241 char *getBuffer() const { return mBegin; }
242 size_t getLength() const { return mBptr - mBegin; }
243 size_t getRemaining() const { return mEnd - mBptr; }
244 size_t getCapacity() const { return mEnd - mBegin; }
245
246 bool updateHeader() {
247 if (mStatus != NO_ERROR) return false;
248 copyTo(mBegin + 0, (uint32_t)getLength());
249 copyTo(mBegin + 4, (uint32_t)mHeaderLen);
250 copyTo(mBegin + mHeaderLen, (uint32_t)mPropCount);
251 return true;
252 }
253
254protected:
255 BufferedItem() = default;
256
257 void reallocFor(size_t required) {
258 if (mStatus != NO_ERROR) return;
259 const size_t remaining = getRemaining();
260 if (required <= remaining) return;
261 if (mBaseRealloc == nullptr) {
262 mStatus = NO_MEMORY;
263 return;
264 }
265
266 const size_t current = getLength();
267 size_t minimum = current + required;
268 if (minimum > SSIZE_MAX >> 1) {
269 mStatus = NO_MEMORY;
270 return;
271 }
272 minimum <<= 1;
273 void *newptr = realloc(*mBaseRealloc, minimum);
274 if (newptr == nullptr) {
275 mStatus = NO_MEMORY;
276 return;
277 }
278 if (newptr != *mBaseRealloc) {
279 // ALOGD("base changed! current:%zu new size %zu", current, minimum);
280 if (*mBaseRealloc == nullptr) {
281 memcpy(newptr, mBegin, current);
282 }
283 mBegin = (char *)newptr;
284 *mBaseRealloc = mBegin;
285 mEnd = mBegin + minimum;
286 mBptr = mBegin + current;
287 } else {
288 // ALOGD("base kept! current:%zu new size %zu", current, minimum);
289 mEnd = mBegin + minimum;
290 }
291 }
292 template<typename T>
293 void copyTo(char *ptr, const T& value) {
294 memcpy(ptr, &value, sizeof(value));
295 }
296
297 void init(const char *key) {
298 mBptr = mBegin;
299 const size_t keylen = strlen(key) + 1;
300 mHeaderLen = 4 + 4 + 2 + 2 + keylen + 4 + 4 + 8;
301 reallocFor(mHeaderLen);
302 if (mStatus != NO_ERROR) return;
303 mBptr = mBegin + mHeaderLen + 4; // this includes propcount.
304
305 if (mEnd < mBptr || keylen > UINT16_MAX) {
306 mStatus = NO_MEMORY;
307 mBptr = mEnd;
308 return;
309 }
310 copyTo(mBegin + 8, kVersion);
311 copyTo(mBegin + 10, (uint16_t)keylen);
312 strcpy(mBegin + 12, key);
313
314 // initialize some parameters (that could be overridden)
315 setPid(-1);
316 setUid(-1);
317 setTimestamp(0);
318 }
319
320 char *mBegin = nullptr;
321 char *mEnd = nullptr;
322 char **mBaseRealloc = nullptr; // set to an address if realloc should be done.
323 // upon return, that pointer is updated with
324 // whatever needs to be freed.
325 char *mBptr = nullptr;
326 status_t mStatus = NO_ERROR;
327 uint32_t mPropCount = 0;
328 uint32_t mHeaderLen = 0;
329};
330
331/**
Ray Essickf27e9872019-12-07 06:28:46 -0800332 * MediaMetrics LogItem is a stack allocated media analytics item used for
Andy Hung1efc9c62019-12-03 13:43:33 -0800333 * fast logging. It falls over to a malloc if needed.
334 *
335 * This is templated with a buffer size to allocate on the stack.
336 */
337template <size_t N = 4096>
Ray Essickf27e9872019-12-07 06:28:46 -0800338class LogItem : public BufferedItem {
Andy Hung1efc9c62019-12-03 13:43:33 -0800339public:
Ray Essickf27e9872019-12-07 06:28:46 -0800340 explicit LogItem(const std::string key) : LogItem(key.c_str()) { }
Andy Hung1efc9c62019-12-03 13:43:33 -0800341
342 // Since this class will not be defined before the base class, we initialize variables
343 // in our own order.
Ray Essickf27e9872019-12-07 06:28:46 -0800344 explicit LogItem(const char *key) {
Andy Hung1efc9c62019-12-03 13:43:33 -0800345 mBegin = mBuffer;
346 mEnd = mBuffer + N;
347 mBaseRealloc = &mReallocPtr;
348 init(key);
349 }
350
Ray Essickf27e9872019-12-07 06:28:46 -0800351 ~LogItem() override {
Andy Hung1efc9c62019-12-03 13:43:33 -0800352 if (mReallocPtr != nullptr) { // do the check before calling free to avoid overhead.
353 free(mReallocPtr);
354 }
355 }
356
357private:
358 char *mReallocPtr = nullptr; // set non-null by base class if realloc happened.
359 char mBuffer[N];
360};
361
Andy Hung1efc9c62019-12-03 13:43:33 -0800362
Andy Hung3253f2d2019-10-21 14:50:07 -0700363/**
Ray Essickf27e9872019-12-07 06:28:46 -0800364 * Media Metrics Item
Andy Hung3253f2d2019-10-21 14:50:07 -0700365 *
366 * A mutable item representing an event or record that will be
Andy Hung1efc9c62019-12-03 13:43:33 -0800367 * logged with the Media Metrics service. For client logging, one should
368 * use the mediametrics::Item.
Andy Hung3253f2d2019-10-21 14:50:07 -0700369 *
Ray Essickf27e9872019-12-07 06:28:46 -0800370 * The Item is designed for the service as it has getters.
Andy Hung3253f2d2019-10-21 14:50:07 -0700371 */
Ray Essickf27e9872019-12-07 06:28:46 -0800372class Item : public mediametrics::BaseItem {
Andy Hungaeef7882019-10-18 15:18:14 -0700373 friend class MediaMetricsJNI; // TODO: remove this access
Ray Essick3938dc62016-11-01 08:56:56 -0700374
Andy Hungaeef7882019-10-18 15:18:14 -0700375public:
Ray Essick3938dc62016-11-01 08:56:56 -0700376
Andy Hung1efc9c62019-12-03 13:43:33 -0800377 // TODO: remove this duplicate definition when frameworks base is updated.
Ray Essickb5fac8e2016-12-12 11:33:56 -0800378 enum Type {
379 kTypeNone = 0,
380 kTypeInt32 = 1,
381 kTypeInt64 = 2,
382 kTypeDouble = 3,
383 kTypeCString = 4,
384 kTypeRate = 5,
385 };
386
Andy Hungaeef7882019-10-18 15:18:14 -0700387 static constexpr const char * const kKeyNone = "none";
388 static constexpr const char * const kKeyAny = "any";
Ray Essick3938dc62016-11-01 08:56:56 -0700389
Ray Essickf65f4212017-08-31 11:41:19 -0700390 enum {
391 PROTO_V0 = 0,
392 PROTO_FIRST = PROTO_V0,
393 PROTO_V1 = 1,
394 PROTO_LAST = PROTO_V1,
395 };
396
Andy Hungaeef7882019-10-18 15:18:14 -0700397 // T must be convertible to mKey
398 template <typename T>
Ray Essickf27e9872019-12-07 06:28:46 -0800399 explicit Item(T key)
Andy Hungaeef7882019-10-18 15:18:14 -0700400 : mKey(key) { }
Ray Essickf27e9872019-12-07 06:28:46 -0800401 Item() = default;
Andy Hung3253f2d2019-10-21 14:50:07 -0700402
Ray Essickf27e9872019-12-07 06:28:46 -0800403 Item(const Item&) = delete;
404 Item &operator=(const Item&) = delete;
Ray Essick3938dc62016-11-01 08:56:56 -0700405
Ray Essickf27e9872019-12-07 06:28:46 -0800406 bool operator==(const Item& other) const {
Andy Hung3253f2d2019-10-21 14:50:07 -0700407 if (mPropCount != other.mPropCount
408 || mPid != other.mPid
409 || mUid != other.mUid
410 || mPkgName != other.mPkgName
411 || mPkgVersionCode != other.mPkgVersionCode
412 || mKey != other.mKey
413 || mTimestamp != other.mTimestamp) return false;
414 for (size_t i = 0; i < mPropCount; ++i) {
415 Prop *p = other.findProp(mProps[i].getName());
416 if (p == nullptr || mProps[i] != *p) return false;
417 }
418 return true;
419 }
Ray Essickf27e9872019-12-07 06:28:46 -0800420 bool operator!=(const Item& other) const {
Andy Hung3253f2d2019-10-21 14:50:07 -0700421 return !(*this == other);
422 }
423
424 template <typename T>
Ray Essickf27e9872019-12-07 06:28:46 -0800425 static Item* create(T key) {
426 return new Item(key);
Andy Hung3253f2d2019-10-21 14:50:07 -0700427 }
Ray Essickf27e9872019-12-07 06:28:46 -0800428 static Item* create() {
429 return new Item();
Andy Hung3253f2d2019-10-21 14:50:07 -0700430 }
Ray Essickba8c4842019-01-18 11:35:33 -0800431
Ray Essickf27e9872019-12-07 06:28:46 -0800432 static Item* convert(mediametrics_handle_t);
433 static mediametrics_handle_t convert(Item *);
Ray Essickbf536ac2019-08-26 11:04:28 -0700434
Ray Essick3938dc62016-11-01 08:56:56 -0700435 // access functions for the class
Ray Essickf27e9872019-12-07 06:28:46 -0800436 ~Item();
Ray Essick3938dc62016-11-01 08:56:56 -0700437
Ray Essick3938dc62016-11-01 08:56:56 -0700438 // reset all contents, discarding any extra data
439 void clear();
Ray Essickf27e9872019-12-07 06:28:46 -0800440 Item *dup();
Ray Essick3938dc62016-11-01 08:56:56 -0700441
Ray Essickf27e9872019-12-07 06:28:46 -0800442 Item &setKey(const char *key) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700443 mKey = key;
444 return *this;
445 }
446 const std::string& getKey() const { return mKey; }
Ray Essick3938dc62016-11-01 08:56:56 -0700447
Andy Hung3253f2d2019-10-21 14:50:07 -0700448 // # of properties in the record
449 size_t count() const { return mPropCount; }
Ray Essick3938dc62016-11-01 08:56:56 -0700450
Andy Hungaeef7882019-10-18 15:18:14 -0700451 template<typename S, typename T>
Ray Essickf27e9872019-12-07 06:28:46 -0800452 Item &set(S key, T value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700453 allocateProp(key)->set(value);
454 return *this;
455 }
Ray Essick3938dc62016-11-01 08:56:56 -0700456
Andy Hungaeef7882019-10-18 15:18:14 -0700457 // set values appropriately
Ray Essickf27e9872019-12-07 06:28:46 -0800458 Item &setInt32(const char *key, int32_t value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700459 return set(key, value);
460 }
Ray Essickf27e9872019-12-07 06:28:46 -0800461 Item &setInt64(const char *key, int64_t value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700462 return set(key, value);
463 }
Ray Essickf27e9872019-12-07 06:28:46 -0800464 Item &setDouble(const char *key, double value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700465 return set(key, value);
466 }
Ray Essickf27e9872019-12-07 06:28:46 -0800467 Item &setRate(const char *key, int64_t count, int64_t duration) {
Andy Hungaeef7882019-10-18 15:18:14 -0700468 return set(key, std::make_pair(count, duration));
469 }
Ray Essickf27e9872019-12-07 06:28:46 -0800470 Item &setCString(const char *key, const char *value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700471 return set(key, value);
472 }
Ray Essick3938dc62016-11-01 08:56:56 -0700473
Andy Hungaeef7882019-10-18 15:18:14 -0700474 // fused get/add/set; if attr wasn't there, it's a simple set.
475 // type-mismatch counts as "wasn't there".
476 template<typename S, typename T>
Ray Essickf27e9872019-12-07 06:28:46 -0800477 Item &add(S key, T value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700478 allocateProp(key)->add(value);
479 return *this;
480 }
481
Ray Essickf27e9872019-12-07 06:28:46 -0800482 Item &addInt32(const char *key, int32_t value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700483 return add(key, value);
484 }
Ray Essickf27e9872019-12-07 06:28:46 -0800485 Item &addInt64(const char *key, int64_t value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700486 return add(key, value);
487 }
Ray Essickf27e9872019-12-07 06:28:46 -0800488 Item &addDouble(const char *key, double value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700489 return add(key, value);
490 }
Ray Essickf27e9872019-12-07 06:28:46 -0800491 Item &addRate(const char *key, int64_t count, int64_t duration) {
Andy Hungaeef7882019-10-18 15:18:14 -0700492 return add(key, std::make_pair(count, duration));
493 }
494
495 // find & extract values
496 // return indicates whether attr exists (and thus value filled in)
497 // NULL parameter value suppresses storage of value.
498 template<typename S, typename T>
499 bool get(S key, T *value) const {
500 Prop *prop = findProp(key);
501 return prop != nullptr && prop->get(value);
502 }
503
Andy Hung3253f2d2019-10-21 14:50:07 -0700504 bool getInt32(const char *key, int32_t *value) const {
Andy Hungaeef7882019-10-18 15:18:14 -0700505 return get(key, value);
506 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700507 bool getInt64(const char *key, int64_t *value) const {
Andy Hungaeef7882019-10-18 15:18:14 -0700508 return get(key, value);
509 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700510 bool getDouble(const char *key, double *value) const {
Andy Hungaeef7882019-10-18 15:18:14 -0700511 return get(key, value);
512 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700513 bool getRate(const char *key, int64_t *count, int64_t *duration, double *rate) const {
Andy Hungaeef7882019-10-18 15:18:14 -0700514 std::pair<int64_t, int64_t> value;
515 if (!get(key, &value)) return false;
516 if (count != nullptr) *count = value.first;
517 if (duration != nullptr) *duration = value.second;
518 if (rate != nullptr) {
519 if (value.second != 0) {
520 *rate = (double)value.first / value.second; // TODO: isn't INF OK?
521 } else {
522 *rate = 0.;
523 }
524 }
525 return true;
526 }
527 // Caller owns the returned string
Andy Hung3253f2d2019-10-21 14:50:07 -0700528 bool getCString(const char *key, char **value) const {
529 const char *cs;
530 if (get(key, &cs)) {
531 *value = cs != nullptr ? strdup(cs) : nullptr;
532 return true;
533 }
534 return false;
Andy Hungaeef7882019-10-18 15:18:14 -0700535 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700536 bool getString(const char *key, std::string *value) const {
Andy Hungaeef7882019-10-18 15:18:14 -0700537 return get(key, value);
538 }
Ray Essick3938dc62016-11-01 08:56:56 -0700539
Andy Hunga87e69c2019-10-18 10:07:40 -0700540 // Deliver the item to MediaMetrics
Ray Essick3938dc62016-11-01 08:56:56 -0700541 bool selfrecord();
542
Andy Hung3253f2d2019-10-21 14:50:07 -0700543 // remove indicated attributes and their values
544 // filterNot() could also be called keepOnly()
545 // return value is # attributes removed
546 // XXX: perhaps 'remove' instead of 'filter'
547 // XXX: filterNot would become 'keep'
548 size_t filter(size_t count, const char *attrs[]);
549 size_t filterNot(size_t count, const char *attrs[]);
550 size_t filter(const char *attr) { return filter(1, &attr); }
Ray Essick3938dc62016-11-01 08:56:56 -0700551
552 // below here are used on server side or to talk to server
553 // clients need not worry about these.
554
555 // timestamp, pid, and uid only used on server side
Ray Essickb5fac8e2016-12-12 11:33:56 -0800556 // timestamp is in 'nanoseconds, unix time'
Ray Essickf27e9872019-12-07 06:28:46 -0800557 Item &setTimestamp(nsecs_t);
Ray Essick3938dc62016-11-01 08:56:56 -0700558 nsecs_t getTimestamp() const;
559
Ray Essickf27e9872019-12-07 06:28:46 -0800560 Item &setPid(pid_t);
Ray Essick3938dc62016-11-01 08:56:56 -0700561 pid_t getPid() const;
562
Ray Essickf27e9872019-12-07 06:28:46 -0800563 Item &setUid(uid_t);
Ray Essick3938dc62016-11-01 08:56:56 -0700564 uid_t getUid() const;
565
Ray Essickf27e9872019-12-07 06:28:46 -0800566 Item &setPkgName(const std::string &pkgName);
Ray Essick783bd0d2018-01-11 11:10:35 -0800567 std::string getPkgName() const { return mPkgName; }
Ray Essickf65f4212017-08-31 11:41:19 -0700568
Ray Essickf27e9872019-12-07 06:28:46 -0800569 Item &setPkgVersionCode(int64_t);
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800570 int64_t getPkgVersionCode() const;
Ray Essickf65f4212017-08-31 11:41:19 -0700571
Andy Hung3253f2d2019-10-21 14:50:07 -0700572 // our serialization code for binder calls
573 status_t writeToParcel(Parcel *) const;
574 status_t readFromParcel(const Parcel&);
Ray Essick3938dc62016-11-01 08:56:56 -0700575
Andy Hung3253f2d2019-10-21 14:50:07 -0700576 status_t writeToByteString(char **bufferptr, size_t *length) const;
577 status_t readFromByteString(const char *bufferptr, size_t length);
578
Ray Essickba8c4842019-01-18 11:35:33 -0800579
Andy Hung17dbaf22019-10-11 14:06:31 -0700580 std::string toString() const;
581 std::string toString(int version) const;
Ray Essick20147322018-11-17 09:08:39 -0800582 const char *toCString();
583 const char *toCString(int version);
Ray Essick3938dc62016-11-01 08:56:56 -0700584
Ray Essick3938dc62016-11-01 08:56:56 -0700585 protected:
586
587 // merge fields from arg into this
588 // with rules for first/last/add, etc
589 // XXX: document semantics and how they are indicated
Ray Essickb5fac8e2016-12-12 11:33:56 -0800590 // caller continues to own 'incoming'
Ray Essickf27e9872019-12-07 06:28:46 -0800591 bool merge(Item *incoming);
Ray Essick3938dc62016-11-01 08:56:56 -0700592
Andy Hung3253f2d2019-10-21 14:50:07 -0700593private:
594 // handle Parcel version 0
595 int32_t writeToParcel0(Parcel *) const;
596 int32_t readFromParcel0(const Parcel&);
597
Ray Essick3938dc62016-11-01 08:56:56 -0700598
Ray Essick3938dc62016-11-01 08:56:56 -0700599
Andy Hung3253f2d2019-10-21 14:50:07 -0700600 // checks equality even with nullptr.
601 static bool stringEquals(const char *a, const char *b) {
602 if (a == nullptr) {
603 return b == nullptr;
604 } else {
605 return b != nullptr && strcmp(a, b) == 0;
606 }
607 }
608
609public:
610
Andy Hungaeef7882019-10-18 15:18:14 -0700611 class Prop {
612 friend class MediaMetricsJNI; // TODO: remove this access
613 public:
614 Prop() = default;
615 Prop(const Prop& other) {
616 *this = other;
617 }
618 Prop& operator=(const Prop& other) {
619 if (other.mName != nullptr) {
620 mName = strdup(other.mName);
621 } else {
622 mName = nullptr;
623 }
Andy Hungaeef7882019-10-18 15:18:14 -0700624 mType = other.mType;
625 switch (mType) {
626 case kTypeInt32:
627 u.int32Value = other.u.int32Value;
628 break;
629 case kTypeInt64:
630 u.int64Value = other.u.int64Value;
631 break;
632 case kTypeDouble:
633 u.doubleValue = other.u.doubleValue;
634 break;
635 case kTypeCString:
636 u.CStringValue = strdup(other.u.CStringValue);
637 break;
638 case kTypeRate:
Andy Hung3253f2d2019-10-21 14:50:07 -0700639 u.rate = other.u.rate;
Andy Hungaeef7882019-10-18 15:18:14 -0700640 break;
641 case kTypeNone:
642 break;
643 default:
644 // abort?
645 break;
646 }
647 return *this;
648 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700649 bool operator==(const Prop& other) const {
650 if (!stringEquals(mName, other.mName)
651 || mType != other.mType) return false;
652 switch (mType) {
653 case kTypeInt32:
654 return u.int32Value == other.u.int32Value;
655 case kTypeInt64:
656 return u.int64Value == other.u.int64Value;
657 case kTypeDouble:
658 return u.doubleValue == other.u.doubleValue;
659 case kTypeCString:
660 return stringEquals(u.CStringValue, other.u.CStringValue);
661 case kTypeRate:
662 return u.rate == other.u.rate;
663 case kTypeNone:
664 default:
665 return true;
666 }
667 }
668 bool operator!=(const Prop& other) const {
669 return !(*this == other);
670 }
Ray Essick3938dc62016-11-01 08:56:56 -0700671
Andy Hungaeef7882019-10-18 15:18:14 -0700672 void clear() {
673 free(mName);
674 mName = nullptr;
Andy Hungaeef7882019-10-18 15:18:14 -0700675 clearValue();
676 }
677 void clearValue() {
678 if (mType == kTypeCString) {
679 free(u.CStringValue);
680 u.CStringValue = nullptr;
681 }
682 mType = kTypeNone;
683 }
Ray Essick3938dc62016-11-01 08:56:56 -0700684
Andy Hungaeef7882019-10-18 15:18:14 -0700685 Type getType() const {
686 return mType;
687 }
Ray Essick3938dc62016-11-01 08:56:56 -0700688
Andy Hungaeef7882019-10-18 15:18:14 -0700689 const char *getName() const {
690 return mName;
691 }
Ray Essick3938dc62016-11-01 08:56:56 -0700692
Andy Hungaeef7882019-10-18 15:18:14 -0700693 void swap(Prop& other) {
694 std::swap(mName, other.mName);
Andy Hungaeef7882019-10-18 15:18:14 -0700695 std::swap(mType, other.mType);
696 std::swap(u, other.u);
697 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800698
Andy Hung3253f2d2019-10-21 14:50:07 -0700699 void setName(const char *name) {
Andy Hungaeef7882019-10-18 15:18:14 -0700700 free(mName);
701 if (name != nullptr) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700702 mName = strdup(name);
Andy Hungaeef7882019-10-18 15:18:14 -0700703 } else {
704 mName = nullptr;
Andy Hungaeef7882019-10-18 15:18:14 -0700705 }
706 }
707
Andy Hungaeef7882019-10-18 15:18:14 -0700708 bool isNamed(const char *name) const {
Andy Hung1efc9c62019-12-03 13:43:33 -0800709 return stringEquals(name, mName);
710 }
711
712 template <typename T> void visit(T f) const {
713 switch (mType) {
Ray Essickf27e9872019-12-07 06:28:46 -0800714 case Item::kTypeInt32:
Andy Hung1efc9c62019-12-03 13:43:33 -0800715 f(u.int32Value);
716 return;
Ray Essickf27e9872019-12-07 06:28:46 -0800717 case Item::kTypeInt64:
Andy Hung1efc9c62019-12-03 13:43:33 -0800718 f(u.int64Value);
719 return;
Ray Essickf27e9872019-12-07 06:28:46 -0800720 case Item::kTypeDouble:
Andy Hung1efc9c62019-12-03 13:43:33 -0800721 f(u.doubleValue);
722 return;
Ray Essickf27e9872019-12-07 06:28:46 -0800723 case Item::kTypeRate:
Andy Hung1efc9c62019-12-03 13:43:33 -0800724 f(u.rate);
725 return;
Ray Essickf27e9872019-12-07 06:28:46 -0800726 case Item::kTypeCString:
Andy Hung1efc9c62019-12-03 13:43:33 -0800727 f(u.CStringValue);
728 return;
729 default:
730 return;
731 }
Andy Hungaeef7882019-10-18 15:18:14 -0700732 }
733
734 template <typename T> bool get(T *value) const = delete;
735 template <>
736 bool get(int32_t *value) const {
737 if (mType != kTypeInt32) return false;
738 if (value != nullptr) *value = u.int32Value;
739 return true;
740 }
741 template <>
742 bool get(int64_t *value) const {
743 if (mType != kTypeInt64) return false;
744 if (value != nullptr) *value = u.int64Value;
745 return true;
746 }
747 template <>
748 bool get(double *value) const {
749 if (mType != kTypeDouble) return false;
750 if (value != nullptr) *value = u.doubleValue;
751 return true;
752 }
753 template <>
Andy Hung3253f2d2019-10-21 14:50:07 -0700754 bool get(const char** value) const {
Andy Hungaeef7882019-10-18 15:18:14 -0700755 if (mType != kTypeCString) return false;
Andy Hung3253f2d2019-10-21 14:50:07 -0700756 if (value != nullptr) *value = u.CStringValue;
Andy Hungaeef7882019-10-18 15:18:14 -0700757 return true;
758 }
759 template <>
760 bool get(std::string* value) const {
761 if (mType != kTypeCString) return false;
762 if (value != nullptr) *value = u.CStringValue;
763 return true;
764 }
765 template <>
766 bool get(std::pair<int64_t, int64_t> *value) const {
767 if (mType != kTypeRate) return false;
768 if (value != nullptr) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700769 *value = u.rate;
Andy Hungaeef7882019-10-18 15:18:14 -0700770 }
771 return true;
772 }
773
774 template <typename T> void set(const T& value) = delete;
775 template <>
776 void set(const int32_t& value) {
777 mType = kTypeInt32;
778 u.int32Value = value;
779 }
780 template <>
781 void set(const int64_t& value) {
782 mType = kTypeInt64;
783 u.int64Value = value;
784 }
785 template <>
786 void set(const double& value) {
787 mType = kTypeDouble;
788 u.doubleValue = value;
789 }
790 template <>
791 void set(const char* const& value) {
792 if (mType == kTypeCString) {
793 free(u.CStringValue);
794 } else {
795 mType = kTypeCString;
796 }
797 if (value == nullptr) {
798 u.CStringValue = nullptr;
799 } else {
Andy Hung3253f2d2019-10-21 14:50:07 -0700800 size_t len = strlen(value);
801 if (len > UINT16_MAX - 1) {
802 len = UINT16_MAX - 1;
803 }
804 u.CStringValue = (char *)malloc(len + 1);
805 strncpy(u.CStringValue, value, len);
806 u.CStringValue[len] = 0;
Andy Hungaeef7882019-10-18 15:18:14 -0700807 }
808 }
809 template <>
810 void set(const std::pair<int64_t, int64_t> &value) {
811 mType = kTypeRate;
812 u.rate = {value.first, value.second};
813 }
814
815 template <typename T> void add(const T& value) = delete;
816 template <>
817 void add(const int32_t& value) {
818 if (mType == kTypeInt32) {
819 u.int32Value += value;
820 } else {
821 mType = kTypeInt32;
822 u.int32Value = value;
823 }
824 }
825 template <>
826 void add(const int64_t& value) {
827 if (mType == kTypeInt64) {
828 u.int64Value += value;
829 } else {
830 mType = kTypeInt64;
831 u.int64Value = value;
832 }
833 }
834 template <>
835 void add(const double& value) {
836 if (mType == kTypeDouble) {
837 u.doubleValue += value;
838 } else {
839 mType = kTypeDouble;
840 u.doubleValue = value;
841 }
842 }
843 template <>
844 void add(const std::pair<int64_t, int64_t>& value) {
845 if (mType == kTypeRate) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700846 u.rate.first += value.first;
847 u.rate.second += value.second;
Andy Hungaeef7882019-10-18 15:18:14 -0700848 } else {
849 mType = kTypeRate;
Andy Hung3253f2d2019-10-21 14:50:07 -0700850 u.rate = value;
Andy Hungaeef7882019-10-18 15:18:14 -0700851 }
852 }
853
Andy Hung3253f2d2019-10-21 14:50:07 -0700854 status_t writeToParcel(Parcel *data) const;
855 status_t readFromParcel(const Parcel& data);
Andy Hungaeef7882019-10-18 15:18:14 -0700856 void toString(char *buffer, size_t length) const;
Andy Hung3253f2d2019-10-21 14:50:07 -0700857 size_t getByteStringSize() const;
858 status_t writeToByteString(char **bufferpptr, char *bufferptrmax) const;
859 status_t readFromByteString(const char **bufferpptr, const char *bufferptrmax);
Andy Hungaeef7882019-10-18 15:18:14 -0700860
Andy Hung3253f2d2019-10-21 14:50:07 -0700861 // TODO: make private (and consider converting to std::variant)
Andy Hungaeef7882019-10-18 15:18:14 -0700862 // private:
863 char *mName = nullptr;
Andy Hungaeef7882019-10-18 15:18:14 -0700864 Type mType = kTypeNone;
Andy Hung3253f2d2019-10-21 14:50:07 -0700865 union u__ {
866 u__() { zero(); }
867 u__(u__ &&other) {
868 *this = std::move(other);
869 }
870 u__& operator=(u__ &&other) {
871 memcpy(this, &other, sizeof(*this));
872 other.zero();
873 return *this;
874 }
875 void zero() { memset(this, 0, sizeof(*this)); }
876
Andy Hungaeef7882019-10-18 15:18:14 -0700877 int32_t int32Value;
878 int64_t int64Value;
879 double doubleValue;
880 char *CStringValue;
Andy Hung3253f2d2019-10-21 14:50:07 -0700881 std::pair<int64_t, int64_t> rate;
Andy Hungaeef7882019-10-18 15:18:14 -0700882 } u;
883 };
884
Andy Hung3253f2d2019-10-21 14:50:07 -0700885 class iterator {
886 public:
Ray Essickf27e9872019-12-07 06:28:46 -0800887 iterator(size_t pos, const Item &_item)
Andy Hung3253f2d2019-10-21 14:50:07 -0700888 : i(std::min(pos, _item.count()))
889 , item(_item) { }
890 iterator &operator++() {
891 i = std::min(i + 1, item.count());
892 return *this;
893 }
894 bool operator!=(iterator &other) const {
895 return i != other.i;
896 }
897 Prop &operator*() const {
898 return item.mProps[i];
899 }
900
901 private:
902 size_t i;
Ray Essickf27e9872019-12-07 06:28:46 -0800903 const Item &item;
Andy Hung3253f2d2019-10-21 14:50:07 -0700904 };
905
906 iterator begin() const {
907 return iterator(0, *this);
908 }
909 iterator end() const {
910 return iterator(SIZE_MAX, *this);
911 }
912
913private:
914
915 // TODO: make prop management class
916 size_t findPropIndex(const char *name) const;
Andy Hungaeef7882019-10-18 15:18:14 -0700917 Prop *findProp(const char *name) const;
Andy Hung3253f2d2019-10-21 14:50:07 -0700918 Prop *allocateProp();
Andy Hungaeef7882019-10-18 15:18:14 -0700919
Ray Essickb5fac8e2016-12-12 11:33:56 -0800920 enum {
921 kGrowProps = 10
922 };
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700923 bool growProps(int increment = kGrowProps);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800924 Prop *allocateProp(const char *name);
Ray Essickf65f4212017-08-31 11:41:19 -0700925 bool removeProp(const char *name);
Andy Hung3253f2d2019-10-21 14:50:07 -0700926 Prop *allocateProp(const std::string& name) { return allocateProp(name.c_str()); }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800927
Andy Hungaeef7882019-10-18 15:18:14 -0700928 size_t mPropCount = 0;
929 size_t mPropSize = 0;
930 Prop *mProps = nullptr;
931
932 pid_t mPid = -1;
933 uid_t mUid = -1;
934 std::string mPkgName;
935 int64_t mPkgVersionCode = 0;
Andy Hung3253f2d2019-10-21 14:50:07 -0700936 std::string mKey{kKeyNone};
Andy Hungaeef7882019-10-18 15:18:14 -0700937 nsecs_t mTimestamp = 0;
Ray Essick3938dc62016-11-01 08:56:56 -0700938};
939
Ray Essickf27e9872019-12-07 06:28:46 -0800940} // namespace mediametrics
Ray Essick3938dc62016-11-01 08:56:56 -0700941} // namespace android
942
943#endif