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