1 /*
2  * Copyright (c) 2021-2023 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 "fault_logger_pipe.h"
17 
18 #include <algorithm>
19 #include <cerrno>
20 #include <cstdio>
21 #include <cstdlib>
22 #include <cstring>
23 #include <ctime>
24 #include <fcntl.h>
25 #include <securec.h>
26 #include <string>
27 #include <sys/socket.h>
28 #include <sys/stat.h>
29 #include <sys/syscall.h>
30 #include <sys/types.h>
31 #include <sys/un.h>
32 #include <unistd.h>
33 #include <vector>
34 #include "dfx_define.h"
35 #include "dfx_log.h"
36 
37 namespace OHOS {
38 namespace HiviewDFX {
39 namespace {
40 const std::string FAULTLOGGER_PIPE_TAG = "FaultLoggerPipe";
41 const int PIPE_TIMEOUT = 10000; // 10 seconds
42 }
43 
FaultLoggerPipe()44 FaultLoggerPipe::FaultLoggerPipe()
45 {
46     init_ = false;
47     write_ = false;
48     Init();
49 }
50 
~FaultLoggerPipe()51 FaultLoggerPipe::~FaultLoggerPipe()
52 {
53     Destroy();
54 }
55 
GetReadFd(void)56 int FaultLoggerPipe::GetReadFd(void)
57 {
58     DFXLOG_DEBUG("%s :: pipe read fd: %d", __func__, fds_[PIPE_READ]);
59     return fds_[PIPE_READ];
60 }
61 
GetWriteFd(void)62 int FaultLoggerPipe::GetWriteFd(void)
63 {
64     DFXLOG_DEBUG("%s :: pipe write fd: %d", __func__, fds_[PIPE_WRITE]);
65     if (!write_) {
66         write_ = true;
67         return fds_[PIPE_WRITE];
68     }
69     return -1;
70 }
71 
Init(void)72 bool FaultLoggerPipe::Init(void)
73 {
74     if (!init_) {
75         if (pipe2(fds_, O_NONBLOCK) != 0) {
76             DFXLOG_ERROR("%s :: Failed to create pipe.", __func__);
77             return false;
78         }
79         DFXLOG_DEBUG("%s :: create pipe.", __func__);
80     }
81     init_ = true;
82     if (!SetSize(MAX_PIPE_SIZE)) {
83         DFXLOG_ERROR("%s :: Failed to set pipe size.", __func__);
84     }
85     return true;
86 }
87 
SetSize(long sz)88 bool FaultLoggerPipe::SetSize(long sz)
89 {
90     if (!init_) {
91         return false;
92     }
93     if (fcntl(fds_[PIPE_READ], F_SETPIPE_SZ, sz) < 0) {
94         return false;
95     }
96     if (fcntl(fds_[PIPE_WRITE], F_SETPIPE_SZ, sz) < 0) {
97         return false;
98     }
99     return true;
100 }
101 
Destroy(void)102 void FaultLoggerPipe::Destroy(void)
103 {
104     if (init_) {
105         DFXLOG_DEBUG("%s :: close pipe.", __func__);
106         Close(fds_[PIPE_READ]);
107         Close(fds_[PIPE_WRITE]);
108     }
109     init_ = false;
110 }
111 
Close(int fd) const112 void FaultLoggerPipe::Close(int fd) const
113 {
114     if (fd > 0) {
115         syscall(SYS_close, fd);
116     }
117 }
118 
FaultLoggerPipe2(uint64_t time,bool isJson)119 FaultLoggerPipe2::FaultLoggerPipe2(uint64_t time, bool isJson)
120 {
121     if (isJson) {
122         faultLoggerJsonPipeBuf_ = std::unique_ptr<FaultLoggerPipe>(new FaultLoggerPipe());
123         faultLoggerJsonPipeRes_ = std::unique_ptr<FaultLoggerPipe>(new FaultLoggerPipe());
124     } else {
125         faultLoggerPipeBuf_ = std::unique_ptr<FaultLoggerPipe>(new FaultLoggerPipe());
126         faultLoggerPipeRes_ = std::unique_ptr<FaultLoggerPipe>(new FaultLoggerPipe());
127     }
128     time_ = time;
129 }
130 
~FaultLoggerPipe2()131 FaultLoggerPipe2::~FaultLoggerPipe2()
132 {
133     faultLoggerPipeBuf_.reset();
134     faultLoggerPipeRes_.reset();
135     faultLoggerJsonPipeBuf_.reset();
136     faultLoggerJsonPipeRes_.reset();
137     time_ = 0;
138 }
139 
FaultLoggerPipeMap()140 FaultLoggerPipeMap::FaultLoggerPipeMap()
141 {
142     std::lock_guard<std::mutex> lck(pipeMapsMutex_);
143     faultLoggerPipes_.clear();
144 }
145 
~FaultLoggerPipeMap()146 FaultLoggerPipeMap::~FaultLoggerPipeMap()
147 {
148     std::lock_guard<std::mutex> lck(pipeMapsMutex_);
149     std::map<int, std::unique_ptr<FaultLoggerPipe2> >::iterator iter = faultLoggerPipes_.begin();
150     while (iter != faultLoggerPipes_.end()) {
151         faultLoggerPipes_.erase(iter++);
152     }
153 }
154 
Set(int pid,uint64_t time,bool isJson)155 void FaultLoggerPipeMap::Set(int pid, uint64_t time, bool isJson)
156 {
157     std::lock_guard<std::mutex> lck(pipeMapsMutex_);
158     if (!Find(pid)) {
159         std::unique_ptr<FaultLoggerPipe2> ptr = std::unique_ptr<FaultLoggerPipe2>(new FaultLoggerPipe2(time, isJson));
160         faultLoggerPipes_.emplace(pid, std::move(ptr));
161     }
162 }
163 
Check(int pid,uint64_t time)164 bool FaultLoggerPipeMap::Check(int pid, uint64_t time)
165 {
166     std::lock_guard<std::mutex> lck(pipeMapsMutex_);
167     std::map<int, std::unique_ptr<FaultLoggerPipe2> >::const_iterator iter = faultLoggerPipes_.find(pid);
168     if (iter != faultLoggerPipes_.end()) {
169         if ((time > faultLoggerPipes_[pid]->time_) && (time - faultLoggerPipes_[pid]->time_) > PIPE_TIMEOUT) {
170             faultLoggerPipes_.erase(iter);
171             return false;
172         }
173         return true;
174     }
175     return false;
176 }
177 
Get(int pid)178 FaultLoggerPipe2* FaultLoggerPipeMap::Get(int pid)
179 {
180     std::lock_guard<std::mutex> lck(pipeMapsMutex_);
181     if (!Find(pid)) {
182         return nullptr;
183     }
184     return faultLoggerPipes_[pid].get();
185 }
186 
Del(int pid)187 void FaultLoggerPipeMap::Del(int pid)
188 {
189     std::lock_guard<std::mutex> lck(pipeMapsMutex_);
190     std::map<int, std::unique_ptr<FaultLoggerPipe2> >::const_iterator iter = faultLoggerPipes_.find(pid);
191     if (iter != faultLoggerPipes_.end()) {
192         faultLoggerPipes_.erase(iter);
193     }
194 }
195 
Find(int pid) const196 bool FaultLoggerPipeMap::Find(int pid) const
197 {
198     std::map<int, std::unique_ptr<FaultLoggerPipe2> >::const_iterator iter = faultLoggerPipes_.find(pid);
199     if (iter != faultLoggerPipes_.end()) {
200         return true;
201     }
202     return false;
203 }
204 } // namespace HiviewDfx
205 } // namespace OHOS
206