• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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