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