Pixelstats: Upload PID/VID reported over USB PD for 1st party chargers

The CL uses standard type-c sysfs nodes(/sys/class/typec/<port>-partner/identity/:
https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-class-typec) to export the
PID/VID for google first party chargers through USB Power delivery spec.

Bug: 138061779
Test: Manually tested by running: adb shell cmd stats print-logs,
adb logcat | grep statsd | grep "105011"
Change-Id: Icc6e6db5b90c3f2c4deeec235f140532541d3d72
Merged-In: Icc6e6db5b90c3f2c4deeec235f140532541d3d72
diff --git a/pixelstats/UeventListener.cpp b/pixelstats/UeventListener.cpp
index f7b3c54..1a9c140 100644
--- a/pixelstats/UeventListener.cpp
+++ b/pixelstats/UeventListener.cpp
@@ -28,6 +28,7 @@
 #include <unistd.h>
 #include <utils/StrongPointer.h>
 
+#include <string>
 #include <thread>
 
 using android::sp;
@@ -40,6 +41,7 @@
 using android::hardware::google::pixel::WlcReporter;
 using android::hardware::google::pixel::PixelAtoms::ChargeStats;
 using android::hardware::google::pixel::PixelAtoms::VoltageTierStats;
+using android::hardware::google::pixel::PixelAtoms::PdVidPid;
 
 namespace android {
 namespace hardware {
@@ -47,6 +49,13 @@
 namespace pixel {
 
 constexpr int32_t UEVENT_MSG_LEN = 2048;  // it's 2048 in all other users.
+constexpr int32_t PRODUCT_TYPE_OFFSET = 23;
+constexpr int32_t PRODUCT_TYPE_MASK = 7;
+constexpr int32_t PRODUCT_TYPE_CHARGER = 3;
+constexpr int32_t VID_MASK = 0xffff;
+constexpr int32_t VID_GOOGLE = 0x18d1;
+constexpr int32_t PID_OFFSET = 2;
+constexpr int32_t PID_LENGTH = 4;
 
 bool UeventListener::ReadFileToInt(const std::string &path, int *val) {
     return ReadFileToInt(path.c_str(), val);
@@ -297,6 +306,66 @@
     battery_capacity_reporter_.checkAndReport(kBatterySSOCPath);
 }
 
+void UeventListener::ReportTypeCPartnerId() {
+    std::string file_contents_vid, file_contents_pid;
+    uint32_t pid, vid;
+
+    if (!ReadFileToString(kTypeCPartnerVidPath.c_str(), &file_contents_vid)) {
+        ALOGE("Unable to read %s - %s", kTypeCPartnerVidPath.c_str(), strerror(errno));
+        return;
+    }
+
+    if (sscanf(file_contents_vid.c_str(), "%x", &vid) != 1) {
+        ALOGE("Unable to parse vid %s from file %s to int.",
+                file_contents_vid.c_str(), kTypeCPartnerVidPath.c_str());
+        return;
+    }
+
+    if (!ReadFileToString(kTypeCPartnerPidPath.c_str(), &file_contents_pid)) {
+        ALOGE("Unable to read %s - %s", kTypeCPartnerPidPath.c_str(), strerror(errno));
+	    return;
+    }
+
+    if (sscanf(file_contents_pid.substr(PID_OFFSET, PID_LENGTH).c_str(), "%x", &pid) != 1) {
+        ALOGE("Unable to parse pid %s from file %s to int.",
+              file_contents_pid.substr(PID_OFFSET, PID_LENGTH).c_str(),
+              kTypeCPartnerPidPath.c_str());
+	return;
+    }
+
+    // Upload data only for chargers
+    if (((vid >> PRODUCT_TYPE_OFFSET) & PRODUCT_TYPE_MASK) != PRODUCT_TYPE_CHARGER) {
+        return;
+    }
+
+    // Upload data only for Google VID
+    if ((VID_MASK & vid) != VID_GOOGLE) {
+        return;
+    }
+
+    std::vector<VendorAtom::Value> values(2);
+    VendorAtom::Value tmp;
+
+    tmp.intValue(vid & VID_MASK);
+    values[PdVidPid::kVidFieldNumber - kVendorAtomOffset] = tmp;
+    tmp.intValue(pid);
+    values[PdVidPid::kPidFieldNumber - kVendorAtomOffset] = tmp;
+    sp<IStats> stats_client = IStats::tryGetService();
+    if (!stats_client) {
+        ALOGE("PD PID/VID Couldn't connect to IStats service");
+        return;
+    }
+
+    // Send vendor atom to IStats HAL
+    VendorAtom event = {.reverseDomainName = PixelAtoms::ReverseDomainNames().pixel(),
+             .atomId = PixelAtoms::Ids::PD_VID_PID,
+             .values = values};
+    Return<void> ret = stats_client->reportVendorAtom(event);
+    if (!ret.isOk()) {
+        ALOGE("Unable to report PD VID/PID to Stats service");
+    }
+}
+
 bool UeventListener::ProcessUevent() {
     char msg[UEVENT_MSG_LEN + 2];
     char *cp;
@@ -304,6 +373,7 @@
     const char *mic_break_status, *mic_degrade_status;
     const char *devpath;
     const char *powpresent;
+    bool collect_partner_id = false;
     int n;
 
     if (uevent_fd_ < 0) {
@@ -347,6 +417,8 @@
             powpresent = cp;
         } else if (!strncmp(cp, "SUBSYSTEM=", strlen("SUBSYSTEM="))) {
             subsystem = cp;
+        } else if (!strncmp(cp, "DEVTYPE=typec_partner", strlen("DEVTYPE=typec_partner"))) {
+            collect_partner_id = true;
         }
 
         /* advance to after the next \0 */
@@ -361,19 +433,25 @@
     ReportChargeMetricsEvent(driver);
     ReportWlc(powpresent);
     ReportBatteryCapacityFGEvent(subsystem);
+    if (collect_partner_id) {
+        ReportTypeCPartnerId();
+    }
 
     return true;
 }
 
 UeventListener::UeventListener(const std::string audio_uevent, const std::string ssoc_details_path,
                                const std::string overheat_path,
-                               const std::string charge_metrics_path)
+                               const std::string charge_metrics_path, const std::string
+                               typec_partner_vid_path, const std::string typec_partner_pid_path)
     : kAudioUevent(audio_uevent),
       kBatterySSOCPath(ssoc_details_path),
       kUsbPortOverheatPath(overheat_path),
       kChargeMetricsPath(charge_metrics_path),
+      kTypeCPartnerVidPath(typec_partner_vid_path),
+      kTypeCPartnerPidPath(typec_partner_pid_path),
       uevent_fd_(-1),
-      wireless_charging_state_(false) {}
+      wireless_charging_state_(false){}
 
 /* Thread function to continuously monitor uevents.
  * Exit after kMaxConsecutiveErrors to prevent spinning. */
diff --git a/pixelstats/include/pixelstats/UeventListener.h b/pixelstats/include/pixelstats/UeventListener.h
index 6ffcfb2..82dc14a 100644
--- a/pixelstats/include/pixelstats/UeventListener.h
+++ b/pixelstats/include/pixelstats/UeventListener.h
@@ -41,7 +41,9 @@
             const std::string audio_uevent, const std::string ssoc_details_path = "",
             const std::string overheat_path =
                     "/sys/devices/platform/soc/soc:google,overheat_mitigation",
-            const std::string charge_metrics_path = "/sys/class/power_supply/battery/charge_stats");
+            const std::string charge_metrics_path = "/sys/class/power_supply/battery/charge_stats",
+            const std::string typec_partner_vid_path = "/sys/class/typec/port0-partner/identity/id_header",
+            const std::string typec_partner_pid_path = "/sys/class/typec/port0-partner/identity/product");
 
     bool ProcessUevent();  // Process a single Uevent.
     void ListenForever();  // Process Uevents forever
@@ -57,11 +59,14 @@
     void ReportChargeMetricsEvent(const char *driver);
     void ReportWlc(const char *driver);
     void ReportBatteryCapacityFGEvent(const char *subsystem);
+    void ReportTypeCPartnerId();
 
     const std::string kAudioUevent;
     const std::string kBatterySSOCPath;
     const std::string kUsbPortOverheatPath;
     const std::string kChargeMetricsPath;
+    const std::string kTypeCPartnerVidPath;
+    const std::string kTypeCPartnerPidPath;
 
     BatteryCapacityReporter battery_capacity_reporter_;
 
diff --git a/pixelstats/pixelatoms.proto b/pixelstats/pixelatoms.proto
index dc2c32a..857e66f 100644
--- a/pixelstats/pixelatoms.proto
+++ b/pixelstats/pixelatoms.proto
@@ -45,6 +45,7 @@
     WIRELESS_CHARGING_STATS = 105008;
     DEVICE_ORIENTATION = 105009;
     FG_CAPACITY = 105010;
+    PD_VID_PID = 105011;
     // AOSP atom ID range ends at 109999
 }
 
@@ -250,3 +251,9 @@
     optional float capacity_ssoc_curve = 6;
 }
 
+message  PdVidPid {
+    /* Vendor ID of wired charger */
+    optional int32 vid = 2;
+    /* Product ID of wired charger */
+    optional int32 pid = 3;
+}