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
registerCoolingDeviceChangedCallbackWithType(const std::shared_ptr<ICoolingDeviceChangedCallback> & callback,CoolingType type)244 ndk::ScopedAStatus Thermal::registerCoolingDeviceChangedCallbackWithType(
245 const std::shared_ptr<ICoolingDeviceChangedCallback> &callback, CoolingType type) {
246 ATRACE_CALL();
247
248 if (callback == nullptr) {
249 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
250 "Invalid nullptr callback");
251 }
252
253 if (!thermal_helper_->isInitializedOk()) {
254 return initErrorStatus();
255 }
256
257 std::lock_guard<std::mutex> _lock(cdev_callback_mutex_);
258 if (std::any_of(cdev_callbacks_.begin(), cdev_callbacks_.end(),
259 [&](const CoolingDeviceCallbackSetting &c) {
260 return interfacesEqual(c.callback, callback);
261 })) {
262 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
263 "Callback already registered");
264 }
265 cdev_callbacks_.emplace_back(callback, true, type);
266
267 // b/315858553 to develope the callback
268 LOG(INFO) << __func__ << ":" << toString(type) << " is under development";
269
270 return ndk::ScopedAStatus::ok();
271 }
272
unregisterCoolingDeviceChangedCallback(const std::shared_ptr<ICoolingDeviceChangedCallback> & callback)273 ndk::ScopedAStatus Thermal::unregisterCoolingDeviceChangedCallback(
274 const std::shared_ptr<ICoolingDeviceChangedCallback> &callback) {
275 ATRACE_CALL();
276
277 if (callback == nullptr) {
278 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
279 "Invalid nullptr callback");
280 }
281
282 bool removed = false;
283 std::lock_guard<std::mutex> _lock(cdev_callback_mutex_);
284 cdev_callbacks_.erase(
285 std::remove_if(
286 cdev_callbacks_.begin(), cdev_callbacks_.end(),
287 [&](const CoolingDeviceCallbackSetting &c) {
288 if (interfacesEqual(c.callback, callback)) {
289 LOG(INFO)
290 << "a callback has been unregistered to ThermalHAL, isFilter: "
291 << c.is_filter_type << " Type: " << toString(c.type);
292 removed = true;
293 return true;
294 }
295 return false;
296 }),
297 cdev_callbacks_.end());
298
299 if (!removed) {
300 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
301 "Callback wasn't registered");
302 }
303
304 // b/315858553 to develope the callback
305 LOG(INFO) << __func__ << " is under development";
306
307 return ndk::ScopedAStatus::ok();
308 }
309
dumpVirtualSensorInfo(std::ostringstream * dump_buf)310 void Thermal::dumpVirtualSensorInfo(std::ostringstream *dump_buf) {
311 *dump_buf << "getVirtualSensorInfo:" << std::endl;
312 const auto &map = thermal_helper_->GetSensorInfoMap();
313 for (const auto &sensor_info_pair : map) {
314 if (sensor_info_pair.second.virtual_sensor_info != nullptr) {
315 *dump_buf << " Name: " << sensor_info_pair.first << std::endl;
316 *dump_buf << " LinkedSensorName: [";
317 for (size_t i = 0;
318 i < sensor_info_pair.second.virtual_sensor_info->linked_sensors.size(); i++) {
319 *dump_buf << sensor_info_pair.second.virtual_sensor_info->linked_sensors[i] << " ";
320 }
321 *dump_buf << "]" << std::endl;
322 *dump_buf << " LinkedSensorCoefficient: [";
323 for (size_t i = 0; i < sensor_info_pair.second.virtual_sensor_info->coefficients.size();
324 i++) {
325 *dump_buf << sensor_info_pair.second.virtual_sensor_info->coefficients[i] << " ";
326 }
327 *dump_buf << "]" << std::endl;
328 *dump_buf << " Offset: " << sensor_info_pair.second.virtual_sensor_info->offset
329 << std::endl;
330 *dump_buf << " Trigger Sensor: ";
331 if (sensor_info_pair.second.virtual_sensor_info->trigger_sensors.empty()) {
332 *dump_buf << "N/A" << std::endl;
333 } else {
334 for (size_t i = 0;
335 i < sensor_info_pair.second.virtual_sensor_info->trigger_sensors.size(); i++) {
336 *dump_buf << sensor_info_pair.second.virtual_sensor_info->trigger_sensors[i]
337 << " ";
338 }
339 *dump_buf << std::endl;
340 }
341 *dump_buf << " Formula: ";
342 switch (sensor_info_pair.second.virtual_sensor_info->formula) {
343 case FormulaOption::COUNT_THRESHOLD:
344 *dump_buf << "COUNT_THRESHOLD";
345 break;
346 case FormulaOption::WEIGHTED_AVG:
347 *dump_buf << "WEIGHTED_AVG";
348 break;
349 case FormulaOption::MAXIMUM:
350 *dump_buf << "MAXIMUM";
351 break;
352 case FormulaOption::MINIMUM:
353 *dump_buf << "MINIMUM";
354 break;
355 default:
356 *dump_buf << "NONE";
357 break;
358 }
359
360 *dump_buf << std::endl;
361 }
362 }
363 }
364
dumpVtEstimatorInfo(std::ostringstream * dump_buf)365 void Thermal::dumpVtEstimatorInfo(std::ostringstream *dump_buf) {
366 *dump_buf << "getVtEstimatorInfo:" << std::endl;
367 const auto &map = thermal_helper_->GetSensorInfoMap();
368 for (const auto &name_info_pair : map) {
369 thermal_helper_->dumpVtEstimatorStatus(name_info_pair.first, dump_buf);
370 }
371 }
372
dumpThrottlingInfo(std::ostringstream * dump_buf)373 void Thermal::dumpThrottlingInfo(std::ostringstream *dump_buf) {
374 *dump_buf << "getThrottlingInfo:" << std::endl;
375 const auto &map = thermal_helper_->GetSensorInfoMap();
376 const auto &thermal_throttling_status_map = thermal_helper_->GetThermalThrottlingStatusMap();
377 for (const auto &name_info_pair : map) {
378 if (name_info_pair.second.throttling_info == nullptr) {
379 continue;
380 }
381 if (name_info_pair.second.throttling_info->binded_cdev_info_map.size()) {
382 if (thermal_throttling_status_map.find(name_info_pair.first) ==
383 thermal_throttling_status_map.end()) {
384 continue;
385 }
386 *dump_buf << " Name: " << name_info_pair.first << std::endl;
387 if (thermal_throttling_status_map.at(name_info_pair.first)
388 .pid_power_budget_map.size()) {
389 *dump_buf << " PID Info:" << std::endl;
390 *dump_buf << " K_po: [";
391 for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
392 *dump_buf << name_info_pair.second.throttling_info->k_po[i] << " ";
393 }
394 *dump_buf << "]" << std::endl;
395 *dump_buf << " K_pu: [";
396 for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
397 *dump_buf << name_info_pair.second.throttling_info->k_pu[i] << " ";
398 }
399 *dump_buf << "]" << std::endl;
400 *dump_buf << " K_i: [";
401 for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
402 *dump_buf << name_info_pair.second.throttling_info->k_i[i] << " ";
403 }
404 *dump_buf << "]" << std::endl;
405 *dump_buf << " K_d: [";
406 for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
407 *dump_buf << name_info_pair.second.throttling_info->k_d[i] << " ";
408 }
409 *dump_buf << "]" << std::endl;
410 *dump_buf << " i_max: [";
411 for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
412 *dump_buf << name_info_pair.second.throttling_info->i_max[i] << " ";
413 }
414 *dump_buf << "]" << std::endl;
415 *dump_buf << " max_alloc_power: [";
416 for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
417 *dump_buf << name_info_pair.second.throttling_info->max_alloc_power[i] << " ";
418 }
419 *dump_buf << "]" << std::endl;
420 *dump_buf << " min_alloc_power: [";
421 for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
422 *dump_buf << name_info_pair.second.throttling_info->min_alloc_power[i] << " ";
423 }
424 *dump_buf << "]" << std::endl;
425 *dump_buf << " s_power: [";
426 for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
427 *dump_buf << name_info_pair.second.throttling_info->s_power[i] << " ";
428 }
429 *dump_buf << "]" << std::endl;
430 *dump_buf << " i_cutoff: [";
431 for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
432 *dump_buf << name_info_pair.second.throttling_info->i_cutoff[i] << " ";
433 }
434 *dump_buf << "]" << std::endl;
435 }
436 const auto &profile = thermal_throttling_status_map.at(name_info_pair.first).profile;
437 *dump_buf << " Binded CDEV Info:" << (profile.empty() ? "default" : profile)
438 << std::endl;
439
440 for (const auto &binded_cdev_info_pair :
441 name_info_pair.second.throttling_info->profile_map.count(profile)
442 ? name_info_pair.second.throttling_info->profile_map.at(profile)
443 : name_info_pair.second.throttling_info->binded_cdev_info_map) {
444 *dump_buf << " Cooling device name: " << binded_cdev_info_pair.first << std::endl;
445 if (thermal_throttling_status_map.at(name_info_pair.first)
446 .pid_power_budget_map.size()) {
447 *dump_buf << " WeightForPID: [";
448 for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
449 *dump_buf << binded_cdev_info_pair.second.cdev_weight_for_pid[i] << " ";
450 }
451 *dump_buf << "]" << std::endl;
452 }
453 *dump_buf << " Ceiling: [";
454 for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
455 *dump_buf << binded_cdev_info_pair.second.cdev_ceiling[i] << " ";
456 }
457 *dump_buf << "]" << std::endl;
458 *dump_buf << " Hard limit: [";
459 for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
460 *dump_buf << binded_cdev_info_pair.second.limit_info[i] << " ";
461 }
462 *dump_buf << "]" << std::endl;
463
464 if (!binded_cdev_info_pair.second.power_rail.empty()) {
465 *dump_buf << " Binded power rail: "
466 << binded_cdev_info_pair.second.power_rail << std::endl;
467 *dump_buf << " Power threshold: [";
468 for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
469 *dump_buf << binded_cdev_info_pair.second.power_thresholds[i] << " ";
470 }
471 *dump_buf << "]" << std::endl;
472 *dump_buf << " Floor with PowerLink: [";
473 for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
474 *dump_buf << binded_cdev_info_pair.second.cdev_floor_with_power_link[i]
475 << " ";
476 }
477 *dump_buf << "]" << std::endl;
478 *dump_buf << " Release logic: ";
479 switch (binded_cdev_info_pair.second.release_logic) {
480 case ReleaseLogic::INCREASE:
481 *dump_buf << "INCREASE";
482 break;
483 case ReleaseLogic::DECREASE:
484 *dump_buf << "DECREASE";
485 break;
486 case ReleaseLogic::STEPWISE:
487 *dump_buf << "STEPWISE";
488 break;
489 case ReleaseLogic::RELEASE_TO_FLOOR:
490 *dump_buf << "RELEASE_TO_FLOOR";
491 break;
492 default:
493 *dump_buf << "NONE";
494 break;
495 }
496 *dump_buf << std::endl;
497 *dump_buf << " high_power_check: " << std::boolalpha
498 << binded_cdev_info_pair.second.high_power_check << std::endl;
499 *dump_buf << " throttling_with_power_link: " << std::boolalpha
500 << binded_cdev_info_pair.second.throttling_with_power_link
501 << std::endl;
502 }
503 }
504 }
505 }
506 }
507
dumpThrottlingRequestStatus(std::ostringstream * dump_buf)508 void Thermal::dumpThrottlingRequestStatus(std::ostringstream *dump_buf) {
509 const auto &thermal_throttling_status_map = thermal_helper_->GetThermalThrottlingStatusMap();
510 if (!thermal_throttling_status_map.size()) {
511 return;
512 }
513 *dump_buf << "getThrottlingRequestStatus:" << std::endl;
514 for (const auto &thermal_throttling_status_pair : thermal_throttling_status_map) {
515 *dump_buf << " Name: " << thermal_throttling_status_pair.first << std::endl;
516 if (thermal_throttling_status_pair.second.pid_power_budget_map.size()) {
517 *dump_buf << " power budget request state" << std::endl;
518 for (const auto &request_pair :
519 thermal_throttling_status_pair.second.pid_power_budget_map) {
520 *dump_buf << " " << request_pair.first << ": " << request_pair.second
521 << std::endl;
522 }
523 }
524 if (thermal_throttling_status_pair.second.pid_cdev_request_map.size()) {
525 *dump_buf << " pid cdev request state" << std::endl;
526 for (const auto &request_pair :
527 thermal_throttling_status_pair.second.pid_cdev_request_map) {
528 *dump_buf << " " << request_pair.first << ": " << request_pair.second
529 << std::endl;
530 }
531 }
532 if (thermal_throttling_status_pair.second.hardlimit_cdev_request_map.size()) {
533 *dump_buf << " hard limit cdev request state" << std::endl;
534 for (const auto &request_pair :
535 thermal_throttling_status_pair.second.hardlimit_cdev_request_map) {
536 *dump_buf << " " << request_pair.first << ": " << request_pair.second
537 << std::endl;
538 }
539 }
540 if (thermal_throttling_status_pair.second.throttling_release_map.size()) {
541 *dump_buf << " cdev release state" << std::endl;
542 for (const auto &request_pair :
543 thermal_throttling_status_pair.second.throttling_release_map) {
544 *dump_buf << " " << request_pair.first << ": " << request_pair.second
545 << std::endl;
546 }
547 }
548 if (thermal_throttling_status_pair.second.cdev_status_map.size()) {
549 *dump_buf << " cdev request state" << std::endl;
550 for (const auto &request_pair : thermal_throttling_status_pair.second.cdev_status_map) {
551 *dump_buf << " " << request_pair.first << ": " << request_pair.second
552 << std::endl;
553 }
554 }
555 }
556 }
557
dumpPowerRailInfo(std::ostringstream * dump_buf)558 void Thermal::dumpPowerRailInfo(std::ostringstream *dump_buf) {
559 const auto &power_rail_info_map = thermal_helper_->GetPowerRailInfoMap();
560 const auto &power_status_map = thermal_helper_->GetPowerStatusMap();
561
562 *dump_buf << "getPowerRailInfo:" << std::endl;
563 for (const auto &power_rail_pair : power_rail_info_map) {
564 *dump_buf << " Power Rail: " << power_rail_pair.first << std::endl;
565 *dump_buf << " Power Sample Count: " << power_rail_pair.second.power_sample_count
566 << std::endl;
567 *dump_buf << " Power Sample Delay: " << power_rail_pair.second.power_sample_delay.count()
568 << std::endl;
569 if (power_status_map.count(power_rail_pair.first)) {
570 auto power_history = power_status_map.at(power_rail_pair.first).power_history;
571 *dump_buf << " Last Updated AVG Power: "
572 << power_status_map.at(power_rail_pair.first).last_updated_avg_power << " mW"
573 << std::endl;
574 if (power_rail_pair.second.virtual_power_rail_info != nullptr) {
575 *dump_buf << " Formula=";
576 switch (power_rail_pair.second.virtual_power_rail_info->formula) {
577 case FormulaOption::COUNT_THRESHOLD:
578 *dump_buf << "COUNT_THRESHOLD";
579 break;
580 case FormulaOption::WEIGHTED_AVG:
581 *dump_buf << "WEIGHTED_AVG";
582 break;
583 case FormulaOption::MAXIMUM:
584 *dump_buf << "MAXIMUM";
585 break;
586 case FormulaOption::MINIMUM:
587 *dump_buf << "MINIMUM";
588 break;
589 default:
590 *dump_buf << "NONE";
591 break;
592 }
593 *dump_buf << std::endl;
594 }
595 for (size_t i = 0; i < power_history.size(); ++i) {
596 if (power_rail_pair.second.virtual_power_rail_info != nullptr) {
597 *dump_buf
598 << " Linked power rail "
599 << power_rail_pair.second.virtual_power_rail_info->linked_power_rails[i]
600 << std::endl;
601 *dump_buf << " Coefficient="
602 << power_rail_pair.second.virtual_power_rail_info->coefficients[i]
603 << std::endl;
604 *dump_buf << " Power Samples: ";
605 } else {
606 *dump_buf << " Power Samples: ";
607 }
608 while (power_history[i].size() > 0) {
609 const auto power_sample = power_history[i].front();
610 power_history[i].pop();
611 *dump_buf << "(T=" << power_sample.duration
612 << ", uWs=" << power_sample.energy_counter << ") ";
613 }
614 *dump_buf << std::endl;
615 }
616 }
617 }
618 }
619
dumpStatsRecord(std::ostringstream * dump_buf,const StatsRecord & stats_record,std::string_view line_prefix)620 void Thermal::dumpStatsRecord(std::ostringstream *dump_buf, const StatsRecord &stats_record,
621 std::string_view line_prefix) {
622 const auto now = boot_clock::now();
623 *dump_buf << line_prefix << "Time Since Last Stats Report: "
624 << std::chrono::duration_cast<std::chrono::minutes>(
625 now - stats_record.last_stats_report_time)
626 .count()
627 << " mins" << std::endl;
628 *dump_buf << line_prefix << "Time in State ms: [";
629 for (const auto &time_in_state : stats_record.time_in_state_ms) {
630 *dump_buf << time_in_state.count() << " ";
631 }
632 *dump_buf << "]" << std::endl;
633 }
634
dumpThermalStats(std::ostringstream * dump_buf)635 void Thermal::dumpThermalStats(std::ostringstream *dump_buf) {
636 *dump_buf << "getThermalStatsInfo:" << std::endl;
637 *dump_buf << " Sensor Temp Stats Info:" << std::endl;
638 const auto &sensor_temp_stats_map_ = thermal_helper_->GetSensorTempStatsSnapshot();
639 const std::string sensor_temp_stats_line_prefix(" ");
640 for (const auto &sensor_temp_stats_pair : sensor_temp_stats_map_) {
641 *dump_buf << " Sensor Name: " << sensor_temp_stats_pair.first << std::endl;
642 const auto &sensor_temp_stats = sensor_temp_stats_pair.second;
643 *dump_buf << " Max Temp: " << sensor_temp_stats.max_temp << ", TimeStamp: "
644 << system_clock::to_time_t(sensor_temp_stats.max_temp_timestamp) << std::endl;
645 *dump_buf << " Min Temp: " << sensor_temp_stats.min_temp << ", TimeStamp: "
646 << system_clock::to_time_t(sensor_temp_stats.min_temp_timestamp) << std::endl;
647 for (const auto &stats_by_threshold : sensor_temp_stats.stats_by_custom_threshold) {
648 *dump_buf << " Record by Threshold: [";
649 for (const auto &threshold : stats_by_threshold.thresholds) {
650 *dump_buf << threshold << " ";
651 }
652 *dump_buf << "]" << std::endl;
653 if (stats_by_threshold.logging_name.has_value()) {
654 *dump_buf << " Logging Name: " << stats_by_threshold.logging_name.value()
655 << std::endl;
656 }
657 dumpStatsRecord(dump_buf, stats_by_threshold.stats_record,
658 sensor_temp_stats_line_prefix);
659 }
660
661 if (sensor_temp_stats.stats_by_default_threshold.has_value()) {
662 *dump_buf << " Record by Severity:" << std::endl;
663 dumpStatsRecord(dump_buf, sensor_temp_stats.stats_by_default_threshold.value(),
664 sensor_temp_stats_line_prefix);
665 }
666 }
667 *dump_buf << " Sensor Cdev Request Stats Info:" << std::endl;
668 const auto &sensor_cdev_request_stats_map_ =
669 thermal_helper_->GetSensorCoolingDeviceRequestStatsSnapshot();
670 const std::string sensor_cdev_request_stats_line_prefix(" ");
671 for (const auto &sensor_cdev_request_stats_pair : sensor_cdev_request_stats_map_) {
672 *dump_buf << " Sensor Name: " << sensor_cdev_request_stats_pair.first << std::endl;
673 for (const auto &cdev_request_stats_pair : sensor_cdev_request_stats_pair.second) {
674 *dump_buf << " Cooling Device Name: " << cdev_request_stats_pair.first << std::endl;
675 const auto &request_stats = cdev_request_stats_pair.second;
676 for (const auto &stats_by_threshold : request_stats.stats_by_custom_threshold) {
677 *dump_buf << " Record by Threshold: [";
678 for (const auto &threshold : stats_by_threshold.thresholds) {
679 *dump_buf << threshold << " ";
680 }
681 *dump_buf << "]" << std::endl;
682 if (stats_by_threshold.logging_name.has_value()) {
683 *dump_buf << " Logging Name: " << stats_by_threshold.logging_name.value()
684 << std::endl;
685 }
686 dumpStatsRecord(dump_buf, stats_by_threshold.stats_record,
687 sensor_cdev_request_stats_line_prefix);
688 }
689 if (request_stats.stats_by_default_threshold.has_value()) {
690 *dump_buf << " Record by All State" << std::endl;
691 dumpStatsRecord(dump_buf, request_stats.stats_by_default_threshold.value(),
692 sensor_cdev_request_stats_line_prefix);
693 }
694 }
695 }
696 }
697
dumpThermalData(int fd,const char ** args,uint32_t numArgs)698 void Thermal::dumpThermalData(int fd, const char **args, uint32_t numArgs) {
699 std::ostringstream dump_buf;
700
701 if (!thermal_helper_->isInitializedOk()) {
702 dump_buf << "ThermalHAL not initialized properly." << std::endl;
703 } else if (numArgs == 0 || std::string(args[0]) == "-a") {
704 const auto &sensor_status_map = thermal_helper_->GetSensorStatusMap();
705 {
706 dump_buf << "getCachedTemperatures:" << std::endl;
707 boot_clock::time_point now = boot_clock::now();
708 for (const auto &sensor_status_pair : sensor_status_map) {
709 if ((sensor_status_pair.second.thermal_cached.timestamp) ==
710 boot_clock::time_point::min()) {
711 continue;
712 }
713 dump_buf << " Name: " << sensor_status_pair.first
714 << " CachedValue: " << sensor_status_pair.second.thermal_cached.temp
715 << " TimeToCache: "
716 << std::chrono::duration_cast<std::chrono::milliseconds>(
717 now - sensor_status_pair.second.thermal_cached.timestamp)
718 .count()
719 << "ms" << std::endl;
720 }
721 }
722 {
723 dump_buf << "getEmulSettings:" << std::endl;
724 for (const auto &sensor_status_pair : sensor_status_map) {
725 if (sensor_status_pair.second.override_status.emul_temp == nullptr) {
726 continue;
727 }
728 dump_buf << " Name: " << sensor_status_pair.first << " EmulTemp: "
729 << sensor_status_pair.second.override_status.emul_temp->temp
730 << " EmulSeverity: "
731 << sensor_status_pair.second.override_status.emul_temp->severity
732 << " maxThrottling: " << std::boolalpha
733 << sensor_status_pair.second.override_status.max_throttling << std::endl;
734 }
735 }
736 {
737 const auto &map = thermal_helper_->GetSensorInfoMap();
738 dump_buf << "getCurrentTemperatures:" << std::endl;
739 Temperature temp_2_0;
740 for (const auto &name_info_pair : map) {
741 thermal_helper_->readTemperature(name_info_pair.first, &temp_2_0, nullptr, true);
742 dump_buf << " Type: " << toString(temp_2_0.type)
743 << " Name: " << name_info_pair.first << " CurrentValue: " << temp_2_0.value
744 << " ThrottlingStatus: " << toString(temp_2_0.throttlingStatus)
745 << std::endl;
746 }
747 dump_buf << "getTemperatureThresholds:" << std::endl;
748 for (const auto &name_info_pair : map) {
749 if (!name_info_pair.second.is_watch) {
750 continue;
751 }
752 dump_buf << " Type: " << toString(name_info_pair.second.type)
753 << " Name: " << name_info_pair.first;
754 dump_buf << " hotThrottlingThreshold: [";
755 for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
756 dump_buf << name_info_pair.second.hot_thresholds[i] << " ";
757 }
758 dump_buf << "] coldThrottlingThreshold: [";
759 for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
760 dump_buf << name_info_pair.second.cold_thresholds[i] << " ";
761 }
762 dump_buf << "] vrThrottlingThreshold: " << name_info_pair.second.vr_threshold;
763 dump_buf << std::endl;
764 }
765 dump_buf << "getHysteresis:" << std::endl;
766 for (const auto &name_info_pair : map) {
767 if (!name_info_pair.second.is_watch) {
768 continue;
769 }
770 dump_buf << " Name: " << name_info_pair.first;
771 dump_buf << " hotHysteresis: [";
772 for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
773 dump_buf << name_info_pair.second.hot_hysteresis[i] << " ";
774 }
775 dump_buf << "] coldHysteresis: [";
776 for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
777 dump_buf << name_info_pair.second.cold_hysteresis[i] << " ";
778 }
779 dump_buf << "]" << std::endl;
780 }
781 }
782 {
783 dump_buf << "getCurrentCoolingDevices:" << std::endl;
784 std::vector<CoolingDevice> cooling_devices;
785 if (!thermal_helper_->fillCurrentCoolingDevices(false, CoolingType::CPU,
786 &cooling_devices)) {
787 dump_buf << " Failed to getCurrentCoolingDevices." << std::endl;
788 }
789
790 for (const auto &c : cooling_devices) {
791 dump_buf << " Type: " << toString(c.type) << " Name: " << c.name
792 << " CurrentValue: " << c.value << std::endl;
793 }
794 }
795 {
796 dump_buf << "getCallbacks:" << std::endl;
797 dump_buf << " Total: " << callbacks_.size() << std::endl;
798 for (const auto &c : callbacks_) {
799 dump_buf << " IsFilter: " << c.is_filter_type << " Type: " << toString(c.type)
800 << std::endl;
801 }
802 }
803 {
804 dump_buf << "sendCallback:" << std::endl;
805 dump_buf << " Enabled List: ";
806 const auto &map = thermal_helper_->GetSensorInfoMap();
807 for (const auto &name_info_pair : map) {
808 if (name_info_pair.second.send_cb) {
809 dump_buf << name_info_pair.first << " ";
810 }
811 }
812 dump_buf << std::endl;
813 }
814 {
815 dump_buf << "sendPowerHint:" << std::endl;
816 dump_buf << " Enabled List: ";
817 const auto &map = thermal_helper_->GetSensorInfoMap();
818 for (const auto &name_info_pair : map) {
819 if (name_info_pair.second.send_powerhint) {
820 dump_buf << name_info_pair.first << " ";
821 }
822 }
823 dump_buf << std::endl;
824 }
825 dumpVirtualSensorInfo(&dump_buf);
826 dumpVtEstimatorInfo(&dump_buf);
827 dumpThrottlingInfo(&dump_buf);
828 dumpThrottlingRequestStatus(&dump_buf);
829 dumpPowerRailInfo(&dump_buf);
830 dumpThermalStats(&dump_buf);
831 {
832 dump_buf << "getAIDLPowerHalInfo:" << std::endl;
833 dump_buf << " Exist: " << std::boolalpha << thermal_helper_->isAidlPowerHalExist()
834 << std::endl;
835 dump_buf << " Connected: " << std::boolalpha << thermal_helper_->isPowerHalConnected()
836 << std::endl;
837 dump_buf << " Ext connected: " << std::boolalpha
838 << thermal_helper_->isPowerHalExtConnected() << std::endl;
839 }
840 } else if (std::string(args[0]) == "-vt-estimator") {
841 dumpVtEstimatorInfo(&dump_buf);
842 }
843
844 std::string buf = dump_buf.str();
845 if (!::android::base::WriteStringToFd(buf, fd)) {
846 PLOG(ERROR) << "Failed to dump state to fd";
847 }
848 fsync(fd);
849 }
850
dump(int fd,const char ** args,uint32_t numArgs)851 binder_status_t Thermal::dump(int fd, const char **args, uint32_t numArgs) {
852 if (numArgs == 0 || std::string(args[0]) == "-a" || std::string(args[0]) == "-vt-estimator") {
853 dumpThermalData(fd, args, numArgs);
854 return STATUS_OK;
855 }
856
857 if (std::string(args[0]) == "emul_temp" && numArgs >= 3) {
858 return thermal_helper_->emulTemp(
859 std::string(args[1]), std::atof(args[2]),
860 numArgs == 3 ? false : std::string(args[3]) == "max_throttling")
861 ? STATUS_OK
862 : STATUS_BAD_VALUE;
863 } else if (std::string(args[0]) == "emul_severity" && numArgs >= 3) {
864 return thermal_helper_->emulSeverity(
865 std::string(args[1]), std::atof(args[2]),
866 numArgs == 3 ? false : std::string(args[3]) == "max_throttling")
867 ? STATUS_OK
868 : STATUS_BAD_VALUE;
869 } else if (std::string(args[0]) == "emul_clear") {
870 return (numArgs != 2 || !thermal_helper_->emulClear(std::string(args[1])))
871 ? STATUS_BAD_VALUE
872 : STATUS_OK;
873 }
874 return STATUS_BAD_VALUE;
875 }
876
addEvent(const Thermal::Looper::Event & e)877 void Thermal::Looper::addEvent(const Thermal::Looper::Event &e) {
878 std::unique_lock<std::mutex> lock(mutex_);
879 events_.push(e);
880 cv_.notify_all();
881 }
882
~Looper()883 Thermal::Looper::~Looper() {
884 {
885 std::unique_lock<std::mutex> lock(mutex_);
886 aborted_ = true;
887 }
888 cv_.notify_one();
889 thread_.join();
890 }
891
loop()892 void Thermal::Looper::loop() {
893 while (!aborted_) {
894 std::unique_lock<std::mutex> lock(mutex_);
895 cv_.wait(lock, [&] { return aborted_ || !events_.empty(); });
896 if (!aborted_ && !events_.empty()) {
897 Event event = events_.front();
898 events_.pop();
899 lock.unlock();
900 event.handler();
901 }
902 }
903 }
904
905 } // namespace implementation
906 } // namespace thermal
907 } // namespace hardware
908 } // namespace android
909 } // namespace aidl
910