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