OpenHarmony-5.PM 子系统(1)

  • 电源管理子系统

1.电源管理子系统概述

电源管理子系统是 OpenHarmony 的基本能力子系统,有电池服务组件、显示控制组件和电源管理服务组件,主要提供如下功能:

  • 重启服务:系统重启和下电。
  • 系统电源管理服务:系统电源状态管理和休眠运行锁管理。
  • 显示相关的能耗调节:包括根据环境光调节背光亮度,和根据接近光亮灭屏。
  • 省电模式 :在不损害主要功能和性能的前提下,提供一种低功耗操作模式 。
  • 电池服务:支持充放电、电池和充电状态的监测,包括状态的更新和上报,还包括关机充电。
  • 温控 :在设备温度到一定程度之后对应用、SoC、外设进行管控,限制温升 。
  • 耗电统计: 主要包括软件耗电和硬件耗电统计,以及单个应用的耗电统计 。
  • 轻设备电池服务。
  • 轻设备电源管理服务。

1.1.电源管理子系统架构

电源管理子系统架构图:

目录结构如下:

c 复制代码
/base/powermgr
├── battery_lite			# 轻设备电池服务
├── battery_manager			# 电池服务
├── battery_statistics		# 耗电统计服务
├── display_manager			# 显示能效管理服务
├── power_manager			# 系统电源管理服务
├── powermgr_lite			# 轻设备电源管理服务
└── thermal_manager			# 温控和热管理服务

电源管理提供了七个子部件,其中部分部件提供了对外接口或者公共事件通知,开发者可以根据场景使用:

  • Power Manager 提供的接口,可以进行申请和释放休眠运行锁 RunningLock、设置电源模式、重启设备、关机等操作,同时也可以通过公共事件来监听省电模式和关机状态的变化。
  • Battery Manager 提供了电池信息查询的接口,同时开发者也可以通过公共事件监听电池状态和充放电状态的变化。
  • Thermal Manager 提供的设备温升状态的查询接口,同时开发者也可以通过注册回调和公共事件来监听设备温升状态。
  • Battery Statistics 提供了软硬件耗电统计的功能,可以查询硬件耗电或者应用耗电情况。
  • Display Power Manager 提供了亮度设置接口。

1.2.电源管理模式

OH节能模式有两种状态:熄屏状态和休眠状态。电源管理子系统包括内核态以及用户态的相互协同工作。

  • 内核对休眠的支持与相关流程如下:

    • freeze: 冻结I/O设备,将它们置于低功耗状态,使处理器进入空闲状态,唤醒最快,耗电比其它standby, mem, disk方式高
    • standby:除了冻结I/O设备外,还会暂停系统,唤醒较快,耗电比其它 mem, disk方式高
    • mem: 将运行状态数据存到内存,并关闭外设,进入等待模式,唤醒较慢,耗电比disk方式高
    • disk: 将运行状态数据存到硬盘,然后关机,唤醒最慢
  • 用户态电源管理子系统电源模式:正常模式,省电模式,性能模式,超级省电。可通过配置文件对详细策略进行修改:

    • base/powermgr/power_manager/services/native/profile/power_mode_config.xml

如下图,电源管理服务与电源管理服务相互协同管理屏幕亮息屏及通过UHDF对设备电源的状态切换。

2.电源服务组件

电源管理服务组件是 OpenHarmony 的电源管理子系统中的重要组件之一,主要提供如下功能:

  • 重启系统。
  • 管理休眠运行锁。
  • 系统电源状态查询。

电源管理子系统之电源管理服务组件架构图:

代码目录:

c 复制代码
/base/powermgr/power_manager
├── figures                  	# 架构图
├── frameworks                  # Framework层
│   ├── napi                  	# NAPI层
│   └── native                  # Native层
├── interfaces                  # 接口层
│   └── inner_api               # 内部接口
├── sa_profile                  # SA 配置文件
├── services                    # 服务层
│   ├── native                  # Native 层
│   └── zidl                    # Zidl 接口层
├── test                        # 测试用例
│   ├── fuzztest                # Fuzz 测试
│   ├── unittest                # 单元测试
│   ├── systemtest              # 系统测试
│   └── utils                   # 测试工具
└── utils                       # 工具和通用层

2.1.电源管理策略

  • OpenHarmony标准系统的统一电源管理策略配置,见 power_mode_config.xml (/base/powermgr/power_manager/services/native/profile/)文件,不同的配置对应不同的功耗情况。
c 复制代码
 17 <!--
 18     Power Mode Definitions:        // 电源模式定义
 19     MODE_NORMAL = 600,             // 正常模式
 20     MODE_POWER_SAVE = 601,         // 省电模式
 21     MODE_PERFORMANCE = 602,        // 性能优先
 22     MODE_EXTREME_POWER_SAVE = 603,// 超级省电
 23 -->
 24 <!--
 25     Action Definitions:             // 行为定义
 26     DisplayOffTime = 101,           // 息屏时间控制
 27     SystemAutoSleepTime = 102,      // 系统自动睡眠时间控制
 28     AutoAdjustBrightness = 103,     // 亮度自动调整时间控制
 29     AutoWindowRotation = 107,       // 窗口自动旋转时间控制
 30     SystemBrightness = 115,         // 系统亮度调节
 31     VibratorsState = 120,           // 马达(震动)状态
 32 -->
 33 <switch_proxy version="1">
 34     <proxy id="600">
           <!-- value[单位:ms],-1表示不设置,如DisplayOffTime设为-1表示不息屏 -->
 35         <switch id="101" value="30000" recover_flag="0"/>
 36         <switch id="102" value="0" recover_flag="0"/>
 37         <switch id="103" value="-1" recover_flag="0"/>
 38         <switch id="107" value="1" recover_flag="0"/>
 39         <switch id="115" value="102" recover_flag="0"/>
 40         <switch id="120" value="1" recover_flag="0"/>
 41     </proxy>
 42     <proxy id="601">
 43         <switch id="101" value="10000" recover_flag="0"/>
 44         <switch id="102" value="5000" recover_flag="0"/>
 45         <switch id="103" value="-1" recover_flag="0"/>
 46         <switch id="107" value="-1" recover_flag="0"/>
 47         <switch id="115" value="50" recover_flag="0"/>
 48         <switch id="120" value="-1" recover_flag="0"/>
 49     </proxy>
 50     <proxy id="602">
 51         <switch id="101" value="-1" recover_flag="0"/>
 52         <switch id="102" value="-1" recover_flag="0"/>
 53         <switch id="103" value="-1" recover_flag="0"/>
 54         <switch id="107" value="1" recover_flag="0"/>
 55         <switch id="115" value="255" recover_flag="0"/>
 56         <switch id="120" value="1" recover_flag="0"/>
 57     </proxy>
 58     <proxy id="603">
 59         <switch id="101" value="5000" recover_flag="0"/>
 60         <switch id="102" value="1000" recover_flag="0"/>
 61         <switch id="103" value="-1" recover_flag="0"/>
 62         <switch id="107" value="-1" recover_flag="0"/>
 63         <switch id="115" value="25" recover_flag="0"/>
 64         <switch id="120" value="-1" recover_flag="0"/>
 65     </proxy>
 66 </switch_proxy>

备注:

修改电源管理策略参考:https://ost.51cto.com/posts/22630

  • 唤醒源配置,见power_wakeup.json(base/powermgr/power_manager/services/native/profile/)
    OpenHarmony支持多种唤醒源,如电源键、键盘、鼠标等,并提供了定制开启和关闭的方式。当设备进入休眠状态后,用户可以通过按电源键、按键盘、鼠标事件、轻触屏幕等,来点亮屏幕并唤醒设备。但不同的产品可能支持不同的外设,比如无手写笔、无皮套等。为此,OpenHarmony提供唤醒源的定制方式,产品可以根据具体的设计规格来定制此特性。
c 复制代码
 1 {
  2     "powerkey": {
  3         "enable": true   //是否开启唤醒监听
  4     },
  5     "keyborad": {
  6         "enable": true
  7     },
  8     "mouse": {
  9         "enable": true
 10     },
 11     "touchscreen": {
 12         "enable": true,
 13         "click": 2   //点击次数
 14     },
 15     "touchpad": {
 16         "enable": true
 17     },
 18     "pen": {
 19         "enable": true
 20     },
 21     "lid": {   //lid 皮套唤醒
 22         "enable": true
 23     },
 24     "switch": { //switch 盖子唤醒
 25         "enable": true
 26     }
 27 }

备注:

定制唤醒源参考:

https://www.seaxiang.com/blog/263c5f62883e453285ff757552c44a61

https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/subsystems/subsys-power-wakeup-source-customization.md

2.2.Power Manager Service 服务启动

源代码位置:

  • base/powermgr/power_manager/services/native/src/power_state_machine.cpp
  • base/powermgr/power_manager/services/native/src/power_mgr_service.cpp

2.2.1.Power Manager Service 注册

c 复制代码
base/powermgr/power_manager/services/native/src/power_mgr_service.cpp:
auto pms = DelayedSpSingleton<PowerMgrService>::GetInstance();
//调用SystemAbility接口注册PowerMgrService实例
const bool G_REGISTER_RESULT = SystemAbility::MakeAndRegisterAbility(pms.GetRefPtr());

//构建入参为serviceid、runoncreate
PowerMgrService::PowerMgrService() : SystemAbility(POWER_MANAGER_SERVICE_ID, true) {}

​  System Ability 管理模块调用 PowerMgrService 的启动函数实现电源管理服务组件的启动:

硬件上电后,电源管理服务被打包到 foundation 进程,将会进行 PowerMgrService 初始化。其中 powerStateMachine 也在 PowerMgrService 中进行初始化。详细启动流程看 System Ability 管理相关的资料。System Ability 管理模块调用 PowerMgrService 的启动函数 OnStart(),实现电源管理服务组件的启动。

2.2.2.Power Manager Service 启动

启动函数 OnStart() 最终分别通过调用 PowerStateMachine: Init()-> InitStateMap() 和 PowerStateMachine::InitState(),实现状态机的初始化和状态机的初态的设置。主要流程有:

  • 调用 Init()函数,实现 PowerStateMachine 状态机的初始化;

  • 调用 AddSystemAbilityListener(),监听依赖的服务,在 OnAddSystemAbility 中调用 RegisterBootCompletedCallback(),并根据具体的设备信息, 设置状态机的初始状态。

c 复制代码
void PowerMgrService::OnStart()
{
    POWER_HILOGD(COMP_SVC, "Power Management startup");
    if (ready_) {
        POWER_HILOGW(COMP_SVC, "OnStart is ready, nothing to do");
        return;
    }
    
    // Init()方法,进行PowerStateMachine初始化,并根据设备信息,设置初始状态。
    if (!Init()) {
        POWER_HILOGE(COMP_SVC, "Call init fail");
        return;
    }
    /* 监听依赖的服务:DEVICE_STANDBY_SERVICE_SYSTEM_ABILITY_ID/DISPLAY_MANAGER_SERVICE_ID
    */
    AddSystemAbilityListener(DEVICE_STANDBY_SERVICE_SYSTEM_ABILITY_ID);
    AddSystemAbilityListener(DISPLAY_MANAGER_SERVICE_ID);
    
    // 注册HdiStatusListener
    SystemSuspendController::GetInstance().RegisterHdiStatusListener();
    if (!Publish(DelayedSpSingleton<PowerMgrService>::GetInstance())) {
        POWER_HILOGE(COMP_SVC, "Register to system ability manager failed");
        return;
    }
    ready_ = true;
    POWER_HILOGI(COMP_SVC, "Add system ability success");
}
  • PowerMgrService::Init()
    调用PowerMgrService::PowerStateMachineInit(),对 PowerStateMachine 的初始化。
c 复制代码
 88 bool PowerMgrService::Init()
 89 {
 90     POWER_HILOGI(COMP_SVC, "Init start");
 91     if (!runningLockMgr_) {
 92         runningLockMgr_ = std::make_shared<RunningLockMgr>(pms);
 93     }
 94     if (!runningLockMgr_->Init()) {
 95         POWER_HILOGE(COMP_SVC, "Running lock init fail");
 96         return false;
 97     }
 98     if (!shutdownController_) {
 99         shutdownController_ = std::make_shared<ShutdownController>();
100     }
         // PowerStateMachine初始化  见下面
101     if (!PowerStateMachineInit()) {
102         POWER_HILOGE(COMP_SVC, "Power state machine init fail");
103     }
104
105     RegisterBootCompletedCallback();
106     POWER_HILOGI(COMP_SVC, "Init success");
107     return true;
108 }

137 bool PowerMgrService::PowerStateMachineInit()
138 {
139     if (powerStateMachine_ == nullptr) {
140         powerStateMachine_ = std::make_shared<PowerStateMachine>(pms);
            // 调用powerStateMachine::Init()进行初始化状态机的所有状态及行为进行初始化
141         if (!(powerStateMachine_->Init())) {
142             POWER_HILOGE(COMP_SVC, "Power state machine start fail!");
143             return false;
144         }
145     }
146     if (powerMgrNotify_ == nullptr) {
147         powerMgrNotify_ = std::make_shared<PowerMgrNotify>();
148         powerMgrNotify_->RegisterPublishEvents();
149     }
150     return true;
151 }
  • PowerStateMachine::Init():
    通过 PowerStateMachine::InitStateMap(),实现对状态机的初始化。
c 复制代码
 base/powermgr/power_manager/services/native/src/power_state_machine.cpp:
  71 bool PowerStateMachine::Init()
  72 {
  73     POWER_HILOGD(FEATURE_POWER_STATE, "Start init");
  74
  75     stateAction_ = PowerMgrFactory::GetDeviceStateAction();
         //初始化状态机的多种状态:awake/inactive/sleep... 
  76     InitStateMap();
  77
  78     if (powerStateCBDeathRecipient_ == nullptr) {
  79         powerStateCBDeathRecipient_ = new PowerStateCallbackDeathRecipient();
  80     }
  81     POWER_HILOGD(FEATURE_POWER_STATE, "Init success");
  82     return true;
  83 }
  
    // 初始化状态机
	void PowerStateMachine::InitStateMap()
	{
	    EmplaceAwake();    // Awake  
	    EmplaceFreeze();   // Freeze:TODO
	    EmplaceInactive(); // Inactive
	    EmplaceStandBy();  // StandBy:TODO
	    EmplaceDoze();     // Doze:TODO
	    EmplaceSleep();    // Sleep     
	    EmplaceHibernate();// Hibernate:TODO
	    EmplaceShutdown(); // Shutdown:TODO
	}
  • EmplaceAwake()
    调用公共函数 DeviceStateAction::SetDisplayState(...),设置 DisplayState 为 DISPLAY_ON 成功后,调用 ResetInactiveTimer(),开启 Inactive 倒计时。
c 复制代码
base/powermgr/power_manager/services/native/src/power_state_machine.cpp:
void PowerStateMachine::EmplaceAwake()
{
    controllerMap_.emplace(PowerState::AWAKE,
        std::make_shared<StateController>(PowerState::AWAKE, shared_from_this(), [this](StateChangeReason reason) {
            POWER_HILOGI(FEATURE_POWER_STATE, "StateController_AWAKE lambda start");
            mDeviceState_.screenState.lastOnTime = GetTickCount();
            // 调用DeviceStateAction::SetDisplayState()
            uint32_t ret = this->stateAction_->SetDisplayState(DisplayState::DISPLAY_ON, reason);
            if (ret != ActionResult::SUCCESS) {
                POWER_HILOGE(FEATURE_POWER_STATE, "Failed to go to AWAKE, display error, ret: %{public}u", ret);
                return TransitResult::DISPLAY_ON_ERR;
            }
            // 进入awake状态会ResetInactiveTimer()
            ResetInactiveTimer();
            return TransitResult::SUCCESS;
        }));
}
  • EmplaceInactive():
    根据 enableDisplaySuspend_参数,传入 DISPLAY_OFF or DISPLAY_SUSPEND,调用公共函数 DeviceStateAction::SetDisplayState(...)。
c 复制代码
void PowerStateMachine::EmplaceInactive()
{
    controllerMap_.emplace(PowerState::INACTIVE,
        std::make_shared<StateController>(PowerState::INACTIVE, shared_from_this(), [this](StateChangeReason reason) {
            POWER_HILOGI(FEATURE_POWER_STATE, "StateController_INACTIVE lambda start");
            mDeviceState_.screenState.lastOffTime = GetTickCount();
            DisplayState state = DisplayState::DISPLAY_OFF;
            // 该参数由用户显示调用SetDisplaySuspend(...)进行设置,默认为false
            if (enableDisplaySuspend_) {
                POWER_HILOGI(FEATURE_POWER_STATE, "Display suspend enabled");
                state = DisplayState::DISPLAY_SUSPEND;
            }
            uint32_t ret = this->stateAction_->SetDisplayState(state, reason);
            if (ret != ActionResult::SUCCESS) {
                POWER_HILOGE(FEATURE_POWER_STATE, "Failed to go to INACTIVE, display error, ret: %{public}u", ret);
                return TransitResult::DISPLAY_OFF_ERR;
            }
            return TransitResult::SUCCESS;
        }));
}

如上两个函数都调用公共函数 DeviceStateAction::SetDisplayState(...):

c 复制代码
base\powermgr\power_manager\services\native\src\actions\default\display\device_state_action.cpp:
uint32_t DeviceStateAction::SetDisplayState(const DisplayState state, StateChangeReason reason)
{   
    // 若当前状态与待设置状态一致,则直接返回
    DisplayState currentState = GetDisplayState();
    if (state == currentState) {
        POWER_HILOGD(FEATURE_POWER_STATE, "Already in state: %{public}d", static_cast<uint32_t>(state));
        return ActionResult::SUCCESS;
    }
    // 注册DisplayState的回调函数
    if (!isRegister_) {
        isRegister_ = DisplayPowerMgrClient::GetInstance().RegisterCallback(dispCallback_);
        POWER_HILOGI(FEATURE_POWER_STATE, "Register Callback is %{public}d", isRegister_);
    }

    DisplayPowerMgr::DisplayState dispState = DisplayPowerMgr::DisplayState::DISPLAY_ON;
    PowerStateChangeReason dispReason = IsTimedOutWhileCoordinated(reason) ?
        PowerStateChangeReason::STATE_CHANGE_REASON_COLLABORATION : static_cast<PowerStateChangeReason>(reason);
    switch (state) {
        case DisplayState::DISPLAY_ON: {
            dispState = DisplayPowerMgr::DisplayState::DISPLAY_ON;
            // 若当前为DisplayState::DISPLAY_OFF,则调用DisplayManager::WakeUpBegin(...),通知相关模块,进行唤醒流程。
            if (currentState == DisplayState::DISPLAY_OFF) {
                std::string identity = IPCSkeleton::ResetCallingIdentity();
                DisplayManager::GetInstance().WakeUpBegin(dispReason);
                IPCSkeleton::SetCallingIdentity(identity);
            }
            break;
        }
        case DisplayState::DISPLAY_DIM:
            dispState = DisplayPowerMgr::DisplayState::DISPLAY_DIM;
            break;
        case DisplayState::DISPLAY_OFF: {
            dispState = DisplayPowerMgr::DisplayState::DISPLAY_OFF;
            // 若当前状态为DisplayState::DISPLAY_ON,则调用DisplayManager::SuspendBegin(...)
            if ((currentState == DisplayState::DISPLAY_ON || currentState == DisplayState::DISPLAY_DIM) &&
                reason != StateChangeReason::STATE_CHANGE_REASON_SENSOR) {
                std::string identity = IPCSkeleton::ResetCallingIdentity();
                 // 调用DM的SuspendBegin的接口,通知相关模块进行息屏、休眠前的处理,如锁屏等。
                DisplayManager::GetInstance().SuspendBegin(dispReason);
                IPCSkeleton::SetCallingIdentity(identity);
            }
            break;
        }
        case DisplayState::DISPLAY_SUSPEND:
            dispState = DisplayPowerMgr::DisplayState::DISPLAY_SUSPEND;
            break;
        default:
            break;
    }
    // 设置DisplayState 通知回调
    // 其中actionCallback_在WakeupController::Init()中调用stateAction->RegisterCallback(callback)来初始化
    dispCallback_->notify_ = actionCallback_;

    // 调用DisplayPowerMgrClient::SetDisplayState(dispState, reason),默认参数uint32_t id = 0
    bool ret = DisplayPowerMgrClient::GetInstance().SetDisplayState(dispState, reason);
    POWER_HILOGI(FEATURE_POWER_STATE, "Set display state finished, ret=%{public}d", ret);
    return ret ? ActionResult::SUCCESS : ActionResult::FAILED;
}

最后调用DisplayPowerMgrClient::SetDisplayState():

c 复制代码
base/powermgr/display_manager/state_manager/frameworks/native/display_power_mgr_client.cpp
// 这里需要了解SystemAbility IPC机制,xxClient-->xxProxy-->xxStub-->xxService
// 默认 uint32_t id = 0
87  bool DisplayPowerMgrClient::SetDisplayState(DisplayState state,
88      PowerMgr::StateChangeReason reason, uint32_t id)
89  {
90      auto proxy = GetProxy();
91      RETURN_IF_WITH_RET(proxy == nullptr, false);
92      return proxy->SetDisplayState(id, state, static_cast<uint32_t>(reason));
93  }

proxy->SetDisplayState 调用如下:
base/powermgr/display_manager/state_manager/service/native/src/display_power_mgr_service.cpp:
224  bool DisplayPowerMgrService::SetDisplayState(uint32_t id, DisplayState state, uint32_t reason)
225  {
226      if (!Permission::IsSystem()) {
227          return false;
228      }
		// 根据id(默认为0),找到对应screenController
229      DISPLAY_HILOGI(COMP_SVC, "[UL_POWER] SetDisplayState %{public}d, %{public}d, %{public}u", id, state, reason);
230      auto iterator = controllerMap_.find(id);
231      if (iterator == controllerMap_.end()) {
232          if (id != DEFALUT_DISPLAY_ID) {
233              return false;
234          }
235          id = GetMainDisplayId();
236          iterator = controllerMap_.find(id);
237          if (iterator == controllerMap_.end()) {
238              return false;
239          }
240      }
241  
242      BrightnessManager::Get().SetDisplayState(id, state, reason);
243      // 若是DISPLAY_OFF,则ScreenOffDelay
244      if (state == DisplayState::DISPLAY_OFF) {
245          if (!isDisplayDelayOff_) {
246              DISPLAY_HILOGI(COMP_SVC, "screen off immediately");
247              bool ret = iterator->second->UpdateState(state, reason);
248              if (!ret) {
249                  DISPLAY_HILOGI(COMP_SVC, "[UL_POWER]undo brightness SetDisplayState");
250                  BrightnessManager::Get().SetDisplayState(id, iterator->second->GetState(), reason);
251              }
252              return ret;
253          }
254          displayId_ = id;
255          displayState_ = state;
256          displayReason_ = reason;
257          FFRTTask task = [this]() { ScreenOffDelay(displayId_, displayState_, displayReason_); };
258          g_screenOffDelayTaskHandle = FFRTUtils::SubmitDelayTask(task, displayOffDelayMs_, queue_);
259          tempState_ = iterator->second->SetDelayOffState();
260          return true;
261      } else if (state == DisplayState::DISPLAY_ON) {
             // 若是DISPLAY_ON,且isDisplayDelayOff_为真,则移除g_screenOffDelayTaskHandle
262          if (isDisplayDelayOff_) {
263              DISPLAY_HILOGI(COMP_SVC, "need remove delay task");
264              FFRTUtils::CancelTask(g_screenOffDelayTaskHandle, queue_);
265              isDisplayDelayOff_ = false;
266              tempState_ = iterator->second->SetOnState();
267              return true;
268          }
269      }
         // 以上都不是,则 ScreenController::UpdateState
270      return iterator->second->UpdateState(state, reason);
271  }

2.2.4.PowerMgrService::RegisterBootCompletedCallback()

c 复制代码
void PowerMgrService::RegisterBootCompletedCallback()
{
    //初始化回调函数g_bootCompletedCallback
    g_bootCompletedCallback = []() {
        POWER_HILOGI(COMP_SVC, "BootCompletedCallback triggered");
        auto power = DelayedSpSingleton<PowerMgrService>::GetInstance();
        if (DelayedSpSingleton<PowerSaveMode>::GetInstance()) {
            auto& powerModeModule = power->GetPowerModeModule();
            powerModeModule.EnableMode(powerModeModule.GetModeItem(), true);
        }
        auto powerStateMachine = power->GetPowerStateMachine();
        // 注册息屏时间的Observer
        powerStateMachine->RegisterDisplayOffTimeObserver();
        // 调用PowerStateMachine::InitState(),设置初始状态:awake(screenOn) or inactive(screenOff)
        powerStateMachine->InitState();
        
        // power的相关初始化
#ifdef POWER_MANAGER_POWER_DIALOG
        power->GetShutdownDialog().LoadDialogConfig();
        power->GetShutdownDialog().KeyMonitorInit();
#endif
#ifndef CONFIG_FACTORY_MODE
        power->HallSensorSubscriberInit();
        POWER_HILOGI(COMP_SVC, "Subscribe Hall sensor");
#else
        POWER_HILOGI(COMP_SVC, "Disabled Hall sensor");
#endif
        power->SwitchSubscriberInit();
        power->InputMonitorInit();
        power->SuspendControllerInit();
        power->WakeupControllerInit();
#ifdef POWER_MANAGER_WAKEUP_ACTION
        power->WakeupActionControllerInit();
#endif
        power->VibratorInit();
        isBootCompleted_ = true;
    };
    WakeupRunningLock::Create();
    // 注册回调函数g_bootCompletedCallback至SysParam
    SysParam::RegisterBootCompletedCallback(g_bootCompletedCallback);
}
  • powerStateMachine->InitState(): 根据当前的设备的状态信息,设置状态机的初态,调用状态设置函数SetState,即PowerStateMachine::SetState.
c 复制代码
/base/powermgr/power_manager/services/native/src/power_state_machine.cpp
void PowerStateMachine::InitState()
{
    POWER_HILOGD(FEATURE_POWER_STATE, "Init power state");
    if (IsScreenOn()) {
        // 设置初始状态:awake
        SetState(PowerState::AWAKE, StateChangeReason::STATE_CHANGE_REASON_INIT, true);
    } else {
        // 设置初始状态:inactive
        SetState(PowerState::INACTIVE, StateChangeReason::STATE_CHANGE_REASON_INIT, true);
    }
}
  • 调用PowerStateMachine::SetState 进行TransitTo状态转换,即调用PowerStateMachine::StateController::TransitTo
c 复制代码
1723  bool PowerStateMachine::SetState(PowerState state, StateChangeReason reason, bool force)
1724  {
1725      POWER_HILOGD(FEATURE_POWER_STATE, "state=%{public}s, reason=%{public}s, force=%{public}d",
1726          PowerUtils::GetPowerStateString(state).c_str(), PowerUtils::GetReasonTypeString(reason).c_str(), force);
1727      std::lock_guard<std::mutex> lock(stateMutex_);

1732      ScreenChangeCheck timeoutCheck(ffrtTimer_, state, reason);
1733      SettingStateFlag flag(state, shared_from_this(), reason);
1738  
1739      HandleProximityScreenOffTimer(state, reason);
1744  
1745      std::shared_ptr<StateController> pController = GetStateController(state);
1751      if (IsTimeoutReason(reason) && forceTimingOut_.load()) {
1752          force = true;
1753      }
1754      UpdateSettingStateFlag(state, reason);
          // TransitTo状态转换:PowerStateMachine::StateController::TransitTo
1755      TransitResult ret = pController->TransitTo(reason, force);
1756      timeoutCheck.Finish(ret);
1759      RestoreSettingStateFlag();
1760      return (ret == TransitResult::SUCCESS || ret == TransitResult::ALREADY_IN_STATE);
1761  }

2015  TransitResult PowerStateMachine::StateController::TransitTo(StateChangeReason reason, bool ignoreLock)
2016  {
2017      POWER_HILOGD(FEATURE_POWER_STATE, "Start");
2018      std::shared_ptr<PowerStateMachine> owner = owner_.lock();
2019      if (owner == nullptr) {
2020          POWER_HILOGW(FEATURE_POWER_STATE, "owner is nullptr");
2021          return TransitResult::OTHER_ERR;
2022      }
2023      POWER_HILOGI(FEATURE_POWER_STATE,
2024          "[UL_POWER] Transit from %{public}s to %{public}s for %{public}s ignoreLock=%{public}d",
2025          PowerUtils::GetPowerStateString(owner->currentState_).c_str(),
2026          PowerUtils::GetPowerStateString(this->state_).c_str(),
2027          PowerUtils::GetReasonTypeString(reason).c_str(), ignoreLock);
2028      MatchState(owner->currentState_, owner->stateAction_->GetDisplayState());
          // 检查状态
2029      if (!CheckState()) {
2030          POWER_HILOGD(FEATURE_POWER_STATE, "Already in state: %{public}d", owner->currentState_);
2031          RecordFailure(owner->currentState_, reason, TransitResult::ALREADY_IN_STATE);
2032          return TransitResult::ALREADY_IN_STATE;
2033      }
2034  
2035      if (reason != StateChangeReason::STATE_CHANGE_REASON_INIT && !owner->CanTransitTo(state_, reason)) {
2036          POWER_HILOGD(FEATURE_POWER_STATE, "Block Transit from %{public}s to %{public}s",
2037              PowerUtils::GetPowerStateString(owner->currentState_).c_str(),
2038              PowerUtils::GetPowerStateString(state_).c_str());
2039          RecordFailure(owner->currentState_, reason, TransitResult::FORBID_TRANSIT);
2040          return TransitResult::FORBID_TRANSIT;
2041      }
2042       // ignoreLock为true时,则不进行runningLock检测
2043      if (!ignoreLock && !owner->CheckRunningLock(GetState())) {
2044          POWER_HILOGD(FEATURE_POWER_STATE, "Running lock block");
2045          RecordFailure(owner->currentState_, reason, TransitResult::LOCKING);
2046          return TransitResult::LOCKING;
2047      }
           // 进入相关状态的处理函数,详见PowerStateMachine::EmplaceXxx()
2048      TransitResult ret = action_(reason);
2049      if (ret == TransitResult::SUCCESS) {
2050          bool needNotify = NeedNotify(owner->currentState_);
2051          lastReason_ = reason;
2052          lastTime_ = GetTickCount();
2053          owner->currentState_ = GetState();
2054          if (needNotify) {
                  // 状态成功后,会调用NotifyPowerStateChanged(...),
2055              owner->NotifyPowerStateChanged(owner->currentState_, reason);
2056          }
2057      } else if (IsReallyFailed(reason)) {
2058          RecordFailure(owner->currentState_, reason, ret);
2059      }
2062      return ret;
2063  }

2.3.Awake流程分析

c 复制代码
PowerStateMachine::InitState()
->SetState(PowerState::AWAKE, StateChangeReason::STATE_CHANGE_REASON_INIT, true);  
	-> PowerStateMachine::SetState
		-> TransitResult ret = action_(reason);
			-> PowerStateMachine::EmplaceAwake

由 PowerStateMachine::InitState(),直接调用 SetState(PowerState::AWAKE, StateChangeReason::STATE_CHANGE_REASON_INIT, true)进入 Awake 状态;最后调用PowerStateMachine::EmplaceAwake()函数,该函数主要进行两个步骤:

  • 步骤 1:DeviceStateAction::SetDisplayState
    调用 DeviceStateAction::SetDisplayState(DisplayState::DISPLAY_ON, reason); 看公共函数的 DISPLAY_ON 分支;
    调用DisplayPowerMgrClient::SetDisplayState
c 复制代码
uint32_t DeviceStateAction::SetDisplayState(const DisplayState state, StateChangeReason reason)
{
    ...
    if (!isRegister_) {
        isRegister_ = DisplayPowerMgrClient::GetInstance().RegisterCallback(dispCallback_);
        POWER_HILOGI(FEATURE_POWER_STATE, "Register Callback is %{public}d", isRegister_);
    }

    DisplayPowerMgr::DisplayState dispState = DisplayPowerMgr::DisplayState::DISPLAY_ON;
    PowerStateChangeReason dispReason = IsLockScreen(reason) ?
        PowerStateChangeReason::POWER_BUTTON : PowerStateChangeReason::STATE_CHANGE_REASON_COLLABORATION;
    switch (state) {
        case DisplayState::DISPLAY_ON: {
            dispState = DisplayPowerMgr::DisplayState::DISPLAY_ON;            
            // 若当前为DisplayState::DISPLAY_OFF,则调用DisplayManager::WakeUpBegin(...),唤醒
            if (currentState == DisplayState::DISPLAY_OFF && reason != StateChangeReason::STATE_CHANGE_REASON_SENSOR) {
                std::string identity = IPCSkeleton::ResetCallingIdentity();
                DisplayManager::GetInstance().WakeUpBegin(dispReason);
                IPCSkeleton::SetCallingIdentity(identity);
            }
            break;
        }
        case DisplayState::DISPLAY_DIM:
            ...
            break;
        case DisplayState::DISPLAY_OFF: {
            ...
            break;
        }
        case DisplayState::DISPLAY_SUSPEND:
            ...
            break;
        default:
            break;
    }
    // DisplayState 通知回调
    dispCallback_->notify_ = actionCallback_;
    
    // 调用DisplayPowerMgrClient::SetDisplayState(dispState, reason)
    bool ret = DisplayPowerMgrClient::GetInstance().SetDisplayState(dispState, reason);
    POWER_HILOGI(FEATURE_POWER_STATE, "Set display state finished, ret=%{public}d", ret);
    return ret ? ActionResult::SUCCESS : ActionResult::FAILED;
}

bool DisplayPowerMgrClient::SetDisplayState(DisplayState state,
    PowerMgr::StateChangeReason reason, uint32_t id)
{
    auto proxy = GetProxy();
    RETURN_IF_WITH_RET(proxy == nullptr, false);
    return proxy->SetDisplayState(id, state, static_cast<uint32_t>(reason));
}
...
224  bool DisplayPowerMgrService::SetDisplayState(uint32_t id, DisplayState state, uint32_t reason)
225  {
		// 根据id(默认为0),找到对应screenController
229      DISPLAY_HILOGI(COMP_SVC, "[UL_POWER] SetDisplayState %{public}d, %{public}d, %{public}u", id, state, reason);
230      auto iterator = controllerMap_.find(id);
231      if (iterator == controllerMap_.end()) {
232          if (id != DEFALUT_DISPLAY_ID) {
233              return false;
234          }
235          id = GetMainDisplayId();
236          iterator = controllerMap_.find(id);
237          if (iterator == controllerMap_.end()) {
238              return false;
239          }
240      }
241  
242      BrightnessManager::Get().SetDisplayState(id, state, reason);
243      // 若是DISPLAY_OFF,则ScreenOffDelay
244      if (state == DisplayState::DISPLAY_OFF) {
245          ...
260          return true;
261      } else if (state == DisplayState::DISPLAY_ON) {
             // 若是DISPLAY_ON,且isDisplayDelayOff_为真,则移除g_screenOffDelayTaskHandle
262          if (isDisplayDelayOff_) {
263              DISPLAY_HILOGI(COMP_SVC, "need remove delay task");
264              FFRTUtils::CancelTask(g_screenOffDelayTaskHandle, queue_);
265              isDisplayDelayOff_ = false;
266              tempState_ = iterator->second->SetOnState();
267              return true;
268          }
269      }
         // 以上都不是,则 ScreenController::UpdateState
270      return iterator->second->UpdateState(state, reason);
271  }
  • 步骤 2:PowerStateMachine::ResetInactiveTimer
    若配置文件中 DisplayOffTime>=0, 则开启 Inactive 计时。
c 复制代码
void PowerStateMachine::ResetInactiveTimer()
{
    CancelDelayTimer(PowerStateMachine::CHECK_USER_ACTIVITY_TIMEOUT_MSG);
    CancelDelayTimer(PowerStateMachine::CHECK_USER_ACTIVITY_OFF_TIMEOUT_MSG);
    if (this->GetDisplayOffTime() < 0) {
        POWER_HILOGD(FEATURE_ACTIVITY, "Auto display off is disabled");
        return;
    }
    // 无Inactive的运行时锁,则在2/3的息屏时间后,发送消息CHECK_USER_ACTIVITY_TIMEOUT_MSG
    if (this->CheckRunningLock(PowerState::INACTIVE)) {
        const double DIMTIMERATE = 2.0/3;
        // SetDelayTimer():发送CHECK_USER_ACTIVITY_TIMEOUT_MSG,在2/3息屏时间后,进入DIM
        this->SetDelayTimer(
            this->GetDisplayOffTime() * DIMTIMERATE, PowerStateMachine::CHECK_USER_ACTIVITY_TIMEOUT_MSG);
    }
}

SetDelayTimer 中调用 SubmitDelayTask,在 delayTime 后,将执行 HandleActivityTimeout 任务。

c 复制代码
void PowerStateMachine::SetDelayTimer(int64_t delayTime, int32_t event)
{
    POWER_HILOGD(FEATURE_ACTIVITY, "Set delay timer, delayTime=%{public}s, event=%{public}d",
        std::to_string(delayTime).c_str(), event);
    switch (event) {
        case CHECK_USER_ACTIVITY_TIMEOUT_MSG: {
            std::lock_guard lock(ffrtMutex_);
            // 2/3的DisplayOffTime后,调用 HandleActivityTimeout
            FFRTTask task = std::bind(&PowerStateMachine::HandleActivityTimeout, this);
            userActivityTimeoutHandle_ = FFRTUtils::SubmitDelayTask(task, delayTime, queue_);
            break;
        }
        case CHECK_USER_ACTIVITY_OFF_TIMEOUT_MSG: {
            auto pms = DelayedSpSingleton<PowerMgrService>::GetInstance();
            auto suspendController = pms->GetSuspendController();
            if (suspendController == nullptr) {
                POWER_HILOGW(FEATURE_ACTIVITY, "suspendController is nullptr");
                return;
            }
            // 余下的1/3息屏时间后,将调用 suspendController::HandleEvent 
            suspendController->HandleEvent(delayTime);
            break;
        }
        default: {
            break;
        }
    }
}
  • 2/3的DisplayOffTime后,调用 HandleActivityTimeout,即PowerStateMachine::HandleActivityTimeout
c 复制代码
void PowerStateMachine::HandleActivityTimeout()
{
    POWER_HILOGD(FEATURE_ACTIVITY, "Enter, displayState = %{public}d", stateAction_->GetDisplayState());
    DisplayState dispState = stateAction_->GetDisplayState();
    const uint32_t THREE = 3;
    if (!this->CheckRunningLock(PowerState::INACTIVE)) {
        POWER_HILOGI(FEATURE_ACTIVITY, "RunningLock is blocking to transit to INACTIVE");
        return;
    }
    
    if (dispState == DisplayState::DISPLAY_ON) {
        // 如果dispState为DISPLAY_ON,则进入DIM状态,变暗
        stateAction_->SetDisplayState(DisplayState::DISPLAY_DIM, StateChangeReason::STATE_CHANGE_REASON_TIMEOUT);
        
        // 并同时调用了SetDelayTimer,在余下的1/3时间到达后,调用suspendController::HandleEvent 
        if (this->GetDisplayOffTime() < 0) {
            POWER_HILOGD(FEATURE_ACTIVITY, "Auto display off is disabled");
            return;
        } else {
            // 余下的1/3 息屏时间到后,发送CHECK_USER_ACTIVITY_OFF_TIMEOUT_MSG,调用suspendController::HandleEvent
            SetDelayTimer(GetDisplayOffTime() / THREE, PowerStateMachine::CHECK_USER_ACTIVITY_OFF_TIMEOUT_MSG);
        }
    } else {
        POWER_HILOGW(FEATURE_ACTIVITY, "Display is not on, ignore activity timeout, state = %{public}d", dispState);
        HandleActivityOffTimeout();
    }
}
  • 余下的 1/3 DisplayOffTime 到达后,调用 TimeoutSuspendMonitor::HandleEvent() 具体的流程如下,即调用基类的 notify 方法。 通知对应的 Listener,设置状态为 Inactive。Listener 由 SuspendController::Init()初始化。
c 复制代码
void SuspendController::HandleEvent(int64_t delayTime)
{
    FFRTTask task = [&]() {
        g_monitorMutex.Lock();
        auto timeoutSuspendMonitor = monitorMap_.find(SuspendDeviceType::SUSPEND_DEVICE_REASON_TIMEOUT);
        if (timeoutSuspendMonitor == monitorMap_.end()) {
            g_monitorMutex.Unlock();
            return;
        }
        g_monitorMutex.Unlock();
        auto monitor = timeoutSuspendMonitor->second;
        monitor->HandleEvent();
    };
    g_userActivityOffTimeoutHandle = FFRTUtils::SubmitDelayTask(task, delayTime, queue_);
}


void TimeoutSuspendMonitor::HandleEvent()
{
    POWER_HILOGI(FEATURE_INPUT, "TimeoutSuspendMonitor HandleEvent");
    //调用基类方法
    Notify();
}

// 基类的SuspendMonitor::Notify
void SuspendMonitor::Notify()
{
    if (listener_ == nullptr) {
        return;
    }
    //SuspendController::Init()会注册ControlListener,详见本段代码底部
    listener_(reason_, action_, delayMs_);
}

// ControlListener主要完成:1.设置 PowerState::INACTIVE 2.StartSleepTimer
void SuspendController::ControlListener(SuspendDeviceType reason, uint32_t action, uint32_t delay)
{
    auto pms = DelayedSpSingleton<PowerMgrService>::GetInstance();
    if (pms == nullptr) {
        return;
    }

    if (pms->CheckDialogAndShuttingDown()) {
        return;
    }

    if (!pms->IsScreenOn()) {
        SuspendWhenScreenOff(reason, action, delay);
        return;
    }

    pid_t pid = IPCSkeleton::GetCallingPid();
    auto uid = IPCSkeleton::GetCallingUid();
    POWER_HILOGI(FEATURE_SUSPEND,
        "Try to suspend device, pid=%{public}d, uid=%{public}d, reason=%{public}d, action=%{public}u, "
        "delay=%{public}u" PRId32 "",
        pid, uid, reason, action, delay);
    bool force = true;
    if (reason == SuspendDeviceType::SUSPEND_DEVICE_REASON_TIMEOUT) {
        force = false;
    }
    if (stateMachine_ == nullptr) {
        POWER_HILOGE(FEATURE_SUSPEND, "Can't get PowerStateMachine");
        return;
    }
    
    // 将设置 PowerState::INACTIVE,
    bool ret = stateMachine_->SetState(
        PowerState::INACTIVE, stateMachine_->GetReasionBySuspendType(static_cast<SuspendDeviceType>(reason)), force);
    
    // 若成功,则StartSleepTimer
    if (ret) {
        StartSleepTimer(reason, action, delay);
    }
}

// StartSleepTimer会根据不同的参数,来调用HandleAction
void SuspendController::StartSleepTimer(SuspendDeviceType reason, uint32_t action, uint32_t delay)
{
    if (static_cast<SuspendAction>(action) == SuspendAction::ACTION_AUTO_SUSPEND) {
        delay = delay + SLEEP_DELAY_MS;
    }
    const int64_t& tmpRef = delay;
    int64_t timeout = GetTickCount() + tmpRef;
    if ((timeout > sleepTime_) && (sleepTime_ != -1)) {
        POWER_HILOGI(FEATURE_SUSPEND, "already have a sleep event (%{public}" PRId64 " > %{public}" PRId64 ")", timeout,
            sleepTime_);
        return;
    }
    sleepTime_ = timeout;
    sleepReason_ = reason;
    sleepAction_ = action;
    sleepDuration_ = delay;
    sleepType_ = action;
    if (delay == 0) {
        // action
        HandleAction(reason, action);
    } else {
        FFRTTask task = [this] {
            HandleAction(GetLastReason(), GetLastAction());
        };
        g_sleepTimeoutHandle = FFRTUtils::SubmitDelayTask(task, delay, queue_);
    }
}

// 根据action类型,调用不同的SuspendAction
void SuspendController::HandleAction(SuspendDeviceType reason, uint32_t action)
{
    switch (static_cast<SuspendAction>(action)) {
        case SuspendAction::ACTION_AUTO_SUSPEND:
            HandleAutoSleep(reason);
            break;
        case SuspendAction::ACTION_FORCE_SUSPEND:
            HandleForceSleep(reason);
            break;
        case SuspendAction::ACTION_HIBERNATE:
            HandleHibernate(reason);
            break;
        case SuspendAction::ACTION_SHUTDOWN:
            HandleShutdown(reason);
            break;
        case SuspendAction::ACTION_NONE:
        default:
            break;
    }
    sleepTime_ = -1;
    sleepAction_ = static_cast<uint32_t>(SuspendAction::ACTION_NONE);
}

//SuspendController::Init()会注册ControlListener
void SuspendController::Init()
{
  ...
}
  • 根据action类型,调用不同的SuspendAction,比如:HandleAutoSleep(reason);
c 复制代码
base/powermgr/power_manager/services/native/src/suspend/suspend_controller.cpp
583  void SuspendController::HandleAutoSleep(SuspendDeviceType reason)
584  {
         // 设置状态为sleep
591      bool ret = stateMachine_->SetState(
592          PowerState::SLEEP, stateMachine_->GetReasonBySuspendType(reason));
593      if (ret) {
594          POWER_HILOGI(FEATURE_SUSPEND, "State changed, set sleep timer");
595          TriggerSyncSleepCallback(false);
596          SystemSuspendController::GetInstance().Suspend([]() {}, []() {}, false);
597      } else {
598          POWER_HILOGI(FEATURE_SUSPEND, "auto suspend: State change failed");
599      }
600  }
  • 驱动部分实现具体的 sleep 的操作,即 suspend:
c 复制代码
base/powermgr/power_manager/services/native/src/actions/default/system_suspend_controller.cpp
122  void SystemSuspendController::Suspend(
123      const std::function<void()>& onSuspend, const std::function<void()>& onWakeup, bool force)
124  {
125      POWER_HILOGI(COMP_SVC, "The hdf interface, force=%{public}u", static_cast<uint32_t>(force));
134      if (force) {
             // 实现在PowerInterfaceImpl
135          powerInterface_->ForceSuspend();
136      } else if (allowSleepTask_.load()) {
137          powerInterface_->StartSuspend();
138      }
139  }
  • PowerInterfaceImpl
    函数 DoSuspend实现在休眠的关键动作,写入mem到/sys/power/state,让设备真正进入休眠状态。
c 复制代码
drivers/peripheral/power/interfaces/hdi_service/src/PowerInterfaceImpl.h
int32_t PowerInterfaceImpl::ForceSuspend()
{
    HDF_LOGI("force suspend");
    {
        std::lock_guard<std::mutex> lock(g_forceMutex);
        g_forceSuspendStart = true;
        g_suspendRetry = false;
    }

    NotifyCallback(CMD_ON_SUSPEND);
    g_powerState = PowerHdfState::SLEEP;
    //直接调用DoSuspend(),进行mem写入
    DoSuspend();
    g_powerState = PowerHdfState::AWAKE;
    NotifyCallback(CMD_ON_WAKEUP);

    std::lock_guard<std::mutex> lock(g_forceMutex);
    if (g_forceSuspendStart) {
        StartSuspend();
    }
    return HDF_SUCCESS;
}

drivers/peripheral/power/interfaces/hdi_service/power_interface_impl.cpp
// 挂起操作:用户态写入mem 至 "/sys/power/state"
int32_t DoSuspend()
{
    std::lock_guard<std::mutex> lock(g_mutex);
    UniqueFd suspendStateFd(TEMP_FAILURE_RETRY(open(SUSPEND_STATE_PATH, O_RDWR | O_CLOEXEC)));
    if (suspendStateFd < 0) {
        return HDF_FAILURE;
    }
    bool ret = SaveStringToFd(suspendStateFd, SUSPEND_STATE);
    if (!ret) {
        HDF_LOGE("DoSuspend fail");
        return HDF_FAILURE;
    }
    return HDF_SUCCESS;
}

/commonlibrary/c_utils/base/src/file_ex.cpp
231  bool SaveStringToFd(int fd, const std::string& content)
232  {
237  
243      const ssize_t len = write(fd, content.c_str(), content.length());
248  
249      if (static_cast<unsigned long>(len) != content.length()) {
250          UTILS_LOGE("the length write to file is not equal to fileLength!len:%{public}zd, fileLen:%{public}zu",
251              len, content.length());
252          return false;
253      }
254  
255      return true;
256  }

refer to

相关推荐
程序猿会指北2 天前
【鸿蒙(HarmonyOS)性能优化指南】内存分析器Allocation Profiler
性能优化·移动开发·harmonyos·openharmony·arkui·组件化·鸿蒙开发
程序猿会指北2 天前
【鸿蒙(HarmonyOS)性能优化指南】启动分析工具Launch Profiler
c++·性能优化·harmonyos·openharmony·arkui·启动优化·鸿蒙开发
程序猿会指北5 天前
纯血鸿蒙APP实战开发——Text实现部分文本高亮和超链接样式
移动开发·harmonyos·arkts·openharmony·arkui·组件化·鸿蒙开发
程序猿会指北6 天前
纯血鸿蒙APP实战开发——应用新功能引导实现案例
移动开发·harmonyos·arkts·openharmony·arkui·组件化·鸿蒙开发
Hacker_Albert7 天前
OpenHarmony-3.HDF Display子系统(6)
openharmony
Hacker_Albert9 天前
OpenHarmony-4.HDI 框架
openharmony
神一样的老师11 天前
【鸿睿创智开发板试用】移植OpenCV 4到OpenHarmony 4.1
人工智能·opencv·计算机视觉·鸿蒙·openharmony
白羊@12 天前
多模块应用、发布使用第三方库(持续更新中)
服务器·前端·网络·harmonyos·鸿蒙·openharmony·第三方库
xianKOG16 天前
openHarHarmony学习
鸿蒙·openharmony