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