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