* Copyright (c) 2021-2022 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 "devsvc_manager_stub.h"
#ifdef WITH_SELINUX
#include <hdf_service_checker.h>
#endif
#include "device_token_proxy.h"
#include "devmgr_service_stub.h"
#include "devsvc_listener_holder.h"
#include "devsvc_manager_proxy.h"
#include "hdf_cstring.h"
#include "hdf_log.h"
#include "hdf_remote_adapter_if.h"
#include "hdf_sbuf.h"
#include "hdf_slist.h"
#include "osal_mem.h"
#define HDF_LOG_TAG devsvc_manager_stub
static int32_t AddServicePermCheck(const char *servName)
{
#ifdef WITH_SELINUX
pid_t callingPid = HdfRemoteGetCallingPid();
if (HdfAddServiceCheck(callingPid, servName) != 0) {
HDF_LOGE("[selinux] %{public}d haven't \"add service\" permission to %{public}s", callingPid, servName);
return HDF_ERR_NOPERM;
}
#endif
return HDF_SUCCESS;
}
static int32_t GetServicePermCheck(const char *servName)
{
#ifdef WITH_SELINUX
pid_t callingPid = HdfRemoteGetCallingPid();
if (HdfGetServiceCheck(callingPid, servName) != 0) {
HDF_LOGE("[selinux] %{public}d haven't \"get service\" permission to %{public}s", callingPid, servName);
return HDF_ERR_NOPERM;
}
#endif
return HDF_SUCCESS;
}
static int32_t ListServicePermCheck()
{
#ifdef WITH_SELINUX
pid_t callingPid = HdfRemoteGetCallingPid();
if (HdfListServiceCheck(callingPid) != 0) {
HDF_LOGE("[selinux] %{public}d haven't \"list service\" permission", callingPid);
return HDF_ERR_NOPERM;
}
#endif
return HDF_SUCCESS;
}
static struct HdfDeviceObject *ObtainServiceObject(
struct DevSvcManagerStub *stub, const char *name, struct HdfRemoteService *service)
{
struct HdfDeviceObject *serviceObject = OsalMemCalloc(sizeof(struct HdfDeviceObject));
if (serviceObject == NULL) {
return NULL;
}
serviceObject->priv = (void *)HdfStringCopy(name);
if (serviceObject->priv == NULL) {
OsalMemFree(serviceObject);
return NULL;
}
serviceObject->service = (struct IDeviceIoService *)service;
service->target = (struct HdfObject *)serviceObject;
HdfRemoteServiceAddDeathRecipient(service, &stub->recipient);
return serviceObject;
}
static void ReleaseServiceObject(struct DevSvcManagerStub *stub, struct HdfDeviceObject *serviceObject)
{
if (serviceObject == NULL) {
return;
}
if (serviceObject->priv == NULL) {
HDF_LOGW("release service object has empty name, may broken object");
return;
}
struct HdfRemoteService *serviceRemote = (struct HdfRemoteService *)serviceObject->service;
HdfRemoteServiceRemoveDeathRecipient(serviceRemote, &stub->recipient);
HdfRemoteServiceRecycle((struct HdfRemoteService *)serviceObject->service);
OsalMemFree(serviceObject->priv);
serviceObject->priv = NULL;
serviceObject->service = NULL;
OsalMemFree(serviceObject);
}
static int32_t DevSvcManagerStubAddService(struct IDevSvcManager *super, struct HdfSBuf *data)
{
int ret = HDF_FAILURE;
struct DevSvcManagerStub *stub = (struct DevSvcManagerStub *)super;
if (!HdfRemoteServiceCheckInterfaceToken(stub->remote, data)) {
HDF_LOGE("%{public}s: invalid interface token", __func__);
return HDF_ERR_INVALID_PARAM;
}
const char *name = HdfSbufReadString(data);
if (name == NULL) {
HDF_LOGE("%{public}s failed, name is null", __func__);
return ret;
}
ret = AddServicePermCheck(name);
if (ret != HDF_SUCCESS) {
return ret;
}
uint16_t devClass = DEVICE_CLASS_DEFAULT;
if (!HdfSbufReadUint16(data, &devClass)) {
HDF_LOGE("%{public}s failed, devClass invalid", __func__);
return ret;
}
struct HdfRemoteService *service = HdfSbufReadRemoteService(data);
if (service == NULL) {
HDF_LOGE("%{public}s failed, service is null", __func__);
return ret;
}
const char *servInfo = HdfSbufReadString(data);
struct HdfDeviceObject *serviceObject = ObtainServiceObject(stub, name, service);
if (serviceObject == NULL) {
return HDF_ERR_MALLOC_FAIL;
}
struct HdfDeviceObject *oldServiceObject = super->GetObject(super, name);
ret = super->AddService(super, name, devClass, serviceObject, servInfo);
if (ret != HDF_SUCCESS) {
ReleaseServiceObject(stub, serviceObject);
} else {
ReleaseServiceObject(stub, oldServiceObject);
}
HDF_LOGI("add service %{public}s, %{public}d", name, ret);
return ret;
}
static int32_t DevSvcManagerStubUpdateService(struct IDevSvcManager *super, struct HdfSBuf *data)
{
int ret = HDF_FAILURE;
struct DevSvcManagerStub *stub = (struct DevSvcManagerStub *)super;
if (!HdfRemoteServiceCheckInterfaceToken(stub->remote, data)) {
HDF_LOGE("%{public}s: invalid interface token", __func__);
return HDF_ERR_INVALID_PARAM;
}
const char *name = HdfSbufReadString(data);
if (name == NULL) {
HDF_LOGE("%{public}s failed, name is null", __func__);
return ret;
}
ret = AddServicePermCheck(name);
if (ret != HDF_SUCCESS) {
return ret;
}
uint16_t devClass = DEVICE_CLASS_DEFAULT;
if (!HdfSbufReadUint16(data, &devClass)) {
HDF_LOGE("%{public}s failed, devClass invalid", __func__);
return ret;
}
struct HdfRemoteService *service = HdfSbufReadRemoteService(data);
if (service == NULL) {
HDF_LOGE("%{public}s failed, remote service is null", __func__);
return ret;
}
const char *servInfo = HdfSbufReadString(data);
struct HdfDeviceObject *oldServiceObject = super->GetObject(super, name);
if (oldServiceObject == NULL) {
HDF_LOGE("update service %{public}s not exist", name);
return HDF_DEV_ERR_NO_DEVICE_SERVICE;
}
struct HdfDeviceObject *serviceObject = ObtainServiceObject(stub, name, service);
if (serviceObject == NULL) {
return HDF_ERR_MALLOC_FAIL;
}
ret = super->UpdateService(super, name, devClass, serviceObject, servInfo);
if (ret != HDF_SUCCESS) {
ReleaseServiceObject(stub, serviceObject);
} else {
ReleaseServiceObject(stub, oldServiceObject);
}
HDF_LOGI("update service %{public}s, %{public}d", name, ret);
return ret;
}
static int32_t DevSvcManagerStubGetService(struct IDevSvcManager *super, struct HdfSBuf *data, struct HdfSBuf *reply)
{
int ret = HDF_FAILURE;
struct DevSvcManagerStub *stub = (struct DevSvcManagerStub *)super;
if (!HdfRemoteServiceCheckInterfaceToken(stub->remote, data)) {
HDF_LOGE("%{public}s: invalid interface token", __func__);
return HDF_ERR_INVALID_PARAM;
}
const char *name = HdfSbufReadString(data);
if (name == NULL) {
HDF_LOGE("%{public}s failed, name is null", __func__);
return ret;
}
ret = GetServicePermCheck(name);
if (ret != HDF_SUCCESS) {
return ret;
}
struct HdfRemoteService *remoteService = (struct HdfRemoteService *)super->GetService(super, name);
if (remoteService != NULL) {
ret = HDF_SUCCESS;
HdfSbufWriteRemoteService(reply, remoteService);
HDF_LOGI("service %{public}s found", name);
} else {
HDF_LOGE("service %{public}s not found", name);
}
return ret;
}
static int32_t DevSvcManagerStubListAllService(
struct IDevSvcManager *super, struct HdfSBuf *data, struct HdfSBuf *reply)
{
struct DevSvcManagerStub *stub = (struct DevSvcManagerStub *)super;
if (!HdfRemoteServiceCheckInterfaceToken(stub->remote, data)) {
HDF_LOGE("%{public}s: invalid interface token", __func__);
return HDF_ERR_INVALID_PARAM;
}
int ret = ListServicePermCheck();
if (ret != HDF_SUCCESS) {
return ret;
}
super->ListAllService(super, reply);
return HDF_SUCCESS;
}
static int32_t DevSvcManagerStubRemoveService(struct IDevSvcManager *super, struct HdfSBuf *data)
{
struct DevSvcManagerStub *stub = (struct DevSvcManagerStub *)super;
if (!HdfRemoteServiceCheckInterfaceToken(stub->remote, data)) {
HDF_LOGE("%{public}s: invalid interface token", __func__);
return HDF_ERR_INVALID_PARAM;
}
const char *name = HdfSbufReadString(data);
if (name == NULL) {
HDF_LOGE("%{public}s failed, name is null", __func__);
return HDF_FAILURE;
}
int32_t ret = AddServicePermCheck(name);
if (ret != HDF_SUCCESS) {
return ret;
}
struct HdfDeviceObject *serviceObject = super->GetObject(super, name);
if (serviceObject == NULL) {
HDF_LOGE("remove service %{public}s not exist", name);
return HDF_DEV_ERR_NO_DEVICE_SERVICE;
}
const char *servName = (const char *)serviceObject->priv;
if (servName == NULL) {
HDF_LOGE("remove service %{public}s is broken object", name);
return HDF_ERR_INVALID_OBJECT;
}
if (strcmp(name, servName) != 0) {
HDF_LOGE("remove service %{public}s name mismatch with %{public}s", name, servName);
return HDF_ERR_INVALID_OBJECT;
}
super->RemoveService(super, name);
HDF_LOGI("service %{public}s removed", name);
ReleaseServiceObject(stub, serviceObject);
return HDF_SUCCESS;
}
static int32_t DevSvcManagerStubRegisterServListener(struct IDevSvcManager *super, struct HdfSBuf *data)
{
struct DevSvcManagerStub *stub = (struct DevSvcManagerStub *)super;
if (!HdfRemoteServiceCheckInterfaceToken(stub->remote, data)) {
HDF_LOGE("%{public}s: invalid interface token", __func__);
return HDF_ERR_INVALID_PARAM;
}
uint16_t listenClass = DEVICE_CLASS_DEFAULT;
if (!HdfSbufReadUint16(data, &listenClass)) {
return HDF_ERR_INVALID_PARAM;
}
struct HdfRemoteService *listenerRemote = HdfSbufReadRemoteService(data);
if (listenerRemote == NULL) {
return HDF_ERR_INVALID_PARAM;
}
struct ServStatListenerHolder *listenerHolder =
ServStatListenerHolderCreate((uintptr_t)listenerRemote, listenClass);
if (listenerHolder == NULL) {
return HDF_ERR_MALLOC_FAIL;
}
int ret = super->RegsterServListener(super, listenerHolder);
if (ret != HDF_SUCCESS) {
ServStatListenerHolderRelease(listenerHolder);
} else {
HDF_LOGI("register servstat listener success");
}
return HDF_SUCCESS;
}
static int32_t DevSvcManagerStubUnregisterServListener(struct IDevSvcManager *super, struct HdfSBuf *data)
{
struct DevSvcManagerStub *stub = (struct DevSvcManagerStub *)super;
if (!HdfRemoteServiceCheckInterfaceToken(stub->remote, data)) {
HDF_LOGE("%{public}s: invalid interface token", __func__);
return HDF_ERR_INVALID_PARAM;
}
struct HdfRemoteService *listenerRemote = HdfSbufReadRemoteService(data);
if (listenerRemote == NULL) {
return HDF_ERR_INVALID_PARAM;
}
struct ServStatListenerHolder *listenerHolder = ServStatListenerHolderGet(listenerRemote->index);
if (listenerHolder == NULL) {
HDF_LOGE("failed to unregister svcstat listener, unknown listener");
HdfRemoteServiceRecycle(listenerRemote);
return HDF_ERR_INVALID_OBJECT;
}
super->UnregsterServListener(super, listenerHolder);
ServStatListenerHolderRelease(listenerHolder);
HdfRemoteServiceRecycle(listenerRemote);
HDF_LOGI("unregister servstat listener success");
return HDF_SUCCESS;
}
int DevSvcManagerStubDispatch(struct HdfRemoteService *service, int code, struct HdfSBuf *data, struct HdfSBuf *reply)
{
int ret = HDF_FAILURE;
struct DevSvcManagerStub *stub = (struct DevSvcManagerStub *)service;
if (stub == NULL) {
HDF_LOGE("DevSvcManagerStubDispatch failed, object is null, code is %{public}d", code);
return ret;
}
struct IDevSvcManager *super = (struct IDevSvcManager *)&stub->super;
HDF_LOGD("DevSvcManagerStubDispatch called: code=%{public}d", code);
switch (code) {
case DEVSVC_MANAGER_ADD_SERVICE:
ret = DevSvcManagerStubAddService(super, data);
break;
case DEVSVC_MANAGER_UPDATE_SERVICE:
ret = DevSvcManagerStubUpdateService(super, data);
break;
case DEVSVC_MANAGER_GET_SERVICE:
ret = DevSvcManagerStubGetService(super, data, reply);
break;
case DEVSVC_MANAGER_REMOVE_SERVICE:
ret = DevSvcManagerStubRemoveService(super, data);
break;
case DEVSVC_MANAGER_REGISTER_SVCLISTENER:
ret = DevSvcManagerStubRegisterServListener(super, data);
break;
case DEVSVC_MANAGER_UNREGISTER_SVCLISTENER:
ret = DevSvcManagerStubUnregisterServListener(super, data);
break;
case DEVSVC_MANAGER_LIST_ALL_SERVICE:
ret = DevSvcManagerStubListAllService(super, data, reply);
break;
default:
HDF_LOGE("Unknown code : %{public}d", code);
ret = HDF_FAILURE;
}
return ret;
}
void DevSvcManagerOnServiceDied(struct HdfDeathRecipient *recipient, struct HdfRemoteService *remote)
{
struct DevSvcManagerStub *stub =
HDF_SLIST_CONTAINER_OF(struct HdfDeathRecipient, recipient, struct DevSvcManagerStub, recipient);
if (stub == NULL) {
return;
}
struct IDevSvcManager *iSvcMgr = &stub->super.super;
struct HdfDeviceObject *serviceObject = (struct HdfDeviceObject *)remote->target;
if (serviceObject == NULL || serviceObject->priv == NULL) {
HDF_LOGI("%{public}s:invalid service object", __func__);
return;
}
if (iSvcMgr->GetService == NULL || iSvcMgr->RemoveService == NULL) {
HDF_LOGI("%{public}s:invalid svcmgr object", __func__);
return;
}
char *serviceName = (char *)serviceObject->priv;
struct HdfObject *service = iSvcMgr->GetService(iSvcMgr, serviceName);
HDF_LOGI("service %{public}s died", serviceName);
if ((uintptr_t)service == (uintptr_t)remote) {
HDF_LOGI("%{public}s: remove died service %{public}s", __func__, serviceName);
iSvcMgr->RemoveService(iSvcMgr, serviceName);
}
ReleaseServiceObject(stub, serviceObject);
}
int DevSvcManagerStubStart(struct IDevSvcManager *svcmgr)
{
struct DevSvcManagerStub *inst = (struct DevSvcManagerStub *)svcmgr;
if (inst == NULL) {
return HDF_ERR_INVALID_PARAM;
}
if (inst->started) {
return HDF_SUCCESS;
}
ServStatListenerHolderinit();
static struct HdfRemoteDispatcher dispatcher = {.Dispatch = DevSvcManagerStubDispatch};
inst->remote = HdfRemoteServiceObtain((struct HdfObject *)inst, &dispatcher);
if (inst->remote == NULL) {
HDF_LOGE("failed to obtain device service manager remote service");
return HDF_ERR_MALLOC_FAIL;
}
if (!HdfRemoteServiceSetInterfaceDesc(inst->remote, "HDI.IServiceManager.V1_0")) {
HDF_LOGE("%{public}s: failed to init interface desc", __func__);
return HDF_ERR_INVALID_OBJECT;
}
inst->recipient.OnRemoteDied = DevSvcManagerOnServiceDied;
int ret = HdfRemoteServiceRegister(DEVICE_SERVICE_MANAGER_SA_ID, inst->remote);
if (ret != 0) {
HDF_LOGE("failed to publish device service manager, %{public}d", ret);
HdfRemoteServiceRecycle(inst->remote);
inst->remote = NULL;
} else {
HDF_LOGI("publish device service manager success");
inst->started = true;
}
return ret;
}
static bool DevSvcManagerStubConstruct(struct DevSvcManagerStub *inst)
{
if (inst == NULL) {
return false;
}
if (!DevSvcManagerConstruct(&inst->super)) {
HDF_LOGE("failed to construct device service manager");
return false;
}
inst->super.super.StartService = DevSvcManagerStubStart;
return true;
}
struct HdfObject *DevSvcManagerStubCreate(void)
{
static struct DevSvcManagerStub *instance;
if (instance != NULL) {
return (struct HdfObject *)instance;
}
instance = OsalMemCalloc(sizeof(struct DevSvcManagerStub));
if (!DevSvcManagerStubConstruct(instance)) {
OsalMemFree(instance);
instance = NULL;
}
return (struct HdfObject *)instance;
}
void DevSvcManagerStubRelease(struct HdfObject *object)
{
struct DevmgrServiceStub *instance = (struct DevmgrServiceStub *)object;
if (instance != NULL) {
if (instance->remote != NULL) {
HdfRemoteServiceRecycle(instance->remote);
instance->remote = NULL;
}
}
}