257 lines
8.2 KiB
C
Executable File
257 lines
8.2 KiB
C
Executable File
/*
|
|
* Copyright (c) 2020 Huawei Device Co., Ltd.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
#include "default_client.h"
|
|
#include <ohos_errno.h>
|
|
#include <string.h>
|
|
#include <log.h>
|
|
#include <service_registry.h>
|
|
#include "client_factory.h"
|
|
#include "iproxy_client.h"
|
|
#include "memory_adapter.h"
|
|
#include "thread_adapter.h"
|
|
#include "endpoint.h"
|
|
|
|
#undef LOG_TAG
|
|
#undef LOG_DOMAIN
|
|
#define LOG_TAG "Samgr"
|
|
#define LOG_DOMAIN 0xD001800
|
|
typedef struct IClientHeader IClientHeader;
|
|
typedef struct IDefaultClient IDefaultClient;
|
|
typedef struct IClientEntry IClientEntry;
|
|
struct IClientHeader {
|
|
SaName key;
|
|
SvcIdentity target;
|
|
uint32 deadId;
|
|
const IpcContext *context;
|
|
};
|
|
|
|
struct IClientEntry {
|
|
INHERIT_IUNKNOWNENTRY(IClientProxy);
|
|
};
|
|
|
|
#pragma pack(1)
|
|
struct IDefaultClient {
|
|
IClientHeader header;
|
|
IClientEntry entry;
|
|
};
|
|
#pragma pack()
|
|
|
|
static int AddRef(IUnknown *iUnknown);
|
|
static int Release(IUnknown *proxy);
|
|
static int ProxyInvoke(IClientProxy *proxy, int funcId, IpcIo *request, IOwner owner, INotify notify);
|
|
static int OnServiceExit(const IpcContext *context, void *ipcMsg, IpcIo *data, void *argv);
|
|
static SvcIdentity QueryIdentity(const IpcContext *context, const char *service, const char *feature);
|
|
static const IClientEntry DEFAULT_ENTRY = {CLIENT_IPROXY_BEGIN, .Invoke = ProxyInvoke, IPROXY_END};
|
|
static MutexId g_mutex = NULL;
|
|
|
|
IUnknown *SAMGR_CreateIProxy(const IpcContext *context, const char *service, const char *feature)
|
|
{
|
|
SvcIdentity identity = QueryIdentity(context, service, feature);
|
|
if (identity.handle == INVALID_INDEX) {
|
|
return NULL;
|
|
}
|
|
|
|
IDefaultClient *client = SAMGR_CreateIClient(service, feature, sizeof(IClientHeader));
|
|
if (client == NULL) {
|
|
client = SAMGR_Malloc(sizeof(IDefaultClient));
|
|
if (client == NULL) {
|
|
return NULL;
|
|
}
|
|
client->entry = DEFAULT_ENTRY;
|
|
}
|
|
|
|
IClientHeader *header = &client->header;
|
|
header->target = identity;
|
|
header->key.service = service;
|
|
header->key.feature = feature;
|
|
header->context = context;
|
|
(void)RegisterDeathCallback(context, identity, OnServiceExit, client, &header->deadId);
|
|
|
|
IClientEntry *entry = &client->entry;
|
|
entry->iUnknown.Invoke = ProxyInvoke;
|
|
entry->iUnknown.AddRef = AddRef;
|
|
entry->iUnknown.Release = Release;
|
|
return GET_IUNKNOWN(*entry);
|
|
}
|
|
|
|
SvcIdentity SAMGR_GetRemoteIdentity(const char *service, const char *feature)
|
|
{
|
|
SvcIdentity identity = {INVALID_INDEX, INVALID_INDEX, INVALID_INDEX};
|
|
IUnknown *iUnknown = SAMGR_FindServiceApi(service, feature);
|
|
if (iUnknown == NULL) {
|
|
return identity;
|
|
}
|
|
IClientProxy *proxy = NULL;
|
|
if (iUnknown->QueryInterface(iUnknown, CLIENT_PROXY_VER, (void **)&proxy) != EC_SUCCESS || proxy == NULL) {
|
|
return identity;
|
|
}
|
|
struct IDefaultClient *client = GET_OBJECT(proxy, struct IDefaultClient, entry.iUnknown);
|
|
identity = client->header.target;
|
|
proxy->Release((IUnknown *)proxy);
|
|
return identity;
|
|
}
|
|
|
|
SaName *SAMGR_GetSAName(const IUnknown *proxy)
|
|
{
|
|
IDefaultClient *client = GET_OBJECT(proxy, IDefaultClient, entry.iUnknown);
|
|
return &(client->header.key);
|
|
}
|
|
|
|
int SAMGR_CompareSAName(const SaName *key1, const SaName *key2)
|
|
{
|
|
if (key1 == key2) {
|
|
return 0;
|
|
}
|
|
|
|
if (key1->service != key2->service) {
|
|
int ret = strcmp(key1->service, key2->service);
|
|
if (ret != 0) {
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
if (key1->feature == key2->feature) {
|
|
return 0;
|
|
}
|
|
|
|
if (key1->feature == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
if (key2->feature == NULL) {
|
|
return 1;
|
|
}
|
|
|
|
return strcmp(key1->feature, key2->feature);
|
|
}
|
|
|
|
static int AddRef(IUnknown *iUnknown)
|
|
{
|
|
MUTEX_Lock(g_mutex);
|
|
int ref = IUNKNOWN_AddRef(iUnknown);
|
|
MUTEX_Unlock(g_mutex);
|
|
return ref;
|
|
}
|
|
|
|
static int Release(IUnknown *proxy)
|
|
{
|
|
MUTEX_Lock(g_mutex);
|
|
int ref = IUNKNOWN_Release(proxy);
|
|
MUTEX_Unlock(g_mutex);
|
|
if (ref != 0) {
|
|
return ref;
|
|
}
|
|
IDefaultClient *client = GET_OBJECT(proxy, IDefaultClient, entry.iUnknown);
|
|
int ret = SAMGR_ReleaseIClient(client->header.key.service, client->header.key.feature, client);
|
|
if (ret == EC_NOHANDLER) {
|
|
SAMGR_Free(client);
|
|
return EC_SUCCESS;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static int ProxyInvoke(IClientProxy *proxy, int funcId, IpcIo *request, IOwner owner, INotify notify)
|
|
{
|
|
if (proxy == NULL) {
|
|
return EC_INVALID;
|
|
}
|
|
|
|
IDefaultClient *client = GET_OBJECT(proxy, IDefaultClient, entry.iUnknown);
|
|
IClientHeader *header = &client->header;
|
|
if (header->target.handle == INVALID_INDEX) {
|
|
header->target = QueryIdentity(header->context, header->key.service, header->key.feature);
|
|
if (header->target.handle == INVALID_INDEX) {
|
|
return EC_INVALID;
|
|
}
|
|
(void)RegisterDeathCallback(header->context, header->target, OnServiceExit, header, &header->deadId);
|
|
}
|
|
|
|
IpcIo reply;
|
|
void *replyBuf = NULL;
|
|
IpcFlag flag = (notify == NULL) ? LITEIPC_FLAG_ONEWAY : LITEIPC_FLAG_DEFAULT;
|
|
int ret = Transact(header->context, header->target, funcId, request, &reply, flag, (uintptr_t *)&replyBuf);
|
|
if (ret != LITEIPC_OK) {
|
|
(void)UnregisterDeathCallback(header->target, header->deadId);
|
|
header->deadId = INVALID_INDEX;
|
|
header->target.handle = INVALID_INDEX;
|
|
header->target.token = INVALID_INDEX;
|
|
header->target.cookie = INVALID_INDEX;
|
|
return EC_FAILURE;
|
|
}
|
|
|
|
if (notify != NULL) {
|
|
notify(owner, ret, &reply);
|
|
}
|
|
|
|
if (replyBuf != NULL) {
|
|
FreeBuffer(header->context, replyBuf);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static int OnServiceExit(const IpcContext *context, void *ipcMsg, IpcIo *data, void *argv)
|
|
{
|
|
(void)data;
|
|
IClientHeader *header = (IClientHeader *)argv;
|
|
(void)UnregisterDeathCallback(header->target, header->deadId);
|
|
#ifdef __LINUX__
|
|
BinderRelease(context, header->target.handle);
|
|
#endif
|
|
header->deadId = INVALID_INDEX;
|
|
header->target.handle = INVALID_INDEX;
|
|
header->target.token = INVALID_INDEX;
|
|
header->target.cookie = INVALID_INDEX;
|
|
if (ipcMsg != NULL) {
|
|
FreeBuffer(header->context, ipcMsg);
|
|
}
|
|
HILOG_ERROR(HILOG_MODULE_SAMGR, "Miss the remote service<%u, %u>!", header->target.handle, header->target.token);
|
|
return EC_SUCCESS;
|
|
}
|
|
|
|
static SvcIdentity QueryIdentity(const IpcContext *context, const char *service, const char *feature)
|
|
{
|
|
IpcIo req;
|
|
uint8 data[MAX_DATA_LEN];
|
|
IpcIoInit(&req, data, MAX_DATA_LEN, 0);
|
|
IpcIoPushUint32(&req, RES_FEATURE);
|
|
IpcIoPushUint32(&req, OP_GET);
|
|
IpcIoPushString(&req, service);
|
|
IpcIoPushBool(&req, feature == NULL);
|
|
if (feature != NULL) {
|
|
IpcIoPushString(&req, feature);
|
|
}
|
|
IpcIo reply;
|
|
void *replyBuf = NULL;
|
|
SvcIdentity samgr = {SAMGR_HANDLE, SAMGR_TOKEN, SAMGR_COOKIE};
|
|
int ret = Transact(context, samgr, INVALID_INDEX, &req, &reply, LITEIPC_FLAG_DEFAULT, (uintptr_t *)&replyBuf);
|
|
ret = (ret != LITEIPC_OK) ? EC_FAILURE : IpcIoPopInt32(&reply);
|
|
SvcIdentity target = {INVALID_INDEX, INVALID_INDEX, INVALID_INDEX};
|
|
if (ret == EC_SUCCESS) {
|
|
SvcIdentity *svc = IpcIoPopSvc(&reply);
|
|
if (svc != NULL) {
|
|
#ifdef __LINUX__
|
|
BinderAcquire(svc->ipcContext, svc->handle);
|
|
#endif
|
|
target = *svc;
|
|
}
|
|
}
|
|
if (ret == EC_PERMISSION) {
|
|
HILOG_INFO(HILOG_MODULE_SAMGR, "Cannot Access<%s, %s> No Permission!", service, feature);
|
|
}
|
|
if (replyBuf != NULL) {
|
|
FreeBuffer(context, replyBuf);
|
|
}
|
|
return target;
|
|
} |