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