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