1 /* 2 * Copyright (C) 2017 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 specic language governing permissions and 14 * limitations under the License. 15 */ 16 17 #define LOG_TAG "libperfmgr" 18 19 #include <set> 20 21 #include <android-base/file.h> 22 #include <android-base/logging.h> 23 24 #include <json/reader.h> 25 #include <json/value.h> 26 27 #include "perfmgr/HintManager.h" 28 29 namespace android { 30 namespace perfmgr { 31 32 bool HintManager::ValidateHint(const std::string& hint_type) const { 33 if (nm_.get() == nullptr) { 34 LOG(ERROR) << "NodeLooperThread not present"; 35 return false; 36 } 37 if (actions_.find(hint_type) == actions_.end()) { 38 LOG(ERROR) << "PowerHint type not present in actions: " << hint_type; 39 return false; 40 } 41 return true; 42 } 43 44 bool HintManager::DoHint(const std::string& hint_type) { 45 LOG(VERBOSE) << "Do Powerhint: " << hint_type; 46 return ValidateHint(hint_type) 47 ? nm_->Request(actions_.at(hint_type), hint_type) 48 : false; 49 } 50 51 bool HintManager::DoHint(const std::string& hint_type, 52 std::chrono::milliseconds timeout_ms_override) { 53 LOG(VERBOSE) << "Do Powerhint: " << hint_type << " for " 54 << timeout_ms_override.count() << "ms"; 55 if (!ValidateHint(hint_type)) { 56 return false; 57 } 58 std::vector<NodeAction> actions_override = actions_.at(hint_type); 59 for (auto& action : actions_override) { 60 action.timeout_ms = timeout_ms_override; 61 } 62 return nm_->Request(actions_override, hint_type); 63 } 64 65 bool HintManager::EndHint(const std::string& hint_type) { 66 LOG(VERBOSE) << "End Powerhint: " << hint_type; 67 return ValidateHint(hint_type) 68 ? nm_->Cancel(actions_.at(hint_type), hint_type) 69 : false; 70 } 71 72 bool HintManager::IsRunning() const { 73 return (nm_.get() == nullptr) ? false : nm_->isRunning(); 74 } 75 76 std::vector<std::string> HintManager::GetHints() const { 77 std::vector<std::string> hints; 78 for (auto const& action : actions_) { 79 hints.push_back(action.first); 80 } 81 return hints; 82 } 83 84 void HintManager::DumpToFd(int fd) { 85 std::string header( 86 "========== Begin perfmgr nodes ==========\n" 87 "Node Name\t" 88 "Node Path\t" 89 "Current Index\t" 90 "Current Value\n"); 91 if (!android::base::WriteStringToFd(header, fd)) { 92 LOG(ERROR) << "Failed to dump fd: " << fd; 93 } 94 nm_->DumpToFd(fd); 95 std::string footer("========== End perfmgr nodes ==========\n"); 96 if (!android::base::WriteStringToFd(footer, fd)) { 97 LOG(ERROR) << "Failed to dump fd: " << fd; 98 } 99 fsync(fd); 100 } 101 102 std::unique_ptr<HintManager> HintManager::GetFromJSON( 103 const std::string& config_path) { 104 std::string json_doc; 105 106 if (!android::base::ReadFileToString(config_path, &json_doc)) { 107 LOG(ERROR) << "Failed to read JSON config from " << config_path; 108 return nullptr; 109 } 110 111 std::vector<std::unique_ptr<Node>> nodes = ParseNodes(json_doc); 112 if (nodes.empty()) { 113 LOG(ERROR) << "Failed to parse Nodes section from " << config_path; 114 return nullptr; 115 } 116 std::map<std::string, std::vector<NodeAction>> actions = 117 HintManager::ParseActions(json_doc, nodes); 118 119 if (actions.empty()) { 120 LOG(ERROR) << "Failed to parse Actions section from " << config_path; 121 return nullptr; 122 } 123 124 sp<NodeLooperThread> nm = new NodeLooperThread(std::move(nodes)); 125 std::unique_ptr<HintManager> hm = 126 std::make_unique<HintManager>(std::move(nm), actions); 127 128 LOG(INFO) << "Initialized HintManager from JSON config: " << config_path; 129 return hm; 130 } 131 132 std::vector<std::unique_ptr<Node>> HintManager::ParseNodes( 133 const std::string& json_doc) { 134 // function starts 135 std::vector<std::unique_ptr<Node>> nodes_parsed; 136 std::set<std::string> nodes_name_parsed; 137 std::set<std::string> nodes_path_parsed; 138 Json::Value root; 139 Json::Reader reader; 140 141 if (!reader.parse(json_doc, root)) { 142 LOG(ERROR) << "Failed to parse JSON config"; 143 return nodes_parsed; 144 } 145 146 Json::Value nodes = root["Nodes"]; 147 for (Json::Value::ArrayIndex i = 0; i < nodes.size(); ++i) { 148 std::string name = nodes[i]["Name"].asString(); 149 LOG(VERBOSE) << "Node[" << i << "]'s Name: " << name; 150 if (name.empty()) { 151 LOG(ERROR) << "Failed to read " 152 << "Node[" << i << "]'s Name"; 153 nodes_parsed.clear(); 154 return nodes_parsed; 155 } 156 157 auto result = nodes_name_parsed.insert(name); 158 if (!result.second) { 159 LOG(ERROR) << "Duplicate Node[" << i << "]'s Name"; 160 nodes_parsed.clear(); 161 return nodes_parsed; 162 } 163 164 std::string path = nodes[i]["Path"].asString(); 165 LOG(VERBOSE) << "Node[" << i << "]'s Path: " << path; 166 if (path.empty()) { 167 LOG(ERROR) << "Failed to read " 168 << "Node[" << i << "]'s Path"; 169 nodes_parsed.clear(); 170 return nodes_parsed; 171 } 172 173 result = nodes_path_parsed.insert(path); 174 if (!result.second) { 175 LOG(ERROR) << "Duplicate Node[" << i << "]'s Path"; 176 nodes_parsed.clear(); 177 return nodes_parsed; 178 }; 179 180 std::vector<RequestGroup> values_parsed; 181 Json::Value values = nodes[i]["Values"]; 182 for (Json::Value::ArrayIndex j = 0; j < values.size(); ++j) { 183 std::string value = values[j].asString(); 184 LOG(VERBOSE) << "Node[" << i << "]'s Value[" << j << "]: " << value; 185 if (value.empty()) { 186 LOG(ERROR) << "Failed to read Node" << i << "'s Value[" << j 187 << "]"; 188 nodes_parsed.clear(); 189 return nodes_parsed; 190 } 191 values_parsed.emplace_back(value); 192 } 193 if (values_parsed.size() < 1) { 194 LOG(ERROR) << "Failed to read Node" << i << "'s Values"; 195 nodes_parsed.clear(); 196 return nodes_parsed; 197 } 198 199 Json::UInt64 default_index = values_parsed.size() - 1; 200 if (nodes[i]["DefaultIndex"].empty() || 201 !nodes[i]["DefaultIndex"].isUInt64()) { 202 LOG(INFO) << "Failed to read Node" << i 203 << "'s DefaultIndex, set to last index: " << default_index; 204 } else { 205 default_index = nodes[i]["DefaultIndex"].asUInt64(); 206 } 207 if (default_index > values_parsed.size() - 1) { 208 default_index = values_parsed.size() - 1; 209 LOG(ERROR) << "Node" << i 210 << "'s DefaultIndex out of bound, max value index: " 211 << default_index; 212 nodes_parsed.clear(); 213 return nodes_parsed; 214 } 215 LOG(VERBOSE) << "Node[" << i << "]'s DefaultIndex: " << default_index; 216 217 bool reset = false; 218 if (nodes[i]["ResetOnInit"].empty() || 219 !nodes[i]["ResetOnInit"].isBool()) { 220 LOG(INFO) << "Failed to read Node" << i 221 << "'s ResetOnInit, set to 'false'"; 222 } else { 223 reset = nodes[i]["ResetOnInit"].asBool(); 224 } 225 LOG(VERBOSE) << "Node[" << i << "]'s ResetOnInit: " << reset; 226 227 bool hold_fd = false; 228 if (nodes[i]["HoldFd"].empty() || !nodes[i]["HoldFd"].isBool()) { 229 LOG(INFO) << "Failed to read Node" << i 230 << "'s HoldFd, set to 'false'"; 231 } else { 232 hold_fd = nodes[i]["HoldFd"].asBool(); 233 } 234 LOG(VERBOSE) << "Node[" << i << "]'s HoldFd: " << hold_fd; 235 236 nodes_parsed.emplace_back(std::make_unique<Node>( 237 name, path, values_parsed, static_cast<std::size_t>(default_index), 238 reset, hold_fd)); 239 } 240 LOG(INFO) << nodes_parsed.size() << " Nodes parsed successfully"; 241 return nodes_parsed; 242 } 243 244 std::map<std::string, std::vector<NodeAction>> HintManager::ParseActions( 245 const std::string& json_doc, 246 const std::vector<std::unique_ptr<Node>>& nodes) { 247 // function starts 248 std::map<std::string, std::vector<NodeAction>> actions_parsed; 249 Json::Value root; 250 Json::Reader reader; 251 252 if (!reader.parse(json_doc, root)) { 253 LOG(ERROR) << "Failed to parse JSON config"; 254 return actions_parsed; 255 } 256 257 Json::Value actions = root["Actions"]; 258 std::size_t total_parsed = 0; 259 260 std::map<std::string, std::size_t> nodes_index; 261 for (std::size_t i = 0; i < nodes.size(); ++i) { 262 nodes_index[nodes[i]->GetName()] = i; 263 } 264 265 for (Json::Value::ArrayIndex i = 0; i < actions.size(); ++i) { 266 const std::string& hint_type = actions[i]["PowerHint"].asString(); 267 LOG(VERBOSE) << "Action[" << i << "]'s PowerHint: " << hint_type; 268 if (hint_type.empty()) { 269 LOG(ERROR) << "Failed to read " 270 << "Action[" << i << "]'s PowerHint"; 271 actions_parsed.clear(); 272 return actions_parsed; 273 } 274 275 std::string node_name = actions[i]["Node"].asString(); 276 LOG(VERBOSE) << "Action[" << i << "]'s Node: " << node_name; 277 std::size_t node_index; 278 279 if (nodes_index.find(node_name) == nodes_index.end()) { 280 LOG(ERROR) << "Failed to find " 281 << "Action" << i 282 << "'s Node from Nodes section: " << node_name; 283 actions_parsed.clear(); 284 return actions_parsed; 285 } 286 node_index = nodes_index[node_name]; 287 288 std::string value_name = actions[i]["Value"].asString(); 289 LOG(VERBOSE) << "Action[" << i << "]'s Value: " << value_name; 290 std::size_t value_index = 0; 291 292 if (!nodes[node_index]->GetValueIndex(value_name, &value_index)) { 293 LOG(ERROR) << "Failed to read Action" << i << "'s Value"; 294 LOG(ERROR) << "Action[" << i << "]'s Value " << value_name 295 << " is not defined in Node[" << node_name; 296 actions_parsed.clear(); 297 return actions_parsed; 298 } 299 LOG(VERBOSE) << "Action[" << i << "]'s ValueIndex: " << value_index; 300 301 Json::UInt64 duration = 0; 302 if (actions[i]["Duration"].empty() || 303 !actions[i]["Duration"].isUInt64()) { 304 LOG(ERROR) << "Failed to read Action" << i << "'s Duration"; 305 actions_parsed.clear(); 306 return actions_parsed; 307 } else { 308 duration = actions[i]["Duration"].asUInt64(); 309 } 310 LOG(VERBOSE) << "Action[" << i << "]'s Duration: " << duration; 311 312 if (actions_parsed.find(hint_type) == actions_parsed.end()) { 313 actions_parsed[hint_type] = std::vector<NodeAction>{ 314 {node_index, value_index, std::chrono::milliseconds(duration)}}; 315 } else { 316 for (const auto& action : actions_parsed[hint_type]) { 317 if (action.node_index == node_index) { 318 LOG(ERROR) 319 << "Action[" << i 320 << "]'s NodeIndex is duplicated with another Action"; 321 actions_parsed.clear(); 322 return actions_parsed; 323 } 324 } 325 actions_parsed[hint_type].emplace_back( 326 node_index, value_index, std::chrono::milliseconds(duration)); 327 } 328 329 ++total_parsed; 330 } 331 332 LOG(INFO) << total_parsed << " Actions parsed successfully"; 333 334 for (const auto& action : actions_parsed) { 335 LOG(INFO) << "PowerHint " << action.first << " has " 336 << action.second.size() << " actions parsed"; 337 } 338 339 return actions_parsed; 340 } 341 342 } // namespace perfmgr 343 } // namespace android 344