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