消息通知之系统层事件发布相关流程

2023-11-18

前言

Openharmony 3.1Release中存在消息通知的处理,消息通知包括系统层事件发布、消息订阅、消息投递与处理,为了开发者能够熟悉消息的处理流程,本篇文章主要介绍系统层事件发布的相关流程。

整体流程

代码流程

发布消息

{
eventAction)want.SetAction("usual.event.license.LIC_EXPIRED");
EventFwk::CommonEventPublishInfo publishInfo;
    CommonEventData commonData;
    commonData.SetWant(want);
    if (!CommonEventManager::PublishCommonEvent(commonData, publishInfo)) {
        LICENSE_LOGI("failed to publish event[%{public}d]", eventAction);
        return false;
    }
    return true;
    
}

 

CommonEventManager函数处理,调用PublishCommonEvent

{
    CommonEventPublishInfo publishInfo;
    return PublishCommonEventAsUser(data, publishInfo, nullptr, UNDEFINED_USER);
}

调用PublishCommonEventAsUser

    const CommonEventPublishInfo &publishInfo, const std::shared_ptr<CommonEventSubscriber> &subscriber,
    const int32_t &userId)
{
    EVENT_LOGI("enter");
    return DelayedSingleton<CommonEvent>::GetInstance()->PublishCommonEventAsUser(data, publishInfo, subscriber,
        userId);
}

调用CommonEvent的PublishCommonEventAsUser

    const std::shared_ptr<CommonEventSubscriber> &subscriber, const int32_t &userId)
{
    EVENT_LOGI("enter");
    sptr<IRemoteObject> commonEventListener = nullptr;
    if (!PublishParameterCheck(data, publishInfo, subscriber, commonEventListener)) {
        return false;
    }
    EVENT_LOGD("before PublishCommonEvent proxy valid state is %{public}d", isProxyValid_);
    return commonEventProxy_->PublishCommonEvent(data, publishInfo, commonEventListener, userId);
}

CommonEventProxy调用PublishCommonEvent向服务端发送CES_PUBLISH_COMMON_EVENT消息

    const sptr<IRemoteObject> &commonEventListener, const int32_t &userId)
{
    EVENT_LOGD("start");

    MessageParcel data;
    MessageParcel reply;

     …….

    bool ret = SendRequest(ICommonEvent::Message::CES_PUBLISH_COMMON_EVENT, data, reply);
    if (ret) {
        ret = reply.ReadBool();
    }

    EVENT_LOGD("end");
    return ret;
}

服务端接收CES_PUBLISH_COMMON_EVENT消息

{
    if (data.ReadInterfaceToken() != GetDescriptor()) {
        EVENT_LOGE("local descriptor is not equal to remote");
        return ERR_TRANSACTION_FAILED;
    }

    switch (code) {
        case static_cast<uint32_t>(ICommonEvent::Message::CES_PUBLISH_COMMON_EVENT): {
            std::unique_ptr<CommonEventData> event(data.ReadParcelable<CommonEventData>());
            std::unique_ptr<CommonEventPublishInfo> publishinfo(data.ReadParcelable<CommonEventPublishInfo>());
            sptr<IRemoteObject> commonEventListener = nullptr;
            bool hasLastSubscriber = data.ReadBool();
            if (hasLastSubscriber) {
                sptr<IRemoteObject> commonEventListener = data.ReadRemoteObject();
            }
            int32_t userId = data.ReadInt32();
            if (!event) {
                EVENT_LOGE("Failed to ReadParcelable<CommonEventData>");
                return ERR_INVALID_VALUE;
            }
            if (!publishinfo) {
                EVENT_LOGE("Failed to ReadParcelable<CommonEventPublishInfo>");
                return ERR_INVALID_VALUE;
            }
            bool ret = PublishCommonEvent(*event, *publishinfo, commonEventListener, userId);
            if (!reply.WriteBool(ret)) {
                EVENT_LOGE("Failed to write reply ");
                return ERR_INVALID_VALUE;
            }
            break;
        }

        ……..

        default:
            EVENT_LOGW("unknown, code = %{public}u, flags= %{public}u", code, option.GetFlags());
            return IPCObjectStub::OnRemoteRequest(code, data, reply, option);
    }
    return NO_ERROR;
}

调用服务端PublishCommonEvent函数

    const CommonEventPublishInfo &publishinfo, const sptr<IRemoteObject> &commonEventListener, const int32_t &userId)
{
    EVENT_LOGI("enter");

    if (!IsReady()) {
        return false;
    }

    return PublishCommonEventDetailed(event, publishinfo, commonEventListener, IPCSkeleton::GetCallingPid(),
                   IPCSkeleton::GetCallingUid(),userId);
}

PublishCommonEventDetailed绑定PublishCommonEvent,然后进行事件投递

    const CommonEventPublishInfo &publishinfo, const sptr<IRemoteObject> &commonEventListener, const pid_t &pid,
    const uid_t &uid, const int32_t &userId)
{
    EVENT_LOGI("enter");

    struct tm recordTime = {0};
    if (!GetSystemCurrentTime(&recordTime)) {
        EVENT_LOGE("Failed to GetSystemCurrentTime");
        return false;
    }

    std::string bundleName = DelayedSingleton<BundleManagerHelper>::GetInstance()->GetBundleName(uid);

    if (DelayedSingleton<PublishManager>::GetInstance()->CheckIsFloodAttack(uid)) {
        EVENT_LOGE("Too many common events have been sent in a short period from %{public}s (pid = %{public}d, uid = "
                   "%{public}d, userId = %{public}d)", bundleName.c_str(), pid, uid, userId);
        return false;
    }

    Security::AccessToken::AccessTokenID callerToken = IPCSkeleton::GetCallingTokenID();

    std::function<void()> PublishCommonEventFunc = std::bind(&InnerCommonEventManager::PublishCommonEvent,
        innerCommonEventManager_, event, publishinfo, commonEventListener, recordTime, pid,
        uid, callerToken, userId, bundleName, this);
    return handler_->PostTask(PublishCommonEventFunc);
}

在事件投递中调用处理InnerCommonEventManager::PublishCommonEvent

    const sptr<IRemoteObject> &commonEventListener, const struct tm &recordTime, const pid_t &pid, const uid_t &uid,
    const Security::AccessToken::AccessTokenID &callerToken, const int32_t &userId, const std::string &bundleName,
    const sptr<IRemoteObject> &service)
{
    EVENT_LOGI("enter %{public}s(pid = %{public}d, uid = %{public}d), event = %{public}s to userId = %{public}d",
        bundleName.c_str(), pid, uid, data.GetWant().GetAction().c_str(), userId);

    if (data.GetWant().GetAction().empty()) {
        EVENT_LOGE("the commonEventdata action is null");
        return false;
    }

    if ((!publishInfo.IsOrdered()) && (commonEventListener != nullptr)) {
        EVENT_LOGE("When publishing unordered events, the subscriber object is not required.");
        return false;
    }

    std::string action = data.GetWant().GetAction();
    bool isSystemEvent = DelayedSingleton<CommonEventSupport>::GetInstance()->IsSystemEvent(action);
    …….
    if (!controlPtr_) {
        EVENT_LOGE("CommonEventControlManager ptr is nullptr");
        return false;
    }
    controlPtr_->PublishCommonEvent(eventRecord, commonEventListener);
        …….
    return true;
}

默认IsOrdered是false,参数不配置调用ProcessUnorderedEvent

    const CommonEventRecord &eventRecord, const sptr<IRemoteObject> &commonEventListener)
{
    EVENT_LOGI("enter");

    bool ret = false;

    if (!eventRecord.publishInfo->IsOrdered()) {
        ret = ProcessUnorderedEvent(eventRecord);
    } else {
        ret = ProcessOrderedEvent(eventRecord, commonEventListener);
    }

    return ret;
}

无序事件处理,投递事件在hander中调用NotifyUnorderedEvent

    const CommonEventRecord &eventRecord, const std::shared_ptr<EventSubscriberRecord> &subscriberRecord)
{
    …….

    std::function<void()> innerCallback =
        std::bind(&CommonEventControlManager::NotifyUnorderedEvent, this, eventRecordPtr);

    if (eventRecord.isSystemEvent) {
        ret = handler_->PostImmediateTask(innerCallback);
    } else {
        ret = handler_->PostTask(innerCallback);
    }

    return ret;
}

NotifyUnorderedEvent调用NotifyEvent

{
    ……
    for (auto vec : eventRecord->receivers) {
        size_t index = eventRecord->nextReceiver++;
        eventRecord->curReceiver = vec->commonEventListener;
        if (vec->isFreeze) {
            eventRecord->deliveryState[index] = OrderedEventRecord::SKIPPED;
            DelayedSingleton<CommonEventSubscriberManager>::GetInstance()->InsertFrozenEvents(vec, *eventRecord);
        } else {
            ……
            if (ret == OrderedEventRecord::DELIVERED) {
                eventRecord->state = OrderedEventRecord::RECEIVEING;
                commonEventListenerProxy->NotifyEvent(
                    *(eventRecord->commonEventData), false, eventRecord->publishInfo->IsSticky());
                eventRecord->state = OrderedEventRecord::RECEIVED;
            }
        }
    }
    ……
}

在EventReceiveProxy::NotifyEvent函数中发送消息CES_NOTIFY_COMMON_EVENT

{
    ……
    int32_t result = remote->SendRequest(
        static_cast<uint32_t>(IEventReceive::Message::CES_NOTIFY_COMMON_EVENT), data, reply, option);
    if (result != OHOS::NO_ERROR) {
        EVENT_LOGE("Failed to SendRequest, error code: %{public}d", result);
        return;
    }

    EVENT_LOGD("end");
}

服务端接收消息调用服务端NotifyEvent函数

{
    if (data.ReadInterfaceToken() != GetDescriptor()) {
        EVENT_LOGE("local descriptor is not equal to remote");
        return ERR_TRANSACTION_FAILED;
    }
    switch (code) {
        case static_cast<uint32_t>(IEventReceive::Message::CES_NOTIFY_COMMON_EVENT): {
            std::unique_ptr<CommonEventData> eventData(data.ReadParcelable<CommonEventData>());
            bool ordered = data.ReadBool();
            bool sticky = data.ReadBool();
            if (eventData == nullptr) {
                EVENT_LOGE("callback stub receive common event data is nullptr");
                return ERR_INVALID_VALUE;
            }
            NotifyEvent(*eventData, ordered, sticky);
            break;
        }

        default:
            EVENT_LOGW("event receive stub receives unknown code, code = %{public}u", code);
            return IPCObjectStub::OnRemoteRequest(code, data, reply, option);
    }

    return NO_ERROR;
}

服务端NotifyEvent函数,调用OnReceiveEvent

{
    EVENT_LOGI("enter");

    std::lock_guard<std::mutex> lock(mutex_);
    if (!IsReady()) {
        EVENT_LOGE("not ready");
        return;
    }

    std::function<void()> onReceiveEventFunc =
        std::bind(&CommonEventListener::OnReceiveEvent, this, commonEventData, ordered, sticky);
    handler_->PostTask(onReceiveEventFunc);
}

从上面我们就梳理整个系统层事件发布流程,希望对大家有所帮助。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

消息通知之系统层事件发布相关流程 的相关文章

  • React 从零开始学习(八)—— 决出胜负

    有两个玩家参与之后 就需要判断胜负 以及游戏何时结束 在 Board js 文件中添加 calculateWinner 方法来计算判断游戏 传入 squares 是一个长度为 9 的数组 function calculateWinner s
  • Go 1.19.3 context原理简析

    Context context Context一般用作函数或方法的第一个参数 其作用为管控协程在用户侧 生命周期 它是线程安全的 在多个goroutine之间可以任意调用其方法 不需考虑锁的问题 原理简析 context的结构是一棵以Bac
  • scrapy mysql的同步插入与异步插入

    主要代码是在Pipeline中进行编写 上完整代码 同步插入代码 同步插入 class MysqlPipeline2 object 同步操作 def init self 建立连接 self conn pymysql connect loca

随机推荐

  • opencv实现答题卡识别

    识别答题卡 import cv2 import numpy as np def showImg img name img cv2 imshow img name img cv2 waitKey cv2 destroyAllWindows d
  • VMware下载与安装

    VMware的简介 VMWare虚拟机软件是一个 虚拟PC 软件 它使你可以在一台机器上同时运行二个或更多Windows DOS LINUX系统 与 多启动 系统相比 VMWare采用了完全不同的概念 多启动系统在一个时刻只能运行一个系统
  • 扩散模型大杀器 ControlNet 解析

    Controlnet的介绍 1 论文信息 标题 Adding Conditional Control to Text to Image Diffusion Models 作者 Lvmin Zhang Maneesh Agrawala 原文链
  • Object.entries()方法使用详解

    一 概述 对象的数据处理方法 我们熟知的有很多 比如Object keys Object values for in等 本文将其与其它常见使用方法进行对比 详细解析其特性 二 对比 for in Object entries 方法的优势 1
  • Python计算过去周末的方法

    在Python中 我们可以使用datetime模块来计算过去的周末数量 datetime模块提供了各种日期和时间相关的函数和类 使我们可以轻松地处理日期和时间 首先 我们需要导入datetime模块 import datetime 然后 我
  • Vue自定义指令 「干货」

    在 Vue 除了核心功能默认内置的指令 v model 和 v show Vue 也允许注册自定义指令 它的作用价值在于当开发人员在某些场景下需要对普通 DOM 元素进行操作 Vue 自定义指令有全局注册和局部注册两种方式 先来看看注册全局
  • springboot修改端口号的两种方式

    前言 springboot默认的端口号为8080 端口号的配置有两种方式 一种是在配置文件application properties中 另一种是在配置文件application yml中 1 第一种方式 修改配置文件application
  • 最短路径-Dijkstra算法与Floyd算法

    最短路径 Dijkstra算法与Floyd算法 原文 https www cnblogs com smile233 p 8303673 html 一 最短路径 在非网图中 最短路径是指两顶点之间经历的边数最少的路径 AE 1 ADE 2 A
  • 【ubuntu22.04 安装优麒麟wine封装版微信】

    选择该版本原因 目前使用体验来说优于deepin封装版 1 到优麒麟软件下载页面找到微信 wine 下载Wine环境包和 微信 wine 包 2 终端输入 sudo apt get install f y ukylin wine 70 6
  • linux 环境下 openssl 生成ecdsa公、私钥

    我的个人博客 逐步前行STEP 1 生成ecdsa私钥 openssl ecparam name prime256v1 genkey noout out prime256v1 key pem 2 从ecdsa私钥提取公钥 openssl p
  • windows下anaconda3安装MySQLdb

    本文转自Windows下python3 6 安装MySQLdb 首先需要下载windows版本的mysqlclient 原作者给出了其中一个版本的下载链接 下载之后 放到合适的文件目录中 然后打开anaconda自带的Anaconda Pr
  • java使用switch语句完成输入1~12之间的整数,显示该月份的英语单词及这个月属第几季度。

    1 程序代码如下 package java实训 import java util Scanner public class SJ4 public static void main String args Scanner input new
  • AI Cloud将百花齐放,青云科技已先走了一步

    三年前 国家超级计算济南中心 济南超算 悄悄干了一件大事 投资数十亿元致力于打造一个融HPC超算 传统云计算 以CPU为主 和智算 以GPU为主 为一体的多元算力中心 这就需要一个统一的并且可以对外开放的运维和运营平台 那时还在打磨阶段的青
  • python注释快捷键 引号注释快捷键 注释字体样式调整

    python注释快捷键分为两种 单行注释 单行注释快捷键是CTRL list red green blue yellow white black print list 0 print list 1 print list 2 list red
  • VS E2996 错误过多,导致IntelliSense引擎无法正常工作。其中一些错误可能在编辑器中不可见。代码没有提示

    一 错误的问题描述 二 这个问题导致的后果 后面程序中用到的很多都会显示找不到定义 三 说实话这个问题真的很坑 由于我更换了我程序的工作电脑 我在VS中属性管理器中重新配置了头文件和对应的库目录 但是这里我犯了一个小错误 就是我更换的时候
  • QT开发技巧之QTableWidget设置表头颜色字体

    1 默认的表头和内容背景字体一样不好区别 可以通过qss设置修改表头样式 2 修改后效果如下 qss代码 表格头背景色 QHeaderView section background rgb 128 255 255 font family 宋
  • vue引入阿里图标 Module parse failed: Unexpected character '�' (1:0)

    操作根据文章 https blog csdn net qq 32113629 article details 79740949 在自己跟着试了一下后报错 Module parse failed Unexpected character 1
  • c++享元模式

    享元模式 1 享元模式简介 享元模式在 设计模式 可复用面向对象软件的基础 一书中是这样说的 运用共享技术有效地支持大量细粒度的对象 本质就是对大量细粒度的对象进行共享 不是每个对象都要通过new的方式去创建 而是通过区分对象的内部状态和外
  • 波形图、频谱图和语谱图

    波形图 反映各质点在同一时刻不同位移的曲线 叫做波的图像 也叫做波形图 波形图用于显示测量值为均匀采集的一条或多条曲线 波形图仅绘制单值函数 即在y f x 中 各点沿x轴均匀分布 例如一个随时间变化的波形 波形图可显示包含任意个数据点的曲
  • 消息通知之系统层事件发布相关流程

    前言 Openharmony 3 1Release中存在消息通知的处理 消息通知包括系统层事件发布 消息订阅 消息投递与处理 为了开发者能够熟悉消息的处理流程 本篇文章主要介绍系统层事件发布的相关流程 整体流程 代码流程 发布消息 even