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