1 /*
2  * Copyright (C) 2018 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 #include <android-base/file.h>
18 #include <android-base/logging.h>
19 #include <getopt.h>
20 #include <sys/types.h>
21 #include <unistd.h>
22 
23 #include <thread>
24 
25 #include "perfmgr/HintManager.h"
26 
27 namespace android {
28 namespace perfmgr {
29 
30 class NodeVerifier : public HintManager {
31   public:
VerifyNodes(const std::string & config_path)32     static bool VerifyNodes(const std::string& config_path) {
33         std::string json_doc;
34 
35         if (!android::base::ReadFileToString(config_path, &json_doc)) {
36             LOG(ERROR) << "Failed to read JSON config from " << config_path;
37             return false;
38         }
39 
40         std::vector<std::unique_ptr<Node>> nodes = ParseNodes(json_doc);
41         if (nodes.empty()) {
42             LOG(ERROR) << "Failed to parse Nodes section from " << config_path;
43             return false;
44         }
45 
46         return true;
47     }
48 
49   private:
50     NodeVerifier() = delete;
51     NodeVerifier(NodeVerifier const &) = delete;
52     NodeVerifier &operator=(NodeVerifier const &) = delete;
53 };
54 
55 }  // namespace perfmgr
56 }  // namespace android
57 
printUsage(const char * exec_name)58 static void printUsage(const char* exec_name) {
59     std::string usage = exec_name;
60     usage =
61         usage +
62         " is a command-line tool to verify Nodes in Json config are writable.\n"
63         "Usages:\n"
64         "    [su system] " +
65         exec_name +
66         " [options]\n"
67         "\n"
68         "Options:\n"
69         "   --config, -c  [PATH]\n"
70         "       path to Json config file\n\n"
71         "   --exec_hint, -e\n"
72         "       do hints in Json config\n\n"
73         "   --hint_name, -i\n"
74         "       do only the specific hint\n\n"
75         "   --hint_duration, -d  [duration]\n"
76         "       duration in ms for each hint\n\n"
77         "   --help, -h\n"
78         "       print this message\n\n"
79         "   --verbose, -v\n"
80         "       print verbose log during execution\n\n";
81 
82     LOG(INFO) << usage;
83 }
84 
execConfig(const std::string & json_file,const std::string & hint_name,uint64_t hint_duration)85 static void execConfig(const std::string& json_file,
86                        const std::string& hint_name, uint64_t hint_duration) {
87     android::perfmgr::HintManager *hm = android::perfmgr::HintManager::GetFromJSON(json_file);
88     if (!hm || !hm->IsRunning()) {
89         LOG(ERROR) << "Failed to Parse JSON config";
90     }
91     std::vector<std::string> hints = hm->GetHints();
92     for (const auto& hint : hints) {
93         if (!hint_name.empty() && hint_name != hint) continue;
94         LOG(INFO) << "Do hint: " << hint;
95         hm->DoHint(hint, std::chrono::milliseconds(hint_duration));
96         std::this_thread::yield();
97         std::this_thread::sleep_for(std::chrono::milliseconds(hint_duration));
98         LOG(INFO) << "End hint: " << hint;
99         hm->EndHint(hint);
100         std::this_thread::yield();
101     }
102 }
103 
main(int argc,char * argv[])104 int main(int argc, char* argv[]) {
105     android::base::InitLogging(argv, android::base::StdioLogger);
106 
107     if (getuid() == 0) {
108         LOG(WARNING) << "Running as root might mask node permission";
109     }
110 
111     std::string config_path;
112     std::string hint_name;
113     bool exec_hint = false;
114     uint64_t hint_duration = 100;
115 
116     while (true) {
117         static struct option opts[] = {
118             {"config", required_argument, nullptr, 'c'},
119             {"exec_hint", no_argument, nullptr, 'e'},
120             {"hint_name", required_argument, nullptr, 'i'},
121             {"hint_duration", required_argument, nullptr, 'd'},
122             {"help", no_argument, nullptr, 'h'},
123             {"verbose", no_argument, nullptr, 'v'},
124             {0, 0, 0, 0}  // termination of the option list
125         };
126 
127         int option_index = 0;
128         int c = getopt_long(argc, argv, "c:ei:d:hv", opts, &option_index);
129         if (c == -1) {
130             break;
131         }
132 
133         switch (c) {
134             case 'c':
135                 config_path = optarg;
136                 break;
137             case 'e':
138                 exec_hint = true;
139                 break;
140             case 'i':
141                 hint_name = optarg;
142                 break;
143             case 'd':
144                 hint_duration = strtoul(optarg, NULL, 10);
145                 break;
146             case 'v':
147                 android::base::SetMinimumLogSeverity(android::base::VERBOSE);
148                 break;
149             case 'h':
150                 printUsage(argv[0]);
151                 return 0;
152             default:
153                 // getopt already prints "invalid option -- %c" for us.
154                 return 1;
155         }
156     }
157 
158     if (config_path.empty()) {
159         LOG(ERROR) << "Need specify JSON config";
160         printUsage(argv[0]);
161         return 1;
162     }
163 
164     if (exec_hint) {
165         execConfig(config_path, hint_name, hint_duration);
166         return 0;
167     }
168 
169     if (android::perfmgr::NodeVerifier::VerifyNodes(config_path)) {
170         LOG(INFO) << "Verified writing to JSON config";
171         return 0;
172     } else {
173         LOG(ERROR) << "Failed to verify nodes in JSON config";
174         return 1;
175     }
176 }
177