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