5

OpenHarmony源码解析之获取显示状态功能-51CTO.COM

 1 year ago
source link: https://os.51cto.com/article/713267.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
140fd1c618ece7ec42c742f8d8bb7526252b4e.png

​想了解更多关于开源的内容,请访问:​

​51CTO 开源基础软件社区​

​https://ost.51cto.com​

本文以OpenHarmony 3.1 Release - powermgr_display_manager源码为基础进行分析。

显示能效管理组件是OpenHarmony电源管理子系统的一个组件,主要负责如下功能:

  1. 显示屏的亮/灭。
  2. 显示屏亮度调节。
  3. 获取显示状态。

本文主要分析获取显示状态功能,包括NAPI接口及功能实现的整个流程。

#夏日挑战赛#OpenHarmony源码解析之获取显示状态功能-开源基础软件社区

图1 电源管理子系统架构图

#夏日挑战赛#OpenHarmony源码解析之获取显示状态功能-开源基础软件社区

图2 显示能效管理组件架构图

2、显示能效管理组件代码目录

base/powermgr/display_manager
├── figures                   # 架构图
├── frameworks                  # FrameWork层
│   ├── napi                    # NAPI
│   └── native                  # Native层
├── interfaces                  # 接口层
│   ├── innerkits               # 内部 APIs
│   └── kits                    # 外部接口 APIs
├── sa_profile                  # SA 配置文件
├── service                     # 服务层
│   ├── native                  # Native 层
│   └── zidl                    # zidl 接口层
├── test                        # 测试用例
└── utils                       # 工具和通用层

3、获取显示状态整体流程

#夏日挑战赛#OpenHarmony源码解析之获取显示状态功能-开源基础软件社区

图3 获取显示状态时序图

流程描述:

  1. JavaScript应用调用getState获取显示状态。
  2. getState调用brightness.cpp注册的NAPI接口GetDisplayState,GetDisplayState会将获取显示屏亮度委托给DisplayPowerMgrClient对象的GetDisplayState方法。
  3. GetDisplayState首先获取显示服务代理端DisplayPowerMgrProxy对象,然后调用DisplayPowerMgrProxy的GetDisplayState方法。
  4. 显示服务代理端对象的GetDisplayState方法调用SendRequest向显示服务提供方DisplayPowerMgrService发送获取显示状态请求。
  5. DisplayPowerMgrService通过父类DisplayPowerMgrStub的OnRemoteRequest方法收到获取显示状态请求后,调用父类DisplayPowerMgrStub的GetDisplayStateStub方法。
  6. GetDisplayStateStub继续调用DisplayPowerMgrService的GetDisplayState方法。
  7. GetDisplayState根据设备id找到对应的ScreenController对象,然后调用ScreenController对象的GetState方法。
  8. ScreenController调用其自身的公共方法GetState方法,直接返回自身的私有成员变量state_,state_变量在构造ScreenController对象时默认设置为on状态,并且可通过ScreenController对象的公共方法UpdateState去改变。

(1)显示能效管理服务注册

  1. 调用System Ability的MakeAndRegisterAbility接口注册Display Power Manager Service实例。
//rk3568/base/powermgr/display_manager/service/native/src/display_system_ability.cpp
REGISTER_SYSTEM_ABILITY_BY_ID(DisplaySystemAbility, DISPLAY_MANAGER_SERVICE_ID, true);
//rk3568/foundation/distributedschedule/safwk/interfaces/innerkits/safwk/system_ability.h
#define REGISTER_SYSTEM_ABILITY_BY_ID(abilityClassName, systemAbilityId, runOnCreate) \
    const bool abilityClassName##_##RegisterResult = \
    SystemAbility::MakeAndRegisterAbility(new abilityClassName(systemAbilityId, runOnCreate));
  1. System Ability调用Display Power Manager Service的OnStart函数实现显示能效管理服务组件的启动。
//rk3568/base/powermgr/display_manager/service/native/src/display_system_ability.cpp

void DisplaySystemAbility::OnStart()
{
    DISPLAY_HILOGI(MODULE_SERVICE, "Start service");
    //将Display Power Manager Service服务发布到System Ability,此时DisplayPowerMgrService成为了显示能效管理服务提供端
    if (!Publish(DelayedSpSingleton<DisplayPowerMgrService>::GetInstance())) {
        DISPLAY_HILOGE(MODULE_SERVICE, "Failed to publish service");
    }
}

(2)显示屏亮度调节NAPI接口定义及实现

  1. NAPI接口声明。
//rk3568/base/powermgr/display_manager/interfaces/kits/js/@ohos.brightness.d.ts
import { AsyncCallback } from './basic';
declare namespace brightness {
  function getState(): number;
  ...
}
export default brightness;
  1. NAPI接口实现,NAPI接口GetDisplayState会进一步调用显示屏亮度调节客户端DisplayPowerMgrClient对象提供的GetDisplayState方法。
//rk3568/base/powermgr/display_manager/frameworks/napi/brightness.cpp
// 获取显示状态的NAPI接口初始化
static napi_value Init(napi_env env, napi_value exports)
{
    // 将JavaScript调用的getState NAPI接口实现声明为GetDisplayState函数
    napi_property_descriptor desc[] = {
        DECLARE_NAPI_FUNCTION("getState", GetDisplayState),
    };
    NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc));
    DISPLAY_HILOGD(MODULE_JS_NAPI, "return");
    return exports;
}
//获取显示状态接口NAPI实现
static napi_value GetDisplayState(napi_env env, napi_callback_info info)
{
    DISPLAY_HILOGD(MODULE_JS_NAPI, "enter");
    size_t argc = 0;//参数个数
    napi_value args[1] = { 0 };//参数定义
    napi_value jsthis;//JS对象的this参数
    void *data = nullptr;//回调数据指针
    /* 根据环境变量获取参数 */
    napi_status status = napi_get_cb_info(env, info, &argc, args, &jsthis, &data);
    NAPI_ASSERT(env, (status == napi_ok) && (argc >= 0), "Bad parameters");
    napi_value result;
     // 调用客户端DisplayPowerMgrClient对象提供的GetDisplayState方法
    DisplayState state = DisplayPowerMgrClient::GetInstance().GetDisplayState();
    //创建js接口的返回值
    napi_create_uint32(env, static_cast<uint32_t>(state), &result);
    DISPLAY_HILOGD(MODULE_JS_NAPI, "return");
    return result;
}

(3)获取显示状态客户端实现

  1. DisplayPowerMgrClient首先会调用GetProxy方法,GetProxy会通过GetSystemAbilityManager方法获取SystemAbilityManager实例,然后通过CheckSystemAbility方法检查对应的SA是否存在,并返回remoteObject对象,最后通过iface_cast构造proxy对象,此时创建了PowerMgrProxy实例。
  2. 然后DisplayPowerMgrClient会将显示状态获取委托给显示服务代理端DisplayPowerMgrProxy对象的GetDisplayState方法处理。
//rk3568/base/powermgr/display_manager/frameworks/native/display_power_mgr_client.cpp
// 调用方不提供id参数,id默认为0,表示本地显示设备
DisplayState DisplayPowerMgrClient::GetDisplayState(uint32_t id)
{
    // 获取显示服务的代理端,这里返回的是DisplayPowerMgrProxy对象(service/zidl/src/display_power_mgr_proxy.cpp)
    auto proxy = GetProxy();
    if (proxy == nullptr) {
        //如果没有获取到proxy,则显示状态返回unknown
        return DisplayState::DISPLAY_UNKNOWN;
    }
     // 调用DisplayPowerMgrProxy的GetDisplayState,通过ipc方式获取显示状态结果
    return proxy->GetDisplayState(id);
}
// 获取显示管理服务提供的代理对象
sptr<IDisplayPowerMgr> DisplayPowerMgrClient::GetProxy()
{
    std::lock_guard lock(mutex_);
    if (proxy_ != nullptr) {
        return proxy_;
    }
    //  获取本设备内注册的SA的proxy
    sptr<ISystemAbilityManager> sam = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
    if (sam == nullptr) {
        DISPLAY_HILOGE(MODULE_INNERKIT, "Failed to get system ability manager");
        return nullptr;
    }
    // 检查显示管理服务是否注册
    sptr<IRemoteObject> obj = sam->CheckSystemAbility(DISPLAY_MANAGER_SERVICE_ID);
    if (obj == nullptr) {
        DISPLAY_HILOGE(MODULE_INNERKIT, "Failed to get display manager service");
        return nullptr;
    }
    sptr<IRemoteObject::DeathRecipient> dr = new DisplayDeathRecipient(*this);
    if ((obj->IsProxyObject()) && (!obj->AddDeathRecipient(dr))) {
        DISPLAY_HILOGE(MODULE_INNERKIT, "Failed to add death recipient");
        return nullptr;
    }
    // 将obj转换成IDisplayPowerMgr具体类型:DisplayPowerMgrProxy
    proxy_ = iface_cast<IDisplayPowerMgr>(obj);
    deathRecipient_ = dr;
    DISPLAY_HILOGI(MODULE_INNERKIT, "Succeed to connect display manager service");
    // 返回DisplayPowerMgrProxy对象
    return proxy_;
}

(4)获取显示状态服务代理端实现

DisplayPowerMgrProxy对象会将获取显示状态请求以IPC方式发送给显示服务提供端DisplayPowerMgrService对象处理。

//rk3568/base/powermgr/display_manager/service/zidl/src/display_power_mgr_proxy.cpp
// 显示服务代理端显示状态获取功能实现
DisplayState DisplayPowerMgrProxy::GetDisplayState(uint32_t id)
{
    sptr<IRemoteObject> remote = Remote();
    RETURN_IF_WITH_RET(remote == nullptr, DisplayState::DISPLAY_UNKNOWN);
    uint32_t result = 0;
    MessageParcel data;
    MessageParcel reply;
    MessageOption option;
    if (!data.WriteInterfaceToken(DisplayPowerMgrProxy::GetDescriptor())) {
        DISPLAY_HILOGE(MODULE_INNERKIT, "DisplayPowerMgrClient::%{public}s write descriptor failed!", __func__);
        return DisplayState::DISPLAY_UNKNOWN;
    }
    WRITE_PARCEL_WITH_RET(data, Uint32, id, DisplayState::DISPLAY_UNKNOWN);
    // 将请求发送给显示服务的stub端,消息类型是GET_DISPLAY_STATE
    int ret = remote->SendRequest(static_cast<int>(IDisplayPowerMgr::GET_DISPLAY_STATE),
        data, reply, option);
    if (ret != ERR_OK) {
        DISPLAY_HILOGE(MODULE_INNERKIT, "DisplayPowerMgrProxy::%{public}s SendRequest is failed,%d", __func__, ret);
        return DisplayState::DISPLAY_UNKNOWN;
    }
    // 获取显示服务stub显示状态获取结果,如果无法获取结果,则返回unknown
    if (!reply.ReadUint32(result)) {
        DISPLAY_HILOGE(MODULE_INNERKIT, "Readback fail!");
        return DisplayState::DISPLAY_UNKNOWN;
    }
    // 返回显示服务stub端执行结果
    return static_cast<DisplayState>(result);
}

(5)获取显示状态服务提供端实现

DisplayPowerMgrStub会将获取显示状态转发给子类DisplayPowerMgrService的SetBrightness方法处理。

//rk3568/base/powermgr/display_manager/service/zidl/src/display_power_mgr_stub.cpp
// 处理显示管理代理端发送的请求
int32_t DisplayPowerMgrStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply,
    MessageOption &option)
{
    DISPLAY_HILOGD(MODULE_SERVICE, "DisplayPowerMgrStub::OnRemoteRequest, cmd = %d, flags= %d",
        code, option.GetFlags());
    std::u16string descripter = DisplayPowerMgrStub::GetDescriptor();
    std::u16string remoteDescripter = data.ReadInterfaceToken();
    if (descripter != remoteDescripter) {
        DISPLAY_HILOGE(MODULE_SERVICE, "DisplayPowerMgrStub::OnRemoteRequest failed, descriptor is not matched!");
        return E_GET_POWER_SERVICE_FAILED;
    }
    switch (code) {
        ...
        // 消息类型为GET_BRIGHTNESS的处理函数    
        case static_cast<int32_t>(IDisplayPowerMgr::GET_DISPLAY_STATE):
            ret = GetDisplayStateStub(data, reply);
            break;
        ...
        default:
            return IPCObjectStub::OnRemoteRequest(code, data, reply, option);
    }
}
// 显示亮度获取stub端处理函数
int32_t DisplayPowerMgrStub::GetDisplayStateStub(MessageParcel& data, MessageParcel& reply)
{
    uint32_t id = 0;
    READ_PARCEL_WITH_RET(data, Uint32, id, E_READ_PARCEL_ERROR);
    // 调用子类DisplayPowerMgrService的GetDisplayState方法
    DisplayState ret = GetDisplayState(id);
    // 将调用结果发送给显示管理代理端
    if (!reply.WriteUint32(static_cast<uint32_t>(ret))) {
        DISPLAY_HILOGE(MODULE_SERVICE, "Failed to write GetDisplayStateStub return value");
        return E_WRITE_PARCEL_ERROR;
    }
    return ERR_OK;
}

DisplayPowerMgrService会根据设备id找到对应的ScreenController对象,然后将显示状态获取转发给ScreenController对象的GetState方法处理。

//rk3568/base/powermgr/display_manager/service/native/src/display_power_mgr_service.cpp
// 显示管理服务端获取显示状态实现函数
DisplayState DisplayPowerMgrService::GetDisplayState(uint32_t id)
{
    DISPLAY_HILOGI(MODULE_SERVICE, "GetDisplayState %{public}d", id);
    //根据设备id找到对应的ScreenController对象,如果没找到则返回unknown
    auto iterater = controllerMap_.find(id);
    if (iterater == controllerMap_.end()) {
        return DisplayState::DISPLAY_UNKNOWN;
    }
    // 返回ScreenController的GetState调用结果
    return iterater->second->GetState();
}

(6)屏幕控制器实现

  1. ScreenController调用其自身的公共方法,直接返回自身的私有成员变量state_。
  2. ScreenController在构造时会加载系统所支持的四个状态(on,dim,off,suspend)到map中,此时state_默认构造为on状态。
  3. ScreenController私有成员变量state_可通过其公共方法UpdateState去改变。
//rk3568/base/powermgr/display_manager/service/native/src/screen_controller.cpp
class ScreenController :
    public AnimateCallback,
    public std::enable_shared_from_this<ScreenController> {
public:
    ...
    DisplayState GetState()
    {
        //直接返回自身的私有成员变量state_
        return state_;
    };
    //ScreenController私有成员变量state_可通过其公共方法UpdateState去改变
    bool UpdateState(DisplayState state, uint32_t reason);
    ...
private:
    ...
    DisplayState state_;
    std::map<DisplayState, uint32_t> stateValues_;
    ...
};
//ScreenController在构造时会加载系统所支持的四个状态(on,dim,off,suspend)到map中,此时state_默认构造为on状态
ScreenController::ScreenController(uint64_t devId, std::shared_ptr<ScreenAction> action)
    : devId_(devId), state_(DisplayState::DISPLAY_ON), action_(action)
{
    DISPLAY_HILOGI(MODULE_SERVICE, "ScreenController created: %{public}d", static_cast<uint32_t>(devId_));
    stateValues_.emplace(DisplayState::DISPLAY_ON, DISPLAY_FULL_BRIGHTNESS);
    stateValues_.emplace(DisplayState::DISPLAY_DIM, DISPLAY_DIM_BRIGHTNESS);
    stateValues_.emplace(DisplayState::DISPLAY_OFF, DISPLAY_OFF_BRIGHTNESS);
    stateValues_.emplace(DisplayState::DISPLAY_SUSPEND, DISPLAY_SUSPEND_BRIGHTNESS);
    animator_ = nullptr;
}

本文主要和大家分享了OpenHarmony电源管理子系统中获取显示状态功能的实现细节,对NAPI接口、显示服务请求端及显示服务提供端流程等,做了较为详细的代码说明,希望通过本文您能初步掌握电源管理子系统的关键功能和核心流程。

​想了解更多关于开源的内容,请访问:​

​51CTO 开源基础软件社区​

​https://ost.51cto.com​​。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK