1 /*
2 * Copyright (C) 2022 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 ATRACE_TAG (ATRACE_TAG_THERMAL | ATRACE_TAG_HAL)
18
19 #include "thermal_watcher.h"
20
21 #include <android-base/file.h>
22 #include <android-base/logging.h>
23 #include <android-base/stringprintf.h>
24 #include <android-base/strings.h>
25 #include <cutils/uevent.h>
26 #include <dirent.h>
27 #include <linux/netlink.h>
28 #include <linux/thermal.h>
29 #include <sys/inotify.h>
30 #include <sys/resource.h>
31 #include <sys/types.h>
32 #include <utils/Trace.h>
33
34 #include <chrono>
35 #include <fstream>
36
37 #include "../thermal-helper.h"
38
39 namespace aidl {
40 namespace android {
41 namespace hardware {
42 namespace thermal {
43 namespace implementation {
44
45 namespace {
46
47 using ::android::base::StringPrintf;
48
49 constexpr static const char *const kNlAttributeStringMap[THERMAL_GENL_ATTR_MAX + 1] = {
50 [THERMAL_GENL_ATTR_TZ_ID] = "tz_id",
51 [THERMAL_GENL_ATTR_TZ_TEMP] = "tz_temp",
52 [THERMAL_GENL_ATTR_TZ_TRIP_ID] = "trip_id",
53 [THERMAL_GENL_ATTR_TZ_TRIP_TYPE] = "trip_type",
54 [THERMAL_GENL_ATTR_TZ_TRIP_TEMP] = "trip_temp",
55 [THERMAL_GENL_ATTR_TZ_TRIP_HYST] = "trip_hyst",
56 [THERMAL_GENL_ATTR_TZ_NAME] = "tz_name",
57 [THERMAL_GENL_ATTR_CDEV_ID] = "cdev_id",
58 [THERMAL_GENL_ATTR_CDEV_CUR_STATE] = "cdev_cur_state",
59 [THERMAL_GENL_ATTR_CDEV_MAX_STATE] = "cdev_max_state",
60 [THERMAL_GENL_ATTR_CDEV_NAME] = "cdev_name",
61 [THERMAL_GENL_ATTR_GOV_NAME] = "gov_name",
62 };
63
setAndLogTzId(const struct nlattr * const attrs[THERMAL_GENL_ATTR_MAX+1],int & tz_id,std::string & out)64 static void setAndLogTzId(const struct nlattr *const attrs[THERMAL_GENL_ATTR_MAX + 1], int &tz_id,
65 std::string &out) {
66 if (attrs[THERMAL_GENL_ATTR_TZ_ID]) {
67 tz_id = nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
68 out.append(StringPrintf(" %s=%d", kNlAttributeStringMap[THERMAL_GENL_ATTR_TZ_ID], tz_id));
69 }
70 }
71
setAndLogTzTemp(const struct nlattr * const attrs[THERMAL_GENL_ATTR_MAX+1],float & tz_temp,std::string & out)72 static void setAndLogTzTemp(const struct nlattr *const attrs[THERMAL_GENL_ATTR_MAX + 1],
73 float &tz_temp, std::string &out) {
74 if (attrs[THERMAL_GENL_ATTR_TZ_TEMP]) {
75 tz_temp = static_cast<float>(nla_get_s32(attrs[THERMAL_GENL_ATTR_TZ_TEMP]));
76 out.append(StringPrintf(" %s=%0.2f", kNlAttributeStringMap[THERMAL_GENL_ATTR_TZ_TEMP],
77 tz_temp));
78 }
79 }
80
log32Attribute(const struct nlattr * const attrs[THERMAL_GENL_ATTR_MAX+1],const thermal_genl_attr & attr_type,std::string & out)81 static void log32Attribute(const struct nlattr *const attrs[THERMAL_GENL_ATTR_MAX + 1],
82 const thermal_genl_attr &attr_type, std::string &out) {
83 if (attrs[attr_type]) {
84 if (attr_type == THERMAL_GENL_ATTR_TZ_TEMP || attr_type == THERMAL_GENL_ATTR_TZ_TRIP_TEMP) {
85 out.append(StringPrintf(" %s=%d", kNlAttributeStringMap[attr_type],
86 nla_get_s32(attrs[attr_type])));
87 } else {
88 // id, hyst and state kind of attr_type will goes into this else
89 out.append(StringPrintf(" %s=%d", kNlAttributeStringMap[attr_type],
90 nla_get_u32(attrs[attr_type])));
91 }
92 }
93 }
94
log32AttributeList(const struct nlattr * const attrs[THERMAL_GENL_ATTR_MAX+1],const std::vector<thermal_genl_attr> & attr_types,std::string & out)95 static void log32AttributeList(const struct nlattr *const attrs[THERMAL_GENL_ATTR_MAX + 1],
96 const std::vector<thermal_genl_attr> &attr_types, std::string &out) {
97 for (const auto &attr_type : attr_types) log32Attribute(attrs, attr_type, out);
98 }
99
logStringAttribute(const struct nlattr * const attrs[THERMAL_GENL_ATTR_MAX+1],const thermal_genl_attr & attr_type,std::string & out)100 static void logStringAttribute(const struct nlattr *const attrs[THERMAL_GENL_ATTR_MAX + 1],
101 const thermal_genl_attr &attr_type, std::string &out) {
102 if (attrs[attr_type])
103 out.append(StringPrintf(" %s=%s", kNlAttributeStringMap[attr_type],
104 nla_get_string(attrs[attr_type])));
105 }
106
nlErrorHandle(struct sockaddr_nl * nla,struct nlmsgerr * err,void * arg)107 static int nlErrorHandle(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) {
108 int *ret = reinterpret_cast<int *>(arg);
109 *ret = err->error;
110 LOG(ERROR) << __func__ << "nl_groups: " << nla->nl_groups << ", nl_pid: " << nla->nl_pid;
111
112 return NL_STOP;
113 }
114
nlFinishHandle(struct nl_msg * msg,void * arg)115 static int nlFinishHandle(struct nl_msg *msg, void *arg) {
116 int *ret = reinterpret_cast<int *>(arg);
117 *ret = 1;
118 struct nlmsghdr *nlh = nlmsg_hdr(msg);
119
120 LOG(VERBOSE) << __func__ << ": nlmsg type: " << nlh->nlmsg_type;
121
122 return NL_OK;
123 }
124
nlAckHandle(struct nl_msg * msg,void * arg)125 static int nlAckHandle(struct nl_msg *msg, void *arg) {
126 int *ret = reinterpret_cast<int *>(arg);
127 *ret = 1;
128 struct nlmsghdr *nlh = nlmsg_hdr(msg);
129
130 LOG(VERBOSE) << __func__ << ": nlmsg type: " << nlh->nlmsg_type;
131
132 return NL_OK;
133 }
134
nlSeqCheckHandle(struct nl_msg * msg,void * arg)135 static int nlSeqCheckHandle(struct nl_msg *msg, void *arg) {
136 int *ret = reinterpret_cast<int *>(arg);
137 *ret = 1;
138 struct nlmsghdr *nlh = nlmsg_hdr(msg);
139
140 LOG(VERBOSE) << __func__ << ": nlmsg type: " << nlh->nlmsg_type;
141
142 return NL_OK;
143 }
144
145 struct HandlerArgs {
146 const char *group;
147 int id;
148 };
149
nlSendMsg(struct nl_sock * sock,struct nl_msg * msg,int (* rx_handler)(struct nl_msg *,void *),void * data)150 static int nlSendMsg(struct nl_sock *sock, struct nl_msg *msg,
151 int (*rx_handler)(struct nl_msg *, void *), void *data) {
152 int err, done = 0;
153
154 std::unique_ptr<nl_cb, decltype(&nl_cb_put)> cb(nl_cb_alloc(NL_CB_DEFAULT), nl_cb_put);
155
156 err = nl_send_auto_complete(sock, msg);
157 if (err < 0)
158 return err;
159
160 err = 0;
161 nl_cb_err(cb.get(), NL_CB_CUSTOM, nlErrorHandle, &err);
162 nl_cb_set(cb.get(), NL_CB_FINISH, NL_CB_CUSTOM, nlFinishHandle, &done);
163 nl_cb_set(cb.get(), NL_CB_ACK, NL_CB_CUSTOM, nlAckHandle, &done);
164
165 if (rx_handler != NULL)
166 nl_cb_set(cb.get(), NL_CB_VALID, NL_CB_CUSTOM, rx_handler, data);
167
168 while (err == 0 && done == 0) nl_recvmsgs(sock, cb.get());
169
170 return err;
171 }
172
nlFamilyHandle(struct nl_msg * msg,void * arg)173 static int nlFamilyHandle(struct nl_msg *msg, void *arg) {
174 struct HandlerArgs *grp = reinterpret_cast<struct HandlerArgs *>(arg);
175 struct nlattr *tb[CTRL_ATTR_MAX + 1];
176 struct genlmsghdr *gnlh = (struct genlmsghdr *)nlmsg_data(nlmsg_hdr(msg));
177 struct nlattr *mcgrp;
178 int rem_mcgrp;
179
180 nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL);
181
182 if (!tb[CTRL_ATTR_MCAST_GROUPS]) {
183 LOG(ERROR) << __func__ << "Multicast group not found";
184 return -1;
185 }
186
187 nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], rem_mcgrp) {
188 struct nlattr *tb_mcgrp[CTRL_ATTR_MCAST_GRP_MAX + 1];
189
190 nla_parse(tb_mcgrp, CTRL_ATTR_MCAST_GRP_MAX, reinterpret_cast<nlattr *>(nla_data(mcgrp)),
191 nla_len(mcgrp), NULL);
192
193 if (!tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME] || !tb_mcgrp[CTRL_ATTR_MCAST_GRP_ID])
194 continue;
195
196 if (strncmp(reinterpret_cast<char *>(nla_data(tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME])),
197 grp->group, nla_len(tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME])) != 0)
198 continue;
199
200 grp->id = nla_get_u32(tb_mcgrp[CTRL_ATTR_MCAST_GRP_ID]);
201
202 break;
203 }
204
205 return 0;
206 }
207
nlGetMulticastId(struct nl_sock * sock,const char * family,const char * group)208 static int nlGetMulticastId(struct nl_sock *sock, const char *family, const char *group) {
209 int err = 0, ctrlid;
210 struct HandlerArgs grp = {
211 .group = group,
212 .id = -ENOENT,
213 };
214
215 std::unique_ptr<nl_msg, decltype(&nlmsg_free)> msg(nlmsg_alloc(), nlmsg_free);
216
217 ctrlid = genl_ctrl_resolve(sock, "nlctrl");
218
219 genlmsg_put(msg.get(), 0, 0, ctrlid, 0, 0, CTRL_CMD_GETFAMILY, 0);
220
221 nla_put_string(msg.get(), CTRL_ATTR_FAMILY_NAME, family);
222
223 err = nlSendMsg(sock, msg.get(), nlFamilyHandle, &grp);
224 if (err)
225 return err;
226
227 err = grp.id;
228 LOG(INFO) << group << " multicast_id: " << grp.id;
229
230 return err;
231 }
232
socketAddMembership(struct nl_sock * sock,const char * group)233 static bool socketAddMembership(struct nl_sock *sock, const char *group) {
234 int mcid = nlGetMulticastId(sock, THERMAL_GENL_FAMILY_NAME, group);
235 if (mcid < 0) {
236 LOG(ERROR) << "Failed to get multicast id: " << group;
237 return false;
238 }
239
240 if (nl_socket_add_membership(sock, mcid)) {
241 LOG(ERROR) << "Failed to add netlink socket membership: " << group;
242 return false;
243 }
244
245 LOG(INFO) << "Added netlink socket membership: " << group;
246 return true;
247 }
248
handleEvent(struct nl_msg * n,void * arg)249 static int handleEvent(struct nl_msg *n, void *arg) {
250 struct nlmsghdr *nlh = nlmsg_hdr(n);
251 struct genlmsghdr *glh = genlmsg_hdr(nlh);
252 struct nlattr *attrs[THERMAL_GENL_ATTR_MAX + 1];
253 std::pair<int, float> *tz_info = reinterpret_cast<std::pair<int, float> *>(arg);
254 int &tz_id = tz_info->first;
255 float &tz_temp = tz_info->second;
256 std::string out;
257
258 genlmsg_parse(nlh, 0, attrs, THERMAL_GENL_ATTR_MAX, NULL);
259
260 switch (glh->cmd) {
261 case THERMAL_GENL_EVENT_TZ_TRIP_UP:
262 out = "THERMAL_GENL_EVENT_TZ_TRIP_UP";
263 setAndLogTzId(attrs, tz_id, out);
264 setAndLogTzTemp(attrs, tz_temp, out);
265 log32Attribute(attrs, THERMAL_GENL_ATTR_TZ_TRIP_ID, out);
266 break;
267 case THERMAL_GENL_EVENT_TZ_TRIP_DOWN:
268 out = "THERMAL_GENL_EVENT_TZ_TRIP_DOWN";
269 setAndLogTzId(attrs, tz_id, out);
270 setAndLogTzTemp(attrs, tz_temp, out);
271 log32Attribute(attrs, THERMAL_GENL_ATTR_TZ_TRIP_ID, out);
272 break;
273 case THERMAL_GENL_EVENT_TZ_GOV_CHANGE:
274 out = "THERMAL_GENL_EVENT_TZ_GOV_CHANGE";
275 setAndLogTzId(attrs, tz_id, out);
276 logStringAttribute(attrs, THERMAL_GENL_ATTR_GOV_NAME, out);
277 break;
278 case THERMAL_GENL_EVENT_TZ_CREATE:
279 out = "THERMAL_GENL_EVENT_TZ_CREATE";
280 setAndLogTzId(attrs, tz_id, out);
281 logStringAttribute(attrs, THERMAL_GENL_ATTR_TZ_NAME, out);
282 break;
283 case THERMAL_GENL_EVENT_TZ_DELETE:
284 out = "THERMAL_GENL_EVENT_TZ_DELETE";
285 setAndLogTzId(attrs, tz_id, out);
286 break;
287 case THERMAL_GENL_EVENT_TZ_DISABLE:
288 out = "THERMAL_GENL_EVENT_TZ_DISABLE";
289 setAndLogTzId(attrs, tz_id, out);
290 break;
291 case THERMAL_GENL_EVENT_TZ_ENABLE:
292 out = "THERMAL_GENL_EVENT_TZ_ENABLE";
293 setAndLogTzId(attrs, tz_id, out);
294 break;
295 case THERMAL_GENL_EVENT_TZ_TRIP_CHANGE:
296 out = "THERMAL_GENL_EVENT_TZ_TRIP_CHANGE";
297 setAndLogTzId(attrs, tz_id, out);
298 log32AttributeList(attrs,
299 {THERMAL_GENL_ATTR_TZ_TRIP_ID, THERMAL_GENL_ATTR_TZ_TRIP_TYPE,
300 THERMAL_GENL_ATTR_TZ_TRIP_TEMP, THERMAL_GENL_ATTR_TZ_TRIP_HYST},
301 out);
302 break;
303 case THERMAL_GENL_EVENT_TZ_TRIP_ADD:
304 out = "THERMAL_GENL_EVENT_TZ_TRIP_ADD";
305 setAndLogTzId(attrs, tz_id, out);
306 log32AttributeList(attrs,
307 {THERMAL_GENL_ATTR_TZ_TRIP_ID, THERMAL_GENL_ATTR_TZ_TRIP_TYPE,
308 THERMAL_GENL_ATTR_TZ_TRIP_TEMP, THERMAL_GENL_ATTR_TZ_TRIP_HYST},
309 out);
310 break;
311 case THERMAL_GENL_EVENT_TZ_TRIP_DELETE:
312 out = "THERMAL_GENL_EVENT_TZ_TRIP_DELETE";
313 setAndLogTzId(attrs, tz_id, out);
314 log32Attribute(attrs, THERMAL_GENL_ATTR_TZ_TRIP_ID, out);
315 break;
316 case THERMAL_GENL_EVENT_CDEV_STATE_UPDATE:
317 out = "THERMAL_GENL_EVENT_CDEV_STATE_UPDATE:";
318 log32AttributeList(attrs, {THERMAL_GENL_ATTR_CDEV_ID, THERMAL_GENL_ATTR_CDEV_CUR_STATE},
319 out);
320 break;
321 case THERMAL_GENL_EVENT_CDEV_ADD:
322 out = "THERMAL_GENL_EVENT_CDEV_ADD";
323 log32Attribute(attrs, THERMAL_GENL_ATTR_CDEV_ID, out);
324 logStringAttribute(attrs, THERMAL_GENL_ATTR_CDEV_NAME, out);
325 log32Attribute(attrs, THERMAL_GENL_ATTR_CDEV_MAX_STATE, out);
326 break;
327 case THERMAL_GENL_EVENT_CDEV_DELETE:
328 out = "THERMAL_GENL_EVENT_CDEV_DELETE";
329 log32Attribute(attrs, THERMAL_GENL_ATTR_CDEV_ID, out);
330 break;
331 case THERMAL_GENL_SAMPLING_TEMP:
332 out = "THERMAL_GENL_SAMPLING_TEMP";
333 setAndLogTzId(attrs, tz_id, out);
334 log32Attribute(attrs, THERMAL_GENL_ATTR_TZ_TEMP, out);
335 break;
336 default:
337 LOG(ERROR) << "Unknown genlink event command: " << glh->cmd;
338 return 0;
339 }
340 LOG(INFO) << out;
341
342 return 0;
343 }
344
345 } // namespace
346
registerFilesToWatch(const std::set<std::string> & sensors_to_watch)347 void ThermalWatcher::registerFilesToWatch(const std::set<std::string> &sensors_to_watch) {
348 LOG(INFO) << "Uevent register file to watch...";
349 monitored_sensors_.insert(sensors_to_watch.begin(), sensors_to_watch.end());
350
351 uevent_fd_.reset((TEMP_FAILURE_RETRY(uevent_open_socket(64 * 1024, true))));
352 if (uevent_fd_.get() < 0) {
353 LOG(ERROR) << "failed to open uevent socket";
354 return;
355 }
356
357 fcntl(uevent_fd_, F_SETFL, O_NONBLOCK);
358
359 looper_->addFd(uevent_fd_.get(), 0, ::android::Looper::EVENT_INPUT, nullptr, nullptr);
360 sleep_ms_ = std::chrono::milliseconds(0);
361 last_update_time_ = boot_clock::now();
362 }
363
registerFilesToWatchNl(const std::set<std::string> & sensors_to_watch)364 void ThermalWatcher::registerFilesToWatchNl(const std::set<std::string> &sensors_to_watch) {
365 LOG(INFO) << "Thermal genl register file to watch...";
366 monitored_sensors_.insert(sensors_to_watch.begin(), sensors_to_watch.end());
367
368 sk_thermal = nl_socket_alloc();
369 if (!sk_thermal) {
370 LOG(ERROR) << "nl_socket_alloc failed";
371 return;
372 }
373
374 if (genl_connect(sk_thermal)) {
375 LOG(ERROR) << "genl_connect failed: sk_thermal";
376 return;
377 }
378
379 thermal_genl_fd_.reset(nl_socket_get_fd(sk_thermal));
380 if (thermal_genl_fd_.get() < 0) {
381 LOG(ERROR) << "Failed to create thermal netlink socket";
382 return;
383 }
384
385 if (!socketAddMembership(sk_thermal, THERMAL_GENL_EVENT_GROUP_NAME)) {
386 return;
387 }
388
389 /*
390 * Currently, only the update_temperature() will send thermal genl samlping events
391 * from kernel. To avoid thermal-hal busy because samlping events are sent
392 * too frequently, ignore thermal genl samlping events until we figure out how to use it.
393 *
394 if (!socketAddMembership(sk_thermal, THERMAL_GENL_SAMPLING_GROUP_NAME)) {
395 return;
396 }
397 */
398
399 fcntl(thermal_genl_fd_, F_SETFL, O_NONBLOCK);
400 looper_->addFd(thermal_genl_fd_.get(), 0, ::android::Looper::EVENT_INPUT, nullptr, nullptr);
401 sleep_ms_ = std::chrono::milliseconds(0);
402 last_update_time_ = boot_clock::now();
403 }
404
startWatchingDeviceFiles()405 bool ThermalWatcher::startWatchingDeviceFiles() {
406 if (cb_) {
407 auto ret = this->run("FileWatcherThread", -10);
408 if (ret != ::android::NO_ERROR) {
409 LOG(ERROR) << "ThermalWatcherThread start fail";
410 return false;
411 } else {
412 LOG(INFO) << "ThermalWatcherThread started";
413 return true;
414 }
415 }
416 return false;
417 }
parseUevent(std::unordered_map<std::string,float> * sensor_map)418 void ThermalWatcher::parseUevent(std::unordered_map<std::string, float> *sensor_map) {
419 bool thermal_event = false;
420 constexpr int kUeventMsgLen = 2048;
421 char msg[kUeventMsgLen + 2];
422 char *cp;
423
424 while (true) {
425 int n = uevent_kernel_multicast_recv(uevent_fd_.get(), msg, kUeventMsgLen);
426 if (n <= 0) {
427 if (errno != EAGAIN && errno != EWOULDBLOCK) {
428 LOG(ERROR) << "Error reading from Uevent Fd";
429 }
430 break;
431 }
432
433 if (n >= kUeventMsgLen) {
434 LOG(ERROR) << "Uevent overflowed buffer, discarding";
435 continue;
436 }
437
438 msg[n] = '\0';
439 msg[n + 1] = '\0';
440
441 cp = msg;
442 while (*cp) {
443 std::string uevent = cp;
444 auto findSubSystemThermal = uevent.find("SUBSYSTEM=thermal");
445 if (!thermal_event) {
446 if (::android::base::StartsWith(uevent, "SUBSYSTEM=")) {
447 if (findSubSystemThermal != std::string::npos) {
448 thermal_event = true;
449 } else {
450 break;
451 }
452 }
453 } else {
454 auto start_pos = uevent.find("NAME=");
455 if (start_pos != std::string::npos) {
456 start_pos += 5;
457 std::string name = uevent.substr(start_pos);
458 if (monitored_sensors_.find(name) != monitored_sensors_.end()) {
459 sensor_map->insert({name, NAN});
460 }
461 break;
462 }
463 }
464 while (*cp++) {
465 }
466 }
467 }
468 }
469
470 // TODO(b/175367921): Consider for potentially adding more type of event in the function
471 // instead of just add the sensors to the list.
parseGenlink(std::unordered_map<std::string,float> * sensor_map)472 void ThermalWatcher::parseGenlink(std::unordered_map<std::string, float> *sensor_map) {
473 int err = 0, done = 0;
474 std::pair<int, float> tz_info(-1, NAN);
475
476 std::unique_ptr<nl_cb, decltype(&nl_cb_put)> cb(nl_cb_alloc(NL_CB_DEFAULT), nl_cb_put);
477
478 nl_cb_err(cb.get(), NL_CB_CUSTOM, nlErrorHandle, &err);
479 nl_cb_set(cb.get(), NL_CB_FINISH, NL_CB_CUSTOM, nlFinishHandle, &done);
480 nl_cb_set(cb.get(), NL_CB_ACK, NL_CB_CUSTOM, nlAckHandle, &done);
481 nl_cb_set(cb.get(), NL_CB_SEQ_CHECK, NL_CB_CUSTOM, nlSeqCheckHandle, &done);
482 nl_cb_set(cb.get(), NL_CB_VALID, NL_CB_CUSTOM, handleEvent, &tz_info);
483
484 while (!done && !err) {
485 nl_recvmsgs(sk_thermal, cb.get());
486
487 if (tz_info.first < 0) {
488 break;
489 }
490
491 std::string name;
492 if (getThermalZoneTypeById(tz_info.first, &name) &&
493 monitored_sensors_.find(name) != monitored_sensors_.end()) {
494 sensor_map->insert({name, tz_info.second});
495 }
496 }
497 }
498
wake()499 void ThermalWatcher::wake() {
500 looper_->wake();
501 }
502
threadLoop()503 bool ThermalWatcher::threadLoop() {
504 LOG(VERBOSE) << "ThermalWatcher polling...";
505
506 int fd;
507 std::unordered_map<std::string, float> sensors;
508
509 auto time_elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(boot_clock::now() -
510 last_update_time_);
511
512 if (time_elapsed_ms < sleep_ms_ &&
513 looper_->pollOnce(sleep_ms_.count(), &fd, nullptr, nullptr) >= 0) {
514 ATRACE_NAME("ThermalWatcher::threadLoop - receive event");
515 if (fd != uevent_fd_.get() && fd != thermal_genl_fd_.get()) {
516 return true;
517 } else if (fd == thermal_genl_fd_.get()) {
518 parseGenlink(&sensors);
519 } else if (fd == uevent_fd_.get()) {
520 parseUevent(&sensors);
521 }
522 // Ignore cb_ if uevent is not from monitored sensors
523 if (sensors.size() == 0) {
524 return true;
525 }
526 }
527
528 sleep_ms_ = cb_(sensors);
529 last_update_time_ = boot_clock::now();
530 return true;
531 }
532
533 } // namespace implementation
534 } // namespace thermal
535 } // namespace hardware
536 } // namespace android
537 } // namespace aidl
538