Game Driver Metrics: get gpu app stats with GpuStatsPuller

Bug: 123529932
Test: adb shell cmd stats pull-source 10055
Change-Id: I04320221de6ac457acd0b0533a05ce2f8dfbdde0
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 4856f77..69372cd 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -5759,7 +5759,7 @@
     optional string tzdb_version = 1;
 }
 
-/*
+/**
  * Logs the GPU stats global health information.
  *
  * Logged from:
@@ -5791,22 +5791,34 @@
     optional int64 vk_loading_failure_count = 8;
 }
 
-/*
+/**
+ * GPU driver loading time info.
+ */
+message GpuDriverLoadingTime {
+    // List of all the driver loading times for this app. The list size is
+    // capped at 50.
+    repeated int64 driver_loading_time = 1;
+}
+
+/**
  * Logs the GPU stats per app health information.
  *
  * Logged from:
  *   frameworks/native/services/gpuservice/gpustats/
  */
 message GpuStatsAppInfo {
-    // Package name of the application that loads the gpu driver.
+    // Package name of the application that loads the gpu driver. Total number
+    // of different packages is capped at 100.
     optional string app_package_name = 1;
 
     // Version code of the gpu driver this app loads.
     optional int64 driver_version_code = 2;
 
-    // List of all the gl driver loading times for this app.
-    repeated int64 gl_driver_loading_time = 3;
+    // gl driver loading time info.
+    optional GpuDriverLoadingTime gl_driver_loading_time = 3
+            [(android.os.statsd.log_mode) = MODE_BYTES];
 
-    // List of all the Vulkan driver laoding times for this app.
-    repeated int64 vk_driver_loading_time = 4;
+    // Vulkan driver loading time info.
+    optional GpuDriverLoadingTime vk_driver_loading_time = 4
+            [(android.os.statsd.log_mode) = MODE_BYTES];
 }
diff --git a/cmds/statsd/src/external/GpuStatsPuller.cpp b/cmds/statsd/src/external/GpuStatsPuller.cpp
index 8445803..130bd85 100644
--- a/cmds/statsd/src/external/GpuStatsPuller.cpp
+++ b/cmds/statsd/src/external/GpuStatsPuller.cpp
@@ -70,6 +70,30 @@
     return true;
 }
 
+static bool pullGpuStatsAppInfo(const sp<IGpuService>& gpuService,
+                                std::vector<std::shared_ptr<LogEvent>>* data) {
+    std::vector<GpuStatsAppInfo> stats;
+    status_t status = gpuService->getGpuStatsAppInfo(&stats);
+    if (status != OK) {
+        return false;
+    }
+
+    data->clear();
+    data->reserve(stats.size());
+    for (const auto& info : stats) {
+        std::shared_ptr<LogEvent> event = make_shared<LogEvent>(
+                android::util::GPU_STATS_APP_INFO, getWallClockNs(), getElapsedRealtimeNs());
+        if (!event->write(info.appPackageName)) return false;
+        if (!event->write((int64_t)info.driverVersionCode)) return false;
+        if (!event->write(int64VectorToProtoByteString(info.glDriverLoadingTime))) return false;
+        if (!event->write(int64VectorToProtoByteString(info.vkDriverLoadingTime))) return false;
+        event->init();
+        data->emplace_back(event);
+    }
+
+    return true;
+}
+
 bool GpuStatsPuller::PullInternal(std::vector<std::shared_ptr<LogEvent>>* data) {
     const sp<IGpuService> gpuService = getGpuService();
     if (!gpuService) {
@@ -79,6 +103,8 @@
     switch (mTagId) {
         case android::util::GPU_STATS_GLOBAL_INFO:
             return pullGpuStatsGlobalInfo(gpuService, data);
+        case android::util::GPU_STATS_APP_INFO:
+            return pullGpuStatsAppInfo(gpuService, data);
         default:
             break;
     }
@@ -86,6 +112,35 @@
     return false;
 }
 
+static std::string protoOutputStreamToByteString(ProtoOutputStream& proto) {
+    if (!proto.size()) return "";
+
+    std::string byteString;
+    auto iter = proto.data();
+    while (iter.readBuffer() != nullptr) {
+        const size_t toRead = iter.currentToRead();
+        byteString.append((char*)iter.readBuffer(), toRead);
+        iter.rp()->move(toRead);
+    }
+
+    if (byteString.size() != proto.size()) return "";
+
+    return byteString;
+}
+
+std::string int64VectorToProtoByteString(const std::vector<int64_t>& value) {
+    if (value.empty()) return "";
+
+    ProtoOutputStream proto;
+    for (const auto& ele : value) {
+        proto.write(android::util::FIELD_TYPE_INT64 | android::util::FIELD_COUNT_REPEATED |
+                            1 /* field id */,
+                    (long long)ele);
+    }
+
+    return protoOutputStreamToByteString(proto);
+}
+
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/statsd/src/external/GpuStatsPuller.h b/cmds/statsd/src/external/GpuStatsPuller.h
index 4c7a4d6..2da199c 100644
--- a/cmds/statsd/src/external/GpuStatsPuller.h
+++ b/cmds/statsd/src/external/GpuStatsPuller.h
@@ -31,6 +31,12 @@
     bool PullInternal(std::vector<std::shared_ptr<LogEvent>>* data) override;
 };
 
+// convert a int64_t vector into a byte string for proto message like:
+// message RepeatedInt64Wrapper {
+//   repeated int64 value = 1;
+// }
+std::string int64VectorToProtoByteString(const std::vector<int64_t>& value);
+
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index 924704b..4f87272 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -244,6 +244,9 @@
         // GpuStatsGlobalInfo
         {android::util::GPU_STATS_GLOBAL_INFO,
          {.puller = new GpuStatsPuller(android::util::GPU_STATS_GLOBAL_INFO)}},
+        // GpuStatsAppInfo
+        {android::util::GPU_STATS_APP_INFO,
+         {.puller = new GpuStatsPuller(android::util::GPU_STATS_APP_INFO)}},
 };
 
 StatsPullerManager::StatsPullerManager() : mNextPullTimeNs(NO_ALARM_UPDATE) {