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
17 #define ATRACE_TAG (ATRACE_TAG_THERMAL | ATRACE_TAG_HAL)
18
19 #include "Thermal.h"
20
21 #include <android-base/file.h>
22 #include <android-base/logging.h>
23 #include <utils/Trace.h>
24
25 namespace aidl {
26 namespace android {
27 namespace hardware {
28 namespace thermal {
29 namespace implementation {
30
31 namespace {
32
initErrorStatus()33 ndk::ScopedAStatus initErrorStatus() {
34 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_STATE,
35 "ThermalHAL not initialized properly.");
36 }
37
readErrorStatus()38 ndk::ScopedAStatus readErrorStatus() {
39 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
40 EX_ILLEGAL_STATE, "ThermalHal cannot read any sensor data");
41 }
42
interfacesEqual(const std::shared_ptr<::ndk::ICInterface> left,const std::shared_ptr<::ndk::ICInterface> right)43 bool interfacesEqual(const std::shared_ptr<::ndk::ICInterface> left,
44 const std::shared_ptr<::ndk::ICInterface> right) {
45 if (left == nullptr || right == nullptr || !left->isRemote() || !right->isRemote()) {
46 return left == right;
47 }
48 return left->asBinder() == right->asBinder();
49 }
50
51 } // namespace
52
Thermal()53 Thermal::Thermal() {
54 thermal_helper_ = std::make_shared<ThermalHelperImpl>(
55 std::bind(&Thermal::sendThermalChangedCallback, this, std::placeholders::_1));
56 }
57
Thermal(const std::shared_ptr<ThermalHelper> & helper)58 Thermal::Thermal(const std::shared_ptr<ThermalHelper> &helper) {
59 thermal_helper_ = helper;
60 }
61
getTemperatures(std::vector<Temperature> * _aidl_return)62 ndk::ScopedAStatus Thermal::getTemperatures(std::vector<Temperature> *_aidl_return) {
63 return getFilteredTemperatures(false, TemperatureType::UNKNOWN, _aidl_return);
64 }
65
getTemperaturesWithType(TemperatureType type,std::vector<Temperature> * _aidl_return)66 ndk::ScopedAStatus Thermal::getTemperaturesWithType(TemperatureType type,
67 std::vector<Temperature> *_aidl_return) {
68 return getFilteredTemperatures(true, type, _aidl_return);
69 }
70
getFilteredTemperatures(bool filterType,TemperatureType type,std::vector<Temperature> * _aidl_return)71 ndk::ScopedAStatus Thermal::getFilteredTemperatures(bool filterType, TemperatureType type,
72 std::vector<Temperature> *_aidl_return) {
73 *_aidl_return = {};
74 if (!thermal_helper_->isInitializedOk()) {
75 return initErrorStatus();
76 }
77 if (!thermal_helper_->fillCurrentTemperatures(filterType, false, type, _aidl_return)) {
78 return readErrorStatus();
79 }
80 return ndk::ScopedAStatus::ok();
81 }
82
getCoolingDevices(std::vector<CoolingDevice> * _aidl_return)83 ndk::ScopedAStatus Thermal::getCoolingDevices(std::vector<CoolingDevice> *_aidl_return) {
84 return getFilteredCoolingDevices(false, CoolingType::BATTERY, _aidl_return);
85 }
86
getCoolingDevicesWithType(CoolingType type,std::vector<CoolingDevice> * _aidl_return)87 ndk::ScopedAStatus Thermal::getCoolingDevicesWithType(CoolingType type,
88 std::vector<CoolingDevice> *_aidl_return) {
89 return getFilteredCoolingDevices(true, type, _aidl_return);
90 }
91
getFilteredCoolingDevices(bool filterType,CoolingType type,std::vector<CoolingDevice> * _aidl_return)92 ndk::ScopedAStatus Thermal::getFilteredCoolingDevices(bool filterType, CoolingType type,
93 std::vector<CoolingDevice> *_aidl_return) {
94 *_aidl_return = {};
95 if (!thermal_helper_->isInitializedOk()) {
96 return initErrorStatus();
97 }
98 if (!thermal_helper_->fillCurrentCoolingDevices(filterType, type, _aidl_return)) {
99 return readErrorStatus();
100 }
101 return ndk::ScopedAStatus::ok();
102 }
103
getTemperatureThresholds(std::vector<TemperatureThreshold> * _aidl_return)104 ndk::ScopedAStatus Thermal::getTemperatureThresholds(
105 std::vector<TemperatureThreshold> *_aidl_return) {
106 *_aidl_return = {};
107 return getFilteredTemperatureThresholds(false, TemperatureType::UNKNOWN, _aidl_return);
108 }
109
getTemperatureThresholdsWithType(TemperatureType type,std::vector<TemperatureThreshold> * _aidl_return)110 ndk::ScopedAStatus Thermal::getTemperatureThresholdsWithType(
111 TemperatureType type, std::vector<TemperatureThreshold> *_aidl_return) {
112 return getFilteredTemperatureThresholds(true, type, _aidl_return);
113 }
114
getFilteredTemperatureThresholds(bool filterType,TemperatureType type,std::vector<TemperatureThreshold> * _aidl_return)115 ndk::ScopedAStatus Thermal::getFilteredTemperatureThresholds(
116 bool filterType, TemperatureType type, std::vector<TemperatureThreshold> *_aidl_return) {
117 *_aidl_return = {};
118 if (!thermal_helper_->isInitializedOk()) {
119 return initErrorStatus();
120 }
121 if (!thermal_helper_->fillTemperatureThresholds(filterType, type, _aidl_return)) {
122 return readErrorStatus();
123 }
124 return ndk::ScopedAStatus::ok();
125 }
126
registerThermalChangedCallback(const std::shared_ptr<IThermalChangedCallback> & callback)127 ndk::ScopedAStatus Thermal::registerThermalChangedCallback(
128 const std::shared_ptr<IThermalChangedCallback> &callback) {
129 ATRACE_CALL();
130 return registerThermalChangedCallback(callback, false, TemperatureType::UNKNOWN);
131 }
132
registerThermalChangedCallbackWithType(const std::shared_ptr<IThermalChangedCallback> & callback,TemperatureType type)133 ndk::ScopedAStatus Thermal::registerThermalChangedCallbackWithType(
134 const std::shared_ptr<IThermalChangedCallback> &callback, TemperatureType type) {
135 ATRACE_CALL();
136 return registerThermalChangedCallback(callback, true, type);
137 }
138
unregisterThermalChangedCallback(const std::shared_ptr<IThermalChangedCallback> & callback)139 ndk::ScopedAStatus Thermal::unregisterThermalChangedCallback(
140 const std::shared_ptr<IThermalChangedCallback> &callback) {
141 if (callback == nullptr) {
142 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
143 "Invalid nullptr callback");
144 }
145 bool removed = false;
146 std::lock_guard<std::mutex> _lock(thermal_callback_mutex_);
147 callbacks_.erase(
148 std::remove_if(
149 callbacks_.begin(), callbacks_.end(),
150 [&](const CallbackSetting &c) {
151 if (interfacesEqual(c.callback, callback)) {
152 LOG(INFO)
153 << "a callback has been unregistered to ThermalHAL, isFilter: "
154 << c.is_filter_type << " Type: " << toString(c.type);
155 removed = true;
156 return true;
157 }
158 return false;
159 }),
160 callbacks_.end());
161 if (!removed) {
162 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
163 "Callback wasn't registered");
164 }
165 return ndk::ScopedAStatus::ok();
166 }
167
registerThermalChangedCallback(const std::shared_ptr<IThermalChangedCallback> & callback,bool filterType,TemperatureType type)168 ndk::ScopedAStatus Thermal::registerThermalChangedCallback(
169 const std::shared_ptr<IThermalChangedCallback> &callback, bool filterType,
170 TemperatureType type) {
171 ATRACE_CALL();
172 if (callback == nullptr) {
173 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
174 "Invalid nullptr callback");
175 }
176 if (!thermal_helper_->isInitializedOk()) {
177 return initErrorStatus();
178 }
179 std::lock_guard<std::mutex> _lock(thermal_callback_mutex_);
180 if (std::any_of(callbacks_.begin(), callbacks_.end(), [&](const CallbackSetting &c) {
181 return interfacesEqual(c.callback, callback);
182 })) {
183 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
184 "Callback already registered");
185 }
186 auto c = callbacks_.emplace_back(callback, filterType, type);
187 LOG(INFO) << "a callback has been registered to ThermalHAL, isFilter: " << c.is_filter_type
188 << " Type: " << toString(c.type);
189 // Send notification right away after successful thermal callback registration
190 std::function<void()> handler = [this, c, filterType, type]() {
191 std::vector<Temperature> temperatures;
192 if (thermal_helper_->fillCurrentTemperatures(filterType, true, type, &temperatures)) {
193 std::lock_guard<std::mutex> _lock(thermal_callback_mutex_);
194 auto it = std::find_if(callbacks_.begin(), callbacks_.end(),
195 [&](const CallbackSetting &cc) {
196 return interfacesEqual(c.callback, cc.callback);
197 });
198 if (it != callbacks_.end()) {
199 if (AIBinder_isAlive(c.callback->asBinder().get())) {
200 for (const auto &t : temperatures) {
201 if (!filterType || t.type == type) {
202 LOG(INFO) << "Sending notification: "
203 << " Type: " << toString(t.type) << " Name: " << t.name
204 << " CurrentValue: " << t.value
205 << " ThrottlingStatus: " << toString(t.throttlingStatus);
206 c.callback->notifyThrottling(t);
207 }
208 }
209 } else {
210 callbacks_.erase(it);
211 }
212 }
213 }
214 };
215 looper_.addEvent(Looper::Event{handler});
216 return ndk::ScopedAStatus::ok();
217 }
218
sendThermalChangedCallback(const Temperature & t)219 void Thermal::sendThermalChangedCallback(const Temperature &t) {
220 ATRACE_CALL();
221 std::lock_guard<std::mutex> _lock(thermal_callback_mutex_);
222 LOG(VERBOSE) << "Sending notification: "
223 << " Type: " << toString(t.type) << " Name: " << t.name
224 << " CurrentValue: " << t.value
225 << " ThrottlingStatus: " << toString(t.throttlingStatus);
226
227 callbacks_.erase(std::remove_if(callbacks_.begin(), callbacks_.end(),
228 [&](const CallbackSetting &c) {
229 if (!c.is_filter_type || t.type == c.type) {
230 ::ndk::ScopedAStatus ret =
231 c.callback->notifyThrottling(t);
232 if (!ret.isOk()) {
233 LOG(ERROR) << "a Thermal callback is dead, removed "
234 "from callback list.";
235 return true;
236 }
237 return false;
238 }
239 return false;
240 }),
241 callbacks_.end());
242 }
243
dumpVirtualSensorInfo(std::ostringstream * dump_buf)244 void Thermal::dumpVirtualSensorInfo(std::ostringstream *dump_buf) {
245 *dump_buf << "getVirtualSensorInfo:" << std::endl;
246 const auto &map = thermal_helper_->GetSensorInfoMap();
247 for (const auto &sensor_info_pair : map) {
248 if (sensor_info_pair.second.virtual_sensor_info != nullptr) {
249 *dump_buf << " Name: " << sensor_info_pair.first << std::endl;
250 *dump_buf << " LinkedSensorName: [";
251 for (size_t i = 0;
252 i < sensor_info_pair.second.virtual_sensor_info->linked_sensors.size(); i++) {
253 *dump_buf << sensor_info_pair.second.virtual_sensor_info->linked_sensors[i] << " ";
254 }
255 *dump_buf << "]" << std::endl;
256 *dump_buf << " LinkedSensorCoefficient: [";
257 for (size_t i = 0; i < sensor_info_pair.second.virtual_sensor_info->coefficients.size();
258 i++) {
259 *dump_buf << sensor_info_pair.second.virtual_sensor_info->coefficients[i] << " ";
260 }
261 *dump_buf << "]" << std::endl;
262 *dump_buf << " Offset: " << sensor_info_pair.second.virtual_sensor_info->offset
263 << std::endl;
264 *dump_buf << " Trigger Sensor: ";
265 if (sensor_info_pair.second.virtual_sensor_info->trigger_sensors.empty()) {
266 *dump_buf << "N/A" << std::endl;
267 } else {
268 for (size_t i = 0;
269 i < sensor_info_pair.second.virtual_sensor_info->trigger_sensors.size(); i++) {
270 *dump_buf << sensor_info_pair.second.virtual_sensor_info->trigger_sensors[i]
271 << " ";
272 }
273 *dump_buf << std::endl;
274 }
275 *dump_buf << " Formula: ";
276 switch (sensor_info_pair.second.virtual_sensor_info->formula) {
277 case FormulaOption::COUNT_THRESHOLD:
278 *dump_buf << "COUNT_THRESHOLD";
279 break;
280 case FormulaOption::WEIGHTED_AVG:
281 *dump_buf << "WEIGHTED_AVG";
282 break;
283 case FormulaOption::MAXIMUM:
284 *dump_buf << "MAXIMUM";
285 break;
286 case FormulaOption::MINIMUM:
287 *dump_buf << "MINIMUM";
288 break;
289 default:
290 *dump_buf << "NONE";
291 break;
292 }
293
294 *dump_buf << std::endl;
295 }
296 }
297 }
298
dumpThrottlingInfo(std::ostringstream * dump_buf)299 void Thermal::dumpThrottlingInfo(std::ostringstream *dump_buf) {
300 *dump_buf << "getThrottlingInfo:" << std::endl;
301 const auto &map = thermal_helper_->GetSensorInfoMap();
302 const auto &thermal_throttling_status_map = thermal_helper_->GetThermalThrottlingStatusMap();
303 for (const auto &name_info_pair : map) {
304 if (name_info_pair.second.throttling_info == nullptr) {
305 continue;
306 }
307 if (name_info_pair.second.throttling_info->binded_cdev_info_map.size()) {
308 if (thermal_throttling_status_map.find(name_info_pair.first) ==
309 thermal_throttling_status_map.end()) {
310 continue;
311 }
312 *dump_buf << " Name: " << name_info_pair.first << std::endl;
313 if (thermal_throttling_status_map.at(name_info_pair.first)
314 .pid_power_budget_map.size()) {
315 *dump_buf << " PID Info:" << std::endl;
316 *dump_buf << " K_po: [";
317 for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
318 *dump_buf << name_info_pair.second.throttling_info->k_po[i] << " ";
319 }
320 *dump_buf << "]" << std::endl;
321 *dump_buf << " K_pu: [";
322 for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
323 *dump_buf << name_info_pair.second.throttling_info->k_pu[i] << " ";
324 }
325 *dump_buf << "]" << std::endl;
326 *dump_buf << " K_i: [";
327 for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
328 *dump_buf << name_info_pair.second.throttling_info->k_i[i] << " ";
329 }
330 *dump_buf << "]" << std::endl;
331 *dump_buf << " K_d: [";
332 for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
333 *dump_buf << name_info_pair.second.throttling_info->k_d[i] << " ";
334 }
335 *dump_buf << "]" << std::endl;
336 *dump_buf << " i_max: [";
337 for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
338 *dump_buf << name_info_pair.second.throttling_info->i_max[i] << " ";
339 }
340 *dump_buf << "]" << std::endl;
341 *dump_buf << " max_alloc_power: [";
342 for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
343 *dump_buf << name_info_pair.second.throttling_info->max_alloc_power[i] << " ";
344 }
345 *dump_buf << "]" << std::endl;
346 *dump_buf << " min_alloc_power: [";
347 for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
348 *dump_buf << name_info_pair.second.throttling_info->min_alloc_power[i] << " ";
349 }
350 *dump_buf << "]" << std::endl;
351 *dump_buf << " s_power: [";
352 for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
353 *dump_buf << name_info_pair.second.throttling_info->s_power[i] << " ";
354 }
355 *dump_buf << "]" << std::endl;
356 *dump_buf << " i_cutoff: [";
357 for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
358 *dump_buf << name_info_pair.second.throttling_info->i_cutoff[i] << " ";
359 }
360 *dump_buf << "]" << std::endl;
361 }
362 const auto &profile = thermal_throttling_status_map.at(name_info_pair.first).profile;
363 *dump_buf << " Binded CDEV Info:" << (profile.empty() ? "default" : profile)
364 << std::endl;
365
366 for (const auto &binded_cdev_info_pair :
367 name_info_pair.second.throttling_info->profile_map.count(profile)
368 ? name_info_pair.second.throttling_info->profile_map.at(profile)
369 : name_info_pair.second.throttling_info->binded_cdev_info_map) {
370 *dump_buf << " Cooling device name: " << binded_cdev_info_pair.first << std::endl;
371 if (thermal_throttling_status_map.at(name_info_pair.first)
372 .pid_power_budget_map.size()) {
373 *dump_buf << " WeightForPID: [";
374 for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
375 *dump_buf << binded_cdev_info_pair.second.cdev_weight_for_pid[i] << " ";
376 }
377 *dump_buf << "]" << std::endl;
378 }
379 *dump_buf << " Ceiling: [";
380 for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
381 *dump_buf << binded_cdev_info_pair.second.cdev_ceiling[i] << " ";
382 }
383 *dump_buf << "]" << std::endl;
384 *dump_buf << " Hard limit: [";
385 for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
386 *dump_buf << binded_cdev_info_pair.second.limit_info[i] << " ";
387 }
388 *dump_buf << "]" << std::endl;
389
390 if (!binded_cdev_info_pair.second.power_rail.empty()) {
391 *dump_buf << " Binded power rail: "
392 << binded_cdev_info_pair.second.power_rail << std::endl;
393 *dump_buf << " Power threshold: [";
394 for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
395 *dump_buf << binded_cdev_info_pair.second.power_thresholds[i] << " ";
396 }
397 *dump_buf << "]" << std::endl;
398 *dump_buf << " Floor with PowerLink: [";
399 for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
400 *dump_buf << binded_cdev_info_pair.second.cdev_floor_with_power_link[i]
401 << " ";
402 }
403 *dump_buf << "]" << std::endl;
404 *dump_buf << " Release logic: ";
405 switch (binded_cdev_info_pair.second.release_logic) {
406 case ReleaseLogic::INCREASE:
407 *dump_buf << "INCREASE";
408 break;
409 case ReleaseLogic::DECREASE:
410 *dump_buf << "DECREASE";
411 break;
412 case ReleaseLogic::STEPWISE:
413 *dump_buf << "STEPWISE";
414 break;
415 case ReleaseLogic::RELEASE_TO_FLOOR:
416 *dump_buf << "RELEASE_TO_FLOOR";
417 break;
418 default:
419 *dump_buf << "NONE";
420 break;
421 }
422 *dump_buf << std::endl;
423 *dump_buf << " high_power_check: " << std::boolalpha
424 << binded_cdev_info_pair.second.high_power_check << std::endl;
425 *dump_buf << " throttling_with_power_link: " << std::boolalpha
426 << binded_cdev_info_pair.second.throttling_with_power_link
427 << std::endl;
428 }
429 }
430 }
431 }
432 }
433
dumpThrottlingRequestStatus(std::ostringstream * dump_buf)434 void Thermal::dumpThrottlingRequestStatus(std::ostringstream *dump_buf) {
435 const auto &thermal_throttling_status_map = thermal_helper_->GetThermalThrottlingStatusMap();
436 if (!thermal_throttling_status_map.size()) {
437 return;
438 }
439 *dump_buf << "getThrottlingRequestStatus:" << std::endl;
440 for (const auto &thermal_throttling_status_pair : thermal_throttling_status_map) {
441 *dump_buf << " Name: " << thermal_throttling_status_pair.first << std::endl;
442 if (thermal_throttling_status_pair.second.pid_power_budget_map.size()) {
443 *dump_buf << " power budget request state" << std::endl;
444 for (const auto &request_pair :
445 thermal_throttling_status_pair.second.pid_power_budget_map) {
446 *dump_buf << " " << request_pair.first << ": " << request_pair.second
447 << std::endl;
448 }
449 }
450 if (thermal_throttling_status_pair.second.pid_cdev_request_map.size()) {
451 *dump_buf << " pid cdev request state" << std::endl;
452 for (const auto &request_pair :
453 thermal_throttling_status_pair.second.pid_cdev_request_map) {
454 *dump_buf << " " << request_pair.first << ": " << request_pair.second
455 << std::endl;
456 }
457 }
458 if (thermal_throttling_status_pair.second.hardlimit_cdev_request_map.size()) {
459 *dump_buf << " hard limit cdev request state" << std::endl;
460 for (const auto &request_pair :
461 thermal_throttling_status_pair.second.hardlimit_cdev_request_map) {
462 *dump_buf << " " << request_pair.first << ": " << request_pair.second
463 << std::endl;
464 }
465 }
466 if (thermal_throttling_status_pair.second.throttling_release_map.size()) {
467 *dump_buf << " cdev release state" << std::endl;
468 for (const auto &request_pair :
469 thermal_throttling_status_pair.second.throttling_release_map) {
470 *dump_buf << " " << request_pair.first << ": " << request_pair.second
471 << std::endl;
472 }
473 }
474 if (thermal_throttling_status_pair.second.cdev_status_map.size()) {
475 *dump_buf << " cdev request state" << std::endl;
476 for (const auto &request_pair : thermal_throttling_status_pair.second.cdev_status_map) {
477 *dump_buf << " " << request_pair.first << ": " << request_pair.second
478 << std::endl;
479 }
480 }
481 }
482 }
483
dumpPowerRailInfo(std::ostringstream * dump_buf)484 void Thermal::dumpPowerRailInfo(std::ostringstream *dump_buf) {
485 const auto &power_rail_info_map = thermal_helper_->GetPowerRailInfoMap();
486 const auto &power_status_map = thermal_helper_->GetPowerStatusMap();
487
488 *dump_buf << "getPowerRailInfo:" << std::endl;
489 for (const auto &power_rail_pair : power_rail_info_map) {
490 *dump_buf << " Power Rail: " << power_rail_pair.first << std::endl;
491 *dump_buf << " Power Sample Count: " << power_rail_pair.second.power_sample_count
492 << std::endl;
493 *dump_buf << " Power Sample Delay: " << power_rail_pair.second.power_sample_delay.count()
494 << std::endl;
495 if (power_status_map.count(power_rail_pair.first)) {
496 auto power_history = power_status_map.at(power_rail_pair.first).power_history;
497 *dump_buf << " Last Updated AVG Power: "
498 << power_status_map.at(power_rail_pair.first).last_updated_avg_power << " mW"
499 << std::endl;
500 if (power_rail_pair.second.virtual_power_rail_info != nullptr) {
501 *dump_buf << " Formula=";
502 switch (power_rail_pair.second.virtual_power_rail_info->formula) {
503 case FormulaOption::COUNT_THRESHOLD:
504 *dump_buf << "COUNT_THRESHOLD";
505 break;
506 case FormulaOption::WEIGHTED_AVG:
507 *dump_buf << "WEIGHTED_AVG";
508 break;
509 case FormulaOption::MAXIMUM:
510 *dump_buf << "MAXIMUM";
511 break;
512 case FormulaOption::MINIMUM:
513 *dump_buf << "MINIMUM";
514 break;
515 default:
516 *dump_buf << "NONE";
517 break;
518 }
519 *dump_buf << std::endl;
520 }
521 for (size_t i = 0; i < power_history.size(); ++i) {
522 if (power_rail_pair.second.virtual_power_rail_info != nullptr) {
523 *dump_buf
524 << " Linked power rail "
525 << power_rail_pair.second.virtual_power_rail_info->linked_power_rails[i]
526 << std::endl;
527 *dump_buf << " Coefficient="
528 << power_rail_pair.second.virtual_power_rail_info->coefficients[i]
529 << std::endl;
530 *dump_buf << " Power Samples: ";
531 } else {
532 *dump_buf << " Power Samples: ";
533 }
534 while (power_history[i].size() > 0) {
535 const auto power_sample = power_history[i].front();
536 power_history[i].pop();
537 *dump_buf << "(T=" << power_sample.duration
538 << ", uWs=" << power_sample.energy_counter << ") ";
539 }
540 *dump_buf << std::endl;
541 }
542 }
543 }
544 }
545
dumpStatsRecord(std::ostringstream * dump_buf,const StatsRecord & stats_record,std::string_view line_prefix)546 void Thermal::dumpStatsRecord(std::ostringstream *dump_buf, const StatsRecord &stats_record,
547 std::string_view line_prefix) {
548 const auto now = boot_clock::now();
549 *dump_buf << line_prefix << "Time Since Last Stats Report: "
550 << std::chrono::duration_cast<std::chrono::minutes>(
551 now - stats_record.last_stats_report_time)
552 .count()
553 << " mins" << std::endl;
554 *dump_buf << line_prefix << "Time in State ms: [";
555 for (const auto &time_in_state : stats_record.time_in_state_ms) {
556 *dump_buf << time_in_state.count() << " ";
557 }
558 *dump_buf << "]" << std::endl;
559 }
560
dumpThermalStats(std::ostringstream * dump_buf)561 void Thermal::dumpThermalStats(std::ostringstream *dump_buf) {
562 *dump_buf << "getThermalStatsInfo:" << std::endl;
563 *dump_buf << " Sensor Temp Stats Info:" << std::endl;
564 const auto &sensor_temp_stats_map_ = thermal_helper_->GetSensorTempStatsSnapshot();
565 const std::string sensor_temp_stats_line_prefix(" ");
566 for (const auto &sensor_temp_stats_pair : sensor_temp_stats_map_) {
567 *dump_buf << " Sensor Name: " << sensor_temp_stats_pair.first << std::endl;
568 const auto &sensor_temp_stats = sensor_temp_stats_pair.second;
569 *dump_buf << " Max Temp: " << sensor_temp_stats.max_temp << ", TimeStamp: "
570 << system_clock::to_time_t(sensor_temp_stats.max_temp_timestamp) << std::endl;
571 *dump_buf << " Min Temp: " << sensor_temp_stats.min_temp << ", TimeStamp: "
572 << system_clock::to_time_t(sensor_temp_stats.min_temp_timestamp) << std::endl;
573 for (const auto &stats_by_threshold : sensor_temp_stats.stats_by_custom_threshold) {
574 *dump_buf << " Record by Threshold: [";
575 for (const auto &threshold : stats_by_threshold.thresholds) {
576 *dump_buf << threshold << " ";
577 }
578 *dump_buf << "]" << std::endl;
579 if (stats_by_threshold.logging_name.has_value()) {
580 *dump_buf << " Logging Name: " << stats_by_threshold.logging_name.value()
581 << std::endl;
582 }
583 dumpStatsRecord(dump_buf, stats_by_threshold.stats_record,
584 sensor_temp_stats_line_prefix);
585 }
586
587 if (sensor_temp_stats.stats_by_default_threshold.has_value()) {
588 *dump_buf << " Record by Severity:" << std::endl;
589 dumpStatsRecord(dump_buf, sensor_temp_stats.stats_by_default_threshold.value(),
590 sensor_temp_stats_line_prefix);
591 }
592 }
593 *dump_buf << " Sensor Cdev Request Stats Info:" << std::endl;
594 const auto &sensor_cdev_request_stats_map_ =
595 thermal_helper_->GetSensorCoolingDeviceRequestStatsSnapshot();
596 const std::string sensor_cdev_request_stats_line_prefix(" ");
597 for (const auto &sensor_cdev_request_stats_pair : sensor_cdev_request_stats_map_) {
598 *dump_buf << " Sensor Name: " << sensor_cdev_request_stats_pair.first << std::endl;
599 for (const auto &cdev_request_stats_pair : sensor_cdev_request_stats_pair.second) {
600 *dump_buf << " Cooling Device Name: " << cdev_request_stats_pair.first << std::endl;
601 const auto &request_stats = cdev_request_stats_pair.second;
602 for (const auto &stats_by_threshold : request_stats.stats_by_custom_threshold) {
603 *dump_buf << " Record by Threshold: [";
604 for (const auto &threshold : stats_by_threshold.thresholds) {
605 *dump_buf << threshold << " ";
606 }
607 *dump_buf << "]" << std::endl;
608 if (stats_by_threshold.logging_name.has_value()) {
609 *dump_buf << " Logging Name: " << stats_by_threshold.logging_name.value()
610 << std::endl;
611 }
612 dumpStatsRecord(dump_buf, stats_by_threshold.stats_record,
613 sensor_cdev_request_stats_line_prefix);
614 }
615 if (request_stats.stats_by_default_threshold.has_value()) {
616 *dump_buf << " Record by All State" << std::endl;
617 dumpStatsRecord(dump_buf, request_stats.stats_by_default_threshold.value(),
618 sensor_cdev_request_stats_line_prefix);
619 }
620 }
621 }
622 }
623
dumpThermalData(int fd)624 void Thermal::dumpThermalData(int fd) {
625 std::ostringstream dump_buf;
626
627 if (!thermal_helper_->isInitializedOk()) {
628 dump_buf << "ThermalHAL not initialized properly." << std::endl;
629 } else {
630 const auto &sensor_status_map = thermal_helper_->GetSensorStatusMap();
631 {
632 dump_buf << "getCachedTemperatures:" << std::endl;
633 boot_clock::time_point now = boot_clock::now();
634 for (const auto &sensor_status_pair : sensor_status_map) {
635 if ((sensor_status_pair.second.thermal_cached.timestamp) ==
636 boot_clock::time_point::min()) {
637 continue;
638 }
639 dump_buf << " Name: " << sensor_status_pair.first
640 << " CachedValue: " << sensor_status_pair.second.thermal_cached.temp
641 << " TimeToCache: "
642 << std::chrono::duration_cast<std::chrono::milliseconds>(
643 now - sensor_status_pair.second.thermal_cached.timestamp)
644 .count()
645 << "ms" << std::endl;
646 }
647 }
648 {
649 dump_buf << "getEmulTemperatures:" << std::endl;
650 for (const auto &sensor_status_pair : sensor_status_map) {
651 if (sensor_status_pair.second.emul_setting == nullptr) {
652 continue;
653 }
654 dump_buf << " Name: " << sensor_status_pair.first
655 << " EmulTemp: " << sensor_status_pair.second.emul_setting->emul_temp
656 << " EmulSeverity: "
657 << sensor_status_pair.second.emul_setting->emul_severity << std::endl;
658 }
659 }
660 {
661 const auto &map = thermal_helper_->GetSensorInfoMap();
662 dump_buf << "getCurrentTemperatures:" << std::endl;
663 Temperature temp_2_0;
664 for (const auto &name_info_pair : map) {
665 thermal_helper_->readTemperature(name_info_pair.first, &temp_2_0, nullptr, true);
666 dump_buf << " Type: " << toString(temp_2_0.type)
667 << " Name: " << name_info_pair.first << " CurrentValue: " << temp_2_0.value
668 << " ThrottlingStatus: " << toString(temp_2_0.throttlingStatus)
669 << std::endl;
670 }
671 dump_buf << "getTemperatureThresholds:" << std::endl;
672 for (const auto &name_info_pair : map) {
673 if (!name_info_pair.second.is_watch) {
674 continue;
675 }
676 dump_buf << " Type: " << toString(name_info_pair.second.type)
677 << " Name: " << name_info_pair.first;
678 dump_buf << " hotThrottlingThreshold: [";
679 for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
680 dump_buf << name_info_pair.second.hot_thresholds[i] << " ";
681 }
682 dump_buf << "] coldThrottlingThreshold: [";
683 for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
684 dump_buf << name_info_pair.second.cold_thresholds[i] << " ";
685 }
686 dump_buf << "] vrThrottlingThreshold: " << name_info_pair.second.vr_threshold;
687 dump_buf << std::endl;
688 }
689 dump_buf << "getHysteresis:" << std::endl;
690 for (const auto &name_info_pair : map) {
691 if (!name_info_pair.second.is_watch) {
692 continue;
693 }
694 dump_buf << " Name: " << name_info_pair.first;
695 dump_buf << " hotHysteresis: [";
696 for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
697 dump_buf << name_info_pair.second.hot_hysteresis[i] << " ";
698 }
699 dump_buf << "] coldHysteresis: [";
700 for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
701 dump_buf << name_info_pair.second.cold_hysteresis[i] << " ";
702 }
703 dump_buf << "]" << std::endl;
704 }
705 }
706 {
707 dump_buf << "getCurrentCoolingDevices:" << std::endl;
708 std::vector<CoolingDevice> cooling_devices;
709 if (!thermal_helper_->fillCurrentCoolingDevices(false, CoolingType::CPU,
710 &cooling_devices)) {
711 dump_buf << " Failed to getCurrentCoolingDevices." << std::endl;
712 }
713
714 for (const auto &c : cooling_devices) {
715 dump_buf << " Type: " << toString(c.type) << " Name: " << c.name
716 << " CurrentValue: " << c.value << std::endl;
717 }
718 }
719 {
720 dump_buf << "getCallbacks:" << std::endl;
721 dump_buf << " Total: " << callbacks_.size() << std::endl;
722 for (const auto &c : callbacks_) {
723 dump_buf << " IsFilter: " << c.is_filter_type << " Type: " << toString(c.type)
724 << std::endl;
725 }
726 }
727 {
728 dump_buf << "sendCallback:" << std::endl;
729 dump_buf << " Enabled List: ";
730 const auto &map = thermal_helper_->GetSensorInfoMap();
731 for (const auto &name_info_pair : map) {
732 if (name_info_pair.second.send_cb) {
733 dump_buf << name_info_pair.first << " ";
734 }
735 }
736 dump_buf << std::endl;
737 }
738 {
739 dump_buf << "sendPowerHint:" << std::endl;
740 dump_buf << " Enabled List: ";
741 const auto &map = thermal_helper_->GetSensorInfoMap();
742 for (const auto &name_info_pair : map) {
743 if (name_info_pair.second.send_powerhint) {
744 dump_buf << name_info_pair.first << " ";
745 }
746 }
747 dump_buf << std::endl;
748 }
749 dumpVirtualSensorInfo(&dump_buf);
750 dumpThrottlingInfo(&dump_buf);
751 dumpThrottlingRequestStatus(&dump_buf);
752 dumpPowerRailInfo(&dump_buf);
753 dumpThermalStats(&dump_buf);
754 {
755 dump_buf << "getAIDLPowerHalInfo:" << std::endl;
756 dump_buf << " Exist: " << std::boolalpha << thermal_helper_->isAidlPowerHalExist()
757 << std::endl;
758 dump_buf << " Connected: " << std::boolalpha << thermal_helper_->isPowerHalConnected()
759 << std::endl;
760 dump_buf << " Ext connected: " << std::boolalpha
761 << thermal_helper_->isPowerHalExtConnected() << std::endl;
762 }
763 }
764 std::string buf = dump_buf.str();
765 if (!::android::base::WriteStringToFd(buf, fd)) {
766 PLOG(ERROR) << "Failed to dump state to fd";
767 }
768 fsync(fd);
769 }
770
dump(int fd,const char ** args,uint32_t numArgs)771 binder_status_t Thermal::dump(int fd, const char **args, uint32_t numArgs) {
772 if (numArgs == 0 || std::string(args[0]) == "-a") {
773 dumpThermalData(fd);
774 return STATUS_OK;
775 }
776
777 if (std::string(args[0]) == "emul_temp") {
778 return (numArgs != 3 || !thermal_helper_->emulTemp(std::string(args[1]), std::atof(args[2])))
779 ? STATUS_BAD_VALUE
780 : STATUS_OK;
781 } else if (std::string(args[0]) == "emul_severity") {
782 return (numArgs != 3 ||
783 !thermal_helper_->emulSeverity(std::string(args[1]), std::atoi(args[2])))
784 ? STATUS_BAD_VALUE
785 : STATUS_OK;
786 } else if (std::string(args[0]) == "emul_clear") {
787 return (numArgs != 2 || !thermal_helper_->emulClear(std::string(args[1])))
788 ? STATUS_BAD_VALUE
789 : STATUS_OK;
790 }
791 return STATUS_BAD_VALUE;
792 }
793
addEvent(const Thermal::Looper::Event & e)794 void Thermal::Looper::addEvent(const Thermal::Looper::Event &e) {
795 std::unique_lock<std::mutex> lock(mutex_);
796 events_.push(e);
797 cv_.notify_all();
798 }
799
~Looper()800 Thermal::Looper::~Looper() {
801 {
802 std::unique_lock<std::mutex> lock(mutex_);
803 aborted_ = true;
804 }
805 cv_.notify_one();
806 thread_.join();
807 }
808
loop()809 void Thermal::Looper::loop() {
810 while (!aborted_) {
811 std::unique_lock<std::mutex> lock(mutex_);
812 cv_.wait(lock, [&] { return aborted_ || !events_.empty(); });
813 if (!aborted_ && !events_.empty()) {
814 Event event = events_.front();
815 events_.pop();
816 lock.unlock();
817 event.handler();
818 }
819 }
820 }
821
822 } // namespace implementation
823 } // namespace thermal
824 } // namespace hardware
825 } // namespace android
826 } // namespace aidl
827