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