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