• Home
  • History
  • Annotate
  • 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  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