summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBadhri Jagan Sridharan <badhri@google.com>2021-07-13 09:54:29 -0700
committerBadhri Jagan Sridharan <badhri@google.com>2021-07-21 14:36:37 -0700
commit400cc0b1b31d3480496af60c786e44093dcebd80 (patch)
treef6f4bef23be5d173ff890801a9622b0d305ae76b
parent0102c84bd717592f7bcdf6d3aa8bff5acb2d6a24 (diff)
downloadpixel-400cc0b1b31d3480496af60c786e44093dcebd80.tar.gz
libpixelusb: Add logic to gather termperature stats for overheat
Added UsbPortOverheat which subscribes to thermal hal's notification callback for monitoring usb port thermal zone's throttling status. When throttled, the relevant thermal zones are queried for temperature and the maximum temperature is stored. The maximum temperature reached during the throttling window is then reported through suez. Bug: 193615568 Test: adb shell "echo 35001 > dev/thermal/tz-by-name/usb_pwr_therm2/emul_temp"; adb shell "echo 31000 > dev/thermal/tz-by-name/usb_pwr_therm/emul_temp"; adb shell "echo 21000 > dev/thermal/tz-by-name/qi_therm/emul_temp"; wait for few seconds, adb shell "echo 10000 > dev/thermal/tz-by-name/usb_pwr_therm2/emul_temp"; Change-Id: I2b3ee4197205f07bf5b3763176233e0fc89519c1
-rw-r--r--usb/Android.bp6
-rw-r--r--usb/UsbOverheatEvent.cpp301
-rw-r--r--usb/include/pixelusb/UsbOverheatEvent.h141
3 files changed, 447 insertions, 1 deletions
diff --git a/usb/Android.bp b/usb/Android.bp
index 348e2242..8927c8a2 100644
--- a/usb/Android.bp
+++ b/usb/Android.bp
@@ -26,6 +26,7 @@ cc_library_static {
srcs: [
"UsbGadgetUtils.cpp",
"MonitorFfs.cpp",
+ "UsbOverheatEvent.cpp"
],
cflags: [
@@ -34,11 +35,14 @@ cc_library_static {
],
shared_libs: [
- "android.hardware.usb.gadget@1.0",
"libbase",
+ "libbinder",
"libcutils",
"libhidlbase",
"libutils",
+ "android.hardware.usb.gadget@1.0",
+ "android.hardware.thermal@1.0",
+ "android.hardware.thermal@2.0",
],
}
diff --git a/usb/UsbOverheatEvent.cpp b/usb/UsbOverheatEvent.cpp
new file mode 100644
index 00000000..f00258f5
--- /dev/null
+++ b/usb/UsbOverheatEvent.cpp
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "libPixelUsbOverheat"
+
+#include "include/pixelusb/UsbOverheatEvent.h"
+
+#include <time.h>
+
+namespace android {
+namespace hardware {
+namespace google {
+namespace pixel {
+namespace usb {
+
+// Start monitoring the temperature
+static volatile bool monitorTemperature;
+
+constexpr int kEpollEvents = 10;
+constexpr char kOverheatLock[] = "overheat";
+constexpr char kWakeLockPath[] = "/sys/power/wake_lock";
+constexpr char kWakeUnlockPath[] = "/sys/power/wake_unlock";
+
+int addEpollFdWakeUp(const unique_fd &epfd, const unique_fd &fd) {
+ struct epoll_event event;
+ int ret;
+
+ event.data.fd = fd;
+ event.events = EPOLLIN | EPOLLWAKEUP;
+
+ ret = epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event);
+ if (ret)
+ ALOGE("epoll_ctl error %d", errno);
+
+ return ret;
+}
+
+UsbOverheatEvent::UsbOverheatEvent(const ZoneInfo &monitored_zone,
+ const std::vector<ZoneInfo> &queried_zones,
+ const int &monitor_interval_sec)
+ : monitored_zone_(monitored_zone),
+ queried_zones_(queried_zones),
+ monitor_interval_sec_(monitor_interval_sec),
+ lock_(),
+ cv_(),
+ monitor_() {
+ int fd = timerfd_create(CLOCK_BOOTTIME_ALARM, 0);
+ if (fd < 0) {
+ ALOGE("timerfd_create failed: %d", errno);
+ }
+
+ unique_fd timerFd(timerfd_create(CLOCK_BOOTTIME_ALARM, 0));
+ if (timerFd == -1) {
+ ALOGE("timerFd failed to create %d", errno);
+ abort();
+ }
+
+ unique_fd epollFd(epoll_create(2));
+ if (epollFd == -1) {
+ ALOGE("epoll_fd_ failed to create %d", errno);
+ abort();
+ }
+
+ unique_fd eventFd(eventfd(0, 0));
+ if (eventFd == -1) {
+ ALOGE("event_fd_ failed to create %d", errno);
+ abort();
+ }
+
+ if (addEpollFdWakeUp(epollFd, timerFd) == -1) {
+ ALOGE("Adding timerFd failed");
+ abort();
+ }
+
+ if (addEpollFdWakeUp(epollFd, eventFd) == -1) {
+ ALOGE("Adding eventFd failed");
+ abort();
+ }
+
+ epoll_fd_ = move(epollFd);
+ timer_fd_ = move(timerFd);
+ event_fd_ = move(eventFd);
+
+ monitor_ = unique_ptr<thread>(new thread(this->monitorThread, this));
+ registerListener();
+}
+
+static int wakelock_cnt = 0;
+static std::mutex wakelock_lock;
+
+static void wakeLockAcquire() {
+ lock_guard<mutex> lock(wakelock_lock);
+
+ wakelock_cnt++;
+ if (wakelock_cnt == 1) {
+ ALOGV("Acquire wakelock");
+ if (!WriteStringToFile(kOverheatLock, kWakeLockPath)) {
+ ALOGE("Failed to acquire wake lock string");
+ }
+ }
+}
+
+static void wakeLockRelease() {
+ lock_guard<mutex> lock(wakelock_lock);
+
+ wakelock_cnt--;
+ if (wakelock_cnt == 0) {
+ ALOGV("Release wakelock");
+ if (!WriteStringToFile(kOverheatLock, kWakeUnlockPath)) {
+ ALOGE("Failed to acquire wake lock string");
+ }
+ }
+}
+
+void *UsbOverheatEvent::monitorThread(void *param) {
+ UsbOverheatEvent *overheatEvent = (UsbOverheatEvent *)param;
+ struct epoll_event events[kEpollEvents];
+ struct itimerspec delay = itimerspec();
+ std::unique_lock<std::mutex> lk(overheatEvent->lock_);
+
+ delay.it_value.tv_sec = overheatEvent->monitor_interval_sec_;
+
+ while (true) {
+ uint64_t fired;
+ float temperature = 0;
+ string status;
+
+ overheatEvent->cv_.wait(lk, [] { return monitorTemperature; });
+
+ for (vector<ZoneInfo>::size_type i = 0; i < overheatEvent->queried_zones_.size(); i++) {
+ if (overheatEvent->getCurrentTemperature(overheatEvent->queried_zones_[i].name_,
+ &temperature)) {
+ if (i == 0)
+ overheatEvent->max_overheat_temp_ =
+ max(temperature, overheatEvent->max_overheat_temp_);
+ status.append(overheatEvent->queried_zones_[i].name_);
+ status.append(":");
+ status.append(std::to_string(temperature));
+ status.append(" ");
+ }
+ }
+ ALOGW("%s", status.c_str());
+
+ int ret = timerfd_settime(overheatEvent->timer_fd_, 0, &delay, NULL);
+ if (ret < 0) {
+ ALOGE("timerfd_settime failed. err:%d", errno);
+ return NULL;
+ }
+
+ wakeLockRelease();
+ int nrEvents = epoll_wait(overheatEvent->epoll_fd_, events, kEpollEvents, -1);
+ wakeLockAcquire();
+ if (nrEvents <= 0) {
+ ALOGE("nrEvents negative skipping");
+ continue;
+ }
+
+ for (int i = 0; i < nrEvents; i++) {
+ ALOGV("event=%u on fd=%d\n", events[i].events, events[i].data.fd);
+
+ if (events[i].data.fd == overheatEvent->timer_fd_) {
+ int numRead = read(overheatEvent->timer_fd_, &fired, sizeof(fired));
+ if (numRead != sizeof(fired)) {
+ ALOGV("numRead incorrect");
+ }
+ if (fired != 1) {
+ ALOGV("Fired not set to 1");
+ }
+ } else {
+ read(overheatEvent->event_fd_, &fired, sizeof(fired));
+ }
+ }
+ }
+
+ return NULL;
+}
+
+bool UsbOverheatEvent::registerListener() {
+ ALOGV("UsbOverheatEvent::registerListener");
+ sp<IServiceManager> sm = IServiceManager::getService();
+ if (sm == NULL) {
+ ALOGE("Hardware service manager is not running");
+ return false;
+ }
+ Return<bool> result = sm->registerForNotifications(IThermal::descriptor, "", this);
+ if (result.isOk()) {
+ return true;
+ }
+ ALOGE("Failed to register for hardware service manager notifications: %s",
+ result.description().c_str());
+ return false;
+}
+
+bool UsbOverheatEvent::startRecording() {
+ lock_guard<mutex> lock(lock_);
+ wakeLockAcquire();
+ monitorTemperature = true;
+ cv_.notify_all();
+ return true;
+}
+
+bool UsbOverheatEvent::stopRecording() {
+ // <flag> value does not have any significance here
+ uint64_t flag = 100;
+ unsigned long ret;
+
+ wakeLockRelease();
+ monitorTemperature = false;
+ ret = TEMP_FAILURE_RETRY(write(event_fd_, &flag, sizeof(flag)));
+ if (ret < 0) {
+ ALOGE("Error writing eventfd errno=%d", errno);
+ }
+
+ return true;
+}
+
+bool UsbOverheatEvent::getCurrentTemperature(const string &name, float *temp) {
+ ThermalStatus thermal_status;
+ hidl_vec<Temperature> thermal_temperatures;
+
+ if (thermal_service_ == NULL)
+ return false;
+
+ auto ret = thermal_service_->getCurrentTemperatures(
+ false, TemperatureType::USB_PORT,
+ [&](ThermalStatus status, hidl_vec<Temperature> temperatures) {
+ thermal_status = status;
+ thermal_temperatures = temperatures;
+ });
+
+ if (ret.isOk() && thermal_status.code == ThermalStatusCode::SUCCESS) {
+ for (auto temperature : thermal_temperatures) {
+ if (temperature.name == name) {
+ *temp = temperature.value;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+float UsbOverheatEvent::getMaxOverheatTemperature() {
+ return max_overheat_temp_;
+}
+
+Return<void> UsbOverheatEvent::onRegistration(const hidl_string & /*fully_qualified_name*/,
+ const hidl_string & /*instance_name*/,
+ bool /*pre_existing*/) {
+ ThermalStatus thermal_status;
+
+ thermal_service_ = IThermal::getService();
+ if (thermal_service_ == NULL) {
+ ALOGE("Unable to get Themal Service");
+ return Void();
+ }
+
+ auto ret = thermal_service_->registerThermalChangedCallback(
+ this, true, monitored_zone_.type_,
+ [&](ThermalStatus status) { thermal_status = status; });
+
+ if (!ret.isOk() || thermal_status.code != ThermalStatusCode::SUCCESS) {
+ ALOGE("failed to register thermal changed callback!");
+ }
+
+ return Void();
+}
+
+Return<void> UsbOverheatEvent::notifyThrottling(const Temperature &temperature) {
+ ALOGV("notifyThrottling '%s' T=%2.2f throttlingStatus=%d", temperature.name.c_str(),
+ temperature.value, temperature.throttlingStatus);
+ if (temperature.type == monitored_zone_.type_) {
+ if (temperature.throttlingStatus >= monitored_zone_.severity_) {
+ startRecording();
+ } else {
+ stopRecording();
+ }
+ }
+ return Void();
+}
+
+ZoneInfo::ZoneInfo(const TemperatureType &type, const string &name,
+ const ThrottlingSeverity &severity)
+ : type_(type), name_(name), severity_(severity) {}
+} // namespace usb
+} // namespace pixel
+} // namespace google
+} // namespace hardware
+} // namespace android
diff --git a/usb/include/pixelusb/UsbOverheatEvent.h b/usb/include/pixelusb/UsbOverheatEvent.h
new file mode 100644
index 00000000..ac8b6b0a
--- /dev/null
+++ b/usb/include/pixelusb/UsbOverheatEvent.h
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HARDWARE_GOOGLE_PIXEL_USB_USBOVERHEATEVENT_H
+#define HARDWARE_GOOGLE_PIXEL_USB_USBOVERHEATEVENT_H
+
+#include <android-base/file.h>
+#include <android-base/properties.h>
+#include <android-base/unique_fd.h>
+#include <android/hardware/thermal/2.0/IThermal.h>
+#include <android/hardware/thermal/2.0/IThermalChangedCallback.h>
+#include <android/hardware/thermal/2.0/types.h>
+#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/epoll.h>
+#include <sys/eventfd.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/timerfd.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <utils/Log.h>
+
+#include <condition_variable>
+#include <mutex>
+#include <string>
+#include <thread>
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace google {
+namespace pixel {
+namespace usb {
+
+using ::android::base::unique_fd;
+using ::android::base::WriteStringToFile;
+
+using ::android::hardware::thermal::V1_0::ThermalStatus;
+using ::android::hardware::thermal::V1_0::ThermalStatusCode;
+using ::android::hardware::thermal::V2_0::IThermal;
+using ::android::hardware::thermal::V2_0::IThermalChangedCallback;
+using ::android::hardware::thermal::V2_0::Temperature;
+using ::android::hardware::thermal::V2_0::TemperatureType;
+using ::android::hardware::thermal::V2_0::ThrottlingSeverity;
+
+using ::android::hidl::manager::V1_0::IServiceManager;
+using ::android::hidl::manager::V1_0::IServiceNotification;
+
+using ::std::lock_guard;
+using ::std::max;
+using ::std::move;
+using ::std::mutex;
+using ::std::string;
+using ::std::thread;
+using ::std::unique_ptr;
+using ::std::vector;
+
+class ZoneInfo {
+ public:
+ // Type of the thermal sensor
+ TemperatureType type_;
+ // Name of the thermal sensor
+ string name_;
+ // Throttling severity when monitor_ is started for polling temperature
+ ThrottlingSeverity severity_;
+ ZoneInfo(const TemperatureType &type, const string &name, const ThrottlingSeverity &severity);
+};
+
+class UsbOverheatEvent : public IServiceNotification, public IThermalChangedCallback {
+ private:
+ // To wake up thread to record max temperature
+ unique_fd timer_fd_;
+ // Pools on timer_fd_
+ unique_fd epoll_fd_;
+ // To wake up the thread when waiting on TimerFd
+ unique_fd event_fd_;
+ // Thermal zone for monitoring Throttling event
+ ZoneInfo monitored_zone_;
+ // Info of thermal zones that are queried during polling.
+ // ATM Suez UsbPortOverheatEvent can only report one of the values though.
+ // Therefore the first one in the list will be used for
+ // getCurrentTemperature and max_overheat_temp_.
+ vector<ZoneInfo> queried_zones_;
+ // Sampling interval for monitoring the temperature
+ int monitor_interval_sec_;
+ // protects the CV.
+ std::mutex lock_;
+ // Thread waits here when mRecordMaxTemp is false
+ std::condition_variable cv_;
+ // Thread object that executes the ep monitoring logic
+ unique_ptr<thread> monitor_;
+ // Maximum overheat temperature recorded
+ float max_overheat_temp_;
+ // Reference to thermal service
+ ::android::sp<IThermal> thermal_service_;
+ // Thread that polls temperature to record max temp
+ static void *monitorThread(void *param);
+ // Register service notification listener
+ bool registerListener();
+ // Thermal ServiceNotification listener
+ Return<void> onRegistration(const hidl_string & /*fully_qualified_name*/,
+ const hidl_string & /*instance_name*/,
+ bool /*pre_existing*/) override;
+ // Thermal service callback
+ Return<void> notifyThrottling(const Temperature &temperature) override;
+
+ public:
+ UsbOverheatEvent(const ZoneInfo &monitored_zone, const std::vector<ZoneInfo> &queried_zones,
+ const int &monitor_interval_sec);
+ // Start monitoring thermal zone for maximum temperature
+ bool startRecording();
+ // Stop monitoring thermal zone
+ bool stopRecording();
+ // Enquire current USB temperature
+ bool getCurrentTemperature(const string &name, float *temp);
+ // Query Max overheat temperature
+ float getMaxOverheatTemperature();
+};
+
+} // namespace usb
+} // namespace pixel
+} // namespace google
+} // namespace hardware
+} // namespace android
+#endif