• 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 
16 #include <array>
17 #include <dlfcn.h>
18 #include <fcntl.h>
19 #include <hwext/gtest-ext.h>
20 #include <hwext/gtest-tag.h>
21 #include <sys/syscall.h>
22 #include <unistd.h>
23 
24 #include "logging.h"
25 #include "openssl/sha.h"
26 
27 using namespace testing::ext;
28 
29 #define HHB(v) (((v) & 0xF0) >> 4)
30 #define LHB(v)  ((v) & 0x0F)
31 
32 namespace {
33 #if defined(__LP64__)
34 const std::string DEFAULT_SO_PATH("/system/lib64/");
35 #else
36 const std::string DEFAULT_SO_PATH("/system/lib/");
37 #endif
38 const std::string DEFAULT_HIPROFILERD_PATH("/system/bin/hiprofilerd");
39 const std::string DEFAULT_HIPROFILER_PLUGINS_PATH("/system/bin/hiprofiler_plugins");
40 const std::string DEFAULT_HIPROFILERD_NAME("hiprofilerd");
41 const std::string DEFAULT_HIPROFILER_PLUGINS_NAME("hiprofiler_plugins");
42 const std::string DEFAULT_HIPROFILER_CMD_PATH("/system/bin/hiprofiler_cmd");
43 const std::string FTRACE_PLUGIN_PATH("/data/local/tmp/libftrace_plugin.z.so");
44 std::string DEFAULT_PATH("/data/local/tmp/");
45 constexpr uint32_t READ_BUFFER_SIZE = 1024;
46 constexpr int SLEEP_TIME = 3;
47 constexpr int FILE_READ_CHUNK_SIZE = 4096;
48 constexpr char HEX_CHARS[] = "0123456789abcdef";
49 constexpr int LINE_SIZE = 1000;
50 
51 
52 class HiprofilerCmdTest : public ::testing::Test {
53 public:
SetUpTestCase()54     static void SetUpTestCase() {}
TearDownTestCase()55     static void TearDownTestCase() {}
56 
StartServerStub(std::string name)57     void StartServerStub(std::string name)
58     {
59         int processNum = fork();
60         if (processNum == 0) {
61             if (DEFAULT_HIPROFILERD_PATH == name) {
62                 // start running hiprofilerd
63                 execl(name.c_str(), nullptr, nullptr);
64             } else if (DEFAULT_HIPROFILER_PLUGINS_PATH == name) {
65                 // start running hiprofiler_plugins
66                 execl(name.c_str(), DEFAULT_PATH.c_str(), nullptr);
67             }
68             _exit(1);
69         } else if (DEFAULT_HIPROFILERD_PATH == name) {
70             g_hiprofilerdPid = processNum;
71         } else if (DEFAULT_HIPROFILER_PLUGINS_PATH == name) {
72             g_hiprofilerPluginsPid = processNum;
73         }
74     }
75 
StopProcessStub(int processNum)76     void StopProcessStub(int processNum)
77     {
78         std::string stopCmd = "kill " + std::to_string(processNum);
79         std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(stopCmd.c_str(), "r"), pclose);
80     }
81 
RunCommand(const std::string & cmd,std::string & content)82     bool RunCommand(const std::string& cmd, std::string& content)
83     {
84         std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd.c_str(), "r"), pclose);
85         CHECK_TRUE(pipe, false, "RunCommand: create popen FAILED!");
86 
87         std::array<char, READ_BUFFER_SIZE> buffer;
88         while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
89             content += buffer.data();
90         }
91         return true;
92     }
93 
ComputeFileSha256(const std::string & path)94     std::string ComputeFileSha256(const std::string& path)
95     {
96         uint8_t out[SHA256_DIGEST_LENGTH];
97         uint8_t buffer[FILE_READ_CHUNK_SIZE];
98         char realPath[PATH_MAX + 1] = {0};
99 
100         SHA256_CTX sha;
101         SHA256_Init(&sha);
102 
103         size_t nbytes = 0;
104 
105         if ((strlen(path.c_str()) >= PATH_MAX) || (realpath(path.c_str(), realPath) == nullptr)) {
106             HILOG_ERROR(LOG_CORE, "%s:path is invalid: %s, errno=%d", __func__, path.c_str(), errno);
107             return "";
108         }
109         FILE* file = fopen(realPath, "rb");
110         if (file == nullptr) {
111             return "";
112         }
113 
114         std::unique_ptr<FILE, decltype(fclose)*> fptr(file, fclose);
115         if (fptr == nullptr) {
116             return "";
117         }
118 
119         while ((nbytes = fread(buffer, 1, sizeof(buffer), fptr.get())) > 0) {
120             SHA256_Update(&sha, buffer, nbytes);
121         }
122         SHA256_Final(out, &sha);
123 
124         std::string result;
125         result.reserve(SHA256_DIGEST_LENGTH + SHA256_DIGEST_LENGTH);
126         for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
127             result.push_back(HEX_CHARS[HHB(out[i])]);
128             result.push_back(HEX_CHARS[LHB(out[i])]);
129         }
130 
131         HILOG_DEBUG(LOG_CORE, "%s:%s-(%s)", __func__, path.c_str(), result.c_str());
132         return result;
133     }
134 
CreateConfigFile(const std::string configFile)135     void CreateConfigFile(const std::string configFile)
136     {
137         // 构建config文件
138         std::string configStr =
139             "request_id: 26\n"
140             "session_config {\n"
141             "  buffers {\n"
142             "    pages: 1000\n"
143             "  }\n"
144             "  result_file: \"/data/local/tmp/hiprofiler_data.htrace\"\n"
145             "  sample_duration: 10000\n"
146             "}\n"
147             "plugin_configs {\n"
148             "  plugin_name: \"ftrace-plugin\"\n"
149             "  sample_interval: 2000\n"
150             "  config_data: {\n"
151             "    ftrace_events: \"sched/sched_switch\"\n"
152             "    ftrace_events: \"sched/sched_wakeup\"\n"
153             "    ftrace_events: \"sched/sched_wakeup_new\"\n"
154             "    ftrace_events: \"sched/sched_waking\"\n"
155             "    ftrace_events: \"sched/sched_process_exit\"\n"
156             "    ftrace_events: \"sched/sched_process_free\"\n"
157             "    buffer_size_kb: 51200\n"
158             "    flush_interval_ms: 1000\n"
159             "    flush_threshold_kb: 4096\n"
160             "    parse_ksyms: true\n"
161             "    clock: \"mono\"\n"
162             "    trace_period_ms: 200\n"
163             "    debug_on: false\n"
164             "  }\n"
165             "}\n";
166 
167         // 根据构建的config写文件
168         FILE* writeFp = fopen(configFile.c_str(), "w");
169         if (writeFp == nullptr) {
170             const int bufSize = 256;
171             char buf[bufSize] = { 0 };
172             strerror_r(errno, buf, bufSize);
173             HILOG_ERROR(LOG_CORE, "CreateConfigFile: fopen() error = %s", buf);
174             return;
175         }
176 
177         size_t len = fwrite(const_cast<char*>(configStr.c_str()), 1, configStr.length(), writeFp);
178         if (len < 0) {
179             const int bufSize = 256;
180             char buf[bufSize] = { 0 };
181             strerror_r(errno, buf, bufSize);
182             HILOG_ERROR(LOG_CORE, "CreateConfigFile: fwrite() error = %s", buf);
183             if (fclose(writeFp) != 0) {
184                 HILOG_ERROR(LOG_CORE, "fclose() error");
185             }
186             return;
187         }
188 
189         int ret = fflush(writeFp);
190         if (ret == EOF) {
191             const int bufSize = 256;
192             char buf[bufSize] = { 0 };
193             strerror_r(errno, buf, bufSize);
194             HILOG_ERROR(LOG_CORE, "CreateConfigFile: fflush() error = %s", buf);
195             if (fclose(writeFp) != 0) {
196                 HILOG_ERROR(LOG_CORE, "fclose() error");
197             }
198             return;
199         }
200 
201         fsync(fileno(writeFp));
202         ret = fclose(writeFp);
203         if (ret != 0) {
204             const int bufSize = 256;
205             char buf[bufSize] = { 0 };
206             strerror_r(errno, buf, bufSize);
207             HILOG_ERROR(LOG_CORE, "CreateConfigFile: fclose() error = %s", buf);
208             return;
209         }
210     }
211 
CreateCommand(const std::string & outFile,int time) const212     std::string CreateCommand(const std::string &outFile, int time) const
213     {
214         std::string cmdStr =
215             "hiprofiler_cmd \\\n"
216             "-c - \\\n";
217         cmdStr += "-o " + outFile + " \\\n";
218         cmdStr += "-t " + std::to_string(time) + " \\\n"
219             "<<CONFIG\n"
220             "request_id: 1\n"
221             "session_config {\n"
222             "  buffers {\n"
223             "    pages: 1000\n"
224             "  }\n"
225             "  result_file: \"/data/local/tmp/hiprofiler_data.htrace\"\n"
226             "  sample_duration: 3000\n"
227             "}\n"
228             "plugin_configs {\n"
229             "  plugin_name: \"ftrace-plugin\"\n"
230             "  sample_interval: 1000\n"
231             "  config_data {\n"
232             "    ftrace_events: \"sched/sched_switch\"\n"
233             "    ftrace_events: \"sched/sched_wakeup\"\n"
234             "    ftrace_events: \"sched/sched_wakeup_new\"\n"
235             "    ftrace_events: \"sched/sched_waking\"\n"
236             "    ftrace_events: \"sched/sched_process_exit\"\n"
237             "    ftrace_events: \"sched/sched_process_free\"\n"
238             "    buffer_size_kb: 51200\n"
239             "    flush_interval_ms: 1000\n"
240             "    flush_threshold_kb: 4096\n"
241             "    parse_ksyms: true\n"
242             "    clock: \"mono\"\n"
243             "    trace_period_ms: 200\n"
244             "    debug_on: false\n"
245             "  }\n"
246             "}\n"
247             "CONFIG\n";
248         return cmdStr;
249     }
250 
KillProcess(const std::string processName)251     void KillProcess(const std::string processName)
252     {
253         int pid = -1;
254         std::string findpid = "pidof " + processName;
255         HILOG_INFO(LOG_CORE, "find pid command : %s", findpid.c_str());
256         std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(findpid.c_str(), "r"), pclose);
257 
258         char line[LINE_SIZE];
259         do {
260             if (fgets(line, sizeof(line), pipe.get()) == nullptr) {
261                 HILOG_INFO(LOG_CORE, "not find processName : %s", processName.c_str());
262                 return;
263             } else if (strlen(line) > 0 && isdigit(static_cast<unsigned char>(line[0]))) {
264                 pid = atoi(line);
265                 HILOG_INFO(LOG_CORE, "find processName : %s, pid: %d", processName.c_str(), pid);
266                 break;
267             }
268         } while (1);
269 
270         if (pid != -1) {
271             StopProcessStub(pid);
272         }
273     }
274 private:
275     int g_hiprofilerdPid = -1;
276     int g_hiprofilerPluginsPid = -1;
277 };
278 
279 /**
280  * @tc.name: native hook
281  * @tc.desc: Test hiprofiler_cmd with -h -q.
282  * @tc.type: FUNC
283  */
284 HWTEST_F(HiprofilerCmdTest, DFX_DFR_Hiprofiler_0110, Function | MediumTest | Level1)
285 {
286     KillProcess(DEFAULT_HIPROFILERD_NAME);
287     KillProcess(DEFAULT_HIPROFILER_PLUGINS_NAME);
288 
289     std::string cmd = DEFAULT_HIPROFILER_CMD_PATH + " -h";
290     std::string content = "";
291     EXPECT_TRUE(RunCommand(cmd, content));
292     std::string destStr = "help";
293     EXPECT_EQ(strncmp(content.c_str(), destStr.c_str(), strlen(destStr.c_str())), 0);
294 
295     content = "";
296     cmd = DEFAULT_HIPROFILER_CMD_PATH + " -q";
297     EXPECT_TRUE(RunCommand(cmd, content));
298     destStr = "Service not started";
299     EXPECT_EQ(strncmp(content.c_str(), destStr.c_str(), strlen(destStr.c_str())), 0);
300 
301     StartServerStub(DEFAULT_HIPROFILERD_PATH);
302     sleep(1);
303     content = "";
304     EXPECT_TRUE(RunCommand(cmd, content));
305     destStr = "OK";
306     EXPECT_EQ(strncmp(content.c_str(), destStr.c_str(), strlen(destStr.c_str())), 0);
307     StopProcessStub(g_hiprofilerdPid);
308 }
309 
310 /**
311  * @tc.name: native hook
312  * @tc.desc: Test hiprofiler_cmd with -c file.
313  * @tc.type: FUNC
314  */
315 HWTEST_F(HiprofilerCmdTest, DFX_DFR_Hiprofiler_0120, Function | MediumTest | Level1)
316 {
317     KillProcess(DEFAULT_HIPROFILERD_NAME);
318     KillProcess(DEFAULT_HIPROFILER_PLUGINS_NAME);
319 
320     // 测试不存在的config文件
321     std::string configTestFile = DEFAULT_PATH + "1234.txt";
322     std::string outFile = DEFAULT_PATH + "trace.htrace";
323     std::string content = "";
324     std::string cmd = DEFAULT_HIPROFILER_CMD_PATH + " -c " + configTestFile + " -o " + outFile + " -t 3";
325     EXPECT_TRUE(RunCommand(cmd, content));
326     std::string destStr = "Read " + configTestFile + " fail";
327     EXPECT_TRUE(content.find(destStr) != std::string::npos);
328 
329     // 创建有效的config文件
330     const std::string configFile = DEFAULT_PATH + "ftrace.config";
331     CreateConfigFile(configFile);
332 
333     // 测试有效的config文件,不开启hiprofilerd和hiprofiler_plugin进程
334     content = "";
335     cmd = DEFAULT_HIPROFILER_CMD_PATH + " -c " + configFile + " -o " + outFile + " -t 3";
336     EXPECT_TRUE(RunCommand(cmd, content));
337     sleep(SLEEP_TIME);
338     EXPECT_NE(access(outFile.c_str(), F_OK), 0);
339 
340     // 开启hiprofilerd和hiprofiler_plugin进程,可以生成trace文件
341     content = "";
342     StartServerStub(DEFAULT_HIPROFILERD_PATH);
343     sleep(1);
344     StartServerStub(DEFAULT_HIPROFILER_PLUGINS_PATH);
345     sleep(1);
346     EXPECT_TRUE(RunCommand(cmd, content));
347     sleep(SLEEP_TIME);
348     EXPECT_EQ(access(outFile.c_str(), F_OK), 0);
349 
350     // 删除资源文件和生成的trace文件
351     cmd = "rm " + configFile + " " + outFile;
352     system(cmd.c_str());
353     StopProcessStub(g_hiprofilerPluginsPid);
354     StopProcessStub(g_hiprofilerdPid);
355 }
356 
357 /**
358  * @tc.name: native hook
359  * @tc.desc: Test hiprofiler_cmd with -c string.
360  * @tc.type: FUNC
361  */
362 HWTEST_F(HiprofilerCmdTest, DFX_DFR_Hiprofiler_0130, Function | MediumTest | Level1)
363 {
364     std::string cmd = "cp " + DEFAULT_SO_PATH + "libftrace_plugin.z.so " + DEFAULT_PATH;
365     system(cmd.c_str());
366 
367     // 开启hiprofilerd和hiprofiler_plugin进程,验证字符串格式的config
368     std::string content = "";
369     StartServerStub(DEFAULT_HIPROFILERD_PATH);
370     sleep(1);
371     StartServerStub(DEFAULT_HIPROFILER_PLUGINS_PATH);
372     sleep(1);
373     std::string outFile = DEFAULT_PATH + "trace.htrace";
374     int time = 3;
375     cmd = CreateCommand(outFile, time);
376     EXPECT_TRUE(RunCommand(cmd, content));
377     sleep(time);
378     EXPECT_EQ(access(outFile.c_str(), F_OK), 0);
379 
380     // 删除资源文件和生成的trace文件
381     cmd = "rm " + FTRACE_PLUGIN_PATH + " " + outFile;
382     system(cmd.c_str());
383     StopProcessStub(g_hiprofilerPluginsPid);
384     StopProcessStub(g_hiprofilerdPid);
385 }
386 }
387