1 /*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved.
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
16 #include <gtest/gtest.h>
17 #include "command_poller.h"
18 #include "hook_manager.h"
19 #include "hook_service.h"
20 #include "hook_socket_client.h"
21 #include "parameters.h"
22 #include "socket_context.h"
23
24 using namespace testing::ext;
25 using namespace OHOS::Developtools::NativeDaemon;
26 namespace {
27 const std::string OUTPUT_PATH = "/data/local/tmp/hiprofiler_data.htrace";
28 const int SMB_PAGES = 16384;
29 class HookManagerTest : public ::testing::Test {
30 public:
SetUpTestCase()31 static void SetUpTestCase()
32 {
33 OHOS::system::SetParameter("hiviewdfx.hiprofiler.profilerd.start", "1");
34 #ifdef COVERAGE_TEST
35 const int coverageSleepTime = 5; // sleep 5s
36 sleep(coverageSleepTime);
37 #else
38 sleep(1); // 睡眠1s确保hiprofilerd进程启动
39 #endif
40 }
TearDownTestCase()41 static void TearDownTestCase()
42 {
43 OHOS::system::SetParameter("hiviewdfx.hiprofiler.profilerd.start", "0");
44 }
45 };
46
CreateCommand(const std::string & outputFile,const int32_t time,const std::string & processName)47 std::string CreateCommand(const std::string& outputFile, const int32_t time, const std::string& processName)
48 {
49 std::ostringstream cmdStream;
50 cmdStream << "hiprofiler_cmd \\\n"
51 << "-c - \\\n"
52 << "-o " << outputFile << " \\\n"
53 << "-t " << time << " \\\n"
54 << "-s \\\n"
55 << "-k \\\n"
56 << "<<CONFIG\n"
57 << "request_id: 1\n"
58 << "session_config {\n"
59 << " buffers {\n"
60 << " pages: 14848" << "\n"
61 << " }\n"
62 << "}\n"
63 << "plugin_configs {\n"
64 << " plugin_name: \"nativehook\"\n"
65 << " config_data {\n"
66 << "process_name: \"" << processName << "\"\n"
67 << "smb_pages: " << SMB_PAGES << "\n"
68 << "dump_nmd: true\n"
69 << " }\n"
70 << "}\n"
71 << "CONFIG\n";
72 return cmdStream.str();
73 }
74
RunCommand(const std::string & cmd,std::string & content)75 bool RunCommand(const std::string& cmd, std::string& content)
76 {
77 std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd.c_str(), "r"), pclose);
78 CHECK_TRUE(pipe, false, "RunCommand: create popen FAILED!");
79 static constexpr int buffSize = 1024;
80 std::array<char, buffSize> buffer;
81 while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
82 content += buffer.data();
83 }
84 return true;
85 }
86
87 /*
88 * @tc.name: RegisterPlugin
89 * @tc.desc: test HookManager::RegisterAgentPlugin with normal case.
90 * @tc.type: FUNC
91 */
92 HWTEST_F(HookManagerTest, RegisterPlugin, TestSize.Level1)
93 {
94 std::shared_ptr<HookManager> hookManager = std::make_shared<HookManager>();
95 ASSERT_TRUE(hookManager != nullptr);
96 std::shared_ptr<CommandPoller> commandPoller = std::make_shared<CommandPoller>(hookManager);
97 ASSERT_TRUE(commandPoller != nullptr);
98 EXPECT_TRUE(commandPoller->OnConnect());
99 hookManager->SetCommandPoller(commandPoller);
100 ASSERT_TRUE(hookManager->RegisterAgentPlugin("nativehook"));
101 ASSERT_TRUE(hookManager->UnregisterAgentPlugin("nativehook"));
102 }
103
104 /*
105 * @tc.name: LoadPlugin
106 * @tc.desc: test HookManager::LoadPlugin with normal case.
107 * @tc.type: FUNC
108 */
109 HWTEST_F(HookManagerTest, LoadPlugin, TestSize.Level1)
110 {
111 std::shared_ptr<HookManager> hookManager = std::make_shared<HookManager>();
112 ASSERT_TRUE(hookManager != nullptr);
113 std::shared_ptr<CommandPoller> commandPoller = std::make_shared<CommandPoller>(hookManager);
114 ASSERT_TRUE(commandPoller != nullptr);
115 EXPECT_TRUE(commandPoller->OnConnect());
116 hookManager->SetCommandPoller(commandPoller);
117 ASSERT_TRUE(hookManager->RegisterAgentPlugin("nativehook"));
118 ASSERT_TRUE(hookManager->LoadPlugin("nativehook"));
119 ASSERT_TRUE(hookManager->UnloadPlugin("nativehook"));
120 ASSERT_TRUE(hookManager->UnregisterAgentPlugin("nativehook"));
121 }
122
123 /*
124 * @tc.name: UnloadPlugin
125 * @tc.desc: test HookManager::UnloadPlugin with normal case.
126 * @tc.type: FUNC
127 */
128 HWTEST_F(HookManagerTest, UnloadPlugin, TestSize.Level1)
129 {
130 std::shared_ptr<HookManager> hookManager = std::make_shared<HookManager>();
131 ASSERT_TRUE(hookManager != nullptr);
132 std::shared_ptr<CommandPoller> commandPoller = std::make_shared<CommandPoller>(hookManager);
133 ASSERT_TRUE(commandPoller != nullptr);
134 EXPECT_TRUE(commandPoller->OnConnect());
135 hookManager->SetCommandPoller(commandPoller);
136 ASSERT_TRUE(hookManager->RegisterAgentPlugin("nativehook"));
137 ASSERT_TRUE(hookManager->LoadPlugin("nativehook"));
138 ASSERT_TRUE(hookManager->UnloadPlugin(commandPoller->GetRequestId()));
139 ASSERT_TRUE(hookManager->UnregisterAgentPlugin("nativehook"));
140 }
141
142 /*
143 * @tc.name: PluginSession
144 * @tc.desc: test HookManager process with normal case.
145 * @tc.type: FUNC
146 */
147 HWTEST_F(HookManagerTest, PluginSession, TestSize.Level1)
148 {
149 std::shared_ptr<HookManager> hookManager = std::make_shared<HookManager>();
150 ASSERT_TRUE(hookManager != nullptr);
151 std::shared_ptr<CommandPoller> commandPoller = std::make_shared<CommandPoller>(hookManager);
152 ASSERT_TRUE(commandPoller != nullptr);
153 EXPECT_TRUE(commandPoller->OnConnect());
154 hookManager->SetCommandPoller(commandPoller);
155
156 std::vector<uint32_t> pluginIds(1);
157 ProfilerPluginConfig config;
158 config.set_name("nativehook");
159 config.set_plugin_sha256("");
160 config.set_sample_interval(20);
161
162 PluginResult result;
163 std::vector<ProfilerPluginConfig> configVec;
164 configVec.push_back(config);
165
166 EXPECT_FALSE(hookManager->CreatePluginSession(configVec));
167 EXPECT_FALSE(hookManager->StartPluginSession(pluginIds, configVec, result));
168 EXPECT_TRUE(hookManager->CreateWriter("name", 0, 0, 0));
169 EXPECT_TRUE(hookManager->ResetWriter(0));
170 EXPECT_FALSE(hookManager->StopPluginSession(pluginIds));
171 EXPECT_TRUE(hookManager->DestroyPluginSession(pluginIds));
172 }
173
174 /*
175 * @tc.name: CheckProcess
176 * @tc.desc: test CheckProcess with false case.
177 * @tc.type: FUNC
178 */
179 HWTEST_F(HookManagerTest, CheckProcess, TestSize.Level1)
180 {
181 HookManager hookManager;
182 NativeHookConfig nativeConfig;
183 nativeConfig.set_process_name("HookManagerTest");
184 hookManager.SetHookConfig(nativeConfig);
185 EXPECT_TRUE(hookManager.CheckProcess());
186
187 nativeConfig.set_startup_mode(true);
188 hookManager.SetHookConfig(nativeConfig);
189 EXPECT_TRUE(hookManager.CheckProcess());
190 hookManager.ResetStartupParam();
191
192 // native_daemon_ut as a testing process
193 nativeConfig.set_startup_mode(false);
194 nativeConfig.set_process_name("native_daemon_ut");
195 hookManager.SetHookConfig(nativeConfig);
196 EXPECT_TRUE(hookManager.CheckProcess());
197 EXPECT_TRUE(hookManager.CheckProcessName());
198 }
199
200 /*
201 * @tc.name: CheckNmdInfo
202 * @tc.desc: test CheckNmdInfoe when process is exit.
203 * @tc.type: FUNC
204 */
205 #ifdef __aarch64__
206 HWTEST_F(HookManagerTest, CheckNmdInfo, TestSize.Level1)
207 {
208 std::string cmd = CreateCommand(OUTPUT_PATH, 1, "hiview");
209 std::string ret;
210 EXPECT_TRUE(RunCommand(cmd, ret));
211 EXPECT_TRUE(ret.find("FAIL") == std::string::npos);
212 std::string filePath = "/data/local/tmp/nmd_hiview.txt";
213 EXPECT_EQ(access(filePath.c_str(), F_OK), 0);
214
215 std::ifstream infile;
216 infile.open(filePath, std::ios::in);
217 EXPECT_TRUE(infile.is_open());
218 std::string buf;
219 bool nmdResult = false;
220 while (getline(infile, buf)) {
221 if (buf.find("jemalloc statistics") != std::string::npos) {
222 nmdResult = true;
223 break;
224 }
225 }
226 EXPECT_TRUE(nmdResult);
227 }
228 #endif
229
230 /*
231 * @tc.name: CheckNmdInfoe002
232 * @tc.desc: test CheckNmdInfoe002 when process is not exit.
233 * @tc.type: FUNC
234 */
235 HWTEST_F(HookManagerTest, CheckNmdInfo002, TestSize.Level1)
236 {
237 std::string cmd = CreateCommand(OUTPUT_PATH, 1, "test_profiler");
238 std::string ret;
239 EXPECT_TRUE(RunCommand(cmd, ret));
240 EXPECT_TRUE(ret.find("FAIL") == std::string::npos);
241 std::string filePath = "/data/local/tmp/test_profiler.txt";
242 EXPECT_EQ(access(filePath.c_str(), F_OK), -1);
243 }
244 } // namespace