1 /*
2 * Copyright (C) 2021 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 LOG_TAG "libPixelUsbOverheat"
18
19 #include "include/pixelusb/UsbOverheatEvent.h"
20
21 #include <time.h>
22
23 namespace android {
24 namespace hardware {
25 namespace google {
26 namespace pixel {
27 namespace usb {
28
29 // Start monitoring the temperature
30 static volatile bool monitorTemperature;
31
32 constexpr int kEpollEvents = 10;
33 constexpr char kOverheatLock[] = "overheat";
34 constexpr char kWakeLockPath[] = "/sys/power/wake_lock";
35 constexpr char kWakeUnlockPath[] = "/sys/power/wake_unlock";
36
addEpollFdWakeUp(const unique_fd & epfd,const unique_fd & fd)37 int addEpollFdWakeUp(const unique_fd &epfd, const unique_fd &fd) {
38 struct epoll_event event;
39 int ret;
40
41 event.data.fd = fd;
42 event.events = EPOLLIN | EPOLLWAKEUP;
43
44 ret = epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event);
45 if (ret)
46 ALOGE("epoll_ctl error %d", errno);
47
48 return ret;
49 }
50
UsbOverheatEvent(const ZoneInfo & monitored_zone,const std::vector<ZoneInfo> & queried_zones,const int & monitor_interval_sec)51 UsbOverheatEvent::UsbOverheatEvent(const ZoneInfo &monitored_zone,
52 const std::vector<ZoneInfo> &queried_zones,
53 const int &monitor_interval_sec)
54 : monitored_zone_(monitored_zone),
55 queried_zones_(queried_zones),
56 monitor_interval_sec_(monitor_interval_sec),
57 monitor_() {
58 int fd = timerfd_create(CLOCK_BOOTTIME_ALARM, 0);
59 if (fd < 0) {
60 ALOGE("timerfd_create failed: %d", errno);
61 }
62
63 unique_fd timerFd(timerfd_create(CLOCK_BOOTTIME_ALARM, 0));
64 if (timerFd == -1) {
65 ALOGE("timerFd failed to create %d", errno);
66 abort();
67 }
68
69 unique_fd epollFd(epoll_create(2));
70 if (epollFd == -1) {
71 ALOGE("epoll_fd_ failed to create %d", errno);
72 abort();
73 }
74
75 unique_fd eventFd(eventfd(0, 0));
76 if (eventFd == -1) {
77 ALOGE("event_fd_ failed to create %d", errno);
78 abort();
79 }
80
81 if (addEpollFdWakeUp(epollFd, timerFd) == -1) {
82 ALOGE("Adding timerFd failed");
83 abort();
84 }
85
86 if (addEpollFdWakeUp(epollFd, eventFd) == -1) {
87 ALOGE("Adding eventFd failed");
88 abort();
89 }
90
91 epoll_fd_ = move(epollFd);
92 timer_fd_ = move(timerFd);
93 event_fd_ = move(eventFd);
94
95 monitor_ = unique_ptr<thread>(new thread(this->monitorThread, this));
96 registerListener();
97 }
98
99 static int wakelock_cnt = 0;
100 static std::mutex wakelock_lock;
101
wakeLockAcquire()102 static void wakeLockAcquire() {
103 lock_guard<mutex> lock(wakelock_lock);
104
105 wakelock_cnt++;
106 if (wakelock_cnt == 1) {
107 ALOGV("Acquire wakelock");
108 if (!WriteStringToFile(kOverheatLock, kWakeLockPath)) {
109 ALOGE("Failed to acquire wake lock string");
110 }
111 }
112 }
113
wakeLockRelease()114 static void wakeLockRelease() {
115 lock_guard<mutex> lock(wakelock_lock);
116
117 wakelock_cnt--;
118 if (wakelock_cnt == 0) {
119 ALOGV("Release wakelock");
120 if (!WriteStringToFile(kOverheatLock, kWakeUnlockPath)) {
121 ALOGE("Failed to acquire wake lock string");
122 }
123 }
124 }
125
monitorThread(void * param)126 void *UsbOverheatEvent::monitorThread(void *param) {
127 UsbOverheatEvent *overheatEvent = (UsbOverheatEvent *)param;
128 struct epoll_event events[kEpollEvents];
129 struct itimerspec delay = itimerspec();
130
131 while (true) {
132 uint64_t fired;
133 float temperature = 0;
134 string status;
135
136 for (vector<ZoneInfo>::size_type i = 0; i < overheatEvent->queried_zones_.size(); i++) {
137 if (overheatEvent->getCurrentTemperature(overheatEvent->queried_zones_[i].name_,
138 &temperature)) {
139 if (i == 0)
140 overheatEvent->max_overheat_temp_ =
141 max(temperature, overheatEvent->max_overheat_temp_);
142 status.append(overheatEvent->queried_zones_[i].name_);
143 status.append(":");
144 status.append(std::to_string(temperature));
145 status.append(" ");
146 }
147 }
148 ALOGW("%s", status.c_str());
149
150 delay.it_value.tv_sec = monitorTemperature ? overheatEvent->monitor_interval_sec_ : 0;
151 int ret = timerfd_settime(overheatEvent->timer_fd_, 0, &delay, NULL);
152 if (ret < 0) {
153 ALOGE("timerfd_settime failed. err:%d tv_sec:%ld", errno, delay.it_value.tv_sec);
154 continue;
155 }
156
157 wakeLockRelease();
158 int nrEvents = epoll_wait(overheatEvent->epoll_fd_, events, kEpollEvents, -1);
159 wakeLockAcquire();
160 if (nrEvents <= 0) {
161 ALOGE("nrEvents negative skipping");
162 continue;
163 }
164
165 for (int i = 0; i < nrEvents; i++) {
166 ALOGV("event=%u on fd=%d\n", events[i].events, events[i].data.fd);
167
168 if (events[i].data.fd == overheatEvent->timer_fd_) {
169 ALOGI("Wake up caused by timer fd");
170 int numRead = read(overheatEvent->timer_fd_, &fired, sizeof(fired));
171 if (numRead != sizeof(fired)) {
172 ALOGV("numRead incorrect");
173 }
174 if (fired != 1) {
175 ALOGV("Fired not set to 1");
176 }
177 } else {
178 ALOGI("Wake up caused by event fd");
179 read(overheatEvent->event_fd_, &fired, sizeof(fired));
180 }
181 }
182 }
183
184 return NULL;
185 }
186
registerListener()187 bool UsbOverheatEvent::registerListener() {
188 ALOGV("UsbOverheatEvent::registerListener");
189 sp<IServiceManager> sm = IServiceManager::getService();
190 if (sm == NULL) {
191 ALOGE("Hardware service manager is not running");
192 return false;
193 }
194 Return<bool> result = sm->registerForNotifications(IThermal::descriptor, "", this);
195 if (result.isOk()) {
196 return true;
197 }
198 ALOGE("Failed to register for hardware service manager notifications: %s",
199 result.description().c_str());
200 return false;
201 }
202
wakeupMonitor()203 void UsbOverheatEvent::wakeupMonitor() {
204 // <flag> value does not have any significance here
205 uint64_t flag = 100;
206
207 unsigned long ret = TEMP_FAILURE_RETRY(write(event_fd_, &flag, sizeof(flag)));
208 if (ret < 0) {
209 ALOGE("Error writing eventfd errno=%d", errno);
210 }
211 }
212
startRecording()213 bool UsbOverheatEvent::startRecording() {
214 ALOGI("Start recording. monitorTemperature:%d", monitorTemperature ? 1 : 0);
215 // Bail out if temperature was being monitored previously
216 if (monitorTemperature)
217 return true;
218
219 wakeLockAcquire();
220 monitorTemperature = true;
221 wakeupMonitor();
222 return true;
223 }
224
stopRecording()225 bool UsbOverheatEvent::stopRecording() {
226 ALOGI("Stop recording. monitorTemperature:%d", monitorTemperature ? 1 : 0);
227 // Bail out if temperature was not being monitored previously
228 if (!monitorTemperature)
229 return true;
230
231 wakeLockRelease();
232 monitorTemperature = false;
233 wakeupMonitor();
234
235 return true;
236 }
237
getCurrentTemperature(const string & name,float * temp)238 bool UsbOverheatEvent::getCurrentTemperature(const string &name, float *temp) {
239 ThermalStatus thermal_status;
240 hidl_vec<Temperature> thermal_temperatures;
241
242 if (thermal_service_ == NULL)
243 return false;
244
245 auto ret = thermal_service_->getCurrentTemperatures(
246 false, TemperatureType::USB_PORT,
247 [&](ThermalStatus status, hidl_vec<Temperature> temperatures) {
248 thermal_status = status;
249 thermal_temperatures = temperatures;
250 });
251
252 if (ret.isOk() && thermal_status.code == ThermalStatusCode::SUCCESS) {
253 for (auto temperature : thermal_temperatures) {
254 if (temperature.name == name) {
255 *temp = temperature.value;
256 return true;
257 }
258 }
259 }
260 return false;
261 }
262
getMaxOverheatTemperature()263 float UsbOverheatEvent::getMaxOverheatTemperature() {
264 return max_overheat_temp_;
265 }
266
onRegistration(const hidl_string &,const hidl_string &,bool)267 Return<void> UsbOverheatEvent::onRegistration(const hidl_string & /*fully_qualified_name*/,
268 const hidl_string & /*instance_name*/,
269 bool /*pre_existing*/) {
270 ThermalStatus thermal_status;
271
272 thermal_service_ = IThermal::getService();
273 if (thermal_service_ == NULL) {
274 ALOGE("Unable to get Themal Service");
275 return Void();
276 }
277
278 auto ret = thermal_service_->registerThermalChangedCallback(
279 this, true, monitored_zone_.type_,
280 [&](ThermalStatus status) { thermal_status = status; });
281
282 if (!ret.isOk() || thermal_status.code != ThermalStatusCode::SUCCESS) {
283 ALOGE("failed to register thermal changed callback!");
284 }
285
286 return Void();
287 }
288
notifyThrottling(const Temperature & temperature)289 Return<void> UsbOverheatEvent::notifyThrottling(const Temperature &temperature) {
290 ALOGV("notifyThrottling '%s' T=%2.2f throttlingStatus=%d", temperature.name.c_str(),
291 temperature.value, temperature.throttlingStatus);
292 if (temperature.type == monitored_zone_.type_) {
293 if (temperature.throttlingStatus >= monitored_zone_.severity_) {
294 startRecording();
295 } else {
296 stopRecording();
297 }
298 }
299 return Void();
300 }
301
ZoneInfo(const TemperatureType & type,const string & name,const ThrottlingSeverity & severity)302 ZoneInfo::ZoneInfo(const TemperatureType &type, const string &name,
303 const ThrottlingSeverity &severity)
304 : type_(type), name_(name), severity_(severity) {}
305 } // namespace usb
306 } // namespace pixel
307 } // namespace google
308 } // namespace hardware
309 } // namespace android
310