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     void 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     std::unique_ptr<android::perfmgr::HintManager> hm =
88         android::perfmgr::HintManager::GetFromJSON(json_file);
89     if (!hm.get() || !hm->IsRunning()) {
90         LOG(ERROR) << "Failed to Parse JSON config";
91     }
92     std::vector<std::string> hints = hm->GetHints();
93     for (const auto& hint : hints) {
94         if (!hint_name.empty() && hint_name != hint) continue;
95         LOG(INFO) << "Do hint: " << hint;
96         hm->DoHint(hint, std::chrono::milliseconds(hint_duration));
97         std::this_thread::yield();
98         std::this_thread::sleep_for(std::chrono::milliseconds(hint_duration));
99         LOG(INFO) << "End hint: " << hint;
100         hm->EndHint(hint);
101         std::this_thread::yield();
102     }
103 }
104 
main(int argc,char * argv[])105 int main(int argc, char* argv[]) {
106     android::base::InitLogging(argv, android::base::StdioLogger);
107 
108     if (getuid() == 0) {
109         LOG(WARNING) << "Running as root might mask node permission";
110     }
111 
112     std::string config_path;
113     std::string hint_name;
114     bool exec_hint = false;
115     uint64_t hint_duration = 100;
116 
117     while (true) {
118         static struct option opts[] = {
119             {"config", required_argument, nullptr, 'c'},
120             {"exec_hint", no_argument, nullptr, 'e'},
121             {"hint_name", required_argument, nullptr, 'i'},
122             {"hint_duration", required_argument, nullptr, 'd'},
123             {"help", no_argument, nullptr, 'h'},
124             {"verbose", no_argument, nullptr, 'v'},
125             {0, 0, 0, 0}  // termination of the option list
126         };
127 
128         int option_index = 0;
129         int c = getopt_long(argc, argv, "c:ei:d:hv", opts, &option_index);
130         if (c == -1) {
131             break;
132         }
133 
134         switch (c) {
135             case 'c':
136                 config_path = optarg;
137                 break;
138             case 'e':
139                 exec_hint = true;
140                 break;
141             case 'i':
142                 hint_name = optarg;
143                 break;
144             case 'd':
145                 hint_duration = strtoul(optarg, NULL, 10);
146                 break;
147             case 'v':
148                 android::base::SetMinimumLogSeverity(android::base::VERBOSE);
149                 break;
150             case 'h':
151                 printUsage(argv[0]);
152                 return 0;
153             default:
154                 // getopt already prints "invalid option -- %c" for us.
155                 return 1;
156         }
157     }
158 
159     if (config_path.empty()) {
160         LOG(ERROR) << "Need specify JSON config";
161         printUsage(argv[0]);
162         return 1;
163     }
164 
165     if (exec_hint) {
166         execConfig(config_path, hint_name, hint_duration);
167         return 0;
168     }
169 
170     if (android::perfmgr::NodeVerifier::VerifyNodes(config_path)) {
171         LOG(INFO) << "Verified writing to JSON config";
172         return 0;
173     } else {
174         LOG(ERROR) << "Failed to verify nodes in JSON config";
175         return 1;
176     }
177 }
178