• 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(DEBUG) << "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::unique_ptr<HintManager> HintManager::sInstance = nullptr;
285 
Reload(bool start)286 void 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     HintManager::GetFromJSON(config_path, start);
299     if (!sInstance) {
300         LOG(FATAL) << "Invalid config: " << config_path;
301     }
302 }
303 
GetInstance()304 HintManager *HintManager::GetInstance() {
305     if (sInstance == nullptr) {
306         HintManager::Reload(false);
307     }
308     return sInstance.get();
309 }
310 
ParseGpuSysfsNode(const std::string & json_doc)311 static std::optional<std::string> ParseGpuSysfsNode(const std::string &json_doc) {
312     Json::Value root;
313     Json::CharReaderBuilder builder;
314     std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
315     std::string errorMessage;
316     if (!reader->parse(&*json_doc.begin(), &*json_doc.end(), &root, &errorMessage)) {
317         LOG(ERROR) << "Failed to parse JSON config: " << errorMessage;
318         return {};
319     }
320 
321     if (root["GpuSysfsPath"].empty() || !root["GpuSysfsPath"].isString()) {
322         return {};
323     }
324     return {root["GpuSysfsPath"].asString()};
325 }
326 
GetFromJSON(const std::string & config_path,bool start)327 HintManager *HintManager::GetFromJSON(const std::string &config_path, bool start) {
328     std::string json_doc;
329 
330     if (!android::base::ReadFileToString(config_path, &json_doc)) {
331         LOG(ERROR) << "Failed to read JSON config from " << config_path;
332         return nullptr;
333     }
334 
335     std::vector<std::unique_ptr<Node>> nodes = ParseNodes(json_doc);
336     if (nodes.empty()) {
337         LOG(ERROR) << "Failed to parse Nodes section from " << config_path;
338         return nullptr;
339     }
340     std::vector<std::shared_ptr<AdpfConfig>> adpfs = HintManager::ParseAdpfConfigs(json_doc);
341     if (adpfs.empty()) {
342         LOG(INFO) << "No AdpfConfig section in the " << config_path;
343     }
344 
345     std::unordered_map<std::string, Hint> actions = HintManager::ParseActions(json_doc, nodes);
346 
347     if (actions.empty()) {
348         LOG(ERROR) << "Failed to parse Actions section from " << config_path;
349         return nullptr;
350     }
351 
352     auto const gpu_sysfs_node = ParseGpuSysfsNode(json_doc);
353 
354     sp<NodeLooperThread> nm = new NodeLooperThread(std::move(nodes));
355     sInstance = std::make_unique<HintManager>(std::move(nm), actions, adpfs, gpu_sysfs_node);
356 
357     if (!HintManager::InitHintStatus(sInstance)) {
358         LOG(ERROR) << "Failed to initialize hint status";
359         return nullptr;
360     }
361 
362     LOG(INFO) << "Initialized HintManager from JSON config: " << config_path;
363 
364     if (start) {
365         sInstance->Start();
366     }
367 
368     return HintManager::GetInstance();
369 }
370 
ParseNodes(const std::string & json_doc)371 std::vector<std::unique_ptr<Node>> HintManager::ParseNodes(
372     const std::string& json_doc) {
373     // function starts
374     std::vector<std::unique_ptr<Node>> nodes_parsed;
375     std::set<std::string> nodes_name_parsed;
376     std::set<std::string> nodes_path_parsed;
377     Json::Value root;
378     Json::CharReaderBuilder builder;
379     std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
380     std::string errorMessage;
381 
382     if (!reader->parse(&*json_doc.begin(), &*json_doc.end(), &root, &errorMessage)) {
383         LOG(ERROR) << "Failed to parse JSON config: " << errorMessage;
384         return nodes_parsed;
385     }
386 
387     Json::Value nodes = root["Nodes"];
388     for (Json::Value::ArrayIndex i = 0; i < nodes.size(); ++i) {
389         std::string name = nodes[i]["Name"].asString();
390         LOG(VERBOSE) << "Node[" << i << "]'s Name: " << name;
391         if (name.empty()) {
392             LOG(ERROR) << "Failed to read "
393                        << "Node[" << i << "]'s Name";
394             nodes_parsed.clear();
395             return nodes_parsed;
396         }
397 
398         auto result = nodes_name_parsed.insert(name);
399         if (!result.second) {
400             LOG(ERROR) << "Duplicate Node[" << i << "]'s Name";
401             nodes_parsed.clear();
402             return nodes_parsed;
403         }
404 
405         std::string path = nodes[i]["Path"].asString();
406         LOG(VERBOSE) << "Node[" << i << "]'s Path: " << path;
407         if (path.empty()) {
408             LOG(ERROR) << "Failed to read "
409                        << "Node[" << i << "]'s Path";
410             nodes_parsed.clear();
411             return nodes_parsed;
412         }
413 
414         result = nodes_path_parsed.insert(path);
415         if (!result.second) {
416             LOG(ERROR) << "Duplicate Node[" << i << "]'s Path";
417             nodes_parsed.clear();
418             return nodes_parsed;
419         }
420 
421         bool is_file = true;
422         std::string node_type = nodes[i]["Type"].asString();
423         LOG(VERBOSE) << "Node[" << i << "]'s Type: " << node_type;
424         if (node_type.empty()) {
425             LOG(VERBOSE) << "Failed to read "
426                          << "Node[" << i << "]'s Type, set to 'File' as default";
427         } else if (node_type == "File") {
428             is_file = true;
429         } else if (node_type == "Property") {
430             is_file = false;
431         } else {
432             LOG(ERROR) << "Invalid Node[" << i
433                        << "]'s Type: only File and Property supported.";
434             nodes_parsed.clear();
435             return nodes_parsed;
436         }
437 
438         std::vector<RequestGroup> values_parsed;
439         std::set<std::string> values_set_parsed;
440         Json::Value values = nodes[i]["Values"];
441         for (Json::Value::ArrayIndex j = 0; j < values.size(); ++j) {
442             std::string value = values[j].asString();
443             LOG(VERBOSE) << "Node[" << i << "]'s Value[" << j << "]: " << value;
444             auto result = values_set_parsed.insert(value);
445             if (!result.second) {
446                 LOG(ERROR) << "Duplicate value parsed in Node[" << i
447                            << "]'s Value[" << j << "]";
448                 nodes_parsed.clear();
449                 return nodes_parsed;
450             }
451             if (is_file && value.empty()) {
452                 LOG(ERROR) << "Failed to read Node[" << i << "]'s Value[" << j
453                            << "]";
454                 nodes_parsed.clear();
455                 return nodes_parsed;
456             }
457             values_parsed.emplace_back(value);
458         }
459         if (values_parsed.size() < 1) {
460             LOG(ERROR) << "Failed to read Node[" << i << "]'s Values";
461             nodes_parsed.clear();
462             return nodes_parsed;
463         }
464 
465         Json::UInt64 default_index = values_parsed.size() - 1;
466         if (nodes[i]["DefaultIndex"].empty() ||
467             !nodes[i]["DefaultIndex"].isUInt64()) {
468             LOG(INFO) << "Failed to read Node[" << i
469                       << "]'s DefaultIndex, set to last index: "
470                       << default_index;
471         } else {
472             default_index = nodes[i]["DefaultIndex"].asUInt64();
473         }
474         if (default_index > values_parsed.size() - 1) {
475             default_index = values_parsed.size() - 1;
476             LOG(ERROR) << "Node[" << i
477                        << "]'s DefaultIndex out of bound, max value index: "
478                        << default_index;
479             nodes_parsed.clear();
480             return nodes_parsed;
481         }
482         LOG(VERBOSE) << "Node[" << i << "]'s DefaultIndex: " << default_index;
483 
484         bool reset = false;
485         if (nodes[i]["ResetOnInit"].empty() ||
486             !nodes[i]["ResetOnInit"].isBool()) {
487             LOG(INFO) << "Failed to read Node[" << i
488                       << "]'s ResetOnInit, set to 'false'";
489         } else {
490             reset = nodes[i]["ResetOnInit"].asBool();
491         }
492         LOG(VERBOSE) << "Node[" << i << "]'s ResetOnInit: " << std::boolalpha
493                      << reset << std::noboolalpha;
494 
495         if (is_file) {
496             bool truncate = android::base::GetBoolProperty(kPowerHalTruncateProp, true);
497             if (nodes[i]["Truncate"].empty() || !nodes[i]["Truncate"].isBool()) {
498                 LOG(INFO) << "Failed to read Node[" << i << "]'s Truncate, set to 'true'";
499             } else {
500                 truncate = nodes[i]["Truncate"].asBool();
501             }
502             LOG(VERBOSE) << "Node[" << i << "]'s Truncate: " << std::boolalpha << truncate
503                          << std::noboolalpha;
504 
505             bool hold_fd = false;
506             if (nodes[i]["HoldFd"].empty() || !nodes[i]["HoldFd"].isBool()) {
507                 LOG(INFO) << "Failed to read Node[" << i
508                           << "]'s HoldFd, set to 'false'";
509             } else {
510                 hold_fd = nodes[i]["HoldFd"].asBool();
511             }
512             LOG(VERBOSE) << "Node[" << i << "]'s HoldFd: " << std::boolalpha
513                          << hold_fd << std::noboolalpha;
514 
515             bool write_only = false;
516             if (nodes[i]["WriteOnly"].empty() || !nodes[i]["WriteOnly"].isBool()) {
517                 LOG(INFO) << "Failed to read Node[" << i
518                           << "]'s WriteOnly, set to 'false'";
519             } else {
520                 write_only = nodes[i]["WriteOnly"].asBool();
521             }
522             LOG(VERBOSE) << "Node[" << i << "]'s WriteOnly: " << std::boolalpha
523                          << write_only << std::noboolalpha;
524 
525             nodes_parsed.emplace_back(std::make_unique<FileNode>(
526                     name, path, values_parsed, static_cast<std::size_t>(default_index), reset,
527                     truncate, hold_fd, write_only));
528         } else {
529             nodes_parsed.emplace_back(std::make_unique<PropertyNode>(
530                 name, path, values_parsed,
531                 static_cast<std::size_t>(default_index), reset));
532         }
533     }
534     LOG(INFO) << nodes_parsed.size() << " Nodes parsed successfully";
535     return nodes_parsed;
536 }
537 
ParseActions(const std::string & json_doc,const std::vector<std::unique_ptr<Node>> & nodes)538 std::unordered_map<std::string, Hint> HintManager::ParseActions(
539         const std::string &json_doc, const std::vector<std::unique_ptr<Node>> &nodes) {
540     // function starts
541     std::unordered_map<std::string, Hint> actions_parsed;
542     Json::Value root;
543     Json::CharReaderBuilder builder;
544     std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
545     std::string errorMessage;
546 
547     if (!reader->parse(&*json_doc.begin(), &*json_doc.end(), &root, &errorMessage)) {
548         LOG(ERROR) << "Failed to parse JSON config";
549         return actions_parsed;
550     }
551 
552     Json::Value actions = root["Actions"];
553     std::size_t total_parsed = 0;
554 
555     std::map<std::string, std::size_t> nodes_index;
556     for (std::size_t i = 0; i < nodes.size(); ++i) {
557         nodes_index[nodes[i]->GetName()] = i;
558     }
559 
560     for (Json::Value::ArrayIndex i = 0; i < actions.size(); ++i) {
561         const std::string& hint_type = actions[i]["PowerHint"].asString();
562         LOG(VERBOSE) << "Action[" << i << "]'s PowerHint: " << hint_type;
563         if (hint_type.empty()) {
564             LOG(ERROR) << "Failed to read "
565                        << "Action[" << i << "]'s PowerHint";
566             actions_parsed.clear();
567             return actions_parsed;
568         }
569 
570         HintActionType action_type = HintActionType::Node;
571         std::string type_string = actions[i]["Type"].asString();
572         std::string enable_property = actions[i]["EnableProperty"].asString();
573         LOG(VERBOSE) << "Action[" << i << "]'s Type: " << type_string;
574         if (type_string.empty()) {
575             LOG(VERBOSE) << "Failed to read "
576                          << "Action[" << i << "]'s Type, set to 'Node' as default";
577         } else if (type_string == "DoHint") {
578             action_type = HintActionType::DoHint;
579         } else if (type_string == "EndHint") {
580             action_type = HintActionType::EndHint;
581         } else if (type_string == "MaskHint") {
582             action_type = HintActionType::MaskHint;
583         } else {
584             LOG(ERROR) << "Invalid Action[" << i << "]'s Type: " << type_string;
585             actions_parsed.clear();
586             return actions_parsed;
587         }
588         if (action_type == HintActionType::Node) {
589             std::string node_name = actions[i]["Node"].asString();
590             LOG(VERBOSE) << "Action[" << i << "]'s Node: " << node_name;
591             std::size_t node_index;
592 
593             if (nodes_index.find(node_name) == nodes_index.end()) {
594                 LOG(ERROR) << "Failed to find "
595                            << "Action[" << i << "]'s Node from Nodes section: [" << node_name
596                            << "]";
597                 actions_parsed.clear();
598                 return actions_parsed;
599             }
600             node_index = nodes_index[node_name];
601 
602             std::string value_name = actions[i]["Value"].asString();
603             LOG(VERBOSE) << "Action[" << i << "]'s Value: " << value_name;
604             std::size_t value_index = 0;
605 
606             if (!nodes[node_index]->GetValueIndex(value_name, &value_index)) {
607                 LOG(ERROR) << "Failed to read Action[" << i << "]'s Value";
608                 LOG(ERROR) << "Action[" << i << "]'s Value " << value_name
609                            << " is not defined in Node[" << node_name << "]";
610                 actions_parsed.clear();
611                 return actions_parsed;
612             }
613             LOG(VERBOSE) << "Action[" << i << "]'s ValueIndex: " << value_index;
614 
615             Json::UInt64 duration = 0;
616             if (actions[i]["Duration"].empty() || !actions[i]["Duration"].isUInt64()) {
617                 LOG(ERROR) << "Failed to read Action[" << i << "]'s Duration";
618                 actions_parsed.clear();
619                 return actions_parsed;
620             } else {
621                 duration = actions[i]["Duration"].asUInt64();
622             }
623             LOG(VERBOSE) << "Action[" << i << "]'s Duration: " << duration;
624 
625             for (const auto &action : actions_parsed[hint_type].node_actions) {
626                 if (action.node_index == node_index) {
627                     LOG(ERROR)
628                         << "Action[" << i
629                         << "]'s NodeIndex is duplicated with another Action";
630                     actions_parsed.clear();
631                     return actions_parsed;
632                 }
633             }
634             actions_parsed[hint_type].node_actions.emplace_back(
635                     node_index, value_index, std::chrono::milliseconds(duration), enable_property);
636 
637         } else {
638             const std::string &hint_value = actions[i]["Value"].asString();
639             LOG(VERBOSE) << "Action[" << i << "]'s Value: " << hint_value;
640             if (hint_value.empty()) {
641                 LOG(ERROR) << "Failed to read "
642                            << "Action[" << i << "]'s Value";
643                 actions_parsed.clear();
644                 return actions_parsed;
645             }
646             actions_parsed[hint_type].hint_actions.emplace_back(action_type, hint_value,
647                                                                 enable_property);
648         }
649 
650         ++total_parsed;
651     }
652 
653     LOG(INFO) << total_parsed << " actions parsed successfully";
654 
655     for (const auto& action : actions_parsed) {
656         LOG(INFO) << "PowerHint " << action.first << " has " << action.second.node_actions.size()
657                   << " node actions"
658                   << ", and " << action.second.hint_actions.size() << " hint actions parsed";
659     }
660 
661     return actions_parsed;
662 }
663 
664 #define ADPF_PARSE(VARIABLE, ENTRY, TYPE)                                                        \
665     static_assert(std::is_same<decltype(adpfs[i][ENTRY].as##TYPE()), decltype(VARIABLE)>::value, \
666                   "Parser type mismatch");                                                       \
667     if (adpfs[i][ENTRY].empty() || !adpfs[i][ENTRY].is##TYPE()) {                                \
668         LOG(ERROR) << "Failed to read AdpfConfig[" << name << "][" ENTRY "]'s Values";           \
669         adpfs_parsed.clear();                                                                    \
670         return adpfs_parsed;                                                                     \
671     }                                                                                            \
672     VARIABLE = adpfs[i][ENTRY].as##TYPE()
673 
674 #define ADPF_PARSE_OPTIONAL(VARIABLE, ENTRY, TYPE)                     \
675     static_assert(std::is_same<decltype(adpfs[i][ENTRY].as##TYPE()),   \
676                                decltype(VARIABLE)::value_type>::value, \
677                   "Parser type mismatch");                             \
678     if (!adpfs[i][ENTRY].empty() && adpfs[i][ENTRY].is##TYPE()) {      \
679         VARIABLE = adpfs[i][ENTRY].as##TYPE();                         \
680     }
681 
ParseAdpfConfigs(const std::string & json_doc)682 std::vector<std::shared_ptr<AdpfConfig>> HintManager::ParseAdpfConfigs(
683         const std::string &json_doc) {
684     // function starts
685     bool pidOn;
686     double pidPOver;
687     double pidPUnder;
688     double pidI;
689     double pidDOver;
690     double pidDUnder;
691     int64_t pidIInit;
692     int64_t pidIHighLimit;
693     int64_t pidILowLimit;
694     bool adpfUclamp;
695     uint32_t uclampMinInit;
696     uint32_t uclampMinHighLimit;
697     uint32_t uclampMinLowLimit;
698     uint64_t samplingWindowP;
699     uint64_t samplingWindowI;
700     uint64_t samplingWindowD;
701     double staleTimeFactor;
702     uint64_t reportingRate;
703     double targetTimeFactor;
704 
705     std::vector<std::shared_ptr<AdpfConfig>> adpfs_parsed;
706     std::set<std::string> name_parsed;
707     Json::Value root;
708     Json::CharReaderBuilder builder;
709     std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
710     std::string errorMessage;
711     if (!reader->parse(&*json_doc.begin(), &*json_doc.end(), &root, &errorMessage)) {
712         LOG(ERROR) << "Failed to parse JSON config: " << errorMessage;
713         return adpfs_parsed;
714     }
715     Json::Value adpfs = root["AdpfConfig"];
716     for (Json::Value::ArrayIndex i = 0; i < adpfs.size(); ++i) {
717         std::optional<bool> gpuBoost;
718         std::optional<uint64_t> gpuBoostCapacityMax;
719         uint64_t gpuCapacityLoadUpHeadroom = 0;
720         std::string name = adpfs[i]["Name"].asString();
721         LOG(VERBOSE) << "AdpfConfig[" << i << "]'s Name: " << name;
722         if (name.empty()) {
723             LOG(ERROR) << "Failed to read "
724                        << "AdpfConfig[" << i << "]'s Name";
725             adpfs_parsed.clear();
726             return adpfs_parsed;
727         }
728         auto result = name_parsed.insert(name);
729         if (!result.second) {
730             LOG(ERROR) << "Duplicate AdpfConfig[" << i << "]'s Name";
731             adpfs_parsed.clear();
732             return adpfs_parsed;
733         }
734 
735         // heuristic boost configs
736         std::optional<bool> heuristicBoostOn;
737         std::optional<uint32_t> hBoostOnMissedCycles;
738         std::optional<double> hBoostOffMaxAvgRatio;
739         std::optional<uint32_t> hBoostOffMissedCycles;
740         std::optional<double> hBoostPidPuFactor;
741         std::optional<uint32_t> hBoostUclampMin;
742         std::optional<double> jankCheckTimeFactor;
743         std::optional<uint32_t> lowFrameRateThreshold;
744         std::optional<uint32_t> maxRecordsNum;
745 
746         std::optional<uint32_t> uclampMinLoadUp;
747         std::optional<uint32_t> uclampMinLoadReset;
748         std::optional<int32_t> uclampMaxEfficientBase;
749         std::optional<int32_t> uclampMaxEfficientOffset;
750 
751         ADPF_PARSE(pidOn, "PID_On", Bool);
752         ADPF_PARSE(pidPOver, "PID_Po", Double);
753         ADPF_PARSE(pidPUnder, "PID_Pu", Double);
754         ADPF_PARSE(pidI, "PID_I", Double);
755         ADPF_PARSE(pidIInit, "PID_I_Init", Int64);
756         ADPF_PARSE(pidIHighLimit, "PID_I_High", Int64);
757         ADPF_PARSE(pidILowLimit, "PID_I_Low", Int64);
758         ADPF_PARSE(pidDOver, "PID_Do", Double);
759         ADPF_PARSE(pidDUnder, "PID_Du", Double);
760         ADPF_PARSE(adpfUclamp, "UclampMin_On", Bool);
761         ADPF_PARSE(uclampMinInit, "UclampMin_Init", UInt);
762         ADPF_PARSE_OPTIONAL(uclampMinLoadUp, "UclampMin_LoadUp", UInt);
763         ADPF_PARSE_OPTIONAL(uclampMinLoadReset, "UclampMin_LoadReset", UInt);
764         ADPF_PARSE(uclampMinHighLimit, "UclampMin_High", UInt);
765         ADPF_PARSE(uclampMinLowLimit, "UclampMin_Low", UInt);
766         ADPF_PARSE(samplingWindowP, "SamplingWindow_P", UInt64);
767         ADPF_PARSE(samplingWindowI, "SamplingWindow_I", UInt64);
768         ADPF_PARSE(samplingWindowD, "SamplingWindow_D", UInt64);
769         ADPF_PARSE(staleTimeFactor, "StaleTimeFactor", Double);
770         ADPF_PARSE(reportingRate, "ReportingRateLimitNs", UInt64);
771         ADPF_PARSE(targetTimeFactor, "TargetTimeFactor", Double);
772         ADPF_PARSE_OPTIONAL(heuristicBoostOn, "HeuristicBoost_On", Bool);
773         ADPF_PARSE_OPTIONAL(hBoostOnMissedCycles, "HBoostOnMissedCycles", UInt);
774         ADPF_PARSE_OPTIONAL(hBoostOffMaxAvgRatio, "HBoostOffMaxAvgRatio", Double);
775         ADPF_PARSE_OPTIONAL(hBoostOffMissedCycles, "HBoostOffMissedCycles", UInt);
776         ADPF_PARSE_OPTIONAL(hBoostPidPuFactor, "HBoostPidPuFactor", Double);
777         ADPF_PARSE_OPTIONAL(hBoostUclampMin, "HBoostUclampMin", UInt);
778         ADPF_PARSE_OPTIONAL(jankCheckTimeFactor, "JankCheckTimeFactor", Double);
779         ADPF_PARSE_OPTIONAL(lowFrameRateThreshold, "LowFrameRateThreshold", UInt);
780         ADPF_PARSE_OPTIONAL(maxRecordsNum, "MaxRecordsNum", UInt);
781         ADPF_PARSE_OPTIONAL(uclampMaxEfficientBase, "UclampMax_EfficientBase", Int);
782         ADPF_PARSE_OPTIONAL(uclampMaxEfficientOffset, "UclampMax_EfficientOffset", Int);
783 
784         if (!adpfs[i]["GpuBoost"].empty() && adpfs[i]["GpuBoost"].isBool()) {
785             gpuBoost = adpfs[i]["GpuBoost"].asBool();
786         }
787         if (!adpfs[i]["GpuCapacityBoostMax"].empty() &&
788             adpfs[i]["GpuCapacityBoostMax"].isUInt64()) {
789             gpuBoostCapacityMax = adpfs[i]["GpuCapacityBoostMax"].asUInt64();
790         }
791         if (!adpfs[i]["GpuCapacityLoadUpHeadroom"].empty() &&
792             adpfs[i]["GpuCapacityLoadUpHeadroom"].isUInt64()) {
793             gpuCapacityLoadUpHeadroom = adpfs[i]["GpuCapacityLoadUpHeadroom"].asUInt64();
794         }
795 
796         // Check all the heuristic configurations are there if heuristic boost is going to
797         // be used.
798         if (heuristicBoostOn.has_value()) {
799             if (!hBoostOnMissedCycles.has_value() || !hBoostOffMaxAvgRatio.has_value() ||
800                 !hBoostOffMissedCycles.has_value() || !hBoostPidPuFactor.has_value() ||
801                 !hBoostUclampMin.has_value() || !jankCheckTimeFactor.has_value() ||
802                 !lowFrameRateThreshold.has_value() || !maxRecordsNum.has_value()) {
803                 LOG(ERROR) << "Part of the heuristic boost configurations are missing!";
804                 adpfs_parsed.clear();
805                 return adpfs_parsed;
806             }
807         }
808 
809         if (uclampMaxEfficientBase.has_value() != uclampMaxEfficientBase.has_value()) {
810             LOG(ERROR) << "Part of the power efficiency configuration is missing!";
811             adpfs_parsed.clear();
812             return adpfs_parsed;
813         }
814 
815         if (!uclampMinLoadUp.has_value()) {
816             uclampMinLoadUp = uclampMinHighLimit;
817         }
818         if (!uclampMinLoadReset.has_value()) {
819             uclampMinLoadReset = uclampMinHighLimit;
820         }
821 
822         adpfs_parsed.emplace_back(std::make_shared<AdpfConfig>(
823                 name, pidOn, pidPOver, pidPUnder, pidI, pidIInit, pidIHighLimit, pidILowLimit,
824                 pidDOver, pidDUnder, adpfUclamp, uclampMinInit, uclampMinHighLimit,
825                 uclampMinLowLimit, samplingWindowP, samplingWindowI, samplingWindowD, reportingRate,
826                 targetTimeFactor, staleTimeFactor, gpuBoost, gpuBoostCapacityMax,
827                 gpuCapacityLoadUpHeadroom, heuristicBoostOn, hBoostOnMissedCycles,
828                 hBoostOffMaxAvgRatio, hBoostOffMissedCycles, hBoostPidPuFactor, hBoostUclampMin,
829                 jankCheckTimeFactor, lowFrameRateThreshold, maxRecordsNum, uclampMinLoadUp.value(),
830                 uclampMinLoadReset.value(), uclampMaxEfficientBase, uclampMaxEfficientOffset));
831     }
832     LOG(INFO) << adpfs_parsed.size() << " AdpfConfigs parsed successfully";
833     return adpfs_parsed;
834 }
835 
GetAdpfProfile() const836 std::shared_ptr<AdpfConfig> HintManager::GetAdpfProfile() const {
837     if (adpfs_.empty())
838         return nullptr;
839     return adpfs_[adpf_index_];
840 }
841 
SetAdpfProfile(const std::string & profile_name)842 bool HintManager::SetAdpfProfile(const std::string &profile_name) {
843     for (std::size_t i = 0; i < adpfs_.size(); ++i) {
844         if (adpfs_[i]->mName == profile_name) {
845             adpf_index_ = i;
846             return true;
847         }
848     }
849     return false;
850 }
851 
IsAdpfProfileSupported(const std::string & profile_name) const852 bool HintManager::IsAdpfProfileSupported(const std::string &profile_name) const {
853     for (std::size_t i = 0; i < adpfs_.size(); ++i) {
854         if (adpfs_[i]->mName == profile_name) {
855             return true;
856         }
857     }
858     return false;
859 }
860 
gpu_sysfs_config_path() const861 std::optional<std::string> HintManager::gpu_sysfs_config_path() const {
862     return gpu_sysfs_config_path_;
863 }
864 
865 }  // namespace perfmgr
866 }  // namespace android
867