| /* |
| * Copyright (C) 2017 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include <cerrno> |
| #include <vector> |
| |
| #include <android-base/file.h> |
| #include <android-base/logging.h> |
| |
| #include "Thermal.h" |
| #include "thermal-helper.h" |
| |
| namespace android { |
| namespace hardware { |
| namespace thermal { |
| namespace V1_1 { |
| namespace implementation { |
| |
| Thermal::Thermal() : enabled(initThermal()) {} |
| |
| namespace { |
| |
| // Saves the IThermalCallback client object registered from the |
| // framework for sending thermal events to the framework thermal event bus. |
| sp<IThermalCallback> gThermalCallback; |
| |
| struct ThermalDeathRecipient : hidl_death_recipient { |
| virtual void serviceDied( |
| uint64_t cookie __unused, const wp<IBase>& who __unused) { |
| gThermalCallback = nullptr; |
| LOG(ERROR) << "IThermalCallback HIDL service died"; |
| } |
| }; |
| |
| sp<ThermalDeathRecipient> gThermalCallbackDied = nullptr; |
| |
| } // anonymous namespace |
| |
| // Methods from ::android::hardware::thermal::V1_0::IThermal follow. |
| Return<void> Thermal::getTemperatures(getTemperatures_cb _hidl_cb) { |
| ThermalStatus status; |
| status.code = ThermalStatusCode::SUCCESS; |
| hidl_vec<Temperature> temperatures; |
| temperatures.resize(kTemperatureNum); |
| |
| if (!enabled) { |
| status.code = ThermalStatusCode::FAILURE; |
| status.debugMessage = "Unsupported hardware"; |
| _hidl_cb(status, temperatures); |
| LOG(ERROR) << "ThermalHAL not initialized properly."; |
| return Void(); |
| } |
| |
| if (fillTemperatures(&temperatures) != kTemperatureNum) { |
| status.code = ThermalStatusCode::FAILURE; |
| status.debugMessage = "Error reading thermal sensors."; |
| } |
| _hidl_cb(status, temperatures); |
| |
| for (auto& t : temperatures) { |
| LOG(DEBUG) << "getTemperatures " |
| << " Type: " << static_cast<int>(t.type) |
| << " Name: " << t.name |
| << " CurrentValue: " << t.currentValue |
| << " ThrottlingThreshold: " << t.throttlingThreshold |
| << " ShutdownThreshold: " << t.shutdownThreshold |
| << " VrThrottlingThreshold: " << t.vrThrottlingThreshold; |
| } |
| |
| return Void(); |
| } |
| |
| Return<void> Thermal::getCpuUsages(getCpuUsages_cb _hidl_cb) { |
| ThermalStatus status; |
| status.code = ThermalStatusCode::SUCCESS; |
| hidl_vec<CpuUsage> cpuUsages; |
| cpuUsages.resize(kCpuNum); |
| |
| if (!enabled) { |
| status.code = ThermalStatusCode::FAILURE; |
| status.debugMessage = "Unsupported hardware"; |
| _hidl_cb(status, cpuUsages); |
| LOG(ERROR) << "ThermalHAL not initialized properly."; |
| return Void(); |
| } |
| |
| ssize_t ret = fillCpuUsages(&cpuUsages); |
| if (ret < 0) { |
| status.code = ThermalStatusCode::FAILURE; |
| status.debugMessage = strerror(-ret); |
| } |
| |
| for (auto& u : cpuUsages) { |
| LOG(DEBUG) << "getCpuUsages " |
| << " Name: " << u.name |
| << " Active: " << u.active |
| << " Total: " << u.total |
| << " IsOnline: " << u.isOnline; |
| } |
| |
| _hidl_cb(status, cpuUsages); |
| return Void(); |
| } |
| |
| Return<void> Thermal::getCoolingDevices(getCoolingDevices_cb _hidl_cb) { |
| ThermalStatus status; |
| status.code = ThermalStatusCode::SUCCESS; |
| hidl_vec<CoolingDevice> coolingDevices; |
| |
| if (!enabled) { |
| status.code = ThermalStatusCode::FAILURE; |
| status.debugMessage = "Unsupported hardware"; |
| _hidl_cb(status, coolingDevices); |
| LOG(ERROR) << "ThermalHAL not initialized properly."; |
| return Void(); |
| } |
| |
| LOG(DEBUG) << "No Cooling Device"; |
| _hidl_cb(status, coolingDevices); |
| return Void(); |
| } |
| |
| // Methods from ::android::hardware::thermal::V1_1::IThermal follow. |
| |
| Return<void> Thermal::registerThermalCallback( |
| const sp<IThermalCallback>& callback) { |
| gThermalCallback = callback; |
| |
| if (gThermalCallback != nullptr) { |
| if (gThermalCallbackDied == nullptr) |
| gThermalCallbackDied = new ThermalDeathRecipient(); |
| |
| if (gThermalCallbackDied != nullptr) |
| gThermalCallback->linkToDeath( |
| gThermalCallbackDied, 0x451F /* cookie, unused */); |
| LOG(INFO) << "ThermalCallback registered"; |
| } else { |
| LOG(INFO) << "ThermalCallback unregistered"; |
| } |
| return Void(); |
| } |
| |
| // Local functions used internally by thermal-engine follow. |
| |
| std::string Thermal::getSkinSensorType() { |
| return getTargetSkinSensorType(); |
| } |
| |
| void Thermal::notifyThrottling( |
| bool isThrottling, const Temperature& temperature) { |
| if (gThermalCallback != nullptr) { |
| Return<void> ret = |
| gThermalCallback->notifyThrottling(isThrottling, temperature); |
| if (!ret.isOk()) { |
| if (ret.isDeadObject()) { |
| gThermalCallback = nullptr; |
| LOG(WARNING) << "Dropped throttling event, ThermalCallback died"; |
| } else { |
| LOG(WARNING) << |
| "Failed to send throttling event to ThermalCallback"; |
| } |
| } |
| } else { |
| LOG(WARNING) << |
| "Dropped throttling event, no ThermalCallback registered"; |
| } |
| } |
| |
| Return<void> Thermal::debug(const hidl_handle& handle, const hidl_vec<hidl_string>&) { |
| if (handle != nullptr && handle->numFds >= 1) { |
| int fd = handle->data[0]; |
| std::ostringstream dump_buf; |
| |
| if (!enabled) { |
| dump_buf << "ThermalHAL not initialized properly." << std::endl; |
| } else { |
| hidl_vec<Temperature> temperatures; |
| hidl_vec<CpuUsage> cpu_usages; |
| cpu_usages.resize(kCpuNum); |
| temperatures.resize(kTemperatureNum); |
| |
| dump_buf << "getTemperatures:" << std::endl; |
| if (fillTemperatures(&temperatures) != kTemperatureNum) { |
| dump_buf << "Failed to read thermal sensors." << std::endl; |
| } else { |
| for (const auto& t : temperatures) { |
| dump_buf << "Name: " << t.name |
| << " Type: " << android::hardware::thermal::V1_0::toString(t.type) |
| << " CurrentValue: " << t.currentValue |
| << " ThrottlingThreshold: " << t.throttlingThreshold |
| << " ShutdownThreshold: " << t.shutdownThreshold |
| << " VrThrottlingThreshold: " << t.vrThrottlingThreshold |
| << std::endl; |
| } |
| } |
| |
| dump_buf << "getCpuUsages:" << std::endl; |
| ssize_t ret = fillCpuUsages(&cpu_usages); |
| if (ret < 0) { |
| dump_buf << "Failed to get CPU usages." << std::endl; |
| } else { |
| for (const auto& usage : cpu_usages) { |
| dump_buf << "Name: " << usage.name |
| << " Active: " << usage.active |
| << " Total: " << usage.total |
| << " IsOnline: " << usage.isOnline |
| << std::endl; |
| } |
| } |
| |
| } |
| std::string buf = dump_buf.str(); |
| if (!android::base::WriteStringToFd(buf, fd)) { |
| PLOG(ERROR) << "Failed to dump state to fd"; |
| } |
| fsync(fd); |
| } |
| return Void(); |
| } |
| |
| } // namespace implementation |
| } // namespace V1_1 |
| } // namespace thermal |
| } // namespace hardware |
| } // namespace android |