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 #include <string>
34 
35 #include "perfmgr/EventNode.h"
36 #include "perfmgr/FileNode.h"
37 #include "perfmgr/PropertyNode.h"
38 
39 namespace android {
40 namespace perfmgr {
41 
42 namespace {
43 constexpr std::chrono::milliseconds kMilliSecondZero = std::chrono::milliseconds(0);
44 constexpr std::chrono::steady_clock::time_point kTimePointMax =
45         std::chrono::steady_clock::time_point::max();
46 }  // namespace
47 
48 using ::android::base::GetProperty;
49 using ::android::base::StringPrintf;
50 
51 constexpr char kPowerHalTruncateProp[] = "vendor.powerhal.truncate";
52 constexpr std::string_view kConfigDebugPathProperty("vendor.powerhal.config.debug");
53 constexpr std::string_view kConfigProperty("vendor.powerhal.config");
54 constexpr std::string_view kConfigDefaultFileName("powerhint.json");
55 constexpr char kAdpfEventNodePath[] = "<AdpfConfig>:";
56 
ValidateHint(const std::string & hint_type) const57 bool HintManager::ValidateHint(const std::string& hint_type) const {
58     if (nm_.get() == nullptr) {
59         LOG(ERROR) << "NodeLooperThread not present";
60         return false;
61     }
62     return IsHintSupported(hint_type);
63 }
64 
IsHintSupported(const std::string & hint_type) const65 bool HintManager::IsHintSupported(const std::string& hint_type) const {
66     if (actions_.find(hint_type) == actions_.end()) {
67         LOG(DEBUG) << "Hint type not present in actions: " << hint_type;
68         return false;
69     }
70     return true;
71 }
72 
IsHintEnabled(const std::string & hint_type) const73 bool HintManager::IsHintEnabled(const std::string &hint_type) const {
74     std::lock_guard<std::mutex> lock(actions_.at(hint_type).hint_lock);
75     return actions_.at(hint_type).mask_requesters.empty();
76 }
77 
InitHintStatus(const std::unique_ptr<HintManager> & hm)78 bool HintManager::InitHintStatus(const std::unique_ptr<HintManager> &hm) {
79     if (hm.get() == nullptr) {
80         return false;
81     }
82     for (auto &a : hm->actions_) {
83         // timeout_ms equaling kMilliSecondZero means forever until cancelling.
84         // As a result, if there's one NodeAction has timeout_ms of 0, we will store
85         // 0 instead of max. Also node actions could be empty, set to 0 in that case.
86         std::chrono::milliseconds timeout = kMilliSecondZero;
87         if (a.second.node_actions.size()) {
88             auto [min, max] =
89                     std::minmax_element(a.second.node_actions.begin(), a.second.node_actions.end(),
90                                         [](const auto act1, const auto act2) {
91                                             return act1.timeout_ms < act2.timeout_ms;
92                                         });
93             timeout = min->timeout_ms == kMilliSecondZero ? kMilliSecondZero : max->timeout_ms;
94         }
95         a.second.status.reset(new HintStatus(timeout));
96     }
97     return true;
98 }
99 
DoHintStatus(const std::string & hint_type,std::chrono::milliseconds timeout_ms)100 void HintManager::DoHintStatus(const std::string &hint_type, std::chrono::milliseconds timeout_ms) {
101     std::lock_guard<std::mutex> lock(actions_.at(hint_type).hint_lock);
102     actions_.at(hint_type).status->stats.count.fetch_add(1);
103     auto now = std::chrono::steady_clock::now();
104     ATRACE_INT(("H:" + hint_type).c_str(), (timeout_ms == kMilliSecondZero)
105                                                    ? std::numeric_limits<int>::max()
106                                                    : timeout_ms.count());
107     if (now > actions_.at(hint_type).status->end_time) {
108         actions_.at(hint_type).status->stats.duration_ms.fetch_add(
109                 std::chrono::duration_cast<std::chrono::milliseconds>(
110                         actions_.at(hint_type).status->end_time -
111                         actions_.at(hint_type).status->start_time)
112                         .count());
113         actions_.at(hint_type).status->start_time = now;
114     }
115     actions_.at(hint_type).status->end_time =
116             (timeout_ms == kMilliSecondZero) ? kTimePointMax : now + timeout_ms;
117 }
118 
EndHintStatus(const std::string & hint_type)119 void HintManager::EndHintStatus(const std::string &hint_type) {
120     std::lock_guard<std::mutex> lock(actions_.at(hint_type).hint_lock);
121     // Update HintStats if the hint ends earlier than expected end_time
122     auto now = std::chrono::steady_clock::now();
123     ATRACE_INT(("H:" + hint_type).c_str(), 0);
124     if (now < actions_.at(hint_type).status->end_time) {
125         actions_.at(hint_type).status->stats.duration_ms.fetch_add(
126                 std::chrono::duration_cast<std::chrono::milliseconds>(
127                         now - actions_.at(hint_type).status->start_time)
128                         .count());
129         actions_.at(hint_type).status->end_time = now;
130     }
131 }
132 
DoHintAction(const std::string & hint_type)133 void HintManager::DoHintAction(const std::string &hint_type) {
134     for (auto &action : actions_.at(hint_type).hint_actions) {
135         if (!action.enable_property.empty() &&
136             !android::base::GetBoolProperty(action.enable_property, true)) {
137             // Disabled action based on its control property
138             continue;
139         }
140         switch (action.type) {
141             case HintActionType::DoHint:
142                 DoHint(action.value);
143                 break;
144             case HintActionType::EndHint:
145                 EndHint(action.value);
146                 break;
147             case HintActionType::MaskHint:
148                 if (actions_.find(action.value) == actions_.end()) {
149                     LOG(ERROR) << "Failed to find " << action.value << " action";
150                 } else {
151                     std::lock_guard<std::mutex> lock(actions_.at(hint_type).hint_lock);
152                     actions_.at(action.value).mask_requesters.insert(hint_type);
153                 }
154                 break;
155             default:
156                 // should not reach here
157                 LOG(ERROR) << "Invalid "
158                            << static_cast<std::underlying_type<HintActionType>::type>(action.type)
159                            << " type";
160         }
161     }
162 }
163 
EndHintAction(const std::string & hint_type)164 void HintManager::EndHintAction(const std::string &hint_type) {
165     for (auto &action : actions_.at(hint_type).hint_actions) {
166         if (action.type == HintActionType::MaskHint &&
167             actions_.find(action.value) != actions_.end()) {
168             std::lock_guard<std::mutex> lock(actions_.at(hint_type).hint_lock);
169             actions_.at(action.value).mask_requesters.erase(hint_type);
170         }
171     }
172 }
173 
DoHint(const std::string & hint_type)174 bool HintManager::DoHint(const std::string& hint_type) {
175     LOG(VERBOSE) << "Do Powerhint: " << hint_type;
176     if (!ValidateHint(hint_type) || !IsHintEnabled(hint_type) ||
177         !nm_->Request(actions_.at(hint_type).node_actions, hint_type)) {
178         return false;
179     }
180     DoHintStatus(hint_type, actions_.at(hint_type).status->max_timeout);
181     DoHintAction(hint_type);
182     return true;
183 }
184 
DoHint(const std::string & hint_type,std::chrono::milliseconds timeout_ms_override)185 bool HintManager::DoHint(const std::string& hint_type,
186                          std::chrono::milliseconds timeout_ms_override) {
187     LOG(VERBOSE) << "Do Powerhint: " << hint_type << " for "
188                  << timeout_ms_override.count() << "ms";
189     if (!ValidateHint(hint_type) || !IsHintEnabled(hint_type)) {
190         return false;
191     }
192     std::vector<NodeAction> actions_override = actions_.at(hint_type).node_actions;
193     for (auto& action : actions_override) {
194         action.timeout_ms = timeout_ms_override;
195     }
196     if (!nm_->Request(actions_override, hint_type)) {
197         return false;
198     }
199     DoHintStatus(hint_type, timeout_ms_override);
200     DoHintAction(hint_type);
201     return true;
202 }
203 
EndHint(const std::string & hint_type)204 bool HintManager::EndHint(const std::string& hint_type) {
205     LOG(VERBOSE) << "End Powerhint: " << hint_type;
206     if (!ValidateHint(hint_type) || !nm_->Cancel(actions_.at(hint_type).node_actions, hint_type)) {
207         return false;
208     }
209     EndHintStatus(hint_type);
210     EndHintAction(hint_type);
211     return true;
212 }
213 
IsRunning() const214 bool HintManager::IsRunning() const {
215     return (nm_.get() == nullptr) ? false : nm_->isRunning();
216 }
217 
GetHints() const218 std::vector<std::string> HintManager::GetHints() const {
219     std::vector<std::string> hints;
220     for (auto const& action : actions_) {
221         hints.push_back(action.first);
222     }
223     return hints;
224 }
225 
GetHintStats(const std::string & hint_type) const226 HintStats HintManager::GetHintStats(const std::string &hint_type) const {
227     HintStats hint_stats;
228     if (ValidateHint(hint_type)) {
229         std::lock_guard<std::mutex> lock(actions_.at(hint_type).hint_lock);
230         hint_stats.count =
231                 actions_.at(hint_type).status->stats.count.load(std::memory_order_relaxed);
232         hint_stats.duration_ms =
233                 actions_.at(hint_type).status->stats.duration_ms.load(std::memory_order_relaxed);
234     }
235     return hint_stats;
236 }
237 
DumpToFd(int fd)238 void HintManager::DumpToFd(int fd) {
239     std::string header("========== Begin perfmgr nodes ==========\n");
240     if (!android::base::WriteStringToFd(header, fd)) {
241         LOG(ERROR) << "Failed to dump fd: " << fd;
242     }
243     nm_->DumpToFd(fd);
244     std::string footer("==========  End perfmgr nodes  ==========\n");
245     if (!android::base::WriteStringToFd(footer, fd)) {
246         LOG(ERROR) << "Failed to dump fd: " << fd;
247     }
248     header = "========== Begin perfmgr stats ==========\n"
249              "Hint Name\t"
250              "Counts\t"
251              "Duration\n";
252     if (!android::base::WriteStringToFd(header, fd)) {
253         LOG(ERROR) << "Failed to dump fd: " << fd;
254     }
255     std::string hint_stats_string;
256     std::vector<std::string> keys(GetHints());
257     std::sort(keys.begin(), keys.end());
258     for (const auto &ordered_key : keys) {
259         HintStats hint_stats(GetHintStats(ordered_key));
260         hint_stats_string += StringPrintf("%s\t%" PRIu32 "\t%" PRIu64 "\n", ordered_key.c_str(),
261                                           hint_stats.count, hint_stats.duration_ms);
262     }
263     if (!android::base::WriteStringToFd(hint_stats_string, fd)) {
264         LOG(ERROR) << "Failed to dump fd: " << fd;
265     }
266     footer = "==========  End perfmgr stats  ==========\n";
267     if (!android::base::WriteStringToFd(footer, fd)) {
268         LOG(ERROR) << "Failed to dump fd: " << fd;
269     }
270 
271     // Dump current ADPF profiles
272     if (IsAdpfSupported()) {
273         header = "========== ADPF Tag Profile begin ==========\n";
274         if (!android::base::WriteStringToFd(header, fd)) {
275             LOG(ERROR) << "Failed to dump fd: " << fd;
276         }
277 
278         header = "---- Default non-tagged adpf profile ----\n";
279         if (!android::base::WriteStringToFd(header, fd)) {
280             LOG(ERROR) << "Failed to dump fd: " << fd;
281         }
282         GetAdpfProfileFromDoHint()->dumpToFd(fd);
283 
284         for (const auto &tag_profile : tag_profile_map_) {
285             header = StringPrintf("---- Tagged ADPF Profile: %s ----\n", tag_profile.first.c_str());
286             if (!android::base::WriteStringToFd(header, fd)) {
287                 LOG(ERROR) << "Failed to dump fd: " << fd;
288             }
289             tag_profile.second->dumpToFd(fd);
290         }
291 
292         footer = "========== ADPF Tag Profile end ==========\n";
293         if (!android::base::WriteStringToFd(footer, fd)) {
294             LOG(ERROR) << "Failed to dump fd: " << fd;
295         }
296     } else {
297         header = "========== IsAdpfSupported: No ===========\n";
298         if (!android::base::WriteStringToFd(header, fd)) {
299             LOG(ERROR) << "Failed to dump fd: " << fd;
300         }
301     }
302     fsync(fd);
303 }
304 
Start()305 bool HintManager::Start() {
306     return nm_->Start();
307 }
308 
309 std::unique_ptr<HintManager> HintManager::sInstance = nullptr;
310 
Reload(bool start)311 void HintManager::Reload(bool start) {
312     std::string config_path = "/vendor/etc/";
313     if (android::base::GetBoolProperty(kConfigDebugPathProperty.data(), false)) {
314         config_path = "/data/vendor/etc/";
315         LOG(WARNING) << "Pixel Power HAL AIDL Service is using debug config from: " << config_path;
316     }
317     config_path.append(GetProperty(kConfigProperty.data(), kConfigDefaultFileName.data()));
318 
319     LOG(INFO) << "Pixel Power HAL AIDL Service with Extension is starting with config: "
320               << config_path;
321     // Reload and start the HintManager
322     HintManager::GetFromJSON(config_path, start);
323     if (!sInstance) {
324         LOG(FATAL) << "Invalid config: " << config_path;
325     }
326 }
327 
GetInstance()328 HintManager *HintManager::GetInstance() {
329     if (sInstance == nullptr) {
330         HintManager::Reload(false);
331     }
332     return sInstance.get();
333 }
334 
ParseGpuSysfsNode(const std::string & json_doc)335 static std::optional<std::string> ParseGpuSysfsNode(const std::string &json_doc) {
336     Json::Value root;
337     Json::CharReaderBuilder builder;
338     std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
339     std::string errorMessage;
340     if (!reader->parse(&*json_doc.begin(), &*json_doc.end(), &root, &errorMessage)) {
341         LOG(ERROR) << "Failed to parse JSON config: " << errorMessage;
342         return {};
343     }
344 
345     if (root["GpuSysfsPath"].empty() || !root["GpuSysfsPath"].isString()) {
346         return {};
347     }
348     return {root["GpuSysfsPath"].asString()};
349 }
350 
GetFromJSON(const std::string & config_path,bool start)351 HintManager *HintManager::GetFromJSON(const std::string &config_path, bool start) {
352     std::string json_doc;
353 
354     if (!android::base::ReadFileToString(config_path, &json_doc)) {
355         LOG(ERROR) << "Failed to read JSON config from " << config_path;
356         return nullptr;
357     }
358 
359     std::vector<std::unique_ptr<Node>> nodes = ParseNodes(json_doc);
360     if (nodes.empty()) {
361         LOG(ERROR) << "Failed to parse Nodes section from " << config_path;
362         return nullptr;
363     }
364     std::vector<std::shared_ptr<AdpfConfig>> adpfs = HintManager::ParseAdpfConfigs(json_doc);
365     if (adpfs.empty()) {
366         LOG(INFO) << "No AdpfConfig section in the " << config_path;
367     }
368 
369     std::unordered_map<std::string, Hint> actions = HintManager::ParseActions(json_doc, nodes);
370 
371     // Parse ADPF Event Node
372     std::unordered_map<std::string, std::shared_ptr<AdpfConfig>> tag_adpfs;
373     LOG(VERBOSE) << "Parse ADPF Hint Event Table from all nodes.";
374     for (std::size_t i = 0; i < nodes.size(); ++i) {
375         const std::string &node_name = nodes[i]->GetName();
376         const std::string &node_path = nodes[i]->GetPath();
377         if (node_path.starts_with(kAdpfEventNodePath)) {
378             std::string tag = node_path.substr(strlen(kAdpfEventNodePath));
379             std::size_t index = nodes[i]->GetDefaultIndex();
380             std::string profile_name = nodes[i]->GetValues()[index];
381             for (std::size_t j = 0; j < adpfs.size(); ++j) {
382                 if (adpfs[j]->mName == profile_name) {
383                     tag_adpfs[tag] = adpfs[j];
384                     LOG(INFO) << "[" << tag << ":" << node_name << "] set to '" << profile_name
385                               << "'";
386                     break;
387                 }
388             }
389             if (!tag_adpfs[tag]) {
390                 tag_adpfs[tag] = adpfs[0];
391                 LOG(INFO) << "[" << tag << ":" << node_name << "] fallback to '" << adpfs[0]->mName
392                           << "'";
393             }
394         }
395     }
396 
397     if (actions.empty()) {
398         LOG(ERROR) << "Failed to parse Actions section from " << config_path;
399         return nullptr;
400     }
401 
402     auto const gpu_sysfs_node = ParseGpuSysfsNode(json_doc);
403 
404     sp<NodeLooperThread> nm = new NodeLooperThread(std::move(nodes));
405     sInstance =
406             std::make_unique<HintManager>(std::move(nm), actions, adpfs, tag_adpfs, gpu_sysfs_node);
407 
408     if (!HintManager::InitHintStatus(sInstance)) {
409         LOG(ERROR) << "Failed to initialize hint status";
410         return nullptr;
411     }
412 
413     LOG(INFO) << "Initialized HintManager from JSON config: " << config_path;
414 
415     if (start) {
416         sInstance->Start();
417     }
418 
419     return HintManager::GetInstance();
420 }
421 
ParseNodes(const std::string & json_doc)422 std::vector<std::unique_ptr<Node>> HintManager::ParseNodes(const std::string &json_doc) {
423     // function starts
424     std::vector<std::unique_ptr<Node>> nodes_parsed;
425     std::set<std::string> nodes_name_parsed;
426     std::set<std::string> nodes_path_parsed;
427     Json::Value root;
428     Json::CharReaderBuilder builder;
429     std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
430     std::string errorMessage;
431 
432     if (!reader->parse(&*json_doc.begin(), &*json_doc.end(), &root, &errorMessage)) {
433         LOG(ERROR) << "Failed to parse JSON config: " << errorMessage;
434         return nodes_parsed;
435     }
436 
437     Json::Value nodes = root["Nodes"];
438     for (Json::Value::ArrayIndex i = 0; i < nodes.size(); ++i) {
439         std::string name = nodes[i]["Name"].asString();
440         LOG(VERBOSE) << "Node[" << i << "]'s Name: " << name;
441         if (name.empty()) {
442             LOG(ERROR) << "Failed to read "
443                        << "Node[" << i << "]'s Name";
444             nodes_parsed.clear();
445             return nodes_parsed;
446         }
447 
448         auto result = nodes_name_parsed.insert(name);
449         if (!result.second) {
450             LOG(ERROR) << "Duplicate Node[" << i << "]'s Name";
451             nodes_parsed.clear();
452             return nodes_parsed;
453         }
454 
455         std::string path = nodes[i]["Path"].asString();
456         LOG(VERBOSE) << "Node[" << i << "]'s Path: " << path;
457         if (path.empty()) {
458             LOG(ERROR) << "Failed to read "
459                        << "Node[" << i << "]'s Path";
460             nodes_parsed.clear();
461             return nodes_parsed;
462         }
463 
464         result = nodes_path_parsed.insert(path);
465         if (!result.second) {
466             LOG(ERROR) << "Duplicate Node[" << i << "]'s Path";
467             nodes_parsed.clear();
468             return nodes_parsed;
469         }
470 
471         bool is_event_node = false;
472         bool is_file = false;
473         std::string node_type = nodes[i]["Type"].asString();
474         LOG(VERBOSE) << "Node[" << i << "]'s Type: " << node_type;
475         if (node_type.empty()) {
476             is_file = true;
477             LOG(VERBOSE) << "Failed to read "
478                          << "Node[" << i << "]'s Type, set to 'File' as default";
479         } else if (node_type == "Event") {
480             is_event_node = true;
481         } else if (node_type == "File") {
482             is_file = true;
483         } else if (node_type == "Property") {
484             is_file = false;
485         } else {
486             LOG(ERROR) << "Invalid Node[" << i
487                        << "]'s Type: only File and Property supported.";
488             nodes_parsed.clear();
489             return nodes_parsed;
490         }
491 
492         std::vector<RequestGroup> values_parsed;
493         std::set<std::string> values_set_parsed;
494         Json::Value values = nodes[i]["Values"];
495         for (Json::Value::ArrayIndex j = 0; j < values.size(); ++j) {
496             std::string value = values[j].asString();
497             LOG(VERBOSE) << "Node[" << i << "]'s Value[" << j << "]: " << value;
498             auto result = values_set_parsed.insert(value);
499             if (!result.second) {
500                 LOG(ERROR) << "Duplicate value parsed in Node[" << i
501                            << "]'s Value[" << j << "]";
502                 nodes_parsed.clear();
503                 return nodes_parsed;
504             }
505             if (is_file && value.empty()) {
506                 LOG(ERROR) << "Failed to read Node[" << i << "]'s Value[" << j
507                            << "]";
508                 nodes_parsed.clear();
509                 return nodes_parsed;
510             }
511             values_parsed.emplace_back(value);
512         }
513         if (values_parsed.size() < 1) {
514             LOG(ERROR) << "Failed to read Node[" << i << "]'s Values";
515             nodes_parsed.clear();
516             return nodes_parsed;
517         }
518 
519         Json::UInt64 default_index = values_parsed.size() - 1;
520         if (nodes[i]["DefaultIndex"].empty() ||
521             !nodes[i]["DefaultIndex"].isUInt64()) {
522             LOG(INFO) << "Failed to read Node[" << i
523                       << "]'s DefaultIndex, set to last index: "
524                       << default_index;
525         } else {
526             default_index = nodes[i]["DefaultIndex"].asUInt64();
527         }
528         if (default_index > values_parsed.size() - 1) {
529             default_index = values_parsed.size() - 1;
530             LOG(ERROR) << "Node[" << i
531                        << "]'s DefaultIndex out of bound, max value index: "
532                        << default_index;
533             nodes_parsed.clear();
534             return nodes_parsed;
535         }
536         LOG(VERBOSE) << "Node[" << i << "]'s DefaultIndex: " << default_index;
537 
538         bool reset = false;
539         if (nodes[i]["ResetOnInit"].empty() ||
540             !nodes[i]["ResetOnInit"].isBool()) {
541             LOG(INFO) << "Failed to read Node[" << i
542                       << "]'s ResetOnInit, set to 'false'";
543         } else {
544             reset = nodes[i]["ResetOnInit"].asBool();
545         }
546         LOG(VERBOSE) << "Node[" << i << "]'s ResetOnInit: " << std::boolalpha
547                      << reset << std::noboolalpha;
548 
549         if (is_event_node) {
550             auto update_callback = [](const std::string &name, const std::string &path,
551                                       const std::string &val) {
552                 HintManager::GetInstance()->OnNodeUpdate(name, path, val);
553             };
554             nodes_parsed.emplace_back(std::make_unique<EventNode>(
555                     name, path, values_parsed, static_cast<std::size_t>(default_index), reset,
556                     update_callback));
557         } else if (is_file) {
558             bool truncate = android::base::GetBoolProperty(kPowerHalTruncateProp, true);
559             if (nodes[i]["Truncate"].empty() || !nodes[i]["Truncate"].isBool()) {
560                 LOG(INFO) << "Failed to read Node[" << i << "]'s Truncate, set to 'true'";
561             } else {
562                 truncate = nodes[i]["Truncate"].asBool();
563             }
564             LOG(VERBOSE) << "Node[" << i << "]'s Truncate: " << std::boolalpha << truncate
565                          << std::noboolalpha;
566 
567             bool hold_fd = false;
568             if (nodes[i]["HoldFd"].empty() || !nodes[i]["HoldFd"].isBool()) {
569                 LOG(INFO) << "Failed to read Node[" << i
570                           << "]'s HoldFd, set to 'false'";
571             } else {
572                 hold_fd = nodes[i]["HoldFd"].asBool();
573             }
574             LOG(VERBOSE) << "Node[" << i << "]'s HoldFd: " << std::boolalpha
575                          << hold_fd << std::noboolalpha;
576 
577             bool write_only = false;
578             if (nodes[i]["WriteOnly"].empty() || !nodes[i]["WriteOnly"].isBool()) {
579                 LOG(INFO) << "Failed to read Node[" << i
580                           << "]'s WriteOnly, set to 'false'";
581             } else {
582                 write_only = nodes[i]["WriteOnly"].asBool();
583             }
584             LOG(VERBOSE) << "Node[" << i << "]'s WriteOnly: " << std::boolalpha
585                          << write_only << std::noboolalpha;
586 
587             nodes_parsed.emplace_back(std::make_unique<FileNode>(
588                     name, path, values_parsed, static_cast<std::size_t>(default_index), reset,
589                     truncate, hold_fd, write_only));
590         } else {
591             nodes_parsed.emplace_back(std::make_unique<PropertyNode>(
592                     name, path, values_parsed, static_cast<std::size_t>(default_index), reset));
593         }
594     }
595     LOG(INFO) << nodes_parsed.size() << " Nodes parsed successfully";
596     return nodes_parsed;
597 }
598 
ParseActions(const std::string & json_doc,const std::vector<std::unique_ptr<Node>> & nodes)599 std::unordered_map<std::string, Hint> HintManager::ParseActions(
600         const std::string &json_doc, const std::vector<std::unique_ptr<Node>> &nodes) {
601     // function starts
602     std::unordered_map<std::string, Hint> actions_parsed;
603     Json::Value root;
604     Json::CharReaderBuilder builder;
605     std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
606     std::string errorMessage;
607 
608     if (!reader->parse(&*json_doc.begin(), &*json_doc.end(), &root, &errorMessage)) {
609         LOG(ERROR) << "Failed to parse JSON config";
610         return actions_parsed;
611     }
612 
613     Json::Value actions = root["Actions"];
614     std::size_t total_parsed = 0;
615 
616     std::map<std::string, std::size_t> nodes_index;
617     for (std::size_t i = 0; i < nodes.size(); ++i) {
618         nodes_index[nodes[i]->GetName()] = i;
619     }
620 
621     for (Json::Value::ArrayIndex i = 0; i < actions.size(); ++i) {
622         const std::string& hint_type = actions[i]["PowerHint"].asString();
623         LOG(VERBOSE) << "Action[" << i << "]'s PowerHint: " << hint_type;
624         if (hint_type.empty()) {
625             LOG(ERROR) << "Failed to read "
626                        << "Action[" << i << "]'s PowerHint";
627             actions_parsed.clear();
628             return actions_parsed;
629         }
630 
631         HintActionType action_type = HintActionType::Node;
632         std::string type_string = actions[i]["Type"].asString();
633         std::string enable_property = actions[i]["EnableProperty"].asString();
634         LOG(VERBOSE) << "Action[" << i << "]'s Type: " << type_string;
635         if (type_string.empty()) {
636             LOG(VERBOSE) << "Failed to read "
637                          << "Action[" << i << "]'s Type, set to 'Node' as default";
638         } else if (type_string == "DoHint") {
639             action_type = HintActionType::DoHint;
640         } else if (type_string == "EndHint") {
641             action_type = HintActionType::EndHint;
642         } else if (type_string == "MaskHint") {
643             action_type = HintActionType::MaskHint;
644         } else {
645             LOG(ERROR) << "Invalid Action[" << i << "]'s Type: " << type_string;
646             actions_parsed.clear();
647             return actions_parsed;
648         }
649         if (action_type == HintActionType::Node) {
650             std::string node_name = actions[i]["Node"].asString();
651             LOG(VERBOSE) << "Action[" << i << "]'s Node: " << node_name;
652             std::size_t node_index;
653 
654             if (nodes_index.find(node_name) == nodes_index.end()) {
655                 LOG(ERROR) << "Failed to find "
656                            << "Action[" << i << "]'s Node from Nodes section: [" << node_name
657                            << "]";
658                 actions_parsed.clear();
659                 return actions_parsed;
660             }
661             node_index = nodes_index[node_name];
662 
663             std::string value_name = actions[i]["Value"].asString();
664             LOG(VERBOSE) << "Action[" << i << "]'s Value: " << value_name;
665             std::size_t value_index = 0;
666 
667             if (!nodes[node_index]->GetValueIndex(value_name, &value_index)) {
668                 LOG(ERROR) << "Failed to read Action[" << i << "]'s Value";
669                 LOG(ERROR) << "Action[" << i << "]'s Value " << value_name
670                            << " is not defined in Node[" << node_name << "]";
671                 actions_parsed.clear();
672                 return actions_parsed;
673             }
674             LOG(VERBOSE) << "Action[" << i << "]'s ValueIndex: " << value_index;
675 
676             Json::UInt64 duration = 0;
677             if (actions[i]["Duration"].empty() || !actions[i]["Duration"].isUInt64()) {
678                 LOG(ERROR) << "Failed to read Action[" << i << "]'s Duration";
679                 actions_parsed.clear();
680                 return actions_parsed;
681             } else {
682                 duration = actions[i]["Duration"].asUInt64();
683             }
684             LOG(VERBOSE) << "Action[" << i << "]'s Duration: " << duration;
685 
686             for (const auto &action : actions_parsed[hint_type].node_actions) {
687                 if (action.node_index == node_index) {
688                     LOG(ERROR)
689                         << "Action[" << i
690                         << "]'s NodeIndex is duplicated with another Action";
691                     actions_parsed.clear();
692                     return actions_parsed;
693                 }
694             }
695             actions_parsed[hint_type].node_actions.emplace_back(
696                     node_index, value_index, std::chrono::milliseconds(duration), enable_property);
697 
698         } else {
699             const std::string &hint_value = actions[i]["Value"].asString();
700             LOG(VERBOSE) << "Action[" << i << "]'s Value: " << hint_value;
701             if (hint_value.empty()) {
702                 LOG(ERROR) << "Failed to read "
703                            << "Action[" << i << "]'s Value";
704                 actions_parsed.clear();
705                 return actions_parsed;
706             }
707             actions_parsed[hint_type].hint_actions.emplace_back(action_type, hint_value,
708                                                                 enable_property);
709         }
710 
711         ++total_parsed;
712     }
713 
714     LOG(INFO) << total_parsed << " actions parsed successfully";
715 
716     for (const auto& action : actions_parsed) {
717         LOG(INFO) << "PowerHint " << action.first << " has " << action.second.node_actions.size()
718                   << " node actions"
719                   << ", and " << action.second.hint_actions.size() << " hint actions parsed";
720     }
721 
722     return actions_parsed;
723 }
724 
725 #define ADPF_PARSE(VARIABLE, ENTRY, TYPE)                                                        \
726     static_assert(std::is_same<decltype(adpfs[i][ENTRY].as##TYPE()), decltype(VARIABLE)>::value, \
727                   "Parser type mismatch");                                                       \
728     if (adpfs[i][ENTRY].empty() || !adpfs[i][ENTRY].is##TYPE()) {                                \
729         LOG(ERROR) << "Failed to read AdpfConfig[" << name << "][" ENTRY "]'s Values";           \
730         adpfs_parsed.clear();                                                                    \
731         return adpfs_parsed;                                                                     \
732     }                                                                                            \
733     VARIABLE = adpfs[i][ENTRY].as##TYPE()
734 
735 #define ADPF_PARSE_OPTIONAL(VARIABLE, ENTRY, TYPE)                     \
736     static_assert(std::is_same<decltype(adpfs[i][ENTRY].as##TYPE()),   \
737                                decltype(VARIABLE)::value_type>::value, \
738                   "Parser type mismatch");                             \
739     if (!adpfs[i][ENTRY].empty() && adpfs[i][ENTRY].is##TYPE()) {      \
740         VARIABLE = adpfs[i][ENTRY].as##TYPE();                         \
741     }
742 
ParseAdpfConfigs(const std::string & json_doc)743 std::vector<std::shared_ptr<AdpfConfig>> HintManager::ParseAdpfConfigs(
744         const std::string &json_doc) {
745     // function starts
746     bool pidOn;
747     double pidPOver;
748     double pidPUnder;
749     double pidI;
750     double pidDOver;
751     double pidDUnder;
752     int64_t pidIInit;
753     int64_t pidIHighLimit;
754     int64_t pidILowLimit;
755     bool adpfUclamp;
756     uint32_t uclampMinInit;
757     uint32_t uclampMinHighLimit;
758     uint32_t uclampMinLowLimit;
759     uint64_t samplingWindowP;
760     uint64_t samplingWindowI;
761     uint64_t samplingWindowD;
762     double staleTimeFactor;
763     uint64_t reportingRate;
764     double targetTimeFactor;
765 
766     std::vector<std::shared_ptr<AdpfConfig>> adpfs_parsed;
767     std::set<std::string> name_parsed;
768     Json::Value root;
769     Json::CharReaderBuilder builder;
770     std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
771     std::string errorMessage;
772     if (!reader->parse(&*json_doc.begin(), &*json_doc.end(), &root, &errorMessage)) {
773         LOG(ERROR) << "Failed to parse JSON config: " << errorMessage;
774         return adpfs_parsed;
775     }
776     Json::Value adpfs = root["AdpfConfig"];
777     for (Json::Value::ArrayIndex i = 0; i < adpfs.size(); ++i) {
778         std::optional<bool> gpuBoost;
779         std::optional<uint64_t> gpuBoostCapacityMax;
780         uint64_t gpuCapacityLoadUpHeadroom = 0;
781         std::string name = adpfs[i]["Name"].asString();
782         LOG(VERBOSE) << "AdpfConfig[" << i << "]'s Name: " << name;
783         if (name.empty()) {
784             LOG(ERROR) << "Failed to read "
785                        << "AdpfConfig[" << i << "]'s Name";
786             adpfs_parsed.clear();
787             return adpfs_parsed;
788         }
789         auto result = name_parsed.insert(name);
790         if (!result.second) {
791             LOG(ERROR) << "Duplicate AdpfConfig[" << i << "]'s Name";
792             adpfs_parsed.clear();
793             return adpfs_parsed;
794         }
795 
796         // heuristic boost configs
797         std::optional<bool> heuristicBoostOn;
798         std::optional<uint32_t> hBoostModerateJankThreshold;
799         std::optional<double> hBoostOffMaxAvgDurRatio;
800         std::optional<double> hBoostSevereJankPidPu;
801         std::optional<uint32_t> hBoostSevereJankThreshold;
802         std::optional<std::pair<uint32_t, uint32_t>> hBoostUclampMinCeilingRange;
803         std::optional<std::pair<uint32_t, uint32_t>> hBoostUclampMinFloorRange;
804         std::optional<double> jankCheckTimeFactor;
805         std::optional<uint32_t> lowFrameRateThreshold;
806         std::optional<uint32_t> maxRecordsNum;
807 
808         std::optional<uint32_t> uclampMinLoadUp;
809         std::optional<uint32_t> uclampMinLoadReset;
810         std::optional<int32_t> uclampMaxEfficientBase;
811         std::optional<int32_t> uclampMaxEfficientOffset;
812 
813         ADPF_PARSE(pidOn, "PID_On", Bool);
814         ADPF_PARSE(pidPOver, "PID_Po", Double);
815         ADPF_PARSE(pidPUnder, "PID_Pu", Double);
816         ADPF_PARSE(pidI, "PID_I", Double);
817         ADPF_PARSE(pidIInit, "PID_I_Init", Int64);
818         ADPF_PARSE(pidIHighLimit, "PID_I_High", Int64);
819         ADPF_PARSE(pidILowLimit, "PID_I_Low", Int64);
820         ADPF_PARSE(pidDOver, "PID_Do", Double);
821         ADPF_PARSE(pidDUnder, "PID_Du", Double);
822         ADPF_PARSE(adpfUclamp, "UclampMin_On", Bool);
823         ADPF_PARSE(uclampMinInit, "UclampMin_Init", UInt);
824         ADPF_PARSE_OPTIONAL(uclampMinLoadUp, "UclampMin_LoadUp", UInt);
825         ADPF_PARSE_OPTIONAL(uclampMinLoadReset, "UclampMin_LoadReset", UInt);
826         ADPF_PARSE(uclampMinHighLimit, "UclampMin_High", UInt);
827         ADPF_PARSE(uclampMinLowLimit, "UclampMin_Low", UInt);
828         ADPF_PARSE(samplingWindowP, "SamplingWindow_P", UInt64);
829         ADPF_PARSE(samplingWindowI, "SamplingWindow_I", UInt64);
830         ADPF_PARSE(samplingWindowD, "SamplingWindow_D", UInt64);
831         ADPF_PARSE(staleTimeFactor, "StaleTimeFactor", Double);
832         ADPF_PARSE(reportingRate, "ReportingRateLimitNs", UInt64);
833         ADPF_PARSE(targetTimeFactor, "TargetTimeFactor", Double);
834         ADPF_PARSE_OPTIONAL(heuristicBoostOn, "HeuristicBoost_On", Bool);
835         ADPF_PARSE_OPTIONAL(hBoostModerateJankThreshold, "HBoostModerateJankThreshold", UInt);
836         ADPF_PARSE_OPTIONAL(hBoostOffMaxAvgDurRatio, "HBoostOffMaxAvgDurRatio", Double);
837         ADPF_PARSE_OPTIONAL(hBoostSevereJankPidPu, "HBoostSevereJankPidPu", Double);
838         ADPF_PARSE_OPTIONAL(hBoostSevereJankThreshold, "HBoostSevereJankThreshold", UInt);
839         ADPF_PARSE_OPTIONAL(jankCheckTimeFactor, "JankCheckTimeFactor", Double);
840         ADPF_PARSE_OPTIONAL(lowFrameRateThreshold, "LowFrameRateThreshold", UInt);
841         ADPF_PARSE_OPTIONAL(maxRecordsNum, "MaxRecordsNum", UInt);
842         ADPF_PARSE_OPTIONAL(uclampMaxEfficientBase, "UclampMax_EfficientBase", Int);
843         ADPF_PARSE_OPTIONAL(uclampMaxEfficientOffset, "UclampMax_EfficientOffset", Int);
844 
845         if (!adpfs[i]["GpuBoost"].empty() && adpfs[i]["GpuBoost"].isBool()) {
846             gpuBoost = adpfs[i]["GpuBoost"].asBool();
847         }
848         if (!adpfs[i]["GpuCapacityBoostMax"].empty() &&
849             adpfs[i]["GpuCapacityBoostMax"].isUInt64()) {
850             gpuBoostCapacityMax = adpfs[i]["GpuCapacityBoostMax"].asUInt64();
851         }
852         if (!adpfs[i]["GpuCapacityLoadUpHeadroom"].empty() &&
853             adpfs[i]["GpuCapacityLoadUpHeadroom"].isUInt64()) {
854             gpuCapacityLoadUpHeadroom = adpfs[i]["GpuCapacityLoadUpHeadroom"].asUInt64();
855         }
856 
857         if (!adpfs[i]["HBoostUclampMinCeilingRange"].empty()) {
858             Json::Value ceilRange = adpfs[i]["HBoostUclampMinCeilingRange"];
859             if (ceilRange.size() == 2 && ceilRange[0].isUInt() && ceilRange[1].isUInt()) {
860                 hBoostUclampMinCeilingRange =
861                         std::make_pair(ceilRange[0].asUInt(), ceilRange[1].asUInt());
862             }
863         }
864 
865         if (!adpfs[i]["HBoostUclampMinFloorRange"].empty()) {
866             Json::Value floorRange = adpfs[i]["HBoostUclampMinFloorRange"];
867             if (floorRange.size() == 2 && floorRange[0].isUInt() && floorRange[1].isUInt()) {
868                 hBoostUclampMinFloorRange =
869                         std::make_pair(floorRange[0].asUInt(), floorRange[1].asUInt());
870             }
871         }
872 
873         // Check all the heuristic configurations are there if heuristic boost is going to
874         // be used.
875         if (heuristicBoostOn.has_value()) {
876             if (!hBoostModerateJankThreshold.has_value() || !hBoostOffMaxAvgDurRatio.has_value() ||
877                 !hBoostSevereJankPidPu.has_value() || !hBoostSevereJankThreshold.has_value() ||
878                 !hBoostUclampMinCeilingRange.has_value() ||
879                 !hBoostUclampMinFloorRange.has_value() || !jankCheckTimeFactor.has_value() ||
880                 !lowFrameRateThreshold.has_value() || !maxRecordsNum.has_value()) {
881                 LOG(ERROR) << "Part of the heuristic boost configurations are missing!";
882                 adpfs_parsed.clear();
883                 return adpfs_parsed;
884             }
885         }
886 
887         if (uclampMaxEfficientBase.has_value() != uclampMaxEfficientBase.has_value()) {
888             LOG(ERROR) << "Part of the power efficiency configuration is missing!";
889             adpfs_parsed.clear();
890             return adpfs_parsed;
891         }
892 
893         if (!uclampMinLoadUp.has_value()) {
894             uclampMinLoadUp = uclampMinHighLimit;
895         }
896         if (!uclampMinLoadReset.has_value()) {
897             uclampMinLoadReset = uclampMinHighLimit;
898         }
899 
900         adpfs_parsed.emplace_back(std::make_shared<AdpfConfig>(
901                 name, pidOn, pidPOver, pidPUnder, pidI, pidIInit, pidIHighLimit, pidILowLimit,
902                 pidDOver, pidDUnder, adpfUclamp, uclampMinInit, uclampMinHighLimit,
903                 uclampMinLowLimit, samplingWindowP, samplingWindowI, samplingWindowD, reportingRate,
904                 targetTimeFactor, staleTimeFactor, gpuBoost, gpuBoostCapacityMax,
905                 gpuCapacityLoadUpHeadroom, heuristicBoostOn, hBoostModerateJankThreshold,
906                 hBoostOffMaxAvgDurRatio, hBoostSevereJankPidPu, hBoostSevereJankThreshold,
907                 hBoostUclampMinCeilingRange, hBoostUclampMinFloorRange, jankCheckTimeFactor,
908                 lowFrameRateThreshold, maxRecordsNum, uclampMinLoadUp.value(),
909                 uclampMinLoadReset.value(), uclampMaxEfficientBase, uclampMaxEfficientOffset));
910     }
911     LOG(INFO) << adpfs_parsed.size() << " AdpfConfigs parsed successfully";
912     return adpfs_parsed;
913 }
914 
915 // TODO(jimmyshiu@): Deprecated. Remove once all powerhint.json up-to-date.
GetAdpfProfileFromDoHint() const916 std::shared_ptr<AdpfConfig> HintManager::GetAdpfProfileFromDoHint() const {
917     if (adpfs_.empty())
918         return nullptr;
919     return adpfs_[adpf_index_];
920 }
921 
922 // TODO(jimmyshiu@): Deprecated. Remove once all powerhint.json up-to-date.
SetAdpfProfileFromDoHint(const std::string & profile_name)923 bool HintManager::SetAdpfProfileFromDoHint(const std::string &profile_name) {
924     for (std::size_t i = 0; i < adpfs_.size(); ++i) {
925         if (adpfs_[i]->mName == profile_name) {
926             if (adpf_index_ != i) {
927                 ATRACE_NAME(StringPrintf("%s %s:%s", __func__, adpfs_[adpf_index_]->mName.c_str(),
928                                          profile_name.c_str())
929                                     .c_str());
930                 adpf_index_ = i;
931             }
932             return true;
933         }
934     }
935     return false;
936 }
937 
IsAdpfSupported() const938 bool HintManager::IsAdpfSupported() const {
939     return !adpfs_.empty();
940 }
941 
GetAdpfProfile(const std::string & tag) const942 std::shared_ptr<AdpfConfig> HintManager::GetAdpfProfile(const std::string &tag) const {
943     if (adpfs_.empty())
944         return nullptr;
945     if (tag_profile_map_.find(tag) == tag_profile_map_.end()) {
946         // TODO(jimmyshiu@): `return adpfs_[0]` once the GetAdpfProfileFromDoHint() retired.
947         return GetAdpfProfileFromDoHint();
948     }
949     return tag_profile_map_.at(tag);
950 }
951 
SetAdpfProfile(const std::string & tag,const std::string & profile)952 bool HintManager::SetAdpfProfile(const std::string &tag, const std::string &profile) {
953     if (tag_profile_map_.find(tag) == tag_profile_map_.end()) {
954         LOG(WARNING) << "SetAdpfProfile('" << tag << "', " << profile << ") Invalidate Tag!!!";
955         return false;
956     }
957     if (tag_profile_map_[tag]->mName == profile) {
958         LOG(VERBOSE) << "SetAdpfProfile:(" << tag << ", " << profile << ") value not changed!";
959         return true;
960     }
961 
962     bool updated = false;
963     for (std::size_t i = 0; i < adpfs_.size(); ++i) {
964         if (adpfs_[i]->mName == profile) {
965             LOG(DEBUG) << "SetAdpfProfile('" << tag << "', '" << profile << "') Done!";
966             tag_profile_map_[tag] = adpfs_[i];
967             updated = true;
968             break;
969         }
970     }
971     if (!updated) {
972         LOG(WARNING) << "SetAdpfProfile(" << tag << ") failed to find profile:'" << profile << "'";
973     }
974     return updated;
975 }
976 
IsAdpfProfileSupported(const std::string & profile_name) const977 bool HintManager::IsAdpfProfileSupported(const std::string &profile_name) const {
978     for (std::size_t i = 0; i < adpfs_.size(); ++i) {
979         if (adpfs_[i]->mName == profile_name) {
980             return true;
981         }
982     }
983     return false;
984 }
985 
OnNodeUpdate(const std::string & name,const std::string & path,const std::string & value)986 void HintManager::OnNodeUpdate(const std::string &name,
987                                __attribute__((unused)) const std::string &path,
988                                const std::string &value) {
989     // Check if the node is to update ADPF.
990     if (path.starts_with(kAdpfEventNodePath)) {
991         std::string tag = path.substr(strlen(kAdpfEventNodePath));
992         bool updated = SetAdpfProfile(tag, value);
993         if (!updated) {
994             LOG(DEBUG) << "OnNodeUpdate:[" << name << "] failed to update '" << value << "'";
995             return;
996         }
997         auto &callback_list = tag_update_callback_list_[tag];
998         for (const auto &callback : callback_list) {
999             (*callback)(tag_profile_map_[tag]);
1000         }
1001     }
1002 }
1003 
RegisterAdpfUpdateEvent(const std::string & tag,AdpfCallback * update_adpf_func)1004 void HintManager::RegisterAdpfUpdateEvent(const std::string &tag, AdpfCallback *update_adpf_func) {
1005     tag_update_callback_list_[tag].push_back(update_adpf_func);
1006 }
1007 
UnregisterAdpfUpdateEvent(const std::string & tag,AdpfCallback * update_adpf_func)1008 void HintManager::UnregisterAdpfUpdateEvent(const std::string &tag,
1009                                             AdpfCallback *update_adpf_func) {
1010     auto &callback_list = tag_update_callback_list_[tag];
1011     // Use std::find to locate the function object
1012     auto it = std::find_if(
1013             callback_list.begin(), callback_list.end(),
1014             [update_adpf_func](const std::function<void(const std::shared_ptr<AdpfConfig>)> *func) {
1015                 return func == update_adpf_func;
1016             });
1017     if (it != callback_list.end()) {
1018         // Erase the found function object
1019         callback_list.erase(it);
1020     }
1021 }
1022 
gpu_sysfs_config_path() const1023 std::optional<std::string> HintManager::gpu_sysfs_config_path() const {
1024     return gpu_sysfs_config_path_;
1025 }
1026 
1027 }  // namespace perfmgr
1028 }  // namespace android
1029