• 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 #define LOG_TAG "pixelstats-uevent"
18 
19 #include <android-base/file.h>
20 #include <android-base/logging.h>
21 #include <android-base/parseint.h>
22 #include <android-base/strings.h>
23 #include <android/frameworks/stats/1.0/IStats.h>
24 #include <cutils/uevent.h>
25 #include <hardware/google/pixel/pixelstats/pixelatoms.pb.h>
26 #include <log/log.h>
27 #include <pixelstats/UeventListener.h>
28 #include <unistd.h>
29 #include <utils/StrongPointer.h>
30 
31 #include <thread>
32 
33 using android::sp;
34 using android::base::ReadFileToString;
35 using android::frameworks::stats::V1_0::HardwareFailed;
36 using android::frameworks::stats::V1_0::IStats;
37 using android::frameworks::stats::V1_0::UsbPortOverheatEvent;
38 using android::frameworks::stats::V1_0::VendorAtom;
39 using android::hardware::google::pixel::PixelAtoms::ChargeStats;
40 using android::hardware::google::pixel::PixelAtoms::VoltageTierStats;
41 
42 namespace android {
43 namespace hardware {
44 namespace google {
45 namespace pixel {
46 
47 constexpr int32_t UEVENT_MSG_LEN = 2048;  // it's 2048 in all other users.
48 
ReadFileToInt(const std::string & path,int * val)49 bool UeventListener::ReadFileToInt(const std::string &path, int *val) {
50     return ReadFileToInt(path.c_str(), val);
51 }
52 
ReadFileToInt(const char * const path,int * val)53 bool UeventListener::ReadFileToInt(const char *const path, int *val) {
54     std::string file_contents;
55 
56     if (!ReadFileToString(path, &file_contents)) {
57         ALOGE("Unable to read %s - %s", path, strerror(errno));
58         return false;
59     } else if (sscanf(file_contents.c_str(), "%d", val) != 1) {
60         ALOGE("Unable to convert %s to int - %s", path, strerror(errno));
61         return false;
62     }
63     return true;
64 }
65 
ReportMicBrokenOrDegraded(const int mic,const bool isbroken)66 void UeventListener::ReportMicBrokenOrDegraded(const int mic, const bool isbroken) {
67     sp<IStats> stats_client = IStats::tryGetService();
68 
69     if (stats_client) {
70         HardwareFailed failure = {
71                 .hardwareType = HardwareFailed::HardwareType::MICROPHONE,
72                 .hardwareLocation = mic,
73                 .errorCode = isbroken ? HardwareFailed::HardwareErrorCode::COMPLETE
74                                       : HardwareFailed::HardwareErrorCode::DEGRADE};
75         Return<void> ret = stats_client->reportHardwareFailed(failure);
76         if (!ret.isOk())
77             ALOGE("Unable to report physical drop to Stats service");
78     } else
79         ALOGE("Unable to connect to Stats service");
80 }
81 
ReportMicStatusUevents(const char * devpath,const char * mic_status)82 void UeventListener::ReportMicStatusUevents(const char *devpath, const char *mic_status) {
83     if (!devpath || !mic_status)
84         return;
85     if (!strcmp(devpath, ("DEVPATH=" + kAudioUevent).c_str())) {
86         std::vector<std::string> value = android::base::Split(mic_status, "=");
87         bool isbroken;
88 
89         if (value.size() == 2) {
90             if (!value[0].compare("MIC_BREAK_STATUS"))
91                 isbroken = true;
92             else if (!value[0].compare("MIC_DEGRADE_STATUS"))
93                 isbroken = false;
94             else
95                 return;
96 
97             if (!value[1].compare("true"))
98                 ReportMicBrokenOrDegraded(0, isbroken);
99             else {
100                 int mic_status = atoi(value[1].c_str());
101 
102                 if (mic_status > 0 && mic_status <= 7) {
103                     for (int mic_bit = 0; mic_bit < 3; mic_bit++)
104                         if (mic_status & (0x1 << mic_bit))
105                             ReportMicBrokenOrDegraded(mic_bit, isbroken);
106                 } else if (mic_status == 0) {
107                     // mic is ok
108                     return;
109                 } else {
110                     // should not enter here
111                     ALOGE("invalid mic status");
112                     return;
113                 }
114             }
115         }
116     }
117 }
118 
ReportUsbPortOverheatEvent(const char * driver)119 void UeventListener::ReportUsbPortOverheatEvent(const char *driver) {
120     UsbPortOverheatEvent event = {};
121     std::string file_contents;
122 
123     if (!driver || strcmp(driver, "DRIVER=google,overheat_mitigation")) {
124         return;
125     }
126 
127     ReadFileToInt((kUsbPortOverheatPath + "/plug_temp"), &event.plugTemperatureDeciC);
128     ReadFileToInt((kUsbPortOverheatPath + "/max_temp"), &event.maxTemperatureDeciC);
129     ReadFileToInt((kUsbPortOverheatPath + "/trip_time"), &event.timeToOverheat);
130     ReadFileToInt((kUsbPortOverheatPath + "/hysteresis_time"), &event.timeToHysteresis);
131     ReadFileToInt((kUsbPortOverheatPath + "/cleared_time"), &event.timeToInactive);
132 
133     sp<IStats> stats_client = IStats::tryGetService();
134 
135     if (stats_client) {
136         stats_client->reportUsbPortOverheatEvent(event);
137     }
138 }
139 
ReportChargeStats(sp<IStats> & stats_client,const char * line)140 void UeventListener::ReportChargeStats(sp<IStats> &stats_client, const char *line) {
141     std::vector<int> charge_stats_fields = {
142             ChargeStats::kAdapterTypeFieldNumber,     ChargeStats::kAdapterVoltageFieldNumber,
143             ChargeStats::kAdapterAmperageFieldNumber, ChargeStats::kSsocInFieldNumber,
144             ChargeStats::kVoltageInFieldNumber,       ChargeStats::kSsocOutFieldNumber,
145             ChargeStats::kVoltageOutFieldNumber};
146     std::vector<VendorAtom::Value> values(charge_stats_fields.size());
147     VendorAtom::Value val;
148     int32_t i = 0, tmp[7] = {0};
149 
150     ALOGD("ChargeStats: processing %s", line);
151     if (sscanf(line, "%d,%d,%d, %d,%d,%d,%d", &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5],
152                &tmp[6]) != 7) {
153         ALOGE("Couldn't process %s", line);
154         return;
155     }
156     for (i = 0; i < charge_stats_fields.size(); i++) {
157         val.intValue(tmp[i]);
158         values[charge_stats_fields[i] - kVendorAtomOffset] = val;
159     }
160 
161     VendorAtom event = {.reverseDomainName = PixelAtoms::ReverseDomainNames().pixel(),
162                         .atomId = PixelAtoms::Ids::CHARGE_STATS,
163                         .values = values};
164     Return<void> ret = stats_client->reportVendorAtom(event);
165     if (!ret.isOk())
166         ALOGE("Unable to report ChargeStats to Stats service");
167 }
168 
ReportVoltageTierStats(sp<IStats> & stats_client,const char * line)169 void UeventListener::ReportVoltageTierStats(sp<IStats> &stats_client, const char *line) {
170     std::vector<int> voltage_tier_stats_fields = {VoltageTierStats::kVoltageTierFieldNumber,
171                                                   VoltageTierStats::kSocInFieldNumber,
172                                                   VoltageTierStats::kCcInFieldNumber,
173                                                   VoltageTierStats::kTempInFieldNumber,
174                                                   VoltageTierStats::kTimeFastSecsFieldNumber,
175                                                   VoltageTierStats::kTimeTaperSecsFieldNumber,
176                                                   VoltageTierStats::kTimeOtherSecsFieldNumber,
177                                                   VoltageTierStats::kTempMinFieldNumber,
178                                                   VoltageTierStats::kTempAvgFieldNumber,
179                                                   VoltageTierStats::kTempMaxFieldNumber,
180                                                   VoltageTierStats::kIbattMinFieldNumber,
181                                                   VoltageTierStats::kIbattAvgFieldNumber,
182                                                   VoltageTierStats::kIbattMaxFieldNumber,
183                                                   VoltageTierStats::kIclMinFieldNumber,
184                                                   VoltageTierStats::kIclAvgFieldNumber,
185                                                   VoltageTierStats::kIclMaxFieldNumber};
186     std::vector<VendorAtom::Value> values(voltage_tier_stats_fields.size());
187     VendorAtom::Value val;
188     float ssoc_tmp;
189     int32_t i = 0, tmp[15] = {0};
190 
191     ALOGD("VoltageTierStats: processing %s", line);
192     if (sscanf(line, "%d, %f,%d,%d, %d,%d,%d, %d,%d,%d, %d,%d,%d, %d,%d,%d", &tmp[0], &ssoc_tmp,
193                &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5], &tmp[6], &tmp[7], &tmp[8], &tmp[9],
194                &tmp[10], &tmp[11], &tmp[12], &tmp[13], &tmp[14]) != 16) {
195         ALOGE("Couldn't process %s", line);
196         return;
197     }
198     val.intValue(tmp[0]);
199     values[voltage_tier_stats_fields[0] - kVendorAtomOffset] = val;
200     val.floatValue(ssoc_tmp);
201     values[voltage_tier_stats_fields[1] - kVendorAtomOffset] = val;
202     for (i = 2; i < voltage_tier_stats_fields.size(); i++) {
203         val.intValue(tmp[i - 1]);
204         values[voltage_tier_stats_fields[i] - kVendorAtomOffset] = val;
205     }
206 
207     VendorAtom event = {.reverseDomainName = PixelAtoms::ReverseDomainNames().pixel(),
208                         .atomId = PixelAtoms::Ids::VOLTAGE_TIER_STATS,
209                         .values = values};
210     Return<void> ret = stats_client->reportVendorAtom(event);
211     if (!ret.isOk())
212         ALOGE("Unable to report VoltageTierStats to Stats service");
213 }
214 
ReportChargeMetricsEvent(const char * driver)215 void UeventListener::ReportChargeMetricsEvent(const char *driver) {
216     if (!driver || strcmp(driver, "DRIVER=google,battery")) {
217         return;
218     }
219 
220     std::string file_contents, line;
221     std::istringstream ss;
222 
223     if (!ReadFileToString(kChargeMetricsPath.c_str(), &file_contents)) {
224         ALOGE("Unable to read %s - %s", kChargeMetricsPath.c_str(), strerror(errno));
225         return;
226     }
227     ss.str(file_contents);
228 
229     if (!std::getline(ss, line)) {
230         ALOGE("Unable to read first line");
231         return;
232     }
233 
234     sp<IStats> stats_client = IStats::tryGetService();
235     if (!stats_client) {
236         ALOGE("Couldn't connect to IStats service");
237         return;
238     }
239 
240     ReportChargeStats(stats_client, line.c_str());
241 
242     while (std::getline(ss, line)) {
243         ReportVoltageTierStats(stats_client, line.c_str());
244     }
245 }
246 
ProcessUevent()247 bool UeventListener::ProcessUevent() {
248     char msg[UEVENT_MSG_LEN + 2];
249     char *cp;
250     const char *action, *power_supply_typec_mode, *driver, *product;
251     const char *mic_break_status, *mic_degrade_status;
252     const char *devpath;
253     int n;
254 
255     if (uevent_fd_ < 0) {
256         uevent_fd_ = uevent_open_socket(64 * 1024, true);
257         if (uevent_fd_ < 0) {
258             ALOGE("uevent_init: uevent_open_socket failed\n");
259             return false;
260         }
261     }
262 
263     n = uevent_kernel_multicast_recv(uevent_fd_, msg, UEVENT_MSG_LEN);
264     if (n <= 0 || n >= UEVENT_MSG_LEN)
265         return false;
266 
267     // Ensure double-null termination of msg.
268     msg[n] = '\0';
269     msg[n + 1] = '\0';
270 
271     action = power_supply_typec_mode = driver = product = NULL;
272     mic_break_status = mic_degrade_status = devpath = NULL;
273 
274     /**
275      * msg is a sequence of null-terminated strings.
276      * Iterate through and record positions of string/value pairs of interest.
277      * Double null indicates end of the message. (enforced above).
278      */
279     cp = msg;
280     while (*cp) {
281         if (!strncmp(cp, "ACTION=", strlen("ACTION="))) {
282             action = cp;
283         } else if (!strncmp(cp, "POWER_SUPPLY_TYPEC_MODE=", strlen("POWER_SUPPLY_TYPEC_MODE="))) {
284             power_supply_typec_mode = cp;
285         } else if (!strncmp(cp, "DRIVER=", strlen("DRIVER="))) {
286             driver = cp;
287         } else if (!strncmp(cp, "PRODUCT=", strlen("PRODUCT="))) {
288             product = cp;
289         } else if (!strncmp(cp, "MIC_BREAK_STATUS=", strlen("MIC_BREAK_STATUS="))) {
290             mic_break_status = cp;
291         } else if (!strncmp(cp, "MIC_DEGRADE_STATUS=", strlen("MIC_DEGRADE_STATUS="))) {
292             mic_degrade_status = cp;
293         } else if (!strncmp(cp, "DEVPATH=", strlen("DEVPATH="))) {
294             devpath = cp;
295         }
296 
297         /* advance to after the next \0 */
298         while (*cp++) {
299         }
300     }
301 
302     /* Process the strings recorded. */
303     ReportMicStatusUevents(devpath, mic_break_status);
304     ReportMicStatusUevents(devpath, mic_degrade_status);
305     ReportUsbPortOverheatEvent(driver);
306     ReportChargeMetricsEvent(driver);
307 
308     return true;
309 }
310 
UeventListener(const std::string audio_uevent,const std::string overheat_path,const std::string charge_metrics_path)311 UeventListener::UeventListener(const std::string audio_uevent, const std::string overheat_path,
312                                const std::string charge_metrics_path)
313     : kAudioUevent(audio_uevent),
314       kUsbPortOverheatPath(overheat_path),
315       kChargeMetricsPath(charge_metrics_path),
316       uevent_fd_(-1) {}
317 
318 /* Thread function to continuously monitor uevents.
319  * Exit after kMaxConsecutiveErrors to prevent spinning. */
ListenForever()320 void UeventListener::ListenForever() {
321     constexpr int kMaxConsecutiveErrors = 10;
322     int consecutive_errors = 0;
323     while (1) {
324         if (ProcessUevent()) {
325             consecutive_errors = 0;
326         } else {
327             if (++consecutive_errors >= kMaxConsecutiveErrors) {
328                 ALOGE("Too many ProcessUevent errors; exiting UeventListener.");
329                 return;
330             }
331         }
332     }
333 }
334 
335 }  // namespace pixel
336 }  // namespace google
337 }  // namespace hardware
338 }  // namespace android
339