📄 platform.cpp
字号:
// determine thread priority settings while we're suspending (in case
// of priority inversion)
if(!GetPMThreadPriority(_T("PreSuspendPriority256"), &giPreSuspendPriority)) {
giPreSuspendPriority = DEF_PRESUSPEND_THREAD_PRIORITY;
}
if(!GetPMThreadPriority(_T("SuspendPriority256"), &giSuspendPriority)) {
giSuspendPriority = DEF_SUSPEND_THREAD_PRIORITY;
}
// Determine whether we will allow unattended mode requests to
// influence how we suspend the system.
gfSuspendToUnattendedMode = PlatformSuspendingToUnattendedMode();
// get events from activity timers
PMLOCK();
pat = ActivityTimerFindByName(_T("UserActivity"));
if(pat != NULL) {
ghevSignalUserActivity = pat->hevReset;
ghevUserActive = pat->hevActive;
ghevUserInactive = pat->hevInactive;
} else {
ghevSignalUserActivity = NULL;
ghevUserActive = NULL;
ghevUserInactive = NULL;
}
PMUNLOCK();
// Get pointers to GWES's suspend/routine APIs. These require GWES, so the OEM may
// not have them on this platform. Also get battery level APIs, which require a
// battery driver and may not be present.
hmCoreDll = (HMODULE) LoadLibrary(_T("coredll.dll"));
gfGwesReady = FALSE;
PmInitPowerStatus(hmCoreDll);
if(hmCoreDll != NULL) {
gpfnGwesPowerDown = (PFN_GwesPowerDown) GetProcAddress(hmCoreDll, _T("GwesPowerDown"));
gpfnGwesPowerUp = (PFN_GwesPowerUp) GetProcAddress(hmCoreDll, _T("GwesPowerUp"));
gpfnShowStartupWindow = (PFN_ShowStartupWindow) GetProcAddress(hmCoreDll, _T("ShowStartupWindow"));
// do we have both gwes suspend/resume APIs?
if(gpfnGwesPowerDown == NULL || gpfnGwesPowerUp == NULL) {
// no, ignore GWES
gpfnGwesPowerDown = NULL;
gpfnGwesPowerUp = NULL;
} else {
// monitor GWES apis
ghevGwesReady = OpenEvent(EVENT_ALL_ACCESS, FALSE, _T("SYSTEM/GweApiSetReady"));
DEBUGCHK(ghevGwesReady != NULL);
}
}
// create events
ghevReloadActivityTimeouts = CreateEvent(NULL, FALSE, FALSE, _T("PowerManager/ReloadActivityTimeouts"));
ghevRestartTimers = CreateEvent(NULL, FALSE, FALSE, NULL);
ghevSystemIdleTimerReset = CreateEvent(NULL, FALSE, FALSE, _T("PowerManager/SystemIdleTimerReset"));
if(ghevReloadActivityTimeouts == NULL
|| ghevRestartTimers == NULL
|| ghevSystemIdleTimerReset == NULL) {
PMLOGMSG(ZONE_WARN, (_T("%s: CreateEvent() failed for system event\r\n"), pszFname));
goto done;
}
// check that all of our activity events exist
if(ghevUserActive == NULL || ghevUserInactive == NULL) {
PMLOGMSG(ZONE_WARN, (_T("%s: activity timer events not found\r\n"), pszFname));
goto done;
}
// create our notification queue
hqNotify = PmPolicyCreateNotificationQueue();
if(hqNotify == NULL) {
PMLOGMSG(ZONE_WARN, (_T("%s: PmPolicyCreateNotificationQueue() failed\r\n"), pszFname));
goto done;
}
// we're up and running
SetEvent(hevReady);
// we don't want to start updating system power states until the PM is completely
// up and running. We'll wait for the first call to SetSystemPowerState() coming from
// device.exe's initialization code as our signal to continue.
PMLOGMSG(ZONE_INIT, (_T("%s: waiting for initialization to complete\r\n"),
pszFname));
hEvents[0] = ghevPmShutdown;
hEvents[1] = ghevReloadActivityTimeouts;
dwStatus = WaitForMultipleObjects(2, hEvents, FALSE, INFINITE);
switch(dwStatus) {
case (WAIT_OBJECT_0 + 0):
PMLOGMSG(ZONE_INIT || ZONE_WARN, (_T("%s: shutdown event signaled, exiting\r\n"),
pszFname));
fDone = TRUE;
break;
case (WAIT_OBJECT_0 + 1):
PMLOGMSG(ZONE_INIT, (_T("%s: initialization complete\r\n"), pszFname));
break;
default:
PMLOGMSG(ZONE_INIT || ZONE_WARN,
(_T("%s: WaitForMultipleObjects() returned %d, exiting\r\n"),
pszFname, dwStatus));
fDone = TRUE;
}
// get notifications in case of hive based registry
ghevBootPhase2 = OpenEvent(EVENT_ALL_ACCESS, FALSE, _T("SYSTEM/BootPhase2"));
// read the timeout values
PlatformLoadTimeouts();
// set up wait events -- assume user is active and system is active
hEvents[0] = ghevPmShutdown;
hEvents[1] = ghevReloadActivityTimeouts;
hEvents[2] = hqNotify;
hEvents[3] = ghevRestartTimers;
hEvents[4] = ghevUserInactive;
hEvents[5] = ghevSystemIdleTimerReset;
if(ghevBootPhase2 != NULL) {
hEvents[6] = ghevBootPhase2;
dwNumEvents = dim(hEvents);
} else {
dwNumEvents = dim(hEvents) - 1;
}
dwTimeout = INFINITE;
PMLOGMSG(ZONE_PLATFORM, (_T("%s: waiting for events\r\n"), pszFname));
while(!fDone) {
PLATFORM_ACTIVITY_EVENT eCurrentActivity = NoActivity;
DWORD dwStartTime, dwElapsedTime;
// wait for an event; keep track of elapsed time
dwStartTime = GetTickCount();
dwStatus = WaitForMultipleObjects(dwNumEvents, hEvents, FALSE, dwTimeout);
dwElapsedTime = GetTickCount() - dwStartTime;
PMLOGMSG(ZONE_PLATFORM,
(_T("%s: wait returned %d, elapsed time %d, timeout was %d\r\n"), pszFname,
dwStatus, dwElapsedTime, dwTimeout));
#ifdef NOT_USED
// sanity check
if(WaitForSingleObject(ghevUserActive, 0) == WAIT_OBJECT_0) PMLOGMSG(TRUE, (_T("%s: user active signaled\r\n"), pszFname));
if(WaitForSingleObject(ghevUserInactive, 0) == WAIT_OBJECT_0) PMLOGMSG(TRUE, (_T("%s: user inactive signaled\r\n"), pszFname));
#endif // NOT_USED
// figure out what happened
switch(dwStatus) {
case (WAIT_OBJECT_0 + 0): // shutdown event signaled
fDone = TRUE;
eCurrentActivity = NoActivity;
break;
case (WAIT_OBJECT_0 + 1): // reset timeout variables and restart timers
PlatformLoadTimeouts();
eCurrentActivity = RestartTimeouts;
break;
case (WAIT_OBJECT_0 + 2): // notification from outside the PM
{
POWERPOLICYMESSAGE ppm;
dwStatus = PmPolicyReadNotificationQueue(hqNotify, &ppm, sizeof(ppm));
if(dwStatus == ERROR_SUCCESS) {
PMLOGMSG(ZONE_PLATFORM, (_T("%s: got request 0x%04x (data 0x%08x) from process 0x%08x\r\n"),
pszFname, ppm.dwMessage, ppm.dwData, ppm.hOwnerProcess));
switch(ppm.dwMessage) {
case PPN_POWERCHANGE:
if(PmUpdatePowerStatus()){
eCurrentActivity = PowerSourceChange;
}
break;
case PPN_UNATTENDEDMODE:
// somebody wants to enter or leave unattended mode
if(ppm.dwData != FALSE) {
eCurrentActivity = EnterUnattendedModeRequest;
} else {
eCurrentActivity = LeaveUnattendedModeRequest;
}
break;
case PPN_SUSPENDKEYPRESSED:
SuspendButtonPressed(gfSupportPowerButtonRelease);
break;
case PPN_SUSPENDKEYRELEASED:
SuspendButtonReleased(gfSupportPowerButtonRelease);
break;
default:
// unhandled notification type, ignore it
PMLOGMSG(ZONE_WARN, (_T("%s: unhandled policy notification 0x%04x (data 0x%08x)\r\n"),
pszFname, ppm.dwMessage, ppm.dwData));
break;
}
}
}
break;
case (WAIT_OBJECT_0 + 3): // restart timers
eCurrentActivity = RestartTimeouts;
break;
case (WAIT_OBJECT_0 + 4): // user activity or inactivity signaled
if(hEvents[4] == ghevUserInactive) {
eCurrentActivity = UserInactivity;
} else {
eCurrentActivity = UserActivity;
}
break;
case (WAIT_OBJECT_0 + 5): // somebody called SystemIdleTimerReset()
eCurrentActivity = SystemIdleTimerWasReset;
break;
case (WAIT_OBJECT_0 + 6): // hive based registry load complete
DEBUGCHK(ghevBootPhase2 != NULL);
// update timeouts in case they've been changed
PlatformLoadTimeouts();
eCurrentActivity = RestartTimeouts;
// don't need to wait on this handle again
dwNumEvents--;
CloseHandle(ghevBootPhase2);
ghevBootPhase2 = NULL;
break;
case WAIT_TIMEOUT:
eCurrentActivity = Timeout;
break;
default:
eCurrentActivity = NoActivity;
PMLOGMSG(ZONE_WARN, (_T("%s: WaitForMultipleObjects() returned %d\r\n"), pszFname,
GetLastError()));
break;
}
// update system power state based on activity information
dwTimeout = PlatformUpdateSystemPowerState(eCurrentActivity, dwElapsedTime);
// determine which activity handles we need to wait on
if(WaitForSingleObject(ghevUserActive, 0) == WAIT_OBJECT_0) {
hEvents[4] = ghevUserInactive;
} else {
hEvents[4] = ghevUserActive;
}
}
done:
// clean up before exiting
if(ghevReloadActivityTimeouts == NULL) {
CloseHandle(ghevReloadActivityTimeouts);
ghevReloadActivityTimeouts = NULL;
}
if(ghevRestartTimers != NULL) {
CloseHandle(ghevRestartTimers);
ghevRestartTimers = NULL;
}
if(ghevSystemIdleTimerReset != NULL) {
CloseHandle(ghevSystemIdleTimerReset);
ghevSystemIdleTimerReset = NULL;
}
if(hqNotify != NULL) {
PmPolicyCloseNotificationQueue(hqNotify);
hqNotify = NULL;
}
if(hmCoreDll != NULL) FreeLibrary(hmCoreDll);
PMLOGMSG(ZONE_PLATFORM, (_T("-%s: exiting\r\n"), pszFname));
}
// This routine is called when the system has resumed. It is responsible for
// determining why the system woke up and initiating the appropriate system
// power state transition. This routine is invoked in the context of the PM's
// resume thread.
// Note: this thread must be running at a higher priority than any thread
// that might suspend the system using SetSystemPowerState(). Otherwise it cannot
// tell whether it needs to update the system power state on its own. In general,
// OEMs should not suspend the system without calling SetSystemPowerState() -- the
// code in this routine that handles unexpected suspends is present only as a fallback.
EXTERN_C VOID WINAPI
PlatformResumeSystem(void)
{
SETFNAME(_T("PlatformResumeSystem"));
PMLOGMSG(ZONE_RESUME, (_T("+%s: suspend flag is %d\r\n"), pszFname, gfSystemSuspended));
// Was this an unexpected resume event? If so, there may be a thread priority problem
// or some piece of software suspended the system without calling SetSystemPowerState().
DEBUGCHK(gfSystemSuspended);
if(!gfSystemSuspended) {
// Unexpected resume -- go to the resuming state. This should not happen unless
// somebody is illegally calling PowerOffSystem() directly.
PMLOGMSG(ZONE_WARN || ZONE_RESUME, (_T("%s: WARNING: unexpected resume!\r\n"), pszFname));
// Go into the new state. OEMs that choose to support unexpected resumes may want to
// lock PM variables with PMLOCK(), then set the curDx and actualDx values for all
// devices to PwrDeviceUnspecified before calling PmSetSystemPowerState_I(). This will
// force an update IOCTL to all devices.
PlatformUpdateSystemPowerState(Resume, INFINITE);
DEBUGCHK(ghevRestartTimers != NULL);
SetEvent(ghevRestartTimers);
}
PMLOGMSG(ZONE_RESUME, (_T("-%s\r\n"), pszFname));
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -