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