• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 /* If you are watching for a new uevent, uncomment the following define.
18  * After flashing your test build, run:
19  *    adb root && adb shell
20  *    stop vendor.pixelstats_vendor
21  *    touch /data/local/tmp/uevents
22  *    /vendor/bin/pixelstats-vendor &
23  *
24  *    then trigger any events.
25  *    If you leave adb connected, you can watch them with
26  *    tail -f /data/local/tmp/uevents
27  *
28  *    Once you are done,
29  *
30  *    adb pull /data/local/tmp/uevents
31  *    adb rm /data/local/tmp/uevents
32  *    adb reboot
33  *
34  *    provide this log in the bug as support for your feature.
35  */
36 // #define LOG_UEVENTS_TO_FILE_ONLY_FOR_DEVEL "/data/local/tmp/uevents"
37 
38 #define LOG_TAG "pixelstats-uevent"
39 
40 #include <android-base/file.h>
41 #include <android-base/logging.h>
42 #include <android-base/parseint.h>
43 #include <android-base/strings.h>
44 #include <android/binder_manager.h>
45 #include <cutils/uevent.h>
46 #include <fcntl.h>
47 #include <hardware/google/pixel/pixelstats/pixelatoms.pb.h>
48 #include <linux/thermal.h>
49 #include <log/log.h>
50 #include <pixelstats/JsonConfigUtils.h>
51 #include <pixelstats/StatsHelper.h>
52 #include <pixelstats/UeventListener.h>
53 #include <sys/stat.h>
54 #include <sys/types.h>
55 #include <unistd.h>
56 #include <utils/StrongPointer.h>
57 #include <fstream>
58 #include <iostream>
59 
60 #include <string>
61 #include <thread>
62 
63 namespace android {
64 namespace hardware {
65 namespace google {
66 namespace pixel {
67 
68 using aidl::android::frameworks::stats::VendorAtom;
69 using aidl::android::frameworks::stats::VendorAtomValue;
70 using android::sp;
71 using android::base::ReadFileToString;
72 using android::base::WriteStringToFile;
73 using android::hardware::google::pixel::PixelAtoms::GpuEvent;
74 using android::hardware::google::pixel::PixelAtoms::PdVidPid;
75 using android::hardware::google::pixel::PixelAtoms::ThermalSensorAbnormalityDetected;
76 using android::hardware::google::pixel::PixelAtoms::VendorHardwareFailed;
77 using android::hardware::google::pixel::PixelAtoms::VendorUsbPortOverheat;
78 using android::hardware::google::pixel::PixelAtoms::WaterEventReported;
79 
80 constexpr int32_t UEVENT_MSG_LEN = 2048;  // it's 2048 in all other users.
81 constexpr int32_t PRODUCT_TYPE_OFFSET = 23;
82 constexpr int32_t PRODUCT_TYPE_MASK = 7;
83 constexpr int32_t PRODUCT_TYPE_CHARGER = 3;
84 constexpr int32_t VID_MASK = 0xffff;
85 constexpr int32_t VID_GOOGLE = 0x18d1;
86 constexpr int32_t PID_OFFSET = 2;
87 constexpr int32_t PID_LENGTH = 4;
88 constexpr uint32_t PID_P30 = 0x4f05;
89 constexpr const char *THERMAL_ABNORMAL_INFO_EQ = "THERMAL_ABNORMAL_INFO=";
90 constexpr const char *THERMAL_ABNORMAL_TYPE_EQ = "THERMAL_ABNORMAL_TYPE=";
91 
ReadFileToInt(const std::string & path,int * val)92 bool UeventListener::ReadFileToInt(const std::string &path, int *val) {
93     return ReadFileToInt(path.c_str(), val);
94 }
95 
ReadFileToInt(const char * const path,int * val)96 bool UeventListener::ReadFileToInt(const char *const path, int *val) {
97     std::string file_contents;
98 
99     if (!ReadFileToString(path, &file_contents)) {
100         ALOGE("Unable to read %s - %s", path, strerror(errno));
101         return false;
102     } else if (sscanf(file_contents.c_str(), "%d", val) != 1) {
103         ALOGE("Unable to convert %s to int - %s", path, strerror(errno));
104         return false;
105     }
106     return true;
107 }
108 
ReportMicBrokenOrDegraded(const std::shared_ptr<IStats> & stats_client,const int mic,const bool isbroken)109 void UeventListener::ReportMicBrokenOrDegraded(const std::shared_ptr<IStats> &stats_client,
110                                                const int mic, const bool isbroken) {
111     VendorHardwareFailed failure;
112     failure.set_hardware_type(VendorHardwareFailed::HARDWARE_FAILED_MICROPHONE);
113     failure.set_hardware_location(mic);
114     failure.set_failure_code(isbroken ? VendorHardwareFailed::COMPLETE
115                                       : VendorHardwareFailed::DEGRADE);
116     reportHardwareFailed(stats_client, failure);
117 }
118 
ReportMicStatusUevents(const std::shared_ptr<IStats> & stats_client,const char * devpath,const char * mic_status)119 void UeventListener::ReportMicStatusUevents(const std::shared_ptr<IStats> &stats_client,
120                                             const char *devpath, const char *mic_status) {
121     if (!devpath || !mic_status)
122         return;
123 
124     std::string audioUevent = getCStringOrDefault(configData, "AudioUevent");
125 
126     if (audioUevent.empty()) {
127         ALOGV("audioUevent not specified in JSON");
128     }
129 
130     if (!strcmp(devpath, ("DEVPATH=" + audioUevent).c_str())) {
131         std::vector<std::string> value = android::base::Split(mic_status, "=");
132         bool isbroken;
133 
134         if (value.size() == 2) {
135             if (!value[0].compare("MIC_BREAK_STATUS"))
136                 isbroken = true;
137             else if (!value[0].compare("MIC_DEGRADE_STATUS"))
138                 isbroken = false;
139             else
140                 return;
141 
142             if (!value[1].compare("true")) {
143                 ReportMicBrokenOrDegraded(stats_client, 0, isbroken);
144             } else {
145                 int mic_status = atoi(value[1].c_str());
146 
147                 if (mic_status > 0 && mic_status <= 7) {
148                     for (int mic_bit = 0; mic_bit < 3; mic_bit++)
149                         if (mic_status & (0x1 << mic_bit))
150                             ReportMicBrokenOrDegraded(stats_client, mic_bit, isbroken);
151                 } else if (mic_status == 0) {
152                     // mic is ok
153                     return;
154                 } else {
155                     // should not enter here
156                     ALOGE("invalid mic status");
157                     return;
158                 }
159             }
160         }
161     }
162 }
163 
ReportUsbPortOverheatEvent(const std::shared_ptr<IStats> & stats_client,const char * driver)164 void UeventListener::ReportUsbPortOverheatEvent(const std::shared_ptr<IStats> &stats_client,
165                                                 const char *driver) {
166 
167     std::string usbPortOverheatPath = getCStringOrDefault(configData, "UsbPortOverheatPath");
168 
169     if (usbPortOverheatPath.empty()) {
170         ALOGV("usbPortOverheatPath not specified in JSON");
171         usbPortOverheatPath = overheat_path_default;
172     }
173     if (!driver || strcmp(driver, "DRIVER=google,overheat_mitigation")) {
174         return;
175     }
176 
177     int32_t plug_temperature_deci_c = 0;
178     int32_t max_temperature_deci_c = 0;
179     int32_t time_to_overheat_secs = 0;
180     int32_t time_to_hysteresis_secs = 0;
181     int32_t time_to_inactive_secs = 0;
182 
183     // TODO(achant b/182941868): test return value and skip reporting in case of an error
184     ReadFileToInt((usbPortOverheatPath + "/plug_temp"), &plug_temperature_deci_c);
185     ReadFileToInt((usbPortOverheatPath + "/max_temp"), &max_temperature_deci_c);
186     ReadFileToInt((usbPortOverheatPath + "/trip_time"), &time_to_overheat_secs);
187     ReadFileToInt((usbPortOverheatPath + "/hysteresis_time"), &time_to_hysteresis_secs);
188     ReadFileToInt((usbPortOverheatPath + "/cleared_time"), &time_to_inactive_secs);
189 
190     VendorUsbPortOverheat overheat_info;
191     overheat_info.set_plug_temperature_deci_c(plug_temperature_deci_c);
192     overheat_info.set_max_temperature_deci_c(max_temperature_deci_c);
193     overheat_info.set_time_to_overheat_secs(time_to_overheat_secs);
194     overheat_info.set_time_to_hysteresis_secs(time_to_hysteresis_secs);
195     overheat_info.set_time_to_inactive_secs(time_to_inactive_secs);
196 
197     reportUsbPortOverheat(stats_client, overheat_info);
198 }
199 
ReportChargeMetricsEvent(const std::shared_ptr<IStats> & stats_client,const char * driver)200 void UeventListener::ReportChargeMetricsEvent(const std::shared_ptr<IStats> &stats_client,
201                                               const char *driver) {
202 
203     std::string chargeMetricsPath = getCStringOrDefault(configData, "ChargeMetricsPath");
204 
205     if (chargeMetricsPath.empty()) {
206         ALOGV("chargeMetricsPath not specified in JSON");
207         chargeMetricsPath = charge_metrics_path_default;
208     }
209     if (!driver || strcmp(driver, "DRIVER=google,battery")) {
210         return;
211     }
212 
213     charge_stats_reporter_.checkAndReport(stats_client, chargeMetricsPath);
214 }
215 
ReportFGMetricsEvent(const std::shared_ptr<IStats> & stats_client,const char * driver)216 void UeventListener::ReportFGMetricsEvent(const std::shared_ptr<IStats> &stats_client,
217                                           const char *driver) {
218     if (!driver || strcmp(driver, "DRIVER=max77779-fg"))
219         return;
220 
221     std::vector<std::string> FGAbnlPath = {""};
222     if (configData.isMember("FGAbnlPath")) {
223         FGAbnlPath = readStringVectorFromJson(configData["FGAbnlPath"]);
224     } else {
225         ALOGV("FGAbnlPath not specified in JSON");
226     }
227     battery_fg_reporter_.checkAndReportFGAbnormality(stats_client, FGAbnlPath);
228 }
229 
ReportFwUpdateEvent(const std::shared_ptr<IStats> & stats_client,const char * driver)230 void UeventListener::ReportFwUpdateEvent(const std::shared_ptr<IStats> &stats_client,
231                                          const char *driver) {
232     if (!driver || strcmp(driver, "DRIVER=max77779-fg"))
233         return;
234 
235     std::vector<std::string> FwUpdatePath = {""};
236     if (configData.isMember("FwUpdatePath")) {
237         FwUpdatePath = readStringVectorFromJson(configData["FwUpdatePath"]);
238     } else {
239         ALOGV("FwUpdatePath not specified in JSON");
240     }
241     battery_fw_update_reporter_.checkAndReportFwUpdate(stats_client, FwUpdatePath, EvtFwUpdate);
242 }
ReportWlcFwUpdateEvent(const std::shared_ptr<IStats> & stats_client,const char * driver)243 void UeventListener::ReportWlcFwUpdateEvent(const std::shared_ptr<IStats> &stats_client,
244                                             const char *driver) {
245     if (!driver || strcmp(driver, "DRIVER=google_wlc"))
246         return;
247 
248     std::vector<std::string> FwUpdatePath = {""};
249     if (configData.isMember("FwUpdatePath")) {
250         FwUpdatePath = readStringVectorFromJson(configData["FwUpdatePath"]);
251     } else {
252         ALOGV("FwUpdatePath not specified in JSON");
253     }
254     battery_fw_update_reporter_.checkAndReportFwUpdate(stats_client, FwUpdatePath, EvtWlcFwUpdate);
255 }
256 /**
257  * Report raw battery capacity, system battery capacity and associated
258  * battery capacity curves. This data is collected to verify the filter
259  * applied on the battery capacity. This will allow debugging of issues
260  * ranging from incorrect fuel gauge hardware calculations to issues
261  * with the software reported battery capacity.
262  *
263  * The data is retrieved by parsing the battery power supply's ssoc_details.
264  *
265  * This atom logs data in 5 potential events:
266  *      1. When a device is connected
267  *      2. When a device is disconnected
268  *      3. When a device has reached a full charge (from the UI's perspective)
269  *      4. When there is a >= 2 percent skip in the UI reported SOC
270  *      5. When there is a difference of >= 4 percent between the raw hardware
271  *          battery capacity and the system reported battery capacity.
272  */
ReportBatteryCapacityFGEvent(const std::shared_ptr<IStats> & stats_client,const char * subsystem)273 void UeventListener::ReportBatteryCapacityFGEvent(const std::shared_ptr<IStats> &stats_client,
274                                                   const char *subsystem) {
275     if (!subsystem || strcmp(subsystem, "SUBSYSTEM=power_supply")) {
276         return;
277     }
278 
279     std::string batterySSOCPath = getCStringOrDefault(configData, "BatterySSOCPath");
280 
281     // Indicates an implicit disable of the battery capacity reporting
282     if (batterySSOCPath.empty()) {
283         ALOGV("batterySSOCPath not specified in JSON");
284         batterySSOCPath = ssoc_details_path;
285     }
286 
287     battery_capacity_reporter_.checkAndReport(stats_client, batterySSOCPath);
288 }
289 
ReportTypeCPartnerId(const std::shared_ptr<IStats> & stats_client)290 void UeventListener::ReportTypeCPartnerId(const std::shared_ptr<IStats> &stats_client) {
291     std::string file_contents_vid, file_contents_pid;
292     uint32_t pid, vid;
293 
294     std::string typeCPartnerVidPath = getCStringOrDefault(configData, "TypeCPartnerVidPath");
295     std::string typeCPartnerPidPath = getCStringOrDefault(configData, "TypeCPartnerPidPath");
296 
297 
298     if (typeCPartnerVidPath.empty()) {
299         ALOGV("typeCPartnerVidPath not specified in JSON");
300         typeCPartnerPidPath = typec_partner_vid_path_default;
301     }
302     if (typeCPartnerPidPath.empty()) {
303         ALOGV("typeCPartnerPidPath not specified in JSON");
304         typeCPartnerPidPath = typec_partner_pid_path_default;
305     }
306 
307     if (!ReadFileToString(typeCPartnerVidPath.c_str(), &file_contents_vid)) {
308         ALOGE("Unable to read %s - %s", typeCPartnerVidPath.c_str(), strerror(errno));
309         return;
310     }
311 
312     if (sscanf(file_contents_vid.c_str(), "%x", &vid) != 1) {
313         ALOGE("Unable to parse vid %s from file %s to int.", file_contents_vid.c_str(),
314               typeCPartnerVidPath.c_str());
315         return;
316     }
317 
318     if (!ReadFileToString(typeCPartnerPidPath.c_str(), &file_contents_pid)) {
319         ALOGE("Unable to read %s - %s", typeCPartnerPidPath.c_str(), strerror(errno));
320         return;
321     }
322 
323     if (sscanf(file_contents_pid.substr(PID_OFFSET, PID_LENGTH).c_str(), "%x", &pid) != 1) {
324         ALOGE("Unable to parse pid %s from file %s to int.",
325               file_contents_pid.substr(PID_OFFSET, PID_LENGTH).c_str(),
326               typeCPartnerPidPath.c_str());
327         return;
328     }
329 
330     // Upload data only for Google VID
331     if ((VID_MASK & vid) != VID_GOOGLE) {
332         return;
333     }
334 
335     // Upload data only for chargers unless for P30 PID where the product type
336     // isn't set to charger.
337     if ((((vid >> PRODUCT_TYPE_OFFSET) & PRODUCT_TYPE_MASK) != PRODUCT_TYPE_CHARGER) &&
338         (pid != PID_P30)) {
339         return;
340     }
341 
342     std::vector<VendorAtomValue> values(2);
343     VendorAtomValue tmp;
344 
345     tmp.set<VendorAtomValue::intValue>(vid & VID_MASK);
346     values[PdVidPid::kVidFieldNumber - kVendorAtomOffset] = tmp;
347     tmp.set<VendorAtomValue::intValue>(pid);
348     values[PdVidPid::kPidFieldNumber - kVendorAtomOffset] = tmp;
349 
350     // Send vendor atom to IStats HAL
351     VendorAtom event = {.reverseDomainName = "",
352                         .atomId = PixelAtoms::Atom::kPdVidPid,
353                         .values = std::move(values)};
354     const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
355     if (!ret.isOk()) {
356         ALOGE("Unable to report PD VID/PID to Stats service");
357     }
358 }
359 
ReportGpuEvent(const std::shared_ptr<IStats> & stats_client,const char * driver,const char * gpu_event_type,const char * gpu_event_info)360 void UeventListener::ReportGpuEvent(const std::shared_ptr<IStats> &stats_client, const char *driver,
361                                     const char *gpu_event_type, const char *gpu_event_info) {
362 
363     if (!stats_client || !driver || !gpu_event_type || !gpu_event_info)
364         return;
365 
366     bool isPVREvent = (strncmp(driver, "DRIVER=pvrsrvkm", strlen("DRIVER=pvrsrvkm")) == 0);
367     bool isMaliEvent = (strncmp(driver, "DRIVER=mali", strlen("DRIVER=mali")) == 0);
368 
369     if (!isMaliEvent && !isPVREvent)
370         return;
371 
372     std::vector<std::string> type = android::base::Split(gpu_event_type, "=");
373     std::vector<std::string> info = android::base::Split(gpu_event_info, "=");
374 
375     if (type.size() != 2 || info.size() != 2)
376         return;
377 
378     if (type[0] != "GPU_UEVENT_TYPE" || info[0] != "GPU_UEVENT_INFO")
379         return;
380 
381     PixelAtoms::GpuEvent::GpuEventType event_type;
382     PixelAtoms::GpuEvent::GpuEventInfo event_info;
383 
384     if (isPVREvent) {
385         auto type_iter = kPVRGpuEventTypeStrToEnum.find(type[1]);
386         auto info_iter = kPVRGpuEventInfoStrToEnum.find(info[1]);
387         if (type_iter == kPVRGpuEventTypeStrToEnum.end() || info_iter == kPVRGpuEventInfoStrToEnum.end())
388             return;
389 
390         event_type = type_iter->second;
391         event_info = info_iter->second;
392     }
393 
394     if (isMaliEvent) {
395         auto type_iter = kMaliGpuEventTypeStrToEnum.find(type[1]);
396         auto info_iter = kMaliGpuEventInfoStrToEnum.find(info[1]);
397         if (type_iter == kMaliGpuEventTypeStrToEnum.end() || info_iter == kMaliGpuEventInfoStrToEnum.end())
398             return;
399 
400         event_type = type_iter->second;
401         event_info = info_iter->second;
402     }
403 
404     VendorAtom event = {.reverseDomainName = "",
405                         .atomId = PixelAtoms::Atom::kGpuEvent,
406                         .values = {event_type, event_info}};
407     const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
408     if (!ret.isOk())
409         ALOGE("Unable to report GPU event.");
410 }
411 
412 /**
413  * Report thermal abnormal event.
414  * The data is sent as uevent environment parameters:
415  *      1. THERMAL_ABNORMAL_TYPE={type}
416  *      2. THERMAL_ABNORMAL_INFO=Name:{name},Val:{val}
417  * This atom logs data in 3 potential events:
418  *      1. thermistor or tj temperature reading stuck
419  *      2. thermistor or tj showing very high temperature reading
420  *      3. thermistor or tj showing very low temperature reading
421  */
ReportThermalAbnormalEvent(const std::shared_ptr<IStats> & stats_client,const char * devpath,const char * thermal_abnormal_event_type,const char * thermal_abnormal_event_info)422 void UeventListener::ReportThermalAbnormalEvent(const std::shared_ptr<IStats> &stats_client,
423                                                 const char *devpath,
424                                                 const char *thermal_abnormal_event_type,
425                                                 const char *thermal_abnormal_event_info) {
426     if (!stats_client || !devpath ||
427         strncmp(devpath, "DEVPATH=/module/pixel_metrics",
428                 strlen("DEVPATH=/module/pixel_metrics")) ||
429         !thermal_abnormal_event_type || !thermal_abnormal_event_info)
430         return;
431     ALOGD("Thermal Abnormal Type: %s, Thermal Abnormal Info: %s", thermal_abnormal_event_type,
432           thermal_abnormal_event_info);
433     std::vector<std::string> type_msg = android::base::Split(thermal_abnormal_event_type, "=");
434     std::vector<std::string> info_msg = android::base::Split(thermal_abnormal_event_info, "=");
435     if (type_msg.size() != 2 || info_msg.size() != 2) {
436         ALOGE("Invalid msg size for thermal abnormal with type(%zu) and info(%zu)", type_msg.size(),
437               info_msg.size());
438         return;
439     }
440 
441     if (type_msg[0] != "THERMAL_ABNORMAL_TYPE" || info_msg[0] != "THERMAL_ABNORMAL_INFO") {
442         ALOGE("Invalid msg prefix for thermal abnormal with type(%s) and info(%s)",
443               type_msg[0].c_str(), info_msg[0].c_str());
444         return;
445     }
446 
447     auto abnormality_type = kThermalAbnormalityTypeStrToEnum.find(type_msg[1]);
448     if (abnormality_type == kThermalAbnormalityTypeStrToEnum.end()) {
449         ALOGE("Unknown thermal abnormal event type %s", type_msg[1].c_str());
450         return;
451     }
452 
453     std::vector<std::string> info_list = android::base::Split(info_msg[1], ",");
454     if (info_list.size() != 2) {
455         ALOGE("Thermal abnormal info(%s) split size %zu != 2", info_msg[1].c_str(),
456               info_list.size());
457         return;
458     }
459 
460     const auto &name_msg = info_list[0], val_msg = info_list[1];
461     if (!android::base::StartsWith(name_msg, "name:") ||
462         !android::base::StartsWith(val_msg, "val:")) {
463         ALOGE("Invalid prefix for thermal abnormal info name(%s), val(%s)", name_msg.c_str(),
464               val_msg.c_str());
465         return;
466     }
467 
468     auto name_start_pos = std::strlen("name:");
469     auto name = name_msg.substr(name_start_pos);
470     if (name.length() > THERMAL_NAME_LENGTH) {
471         ALOGE("Invalid sensor name %s with length %zu > %d", name.c_str(), name.length(),
472               THERMAL_NAME_LENGTH);
473         return;
474     }
475 
476     auto val_start_pos = std::strlen("val:");
477     auto val_str = val_msg.substr(val_start_pos);
478     int val;
479     if (sscanf(val_str.c_str(), "%d", &val) != 1) {
480         ALOGE("Invalid value for thermal abnormal info: %s", val_str.c_str());
481         return;
482     }
483     ALOGI("Reporting Thermal Abnormal event of type: %s(%d) for %s with val: %d",
484           abnormality_type->first.c_str(), abnormality_type->second, name.c_str(), val);
485     VendorAtom event = {.reverseDomainName = "",
486                         .atomId = PixelAtoms::Atom::kThermalSensorAbnormalityDetected,
487                         .values = {abnormality_type->second, name, val}};
488     const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
489     if (!ret.isOk())
490         ALOGE("Unable to report Thermal Abnormal event.");
491 }
492 
ReportWaterEvent(const std::shared_ptr<IStats> & stats_client,const char * driver,const char * devpath)493 void UeventListener::ReportWaterEvent(const std::shared_ptr<IStats> &stats_client,
494                                       const char *driver, const char *devpath)
495 {
496     if (!stats_client || !driver || !devpath || !water_event_reporter_.ueventDriverMatch(driver))
497         return;
498 
499     water_event_reporter_.logUevent(stats_client, devpath);
500 }
501 
ProcessUevent()502 bool UeventListener::ProcessUevent() {
503     char msg[UEVENT_MSG_LEN + 2];
504     char *cp;
505     const char *driver, *product, *subsystem;
506     const char *mic_break_status, *mic_degrade_status;
507     const char *devpath;
508     bool collect_partner_id = false;
509     const char *gpu_event_type = nullptr, *gpu_event_info = nullptr;
510     const char *thermal_abnormal_event_type = nullptr, *thermal_abnormal_event_info = nullptr;
511     int n;
512 
513     if (uevent_fd_ < 0) {
514         uevent_fd_ = uevent_open_socket(64 * 1024, true);
515         if (uevent_fd_ < 0) {
516             ALOGE("uevent_init: uevent_open_socket failed\n");
517             return false;
518         }
519     }
520 
521 #ifdef LOG_UEVENTS_TO_FILE_ONLY_FOR_DEVEL
522     if (log_fd_ < 0) {
523         /* Intentionally no O_CREAT so no logging will happen
524          * unless the user intentionally 'touch's the file.
525          */
526         log_fd_ = open(LOG_UEVENTS_TO_FILE_ONLY_FOR_DEVEL, O_WRONLY);
527     }
528 #endif
529 
530     n = uevent_kernel_multicast_recv(uevent_fd_, msg, UEVENT_MSG_LEN);
531     if (n <= 0 || n >= UEVENT_MSG_LEN)
532         return false;
533 
534     // Ensure double-null termination of msg.
535     msg[n] = '\0';
536     msg[n + 1] = '\0';
537 
538     driver = product = subsystem = NULL;
539     mic_break_status = mic_degrade_status = devpath = NULL;
540 
541     std::string typeCPartnerUevent = getCStringOrDefault(configData, "TypeCPartnerUevent");
542 
543     if (typeCPartnerUevent.empty()) {
544         ALOGV("typeCPartnerUevent not specified in JSON");
545     }
546     /**
547      * msg is a sequence of null-terminated strings.
548      * Iterate through and record positions of string/value pairs of interest.
549      * Double null indicates end of the message. (enforced above).
550      */
551     cp = msg;
552     while (*cp) {
553         if (log_fd_ > 0) {
554             write(log_fd_, cp, strlen(cp));
555             write(log_fd_, "\n", 1);
556         }
557 
558         if (!strncmp(cp, "DRIVER=", strlen("DRIVER="))) {
559             driver = cp;
560         } else if (!strncmp(cp, "PRODUCT=", strlen("PRODUCT="))) {
561             product = cp;
562         } else if (!strncmp(cp, "MIC_BREAK_STATUS=", strlen("MIC_BREAK_STATUS="))) {
563             mic_break_status = cp;
564         } else if (!strncmp(cp, "MIC_DEGRADE_STATUS=", strlen("MIC_DEGRADE_STATUS="))) {
565             mic_degrade_status = cp;
566         } else if (!strncmp(cp, "DEVPATH=", strlen("DEVPATH="))) {
567             devpath = cp;
568         } else if (!strncmp(cp, "SUBSYSTEM=", strlen("SUBSYSTEM="))) {
569             subsystem = cp;
570         } else if (!strncmp(cp, typeCPartnerUevent.c_str(), typeCPartnerUevent.size())) {
571             collect_partner_id = true;
572         } else if (!strncmp(cp, "GPU_UEVENT_TYPE=", strlen("GPU_UEVENT_TYPE="))) {
573             gpu_event_type = cp;
574         } else if (!strncmp(cp, "GPU_UEVENT_INFO=", strlen("GPU_UEVENT_INFO="))) {
575             gpu_event_info = cp;
576         } else if (!strncmp(cp, THERMAL_ABNORMAL_TYPE_EQ, strlen(THERMAL_ABNORMAL_TYPE_EQ))) {
577             thermal_abnormal_event_type = cp;
578         } else if (!strncmp(cp, THERMAL_ABNORMAL_INFO_EQ, strlen(THERMAL_ABNORMAL_INFO_EQ))) {
579             thermal_abnormal_event_info = cp;
580         }
581         /* advance to after the next \0 */
582         while (*cp++) {
583         }
584     }
585 
586     std::shared_ptr<IStats> stats_client = getStatsService();
587     if (!stats_client) {
588         ALOGE("Unable to get Stats service instance.");
589     } else {
590         /* Process the strings recorded. */
591         ReportMicStatusUevents(stats_client, devpath, mic_break_status);
592         ReportMicStatusUevents(stats_client, devpath, mic_degrade_status);
593         ReportUsbPortOverheatEvent(stats_client, driver);
594         ReportChargeMetricsEvent(stats_client, driver);
595         ReportBatteryCapacityFGEvent(stats_client, subsystem);
596         if (collect_partner_id) {
597             ReportTypeCPartnerId(stats_client);
598         }
599         ReportGpuEvent(stats_client, driver, gpu_event_type, gpu_event_info);
600         ReportThermalAbnormalEvent(stats_client, devpath, thermal_abnormal_event_type,
601                                    thermal_abnormal_event_info);
602         ReportFGMetricsEvent(stats_client, driver);
603         ReportWaterEvent(stats_client, driver, devpath);
604         ReportFwUpdateEvent(stats_client, driver);
605         ReportWlcFwUpdateEvent(stats_client, driver);
606     }
607 
608     if (log_fd_ > 0) {
609         write(log_fd_, "\n", 1);
610     }
611     return true;
612 }
613 
UeventListener(const Json::Value & configData)614 UeventListener::UeventListener(const Json::Value& configData)
615     : configData(configData),
616       uevent_fd_(-1),
617       log_fd_(-1) {}
618 
619 /* Thread function to continuously monitor uevents.
620  * Exit after kMaxConsecutiveErrors to prevent spinning. */
ListenForever()621 void UeventListener::ListenForever() {
622     constexpr int kMaxConsecutiveErrors = 10;
623     int consecutive_errors = 0;
624 
625     while (1) {
626         if (ProcessUevent()) {
627             consecutive_errors = 0;
628         } else {
629             if (++consecutive_errors >= kMaxConsecutiveErrors) {
630                 ALOGE("Too many ProcessUevent errors; exiting UeventListener.");
631                 return;
632             }
633         }
634     }
635 }
636 
637 }  // namespace pixel
638 }  // namespace google
639 }  // namespace hardware
640 }  // namespace android
641