blob: f0deaafa9659fd113cf08b6c636eda5ab971a218 [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
Ray Essick783bd0d2018-01-11 11:10:35 -080022#include <string>
Ray Essick3938dc62016-11-01 08:56:56 -070023#include <sys/types.h>
Ray Essickba8c4842019-01-18 11:35:33 -080024
25#include <cutils/properties.h>
Ray Essick3938dc62016-11-01 08:56:56 -070026#include <utils/Errors.h>
27#include <utils/KeyedVector.h>
28#include <utils/RefBase.h>
29#include <utils/StrongPointer.h>
30#include <utils/Timers.h>
31
Ray Essick3938dc62016-11-01 08:56:56 -070032namespace android {
33
Ray Essick3938dc62016-11-01 08:56:56 -070034class IMediaAnalyticsService;
Ray Essick783bd0d2018-01-11 11:10:35 -080035class Parcel;
Ray Essick3938dc62016-11-01 08:56:56 -070036
37// the class interface
38//
39
Ray Essickb5fac8e2016-12-12 11:33:56 -080040class MediaAnalyticsItem {
Andy Hungaeef7882019-10-18 15:18:14 -070041 friend class MediaMetricsJNI; // TODO: remove this access
42 friend class MediaMetricsDeathNotifier; // for dropInstance
Ray Essick3938dc62016-11-01 08:56:56 -070043
Andy Hungaeef7882019-10-18 15:18:14 -070044public:
Ray Essick3938dc62016-11-01 08:56:56 -070045
Ray Essickb5fac8e2016-12-12 11:33:56 -080046 enum Type {
47 kTypeNone = 0,
48 kTypeInt32 = 1,
49 kTypeInt64 = 2,
50 kTypeDouble = 3,
51 kTypeCString = 4,
52 kTypeRate = 5,
53 };
54
Andy Hungaeef7882019-10-18 15:18:14 -070055 // Key: the record descriminator
56 // values for the record discriminator
57 // values can be "component/component"
58 // basic values: "video", "audio", "drm"
59 // XXX: need to better define the format
60 using Key = std::string;
61 static constexpr const char * const kKeyNone = "none";
62 static constexpr const char * const kKeyAny = "any";
Ray Essick3938dc62016-11-01 08:56:56 -070063
64 // Attr: names for attributes within a record
65 // format "prop1" or "prop/subprop"
66 // XXX: need to better define the format
Ray Essickb5fac8e2016-12-12 11:33:56 -080067 typedef const char *Attr;
Ray Essick3938dc62016-11-01 08:56:56 -070068
69
Ray Essickf65f4212017-08-31 11:41:19 -070070 enum {
71 PROTO_V0 = 0,
72 PROTO_FIRST = PROTO_V0,
73 PROTO_V1 = 1,
74 PROTO_LAST = PROTO_V1,
75 };
76
Andy Hungaeef7882019-10-18 15:18:14 -070077 // T must be convertible to mKey
78 template <typename T>
79 explicit MediaAnalyticsItem(T key)
80 : mKey(key) { }
81 MediaAnalyticsItem(const MediaAnalyticsItem&) = delete;
82 MediaAnalyticsItem &operator=(const MediaAnalyticsItem&) = delete;
Ray Essick3938dc62016-11-01 08:56:56 -070083
Ray Essickba8c4842019-01-18 11:35:33 -080084 static MediaAnalyticsItem* create(Key key);
85 static MediaAnalyticsItem* create();
86
Ray Essickbf536ac2019-08-26 11:04:28 -070087 static MediaAnalyticsItem* convert(mediametrics_handle_t);
88 static mediametrics_handle_t convert(MediaAnalyticsItem *);
89
Ray Essick3938dc62016-11-01 08:56:56 -070090 // access functions for the class
Ray Essick3938dc62016-11-01 08:56:56 -070091 ~MediaAnalyticsItem();
92
Ray Essick3938dc62016-11-01 08:56:56 -070093 // reset all contents, discarding any extra data
94 void clear();
Ray Essickb5fac8e2016-12-12 11:33:56 -080095 MediaAnalyticsItem *dup();
Ray Essick3938dc62016-11-01 08:56:56 -070096
97 // set the key discriminator for the record.
98 // most often initialized as part of the constructor
99 MediaAnalyticsItem &setKey(MediaAnalyticsItem::Key);
Andy Hung17dbaf22019-10-11 14:06:31 -0700100 const MediaAnalyticsItem::Key& getKey() const { return mKey; }
Ray Essick3938dc62016-11-01 08:56:56 -0700101
102 // # of attributes in the record
103 int32_t count() const;
104
Andy Hungaeef7882019-10-18 15:18:14 -0700105 template<typename S, typename T>
106 MediaAnalyticsItem &set(S key, T value) {
107 allocateProp(key)->set(value);
108 return *this;
109 }
Ray Essick3938dc62016-11-01 08:56:56 -0700110
Andy Hungaeef7882019-10-18 15:18:14 -0700111 // set values appropriately
112 MediaAnalyticsItem &setInt32(Attr key, int32_t value) {
113 return set(key, value);
114 }
115 MediaAnalyticsItem &setInt64(Attr key, int64_t value) {
116 return set(key, value);
117 }
118 MediaAnalyticsItem &setDouble(Attr key, double value) {
119 return set(key, value);
120 }
121 MediaAnalyticsItem &setRate(Attr key, int64_t count, int64_t duration) {
122 return set(key, std::make_pair(count, duration));
123 }
124 MediaAnalyticsItem &setCString(Attr key, const char *value) {
125 return set(key, value);
126 }
Ray Essick3938dc62016-11-01 08:56:56 -0700127
Andy Hungaeef7882019-10-18 15:18:14 -0700128 // fused get/add/set; if attr wasn't there, it's a simple set.
129 // type-mismatch counts as "wasn't there".
130 template<typename S, typename T>
131 MediaAnalyticsItem &add(S key, T value) {
132 allocateProp(key)->add(value);
133 return *this;
134 }
135
136 MediaAnalyticsItem &addInt32(Attr key, int32_t value) {
137 return add(key, value);
138 }
139 MediaAnalyticsItem &addInt64(Attr key, int64_t value) {
140 return add(key, value);
141 }
142 MediaAnalyticsItem &addDouble(Attr key, double value) {
143 return add(key, value);
144 }
145 MediaAnalyticsItem &addRate(Attr key, int64_t count, int64_t duration) {
146 return add(key, std::make_pair(count, duration));
147 }
148
149 // find & extract values
150 // return indicates whether attr exists (and thus value filled in)
151 // NULL parameter value suppresses storage of value.
152 template<typename S, typename T>
153 bool get(S key, T *value) const {
154 Prop *prop = findProp(key);
155 return prop != nullptr && prop->get(value);
156 }
157
158 bool getInt32(Attr key, int32_t *value) const {
159 return get(key, value);
160 }
161 bool getInt64(Attr key, int64_t *value) const {
162 return get(key, value);
163 }
164 bool getDouble(Attr key, double *value) const {
165 return get(key, value);
166 }
167 bool getRate(Attr key, int64_t *count, int64_t *duration, double *rate) const {
168 std::pair<int64_t, int64_t> value;
169 if (!get(key, &value)) return false;
170 if (count != nullptr) *count = value.first;
171 if (duration != nullptr) *duration = value.second;
172 if (rate != nullptr) {
173 if (value.second != 0) {
174 *rate = (double)value.first / value.second; // TODO: isn't INF OK?
175 } else {
176 *rate = 0.;
177 }
178 }
179 return true;
180 }
181 // Caller owns the returned string
182 bool getCString(Attr key, char **value) const {
183 return get(key, value);
184 }
185 bool getString(Attr key, std::string *value) const {
186 return get(key, value);
187 }
Ray Essick3938dc62016-11-01 08:56:56 -0700188
Andy Hunga87e69c2019-10-18 10:07:40 -0700189 // Deliver the item to MediaMetrics
Ray Essick3938dc62016-11-01 08:56:56 -0700190 bool selfrecord();
191
192 // remove indicated attributes and their values
193 // filterNot() could also be called keepOnly()
194 // return value is # attributes removed
195 // XXX: perhaps 'remove' instead of 'filter'
196 // XXX: filterNot would become 'keep'
197 int32_t filter(int count, Attr attrs[]);
198 int32_t filterNot(int count, Attr attrs[]);
199 int32_t filter(Attr attr);
200
201 // below here are used on server side or to talk to server
202 // clients need not worry about these.
203
204 // timestamp, pid, and uid only used on server side
Ray Essickb5fac8e2016-12-12 11:33:56 -0800205 // timestamp is in 'nanoseconds, unix time'
Ray Essick3938dc62016-11-01 08:56:56 -0700206 MediaAnalyticsItem &setTimestamp(nsecs_t);
207 nsecs_t getTimestamp() const;
208
209 MediaAnalyticsItem &setPid(pid_t);
210 pid_t getPid() const;
211
212 MediaAnalyticsItem &setUid(uid_t);
213 uid_t getUid() const;
214
Ray Essick783bd0d2018-01-11 11:10:35 -0800215 MediaAnalyticsItem &setPkgName(const std::string &pkgName);
216 std::string getPkgName() const { return mPkgName; }
Ray Essickf65f4212017-08-31 11:41:19 -0700217
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800218 MediaAnalyticsItem &setPkgVersionCode(int64_t);
219 int64_t getPkgVersionCode() const;
Ray Essickf65f4212017-08-31 11:41:19 -0700220
Ray Essick3938dc62016-11-01 08:56:56 -0700221 // our serialization code for binder calls
222 int32_t writeToParcel(Parcel *);
223 int32_t readFromParcel(const Parcel&);
224
Ray Essickba8c4842019-01-18 11:35:33 -0800225 // supports the stable interface
226 bool dumpAttributes(char **pbuffer, size_t *plength);
227
Andy Hung17dbaf22019-10-11 14:06:31 -0700228 std::string toString() const;
229 std::string toString(int version) const;
Ray Essick20147322018-11-17 09:08:39 -0800230 const char *toCString();
231 const char *toCString(int version);
Ray Essick3938dc62016-11-01 08:56:56 -0700232
233 // are we collecting analytics data
234 static bool isEnabled();
235
Ray Essickba8c4842019-01-18 11:35:33 -0800236 private:
237 // handle Parcel version 0
238 int32_t writeToParcel0(Parcel *);
239 int32_t readFromParcel0(const Parcel&);
240
Ray Essick3938dc62016-11-01 08:56:56 -0700241 protected:
242
243 // merge fields from arg into this
244 // with rules for first/last/add, etc
245 // XXX: document semantics and how they are indicated
Ray Essickb5fac8e2016-12-12 11:33:56 -0800246 // caller continues to own 'incoming'
247 bool merge(MediaAnalyticsItem *incoming);
Ray Essick3938dc62016-11-01 08:56:56 -0700248
Andy Hungaeef7882019-10-18 15:18:14 -0700249 // enabled 1, disabled 0
250 static constexpr const char * const EnabledProperty = "media.metrics.enabled";
251 static constexpr const char * const EnabledPropertyPersist = "persist.media.metrics.enabled";
252 static const int EnabledProperty_default = 1;
Ray Essick3938dc62016-11-01 08:56:56 -0700253
254 private:
255
Andy Hungaeef7882019-10-18 15:18:14 -0700256 // let's reuse a binder connection
257 static sp<IMediaAnalyticsService> sAnalyticsService;
258 static sp<IMediaAnalyticsService> getInstance();
259 static void dropInstance();
Ray Essick3938dc62016-11-01 08:56:56 -0700260
Andy Hungaeef7882019-10-18 15:18:14 -0700261 class Prop {
262 friend class MediaMetricsJNI; // TODO: remove this access
263 public:
264 Prop() = default;
265 Prop(const Prop& other) {
266 *this = other;
267 }
268 Prop& operator=(const Prop& other) {
269 if (other.mName != nullptr) {
270 mName = strdup(other.mName);
271 } else {
272 mName = nullptr;
273 }
274 mNameLen = other.mNameLen;
275 mType = other.mType;
276 switch (mType) {
277 case kTypeInt32:
278 u.int32Value = other.u.int32Value;
279 break;
280 case kTypeInt64:
281 u.int64Value = other.u.int64Value;
282 break;
283 case kTypeDouble:
284 u.doubleValue = other.u.doubleValue;
285 break;
286 case kTypeCString:
287 u.CStringValue = strdup(other.u.CStringValue);
288 break;
289 case kTypeRate:
290 u.rate = {other.u.rate.count, other.u.rate.duration};
291 break;
292 case kTypeNone:
293 break;
294 default:
295 // abort?
296 break;
297 }
298 return *this;
299 }
Ray Essick3938dc62016-11-01 08:56:56 -0700300
Andy Hungaeef7882019-10-18 15:18:14 -0700301 void clear() {
302 free(mName);
303 mName = nullptr;
304 mNameLen = 0;
305 clearValue();
306 }
307 void clearValue() {
308 if (mType == kTypeCString) {
309 free(u.CStringValue);
310 u.CStringValue = nullptr;
311 }
312 mType = kTypeNone;
313 }
Ray Essick3938dc62016-11-01 08:56:56 -0700314
Andy Hungaeef7882019-10-18 15:18:14 -0700315 Type getType() const {
316 return mType;
317 }
Ray Essick3938dc62016-11-01 08:56:56 -0700318
Andy Hungaeef7882019-10-18 15:18:14 -0700319 const char *getName() const {
320 return mName;
321 }
Ray Essick3938dc62016-11-01 08:56:56 -0700322
Andy Hungaeef7882019-10-18 15:18:14 -0700323 void swap(Prop& other) {
324 std::swap(mName, other.mName);
325 std::swap(mNameLen, other.mNameLen);
326 std::swap(mType, other.mType);
327 std::swap(u, other.u);
328 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800329
Andy Hungaeef7882019-10-18 15:18:14 -0700330 void setName(const char *name, size_t len) {
331 free(mName);
332 if (name != nullptr) {
333 mName = (char *)malloc(len + 1);
334 mNameLen = len;
335 strncpy(mName, name, len);
336 mName[len] = 0;
337 } else {
338 mName = nullptr;
339 mNameLen = 0;
340 }
341 }
342
343 bool isNamed(const char *name, size_t len) const {
344 return len == mNameLen && memcmp(name, mName, len) == 0;
345 }
346
347 // TODO: remove duplicate but different definition
348 bool isNamed(const char *name) const {
349 return strcmp(name, mName) == 0;
350 }
351
352 template <typename T> bool get(T *value) const = delete;
353 template <>
354 bool get(int32_t *value) const {
355 if (mType != kTypeInt32) return false;
356 if (value != nullptr) *value = u.int32Value;
357 return true;
358 }
359 template <>
360 bool get(int64_t *value) const {
361 if (mType != kTypeInt64) return false;
362 if (value != nullptr) *value = u.int64Value;
363 return true;
364 }
365 template <>
366 bool get(double *value) const {
367 if (mType != kTypeDouble) return false;
368 if (value != nullptr) *value = u.doubleValue;
369 return true;
370 }
371 template <>
372 bool get(char** value) const {
373 if (mType != kTypeCString) return false;
374 if (value != nullptr) *value = strdup(u.CStringValue);
375 return true;
376 }
377 template <>
378 bool get(std::string* value) const {
379 if (mType != kTypeCString) return false;
380 if (value != nullptr) *value = u.CStringValue;
381 return true;
382 }
383 template <>
384 bool get(std::pair<int64_t, int64_t> *value) const {
385 if (mType != kTypeRate) return false;
386 if (value != nullptr) {
387 value->first = u.rate.count;
388 value->second = u.rate.duration;
389 }
390 return true;
391 }
392
393 template <typename T> void set(const T& value) = delete;
394 template <>
395 void set(const int32_t& value) {
396 mType = kTypeInt32;
397 u.int32Value = value;
398 }
399 template <>
400 void set(const int64_t& value) {
401 mType = kTypeInt64;
402 u.int64Value = value;
403 }
404 template <>
405 void set(const double& value) {
406 mType = kTypeDouble;
407 u.doubleValue = value;
408 }
409 template <>
410 void set(const char* const& value) {
411 if (mType == kTypeCString) {
412 free(u.CStringValue);
413 } else {
414 mType = kTypeCString;
415 }
416 if (value == nullptr) {
417 u.CStringValue = nullptr;
418 } else {
419 u.CStringValue = strdup(value);
420 }
421 }
422 template <>
423 void set(const std::pair<int64_t, int64_t> &value) {
424 mType = kTypeRate;
425 u.rate = {value.first, value.second};
426 }
427
428 template <typename T> void add(const T& value) = delete;
429 template <>
430 void add(const int32_t& value) {
431 if (mType == kTypeInt32) {
432 u.int32Value += value;
433 } else {
434 mType = kTypeInt32;
435 u.int32Value = value;
436 }
437 }
438 template <>
439 void add(const int64_t& value) {
440 if (mType == kTypeInt64) {
441 u.int64Value += value;
442 } else {
443 mType = kTypeInt64;
444 u.int64Value = value;
445 }
446 }
447 template <>
448 void add(const double& value) {
449 if (mType == kTypeDouble) {
450 u.doubleValue += value;
451 } else {
452 mType = kTypeDouble;
453 u.doubleValue = value;
454 }
455 }
456 template <>
457 void add(const std::pair<int64_t, int64_t>& value) {
458 if (mType == kTypeRate) {
459 u.rate.count += value.first;
460 u.rate.duration += value.second;
461 } else {
462 mType = kTypeRate;
463 u.rate = {value.first, value.second};
464 }
465 }
466
467 void writeToParcel(Parcel *data) const;
468 void toString(char *buffer, size_t length) const;
469
470 // TODO: make private
471 // private:
472 char *mName = nullptr;
473 size_t mNameLen = 0; // the strlen(), doesn't include the null
474 Type mType = kTypeNone;
475 union {
476 int32_t int32Value;
477 int64_t int64Value;
478 double doubleValue;
479 char *CStringValue;
480 struct { int64_t count, duration; } rate;
481 } u;
482 };
483
484 size_t findPropIndex(const char *name, size_t len) const;
485 Prop *findProp(const char *name) const;
486
Ray Essickb5fac8e2016-12-12 11:33:56 -0800487 enum {
488 kGrowProps = 10
489 };
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700490 bool growProps(int increment = kGrowProps);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800491 Prop *allocateProp(const char *name);
Ray Essickf65f4212017-08-31 11:41:19 -0700492 bool removeProp(const char *name);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800493
Andy Hungaeef7882019-10-18 15:18:14 -0700494 size_t mPropCount = 0;
495 size_t mPropSize = 0;
496 Prop *mProps = nullptr;
497
498 pid_t mPid = -1;
499 uid_t mUid = -1;
500 std::string mPkgName;
501 int64_t mPkgVersionCode = 0;
502 Key mKey{kKeyNone};
503 nsecs_t mTimestamp = 0;
Ray Essick3938dc62016-11-01 08:56:56 -0700504};
505
506} // namespace android
507
508#endif