• 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,bool uevent_monitor)38 void ThermalWatcher::registerFilesToWatch(const std::set<std::string> &sensors_to_watch,
39                                           bool uevent_monitor) {
40     monitored_sensors_.insert(sensors_to_watch.begin(), sensors_to_watch.end());
41     if (!uevent_monitor) {
42         is_polling_ = true;
43         return;
44     }
45     uevent_fd_.reset((TEMP_FAILURE_RETRY(uevent_open_socket(64 * 1024, true))));
46     if (uevent_fd_.get() < 0) {
47         LOG(ERROR) << "failed to open uevent socket";
48         is_polling_ = true;
49         return;
50     }
51 
52     fcntl(uevent_fd_, F_SETFL, O_NONBLOCK);
53 
54     looper_->addFd(uevent_fd_.get(), 0, Looper::EVENT_INPUT, nullptr, nullptr);
55     is_polling_ = false;
56     thermal_triggered_ = true;
57     last_update_time_ = boot_clock::now();
58 }
59 
startWatchingDeviceFiles()60 bool ThermalWatcher::startWatchingDeviceFiles() {
61     if (cb_) {
62         auto ret = this->run("FileWatcherThread", PRIORITY_HIGHEST);
63         if (ret != NO_ERROR) {
64             LOG(ERROR) << "ThermalWatcherThread start fail";
65             return false;
66         } else {
67             LOG(INFO) << "ThermalWatcherThread started";
68             return true;
69         }
70     }
71     return false;
72 }
parseUevent(std::set<std::string> * sensors_set)73 void ThermalWatcher::parseUevent(std::set<std::string> *sensors_set) {
74     bool thermal_event = false;
75     constexpr int kUeventMsgLen = 2048;
76     char msg[kUeventMsgLen + 2];
77     char *cp;
78 
79     while (true) {
80         int n = uevent_kernel_multicast_recv(uevent_fd_.get(), msg, kUeventMsgLen);
81         if (n <= 0) {
82             if (errno != EAGAIN && errno != EWOULDBLOCK) {
83                 LOG(ERROR) << "Error reading from Uevent Fd";
84             }
85             break;
86         }
87 
88         if (n >= kUeventMsgLen) {
89             LOG(ERROR) << "Uevent overflowed buffer, discarding";
90             continue;
91         }
92 
93         msg[n] = '\0';
94         msg[n + 1] = '\0';
95 
96         cp = msg;
97         while (*cp) {
98             std::string uevent = cp;
99             if (!thermal_event) {
100                 if (uevent.find("SUBSYSTEM=") == 0) {
101                     if (uevent.find("SUBSYSTEM=thermal") != std::string::npos) {
102                         thermal_event = true;
103                     } else {
104                         break;
105                     }
106                 }
107             } else {
108                 auto start_pos = uevent.find("NAME=");
109                 if (start_pos != std::string::npos) {
110                     start_pos += 5;
111                     std::string name = uevent.substr(start_pos);
112                     if (std::find(monitored_sensors_.begin(), monitored_sensors_.end(), name) !=
113                         monitored_sensors_.end()) {
114                         sensors_set->insert(name);
115                     }
116                     break;
117                 }
118             }
119             while (*cp++) {
120             }
121         }
122     }
123 }
124 
wake()125 void ThermalWatcher::wake() {
126     looper_->wake();
127 }
128 
threadLoop()129 bool ThermalWatcher::threadLoop() {
130     LOG(VERBOSE) << "ThermalWatcher polling...";
131     // Polling interval 2s
132     static constexpr int kMinPollIntervalMs = 2000;
133     // Max uevent timeout 5mins
134     static constexpr int kUeventPollTimeoutMs = 300000;
135     int fd;
136     std::set<std::string> sensors;
137 
138     auto time_elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(boot_clock::now() -
139                                                                                  last_update_time_)
140                                    .count();
141     int timeout = (thermal_triggered_ || is_polling_) ? kMinPollIntervalMs : kUeventPollTimeoutMs;
142     if (time_elapsed_ms < timeout && looper_->pollOnce(timeout, &fd, nullptr, nullptr) >= 0) {
143         if (fd != uevent_fd_.get()) {
144             return true;
145         }
146         parseUevent(&sensors);
147         // Ignore cb_ if uevent is not from monitored sensors
148         if (sensors.size() == 0) {
149             return true;
150         }
151     }
152     thermal_triggered_ = cb_(sensors);
153     last_update_time_ = boot_clock::now();
154     return true;
155 }
156 
157 }  // namespace implementation
158 }  // namespace V2_0
159 }  // namespace thermal
160 }  // namespace hardware
161 }  // namespace android
162