• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 "appspawn_client.h"
17 
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <pthread.h>
21 #include <string.h>
22 #include <unistd.h>
23 
24 #include <linux/in.h>
25 #include <linux/socket.h>
26 #include <linux/tcp.h>
27 #include <sys/socket.h>
28 #include <sys/time.h>
29 #include <sys/types.h>
30 #include <sys/un.h>
31 
32 #include "appspawn_mount_permission.h"
33 #include "appspawn_hook.h"
34 #include "appspawn_utils.h"
35 #include "parameter.h"
36 #include "securec.h"
37 
38 static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
39 static AppSpawnReqMsgMgr *g_clientInstance[CLIENT_MAX] = {NULL};
40 
GetDefaultTimeout(uint32_t def)41 static uint32_t GetDefaultTimeout(uint32_t def)
42 {
43     uint32_t value = def;
44     char data[32] = {};  // 32 length
45     int ret = GetParameter("persist.appspawn.reqMgr.timeout", "0", data, sizeof(data));
46     if (ret > 0 && strcmp(data, "0") != 0) {
47         errno = 0;
48         value = atoi(data);
49         return (errno != 0) ? def : value;
50     }
51     return value;
52 }
53 
InitClientInstance(AppSpawnClientType type)54 static int InitClientInstance(AppSpawnClientType type)
55 {
56     pthread_mutex_lock(&g_mutex);
57     if (g_clientInstance[type] != NULL) {
58         pthread_mutex_unlock(&g_mutex);
59         return 0;
60     }
61     AppSpawnReqMsgMgr *clientInstance = malloc(sizeof(AppSpawnReqMsgMgr) + RECV_BLOCK_LEN);
62     if (clientInstance == NULL) {
63         pthread_mutex_unlock(&g_mutex);
64         return APPSPAWN_SYSTEM_ERROR;
65     }
66     // init
67     clientInstance->type = type;
68     clientInstance->msgNextId = 1;
69     clientInstance->timeout = GetDefaultTimeout(TIMEOUT_DEF);
70     clientInstance->maxRetryCount = MAX_RETRY_SEND_COUNT;
71     clientInstance->socketId = -1;
72     pthread_mutex_init(&clientInstance->mutex, NULL);
73     // init recvBlock
74     OH_ListInit(&clientInstance->recvBlock.node);
75     clientInstance->recvBlock.blockSize = RECV_BLOCK_LEN;
76     clientInstance->recvBlock.currentIndex = 0;
77     g_clientInstance[type] = clientInstance;
78     pthread_mutex_unlock(&g_mutex);
79     return 0;
80 }
81 
CloseClientSocket(int socketId)82 APPSPAWN_STATIC void CloseClientSocket(int socketId)
83 {
84     APPSPAWN_LOGV("Closed socket with fd %{public}d", socketId);
85     if (socketId >= 0) {
86         int flag = 0;
87         setsockopt(socketId, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int));
88         close(socketId);
89     }
90 }
91 
CreateClientSocket(uint32_t type,uint32_t timeout)92 APPSPAWN_STATIC int CreateClientSocket(uint32_t type, uint32_t timeout)
93 {
94     const char *socketName = type == CLIENT_FOR_APPSPAWN ? APPSPAWN_SOCKET_NAME : NWEBSPAWN_SOCKET_NAME;
95     int socketFd = socket(AF_UNIX, SOCK_STREAM, 0);  // SOCK_SEQPACKET
96     APPSPAWN_CHECK(socketFd >= 0, return -1,
97         "Socket socket fd: %{public}s error: %{public}d", socketName, errno);
98     int ret = 0;
99     do {
100         int flag = 1;
101         ret = setsockopt(socketFd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int));
102         flag = 1;
103         ret = setsockopt(socketFd, SOL_SOCKET, SO_PASSCRED, &flag, sizeof(flag));
104         APPSPAWN_CHECK(ret == 0, break, "Set opt SO_PASSCRED name: %{public}s error: %{public}d", socketName, errno);
105 
106         struct timeval timeoutVal = {timeout, 0};
107         ret = setsockopt(socketFd, SOL_SOCKET, SO_SNDTIMEO, &timeoutVal, sizeof(timeoutVal));
108         APPSPAWN_CHECK(ret == 0, break, "Set opt SO_SNDTIMEO name: %{public}s error: %{public}d", socketName, errno);
109         ret = setsockopt(socketFd, SOL_SOCKET, SO_RCVTIMEO, &timeoutVal, sizeof(timeoutVal));
110         APPSPAWN_CHECK(ret == 0, break, "Set opt SO_RCVTIMEO name: %{public}s error: %{public}d", socketName, errno);
111 
112         ret = APPSPAWN_SYSTEM_ERROR;
113         struct sockaddr_un addr;
114         socklen_t pathSize = sizeof(addr.sun_path);
115         int pathLen = snprintf_s(addr.sun_path, pathSize, (pathSize - 1), "%s%s", APPSPAWN_SOCKET_DIR, socketName);
116         APPSPAWN_CHECK(pathLen > 0, break, "Format path %{public}s error: %{public}d", socketName, errno);
117         addr.sun_family = AF_LOCAL;
118         socklen_t socketAddrLen = offsetof(struct sockaddr_un, sun_path) + pathLen + 1;
119         ret = connect(socketFd, (struct sockaddr *)(&addr), socketAddrLen);
120         APPSPAWN_CHECK(ret == 0, break,
121             "Failed to connect %{public}s error: %{public}d", addr.sun_path, errno);
122         APPSPAWN_LOGI("Create socket success %{public}s socketFd: %{public}d", addr.sun_path, socketFd);
123         return socketFd;
124     } while (0);
125     CloseClientSocket(socketFd);
126     return -1;
127 }
128 
ReadMessage(int socketFd,uint32_t sendMsgId,uint8_t * buf,int len,AppSpawnResult * result)129 static int ReadMessage(int socketFd, uint32_t sendMsgId, uint8_t *buf, int len, AppSpawnResult *result)
130 {
131     ssize_t rLen = TEMP_FAILURE_RETRY(read(socketFd, buf, len));
132     APPSPAWN_CHECK(rLen >= 0, return APPSPAWN_TIMEOUT,
133         "Read message from fd %{public}d rLen %{public}zd errno: %{public}d", socketFd, rLen, errno);
134     if ((size_t)rLen >= sizeof(AppSpawnResponseMsg)) {
135         AppSpawnResponseMsg *msg = (AppSpawnResponseMsg *)(buf);
136         APPSPAWN_CHECK_ONLY_LOG(sendMsgId == msg->msgHdr.msgId,
137             "Invalid msg recvd %{public}u %{public}u", sendMsgId, msg->msgHdr.msgId);
138         return memcpy_s(result, sizeof(AppSpawnResult), &msg->result, sizeof(msg->result));
139     }
140     return APPSPAWN_TIMEOUT;
141 }
142 
WriteMessage(int socketFd,const uint8_t * buf,ssize_t len)143 static int WriteMessage(int socketFd, const uint8_t *buf, ssize_t len)
144 {
145     ssize_t written = 0;
146     ssize_t remain = len;
147     const uint8_t *offset = buf;
148     for (ssize_t wLen = 0; remain > 0; offset += wLen, remain -= wLen, written += wLen) {
149         wLen = send(socketFd, offset, remain, MSG_NOSIGNAL);
150         APPSPAWN_LOGV("Write msg errno: %{public}d %{public}zd", errno, wLen);
151         APPSPAWN_CHECK((wLen > 0) || (errno == EINTR), return -errno,
152             "Failed to write message to fd %{public}d, wLen %{public}zd errno: %{public}d", socketFd, wLen, errno);
153     }
154     return written == len ? 0 : -EFAULT;
155 }
156 
HandleMsgSend(AppSpawnReqMsgMgr * reqMgr,int socketId,AppSpawnReqMsgNode * reqNode)157 static int HandleMsgSend(AppSpawnReqMsgMgr *reqMgr, int socketId, AppSpawnReqMsgNode *reqNode)
158 {
159     APPSPAWN_LOGV("HandleMsgSend reqId: %{public}u msgId: %{public}d", reqNode->reqId, reqNode->msg->msgId);
160     ListNode *sendNode = reqNode->msgBlocks.next;
161     uint32_t currentIndex = 0;
162     while (sendNode != NULL && sendNode != &reqNode->msgBlocks) {
163         AppSpawnMsgBlock *sendBlock = (AppSpawnMsgBlock *)ListEntry(sendNode, AppSpawnMsgBlock, node);
164         int ret = WriteMessage(socketId, sendBlock->buffer, sendBlock->currentIndex);
165         currentIndex += sendBlock->currentIndex;
166         APPSPAWN_LOGV("Write msg ret: %{public}d msgId: %{public}u %{public}u %{public}u",
167             ret, reqNode->msg->msgId, reqNode->msg->msgLen, currentIndex);
168         if (ret == 0) {
169             sendNode = sendNode->next;
170             continue;
171         }
172         APPSPAWN_LOGE("Send msg fail reqId: %{public}u msgId: %{public}d ret: %{public}d",
173             reqNode->reqId, reqNode->msg->msgId, ret);
174         return ret;
175     }
176     return 0;
177 }
178 
TryCreateSocket(AppSpawnReqMsgMgr * reqMgr)179 static void TryCreateSocket(AppSpawnReqMsgMgr *reqMgr)
180 {
181     uint32_t retryCount = 1;
182     while (retryCount <= reqMgr->maxRetryCount) {
183         if (reqMgr->socketId < 0) {
184             reqMgr->socketId = CreateClientSocket(reqMgr->type, reqMgr->timeout);
185         }
186         if (reqMgr->socketId < 0) {
187             APPSPAWN_LOGV("Failed to create socket, try again");
188             usleep(RETRY_TIME);
189             retryCount++;
190             continue;
191         }
192         break;
193     }
194 }
195 
ClientSendMsg(AppSpawnReqMsgMgr * reqMgr,AppSpawnReqMsgNode * reqNode,AppSpawnResult * result)196 static int ClientSendMsg(AppSpawnReqMsgMgr *reqMgr, AppSpawnReqMsgNode *reqNode, AppSpawnResult *result)
197 {
198     uint32_t retryCount = 1;
199     while (retryCount <= reqMgr->maxRetryCount) {
200         if (reqMgr->socketId < 0) { // try create socket
201             TryCreateSocket(reqMgr);
202             if (reqMgr->socketId < 0) {
203                 usleep(RETRY_TIME);
204                 retryCount++;
205                 continue;
206             }
207         }
208 
209         if (reqNode->msg->msgId == 0) {
210             reqNode->msg->msgId = reqMgr->msgNextId++;
211         }
212         int ret = HandleMsgSend(reqMgr, reqMgr->socketId, reqNode);
213         if (ret == 0) {
214             ret = ReadMessage(reqMgr->socketId, reqNode->msg->msgId,
215                 reqMgr->recvBlock.buffer, reqMgr->recvBlock.blockSize, result);
216         }
217         if (ret == 0) {
218             return 0;
219         }
220         // retry
221         CloseClientSocket(reqMgr->socketId);
222         reqMgr->socketId = -1;
223         reqMgr->msgNextId = 1;
224         reqNode->msg->msgId = 0;
225         usleep(RETRY_TIME);
226         retryCount++;
227     }
228     return APPSPAWN_TIMEOUT;
229 }
230 
AppSpawnClientInit(const char * serviceName,AppSpawnClientHandle * handle)231 int AppSpawnClientInit(const char *serviceName, AppSpawnClientHandle *handle)
232 {
233     APPSPAWN_CHECK(serviceName != NULL, return APPSPAWN_ARG_INVALID, "Invalid service name");
234     APPSPAWN_CHECK(handle != NULL, return APPSPAWN_ARG_INVALID, "Invalid handle for %{public}s", serviceName);
235     APPSPAWN_LOGV("AppSpawnClientInit serviceName %{public}s", serviceName);
236     AppSpawnClientType type = CLIENT_FOR_APPSPAWN;
237     if (strcmp(serviceName, NWEBSPAWN_SERVER_NAME) == 0 || strstr(serviceName, NWEBSPAWN_SOCKET_NAME) != NULL) {
238         type = CLIENT_FOR_NWEBSPAWN;
239     }
240     int ret = InitClientInstance(type);
241     APPSPAWN_CHECK(ret == 0, return APPSPAWN_SYSTEM_ERROR, "Failed to create reqMgr");
242     *handle = (AppSpawnClientHandle)g_clientInstance[type];
243     return 0;
244 }
245 
AppSpawnClientDestroy(AppSpawnClientHandle handle)246 int AppSpawnClientDestroy(AppSpawnClientHandle handle)
247 {
248     AppSpawnReqMsgMgr *reqMgr = (AppSpawnReqMsgMgr *)handle;
249     APPSPAWN_CHECK(reqMgr != NULL, return APPSPAWN_SYSTEM_ERROR, "Invalid reqMgr");
250     pthread_mutex_lock(&g_mutex);
251     if (reqMgr->type < sizeof(g_clientInstance) / sizeof(g_clientInstance[0])) {
252         g_clientInstance[reqMgr->type] = NULL;
253     }
254     pthread_mutex_unlock(&g_mutex);
255     pthread_mutex_destroy(&reqMgr->mutex);
256     if (reqMgr->socketId >= 0) {
257         CloseClientSocket(reqMgr->socketId);
258         reqMgr->socketId = -1;
259     }
260     free(reqMgr);
261     return 0;
262 }
263 
AppSpawnClientSendMsg(AppSpawnClientHandle handle,AppSpawnReqMsgHandle reqHandle,AppSpawnResult * result)264 int AppSpawnClientSendMsg(AppSpawnClientHandle handle, AppSpawnReqMsgHandle reqHandle, AppSpawnResult *result)
265 {
266     APPSPAWN_CHECK(result != NULL, AppSpawnReqMsgFree(reqHandle);
267         return APPSPAWN_ARG_INVALID, "Invalid result");
268     result->result = APPSPAWN_ARG_INVALID;
269     result->pid = 0;
270     AppSpawnReqMsgMgr *reqMgr = (AppSpawnReqMsgMgr *)handle;
271     APPSPAWN_CHECK(reqMgr != NULL, AppSpawnReqMsgFree(reqHandle);
272         return APPSPAWN_ARG_INVALID, "Invalid reqMgr");
273     AppSpawnReqMsgNode *reqNode = (AppSpawnReqMsgNode *)reqHandle;
274     APPSPAWN_CHECK(reqNode != NULL && reqNode->msg != NULL, AppSpawnReqMsgFree(reqHandle);
275         return APPSPAWN_ARG_INVALID, "Invalid msgReq");
276 
277     APPSPAWN_LOGI("AppSpawnClientSendMsg reqId: %{public}u msgLen: %{public}u %{public}s",
278         reqNode->reqId, reqNode->msg->msgLen, reqNode->msg->processName);
279     pthread_mutex_lock(&reqMgr->mutex);
280     int ret = ClientSendMsg(reqMgr, reqNode, result);
281     if (ret != 0) {
282         result->result = ret;
283     }
284     pthread_mutex_unlock(&reqMgr->mutex);
285     APPSPAWN_LOGI("AppSpawnClientSendMsg reqId: %{public}u end result: 0x%{public}x pid: %{public}d",
286         reqNode->reqId, result->result, result->pid);
287     AppSpawnReqMsgFree(reqHandle);
288     return ret;
289 }
290