148f512ceSopenharmony_ci/*
248f512ceSopenharmony_ci * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
348f512ceSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
448f512ceSopenharmony_ci * you may not use this file except in compliance with the License.
548f512ceSopenharmony_ci * You may obtain a copy of the License at
648f512ceSopenharmony_ci *
748f512ceSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
848f512ceSopenharmony_ci *
948f512ceSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
1048f512ceSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
1148f512ceSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1248f512ceSopenharmony_ci * See the License for the specific language governing permissions and
1348f512ceSopenharmony_ci * limitations under the License.
1448f512ceSopenharmony_ci */
1548f512ceSopenharmony_ci
1648f512ceSopenharmony_ci#include "subcommand.h"
1748f512ceSopenharmony_ci#include <mutex>
1848f512ceSopenharmony_ci#include "debug_logger.h"
1948f512ceSopenharmony_ci#include "option.h"
2048f512ceSopenharmony_ci
2148f512ceSopenharmony_ciusing namespace std;
2248f512ceSopenharmony_cinamespace OHOS {
2348f512ceSopenharmony_cinamespace Developtools {
2448f512ceSopenharmony_cinamespace HiPerf {
2548f512ceSopenharmony_cistatic std::map<std::string, std::unique_ptr<SubCommand>> g_SubCommandsMap;
2648f512ceSopenharmony_cistd::mutex g_subCommandMutex;
2748f512ceSopenharmony_ci
2848f512ceSopenharmony_ci// parse option first
2948f512ceSopenharmony_cibool SubCommand::OnSubCommandOptions(std::vector<std::string> args)
3048f512ceSopenharmony_ci{
3148f512ceSopenharmony_ci    // parse common first
3248f512ceSopenharmony_ci    if (!Option::GetOptionValue(args, "--dumpoptions", dumpOptions_)) {
3348f512ceSopenharmony_ci        return false;
3448f512ceSopenharmony_ci    }
3548f512ceSopenharmony_ci    if (!Option::GetOptionValue(args, "--help", showHelp_)
3648f512ceSopenharmony_ci        || !Option::GetOptionValue(args, "-h", showHelp_)) {
3748f512ceSopenharmony_ci        return false;
3848f512ceSopenharmony_ci    }
3948f512ceSopenharmony_ci
4048f512ceSopenharmony_ci    if (showHelp_) {
4148f512ceSopenharmony_ci        if (!args.empty()) {
4248f512ceSopenharmony_ci            printf("unknown option '%s'\n", args.front().c_str());
4348f512ceSopenharmony_ci            return false;
4448f512ceSopenharmony_ci        }
4548f512ceSopenharmony_ci        if (OnPreSubCommand()) {
4648f512ceSopenharmony_ci            return false;
4748f512ceSopenharmony_ci        }
4848f512ceSopenharmony_ci    }
4948f512ceSopenharmony_ci
5048f512ceSopenharmony_ci    if (ParseOption(args)) {
5148f512ceSopenharmony_ci        if (dumpOptions_) {
5248f512ceSopenharmony_ci            DumpOptions();
5348f512ceSopenharmony_ci        }
5448f512ceSopenharmony_ci        HLOGD(" args left over: (%zu): %s", args.size(), VectorToString(args).c_str());
5548f512ceSopenharmony_ci        if (!args.empty()) {
5648f512ceSopenharmony_ci            printf("unknown option '%s'\n", args.front().c_str());
5748f512ceSopenharmony_ci            return false;
5848f512ceSopenharmony_ci        }
5948f512ceSopenharmony_ci    } else {
6048f512ceSopenharmony_ci        HLOGD("incorrect option(s)\n");
6148f512ceSopenharmony_ci        return false;
6248f512ceSopenharmony_ci    }
6348f512ceSopenharmony_ci    return true;
6448f512ceSopenharmony_ci}
6548f512ceSopenharmony_ci
6648f512ceSopenharmony_cibool SubCommand::CheckRestartOption(std::string &appPackage, bool targetSystemWide, bool restart,
6748f512ceSopenharmony_ci                                    std::vector<pid_t> &selectPids)
6848f512ceSopenharmony_ci{
6948f512ceSopenharmony_ci    if (!restart) {
7048f512ceSopenharmony_ci        return true;
7148f512ceSopenharmony_ci    }
7248f512ceSopenharmony_ci    if (appPackage.empty()) {
7348f512ceSopenharmony_ci        printf("to detect the performance of application startup, --app option must be given\n");
7448f512ceSopenharmony_ci        return false;
7548f512ceSopenharmony_ci    }
7648f512ceSopenharmony_ci    if (targetSystemWide || !selectPids.empty()) {
7748f512ceSopenharmony_ci        printf("option --restart and -p/-a is conflict, please check usage\n");
7848f512ceSopenharmony_ci        return false;
7948f512ceSopenharmony_ci    }
8048f512ceSopenharmony_ci
8148f512ceSopenharmony_ci    if (!appPackage.empty()) {
8248f512ceSopenharmony_ci        return IsRestarted(appPackage);
8348f512ceSopenharmony_ci    }
8448f512ceSopenharmony_ci    return false;
8548f512ceSopenharmony_ci}
8648f512ceSopenharmony_ci
8748f512ceSopenharmony_cibool SubCommand::HandleSubCommandExclude(const std::vector<pid_t> &excludeTids, const std::vector<std::string>
8848f512ceSopenharmony_ci                                         &excludeThreadNames, std::vector<pid_t> &selectTids)
8948f512ceSopenharmony_ci{
9048f512ceSopenharmony_ci    if (!excludeTids.empty() && !excludeThreadNames.empty()) {
9148f512ceSopenharmony_ci        printf("option --exclude-thread and --exclude-tid is conflict, please check usage\n");
9248f512ceSopenharmony_ci        return false;
9348f512ceSopenharmony_ci    }
9448f512ceSopenharmony_ci    if (excludeTids.empty() && excludeThreadNames.empty()) {
9548f512ceSopenharmony_ci        return true;
9648f512ceSopenharmony_ci    }
9748f512ceSopenharmony_ci    if (selectTids.empty()) {
9848f512ceSopenharmony_ci        printf("No thread is Monitored, while attempt to exclude some threads.\n");
9948f512ceSopenharmony_ci        return true;
10048f512ceSopenharmony_ci    }
10148f512ceSopenharmony_ci    if (!excludeTids.empty()) {
10248f512ceSopenharmony_ci        ExcludeTidsFromSelectTids(excludeTids, selectTids);
10348f512ceSopenharmony_ci        return true;
10448f512ceSopenharmony_ci    }
10548f512ceSopenharmony_ci    ExcludeThreadsFromSelectTids(excludeThreadNames, selectTids);
10648f512ceSopenharmony_ci    return true;
10748f512ceSopenharmony_ci}
10848f512ceSopenharmony_ci
10948f512ceSopenharmony_civoid SubCommand::ExcludeTidsFromSelectTids(const std::vector<pid_t> &excludeTids, std::vector<pid_t> &selectTids)
11048f512ceSopenharmony_ci{
11148f512ceSopenharmony_ci    for (auto excludeTid : excludeTids) {
11248f512ceSopenharmony_ci        bool hasExclude = false;
11348f512ceSopenharmony_ci        auto pos = selectTids.begin();
11448f512ceSopenharmony_ci        while (pos != selectTids.end()) {
11548f512ceSopenharmony_ci            if (excludeTid == *pos) {
11648f512ceSopenharmony_ci                pos = selectTids.erase(pos);
11748f512ceSopenharmony_ci                hasExclude = true;
11848f512ceSopenharmony_ci                continue;
11948f512ceSopenharmony_ci            }
12048f512ceSopenharmony_ci            ++pos;
12148f512ceSopenharmony_ci        }
12248f512ceSopenharmony_ci        if (!hasExclude) {
12348f512ceSopenharmony_ci            printf("No thread id %d was found to exclude.\n", excludeTid);
12448f512ceSopenharmony_ci        }
12548f512ceSopenharmony_ci    }
12648f512ceSopenharmony_ci}
12748f512ceSopenharmony_ci
12848f512ceSopenharmony_civoid SubCommand::ExcludeThreadsFromSelectTids(const std::vector<std::string> &excludeThreadNames,
12948f512ceSopenharmony_ci                                              std::vector<pid_t> &selectTids)
13048f512ceSopenharmony_ci{
13148f512ceSopenharmony_ci    for (auto excludeName : excludeThreadNames) {
13248f512ceSopenharmony_ci        bool hasExclude = false;
13348f512ceSopenharmony_ci        auto pos = selectTids.begin();
13448f512ceSopenharmony_ci        while (pos != selectTids.end()) {
13548f512ceSopenharmony_ci            std::string threadName = virtualRuntime_.ReadThreadName(*pos, true);
13648f512ceSopenharmony_ci            if (excludeName == threadName) {
13748f512ceSopenharmony_ci                pos = selectTids.erase(pos);
13848f512ceSopenharmony_ci                hasExclude = true;
13948f512ceSopenharmony_ci                continue;
14048f512ceSopenharmony_ci            }
14148f512ceSopenharmony_ci            ++pos;
14248f512ceSopenharmony_ci        }
14348f512ceSopenharmony_ci        if (!hasExclude) {
14448f512ceSopenharmony_ci            printf("No thread named %s was found to exclude.\n", excludeName.c_str());
14548f512ceSopenharmony_ci        }
14648f512ceSopenharmony_ci    }
14748f512ceSopenharmony_ci}
14848f512ceSopenharmony_ci
14948f512ceSopenharmony_cibool SubCommand::RegisterSubCommand(std::string cmdName, std::unique_ptr<SubCommand> subCommand)
15048f512ceSopenharmony_ci{
15148f512ceSopenharmony_ci    HLOGV("%s", cmdName.c_str());
15248f512ceSopenharmony_ci    if (cmdName.empty()) {
15348f512ceSopenharmony_ci        HLOGE("unable to register empty subcommand!");
15448f512ceSopenharmony_ci        return false;
15548f512ceSopenharmony_ci    }
15648f512ceSopenharmony_ci    if (cmdName.front() == '-') {
15748f512ceSopenharmony_ci        HLOGE("unable use '-' at the begin of subcommand '%s'", cmdName.c_str());
15848f512ceSopenharmony_ci        return false;
15948f512ceSopenharmony_ci    }
16048f512ceSopenharmony_ci
16148f512ceSopenharmony_ci    if (g_SubCommandsMap.count(cmdName) == 0) {
16248f512ceSopenharmony_ci        std::lock_guard<std::mutex> lock(g_subCommandMutex);
16348f512ceSopenharmony_ci        g_SubCommandsMap.insert(std::make_pair(cmdName, std::move(subCommand)));
16448f512ceSopenharmony_ci        return true;
16548f512ceSopenharmony_ci    } else {
16648f512ceSopenharmony_ci        HLOGE("subcommand '%s' already registered!", cmdName.c_str());
16748f512ceSopenharmony_ci        return false;
16848f512ceSopenharmony_ci    }
16948f512ceSopenharmony_ci}
17048f512ceSopenharmony_ci
17148f512ceSopenharmony_civoid SubCommand::ClearSubCommands()
17248f512ceSopenharmony_ci{
17348f512ceSopenharmony_ci    std::lock_guard<std::mutex> lock(g_subCommandMutex);
17448f512ceSopenharmony_ci    g_SubCommandsMap.clear();
17548f512ceSopenharmony_ci}
17648f512ceSopenharmony_ci
17748f512ceSopenharmony_ciconst std::map<std::string, std::unique_ptr<SubCommand>> &SubCommand::GetSubCommands()
17848f512ceSopenharmony_ci{
17948f512ceSopenharmony_ci    return g_SubCommandsMap;
18048f512ceSopenharmony_ci}
18148f512ceSopenharmony_ci
18248f512ceSopenharmony_ciSubCommand *SubCommand::FindSubCommand(std::string &cmdName)
18348f512ceSopenharmony_ci{
18448f512ceSopenharmony_ci    HLOGV("%s", cmdName.c_str());
18548f512ceSopenharmony_ci    std::lock_guard<std::mutex> lock(g_subCommandMutex);
18648f512ceSopenharmony_ci    auto found = g_SubCommandsMap.find(cmdName);
18748f512ceSopenharmony_ci    if (found != g_SubCommandsMap.end()) {
18848f512ceSopenharmony_ci        // remove the subcmd itself
18948f512ceSopenharmony_ci        return found->second.get();
19048f512ceSopenharmony_ci    } else {
19148f512ceSopenharmony_ci        return nullptr;
19248f512ceSopenharmony_ci    }
19348f512ceSopenharmony_ci}
19448f512ceSopenharmony_ci} // namespace HiPerf
19548f512ceSopenharmony_ci} // namespace Developtools
19648f512ceSopenharmony_ci} // namespace OHOS
197