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