/* * 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 #include #include #include #include #include #include #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 // Return false when failed parsing bool getTypeFromString(std::string_view str, T *out) { auto types = hidl_enum_range(); 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 ParseSensorInfo(std::string_view config_path) { std::string json_doc; std::map 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::Reader reader; if (!reader.parse(json_doc, root)) { LOG(ERROR) << "Failed to parse JSON config"; return sensors_parsed; } Json::Value sensors = root["Sensors"]; std::size_t total_parsed = 0; std::set 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 hot_thresholds; hot_thresholds.fill(NAN); std::array cold_thresholds; cold_thresholds.fill(NAN); std::array hot_hysteresis; hot_hysteresis.fill(0.0); std::array 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::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::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 ParseCoolingDevice(std::string_view config_path) { std::string json_doc; std::map 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::Reader reader; if (!reader.parse(json_doc, root)) { 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 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