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