• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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 #define _GNU_SOURCE
17 
18 #include <hilog_adapter.h>
19 
20 #include <errno.h>
21 #include <stdint.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <sys/socket.h>
25 #include <sys/time.h>
26 #include <sys/uio.h>
27 #include <sys/un.h>
28 #include <time.h>
29 #include <unistd.h>
30 #include <pthread.h>
31 #include <stdlib.h>
32 #include <fcntl.h>
33 #include <atomic.h>
34 
35 #include "hilog_common.h"
36 #ifdef OHOS_ENABLE_PARAMETER
37 #include "sys_param.h"
38 #endif
39 #include "vsnprintf_s_p.h"
40 
41 #define LOG_LEN 3
42 #define ERROR_FD 2
43 #ifdef OHOS_ENABLE_PARAMETER
44 #define SYSPARAM_LENGTH 32
45 #endif
46 
47 #define INVALID_SOCKET (-1)
48 #define INVALID_RESULT (-1)
49 #define CAS_FAIL (-1)
50 
51 const int SOCKET_TYPE = SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC;
52 const struct sockaddr_un SOCKET_ADDR = {AF_UNIX, SOCKET_FILE_DIR INPUT_SOCKET_NAME};
53 
54 static bool musl_log_enable = false;
55 
56 #ifdef OHOS_ENABLE_PARAMETER
57 static const char *param_name = "musl.log.enable";
58 static const char *g_logLevelParam = "musl.log.level";
59 #endif
60 static int g_logLevel = LOG_WARN;
61 static volatile int g_socketFd = INVALID_SOCKET;
62 
63 extern int __close(int fd);
64 
65 // only generate a new socketFd
GenerateHilogSocketFd()66 static int GenerateHilogSocketFd()
67 {
68     int socketFd = TEMP_FAILURE_RETRY(socket(AF_UNIX, SOCKET_TYPE, 0));
69     if (socketFd == INVALID_SOCKET) {
70         dprintf(ERROR_FD, "HiLogAdapter_init: Can't create socket! Errno: %d\n", errno);
71         return INVALID_SOCKET;
72     }
73     long int result =
74         TEMP_FAILURE_RETRY(connect(socketFd, (const struct sockaddr *)(&SOCKET_ADDR), sizeof(SOCKET_ADDR)));
75     if (result == INVALID_RESULT) {
76         dprintf(ERROR_FD, "HiLogAdapter_init: Can't connect to server. Errno: %d\n", errno);
77         __close(socketFd);
78         return INVALID_SOCKET;
79     }
80     return socketFd;
81 }
82 
83 HILOG_LOCAL_API
CASHilogGlobalSocketFd(int socketFd)84 int CASHilogGlobalSocketFd(int socketFd)
85 {
86     if (socketFd == INVALID_SOCKET) {
87         return INVALID_RESULT;
88     }
89     // we should use CAS to avoid multi-thread problem
90     if (a_cas(&g_socketFd, INVALID_SOCKET, socketFd) != INVALID_SOCKET) {
91         // failure CAS: other threads execute to this branch to close extra fd
92         return CAS_FAIL;
93     }
94     // success CAS: only one thread can execute to this branch
95     return socketFd;
96 }
97 
98 HILOG_LOCAL_API
CheckHilogValid()99 bool CheckHilogValid()
100 {
101     int socketFd = INVALID_SOCKET;
102     // read fd by using atomic operation
103 #ifdef a_ll
104     socketFd = a_ll(&g_socketFd);
105 #else
106     socketFd = g_socketFd;
107 #endif
108     return socketFd != INVALID_SOCKET;
109 }
110 
111 /**
112 * This interface only for static-link style testcase, this symbol should not be exposed in dynamic libraries
113 * Dangerous operation, please do not use in normal business
114 */
115 HILOG_LOCAL_API
RefreshHiLogSocketFd()116 void RefreshHiLogSocketFd()
117 {
118     int socketFd = INVALID_SOCKET;
119     // read fd by using atomic operation
120 #ifdef a_ll
121     socketFd = a_ll(&g_socketFd);
122 #else
123     socketFd = g_socketFd;
124 #endif
125     if (socketFd == INVALID_SOCKET) {
126         return;
127     }
128     a_store(&g_socketFd, INVALID_SOCKET);
129     __close(socketFd);
130 }
131 
InitHilogSocketFd()132 void InitHilogSocketFd()
133 {
134     int socketFd = GenerateHilogSocketFd();
135     if (socketFd == INVALID_SOCKET) {
136         return;
137     }
138     int result = CASHilogGlobalSocketFd(socketFd);
139     if (result == CAS_FAIL) {
140         __close(socketFd);
141     }
142 }
143 
SendMessage(HilogMsg * header,const char * tag,uint16_t tagLen,const char * fmt,uint16_t fmtLen)144 static int SendMessage(HilogMsg *header, const char *tag, uint16_t tagLen, const char *fmt, uint16_t fmtLen)
145 {
146     bool releaseSocket = false;
147     int socketFd = INVALID_SOCKET;
148     // read fd by using atomic operation
149 #ifdef a_ll
150     socketFd = a_ll(&g_socketFd);
151 #else
152     socketFd = g_socketFd;
153 #endif
154     if (socketFd == INVALID_SOCKET) {
155         socketFd = GenerateHilogSocketFd();
156         if (socketFd == INVALID_SOCKET) {
157             return INVALID_RESULT;
158         }
159         int result = CASHilogGlobalSocketFd(socketFd);
160         if (result == CAS_FAIL) {
161             releaseSocket = true;
162         }
163     }
164 
165     struct timespec ts = {0};
166     (void)clock_gettime(CLOCK_REALTIME, &ts);
167     struct timespec ts_mono = {0};
168     (void)clock_gettime(CLOCK_MONOTONIC, &ts_mono);
169     header->tv_sec = (uint32_t)(ts.tv_sec);
170     header->tv_nsec = (uint32_t)(ts.tv_nsec);
171     header->mono_sec = (uint32_t)(ts_mono.tv_sec);
172     header->len = sizeof(HilogMsg) + tagLen + fmtLen;
173     header->tag_len = tagLen;
174 
175     struct iovec vec[LOG_LEN] = {0};
176     vec[0].iov_base = header;                   // 0 : index of hos log header
177     vec[0].iov_len = sizeof(HilogMsg);          // 0 : index of hos log header
178     vec[1].iov_base = (void *)((char *)(tag));  // 1 : index of log tag
179     vec[1].iov_len = tagLen;                    // 1 : index of log tag
180     vec[2].iov_base = (void *)((char *)(fmt));  // 2 : index of log content
181     vec[2].iov_len = fmtLen;                    // 2 : index of log content
182     int ret = TEMP_FAILURE_RETRY(writev(socketFd, vec, LOG_LEN));
183     if (releaseSocket) {
184         __close(socketFd);
185     }
186     return ret;
187 }
188 
189 HILOG_LOCAL_API
HiLogAdapterPrintArgs(const LogType type,const LogLevel level,const unsigned int domain,const char * tag,const char * fmt,va_list ap)190 int HiLogAdapterPrintArgs(
191     const LogType type, const LogLevel level, const unsigned int domain, const char *tag, const char *fmt, va_list ap)
192 {
193     char buf[MAX_LOG_LEN] = {0};
194 
195     vsnprintfp_s(buf, MAX_LOG_LEN, MAX_LOG_LEN - 1, true, fmt, ap);
196 
197     size_t tagLen = strnlen(tag, MAX_TAG_LEN - 1);
198     size_t logLen = strnlen(buf, MAX_LOG_LEN - 1);
199     HilogMsg header = {0};
200     header.type = type;
201     header.level = level;
202 #ifndef __RECV_MSG_WITH_UCRED_
203     header.pid = getpid();
204 #endif
205     header.tid = (uint32_t)(gettid());
206     header.domain = domain;
207 
208     return SendMessage(&header, tag, tagLen + 1, buf, logLen + 1);
209 }
210 
211 HILOG_LOCAL_API
HiLogAdapterPrint(LogType type,LogLevel level,unsigned int domain,const char * tag,const char * fmt,...)212 int HiLogAdapterPrint(LogType type, LogLevel level, unsigned int domain, const char *tag, const char *fmt, ...)
213 {
214     if (!HiLogAdapterIsLoggable(domain, tag, level)) {
215         return -1;
216     }
217 
218     int ret;
219     va_list ap;
220     va_start(ap, fmt);
221     ret = HiLogAdapterPrintArgs(type, level, domain, tag, fmt, ap);
222     va_end(ap);
223     return ret;
224 }
225 
226 HILOG_LOCAL_API
HiLogAdapterVaList(LogType type,LogLevel level,unsigned int domain,const char * tag,const char * fmt,va_list ap)227 int HiLogAdapterVaList(LogType type, LogLevel level, unsigned int domain, const char *tag, const char *fmt, va_list ap)
228 {
229     if (!HiLogAdapterIsLoggable(domain, tag, level)) {
230         return -1;
231     }
232     return HiLogAdapterPrintArgs(type, level, domain, tag, fmt, ap);
233 }
234 
is_musl_log_enable()235 bool is_musl_log_enable()
236 {
237     if (getpid() == 1) {
238         return false;
239     }
240     return musl_log_enable;
241 }
242 
HiLogAdapterIsLoggable(unsigned int domain,const char * tag,LogLevel level)243 bool HiLogAdapterIsLoggable(unsigned int domain, const char *tag, LogLevel level)
244 {
245     if (tag == NULL || level < g_logLevel || level <= LOG_LEVEL_MIN || level >= LOG_LEVEL_MAX) {
246         return false;
247     }
248 
249     if (!is_musl_log_enable()) {
250         return false;
251     }
252 
253     return true;
254 }
255 
256 #ifdef OHOS_ENABLE_PARAMETER
get_bool_sysparam(CachedHandle cachedhandle)257 bool get_bool_sysparam(CachedHandle cachedhandle)
258 {
259     const char *param_value = CachedParameterGet(cachedhandle);
260     if (param_value != NULL) {
261         if (strcmp(param_value, "true") == 0) {
262             return true;
263         }
264     }
265     return false;
266 }
267 
resetLogLevel()268 void resetLogLevel()
269 {
270     static CachedHandle muslLogLevelHandle = NULL;
271     if (muslLogLevelHandle == NULL) {
272         muslLogLevelHandle = CachedParameterCreate(g_logLevelParam, "WARN");
273     }
274     const char *value = CachedParameterGet(muslLogLevelHandle);
275     if (value != NULL) {
276         if (!strcmp(value, "DEBUG")) {
277             g_logLevel = LOG_DEBUG;
278         } else if (!strcmp(value, "INFO")) {
279             g_logLevel = LOG_INFO;
280         } else if (!strcmp(value, "WARN")) {
281             g_logLevel = LOG_WARN;
282         } else if (!strcmp(value, "ERROR")) {
283             g_logLevel = LOG_ERROR;
284         } else if (!strcmp(value, "FATAL")) {
285             g_logLevel = LOG_FATAL;
286         } else {
287             g_logLevel = LOG_WARN;
288         }
289     } else {
290         g_logLevel = LOG_WARN;
291     }
292 }
293 
294 #endif
295 
musl_log_reset()296 void musl_log_reset()
297 {
298 #if (defined(OHOS_ENABLE_PARAMETER))
299     static CachedHandle musl_log_Handle = NULL;
300     if (musl_log_Handle == NULL) {
301         musl_log_Handle = CachedParameterCreate(param_name, "false");
302     }
303     musl_log_enable = get_bool_sysparam(musl_log_Handle);
304     resetLogLevel();
305 #elif (defined(ENABLE_MUSL_LOG))
306     musl_log_enable = true;
307 #endif
308 }
309