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 bool send_powerhint = false;
221 if (sensors[i]["SendPowerHint"].empty() || !sensors[i]["SendPowerHint"].isBool()) {
222 LOG(INFO) << "Failed to read Sensor[" << name << "]'s SendPowerHint, set to 'false'";
223 } else {
224 send_powerhint = sensors[i]["SendPowerHint"].asBool();
225 }
226 LOG(INFO) << "Sensor[" << name << "]'s SendPowerHint: " << std::boolalpha << send_powerhint
227 << std::noboolalpha;
228
229 sensors_parsed[name] = {
230 .type = sensor_type,
231 .hot_thresholds = hot_thresholds,
232 .cold_thresholds = cold_thresholds,
233 .hot_hysteresis = hot_hysteresis,
234 .cold_hysteresis = cold_hysteresis,
235 .vr_threshold = vr_threshold,
236 .multiplier = multiplier,
237 .is_monitor = is_monitor,
238 .send_powerhint = send_powerhint,
239 };
240 ++total_parsed;
241 }
242
243 LOG(INFO) << total_parsed << " Sensors parsed successfully";
244 return sensors_parsed;
245 }
246
ParseCoolingDevice(std::string_view config_path)247 std::map<std::string, CoolingType> ParseCoolingDevice(std::string_view config_path) {
248 std::string json_doc;
249 std::map<std::string, CoolingType> cooling_devices_parsed;
250 if (!android::base::ReadFileToString(config_path.data(), &json_doc)) {
251 LOG(ERROR) << "Failed to read JSON config from " << config_path;
252 return cooling_devices_parsed;
253 }
254
255 Json::Value root;
256 Json::Reader reader;
257
258 if (!reader.parse(json_doc, root)) {
259 LOG(ERROR) << "Failed to parse JSON config";
260 return cooling_devices_parsed;
261 }
262
263 Json::Value cooling_devices = root["CoolingDevices"];
264 std::size_t total_parsed = 0;
265 std::set<std::string> cooling_devices_name_parsed;
266
267 for (Json::Value::ArrayIndex i = 0; i < cooling_devices.size(); ++i) {
268 const std::string &name = cooling_devices[i]["Name"].asString();
269 LOG(INFO) << "CoolingDevice[" << i << "]'s Name: " << name;
270 if (name.empty()) {
271 LOG(ERROR) << "Failed to read "
272 << "CoolingDevice[" << i << "]'s Name";
273 cooling_devices_parsed.clear();
274 return cooling_devices_parsed;
275 }
276
277 auto result = cooling_devices_name_parsed.insert(name.data());
278 if (!result.second) {
279 LOG(ERROR) << "Duplicate CoolingDevice[" << i << "]'s Name";
280 cooling_devices_parsed.clear();
281 return cooling_devices_parsed;
282 }
283
284 std::string cooling_device_type_str = cooling_devices[i]["Type"].asString();
285 LOG(INFO) << "CoolingDevice[" << name << "]'s Type: " << cooling_device_type_str;
286 CoolingType cooling_device_type;
287
288 if (!getTypeFromString(cooling_device_type_str, &cooling_device_type)) {
289 LOG(ERROR) << "Invalid "
290 << "CoolingDevice[" << name << "]'s Type: " << cooling_device_type_str;
291 cooling_devices_parsed.clear();
292 return cooling_devices_parsed;
293 }
294
295 cooling_devices_parsed[name] = cooling_device_type;
296
297 ++total_parsed;
298 }
299
300 LOG(INFO) << total_parsed << " CoolingDevices parsed successfully";
301 return cooling_devices_parsed;
302 }
303
304 } // namespace implementation
305 } // namespace V2_0
306 } // namespace thermal
307 } // namespace hardware
308 } // namespace android
309