• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <sys/inotify.h>
19 #include <sys/resource.h>
20 #include <sys/types.h>
21 #include <chrono>
22 #include <fstream>
23 
24 #include <android-base/file.h>
25 #include <android-base/logging.h>
26 #include <android-base/strings.h>
27 
28 #include "thermal_watcher.h"
29 
30 namespace android {
31 namespace hardware {
32 namespace thermal {
33 namespace V2_0 {
34 namespace implementation {
35 
36 using std::chrono_literals::operator""ms;
37 
registerFilesToWatch(const std::set<std::string> & sensors_to_watch,const std::set<std::string> & cdev_to_watch,bool uevent_monitor)38 void ThermalWatcher::registerFilesToWatch(const std::set<std::string> &sensors_to_watch,
39                                           const std::set<std::string> &cdev_to_watch,
40                                           bool uevent_monitor) {
41     int flags = O_RDONLY | O_CLOEXEC | O_BINARY;
42 
43     for (const auto &path : cdev_to_watch) {
44         android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), flags)));
45         if (fd == -1) {
46             PLOG(ERROR) << "failed to watch: " << path;
47             continue;
48         }
49         watch_to_file_path_map_.emplace(fd.get(), path);
50         fds_.emplace_back(std::move(fd));
51         looper_->addFd(fd.get(), 0, Looper::EVENT_INPUT, nullptr, nullptr);
52     }
53     monitored_sensors_.insert(sensors_to_watch.begin(), sensors_to_watch.end());
54     if (!uevent_monitor) {
55         is_polling_ = true;
56         return;
57     }
58     uevent_fd_.reset((TEMP_FAILURE_RETRY(uevent_open_socket(64 * 1024, true))));
59     if (uevent_fd_.get() < 0) {
60         LOG(ERROR) << "failed to open uevent socket";
61         is_polling_ = true;
62         return;
63     }
64 
65     fcntl(uevent_fd_, F_SETFL, O_NONBLOCK);
66 
67     looper_->addFd(uevent_fd_.get(), 0, Looper::EVENT_INPUT, nullptr, nullptr);
68     is_polling_ = false;
69     thermal_triggered_ = true;
70 }
71 
startWatchingDeviceFiles()72 bool ThermalWatcher::startWatchingDeviceFiles() {
73     if (cb_) {
74         auto ret = this->run("FileWatcherThread", PRIORITY_HIGHEST);
75         if (ret != NO_ERROR) {
76             LOG(ERROR) << "ThermalWatcherThread start fail";
77             return false;
78         } else {
79             LOG(INFO) << "ThermalWatcherThread started";
80             return true;
81         }
82     }
83     return false;
84 }
parseUevent(std::set<std::string> * sensors_set)85 void ThermalWatcher::parseUevent(std::set<std::string> *sensors_set) {
86     bool thermal_event = false;
87     constexpr int kUeventMsgLen = 2048;
88     char msg[kUeventMsgLen + 2];
89     char *cp;
90 
91     while (true) {
92         int n = uevent_kernel_multicast_recv(uevent_fd_.get(), msg, kUeventMsgLen);
93         if (n <= 0) {
94             if (errno != EAGAIN && errno != EWOULDBLOCK) {
95                 LOG(ERROR) << "Error reading from Uevent Fd";
96             }
97             break;
98         }
99 
100         if (n >= kUeventMsgLen) {
101             LOG(ERROR) << "Uevent overflowed buffer, discarding";
102             continue;
103         }
104 
105         msg[n] = '\0';
106         msg[n + 1] = '\0';
107 
108         cp = msg;
109         while (*cp) {
110             std::string uevent = cp;
111             if (!thermal_event) {
112                 if (uevent.find("SUBSYSTEM=") == 0) {
113                     if (uevent.find("SUBSYSTEM=thermal") != std::string::npos) {
114                         thermal_event = true;
115                     } else {
116                         break;
117                     }
118                 }
119             } else {
120                 auto start_pos = uevent.find("NAME=");
121                 if (start_pos != std::string::npos) {
122                     start_pos += 5;
123                     std::string name = uevent.substr(start_pos);
124                     if (std::find(monitored_sensors_.begin(), monitored_sensors_.end(), name) !=
125                         monitored_sensors_.end()) {
126                         sensors_set->insert(name);
127                     }
128                     break;
129                 }
130             }
131             while (*cp++) {
132             }
133         }
134     }
135 }
136 
wake()137 void ThermalWatcher::wake() {
138     looper_->wake();
139 }
140 
threadLoop()141 bool ThermalWatcher::threadLoop() {
142     LOG(VERBOSE) << "ThermalWatcher polling...";
143     // Polling interval 2s
144     static constexpr int kMinPollIntervalMs = 2000;
145     // Max uevent timeout 5mins
146     static constexpr int kUeventPollTimeoutMs = 300000;
147     int fd;
148     std::set<std::string> sensors;
149 
150     int timeout = (thermal_triggered_ || is_polling_) ? kMinPollIntervalMs : kUeventPollTimeoutMs;
151     if (looper_->pollOnce(timeout, &fd, nullptr, nullptr) >= 0) {
152         if (fd != uevent_fd_.get()) {
153             return true;
154         }
155         parseUevent(&sensors);
156         // Ignore cb_ if uevent is not from monitored sensors
157         if (sensors.size() == 0) {
158             return true;
159         }
160     }
161     thermal_triggered_ = cb_(sensors);
162     return true;
163 }
164 
165 }  // namespace implementation
166 }  // namespace V2_0
167 }  // namespace thermal
168 }  // namespace hardware
169 }  // namespace android
170