[经验分享] OpenHarmony 资源调度之内存管理源码分析

深开鸿_张守忠 显示全部楼层 发表于 2023-10-31 10:03:55
作者:张守忠
1 内存管理简介
内存管理部件位于全局资源调度管控子系统中,基于应用的生命周期状态,更新进程回收优先级列表,通过内存回收、查杀等手段管理系统内存,保障内存供给。
1.1 fakename.png 内存管理框架
内存管理部件主要基于事件触发回收优先级更新,并基于回收优先级管理内存回收和查杀,其框架如下所示(下图虚线右侧为本部件),主要分为如下几个模块:
fakename.png
图 1 框架图1、事件管理模块:统筹管理本部件所要对外响应的事件。主要功能为调用其他子系统提供的接口注册事件监听,并将事件通知到回收优先级管理模块、回收策略模块和查杀策略模块。
2、回收优先级管理模块:基于事件管理模块的应用和用户的事件通知,给出进程的回收和查杀的先后顺序列表,并向回收策略和查杀策略提供查询此列表的接口。
3、回收策略模块:根据回收优先级列表,调整回收内存水线、文件页/匿名页回收比例、压缩/换出比例等回收参数,以及协调不同回收机制协同工作,保障内存中低负载下的供给性能。
4、查杀策略模块:作为回收的逻辑末端,根据回收优先级列表,保障内存重负载下的内存供给。
5、Kernel接口管控模块:负责将回收参数、查杀等管控命令下发到Kernel。
6、内存特性配置:读取回收策略模块、查杀策略模块等需要的配置文件。
1.2 ESWAP简介
ESWAP(Enhanced SWAP)是 OpenHarmony 针对传统linux内存优化问题提供的一套完善的内存解决方案,结合内存压缩和内存交换技术,定制了一套合理高效的调度管理策略,使压缩和交换两者的工作能够高效且平衡。ESWAP 基于关联性的数据聚合技术及上层指导策略,将内存划分为不同的分组进行管理,通过回收优先级来区分不同分组下内存的活跃程度,优先压缩、换出较不活跃的内存数据,以提升数据交换性能,减少冲击。ESWAP 解决方案在全局资源调度子系统中增加了一个系统资源调度模块,通过向账户子系统订阅本地账户的变化来感知当前的账户状态和内存状态,然后根据账户状态给各个账户设置不同的回收优先级、设置目标可用内存量、设置压缩和换出的比例等参数,并将这些参数下发给 ZSWAPD。ZSWAPD 会依据回收优先级判断回收的先后顺序;依据目标可用内存量和当前可用内存量的差值决定回收的量;依据压缩和换出的比例来决定压缩和换出的量,从而实现在达成内存扩展效果前提下的性能和功耗平衡。 ESWAP方案涉及的关键技术:
  • 定制的ZRAM和交换分区,ESWAP 结合内存压缩和内存交换技术,提供了自定义新增存储分区作为内存交换分区的能力,并在内核中创建了一个常驻进程 ZSWAPD,用于将 ZRAM 压缩后的匿名页加密换出到 ESWAP 存储分区中,从而能完全地空出一块可用内存,以此来达到维持 Memavailable 水线的目标。同时,ESWAP 模块还可以记录每个匿名页的冷热特征信息,并将这些数据通过关联性、冷热顺序进行相应的存放,使 ESWAP 交换区中连续存放的匿名页具有时间和空间局部性。因此在匿名页换入时,可以将交换区中的相邻匿名页一并读入 ZRAM,以此来保证数据的存取速度,提升 IO 性能。
  • 动态的内存回收机制,提供了一种额外的内存回收机制 ZSWAPD,并创建了“buffer”来作为衡量当前系统内存能力的指标。buffer 指的是当前系统能提供的最大可用内存。ZSWAPD 会根据 buffer 量以及上文所述的各种策略,来对匿名页进行压缩换出以回收。
  • 灵活的内存回收策略,基于 Memcg 分组进行了回收策略的增强,使用回收优先级来指导 ZSWAPD 回收的先后顺序。上层可以根据需要,通过灵活地配置交换策略,控制RAM、ZRAM、ESWAP 三个模块中存储的比例,避免频繁换入换出带来的负面影响。

1.3 PSI简介
PSI (Pressure Stall Information)  是 Facebook 在 2018 年开源的一套解决重要计算集群管理问题的 Linux 内核组件和相关工具中重要的资源度量工具,它提供了一种实时检测系统资源竞争程度的方法,以竞争等待时间的方式呈现,简单而准确地供用户以及资源调度者进行决策。PSI 软件结构图如下所示:
fakename.png 图 2 PSI软件结构图对上,PSI 模块通过文件系统节点向用户空间开放两种形态的接口。一种是系统级别的接口,即输出整个系统级别的资源压力信息。另外一种是结合 control group,进行更精细化的分组。对下,PSI 模块通过在内存管理模块以及调度器模块中插桩,我们可以跟踪每一个任务由于 memory、io 以及 CPU 资源而进入等待状态的信息。例如系统中处于 iowait 状态的 task 数目、由于等待 memory 资源而处于阻塞状态的任务数目。基于 task 维度的信息,PSI 模块会将其汇聚成 PSI group 上的 per cpu 维度的时间信息。例如该cpu上部分任务由于等待 IO 操作而阻塞的时间长度(CPU 并没有浪费,还有其他任务在执行)。PSI group 还会设定一个固定的周期去计算该采样周期内核的当前 psi 值(基于该 group 的 per cpu 时间统计信息)。为了避免 PSI 值的抖动,实际上上层应用通过系统调用获取某个 PSI group 的压力值的时候会上报近期一段时间值的滑动平均值。
1.3.1 PSI用户接口定义
每类资源的压力信息都通过 proc 文件系统的独立文件来提供,路径为 /proc/pressure/ -- cpu, memory, and io.其中 CPU 压力信息格式如下:some avg10=2.98 avg60=2.81 avg300=1.41 total=268109926memory 和 io 格式如下:some avg10=0.30 avg60=0.12 avg300=0.02 total=4170757full avg10=0.12 avg60=0.05 avg300=0.01 total=1856503avg10、avg60、avg300 分别代表 10s、60s、300s 的时间周期内的阻塞时间百分比。total 是总累计时间,以毫秒为单位some 这一行,代表至少有一个任务在某个资源上阻塞的时间占比,full 这一行,代表所有的非idle任务同时被阻塞的时间占比,这期间 cpu 被完全浪费,会带来严重的性能问题。
2 关键实现2.1 内存管理服务初始化
内存管理服务运行在进程memmgrservice中,在进程拉起时调用内存管理服务初始化程序,其初始化工作主要包括:配置文件解析、回收优先级初始化、更新账户优先级、回收策略初始化和各类监听事件注册,时序图如下:
2.2 回收优先级更新
回收优先级的更新涉及多个事件的触发,Account状态变化、应用状态变化、屏幕状态变化、电源状态等通用事件。
2.3 PSI上报事件处理
fakename.png
图 3 初始化时序图
系统能力注册在文件res_sched_service_ability.cpp中调用宏"REGISTER_SYSTEM_ABILITY_BY_ID"注册系统能力ResSchedServiceAbility
namespace OHOS {
namespace ResourceSchedule {
REGISTER_SYSTEM_ABILITY_BY_ID(ResSchedServiceAbility, RES_SCHED_SYS_ABILITY_ID, true);
系统能力初始化系统能力初始化分为资源调度管理初始化、系统服务发布、cpu分组调度初始化、注册监听的SA四个子过程。
void ResSchedServiceAbility::OnStart()
{
    ResSchedMgr::GetInstance().Init();
    if (!service_) {
        try {
            service_ = new ResSchedService();
        } catch(const std::bad_alloc &e) {
            RESSCHED_LOGE("ResSchedServiceAbility:: new ResSchedService failed.");
        }
    }
    if (!Publish(service_)) {
        RESSCHED_LOGE("ResSchedServiceAbility:: Register service failed.");
    }
    CgroupSchedInit();
    AddSystemAbilityListener(APP_MGR_SERVICE_ID);
    AddSystemAbilityListener(WINDOW_MANAGER_SERVICE_ID);
    AddSystemAbilityListener(BACKGROUND_TASK_MANAGER_SERVICE_ID);
    RESSCHED_LOGI("ResSchedServiceAbility ::OnStart.");
}
资源调度管理初始化过程主要包括frame_aware和socperf两个的插件加载及函数指针获取,eventHandler对象创建。插件so库的路径配置在xml文件"res_sched_plugin_switch.xml"中。
void ResSchedMgr::Init()
{
    PluginMgr::GetInstance().Init();

    if (!mainHandler_) {
        mainHandler_ = std::make_shared<EventHandler>(EventRunner::Create(RSS_THREAD_NAME));
    }
}

void PluginMgr::Init()
{
   
    ...
    //读取res_sched_plugin_switch.xml
    if (!pluginSwitch_) {
        pluginSwitch_ = make_unique<luginSwitch>();
        
        ...
        
        bool loadRet = pluginSwitch_->LoadFromConfigFile(realPath);
        if (!loadRet) {
            RESSCHED_LOGW("luginMgr::Init load switch config file failed!");
        }
    }
    //读取res_sched_config.xml
    if (!configReader_) {
   
        ...
        
        std::string realPath(tmpPath);
        bool loadRet = configReader_->LoadFromCustConfigFile(realPath);
        if (!loadRet) {
            RESSCHED_LOGW("luginMgr::Init load config file failed!");
        }
    }

    StackProtect();
    LoadPlugin(); //用linux系统接口dlopen加载so插件
    if (!dispatcherHandler_) {
        dispatcherHandler_ = std::make_shared<EventHandler>(EventRunner::Create(RUNNER_NAME));
    }
    RESSCHED_LOGI("luginMgr::Init success!");
}
cpu分组调度初始化主要分为supervisor、cgroupHandler和cgroupAdjuster三个子模块的初始化。
void SchedController::Init()
{
    ChronoScope cs("Init SchedController.");
    // Init supervisor which contains cached data for ccgroup controller.
    InitSupervisor();
    // Init cgroup handler thread
    InitCgroupHandler();
    // Init cgroup adjuster thread
    InitCgroupAdjuster();
}
注册监听的SA调用SA框架提供的接口完成监听SA的注册, 目前监听了三个SA,分别是应用管理服务(id: APP_MGR_SERVICE_ID)、窗口管理服务(id: WINDOW_MANAGER_SERVICE_ID)和后台任务管理服务(id: BACKGROUND_TASK_MANAGER_SERVICE_ID).
bool SystemAbility::AddSystemAbilityListener(int32_t systemAbilityId)
{
    HILOGD(TAG, "SA:%{public}d, listenerSA:%{public}d", systemAbilityId, saId_);
    return LocalAbilityManager::GetInstance().AddSystemAbilityListener(systemAbilityId, saId_);
}

bool LocalAbilityManager::AddSystemAbilityListener(int32_t systemAbilityId, int32_t listenerSaId)
{
    ...
   
    auto samgrProxy = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
    if (samgrProxy == nullptr) {
        HILOGE(TAG, "failed to get samgrProxy");
        return false;
    }

    {
        ...
        
        auto& listenerSaIdList = listenerMap_[systemAbilityId];
        auto iter = std::find_if(listenerSaIdList.begin(), listenerSaIdList.end(), [listenerSaId](int32_t SaId) {
            return SaId == listenerSaId;
        });
        if (iter == listenerSaIdList.end()) {
            listenerSaIdList.emplace_back(listenerSaId);
        }
        ...
    }

    int32_t ret = samgrProxy->SubscribeSystemAbility(systemAbilityId, GetSystemAbilityStatusChange());
    if (ret) {
        HILOGE(TAG, "failed to subscribe sa:%{public}d, process name:%{public}s", systemAbilityId,
            Str16ToStr8(procName_).c_str());
        return false;
    }
    return true;
}2.3 绘帧信息收集流程
fakename.png
图 4 绘帧信息收集资源调度时序图
绘帧信息收集主要根据场景分为输入子系统手势变化等的感知调度,ace子系统的窗口变化等的感知调度,图形子系统的渲染、动画感知调度。图4描述的是BeginListFling、BeginFlushBuild、Render三个绘帧信息资源调度时序图,其他的流程类似,不一一列举。绘帧信息收集资源调度的最终是通过内核接口ioctrl写关联线程组"/dev/sched_rtg_ctrl", 包括线程加入、移除关联线程组,设置关联线程组的属性等等。
void RSRenderThread::Render()
{
    ROSEN_TRACE_BEGIN(BYTRACE_TAG_GRAPHIC_AGP, "RSRenderThread::Render");
    if (RsFrameReport::GetInstance().GetEnable()) {
        RsFrameReport::GetInstance().RenderStart();
    }
   
    ...
   
    rootNode->repare(visitor_);
    rootNode->rocess(visitor_);
    ROSEN_TRACE_END(BYTRACE_TAG_GRAPHIC_AGP);
}

void RsFrameReport::RenderStart()
{
    renderStartRunc_ = (RenderStartFunc)LoadSymbol("RenderStart");
    if (renderStartRunc_ != nullptr) {
        renderStartRunc_();
    }
   
    ...
   
}

extern "C" void RenderStart()
{
    FrameUiIntf::GetInstance().RenderStart();
}

void FrameUiIntf::RenderStart() const
{
    if (!inited) {
        return;
    }
    FrameMsgMgr::GetInstance().EventUpdate(FrameEvent::EVENT_RENDER_START);
}

void FrameMsgMgr::EventUpdate(FrameEvent event)
{
    switch (event) {
        case FrameEvent::EVENT_SET_PARAM:
            SetSchedParam();
            break;
        default:
            HandleFrameMsgKey(event);
            break;
    }
}

bool FrameMsgMgr::HandleFrameMsgKey(FrameEvent event)
{
    std::map<FrameEvent, PHandle>::iterator iter = m_frameMsgKeyToFunc.find(event);
   
    ...
   
    PHandle pFunction = iter->second;
    (this->*pFunction)();
    return true;
}

void FrameMsgMgr::FrameMapKeyToFunc()
{
    ...
   
    m_frameMsgKeyToFunc[FrameEvent::EVENT_RENDER_START] = &FrameMsgMgr::RenderStart;
    m_frameMsgKeyToFunc[FrameEvent::EVENT_SEND_COMMANDS_START] = &FrameMsgMgr::SendCommandsStart;
    m_frameMsgKeyToFunc[FrameEvent::EVENT_END_FRAME] = &FrameMsgMgr::HandleEndFrame;
}

void FrameMsgMgr::RenderStart()
{
    FrameSceneSched *scene = GetSceneHandler();
   
    ...
   
    scene->RenderStart();
}

void RmeCoreSched::RenderStart()
{
    RmeTraceBegin(("FrameS-SetMargin:" + to_string(m_rtg) + " margin:" + to_string(MARGIN_THREE)).c_str());
    SetMargin(m_rtg, MARGIN_THREE);
    RmeTraceEnd();
}

int SetMargin(int grpId, int stateParam)
{
    ...
   
    int fd = BasicOpenRtgNode();
    if (fd < 0) {
        return fd;
    }
    ret = ioctl(fd, CMD_ID_SET_MARGIN, &state_data);
   
    ...
   
}2.4 帧感知调度流程
  • 被监听的SA的相关属性或状态变化,调用订阅的对象接口进行响应。

void WindowStateObserver::OnFocused(const sptr<FocusChangeInfo>& focusChangeInfo)
{
    auto cgHander = SchedController::GetInstance().GetCgroupEventHandler();
    if (cgHander && focusChangeInfo) {
        auto windowId = focusChangeInfo->windowId_;
        auto token = reinterpret_cast<uint64_t>(focusChangeInfo->abilityToken_.GetRefPtr());
        auto windowType = focusChangeInfo->windowType_;
        auto displayId = focusChangeInfo->displayId_;
        auto pid = focusChangeInfo->pid_;
        auto uid = focusChangeInfo->uid_;

        cgHander->ostTask([cgHander, windowId, token, windowType, displayId, pid, uid] {
            cgHander->HandleFocusedWindow(windowId, token, windowType, displayId, pid, uid);
        });
    }
}
  • 该对象通过eventHandler机制在event runner线程中调整进程组, 通过进程间通讯IPC通知资源调度服务进程。cgroup处理窗口焦点的eventHandler回调函数

void CgroupEventHandler::HandleFocusedWindow(uint32_t windowId, uint64_t abilityToken,
    WindowType windowType, uint64_t displayId, int32_t pid, int32_t uid)
{
    ...
   
        supervisor_->focusedApp_ = app;
        SchedController::GetInstance().AdjustAllProcessGroup(*(app.get()), AdjustSource::ADJS_FOCUSED_WINDOW);
    }
    payload["bundleName"] = app->name_;
    ResSchedUtils::GetInstance().ReportDataInProcess(ResType::RES_TYPE_WINDOW_FOCUS, 0, payload);
}
调整进程组
void SchedController::AdjustAllProcessGroup(Application &app, AdjustSource source)
{
    ...
   
    cgAdjuster_->AdjustAllProcessGroup(app, source);
}

void CgroupAdjuster::AdjustProcessGroup(Application &app, ProcessRecord &pr, AdjustSource source)
{
    CGS_LOGI("%{public}s for %{public}d, source : %{public}d", __func__, pr.GetPid(), source);
    ComputeProcessGroup(app, pr, source);
    ApplyProcessGroup(app, pr);
}

void CgroupAdjuster::ComputeProcessGroup(Application &app, ProcessRecord &pr, AdjustSource source)
{
    SchedPolicy group = SchedPolicy::SP_DEFAULT;
   
    ...

        if (group == SchedPolicy::SP_BACKGROUND && pr.runningContinuousTask_) {
            group = SchedPolicy::SP_FOREGROUND; // move background key task to fg
        }

        pr.setSchedGroup_ = group;
    }
}

void CgroupAdjuster::ApplyProcessGroup(Application &app, ProcessRecord &pr)
{
    ChronoScope cs("ApplyProcessGroup");
    if (pr.curSchedGroup_ != pr.setSchedGroup_) {
        pid_t pid = pr.GetPid();
        int ret = CgroupSetting::SetThreadGroupSchedPolicy(pid, (int)pr.setSchedGroup_);
        if (ret != 0) {
            CGS_LOGE("%{public}s set %{public}d to group %{public}d failed, ret=%{public}d!",
                __func__, pid, pr.setSchedGroup_, ret);
            return;
        }
        
        ...
        
    }
}
通过进程间通讯IPC通知资源调度服务进程
void ResSchedClient::ReportDataInProcess(uint32_t resType, int64_t value, const Json::Value& payload)
{
    RESSCHED_LOGI("ResSchedClient::ReportDataInProcess receive resType = %{public}u, value = %{public}lld.",
        resType, value);
    ResSchedMgr::GetInstance().ReportData(resType, value, payload);
}

void ResSchedServiceProxy::ReportData(uint32_t resType, int64_t value, const Json::Value& payload)
{
    ...
   
    error = Remote()->SendRequest(IResSchedService::REPORT_DATA, data, reply, option);
    if (error != NO_ERROR) {
        RESSCHED_LOGE("Send request error: %{public}d", error);
        return;
    }
    RESSCHED_LOGD("ResSchedServiceProxy::ReportData success.");
}

int ResSchedServiceStub::OnRemoteRequest(uint32_t code, MessageParcel &data,
    MessageParcel &reply, MessageOption &option)
{
    auto uid = IPCSkeleton::GetCallingUid();
    RESSCHED_LOGD("ResSchedServiceStub::OnRemoteRequest, code = %{public}u, flags = %{public}d,"
        " uid = %{public}d", code, option.GetFlags(), uid);

    auto itFunc = funcMap_.find(code);
    if (itFunc != funcMap_.end()) {
        auto requestFunc = itFunc->second;
        if (requestFunc) {
            return requestFunc(data, reply);
        }
    }
    return IPCObjectStub::OnRemoteRequest(code, data, reply, option);
}
  • 资源调度服务进程收到信息后,根据资源调度类型分发任务给frame_aware和socperf两个插件分别进行处理。

int32_t ResSchedServiceStub::ReportDataInner(MessageParcel& data, [[maybe_unused]] MessageParcel& reply)
{
    ...

    ReportData(type, value, StringToJson(payload));
    return ERR_OK;
}

void ResSchedService::ReportData(uint32_t resType, int64_t value, const Json::Value& payload)
{
    RESSCHED_LOGI("ResSchedService::ReportData from ipc receive data resType = %{public}d, value = %{public}lld.",
        resType, value);
    ResSchedMgr::GetInstance().ReportData(resType, value, payload);
}

void ResSchedMgr::ReportData(uint32_t resType, int64_t value, const Json::Value& payload)
{
    ...
   
    mainHandler_->ostTask([resType, value, payload] {
        PluginMgr::GetInstance().DispatchResource(std::make_shared<ResData>(resType, value, payload));
    });
}

void PluginMgr:ispatchResource(const std::shared_ptr<ResData>& resData)
{
    ...
   
    auto iter = resTypeLibMap_.find(resData->resType);
    if (iter == resTypeLibMap_.end()) {
        RESSCHED_LOGW("luginMgr:ispatchResource resType no lib register!");
        return;
    }
   
    ...
   
        for (const auto& libPath : iter->second) {
            dispatcherHandler_->ostTask(
                [libPath, resData, this] { deliverResourceToPlugin(libPath, resData); });
        }
    }
}

void PluginMgr::deliverResourceToPlugin(const std::string& pluginLib, const std::shared_ptr<ResData>& resData)
{
    std::lock_guard<std::mutex> autoLock(pluginMutex_);
    auto itMap = pluginLibMap_.find(pluginLib);
    if (itMap == pluginLibMap_.end()) {
        RESSCHED_LOGE("PluginMgr::deliverResourceToPlugin no plugin %{public}s !", pluginLib.c_str());
        return;
    }
    OnDispatchResourceFunc fun = itMap->second.onDispatchResourceFunc_;
    if (!fun) {
        RESSCHED_LOGE("PluginMgr::deliverResourceToPlugin no DispatchResourceFun !");
        return;
    }

    auto beginTime = Clock::now();
    // if a exception happen, will goto else
    if (!sigsetjmp(env, 1)) {
        fun(resData);
    } else {
        return;
    }
   
    ...
}
  • frame_aware插件主要负责关联线程组的操作,ioctrl操作的文件是"/dev/sched_rtg_ctrl"

void FrameAwarePlugin:ispatchResource(const std::shared_ptr<ResData>& data)
{
    ...
   
    switch (data->resType) {
        case RES_TYPE_APP_STATE_CHANGE:
            {
                int uid = payload["uid"].asInt();
                RESSCHED_LOGD("FrameAwarePlugin::[DispatchResource]:app state! uid:%{public}d", uid);
            }
            break;
        case RES_TYPE_PROCESS_STATE_CHANGE:
            {
                ...
               
                RME::FrameMsgIntf::GetInstance().ReportProcessInfo(pid, tid, state);
                RESSCHED_LOGD("FrameAwarePlugin::[DispatchResource]:process info! resType: %{public}u.", data->resType);
            }
            break;
        case RES_TYPE_WINDOW_FOCUS:
            {
                pid = payload["pid"].asInt();
                RME::FrameMsgIntf::GetInstance().ReportWindowFocus(pid, data->value);
                RESSCHED_LOGD("FrameAwarePlugin::[DispatchResource]:window focus! resType: %{public}u.", data->resType);
            }
            break;
        default:
            RESSCHED_LOGI("FrameAwarePlugin::[DispatchResource]:unknow msg, resType: %{public}u.", data->resType);
            break;
    }
}

void FrameMsgIntf::ReportWindowFocus(const int pid, const int isFocus)
{
    ...
   
    threadHandler_->PostTask([pid, isFocus] {
        IntelliSenseServer::GetInstance().ReportWindowFocus(pid, isFocus);
    });
}

void IntelliSenseServer::ReportWindowFocus(const int pid, int isFocus)
{
    if (!m_switch) {
        return;
    }
    RME_FUNCTION_TRACE();
    int rtGrp = AppInfoMgr::GetInstance().GetAppRtgrp(pid);
    switch (isFocus) {
        case static_cast<int>(WindowState::FOCUS_YES): // isFocus: 0
            {
                rtGrp = RtgMsgMgr::GetInstance().OnForeground("", pid);
                AppInfoMgr::GetInstance().OnForegroundChanged(pid, "", rtGrp);
                RME_LOGI("[ReportWindowFocus]: Focus yes!rtGrp: %{public}d", rtGrp);
            }
            break;
        case static_cast<int>(WindowState::FOCUS_NO): // isFocus: 1
            {
                RtgMsgMgr::GetInstance().OnBackground("", pid, rtGrp);
                AppInfoMgr::GetInstance().OnBackgroundChanged(pid, "");
                RME_LOGI("[ReportWindowFocus]: Focus No!rtGrp: %{public}d", rtGrp);
            }
            break;
        default:
            RME_LOGI("[ReportWindowFocus]:unknown msg!");
            break;
    }
    AppInfoMgr::GetInstance().OnWindowFocus(pid, isFocus);
    RtgMsgMgr::GetInstance().FocusChanged(pid, isFocus);
}

int RtgMsgMgr::OnForeground(const std::string appName, const int pid)
{
    // for multiwindow
    RmeTraceBegin(("FrameC-createRtgGrp-pid"+ to_string(pid)).c_str());
    int rtGrp = CreateNewRtgGrp(PRIO_TYPE, RT_NUM);
    if (rtGrp <= 0) {
        RME_LOGE("[OnForeground]: createNewRtgGroup failed! rtGrp:%{public}d, pid: %{public}d", rtGrp, pid);
        return rtGrp;
    }
    RmeTraceEnd();
    RmeTraceBegin(("FrameC-addThread-pid:" + to_string(pid), +" rtgrp:" + to_string(rtGrp)).c_str());
    int ret = AddThreadToRtg(pid, rtGrp, PID_PRIO_TYPE); // add ui thread
    if (ret != 0) {
        RME_LOGE("[OnFore]:add thread fail! pid:%{public}d,rtg:%{public}d!ret:%{publid}d", pid, rtGrp, ret);
    }
    RmeTraceEnd();
    return rtGrp;
}

int AddThreadToRtg(int tid, int grpId, int prioType)
{
    ...
   
    ret = ioctl(fd, CMD_ID_SET_RTG, &grp_data);
    close(fd);
    return ret;
}
  • socperf主要负责cpu频率的修改,操作文件是"/dev/cpuctl"和"/dev/cpuset"

void SocPerfPlugin:ispatchResource(const std::shared_ptr<ResData>& data)
{
    RESSCHED_LOGI("SocPerfPlugin:ispatchResource resType=%{public}u, value=%{public}lld",
        data->resType, data->value);
    auto funcIter = functionMap.find(data->resType);
    if (funcIter != functionMap.end()) {
        auto function = funcIter->second;
        if (function) {
            function(data);
        }
    }
}

void SocPerfPlugin::HandleWindowFocus(const std::shared_ptr<ResData>& data)
{
    if (data->value == WINDOW_FOCUSED) {
        RESSCHED_LOGI("SocPerfPlugin: socperf->WINDOW_SWITCH");
        OHOS::SOCPERF::SocPerfClient::GetInstance().PerfRequest(PERF_REQUEST_CMD_ID_WINDOW_SWITCH_FIRST, "");
        OHOS::SOCPERF::SocPerfClient::GetInstance().PerfRequest(PERF_REQUEST_CMD_ID_WINDOW_SWITCH_SECOND, "");
    }
}

void SocPerfClient:erfRequest(int cmdId, const std::string& msg)
{
    if (!CheckClientValid()) {
        return;
    }
    std::string newMsg = AddPidAndTidInfo(msg);
    client->PerfRequest(cmdId, newMsg);
}

void SocPerfProxy:erfRequest(int cmdId, const std::string& msg)
{
    ...
   
    Remote()->SendRequest(TRANS_IPC_ID_PERF_REQUEST, data, reply, option);
}

int SocPerfStub::OnRemoteRequest(uint32_t code, MessageParcel &data,
    MessageParcel &reply, MessageOption &option)
{
    auto remoteDescriptor = data.ReadInterfaceToken();
    if (GetDescriptor() != remoteDescriptor) {
        return ERR_INVALID_STATE;
    }
    switch (code) {
        case TRANS_IPC_ID_PERF_REQUEST: {
            int cmdId = data.ReadInt32();
            std::string msg = data.ReadString();
            PerfRequest(cmdId, msg);
            return 0;
        }
        case TRANS_IPC_ID_PERF_REQUEST_EX: {
            int cmdId = data.ReadInt32();
            bool onOffTag = data.ReadBool();
            std::string msg = data.ReadString();
            PerfRequestEx(cmdId, onOffTag, msg);
            return 0;
        }
        
        ...
}

void SocPerf:erfRequest(int cmdId, const std::string& msg)
{
    ...
   
    if (perfActionInfo.find(cmdId) == perfActionInfo.end()
        || perfActionInfo[cmdId]->duration == 0) {
        SOC_PERF_LOGE("Invalid PerfRequest cmdId[%{public}d]", cmdId);
        return;
    }
    SOC_PERF_LOGI("PerfRequest cmdId[%{public}d]msg[%{public}s]", cmdId, msg.c_str());
    DoFreqAction(perfActionInfo[cmdId], EVENT_INVALID, ACTION_TYPE_PERF);
}

void SocPerf:oFreqAction(std::shared_ptr<Action> action, int onOff, int actionType)
{
    for (int i = 0; i < (int)action->variable.size(); i += RES_ID_AND_VALUE_PAIR) {
        auto resAction = std::make_shared<ResAction>(action->variable[i + 1], action->duration, actionType, onOff);
        auto event = AppExecFwk::InnerEvent::Get(INNER_EVENT_ID_DO_FREQ_ACTION, resAction, action->variable);
        handlers[action->variable / RES_ID_NUMS_PER_TYPE - 1]->SendEvent(event);
    }
}

void SocPerfHandler:rocessEvent(const AppExecFwk::InnerEvent:ointer &event)
{
    switch (event->GetInnerEventId()) {
        ...
        
        case INNER_EVENT_ID_DO_FREQ_ACTION: {
            int resId = event->GetParam();
            if (!IsValidResId(resId)) {
                return;
            }
            std::shared_ptr<ResAction> resAction = event->GetSharedObject<ResAction>();
            UpdateResActionList(resId, resAction, false);
            break;
        }
        ...
        
    }
}
总结
本文主要介绍了智能感知调度模块的主要类关系、初始化流程、绘帧信息调度流程和帧感知调度流程并贴出相关主要代码,为开发人员维护和扩展功能提供参考。
fakename.png

©著作权归作者所有,转载或内容合作请联系作者

您尚未登录,无法参与评论,登录后可以:
参与开源共建问题交流
认同或收藏高质量问答
获取积分成为开源共建先驱

精彩评论2

maxia

沙发 发表于 2023-12-12 10:07:39
这篇不是内存管理吗?为什么后面突然开始讲resource_schedule_service

深开鸿_张守忠

发表于 2023-12-13 15:47  IP属地: 江苏省

回复 maxia: 是资源调度里的内存管理

【1 条回复】

Copyright   ©2023  OpenHarmony开发者论坛  京ICP备2020036654号-3 |技术支持 Discuz!

返回顶部