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