7 Star 30 Fork 8

Gitee Community / OpenHarmony组件开发大赛-有奖征文

 / 详情

源码解读-WiFi模块C代码的Rpc调用

意向
需求
创建于  
2021-10-08 14:23

WiFi C代码Rpc调用

  • 以GetSupportFeature函数为例

communication\wifi\services\wifi_standard\wifi_framework\wifi_manage\idl_client\idl_interface\i_wifi_sta_iface.c

WifiErrorNo GetSupportFeature(long *feature)
{
    RpcClient *client = GetStaRpcClient();
    LockRpcClient(client);
    Context *context = client->context;
    WriteBegin(context, 0);
    WriteFunc(context, "GetSupportFeature");
    WriteEnd(context);
    if (RpcClientCall(client, "GetSupportFeature") != WIFI_IDL_OPT_OK) {
        return WIFI_IDL_OPT_FAILED;
    }
    int result = WIFI_IDL_OPT_FAILED;
    ReadInt(context, &result);
    if (result == WIFI_IDL_OPT_OK) {
        ReadLong(context, feature);
    }
    ReadClientEnd(client);
    UnlockRpcClient(client);
    return result;
}
  • 调用时获取了RpcClient* 指针,然后针对context进行数据封装并进行跨进程调用。

RpcClient* 指针获取

RpcClient *GetStaRpcClient(void)
{
    return OHOS::Wifi::WifiStaHalInterface::GetInstance().mIdlClient->pRpcClient;
}

  • RpcClient* 的初始化相关实现
    communication\wifi\services\wifi_standard\wifi_framework\wifi_manage\idl_client\wifi_idl_client.cpp
int WifiIdlClient::InitClient(void)
{
    const std::string idlSockPath = "/data/misc/wifi/unix_sock.sock";
    pRpcClient = CreateRpcClient(idlSockPath.c_str());  // 注:call CreateRpcClient
    if (pRpcClient == nullptr) {
        LOGE("init rpc client failed!");
        return -1;
    }
    return 0;
}
RpcClient *CreateRpcClient(const char *path)
{
    int fd = ConnectUnixServer(path); // 注:call ConnectUnixServer
    if (fd < 0) {
        return NULL;
    }
    SetNonBlock(fd, 1);
    RpcClient *client = (RpcClient *)calloc(1, sizeof(RpcClient));
    if (client == NULL) {
        close(fd);
        return NULL;
    }
    client->context = CreateContext(CONTEXT_BUFFER_MIN_SIZE);
    if (client->context == NULL) {
        close(fd);
        free(client);
        return NULL;
    }
    client->context->fd = fd;
    client->threadRunFlag = 1;
    client->threadId = 0;
    client->waitReply = CLIENT_STATE_IDLE;
    client->callLockFlag = 0;
    pthread_mutex_init(&client->mutex, NULL);
    pthread_cond_init(&client->condW, NULL);
    pthread_mutex_init(&client->lockMutex, NULL);
    pthread_cond_init(&client->lockCond, NULL);
    int ret = pthread_create(&client->threadId, NULL, RpcClientThreadDeal, client);
    if (ret) {
        pthread_cond_destroy(&client->condW);
        pthread_mutex_destroy(&client->mutex);
        pthread_cond_destroy(&client->lockCond);
        pthread_mutex_destroy(&client->lockMutex);
        ReleaseContext(client->context);
        close(fd);
        free(client);
        return NULL;
    }
    signal(SIGPIPE, SIG_IGN);
    return client;
}
int ConnectUnixServer(const char *path)
{
    struct sockaddr_un sockAddr;
    if (memset_s(&sockAddr, sizeof(sockAddr), 0, sizeof(sockAddr)) != EOK) {
        return -1;
    }
    sockAddr.sun_family = AF_LOCAL;
    if (strncpy_s(sockAddr.sun_path, sizeof(sockAddr.sun_path), path, strlen(path)) != EOK) {
        return -1;
    }
    int sock = CreateSocket(AF_LOCAL);
    if (sock < 0) {
        return -1;
    }
    if (connect(sock, (struct sockaddr *)&sockAddr, sizeof(sockAddr)) < 0) {
        LOGE("connect failed!");
        close(sock);
        return -1;
    }
    return sock;
}

可见Rpc的调用,本质上是创建了一个socket。

  • Rpc调用
    回到WifiErrorNo GetSupportFeature(long *feature),查看调用函数RpcClientCall(client, "GetSupportFeature")。最终调用了int RemoteCall(RpcClient *client)
int RemoteCall(RpcClient *client)
{
    if (client == NULL) {
        return -1;
    }
    if (client->waitReply == CLIENT_STATE_EXIT) {
        return -1;
    }
    int ret = 0;
    Context *context = client->context;
    while (context->wBegin != context->wEnd && ret >= 0) {
        ret = ContextWriteNet(context); // 注:call ContextWriteNet
    }
    if (ret < 0) {
        return ret;
    }
    ret = 0; /* reset ret value */
    pthread_mutex_lock(&client->mutex);
    while (client->waitReply != CLIENT_STATE_DEAL_REPLY && client->waitReply != CLIENT_STATE_EXIT) {
        pthread_cond_wait(&client->condW, &client->mutex);
    }
    if (client->waitReply == CLIENT_STATE_EXIT) {
        ret = -1;
    }
    pthread_mutex_unlock(&client->mutex);
    return ret;
}
int ContextWriteNet(Context *context)
{
    if (context == NULL) {
        return -1;
    }
    if (context->wBegin == context->wEnd) {
        return 0;
    }
    if (context->wBegin < context->wEnd) {
        int ret = MyWrite(context->fd, context->szWrite + context->wBegin, context->wEnd - context->wBegin);
        if (ret > 0) {
            context->wBegin += ret;
        }
        return ret;
    }
    int len = context->wCapacity - context->wBegin;
    int ret = MyWrite(context->fd, context->szWrite + context->wBegin, len); // 注:call MyWrite
    if (ret < 0) {
        return ret;
    }
    if (ret < len) {
        context->wBegin += ret;
        return ret;
    }
    context->wBegin = 0;
    ret = MyWrite(context->fd, context->szWrite, context->wEnd);
    if (ret > 0) {
        context->wBegin = ret;
    }
    return ret;
}
int MyWrite(int fd, const char *buf, int count)
{
    int pos = 0;
    while (count > 0) {
        int ret = write(fd, buf + pos, count);
        if (ret == 0) {
            return SOCK_CLOSE;
        } else if (ret < 0) {
            if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) {
                break;
            } else {
                LOGE("write failed! error is %{public}d", errno);
                return SOCK_ERR;
            }
        }
#ifdef DEBUG
        int tmpSize = ret + 1;
        char *szTmp = (char *)calloc(tmpSize, sizeof(char));
        if (szTmp != NULL) {
            if (strncpy_s(szTmp, tmpSize, buf + pos, ret) == EOK) {
                LOGD("write: %{private}s", szTmp);
            }
            free(szTmp);
        }
#endif
        pos += ret;
        count -= ret;
    }
    return pos;
}

可见Rpc调用就是写socket。

  • Rpc处理
    写socket后需要有处理方,处理方在:communication\wifi\services\wifi_standard\wifi_hal\main.c
int main(void)
{
    char rpcSockPath[] = "/data/misc/wifi/unix_sock.sock";
    if (access(rpcSockPath, 0) == 0) {
        unlink(rpcSockPath);
    }
    if (InitRpcFunc() < 0) { // 注:初始化Rpc函数表
        LOGE("Init Rpc Function failed!");
        return -1;
    }
    RpcServer *server = CreateRpcServer(rpcSockPath);  // 注:创建Rpc服务
    if (server == NULL) {
        LOGE("Create RPC Server by %{public}s failed!", rpcSockPath);
        return -1;
    }
    SetRpcServerInited(server);
    setvbuf(stdout, NULL, _IOLBF, 0);
    signal(SIGINT, SignalExit);
    signal(SIGTERM, SignalExit);
    signal(SIGPIPE, SIG_IGN);

    RunRpcLoop(server); // 注:进入Rpc消息循环
    /* stop wpa_supplicant, hostapd, and other resources */
    ForceStop();
    StopSoftAp();
    P2pForceStop();
    ReleaseWifiHalVendorInterface();
    /* clear RPC Server */
    SetRpcServerInited(NULL);
    ReleaseRpcServer(server);
    ReleaseRpcFunc();
    LOGI("hal service exists!");
    return 0;
}

从代码逻辑看,wifi_hal进程起来后初始化函数表,然后建立socket连接,并进入消息循环,处理接收到的Rpc socket消息

一、初始化函数表
int InitRpcFunc(void)
{
    if (g_rpcFuncHandle != NULL) {
        return 0;
    }
    g_rpcFuncHandle = (WifiHalRpcFunc *)calloc(RPC_FUNC_NUM, sizeof(WifiHalRpcFunc));
    if (g_rpcFuncHandle == NULL) {
        return -1;
    }
    int ret = 0;
    ret += InitRpcFuncMapBase();
    ret += InitRpcFuncMapChip();
    ret += InitRpcFuncMapSupplicant();
    ret += InitRpcFuncMapSta();
    ret += InitRpcFuncMapAp();
    ret += InitRpcFuncMapCommon();
    ret += InitRpcFuncMapP2p();
    if (ret < 0) {
        return -1;
    }
    if (InitCallbackMsg() < 0) {
        return -1;
    }
    return 0;
}
static int InitRpcFuncMapSta(void)
{
    int ret = 0;
    ret += PushRpcFunc("Start", RpcStart);
    ret += PushRpcFunc("Stop", RpcStop);
    ret += PushRpcFunc("StartScan", RpcStartScan);
    ret += PushRpcFunc("GetScanInfos", RpcGetScanInfos);
    ret += PushRpcFunc("StartPnoScan", RpcStartPnoScan);
    ret += PushRpcFunc("StopPnoScan", RpcStopPnoScan);
    ret += PushRpcFunc("Connect", RpcConnect);
    ret += PushRpcFunc("Reconnect", RpcReconnect);
    ret += PushRpcFunc("Reassociate", RpcReassociate);
    ret += PushRpcFunc("Disconnect", RpcDisconnect);
    ret += PushRpcFunc("GetStaCapabilities", RpcGetStaCapabilities);
    ret += PushRpcFunc("GetDeviceMacAddress", RpcGetDeviceMacAddress);
    ret += PushRpcFunc("GetFrequencies", RpcGetFrequencies);
    ret += PushRpcFunc("SetAssocMacAddr", RpcSetAssocMacAddr);
    ret += PushRpcFunc("SetScanningMacAddress", RpcSetScanningMacAddress);
    ret += PushRpcFunc("DeauthLastRoamingBssid", RpcDeauthLastRoamingBssid);
    ret += PushRpcFunc("GetSupportFeature", RpcGetSupportFeature);
    ret += PushRpcFunc("RunCmd", RpcRunCmd);
    ret += PushRpcFunc("SetWifiTxPower", RpcSetWifiTxPower);
    ret += PushRpcFunc("RemoveNetwork", RpcRemoveNetwork);
    ret += PushRpcFunc("AddNetwork", RpcAddNetwork);
    ret += PushRpcFunc("EnableNetwork", RpcEnableNetwork);
    ret += PushRpcFunc("DisableNetwork", RpcDisableNetwork);
    ret += PushRpcFunc("SetNetwork", RpcSetNetwork);
    ret += PushRpcFunc("SaveNetworkConfig", RpcSaveNetworkConfig);
    ret += PushRpcFunc("StartWpsPbcMode", RpcStartWpsPbcMode);
    ret += PushRpcFunc("StartWpsPinMode", RpcStartWpsPinMode);
    ret += PushRpcFunc("StopWps", RpcStopWps);
    ret += PushRpcFunc("GetRoamingCapabilities", RpcGetRoamingCapabilities);
    ret += PushRpcFunc("SetRoamConfig", RpcSetRoamConfig);
    ret += PushRpcFunc("WpaGetNetwork", RpcWpaGetNetwork);
    ret += PushRpcFunc("WpaAutoConnect", RpcWpaAutoConnect);
    ret += PushRpcFunc("WpaBlocklistClear", RpcWpaBlocklistClear);
    ret += PushRpcFunc("GetNetworkList", RpcGetNetworkList);
    ret += PushRpcFunc("GetConnectSignalInfo", RpcGetConnectSignalInfo);
    return ret;
}
二、建立Socket通信
RpcServer *CreateRpcServer(const char *path)
{
    if (path == NULL) {
        return NULL;
    }
    RpcServer *server = (RpcServer *)calloc(1, sizeof(RpcServer));
    if (server == NULL) {
        return NULL;
    }
    int flag = 1;
    do {
        int ret = CreateUnixServer(path, DEFAULT_LISTEN_QUEUE_SIZE); // 注: call CreateUnixServer,建立socket通信
        if (ret < 0) {
            break;
        }
        server->listenFd = ret;
        server->loop = CreateEventLoop(MAX_SUPPORT_CLIENT_FD_SIZE);
        if (server->loop == NULL) {
            break;
        }
        server->clients = InitHashTable(DEFAULT_HASHTABLE_SLOTS);
        if (server->clients == NULL) {
            break;
        }
        if (AddFdEvent(server->loop, server->listenFd, READ_EVENT) < 0) {
            break;
        }
        pthread_mutex_init(&server->mutex, NULL);
        flag = 0;
    } while (0);
    if (flag) {
        ReleaseRpcServer(server);
        return NULL;
    }
    return server;
}
int CreateUnixServer(const char *path, int backlog)
{
    struct sockaddr_un sockAddr;
    if (memset_s(&sockAddr, sizeof(sockAddr), 0, sizeof(sockAddr)) != EOK) {
        return -1;
    }
    sockAddr.sun_family = AF_LOCAL;
    if (strncpy_s(sockAddr.sun_path, sizeof(sockAddr.sun_path), path, strlen(path)) != EOK) {
        return -1;
    }
    int sock = CreateSocket(AF_LOCAL);
    if (sock < 0) {
        return -1;
    }
    int keepAlive = 1;
    setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepAlive, sizeof(keepAlive));
    int reuseaddr = 1;
    setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&reuseaddr, sizeof(reuseaddr));
    if (bind(sock, (struct sockaddr *)&sockAddr, sizeof(sockAddr)) < 0) {
        LOGE("bind failed!");
        close(sock);
        return -1;
    }
    if (SetNonBlock(sock, 1) != 0) {
        LOGE("set socket non block failed!");
        close(sock);
        return -1;
    }
    fcntl(sock, F_SETFD, FD_CLOEXEC);
    if (listen(sock, backlog) < 0) {
        LOGE("listen failed!");
        close(sock);
        return -1;
    }
    return sock;
}
三、进行事件循环
int RunRpcLoop(RpcServer *server)
{
    if (server == NULL) {
        return -1;
    }
    EventLoop *loop = server->loop;
    while (!loop->stop) {
        BeforeLoop(server);
        int retval = epoll_wait(loop->epfd, loop->epEvents, loop->setSize, 1); /* wait 1ms */
        for (int i = 0; i < retval; ++i) {
            struct epoll_event *e = loop->epEvents + i;
            int fd = e->data.fd;
            unsigned int mask = CheckEventMask(e);
            if (fd == server->listenFd) {
                OnAccept(server, mask);
            } else {
                DealFdEvents(server, fd, mask);
            }
        }
    }
    return 0;
}

  • 接收函数中响应消息并处理
int RpcGetSupportFeature(RpcServer *server, Context *context)
{
    if (server == NULL || context == NULL) {
        return -1;
    }
    long feature = 0;
    WifiErrorNo err = GetSupportFeature(&feature);
    WriteBegin(context, 0);
    WriteInt(context, err);
    if (err == WIFI_HAL_SUCCESS) {
        WriteLong(context, feature);
    }
    WriteEnd(context);
    return 0;
}

因此,Rpc正是依靠socket实现了跨进程收发,发送方将数据打包进数据包,然后写入和目标方建立的socket通道,目标方在进程启动时进入消息循环读取数据,如果有数据过来,读取到数据解析后转发给对应的函数进行处理。

评论 (3)

zf0606 创建了需求
展开全部操作日志

学到了,感谢分享

06-20 10:09:32.693 1041 1041 E 01560/WifiHalService: Create RPC Server by /data/misc/wifi/unix_sock.sock failed!
06-20 10:09:34.011 1106 1106 E 00000/WifiRpcNet: bind failed!
06-20 10:09:34.011 1106 1106 E 01560/WifiHalService: Create RPC Server by /data/misc/wifi/unix_sock.sock failed!

这种socket创建fail可能是啥原因呢?

一般是权限原因的可能性大一些。比如目录权限等,进程启动账号等

登录 后才可以发表评论

状态
负责人
项目
里程碑
Pull Requests
关联的 Pull Requests 被合并后可能会关闭此 issue
分支
开始日期   -   截止日期
-
置顶选项
优先级
预计工期 (小时)
参与者(3)
5522482 ltree930 1578988012
其他
1
https://gitee.com/gitee-community/OHZW210809.git
git@gitee.com:gitee-community/OHZW210809.git
gitee-community
OHZW210809
OpenHarmony组件开发大赛-有奖征文

搜索帮助