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