* 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 <fcntl.h>
#include <limits.h>
#include <securec.h>
#include <stdlib.h>
#include <sys/syscall.h>
#include <unistd.h>
#include "devhost_service_proxy.h"
#include "device_token_proxy.h"
#include "devmgr_query_device.h"
#include "devsvc_manager.h"
#include "hdf_log.h"
#include "hdf_sbuf.h"
#include "osal_mem.h"
#include "osal_sysevent.h"
#include "devmgr_service_stub.h"
#define HDF_LOG_TAG devmgr_service_stub
static int32_t DevmgrServiceStubDispatchAttachDevice(struct IDevmgrService *devmgrSvc, struct HdfSBuf *data)
{
uint32_t deviceId;
if (!HdfSbufReadUint32(data, &deviceId)) {
HDF_LOGE("%{public}s:failed to get host id and device id", __func__);
return HDF_ERR_INVALID_PARAM;
}
struct HdfDevTokenProxy *tokenClnt = HdfDevTokenProxyObtain(NULL);
if (tokenClnt == NULL) {
return HDF_FAILURE;
}
tokenClnt->super.devid = deviceId;
return devmgrSvc->AttachDevice(devmgrSvc, &tokenClnt->super);
}
static int32_t DevmgrServiceStubDispatchDetachDevice(struct IDevmgrService *devmgrSvc, struct HdfSBuf *data)
{
uint32_t deviceId;
if (!HdfSbufReadUint32(data, &deviceId)) {
HDF_LOGE("%{public}s:failed to get host id and device id", __func__);
return HDF_ERR_INVALID_PARAM;
}
return devmgrSvc->DetachDevice(devmgrSvc, deviceId);
}
static int32_t DevmgrServiceStubDispatchLoadDevice(struct IDevmgrService *devmgrSvc, struct HdfSBuf *data)
{
const char *serviceName = HdfSbufReadString(data);
if (serviceName == NULL) {
HDF_LOGE("%{public}s:service name is null", __func__);
return HDF_ERR_INVALID_PARAM;
}
HDF_LOGI("%{public}s:load service %{public}s", __func__, serviceName);
return devmgrSvc->LoadDevice(devmgrSvc, serviceName);
}
static int32_t DevmgrServiceStubDispatchUnloadDevice(struct IDevmgrService *devmgrSvc, struct HdfSBuf *data)
{
const char *serviceName = HdfSbufReadString(data);
if (serviceName == NULL) {
HDF_LOGE("%{public}s:service name is null", __func__);
return HDF_ERR_INVALID_PARAM;
}
HDF_LOGI("%{public}s:unload service %{public}s", __func__, serviceName);
return devmgrSvc->UnloadDevice(devmgrSvc, serviceName);
}
static int32_t DevmgrServiceStubDispatchListAllDevice(struct IDevmgrService *devmgrSvc, struct HdfSBuf *reply)
{
if (reply == NULL) {
HDF_LOGE("%{public}s:service name is null", __func__);
return HDF_ERR_INVALID_PARAM;
}
HDF_LOGD("%{public}s:get all device info", __func__);
return devmgrSvc->ListAllDevice(devmgrSvc, reply);
}
int32_t DevmgrServiceStubDispatch(struct HdfRemoteService *stub, int code, struct HdfSBuf *data, struct HdfSBuf *reply)
{
int32_t ret = HDF_FAILURE;
struct DevmgrServiceStub *serviceStub = (struct DevmgrServiceStub *)stub;
if (serviceStub == NULL) {
return HDF_ERR_INVALID_PARAM;
}
struct IDevmgrService *super = (struct IDevmgrService *)&serviceStub->super;
if (!HdfRemoteServiceCheckInterfaceToken(serviceStub->remote, data)) {
HDF_LOGE("%{public}s: invalid interface token, code=%{public}d", __func__, code);
return HDF_ERR_INVALID_PARAM;
}
uint32_t hostId = 0;
switch (code) {
case DEVMGR_SERVICE_ATTACH_DEVICE_HOST:
if (!HdfSbufReadUint32(data, &hostId)) {
HDF_LOGE("invalid host id");
return HDF_FAILURE;
}
struct HdfRemoteService *service = HdfSbufReadRemoteService(data);
struct IDevHostService *hostIf = DevHostServiceProxyObtain(hostId, service);
ret = super->AttachDeviceHost(super, hostId, hostIf);
break;
case DEVMGR_SERVICE_ATTACH_DEVICE:
ret = DevmgrServiceStubDispatchAttachDevice(super, data);
break;
case DEVMGR_SERVICE_DETACH_DEVICE:
ret = DevmgrServiceStubDispatchDetachDevice(super, data);
break;
case DEVMGR_SERVICE_LOAD_DEVICE:
ret = DevmgrServiceStubDispatchLoadDevice(super, data);
break;
case DEVMGR_SERVICE_UNLOAD_DEVICE:
ret = DevmgrServiceStubDispatchUnloadDevice(super, data);
break;
case DEVMGR_SERVICE_QUERY_DEVICE:
ret = DevFillQueryDeviceInfo(super, data, reply);
break;
case DEVMGR_SERVICE_LIST_ALL_DEVICE:
ret = DevmgrServiceStubDispatchListAllDevice(super, reply);
break;
default:
break;
}
if (ret != HDF_SUCCESS) {
HDF_LOGE("%{public}s devmgr service stub dispach failed, cmd id is %{public}d, ret = %{public}d", __func__,
code, ret);
HdfSbufWriteInt32(reply, ret);
}
return ret;
}
static void RemoveModule(const char *module)
{
uint32_t flags = O_NONBLOCK | O_EXCL;
if (syscall(__NR_delete_module, module, flags) != 0) {
HDF_LOGE("failed to remove module %{public}s", module);
}
}
static int32_t InstallModule(const char *module)
{
HDF_LOGI("try to install module %{public}s", module);
int fd = open(module, O_RDONLY | O_CLOEXEC);
if (fd < 0) {
HDF_LOGE("module %{public}s is invalid", module);
return HDF_ERR_BAD_FD;
}
int32_t ret = syscall(SYS_finit_module, fd, "", 0);
if (ret != 0) {
HDF_LOGE("failed to install module %{public}s, %{public}d", module, ret);
}
close(fd);
return ret;
}
static int32_t MakeModulePath(char *buffer, const char *moduleName)
{
char temp[PATH_MAX] = {0};
if (sprintf_s(temp, PATH_MAX, "%s/%s.ko", HDF_MODULE_DIR, moduleName) <= 0) {
HDF_LOGI("driver module path sprintf failed: %{public}s", moduleName);
return HDF_FAILURE;
}
HDF_LOGI("driver module file: %{public}s", temp);
char *path = realpath(temp, buffer);
if (path == NULL || strncmp(path, HDF_MODULE_DIR, strlen(HDF_MODULE_DIR)) != 0) {
HDF_LOGE("driver module file is invalid: %{public}s", temp);
return HDF_ERR_INVALID_PARAM;
}
return HDF_SUCCESS;
}
static int32_t ModuleSysEventHandle(
struct HdfSysEventNotifyNode *self, uint64_t eventClass, uint32_t event, const char *content)
{
if (self == NULL || (eventClass & HDF_SYSEVENT_CLASS_MODULE) == 0 || content == NULL) {
return HDF_ERR_INVALID_PARAM;
}
HDF_LOGI("handle driver module: %{public}s", content);
char modulePath[PATH_MAX] = {0};
int32_t ret = MakeModulePath(modulePath, content);
if (ret != HDF_SUCCESS) {
return ret;
}
switch (event) {
case KEVENT_MODULE_INSTALL:
ret = InstallModule(modulePath);
break;
case KEVENT_MODULE_REMOVE:
RemoveModule(modulePath);
break;
default:
ret = HDF_ERR_NOT_SUPPORT;
break;
}
return ret;
}
static int32_t DriverModuleLoadHelperInit(void)
{
static struct HdfSysEventNotifyNode sysEventNotify = {
.callback = ModuleSysEventHandle,
};
int32_t ret = HdfSysEventNotifyRegister(&sysEventNotify, HDF_SYSEVENT_CLASS_MODULE);
if (ret != HDF_SUCCESS) {
HDF_LOGW("ModuleLoadHelper:failed to register module event listener");
}
return ret;
}
static struct HdfRemoteDispatcher g_devmgrDispatcher = {
.Dispatch = DevmgrServiceStubDispatch,
};
int DevmgrServiceStubStartService(struct IDevmgrService *inst)
{
struct DevmgrServiceStub *fullService = (struct DevmgrServiceStub *)inst;
if (fullService == NULL) {
return HDF_ERR_INVALID_PARAM;
}
struct IDevSvcManager *serviceManager = DevSvcManagerGetInstance();
if (serviceManager == NULL) {
HDF_LOGI("Start service failed, fullService is null");
return HDF_ERR_INVALID_OBJECT;
}
struct HdfRemoteService *remoteService = HdfRemoteServiceObtain((struct HdfObject *)inst, &g_devmgrDispatcher);
if (remoteService == NULL) {
HDF_LOGI("failed to start devmgr, remoteService obtain err");
return HDF_ERR_MALLOC_FAIL;
}
if (!HdfRemoteServiceSetInterfaceDesc(remoteService, "HDI.IDeviceManager.V1_0")) {
HDF_LOGE("%{public}s: failed to init interface desc", __func__);
HdfRemoteServiceRecycle(remoteService);
return HDF_FAILURE;
}
struct HdfDeviceObject *deviceObject = OsalMemCalloc(sizeof(struct HdfDeviceObject));
if (deviceObject == NULL) {
HdfRemoteServiceRecycle(remoteService);
return HDF_ERR_MALLOC_FAIL;
}
deviceObject->service = (struct IDeviceIoService *)remoteService;
int status =
DevSvcManagerAddService(serviceManager, DEVICE_MANAGER_SERVICE, DEVICE_CLASS_DEFAULT, deviceObject, NULL);
if (status != HDF_SUCCESS) {
HdfRemoteServiceRecycle(remoteService);
OsalMemFree(deviceObject);
return status;
}
fullService->remote = remoteService;
(void)DriverModuleLoadHelperInit();
status = DevmgrServiceStartService((struct IDevmgrService *)&fullService->super);
if (status != HDF_SUCCESS) {
HdfRemoteServiceRecycle(remoteService);
OsalMemFree(deviceObject);
return status;
}
return DevSvcManagerStartService();
}
static void DevmgrServiceStubConstruct(struct DevmgrServiceStub *inst)
{
struct IDevmgrService *pvtbl = (struct IDevmgrService *)inst;
DevmgrServiceFullConstruct(&inst->super);
pvtbl->StartService = DevmgrServiceStubStartService;
inst->remote = NULL;
OsalMutexInit(&inst->devmgrStubMutx);
}
struct HdfObject *DevmgrServiceStubCreate(void)
{
static struct DevmgrServiceStub *instance = NULL;
if (instance == NULL) {
instance = (struct DevmgrServiceStub *)OsalMemCalloc(sizeof(struct DevmgrServiceStub));
if (instance == NULL) {
HDF_LOGE("Creating devmgr service stub failed, alloc mem error");
return NULL;
}
DevmgrServiceStubConstruct(instance);
}
return (struct HdfObject *)instance;
}
void DevmgrServiceStubRelease(struct HdfObject *object)
{
struct DevmgrServiceStub *instance = (struct DevmgrServiceStub *)object;
if (instance != NULL) {
if (instance->remote != NULL) {
HdfRemoteServiceRecycle(instance->remote);
instance->remote = NULL;
}
OsalMutexDestroy(&instance->devmgrStubMutx);
OsalMemFree(instance);
}
}