pixelstats: Add a listener for GPU uevents

The GPU driver (mali) can send uevents with GPU_UEVENT_TYPE and
GPU_UEVENT_INFO env. Report these from pixelstats.

Bug: 275367216
Bug: 276704984
Change-Id: I550ab58f426fe2961c3b3f5935df2c420005fde8
Signed-off-by: Varad Gautam <varadgautam@google.com>
Test: b/276704984
diff --git a/pixelstats/UeventListener.cpp b/pixelstats/UeventListener.cpp
index 07c8c95..8af43a0 100644
--- a/pixelstats/UeventListener.cpp
+++ b/pixelstats/UeventListener.cpp
@@ -66,6 +66,7 @@
 using android::sp;
 using android::base::ReadFileToString;
 using android::base::WriteStringToFile;
+using android::hardware::google::pixel::PixelAtoms::GpuEvent;
 using android::hardware::google::pixel::PixelAtoms::PdVidPid;
 using android::hardware::google::pixel::PixelAtoms::VendorHardwareFailed;
 using android::hardware::google::pixel::PixelAtoms::VendorUsbPortOverheat;
@@ -271,6 +272,34 @@
     }
 }
 
+void UeventListener::ReportGpuEvent(const std::shared_ptr<IStats> &stats_client, const char *driver,
+                                    const char *gpu_event_type, const char *gpu_event_info) {
+    if (!stats_client || !driver || strncmp(driver, "DRIVER=mali", strlen("DRIVER=mali")) ||
+        !gpu_event_type || !gpu_event_info)
+        return;
+
+    std::vector<std::string> type = android::base::Split(gpu_event_type, "=");
+    std::vector<std::string> info = android::base::Split(gpu_event_info, "=");
+
+    if (type.size() != 2 || info.size() != 2)
+        return;
+
+    if (type[0] != "GPU_UEVENT_TYPE" || info[0] != "GPU_UEVENT_INFO")
+        return;
+
+    auto event_type = kGpuEventTypeStrToEnum.find(type[1]);
+    auto event_info = kGpuEventInfoStrToEnum.find(info[1]);
+    if (event_type == kGpuEventTypeStrToEnum.end() || event_info == kGpuEventInfoStrToEnum.end())
+        return;
+
+    VendorAtom event = {.reverseDomainName = "",
+                        .atomId = PixelAtoms::Atom::kGpuEvent,
+                        .values = {event_type->second, event_info->second}};
+    const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
+    if (!ret.isOk())
+        ALOGE("Unable to report GPU event.");
+}
+
 bool UeventListener::ProcessUevent() {
     char msg[UEVENT_MSG_LEN + 2];
     char *cp;
@@ -278,6 +307,7 @@
     const char *mic_break_status, *mic_degrade_status;
     const char *devpath;
     bool collect_partner_id = false;
+    const char *gpu_event_type = nullptr, *gpu_event_info = nullptr;
     int n;
 
     if (uevent_fd_ < 0) {
@@ -333,6 +363,10 @@
             subsystem = cp;
         } else if (!strncmp(cp, kTypeCPartnerUevent.c_str(), kTypeCPartnerUevent.size())) {
             collect_partner_id = true;
+        } else if (!strncmp(cp, "GPU_UEVENT_TYPE=", strlen("GPU_UEVENT_TYPE="))) {
+            gpu_event_type = cp;
+        } else if (!strncmp(cp, "GPU_UEVENT_INFO=", strlen("GPU_UEVENT_INFO="))) {
+            gpu_event_info = cp;
         }
         /* advance to after the next \0 */
         while (*cp++) {
@@ -352,6 +386,7 @@
         if (collect_partner_id) {
             ReportTypeCPartnerId(stats_client);
         }
+        ReportGpuEvent(stats_client, driver, gpu_event_type, gpu_event_info);
     }
 
     if (log_fd_ > 0) {
diff --git a/pixelstats/include/pixelstats/UeventListener.h b/pixelstats/include/pixelstats/UeventListener.h
index 5316afa..352beb8 100644
--- a/pixelstats/include/pixelstats/UeventListener.h
+++ b/pixelstats/include/pixelstats/UeventListener.h
@@ -88,6 +88,8 @@
     void ReportBatteryCapacityFGEvent(const std::shared_ptr<IStats> &stats_client,
                                       const char *subsystem);
     void ReportTypeCPartnerId(const std::shared_ptr<IStats> &stats_client);
+    void ReportGpuEvent(const std::shared_ptr<IStats> &stats_client, const char *driver,
+                        const char *gpu_event_type, const char *gpu_event_info);
 
     const std::string kAudioUevent;
     const std::string kBatterySSOCPath;
@@ -97,6 +99,47 @@
     const std::string kTypeCPartnerVidPath;
     const std::string kTypeCPartnerPidPath;
 
+    const std::unordered_map<std::string, PixelAtoms::GpuEvent::GpuEventType>
+            kGpuEventTypeStrToEnum{
+                    {"KMD_ERROR",
+                     PixelAtoms::GpuEvent::GpuEventType::GpuEvent_GpuEventType_MALI_KMD_ERROR},
+                    {"GPU_RESET",
+                     PixelAtoms::GpuEvent::GpuEventType::GpuEvent_GpuEventType_MALI_GPU_RESET}};
+
+    const std::unordered_map<std::string, PixelAtoms::GpuEvent::GpuEventInfo>
+            kGpuEventInfoStrToEnum{
+                    {"CSG_REQ_STATUS_UPDATE",
+                     PixelAtoms::GpuEvent::GpuEventInfo::
+                             GpuEvent_GpuEventInfo_MALI_CSG_REQ_STATUS_UPDATE},
+                    {"CSG_SUSPEND",
+                     PixelAtoms::GpuEvent::GpuEventInfo::GpuEvent_GpuEventInfo_MALI_CSG_SUSPEND},
+                    {"CSG_SLOTS_SUSPEND", PixelAtoms::GpuEvent::GpuEventInfo::
+                                                  GpuEvent_GpuEventInfo_MALI_CSG_SLOTS_SUSPEND},
+                    {"CSG_GROUP_SUSPEND", PixelAtoms::GpuEvent::GpuEventInfo::
+                                                  GpuEvent_GpuEventInfo_MALI_CSG_GROUP_SUSPEND},
+                    {"CSG_EP_CFG",
+                     PixelAtoms::GpuEvent::GpuEventInfo::GpuEvent_GpuEventInfo_MALI_CSG_EP_CFG},
+                    {"CSG_SLOTS_START", PixelAtoms::GpuEvent::GpuEventInfo::
+                                                GpuEvent_GpuEventInfo_MALI_CSG_SLOTS_START},
+                    {"GROUP_TERM",
+                     PixelAtoms::GpuEvent::GpuEventInfo::GpuEvent_GpuEventInfo_MALI_GROUP_TERM},
+                    {"QUEUE_START",
+                     PixelAtoms::GpuEvent::GpuEventInfo::GpuEvent_GpuEventInfo_MALI_QUEUE_START},
+                    {"QUEUE_STOP",
+                     PixelAtoms::GpuEvent::GpuEventInfo::GpuEvent_GpuEventInfo_MALI_QUEUE_STOP},
+                    {"QUEUE_STOP_ACK",
+                     PixelAtoms::GpuEvent::GpuEventInfo::GpuEvent_GpuEventInfo_MALI_QUEUE_STOP_ACK},
+                    {"CSG_SLOT_READY",
+                     PixelAtoms::GpuEvent::GpuEventInfo::GpuEvent_GpuEventInfo_MALI_CSG_SLOT_READY},
+                    {"L2_PM_TIMEOUT",
+                     PixelAtoms::GpuEvent::GpuEventInfo::GpuEvent_GpuEventInfo_MALI_L2_PM_TIMEOUT},
+                    {"PM_TIMEOUT",
+                     PixelAtoms::GpuEvent::GpuEventInfo::GpuEvent_GpuEventInfo_MALI_PM_TIMEOUT},
+                    {"CSF_RESET_OK",
+                     PixelAtoms::GpuEvent::GpuEventInfo::GpuEvent_GpuEventInfo_MALI_CSF_RESET_OK},
+                    {"CSF_RESET_FAILED", PixelAtoms::GpuEvent::GpuEventInfo::
+                                                 GpuEvent_GpuEventInfo_MALI_CSF_RESET_FAILED}};
+
     BatteryCapacityReporter battery_capacity_reporter_;
     ChargeStatsReporter charge_stats_reporter_;