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