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 <log/log.h>
49 #include <pixelstats/StatsHelper.h>
50 #include <pixelstats/UeventListener.h>
51 #include <pixelstats/WlcReporter.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::WlcReporter;
71 using android::hardware::google::pixel::PixelAtoms::ChargeStats;
72 using android::hardware::google::pixel::PixelAtoms::PdVidPid;
73 using android::hardware::google::pixel::PixelAtoms::VendorHardwareFailed;
74 using android::hardware::google::pixel::PixelAtoms::VendorUsbPortOverheat;
75 using android::hardware::google::pixel::PixelAtoms::VoltageTierStats;
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 
ReadFileToInt(const std::string & path,int * val)87 bool UeventListener::ReadFileToInt(const std::string &path, int *val) {
88     return ReadFileToInt(path.c_str(), val);
89 }
90 
ReadFileToInt(const char * const path,int * val)91 bool UeventListener::ReadFileToInt(const char *const path, int *val) {
92     std::string file_contents;
93 
94     if (!ReadFileToString(path, &file_contents)) {
95         ALOGE("Unable to read %s - %s", path, strerror(errno));
96         return false;
97     } else if (sscanf(file_contents.c_str(), "%d", val) != 1) {
98         ALOGE("Unable to convert %s to int - %s", path, strerror(errno));
99         return false;
100     }
101     return true;
102 }
103 
ReportMicBrokenOrDegraded(const std::shared_ptr<IStats> & stats_client,const int mic,const bool isbroken)104 void UeventListener::ReportMicBrokenOrDegraded(const std::shared_ptr<IStats> &stats_client,
105                                                const int mic, const bool isbroken) {
106     VendorHardwareFailed failure;
107     failure.set_hardware_type(VendorHardwareFailed::HARDWARE_FAILED_MICROPHONE);
108     failure.set_hardware_location(mic);
109     failure.set_failure_code(isbroken ? VendorHardwareFailed::COMPLETE
110                                       : VendorHardwareFailed::DEGRADE);
111     reportHardwareFailed(stats_client, failure);
112 }
113 
ReportMicStatusUevents(const std::shared_ptr<IStats> & stats_client,const char * devpath,const char * mic_status)114 void UeventListener::ReportMicStatusUevents(const std::shared_ptr<IStats> &stats_client,
115                                             const char *devpath, const char *mic_status) {
116     if (!devpath || !mic_status)
117         return;
118     if (!strcmp(devpath, ("DEVPATH=" + kAudioUevent).c_str())) {
119         std::vector<std::string> value = android::base::Split(mic_status, "=");
120         bool isbroken;
121 
122         if (value.size() == 2) {
123             if (!value[0].compare("MIC_BREAK_STATUS"))
124                 isbroken = true;
125             else if (!value[0].compare("MIC_DEGRADE_STATUS"))
126                 isbroken = false;
127             else
128                 return;
129 
130             if (!value[1].compare("true")) {
131                 ReportMicBrokenOrDegraded(stats_client, 0, isbroken);
132             } else {
133                 int mic_status = atoi(value[1].c_str());
134 
135                 if (mic_status > 0 && mic_status <= 7) {
136                     for (int mic_bit = 0; mic_bit < 3; mic_bit++)
137                         if (mic_status & (0x1 << mic_bit))
138                             ReportMicBrokenOrDegraded(stats_client, mic_bit, isbroken);
139                 } else if (mic_status == 0) {
140                     // mic is ok
141                     return;
142                 } else {
143                     // should not enter here
144                     ALOGE("invalid mic status");
145                     return;
146                 }
147             }
148         }
149     }
150 }
151 
ReportUsbPortOverheatEvent(const std::shared_ptr<IStats> & stats_client,const char * driver)152 void UeventListener::ReportUsbPortOverheatEvent(const std::shared_ptr<IStats> &stats_client,
153                                                 const char *driver) {
154     if (!driver || strcmp(driver, "DRIVER=google,overheat_mitigation")) {
155         return;
156     }
157 
158     int32_t plug_temperature_deci_c = 0;
159     int32_t max_temperature_deci_c = 0;
160     int32_t time_to_overheat_secs = 0;
161     int32_t time_to_hysteresis_secs = 0;
162     int32_t time_to_inactive_secs = 0;
163 
164     // TODO(achant b/182941868): test return value and skip reporting in case of an error
165     ReadFileToInt((kUsbPortOverheatPath + "/plug_temp"), &plug_temperature_deci_c);
166     ReadFileToInt((kUsbPortOverheatPath + "/max_temp"), &max_temperature_deci_c);
167     ReadFileToInt((kUsbPortOverheatPath + "/trip_time"), &time_to_overheat_secs);
168     ReadFileToInt((kUsbPortOverheatPath + "/hysteresis_time"), &time_to_hysteresis_secs);
169     ReadFileToInt((kUsbPortOverheatPath + "/cleared_time"), &time_to_inactive_secs);
170 
171     VendorUsbPortOverheat overheat_info;
172     overheat_info.set_plug_temperature_deci_c(plug_temperature_deci_c);
173     overheat_info.set_max_temperature_deci_c(max_temperature_deci_c);
174     overheat_info.set_time_to_overheat_secs(time_to_overheat_secs);
175     overheat_info.set_time_to_hysteresis_secs(time_to_hysteresis_secs);
176     overheat_info.set_time_to_inactive_secs(time_to_inactive_secs);
177 
178     reportUsbPortOverheat(stats_client, overheat_info);
179 }
180 
ReportChargeStats(const std::shared_ptr<IStats> & stats_client,const std::string line,const std::string wline_at,const std::string wline_ac,const std::string pca_line)181 void UeventListener::ReportChargeStats(const std::shared_ptr<IStats> &stats_client,
182                                        const std::string line, const std::string wline_at,
183                                        const std::string wline_ac, const std::string pca_line) {
184     int charge_stats_fields[] = {ChargeStats::kAdapterTypeFieldNumber,
185                                  ChargeStats::kAdapterVoltageFieldNumber,
186                                  ChargeStats::kAdapterAmperageFieldNumber,
187                                  ChargeStats::kSsocInFieldNumber,
188                                  ChargeStats::kVoltageInFieldNumber,
189                                  ChargeStats::kSsocOutFieldNumber,
190                                  ChargeStats::kVoltageOutFieldNumber,
191                                  ChargeStats::kAdapterCapabilities0FieldNumber,
192                                  ChargeStats::kAdapterCapabilities1FieldNumber,
193                                  ChargeStats::kAdapterCapabilities2FieldNumber,
194                                  ChargeStats::kAdapterCapabilities3FieldNumber,
195                                  ChargeStats::kAdapterCapabilities4FieldNumber,
196                                  ChargeStats::kReceiverState0FieldNumber,
197                                  ChargeStats::kReceiverState1FieldNumber};
198     const int32_t chg_fields_size = std::size(charge_stats_fields);
199     static_assert(chg_fields_size == 14, "Unexpected charge stats fields size");
200     const int32_t wlc_fields_size = 7;
201     std::vector<VendorAtomValue> values(chg_fields_size);
202     VendorAtomValue val;
203     int32_t i = 0, tmp[chg_fields_size] = {0}, fields_size = (chg_fields_size - wlc_fields_size);
204     int32_t pca_ac[2] = {0}, pca_rs[5] = {0};
205 
206     ALOGD("ChargeStats: processing %s", line.c_str());
207     if (sscanf(line.c_str(), "%d,%d,%d, %d,%d,%d,%d", &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4],
208                &tmp[5], &tmp[6]) != 7) {
209         ALOGE("Couldn't process %s", line.c_str());
210         return;
211     }
212 
213     if (!wline_at.empty()) {
214         int32_t ssoc_tmp = 0;
215         ALOGD("ChargeStats(wlc): processing %s", wline_at.c_str());
216         if (sscanf(wline_at.c_str(), "A:%d", &ssoc_tmp) != 1) {
217             ALOGE("Couldn't process %s", wline_at.c_str());
218         } else {
219             tmp[0] = wireless_charge_stats_.TranslateSysModeToAtomValue(ssoc_tmp);
220             ALOGD("ChargeStats(wlc): processing %s", wline_ac.c_str());
221             if (sscanf(wline_ac.c_str(), "D:%x,%x,%x,%x,%x, %x,%x", &tmp[7], &tmp[8], &tmp[9],
222                        &tmp[10], &tmp[11], &tmp[12], &tmp[13]) != 7)
223                 ALOGE("Couldn't process %s", wline_ac.c_str());
224             else
225                 fields_size = chg_fields_size; /* include wlc stats */
226         }
227     }
228 
229     if (!pca_line.empty()) {
230         ALOGD("ChargeStats(pca): processing %s", pca_line.c_str());
231         if (sscanf(pca_line.c_str(), "D:%x,%x %x,%x,%x,%x,%x", &pca_ac[0], &pca_ac[1], &pca_rs[0],
232                    &pca_rs[1], &pca_rs[2], &pca_rs[3], &pca_rs[4]) != 7) {
233             ALOGE("Couldn't process %s", pca_line.c_str());
234         } else {
235             fields_size = chg_fields_size; /* include pca stats */
236             tmp[9] = pca_rs[2];
237             tmp[10] = pca_rs[3];
238             tmp[11] = pca_rs[4];
239             tmp[13] = pca_rs[1];
240             if (wline_at.empty()) {
241                 tmp[7] = pca_ac[0];
242                 tmp[8] = pca_ac[1];
243                 tmp[12] = pca_rs[0];
244             }
245         }
246     }
247 
248     for (i = 0; i < fields_size; i++) {
249         val.set<VendorAtomValue::intValue>(tmp[i]);
250         values[charge_stats_fields[i] - kVendorAtomOffset] = val;
251     }
252 
253     VendorAtom event = {.reverseDomainName = PixelAtoms::ReverseDomainNames().pixel(),
254                         .atomId = PixelAtoms::Atom::kChargeStats,
255                         .values = std::move(values)};
256     const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
257     if (!ret.isOk())
258         ALOGE("Unable to report ChargeStats to Stats service");
259 }
260 
ReportVoltageTierStats(const std::shared_ptr<IStats> & stats_client,const char * line,const bool has_wireless,const std::string wfile_contents)261 void UeventListener::ReportVoltageTierStats(const std::shared_ptr<IStats> &stats_client,
262                                             const char *line, const bool has_wireless,
263                                             const std::string wfile_contents) {
264     int voltage_tier_stats_fields[] = {
265             VoltageTierStats::kVoltageTierFieldNumber,
266             VoltageTierStats::kSocInFieldNumber, /* retrieved via ssoc_tmp */
267             VoltageTierStats::kCcInFieldNumber,
268             VoltageTierStats::kTempInFieldNumber,
269             VoltageTierStats::kTimeFastSecsFieldNumber,
270             VoltageTierStats::kTimeTaperSecsFieldNumber,
271             VoltageTierStats::kTimeOtherSecsFieldNumber,
272             VoltageTierStats::kTempMinFieldNumber,
273             VoltageTierStats::kTempAvgFieldNumber,
274             VoltageTierStats::kTempMaxFieldNumber,
275             VoltageTierStats::kIbattMinFieldNumber,
276             VoltageTierStats::kIbattAvgFieldNumber,
277             VoltageTierStats::kIbattMaxFieldNumber,
278             VoltageTierStats::kIclMinFieldNumber,
279             VoltageTierStats::kIclAvgFieldNumber,
280             VoltageTierStats::kIclMaxFieldNumber,
281             VoltageTierStats::kMinAdapterPowerOutFieldNumber,
282             VoltageTierStats::kTimeAvgAdapterPowerOutFieldNumber,
283             VoltageTierStats::kMaxAdapterPowerOutFieldNumber,
284             VoltageTierStats::kChargingOperatingPointFieldNumber};
285 
286     const int32_t vtier_fields_size = std::size(voltage_tier_stats_fields);
287     static_assert(vtier_fields_size == 20, "Unexpected voltage tier stats fields size");
288     const int32_t wlc_fields_size = 4;
289     std::vector<VendorAtomValue> values(vtier_fields_size);
290     VendorAtomValue val;
291     float ssoc_tmp;
292     int32_t i = 0, tmp[vtier_fields_size - 1] = {0}, /* ssoc_tmp is not saved in this array */
293             fields_size = (vtier_fields_size - wlc_fields_size);
294 
295     if (sscanf(line, "%d, %f,%d,%d, %d,%d,%d, %d,%d,%d, %d,%d,%d, %d,%d,%d", &tmp[0], &ssoc_tmp,
296                &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5], &tmp[6], &tmp[7], &tmp[8], &tmp[9],
297                &tmp[10], &tmp[11], &tmp[12], &tmp[13], &tmp[14]) != 16) {
298         /* If format isn't as expected, then ignore line on purpose */
299         return;
300     }
301 
302     if (has_wireless) {
303         wireless_charge_stats_.CalculateWirelessChargeStats(static_cast<int>(ssoc_tmp),
304                                                             wfile_contents);
305         tmp[15] = wireless_charge_stats_.pout_min_;
306         tmp[16] = wireless_charge_stats_.pout_avg_;
307         tmp[17] = wireless_charge_stats_.pout_max_;
308         tmp[18] = wireless_charge_stats_.of_freq_;
309         fields_size = vtier_fields_size; /* include wlc stats */
310     }
311 
312     ALOGD("VoltageTierStats: processed %s", line);
313     val.set<VendorAtomValue::intValue>(tmp[0]);
314     values[voltage_tier_stats_fields[0] - kVendorAtomOffset] = val;
315     val.set<VendorAtomValue::floatValue>(ssoc_tmp);
316     values[voltage_tier_stats_fields[1] - kVendorAtomOffset] = val;
317     for (i = 2; i < fields_size; i++) {
318         val.set<VendorAtomValue::intValue>(tmp[i - 1]);
319         values[voltage_tier_stats_fields[i] - kVendorAtomOffset] = val;
320     }
321 
322     VendorAtom event = {.reverseDomainName = PixelAtoms::ReverseDomainNames().pixel(),
323                         .atomId = PixelAtoms::Atom::kVoltageTierStats,
324                         .values = std::move(values)};
325     const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
326     if (!ret.isOk())
327         ALOGE("Unable to report VoltageTierStats to Stats service");
328 }
329 
ReportChargeMetricsEvent(const std::shared_ptr<IStats> & stats_client,const char * driver)330 void UeventListener::ReportChargeMetricsEvent(const std::shared_ptr<IStats> &stats_client,
331                                               const char *driver) {
332     if (!driver || strcmp(driver, "DRIVER=google,battery")) {
333         return;
334     }
335 
336     std::string file_contents, line, wfile_contents, wline_at, wline_ac, pca_file_contents,
337             pca_line;
338     std::istringstream ss;
339     bool has_wireless = wireless_charge_stats_.CheckWirelessContentsAndAck(&wfile_contents);
340     bool has_pca = pca_charge_stats_.CheckPcaContentsAndAck(&pca_file_contents);
341 
342     if (!ReadFileToString(kChargeMetricsPath.c_str(), &file_contents)) {
343         ALOGE("Unable to read %s - %s", kChargeMetricsPath.c_str(), strerror(errno));
344         return;
345     }
346 
347     ss.str(file_contents);
348 
349     if (!std::getline(ss, line)) {
350         ALOGE("Unable to read first line");
351         return;
352     }
353 
354     if (!WriteStringToFile(std::to_string(0), kChargeMetricsPath.c_str())) {
355         ALOGE("Couldn't clear %s - %s", kChargeMetricsPath.c_str(), strerror(errno));
356     }
357 
358     if (has_pca) {
359         std::istringstream pca_ss;
360 
361         pca_ss.str(pca_file_contents);
362         std::getline(pca_ss, pca_line);
363     }
364 
365     if (has_wireless) {
366         std::istringstream wss;
367 
368         /* there are two lines in the head, A: ...(Adapter Type) and D: ...(Adapter Capabilities) */
369         wss.str(wfile_contents);
370         std::getline(wss, wline_at);
371         std::getline(wss, wline_ac);
372 
373         /* reset initial tier soc */
374         wireless_charge_stats_.tier_soc_ = 0;
375     }
376 
377     ReportChargeStats(stats_client, line, wline_at, wline_ac, pca_line);
378 
379     while (std::getline(ss, line)) {
380         ReportVoltageTierStats(stats_client, line.c_str(), has_wireless, wfile_contents);
381     }
382 }
383 
384 /* ReportWlc
385  * Report wireless relate  metrics when wireless charging start
386  */
ReportWlc(const std::shared_ptr<IStats> & stats_client,const bool pow_wireless,const bool online,const char * ptmc)387 void UeventListener::ReportWlc(const std::shared_ptr<IStats> &stats_client, const bool pow_wireless,
388                                const bool online, const char *ptmc) {
389     if (!pow_wireless) {
390         return;
391     }
392 
393     wlc_reporter_.checkAndReport(stats_client, online, ptmc);
394 }
395 /**
396  * Report raw battery capacity, system battery capacity and associated
397  * battery capacity curves. This data is collected to verify the filter
398  * applied on the battery capacity. This will allow debugging of issues
399  * ranging from incorrect fuel gauge hardware calculations to issues
400  * with the software reported battery capacity.
401  *
402  * The data is retrieved by parsing the battery power supply's ssoc_details.
403  *
404  * This atom logs data in 5 potential events:
405  *      1. When a device is connected
406  *      2. When a device is disconnected
407  *      3. When a device has reached a full charge (from the UI's perspective)
408  *      4. When there is a >= 2 percent skip in the UI reported SOC
409  *      5. When there is a difference of >= 4 percent between the raw hardware
410  *          battery capacity and the system reported battery capacity.
411  */
ReportBatteryCapacityFGEvent(const std::shared_ptr<IStats> & stats_client,const char * subsystem)412 void UeventListener::ReportBatteryCapacityFGEvent(const std::shared_ptr<IStats> &stats_client,
413                                                   const char *subsystem) {
414     if (!subsystem || strcmp(subsystem, "SUBSYSTEM=power_supply")) {
415         return;
416     }
417 
418     // Indicates an implicit disable of the battery capacity reporting
419     if (kBatterySSOCPath.empty()) {
420         return;
421     }
422 
423     battery_capacity_reporter_.checkAndReport(stats_client, kBatterySSOCPath);
424 }
425 
ReportTypeCPartnerId(const std::shared_ptr<IStats> & stats_client)426 void UeventListener::ReportTypeCPartnerId(const std::shared_ptr<IStats> &stats_client) {
427     std::string file_contents_vid, file_contents_pid;
428     uint32_t pid, vid;
429 
430     if (!ReadFileToString(kTypeCPartnerVidPath.c_str(), &file_contents_vid)) {
431         ALOGE("Unable to read %s - %s", kTypeCPartnerVidPath.c_str(), strerror(errno));
432         return;
433     }
434 
435     if (sscanf(file_contents_vid.c_str(), "%x", &vid) != 1) {
436         ALOGE("Unable to parse vid %s from file %s to int.", file_contents_vid.c_str(),
437               kTypeCPartnerVidPath.c_str());
438         return;
439     }
440 
441     if (!ReadFileToString(kTypeCPartnerPidPath.c_str(), &file_contents_pid)) {
442         ALOGE("Unable to read %s - %s", kTypeCPartnerPidPath.c_str(), strerror(errno));
443         return;
444     }
445 
446     if (sscanf(file_contents_pid.substr(PID_OFFSET, PID_LENGTH).c_str(), "%x", &pid) != 1) {
447         ALOGE("Unable to parse pid %s from file %s to int.",
448               file_contents_pid.substr(PID_OFFSET, PID_LENGTH).c_str(),
449               kTypeCPartnerPidPath.c_str());
450         return;
451     }
452 
453     // Upload data only for Google VID
454     if ((VID_MASK & vid) != VID_GOOGLE) {
455         return;
456     }
457 
458     // Upload data only for chargers unless for P30 PID where the product type
459     // isn't set to charger.
460     if ((((vid >> PRODUCT_TYPE_OFFSET) & PRODUCT_TYPE_MASK) != PRODUCT_TYPE_CHARGER) &&
461         (pid != PID_P30)) {
462         return;
463     }
464 
465     std::vector<VendorAtomValue> values(2);
466     VendorAtomValue tmp;
467 
468     tmp.set<VendorAtomValue::intValue>(vid & VID_MASK);
469     values[PdVidPid::kVidFieldNumber - kVendorAtomOffset] = tmp;
470     tmp.set<VendorAtomValue::intValue>(pid);
471     values[PdVidPid::kPidFieldNumber - kVendorAtomOffset] = tmp;
472 
473     // Send vendor atom to IStats HAL
474     VendorAtom event = {.reverseDomainName = PixelAtoms::ReverseDomainNames().pixel(),
475                         .atomId = PixelAtoms::Atom::kPdVidPid,
476                         .values = std::move(values)};
477     const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
478     if (!ret.isOk()) {
479         ALOGE("Unable to report PD VID/PID to Stats service");
480     }
481 }
482 
ProcessUevent()483 bool UeventListener::ProcessUevent() {
484     char msg[UEVENT_MSG_LEN + 2];
485     char *cp;
486     const char *driver, *product, *subsystem;
487     const char *mic_break_status, *mic_degrade_status;
488     const char *devpath;
489     bool collect_partner_id = false;
490     bool pow_online;
491     bool pow_wireless;
492     const char *pow_ptmc;
493     int n;
494 
495     if (uevent_fd_ < 0) {
496         uevent_fd_ = uevent_open_socket(64 * 1024, true);
497         if (uevent_fd_ < 0) {
498             ALOGE("uevent_init: uevent_open_socket failed\n");
499             return false;
500         }
501     }
502 
503 #ifdef LOG_UEVENTS_TO_FILE_ONLY_FOR_DEVEL
504     if (log_fd_ < 0) {
505         /* Intentionally no O_CREAT so no logging will happen
506          * unless the user intentionally 'touch's the file.
507          */
508         log_fd_ = open(LOG_UEVENTS_TO_FILE_ONLY_FOR_DEVEL, O_WRONLY);
509     }
510 #endif
511 
512     n = uevent_kernel_multicast_recv(uevent_fd_, msg, UEVENT_MSG_LEN);
513     if (n <= 0 || n >= UEVENT_MSG_LEN)
514         return false;
515 
516     // Ensure double-null termination of msg.
517     msg[n] = '\0';
518     msg[n + 1] = '\0';
519 
520     driver = product = subsystem = NULL;
521     mic_break_status = mic_degrade_status = devpath = pow_ptmc = NULL;
522     pow_online = pow_wireless = false;
523 
524     /**
525      * msg is a sequence of null-terminated strings.
526      * Iterate through and record positions of string/value pairs of interest.
527      * Double null indicates end of the message. (enforced above).
528      */
529     cp = msg;
530     while (*cp) {
531         if (log_fd_ > 0) {
532             write(log_fd_, cp, strlen(cp));
533             write(log_fd_, "\n", 1);
534         }
535         if (!strncmp(cp, "DRIVER=", strlen("DRIVER="))) {
536             driver = cp;
537         } else if (!strncmp(cp, "PRODUCT=", strlen("PRODUCT="))) {
538             product = cp;
539         } else if (!strncmp(cp, "MIC_BREAK_STATUS=", strlen("MIC_BREAK_STATUS="))) {
540             mic_break_status = cp;
541         } else if (!strncmp(cp, "MIC_DEGRADE_STATUS=", strlen("MIC_DEGRADE_STATUS="))) {
542             mic_degrade_status = cp;
543         } else if (!strncmp(cp, "DEVPATH=", strlen("DEVPATH="))) {
544             devpath = cp;
545         } else if (!strncmp(cp, "SUBSYSTEM=", strlen("SUBSYSTEM="))) {
546             subsystem = cp;
547         } else if (!strncmp(cp, kTypeCPartnerUevent.c_str(), kTypeCPartnerUevent.size())) {
548             collect_partner_id = true;
549         } else if (!strncmp(cp, "POWER_SUPPLY_NAME=wireless",
550                             strlen("POWER_SUPPLY_NAME=wireless"))) {
551             pow_wireless = true;
552         } else if (!strncmp(cp, "POWER_SUPPLY_ONLINE=1", strlen("POWER_SUPPLY_ONLINE=1"))) {
553             pow_online = true;
554         } else if (!kWirelessChargerPtmcUevent.empty() &&
555                    !strncmp(cp, kWirelessChargerPtmcUevent.c_str(),
556                             strlen(kWirelessChargerPtmcUevent.c_str()))) {
557             pow_ptmc = cp + strlen(kWirelessChargerPtmcUevent.c_str());
558         }
559         /* advance to after the next \0 */
560         while (*cp++) {
561         }
562     }
563 
564     std::shared_ptr<IStats> stats_client = getStatsService();
565     if (!stats_client) {
566         ALOGE("Unable to get Stats service instance.");
567     } else {
568         /* Process the strings recorded. */
569         ReportMicStatusUevents(stats_client, devpath, mic_break_status);
570         ReportMicStatusUevents(stats_client, devpath, mic_degrade_status);
571         ReportUsbPortOverheatEvent(stats_client, driver);
572         ReportChargeMetricsEvent(stats_client, driver);
573         ReportWlc(stats_client, pow_wireless, pow_online, pow_ptmc);
574         ReportBatteryCapacityFGEvent(stats_client, subsystem);
575         if (collect_partner_id) {
576             ReportTypeCPartnerId(stats_client);
577         }
578     }
579 
580     if (log_fd_ > 0) {
581         write(log_fd_, "\n", 1);
582     }
583     return true;
584 }
585 
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)586 UeventListener::UeventListener(const std::string audio_uevent, const std::string ssoc_details_path,
587                                const std::string overheat_path,
588                                const std::string charge_metrics_path,
589                                const std::string typec_partner_vid_path,
590                                const std::string typec_partner_pid_path)
591     : kAudioUevent(audio_uevent),
592       kBatterySSOCPath(ssoc_details_path),
593       kUsbPortOverheatPath(overheat_path),
594       kChargeMetricsPath(charge_metrics_path),
595       kTypeCPartnerUevent(typec_partner_uevent_default),
596       kTypeCPartnerVidPath(typec_partner_vid_path),
597       kTypeCPartnerPidPath(typec_partner_pid_path),
598       kWirelessChargerPtmcUevent(""),
599       kWirelessChargerPtmcPath(""),
600       uevent_fd_(-1),
601       log_fd_(-1) {}
602 
UeventListener(const struct UeventPaths & uevents_paths)603 UeventListener::UeventListener(const struct UeventPaths &uevents_paths)
604     : kAudioUevent((uevents_paths.AudioUevent == nullptr) ? "" : uevents_paths.AudioUevent),
605       kBatterySSOCPath((uevents_paths.SsocDetailsPath == nullptr) ? ssoc_details_path
606                                                                   : uevents_paths.SsocDetailsPath),
607       kUsbPortOverheatPath((uevents_paths.OverheatPath == nullptr) ? overheat_path_default
608                                                                    : uevents_paths.OverheatPath),
609       kChargeMetricsPath((uevents_paths.ChargeMetricsPath == nullptr)
610                                  ? charge_metrics_path_default
611                                  : uevents_paths.ChargeMetricsPath),
612       kTypeCPartnerUevent((uevents_paths.TypeCPartnerUevent == nullptr)
613                                   ? typec_partner_uevent_default
614                                   : uevents_paths.TypeCPartnerUevent),
615       kTypeCPartnerVidPath((uevents_paths.TypeCPartnerVidPath == nullptr)
616                                    ? typec_partner_vid_path_default
617                                    : uevents_paths.TypeCPartnerVidPath),
618       kTypeCPartnerPidPath((uevents_paths.TypeCPartnerPidPath == nullptr)
619                                    ? typec_partner_pid_path_default
620                                    : uevents_paths.TypeCPartnerPidPath),
621       kWirelessChargerPtmcUevent((uevents_paths.WirelessChargerPtmcUevent == nullptr)
622                                          ? ""
623                                          : uevents_paths.WirelessChargerPtmcUevent),
624       kWirelessChargerPtmcPath((uevents_paths.WirelessChargerPtmcPath == nullptr)
625                                        ? ""
626                                        : uevents_paths.WirelessChargerPtmcPath),
627       uevent_fd_(-1),
628       log_fd_(-1) {}
629 
630 /* Thread function to continuously monitor uevents.
631  * Exit after kMaxConsecutiveErrors to prevent spinning. */
ListenForever()632 void UeventListener::ListenForever() {
633     constexpr int kMaxConsecutiveErrors = 10;
634     int consecutive_errors = 0;
635 
636     while (1) {
637         if (ProcessUevent()) {
638             consecutive_errors = 0;
639         } else {
640             if (++consecutive_errors >= kMaxConsecutiveErrors) {
641                 ALOGE("Too many ProcessUevent errors; exiting UeventListener.");
642                 return;
643             }
644         }
645     }
646 }
647 
648 }  // namespace pixel
649 }  // namespace google
650 }  // namespace hardware
651 }  // namespace android
652