• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include <thread>
16 
17 #include "common.h"
18 #include "command_poller.h"
19 #include "hook_manager.h"
20 #include "logging.h"
21 #include "plugin_service_types.pb.h"
22 #include "writer_adapter.h"
23 #include "hook_standalone.h"
24 #include "hook_common.h"
25 namespace {
26 const int SLEEP_ONE_SECOND = 1000;
27 const int BUF_MAX_LEN = 10;
28 const int VC_ARG_TWAIN = 2;
29 const int VC_ARG_STEP_SIZE = 2;
30 const int SMBSIZE_BASE = 4096;
31 
ProcessExist(std::string pid)32 bool ProcessExist(std::string pid)
33 {
34     int ret = 0;
35     std::string pid_path = std::string();
36     struct stat stat_buf;
37     if (pid.size() == 0) {
38         return false;
39     }
40     pid_path = "/proc/" + pid + "/status";
41     if (stat(pid_path.c_str(), &stat_buf) != 0) {
42         return false;
43     }
44     return true;
45 }
46 
ParseCommand(std::vector<std::string> args,HookData & hookData)47 bool ParseCommand(std::vector<std::string> args, HookData& hookData)
48 {
49     int idx = 0;
50     while (idx < args.size()) {
51         if (args[idx] == "-o") {
52             hookData.fileName = args[idx + 1].c_str();
53         } else if (args[idx] == "-p") {
54             hookData.pid = std::stoi(args[idx + 1], nullptr);
55             if (std::to_string(hookData.pid) != args[idx + 1]) {
56                 return false;
57             }
58             if (!ProcessExist(args[idx + 1])) {
59                 printf("process does not exist\n");
60                 return false;
61             }
62         } else if (args[idx] == "-n") {
63             hookData.processName = args[idx + 1];
64         } else if (args[idx] == "-s") {
65             hookData.smbSize = std::stoi(args[idx + 1], nullptr);
66             if (std::to_string(hookData.smbSize) != args[idx + 1]) {
67                 return false;
68             }
69         } else if (args[idx] == "-f") {
70             hookData.filterSize = std::stoi(args[idx + 1], nullptr);
71             if (std::to_string(hookData.filterSize) != args[idx + 1]) {
72                 return false;
73             }
74             if (hookData.filterSize > MAX_UNWIND_DEPTH) {
75                 printf("set max depth = %d\n", MAX_UNWIND_DEPTH);
76             }
77         } else if (args[idx] == "-d") {
78             hookData.maxStackDepth = std::stoi(args[idx + 1], nullptr);
79             if (std::to_string(hookData.maxStackDepth) != args[idx + 1]) {
80                 return false;
81             }
82         } else if (args[idx] == "-L") {
83             if (idx + 1 < args.size()) {
84                 hookData.duration = std::stoull(args[idx + 1]);
85             }
86         } else if (args[idx] == "-F") {
87             if (idx + 1 < args.size()) {
88                 hookData.performance_filename = args[idx + 1];
89             }
90         } else if (args[idx] == "-u") {
91             std::string unwind = args[idx + 1];
92             if (unwind == "dwarf") {
93                 hookData.fpUnwind = false;
94             } else if (unwind == "fp") {
95                 hookData.fpUnwind = true;
96             } else {
97                 return false;
98             }
99             printf("set unwind mode:%s\n", unwind.c_str());
100         } else {
101             printf("args[%d] = %s\n", idx, args[idx].c_str());
102             return false;
103         }
104         idx += VC_ARG_STEP_SIZE;
105     }
106     return true;
107 }
108 
VerifyCommand(std::vector<std::string> args,HookData & hookData)109 bool VerifyCommand(std::vector<std::string> args, HookData& hookData)
110 {
111     if ((args.size() % VC_ARG_TWAIN) != 0) {
112         return false;
113     }
114     hookData.pid = 0;
115     hookData.duration = 0;
116     hookData.performance_filename = "./performance.txt";
117     hookData.fileName = "";
118     if (!ParseCommand(args, hookData)) {
119         return false;
120     }
121     if ((hookData.smbSize % SMBSIZE_BASE) != 0) {
122         printf("Please configure a multiple of 4096 for the shared memory size\n");
123         return false;
124     }
125     if (!hookData.fileName.empty() && (!hookData.processName.empty() || hookData.pid > 0)) {
126         return true;
127     }
128     return false;
129 }
130 
GetHookedProceInfo(HookData & hookData)131 void GetHookedProceInfo(HookData& hookData)
132 {
133     printf("Record file = %s, apply sharememory size = %u\n", hookData.fileName.c_str(), hookData.smbSize);
134     if (hookData.pid > 0) {
135         printf("Please send signal 36 to target process %d\n", hookData.pid);
136     } else if (!hookData.processName.empty()) {
137         int pidValue = -1;
138         bool isExist = COMMON::IsProcessExist(hookData.processName, pidValue);
139         if (!isExist) {
140             printf("Please start process %s\n", hookData.processName.c_str());
141         } else {
142             printf("If you want to hook current process, please send signal 36 to target process %d\n", pidValue);
143             printf("If you want to hook new process, please\n");
144             printf("1.param set libc.hook_mode startup:%s\n", hookData.processName.c_str());
145             printf("2.restart process %s\n", hookData.processName.c_str());
146         }
147     }
148 
149     if (hookData.maxStackDepth > 0) {
150         printf("depth greater than %u will not display\n", hookData.maxStackDepth);
151     }
152     if (hookData.filterSize > 0) {
153         printf("malloc size smaller than %u will not record\n", hookData.filterSize);
154     }
155 
156     if (!OHOS::Developtools::Profiler::Hook::StartHook(hookData)) {
157         return;
158     }
159     while (true) {
160         std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_ONE_SECOND));
161     }
162 }
163 } // namespace
164 
main(int argc,char * argv[])165 int main(int argc, char* argv[])
166 {
167     if (COMMON::IsProcessRunning()) { // process is running
168         return 0;
169     }
170 
171     if (argc > 1) {
172         std::vector<std::string> args;
173         for (int i = 1; i < argc; i++) {
174             args.push_back(argv[i]);
175         }
176         HookData hookData = {0, 0, 0, 0, MAX_UNWIND_DEPTH, "", "", "", false, false, false, false};
177         if (VerifyCommand(args, hookData)) {
178             GetHookedProceInfo(hookData);
179         } else {
180             printf(
181                 "Usage: native_daemon [-o file] [-s smb_size] <-p pid> <-n process_name> "
182                 "<-f filter_size> <-d max_stack_depth> <-u fp|dwarf>\n");
183             return 0;
184         }
185     } else {
186         auto hookManager = std::make_shared<HookManager>();
187         CHECK_NOTNULL(hookManager, 1, "create PluginManager FAILED!");
188 
189         auto commandPoller = std::make_shared<CommandPoller>(hookManager);
190         CHECK_NOTNULL(commandPoller, 1, "create CommandPoller FAILED!");
191         CHECK_TRUE(commandPoller->OnConnect(), 1, "connect FAILED");
192         hookManager->SetCommandPoller(commandPoller);
193         hookManager->RegisterAgentPlugin("nativehook");
194         while (true) {
195             std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_ONE_SECOND));
196         }
197     }
198     return 0;
199 }
200