• 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 #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