| /* |
| * Copyright (C) 2018 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 <android-base/file.h> |
| #include <android-base/logging.h> |
| #include <android-base/strings.h> |
| #include <cmath> |
| #include <set> |
| |
| #include <json/reader.h> |
| #include <json/value.h> |
| |
| #include "config_parser.h" |
| |
| namespace android { |
| namespace hardware { |
| namespace thermal { |
| namespace V2_0 { |
| namespace implementation { |
| |
| using ::android::hardware::hidl_enum_range; |
| using ::android::hardware::thermal::V2_0::toString; |
| using TemperatureType_2_0 = ::android::hardware::thermal::V2_0::TemperatureType; |
| |
| namespace { |
| |
| template <typename T> |
| // Return false when failed parsing |
| bool getTypeFromString(std::string_view str, T *out) { |
| auto types = hidl_enum_range<T>(); |
| for (const auto &type : types) { |
| if (toString(type) == str) { |
| *out = type; |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| float getFloatFromValue(const Json::Value &value) { |
| if (value.isString()) { |
| return std::stof(value.asString()); |
| } else { |
| return value.asFloat(); |
| } |
| } |
| |
| } // namespace |
| |
| std::map<std::string, SensorInfo> ParseSensorInfo(std::string_view config_path) { |
| std::string json_doc; |
| std::map<std::string, SensorInfo> sensors_parsed; |
| if (!android::base::ReadFileToString(config_path.data(), &json_doc)) { |
| LOG(ERROR) << "Failed to read JSON config from " << config_path; |
| return sensors_parsed; |
| } |
| |
| Json::Value root; |
| Json::CharReaderBuilder builder; |
| std::unique_ptr<Json::CharReader> reader(builder.newCharReader()); |
| std::string errorMessage; |
| |
| if (!reader->parse(&*json_doc.begin(), &*json_doc.end(), &root, &errorMessage)) { |
| LOG(ERROR) << "Failed to parse JSON config"; |
| return sensors_parsed; |
| } |
| |
| Json::Value sensors = root["Sensors"]; |
| std::size_t total_parsed = 0; |
| std::set<std::string> sensors_name_parsed; |
| |
| for (Json::Value::ArrayIndex i = 0; i < sensors.size(); ++i) { |
| const std::string &name = sensors[i]["Name"].asString(); |
| LOG(INFO) << "Sensor[" << i << "]'s Name: " << name; |
| if (name.empty()) { |
| LOG(ERROR) << "Failed to read " |
| << "Sensor[" << i << "]'s Name"; |
| sensors_parsed.clear(); |
| return sensors_parsed; |
| } |
| |
| auto result = sensors_name_parsed.insert(name); |
| if (!result.second) { |
| LOG(ERROR) << "Duplicate Sensor[" << i << "]'s Name"; |
| sensors_parsed.clear(); |
| return sensors_parsed; |
| } |
| |
| std::string sensor_type_str = sensors[i]["Type"].asString(); |
| LOG(INFO) << "Sensor[" << name << "]'s Type: " << sensor_type_str; |
| TemperatureType_2_0 sensor_type; |
| |
| if (!getTypeFromString(sensor_type_str, &sensor_type)) { |
| LOG(ERROR) << "Invalid " |
| << "Sensor[" << name << "]'s Type: " << sensor_type_str; |
| sensors_parsed.clear(); |
| return sensors_parsed; |
| } |
| |
| std::array<float, kThrottlingSeverityCount> hot_thresholds; |
| hot_thresholds.fill(NAN); |
| std::array<float, kThrottlingSeverityCount> cold_thresholds; |
| cold_thresholds.fill(NAN); |
| std::array<float, kThrottlingSeverityCount> hot_hysteresis; |
| hot_hysteresis.fill(0.0); |
| std::array<float, kThrottlingSeverityCount> cold_hysteresis; |
| cold_hysteresis.fill(0.0); |
| |
| Json::Value values = sensors[i]["HotThreshold"]; |
| if (values.size() != kThrottlingSeverityCount) { |
| LOG(ERROR) << "Invalid " |
| << "Sensor[" << name << "]'s HotThreshold count" << values.size(); |
| sensors_parsed.clear(); |
| return sensors_parsed; |
| } else { |
| float min = std::numeric_limits<float>::min(); |
| for (Json::Value::ArrayIndex j = 0; j < kThrottlingSeverityCount; ++j) { |
| hot_thresholds[j] = getFloatFromValue(values[j]); |
| if (!std::isnan(hot_thresholds[j])) { |
| if (hot_thresholds[j] < min) { |
| LOG(ERROR) << "Invalid " |
| << "Sensor[" << name << "]'s HotThreshold[j" << j |
| << "]: " << hot_thresholds[j] << " < " << min; |
| sensors_parsed.clear(); |
| return sensors_parsed; |
| } |
| min = hot_thresholds[j]; |
| } |
| LOG(INFO) << "Sensor[" << name << "]'s HotThreshold[" << j |
| << "]: " << hot_thresholds[j]; |
| } |
| } |
| |
| values = sensors[i]["HotHysteresis"]; |
| if (values.size() != kThrottlingSeverityCount) { |
| LOG(INFO) << "Cannot find valid " |
| << "Sensor[" << name << "]'s HotHysteresis, default all to 0.0"; |
| } else { |
| for (Json::Value::ArrayIndex j = 0; j < kThrottlingSeverityCount; ++j) { |
| hot_hysteresis[j] = getFloatFromValue(values[j]); |
| if (std::isnan(hot_hysteresis[j])) { |
| LOG(ERROR) << "Invalid " |
| << "Sensor[" << name << "]'s HotHysteresis: " << hot_hysteresis[j]; |
| sensors_parsed.clear(); |
| return sensors_parsed; |
| } |
| LOG(INFO) << "Sensor[" << name << "]'s HotHysteresis[" << j |
| << "]: " << hot_hysteresis[j]; |
| } |
| } |
| |
| values = sensors[i]["ColdThreshold"]; |
| if (values.size() != kThrottlingSeverityCount) { |
| LOG(INFO) << "Cannot find valid " |
| << "Sensor[" << name << "]'s ColdThreshold, default all to NAN"; |
| } else { |
| float max = std::numeric_limits<float>::max(); |
| for (Json::Value::ArrayIndex j = 0; j < kThrottlingSeverityCount; ++j) { |
| cold_thresholds[j] = getFloatFromValue(values[j]); |
| if (!std::isnan(cold_thresholds[j])) { |
| if (cold_thresholds[j] > max) { |
| LOG(ERROR) << "Invalid " |
| << "Sensor[" << name << "]'s ColdThreshold[j" << j |
| << "]: " << cold_thresholds[j] << " > " << max; |
| sensors_parsed.clear(); |
| return sensors_parsed; |
| } |
| max = cold_thresholds[j]; |
| } |
| LOG(INFO) << "Sensor[" << name << "]'s ColdThreshold[" << j |
| << "]: " << cold_thresholds[j]; |
| } |
| } |
| |
| values = sensors[i]["ColdHysteresis"]; |
| if (values.size() != kThrottlingSeverityCount) { |
| LOG(INFO) << "Cannot find valid " |
| << "Sensor[" << name << "]'s ColdHysteresis, default all to 0.0"; |
| } else { |
| for (Json::Value::ArrayIndex j = 0; j < kThrottlingSeverityCount; ++j) { |
| cold_hysteresis[j] = getFloatFromValue(values[j]); |
| if (std::isnan(cold_hysteresis[j])) { |
| LOG(ERROR) << "Invalid " |
| << "Sensor[" << name |
| << "]'s ColdHysteresis: " << cold_hysteresis[j]; |
| sensors_parsed.clear(); |
| return sensors_parsed; |
| } |
| LOG(INFO) << "Sensor[" << name << "]'s ColdHysteresis[" << j |
| << "]: " << cold_hysteresis[j]; |
| } |
| } |
| |
| float vr_threshold = NAN; |
| vr_threshold = getFloatFromValue(sensors[i]["VrThreshold"]); |
| LOG(INFO) << "Sensor[" << name << "]'s VrThreshold: " << vr_threshold; |
| |
| float multiplier = sensors[i]["Multiplier"].asFloat(); |
| LOG(INFO) << "Sensor[" << name << "]'s Multiplier: " << multiplier; |
| |
| bool is_monitor = false; |
| if (sensors[i]["Monitor"].empty() || !sensors[i]["Monitor"].isBool()) { |
| LOG(INFO) << "Failed to read Sensor[" << name << "]'s Monitor, set to 'false'"; |
| } else { |
| is_monitor = sensors[i]["Monitor"].asBool(); |
| } |
| LOG(INFO) << "Sensor[" << name << "]'s Monitor: " << std::boolalpha << is_monitor |
| << std::noboolalpha; |
| |
| sensors_parsed[name] = { |
| .type = sensor_type, |
| .hot_thresholds = hot_thresholds, |
| .cold_thresholds = cold_thresholds, |
| .hot_hysteresis = hot_hysteresis, |
| .cold_hysteresis = cold_hysteresis, |
| .vr_threshold = vr_threshold, |
| .multiplier = multiplier, |
| .is_monitor = is_monitor, |
| }; |
| ++total_parsed; |
| } |
| |
| LOG(INFO) << total_parsed << " Sensors parsed successfully"; |
| return sensors_parsed; |
| } |
| |
| std::map<std::string, CoolingType> ParseCoolingDevice(std::string_view config_path) { |
| std::string json_doc; |
| std::map<std::string, CoolingType> cooling_devices_parsed; |
| if (!android::base::ReadFileToString(config_path.data(), &json_doc)) { |
| LOG(ERROR) << "Failed to read JSON config from " << config_path; |
| return cooling_devices_parsed; |
| } |
| |
| Json::Value root; |
| Json::CharReaderBuilder builder; |
| std::unique_ptr<Json::CharReader> reader(builder.newCharReader()); |
| std::string errorMessage; |
| |
| if (!reader->parse(&*json_doc.begin(), &*json_doc.end(), &root, &errorMessage)) { |
| LOG(ERROR) << "Failed to parse JSON config"; |
| return cooling_devices_parsed; |
| } |
| |
| Json::Value cooling_devices = root["CoolingDevices"]; |
| std::size_t total_parsed = 0; |
| std::set<std::string> cooling_devices_name_parsed; |
| |
| for (Json::Value::ArrayIndex i = 0; i < cooling_devices.size(); ++i) { |
| const std::string &name = cooling_devices[i]["Name"].asString(); |
| LOG(INFO) << "CoolingDevice[" << i << "]'s Name: " << name; |
| if (name.empty()) { |
| LOG(ERROR) << "Failed to read " |
| << "CoolingDevice[" << i << "]'s Name"; |
| cooling_devices_parsed.clear(); |
| return cooling_devices_parsed; |
| } |
| |
| auto result = cooling_devices_name_parsed.insert(name.data()); |
| if (!result.second) { |
| LOG(ERROR) << "Duplicate CoolingDevice[" << i << "]'s Name"; |
| cooling_devices_parsed.clear(); |
| return cooling_devices_parsed; |
| } |
| |
| std::string cooling_device_type_str = cooling_devices[i]["Type"].asString(); |
| LOG(INFO) << "CoolingDevice[" << name << "]'s Type: " << cooling_device_type_str; |
| CoolingType cooling_device_type; |
| |
| if (!getTypeFromString(cooling_device_type_str, &cooling_device_type)) { |
| LOG(ERROR) << "Invalid " |
| << "CoolingDevice[" << name << "]'s Type: " << cooling_device_type_str; |
| cooling_devices_parsed.clear(); |
| return cooling_devices_parsed; |
| } |
| |
| cooling_devices_parsed[name] = cooling_device_type; |
| |
| ++total_parsed; |
| } |
| |
| LOG(INFO) << total_parsed << " CoolingDevices parsed successfully"; |
| return cooling_devices_parsed; |
| } |
| |
| } // namespace implementation |
| } // namespace V2_0 |
| } // namespace thermal |
| } // namespace hardware |
| } // namespace android |