1 /*
2  * Copyright (c) 2020 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 #include "default_client.h"
16 #include <ohos_errno.h>
17 #include <string.h>
18 #include <log.h>
19 #include <service_registry.h>
20 #include "client_factory.h"
21 #include "iproxy_client.h"
22 #include "memory_adapter.h"
23 #include "thread_adapter.h"
24 #include "endpoint.h"
25 
26 #undef LOG_TAG
27 #undef LOG_DOMAIN
28 #define LOG_TAG "Samgr"
29 #define LOG_DOMAIN 0xD001800
30 typedef struct IClientHeader IClientHeader;
31 typedef struct IDefaultClient IDefaultClient;
32 typedef struct IClientEntry IClientEntry;
33 struct IClientHeader {
34     SaName key;
35     SvcIdentity target;
36     uint32 deadId;
37     const IpcContext *context;
38 };
39 
40 struct IClientEntry {
41     INHERIT_IUNKNOWNENTRY(IClientProxy);
42 };
43 
44 #pragma pack(1)
45 struct IDefaultClient {
46     IClientHeader header;
47     IClientEntry entry;
48 };
49 #pragma pack()
50 
51 static int AddRef(IUnknown *iUnknown);
52 static int Release(IUnknown *proxy);
53 static int ProxyInvoke(IClientProxy *proxy, int funcId, IpcIo *request, IOwner owner, INotify notify);
54 static int OnServiceExit(const IpcContext *context, void *ipcMsg, IpcIo *data, void *argv);
55 static SvcIdentity QueryIdentity(const IpcContext *context, const char *service, const char *feature);
56 static const IClientEntry DEFAULT_ENTRY = {CLIENT_IPROXY_BEGIN, .Invoke = ProxyInvoke, IPROXY_END};
57 static MutexId g_mutex = NULL;
58 
SAMGR_CreateIProxy(const IpcContext * context,const char * service,const char * feature)59 IUnknown *SAMGR_CreateIProxy(const IpcContext *context, const char *service, const char *feature)
60 {
61     SvcIdentity identity = QueryIdentity(context, service, feature);
62     if (identity.handle == INVALID_INDEX) {
63         return NULL;
64     }
65 
66     IDefaultClient *client = SAMGR_CreateIClient(service, feature, sizeof(IClientHeader));
67     if (client == NULL) {
68         client = SAMGR_Malloc(sizeof(IDefaultClient));
69         if (client == NULL) {
70             return NULL;
71         }
72         client->entry = DEFAULT_ENTRY;
73     }
74 
75     IClientHeader *header = &client->header;
76     header->target = identity;
77     header->key.service = service;
78     header->key.feature = feature;
79     header->context = context;
80     (void)RegisterDeathCallback(context, identity, OnServiceExit, client, &header->deadId);
81 
82     IClientEntry *entry = &client->entry;
83     entry->iUnknown.Invoke = ProxyInvoke;
84     entry->iUnknown.AddRef = AddRef;
85     entry->iUnknown.Release = Release;
86     return GET_IUNKNOWN(*entry);
87 }
88 
SAMGR_GetRemoteIdentity(const char * service,const char * feature)89 SvcIdentity SAMGR_GetRemoteIdentity(const char *service, const char *feature)
90 {
91     SvcIdentity identity = {INVALID_INDEX, INVALID_INDEX, INVALID_INDEX};
92     IUnknown *iUnknown = SAMGR_FindServiceApi(service, feature);
93     if (iUnknown == NULL) {
94         return identity;
95     }
96     IClientProxy *proxy = NULL;
97     if (iUnknown->QueryInterface(iUnknown, CLIENT_PROXY_VER, (void **)&proxy) != EC_SUCCESS || proxy == NULL) {
98         return identity;
99     }
100     struct IDefaultClient *client = GET_OBJECT(proxy, struct IDefaultClient, entry.iUnknown);
101     identity = client->header.target;
102     proxy->Release((IUnknown *)proxy);
103     return identity;
104 }
105 
SAMGR_GetSAName(const IUnknown * proxy)106 SaName *SAMGR_GetSAName(const IUnknown *proxy)
107 {
108     IDefaultClient *client = GET_OBJECT(proxy, IDefaultClient, entry.iUnknown);
109     return &(client->header.key);
110 }
111 
SAMGR_CompareSAName(const SaName * key1,const SaName * key2)112 int SAMGR_CompareSAName(const SaName *key1, const SaName *key2)
113 {
114     if (key1 == key2) {
115         return 0;
116     }
117 
118     if (key1->service != key2->service) {
119         int ret = strcmp(key1->service, key2->service);
120         if (ret != 0) {
121             return ret;
122         }
123     }
124 
125     if (key1->feature == key2->feature) {
126         return 0;
127     }
128 
129     if (key1->feature == NULL) {
130         return -1;
131     }
132 
133     if (key2->feature == NULL) {
134         return 1;
135     }
136 
137     return strcmp(key1->feature, key2->feature);
138 }
139 
AddRef(IUnknown * iUnknown)140 static int AddRef(IUnknown *iUnknown)
141 {
142     MUTEX_Lock(g_mutex);
143     int ref = IUNKNOWN_AddRef(iUnknown);
144     MUTEX_Unlock(g_mutex);
145     return ref;
146 }
147 
Release(IUnknown * proxy)148 static int Release(IUnknown *proxy)
149 {
150     MUTEX_Lock(g_mutex);
151     int ref = IUNKNOWN_Release(proxy);
152     MUTEX_Unlock(g_mutex);
153     if (ref != 0) {
154         return ref;
155     }
156     IDefaultClient *client = GET_OBJECT(proxy, IDefaultClient, entry.iUnknown);
157     int ret = SAMGR_ReleaseIClient(client->header.key.service, client->header.key.feature, client);
158     if (ret == EC_NOHANDLER) {
159         SAMGR_Free(client);
160         return EC_SUCCESS;
161     }
162     return ret;
163 }
164 
ProxyInvoke(IClientProxy * proxy,int funcId,IpcIo * request,IOwner owner,INotify notify)165 static int ProxyInvoke(IClientProxy *proxy, int funcId, IpcIo *request, IOwner owner, INotify notify)
166 {
167     if (proxy == NULL) {
168         return EC_INVALID;
169     }
170 
171     IDefaultClient *client = GET_OBJECT(proxy, IDefaultClient, entry.iUnknown);
172     IClientHeader *header = &client->header;
173     if (header->target.handle == INVALID_INDEX) {
174         header->target = QueryIdentity(header->context, header->key.service, header->key.feature);
175         if (header->target.handle == INVALID_INDEX) {
176             return EC_INVALID;
177         }
178         (void)RegisterDeathCallback(header->context, header->target, OnServiceExit, header, &header->deadId);
179     }
180 
181     IpcIo reply;
182     void *replyBuf = NULL;
183     IpcFlag flag = (notify == NULL) ? LITEIPC_FLAG_ONEWAY : LITEIPC_FLAG_DEFAULT;
184     int ret = Transact(header->context, header->target, funcId, request, &reply, flag, (uintptr_t *)&replyBuf);
185     if (ret != LITEIPC_OK) {
186         (void)UnregisterDeathCallback(header->target, header->deadId);
187         header->deadId = INVALID_INDEX;
188         header->target.handle = INVALID_INDEX;
189         header->target.token = INVALID_INDEX;
190         header->target.cookie = INVALID_INDEX;
191         return EC_FAILURE;
192     }
193 
194     if (notify != NULL) {
195         notify(owner, ret, &reply);
196     }
197 
198     if (replyBuf != NULL) {
199         FreeBuffer(header->context, replyBuf);
200     }
201     return ret;
202 }
203 
OnServiceExit(const IpcContext * context,void * ipcMsg,IpcIo * data,void * argv)204 static int OnServiceExit(const IpcContext *context, void *ipcMsg, IpcIo *data, void *argv)
205 {
206     (void)data;
207     IClientHeader *header = (IClientHeader *)argv;
208     (void)UnregisterDeathCallback(header->target, header->deadId);
209 #ifdef __LINUX__
210     BinderRelease(context, header->target.handle);
211 #endif
212     header->deadId = INVALID_INDEX;
213     header->target.handle = INVALID_INDEX;
214     header->target.token = INVALID_INDEX;
215     header->target.cookie = INVALID_INDEX;
216     if (ipcMsg != NULL) {
217         FreeBuffer(header->context, ipcMsg);
218     }
219     HILOG_ERROR(HILOG_MODULE_SAMGR, "Miss the remote service<%u, %u>!", header->target.handle, header->target.token);
220     return EC_SUCCESS;
221 }
222 
QueryIdentity(const IpcContext * context,const char * service,const char * feature)223 static SvcIdentity QueryIdentity(const IpcContext *context, const char *service, const char *feature)
224 {
225     IpcIo req;
226     uint8 data[MAX_DATA_LEN];
227     IpcIoInit(&req, data, MAX_DATA_LEN, 0);
228     IpcIoPushUint32(&req, RES_FEATURE);
229     IpcIoPushUint32(&req, OP_GET);
230     IpcIoPushString(&req, service);
231     IpcIoPushBool(&req, feature == NULL);
232     if (feature != NULL) {
233         IpcIoPushString(&req, feature);
234     }
235     IpcIo reply;
236     void *replyBuf = NULL;
237     SvcIdentity samgr = {SAMGR_HANDLE, SAMGR_TOKEN, SAMGR_COOKIE};
238     int ret = Transact(context, samgr, INVALID_INDEX, &req, &reply, LITEIPC_FLAG_DEFAULT, (uintptr_t *)&replyBuf);
239     ret = (ret != LITEIPC_OK) ? EC_FAILURE : IpcIoPopInt32(&reply);
240     SvcIdentity target = {INVALID_INDEX, INVALID_INDEX, INVALID_INDEX};
241     if (ret == EC_SUCCESS) {
242         SvcIdentity *svc = IpcIoPopSvc(&reply);
243         if (svc != NULL) {
244 #ifdef __LINUX__
245             BinderAcquire(svc->ipcContext, svc->handle);
246 #endif
247             target = *svc;
248 #ifdef __LINUX__
249             free(svc);
250 #endif
251         }
252     }
253     if (ret == EC_PERMISSION) {
254         HILOG_INFO(HILOG_MODULE_SAMGR, "Cannot Access<%s, %s> No Permission!", service, feature);
255     }
256     if (replyBuf != NULL) {
257         FreeBuffer(context, replyBuf);
258     }
259     return target;
260 }