blob: bff7c9b44386a4b1335edf2d18b63b67a4530ec3 [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 Essick3938dc62016-11-01 08:56:56 -070035class IMediaAnalyticsService;
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
118 static sp<IMediaAnalyticsService> sAnalyticsService;
119 static sp<IMediaAnalyticsService> getInstance();
120 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/**
332 * MediaMetrics Item is a stack allocated media analytics item used for
333 * 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>
338class Item : public BufferedItem {
339public:
340 explicit Item(const std::string key) : Item(key.c_str()) { }
341
342 // Since this class will not be defined before the base class, we initialize variables
343 // in our own order.
344 explicit Item(const char *key) {
345 mBegin = mBuffer;
346 mEnd = mBuffer + N;
347 mBaseRealloc = &mReallocPtr;
348 init(key);
349 }
350
351 ~Item() override {
352 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
362} // mediametrics
363
Andy Hung3253f2d2019-10-21 14:50:07 -0700364/**
365 * Media Metrics MediaAnalyticsItem
366 *
367 * A mutable item representing an event or record that will be
Andy Hung1efc9c62019-12-03 13:43:33 -0800368 * logged with the Media Metrics service. For client logging, one should
369 * use the mediametrics::Item.
Andy Hung3253f2d2019-10-21 14:50:07 -0700370 *
Andy Hung1efc9c62019-12-03 13:43:33 -0800371 * The MediaAnalyticsItem is designed for the service as it has getters.
Andy Hung3253f2d2019-10-21 14:50:07 -0700372 */
Andy Hung1efc9c62019-12-03 13:43:33 -0800373class MediaAnalyticsItem : public mediametrics::BaseItem {
Andy Hungaeef7882019-10-18 15:18:14 -0700374 friend class MediaMetricsJNI; // TODO: remove this access
Ray Essick3938dc62016-11-01 08:56:56 -0700375
Andy Hungaeef7882019-10-18 15:18:14 -0700376public:
Ray Essick3938dc62016-11-01 08:56:56 -0700377
Andy Hung1efc9c62019-12-03 13:43:33 -0800378 // TODO: remove this duplicate definition when frameworks base is updated.
Ray Essickb5fac8e2016-12-12 11:33:56 -0800379 enum Type {
380 kTypeNone = 0,
381 kTypeInt32 = 1,
382 kTypeInt64 = 2,
383 kTypeDouble = 3,
384 kTypeCString = 4,
385 kTypeRate = 5,
386 };
387
Andy Hungaeef7882019-10-18 15:18:14 -0700388 static constexpr const char * const kKeyNone = "none";
389 static constexpr const char * const kKeyAny = "any";
Ray Essick3938dc62016-11-01 08:56:56 -0700390
Ray Essickf65f4212017-08-31 11:41:19 -0700391 enum {
392 PROTO_V0 = 0,
393 PROTO_FIRST = PROTO_V0,
394 PROTO_V1 = 1,
395 PROTO_LAST = PROTO_V1,
396 };
397
Andy Hungaeef7882019-10-18 15:18:14 -0700398 // T must be convertible to mKey
399 template <typename T>
400 explicit MediaAnalyticsItem(T key)
401 : mKey(key) { }
Andy Hung3253f2d2019-10-21 14:50:07 -0700402 MediaAnalyticsItem() = default;
403
Andy Hungaeef7882019-10-18 15:18:14 -0700404 MediaAnalyticsItem(const MediaAnalyticsItem&) = delete;
405 MediaAnalyticsItem &operator=(const MediaAnalyticsItem&) = delete;
Ray Essick3938dc62016-11-01 08:56:56 -0700406
Andy Hung3253f2d2019-10-21 14:50:07 -0700407 bool operator==(const MediaAnalyticsItem& other) const {
408 if (mPropCount != other.mPropCount
409 || mPid != other.mPid
410 || mUid != other.mUid
411 || mPkgName != other.mPkgName
412 || mPkgVersionCode != other.mPkgVersionCode
413 || mKey != other.mKey
414 || mTimestamp != other.mTimestamp) return false;
415 for (size_t i = 0; i < mPropCount; ++i) {
416 Prop *p = other.findProp(mProps[i].getName());
417 if (p == nullptr || mProps[i] != *p) return false;
418 }
419 return true;
420 }
421 bool operator!=(const MediaAnalyticsItem& other) const {
422 return !(*this == other);
423 }
424
425 template <typename T>
426 static MediaAnalyticsItem* create(T key) {
427 return new MediaAnalyticsItem(key);
428 }
429 static MediaAnalyticsItem* create() {
430 return new MediaAnalyticsItem();
431 }
Ray Essickba8c4842019-01-18 11:35:33 -0800432
Ray Essickbf536ac2019-08-26 11:04:28 -0700433 static MediaAnalyticsItem* convert(mediametrics_handle_t);
434 static mediametrics_handle_t convert(MediaAnalyticsItem *);
435
Ray Essick3938dc62016-11-01 08:56:56 -0700436 // access functions for the class
Ray Essick3938dc62016-11-01 08:56:56 -0700437 ~MediaAnalyticsItem();
438
Ray Essick3938dc62016-11-01 08:56:56 -0700439 // reset all contents, discarding any extra data
440 void clear();
Ray Essickb5fac8e2016-12-12 11:33:56 -0800441 MediaAnalyticsItem *dup();
Ray Essick3938dc62016-11-01 08:56:56 -0700442
Andy Hung3253f2d2019-10-21 14:50:07 -0700443 MediaAnalyticsItem &setKey(const char *key) {
444 mKey = key;
445 return *this;
446 }
447 const std::string& getKey() const { return mKey; }
Ray Essick3938dc62016-11-01 08:56:56 -0700448
Andy Hung3253f2d2019-10-21 14:50:07 -0700449 // # of properties in the record
450 size_t count() const { return mPropCount; }
Ray Essick3938dc62016-11-01 08:56:56 -0700451
Andy Hungaeef7882019-10-18 15:18:14 -0700452 template<typename S, typename T>
453 MediaAnalyticsItem &set(S key, T value) {
454 allocateProp(key)->set(value);
455 return *this;
456 }
Ray Essick3938dc62016-11-01 08:56:56 -0700457
Andy Hungaeef7882019-10-18 15:18:14 -0700458 // set values appropriately
Andy Hung3253f2d2019-10-21 14:50:07 -0700459 MediaAnalyticsItem &setInt32(const char *key, int32_t value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700460 return set(key, value);
461 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700462 MediaAnalyticsItem &setInt64(const char *key, int64_t value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700463 return set(key, value);
464 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700465 MediaAnalyticsItem &setDouble(const char *key, double value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700466 return set(key, value);
467 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700468 MediaAnalyticsItem &setRate(const char *key, int64_t count, int64_t duration) {
Andy Hungaeef7882019-10-18 15:18:14 -0700469 return set(key, std::make_pair(count, duration));
470 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700471 MediaAnalyticsItem &setCString(const char *key, const char *value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700472 return set(key, value);
473 }
Ray Essick3938dc62016-11-01 08:56:56 -0700474
Andy Hungaeef7882019-10-18 15:18:14 -0700475 // fused get/add/set; if attr wasn't there, it's a simple set.
476 // type-mismatch counts as "wasn't there".
477 template<typename S, typename T>
478 MediaAnalyticsItem &add(S key, T value) {
479 allocateProp(key)->add(value);
480 return *this;
481 }
482
Andy Hung3253f2d2019-10-21 14:50:07 -0700483 MediaAnalyticsItem &addInt32(const char *key, int32_t value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700484 return add(key, value);
485 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700486 MediaAnalyticsItem &addInt64(const char *key, int64_t value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700487 return add(key, value);
488 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700489 MediaAnalyticsItem &addDouble(const char *key, double value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700490 return add(key, value);
491 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700492 MediaAnalyticsItem &addRate(const char *key, int64_t count, int64_t duration) {
Andy Hungaeef7882019-10-18 15:18:14 -0700493 return add(key, std::make_pair(count, duration));
494 }
495
496 // find & extract values
497 // return indicates whether attr exists (and thus value filled in)
498 // NULL parameter value suppresses storage of value.
499 template<typename S, typename T>
500 bool get(S key, T *value) const {
501 Prop *prop = findProp(key);
502 return prop != nullptr && prop->get(value);
503 }
504
Andy Hung3253f2d2019-10-21 14:50:07 -0700505 bool getInt32(const char *key, int32_t *value) const {
Andy Hungaeef7882019-10-18 15:18:14 -0700506 return get(key, value);
507 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700508 bool getInt64(const char *key, int64_t *value) const {
Andy Hungaeef7882019-10-18 15:18:14 -0700509 return get(key, value);
510 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700511 bool getDouble(const char *key, double *value) const {
Andy Hungaeef7882019-10-18 15:18:14 -0700512 return get(key, value);
513 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700514 bool getRate(const char *key, int64_t *count, int64_t *duration, double *rate) const {
Andy Hungaeef7882019-10-18 15:18:14 -0700515 std::pair<int64_t, int64_t> value;
516 if (!get(key, &value)) return false;
517 if (count != nullptr) *count = value.first;
518 if (duration != nullptr) *duration = value.second;
519 if (rate != nullptr) {
520 if (value.second != 0) {
521 *rate = (double)value.first / value.second; // TODO: isn't INF OK?
522 } else {
523 *rate = 0.;
524 }
525 }
526 return true;
527 }
528 // Caller owns the returned string
Andy Hung3253f2d2019-10-21 14:50:07 -0700529 bool getCString(const char *key, char **value) const {
530 const char *cs;
531 if (get(key, &cs)) {
532 *value = cs != nullptr ? strdup(cs) : nullptr;
533 return true;
534 }
535 return false;
Andy Hungaeef7882019-10-18 15:18:14 -0700536 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700537 bool getString(const char *key, std::string *value) const {
Andy Hungaeef7882019-10-18 15:18:14 -0700538 return get(key, value);
539 }
Ray Essick3938dc62016-11-01 08:56:56 -0700540
Andy Hunga87e69c2019-10-18 10:07:40 -0700541 // Deliver the item to MediaMetrics
Ray Essick3938dc62016-11-01 08:56:56 -0700542 bool selfrecord();
543
Andy Hung3253f2d2019-10-21 14:50:07 -0700544 // remove indicated attributes and their values
545 // filterNot() could also be called keepOnly()
546 // return value is # attributes removed
547 // XXX: perhaps 'remove' instead of 'filter'
548 // XXX: filterNot would become 'keep'
549 size_t filter(size_t count, const char *attrs[]);
550 size_t filterNot(size_t count, const char *attrs[]);
551 size_t filter(const char *attr) { return filter(1, &attr); }
Ray Essick3938dc62016-11-01 08:56:56 -0700552
553 // below here are used on server side or to talk to server
554 // clients need not worry about these.
555
556 // timestamp, pid, and uid only used on server side
Ray Essickb5fac8e2016-12-12 11:33:56 -0800557 // timestamp is in 'nanoseconds, unix time'
Ray Essick3938dc62016-11-01 08:56:56 -0700558 MediaAnalyticsItem &setTimestamp(nsecs_t);
559 nsecs_t getTimestamp() const;
560
561 MediaAnalyticsItem &setPid(pid_t);
562 pid_t getPid() const;
563
564 MediaAnalyticsItem &setUid(uid_t);
565 uid_t getUid() const;
566
Ray Essick783bd0d2018-01-11 11:10:35 -0800567 MediaAnalyticsItem &setPkgName(const std::string &pkgName);
568 std::string getPkgName() const { return mPkgName; }
Ray Essickf65f4212017-08-31 11:41:19 -0700569
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800570 MediaAnalyticsItem &setPkgVersionCode(int64_t);
571 int64_t getPkgVersionCode() const;
Ray Essickf65f4212017-08-31 11:41:19 -0700572
Andy Hung3253f2d2019-10-21 14:50:07 -0700573 // our serialization code for binder calls
574 status_t writeToParcel(Parcel *) const;
575 status_t readFromParcel(const Parcel&);
Ray Essick3938dc62016-11-01 08:56:56 -0700576
Andy Hung3253f2d2019-10-21 14:50:07 -0700577 status_t writeToByteString(char **bufferptr, size_t *length) const;
578 status_t readFromByteString(const char *bufferptr, size_t length);
579
Ray Essickba8c4842019-01-18 11:35:33 -0800580
Andy Hung17dbaf22019-10-11 14:06:31 -0700581 std::string toString() const;
582 std::string toString(int version) const;
Ray Essick20147322018-11-17 09:08:39 -0800583 const char *toCString();
584 const char *toCString(int version);
Ray Essick3938dc62016-11-01 08:56:56 -0700585
Ray Essick3938dc62016-11-01 08:56:56 -0700586 protected:
587
588 // merge fields from arg into this
589 // with rules for first/last/add, etc
590 // XXX: document semantics and how they are indicated
Ray Essickb5fac8e2016-12-12 11:33:56 -0800591 // caller continues to own 'incoming'
592 bool merge(MediaAnalyticsItem *incoming);
Ray Essick3938dc62016-11-01 08:56:56 -0700593
Andy Hung3253f2d2019-10-21 14:50:07 -0700594private:
595 // handle Parcel version 0
596 int32_t writeToParcel0(Parcel *) const;
597 int32_t readFromParcel0(const Parcel&);
598
Ray Essick3938dc62016-11-01 08:56:56 -0700599
Ray Essick3938dc62016-11-01 08:56:56 -0700600
Andy Hung3253f2d2019-10-21 14:50:07 -0700601 // checks equality even with nullptr.
602 static bool stringEquals(const char *a, const char *b) {
603 if (a == nullptr) {
604 return b == nullptr;
605 } else {
606 return b != nullptr && strcmp(a, b) == 0;
607 }
608 }
609
610public:
611
Andy Hungaeef7882019-10-18 15:18:14 -0700612 class Prop {
613 friend class MediaMetricsJNI; // TODO: remove this access
614 public:
615 Prop() = default;
616 Prop(const Prop& other) {
617 *this = other;
618 }
619 Prop& operator=(const Prop& other) {
620 if (other.mName != nullptr) {
621 mName = strdup(other.mName);
622 } else {
623 mName = nullptr;
624 }
Andy Hungaeef7882019-10-18 15:18:14 -0700625 mType = other.mType;
626 switch (mType) {
627 case kTypeInt32:
628 u.int32Value = other.u.int32Value;
629 break;
630 case kTypeInt64:
631 u.int64Value = other.u.int64Value;
632 break;
633 case kTypeDouble:
634 u.doubleValue = other.u.doubleValue;
635 break;
636 case kTypeCString:
637 u.CStringValue = strdup(other.u.CStringValue);
638 break;
639 case kTypeRate:
Andy Hung3253f2d2019-10-21 14:50:07 -0700640 u.rate = other.u.rate;
Andy Hungaeef7882019-10-18 15:18:14 -0700641 break;
642 case kTypeNone:
643 break;
644 default:
645 // abort?
646 break;
647 }
648 return *this;
649 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700650 bool operator==(const Prop& other) const {
651 if (!stringEquals(mName, other.mName)
652 || mType != other.mType) return false;
653 switch (mType) {
654 case kTypeInt32:
655 return u.int32Value == other.u.int32Value;
656 case kTypeInt64:
657 return u.int64Value == other.u.int64Value;
658 case kTypeDouble:
659 return u.doubleValue == other.u.doubleValue;
660 case kTypeCString:
661 return stringEquals(u.CStringValue, other.u.CStringValue);
662 case kTypeRate:
663 return u.rate == other.u.rate;
664 case kTypeNone:
665 default:
666 return true;
667 }
668 }
669 bool operator!=(const Prop& other) const {
670 return !(*this == other);
671 }
Ray Essick3938dc62016-11-01 08:56:56 -0700672
Andy Hungaeef7882019-10-18 15:18:14 -0700673 void clear() {
674 free(mName);
675 mName = nullptr;
Andy Hungaeef7882019-10-18 15:18:14 -0700676 clearValue();
677 }
678 void clearValue() {
679 if (mType == kTypeCString) {
680 free(u.CStringValue);
681 u.CStringValue = nullptr;
682 }
683 mType = kTypeNone;
684 }
Ray Essick3938dc62016-11-01 08:56:56 -0700685
Andy Hungaeef7882019-10-18 15:18:14 -0700686 Type getType() const {
687 return mType;
688 }
Ray Essick3938dc62016-11-01 08:56:56 -0700689
Andy Hungaeef7882019-10-18 15:18:14 -0700690 const char *getName() const {
691 return mName;
692 }
Ray Essick3938dc62016-11-01 08:56:56 -0700693
Andy Hungaeef7882019-10-18 15:18:14 -0700694 void swap(Prop& other) {
695 std::swap(mName, other.mName);
Andy Hungaeef7882019-10-18 15:18:14 -0700696 std::swap(mType, other.mType);
697 std::swap(u, other.u);
698 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800699
Andy Hung3253f2d2019-10-21 14:50:07 -0700700 void setName(const char *name) {
Andy Hungaeef7882019-10-18 15:18:14 -0700701 free(mName);
702 if (name != nullptr) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700703 mName = strdup(name);
Andy Hungaeef7882019-10-18 15:18:14 -0700704 } else {
705 mName = nullptr;
Andy Hungaeef7882019-10-18 15:18:14 -0700706 }
707 }
708
Andy Hungaeef7882019-10-18 15:18:14 -0700709 bool isNamed(const char *name) const {
Andy Hung1efc9c62019-12-03 13:43:33 -0800710 return stringEquals(name, mName);
711 }
712
713 template <typename T> void visit(T f) const {
714 switch (mType) {
715 case MediaAnalyticsItem::kTypeInt32:
716 f(u.int32Value);
717 return;
718 case MediaAnalyticsItem::kTypeInt64:
719 f(u.int64Value);
720 return;
721 case MediaAnalyticsItem::kTypeDouble:
722 f(u.doubleValue);
723 return;
724 case MediaAnalyticsItem::kTypeRate:
725 f(u.rate);
726 return;
727 case MediaAnalyticsItem::kTypeCString:
728 f(u.CStringValue);
729 return;
730 default:
731 return;
732 }
Andy Hungaeef7882019-10-18 15:18:14 -0700733 }
734
735 template <typename T> bool get(T *value) const = delete;
736 template <>
737 bool get(int32_t *value) const {
738 if (mType != kTypeInt32) return false;
739 if (value != nullptr) *value = u.int32Value;
740 return true;
741 }
742 template <>
743 bool get(int64_t *value) const {
744 if (mType != kTypeInt64) return false;
745 if (value != nullptr) *value = u.int64Value;
746 return true;
747 }
748 template <>
749 bool get(double *value) const {
750 if (mType != kTypeDouble) return false;
751 if (value != nullptr) *value = u.doubleValue;
752 return true;
753 }
754 template <>
Andy Hung3253f2d2019-10-21 14:50:07 -0700755 bool get(const char** value) const {
Andy Hungaeef7882019-10-18 15:18:14 -0700756 if (mType != kTypeCString) return false;
Andy Hung3253f2d2019-10-21 14:50:07 -0700757 if (value != nullptr) *value = u.CStringValue;
Andy Hungaeef7882019-10-18 15:18:14 -0700758 return true;
759 }
760 template <>
761 bool get(std::string* value) const {
762 if (mType != kTypeCString) return false;
763 if (value != nullptr) *value = u.CStringValue;
764 return true;
765 }
766 template <>
767 bool get(std::pair<int64_t, int64_t> *value) const {
768 if (mType != kTypeRate) return false;
769 if (value != nullptr) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700770 *value = u.rate;
Andy Hungaeef7882019-10-18 15:18:14 -0700771 }
772 return true;
773 }
774
775 template <typename T> void set(const T& value) = delete;
776 template <>
777 void set(const int32_t& value) {
778 mType = kTypeInt32;
779 u.int32Value = value;
780 }
781 template <>
782 void set(const int64_t& value) {
783 mType = kTypeInt64;
784 u.int64Value = value;
785 }
786 template <>
787 void set(const double& value) {
788 mType = kTypeDouble;
789 u.doubleValue = value;
790 }
791 template <>
792 void set(const char* const& value) {
793 if (mType == kTypeCString) {
794 free(u.CStringValue);
795 } else {
796 mType = kTypeCString;
797 }
798 if (value == nullptr) {
799 u.CStringValue = nullptr;
800 } else {
Andy Hung3253f2d2019-10-21 14:50:07 -0700801 size_t len = strlen(value);
802 if (len > UINT16_MAX - 1) {
803 len = UINT16_MAX - 1;
804 }
805 u.CStringValue = (char *)malloc(len + 1);
806 strncpy(u.CStringValue, value, len);
807 u.CStringValue[len] = 0;
Andy Hungaeef7882019-10-18 15:18:14 -0700808 }
809 }
810 template <>
811 void set(const std::pair<int64_t, int64_t> &value) {
812 mType = kTypeRate;
813 u.rate = {value.first, value.second};
814 }
815
816 template <typename T> void add(const T& value) = delete;
817 template <>
818 void add(const int32_t& value) {
819 if (mType == kTypeInt32) {
820 u.int32Value += value;
821 } else {
822 mType = kTypeInt32;
823 u.int32Value = value;
824 }
825 }
826 template <>
827 void add(const int64_t& value) {
828 if (mType == kTypeInt64) {
829 u.int64Value += value;
830 } else {
831 mType = kTypeInt64;
832 u.int64Value = value;
833 }
834 }
835 template <>
836 void add(const double& value) {
837 if (mType == kTypeDouble) {
838 u.doubleValue += value;
839 } else {
840 mType = kTypeDouble;
841 u.doubleValue = value;
842 }
843 }
844 template <>
845 void add(const std::pair<int64_t, int64_t>& value) {
846 if (mType == kTypeRate) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700847 u.rate.first += value.first;
848 u.rate.second += value.second;
Andy Hungaeef7882019-10-18 15:18:14 -0700849 } else {
850 mType = kTypeRate;
Andy Hung3253f2d2019-10-21 14:50:07 -0700851 u.rate = value;
Andy Hungaeef7882019-10-18 15:18:14 -0700852 }
853 }
854
Andy Hung3253f2d2019-10-21 14:50:07 -0700855 status_t writeToParcel(Parcel *data) const;
856 status_t readFromParcel(const Parcel& data);
Andy Hungaeef7882019-10-18 15:18:14 -0700857 void toString(char *buffer, size_t length) const;
Andy Hung3253f2d2019-10-21 14:50:07 -0700858 size_t getByteStringSize() const;
859 status_t writeToByteString(char **bufferpptr, char *bufferptrmax) const;
860 status_t readFromByteString(const char **bufferpptr, const char *bufferptrmax);
Andy Hungaeef7882019-10-18 15:18:14 -0700861
Andy Hung3253f2d2019-10-21 14:50:07 -0700862 // TODO: make private (and consider converting to std::variant)
Andy Hungaeef7882019-10-18 15:18:14 -0700863 // private:
864 char *mName = nullptr;
Andy Hungaeef7882019-10-18 15:18:14 -0700865 Type mType = kTypeNone;
Andy Hung3253f2d2019-10-21 14:50:07 -0700866 union u__ {
867 u__() { zero(); }
868 u__(u__ &&other) {
869 *this = std::move(other);
870 }
871 u__& operator=(u__ &&other) {
872 memcpy(this, &other, sizeof(*this));
873 other.zero();
874 return *this;
875 }
876 void zero() { memset(this, 0, sizeof(*this)); }
877
Andy Hungaeef7882019-10-18 15:18:14 -0700878 int32_t int32Value;
879 int64_t int64Value;
880 double doubleValue;
881 char *CStringValue;
Andy Hung3253f2d2019-10-21 14:50:07 -0700882 std::pair<int64_t, int64_t> rate;
Andy Hungaeef7882019-10-18 15:18:14 -0700883 } u;
884 };
885
Andy Hung3253f2d2019-10-21 14:50:07 -0700886 class iterator {
887 public:
888 iterator(size_t pos, const MediaAnalyticsItem &_item)
889 : i(std::min(pos, _item.count()))
890 , item(_item) { }
891 iterator &operator++() {
892 i = std::min(i + 1, item.count());
893 return *this;
894 }
895 bool operator!=(iterator &other) const {
896 return i != other.i;
897 }
898 Prop &operator*() const {
899 return item.mProps[i];
900 }
901
902 private:
903 size_t i;
904 const MediaAnalyticsItem &item;
905 };
906
907 iterator begin() const {
908 return iterator(0, *this);
909 }
910 iterator end() const {
911 return iterator(SIZE_MAX, *this);
912 }
913
914private:
915
916 // TODO: make prop management class
917 size_t findPropIndex(const char *name) const;
Andy Hungaeef7882019-10-18 15:18:14 -0700918 Prop *findProp(const char *name) const;
Andy Hung3253f2d2019-10-21 14:50:07 -0700919 Prop *allocateProp();
Andy Hungaeef7882019-10-18 15:18:14 -0700920
Ray Essickb5fac8e2016-12-12 11:33:56 -0800921 enum {
922 kGrowProps = 10
923 };
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700924 bool growProps(int increment = kGrowProps);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800925 Prop *allocateProp(const char *name);
Ray Essickf65f4212017-08-31 11:41:19 -0700926 bool removeProp(const char *name);
Andy Hung3253f2d2019-10-21 14:50:07 -0700927 Prop *allocateProp(const std::string& name) { return allocateProp(name.c_str()); }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800928
Andy Hungaeef7882019-10-18 15:18:14 -0700929 size_t mPropCount = 0;
930 size_t mPropSize = 0;
931 Prop *mProps = nullptr;
932
933 pid_t mPid = -1;
934 uid_t mUid = -1;
935 std::string mPkgName;
936 int64_t mPkgVersionCode = 0;
Andy Hung3253f2d2019-10-21 14:50:07 -0700937 std::string mKey{kKeyNone};
Andy Hungaeef7882019-10-18 15:18:14 -0700938 nsecs_t mTimestamp = 0;
Ray Essick3938dc62016-11-01 08:56:56 -0700939};
940
941} // namespace android
942
943#endif