1 /*
2 * Copyright (C) 2021 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 "ipc_process_skeleton.h"
17 #include "ipc_skeleton.h"
18 #include "ipc_skeleton_pri.h"
19 #include "ipc_thread_pool.h"
20 #include "iremote_invoker.h"
21 #include "rpc_errno.h"
22 #include "rpc_log.h"
23 #include "rpc_os_adapter.h"
24 #include "rpc_process_skeleton.h"
25 #include "rpc_types.h"
26 #include "securec.h"
27 #include "utils_list.h"
28
29 static IpcSkeleton *g_ipcSkeleton = NULL;
30 static pthread_mutex_t g_ipcSkeletonMutex = PTHREAD_MUTEX_INITIALIZER;
31 static SvcIdentity g_samgrSvc = {
32 .handle = 0,
33 .token = 0,
34 .cookie = 0
35 };
36
DeleteIpcSkeleton(IpcSkeleton * temp)37 static void DeleteIpcSkeleton(IpcSkeleton *temp)
38 {
39 if (temp == NULL) {
40 return;
41 }
42 DeinitThreadPool(temp->threadPool);
43 free(temp);
44 }
45
IpcProcessSkeleton()46 static IpcSkeleton* IpcProcessSkeleton()
47 {
48 IpcSkeleton *temp = (IpcSkeleton *)calloc(1, sizeof(IpcSkeleton));
49 if (temp == NULL) {
50 RPC_LOG_ERROR("create ipc skeleton failed.");
51 return NULL;
52 }
53 temp->threadPool = InitThreadPool(SET_MAX_THREADS_DEFAULT);
54 if (temp->threadPool == NULL) {
55 free(temp);
56 RPC_LOG_ERROR("init thread pool failed.");
57 return NULL;
58 }
59 RemoteInvoker *invoker = GetRemoteInvoker();
60 if (invoker == NULL) {
61 DeleteIpcSkeleton(temp);
62 RPC_LOG_ERROR("get remote invoker failed.");
63 return NULL;
64 }
65 if ((invoker->SetMaxWorkThread)(SET_MAX_THREADS_DEFAULT) != ERR_NONE) {
66 DeleteIpcSkeleton(temp);
67 RPC_LOG_ERROR("init thread context failed.");
68 return NULL;
69 }
70 SpawnNewThread(temp->threadPool, SPAWN_ACTIVE, IF_PROT_BINDER);
71 UtilsListInit(&temp->objects);
72 pthread_mutex_init(&temp->lock, NULL);
73 return temp;
74 }
75
GetCurrentSkeleton(void)76 IpcSkeleton *GetCurrentSkeleton(void)
77 {
78 if (g_ipcSkeleton == NULL) {
79 if (pthread_mutex_lock(&g_ipcSkeletonMutex) != 0) {
80 RPC_LOG_ERROR("init ipc skeleton lock failed.");
81 return NULL;
82 }
83 if (g_ipcSkeleton == NULL) {
84 IpcSkeleton *temp = IpcProcessSkeleton();
85 if (temp == NULL) {
86 pthread_mutex_unlock(&g_ipcSkeletonMutex);
87 RPC_LOG_ERROR("create binder connector failed.");
88 return NULL;
89 }
90 g_ipcSkeleton = temp;
91 int32_t ret = RpcProcessSkeleton();
92 if (ret != ERR_NONE) {
93 RPC_LOG_ERROR("rpc process skeleton init failed");
94 }
95 }
96 pthread_mutex_unlock(&g_ipcSkeletonMutex);
97 }
98 return g_ipcSkeleton;
99 }
100
SpawnThread(int32_t policy,int32_t proto)101 int32_t SpawnThread(int32_t policy, int32_t proto)
102 {
103 if (g_ipcSkeleton == NULL || g_ipcSkeleton->threadPool == NULL) {
104 RPC_LOG_ERROR("ipc skeleton not init");
105 return ERR_IPC_SKELETON_NOT_INIT;
106 }
107 return SpawnNewThread(g_ipcSkeleton->threadPool, policy, proto);
108 }
109
SetMaxWorkThread(int32_t maxThreadNum)110 int32_t SetMaxWorkThread(int32_t maxThreadNum)
111 {
112 if (g_ipcSkeleton == NULL || g_ipcSkeleton->threadPool == NULL) {
113 RPC_LOG_ERROR("ipc skeleton not init");
114 return ERR_IPC_SKELETON_NOT_INIT;
115 }
116 UpdateMaxThreadNum(g_ipcSkeleton->threadPool, maxThreadNum);
117
118 RemoteInvoker *invoker = GetRemoteInvoker();
119 if (invoker != NULL) {
120 return (invoker->SetMaxWorkThread)(maxThreadNum);
121 }
122 RPC_LOG_ERROR("current thread context not init");
123 return ERR_THREAD_INVOKER_NOT_INIT;
124 }
125
JoinMainWorkThread(void)126 void JoinMainWorkThread(void)
127 {
128 RemoteInvoker *invoker = GetRemoteInvoker();
129 if (invoker != NULL) {
130 (invoker->JoinThread)(true);
131 }
132 }
133
ProcessGetCallingPid(void)134 pid_t ProcessGetCallingPid(void)
135 {
136 if (g_ipcSkeleton != NULL) {
137 ThreadContext *currentContext = GetCurrentThreadContext();
138 if (currentContext != NULL) {
139 return currentContext->callerPid;
140 }
141 }
142 return RpcGetPid();
143 }
144
ProcessGetCallingUid(void)145 pid_t ProcessGetCallingUid(void)
146 {
147 if (g_ipcSkeleton != NULL) {
148 ThreadContext *currentContext = GetCurrentThreadContext();
149 if (currentContext != NULL) {
150 return currentContext->callerUid;
151 }
152 }
153 return RpcGetUid();
154 }
155
GetRegistryObject(void)156 const SvcIdentity *GetRegistryObject(void)
157 {
158 return &g_samgrSvc;
159 }
160
SetRegistryObject(SvcIdentity target)161 int32_t SetRegistryObject(SvcIdentity target)
162 {
163 int32_t ret = ERR_THREAD_INVOKER_NOT_INIT;
164 RemoteInvoker *invoker = GetRemoteInvoker();
165 if (invoker != NULL) {
166 ret = (invoker->SetRegistryObject)(target, &g_samgrSvc);
167 }
168 return ret;
169 }
170
DeleteHandle(int32_t handle)171 int32_t DeleteHandle(int32_t handle)
172 {
173 if (pthread_mutex_lock(&g_ipcSkeleton->lock) != 0) {
174 RPC_LOG_ERROR("Get ipc skeleton mutex failed.");
175 return ERR_FAILED;
176 }
177 DeathCallback *node = NULL;
178 DeathCallback *next = NULL;
179 bool isValidHandle = false;
180 int32_t ret = ERR_INVALID_PARAM;
181 UTILS_DL_LIST_FOR_EACH_ENTRY_SAFE(node, next, &g_ipcSkeleton->objects, DeathCallback, list)
182 {
183 if (node->handle == handle) {
184 isValidHandle = true;
185 pthread_mutex_destroy(&node->lock);
186 UtilsListDelete(&node->list);
187 free(node);
188 break;
189 }
190 }
191 pthread_mutex_unlock(&g_ipcSkeleton->lock);
192 if (isValidHandle) {
193 RemoteInvoker *invoker = GetRemoteInvoker();
194 if (invoker != NULL) {
195 (invoker->ReleaseHandle)(handle);
196 }
197 ret = ERR_NONE;
198 }
199 return ret;
200 }
201
ProcessSendRequest(SvcIdentity target,uint32_t code,IpcIo * data,IpcIo * reply,MessageOption option,uintptr_t * buffer)202 int32_t ProcessSendRequest(SvcIdentity target, uint32_t code, IpcIo *data, IpcIo *reply,
203 MessageOption option, uintptr_t *buffer)
204 {
205 int32_t ret = ERR_THREAD_INVOKER_NOT_INIT;
206 RemoteInvoker *invoker = GetRemoteInvoker();
207 if (invoker != NULL) {
208 ret = (invoker->SendRequest)(target, code, data, reply, option, buffer);
209 }
210 return ret;
211 }
212
ProcessFreeBuffer(void * ptr)213 int32_t ProcessFreeBuffer(void *ptr)
214 {
215 RemoteInvoker *invoker = GetRemoteInvoker();
216 if (invoker != NULL) {
217 return (invoker->FreeBuffer)(ptr);
218 }
219 return ERR_THREAD_INVOKER_NOT_INIT;
220 }
221
FirstAddObject(int32_t handle)222 static bool FirstAddObject(int32_t handle)
223 {
224 if (pthread_mutex_lock(&g_ipcSkeleton->lock) != 0) {
225 RPC_LOG_ERROR("Get ipc skeleton mutex failed.");
226 return false;
227 }
228 DeathCallback *node = NULL;
229 DeathCallback *next = NULL;
230 UTILS_DL_LIST_FOR_EACH_ENTRY_SAFE(node, next, &g_ipcSkeleton->objects, DeathCallback, list)
231 {
232 if (node->handle == handle) {
233 RPC_LOG_INFO("current handle already exist");
234 pthread_mutex_unlock(&g_ipcSkeleton->lock);
235 return false;
236 }
237 }
238 node = (DeathCallback*)calloc(1, sizeof(DeathCallback));
239 if (node == NULL) {
240 pthread_mutex_unlock(&g_ipcSkeleton->lock);
241 return false;
242 }
243
244 node->handle = handle;
245 node->deathNum = 0;
246 node->isRemoteDead = false;
247 node->isNewHandler = true;
248 pthread_mutex_init(&node->lock, NULL);
249 UtilsListAdd(&g_ipcSkeleton->objects, &node->list);
250 pthread_mutex_unlock(&g_ipcSkeleton->lock);
251 return true;
252 }
253
OnFirstStrongRef(int32_t handle)254 void OnFirstStrongRef(int32_t handle)
255 {
256 if (handle <= 0) {
257 RPC_LOG_ERROR("invalid handle.");
258 return;
259 }
260 if (FirstAddObject(handle)) {
261 RemoteInvoker *invoker = GetRemoteInvoker();
262 if (invoker != NULL) {
263 (invoker->AcquireHandle)(handle);
264 }
265 }
266 }
267
SetDeathHandlerPair(DeathCallback * node,uint32_t index,OnRemoteDead func,void * args)268 static uint32_t SetDeathHandlerPair(DeathCallback *node, uint32_t index, OnRemoteDead func, void* args)
269 {
270 node->handler[index].usedFlag = true;
271 node->handler[index].func = func;
272 node->handler[index].args = args;
273 node->deathNum++;
274 return index;
275 }
276
ProcessAddDeathRecipient(int32_t handle,OnRemoteDead deathFunc,void * args,uint32_t * cbId)277 int32_t ProcessAddDeathRecipient(int32_t handle, OnRemoteDead deathFunc, void *args, uint32_t *cbId)
278 {
279 int32_t ret = ERR_INVALID_PARAM;
280 if (g_ipcSkeleton == NULL) {
281 return ERR_IPC_SKELETON_NOT_INIT;
282 }
283 if (deathFunc == NULL || cbId == NULL) {
284 return ERR_INVALID_PARAM;
285 }
286 if (pthread_mutex_lock(&g_ipcSkeleton->lock) != 0) {
287 return ERR_FAILED;
288 }
289 DeathCallback *node = NULL;
290 DeathCallback *next = NULL;
291 bool firstDeathNode = false;
292 UTILS_DL_LIST_FOR_EACH_ENTRY_SAFE(node, next, &g_ipcSkeleton->objects, DeathCallback, list)
293 {
294 if (node->handle != handle) {
295 continue;
296 }
297 if (node->isRemoteDead) {
298 pthread_mutex_unlock(&g_ipcSkeleton->lock);
299 return ERR_DEAD_OBJECT;
300 }
301 if (node->deathNum == MAX_DEATH_CALLBACK_NUM) {
302 pthread_mutex_unlock(&g_ipcSkeleton->lock);
303 return ERR_INVALID_PARAM;
304 }
305 (void)pthread_mutex_lock(&node->lock);
306 for (int i = 0; i < MAX_DEATH_CALLBACK_NUM; i++) {
307 if (!node->handler[i].usedFlag) {
308 *cbId = SetDeathHandlerPair(node, i, deathFunc, args);
309 ret = ERR_NONE;
310 break;
311 }
312 }
313 pthread_mutex_unlock(&node->lock);
314 if (node->deathNum == 1 && node->isNewHandler) {
315 firstDeathNode = true;
316 node->isNewHandler = false;
317 }
318 break;
319 }
320 pthread_mutex_unlock(&g_ipcSkeleton->lock);
321 if (firstDeathNode) {
322 RPC_LOG_ERROR("first add death callback for handle = %d.", handle);
323 RemoteInvoker *invoker = GetRemoteInvoker();
324 ret = ERR_INVALID_PARAM;
325 if (invoker != NULL) {
326 ret = (invoker->AddDeathRecipient)(handle, node);
327 }
328 }
329 return ret;
330 }
331
ProcessRemoveDeathRecipient(int32_t handle,uint32_t cbId)332 int32_t ProcessRemoveDeathRecipient(int32_t handle, uint32_t cbId)
333 {
334 int32_t ret = ERR_INVALID_PARAM;
335 if (g_ipcSkeleton == NULL) {
336 return ERR_IPC_SKELETON_NOT_INIT;
337 }
338 if (cbId >= MAX_DEATH_CALLBACK_NUM) {
339 RPC_LOG_ERROR("invalid callback id.");
340 return ERR_INVALID_PARAM;
341 }
342 if (pthread_mutex_lock(&g_ipcSkeleton->lock) != 0) {
343 return ERR_FAILED;
344 }
345 DeathCallback *node = NULL;
346 DeathCallback *next = NULL;
347 UTILS_DL_LIST_FOR_EACH_ENTRY_SAFE(node, next, &g_ipcSkeleton->objects, DeathCallback, list)
348 {
349 if (node->handle != handle) {
350 continue;
351 }
352 if (node->isRemoteDead) {
353 RPC_LOG_ERROR("service is dead, delete it later.");
354 pthread_mutex_unlock(&g_ipcSkeleton->lock);
355 return ERR_DEAD_OBJECT;
356 }
357 (void)pthread_mutex_lock(&node->lock);
358 if (node->handler[cbId].usedFlag) {
359 node->handler[cbId].usedFlag = false;
360 node->handler[cbId].func = NULL;
361 node->deathNum--;
362 ret = ERR_NONE;
363 }
364 (void)pthread_mutex_unlock(&node->lock);
365 break;
366 }
367 pthread_mutex_unlock(&g_ipcSkeleton->lock);
368 return ret;
369 }
370
OnRemoteRequestInner(uint32_t code,IpcIo * data,IpcIo * reply,MessageOption option,IpcObjectStub * objectStub)371 int32_t OnRemoteRequestInner(uint32_t code, IpcIo *data, IpcIo *reply, MessageOption option, IpcObjectStub *objectStub)
372 {
373 int32_t result = RpcOnRemoteRequestInner(code, data, reply, option, objectStub);
374 if (result == ERR_NOT_RPC) {
375 if (objectStub != NULL && objectStub->func != NULL) {
376 result = (OnRemoteRequest)(objectStub->func)(code, data, reply, option);
377 }
378 }
379 return result;
380 }
381
SendObituary(DeathCallback * deathCallback)382 void SendObituary(DeathCallback *deathCallback)
383 {
384 (void)pthread_mutex_lock(&deathCallback->lock);
385 int32_t deathNum = deathCallback->deathNum;
386 DeathHandler handler[deathNum];
387 deathCallback->isRemoteDead = true;
388 if (deathNum > 0) {
389 int32_t index = 0;
390 for (int32_t i = 0; i < MAX_DEATH_CALLBACK_NUM && index < deathNum; i++) {
391 if (deathCallback->handler[i].usedFlag && deathCallback->handler[i].func != NULL) {
392 handler[index].func = deathCallback->handler[i].func;
393 handler[index].args = deathCallback->handler[i].args;
394 ++index;
395 }
396 }
397 RemoteInvoker *invoker = GetRemoteInvoker();
398 if (invoker != NULL) {
399 (invoker->RemoveDeathRecipient)(deathCallback->handle, deathCallback);
400 }
401 }
402 pthread_mutex_unlock(&deathCallback->lock);
403 for (int32_t i = 0; i < deathNum; i++) {
404 handler[i].func(handler[i].args);
405 }
406 }
407
WaitForProxyInit(SvcIdentity * svc)408 void WaitForProxyInit(SvcIdentity *svc)
409 {
410 if (svc == NULL) {
411 RPC_LOG_ERROR("invalid svc.");
412 return;
413 }
414 RPC_LOG_INFO("ipc skeleton wait for proxy init");
415 OnFirstStrongRef(svc->handle);
416 UpdateProtoIfNeed(svc);
417 }
418
DeleteDeathCallback(DeathCallback * deathCallback)419 void DeleteDeathCallback(DeathCallback *deathCallback)
420 {
421 UtilsListDelete(&deathCallback->list);
422 pthread_mutex_destroy(&deathCallback->lock);
423 free(deathCallback);
424 }
425
DeleteAllNode(void)426 static void DeleteAllNode(void)
427 {
428 if (g_ipcSkeleton == NULL) {
429 RPC_LOG_ERROR("invalid ipcSkeleton");
430 return;
431 }
432 (void)pthread_mutex_lock(&g_ipcSkeleton->lock);
433 DeathCallback *node = NULL;
434 DeathCallback *next = NULL;
435 UTILS_DL_LIST_FOR_EACH_ENTRY_SAFE(node, next, &g_ipcSkeleton->objects, DeathCallback, list)
436 {
437 pthread_mutex_destroy(&node->lock);
438 UtilsListDelete(&node->list);
439 free(node);
440 }
441 pthread_mutex_unlock(&g_ipcSkeleton->lock);
442 }
443
ResetIpc(void)444 void ResetIpc(void)
445 {
446 RPC_LOG_INFO("ResetIpc called");
447 RemoteInvoker *invoker = GetRemoteInvoker();
448 if (invoker != NULL && invoker->InvokerResetIpc != NULL) {
449 (invoker->InvokerResetIpc)();
450 }
451 DeleteAllNode();
452 #ifdef IPC_RESET_SKELETON
453 DeleteIpcSkeleton(g_ipcSkeleton);
454 g_ipcSkeleton = NULL;
455 g_ipcSkeleton = IpcProcessSkeleton();
456 #endif
457 }