summaryrefslogtreecommitdiff
path: root/battery_mitigation
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-07-07 05:11:42 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-07-07 05:11:42 +0000
commitbecceed833bea7e9ebc2b6b681d11de748727a3f (patch)
treea6f442eba168310a88707d45fb20952ad3f9ec73 /battery_mitigation
parentf68db2b9637283a61107060b660c8ff865c60337 (diff)
parentc7f3e0ba3acb455437abc7c931aae1afafcb57f2 (diff)
downloadpixel-4b28dd14e303b2def8170c07502efa6b7a527083.tar.gz
Change-Id: Idc023fbdc5b38a577e99f595ff2046edfbdb15ff
Diffstat (limited to 'battery_mitigation')
-rw-r--r--battery_mitigation/Android.bp46
-rw-r--r--battery_mitigation/BatteryMitigation.cpp67
-rw-r--r--battery_mitigation/MitigationThermalManager.cpp189
-rw-r--r--battery_mitigation/OWNERS2
-rw-r--r--battery_mitigation/include/battery_mitigation/BatteryMitigation.h44
-rw-r--r--battery_mitigation/include/battery_mitigation/MitigationConfig.h50
-rw-r--r--battery_mitigation/include/battery_mitigation/MitigationThermalManager.h121
7 files changed, 519 insertions, 0 deletions
diff --git a/battery_mitigation/Android.bp b/battery_mitigation/Android.bp
new file mode 100644
index 00000000..1a5d6c6e
--- /dev/null
+++ b/battery_mitigation/Android.bp
@@ -0,0 +1,46 @@
+//
+// Copyright (C) 2022 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.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_library {
+ name: "libpixelmitigation",
+ export_include_dirs: ["include"],
+ vendor_available: true,
+ srcs: [
+ "BatteryMitigation.cpp",
+ "MitigationThermalManager.cpp",
+ ],
+ static_libs: [
+ "libmath",
+ ],
+
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "libcutils",
+ "libhardware",
+ "liblog",
+ "libutils",
+ "android.hardware.thermal-V1-ndk"
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+}
diff --git a/battery_mitigation/BatteryMitigation.cpp b/battery_mitigation/BatteryMitigation.cpp
new file mode 100644
index 00000000..98419fc5
--- /dev/null
+++ b/battery_mitigation/BatteryMitigation.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#include <battery_mitigation/BatteryMitigation.h>
+
+#include <sstream>
+
+#define MAX_BROWNOUT_DATA_AGE_SECONDS 300
+
+namespace android {
+namespace hardware {
+namespace google {
+namespace pixel {
+
+BatteryMitigation::BatteryMitigation(const struct MitigationConfig::Config &cfg) {
+ mThermalMgr = &MitigationThermalManager::getInstance();
+ mThermalMgr->updateConfig(cfg);
+}
+
+bool BatteryMitigation::isMitigationLogTimeValid(std::chrono::system_clock::time_point startTime,
+ const char *const logFilePath,
+ const char *const timestampFormat,
+ const std::regex pattern) {
+ std::string logFile;
+ if (!android::base::ReadFileToString(logFilePath, &logFile)) {
+ return false;
+ }
+ std::istringstream content(logFile);
+ std::string line;
+ int counter = 0;
+ std::smatch pattern_match;
+ while (std::getline(content, line)) {
+ if (std::regex_match(line, pattern_match, pattern)) {
+ std::tm triggeredTimestamp = {};
+ std::istringstream ss(pattern_match.str());
+ ss >> std::get_time(&triggeredTimestamp, timestampFormat);
+ auto logFileTime = std::chrono::system_clock::from_time_t(mktime(&triggeredTimestamp));
+ auto delta = std::chrono::duration_cast<std::chrono::seconds>(startTime - logFileTime);
+ if ((delta.count() < MAX_BROWNOUT_DATA_AGE_SECONDS) && (delta.count() > 0)) {
+ return true;
+ }
+ }
+ counter += 1;
+ if (counter > 5) {
+ break;
+ }
+ }
+ return false;
+}
+
+} // namespace pixel
+} // namespace google
+} // namespace hardware
+} // namespace android
diff --git a/battery_mitigation/MitigationThermalManager.cpp b/battery_mitigation/MitigationThermalManager.cpp
new file mode 100644
index 00000000..42e6e3cb
--- /dev/null
+++ b/battery_mitigation/MitigationThermalManager.cpp
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2022 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 "mitigation-logger"
+
+#include <android-base/chrono_utils.h>
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <battery_mitigation/MitigationThermalManager.h>
+#include <errno.h>
+#include <utils/Log.h>
+
+#include <chrono>
+#include <ctime>
+#include <iomanip>
+#include <iostream>
+#include <string>
+#include <thread>
+
+#define NUM_OF_SAMPLES 20
+#define CAPTURE_INTERVAL_S 2 /* 2 seconds between new capture */
+
+namespace android {
+namespace hardware {
+namespace google {
+namespace pixel {
+
+MitigationThermalManager &MitigationThermalManager::getInstance() {
+ static MitigationThermalManager mitigationThermalManager;
+ return mitigationThermalManager;
+}
+
+void MitigationThermalManager::remove() {
+ const std::lock_guard<std::mutex> lock(thermal_hal_mutex_);
+ if (!thermal) {
+ return;
+ }
+ if (callback) {
+ auto ret = thermal->unregisterThermalChangedCallback(callback);
+ if (!ret.isOk()) {
+ LOG(ERROR) << "Failed to release thermal callback! " << ret.getMessage();
+ }
+ }
+}
+
+MitigationThermalManager::MitigationThermalManager() {
+ if (!ABinderProcess_isThreadPoolStarted()) {
+ // if no thread pool then the thermal callback will not work, so abort
+ LOG(ERROR) << "The user of MitigationThermalManager did not start a thread pool!";
+ return;
+ }
+ if (!connectThermalHal()) {
+ remove();
+ }
+}
+
+MitigationThermalManager::~MitigationThermalManager() {
+ remove();
+}
+
+void MitigationThermalManager::updateConfig(const struct MitigationConfig::Config &cfg) {
+ kLogFilePath = std::string(cfg.LogFilePath);
+ kSystemPath = cfg.SystemPath;
+ kSystemName = cfg.SystemName;
+ kFilteredZones = cfg.FilteredZones;
+ kTimestampFormat = cfg.TimestampFormat;
+}
+
+bool MitigationThermalManager::connectThermalHal() {
+ const std::string thermal_instance_name =
+ std::string(::aidl::android::hardware::thermal::IThermal::descriptor) + "/default";
+ std::shared_ptr<aidl::android::hardware::thermal::IThermal> thermal_aidl_service;
+ const std::lock_guard<std::mutex> lock(thermal_hal_mutex_);
+ if (AServiceManager_isDeclared(thermal_instance_name.c_str())) {
+ thermal = ::aidl::android::hardware::thermal::IThermal::fromBinder(
+ ndk::SpAIBinder(AServiceManager_waitForService(thermal_instance_name.c_str())));
+ lastCapturedTime = ::android::base::boot_clock::now();
+ return registerCallback();
+ } else {
+ LOG(ERROR) << "Thermal AIDL service is not declared";
+ }
+ return false;
+}
+
+bool MitigationThermalManager::isMitigationTemperature(const Temperature &temperature) {
+ if (std::find(kFilteredZones.begin(), kFilteredZones.end(), temperature.name) !=
+ kFilteredZones.end()) {
+ return true;
+ }
+ return false;
+}
+
+void MitigationThermalManager::thermalCb(const Temperature &temperature) {
+ if ((temperature.throttlingStatus == ThrottlingSeverity::NONE) ||
+ (!isMitigationTemperature(temperature))) {
+ return;
+ }
+ auto currentTime = ::android::base::boot_clock::now();
+ auto delta =
+ std::chrono::duration_cast<std::chrono::seconds>(currentTime - lastCapturedTime);
+ if (delta.count() < CAPTURE_INTERVAL_S) {
+ /* Do not log if delta is within 2 seconds */
+ return;
+ }
+ int flag = O_WRONLY | O_CREAT | O_NOFOLLOW | O_CLOEXEC | O_APPEND | O_TRUNC;
+ android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(kLogFilePath.c_str(), flag, 0644)));
+ lastCapturedTime = currentTime;
+ std::stringstream oss;
+ oss << temperature.name << " triggered at " << temperature.value << std::endl << std::flush;
+ android::base::WriteStringToFd(oss.str(), fd);
+ fsync(fd);
+
+ for (int i = 0; i < NUM_OF_SAMPLES; i++) {
+ auto now = std::chrono::system_clock::now();
+ auto time_sec = std::chrono::system_clock::to_time_t(now);
+ auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) -
+ std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch());
+ struct tm now_tm;
+ localtime_r(&time_sec, &now_tm);
+ oss << std::put_time(&now_tm, kTimestampFormat.c_str()) << "." << std::setw(3)
+ << std::setfill('0') << ms.count() << std::endl
+ << std::flush;
+ android::base::WriteStringToFd(oss.str(), fd);
+ fsync(fd);
+ oss.str("");
+ /* log System info */
+ for (int j = 0; j < kSystemName.size(); j++) {
+ std::string value;
+ bool result = android::base::ReadFileToString(kSystemPath[j], &value);
+ if (!result) {
+ LOG(ERROR) << "Could not read: " << kSystemName[j];
+ }
+ android::base::WriteStringToFd(kSystemName[j] + ":" + value, fd);
+ }
+ }
+ fsync(fd);
+}
+
+bool MitigationThermalManager::registerCallback() {
+ if (!thermal) {
+ LOG(ERROR) << "Unable to connect Thermal AIDL service";
+ return false;
+ }
+ // Create thermal callback recipient object.
+ if (callback == nullptr) {
+ callback =
+ ndk::SharedRefBase::make<ThermalCallback>([this](const Temperature &temperature) {
+ std::lock_guard api_lock(thermal_callback_mutex_);
+ thermalCb(temperature);
+ });
+ }
+ // Register thermal callback to thermal hal to cover all. Cannot register twice.
+ auto ret_callback = thermal->registerThermalChangedCallback(callback);
+ if (!ret_callback.isOk()) {
+ LOG(ERROR) << "Failed to register thermal callback! " << ret_callback.getMessage();
+ return false;
+ }
+
+ // Create AIDL thermal death recipient object.
+ if (aidlDeathRecipient.get() == nullptr) {
+ aidlDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(
+ AIBinder_DeathRecipient_new(onThermalAidlBinderDied));
+ }
+ auto linked = AIBinder_linkToDeath(thermal->asBinder().get(), aidlDeathRecipient.get(), this);
+ if (linked != STATUS_OK) {
+ // should we continue if the death recipient is not registered?
+ LOG(ERROR) << "Failed to register AIDL thermal death notification";
+ }
+ return true;
+}
+
+} // namespace pixel
+} // namespace google
+} // namespace hardware
+} // namespace android
diff --git a/battery_mitigation/OWNERS b/battery_mitigation/OWNERS
new file mode 100644
index 00000000..363efac2
--- /dev/null
+++ b/battery_mitigation/OWNERS
@@ -0,0 +1,2 @@
+geolee@google.com
+wvw@google.com
diff --git a/battery_mitigation/include/battery_mitigation/BatteryMitigation.h b/battery_mitigation/include/battery_mitigation/BatteryMitigation.h
new file mode 100644
index 00000000..d3ce433d
--- /dev/null
+++ b/battery_mitigation/include/battery_mitigation/BatteryMitigation.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#pragma once
+
+#include <utils/RefBase.h>
+
+#include "MitigationThermalManager.h"
+
+namespace android {
+namespace hardware {
+namespace google {
+namespace pixel {
+
+using ::android::sp;
+
+class BatteryMitigation : public RefBase {
+ public:
+ BatteryMitigation(const struct MitigationConfig::Config &cfg);
+ bool isMitigationLogTimeValid(std::chrono::system_clock::time_point startTime,
+ const char *const logFilePath, const char *const timestampFormat,
+ const std::regex pattern);
+
+ private:
+ MitigationThermalManager *mThermalMgr;
+};
+
+} // namespace pixel
+} // namespace google
+} // namespace hardware
+} // namespace android
diff --git a/battery_mitigation/include/battery_mitigation/MitigationConfig.h b/battery_mitigation/include/battery_mitigation/MitigationConfig.h
new file mode 100644
index 00000000..825e30c6
--- /dev/null
+++ b/battery_mitigation/include/battery_mitigation/MitigationConfig.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 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_BATTERY_MITIGATION_CONFIG_H
+#define HARDWARE_GOOGLE_PIXEL_BATTERY_MITIGATION_CONFIG_H
+
+namespace android {
+namespace hardware {
+namespace google {
+namespace pixel {
+
+class MitigationConfig {
+ public:
+ struct Config {
+ const std::vector<std::string> SystemPath;
+ const std::vector<std::string> FilteredZones;
+ const std::vector<std::string> SystemName;
+ const char *const LogFilePath;
+ const char *const TimestampFormat;
+ };
+
+ MitigationConfig(const struct Config &cfg);
+
+ private:
+ const std::vector<std::string> kSystemPath;
+ const std::vector<std::string> kFilteredZones;
+ const std::vector<std::string> kSystemName;
+ const char *const kLogFilePath;
+ const char *const kTimestampFormat;
+};
+
+} // namespace pixel
+} // namespace google
+} // namespace hardware
+} // namespace android
+
+#endif // HARDWARE_GOOGLE_PIXEL_BATTERY_MITIGATION_CONFIG_H
diff --git a/battery_mitigation/include/battery_mitigation/MitigationThermalManager.h b/battery_mitigation/include/battery_mitigation/MitigationThermalManager.h
new file mode 100644
index 00000000..5b5a3f0a
--- /dev/null
+++ b/battery_mitigation/include/battery_mitigation/MitigationThermalManager.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#pragma once
+
+#ifndef MITIGATION_THERMAL_MANAGER_H_
+#define MITIGATION_THERMAL_MANAGER_H_
+
+#include <aidl/android/hardware/thermal/BnThermalChangedCallback.h>
+#include <aidl/android/hardware/thermal/IThermal.h>
+#include <android-base/chrono_utils.h>
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/parseint.h>
+#include <android-base/properties.h>
+#include <android-base/strings.h>
+#include <android/binder_auto_utils.h>
+#include <unistd.h>
+#include <utils/Mutex.h>
+
+#include <fstream>
+#include <iostream>
+#include <regex>
+
+#include "MitigationConfig.h"
+
+namespace android {
+namespace hardware {
+namespace google {
+namespace pixel {
+
+using ::aidl::android::hardware::thermal::BnThermalChangedCallback;
+using ::aidl::android::hardware::thermal::IThermal;
+using ::aidl::android::hardware::thermal::Temperature;
+using ::aidl::android::hardware::thermal::TemperatureType;
+using ::aidl::android::hardware::thermal::ThrottlingSeverity;
+using android::hardware::google::pixel::MitigationConfig;
+
+class MitigationThermalManager {
+ public:
+ static MitigationThermalManager &getInstance();
+
+ // delete copy and move constructors and assign operators
+ MitigationThermalManager(MitigationThermalManager const &) = delete;
+ MitigationThermalManager(MitigationThermalManager &&) = delete;
+ MitigationThermalManager &operator=(MitigationThermalManager const &) = delete;
+ MitigationThermalManager &operator=(MitigationThermalManager &&) = delete;
+
+ private:
+ // ThermalCallback implements the HIDL thermal changed callback
+ // interface, IThermalChangedCallback.
+ void thermalCb(const Temperature &temperature);
+ android::base::boot_clock::time_point lastCapturedTime;
+
+ class ThermalCallback : public BnThermalChangedCallback {
+ public:
+ ThermalCallback(std::function<void(const Temperature &)> notify_function)
+ : notifyFunction(notify_function) {}
+
+ // Callback function. thermal service will call this.
+ ndk::ScopedAStatus notifyThrottling(const Temperature &temperature) override {
+ if ((temperature.type == TemperatureType::BCL_VOLTAGE) ||
+ (temperature.type == TemperatureType::BCL_CURRENT)) {
+ notifyFunction(temperature);
+ }
+ return ndk::ScopedAStatus::ok();
+ }
+
+ private:
+ std::function<void(const Temperature &)> notifyFunction;
+ };
+
+ static void onThermalAidlBinderDied(void *) {
+ LOG(ERROR) << "Thermal AIDL service died, trying to reconnect";
+ MitigationThermalManager::getInstance().connectThermalHal();
+ }
+
+ public:
+ MitigationThermalManager();
+ ~MitigationThermalManager();
+ bool connectThermalHal();
+ bool isMitigationTemperature(const Temperature &temperature);
+ bool registerCallback();
+ void remove();
+ void updateConfig(const struct MitigationConfig::Config &cfg);
+
+
+ private:
+ std::mutex thermal_callback_mutex_;
+ std::mutex thermal_hal_mutex_;
+ // Thermal hal interface.
+ std::shared_ptr<IThermal> thermal;
+ // Thermal hal callback object.
+ std::shared_ptr<ThermalCallback> callback;
+ // Receiver when AIDL thermal hal restart.
+ ndk::ScopedAIBinder_DeathRecipient aidlDeathRecipient;
+ std::vector<std::string> kSystemPath;
+ std::vector<std::string> kFilteredZones;
+ std::vector<std::string> kSystemName;
+ std::string kLogFilePath;
+ std::string kTimestampFormat;
+};
+
+} // namespace pixel
+} // namespace google
+} // namespace hardware
+} // namespace android
+#endif