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