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