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 }