• [转]WM/WINCE代码研读系列之 Power Management(1)


    本文对Power Management这部分代码的研究是基于Wince5.0的(注:在最新的Wince 6.0上对电源管理的架构做了较大改变)。
    这部分的代码在\PUBLIC\COMMON\OAK\DRIVERS\PM下,在OS中以PM.dll的形式存在。


    一、PowerManagement Architecture

    在\PUBLIC\COMMON\OAK\DRIVERS\PM下的代码有两套电源管理机制:
    一种是Minimal的电源管理架构, 在\PUBLIC\COMMON\OAK\DRIVERS\PM\PMSTUBS\下,用SYSGEN_PMSTUBS环境变量去使能这个架构;在这种架 构下只支持消息接口类的电源管理API即PmRequestPowerNotifications和PmStopPowerNotifications, 且PmSetSystemPowerState里面只做了Suspended/Resuming的简单处理。
    另一种是Full的电源管理架构, 在\PUBLIC\COMMON\OAK\DRIVERS\PM\下的MDD和PDD目录,用SYSGEN_PM环境变量去使能这个架构;在这种架构下支 持所有类型的电源管理API。在Full的电源管理架构中,又分两个子类DEFAULT和PDA。在用SYSGEN_PM环境变量启用这个架构后默认使用 DEFAULT,用SYSGEN_PM_PDA可以使能PDA这个子类。
    在Windows Mobile 6(wince 5.0核心)中,无论是Windows Mobile 6 Professional/ Windows Mobile 6 Classic (在\PUBLIC\WPC\OAK\MISC\wpc.bat)还是Windows Mobile 6 Standard(在\PUBLIC\SMARTFON\OAK\MISC\smartfon.bat)都设置了SYSGEN_PM = 1,SYSGEN_PM_PDA = 1;
    下面我将详细讨论PDA子类。


    系统电源状态共有九种:
    On,UserIdle,BacklightOff,ScreenOff,Unattended,Resuming,Suspended,ColdReboot,Reboot.
    ColdReboot,Reboot这两个状态不能在电源管理的状态机中自由迁移,它们只能通过调用SetSystemPowerState来进入。

    此外,Windows Mobile 6 Professional和Windows Mobile 6 Classic (即PPC)在\PUBLIC\WPC\OAK\FILES\下的project.reg里面做了如下设置

    [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Power\Timeouts]

    "ACUserIdle"=dword:0                        ; in seconds

    "BattUserIdle"=dword:0                      ; in seconds

    "BattSuspendTimeout"=dword:3c       ; in seconds

    这样就把自动超时进入UserIdle状态的方式给屏蔽了,无法在PPC里面自动超时迁移到UserIdle这个电源状态。

    Windows Mobile 6 Standard(即SmartPhone)在\PUBLIC\SMARTFON\OAK\FILES\下的project.reg里面做了如下设置

    [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Power\Timeouts]

    "ACSuspendTimeout"=dword:0         ; in seconds

    "BattSuspendTimeout"=dword:0       ; in seconds

    这样就把自动超时进入Suspended状态的方式给屏蔽了,无法在SmartPhone里面自动超时迁移到Suspended这个电源状态。

    根据文档:Windows Mobile 6 Professional和Windows Mobile 6 Classic (即PPC) 不支持UserIdle这个状态,Windows Mobile 6 Standard(即SmartPhone)不支持Unattended,Resuming,Suspended三个状态。


    影响系统电源状态变迁的事件共有以下十一种:

    Wake source event:
    这是OEM自己定义的唤醒事件,它们都是特定选择的一些硬件中断 (例如USB线或是充电器的插入拔出中断,Baseband的中断,键盘中断,闹钟中断等)。在PPC中这些唤醒事件用来把系统从Suspended状态 变到Resuming状态。在SmartPhone中没有Suspended状态,相应的低功耗模式是进入OEMIdle()。在有些特定硬件平台中,为 了降低功耗往往在OEMIdle()里将CPU配置进低功耗模式或者Stop掉。例如PXA27X,PXA3XX的SmartPhone平台下,在 OEMIdle()里让CPU进Standby模式,把一些硬件中断配置为Wake source event以唤醒CPU并退出OEMIdle()。在PPC里进入Suspended状态或是关机都会调用OEMPowerOff(),但在 SmartPhone里OEMPowerOff()只在关机时被调用。

    On/off event:
    Power Button被按下。这个事件只在PPC里有效。
    在Resuming,Unattended,ScreenOff状态下,按下Power Button将系统迁移到On状态。在On,BacklightOff,UserIdle状态下,按下Power Button将系统迁移到Unattended状态。

    On event:
    Application Buttons被按下。这个事件也只在PPC里有效。
    在On,BacklightOff,UserIdle,Resuming,Unattended,ScreenOff状态下,按下Application Buttons都会将系统迁移到On状态。

    Enter unattended:
    调用PowerPolicyNotify(PPN_UNATTENDEDMODE,TRUE)让系统进入unattended模式。这时候m_dwUnattendedModeRef加一。
    Leave unattended:
    调用PowerPolicyNotify(PPN_UNATTENDEDMODE,FALSE)让系统离开unattended模式。这时候m_dwUnattendedModeRef加一。
    任 何状态要迁移到Suspended状态肯定会先迁移unattended状态。如果m_dwUnattendedModeRef为0则直接进入 Suspended状态。不为0时会将SystemIdleTimeout定时器复位,在SystemIdle Timeout后才会进入Suspended状态。

    下面接下来是四个Timeout事件:

    15-second timeout(即ResumingSuspendTimeout):
    15S超时其实是代码中的ResumingSuspendTimeout,这是专门用于Resuming状态的。
    当系统从Suspended唤醒到Resuming状态时,如果15s内没有人系统迁移出这状态,则系统电源状态就会变到Unattended状态。
    这个15s的时间是系统默认的(在PUBLIC\COMMON\OAK\DRIVERS\PM\PDD\PDA\下的pwstates.h定义的),但它也是可以被改变的。
    修改TEXT("HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Power\\Timeouts")下面的_T("Batt
    ResumingSuspendTimeout") 的值可以改变没有使用外部电源时的超时时间。修改TEXT("HKEY_LOCAL_MACHINE\\SYSTEM \\CurrentControlSet\\Control\\Power\\Timeouts")下面的 _T("ACResumingSuspendTimeout")的值可以改变使用外部电源时的超时时间。

    SystemIdle Timeout(即SuspendTimeout):
    系统自动进入 Suspended状态的超时时间,用户可以通过控制面板去改变它。在On,BacklightOff,UserIdle,ScreenOff状态下 SystemIdle Timeout会让系统进入Unattended状态,在Unattended状态下SystemIdle Timeout会让系统进入Suspended状态。
    这个SystemIdle Timeout时间也是可以通过修改注册表去改变的。这个时间分两个,在不使用外部电源时是m_dwBattSuspendTimeout,使用外部电源时是m_dwACSuspendTimeout。
    从 代码上看,m_dwBattSuspendTimeout的默认值是300s,m_dwACSuspendTimeout的默认值是600s.然后 在\PUBLIC\WPC\OAK\FILES\下(适用于PPC)或是\PUBLIC\SMARTFON\OAK\FILES\(适用于 SmartPhone)的project.reg里对此又作了设置修改。修改TEXT("HKEY_LOCAL_MACHINE\\SYSTEM \\CurrentControlSet\\Control\\Power\\Timeouts")下面的 _T("BattSuspendTimeout")的值可以改变m_dwBattSuspendTimeout。修改 TEXT("HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Power \\Timeouts")下面的_T("ACSuspendTimeout")的值可以改变m_dwACSuspendTimeout。

    Backlight Timeout:
    系统自动进入BacklightOff状态的超时时间。在On状 态下Backlight Timeout会让系统进入BacklightOff状态,在BacklightOff,UserIdle,ScreenOff,Unattended状 态下会屏蔽掉Backlight Timeout。
    同样这个时间分两个:在不使用外部电源时是m_dwBattBacklightTimeout,默认是30s,使用外部电源时是m_dwACBacklightTimeout,默认是60s。用户同样可以通过控制面板去改变它。
    这个Backlight Timeout时间也是可以通过修改注册表去改变的。
    修 改TEXT("HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Power \\Timeouts")下面的_T("BattBacklightTimeout")的值和TEXT("HKEY_CURRENT_USER \\ControlPanel\\Backlight")下面的_T("BatteryTimeout")的值中的任何一个都可以改变 m_dwBattBacklightTimeout。
    修改TEXT("HKEY_LOCAL_MACHINE\\SYSTEM \\CurrentControlSet\\Control\\Power\\Timeouts")下面的 _T("ACBacklightTimeout")的值和TEXT("HKEY_CURRENT_USER\\ControlPanel \\Backlight")下面的_T("ACTimeout")的值中的任何一个都可以改变m_dwACBacklightTimeout。

    注意的是:为了避免冲突,我们修改Backlight Timeout时,上面的两组注册表值最好只用一组,就是要么用TEXT("HKEY_LOCAL_MACHINE\\SYSTEM \\CurrentControlSet\\Control\\Power\\Timeouts")下面的 _T("BattBacklightTimeout")和_T("ACBacklightTimeout")要么就用 TEXT("HKEY_CURRENT_USER\\ControlPanel\\Backlight")下面的 _T("BatteryTimeout")和_T("ACTimeout")。
    如果两组同时用的话,根据pwstates.cpp文件里 PowerStateManager::PlatformLoadTimeouts里的代码(先读取 TEXT("HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Power \\Timeouts")下面的_T("BattBacklightTimeout")和_T("ACBacklightTimeout")后读取 TEXT("HKEY_CURRENT_USER\\ControlPanel\\Backlight")下面的 _T("BatteryTimeout")和_T("ACTimeout")),会以后一组的注册表值为实际值。

    User Timeout:
    这个超时机制只在Windows Mobile 6 Standard设备中用。在Windows Mobile 6 Professional 和Windows Mobile 6 Classic 设备没有UserIdle这个状态,也就没有使用这个超时机制。
    在On,BacklightOff状态下UserTimeout会让系统进入UserIdle状态,在UserIdle,ScreenOff,Unattended状态下会屏蔽掉User Timeout。
    在Windows Mobile 6 Standard设备中,这个时间也分两个m_dwBattUserIdleTimeout和m_dwACUserIdleTimeout。
    修 改TEXT("HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Power \\Timeouts")下面的_T("BattUserIdle")的值和TEXT("HKEY_CURRENT_USER \\ControlPanel\\Power")下面的_T("Display")的值中的任何一个都可以改变 m_dwBattUserIdleTimeout。
    修改TEXT("HKEY_LOCAL_MACHINE\\SYSTEM \\CurrentControlSet\\Control\\Power\\Timeouts")下面的_T("ACUserIdle")的值和 TEXT("HKEY_CURRENT_USER\\ControlPanel\\Power")下面的_T("Display")的值中的任何一个都可 以改变m_dwACUserIdleTimeout。

    和Backlight Timeout一样,不要同时使用TEXT("HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet \\Control\\Power\\Timeouts")下面的_T("BattUserIdle")和_T("ACUserIdle")与 TEXT("HKEY_CURRENT_USER\\ControlPanel\\Power")下面的_T("Display")这两组值,否则会以后 一组的注册表值为实际值。

    User Active事件:
    当有任何用户操作时激活此事件。
    在BacklightOff,UserIdle状态下User Active事件会让系统进入On状态,在On,ScreenOff,Unattended状态下对User Active事件不做处理。
    在 HKEY_LOCAL_MACHINE\System\GWE\ActivityEvent下的键值就是当GWES发现有任何用户操作时要发送的事件 --PowerManager/ActivityTimer/UserActivity。在pmtimer.cpp文件里的 ActivityTimersThreadProc()函数里根据在超时时间内是否有PowerManager/ActivityTimer /UserActivity事件判断当前是UserActivity状态还是UserInactivity状态,并且分别再发PowerManager /UserActivity_Active和PowerManager/UserActivity_Inactive事件。
    对应的 ActivityTimers的注册表在TEXT("HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet \\Control\\Power\\ActivityTimers")下。在PPC里这项注册表下只有_T("UserActivity")这个子项, 这个子项下只有_T("TimeoutMs")=100值。也就是说从UserActivity状态转换到UserInactivity状态的超时时间是 100ms,这样实际上PM模块就会忽略掉这里的PowerManager/UserActivity_Inactive事件,只会在GWE发 PowerManager/ActivityTimer/UserActivity事件时通知PM当前是User Active事件。

    SystemIdleTimerReset:
    复位SystemIdleTimer,调用 SystemIdleTimerReset()函数会发送_T("PowerManager/SystemIdleTimerReset")事件。此时 PM在pwstates.cpp文件的PowerState::WaitForEvent()函数里会调用 m_pPwrStateMgr->ResetSystemIdleTimeTimeout(TRUE);platEvent = SystemActivity;这样将m_dwCurSuspendTimeout复位并且platEvent = SystemActivity时系统电源状态不做迁移。

    Power Manager API(SetSystemPowerState):
    这里的PowerManager API特指能直接改变系统电源状态的SetSystemPowerState。
    SetSystemPowerState 的调用路径是 PmSetSystemPowerState->PlatformSendSystemPowerState->g_pPowerStateManager->SendSystemPowerState.
    先 判断要设置的系统电源状态是否可以被SetSystemPowerState直接设置(调用AppsCanRequestState),其中 On,UserIdle,Suspended,ScreenOff,ColdReboot,Reboot可以被设 置,BacklightOff,Resuming,Unattended不可以被设置。其次依次调用 pNewPowerState->EnterState();pNewPowerState = SetSystemState(pNewPowerState );m_pCurPowerState = pNewPowerState;SetEvent(m_hSystemApiCalled);将函数传入的状态设置为当前系统电源状态。


    FROM:

    http://blog.sina.com.cn/s/blog_4ef8be9f0100e77r.html
     

  • 相关阅读:
    蜗牛讲-Fabric入门之架构
    No module named flask 错误解决
    adb测试Doze和App Standby模式
    以太坊挖矿原理
    mac上 go-delve 安装出现The specified item could not be found in the keychain 解决方法
    nginx+lua 根据指定路径反向代理
    asp.net 网站监控方案
    go开源项目influxdb-relay源码分析(一)
    碰到的jpython用ssh连接机器,有些命令无法运行
    git常用命令(备忘)
  • 原文地址:https://www.cnblogs.com/answer/p/1956244.html
Copyright © 2020-2023  润新知