3

OpenHarmony源码解析之显示屏亮度获取功能

 1 year ago
source link: https://www.51cto.com/article/716284.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.
150bc9065fe42ee90f1841758183a137309614.png

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

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

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

显示能效管理组件是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应用调用getValue获取显示屏亮度。
  2. getValue调用brightness.cpp注册的NAPI接口GetValue,GetValue会将获取显示屏亮度委托给DisplayPowerMgrClient对象的GetBrightness方法。
  3. GetBrightness首先获取显示服务代理端DisplayPowerMgrProxy对象,然后调用DisplayPowerMgrProxy的GetBrightness方法。
  4. 显示服务代理端对象的GetBrightness方法调用SendRequest向显示服务提供方DisplayPowerMgrService发送获取屏幕亮度请求。
  5. DisplayPowerMgrService通过父类DisplayPowerMgrStub的OnRemoteRequest方法收到获取屏幕亮度请求后,调用父类DisplayPowerMgrStub的GetBrightnessStub方法。
  6. GetBrightnessStub继续调用DisplayPowerMgrService的GetBrightness方法。
  7. GetBrightness根据设备id找到对应的ScreenController对象,然后调用ScreenController对象的GetBrightness方法。
  8. ScreenController对象的GetBrightness方法调用ScreenAction对象的GetBrightness方法。
  9. ScreenAction对象的GetBrightness方法调用DisplayManager的GetScreenBrightness操控底层硬件实现显示屏的亮度获取。

(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 getValue(): number;
  ...
}
export default brightness;
  1. NAPI接口实现,NAPI接口GetValue会进一步调用显示屏亮度调节客户端DisplayPowerMgrClient对象提供的GetBrightness方法。
//rk3568/base/powermgr/display_manager/frameworks/napi/brightness.cpp
// 显示屏亮度获取的NAPI接口初始化
static napi_value Init(napi_env env, napi_value exports)
{
    // 将JavaScript调用的getValue NAPI接口实现声明为GetValue函数
    napi_property_descriptor desc[] = {
        DECLARE_NAPI_FUNCTION("getValue", GetValue),
    };
    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 GetValue(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, "Failed to get cb info");
    // 调用客户端DisplayPowerMgrClient对象提供的GetBrightness方法
    uint32_t brightness = DisplayPowerMgrClient::GetInstance().GetBrightness();
    napi_value result;
    //创建js接口的返回值
    napi_create_uint32(env, brightness, &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对象的GetBrightness方法处理。
//rk3568/base/powermgr/display_manager/frameworks/native/display_power_mgr_client.cpp
// 调用方不提供id参数,id默认为0,表示本地显示设备
uint32_t DisplayPowerMgrClient::GetBrightness(uint32_t id)
{
    // 获取显示服务的代理端,这里返回的是DisplayPowerMgrProxy对象(service/zidl/src/display_power_mgr_proxy.cpp)
    auto proxy = GetProxy();
    if (proxy == nullptr) {
        return 0;
    }
    // 调用DisplayPowerMgrProxy的GetBrightness,通过ipc方式获取亮度结果
    return proxy->GetBrightness(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
// 显示服务代理端亮度获取功能实现
uint32_t DisplayPowerMgrProxy::GetBrightness(uint32_t id)
{
    sptr<IRemoteObject> remote = Remote();
    RETURN_IF_WITH_RET(remote == nullptr, false);
    uint32_t result = 0;
    MessageParcel data;
    MessageParcel reply;
    MessageOption option;
    if (!data.WriteInterfaceToken(DisplayPowerMgrProxy::GetDescriptor())) {
        DISPLAY_HILOGE(MODULE_INNERKIT, "DisplayPowerMgrProxy::%{public}s write descriptor failed!", __func__);
        return result;
    }
    WRITE_PARCEL_WITH_RET(data, Uint32, id, false);
    // 将请求发送给显示服务的stub端,消息类型是GET_BRIGHTNESS
    int ret = remote->SendRequest(static_cast<int>(IDisplayPowerMgr::GET_BRIGHTNESS),
        data, reply, option);
    if (ret != ERR_OK) {
        DISPLAY_HILOGE(MODULE_INNERKIT, "DisplayPowerMgrProxy::%{public}s SendRequest is failed: %d", __func__, ret);
        return result;
    }
    // 获取显示服务stub亮度获取结果,如果无法获取结果,则返回false
    if (!reply.ReadUint32(result)) {
        DISPLAY_HILOGE(MODULE_INNERKIT, "Readback fail!");
        return result;
    }
     // 返回显示服务stub端执行结果
    return 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_BRIGHTNESS):
            ret = GetBrightnessStub(data, reply);
            break;
        ...
        default:
            return IPCObjectStub::OnRemoteRequest(code, data, reply, option);
    }
}
// 显示亮度获取stub端处理函数
int32_t DisplayPowerMgrStub::GetBrightnessStub(MessageParcel& data, MessageParcel& reply)
{
    uint32_t id = 0;
    READ_PARCEL_WITH_RET(data, Uint32, id, E_READ_PARCEL_ERROR);
     // 调用子类DisplayPowerMgrService的GetBrightness方法
    uint32_t ret = GetBrightness(id);
    // 将调用结果发送给显示管理代理端
    if (!reply.WriteUint32(ret)) {
        DISPLAY_HILOGE(MODULE_SERVICE, "Failed to write GetBrightness return value");
        return E_WRITE_PARCEL_ERROR;
    }
    return ERR_OK;
}

DisplayPowerMgrService会根据设备id找到对应的ScreenController对象,然后将亮度获取转发给ScreenController对象的GetBrightness方法处理。

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

(6)屏幕控制器实现

ScreenController将亮度调节转发给ScreenAction对象的GetBrightness方法处理。

////rk3568/base/powermgr/display_manager/service/native/src/screen_controller.cpp
uint32_t ScreenController::GetBrightness()
{
    std::lock_guard lock(mutex_);
    if (brightness_ == 0) {
        // 调用ScreenAction::SetBrightness
        brightness_ = action_->GetBrightness(devId_);
    }
    return brightness_;
}

(7)屏幕Action实现

ScreenAction最终调用底层驱动获取显示屏亮度。

//rk3568/base/powermgr/display_manager/service/native/src/screen_action.cpp
uint32_t ScreenAction::GetBrightness(uint64_t devId)
{
    DISPLAY_HILOGI(MODULE_SERVICE, "GetBrightness: %{public}d", static_cast<int>(devId));
    // 调用驱动亮度获取实现函数
    return Rosen::DisplayManager::GetInstance()
        .GetScreenBrightness(static_cast<uint64_t>(devId));
}

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

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

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

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK