Chapter 7: Creating Mobility-Aware Longhorn Applications

 

Introduction
Chapter 1: The "Longhorn" Application Model
Chapter 2: Building a "Longhorn" Application
Chapter 3: Controls and XAML
Chapter 4: Storage
Chapter 5: Data Binding
Chapter 6: Communication

Chapter 7: Creating Mobility-Aware Longhorn Applications

Brent Rector
Wise Owl Consulting

April 2004

Contents

Power Management
Form Factor
Network Awareness
Summary

Mobility is another major theme of Longhorn. Laptops, notebooks, and Tablet PCs are specific and identifiable hardware form factors that support scenarios distinct from those supported by desktop PCs. Mobile PCs comprise a large and growing segment of the overall PC market. Mobile PCs make up about 30 percent of the worldwide PC market now, and the segment is growing more rapidly than desktops.

In absolute terms, shipments of mobile PCs in the United States and Western Europe have increased year after year, whereas desktop shipments have declined (IDC PC Tracker, June 2002). Given that laptops cost more than desktops and given an economy in which the overall PC market is shrinking, the growth of laptop shipments and share is a striking and important trend.

The Japanese market is even more favorable for mobile PCs. In Japan, laptops account for nearly 50 percent of the PC market.

The latest forecasts from IDC and Gartner Dataquest (March 2003) agree that laptop share will continue to increase through the next several years. By fiscal year 2007, these forecasts show mobile PC share of 30 percent in the United States, 33 percent in Western Europe, and 56 percent in Japan. The forecasts also agree that this trend applies to both the consumer and the enterprise markets.

Applications should be written with mobility in mind for the following key reasons:

  • Mobile PCs are a growing segment of both the enterprise and the consumer PC markets. The rapid expansion of wireless technology will only accelerate this trend.
  • Laptops cost more than desktops: They are a premium PC product. The growing number of buyers who are choosing laptops—who pay more despite getting less traditional capability—demonstrates that mobility has real value.
  • A significant amount of industry research and development is focused on mobile PCs, so the value associated with applications on these PCs should increase. Innovations in both hardware and software will yield to new and improved mobile PCs with low-power processors, innovative form factors (such as the Tablet PC), longer battery life, and improved performance.

Areas of ongoing investment for Longhorn mobility include the following:

  • Anywhere wireless networking (the ability to move between wireless environments)
  • Peer-to-peer collaboration
  • Hot docking and undocking (easy and stable)
  • Multimonitor support for docking and meeting room projection scenarios
  • Improved power management (for longer battery life)
  • Fast, consistent resume from standby
  • Find me, hide me (management of notifications)
  • Offline access and seamless synchronization of data
  • Location awareness and location-aware services

Some of the fundamentals that software designers need to consider while designing applications for Longhorn mobile scenarios are power management, form factor (including docking/undocking and readability), and network awareness. Each of these fundamentals is discussed in the following sections.

Power Management

The mobility trends described earlier will gradually cause two fundamental shifts in the way most people use their computers. First, people take their PCs with them when they leave their offices to work offsite, to travel, or to attend meetings. Second, people now expect to be able to use their PCs much more like they do PDAs and cell phones, without having to go through long startup and shutdown procedures between sessions.

To meet these expectations, the hardware, operating system, and applications must each do their part to help realize extended battery life and fast, reliable system standby and resume transitions. Through the OnNow power management initiatives, Microsoft has been working since the release of Windows 98 to drive battery life and availability improvements in PC hardware, the core Windows components, and applications.

Longhorn continues this investment with several key new features for improved power management, including a redesigned and enhanced kernel power policy manager. Extensions to the power manager will provide a common framework for applications and devices to register for and receive notifications of important system power events, including the user's current power preferences (for example, the user currently wants maximum battery life or maximum performance), and notifications of when the remaining battery capacity crosses specific thresholds (for example, remaining battery capacity is 30 percent).

An application can also use the power policy manager to handle the storage and retrieval of its application-specific power settings with the current user system power policy. When a power transition occurs that affects a power setting that the application has registered for, the power manager will notify the application with an updated value for the power setting. The power manager can handle all overhead of storing, managing, and retrieving power settings for an application. This can significantly reduce the work required by the application to support intelligent and efficient power-aware behavior.

Coinciding with the release of Windows 98, Microsoft published a white paper on designing power-aware applications: "OnNow Power Management Architecture for Applications." Many of the fundamental design and implementation guidelines in this paper are unchanged under the new Longhorn power manager framework. Before we examine what has changed for Longhorn applications, it's worth reviewing what has not.

First and foremost, applications should respond to and make proper use of the system power broadcast (WM_POWERBROADCAST) messages. When the system is about to go to sleep, Windows will broadcast a sleep query message, along with a flag indicating whether applications are allowed to display the user interface (UI). Regardless of the state of the "UI allowed" flag, applications should make every effort to prepare for sleep without querying or notifying the user. When the flag is set to disallow UI, it usually indicates that the user is unable to see and respond to the UI—for example, when the lid on a laptop is closed. Unless an application is in the middle of an uninterruptible operation, it should use the sleep query message to quickly and silently save its state so that it can seamlessly resume when the system wakes up again. In particular, because network connections and file handles are likely to be invalid after a standby/resume transition, applications should autosave any open files and silently close open file handles as part of their sleep preparation sequence.

Windows monitors system utilization and user input to detect when the system is being actively used, and depending on current power policy settings, it might turn off specific devices or transition the entire system to the standby state (ACPI-defined S3, or suspend to RAM state) to save power after the idle time-out has expired. Longhorn will be more aggressive about reducing system power consumption. The S3 system standby sleep state will be used much more frequently than in earlier versions of Windows.

Users often perform tasks with their PCs that might not be detected by the system as actual activity. One common example is when a user is presenting a document to others. Applications designed to understand such a presentation mode can call Windows application programming interfaces (APIs) to tell the power manager that the system or display is currently required, thus preventing the idle timers from expiring.

However, the user might be running an application such as a spreadsheet that has no concept of this presentation scenario and does not use these API calls to prevent system power management events. Windows users frequently complain about the display turning off in this case. To address this problem, Longhorn will include a "keep the system and display on" setting, which will temporarily override current power policy values; this setting will be easily accessible from the system battery meter. When the user chooses this setting, all idle timers will be disabled until the temporary override expires or is explicitly canceled.

Applications can also use timer objects to schedule the system to wake or to ensure that the system will be available at a predetermined time. This enables applications to schedule tasks such as backup, media recording, and the like.

Applications should be aware that the level of activity generated by a task might fall below the system idle detection threshold, and thus the system might transition to a low-power standby state at any time. To prevent this, applications should call the SetThreadExecutionState API when performing critical work. This ensures that the system will remain in the working state for the duration of the task. Applications must also take care to call the SetThreadExecutionState API again when the work is complete, thus allowing the system to continue to monitor system utilization and transition to a low-power state as indicated by the current power policy.

Application developers should also be aware of how their designs affect processor power management features. Recent mobile CPU designs have achieved impressive power efficiency through the use of processor idle sleep states (ACPI-defined C states) and dynamic voltage and frequency scaling technologies, otherwise known as performance states. These technologies dynamically reduce processor power consumption while providing performance on demand. However, periodic activity will cause the processor to exit the low-power idle sleep state (C state), and increases in CPU utilization might cause the operating system to increase the current CPU performance state, resulting in greatly increased CPU power consumption. You should test and profile applications on mobile or desktop systems employing these power-saving technologies to evaluate and minimize the effect the application has on processor power consumption.

Software developers should consider how application features can be scaled back based on the system power state (for example, is the system running on utility or battery power?) and the current power policy (for example, the user has indicated, via selecting a power policy, that she wants maximum battery life). In such cases, the user is agreeing to a reduced experience in exchange for the longest possible battery life. Software features that are good candidates for scaling or temporary suspension when operating the system in low-power modes include the following:

  • Nonessential background content processing such as spelling checking, grammar checking, pagination, and indexing for future searches. Some tasks, such as indexing, can be turned off entirely while the system is running on a battery, others can reduce their processing, and therefore power, requirements by reducing the update frequency.
  • Visual elements and effects such as thumbnail and preview panes, animations, and media playback. Thumbnail and preview pane update frequency should be reduced to less than once per second. Animations and playback can be scaled by reducing size and frame rate. Some effects should be turned off entirely if they are nonessential and cannot scale gracefully.
  • Polling for status changes and new data. Polling is almost always an inferior design, and should be avoided whenever possible. Any polling activity necessary should be scaled down in frequency to less than one activity per second. When possible, polling should be replaced by notifications or synchronous designs.
// This program demonstrates how a managed program can notice the
// power state of the machine changing, and respond appropriately:
// changing intervals of regularly performed actions, and suspending
// or resuming actions.

using System;
using System.Threading;
using System.Runtime.InteropServices;
using Microsoft.Win32;
 
namespace PowerSample {
  class PowerSample {
    private PowerThread[] _threads;

    // this struct and system API call are described in MSDN. It
    // does not take much interop to get a lot of information
    // about the machine.
       
    enum _ACLineStatus : byte {
      Offline = 0, Online = 1, Unknown = 255
    }
    enum _BatteryFlag : byte {
      High = 1, Low = 2, Critical = 4, Charging = 8,
      NoSystemBattery = 128, Unknown = 255
    }

    internal struct SystemPowerStatus {
      public _ACLineStatus ACLineStatus;
      public _BatteryFlag  BatteryFlag;
      public byte          BatteryLifePercent;
      public byte          Reserved1;
      public uint          BatteryLifeTime;
      public uint          BatteryFullLifeTime;
    }
    
    [DllImport("kernel32")]
    internal static extern
    bool GetSystemPowerStatus (out SystemPowerStatus sps);

    // these flags and system API call are also described in MSDN.

    [Flags]
    enum ExecutionState : uint {
      SystemRequired        = 0x01,
      SystemDisplayRequired = 0x02,
      UserPresent           = 0x04,
      Continuous            = 0x80000000,
    }

    [DllImport("kernel32")] internal static extern
    uint SetThreadExecutionState (ExecutionState esFlags);

    // This nested class represents application code with periodic
    // processing to do. It encapsulates a Thread object. This
    // object is responsive to a method to let it know the power
    // state of the machine; when the machine goes from AC to DC
    // power, we suspend all low priority processing, and increase
    // the interval at which we perform other periodic processing.
    //
    // In the best of all possible worlds, the application
    // programmer would not be required to poll in worker threads
    // like this; being sensitive to the system's power state
    // minimizes the negative consequences of this kind of code.
    // This example assumes that there is some periodic activity
    // that needs to occur.

    class PowerThread {
      private bool _lowPriority;
      private Thread _thread;
      private string _name;

      // storage used primarily in the context of the worker thread
      private int _sleepDelay;
      private bool _onBattery;

      public PowerThread(string name, bool lowPriority) {
        this._name = name;
        this._lowPriority = lowPriority;

        this._thread = null;
        this._sleepDelay = lowPriority ? 5000 : 1000;
        this._onBattery = false;
      }

      public void Start() {
        if (null == this._thread) {
          this._thread = new Thread(new ThreadStart(ThreadProc));

          this._thread.IsBackground = true;
                    
          if (this._lowPriority) {
            this._thread.Priority = ThreadPriority.Lowest;
          }

          this._thread.Start();

          // When the thread is initialized, we examine the
          // power state of the machine and notify the
          // thread. This way the initial state of the
          // thread (once it's initialized) will be
          // consistent with the power state of the machine.
          SystemPowerStatus status = new SystemPowerStatus();
          if (GetSystemPowerStatus (out status)) {
            this.PowerChange(status);
          }
        }
      }

      private void ThreadProc() {
        while (true) {
          int milliseconds = _sleepDelay;
          if (this._onBattery) {
            // This is where we artificially slow things
            // down on DC power. Your application might
            // adopt a different strategy for minimizing
            // power use while on DC.
            milliseconds *= 2;
          }
          else {
            // when on AC, we keep the computer awake
            // every time we do some processing. Once
            // we're done with our processing, the
            // computer will go back to the normal timeout
            // as dictated by the kernel power policy.
            SetThreadExecutionState(ES_SYSTEM_REQUIRED);
          }

          Console.WriteLine(_name + " working every "
                + milliseconds.ToString()
                + " milliseconds "
                + (this._onBattery ? "and letting system time out"
                                   : "and reserving system")
                );

          Thread.Sleep(milliseconds);
        }
      }

      public void PowerChange (SystemPowerStatus status) {
        // the significance of the numbers in the
        // SYSTEM_POWER_STATUS fields is described in MSDN
        if (ACLineStatus.Online == status.ACLineStatus &&
            true == _onBattery) {
          // system is now on AC power
          Console.WriteLine(_name + " transitioning to AC power");
          _onBattery = false;

          if (true == this._lowPriority) {
            Console.WriteLine("Resuming " + this._name);
            this._thread.Resume();
          }
        }
        else if (0 == status.ACLineStatus && false == _onBattery) {
          // AC is offline (we've gone on DC - battery or UPS)
          Console.WriteLine(_name + " transitioning to DC power");
          _onBattery = true;

          if (true == this._lowPriority) {
            Console.WriteLine ("Suspending " + this._name);
            this._thread.Suspend();
          }
        }
      }
    }

    // This is our event handler for the system event. The event
    // indicates whether the power state of the machine has
    // changed, or if we've come back from a standby, etc. Our
    // behavior is the same in any case - we're just going to turn
    // around and get more detailed information about the power
    // state of the machine, and feed that information to our
    // worker threads.
    void OnPowerModeChange(object obj, PowerModeChangedEventArgs e) {
      if (e.Mode == PowerModes.StatusChange) {
        Console.WriteLine("Power status or capacity change detected");
        if (null != this._threads) {
          SystemPowerStatus status = new SystemPowerStatus();

          if (GetSystemPowerStatus (out status)) {
            foreach (PowerThread victim in this._threads) {
              victim.PowerChange(status);
            }
          }
        }
      }
    }

    // This routine sets up an event hook, creates a few worker
    // threads, lets the threads run for a while (being responsive
    // to power changes), and then terminates.
    void Go () {
      SystemEvents.PowerModeChanged += 
                new PowerModeChangedEventHandler(OnPowerModeChange);
            
      Console.WriteLine("Creating worker threads");
            
      this._threads = new PowerThread[3];
      this._threads[0] = new PowerThread("Worker thread 1", false);
      this._threads[1] = new PowerThread("Worker thread 2", false);
      this._threads[2] = new PowerThread("Low-priority thread", true);

      foreach (PowerThread victim in this._threads) {
        victim.Start();
      }

      Console.WriteLine ("Working for five minutes");
      Console.WriteLine ("(Please trip over the power cord now!)");
      Thread.Sleep(5 * 60 * 1000);

      Console.WriteLine("Ending worker threads - bye");
    }

    static void Main (string[] args) {
      PowerSample ps = new PowerSample();

      if (null != ps) ps.Go ();
    }
  }
}

Form Factor

Laptops, notebooks, and Tablet PCs present challenges to application developers not encountered on desktop PCs. These challenges include grab-and-go docking and readability.

Grab-and-Go Docking

One feature of Longhorn laptops and Tablet PCs is the ability to remove the computer from a docking station or port at any time, without prior warning. Grab-and-go docking presents a challenge for the software designer, who must consider computer connectivity to mass storage devices (hard disks in docking stations, CD-R drives, 1394 hard disks, and others). Any device to which the user is currently writing data or from which the user is reading data can suddenly be disconnected. Software developers should design fallbacks for all these actions—preferably fallbacks that do not require user interaction and are self-healing when device connectivity is restored.

Many Longhorn mobile PC form factors will include two display adapters: one for the built-in screen and one for an external monitor that is used while the device is docked. Consider how your application works when a user interacts with it by using a pen on a Tablet PC or runs another application on an external monitor. You can take advantage of both displays simultaneously. While docked, the built-in display becomes a private display that interacts with the pen, while the external screen is the public interface.

Data such as files, contacts, and devices should be synchronized using the Longhorn Synchronization Manager. The Synchronization Manager will provide users with a single place to synchronize all data.

Designing for Readability

Reading is a common and frequent task for mobile PC users. You can take advantage of mobile PCs as a reading tool by ensuring that your application provides the following capabilities:

  • Responds to page-up and page-down events.
  • Uses smooth scrolling (real time, no flashing) to allow a user's eye to track the movement of a document as the user scrolls.
  • Provides a riffle control that uses a half-second transition per move and per repeat. A riffle control enables users to flip through pages or screens of content quickly.
  • Provides a rich contrast between the background and the content of the document so that it is readable even when viewed from an angle or when some glare exists.
  • Uses colors with a rich contrast for better readability. Do not use yellows, oranges, or other light colors for important items on the screen. Dark colors are easier to distinguish on backlit screens.

Network Awareness

In the past, network-connected machines were stationary devices permanently connected to a network. Applications were developed with this assumption in mind. In the new world of wireless access and mobile devices, application developers can no longer assume that the network is always present or that there is only a single path to a resource. Even though the Transmission Control Protocol (TCP) has complex algorithms to ensure guaranteed delivery, it cannot overcome the transient nature of the mobile user's network environment. Both wireless networking and grab-and-go docking mean that network connections and external hard disks can become disconnected without warning. Although this has always been a concern of desktop applications, these potential problems become much more common on mobile PCs. Applications should be able to handle these dynamic and divergent network environments.

Although each application has its own unique constraints on network behavior, developers should consider implementing several features:

  • Implicit online/offline switching If your application has two separate modes for online and offline behavior, take advantage of the network presence detection in Longhorn and switch between them automatically, without requiring user action or approval.
  • Background and cached file writing Rather than locking the UI when writing to a file, save immediately to a known local file, and attempt to update the real file in the background.
  • Delayed file writing Add functional dexterity by allowing users to save and close a file without the storage available. Prompt users for actions only when necessary (for example, if the online and offline versions become unsynchronized).
  • Cache copies of embedded or linked data For example, at a minimum, keep a static representation of all objects in your file as bitmaps. That way, if the source disappears, users can at least perform basic rendering.

You should continue to design your software to account for sudden disconnection from network resources, including the capability to automatically or manually store data on a local device, and use time-outs on all network actions. Some considerations in this regard include the following:

  • Handling sudden removal and addition of network connections and peripherals.
  • Implementing operations that can recover if problems arise, such as load or save operations to a USB, 1394 hard disk, or CD peripheral. Then, when such operations are interrupted with a docking or undocking action, they can be restarted later.
  • Using best practices for network connectivity. Your application should operate seamlessly in situations where networks are temporarily unavailable or set or reset themselves. For example, your application should include the following capabilities:
    • Handle connectivity transitions.
    • Provide auto reconnection that does not require restarting the application.
    • Give clear feedback of network availability so that the user is aware of this state.
    • Have the ability to be used offline. It is not unusual for a wireless network connection to be intermittent or for users to be offline for a short time without realizing it. Your application should behave seamlessly in these situations. The application should not stop responding while the network is unavailable.
    • Implement automatic synchronization capability when a connection is reestablished, if your application needs to synchronize offline and online data. It is tedious for users to have to remember the explicit steps for synchronizing. Manual synchronization is unnecessary if your application can detect a reconnection to the network and can run automatic data synchronization.

You can choose from many methods to make both streaming and transactions applications perform quickly and effectively across transient and low bandwidth networks. MSDN provides several white papers that deal exclusively with that subject. Briefly, these white papers conclude that a well-written network application should provide the following features:

  • Limit the number of small transactions. Roundtrips between server and host are expensive.
  • Be tested with the applications in environments that have packet loss and low bandwidth.
  • Have intelligent error handling systems, which keep the user informed.
  • Treat the network as an unreliable resource.

You need to keep in mind several other situations that apply to a mobile user:

  • The disappearance of the network completely
  • Changes in the network properties
  • What happens when a mobile user moves to a new valid network that does not have the resources the application needs
  • Dramatic changes in bandwidth

Several improvements in Longhorn will make it simpler to address some of these issues. Network Location API (NLA) will provide a single place where an application can get all the network parameters for a machine. The API will also inform the application whether the parameters have been changed and will even give the application some network context information.

For each interface, the API will provide IP address and configuration information, domain name, adapter GUIDs, and context information. NLA will assign the connection to one of the categories described in the following table.

Type Definition
Ad hoc The interface is on an ad hoc network not connected to any other network.
Managed The interface is connected to a managed "secure" network such as an enterprise, with a Windows domain controller.
Unmanaged The interface is not connected to a Windows domain.
Unknown The service is unable to determine the connection's characteristics.

Each of these categories, with the exception of ad hoc, can also indicate the Internet flag, as described in the following table.

Flag Definition
Internet The interface has Internet connectivity, defined as being able to resolve a common DNS A record from the Internet.

Although these categories are not foolproof, they give the application a good idea of where the host is on the network.

Although NLA helps with traversing the network, it does not solve the problem of the absence of a network resource on a valid network. In this case, the application can wait for the send failure, but this provides little real information about why the failure happened. A more elegant and effective solution is an application layer ping.

A standard Internet Control Message Protocol (ICMP) echo of the resource's name provides the application with little information. The ICMP response can fail for many reasons other than the absence of the resource. Broken name resolution and blocking of ICMP responses (common for security reasons) could easily provide false negatives. An application ping or probe can provide much more information than just the presence of the resource on the new network. It tells the application not only that the server is responding but also whether the application on the server is responsive.

You can also use an application ping to calculate the throughput of a connection, which is extremely useful when the user is moving from a high-bandwidth wired connection to a low-bandwidth wide area network (WAN) connection.

Here is a formula that can assist with calculating the true capacity of the connection:

(OID_GEN_LINK_SPEED*RTT(secs)) = capacity (bps)

After the application has knowledge of the throughput of the connection, it can make intelligent decisions about what type of transactions are appropriate for the size of the pipe. For example, an application can use this information to determine whether the download of a large piece of data would be unreasonable given the network conditions. Applications can tailor their behavior to the conditions.

In the near-term, wireless WAN will be severely bandwidth restricted. The quoted maximum speeds are possible only under optimal conditions. The user would need to be stationary, and with most technologies, only one user per cell could get the full amount of bandwidth allowed by the topology. Unfortunately, these technologies also introduce highly varied amounts of delay. A user could easily see roundtrip time changes from 500 ms to 3000 ms from packet to packet. This discrepancy can make a single ping or probe provide erroneous information to the application about current conditions. This problem can be countered by calculating averages gathered over the history of the connection.

Summary

With increased laptop, notebook, and Tablet PC sales, Microsoft recognizes the value of improving mobile PC use. Longhorn will emphasize a number of mobility scenarios that application developers should be aware of as they design Longhorn-compatible software. Keeping in mind power management, docking/undocking (including data synchronization), and network awareness will be key in building and deploying Longhorn applications for mobile PCs.