• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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 "faultlog_hilog_helper.h"
16 
17 #include <fcntl.h>
18 #include <poll.h>
19 #include <queue>
20 #include <unistd.h>
21 
22 #include <sys/syscall.h>
23 #include <sys/wait.h>
24 
25 #include "constants.h"
26 #include "hiview_logger.h"
27 #include "parameter_ex.h"
28 
29 // define Fdsan Domain
30 #ifndef FDSAN_DOMAIN
31 #undef FDSAN_DOMAIN
32 #endif
33 #define FDSAN_DOMAIN 0xD002D11
34 
35 namespace OHOS {
36 namespace HiviewDFX {
37 DEFINE_LOG_LABEL(0xD002D11, "Faultlogger");
38 using namespace FaultLogger;
39 namespace {
40 constexpr int READ_HILOG_BUFFER_SIZE = 1024;
41 constexpr int NUMBER_ONE_THOUSAND = 1000;
42 constexpr int NUMBER_ONE_MILLION = 1000 * 1000;
43 constexpr uint64_t MAX_HILOG_TIMEOUT = 15 * 1000;
44 
GetTimeMilliseconds(void)45 uint64_t GetTimeMilliseconds(void)
46 {
47     struct timespec ts;
48     (void)clock_gettime(CLOCK_REALTIME, &ts);
49     return (static_cast<uint64_t>(ts.tv_sec) * NUMBER_ONE_THOUSAND) +
50         (static_cast<uint64_t>(ts.tv_nsec) / NUMBER_ONE_MILLION);
51 }
52 
ReadDataFromPipe(int fd,std::string & log)53 void ReadDataFromPipe(int fd, std::string &log)
54 {
55     char buffer[READ_HILOG_BUFFER_SIZE];
56     ssize_t nread {0};
57     do {
58         nread = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer) - 1));
59         if (nread > 0) {
60             log.append(buffer, nread);
61         }
62     } while (nread > 0);
63 }
64 } // namespace
65 
ReadHilogTimeout(int fd,uint64_t timeout)66 std::string FaultlogHilogHelper::ReadHilogTimeout(int fd, uint64_t timeout)
67 {
68     if (fd < 0 || timeout > MAX_HILOG_TIMEOUT) {
69         HIVIEW_LOGE("Invalid fd or timeout");
70         return "";
71     }
72     uint64_t startTime = GetTimeMilliseconds();
73     uint64_t endTime = startTime + timeout;
74 
75     struct pollfd pfds[1];
76     pfds[0].fd = fd;
77     pfds[0].events = POLLIN | POLLHUP;
78 
79     std::string log;
80     int pollRet = -1;
81     do {
82         uint64_t now = GetTimeMilliseconds();
83         if (now >= endTime || now < startTime) {
84             HIVIEW_LOGI("read hilog timeout.");
85             break;
86         } else {
87             timeout = endTime - now;
88         }
89 
90         pollRet = poll(pfds, 1, timeout);
91         if (pollRet < 0) {
92             continue;
93         } else if (pollRet == 0) {
94             HIVIEW_LOGI("poll timeout");
95             break;
96         } else {
97             if (pfds[0].revents & POLLHUP) {
98                 ReadDataFromPipe(fd, log);
99                 break;
100             }
101 
102             if ((pfds[0].revents & POLLIN)) {
103                 ReadDataFromPipe(fd, log);
104             }
105         }
106     } while (pollRet > 0 || errno == EINTR);
107     return log;
108 }
109 
GetHilogByPid(int32_t pid)110 std::string FaultlogHilogHelper::GetHilogByPid(int32_t pid)
111 {
112     if (Parameter::IsOversea() && !Parameter::IsBetaVersion()) {
113         HIVIEW_LOGI("Do not get hilog in oversea commercial version.");
114         return "";
115     }
116     int fds[2] = {-1, -1}; // 2: one read pipe, one write pipe
117     if (pipe2(fds, O_NONBLOCK) != 0) {
118         HIVIEW_LOGE("Failed to create pipe for get log.");
119         return "";
120     }
121     uint64_t ownerTag = fdsan_create_owner_tag(FDSAN_OWNER_TYPE_FILE, FDSAN_DOMAIN);
122     fdsan_exchange_owner_tag(fds[0], 0, ownerTag);
123     fdsan_exchange_owner_tag(fds[1], 0, ownerTag);
124 
125     int childPid = fork();
126     if (childPid < 0) {
127         HIVIEW_LOGE("fork fail");
128         return "";
129     } else if (childPid == 0) {
130         syscall(SYS_close, fds[0]);
131         int rc = DoGetHilogProcess(pid, fds[1]);
132         fdsan_close_with_tag(fds[1], ownerTag);
133         _exit(rc);
134     } else {
135         fdsan_close_with_tag(fds[1], ownerTag);
136         HIVIEW_LOGI("read hilog start");
137         std::string log = ReadHilogTimeout(fds[0]);
138         fdsan_close_with_tag(fds[0], ownerTag);
139 
140         if (TEMP_FAILURE_RETRY(waitpid(childPid, nullptr, 0)) != childPid) {
141             HIVIEW_LOGE("waitpid fail, pid: %{public}d, errno: %{public}d", childPid, errno);
142             return "";
143         }
144         HIVIEW_LOGI("get hilog waitpid %{public}d success", childPid);
145         return log;
146     }
147     return "";
148 }
149 
DoGetHilogProcess(int32_t pid,int writeFd)150 int FaultlogHilogHelper::DoGetHilogProcess(int32_t pid, int writeFd)
151 {
152     HIVIEW_LOGD("Start do get hilog process, pid:%{public}d", pid);
153     if (writeFd < 0 || dup2(writeFd, STDOUT_FILENO) == -1 ||
154         dup2(writeFd, STDERR_FILENO) == -1) {
155         HIVIEW_LOGE("dup2 writeFd fail");
156         return -1;
157     }
158 
159     int ret = -1;
160     ret = execl("/system/bin/hilog", "hilog", "-z", "1000", "-P", std::to_string(pid).c_str(), nullptr);
161     if (ret < 0) {
162         HIVIEW_LOGE("execl %{public}d, errno: %{public}d", ret, errno);
163         return ret;
164     }
165     return 0;
166 }
167 
ParseHilogToJson(const std::string & hilogStr)168 Json::Value FaultlogHilogHelper::ParseHilogToJson(const std::string &hilogStr)
169 {
170     Json::Value hilog(Json::arrayValue);
171     if (hilogStr.empty()) {
172         HIVIEW_LOGE("Get hilog is empty");
173         return hilog;
174     }
175     std::stringstream logStream(hilogStr);
176     std::string oneLine;
177     std::queue<std::string> hilogContent;
178     while (getline(logStream, oneLine)) {
179         if (hilogContent.size() == REPORT_HILOG_LINE) {
180             hilogContent.pop();
181         }
182         hilogContent.push(std::move(oneLine));
183     }
184     while (!hilogContent.empty()) {
185         hilog.append(std::move(hilogContent.front()));
186         hilogContent.pop();
187     }
188     return hilog;
189 }
190 } // namespace HiviewDFX
191 } // namespace OHOS
192