blob: af3a71464a1126dd7e19b7aececb18d9c64a9ec8 [file] [log] [blame]
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specic language governing permissions and
* limitations under the License.
*/
#include <thread>
#include <getopt.h>
#include <unistd.h>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <sys/types.h>
#include "perfmgr/HintManager.h"
namespace android {
namespace perfmgr {
class NodeVerifier : public HintManager {
public:
static bool VerifyNodes(const std::string& config_path) {
std::string json_doc;
if (!android::base::ReadFileToString(config_path, &json_doc)) {
LOG(ERROR) << "Failed to read JSON config from " << config_path;
return false;
}
std::vector<std::unique_ptr<Node>> nodes = ParseNodes(json_doc);
if (nodes.empty()) {
LOG(ERROR) << "Failed to parse Nodes section from " << config_path;
return false;
}
for (const auto& node : nodes) {
std::vector<std::string> values = node->GetValues();
std::string default_value = values[node->GetDefaultIndex()];
// Always set to default first
values.insert(values.begin(), default_value);
// And reset to default after test
values.push_back(default_value);
for (const auto& value : values) {
if (!android::base::WriteStringToFile(value, node->GetPath())) {
LOG(ERROR) << "Failed to write to node: " << node->GetPath()
<< " with value: " << value;
return false;
}
LOG(VERBOSE) << "Wrote to node: " << node->GetPath()
<< " with value: " << value;
}
}
return true;
}
private:
NodeVerifier(sp<NodeLooperThread> nm,
const std::map<std::string, std::vector<NodeAction>>& actions)
: HintManager(std::move(nm), actions) {}
};
} // namespace perfmgr
} // namespace android
static void printUsage(const char* exec_name) {
std::string usage = exec_name;
usage =
usage +
" is a command-line tool to verify Nodes in Json config are writable.\n"
"Usages:\n"
" [su system] " +
exec_name +
" [options]\n"
"\n"
"Options:\n"
" --config [PATH], -c\n"
" path to Json config file\n\n"
" --exec_hint, -e\n"
" do hints in Json config\n\n"
" --help, -h\n"
" print this message\n\n"
" --verbose, -v\n"
" print verbose log during execution\n\n";
LOG(INFO) << usage;
}
static void execConfig(const std::string& json_file) {
std::unique_ptr<android::perfmgr::HintManager> hm =
android::perfmgr::HintManager::GetFromJSON(json_file);
if (!hm.get() || !hm->IsRunning()) {
LOG(ERROR) << "Failed to Parse JSON config";
}
std::vector<std::string> hints = hm->GetHints();
for (const auto& hint : hints) {
LOG(INFO) << "Do hint: " << hint;
hm->DoHint(hint);
std::this_thread::yield();
std::this_thread::sleep_for(std::chrono::milliseconds(50));
LOG(INFO) << "End hint: " << hint;
hm->EndHint(hint);
std::this_thread::yield();
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
}
int main(int argc, char* argv[]) {
android::base::InitLogging(argv, android::base::StderrLogger);
if (getuid() == 0) {
LOG(WARNING) << "Running as root might mask node permission";
}
std::string config_path;
bool exec_hint = false;
while (true) {
static struct option opts[] = {
{"config", required_argument, nullptr, 'c'},
{"exec_hint", no_argument, nullptr, 'e'},
{"help", no_argument, nullptr, 'h'},
{"verbose", no_argument, nullptr, 'v'},
{0, 0, 0, 0} // termination of the option list
};
int option_index = 0;
int c = getopt_long(argc, argv, "c:ehv", opts, &option_index);
if (c == -1) {
break;
}
switch (c) {
case 'c':
config_path = optarg;
break;
case 'e':
exec_hint = true;
break;
case 'v':
android::base::SetMinimumLogSeverity(android::base::VERBOSE);
break;
case 'h':
printUsage(argv[0]);
return 0;
default:
// getopt already prints "invalid option -- %c" for us.
return 1;
}
}
if (config_path.empty()) {
LOG(ERROR) << "Need specify JSON config";
printUsage(argv[0]);
return 1;
}
if (exec_hint) {
execConfig(config_path);
return 0;
}
if (android::perfmgr::NodeVerifier::VerifyNodes(config_path)) {
LOG(INFO) << "Verified writing to JSON config";
return 0;
} else {
LOG(ERROR) << "Failed to verify nodes in JSON config";
return 1;
}
}