• 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 ATRACE_TAG (ATRACE_TAG_POWER | ATRACE_TAG_HAL)
18 #define LOG_TAG "libperfmgr"
19 
20 #include "perfmgr/HintManager.h"
21 
22 #include <android-base/file.h>
23 #include <android-base/logging.h>
24 #include <android-base/properties.h>
25 #include <android-base/stringprintf.h>
26 #include <inttypes.h>
27 #include <json/reader.h>
28 #include <json/value.h>
29 #include <utils/Trace.h>
30 
31 #include <algorithm>
32 #include <set>
33 
34 #include "perfmgr/FileNode.h"
35 #include "perfmgr/PropertyNode.h"
36 
37 namespace android {
38 namespace perfmgr {
39 
40 namespace {
41 constexpr std::chrono::milliseconds kMilliSecondZero = std::chrono::milliseconds(0);
42 constexpr std::chrono::steady_clock::time_point kTimePointMax =
43         std::chrono::steady_clock::time_point::max();
44 }  // namespace
45 
46 constexpr char kPowerHalTruncateProp[] = "vendor.powerhal.truncate";
47 constexpr std::string_view kConfigDebugPathProperty("vendor.powerhal.config.debug");
48 constexpr std::string_view kConfigProperty("vendor.powerhal.config");
49 constexpr std::string_view kConfigDefaultFileName("powerhint.json");
50 
ValidateHint(const std::string & hint_type) const51 bool HintManager::ValidateHint(const std::string& hint_type) const {
52     if (nm_.get() == nullptr) {
53         LOG(ERROR) << "NodeLooperThread not present";
54         return false;
55     }
56     return IsHintSupported(hint_type);
57 }
58 
IsHintSupported(const std::string & hint_type) const59 bool HintManager::IsHintSupported(const std::string& hint_type) const {
60     if (actions_.find(hint_type) == actions_.end()) {
61         LOG(INFO) << "Hint type not present in actions: " << hint_type;
62         return false;
63     }
64     return true;
65 }
66 
IsHintEnabled(const std::string & hint_type) const67 bool HintManager::IsHintEnabled(const std::string &hint_type) const {
68     std::lock_guard<std::mutex> lock(actions_.at(hint_type).hint_lock);
69     return actions_.at(hint_type).mask_requesters.empty();
70 }
71 
InitHintStatus(const std::unique_ptr<HintManager> & hm)72 bool HintManager::InitHintStatus(const std::unique_ptr<HintManager> &hm) {
73     if (hm.get() == nullptr) {
74         return false;
75     }
76     for (auto &a : hm->actions_) {
77         // timeout_ms equaling kMilliSecondZero means forever until cancelling.
78         // As a result, if there's one NodeAction has timeout_ms of 0, we will store
79         // 0 instead of max. Also node actions could be empty, set to 0 in that case.
80         std::chrono::milliseconds timeout = kMilliSecondZero;
81         if (a.second.node_actions.size()) {
82             auto [min, max] =
83                     std::minmax_element(a.second.node_actions.begin(), a.second.node_actions.end(),
84                                         [](const auto act1, const auto act2) {
85                                             return act1.timeout_ms < act2.timeout_ms;
86                                         });
87             timeout = min->timeout_ms == kMilliSecondZero ? kMilliSecondZero : max->timeout_ms;
88         }
89         a.second.status.reset(new HintStatus(timeout));
90     }
91     return true;
92 }
93 
DoHintStatus(const std::string & hint_type,std::chrono::milliseconds timeout_ms)94 void HintManager::DoHintStatus(const std::string &hint_type, std::chrono::milliseconds timeout_ms) {
95     std::lock_guard<std::mutex> lock(actions_.at(hint_type).hint_lock);
96     actions_.at(hint_type).status->stats.count.fetch_add(1);
97     auto now = std::chrono::steady_clock::now();
98     ATRACE_INT(hint_type.c_str(), (timeout_ms == kMilliSecondZero) ? std::numeric_limits<int>::max()
99                                                                    : timeout_ms.count());
100     if (now > actions_.at(hint_type).status->end_time) {
101         actions_.at(hint_type).status->stats.duration_ms.fetch_add(
102                 std::chrono::duration_cast<std::chrono::milliseconds>(
103                         actions_.at(hint_type).status->end_time -
104                         actions_.at(hint_type).status->start_time)
105                         .count());
106         actions_.at(hint_type).status->start_time = now;
107     }
108     actions_.at(hint_type).status->end_time =
109             (timeout_ms == kMilliSecondZero) ? kTimePointMax : now + timeout_ms;
110 }
111 
EndHintStatus(const std::string & hint_type)112 void HintManager::EndHintStatus(const std::string &hint_type) {
113     std::lock_guard<std::mutex> lock(actions_.at(hint_type).hint_lock);
114     // Update HintStats if the hint ends earlier than expected end_time
115     auto now = std::chrono::steady_clock::now();
116     ATRACE_INT(hint_type.c_str(), 0);
117     if (now < actions_.at(hint_type).status->end_time) {
118         actions_.at(hint_type).status->stats.duration_ms.fetch_add(
119                 std::chrono::duration_cast<std::chrono::milliseconds>(
120                         now - actions_.at(hint_type).status->start_time)
121                         .count());
122         actions_.at(hint_type).status->end_time = now;
123     }
124 }
125 
DoHintAction(const std::string & hint_type)126 void HintManager::DoHintAction(const std::string &hint_type) {
127     for (auto &action : actions_.at(hint_type).hint_actions) {
128         if (!action.enable_property.empty() &&
129             !android::base::GetBoolProperty(action.enable_property, true)) {
130             // Disabled action based on its control property
131             continue;
132         }
133         switch (action.type) {
134             case HintActionType::DoHint:
135                 DoHint(action.value);
136                 break;
137             case HintActionType::EndHint:
138                 EndHint(action.value);
139                 break;
140             case HintActionType::MaskHint:
141                 if (actions_.find(action.value) == actions_.end()) {
142                     LOG(ERROR) << "Failed to find " << action.value << " action";
143                 } else {
144                     std::lock_guard<std::mutex> lock(actions_.at(hint_type).hint_lock);
145                     actions_.at(action.value).mask_requesters.insert(hint_type);
146                 }
147                 break;
148             default:
149                 // should not reach here
150                 LOG(ERROR) << "Invalid "
151                            << static_cast<std::underlying_type<HintActionType>::type>(action.type)
152                            << " type";
153         }
154     }
155 }
156 
EndHintAction(const std::string & hint_type)157 void HintManager::EndHintAction(const std::string &hint_type) {
158     for (auto &action : actions_.at(hint_type).hint_actions) {
159         if (action.type == HintActionType::MaskHint &&
160             actions_.find(action.value) != actions_.end()) {
161             std::lock_guard<std::mutex> lock(actions_.at(hint_type).hint_lock);
162             actions_.at(action.value).mask_requesters.erase(hint_type);
163         }
164     }
165 }
166 
DoHint(const std::string & hint_type)167 bool HintManager::DoHint(const std::string& hint_type) {
168     LOG(VERBOSE) << "Do Powerhint: " << hint_type;
169     if (!ValidateHint(hint_type) || !IsHintEnabled(hint_type) ||
170         !nm_->Request(actions_.at(hint_type).node_actions, hint_type)) {
171         return false;
172     }
173     DoHintStatus(hint_type, actions_.at(hint_type).status->max_timeout);
174     DoHintAction(hint_type);
175     return true;
176 }
177 
DoHint(const std::string & hint_type,std::chrono::milliseconds timeout_ms_override)178 bool HintManager::DoHint(const std::string& hint_type,
179                          std::chrono::milliseconds timeout_ms_override) {
180     LOG(VERBOSE) << "Do Powerhint: " << hint_type << " for "
181                  << timeout_ms_override.count() << "ms";
182     if (!ValidateHint(hint_type) || !IsHintEnabled(hint_type)) {
183         return false;
184     }
185     std::vector<NodeAction> actions_override = actions_.at(hint_type).node_actions;
186     for (auto& action : actions_override) {
187         action.timeout_ms = timeout_ms_override;
188     }
189     if (!nm_->Request(actions_override, hint_type)) {
190         return false;
191     }
192     DoHintStatus(hint_type, timeout_ms_override);
193     DoHintAction(hint_type);
194     return true;
195 }
196 
EndHint(const std::string & hint_type)197 bool HintManager::EndHint(const std::string& hint_type) {
198     LOG(VERBOSE) << "End Powerhint: " << hint_type;
199     if (!ValidateHint(hint_type) || !nm_->Cancel(actions_.at(hint_type).node_actions, hint_type)) {
200         return false;
201     }
202     EndHintStatus(hint_type);
203     EndHintAction(hint_type);
204     return true;
205 }
206 
IsRunning() const207 bool HintManager::IsRunning() const {
208     return (nm_.get() == nullptr) ? false : nm_->isRunning();
209 }
210 
GetHints() const211 std::vector<std::string> HintManager::GetHints() const {
212     std::vector<std::string> hints;
213     for (auto const& action : actions_) {
214         hints.push_back(action.first);
215     }
216     return hints;
217 }
218 
GetHintStats(const std::string & hint_type) const219 HintStats HintManager::GetHintStats(const std::string &hint_type) const {
220     HintStats hint_stats;
221     if (ValidateHint(hint_type)) {
222         std::lock_guard<std::mutex> lock(actions_.at(hint_type).hint_lock);
223         hint_stats.count =
224                 actions_.at(hint_type).status->stats.count.load(std::memory_order_relaxed);
225         hint_stats.duration_ms =
226                 actions_.at(hint_type).status->stats.duration_ms.load(std::memory_order_relaxed);
227     }
228     return hint_stats;
229 }
230 
DumpToFd(int fd)231 void HintManager::DumpToFd(int fd) {
232     std::string header("========== Begin perfmgr nodes ==========\n");
233     if (!android::base::WriteStringToFd(header, fd)) {
234         LOG(ERROR) << "Failed to dump fd: " << fd;
235     }
236     nm_->DumpToFd(fd);
237     std::string footer("==========  End perfmgr nodes  ==========\n");
238     if (!android::base::WriteStringToFd(footer, fd)) {
239         LOG(ERROR) << "Failed to dump fd: " << fd;
240     }
241     header = "========== Begin perfmgr stats ==========\n"
242              "Hint Name\t"
243              "Counts\t"
244              "Duration\n";
245     if (!android::base::WriteStringToFd(header, fd)) {
246         LOG(ERROR) << "Failed to dump fd: " << fd;
247     }
248     std::string hint_stats_string;
249     std::vector<std::string> keys(GetHints());
250     std::sort(keys.begin(), keys.end());
251     for (const auto &ordered_key : keys) {
252         HintStats hint_stats(GetHintStats(ordered_key));
253         hint_stats_string +=
254                 android::base::StringPrintf("%s\t%" PRIu32 "\t%" PRIu64 "\n", ordered_key.c_str(),
255                                             hint_stats.count, hint_stats.duration_ms);
256     }
257     if (!android::base::WriteStringToFd(hint_stats_string, fd)) {
258         LOG(ERROR) << "Failed to dump fd: " << fd;
259     }
260     footer = "==========  End perfmgr stats  ==========\n";
261     if (!android::base::WriteStringToFd(footer, fd)) {
262         LOG(ERROR) << "Failed to dump fd: " << fd;
263     }
264 
265     // Dump current ADPF profile
266     if (GetAdpfProfile()) {
267         header = "========== Begin current adpf profile ==========\n";
268         if (!android::base::WriteStringToFd(header, fd)) {
269             LOG(ERROR) << "Failed to dump fd: " << fd;
270         }
271         GetAdpfProfile()->dumpToFd(fd);
272         footer = "==========  End current adpf profile  ==========\n";
273         if (!android::base::WriteStringToFd(footer, fd)) {
274             LOG(ERROR) << "Failed to dump fd: " << fd;
275         }
276     }
277     fsync(fd);
278 }
279 
Start()280 bool HintManager::Start() {
281     return nm_->Start();
282 }
283 
284 std::shared_ptr<HintManager> HintManager::mInstance = nullptr;
285 
Reload(bool start)286 std::shared_ptr<HintManager> HintManager::Reload(bool start) {
287     std::string config_path = "/vendor/etc/";
288     if (android::base::GetBoolProperty(kConfigDebugPathProperty.data(), false)) {
289         config_path = "/data/vendor/etc/";
290         LOG(WARNING) << "Pixel Power HAL AIDL Service is using debug config from: " << config_path;
291     }
292     config_path.append(
293             android::base::GetProperty(kConfigProperty.data(), kConfigDefaultFileName.data()));
294 
295     LOG(INFO) << "Pixel Power HAL AIDL Service with Extension is starting with config: "
296               << config_path;
297     // Reload and start the HintManager
298     mInstance = HintManager::GetFromJSON(config_path, start);
299     if (!mInstance) {
300         LOG(FATAL) << "Invalid config: " << config_path;
301     }
302     return mInstance;
303 }
304 
GetInstance()305 std::shared_ptr<HintManager> HintManager::GetInstance() {
306     if (!mInstance) {
307         mInstance = HintManager::Reload(false);
308     }
309     return mInstance;
310 }
311 
GetFromJSON(const std::string & config_path,bool start)312 std::unique_ptr<HintManager> HintManager::GetFromJSON(
313     const std::string& config_path, bool start) {
314     std::string json_doc;
315 
316     if (!android::base::ReadFileToString(config_path, &json_doc)) {
317         LOG(ERROR) << "Failed to read JSON config from " << config_path;
318         return nullptr;
319     }
320 
321     std::vector<std::unique_ptr<Node>> nodes = ParseNodes(json_doc);
322     if (nodes.empty()) {
323         LOG(ERROR) << "Failed to parse Nodes section from " << config_path;
324         return nullptr;
325     }
326     std::vector<std::shared_ptr<AdpfConfig>> adpfs = HintManager::ParseAdpfConfigs(json_doc);
327     if (adpfs.empty()) {
328         LOG(INFO) << "No AdpfConfig section in the " << config_path;
329     }
330 
331     std::unordered_map<std::string, Hint> actions = HintManager::ParseActions(json_doc, nodes);
332 
333     if (actions.empty()) {
334         LOG(ERROR) << "Failed to parse Actions section from " << config_path;
335         return nullptr;
336     }
337 
338     sp<NodeLooperThread> nm = new NodeLooperThread(std::move(nodes));
339     std::unique_ptr<HintManager> hm = std::make_unique<HintManager>(std::move(nm), actions, adpfs);
340 
341     if (!HintManager::InitHintStatus(hm)) {
342         LOG(ERROR) << "Failed to initialize hint status";
343         return nullptr;
344     }
345 
346     LOG(INFO) << "Initialized HintManager from JSON config: " << config_path;
347 
348     if (start) {
349         hm->Start();
350     }
351     return hm;
352 }
353 
ParseNodes(const std::string & json_doc)354 std::vector<std::unique_ptr<Node>> HintManager::ParseNodes(
355     const std::string& json_doc) {
356     // function starts
357     std::vector<std::unique_ptr<Node>> nodes_parsed;
358     std::set<std::string> nodes_name_parsed;
359     std::set<std::string> nodes_path_parsed;
360     Json::Value root;
361     Json::CharReaderBuilder builder;
362     std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
363     std::string errorMessage;
364 
365     if (!reader->parse(&*json_doc.begin(), &*json_doc.end(), &root, &errorMessage)) {
366         LOG(ERROR) << "Failed to parse JSON config: " << errorMessage;
367         return nodes_parsed;
368     }
369 
370     Json::Value nodes = root["Nodes"];
371     for (Json::Value::ArrayIndex i = 0; i < nodes.size(); ++i) {
372         std::string name = nodes[i]["Name"].asString();
373         LOG(VERBOSE) << "Node[" << i << "]'s Name: " << name;
374         if (name.empty()) {
375             LOG(ERROR) << "Failed to read "
376                        << "Node[" << i << "]'s Name";
377             nodes_parsed.clear();
378             return nodes_parsed;
379         }
380 
381         auto result = nodes_name_parsed.insert(name);
382         if (!result.second) {
383             LOG(ERROR) << "Duplicate Node[" << i << "]'s Name";
384             nodes_parsed.clear();
385             return nodes_parsed;
386         }
387 
388         std::string path = nodes[i]["Path"].asString();
389         LOG(VERBOSE) << "Node[" << i << "]'s Path: " << path;
390         if (path.empty()) {
391             LOG(ERROR) << "Failed to read "
392                        << "Node[" << i << "]'s Path";
393             nodes_parsed.clear();
394             return nodes_parsed;
395         }
396 
397         result = nodes_path_parsed.insert(path);
398         if (!result.second) {
399             LOG(ERROR) << "Duplicate Node[" << i << "]'s Path";
400             nodes_parsed.clear();
401             return nodes_parsed;
402         }
403 
404         bool is_file = true;
405         std::string node_type = nodes[i]["Type"].asString();
406         LOG(VERBOSE) << "Node[" << i << "]'s Type: " << node_type;
407         if (node_type.empty()) {
408             LOG(VERBOSE) << "Failed to read "
409                          << "Node[" << i << "]'s Type, set to 'File' as default";
410         } else if (node_type == "File") {
411             is_file = true;
412         } else if (node_type == "Property") {
413             is_file = false;
414         } else {
415             LOG(ERROR) << "Invalid Node[" << i
416                        << "]'s Type: only File and Property supported.";
417             nodes_parsed.clear();
418             return nodes_parsed;
419         }
420 
421         std::vector<RequestGroup> values_parsed;
422         std::set<std::string> values_set_parsed;
423         Json::Value values = nodes[i]["Values"];
424         for (Json::Value::ArrayIndex j = 0; j < values.size(); ++j) {
425             std::string value = values[j].asString();
426             LOG(VERBOSE) << "Node[" << i << "]'s Value[" << j << "]: " << value;
427             auto result = values_set_parsed.insert(value);
428             if (!result.second) {
429                 LOG(ERROR) << "Duplicate value parsed in Node[" << i
430                            << "]'s Value[" << j << "]";
431                 nodes_parsed.clear();
432                 return nodes_parsed;
433             }
434             if (is_file && value.empty()) {
435                 LOG(ERROR) << "Failed to read Node[" << i << "]'s Value[" << j
436                            << "]";
437                 nodes_parsed.clear();
438                 return nodes_parsed;
439             }
440             values_parsed.emplace_back(value);
441         }
442         if (values_parsed.size() < 1) {
443             LOG(ERROR) << "Failed to read Node[" << i << "]'s Values";
444             nodes_parsed.clear();
445             return nodes_parsed;
446         }
447 
448         Json::UInt64 default_index = values_parsed.size() - 1;
449         if (nodes[i]["DefaultIndex"].empty() ||
450             !nodes[i]["DefaultIndex"].isUInt64()) {
451             LOG(INFO) << "Failed to read Node[" << i
452                       << "]'s DefaultIndex, set to last index: "
453                       << default_index;
454         } else {
455             default_index = nodes[i]["DefaultIndex"].asUInt64();
456         }
457         if (default_index > values_parsed.size() - 1) {
458             default_index = values_parsed.size() - 1;
459             LOG(ERROR) << "Node[" << i
460                        << "]'s DefaultIndex out of bound, max value index: "
461                        << default_index;
462             nodes_parsed.clear();
463             return nodes_parsed;
464         }
465         LOG(VERBOSE) << "Node[" << i << "]'s DefaultIndex: " << default_index;
466 
467         bool reset = false;
468         if (nodes[i]["ResetOnInit"].empty() ||
469             !nodes[i]["ResetOnInit"].isBool()) {
470             LOG(INFO) << "Failed to read Node[" << i
471                       << "]'s ResetOnInit, set to 'false'";
472         } else {
473             reset = nodes[i]["ResetOnInit"].asBool();
474         }
475         LOG(VERBOSE) << "Node[" << i << "]'s ResetOnInit: " << std::boolalpha
476                      << reset << std::noboolalpha;
477 
478         if (is_file) {
479             bool truncate = android::base::GetBoolProperty(kPowerHalTruncateProp, true);
480             if (nodes[i]["Truncate"].empty() || !nodes[i]["Truncate"].isBool()) {
481                 LOG(INFO) << "Failed to read Node[" << i << "]'s Truncate, set to 'true'";
482             } else {
483                 truncate = nodes[i]["Truncate"].asBool();
484             }
485             LOG(VERBOSE) << "Node[" << i << "]'s Truncate: " << std::boolalpha << truncate
486                          << std::noboolalpha;
487 
488             bool hold_fd = false;
489             if (nodes[i]["HoldFd"].empty() || !nodes[i]["HoldFd"].isBool()) {
490                 LOG(INFO) << "Failed to read Node[" << i
491                           << "]'s HoldFd, set to 'false'";
492             } else {
493                 hold_fd = nodes[i]["HoldFd"].asBool();
494             }
495             LOG(VERBOSE) << "Node[" << i << "]'s HoldFd: " << std::boolalpha
496                          << hold_fd << std::noboolalpha;
497 
498             nodes_parsed.emplace_back(std::make_unique<FileNode>(
499                     name, path, values_parsed, static_cast<std::size_t>(default_index), reset,
500                     truncate, hold_fd));
501         } else {
502             nodes_parsed.emplace_back(std::make_unique<PropertyNode>(
503                 name, path, values_parsed,
504                 static_cast<std::size_t>(default_index), reset));
505         }
506     }
507     LOG(INFO) << nodes_parsed.size() << " Nodes parsed successfully";
508     return nodes_parsed;
509 }
510 
ParseActions(const std::string & json_doc,const std::vector<std::unique_ptr<Node>> & nodes)511 std::unordered_map<std::string, Hint> HintManager::ParseActions(
512         const std::string &json_doc, const std::vector<std::unique_ptr<Node>> &nodes) {
513     // function starts
514     std::unordered_map<std::string, Hint> actions_parsed;
515     Json::Value root;
516     Json::CharReaderBuilder builder;
517     std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
518     std::string errorMessage;
519 
520     if (!reader->parse(&*json_doc.begin(), &*json_doc.end(), &root, &errorMessage)) {
521         LOG(ERROR) << "Failed to parse JSON config";
522         return actions_parsed;
523     }
524 
525     Json::Value actions = root["Actions"];
526     std::size_t total_parsed = 0;
527 
528     std::map<std::string, std::size_t> nodes_index;
529     for (std::size_t i = 0; i < nodes.size(); ++i) {
530         nodes_index[nodes[i]->GetName()] = i;
531     }
532 
533     for (Json::Value::ArrayIndex i = 0; i < actions.size(); ++i) {
534         const std::string& hint_type = actions[i]["PowerHint"].asString();
535         LOG(VERBOSE) << "Action[" << i << "]'s PowerHint: " << hint_type;
536         if (hint_type.empty()) {
537             LOG(ERROR) << "Failed to read "
538                        << "Action[" << i << "]'s PowerHint";
539             actions_parsed.clear();
540             return actions_parsed;
541         }
542 
543         HintActionType action_type = HintActionType::Node;
544         std::string type_string = actions[i]["Type"].asString();
545         std::string enable_property = actions[i]["EnableProperty"].asString();
546         LOG(VERBOSE) << "Action[" << i << "]'s Type: " << type_string;
547         if (type_string.empty()) {
548             LOG(VERBOSE) << "Failed to read "
549                          << "Action[" << i << "]'s Type, set to 'Node' as default";
550         } else if (type_string == "DoHint") {
551             action_type = HintActionType::DoHint;
552         } else if (type_string == "EndHint") {
553             action_type = HintActionType::EndHint;
554         } else if (type_string == "MaskHint") {
555             action_type = HintActionType::MaskHint;
556         } else {
557             LOG(ERROR) << "Invalid Action[" << i << "]'s Type: " << type_string;
558             actions_parsed.clear();
559             return actions_parsed;
560         }
561         if (action_type == HintActionType::Node) {
562             std::string node_name = actions[i]["Node"].asString();
563             LOG(VERBOSE) << "Action[" << i << "]'s Node: " << node_name;
564             std::size_t node_index;
565 
566             if (nodes_index.find(node_name) == nodes_index.end()) {
567                 LOG(ERROR) << "Failed to find "
568                            << "Action[" << i << "]'s Node from Nodes section: [" << node_name
569                            << "]";
570                 actions_parsed.clear();
571                 return actions_parsed;
572             }
573             node_index = nodes_index[node_name];
574 
575             std::string value_name = actions[i]["Value"].asString();
576             LOG(VERBOSE) << "Action[" << i << "]'s Value: " << value_name;
577             std::size_t value_index = 0;
578 
579             if (!nodes[node_index]->GetValueIndex(value_name, &value_index)) {
580                 LOG(ERROR) << "Failed to read Action[" << i << "]'s Value";
581                 LOG(ERROR) << "Action[" << i << "]'s Value " << value_name
582                            << " is not defined in Node[" << node_name << "]";
583                 actions_parsed.clear();
584                 return actions_parsed;
585             }
586             LOG(VERBOSE) << "Action[" << i << "]'s ValueIndex: " << value_index;
587 
588             Json::UInt64 duration = 0;
589             if (actions[i]["Duration"].empty() || !actions[i]["Duration"].isUInt64()) {
590                 LOG(ERROR) << "Failed to read Action[" << i << "]'s Duration";
591                 actions_parsed.clear();
592                 return actions_parsed;
593             } else {
594                 duration = actions[i]["Duration"].asUInt64();
595             }
596             LOG(VERBOSE) << "Action[" << i << "]'s Duration: " << duration;
597 
598             for (const auto &action : actions_parsed[hint_type].node_actions) {
599                 if (action.node_index == node_index) {
600                     LOG(ERROR)
601                         << "Action[" << i
602                         << "]'s NodeIndex is duplicated with another Action";
603                     actions_parsed.clear();
604                     return actions_parsed;
605                 }
606             }
607             actions_parsed[hint_type].node_actions.emplace_back(
608                     node_index, value_index, std::chrono::milliseconds(duration), enable_property);
609 
610         } else {
611             const std::string &hint_value = actions[i]["Value"].asString();
612             LOG(VERBOSE) << "Action[" << i << "]'s Value: " << hint_value;
613             if (hint_value.empty()) {
614                 LOG(ERROR) << "Failed to read "
615                            << "Action[" << i << "]'s Value";
616                 actions_parsed.clear();
617                 return actions_parsed;
618             }
619             actions_parsed[hint_type].hint_actions.emplace_back(action_type, hint_value,
620                                                                 enable_property);
621         }
622 
623         ++total_parsed;
624     }
625 
626     LOG(INFO) << total_parsed << " actions parsed successfully";
627 
628     for (const auto& action : actions_parsed) {
629         LOG(INFO) << "PowerHint " << action.first << " has " << action.second.node_actions.size()
630                   << " node actions"
631                   << ", and " << action.second.hint_actions.size() << " hint actions parsed";
632     }
633 
634     return actions_parsed;
635 }
636 
ParseAdpfConfigs(const std::string & json_doc)637 std::vector<std::shared_ptr<AdpfConfig>> HintManager::ParseAdpfConfigs(
638         const std::string &json_doc) {
639     // function starts
640     bool pidOn;
641     double pidPOver;
642     double pidPUnder;
643     double pidI;
644     double pidDOver;
645     double pidDUnder;
646     int64_t pidIInit;
647     int64_t pidIHighLimit;
648     int64_t pidILowLimit;
649     bool adpfUclamp;
650     uint32_t uclampMinInit;
651     uint32_t uclampMinHighLimit;
652     uint32_t uclampMinLowLimit;
653     uint64_t samplingWindowP;
654     uint64_t samplingWindowI;
655     uint64_t samplingWindowD;
656     double staleTimeFactor;
657     uint64_t reportingRate;
658     bool earlyBoostOn;
659     double earlyBoostTimeFactor;
660     double targetTimeFactor;
661     std::vector<std::shared_ptr<AdpfConfig>> adpfs_parsed;
662     std::set<std::string> name_parsed;
663     Json::Value root;
664     Json::CharReaderBuilder builder;
665     std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
666     std::string errorMessage;
667     if (!reader->parse(&*json_doc.begin(), &*json_doc.end(), &root, &errorMessage)) {
668         LOG(ERROR) << "Failed to parse JSON config: " << errorMessage;
669         return adpfs_parsed;
670     }
671     Json::Value adpfs = root["AdpfConfig"];
672     for (Json::Value::ArrayIndex i = 0; i < adpfs.size(); ++i) {
673         std::string name = adpfs[i]["Name"].asString();
674         LOG(VERBOSE) << "AdpfConfig[" << i << "]'s Name: " << name;
675         if (name.empty()) {
676             LOG(ERROR) << "Failed to read "
677                        << "AdpfConfig[" << i << "]'s Name";
678             adpfs_parsed.clear();
679             return adpfs_parsed;
680         }
681         auto result = name_parsed.insert(name);
682         if (!result.second) {
683             LOG(ERROR) << "Duplicate AdpfConfig[" << i << "]'s Name";
684             adpfs_parsed.clear();
685             return adpfs_parsed;
686         }
687 
688         if (adpfs[i]["PID_On"].empty() || !adpfs[i]["PID_On"].isBool()) {
689             LOG(ERROR) << "Failed to read AdpfConfig[" << name << "][PID_On]'s Values";
690             adpfs_parsed.clear();
691             return adpfs_parsed;
692         }
693         pidOn = adpfs[i]["PID_On"].asBool();
694 
695         if (adpfs[i]["PID_Po"].empty() || !adpfs[i]["PID_Po"].isDouble()) {
696             LOG(ERROR) << "Failed to read AdpfConfig[" << name << "][PID_Po]'s Values";
697             adpfs_parsed.clear();
698             return adpfs_parsed;
699         }
700         pidPOver = adpfs[i]["PID_Po"].asDouble();
701 
702         if (adpfs[i]["PID_Pu"].empty() || !adpfs[i]["PID_Pu"].isDouble()) {
703             LOG(ERROR) << "Failed to read AdpfConfig[" << name << "][PID_Pu]'s Values";
704             adpfs_parsed.clear();
705             return adpfs_parsed;
706         }
707         pidPUnder = adpfs[i]["PID_Pu"].asDouble();
708 
709         if (adpfs[i]["PID_I"].empty() || !adpfs[i]["PID_I"].isDouble()) {
710             LOG(ERROR) << "Failed to read AdpfConfig[" << name << "][PID_I]'s Values";
711             adpfs_parsed.clear();
712             return adpfs_parsed;
713         }
714         pidI = adpfs[i]["PID_I"].asDouble();
715 
716         if (adpfs[i]["PID_I_Init"].empty() || !adpfs[i]["PID_I_Init"].isInt64()) {
717             LOG(ERROR) << "Failed to read AdpfConfig[" << name << "][PID_I_Init]'s Values";
718             adpfs_parsed.clear();
719             return adpfs_parsed;
720         }
721         pidIInit = adpfs[i]["PID_I_Init"].asInt64();
722 
723         if (adpfs[i]["PID_I_High"].empty() || !adpfs[i]["PID_I_High"].isInt64()) {
724             LOG(ERROR) << "Failed to read AdpfConfig[" << name << "][PID_I_High]'s Values";
725             adpfs_parsed.clear();
726             return adpfs_parsed;
727         }
728         pidIHighLimit = adpfs[i]["PID_I_High"].asInt64();
729 
730         if (adpfs[i]["PID_I_Low"].empty() || !adpfs[i]["PID_I_Low"].isInt64()) {
731             LOG(ERROR) << "Failed to read AdpfConfig[" << name << "][PID_I_Low]'s Values";
732             adpfs_parsed.clear();
733             return adpfs_parsed;
734         }
735         pidILowLimit = adpfs[i]["PID_I_Low"].asInt64();
736 
737         if (adpfs[i]["PID_Do"].empty() || !adpfs[i]["PID_Do"].isDouble()) {
738             LOG(ERROR) << "Failed to read AdpfConfig[" << name << "][PID_Do]'s Values";
739             adpfs_parsed.clear();
740             return adpfs_parsed;
741         }
742         pidDOver = adpfs[i]["PID_Do"].asDouble();
743 
744         if (adpfs[i]["PID_Du"].empty() || !adpfs[i]["PID_Du"].isDouble()) {
745             LOG(ERROR) << "Failed to read AdpfConfig[" << name << "][PID_Du]'s Values";
746             adpfs_parsed.clear();
747             return adpfs_parsed;
748         }
749         pidDUnder = adpfs[i]["PID_Du"].asDouble();
750 
751         if (adpfs[i]["UclampMin_On"].empty() || !adpfs[i]["UclampMin_On"].isBool()) {
752             LOG(ERROR) << "Failed to read AdpfConfig[" << name << "][UclampMin_On]'s Values";
753             adpfs_parsed.clear();
754             return adpfs_parsed;
755         }
756         adpfUclamp = adpfs[i]["UclampMin_On"].asBool();
757 
758         if (adpfs[i]["UclampMin_Init"].empty() || !adpfs[i]["UclampMin_Init"].isInt()) {
759             LOG(ERROR) << "Failed to read AdpfConfig[" << name << "][UclampMin_Init]'s Values";
760             adpfs_parsed.clear();
761             return adpfs_parsed;
762         }
763         uclampMinInit = adpfs[i]["UclampMin_Init"].asInt();
764 
765         if (adpfs[i]["UclampMin_High"].empty() || !adpfs[i]["UclampMin_High"].isUInt()) {
766             LOG(ERROR) << "Failed to read AdpfConfig[" << name << "][UclampMin_High]'s Values";
767             adpfs_parsed.clear();
768             return adpfs_parsed;
769         }
770         uclampMinHighLimit = adpfs[i]["UclampMin_High"].asUInt();
771 
772         if (adpfs[i]["UclampMin_Low"].empty() || !adpfs[i]["UclampMin_Low"].isUInt()) {
773             LOG(ERROR) << "Failed to read AdpfConfig[" << name << "][UclampMin_Low]'s Values";
774             adpfs_parsed.clear();
775             return adpfs_parsed;
776         }
777         uclampMinLowLimit = adpfs[i]["UclampMin_Low"].asUInt();
778 
779         if (adpfs[i]["SamplingWindow_P"].empty() || !adpfs[i]["SamplingWindow_P"].isUInt64()) {
780             LOG(ERROR) << "Failed to read AdpfConfig[" << name << "][SamplingWindow_P]'s Values";
781             adpfs_parsed.clear();
782             return adpfs_parsed;
783         }
784         samplingWindowP = adpfs[i]["SamplingWindow_P"].asUInt64();
785 
786         if (adpfs[i]["SamplingWindow_I"].empty() || !adpfs[i]["SamplingWindow_I"].isUInt64()) {
787             LOG(ERROR) << "Failed to read AdpfConfig[" << name << "][SamplingWindow_I]'s Values";
788             adpfs_parsed.clear();
789             return adpfs_parsed;
790         }
791         samplingWindowI = adpfs[i]["SamplingWindow_I"].asUInt64();
792 
793         if (adpfs[i]["SamplingWindow_D"].empty() || !adpfs[i]["SamplingWindow_D"].isUInt64()) {
794             LOG(ERROR) << "Failed to read AdpfConfig[" << name << "][SamplingWindow_D]'s Values";
795             adpfs_parsed.clear();
796             return adpfs_parsed;
797         }
798         samplingWindowD = adpfs[i]["SamplingWindow_D"].asUInt64();
799 
800         if (adpfs[i]["StaleTimeFactor"].empty() || !adpfs[i]["StaleTimeFactor"].isUInt64()) {
801             LOG(ERROR) << "Failed to read AdpfConfig[" << name << "][StaleTimeFactor]'s Values";
802             adpfs_parsed.clear();
803             return adpfs_parsed;
804         }
805         staleTimeFactor = adpfs[i]["StaleTimeFactor"].asDouble();
806 
807         if (adpfs[i]["ReportingRateLimitNs"].empty() ||
808             !adpfs[i]["ReportingRateLimitNs"].isInt64()) {
809             LOG(ERROR) << "Failed to read AdpfConfig[" << name
810                        << "][ReportingRateLimitNs]'s Values";
811             adpfs_parsed.clear();
812             return adpfs_parsed;
813         }
814         reportingRate = adpfs[i]["ReportingRateLimitNs"].asInt64();
815 
816         if (adpfs[i]["EarlyBoost_On"].empty() || !adpfs[i]["EarlyBoost_On"].isBool()) {
817             LOG(ERROR) << "Failed to read AdpfConfig[" << name << "][EarlyBoost_On]'s Values";
818             adpfs_parsed.clear();
819             return adpfs_parsed;
820         }
821         earlyBoostOn = adpfs[i]["EarlyBoost_On"].asBool();
822 
823         if (adpfs[i]["EarlyBoost_TimeFactor"].empty() ||
824             !adpfs[i]["EarlyBoost_TimeFactor"].isDouble()) {
825             LOG(ERROR) << "Failed to read AdpfConfig[" << name
826                        << "][EarlyBoost_TimeFactor]'s Values";
827             adpfs_parsed.clear();
828             return adpfs_parsed;
829         }
830         earlyBoostTimeFactor = adpfs[i]["EarlyBoost_TimeFactor"].asDouble();
831 
832         if (adpfs[i]["TargetTimeFactor"].empty() || !adpfs[i]["TargetTimeFactor"].isDouble()) {
833             LOG(ERROR) << "Failed to read AdpfConfig[" << name << "][TargetTimeFactor]'s Values";
834             adpfs_parsed.clear();
835             return adpfs_parsed;
836         }
837         targetTimeFactor = adpfs[i]["TargetTimeFactor"].asDouble();
838 
839         adpfs_parsed.emplace_back(std::make_shared<AdpfConfig>(
840                 name, pidOn, pidPOver, pidPUnder, pidI, pidIInit, pidIHighLimit, pidILowLimit,
841                 pidDOver, pidDUnder, adpfUclamp, uclampMinInit, uclampMinHighLimit,
842                 uclampMinLowLimit, samplingWindowP, samplingWindowI, samplingWindowD, reportingRate,
843                 earlyBoostOn, earlyBoostTimeFactor, targetTimeFactor, staleTimeFactor));
844     }
845     LOG(INFO) << adpfs_parsed.size() << " AdpfConfigs parsed successfully";
846     return adpfs_parsed;
847 }
848 
GetAdpfProfile() const849 std::shared_ptr<AdpfConfig> HintManager::GetAdpfProfile() const {
850     if (adpfs_.empty())
851         return nullptr;
852     return adpfs_[adpf_index_];
853 }
854 
SetAdpfProfile(const std::string & profile_name)855 bool HintManager::SetAdpfProfile(const std::string &profile_name) {
856     for (std::size_t i = 0; i < adpfs_.size(); ++i) {
857         if (adpfs_[i]->mName == profile_name) {
858             adpf_index_ = i;
859             return true;
860         }
861     }
862     return false;
863 }
864 
865 }  // namespace perfmgr
866 }  // namespace android
867