• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
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