blob: 5558211421265a9d83cac0382e70f17dd1dba386 [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/*
39 * Media Metrics
40 * Byte String format for communication of MediaAnalyticsItem.
41 *
42 * .... begin of item
43 * .... begin of header
44 * (uint32) length: including the length field itself
45 * (uint32) header length, including header_length and length fields.
46 * (uint16) version: 0
47 * (uint16) key length, including zero termination
48 * (int8)+ key string, including 0 termination
49 * (int32) pid
50 * (int32) uid
51 * (int64) timestamp
52 * .... end of header
53 * .... begin body
54 * (uint32) properties
55 * #properties of the following:
56 * (uint16) property_length, including property_length field itself
57 * (uint8) type of property
58 * (int8)+ key string, including 0 termination
59 * based on type of property (above), one of:
60 * (int32)
61 * (int64)
62 * (double)
63 * (int8)+ for cstring, including 0 termination
64 * (int64, int64) for rate
65 * .... end body
66 * .... end of item
67 */
68
69/**
70 * Media Metrics MediaAnalyticsItem
71 *
72 * A mutable item representing an event or record that will be
73 * logged with the Media Metrics service.
74 *
75 */
Ray Essick3938dc62016-11-01 08:56:56 -070076
Ray Essickb5fac8e2016-12-12 11:33:56 -080077class MediaAnalyticsItem {
Andy Hungaeef7882019-10-18 15:18:14 -070078 friend class MediaMetricsJNI; // TODO: remove this access
79 friend class MediaMetricsDeathNotifier; // for dropInstance
Ray Essick3938dc62016-11-01 08:56:56 -070080
Andy Hungaeef7882019-10-18 15:18:14 -070081public:
Ray Essick3938dc62016-11-01 08:56:56 -070082
Ray Essickb5fac8e2016-12-12 11:33:56 -080083 enum Type {
84 kTypeNone = 0,
85 kTypeInt32 = 1,
86 kTypeInt64 = 2,
87 kTypeDouble = 3,
88 kTypeCString = 4,
89 kTypeRate = 5,
90 };
91
Andy Hungaeef7882019-10-18 15:18:14 -070092 static constexpr const char * const kKeyNone = "none";
93 static constexpr const char * const kKeyAny = "any";
Ray Essick3938dc62016-11-01 08:56:56 -070094
Ray Essickf65f4212017-08-31 11:41:19 -070095 enum {
96 PROTO_V0 = 0,
97 PROTO_FIRST = PROTO_V0,
98 PROTO_V1 = 1,
99 PROTO_LAST = PROTO_V1,
100 };
101
Andy Hungaeef7882019-10-18 15:18:14 -0700102 // T must be convertible to mKey
103 template <typename T>
104 explicit MediaAnalyticsItem(T key)
105 : mKey(key) { }
Andy Hung3253f2d2019-10-21 14:50:07 -0700106 MediaAnalyticsItem() = default;
107
Andy Hungaeef7882019-10-18 15:18:14 -0700108 MediaAnalyticsItem(const MediaAnalyticsItem&) = delete;
109 MediaAnalyticsItem &operator=(const MediaAnalyticsItem&) = delete;
Ray Essick3938dc62016-11-01 08:56:56 -0700110
Andy Hung3253f2d2019-10-21 14:50:07 -0700111 bool operator==(const MediaAnalyticsItem& other) const {
112 if (mPropCount != other.mPropCount
113 || mPid != other.mPid
114 || mUid != other.mUid
115 || mPkgName != other.mPkgName
116 || mPkgVersionCode != other.mPkgVersionCode
117 || mKey != other.mKey
118 || mTimestamp != other.mTimestamp) return false;
119 for (size_t i = 0; i < mPropCount; ++i) {
120 Prop *p = other.findProp(mProps[i].getName());
121 if (p == nullptr || mProps[i] != *p) return false;
122 }
123 return true;
124 }
125 bool operator!=(const MediaAnalyticsItem& other) const {
126 return !(*this == other);
127 }
128
129 template <typename T>
130 static MediaAnalyticsItem* create(T key) {
131 return new MediaAnalyticsItem(key);
132 }
133 static MediaAnalyticsItem* create() {
134 return new MediaAnalyticsItem();
135 }
Ray Essickba8c4842019-01-18 11:35:33 -0800136
Ray Essickbf536ac2019-08-26 11:04:28 -0700137 static MediaAnalyticsItem* convert(mediametrics_handle_t);
138 static mediametrics_handle_t convert(MediaAnalyticsItem *);
139
Ray Essick3938dc62016-11-01 08:56:56 -0700140 // access functions for the class
Ray Essick3938dc62016-11-01 08:56:56 -0700141 ~MediaAnalyticsItem();
142
Ray Essick3938dc62016-11-01 08:56:56 -0700143 // reset all contents, discarding any extra data
144 void clear();
Ray Essickb5fac8e2016-12-12 11:33:56 -0800145 MediaAnalyticsItem *dup();
Ray Essick3938dc62016-11-01 08:56:56 -0700146
Andy Hung3253f2d2019-10-21 14:50:07 -0700147 MediaAnalyticsItem &setKey(const char *key) {
148 mKey = key;
149 return *this;
150 }
151 const std::string& getKey() const { return mKey; }
Ray Essick3938dc62016-11-01 08:56:56 -0700152
Andy Hung3253f2d2019-10-21 14:50:07 -0700153 // # of properties in the record
154 size_t count() const { return mPropCount; }
Ray Essick3938dc62016-11-01 08:56:56 -0700155
Andy Hungaeef7882019-10-18 15:18:14 -0700156 template<typename S, typename T>
157 MediaAnalyticsItem &set(S key, T value) {
158 allocateProp(key)->set(value);
159 return *this;
160 }
Ray Essick3938dc62016-11-01 08:56:56 -0700161
Andy Hungaeef7882019-10-18 15:18:14 -0700162 // set values appropriately
Andy Hung3253f2d2019-10-21 14:50:07 -0700163 MediaAnalyticsItem &setInt32(const char *key, int32_t value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700164 return set(key, value);
165 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700166 MediaAnalyticsItem &setInt64(const char *key, int64_t value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700167 return set(key, value);
168 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700169 MediaAnalyticsItem &setDouble(const char *key, double value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700170 return set(key, value);
171 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700172 MediaAnalyticsItem &setRate(const char *key, int64_t count, int64_t duration) {
Andy Hungaeef7882019-10-18 15:18:14 -0700173 return set(key, std::make_pair(count, duration));
174 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700175 MediaAnalyticsItem &setCString(const char *key, const char *value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700176 return set(key, value);
177 }
Ray Essick3938dc62016-11-01 08:56:56 -0700178
Andy Hungaeef7882019-10-18 15:18:14 -0700179 // fused get/add/set; if attr wasn't there, it's a simple set.
180 // type-mismatch counts as "wasn't there".
181 template<typename S, typename T>
182 MediaAnalyticsItem &add(S key, T value) {
183 allocateProp(key)->add(value);
184 return *this;
185 }
186
Andy Hung3253f2d2019-10-21 14:50:07 -0700187 MediaAnalyticsItem &addInt32(const char *key, int32_t value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700188 return add(key, value);
189 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700190 MediaAnalyticsItem &addInt64(const char *key, int64_t value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700191 return add(key, value);
192 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700193 MediaAnalyticsItem &addDouble(const char *key, double value) {
Andy Hungaeef7882019-10-18 15:18:14 -0700194 return add(key, value);
195 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700196 MediaAnalyticsItem &addRate(const char *key, int64_t count, int64_t duration) {
Andy Hungaeef7882019-10-18 15:18:14 -0700197 return add(key, std::make_pair(count, duration));
198 }
199
200 // find & extract values
201 // return indicates whether attr exists (and thus value filled in)
202 // NULL parameter value suppresses storage of value.
203 template<typename S, typename T>
204 bool get(S key, T *value) const {
205 Prop *prop = findProp(key);
206 return prop != nullptr && prop->get(value);
207 }
208
Andy Hung3253f2d2019-10-21 14:50:07 -0700209 bool getInt32(const char *key, int32_t *value) const {
Andy Hungaeef7882019-10-18 15:18:14 -0700210 return get(key, value);
211 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700212 bool getInt64(const char *key, int64_t *value) const {
Andy Hungaeef7882019-10-18 15:18:14 -0700213 return get(key, value);
214 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700215 bool getDouble(const char *key, double *value) const {
Andy Hungaeef7882019-10-18 15:18:14 -0700216 return get(key, value);
217 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700218 bool getRate(const char *key, int64_t *count, int64_t *duration, double *rate) const {
Andy Hungaeef7882019-10-18 15:18:14 -0700219 std::pair<int64_t, int64_t> value;
220 if (!get(key, &value)) return false;
221 if (count != nullptr) *count = value.first;
222 if (duration != nullptr) *duration = value.second;
223 if (rate != nullptr) {
224 if (value.second != 0) {
225 *rate = (double)value.first / value.second; // TODO: isn't INF OK?
226 } else {
227 *rate = 0.;
228 }
229 }
230 return true;
231 }
232 // Caller owns the returned string
Andy Hung3253f2d2019-10-21 14:50:07 -0700233 bool getCString(const char *key, char **value) const {
234 const char *cs;
235 if (get(key, &cs)) {
236 *value = cs != nullptr ? strdup(cs) : nullptr;
237 return true;
238 }
239 return false;
Andy Hungaeef7882019-10-18 15:18:14 -0700240 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700241 bool getString(const char *key, std::string *value) const {
Andy Hungaeef7882019-10-18 15:18:14 -0700242 return get(key, value);
243 }
Ray Essick3938dc62016-11-01 08:56:56 -0700244
Andy Hunga87e69c2019-10-18 10:07:40 -0700245 // Deliver the item to MediaMetrics
Ray Essick3938dc62016-11-01 08:56:56 -0700246 bool selfrecord();
247
Andy Hung3253f2d2019-10-21 14:50:07 -0700248 // remove indicated attributes and their values
249 // filterNot() could also be called keepOnly()
250 // return value is # attributes removed
251 // XXX: perhaps 'remove' instead of 'filter'
252 // XXX: filterNot would become 'keep'
253 size_t filter(size_t count, const char *attrs[]);
254 size_t filterNot(size_t count, const char *attrs[]);
255 size_t filter(const char *attr) { return filter(1, &attr); }
Ray Essick3938dc62016-11-01 08:56:56 -0700256
257 // below here are used on server side or to talk to server
258 // clients need not worry about these.
259
260 // timestamp, pid, and uid only used on server side
Ray Essickb5fac8e2016-12-12 11:33:56 -0800261 // timestamp is in 'nanoseconds, unix time'
Ray Essick3938dc62016-11-01 08:56:56 -0700262 MediaAnalyticsItem &setTimestamp(nsecs_t);
263 nsecs_t getTimestamp() const;
264
265 MediaAnalyticsItem &setPid(pid_t);
266 pid_t getPid() const;
267
268 MediaAnalyticsItem &setUid(uid_t);
269 uid_t getUid() const;
270
Ray Essick783bd0d2018-01-11 11:10:35 -0800271 MediaAnalyticsItem &setPkgName(const std::string &pkgName);
272 std::string getPkgName() const { return mPkgName; }
Ray Essickf65f4212017-08-31 11:41:19 -0700273
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800274 MediaAnalyticsItem &setPkgVersionCode(int64_t);
275 int64_t getPkgVersionCode() const;
Ray Essickf65f4212017-08-31 11:41:19 -0700276
Andy Hung3253f2d2019-10-21 14:50:07 -0700277 // our serialization code for binder calls
278 status_t writeToParcel(Parcel *) const;
279 status_t readFromParcel(const Parcel&);
Ray Essick3938dc62016-11-01 08:56:56 -0700280
Andy Hung3253f2d2019-10-21 14:50:07 -0700281 status_t writeToByteString(char **bufferptr, size_t *length) const;
282 status_t readFromByteString(const char *bufferptr, size_t length);
283
284 static status_t writeToByteString(
285 const char *name, int32_t value, char **bufferpptr, char *bufferptrmax);
286 static status_t writeToByteString(
287 const char *name, int64_t value, char **bufferpptr, char *bufferptrmax);
288 static status_t writeToByteString(
289 const char *name, double value, char **bufferpptr, char *bufferptrmax);
290 static status_t writeToByteString(
291 const char *name, const std::pair<int64_t, int64_t> &value, char **bufferpptr, char *bufferptrmax);
292 static status_t writeToByteString(
293 const char *name, char * const &value, char **bufferpptr, char *bufferptrmax);
294 struct none_t {}; // for kTypeNone
295 static status_t writeToByteString(
296 const char *name, const none_t &, char **bufferpptr, char *bufferptrmax);
Ray Essickba8c4842019-01-18 11:35:33 -0800297
Andy Hung17dbaf22019-10-11 14:06:31 -0700298 std::string toString() const;
299 std::string toString(int version) const;
Ray Essick20147322018-11-17 09:08:39 -0800300 const char *toCString();
301 const char *toCString(int version);
Ray Essick3938dc62016-11-01 08:56:56 -0700302
303 // are we collecting analytics data
304 static bool isEnabled();
305
306 protected:
307
308 // merge fields from arg into this
309 // with rules for first/last/add, etc
310 // XXX: document semantics and how they are indicated
Ray Essickb5fac8e2016-12-12 11:33:56 -0800311 // caller continues to own 'incoming'
312 bool merge(MediaAnalyticsItem *incoming);
Ray Essick3938dc62016-11-01 08:56:56 -0700313
Andy Hung3253f2d2019-10-21 14:50:07 -0700314private:
315 // handle Parcel version 0
316 int32_t writeToParcel0(Parcel *) const;
317 int32_t readFromParcel0(const Parcel&);
318
Andy Hungaeef7882019-10-18 15:18:14 -0700319 // enabled 1, disabled 0
320 static constexpr const char * const EnabledProperty = "media.metrics.enabled";
321 static constexpr const char * const EnabledPropertyPersist = "persist.media.metrics.enabled";
322 static const int EnabledProperty_default = 1;
Ray Essick3938dc62016-11-01 08:56:56 -0700323
Andy Hungaeef7882019-10-18 15:18:14 -0700324 // let's reuse a binder connection
325 static sp<IMediaAnalyticsService> sAnalyticsService;
326 static sp<IMediaAnalyticsService> getInstance();
327 static void dropInstance();
Ray Essick3938dc62016-11-01 08:56:56 -0700328
Andy Hung3253f2d2019-10-21 14:50:07 -0700329 // checks equality even with nullptr.
330 static bool stringEquals(const char *a, const char *b) {
331 if (a == nullptr) {
332 return b == nullptr;
333 } else {
334 return b != nullptr && strcmp(a, b) == 0;
335 }
336 }
337
338public:
339
Andy Hungaeef7882019-10-18 15:18:14 -0700340 class Prop {
341 friend class MediaMetricsJNI; // TODO: remove this access
342 public:
343 Prop() = default;
344 Prop(const Prop& other) {
345 *this = other;
346 }
347 Prop& operator=(const Prop& other) {
348 if (other.mName != nullptr) {
349 mName = strdup(other.mName);
350 } else {
351 mName = nullptr;
352 }
Andy Hungaeef7882019-10-18 15:18:14 -0700353 mType = other.mType;
354 switch (mType) {
355 case kTypeInt32:
356 u.int32Value = other.u.int32Value;
357 break;
358 case kTypeInt64:
359 u.int64Value = other.u.int64Value;
360 break;
361 case kTypeDouble:
362 u.doubleValue = other.u.doubleValue;
363 break;
364 case kTypeCString:
365 u.CStringValue = strdup(other.u.CStringValue);
366 break;
367 case kTypeRate:
Andy Hung3253f2d2019-10-21 14:50:07 -0700368 u.rate = other.u.rate;
Andy Hungaeef7882019-10-18 15:18:14 -0700369 break;
370 case kTypeNone:
371 break;
372 default:
373 // abort?
374 break;
375 }
376 return *this;
377 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700378 bool operator==(const Prop& other) const {
379 if (!stringEquals(mName, other.mName)
380 || mType != other.mType) return false;
381 switch (mType) {
382 case kTypeInt32:
383 return u.int32Value == other.u.int32Value;
384 case kTypeInt64:
385 return u.int64Value == other.u.int64Value;
386 case kTypeDouble:
387 return u.doubleValue == other.u.doubleValue;
388 case kTypeCString:
389 return stringEquals(u.CStringValue, other.u.CStringValue);
390 case kTypeRate:
391 return u.rate == other.u.rate;
392 case kTypeNone:
393 default:
394 return true;
395 }
396 }
397 bool operator!=(const Prop& other) const {
398 return !(*this == other);
399 }
Ray Essick3938dc62016-11-01 08:56:56 -0700400
Andy Hungaeef7882019-10-18 15:18:14 -0700401 void clear() {
402 free(mName);
403 mName = nullptr;
Andy Hungaeef7882019-10-18 15:18:14 -0700404 clearValue();
405 }
406 void clearValue() {
407 if (mType == kTypeCString) {
408 free(u.CStringValue);
409 u.CStringValue = nullptr;
410 }
411 mType = kTypeNone;
412 }
Ray Essick3938dc62016-11-01 08:56:56 -0700413
Andy Hungaeef7882019-10-18 15:18:14 -0700414 Type getType() const {
415 return mType;
416 }
Ray Essick3938dc62016-11-01 08:56:56 -0700417
Andy Hungaeef7882019-10-18 15:18:14 -0700418 const char *getName() const {
419 return mName;
420 }
Ray Essick3938dc62016-11-01 08:56:56 -0700421
Andy Hungaeef7882019-10-18 15:18:14 -0700422 void swap(Prop& other) {
423 std::swap(mName, other.mName);
Andy Hungaeef7882019-10-18 15:18:14 -0700424 std::swap(mType, other.mType);
425 std::swap(u, other.u);
426 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800427
Andy Hung3253f2d2019-10-21 14:50:07 -0700428 void setName(const char *name) {
Andy Hungaeef7882019-10-18 15:18:14 -0700429 free(mName);
430 if (name != nullptr) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700431 mName = strdup(name);
Andy Hungaeef7882019-10-18 15:18:14 -0700432 } else {
433 mName = nullptr;
Andy Hungaeef7882019-10-18 15:18:14 -0700434 }
435 }
436
Andy Hungaeef7882019-10-18 15:18:14 -0700437 bool isNamed(const char *name) const {
438 return strcmp(name, mName) == 0;
439 }
440
441 template <typename T> bool get(T *value) const = delete;
442 template <>
443 bool get(int32_t *value) const {
444 if (mType != kTypeInt32) return false;
445 if (value != nullptr) *value = u.int32Value;
446 return true;
447 }
448 template <>
449 bool get(int64_t *value) const {
450 if (mType != kTypeInt64) return false;
451 if (value != nullptr) *value = u.int64Value;
452 return true;
453 }
454 template <>
455 bool get(double *value) const {
456 if (mType != kTypeDouble) return false;
457 if (value != nullptr) *value = u.doubleValue;
458 return true;
459 }
460 template <>
Andy Hung3253f2d2019-10-21 14:50:07 -0700461 bool get(const char** value) const {
Andy Hungaeef7882019-10-18 15:18:14 -0700462 if (mType != kTypeCString) return false;
Andy Hung3253f2d2019-10-21 14:50:07 -0700463 if (value != nullptr) *value = u.CStringValue;
Andy Hungaeef7882019-10-18 15:18:14 -0700464 return true;
465 }
466 template <>
467 bool get(std::string* value) const {
468 if (mType != kTypeCString) return false;
469 if (value != nullptr) *value = u.CStringValue;
470 return true;
471 }
472 template <>
473 bool get(std::pair<int64_t, int64_t> *value) const {
474 if (mType != kTypeRate) return false;
475 if (value != nullptr) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700476 *value = u.rate;
Andy Hungaeef7882019-10-18 15:18:14 -0700477 }
478 return true;
479 }
480
481 template <typename T> void set(const T& value) = delete;
482 template <>
483 void set(const int32_t& value) {
484 mType = kTypeInt32;
485 u.int32Value = value;
486 }
487 template <>
488 void set(const int64_t& value) {
489 mType = kTypeInt64;
490 u.int64Value = value;
491 }
492 template <>
493 void set(const double& value) {
494 mType = kTypeDouble;
495 u.doubleValue = value;
496 }
497 template <>
498 void set(const char* const& value) {
499 if (mType == kTypeCString) {
500 free(u.CStringValue);
501 } else {
502 mType = kTypeCString;
503 }
504 if (value == nullptr) {
505 u.CStringValue = nullptr;
506 } else {
Andy Hung3253f2d2019-10-21 14:50:07 -0700507 size_t len = strlen(value);
508 if (len > UINT16_MAX - 1) {
509 len = UINT16_MAX - 1;
510 }
511 u.CStringValue = (char *)malloc(len + 1);
512 strncpy(u.CStringValue, value, len);
513 u.CStringValue[len] = 0;
Andy Hungaeef7882019-10-18 15:18:14 -0700514 }
515 }
516 template <>
517 void set(const std::pair<int64_t, int64_t> &value) {
518 mType = kTypeRate;
519 u.rate = {value.first, value.second};
520 }
521
522 template <typename T> void add(const T& value) = delete;
523 template <>
524 void add(const int32_t& value) {
525 if (mType == kTypeInt32) {
526 u.int32Value += value;
527 } else {
528 mType = kTypeInt32;
529 u.int32Value = value;
530 }
531 }
532 template <>
533 void add(const int64_t& value) {
534 if (mType == kTypeInt64) {
535 u.int64Value += value;
536 } else {
537 mType = kTypeInt64;
538 u.int64Value = value;
539 }
540 }
541 template <>
542 void add(const double& value) {
543 if (mType == kTypeDouble) {
544 u.doubleValue += value;
545 } else {
546 mType = kTypeDouble;
547 u.doubleValue = value;
548 }
549 }
550 template <>
551 void add(const std::pair<int64_t, int64_t>& value) {
552 if (mType == kTypeRate) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700553 u.rate.first += value.first;
554 u.rate.second += value.second;
Andy Hungaeef7882019-10-18 15:18:14 -0700555 } else {
556 mType = kTypeRate;
Andy Hung3253f2d2019-10-21 14:50:07 -0700557 u.rate = value;
Andy Hungaeef7882019-10-18 15:18:14 -0700558 }
559 }
560
Andy Hung3253f2d2019-10-21 14:50:07 -0700561 status_t writeToParcel(Parcel *data) const;
562 status_t readFromParcel(const Parcel& data);
Andy Hungaeef7882019-10-18 15:18:14 -0700563 void toString(char *buffer, size_t length) const;
Andy Hung3253f2d2019-10-21 14:50:07 -0700564 size_t getByteStringSize() const;
565 status_t writeToByteString(char **bufferpptr, char *bufferptrmax) const;
566 status_t readFromByteString(const char **bufferpptr, const char *bufferptrmax);
Andy Hungaeef7882019-10-18 15:18:14 -0700567
Andy Hung3253f2d2019-10-21 14:50:07 -0700568 // TODO: make private (and consider converting to std::variant)
Andy Hungaeef7882019-10-18 15:18:14 -0700569 // private:
570 char *mName = nullptr;
Andy Hungaeef7882019-10-18 15:18:14 -0700571 Type mType = kTypeNone;
Andy Hung3253f2d2019-10-21 14:50:07 -0700572 union u__ {
573 u__() { zero(); }
574 u__(u__ &&other) {
575 *this = std::move(other);
576 }
577 u__& operator=(u__ &&other) {
578 memcpy(this, &other, sizeof(*this));
579 other.zero();
580 return *this;
581 }
582 void zero() { memset(this, 0, sizeof(*this)); }
583
Andy Hungaeef7882019-10-18 15:18:14 -0700584 int32_t int32Value;
585 int64_t int64Value;
586 double doubleValue;
587 char *CStringValue;
Andy Hung3253f2d2019-10-21 14:50:07 -0700588 std::pair<int64_t, int64_t> rate;
Andy Hungaeef7882019-10-18 15:18:14 -0700589 } u;
590 };
591
Andy Hung3253f2d2019-10-21 14:50:07 -0700592 class iterator {
593 public:
594 iterator(size_t pos, const MediaAnalyticsItem &_item)
595 : i(std::min(pos, _item.count()))
596 , item(_item) { }
597 iterator &operator++() {
598 i = std::min(i + 1, item.count());
599 return *this;
600 }
601 bool operator!=(iterator &other) const {
602 return i != other.i;
603 }
604 Prop &operator*() const {
605 return item.mProps[i];
606 }
607
608 private:
609 size_t i;
610 const MediaAnalyticsItem &item;
611 };
612
613 iterator begin() const {
614 return iterator(0, *this);
615 }
616 iterator end() const {
617 return iterator(SIZE_MAX, *this);
618 }
619
620private:
621
622 // TODO: make prop management class
623 size_t findPropIndex(const char *name) const;
Andy Hungaeef7882019-10-18 15:18:14 -0700624 Prop *findProp(const char *name) const;
Andy Hung3253f2d2019-10-21 14:50:07 -0700625 Prop *allocateProp();
Andy Hungaeef7882019-10-18 15:18:14 -0700626
Ray Essickb5fac8e2016-12-12 11:33:56 -0800627 enum {
628 kGrowProps = 10
629 };
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700630 bool growProps(int increment = kGrowProps);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800631 Prop *allocateProp(const char *name);
Ray Essickf65f4212017-08-31 11:41:19 -0700632 bool removeProp(const char *name);
Andy Hung3253f2d2019-10-21 14:50:07 -0700633 Prop *allocateProp(const std::string& name) { return allocateProp(name.c_str()); }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800634
Andy Hungaeef7882019-10-18 15:18:14 -0700635 size_t mPropCount = 0;
636 size_t mPropSize = 0;
637 Prop *mProps = nullptr;
638
639 pid_t mPid = -1;
640 uid_t mUid = -1;
641 std::string mPkgName;
642 int64_t mPkgVersionCode = 0;
Andy Hung3253f2d2019-10-21 14:50:07 -0700643 std::string mKey{kKeyNone};
Andy Hungaeef7882019-10-18 15:18:14 -0700644 nsecs_t mTimestamp = 0;
Ray Essick3938dc62016-11-01 08:56:56 -0700645};
646
647} // namespace android
648
649#endif