OpenHarmony源码解析之显示屏亮度获取功能 原创 精华

深开鸿
发布于 2022-8-11 17:02
浏览
8收藏

作者:严明舟

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

1 简介

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

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

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

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

OpenHarmony源码解析之显示屏亮度获取功能-鸿蒙开发者社区

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

OpenHarmony源码解析之显示屏亮度获取功能-鸿蒙开发者社区

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 显示屏亮度获取整体流程

图3 显示屏亮度获取时序图

OpenHarmony源码解析之显示屏亮度获取功能-鸿蒙开发者社区

流程描述:

  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操控底层硬件实现显示屏的亮度获取。

3.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");
    }
}

3.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.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_;
}

3.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;
}

3.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();
}

3.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_;
}

3.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接口、显示服务请求端及显示服务提供端流程等,做了较为详细的代码说明,希望通过本文您能初步掌握电源管理子系统的关键功能和核心流程。关于OpenHarmony其它子系统的分析,请关注后续文章。

更多原创内容请关注:深开鸿技术团队

入门到精通、技巧到案例,系统化分享HarmonyOS开发技术,欢迎投稿和订阅,让我们一起携手前行共建鸿蒙生态。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
已于2022-8-11 17:05:00修改
6
收藏 8
回复
举报
6条回复
按时间正序
/
按时间倒序
红叶亦知秋
红叶亦知秋

看到新的组件我马上前排收藏,原来亮度也是在电源管理下。

回复
2022-8-11 17:40:34
笨笨的婧婧
笨笨的婧婧

厉害呀,这么详细的讲解。

1
回复
2022-8-12 13:52:28
物联风景
物联风景

不错不错

1
回复
2022-8-12 14:23:31
liurick
liurick

OpenHarmony每个版本老师都会做讲解吗?

1
回复
2022-8-12 15:14:30
青舟321
青舟321

文中的图是从文档中有吗?

1
回复
2022-8-12 17:40:21
一緑向北
一緑向北

膜拜啃源码的大佬,自己看太困难了

1
回复
2022-8-12 18:38:47
回复
    相关推荐