MediaMetrics: Change dumpsys format
As the dumpsys no longer needs to be parseable by a program
convert to a more human readable form.
1) Make default time REALTIME consistently.
2) Dump time as a human readable string.
3) Remove dumpsys versioning code.
4) Delimiter changes.
Test: atest mediametrics_tests
Test: adb shell dumpsys media.metrics
Bug: 138583596
Change-Id: I6ee7d81a18e0e220b258c722d232c05805118abb
diff --git a/media/libmediametrics/MediaMetricsItem.cpp b/media/libmediametrics/MediaMetricsItem.cpp
index 62af0f7..4371668 100644
--- a/media/libmediametrics/MediaMetricsItem.cpp
+++ b/media/libmediametrics/MediaMetricsItem.cpp
@@ -210,31 +210,66 @@
}
const char *mediametrics::Item::toCString() {
- return toCString(PROTO_LAST);
-}
-
-const char * mediametrics::Item::toCString(int version) {
- std::string val = toString(version);
+ std::string val = toString();
return strdup(val.c_str());
}
-std::string mediametrics::Item::toString() const {
- return toString(PROTO_LAST);
+/*
+ * Similar to audio_utils/clock.h but customized for displaying mediametrics time.
+ */
+
+void nsToString(int64_t ns, char *buffer, size_t bufferSize, PrintFormat format)
+{
+ if (bufferSize == 0) return;
+
+ const int one_second = 1000000000;
+ const time_t sec = ns / one_second;
+ struct tm tm;
+
+ // Supported on bionic, glibc, and macOS, but not mingw.
+ if (localtime_r(&sec, &tm) == NULL) {
+ buffer[0] = '\0';
+ return;
+ }
+
+ switch (format) {
+ default:
+ case kPrintFormatLong:
+ if (snprintf(buffer, bufferSize, "%02d-%02d %02d:%02d:%02d.%03d",
+ tm.tm_mon + 1, // localtime_r uses months in 0 - 11 range
+ tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
+ (int)(ns % one_second / 1000000)) < 0) {
+ buffer[0] = '\0'; // null terminate on format error, which should not happen
+ }
+ break;
+ case kPrintFormatShort:
+ if (snprintf(buffer, bufferSize, "%02d:%02d:%02d.%03d",
+ tm.tm_hour, tm.tm_min, tm.tm_sec,
+ (int)(ns % one_second / 1000000)) < 0) {
+ buffer[0] = '\0'; // null terminate on format error, which should not happen
+ }
+ break;
+ }
}
-std::string mediametrics::Item::toString(int version) const {
+std::string mediametrics::Item::toString() const {
std::string result;
char buffer[kMaxPropertyStringSize];
- snprintf(buffer, sizeof(buffer), "[%d:%s:%d:%d:%lld:%s:%zu:",
- version, mKey.c_str(), mPid, mUid, (long long)mTimestamp,
- mPkgName.c_str(), mProps.size());
+ snprintf(buffer, sizeof(buffer), "{%s, (%s), (%s, %d, %d)",
+ mKey.c_str(),
+ timeStringFromNs(mTimestamp, kPrintFormatLong).time,
+ mPkgName.c_str(), mPid, mUid
+ );
result.append(buffer);
+ bool first = true;
for (auto &prop : *this) {
prop.toStringBuffer(buffer, sizeof(buffer));
- result.append(buffer);
+ result += first ? ", (" : ", ";
+ result += buffer;
+ first = false;
}
- result.append("]");
+ result.append(")}");
return result;
}
diff --git a/media/libmediametrics/include/media/MediaMetricsItem.h b/media/libmediametrics/include/media/MediaMetricsItem.h
index 6141b36..b40eb4c 100644
--- a/media/libmediametrics/include/media/MediaMetricsItem.h
+++ b/media/libmediametrics/include/media/MediaMetricsItem.h
@@ -149,6 +149,85 @@
kTypeRate = 5,
};
+/*
+ * Time printing
+ *
+ * kPrintFormatLong time string is 19 characters (including null termination).
+ * Example Long Form: "03-27 16:47:06.187"
+ * MM DD HH MM SS MS
+ *
+ * kPrintFormatShort time string is 13 characters (including null termination).
+ * Example Short Form: "16:47:06.187"
+ * HH MM SS MS
+ */
+
+enum PrintFormat {
+ kPrintFormatLong = 0,
+ kPrintFormatShort = 1,
+};
+
+/**
+ * Converts real time in ns to a time string object, with format similar to logcat.
+ *
+ * \param ns input real time in nanoseconds to convert.
+ * \param buffer the buffer location to put the converted string.
+ * \param bufferSize the size of buffer in bytes.
+ * \param format format, from enum PrintFormat.
+ */
+void nsToString(
+ int64_t ns, char *buffer, size_t bufferSize, PrintFormat format = kPrintFormatLong);
+
+// Contains the time string
+struct time_string_t {
+ char time[19]; /* minimum size buffer */
+};
+
+/**
+ * Converts real time in ns to a time string object, with format similar to logcat.
+ *
+ * \param ns input real time in nanoseconds to convert.
+ * \param format format, from enum PrintFormat.
+ * \return a time_string_t object with the time string encoded.
+ */
+static inline time_string_t timeStringFromNs(int64_t ns, PrintFormat format = kPrintFormatLong) {
+ time_string_t ts;
+ nsToString(ns, ts.time, sizeof(ts.time), format);
+ return ts;
+}
+
+/**
+ * Finds the end of the common time prefix.
+ *
+ * This is as an option to remove the common time prefix to avoid
+ * unnecessary duplicated strings.
+ *
+ * \param time1 a time string from timeStringFromNs
+ * \param time2 a time string from timeStringFromNs
+ * \return the position where the common time prefix ends. For abbreviated
+ * printing of time2, offset the character pointer by this position.
+ */
+static inline size_t commonTimePrefixPosition(const char *time1, const char *time2) {
+ size_t i;
+
+ // Find location of the first mismatch between strings
+ for (i = 0; ; ++i) {
+ if (time1[i] != time2[i]) {
+ break;
+ }
+ if (time1[i] == 0) {
+ return i; // strings match completely
+ }
+ }
+
+ // Go backwards until we find a delimeter or space.
+ for (; i > 0
+ && isdigit(time1[i]) // still a number
+ && time1[i - 1] != ' '
+ ; --i) {
+ }
+ return i;
+}
+
/**
* The MediaMetrics Item has special Item properties,
* derived internally or through dedicated setters.
@@ -341,35 +420,35 @@
template <> // static
void toStringBuffer(
const char *name, const int32_t& value, char *buffer, size_t length) {
- snprintf(buffer, length, "%s=%d:", name, value);
+ snprintf(buffer, length, "%s=%d", name, value);
}
template <> // static
void toStringBuffer(
const char *name, const int64_t& value, char *buffer, size_t length) {
- snprintf(buffer, length, "%s=%lld:", name, (long long)value);
+ snprintf(buffer, length, "%s=%lld", name, (long long)value);
}
template <> // static
void toStringBuffer(
const char *name, const double& value, char *buffer, size_t length) {
- snprintf(buffer, length, "%s=%e:", name, value);
+ snprintf(buffer, length, "%s=%e", name, value);
}
template <> // static
void toStringBuffer(
const char *name, const std::pair<int64_t, int64_t>& value,
char *buffer, size_t length) {
- snprintf(buffer, length, "%s=%lld/%lld:",
+ snprintf(buffer, length, "%s=%lld/%lld",
name, (long long)value.first, (long long)value.second);
}
template <> // static
void toStringBuffer(
const char *name, const std::string& value, char *buffer, size_t length) {
// TODO sanitize string for ':' '='
- snprintf(buffer, length, "%s=%s:", name, value.c_str());
+ snprintf(buffer, length, "%s=%s", name, value.c_str());
}
template <> // static
void toStringBuffer(
const char *name, const std::monostate&, char *buffer, size_t length) {
- snprintf(buffer, length, "%s=():", name);
+ snprintf(buffer, length, "%s=()", name);
}
template <typename T>
@@ -839,13 +918,6 @@
return iterator(mProps.cend());
}
- enum {
- PROTO_V0 = 0,
- PROTO_FIRST = PROTO_V0,
- PROTO_V1 = 1,
- PROTO_LAST = PROTO_V1,
- };
-
// T must be convertible to mKey
template <typename T>
explicit Item(T key)
@@ -1043,9 +1115,7 @@
std::string toString() const;
- std::string toString(int version) const;
const char *toCString();
- const char *toCString(int version);
/**
* Returns true if the item has a property with a target value.