1 /*
2 * Copyright (C) 2022 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 #define LOG_TAG "mitigation-logger"
17
18 #include <android-base/chrono_utils.h>
19 #include <android-base/file.h>
20 #include <android-base/logging.h>
21 #include <android/binder_manager.h>
22 #include <android/binder_process.h>
23 #include <battery_mitigation/MitigationThermalManager.h>
24 #include <errno.h>
25 #include <utils/Log.h>
26
27 #include <chrono>
28 #include <ctime>
29 #include <iomanip>
30 #include <iostream>
31 #include <string>
32 #include <thread>
33
34 #define NUM_OF_SAMPLES 20
35 #define CAPTURE_INTERVAL_S 2 /* 2 seconds between new capture */
36
37 namespace android {
38 namespace hardware {
39 namespace google {
40 namespace pixel {
41
getInstance()42 MitigationThermalManager &MitigationThermalManager::getInstance() {
43 static MitigationThermalManager mitigationThermalManager;
44 return mitigationThermalManager;
45 }
46
remove()47 void MitigationThermalManager::remove() {
48 const std::lock_guard<std::mutex> lock(thermal_hal_mutex_);
49 if (!thermal) {
50 return;
51 }
52 if (callback) {
53 auto ret = thermal->unregisterThermalChangedCallback(callback);
54 if (!ret.isOk()) {
55 LOG(ERROR) << "Failed to release thermal callback! " << ret.getMessage();
56 }
57 }
58 }
59
MitigationThermalManager()60 MitigationThermalManager::MitigationThermalManager() {
61 if (!ABinderProcess_isThreadPoolStarted()) {
62 // if no thread pool then the thermal callback will not work, so abort
63 LOG(ERROR) << "The user of MitigationThermalManager did not start a thread pool!";
64 return;
65 }
66 if (!connectThermalHal()) {
67 remove();
68 }
69 }
70
~MitigationThermalManager()71 MitigationThermalManager::~MitigationThermalManager() {
72 remove();
73 }
74
updateConfig(const struct MitigationConfig::Config & cfg)75 void MitigationThermalManager::updateConfig(const struct MitigationConfig::Config &cfg) {
76 kLogFilePath = std::string(cfg.LogFilePath);
77 kSystemPath = cfg.SystemPath;
78 kSystemName = cfg.SystemName;
79 kFilteredZones = cfg.FilteredZones;
80 kTimestampFormat = cfg.TimestampFormat;
81 }
82
connectThermalHal()83 bool MitigationThermalManager::connectThermalHal() {
84 const std::string thermal_instance_name =
85 std::string(::aidl::android::hardware::thermal::IThermal::descriptor) + "/default";
86 std::shared_ptr<aidl::android::hardware::thermal::IThermal> thermal_aidl_service;
87 const std::lock_guard<std::mutex> lock(thermal_hal_mutex_);
88 if (AServiceManager_isDeclared(thermal_instance_name.c_str())) {
89 thermal = ::aidl::android::hardware::thermal::IThermal::fromBinder(
90 ndk::SpAIBinder(AServiceManager_waitForService(thermal_instance_name.c_str())));
91 lastCapturedTime = ::android::base::boot_clock::now();
92 return registerCallback();
93 } else {
94 LOG(ERROR) << "Thermal AIDL service is not declared";
95 }
96 return false;
97 }
98
isMitigationTemperature(const Temperature & temperature)99 bool MitigationThermalManager::isMitigationTemperature(const Temperature &temperature) {
100 if (std::find(kFilteredZones.begin(), kFilteredZones.end(), temperature.name) !=
101 kFilteredZones.end()) {
102 return true;
103 }
104 return false;
105 }
106
thermalCb(const Temperature & temperature)107 void MitigationThermalManager::thermalCb(const Temperature &temperature) {
108 if ((temperature.throttlingStatus == ThrottlingSeverity::NONE) ||
109 (!isMitigationTemperature(temperature))) {
110 return;
111 }
112 auto currentTime = ::android::base::boot_clock::now();
113 auto delta =
114 std::chrono::duration_cast<std::chrono::seconds>(currentTime - lastCapturedTime);
115 if (delta.count() < CAPTURE_INTERVAL_S) {
116 /* Do not log if delta is within 2 seconds */
117 return;
118 }
119 int flag = O_WRONLY | O_CREAT | O_NOFOLLOW | O_CLOEXEC | O_APPEND | O_TRUNC;
120 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(kLogFilePath.c_str(), flag, 0644)));
121 lastCapturedTime = currentTime;
122 std::stringstream oss;
123 oss << temperature.name << " triggered at " << temperature.value << std::endl << std::flush;
124 android::base::WriteStringToFd(oss.str(), fd);
125 fsync(fd);
126
127 for (int i = 0; i < NUM_OF_SAMPLES; i++) {
128 auto now = std::chrono::system_clock::now();
129 auto time_sec = std::chrono::system_clock::to_time_t(now);
130 auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) -
131 std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch());
132 struct tm now_tm;
133 localtime_r(&time_sec, &now_tm);
134 oss << std::put_time(&now_tm, kTimestampFormat.c_str()) << "." << std::setw(3)
135 << std::setfill('0') << ms.count() << std::endl
136 << std::flush;
137 android::base::WriteStringToFd(oss.str(), fd);
138 fsync(fd);
139 oss.str("");
140 /* log System info */
141 for (int j = 0; j < kSystemName.size(); j++) {
142 std::string value;
143 bool result = android::base::ReadFileToString(kSystemPath[j], &value);
144 if (!result) {
145 LOG(ERROR) << "Could not read: " << kSystemName[j];
146 }
147 android::base::WriteStringToFd(kSystemName[j] + ":" + value, fd);
148 }
149 }
150 fsync(fd);
151 }
152
registerCallback()153 bool MitigationThermalManager::registerCallback() {
154 if (!thermal) {
155 LOG(ERROR) << "Unable to connect Thermal AIDL service";
156 return false;
157 }
158 // Create thermal callback recipient object.
159 if (callback == nullptr) {
160 callback =
161 ndk::SharedRefBase::make<ThermalCallback>([this](const Temperature &temperature) {
162 std::lock_guard api_lock(thermal_callback_mutex_);
163 thermalCb(temperature);
164 });
165 }
166 // Register thermal callback to thermal hal to cover all. Cannot register twice.
167 auto ret_callback = thermal->registerThermalChangedCallback(callback);
168 if (!ret_callback.isOk()) {
169 LOG(ERROR) << "Failed to register thermal callback! " << ret_callback.getMessage();
170 return false;
171 }
172
173 // Create AIDL thermal death recipient object.
174 if (aidlDeathRecipient.get() == nullptr) {
175 aidlDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(
176 AIBinder_DeathRecipient_new(onThermalAidlBinderDied));
177 }
178 auto linked = AIBinder_linkToDeath(thermal->asBinder().get(), aidlDeathRecipient.get(), this);
179 if (linked != STATUS_OK) {
180 // should we continue if the death recipient is not registered?
181 LOG(ERROR) << "Failed to register AIDL thermal death notification";
182 }
183 return true;
184 }
185
186 } // namespace pixel
187 } // namespace google
188 } // namespace hardware
189 } // namespace android
190