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 #include <hilog_adapter.h>
17 #include <stdlib.h>
18 #include "functionalext.h"
19 #include "test.h"
20 #include <stdio.h>
21 #include <stdbool.h>
22 #include <time.h>
23 #include <errno.h>
24 #include <pthread.h>
25 #include <sys/un.h>
26 #include <bits/alltypes.h>
27 #include <sys/socket.h>
28 #include <linux/socket.h>
29 #include <fcntl.h>
30 #include <dirent.h>
31 #include <securec.h>
32
33 #define MUSL_LOG_TYPE LOG_CORE
34 #define MUSL_LOG_DOMAIN 0xD003F00
35 #define MUSL_LOG_TAG "MUSL"
36 #define LOG_ERROR (6)
37 #define CLOSE_FD_COUNT (1024)
38
39 #define ENABLE_LOG "param set musl.log.enable true"
40 #define LOG_LEVEL_ERROR "param set musl.log.level ERROR"
41
42 #define MUSL_LOGE(...) ((void)HiLogAdapterPrint(MUSL_LOG_TYPE, LOG_ERROR, MUSL_LOG_DOMAIN, MUSL_LOG_TAG, __VA_ARGS__))
43
44 #define PRINT_STRING_A "HilogAdapterPrinttest_a"
45 #define PRINT_STRING_B "HilogAdapterPrinttest_b"
46 #define PRINT_STRING_C "HilogAdapterPrinttest_c"
47
48 #define ZERO (0)
49 #define TWO (2)
50 #define THREE (3)
51 #define NEGATIVE_ONE (-1)
52 #define INVALID_SOCKET (-1)
53 #define THREAD_COUNT (10)
54 #define STR_LENGTH (20)
55 char str[THREAD_COUNT][STR_LENGTH];
56
GenerateRandomString(char * randomString,int index)57 void GenerateRandomString(char* randomString, int index)
58 {
59 #define RANDOM_STRING_LENGTH (16)
60 #define RANDOM_STRING_END (18)
61 #define RANDOM_STRING_START (2)
62 // 将索引转换为字符串并拼接到随机字符串前面
63 (void)sprintf_s(randomString, STR_LENGTH, "%02d", index);
64
65 char charset[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
66 int r = 0;
67 int num = 0;
68 int fd = open("/dev/random", O_RDONLY);
69 if (fd == NEGATIVE_ONE) {
70 strcpy_s(randomString + RANDOM_STRING_START, RANDOM_STRING_LENGTH, "MUSLHILOGFIXED");
71 } else {
72 for (int i = RANDOM_STRING_START; i < RANDOM_STRING_LENGTH; i++) {
73 read(fd, &r, sizeof(int));
74 // 非安全场景,使用种子确保随机字符串每次运行都不一样
75 randomString[i] = charset[r % (sizeof(charset) - 1)];
76 }
77 }
78 close(fd);
79 randomString[RANDOM_STRING_END] = '\0'; // 添加字符串结尾符
80 }
81
82 // 检查是否有相应的日志生成,如果有当前日志,则返回true,如果没有则返回false
CheckHiLogPrint(char * needToMatch)83 bool CheckHiLogPrint(char *needToMatch)
84 {
85 #define COMMAND_SIZE (50)
86 #define READ_SIZE (49)
87 #define BUFFER_SIZE (1024)
88 #define FAIL_CLOSE (-1)
89 bool flag = false;
90 // 1. 通过system函数读取当前hilog日志信息
91 char command[] = "/bin/hilog -x | grep ";
92 char finalCommand[COMMAND_SIZE];
93 int res = snprintf_s(finalCommand, COMMAND_SIZE, READ_SIZE, "%s%s", command, needToMatch);
94 if (res == NEGATIVE_ONE) {
95 printf("CheckHiLogPrint command generate snprintf_s failed\n");
96 return false;
97 }
98 finalCommand[READ_SIZE] = '\0';
99 char buffer[BUFFER_SIZE];
100 FILE* pipe;
101 pipe = popen(finalCommand, "r");
102 if (pipe == NULL) {
103 printf("CheckHiLogPrint: Failed to run command\n");
104 return false;
105 }
106
107 // 读取命令输出并打印
108 while (fgets(buffer, BUFFER_SIZE, pipe) != NULL) {
109 printf("%s", buffer);
110 flag = true;
111 }
112
113 // 关闭管道并获取返回值
114 int returnValue = pclose(pipe);
115 if (returnValue == FAIL_CLOSE) {
116 printf("CheckHiLogPrint pclose failed returnValue=-1 errno=%d\n", errno);
117 }
118 return flag;
119 }
120
121 // 检测有多少fd链到了hilogd
CheckHiLogdLinked()122 int CheckHiLogdLinked()
123 {
124 #define PROC_PATH_LENGTH (64)
125 int result = 0;
126 char proc_path[PROC_PATH_LENGTH];
127 int res = snprintf_s(proc_path, PROC_PATH_LENGTH, PROC_PATH_LENGTH - 1, "/proc/%d/fd", getpid());
128 if (res == NEGATIVE_ONE) {
129 printf("CheckHiLogdLinked getpid snprintf_s failed\n");
130 return ZERO;
131 }
132 DIR *dir = opendir(proc_path);
133 if (dir == NULL) {
134 return result;
135 }
136 struct dirent *entry;
137 while ((entry = readdir(dir)) != NULL) {
138 if (entry->d_type != DT_LNK) {
139 continue;
140 }
141 char fd_path[128];
142 res = snprintf_s(fd_path, sizeof(fd_path), sizeof(fd_path) - 1, "%s/%s", proc_path, entry->d_name);
143 if (res == NEGATIVE_ONE) {
144 printf("CheckHiLogdLinked fd search snprintf_s failed\n");
145 return ZERO;
146 }
147
148 char target[256];
149 ssize_t len = readlink(fd_path, target, sizeof(target) - 1);
150 if (len == -1) {
151 continue;
152 }
153 target[len] = '\0';
154 if (!strstr(target, "socket")) {
155 continue;
156 }
157 struct sockaddr_un addr;
158 socklen_t addr_len = sizeof(addr);
159
160 // 获取连接到 socket 的对端地址信息
161 getpeername(atoi(entry->d_name), (struct sockaddr *)&addr, &addr_len);
162 if (strstr(addr.sun_path, "hilogInput")) {
163 printf("FD: %s Connected to: %s\n", entry->d_name, addr.sun_path);
164 result++;
165 }
166 }
167
168 closedir(dir);
169 return result;
170 }
171
172
173 // 子线程打印日志执行的函数
FunctionPrintLog(void * arg)174 void* FunctionPrintLog(void* arg)
175 {
176 int index = (int)arg;
177 int ret = HiLogAdapterPrint(MUSL_LOG_TYPE, LOG_ERROR, MUSL_LOG_DOMAIN, MUSL_LOG_TAG,
178 "FunctionPrintLog %{public}s", str[index]);
179 return NULL;
180 }
181 /**
182 * @tc.name : HiLogAdapterPrint_0010
183 * @tc.desc : Test HiLogAdapterPrint after musl_log_reset
184 * @tc.level : Level 2
185 */
HiLogAdapterPrint_0010(void)186 static void HiLogAdapterPrint_0010(void)
187 {
188 musl_log_reset();
189 int ret = HiLogAdapterPrint(MUSL_LOG_TYPE, LOG_ERROR, MUSL_LOG_DOMAIN, MUSL_LOG_TAG, PRINT_STRING_A);
190 EXPECT_NE("HiLogAdapterPrint_0010", ret, 0);
191 // 同时也要查看hilog
192 EXPECT_EQ("HiLogAdapterPrint_0010", CheckHiLogPrint(PRINT_STRING_A), true);
193 ret = HiLogAdapterPrint(MUSL_LOG_TYPE, LOG_INFO, MUSL_LOG_DOMAIN, MUSL_LOG_TAG, PRINT_STRING_B);
194 EXPECT_EQ("HiLogAdapterPrint_0010", ret, -1);
195 }
196
197 /**
198 * @tc.name : HilogAdapterPrint_0020
199 * @tc.desc : Test single thread HilogAdapterPrint after hilog fd close
200 * @tc.level : Level 2
201 */
HilogAdapterPrint_0020(void)202 static void HilogAdapterPrint_0020(void)
203 {
204 musl_log_reset();
205 // We need to refresh the hilog socket to close previous socket
206 RefreshHiLogSocketFd();
207 // 前置条件:校验g_socketFd无效
208 EXPECT_EQ("HilogAdapterPrint_0020 CheckHilogInvalid", CheckHilogValid(), ZERO);
209 int ret = HiLogAdapterPrint(MUSL_LOG_TYPE, LOG_ERROR, MUSL_LOG_DOMAIN, MUSL_LOG_TAG, PRINT_STRING_C);
210 // 检查g_socketFd有效
211 EXPECT_NE("HilogAdapterPrint_0020 CheckHilogValid", CheckHilogValid(), ZERO);
212 // 检查write正常
213 EXPECT_GT("HiLogAdapterPrint_0020", ret, 0);
214 bool result = CheckHiLogPrint(PRINT_STRING_C);
215 // 检查有日志生成
216 EXPECT_EQ("HilogAdapterPrint_0020_CheckHiLogPrint", result, true);
217 }
218
219 /**
220 * @tc.name : HilogAdapterPrint_0030
221 * @tc.desc : dls3阶段初始化异常时,线程自己初始化成功,
222 * 单线程:预期是能够替换g_socketFd,并能够正常打印日志
223 * 多线程:预期是能够替换g_socketFd,并能够正常打印日志,且fd未发生泄漏
224 * @tc.level : Level 2
225 */
HilogAdapterPrint_0030(void)226 static void HilogAdapterPrint_0030(void)
227 {
228 musl_log_reset();
229 // 关闭socketFd
230 RefreshHiLogSocketFd();
231 // 前置条件:校验g_socketFd无效
232 EXPECT_EQ("HilogAdapterPrint_0030 CheckHilogInvalid", CheckHilogValid(), ZERO);
233 pthread_t threads[THREAD_COUNT];
234 // 创建线程并发打印,每个线程打印的日志都不能丢
235 for (int i = ZERO; i < THREAD_COUNT; i++) {
236 // 生成一个随机字符串,然后将下标通过值传递给子线程,让子线程拿到全局的数据
237 GenerateRandomString(str[i], i);
238 if (pthread_create(&threads[i], NULL, FunctionPrintLog, (void *)i) != 0) {
239 fprintf(stderr, "Failed to create thread %d\n", i);
240 }
241 }
242 // 检查g_socketFd有效
243 EXPECT_NE("HilogAdapterPrint_0030 CheckHilogValid", CheckHilogValid(), ZERO);
244 // 等待线程执行完毕
245 for (int i = ZERO; i < THREAD_COUNT; i++) {
246 if (pthread_join(threads[i], NULL) != 0) {
247 fprintf(stderr, "Failed to join thread %d\n", i);
248 } else {
249 // 在这里判断当前日志是否打印成功
250 bool result = CheckHiLogPrint(str[i]);
251 EXPECT_EQ("HilogAdapterPrint_0030_CheckHiLogPrint", result, true);
252 }
253 }
254
255 // 检查有几个socket链到了hilogInput
256 int result = CheckHiLogdLinked();
257 EXPECT_EQ("CheckHiLogdLinked failed", result, TWO);
258 }
259
main(void)260 int main(void)
261 {
262 // 解除限制
263 system("/bin/hilog -Q pidoff");
264 system("/bin/hilog -Q domainoff");
265
266 system(ENABLE_LOG);
267 system(LOG_LEVEL_ERROR);
268 HiLogAdapterPrint_0010();
269 HilogAdapterPrint_0020();
270 HilogAdapterPrint_0030();
271
272 // 恢复限制
273 system("/bin/hilog -Q pidon");
274 system("/bin/hilog -Q domainon");
275 return t_status;
276 }
277