1 /*
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_MEDIAMETRICSITEM_H
18 #define ANDROID_MEDIA_MEDIAMETRICSITEM_H
19
20 #include "MediaMetrics.h"
21 #include "MediaMetricsConstants.h"
22
23 #include <algorithm>
24 #include <map>
25 #include <string>
26 #include <sys/types.h>
27 #include <variant>
28
29 #include <binder/Parcel.h>
30 #include <log/log.h>
31 #include <utils/Errors.h>
32 #include <utils/Timers.h> // nsecs_t
33
34 namespace android {
35
36 class Parcel;
37
38 /*
39 * MediaMetrics Item
40 *
41 * The MediaMetrics Item allows get/set operations and recording to the service.
42 *
43 * The MediaMetrics LogItem is a faster logging variant. It allows set operations only,
44 * and then recording to the service.
45 *
46 * The Byte String format is as follows:
47 *
48 * For Java
49 * int64 corresponds to long
50 * int32, uint32 corresponds to int
51 * uint16 corresponds to char
52 * uint8, int8 corresponds to byte
53 *
54 * For items transmitted from Java, uint8 and uint32 values are limited
55 * to INT8_MAX and INT32_MAX. This constrains the size of large items
56 * to 2GB, which is consistent with ByteBuffer max size. A native item
57 * can conceivably have size of 4GB.
58 *
59 * Physical layout of integers and doubles within the MediaMetrics byte string
60 * is in Native / host order, which is usually little endian.
61 *
62 * Note that primitive data (ints, doubles) within a Byte String has
63 * no extra padding or alignment requirements, like ByteBuffer.
64 *
65 * -- begin of item
66 * -- begin of header
67 * (uint32) item size: including the item size field
68 * (uint32) header size, including the item size and header size fields.
69 * (uint16) version: exactly 0
70 * (uint16) key size, that is key strlen + 1 for zero termination.
71 * (int8)+ key, a string which is 0 terminated (UTF-8).
72 * (int32) pid
73 * (int32) uid
74 * (int64) timestamp
75 * -- end of header
76 * -- begin body
77 * (uint32) number of properties
78 * -- repeat for number of properties
79 * (uint16) property size, including property size field itself
80 * (uint8) type of property
81 * (int8)+ key string, including 0 termination
82 * based on type of property (given above), one of:
83 * (int32)
84 * (int64)
85 * (double)
86 * (int8)+ for TYPE_CSTRING, including 0 termination
87 * (int64, int64) for rate
88 * -- end body
89 * -- end of item
90 *
91 * The Byte String format must match MediaMetrics.java.
92 */
93
94 namespace mediametrics {
95
96 // Type must match MediaMetrics.java
97 enum Type {
98 kTypeNone = 0,
99 kTypeInt32 = 1,
100 kTypeInt64 = 2,
101 kTypeDouble = 3,
102 kTypeCString = 4,
103 kTypeRate = 5,
104 };
105
106 /*
107 * Helper for status conversions
108 */
109
statusToStatusString(status_t status)110 inline constexpr const char* statusToStatusString(status_t status) {
111 switch (status) {
112 case BAD_VALUE:
113 return AMEDIAMETRICS_PROP_STATUS_VALUE_ARGUMENT;
114 case DEAD_OBJECT:
115 case FAILED_TRANSACTION:
116 return AMEDIAMETRICS_PROP_STATUS_VALUE_IO;
117 case NO_MEMORY:
118 return AMEDIAMETRICS_PROP_STATUS_VALUE_MEMORY;
119 case PERMISSION_DENIED:
120 return AMEDIAMETRICS_PROP_STATUS_VALUE_SECURITY;
121 case NO_INIT:
122 case INVALID_OPERATION:
123 return AMEDIAMETRICS_PROP_STATUS_VALUE_STATE;
124 case WOULD_BLOCK:
125 return AMEDIAMETRICS_PROP_STATUS_VALUE_TIMEOUT;
126 default:
127 if (status >= 0) return AMEDIAMETRICS_PROP_STATUS_VALUE_OK; // non-negative values "OK"
128 [[fallthrough]]; // negative values are error.
129 case UNKNOWN_ERROR:
130 return AMEDIAMETRICS_PROP_STATUS_VALUE_UNKNOWN;
131 }
132 }
133
134 status_t statusStringToStatus(const char *error);
135
136 /*
137 * Time printing
138 *
139 * kPrintFormatLong time string is 19 characters (including null termination).
140 * Example Long Form: "03-27 16:47:06.187"
141 * MM DD HH MM SS MS
142 *
143 * kPrintFormatShort time string is 13 characters (including null termination).
144 * Example Short Form: "16:47:06.187"
145 * HH MM SS MS
146 */
147
148 enum PrintFormat {
149 kPrintFormatLong = 0,
150 kPrintFormatShort = 1,
151 };
152
153 /**
154 * Converts real time in ns to a time string object, with format similar to logcat.
155 *
156 * \param ns input real time in nanoseconds to convert.
157 * \param buffer the buffer location to put the converted string.
158 * \param bufferSize the size of buffer in bytes.
159 * \param format format, from enum PrintFormat.
160 */
161 void nsToString(
162 int64_t ns, char *buffer, size_t bufferSize, PrintFormat format = kPrintFormatLong);
163
164 // Contains the time string
165 struct time_string_t {
166 char time[19]; /* minimum size buffer */
167 };
168
169 /**
170 * Converts real time in ns to a time string object, with format similar to logcat.
171 *
172 * \param ns input real time in nanoseconds to convert.
173 * \param format format, from enum PrintFormat.
174 * \return a time_string_t object with the time string encoded.
175 */
176 static inline time_string_t timeStringFromNs(int64_t ns, PrintFormat format = kPrintFormatLong) {
177 time_string_t ts;
178 nsToString(ns, ts.time, sizeof(ts.time), format);
179 return ts;
180 }
181
182 /**
183 * Finds the end of the common time prefix.
184 *
185 * This is as an option to remove the common time prefix to avoid
186 * unnecessary duplicated strings.
187 *
188 * \param time1 a time string from timeStringFromNs
189 * \param time2 a time string from timeStringFromNs
190 * \return the position where the common time prefix ends. For abbreviated
191 * printing of time2, offset the character pointer by this position.
192 */
commonTimePrefixPosition(const char * time1,const char * time2)193 static inline size_t commonTimePrefixPosition(const char *time1, const char *time2) {
194 size_t i;
195
196 // Find location of the first mismatch between strings
197 for (i = 0; ; ++i) {
198 if (time1[i] != time2[i]) {
199 break;
200 }
201 if (time1[i] == 0) {
202 return i; // strings match completely
203 }
204 }
205
206 // Go backwards until we find a delimeter or space.
207 for (; i > 0
208 && isdigit(time1[i]) // still a number
209 && time1[i - 1] != ' '
210 ; --i) {
211 }
212 return i;
213 }
214
215 /**
216 * The MediaMetrics Item has special Item properties,
217 * derived internally or through dedicated setters.
218 *
219 * For consistency we use the following keys to represent
220 * these special Item properties when in a generic Bundle
221 * or in a std::map.
222 *
223 * These values must match MediaMetrics.java
224 */
225 static inline constexpr const char *BUNDLE_TOTAL_SIZE = "_totalSize";
226 static inline constexpr const char *BUNDLE_HEADER_SIZE = "_headerSize";
227 static inline constexpr const char *BUNDLE_VERSION = "_version";
228 static inline constexpr const char *BUNDLE_KEY_SIZE = "_keySize";
229 static inline constexpr const char *BUNDLE_KEY = "_key";
230 static inline constexpr const char *BUNDLE_PID = "_pid";
231 static inline constexpr const char *BUNDLE_UID = "_uid";
232 static inline constexpr const char *BUNDLE_TIMESTAMP = "_timestamp";
233 static inline constexpr const char *BUNDLE_PROPERTY_COUNT = "_propertyCount";
234
235 template<size_t N>
startsWith(const std::string & s,const char (& comp)[N])236 static inline bool startsWith(const std::string &s, const char (&comp)[N]) {
237 return !strncmp(s.c_str(), comp, N - 1); // last char is null termination
238 }
239
startsWith(const std::string & s,const std::string & comp)240 static inline bool startsWith(const std::string& s, const std::string& comp) {
241 return !strncmp(s.c_str(), comp.c_str(), comp.size());
242 }
243
244 /**
245 * Defers a function to run in the destructor.
246 *
247 * This helper class is used to log results on exit of a method.
248 */
249 class Defer {
250 public:
251 template <typename U>
Defer(U && f)252 explicit Defer(U &&f) : mThunk(std::forward<U>(f)) {}
~Defer()253 ~Defer() { mThunk(); }
254
255 private:
256 const std::function<void()> mThunk;
257 };
258
259 /**
260 * Media Metrics BaseItem
261 *
262 * A base class which contains utility static functions to write to a byte stream
263 * and access the Media Metrics service.
264 */
265
266 class BaseItem {
267 friend class MediaMetricsDeathNotifier; // for dropInstance
268 // enabled 1, disabled 0
269 public:
270 // are we collecting metrics data
271 static bool isEnabled();
272 // submits a raw buffer directly to the MediaMetrics service - this is highly optimized.
273 static status_t submitBuffer(const char *buffer, size_t len);
274
275 protected:
276 static constexpr const char * const EnabledProperty = "media.metrics.enabled";
277 static constexpr const char * const EnabledPropertyPersist = "persist.media.metrics.enabled";
278 static const int EnabledProperty_default = 1;
279
280 static void dropInstance();
281
282 template <typename T>
283 struct is_item_type {
284 static constexpr inline bool value =
285 std::is_same<T, int32_t>::value
286 || std::is_same<T, int64_t>::value
287 || std::is_same<T, double>::value
288 || std::is_same<T, std::pair<int64_t, int64_t>>:: value
289 || std::is_same<T, std::string>::value
290 || std::is_same<T, std::monostate>::value;
291 };
292
293 template <typename T>
294 struct get_type_of {
295 static_assert(is_item_type<T>::value);
296 static constexpr inline Type value =
297 std::is_same<T, int32_t>::value ? kTypeInt32
298 : std::is_same<T, int64_t>::value ? kTypeInt64
299 : std::is_same<T, double>::value ? kTypeDouble
300 : std::is_same<T, std::pair<int64_t, int64_t>>:: value ? kTypeRate
301 : std::is_same<T, std::string>::value ? kTypeCString
302 : std::is_same<T, std::monostate>::value ? kTypeNone
303 : kTypeNone;
304 };
305
306 template <typename T>
sizeOfByteString(const char * name,const T & value)307 static size_t sizeOfByteString(const char *name, const T& value) {
308 static_assert(is_item_type<T>::value);
309 return 2 + 1 + strlen(name) + 1 + sizeof(value);
310 }
311 template <> // static
sizeOfByteString(const char * name,const std::string & value)312 size_t sizeOfByteString(const char *name, const std::string& value) {
313 return 2 + 1 + strlen(name) + 1 + value.size() + 1;
314 }
315 template <> // static
sizeOfByteString(const char * name,const std::monostate &)316 size_t sizeOfByteString(const char *name, const std::monostate&) {
317 return 2 + 1 + strlen(name) + 1;
318 }
319 // for speed
sizeOfByteString(const char * name,const char * value)320 static size_t sizeOfByteString(const char *name, const char *value) {
321 return 2 + 1 + strlen(name) + 1 + strlen(value) + 1;
322 }
323
324 template <typename T>
insert(const T & val,char ** bufferpptr,char * bufferptrmax)325 static status_t insert(const T& val, char **bufferpptr, char *bufferptrmax) {
326 static_assert(std::is_trivially_constructible<T>::value);
327 const size_t size = sizeof(val);
328 if (*bufferpptr + size > bufferptrmax) {
329 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
330 return BAD_VALUE;
331 }
332 memcpy(*bufferpptr, &val, size);
333 *bufferpptr += size;
334 return NO_ERROR;
335 }
336 template <> // static
insert(const std::string & val,char ** bufferpptr,char * bufferptrmax)337 status_t insert(const std::string& val, char **bufferpptr, char *bufferptrmax) {
338 const size_t size = val.size() + 1;
339 if (size > UINT16_MAX || *bufferpptr + size > bufferptrmax) {
340 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
341 return BAD_VALUE;
342 }
343 memcpy(*bufferpptr, val.c_str(), size);
344 *bufferpptr += size;
345 return NO_ERROR;
346 }
347 template <> // static
insert(const std::pair<int64_t,int64_t> & val,char ** bufferpptr,char * bufferptrmax)348 status_t insert(const std::pair<int64_t, int64_t>& val,
349 char **bufferpptr, char *bufferptrmax) {
350 const size_t size = sizeof(val.first) + sizeof(val.second);
351 if (*bufferpptr + size > bufferptrmax) {
352 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
353 return BAD_VALUE;
354 }
355 memcpy(*bufferpptr, &val.first, sizeof(val.first));
356 memcpy(*bufferpptr + sizeof(val.first), &val.second, sizeof(val.second));
357 *bufferpptr += size;
358 return NO_ERROR;
359 }
360 template <> // static
insert(const std::monostate &,char **,char *)361 status_t insert(const std::monostate&, char **, char *) {
362 return NO_ERROR;
363 }
364 // for speed
insert(const char * val,char ** bufferpptr,char * bufferptrmax)365 static status_t insert(const char *val, char **bufferpptr, char *bufferptrmax) {
366 const size_t size = strlen(val) + 1;
367 if (size > UINT16_MAX || *bufferpptr + size > bufferptrmax) {
368 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
369 return BAD_VALUE;
370 }
371 memcpy(*bufferpptr, val, size);
372 *bufferpptr += size;
373 return NO_ERROR;
374 }
375
376 template <typename T>
writeToByteString(const char * name,const T & value,char ** bufferpptr,char * bufferptrmax)377 static status_t writeToByteString(
378 const char *name, const T& value, char **bufferpptr, char *bufferptrmax) {
379 static_assert(is_item_type<T>::value);
380 const size_t len = sizeOfByteString(name, value);
381 if (len > UINT16_MAX) return BAD_VALUE;
382 return insert((uint16_t)len, bufferpptr, bufferptrmax)
383 ?: insert((uint8_t)get_type_of<T>::value, bufferpptr, bufferptrmax)
384 ?: insert(name, bufferpptr, bufferptrmax)
385 ?: insert(value, bufferpptr, bufferptrmax);
386 }
387 // for speed
writeToByteString(const char * name,const char * value,char ** bufferpptr,char * bufferptrmax)388 static status_t writeToByteString(
389 const char *name, const char *value, char **bufferpptr, char *bufferptrmax) {
390 const size_t len = sizeOfByteString(name, value);
391 if (len > UINT16_MAX) return BAD_VALUE;
392 return insert((uint16_t)len, bufferpptr, bufferptrmax)
393 ?: insert((uint8_t)kTypeCString, bufferpptr, bufferptrmax)
394 ?: insert(name, bufferpptr, bufferptrmax)
395 ?: insert(value, bufferpptr, bufferptrmax);
396 }
397
398 template <typename T>
399 static void toStringBuffer(
400 const char *name, const T& value, char *buffer, size_t length) = delete;
401 template <> // static
toStringBuffer(const char * name,const int32_t & value,char * buffer,size_t length)402 void toStringBuffer(
403 const char *name, const int32_t& value, char *buffer, size_t length) {
404 snprintf(buffer, length, "%s=%d", name, value);
405 }
406 template <> // static
toStringBuffer(const char * name,const int64_t & value,char * buffer,size_t length)407 void toStringBuffer(
408 const char *name, const int64_t& value, char *buffer, size_t length) {
409 snprintf(buffer, length, "%s=%lld", name, (long long)value);
410 }
411 template <> // static
toStringBuffer(const char * name,const double & value,char * buffer,size_t length)412 void toStringBuffer(
413 const char *name, const double& value, char *buffer, size_t length) {
414 snprintf(buffer, length, "%s=%e", name, value);
415 }
416 template <> // static
toStringBuffer(const char * name,const std::pair<int64_t,int64_t> & value,char * buffer,size_t length)417 void toStringBuffer(
418 const char *name, const std::pair<int64_t, int64_t>& value,
419 char *buffer, size_t length) {
420 snprintf(buffer, length, "%s=%lld/%lld",
421 name, (long long)value.first, (long long)value.second);
422 }
423 template <> // static
toStringBuffer(const char * name,const std::string & value,char * buffer,size_t length)424 void toStringBuffer(
425 const char *name, const std::string& value, char *buffer, size_t length) {
426 // TODO sanitize string for ':' '='
427 snprintf(buffer, length, "%s=%s", name, value.c_str());
428 }
429 template <> // static
toStringBuffer(const char * name,const std::monostate &,char * buffer,size_t length)430 void toStringBuffer(
431 const char *name, const std::monostate&, char *buffer, size_t length) {
432 snprintf(buffer, length, "%s=()", name);
433 }
434
435 template <typename T>
436 static status_t writeToParcel(std::string_view name, const T& value, Parcel *parcel) = delete;
437 template <> // static
writeToParcel(std::string_view name,const int32_t & value,Parcel * parcel)438 status_t writeToParcel(std::string_view name, const int32_t& value, Parcel *parcel) {
439 return parcel->writeString8(name.data(), name.length())
440 ?: parcel->writeInt32(get_type_of<int32_t>::value)
441 ?: parcel->writeInt32(value);
442 }
443 template <> // static
writeToParcel(std::string_view name,const int64_t & value,Parcel * parcel)444 status_t writeToParcel(std::string_view name, const int64_t& value, Parcel *parcel) {
445 return parcel->writeString8(name.data(), name.length())
446 ?: parcel->writeInt32(get_type_of<int64_t>::value)
447 ?: parcel->writeInt64(value);
448 }
449 template <> // static
writeToParcel(std::string_view name,const double & value,Parcel * parcel)450 status_t writeToParcel(std::string_view name, const double& value, Parcel *parcel) {
451 return parcel->writeString8(name.data(), name.length())
452 ?: parcel->writeInt32(get_type_of<double>::value)
453 ?: parcel->writeDouble(value);
454 }
455 template <> // static
writeToParcel(std::string_view name,const std::pair<int64_t,int64_t> & value,Parcel * parcel)456 status_t writeToParcel(std::string_view name, const std::pair<int64_t, int64_t>& value,
457 Parcel* parcel) {
458 return parcel->writeString8(name.data(), name.length())
459 ?: parcel->writeInt32(get_type_of< std::pair<int64_t, int64_t>>::value)
460 ?: parcel->writeInt64(value.first)
461 ?: parcel->writeInt64(value.second);
462 }
463 template <> // static
writeToParcel(std::string_view name,const std::string & value,Parcel * parcel)464 status_t writeToParcel(std::string_view name, const std::string& value, Parcel *parcel) {
465 return parcel->writeString8(name.data(), name.length())
466 ?: parcel->writeInt32(get_type_of<std::string>::value)
467 ?: parcel->writeString8(value.data(), value.length());
468 }
469 template <> // static
writeToParcel(std::string_view name,const std::monostate &,Parcel * parcel)470 status_t writeToParcel(std::string_view name, const std::monostate&, Parcel *parcel) {
471 return parcel->writeString8(name.data(), name.length())
472 ?: parcel->writeInt32(get_type_of<std::monostate>::value);
473 }
474
475 template <typename T>
extract(T * val,const char ** bufferpptr,const char * bufferptrmax)476 static status_t extract(T *val, const char **bufferpptr, const char *bufferptrmax) {
477 static_assert(std::is_trivially_constructible<T>::value);
478 const size_t size = sizeof(*val);
479 if (*bufferpptr + size > bufferptrmax) {
480 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
481 return BAD_VALUE;
482 }
483 memcpy(val, *bufferpptr, size);
484 *bufferpptr += size;
485 return NO_ERROR;
486 }
487 template <> // static
extract(std::string * val,const char ** bufferpptr,const char * bufferptrmax)488 status_t extract(std::string *val, const char **bufferpptr, const char *bufferptrmax) {
489 const char *ptr = *bufferpptr;
490 do {
491 if (ptr >= bufferptrmax) {
492 ALOGE("%s: buffer exceeded", __func__);
493 android_errorWriteLog(0x534e4554, "204445255");
494 return BAD_VALUE;
495 }
496 } while (*ptr++ != 0);
497 // ptr is terminator+1, == bufferptrmax if we finished entire buffer
498 *val = *bufferpptr;
499 *bufferpptr = ptr;
500 return NO_ERROR;
501 }
502 template <> // static
extract(std::pair<int64_t,int64_t> * val,const char ** bufferpptr,const char * bufferptrmax)503 status_t extract(std::pair<int64_t, int64_t> *val,
504 const char **bufferpptr, const char *bufferptrmax) {
505 const size_t size = sizeof(val->first) + sizeof(val->second);
506 if (*bufferpptr + size > bufferptrmax) {
507 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
508 return BAD_VALUE;
509 }
510 memcpy(&val->first, *bufferpptr, sizeof(val->first));
511 memcpy(&val->second, *bufferpptr + sizeof(val->first), sizeof(val->second));
512 *bufferpptr += size;
513 return NO_ERROR;
514 }
515 template <> // static
extract(std::monostate *,const char **,const char *)516 status_t extract(std::monostate *, const char **, const char *) {
517 return NO_ERROR;
518 }
519 };
520
521 /**
522 * Media Metrics BufferedItem
523 *
524 * A base class which represents a put-only Media Metrics item, storing
525 * the Media Metrics data in a buffer with begin and end pointers.
526 *
527 * If a property key is entered twice, it will be stored in the buffer twice,
528 * and (implementation defined) the last value for that key will be used
529 * by the Media Metrics service.
530 *
531 * For realloc, a baseRealloc pointer must be passed in either explicitly
532 * or implicitly in the constructor. This will be updated with the value used on realloc.
533 */
534 class BufferedItem : public BaseItem {
535 public:
536 static inline constexpr uint16_t kVersion = 0;
537
538 virtual ~BufferedItem() = default;
539 BufferedItem(const BufferedItem&) = delete;
540 BufferedItem& operator=(const BufferedItem&) = delete;
541
BufferedItem(const std::string & key,char * begin,char * end)542 BufferedItem(const std::string& key, char *begin, char *end)
543 : BufferedItem(key.c_str(), begin, end) { }
544
BufferedItem(const char * key,char * begin,char * end)545 BufferedItem(const char *key, char *begin, char *end)
546 : BufferedItem(key, begin, end, nullptr) { }
547
BufferedItem(const char * key,char ** begin,char * end)548 BufferedItem(const char *key, char **begin, char *end)
549 : BufferedItem(key, *begin, end, begin) { }
550
BufferedItem(const char * key,char * begin,char * end,char ** baseRealloc)551 BufferedItem(const char *key, char *begin, char *end, char **baseRealloc)
552 : mBegin(begin)
553 , mEnd(end)
554 , mBaseRealloc(baseRealloc)
555 {
556 init(key);
557 }
558
559 template<typename T>
set(const char * key,const T & value)560 BufferedItem &set(const char *key, const T& value) {
561 reallocFor(sizeOfByteString(key, value));
562 if (mStatus == NO_ERROR) {
563 mStatus = BaseItem::writeToByteString(key, value, &mBptr, mEnd);
564 ++mPropCount;
565 }
566 return *this;
567 }
568
569 template<typename T>
set(const std::string & key,const T & value)570 BufferedItem &set(const std::string& key, const T& value) {
571 return set(key.c_str(), value);
572 }
573
setPid(pid_t pid)574 BufferedItem &setPid(pid_t pid) {
575 if (mStatus == NO_ERROR) {
576 copyTo(mBegin + mHeaderLen - 16, (int32_t)pid);
577 }
578 return *this;
579 }
580
setUid(uid_t uid)581 BufferedItem &setUid(uid_t uid) {
582 if (mStatus == NO_ERROR) {
583 copyTo(mBegin + mHeaderLen - 12, (int32_t)uid);
584 }
585 return *this;
586 }
587
setTimestamp(nsecs_t timestamp)588 BufferedItem &setTimestamp(nsecs_t timestamp) {
589 if (mStatus == NO_ERROR) {
590 copyTo(mBegin + mHeaderLen - 8, (int64_t)timestamp);
591 }
592 return *this;
593 }
594
record()595 bool record() {
596 return updateHeader()
597 && BaseItem::submitBuffer(getBuffer(), getLength()) == OK;
598 }
599
isValid()600 bool isValid () const {
601 return mStatus == NO_ERROR;
602 }
603
getBuffer()604 char *getBuffer() const { return mBegin; }
getLength()605 size_t getLength() const { return mBptr - mBegin; }
getRemaining()606 size_t getRemaining() const { return mEnd - mBptr; }
getCapacity()607 size_t getCapacity() const { return mEnd - mBegin; }
608
updateHeader()609 bool updateHeader() {
610 if (mStatus != NO_ERROR) return false;
611 copyTo(mBegin + 0, (uint32_t)getLength());
612 copyTo(mBegin + 4, (uint32_t)mHeaderLen);
613 copyTo(mBegin + mHeaderLen, (uint32_t)mPropCount);
614 return true;
615 }
616
617 protected:
618 BufferedItem() = default;
619
reallocFor(size_t required)620 void reallocFor(size_t required) {
621 if (mStatus != NO_ERROR) return;
622 const size_t remaining = getRemaining();
623 if (required <= remaining) return;
624 if (mBaseRealloc == nullptr) {
625 mStatus = NO_MEMORY;
626 return;
627 }
628
629 const size_t current = getLength();
630 size_t minimum = current + required;
631 if (minimum > SSIZE_MAX >> 1) {
632 mStatus = NO_MEMORY;
633 return;
634 }
635 minimum <<= 1;
636 void *newptr = realloc(*mBaseRealloc, minimum);
637 if (newptr == nullptr) {
638 mStatus = NO_MEMORY;
639 return;
640 }
641 if (newptr != *mBaseRealloc) {
642 // ALOGD("base changed! current:%zu new size %zu", current, minimum);
643 if (*mBaseRealloc == nullptr) {
644 memcpy(newptr, mBegin, current);
645 }
646 mBegin = (char *)newptr;
647 *mBaseRealloc = mBegin;
648 mEnd = mBegin + minimum;
649 mBptr = mBegin + current;
650 } else {
651 // ALOGD("base kept! current:%zu new size %zu", current, minimum);
652 mEnd = mBegin + minimum;
653 }
654 }
655 template<typename T>
copyTo(char * ptr,const T & value)656 void copyTo(char *ptr, const T& value) {
657 memcpy(ptr, &value, sizeof(value));
658 }
659
init(const char * key)660 void init(const char *key) {
661 mBptr = mBegin;
662 const size_t keylen = key == nullptr ? 0 : strlen(key) + 1;
663 if (keylen <= 1) {
664 mStatus = BAD_VALUE; // prevent null pointer or empty keys.
665 return;
666 }
667 mHeaderLen = 4 + 4 + 2 + 2 + keylen + 4 + 4 + 8;
668 reallocFor(mHeaderLen);
669 if (mStatus != NO_ERROR) return;
670 mBptr = mBegin + mHeaderLen + 4; // this includes propcount.
671
672 if (mEnd < mBptr || keylen > UINT16_MAX) {
673 mStatus = NO_MEMORY;
674 mBptr = mEnd;
675 return;
676 }
677 copyTo(mBegin + 8, kVersion);
678 copyTo(mBegin + 10, (uint16_t)keylen);
679 strcpy(mBegin + 12, key);
680
681 // initialize some parameters (that could be overridden)
682 setPid(-1);
683 setUid(-1);
684 setTimestamp(0);
685 }
686
687 char *mBegin = nullptr;
688 char *mEnd = nullptr;
689 char **mBaseRealloc = nullptr; // set to an address if realloc should be done.
690 // upon return, that pointer is updated with
691 // whatever needs to be freed.
692 char *mBptr = nullptr;
693 status_t mStatus = NO_ERROR;
694 uint32_t mPropCount = 0;
695 uint32_t mHeaderLen = 0;
696 };
697
698 /**
699 * MediaMetrics LogItem is a stack allocated mediametrics item used for
700 * fast logging. It falls over to a malloc if needed.
701 *
702 * This is templated with a buffer size to allocate on the stack.
703 */
704 template <size_t N = 4096>
705 class LogItem : public BufferedItem {
706 public:
LogItem(const std::string & key)707 explicit LogItem(const std::string& key) : LogItem(key.c_str()) { }
708
709 // Since this class will not be defined before the base class, we initialize variables
710 // in our own order.
LogItem(const char * key)711 explicit LogItem(const char *key) {
712 mBegin = mBuffer;
713 mEnd = mBuffer + N;
714 mBaseRealloc = &mReallocPtr;
715 init(key);
716 }
717
~LogItem()718 ~LogItem() override {
719 if (mReallocPtr != nullptr) { // do the check before calling free to avoid overhead.
720 free(mReallocPtr);
721 }
722 }
723
724 private:
725 char *mReallocPtr = nullptr; // set non-null by base class if realloc happened.
726 char mBuffer[N];
727 };
728
729
730 /**
731 * Media Metrics Item
732 *
733 * A mutable item representing an event or record that will be
734 * logged with the Media Metrics service. For client logging, one should
735 * use the mediametrics::Item.
736 *
737 * The Item is designed for the service as it has getters.
738 */
739 class Item final : public mediametrics::BaseItem {
740 public:
741
742 class Prop {
743 public:
744 using Elem = std::variant<
745 std::monostate, // kTypeNone
746 int32_t, // kTypeInt32
747 int64_t, // kTypeInt64
748 double, // kTypeDouble
749 std::string, // kTypeCString
750 std::pair<int64_t, int64_t> // kTypeRate
751 >;
752
753 Prop() = default;
Prop(const Prop & other)754 Prop(const Prop& other) {
755 *this = other;
756 }
757 Prop& operator=(const Prop& other) {
758 mName = other.mName;
759 mElem = other.mElem;
760 return *this;
761 }
Prop(Prop && other)762 Prop(Prop&& other) noexcept {
763 *this = std::move(other);
764 }
765 Prop& operator=(Prop&& other) noexcept {
766 mName = std::move(other.mName);
767 mElem = std::move(other.mElem);
768 return *this;
769 }
770
771 bool operator==(const Prop& other) const {
772 return mName == other.mName && mElem == other.mElem;
773 }
774 bool operator!=(const Prop& other) const {
775 return !(*this == other);
776 }
777
clear()778 void clear() {
779 mName.clear();
780 mElem = std::monostate{};
781 }
clearValue()782 void clearValue() {
783 mElem = std::monostate{};
784 }
785
getName()786 const char *getName() const {
787 return mName.c_str();
788 }
789
swap(Prop & other)790 void swap(Prop& other) {
791 std::swap(mName, other.mName);
792 std::swap(mElem, other.mElem);
793 }
794
setName(const char * name)795 void setName(const char *name) {
796 mName = name;
797 }
798
setName(std::string name)799 void setName(std::string name) {
800 mName = std::move(name);
801 }
802
isNamed(const char * name)803 bool isNamed(const char *name) const {
804 return mName == name;
805 }
806
visit(T f)807 template <typename T> void visit(T f) const {
808 std::visit(f, mElem);
809 }
810
get(T * value)811 template <typename T> bool get(T *value) const {
812 auto pval = std::get_if<T>(&mElem);
813 if (pval != nullptr) {
814 *value = *pval;
815 return true;
816 }
817 return false;
818 }
819
get()820 const Elem& get() const {
821 return mElem;
822 }
823
set(const T & value)824 template <typename T> void set(const T& value) {
825 mElem = value;
826 }
827
add(const T & value)828 template <typename T> void add(const T& value) {
829 auto pval = std::get_if<T>(&mElem);
830 if (pval != nullptr) {
831 *pval += value;
832 } else {
833 mElem = value;
834 }
835 }
836
add(const std::pair<int64_t,int64_t> & value)837 template <> void add(const std::pair<int64_t, int64_t>& value) {
838 auto pval = std::get_if<std::pair<int64_t, int64_t>>(&mElem);
839 if (pval != nullptr) {
840 pval->first += value.first;
841 pval->second += value.second;
842 } else {
843 mElem = value;
844 }
845 }
846
writeToParcel(Parcel * parcel)847 status_t writeToParcel(Parcel *parcel) const {
848 return std::visit([this, parcel](auto &value) {
849 return BaseItem::writeToParcel(mName, value, parcel);}, mElem);
850 }
851
toStringBuffer(char * buffer,size_t length)852 void toStringBuffer(char *buffer, size_t length) const {
853 return std::visit([this, buffer, length](auto &value) {
854 BaseItem::toStringBuffer(mName.c_str(), value, buffer, length);}, mElem);
855 }
856
getByteStringSize()857 size_t getByteStringSize() const {
858 return std::visit([this](auto &value) {
859 return BaseItem::sizeOfByteString(mName.c_str(), value);}, mElem);
860 }
861
writeToByteString(char ** bufferpptr,char * bufferptrmax)862 status_t writeToByteString(char **bufferpptr, char *bufferptrmax) const {
863 return std::visit([this, bufferpptr, bufferptrmax](auto &value) {
864 return BaseItem::writeToByteString(mName.c_str(), value, bufferpptr, bufferptrmax);
865 }, mElem);
866 }
867
868 status_t readFromParcel(const Parcel& data);
869
870 status_t readFromByteString(const char **bufferpptr, const char *bufferptrmax);
871
872 private:
873 std::string mName;
874 Elem mElem;
875 };
876
877 // Iteration of props within item
878 class iterator {
879 public:
iterator(const std::map<std::string,Prop>::const_iterator & _it)880 explicit iterator(const std::map<std::string, Prop>::const_iterator &_it) : it(_it) { }
881 iterator &operator++() {
882 ++it;
883 return *this;
884 }
885 bool operator!=(iterator &other) const {
886 return it != other.it;
887 }
888 const Prop &operator*() const {
889 return it->second;
890 }
891
892 private:
893 std::map<std::string, Prop>::const_iterator it;
894 };
895
begin()896 iterator begin() const {
897 return iterator(mProps.cbegin());
898 }
899
end()900 iterator end() const {
901 return iterator(mProps.cend());
902 }
903
904 // T must be convertible to mKey
905 template <typename T>
Item(T key)906 explicit Item(T key)
907 : mKey(key) { }
908 Item() = default;
909
910 // We enable default copy and move constructors and make this class final
911 // to prevent a derived class; this avoids possible data slicing.
912 Item(const Item& other) = default;
913 Item(Item&& other) = default;
914 Item& operator=(const Item& other) = default;
915 Item& operator=(Item&& other) = default;
916
917 bool operator==(const Item& other) const {
918 return mPid == other.mPid
919 && mUid == other.mUid
920 && mPkgName == other.mPkgName
921 && mPkgVersionCode == other.mPkgVersionCode
922 && mKey == other.mKey
923 && mTimestamp == other.mTimestamp
924 && mProps == other.mProps
925 ;
926 }
927 bool operator!=(const Item& other) const {
928 return !(*this == other);
929 }
930
931 template <typename T>
create(T key)932 static Item* create(T key) {
933 return new Item(key);
934 }
create()935 static Item* create() {
936 return new Item();
937 }
938
939 static Item* convert(mediametrics_handle_t);
940 static mediametrics_handle_t convert(Item *);
941
942 // access functions for the class
943 ~Item();
944
clear()945 void clear() {
946 mPid = -1;
947 mUid = -1;
948 mPkgName.clear();
949 mPkgVersionCode = 0;
950 mTimestamp = 0;
951 mKey.clear();
952 mProps.clear();
953 }
954
dup()955 Item *dup() const { return new Item(*this); }
956
setKey(const char * key)957 Item &setKey(const char *key) {
958 mKey = key;
959 return *this;
960 }
getKey()961 const std::string& getKey() const { return mKey; }
962
963 // # of properties in the record
count()964 size_t count() const { return mProps.size(); }
965
966 template<typename S, typename T>
set(S key,T value)967 Item &set(S key, T value) {
968 findOrAllocateProp(key).set(value);
969 return *this;
970 }
971
972 // set values appropriately
setInt32(const char * key,int32_t value)973 Item &setInt32(const char *key, int32_t value) {
974 return set(key, value);
975 }
setInt64(const char * key,int64_t value)976 Item &setInt64(const char *key, int64_t value) {
977 return set(key, value);
978 }
setDouble(const char * key,double value)979 Item &setDouble(const char *key, double value) {
980 return set(key, value);
981 }
setRate(const char * key,int64_t count,int64_t duration)982 Item &setRate(const char *key, int64_t count, int64_t duration) {
983 return set(key, std::make_pair(count, duration));
984 }
setCString(const char * key,const char * value)985 Item &setCString(const char *key, const char *value) {
986 return set(key, value);
987 }
988
989 // fused get/add/set; if attr wasn't there, it's a simple set.
990 // type-mismatch counts as "wasn't there".
991 template<typename S, typename T>
add(S key,T value)992 Item &add(S key, T value) {
993 findOrAllocateProp(key).add(value);
994 return *this;
995 }
996
addInt32(const char * key,int32_t value)997 Item &addInt32(const char *key, int32_t value) {
998 return add(key, value);
999 }
addInt64(const char * key,int64_t value)1000 Item &addInt64(const char *key, int64_t value) {
1001 return add(key, value);
1002 }
addDouble(const char * key,double value)1003 Item &addDouble(const char *key, double value) {
1004 return add(key, value);
1005 }
addRate(const char * key,int64_t count,int64_t duration)1006 Item &addRate(const char *key, int64_t count, int64_t duration) {
1007 return add(key, std::make_pair(count, duration));
1008 }
1009
1010 // find & extract values
1011 // return indicates whether attr exists (and thus value filled in)
1012 // NULL parameter value suppresses storage of value.
1013 template<typename S, typename T>
get(S key,T * value)1014 bool get(S key, T *value) const {
1015 const Prop *prop = findProp(key);
1016 return prop != nullptr && prop->get(value);
1017 }
1018
getInt32(const char * key,int32_t * value)1019 bool getInt32(const char *key, int32_t *value) const {
1020 return get(key, value);
1021 }
getInt64(const char * key,int64_t * value)1022 bool getInt64(const char *key, int64_t *value) const {
1023 return get(key, value);
1024 }
getDouble(const char * key,double * value)1025 bool getDouble(const char *key, double *value) const {
1026 return get(key, value);
1027 }
getRate(const char * key,int64_t * count,int64_t * duration,double * rate)1028 bool getRate(const char *key, int64_t *count, int64_t *duration, double *rate) const {
1029 std::pair<int64_t, int64_t> value;
1030 if (!get(key, &value)) return false;
1031 if (count != nullptr) *count = value.first;
1032 if (duration != nullptr) *duration = value.second;
1033 if (rate != nullptr) {
1034 if (value.second != 0) {
1035 *rate = (double)value.first / value.second; // TODO: isn't INF OK?
1036 } else {
1037 *rate = 0.;
1038 }
1039 }
1040 return true;
1041 }
getString(const char * key,std::string * value)1042 bool getString(const char *key, std::string *value) const {
1043 return get(key, value);
1044 }
1045 // Caller owns the returned string
getCString(const char * key,char ** value)1046 bool getCString(const char *key, char **value) const {
1047 std::string s;
1048 if (get(key, &s)) {
1049 *value = strdup(s.c_str());
1050 return true;
1051 }
1052 return false;
1053 }
1054
get(const char * key)1055 const Prop::Elem* get(const char *key) const {
1056 const Prop *prop = findProp(key);
1057 return prop == nullptr ? nullptr : &prop->get();
1058 }
1059
1060 // Deliver the item to MediaMetrics
1061 bool selfrecord();
1062
1063 // remove indicated attributes and their values
1064 // filterNot() could also be called keepOnly()
1065 // return value is # attributes removed
1066 // XXX: perhaps 'remove' instead of 'filter'
1067 // XXX: filterNot would become 'keep'
1068 size_t filter(size_t count, const char *attrs[]);
1069 size_t filterNot(size_t count, const char *attrs[]);
filter(const char * attr)1070 size_t filter(const char *attr) { return filter(1, &attr); }
1071
1072 // below here are used on server side or to talk to server
1073 // clients need not worry about these.
1074
1075 // timestamp, pid, and uid only used on server side
1076 // timestamp is in 'nanoseconds, unix time'
1077 Item &setTimestamp(nsecs_t);
1078 nsecs_t getTimestamp() const;
1079
1080 Item &setPid(pid_t);
1081 pid_t getPid() const;
1082
1083 Item &setUid(uid_t);
1084 uid_t getUid() const;
1085
1086 Item &setPkgName(const std::string &pkgName);
getPkgName()1087 std::string getPkgName() const { return mPkgName; }
1088
1089 Item &setPkgVersionCode(int64_t);
1090 int64_t getPkgVersionCode() const;
1091
1092 // our serialization code for binder calls
1093 status_t writeToParcel(Parcel *) const;
1094 status_t readFromParcel(const Parcel&);
1095
1096 status_t writeToByteString(char **bufferptr, size_t *length) const;
1097 status_t readFromByteString(const char *bufferptr, size_t length);
1098
1099
1100 std::string toString() const;
1101 const char *toCString();
1102
1103 /**
1104 * Returns true if the item has a property with a target value.
1105 *
1106 * If propName is nullptr, hasPropElem() returns false.
1107 *
1108 * \param propName is the property name.
1109 * \param elem is the value to match. std::monostate matches any.
1110 */
hasPropElem(const char * propName,const Prop::Elem & elem)1111 bool hasPropElem(const char *propName, const Prop::Elem& elem) const {
1112 if (propName == nullptr) return false;
1113 const Prop::Elem *e = get(propName);
1114 return e != nullptr && (std::holds_alternative<std::monostate>(elem) || elem == *e);
1115 }
1116
1117 /**
1118 * Returns -2, -1, 0 (success) if the item has a property (wildcard matched) with a
1119 * target value.
1120 *
1121 * The enum RecursiveWildcardCheck designates the meaning of the returned value.
1122 *
1123 * RECURSIVE_WILDCARD_CHECK_NO_MATCH_NO_WILDCARD = -2,
1124 * RECURSIVE_WILDCARD_CHECK_NO_MATCH_WILDCARD_FOUND = -1,
1125 * RECURSIVE_WILDCARD_CHECK_MATCH_FOUND = 0.
1126 *
1127 * If url is nullptr, RECURSIVE_WILDCARD_CHECK_NO_MATCH_NO_WILDCARD is returned.
1128 *
1129 * \param url is the full item + property name, which may have wildcards '*'
1130 * denoting an arbitrary sequence of 0 or more characters.
1131 * \param elem is the target property value to match. std::monostate matches any.
1132 * \return 0 if the property was matched,
1133 * -1 if the property was not matched and a wildcard char was encountered,
1134 * -2 if the property was not matched with no wildcard char encountered.
1135 */
1136 enum RecursiveWildcardCheck {
1137 RECURSIVE_WILDCARD_CHECK_NO_MATCH_NO_WILDCARD = -2,
1138 RECURSIVE_WILDCARD_CHECK_NO_MATCH_WILDCARD_FOUND = -1,
1139 RECURSIVE_WILDCARD_CHECK_MATCH_FOUND = 0,
1140 };
1141
recursiveWildcardCheckElem(const char * url,const Prop::Elem & elem)1142 enum RecursiveWildcardCheck recursiveWildcardCheckElem(
1143 const char *url, const Prop::Elem& elem) const {
1144 if (url == nullptr) return RECURSIVE_WILDCARD_CHECK_NO_MATCH_NO_WILDCARD;
1145 return recursiveWildcardCheckElem(getKey().c_str(), url, elem);
1146 }
1147
1148 private:
1149
recursiveWildcardCheckElem(const char * itemKeyPtr,const char * url,const Prop::Elem & elem)1150 enum RecursiveWildcardCheck recursiveWildcardCheckElem(
1151 const char *itemKeyPtr, const char *url, const Prop::Elem& elem) const {
1152 for (; *url && *itemKeyPtr; ++url, ++itemKeyPtr) {
1153 if (*url != *itemKeyPtr) {
1154 if (*url == '*') { // wildcard
1155 ++url;
1156 while (true) {
1157 if (recursiveWildcardCheckElem(itemKeyPtr, url, elem)
1158 == RECURSIVE_WILDCARD_CHECK_MATCH_FOUND) {
1159 return RECURSIVE_WILDCARD_CHECK_MATCH_FOUND;
1160 }
1161 if (*itemKeyPtr == 0) break;
1162 ++itemKeyPtr;
1163 }
1164 return RECURSIVE_WILDCARD_CHECK_NO_MATCH_WILDCARD_FOUND;
1165 }
1166 return RECURSIVE_WILDCARD_CHECK_NO_MATCH_NO_WILDCARD;
1167 }
1168 }
1169 if (itemKeyPtr[0] != 0 || url[0] != '.') {
1170 return RECURSIVE_WILDCARD_CHECK_NO_MATCH_NO_WILDCARD;
1171 }
1172 const char *propName = url + 1; // skip the '.'
1173 return hasPropElem(propName, elem)
1174 ? RECURSIVE_WILDCARD_CHECK_MATCH_FOUND
1175 : RECURSIVE_WILDCARD_CHECK_NO_MATCH_NO_WILDCARD;
1176 }
1177
1178 // handle Parcel version 0
1179 int32_t writeToParcel0(Parcel *) const;
1180 int32_t readFromParcel0(const Parcel&);
1181
findProp(const char * key)1182 const Prop *findProp(const char *key) const {
1183 auto it = mProps.find(key);
1184 return it != mProps.end() ? &it->second : nullptr;
1185 }
1186
findOrAllocateProp(const char * key)1187 Prop &findOrAllocateProp(const char *key) {
1188 auto it = mProps.find(key);
1189 if (it != mProps.end()) return it->second;
1190 Prop &prop = mProps[key];
1191 prop.setName(key);
1192 return prop;
1193 }
1194
1195 // Changes to member variables below require changes to clear().
1196 pid_t mPid = -1;
1197 uid_t mUid = -1;
1198 std::string mPkgName;
1199 int64_t mPkgVersionCode = 0;
1200 std::string mKey;
1201 nsecs_t mTimestamp = 0;
1202 std::map<std::string, Prop> mProps;
1203 };
1204
1205 } // namespace mediametrics
1206 } // namespace android
1207
1208 #endif // ANDROID_MEDIA_MEDIAMETRICSITEM_H
1209