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