• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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