#创作者激励#消息通知之消息投递与处理 原创

软通动力HOS
发布于 2023-3-14 11:04
浏览
3收藏

【本文正在参加2023年第一期优质创作者激励计划】

前言

通过前面两篇的消息通知的文章,我们已经了解到系统层事件发布和消息订阅相关处理机制,从整体上掌握了消息发布与订阅的基本轮廓,在事件发布和消息订阅的处理流程中我们经常可以看到消息投递处理过程中使用handler_->PostTask进行消息投递,这篇文章我们在OpenHarmony 3.1Release代码基础上深入的分析PostTask动作,了解投递与处理流程,补全OpenHarmony消息通知的整体知识地图与流程地图。消息投递与处理包括三个部分消息事件的初始化、消息事件的投递与消息事件的处理。下面我们来详细介绍相关处理细节,经过这篇文章的学习,能够更加深入的理解消息通知这块的功能。

结构图

#创作者激励#消息通知之消息投递与处理-鸿蒙开发者社区
我们从整体上把握消息投递与处理框架,主要的类调用关系为CommonEventManagerService-> EventRunner-> EventRunnerImpl-> EventQueue-> EventHandler,所有的消息投递与处理在这几个类中传递,只要把握住这几个类,我们就能梳理清楚消息投递与处理的基本流程。下面我们就看一下消息详细处理细节。

代码流程

1、handler事件句柄的初始化与EventRunner线程的创建

CommonEventManagerService::Init函数中首先创建EventRunner得到runner_,然后通过runner_生成handler_

{
    ……
    runner_ = EventRunner::Create(true);
    if (!runner_) {
        EVENT_LOGE("Failed to init due to create runner error");
        return ERR_INVALID_OPERATION;
    }
    handler_ = std::make_shared<EventHandler>(runner_);
    if (!handler_) {
        EVENT_LOGE("Failed to init due to create handler error");
        return ERR_INVALID_OPERATION;
    }

    if (!Publish(this)) {
            EVENT_LOGE("Failed to publish CommonEventManagerService to SystemAbilityMgr");
            return ERR_INVALID_OPERATION;
       }

       EVENT_LOGI("init success");

       return ERR_OK;
}

EventRunner::Create实现细节,如果是新加线程直接调用create函数创建线程,否则将原来加入事件运行队列中。

{
    if (inNewThread) {
        return Create(std::string());
    }

    // Constructor of 'EventRunner' is private, could not use 'std::make_shared' to construct it.
    std::shared_ptr<EventRunner> sp(new EventRunner(false));
    auto innerRunner = std::make_shared<EventRunnerImpl>(sp);
    sp->innerRunner_ = innerRunner;
    sp->queue_ = innerRunner->GetEventQueue();

    return sp;
}

创建新线程过程中,首先初始化事件队列,然后将事件加入到事件运行队列中,最后调用运行线程

{
    // Constructor of 'EventRunner' is private, could not use 'std::make_shared' to construct it.
    std::shared_ptr<EventRunner> sp(new EventRunner(true));
    auto innerRunner = std::make_shared<EventRunnerImpl>(sp);
    sp->innerRunner_ = innerRunner;
    sp->queue_ = innerRunner->GetEventQueue();

    // Start new thread
    innerRunner->SetThreadName(threadName);
    auto thread =
        std::make_unique<std::thread>(EventRunnerImpl::ThreadMain, std::weak_ptr<EventRunnerImpl>(innerRunner));
    if (!innerRunner->Attach(thread)) {
        HILOGW("Create: Failed to attach thread, maybe process is exiting");
        innerRunner->Stop();
        thread->join();
    }

    return sp;
}

EventRunnerImpl的具体实现ThreadMain中首先获取锁,然后调用run函数循环处理消息通知事件

{
        std::shared_ptr<EventRunnerImpl> inner = wp.lock();
        if (inner) {
            HILOGD("ThreadMain: Start running for thread '%{public}s'", inner->threadName_.c_str());

            // Call system call to modify thread name.
            SystemCallSetThreadName(inner->threadName_);

            // Enter event loop.
            inner->Run();

            HILOGD("ThreadMain: Stopped running for thread '%{public}s'", inner->threadName_.c_str());
        } else {
            HILOGW("ThreadMain: EventRunner has been released just after its creation");
        }

        // Reclaim current thread.
        ThreadCollector::GetInstance().ReclaimCurrentThread();
}

2、消息事件的投递

消息订阅的使用过程中,首先std::bind事件绑定订阅函数,然后说使用PostTask函数进行消息投递。

    const CommonEventSubscribeInfo &subscribeInfo, const sptr<IRemoteObject> &commonEventListener)
{
    ……..

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

    std::function<void()> SubscribeCommonEventFunc = std::bind(&InnerCommonEventManager::SubscribeCommonEvent,
        innerCommonEventManager_,subscribeInfo,commonEventListener,recordTime,IPCSkeleton::GetCallingPid(),
        callingUid,callerToken,bundleName);
    return handler_->PostTask(SubscribeCommonEventFunc);
}

消息投递函数PostTask直接调用SendEvent函数进行事件发送。

        Priority priority = Priority::LOW)
 {
        return SendEvent(InnerEvent::Get(callback, name), delayTime, priority);
  }

SendEvent函数,将消息通知事件插入到事件运行队列中。

{
    ……..
    event->SetOwner(shared_from_this());
    // get traceId from event, if HiTrace::begin has been called, would get a valid trace id.
    auto traceId = event->GetOrCreateTraceId();
    // if traceId is valid, out put trace information
    if (AllowHiTraceOutPut(traceId, event->HasWaiter())) {
        HiTracePointerOutPut(traceId, event, "Send", HiTraceTracepointType::HITRACE_TP_CS);
    }

    eventRunner_->GetEventQueue()->Insert(event, priority);
    return true;
}

插入消息通知到事件队列的具体实现,根据传入参数的优先级调用InsertEventsLocked函数

{
    if (!event) {
        HILOGE("Insert: Could not insert an invalid event");
        return;
    }

    std::lock_guard<std::mutex> lock(queueLock_);
    bool needNotify = false;
    switch (priority) {
        case Priority::IMMEDIATE:
        case Priority::HIGH:
        case Priority::LOW: {
            needNotify = (event->GetHandleTime() < wakeUpTime_);
            InsertEventsLocked(subEventQueues_[static_cast<uint32_t>(priority)].queue, event);
            break;
        }
        case Priority::IDLE: {
            // Never wake up thread if insert an idle event.
            InsertEventsLocked(idleEvents_, event);
            break;
        }
        default:
            break;
    }

    if (needNotify) {
        ioWaiter_->NotifyOne();
    }
}

调用InsertEventsLocked函数将消息通知插入到事件队列中

{
    auto f = [](const InnerEvent::Pointer &first, const InnerEvent::Pointer &second) {
        if (!first || !second) {
            return false;
        }
        return first->GetHandleTime() < second->GetHandleTime();
    };
    auto it = std::upper_bound(events.begin(), events.end(), event, f);
    events.insert(it, std::move(event));
}

3、事件处理

循环处理消息通知,从事件队列中获取相应的事件进行处理,并调用DistributeEvent函数进行事件分发。

    {
        // Prepare to start event loop.
        queue_->Prepare();

        // Make sure instance of 'EventRunner' exists.
        if (owner_.expired()) {
            return;
        }

        threadId_ = std::this_thread::get_id();

        // Save old event runner.
        std::weak_ptr<EventRunner> oldRunner = currentEventRunner;
        // Set current event runner into thread local data.
        currentEventRunner = owner_;

        // Start event looper.
        //处理事件调用DistributeEvent
        for (auto event = queue_->GetEvent(); event; event = queue_->GetEvent()) {
            std::shared_ptr<EventHandler> handler = event->GetOwner();
            // Make sure owner of the event exists.
            if (handler) {
                std::shared_ptr<Logger> logging = logger_;
                std::stringstream address;
                address << handler.get();
                if (logging != nullptr) {
                    if (!event->HasTask()) {
                        logging->Log("Dispatching to handler event id = " + std::to_string(event->GetInnerEventId()));
                    } else {
                        logging->Log("Dispatching to handler event task name = " + event->GetTaskName());
                    }
                }
                handler->DistributeEvent(event);

                if (logging != nullptr) {
                    logging->Log("Finished to handler(0x" + address.str() + ")");
                }
            }
            // Release event manually, otherwise event will be released until next event coming.
            event.reset();
        }

        // Restore current event runner.
        currentEventRunner = oldRunner;
    }

DistributeEvent函数中进行消息通知事件的处理。

{
    ……
    if (event->HasTask()) {
        // Call task callback directly if contains a task.
        (event->GetTaskCallback())();
    } else {
        // Otherwise let developers to handle it.
        ProcessEvent(event);
    }

    DistributeTimeAction(event, nowStart);

    if (allowTraceOutPut) {
        HiTrace::Tracepoint(HiTraceTracepointType::HITRACE_TP_SS, *spanId, "Event Distribute over");
        HiTrace::ClearId();
        if (traceId.IsValid()) {
            HiTrace::SetId(traceId);
        }
    }

    // Restore current event handler.
    if (oldHandler.expired()) {
        currentEventHandler = nullptr;
    } else {
        currentEventHandler = oldHandler;
    }
}

以上就是整个消息的投递与处理流程,希望对大家有所帮助。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
消息通知.pdf 1.21M 71次下载
已于2023-3-14 11:04:02修改
4
收藏 3
回复
举报
1条回复
按时间正序
/
按时间倒序
红叶亦知秋
红叶亦知秋

附件中的大图展示的很清晰

已于2023-3-14 14:27:28修改
回复
2023-3-14 14:26:38
回复
    相关推荐