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