|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionAs a regular reader of the MSDN support forums and other online development communities, I see several questions (some reoccurring) about the aspects of power management and control on Windows Mobile devices. Sometimes, a developer wants to reduce the demand on power, and at other times, disable the power saving features. Then, there are coding patterns that contribute to killing the battery much faster. In response to the voices of the community, I’ve collected information on Windows Mobile power management. While Windows Mobile Standard devices are mentioned within this document, it is centered around Windows Mobile Professional. Power management is a huge area to cover, and there is much I have to discuss and add to this article. However, at this point, I feel that the information presented can be helpful to a number of people, and I have decided to make the article available with the plans on evolving it over a period of time until it reaches a point at which I feel it is complete. If the article becomes too large, then it may be broken into more than one article. About the CodeThe code examples included with this article are a collection of small programs that demonstrate one or two power management concepts. These programs rely on several native calls. Rather than declare P/Invokes in each individual program, there is a single project that contains all of the necessary native calls, and the example programs make their low level calls through the classes in that project. I would normally wrap these calls in a helper, but have avoided using one for these examples so as to not add a layer of separation between the calls that I wish to demonstrate. All of the sample code is in C#, with P/Invoke calls. Since the APIs used are listed, the information should be useful to C++ developers as well. The example programs in the attached code illustrates the following:
Driver DependenciesAs mentioned, some aspects of power management deal with low level calls. As such, some code examples may not work on your device because of dependencies on the driver implementation. During the course of collecting this information, I performed a firmware update on a Windows Mobile 6 device I own (now a 6.1 device). Some examples stopped working, and the cause of the problem was that the manufacturer of this specific device decided not to use the standard power manager in their firmware update. Many of the code examples will run on Windows Mobile 5 devices, but I am targeting Windows Mobile 6. Running certain examples on Windows Mobile 5 may cause a "NotSupported" exception to be thrown. Within the next week, I plan to resolve any Windows Mobile 5 compatibility problems. Terms – Windows Mobile Professional and Windows Mobile StandardSome parts of the information within this article are specific to Windows Mobile Professional and Windows Mobile Standard. Rather than use these terms to refer to these device classes, I am reverting to the older names for these platforms. For devices that do not have a touch screen, I will use the term Smartphone instead of Windows Mobile Standard device. For devices with a touch screen, I will use the term Pocket PC instead of Windows Mobile Professional device. While these terms are considered obsolete, I find that it is easier to visually distinguish the two words. When I speak of attributes that are common to both platforms, I will use the term “Windows Mobile”. What does “Off” Mean?Foundational to this discussion is an understanding of what is meant by the word “off”. A typical light bulb on a typical light switch is either on or off, with no states in between. Historically, that could be said of many electrical devices, but in today’s world, many devices do not frequently use true off states unless their power supply is disrupted. The off state has been displaced be a suspended state or low power state. The power behavior on Smartphone and Pocket PC devices are different, so I’ll describe these separately. But, common amongst both platforms is that if I ever say that the device is "Off", that means that power is not flowing through the devices, while when a typical user says “Off”, they will mean that the device screen is off irrespective of whether or not the device is actually consuming power or performing actions. Smartphone©Windows Mobile Standard devices are typically on. If you turn the phone to its true off state, then you won’t be able to receive phone calls. If you don’t interact with the device, the screen will power off and the processor will run at a lower speed, but it is still on and running. According to the Windows Mobile Team blog, having the device in an always on state contributes to better power savings. A potential problem with this mode is that a badly written program will cause the processor to consume more power than it needs to when it is idle. Pocket PCWindows Mobile Professional has four power modes that we should know about. In the full powered state, the device’s screen and backlight are on. If you press the power button or don’t interact with the device, then after so much time, it goes into the “unattended” state. In this state, the device is still running, but the screen and backlight are powered down. The user would look at this as being an off state, but the device is still awake. After about 15 seconds, the device will go from an unattended state to a suspended state. In the suspended state, all of the programs that had been running are still in memory, but they make no progress since the CPU is in a halted state. The final state we are concerned about is the true off state. The Power StatesSystem Power StatesWindows Mobile devices have several predefined power states. Some of these states are specific to the Pocket PC, some to the Smartphone, and others can be found on both. The following table lists the power states, and describes what occurs to transition the device into a said power state. P means that a state is applicable to Pocket PCs, and S means the state is applicable to Smartphones.
Note that programs can alter a device's transition among power states. An example of such a program is an instant messenger which may prevent a device from suspending so that it can continue to receive messages. Device Driver Power StatesThe individual components of Windows Mobile Devices can have their own power states. The most noticeable of which is the screen and the backlight. The device can be on while the backlight or the screen is turned off (a common power configuration when using a media player). The power states for device drivers are named a little more abstractly.
Depending on the hardware and driver, some of these power states are identical. When the power state of a device needs to be changed, a request to change the state should be passed through Requesting and Changing the Power StateUse the native function If your application needs for the Windows Mobile device to stay in a certain power state, then use The power state of the system can be set through the native function (You can also request that your program be started automatically during certain power change events. See Automatically Starting Your Application on Windows Mobile for more details.) When you have an application that needs to run in unattended mode, use the native function a target=_blank href="http://msdn.microsoft.com/en-us/library/aa908497.aspx"> Without the Power ManagerWhile Windows Mobile devices have use of the Power Manager, Windows CE devices may or may not. For devices that do not support the power manager API, calls to the GWES system can be used to power the system down programmatically. Only use GWES functions if the power manager API is not available. keybd_event( VK_OFF,0, KEYEVENTF_SILENT,0); keybd_event( VK_OFF,0, KEYEVENTF_SILENT|KEYEVENTF_KEYUP,0); In either case, since the messages must be processed by GWES, the function calls will return, and a few more lines of code will execute before the system suspends. If you need your system to stop doing work after calling this method, then make a call to Enumerating HardwareActive hardware in Windows CE devices can be found by first looking in the Registry in HKLM\Drivers\Active. A group of Registry keys with numeric names will be found at that location. Looking at the “Name” string inside of each one of those keys will give the name of an item of hardware. In the sample program CePowerState, I enumerate the hardware with the following code: // Get the names of all of the subkeys that
// refer to hardware on the device.
RegistryKey driverKeyRoot =
Microsoft.Win32.Registry.LocalMachine.OpenSubKey("Drivers\\Active");
string[] keyName = driverKeyRoot.GetSubKeyNames();
//We are saving this information to list for sorting later
List<string> deviceNameList = new List<string>();
for (int i = 0; i < keyName.Length; ++i)
{
//Get the name of the hardware and add it to the list
RegistryKey currentKey = driverKeyRoot.OpenSubKey(keyName[i]);
string deviceName = currentKey.GetValue("Name") as string;
if(deviceName!=null)
deviceNameList.Add(deviceName);
}
//Sort the list
deviceNameList.Sort();
//Add the list to the list box so the user can select hardware
for (int i = 0; i < deviceNameList.Count; ++i)
{
lstDeviceList.Items.Add(deviceNameList[i]);
}
The sample program CePowerState will enumerate all of the hardware found in this location and allow you to directly set the power state of the hardware by calling //Get the name of the selected hardware
string deviceName = lstDeviceList.SelectedItem as string;
//Get the power state to which the device will be changed
CEDEVICE_POWER_STATE state = (CEDEVICE_POWER_STATE)Enum.Parse(
typeof(CEDEVICE_POWER_STATE), lstPowerState.SelectedItem as string,true);
//deviceHandle = CoreDLL.SetPowerRequirement(deviceName, state,
(DevicePowerFlags)1 , IntPtr.Zero, 0);
CoreDLL.SetDevicePower(deviceName, DevicePowerFlags.POWER_NAME, state);
Registered Device Power Settings for Power StatesThere are default device power settings for certain power states. For example, in unattended state, my Windows Mobile Professional phone turns off the backlight on the screen but keeps the sound adapter and the GPS receiver powered on. The information on these settings can be found in HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Power\Timeouts\State\. For each one of the power states, you will find a key. The contents of this key are string sub keys whose names match hardware on the device and whose value match a device power state (so 0x04 matches Preventing the System from Powering DownPocket PCs will automatically progress towards their suspended states if no user actions are detected. There are times at which you may need for a device to maintain its full power state even though the user isn’t directly interacting with the system (such as when listening to music with Windows Media Player). To prevent the system from powering down from being idle periodically, make calls to
The timeout values can also be retrieved from the Registry. Look in the location [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Power] for the following keys:
The Battery StateThe state of the batteries in Windows Mobile devices is available through the native method In the attached sample programs, there is a program called “Battery Status” that displays the information on the battery. The top of the program displays the most important data on the battery: its current capacity, whether or not it is connected to an AC source, the battery’s temperature, the voltage output, and the battery’s current (note that the sign on the current will change when the device is charging).
The Preserving PowerIf you would like to ensure that your programs act responsibly and don’t unnecessarily burn through the battery’s power, then the best thing that your program can do is to stop performing work when no work needs to be performed. Sounds like common sense, doesn’t it? But, you would be surprised of the unnecessary amount of work that programs do when they could save power by doing nothing. The most common power burning pattern I came across in the support forums is continuous polling. An example of such an implementation follows: BeginSomeTimeConsumingTask();
while(!taskComplete)
{
Application.DoEvents();
}
The above code is written with the intention of running a long running process on another thread and waiting on it to complete in the main thread without impacting the responsiveness of the main thread. If there is no work for the main thread to do, then the CPU is unnecessarily burning cycles waiting for the other thread to continue. The better alternative is to have a background task signal. Problem – Iterative CheckingDescriptionA thread needs to wait for an event to occur before moving on to perform the rest of its actions. Many developers will create a Boolean variable and will change its value when the other thread can continue. The waiting thread pools this variable until it changes, then it continues its task. ExplanationThe waiting thread is unnecessarily polling a variable and burning through CPU cycles while not accomplishing any work. SolutionThere are already facilities to implement this same functionality, provided by the runtime and the Operating System through various synchronization objects. Synchronization techniques could be used instead to block a thread until a task is complete or another thread signals for it to complete. A program can also wait on an external event, or register itself to be started during a certain external event (such as the device being connected to power, or an ActiveSync session being initialized). For these situations, the program can register to be notified or started up when the event occurs. When polling is the only way to query for status, then consider putting your thread to sleep between checks. Example: NoPollingFor a simple example, I will use delegates and the thread pool to perform my long running tasks. The delegates are necessary since UI elements cannot be updated from a secondary thread and delegates can be used to ensure UI updates occur on the correct thread. The complete program can be found in the attached sample code. delegate void UpdateStatusDelegate(int progress);
delegate void VoidDelegate();
UpdateStatusDelegate _updateStatus;
VoidDelegate _taskComplete;
WaitCallback _longRunningTask;
public Form1()
{
InitializeComponent();
_longRunningTask = new WaitCallback(LongRunningTask);
_updateStatus = new UpdateStatusDelegate(UpdateStatus);
_taskComplete = new VoidDelegate(TaskComplete);
}
// We cannot update UI elements from secondary threads. However
// the Control.Invoke method can be used to execute a delegate
// on the main thread. If UpdateStatus is called from a secondary
// thread it will automatically call itself through Control.Invoke
// to ensure its work is performed on the primary (UI) thread.
void UpdateStatus(int progress)
{
if (this.InvokeRequired)
BeginInvoke(_updateStatus, new object[] { progress });
else
{
this.txtFeedback.Text = progress.ToString();
pbWorkStatus.Value = progress;
}
}
// The long running task is contained within this method.
// as the task runs it will pass progress updates back to
// the UI through the UpdateStatus method. Upon completion
// of the task a call is made to TaskComplete
void LongRunningTask(object o)
{
try
{
for (int i = 0; i < 100; ++i)
{
Thread.Sleep(100);
UpdateStatus(i);
}
TaskComplete();
}
catch (ThreadAbortException exc)
{
//The task is being cancelled.
}
}
// Since the actions the program takes at completion of the long
// running task touch UI elements the TaskComplete method will
// also call itself (if necessary) through Control.Invoke to
// ensure that it is executing on the primary (UI) thread.
void TaskComplete()
{
if (this.InvokeRequired)
{
this.Invoke(_taskComplete);
}
else
{
pbWorkStatus.Value = 0;
miWork.Enabled = true;
txtFeedback.Text = "Complete";
}
}
// When the user selects the menu item to begin working
// I will disable the work menu item to prevent concurrent
// request and start the long running progress on a secondary
// thread.
private void miWork_Click(object sender, EventArgs e)
{
miWork.Enabled = false;
ThreadPool.QueueUserWorkItem(_longRunningTask);
}
private void miQuit_Click(object sender, EventArgs e)
{
this.Close();
}
Problem – Don’t Let the Device SleepDescriptionA program is performing a long running task that does not require user interaction such as GPS navigations (for which the user would probably look at the screen but not touch it). After the program has run for an amount of time, the screen turns off and disrupts the user’s experience. ExplanationSince the user is not interacting with the system, it does as it normally should, and is powering the device down to save power. SolutionCall the native function Example Program: PreventSleepThe program “PreventSleep” reads the idle timeout values from the Registry and will call In the code example, using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Win32;
using Microsoft.Win32;
namespace PreventSleep
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
// Look in the registry to see what the shortest timeout
// period is. Note that Zero is a special value with respect
// to timeouts. It indicates that a timeout will not occur.
// As long as as SystemIdleTimeerReset is called on intervals
// that are shorter than the smallest non-zero timeout value
// then the device will not sleep from idleness. This does
// not prevent the device from sleeping due to the power
// button being pressed.
int ShortestTimeoutInterval()
{
int retVal = 1000;
RegistryKey key = Registry.LocalMachine.OpenSubKey(
@"\SYSTEM\CurrentControlSet\Control\Power");
object oBatteryTimeout = key.GetValue("BattPowerOff");
object oACTimeOut = key.GetValue("ExtPowerOff");
object oScreenPowerOff = key.GetValue("ScreenPowerOff");
if (oBatteryTimeout is int)
{
int v = (int)oBatteryTimeout;
if(v>0)
retVal = Math.Min(retVal,v);
}
if (oACTimeOut is int)
{
int v = (int)oACTimeOut;
if(v>0)
retVal = Math.Min(retVal, v);
}
if (oScreenPowerOff is int)
{
int v = (int)oScreenPowerOff;
if(v>0)
retVal = Math.Min(retVal, v);
}
return retVal*9/10;
}
private void Form1_Load(object sender, EventArgs e)
{
// Set the interval on our timer and start the
// timer. It will run for the duration of the
// program
int interval = ShortestTimeoutInterval();
resetTimer.Interval = interval;
resetTimer.Enabled = true;
}
private void miQuit_Click(object sender, EventArgs e)
{
this.Close();
}
// Call the SystemIdleTimerReset method to prevent the
// device from sleeping
private void resetTimer_Tick(object sender, EventArgs e)
{
CoreDLL.SystemIdleTimerReset();
}
}
}
Problem – Wake up and Quietly WorkDescriptionYour program needs to wake up and perform some work at a predetermined time. ExplanationWhen the device wakes up and your program begins to work, placing the device in a full powered mode will unnecessarily get the attention of the user, or may lead to screens and buttons receiving key presses if the device were in the user's problem. We need to wake up the device without powering up the screen. The user should be totally unaware that the device is doing any work. SolutionWhen the device wakes up, the program should promptly place the Windows Mobile device in unattended mode. In this mode, if the user were not using the device, then the device’s screen is not going to power up, yet the program is able to run as though the device were fully powered. Once the program completes its work, it can release its requirement for the device to be in unattended mode, and can go back to sleep with the user never being made aware that the device had done anything. Example Program: Work QuietlyWorkQuietly allows the user to select a sound file and a time delay when started. After selecting the “Run” menu option, the program will schedule for a restart of itself using the This is one of the rare cases in which I modify the // Schedule the execution of the program and terminate.
// You can either pur the device to sleep or leave it at
// full power. In either case the program will run at its
// assigned time, play a sound, and then terminate
private void miRun_Click(object sender, EventArgs e)
{
int waitTime = int.Parse(this.cboStartTime.Text);
DateTime startTime = DateTime.Now.AddSeconds(waitTime);
string targetExecutable =
this.GetType().Assembly.GetModules()[0].FullyQualifiedName;
RunAppAtTime(targetExecutable, startTime);
using (StreamWriter sw = new StreamWriter(targetExecutable + ".soundPath"))
{
sw.Write(txtSoundPath.Text);
sw.Close();
}
this.Close();
}
The following is my modified [MTAThread]
static void Main(string[] args)
{
if (args.Length == 0)
Application.Run(new Form1());
else if (args[0].Equals("AppRunAtTime"))
{
string soundPath;
// We started due to a scheduled event
CoreDLL.PowerPolicyNotify(PPNMessage.PPN_UNATTENDEDMODE, -1);
string targetExecutable =
typeof(Form1).Assembly.GetModules()[0].FullyQualifiedName;
StreamWriter argInfo = new StreamWriter(targetExecutable + ".argument.txt");
argInfo.WriteLine(args[0]);
argInfo.Close();
using (StreamReader sr = new StreamReader(targetExecutable + ".soundPath"))
{
soundPath = sr.ReadToEnd();
sr.Close();
}
if (File.Exists(soundPath))
Aygshell.SndPlaySync(soundPath, 0);
CoreDLL.PowerPolicyNotify(PPNMessage.PPN_UNATTENDEDMODE, 0);
}
}
Problem – Your Program Needs to Query the Power Level of the BatteryBeing able to query the power level of the battery is useful for creating Windows Mobile utilities and for making programs that respond responsibly to available power levels. Example Program: BatteryStatusThe process of acquiring the battery status information is incredibly simple. The P/Invoke declaration and a helper function are displayed below: [DllImport("CoreDLL")]
public static extern int GetSystemPowerStatusEx2(
SYSTEM_POWER_STATUS_EX2 statusInfo,
int length,
int getLatest
);
public static SYSTEM_POWER_STATUS_EX2 GetSystemPowerStatus()
{
SYSTEM_POWER_STATUS_EX2 retVal = new SYSTEM_POWER_STATUS_EX2();
int result = GetSystemPowerStatusEx2( retVal, Marshal.SizeOf(retVal) , 0);
return retVal;
}
The parameter
Curiosity: What Power States are Supported on my DeviceI stumbled across some interesting Registry keys while searching for other information, which resulted in this program. Using the Registry, this program will list your device’s power states. Selecting one of the power states will cause the program to inform you of the default power state for the device drivers along with the hardware that should have some state other than the default.
Example Program: MyPowerStatesThe code for this does nothing more than a filtered Registry dump. Here’s the source code of the main part of the program: const string BASE_POWER_HIVE = @"System\CurrentControlSet\Control\Power\State";
string[] _powerStateNames = {"Full Power","Power Savings",
"Standby","Sleep Mode",
"Power Off"};
Regex _targetRegistryValue = new Regex("(DEFAULT)|(^.*:$)",
RegexOptions.IgnoreCase);
string[] GetPowerStateList()
{
RegistryKey powerStateKey = Registry.LocalMachine.OpenSubKey(BASE_POWER_HIVE);
return powerStateKey.GetSubKeyNames();
}
string[][] GetPowerStateInfo(string stateName)
{
RegistryKey stateInformationKey =
Registry.LocalMachine.OpenSubKey(String.Format(@"{0}\{1}",
BASE_POWER_HIVE, stateName));
string[] valueList = stateInformationKey.GetValueNames();
List<string[]> StateInfo = new List<string[]>();
for (int i = 0; i < valueList.Length; ++i)
{
string currentValue = valueList[i];
if (_targetRegistryValue.IsMatch(currentValue))
{
StateInfo.Add(new string[] { valueList[i],
_powerStateNames[(int) stateInformationKey.GetValue(currentValue)]});
}
}
return StateInfo.ToArray();
}
void PopulatePowerState()
{
cboPowerState.Items.Clear();
string[] stateList = GetPowerStateList();
List<string> sortList = new List<string>(stateList);
sortList.Sort();
for (int i = 0; i < sortList.Count; ++i)
{
cboPowerState.Items.Add(sortList[i]);
}
}
AdditionsAs mentioned, this document is a work in progress that I've decided to share since I feel it will be helpful to the community. Over the next several weeks, the document will be edited and example programs will be added. If there is something you would like to see, don't hesitate to make a request. Just leave a message below. If you like this article, then please rate it. Resources and ReferencesAPI ReferencesArticles and Blog Entries
Books
History
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||