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 }