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