536 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			536 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C++
		
	
	
	
| /*
 | |
|  * Copyright (C) 2018 The Android Open Source Project
 | |
|  *
 | |
|  * Licensed under the Apache License, Version 2.0 (the "License");
 | |
|  * you may not use this file except in compliance with the License.
 | |
|  * You may obtain a copy of the License at
 | |
|  *
 | |
|  *      http://www.apache.org/licenses/LICENSE-2.0
 | |
|  *
 | |
|  * Unless required by applicable law or agreed to in writing, software
 | |
|  * distributed under the License is distributed on an "AS IS" BASIS,
 | |
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
|  * See the License for the specific language governing permissions and
 | |
|  * limitations under the License.
 | |
|  */
 | |
| 
 | |
| #define ATRACE_TAG (ATRACE_TAG_THERMAL | ATRACE_TAG_HAL)
 | |
| 
 | |
| #include "thermal_watcher.h"
 | |
| 
 | |
| #include <android-base/file.h>
 | |
| #include <android-base/logging.h>
 | |
| #include <android-base/stringprintf.h>
 | |
| #include <android-base/strings.h>
 | |
| #include <cutils/uevent.h>
 | |
| #include <dirent.h>
 | |
| #include <linux/netlink.h>
 | |
| #include <linux/thermal.h>
 | |
| #include <sys/inotify.h>
 | |
| #include <sys/resource.h>
 | |
| #include <sys/types.h>
 | |
| #include <utils/Trace.h>
 | |
| 
 | |
| #include <chrono>
 | |
| #include <fstream>
 | |
| 
 | |
| #include "thermal-helper.h"
 | |
| 
 | |
| namespace android {
 | |
| namespace hardware {
 | |
| namespace thermal {
 | |
| namespace V2_0 {
 | |
| namespace implementation {
 | |
| 
 | |
| namespace {
 | |
| 
 | |
| static int nlErrorHandle(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) {
 | |
|     int *ret = reinterpret_cast<int *>(arg);
 | |
|     *ret = err->error;
 | |
|     LOG(ERROR) << __func__ << "nl_groups: " << nla->nl_groups << ", nl_pid: " << nla->nl_pid;
 | |
| 
 | |
|     return NL_STOP;
 | |
| }
 | |
| 
 | |
| static int nlFinishHandle(struct nl_msg *msg, void *arg) {
 | |
|     int *ret = reinterpret_cast<int *>(arg);
 | |
|     *ret = 1;
 | |
|     struct nlmsghdr *nlh = nlmsg_hdr(msg);
 | |
| 
 | |
|     LOG(VERBOSE) << __func__ << ": nlmsg type: " << nlh->nlmsg_type;
 | |
| 
 | |
|     return NL_OK;
 | |
| }
 | |
| 
 | |
| static int nlAckHandle(struct nl_msg *msg, void *arg) {
 | |
|     int *ret = reinterpret_cast<int *>(arg);
 | |
|     *ret = 1;
 | |
|     struct nlmsghdr *nlh = nlmsg_hdr(msg);
 | |
| 
 | |
|     LOG(VERBOSE) << __func__ << ": nlmsg type: " << nlh->nlmsg_type;
 | |
| 
 | |
|     return NL_OK;
 | |
| }
 | |
| 
 | |
| static int nlSeqCheckHandle(struct nl_msg *msg, void *arg) {
 | |
|     int *ret = reinterpret_cast<int *>(arg);
 | |
|     *ret = 1;
 | |
|     struct nlmsghdr *nlh = nlmsg_hdr(msg);
 | |
| 
 | |
|     LOG(VERBOSE) << __func__ << ": nlmsg type: " << nlh->nlmsg_type;
 | |
| 
 | |
|     return NL_OK;
 | |
| }
 | |
| 
 | |
| struct HandlerArgs {
 | |
|     const char *group;
 | |
|     int id;
 | |
| };
 | |
| 
 | |
| static int nlSendMsg(struct nl_sock *sock, struct nl_msg *msg,
 | |
|                      int (*rx_handler)(struct nl_msg *, void *), void *data) {
 | |
|     int err, done = 0;
 | |
| 
 | |
|     std::unique_ptr<nl_cb, decltype(&nl_cb_put)> cb(nl_cb_alloc(NL_CB_DEFAULT), nl_cb_put);
 | |
| 
 | |
|     err = nl_send_auto_complete(sock, msg);
 | |
|     if (err < 0)
 | |
|         return err;
 | |
| 
 | |
|     err = 0;
 | |
|     nl_cb_err(cb.get(), NL_CB_CUSTOM, nlErrorHandle, &err);
 | |
|     nl_cb_set(cb.get(), NL_CB_FINISH, NL_CB_CUSTOM, nlFinishHandle, &done);
 | |
|     nl_cb_set(cb.get(), NL_CB_ACK, NL_CB_CUSTOM, nlAckHandle, &done);
 | |
| 
 | |
|     if (rx_handler != NULL)
 | |
|         nl_cb_set(cb.get(), NL_CB_VALID, NL_CB_CUSTOM, rx_handler, data);
 | |
| 
 | |
|     while (err == 0 && done == 0) nl_recvmsgs(sock, cb.get());
 | |
| 
 | |
|     return err;
 | |
| }
 | |
| 
 | |
| static int nlFamilyHandle(struct nl_msg *msg, void *arg) {
 | |
|     struct HandlerArgs *grp = reinterpret_cast<struct HandlerArgs *>(arg);
 | |
|     struct nlattr *tb[CTRL_ATTR_MAX + 1];
 | |
|     struct genlmsghdr *gnlh = (struct genlmsghdr *)nlmsg_data(nlmsg_hdr(msg));
 | |
|     struct nlattr *mcgrp;
 | |
|     int rem_mcgrp;
 | |
| 
 | |
|     nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL);
 | |
| 
 | |
|     if (!tb[CTRL_ATTR_MCAST_GROUPS]) {
 | |
|         LOG(ERROR) << __func__ << "Multicast group not found";
 | |
|         return -1;
 | |
|     }
 | |
| 
 | |
|     nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], rem_mcgrp) {
 | |
|         struct nlattr *tb_mcgrp[CTRL_ATTR_MCAST_GRP_MAX + 1];
 | |
| 
 | |
|         nla_parse(tb_mcgrp, CTRL_ATTR_MCAST_GRP_MAX, reinterpret_cast<nlattr *>(nla_data(mcgrp)),
 | |
|                   nla_len(mcgrp), NULL);
 | |
| 
 | |
|         if (!tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME] || !tb_mcgrp[CTRL_ATTR_MCAST_GRP_ID])
 | |
|             continue;
 | |
| 
 | |
|         if (strncmp(reinterpret_cast<char *>(nla_data(tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME])),
 | |
|                     grp->group, nla_len(tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME])) != 0)
 | |
|             continue;
 | |
| 
 | |
|         grp->id = nla_get_u32(tb_mcgrp[CTRL_ATTR_MCAST_GRP_ID]);
 | |
| 
 | |
|         break;
 | |
|     }
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| static int nlGetMulticastId(struct nl_sock *sock, const char *family, const char *group) {
 | |
|     int err = 0, ctrlid;
 | |
|     struct HandlerArgs grp = {
 | |
|             .group = group,
 | |
|             .id = -ENOENT,
 | |
|     };
 | |
| 
 | |
|     std::unique_ptr<nl_msg, decltype(&nlmsg_free)> msg(nlmsg_alloc(), nlmsg_free);
 | |
| 
 | |
|     ctrlid = genl_ctrl_resolve(sock, "nlctrl");
 | |
| 
 | |
|     genlmsg_put(msg.get(), 0, 0, ctrlid, 0, 0, CTRL_CMD_GETFAMILY, 0);
 | |
| 
 | |
|     nla_put_string(msg.get(), CTRL_ATTR_FAMILY_NAME, family);
 | |
| 
 | |
|     err = nlSendMsg(sock, msg.get(), nlFamilyHandle, &grp);
 | |
|     if (err)
 | |
|         return err;
 | |
| 
 | |
|     err = grp.id;
 | |
|     LOG(INFO) << group << " multicast_id: " << grp.id;
 | |
| 
 | |
|     return err;
 | |
| }
 | |
| 
 | |
| static bool socketAddMembership(struct nl_sock *sock, const char *group) {
 | |
|     int mcid = nlGetMulticastId(sock, THERMAL_GENL_FAMILY_NAME, group);
 | |
|     if (mcid < 0) {
 | |
|         LOG(ERROR) << "Failed to get multicast id: " << group;
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     if (nl_socket_add_membership(sock, mcid)) {
 | |
|         LOG(ERROR) << "Failed to add netlink socket membership: " << group;
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     LOG(INFO) << "Added netlink socket membership: " << group;
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| static int handleEvent(struct nl_msg *n, void *arg) {
 | |
|     struct nlmsghdr *nlh = nlmsg_hdr(n);
 | |
|     struct genlmsghdr *glh = genlmsg_hdr(nlh);
 | |
|     struct nlattr *attrs[THERMAL_GENL_ATTR_MAX + 1];
 | |
|     int *tz_id = reinterpret_cast<int *>(arg);
 | |
| 
 | |
|     genlmsg_parse(nlh, 0, attrs, THERMAL_GENL_ATTR_MAX, NULL);
 | |
| 
 | |
|     if (glh->cmd == THERMAL_GENL_EVENT_TZ_TRIP_UP) {
 | |
|         LOG(INFO) << "THERMAL_GENL_EVENT_TZ_TRIP_UP";
 | |
|         if (attrs[THERMAL_GENL_ATTR_TZ_ID]) {
 | |
|             LOG(INFO) << "Thermal zone id: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
 | |
|             *tz_id = nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
 | |
|         }
 | |
|         if (attrs[THERMAL_GENL_ATTR_TZ_TRIP_ID])
 | |
|             LOG(INFO) << "Thermal zone trip id: "
 | |
|                       << nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_ID]);
 | |
|     }
 | |
| 
 | |
|     if (glh->cmd == THERMAL_GENL_EVENT_TZ_TRIP_DOWN) {
 | |
|         LOG(INFO) << "THERMAL_GENL_EVENT_TZ_TRIP_DOWN";
 | |
|         if (attrs[THERMAL_GENL_ATTR_TZ_ID]) {
 | |
|             LOG(INFO) << "Thermal zone id: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
 | |
|             *tz_id = nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
 | |
|         }
 | |
|         if (attrs[THERMAL_GENL_ATTR_TZ_TRIP_ID])
 | |
|             LOG(INFO) << "Thermal zone trip id: "
 | |
|                       << nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_ID]);
 | |
|     }
 | |
| 
 | |
|     if (glh->cmd == THERMAL_GENL_EVENT_TZ_GOV_CHANGE) {
 | |
|         LOG(INFO) << "THERMAL_GENL_EVENT_TZ_GOV_CHANGE";
 | |
|         if (attrs[THERMAL_GENL_ATTR_TZ_ID]) {
 | |
|             LOG(INFO) << "Thermal zone id: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
 | |
|             *tz_id = nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
 | |
|         }
 | |
|         if (attrs[THERMAL_GENL_ATTR_GOV_NAME])
 | |
|             LOG(INFO) << "Governor name: " << nla_get_string(attrs[THERMAL_GENL_ATTR_GOV_NAME]);
 | |
|     }
 | |
| 
 | |
|     if (glh->cmd == THERMAL_GENL_EVENT_TZ_CREATE) {
 | |
|         LOG(INFO) << "THERMAL_GENL_EVENT_TZ_CREATE";
 | |
|         if (attrs[THERMAL_GENL_ATTR_TZ_ID]) {
 | |
|             LOG(INFO) << "Thermal zone id: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
 | |
|             *tz_id = nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
 | |
|         }
 | |
|         if (attrs[THERMAL_GENL_ATTR_TZ_NAME])
 | |
|             LOG(INFO) << "Thermal zone name: " << nla_get_string(attrs[THERMAL_GENL_ATTR_TZ_NAME]);
 | |
|     }
 | |
| 
 | |
|     if (glh->cmd == THERMAL_GENL_EVENT_TZ_DELETE) {
 | |
|         LOG(INFO) << "THERMAL_GENL_EVENT_TZ_DELETE";
 | |
|         if (attrs[THERMAL_GENL_ATTR_TZ_ID]) {
 | |
|             LOG(INFO) << "Thermal zone id: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
 | |
|             *tz_id = nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if (glh->cmd == THERMAL_GENL_EVENT_TZ_DISABLE) {
 | |
|         LOG(INFO) << "THERMAL_GENL_EVENT_TZ_DISABLE";
 | |
|         if (attrs[THERMAL_GENL_ATTR_TZ_ID]) {
 | |
|             LOG(INFO) << "Thermal zone id: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
 | |
|             *tz_id = nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if (glh->cmd == THERMAL_GENL_EVENT_TZ_ENABLE) {
 | |
|         LOG(INFO) << "THERMAL_GENL_EVENT_TZ_ENABLE";
 | |
|         if (attrs[THERMAL_GENL_ATTR_TZ_ID]) {
 | |
|             LOG(INFO) << "Thermal zone id: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
 | |
|             *tz_id = nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if (glh->cmd == THERMAL_GENL_EVENT_TZ_TRIP_CHANGE) {
 | |
|         LOG(INFO) << "THERMAL_GENL_EVENT_TZ_TRIP_CHANGE";
 | |
|         if (attrs[THERMAL_GENL_ATTR_TZ_ID]) {
 | |
|             LOG(INFO) << "Thermal zone id: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
 | |
|             *tz_id = nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
 | |
|         }
 | |
|         if (attrs[THERMAL_GENL_ATTR_TZ_TRIP_ID])
 | |
|             LOG(INFO) << "Trip id:: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_ID]);
 | |
|         if (attrs[THERMAL_GENL_ATTR_TZ_TRIP_TYPE])
 | |
|             LOG(INFO) << "Trip type: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_TYPE]);
 | |
|         if (attrs[THERMAL_GENL_ATTR_TZ_TRIP_TEMP])
 | |
|             LOG(INFO) << "Trip temp: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_TEMP]);
 | |
|         if (attrs[THERMAL_GENL_ATTR_TZ_TRIP_HYST])
 | |
|             LOG(INFO) << "Trip hyst: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_HYST]);
 | |
|     }
 | |
| 
 | |
|     if (glh->cmd == THERMAL_GENL_EVENT_TZ_TRIP_ADD) {
 | |
|         LOG(INFO) << "THERMAL_GENL_EVENT_TZ_TRIP_ADD";
 | |
|         if (attrs[THERMAL_GENL_ATTR_TZ_ID])
 | |
|             LOG(INFO) << "Thermal zone id: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
 | |
|         if (attrs[THERMAL_GENL_ATTR_TZ_TRIP_ID])
 | |
|             LOG(INFO) << "Trip id:: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_ID]);
 | |
|         if (attrs[THERMAL_GENL_ATTR_TZ_TRIP_TYPE])
 | |
|             LOG(INFO) << "Trip type: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_TYPE]);
 | |
|         if (attrs[THERMAL_GENL_ATTR_TZ_TRIP_TEMP])
 | |
|             LOG(INFO) << "Trip temp: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_TEMP]);
 | |
|         if (attrs[THERMAL_GENL_ATTR_TZ_TRIP_HYST])
 | |
|             LOG(INFO) << "Trip hyst: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_HYST]);
 | |
|     }
 | |
| 
 | |
|     if (glh->cmd == THERMAL_GENL_EVENT_TZ_TRIP_DELETE) {
 | |
|         LOG(INFO) << "THERMAL_GENL_EVENT_TZ_TRIP_DELETE";
 | |
|         if (attrs[THERMAL_GENL_ATTR_TZ_ID]) {
 | |
|             LOG(INFO) << "Thermal zone id: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
 | |
|             *tz_id = nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
 | |
|         }
 | |
|         if (attrs[THERMAL_GENL_ATTR_TZ_TRIP_ID])
 | |
|             LOG(INFO) << "Trip id:: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TRIP_ID]);
 | |
|     }
 | |
| 
 | |
|     if (glh->cmd == THERMAL_GENL_EVENT_CDEV_STATE_UPDATE) {
 | |
|         LOG(INFO) << "THERMAL_GENL_EVENT_CDEV_STATE_UPDATE";
 | |
|         if (attrs[THERMAL_GENL_ATTR_CDEV_ID])
 | |
|             LOG(INFO) << "Cooling device id: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_CDEV_ID]);
 | |
|         if (attrs[THERMAL_GENL_ATTR_CDEV_CUR_STATE])
 | |
|             LOG(INFO) << "Cooling device current state: "
 | |
|                       << nla_get_u32(attrs[THERMAL_GENL_ATTR_CDEV_CUR_STATE]);
 | |
|     }
 | |
| 
 | |
|     if (glh->cmd == THERMAL_GENL_EVENT_CDEV_ADD) {
 | |
|         LOG(INFO) << "THERMAL_GENL_EVENT_CDEV_ADD";
 | |
|         if (attrs[THERMAL_GENL_ATTR_CDEV_NAME])
 | |
|             LOG(INFO) << "Cooling device name: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_CDEV_NAME]);
 | |
|         if (attrs[THERMAL_GENL_ATTR_CDEV_ID])
 | |
|             LOG(INFO) << "Cooling device id: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_CDEV_ID]);
 | |
|         if (attrs[THERMAL_GENL_ATTR_CDEV_MAX_STATE])
 | |
|             LOG(INFO) << "Cooling device max state: "
 | |
|                       << nla_get_u32(attrs[THERMAL_GENL_ATTR_CDEV_MAX_STATE]);
 | |
|     }
 | |
| 
 | |
|     if (glh->cmd == THERMAL_GENL_EVENT_CDEV_DELETE) {
 | |
|         LOG(INFO) << "THERMAL_GENL_EVENT_CDEV_DELETE";
 | |
|         if (attrs[THERMAL_GENL_ATTR_CDEV_ID])
 | |
|             LOG(INFO) << "Cooling device id: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_CDEV_ID]);
 | |
|     }
 | |
| 
 | |
|     if (glh->cmd == THERMAL_GENL_SAMPLING_TEMP) {
 | |
|         LOG(INFO) << "THERMAL_GENL_SAMPLING_TEMP";
 | |
|         if (attrs[THERMAL_GENL_ATTR_TZ_ID]) {
 | |
|             LOG(INFO) << "Thermal zone id: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
 | |
|             *tz_id = nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
 | |
|         }
 | |
|         if (attrs[THERMAL_GENL_ATTR_TZ_TEMP])
 | |
|             LOG(INFO) << "Thermal zone temp: " << nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TEMP]);
 | |
|     }
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| }  // namespace
 | |
| 
 | |
| void ThermalWatcher::registerFilesToWatch(const std::set<std::string> &sensors_to_watch) {
 | |
|     LOG(INFO) << "Uevent register file to watch...";
 | |
|     monitored_sensors_.insert(sensors_to_watch.begin(), sensors_to_watch.end());
 | |
| 
 | |
|     uevent_fd_.reset((TEMP_FAILURE_RETRY(uevent_open_socket(64 * 1024, true))));
 | |
|     if (uevent_fd_.get() < 0) {
 | |
|         LOG(ERROR) << "failed to open uevent socket";
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     fcntl(uevent_fd_, F_SETFL, O_NONBLOCK);
 | |
| 
 | |
|     looper_->addFd(uevent_fd_.get(), 0, Looper::EVENT_INPUT, nullptr, nullptr);
 | |
|     sleep_ms_ = std::chrono::milliseconds(0);
 | |
|     last_update_time_ = boot_clock::now();
 | |
| }
 | |
| 
 | |
| void ThermalWatcher::registerFilesToWatchNl(const std::set<std::string> &sensors_to_watch) {
 | |
|     LOG(INFO) << "Thermal genl register file to watch...";
 | |
|     monitored_sensors_.insert(sensors_to_watch.begin(), sensors_to_watch.end());
 | |
| 
 | |
|     sk_thermal = nl_socket_alloc();
 | |
|     if (!sk_thermal) {
 | |
|         LOG(ERROR) << "nl_socket_alloc failed";
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     if (genl_connect(sk_thermal)) {
 | |
|         LOG(ERROR) << "genl_connect failed: sk_thermal";
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     thermal_genl_fd_.reset(nl_socket_get_fd(sk_thermal));
 | |
|     if (thermal_genl_fd_.get() < 0) {
 | |
|         LOG(ERROR) << "Failed to create thermal netlink socket";
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     if (!socketAddMembership(sk_thermal, THERMAL_GENL_EVENT_GROUP_NAME)) {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     /*
 | |
|      * Currently, only the update_temperature() will send thermal genl samlping events
 | |
|      * from kernel. To avoid thermal-hal busy because samlping events are sent
 | |
|      * too frequently, ignore thermal genl samlping events until we figure out how to use it.
 | |
|      *
 | |
|     if (!socketAddMembership(sk_thermal, THERMAL_GENL_SAMPLING_GROUP_NAME)) {
 | |
|         return;
 | |
|     }
 | |
|     */
 | |
| 
 | |
|     fcntl(thermal_genl_fd_, F_SETFL, O_NONBLOCK);
 | |
|     looper_->addFd(thermal_genl_fd_.get(), 0, Looper::EVENT_INPUT, nullptr, nullptr);
 | |
|     sleep_ms_ = std::chrono::milliseconds(0);
 | |
|     last_update_time_ = boot_clock::now();
 | |
| }
 | |
| 
 | |
| bool ThermalWatcher::startWatchingDeviceFiles() {
 | |
|     if (cb_) {
 | |
|         auto ret = this->run("FileWatcherThread", PRIORITY_HIGHEST);
 | |
|         if (ret != NO_ERROR) {
 | |
|             LOG(ERROR) << "ThermalWatcherThread start fail";
 | |
|             return false;
 | |
|         } else {
 | |
|             LOG(INFO) << "ThermalWatcherThread started";
 | |
|             return true;
 | |
|         }
 | |
|     }
 | |
|     return false;
 | |
| }
 | |
| void ThermalWatcher::parseUevent(std::set<std::string> *sensors_set) {
 | |
|     bool thermal_event = false;
 | |
|     constexpr int kUeventMsgLen = 2048;
 | |
|     char msg[kUeventMsgLen + 2];
 | |
|     char *cp;
 | |
| 
 | |
|     while (true) {
 | |
|         int n = uevent_kernel_multicast_recv(uevent_fd_.get(), msg, kUeventMsgLen);
 | |
|         if (n <= 0) {
 | |
|             if (errno != EAGAIN && errno != EWOULDBLOCK) {
 | |
|                 LOG(ERROR) << "Error reading from Uevent Fd";
 | |
|             }
 | |
|             break;
 | |
|         }
 | |
| 
 | |
|         if (n >= kUeventMsgLen) {
 | |
|             LOG(ERROR) << "Uevent overflowed buffer, discarding";
 | |
|             continue;
 | |
|         }
 | |
| 
 | |
|         msg[n] = '\0';
 | |
|         msg[n + 1] = '\0';
 | |
| 
 | |
|         cp = msg;
 | |
|         while (*cp) {
 | |
|             std::string uevent = cp;
 | |
|             auto findSubSystemThermal = uevent.find("SUBSYSTEM=thermal");
 | |
|             if (!thermal_event) {
 | |
|                 if (!uevent.find("SUBSYSTEM=")) {
 | |
|                     if (findSubSystemThermal != std::string::npos) {
 | |
|                         thermal_event = true;
 | |
|                     } else {
 | |
|                         break;
 | |
|                     }
 | |
|                 }
 | |
|             } else {
 | |
|                 auto start_pos = uevent.find("NAME=");
 | |
|                 if (start_pos != std::string::npos) {
 | |
|                     start_pos += 5;
 | |
|                     std::string name = uevent.substr(start_pos);
 | |
|                     if (std::find(monitored_sensors_.begin(), monitored_sensors_.end(), name) !=
 | |
|                         monitored_sensors_.end()) {
 | |
|                         sensors_set->insert(name);
 | |
|                     }
 | |
|                     break;
 | |
|                 }
 | |
|             }
 | |
|             while (*cp++) {
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| // TODO(b/175367921): Consider for potentially adding more type of event in the function
 | |
| // instead of just add the sensors to the list.
 | |
| void ThermalWatcher::parseGenlink(std::set<std::string> *sensors_set) {
 | |
|     int err = 0, done = 0, tz_id = -1;
 | |
| 
 | |
|     std::unique_ptr<nl_cb, decltype(&nl_cb_put)> cb(nl_cb_alloc(NL_CB_DEFAULT), nl_cb_put);
 | |
| 
 | |
|     nl_cb_err(cb.get(), NL_CB_CUSTOM, nlErrorHandle, &err);
 | |
|     nl_cb_set(cb.get(), NL_CB_FINISH, NL_CB_CUSTOM, nlFinishHandle, &done);
 | |
|     nl_cb_set(cb.get(), NL_CB_ACK, NL_CB_CUSTOM, nlAckHandle, &done);
 | |
|     nl_cb_set(cb.get(), NL_CB_SEQ_CHECK, NL_CB_CUSTOM, nlSeqCheckHandle, &done);
 | |
|     nl_cb_set(cb.get(), NL_CB_VALID, NL_CB_CUSTOM, handleEvent, &tz_id);
 | |
| 
 | |
|     while (!done && !err) {
 | |
|         nl_recvmsgs(sk_thermal, cb.get());
 | |
| 
 | |
|         if (tz_id < 0) {
 | |
|             break;
 | |
|         }
 | |
| 
 | |
|         std::string name;
 | |
|         if (getThermalZoneTypeById(tz_id, &name) &&
 | |
|             std::find(monitored_sensors_.begin(), monitored_sensors_.end(), name) !=
 | |
|                     monitored_sensors_.end()) {
 | |
|             sensors_set->insert(name);
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| void ThermalWatcher::wake() {
 | |
|     looper_->wake();
 | |
| }
 | |
| 
 | |
| bool ThermalWatcher::threadLoop() {
 | |
|     LOG(VERBOSE) << "ThermalWatcher polling...";
 | |
| 
 | |
|     int fd;
 | |
|     std::set<std::string> sensors;
 | |
| 
 | |
|     auto time_elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(boot_clock::now() -
 | |
|                                                                                  last_update_time_);
 | |
| 
 | |
|     if (time_elapsed_ms < sleep_ms_ &&
 | |
|         looper_->pollOnce(sleep_ms_.count(), &fd, nullptr, nullptr) >= 0) {
 | |
|         ATRACE_NAME("ThermalWatcher::threadLoop - receive event");
 | |
|         if (fd != uevent_fd_.get() && fd != thermal_genl_fd_.get()) {
 | |
|             return true;
 | |
|         } else if (fd == thermal_genl_fd_.get()) {
 | |
|             parseGenlink(&sensors);
 | |
|         } else if (fd == uevent_fd_.get()) {
 | |
|             parseUevent(&sensors);
 | |
|         }
 | |
|         // Ignore cb_ if uevent is not from monitored sensors
 | |
|         if (sensors.size() == 0) {
 | |
|             return true;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     sleep_ms_ = cb_(sensors);
 | |
|     last_update_time_ = boot_clock::now();
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| }  // namespace implementation
 | |
| }  // namespace V2_0
 | |
| }  // namespace thermal
 | |
| }  // namespace hardware
 | |
| }  // namespace android
 |