/* * Copyright (C) 2019 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 specific language governing permissions and * limitations under the License. */ #define LOG_TAG "perfstatsd" #include #include enum MODE { DUMP_HISTORY, SET_OPTION }; android::sp perfstatsdSp; void *perfstatsdMain(void *) { LOG(INFO) << "main thread started"; perfstatsdSp = new Perfstatsd(); while (true) { perfstatsdSp->refresh(); perfstatsdSp->pause(); } return NULL; } void help(char **argv) { std::string usage = argv[0]; usage = "Usage: " + usage + " [-s][-d][-o]\n" + "Options:\n" " -s, start as service\n" " -d, dump perf stats history for dumpstate_board\n" " -o, set key/value option"; fprintf(stderr, "%s\n", usage.c_str()); } int startService(void) { pthread_t perfstatsdMainThread; errno = pthread_create(&perfstatsdMainThread, NULL, perfstatsdMain, NULL); if (errno != 0) { PLOG(ERROR) << "Failed to create main thread"; return -1; } else { pthread_setname_np(perfstatsdMainThread, "perfstatsd_main"); } android::ProcessState::initWithDriver("/dev/vndbinder"); if (PerfstatsdPrivateService::start() != android::OK) { PLOG(ERROR) << "Failed to start perfstatsd service"; return -1; } else LOG(INFO) << "perfstatsd_pri_service started"; android::ProcessState::self()->startThreadPool(); android::IPCThreadState::self()->joinThreadPool(); pthread_join(perfstatsdMainThread, NULL); return 0; } int serviceCall(int mode, const std::string &key, const std::string &value) { android::ProcessState::initWithDriver("/dev/vndbinder"); android::sp perfstatsdPrivateService = getPerfstatsdPrivateService(); if (perfstatsdPrivateService == NULL) { PLOG(ERROR) << "Cannot find perfstatsd service."; fprintf(stdout, "Cannot find perfstatsd service.\n"); return -1; } switch (mode) { case DUMP_HISTORY: { std::string history; LOG(INFO) << "dump perfstats history."; if (!perfstatsdPrivateService->dumpHistory(&history).isOk() || history.empty()) { PLOG(ERROR) << "perf stats history is not available"; fprintf(stdout, "perf stats history is not available\n"); return -1; } fprintf(stdout, "%s\n", history.c_str()); break; } case SET_OPTION: LOG(INFO) << "set option: " << key << " , " << value; if (!perfstatsdPrivateService ->setOptions(std::forward(key), std::forward(value)) .isOk()) { PLOG(ERROR) << "fail to set options"; fprintf(stdout, "fail to set options\n"); return -1; } break; } return 0; } int serviceCall(int mode) { std::string empty(""); return serviceCall(mode, empty, empty); } int main(int argc, char **argv) { android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM)); int c; while ((c = getopt(argc, argv, "sdo:h")) != -1) { switch (c) { case 's': return startService(); case 'd': return serviceCall(DUMP_HISTORY); case 'o': // set options if (argc == 4) { std::string key(argv[2]); std::string value(argv[3]); return serviceCall(SET_OPTION, std::move(key), std::move(value)); } FALLTHROUGH_INTENDED; case 'h': // print usage FALLTHROUGH_INTENDED; default: help(argv); return 2; } } return 0; }