1 /*
2  * Copyright (C) 2018 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 #include <android-base/file.h>
17 #include <android-base/logging.h>
18 #include <android-base/strings.h>
19 #include <cmath>
20 #include <set>
21 
22 #include <json/reader.h>
23 #include <json/value.h>
24 
25 #include "config_parser.h"
26 
27 namespace android {
28 namespace hardware {
29 namespace thermal {
30 namespace V2_0 {
31 namespace implementation {
32 
33 using ::android::hardware::hidl_enum_range;
34 using ::android::hardware::thermal::V2_0::toString;
35 using TemperatureType_2_0 = ::android::hardware::thermal::V2_0::TemperatureType;
36 
37 namespace {
38 
39 template <typename T>
40 // Return false when failed parsing
getTypeFromString(std::string_view str,T * out)41 bool getTypeFromString(std::string_view str, T *out) {
42     auto types = hidl_enum_range<T>();
43     for (const auto &type : types) {
44         if (toString(type) == str) {
45             *out = type;
46             return true;
47         }
48     }
49     return false;
50 }
51 
getFloatFromValue(const Json::Value & value)52 float getFloatFromValue(const Json::Value &value) {
53     if (value.isString()) {
54         return std::stof(value.asString());
55     } else {
56         return value.asFloat();
57     }
58 }
59 
60 }  // namespace
61 
ParseSensorInfo(std::string_view config_path)62 std::map<std::string, SensorInfo> ParseSensorInfo(std::string_view config_path) {
63     std::string json_doc;
64     std::map<std::string, SensorInfo> sensors_parsed;
65     if (!android::base::ReadFileToString(config_path.data(), &json_doc)) {
66         LOG(ERROR) << "Failed to read JSON config from " << config_path;
67         return sensors_parsed;
68     }
69 
70     Json::Value root;
71     Json::Reader reader;
72 
73     if (!reader.parse(json_doc, root)) {
74         LOG(ERROR) << "Failed to parse JSON config";
75         return sensors_parsed;
76     }
77 
78     Json::Value sensors = root["Sensors"];
79     std::size_t total_parsed = 0;
80     std::set<std::string> sensors_name_parsed;
81 
82     for (Json::Value::ArrayIndex i = 0; i < sensors.size(); ++i) {
83         const std::string &name = sensors[i]["Name"].asString();
84         LOG(INFO) << "Sensor[" << i << "]'s Name: " << name;
85         if (name.empty()) {
86             LOG(ERROR) << "Failed to read "
87                        << "Sensor[" << i << "]'s Name";
88             sensors_parsed.clear();
89             return sensors_parsed;
90         }
91 
92         auto result = sensors_name_parsed.insert(name);
93         if (!result.second) {
94             LOG(ERROR) << "Duplicate Sensor[" << i << "]'s Name";
95             sensors_parsed.clear();
96             return sensors_parsed;
97         }
98 
99         std::string sensor_type_str = sensors[i]["Type"].asString();
100         LOG(INFO) << "Sensor[" << name << "]'s Type: " << sensor_type_str;
101         TemperatureType_2_0 sensor_type;
102 
103         if (!getTypeFromString(sensor_type_str, &sensor_type)) {
104             LOG(ERROR) << "Invalid "
105                        << "Sensor[" << name << "]'s Type: " << sensor_type_str;
106             sensors_parsed.clear();
107             return sensors_parsed;
108         }
109 
110         std::array<float, kThrottlingSeverityCount> hot_thresholds;
111         hot_thresholds.fill(NAN);
112         std::array<float, kThrottlingSeverityCount> cold_thresholds;
113         cold_thresholds.fill(NAN);
114         std::array<float, kThrottlingSeverityCount> hot_hysteresis;
115         hot_hysteresis.fill(0.0);
116         std::array<float, kThrottlingSeverityCount> cold_hysteresis;
117         cold_hysteresis.fill(0.0);
118 
119         Json::Value values = sensors[i]["HotThreshold"];
120         if (values.size() != kThrottlingSeverityCount) {
121             LOG(ERROR) << "Invalid "
122                        << "Sensor[" << name << "]'s HotThreshold count" << values.size();
123             sensors_parsed.clear();
124             return sensors_parsed;
125         } else {
126             float min = std::numeric_limits<float>::min();
127             for (Json::Value::ArrayIndex j = 0; j < kThrottlingSeverityCount; ++j) {
128                 hot_thresholds[j] = getFloatFromValue(values[j]);
129                 if (!std::isnan(hot_thresholds[j])) {
130                     if (hot_thresholds[j] < min) {
131                         LOG(ERROR) << "Invalid "
132                                    << "Sensor[" << name << "]'s HotThreshold[j" << j
133                                    << "]: " << hot_thresholds[j] << " < " << min;
134                         sensors_parsed.clear();
135                         return sensors_parsed;
136                     }
137                     min = hot_thresholds[j];
138                 }
139                 LOG(INFO) << "Sensor[" << name << "]'s HotThreshold[" << j
140                           << "]: " << hot_thresholds[j];
141             }
142         }
143 
144         values = sensors[i]["HotHysteresis"];
145         if (values.size() != kThrottlingSeverityCount) {
146             LOG(INFO) << "Cannot find valid "
147                       << "Sensor[" << name << "]'s HotHysteresis, default all to 0.0";
148         } else {
149             for (Json::Value::ArrayIndex j = 0; j < kThrottlingSeverityCount; ++j) {
150                 hot_hysteresis[j] = getFloatFromValue(values[j]);
151                 if (std::isnan(hot_hysteresis[j])) {
152                     LOG(ERROR) << "Invalid "
153                                << "Sensor[" << name << "]'s HotHysteresis: " << hot_hysteresis[j];
154                     sensors_parsed.clear();
155                     return sensors_parsed;
156                 }
157                 LOG(INFO) << "Sensor[" << name << "]'s HotHysteresis[" << j
158                           << "]: " << hot_hysteresis[j];
159             }
160         }
161 
162         values = sensors[i]["ColdThreshold"];
163         if (values.size() != kThrottlingSeverityCount) {
164             LOG(INFO) << "Cannot find valid "
165                       << "Sensor[" << name << "]'s ColdThreshold, default all to NAN";
166         } else {
167             float max = std::numeric_limits<float>::max();
168             for (Json::Value::ArrayIndex j = 0; j < kThrottlingSeverityCount; ++j) {
169                 cold_thresholds[j] = getFloatFromValue(values[j]);
170                 if (!std::isnan(cold_thresholds[j])) {
171                     if (cold_thresholds[j] > max) {
172                         LOG(ERROR) << "Invalid "
173                                    << "Sensor[" << name << "]'s ColdThreshold[j" << j
174                                    << "]: " << cold_thresholds[j] << " > " << max;
175                         sensors_parsed.clear();
176                         return sensors_parsed;
177                     }
178                     max = cold_thresholds[j];
179                 }
180                 LOG(INFO) << "Sensor[" << name << "]'s ColdThreshold[" << j
181                           << "]: " << cold_thresholds[j];
182             }
183         }
184 
185         values = sensors[i]["ColdHysteresis"];
186         if (values.size() != kThrottlingSeverityCount) {
187             LOG(INFO) << "Cannot find valid "
188                       << "Sensor[" << name << "]'s ColdHysteresis, default all to 0.0";
189         } else {
190             for (Json::Value::ArrayIndex j = 0; j < kThrottlingSeverityCount; ++j) {
191                 cold_hysteresis[j] = getFloatFromValue(values[j]);
192                 if (std::isnan(cold_hysteresis[j])) {
193                     LOG(ERROR) << "Invalid "
194                                << "Sensor[" << name
195                                << "]'s ColdHysteresis: " << cold_hysteresis[j];
196                     sensors_parsed.clear();
197                     return sensors_parsed;
198                 }
199                 LOG(INFO) << "Sensor[" << name << "]'s ColdHysteresis[" << j
200                           << "]: " << cold_hysteresis[j];
201             }
202         }
203 
204         float vr_threshold = NAN;
205         vr_threshold = getFloatFromValue(sensors[i]["VrThreshold"]);
206         LOG(INFO) << "Sensor[" << name << "]'s VrThreshold: " << vr_threshold;
207 
208         float multiplier = sensors[i]["Multiplier"].asFloat();
209         LOG(INFO) << "Sensor[" << name << "]'s Multiplier: " << multiplier;
210 
211         bool is_monitor = false;
212         if (sensors[i]["Monitor"].empty() || !sensors[i]["Monitor"].isBool()) {
213             LOG(INFO) << "Failed to read Sensor[" << name << "]'s Monitor, set to 'false'";
214         } else {
215             is_monitor = sensors[i]["Monitor"].asBool();
216         }
217         LOG(INFO) << "Sensor[" << name << "]'s Monitor: " << std::boolalpha << is_monitor
218                   << std::noboolalpha;
219 
220         sensors_parsed[name] = {
221                 .type = sensor_type,
222                 .hot_thresholds = hot_thresholds,
223                 .cold_thresholds = cold_thresholds,
224                 .hot_hysteresis = hot_hysteresis,
225                 .cold_hysteresis = cold_hysteresis,
226                 .vr_threshold = vr_threshold,
227                 .multiplier = multiplier,
228                 .is_monitor = is_monitor,
229         };
230         ++total_parsed;
231     }
232 
233     LOG(INFO) << total_parsed << " Sensors parsed successfully";
234     return sensors_parsed;
235 }
236 
ParseCoolingDevice(std::string_view config_path)237 std::map<std::string, CoolingType> ParseCoolingDevice(std::string_view config_path) {
238     std::string json_doc;
239     std::map<std::string, CoolingType> cooling_devices_parsed;
240     if (!android::base::ReadFileToString(config_path.data(), &json_doc)) {
241         LOG(ERROR) << "Failed to read JSON config from " << config_path;
242         return cooling_devices_parsed;
243     }
244 
245     Json::Value root;
246     Json::Reader reader;
247 
248     if (!reader.parse(json_doc, root)) {
249         LOG(ERROR) << "Failed to parse JSON config";
250         return cooling_devices_parsed;
251     }
252 
253     Json::Value cooling_devices = root["CoolingDevices"];
254     std::size_t total_parsed = 0;
255     std::set<std::string> cooling_devices_name_parsed;
256 
257     for (Json::Value::ArrayIndex i = 0; i < cooling_devices.size(); ++i) {
258         const std::string &name = cooling_devices[i]["Name"].asString();
259         LOG(INFO) << "CoolingDevice[" << i << "]'s Name: " << name;
260         if (name.empty()) {
261             LOG(ERROR) << "Failed to read "
262                        << "CoolingDevice[" << i << "]'s Name";
263             cooling_devices_parsed.clear();
264             return cooling_devices_parsed;
265         }
266 
267         auto result = cooling_devices_name_parsed.insert(name.data());
268         if (!result.second) {
269             LOG(ERROR) << "Duplicate CoolingDevice[" << i << "]'s Name";
270             cooling_devices_parsed.clear();
271             return cooling_devices_parsed;
272         }
273 
274         std::string cooling_device_type_str = cooling_devices[i]["Type"].asString();
275         LOG(INFO) << "CoolingDevice[" << name << "]'s Type: " << cooling_device_type_str;
276         CoolingType cooling_device_type;
277 
278         if (!getTypeFromString(cooling_device_type_str, &cooling_device_type)) {
279             LOG(ERROR) << "Invalid "
280                        << "CoolingDevice[" << name << "]'s Type: " << cooling_device_type_str;
281             cooling_devices_parsed.clear();
282             return cooling_devices_parsed;
283         }
284 
285         cooling_devices_parsed[name] = cooling_device_type;
286 
287         ++total_parsed;
288     }
289 
290     LOG(INFO) << total_parsed << " CoolingDevices parsed successfully";
291     return cooling_devices_parsed;
292 }
293 
294 }  // namespace implementation
295 }  // namespace V2_0
296 }  // namespace thermal
297 }  // namespace hardware
298 }  // namespace android
299