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 "hilog_base/log_base.h"
17
18 #include <hilog_common.h>
19 #include <vsnprintf_s_p.h>
20
21 #include <array>
22 #include <atomic>
23 #include <cstring>
24 #include <fstream>
25 #include <iostream>
26 #include <sys/socket.h>
27 #include <sys/time.h>
28 #include <sys/uio.h>
29 #include <sys/un.h>
30 #include <unistd.h>
31
32 namespace {
33 constexpr int SOCKET_TYPE = SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC;
34 constexpr int INVALID_SOCKET = -1;
35 constexpr size_t HILOG_VEC_MAX_SIZE = 4;
36 constexpr size_t HILOG_VEC_SIZE_OHCORE = 4;
37 constexpr size_t HILOG_VEC_SIZE_OH = 3;
38 constexpr int32_t MAX_DOMAIN_TAGSIZE = 64;
39
40 struct SocketHandler {
41 std::atomic_int socketFd {INVALID_SOCKET};
42 std::atomic_bool isConnected {false};
~SocketHandler__anonb53613a30111::SocketHandler43 ~SocketHandler()
44 {
45 int currentFd = socketFd.exchange(INVALID_SOCKET);
46 if (currentFd >= 0) {
47 close(currentFd);
48 }
49 }
50 };
51
52 typedef struct LogTime {
53 uint32_t tvSec;
54 uint32_t tvNsec;
55 } __attribute__((__packed__)) LogTime;
56
57 typedef struct __attribute__((__packed__)) {
58 uint8_t id;
59 uint16_t tid;
60 uint16_t ohPid;
61 LogTime realtime;
62 } LogHeader;
63
64 struct HiLogMsgInfo {
65 HilogMsg *header_;
66 const char *tag_;
67 uint16_t tagLen_;
68 const char *fmt_;
69 uint16_t fmtLen_;
HiLogMsgInfo__anonb53613a30111::HiLogMsgInfo70 HiLogMsgInfo(HilogMsg *header, const char *tag, uint16_t tagLen, const char *fmt, uint16_t fmtLen)
71 {
72 header_ = header;
73 tag_ = tag;
74 tagLen_ = tagLen;
75 fmt_ = fmt;
76 fmtLen_ = fmtLen;
77 }
78 };
79
80 typedef enum {
81 TYPE_OH = 0,
82 TYPE_OHCORE = 1,
83 } HiLogProtocolType;
84
85 sockaddr_un g_sockAddr = {AF_UNIX, SOCKET_FILE_DIR INPUT_SOCKET_NAME};
86 HiLogProtocolType g_protocolType = TYPE_OH;
87
88 struct Initializer {
Initializer__anonb53613a30111::Initializer89 Initializer()
90 {
91 constexpr char configFile[] = "/system/etc/hilog_config";
92 if (access(configFile, F_OK) != 0) {
93 return;
94 }
95 std::ifstream file;
96 file.open(configFile);
97 if (file.fail()) {
98 std::cerr << "open hilog_config config file failed" << std::endl;
99 return;
100 }
101
102 std::string sock;
103 std::string protocol;
104 file >> sock >> protocol;
105 if (auto posColon = sock.find(":"); posColon != sock.npos) {
106 std::string sockPath = sock.substr(posColon + 1);
107 size_t pos = 0;
108 while (pos < sockPath.size() && pos < (sizeof(g_sockAddr.sun_path) - 1)) {
109 g_sockAddr.sun_path[pos] = sockPath[pos];
110 pos++;
111 }
112 g_sockAddr.sun_path[pos] = '\0';
113 }
114 if (auto posColon = protocol.find(":"); posColon != protocol.npos) {
115 g_protocolType = protocol.substr(posColon + 1) == "ohcore" ? TYPE_OHCORE : TYPE_OH;
116 }
117 file.close();
118 }
119 };
120 Initializer g_initializer;
121
GenerateFD()122 static int GenerateFD()
123 {
124 int tmpFd = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCKET_TYPE, 0));
125 int res = tmpFd;
126 if (tmpFd == 0) {
127 res = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCKET_TYPE, 0));
128 close(tmpFd);
129 }
130 return res;
131 }
132
CheckSocket(SocketHandler & socketHandler)133 static int CheckSocket(SocketHandler& socketHandler)
134 {
135 int currentFd = socketHandler.socketFd.load();
136 if (currentFd >= 0) {
137 return currentFd;
138 }
139
140 int fd = GenerateFD();
141 if (fd < 0) {
142 std::cerr << "Can't get hilog socket! Errno: " << errno << std::endl;
143 return fd;
144 }
145
146 currentFd = INVALID_SOCKET;
147 if (!socketHandler.socketFd.compare_exchange_strong(currentFd, fd)) {
148 close(fd);
149 return currentFd;
150 }
151 return fd;
152 }
153
CheckConnection(SocketHandler & socketHandler)154 static int CheckConnection(SocketHandler& socketHandler)
155 {
156 bool isConnected = socketHandler.isConnected.load();
157 if (isConnected) {
158 return 0;
159 }
160
161 isConnected = socketHandler.isConnected.load();
162 if (isConnected) {
163 return 0;
164 }
165
166 auto result = TEMP_FAILURE_RETRY(connect(socketHandler.socketFd.load(),
167 reinterpret_cast<const sockaddr*>(&g_sockAddr), sizeof(g_sockAddr)));
168 if (result < 0) {
169 std::cerr << "Can't connect to hilog server. Errno: " << errno << std::endl;
170 return result;
171 }
172 socketHandler.isConnected.store(true);
173 return 0;
174 }
175
BuildHilogMessageForOhCore(struct HiLogMsgInfo * logMsgInfo,LogHeader & logHeader,uint16_t & logLevel,char tagBuf[],struct iovec * vec)176 static size_t BuildHilogMessageForOhCore(struct HiLogMsgInfo* logMsgInfo, LogHeader& logHeader, uint16_t& logLevel,
177 char tagBuf[], struct iovec *vec)
178 {
179 struct timespec ts = {0};
180 (void)clock_gettime(CLOCK_REALTIME, &ts);
181 logHeader.realtime.tvSec = static_cast<uint32_t>(ts.tv_sec);
182 logHeader.realtime.tvNsec = static_cast<uint32_t>(ts.tv_nsec);
183 logHeader.tid = static_cast<uint32_t>(gettid());
184 logHeader.ohPid = static_cast<uint32_t>(getpid());
185 logLevel = logMsgInfo->header_->level;
186 constexpr uint32_t domainFilter = 0x000FFFFF;
187 if (vsnprintfp_s(tagBuf, MAX_DOMAIN_TAGSIZE, MAX_DOMAIN_TAGSIZE - 1, false, "%05X/%s",
188 (logMsgInfo->header_->domain & domainFilter), logMsgInfo->tag_) < 0) {
189 return 0;
190 }
191
192 vec[0].iov_base = reinterpret_cast<unsigned char *>(&logHeader); // 0 : index of hos log header
193 vec[0].iov_len = sizeof(logHeader); // 0 : index of hos log header
194 vec[1].iov_base = reinterpret_cast<unsigned char *>(&logLevel); // 1 : index of log level
195 vec[1].iov_len = 1; // 1 : index of log level
196 vec[2].iov_base = reinterpret_cast<void *>(const_cast<char*>(tagBuf)); // 2 : index of log tag
197 vec[2].iov_len = strlen(tagBuf) + 1; // 2 : index of log tag
198 vec[3].iov_base = reinterpret_cast<void *>(const_cast<char*>(logMsgInfo->fmt_)); // 3 : index of log format
199 vec[3].iov_len = logMsgInfo->fmtLen_; // 3 : index of log format
200 return HILOG_VEC_SIZE_OHCORE;
201 }
202
BuildHilogMessageForOh(struct HiLogMsgInfo * logMsgInfo,struct iovec * vec)203 static size_t BuildHilogMessageForOh(struct HiLogMsgInfo* logMsgInfo, struct iovec *vec)
204 {
205 struct timespec ts = {0};
206 (void)clock_gettime(CLOCK_REALTIME, &ts);
207 struct timespec tsMono = {0};
208 (void)clock_gettime(CLOCK_MONOTONIC, &tsMono);
209 logMsgInfo->header_->tv_sec = static_cast<uint32_t>(ts.tv_sec);
210 logMsgInfo->header_->tv_nsec = static_cast<uint32_t>(ts.tv_nsec);
211 logMsgInfo->header_->mono_sec = static_cast<uint32_t>(tsMono.tv_sec);
212 logMsgInfo->header_->len = sizeof(HilogMsg) + logMsgInfo->tagLen_ + logMsgInfo->fmtLen_;
213 logMsgInfo->header_->tag_len = logMsgInfo->tagLen_;
214
215 vec[0].iov_base = logMsgInfo->header_; // 0 : index of hos log header
216 vec[0].iov_len = sizeof(HilogMsg); // 0 : index of hos log header
217 vec[1].iov_base = reinterpret_cast<void*>(const_cast<char *>(logMsgInfo->tag_)); // 1 : index of log tag
218 vec[1].iov_len = logMsgInfo->tagLen_; // 1 : index of log tag
219 vec[2].iov_base = reinterpret_cast<void*>(const_cast<char *>(logMsgInfo->fmt_)); // 2 : index of log content
220 vec[2].iov_len = logMsgInfo->fmtLen_; // 2 : index of log content
221 return HILOG_VEC_SIZE_OH;
222 }
223
SendMessage(HilogMsg * header,const char * tag,uint16_t tagLen,const char * fmt,uint16_t fmtLen)224 static int SendMessage(HilogMsg *header, const char *tag, uint16_t tagLen, const char *fmt, uint16_t fmtLen)
225 {
226 SocketHandler socketHandler;
227 int ret = CheckSocket(socketHandler);
228 if (ret < 0) {
229 return ret;
230 }
231 ret = CheckConnection(socketHandler);
232 if (ret < 0) {
233 return ret;
234 }
235
236 struct iovec vec[HILOG_VEC_MAX_SIZE];
237 struct HiLogMsgInfo msgInfo(header, tag, tagLen, fmt, fmtLen);
238 LogHeader logHeader;
239 uint16_t logLevel = 0;
240 char tagBuf[MAX_DOMAIN_TAGSIZE] = {0};
241 auto vecSize = (g_protocolType == TYPE_OHCORE) ?
242 BuildHilogMessageForOhCore(&msgInfo, logHeader, logLevel, tagBuf, vec) :
243 BuildHilogMessageForOh(&msgInfo, vec);
244 if (vecSize == 0) {
245 std::cerr << "BuildHilogMessage failed ret = " << vecSize << std::endl;
246 return RET_FAIL;
247 }
248 return TEMP_FAILURE_RETRY(::writev(socketHandler.socketFd.load(), vec, vecSize));
249 }
250
HiLogBasePrintArgs(const LogType type,const LogLevel level,const unsigned int domain,const char * tag,const char * fmt,va_list ap)251 static int HiLogBasePrintArgs(const LogType type, const LogLevel level, const unsigned int domain, const char *tag,
252 const char *fmt, va_list ap)
253 {
254 if (!HiLogBaseIsLoggable(domain, tag, level)) {
255 return -1;
256 }
257
258 char buf[MAX_LOG_LEN] = {0};
259
260 vsnprintfp_s(buf, MAX_LOG_LEN, MAX_LOG_LEN - 1, true, fmt, ap);
261
262 auto tagLen = strnlen(tag, MAX_TAG_LEN - 1);
263 auto logLen = strnlen(buf, MAX_LOG_LEN - 1);
264 HilogMsg header = {0};
265 header.type = type;
266 header.level = level;
267 #ifndef __RECV_MSG_WITH_UCRED_
268 header.pid = getpid();
269 #endif
270 header.tid = static_cast<uint32_t>(gettid());
271 header.domain = domain;
272
273 return SendMessage(&header, tag, tagLen + 1, buf, logLen + 1);
274 }
275
276 } // namespace
277
HiLogBasePrint(LogType type,LogLevel level,unsigned int domain,const char * tag,const char * fmt,...)278 int HiLogBasePrint(LogType type, LogLevel level, unsigned int domain, const char *tag, const char *fmt, ...)
279 {
280 int ret;
281 va_list ap;
282 va_start(ap, fmt);
283 ret = HiLogBasePrintArgs(type, level, domain, tag, fmt, ap);
284 va_end(ap);
285 return ret;
286 }
287
HiLogBaseIsLoggable(unsigned int domain,const char * tag,LogLevel level)288 bool HiLogBaseIsLoggable(unsigned int domain, const char *tag, LogLevel level)
289 {
290 if ((level <= LOG_LEVEL_MIN) || (level >= LOG_LEVEL_MAX) || tag == nullptr) {
291 return false;
292 }
293 return true;
294 }
295