• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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