1 /*
2  * Copyright (c) 2024 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 "hilog_collector_impl.h"
17 #include <sys/wait.h>
18 #include <unistd.h>
19 #include "hiview_logger.h"
20 #include "hilog_decorator.h"
21 
22 namespace OHOS::HiviewDFX::UCollectUtil {
23 DEFINE_LOG_TAG("HilogCollector");
24 
Create()25 std::shared_ptr<HilogCollector> HilogCollector::Create()
26 {
27     return std::make_shared<HilogDecorator>(std::make_shared<HilogCollectorImpl>());
28 }
29 
ExecuteHilog(int32_t pid,uint32_t lineCount,int writeFd) const30 void HilogCollectorImpl::ExecuteHilog(int32_t pid, uint32_t lineCount, int writeFd) const
31 {
32     if (writeFd < 0 || dup2(writeFd, STDOUT_FILENO) == -1 || dup2(writeFd, STDERR_FILENO) == -1) {
33         HIVIEW_LOGE("dup2 writeFd fail");
34         _exit(EXIT_FAILURE);
35     }
36 
37     int ret = execl("/system/bin/hilog", "hilog", "-z", std::to_string(lineCount).c_str(),
38         "-P", std::to_string(pid).c_str(), nullptr);
39     close(writeFd);
40     if (ret < 0) {
41         HIVIEW_LOGE("execl %{public}d, errno: %{public}d", ret, errno);
42         _exit(EXIT_FAILURE);
43     }
44     _exit(EXIT_SUCCESS);
45 }
46 
ReadHilog(int readFd,std::string & log) const47 void HilogCollectorImpl::ReadHilog(int readFd, std::string& log) const
48 {
49     constexpr int READ_HILOG_BUFFER_SIZE = 1024;
50     while (true) {
51         char buffer[READ_HILOG_BUFFER_SIZE] = {0};
52         ssize_t nread = read(readFd, buffer, sizeof(buffer) - 1);
53         if (nread <= 0) {
54             HIVIEW_LOGI("read hilog finished");
55             break;
56         }
57         log.append(buffer);
58     }
59     close(readFd);
60 }
61 
CollectLastLog(uint32_t pid,uint32_t lineNum)62 CollectResult<std::string> HilogCollectorImpl::CollectLastLog(uint32_t pid, uint32_t lineNum)
63 {
64     CollectResult<std::string> result;
65     result.retCode = UCollect::SYSTEM_ERROR;
66     int fds[2] = {-1, -1}; // 2: one read pipe, one write pipe
67     if (pipe(fds) != 0) {
68         HIVIEW_LOGE("pipe fail.");
69         return result;
70     }
71 
72     int childPid = fork();
73     if (childPid < 0) {
74         HIVIEW_LOGE("fork fail.");
75         return result;
76     }
77 
78     if (childPid == 0) {
79         close(fds[0]);
80         constexpr uint32_t MAX_LINE_NUM = 10000;
81         ExecuteHilog(pid, lineNum > MAX_LINE_NUM ? MAX_LINE_NUM : lineNum, fds[1]);
82     } else {
83         close(fds[1]);
84         ReadHilog(fds[0], result.data);
85         result.retCode = UCollect::SUCCESS;
86         if (waitpid(childPid, nullptr, 0) != childPid) {
87             HIVIEW_LOGE("waitpid fail, pid: %{public}d, errno: %{public}d", childPid, errno);
88         } else {
89             HIVIEW_LOGI("waitpid %{public}d success", childPid);
90         }
91     }
92     return result;
93 }
94 } // namespace OHOS::HiviewDFX::UCollectUtil