December 2009 4 posts

Keeping the backlight lit in a Windows Mobile app

Monday, December 21, 2009


To keep the backlight on, you may think it makes sense to call SystemIdleTimerReset() repeatedly. (Or at least I thought so.) But this doesn't work on all (most?) phones:

[DllImport("coredll.dll")]
public static extern void SystemIdleTimerReset();

public static void Main(string[] args) {
    // Reset the idle timer every 10 seconds, starting now
    var Timer = new Timer(SystemIdleTimerReset, null, 0, 10000);

    // do useful stuff...
}

This does work, however:

[DllImport("coredll.dll")]
public static extern void SystemIdleTimerReset();

[DllImport("coredll.dll")]
public static extern IntPtr SetPowerRequirement(
    string device, int deviceState, int deviceFlags, IntPtr systemState, int stateFlags);

[DllImport("coredll.dll")]
public static extern int ReleasePowerRequirement(IntPtr handle);

public enum CEDEVICE_POWER_STATE {
    PwrDeviceUnspecified = -1,
    D0 = 0, // full on
    D1,
    D2,
    D3,
    D4, // off
    PwrDeviceMaximum
}

public static void Main(string[] args) {
    var Timer = new Timer(SystemIdleTimerReset, null, 0, 10000);
    IntPtr handle = SetPowerRequirement(
        "BKL1:", 
        (int) CEDEVICE_POWER_STATE.D1, 
        1, 
        IntPtr.Zero, 
        0
    );
    
    // do useful stuff...
    
    ReleasePowerRequirement(handle);
}

SetPowerRequirement() forces the system to remain in a higher power consumption state than it otherwise would be in. CEDEVICE_POWER_STATE.D0 is "Full On"; D1 is "Low On" and D4 is "Off." Be sure to ReleasePowerRequirement() when you're done.

The BLK1: is the backlight device name. It's been the same on all the phones I've tested on, but there aren't any guarantees. To find out what the name is on your particular phone, look in the registry in HKLM\Drivers\BuiltIn. There will be a key called Backlight or Frontlight or something similar. The device name seems to be determined by the values Prefix and Index (on my phones these are BKL and 1).

Tags: backlight, wince, winmo | Posted at 22:30 | Comments (3)

Watson crash in RIL_GetCellTowerInfo()

Tuesday, December 15, 2009


I've banged my head against the keyboard for far too long on this problem, so hopefully this post will help preserve someone else's forehead/keyboard.

On the Bing client for Windows Mobile 6, we were getting random Watson crashes (the error window with the Send/Don't Send buttons) and eventually narrowed it down to the RIL_GetCellTowerInfo() call. The probability of a single call to that function causing a crash was about 0.2% and seemed to happen totally randomly. What were we doing wrong?

After narrowing down the cause of the crash by manually running the app over and over, inspecting dumps, etc, I came up with the following code that would crash the phone every time I ran it. It'd die on average around the 500th iteration, sometimes on the first few iterations, and never made it past about 2000. RIL (radio interface layer) talks to drivers underneath it which are of course hardware-specific — but this code crashed every phone I tried it on.

I found another person who was having the same issue as me, but there was no solution. The only answer was a link to a blog which had code that looks just like what I was already using, so that didn't help either.

So, here's the code that crashes. Briefly, what it does is (in a loop):

  1. Call RIL_Initialize(), passing it some parameters including the CellTowerInfoCallback which GetCellTowerInfo() will later call.
  2. If it succeeds (I've never seen it fail on a real phone), call GetCellTowerInfo(), which returns a status code immediately and spawns a thread to do the callback.
  3. Wait for GetCellTowerInfo() to invoke the CellTowerInfoCallback. Sometimes this times out, but that is no big deal and doesn't break anything.
  4. Call RIL_Deinitialize()
using System;
using System.Runtime.InteropServices;
using System.Threading;

static class Program {
  public delegate void RILRESULTCALLBACK(uint dwCode, IntPtr hrCmdID, 
    IntPtr lpData, uint cbData, uint dwParam);
  
  public delegate void RILNOTIFYCALLBACK(uint dwCode, IntPtr lpData, 
    uint cbData, uint dwParam);

  [DllImport("ril.dll")]
  private static extern uint RIL_GetCellTowerInfo(IntPtr rilHandle);

  [DllImport("ril.dll")]
  private static extern uint RIL_Initialize(
    uint rilPortIndex, 
    RILRESULTCALLBACK resultCallback, 
    RILNOTIFYCALLBACK notifyCallback,
    uint notificationClasses,
    uint userParam,
    out IntPtr rilHandle
  );

  [DllImport("ril.dll")]
  private static extern uint RIL_Deinitialize(IntPtr rilHandle);

  private static readonly AutoResetEvent CallbackWaitHandle = new AutoResetEvent(false);

  [MTAThread]
  public static void Main(string[] args) {
    for (int i = 0;; i++) {
      IntPtr ril;
      uint result = RIL_Initialize(1, CellTowerInfoCallback, null, 0, 0, out ril);
      if (result == 0) {
        result = RIL_GetCellTowerInfo(ril);
        if (result >= 0) {
          if (CallbackWaitHandle.WaitOne(3000, false))
            Console.WriteLine("Successfully waited");
        }
      }
      RIL_Deinitialize(ril);
    }
  }

  private static void CellTowerInfoCallback(uint code, IntPtr commandId,
      IntPtr commandData, uint commandDataLength, uint userParam) {
    // normally, you'd do stuff with the data passed here and then set the signal
    CallbackWaitHandle.Set();
  }
}

To me, and quite a few other devs, it looked like we weren't doing anything wrong. Having come straight out of college, where I used primarily Java and some C/C++, but never both simultaneously, it was easy to fall into what is probably a common trap when bridging the managed/unmanaged divide. The problem is that the garbage collector decided to collect or move the CellTowerInfoCallback function right after RIL_Initialize() was called, so that when RIL_GetCellTowerInfo() tries to invoke the callback, it fails and throws an uncatchable exception (since it's thrown from a different thread), which is then handled by Watson.

The fix? Tell the garbage collector to not touch that function. Everything works great if we write the code like this:

public static void Main(string[] args) {
  for (int i = 0;; i++) {
    IntPtr ril;
    RILRESULTCALLBACK func = this.CellTowerInfoCallback;
    GCHandle cb = GCHandle.Alloc(func, GCHandleType.Pinned);
    uint result = RIL_Initialize(1, (RILRESULTCALLBACK)cb.Target, null, 0, 0, out ril);
    if (result == 0) {
      result = RIL_GetCellTowerInfo(ril);
      if (result >= 0) {
        if (CallbackWaitHandle.WaitOne(3000, false))
          Console.WriteLine("Successfully waited");
      }
    }
    RIL_Deinitialize(ril);
    cb.Free();
  }
}

Tags: crash, ril, watson, wince, winmo | Posted at 21:03 | Comments (6)

Filesystem performance on flash drives

Tuesday, December 15, 2009


I got bored and decided to test out the speed of various filesystems on a USB flash drive. I ran each of these a couple of times but the results are by no means scientific.

First up is the speed of copying some files from my hard drive to the USB drive. In the graphs below, "big" is one 756 MB file, and "small" is about 13,000 small files and directories, with a combined size of 359 MB (I used /lib/modules).

performance of a flash drive when copying to USB drive

Copying one file is largely bottlenecked by the slow speed of the USB drive itself, so the numbers for that are about the same across the board, though ext3 is pretty slow for some reason. Copying small files is a better test of the filesystem. For some reason, ntfs-3g is over twice as fast as the next fastest (xfs) even though it's a FUSE module and not even in the kernel. Repeated runs verified this.

Next up is the deletion speed. Again, "big" and "small" refer to the same datasets.

performance of a flash drive when deleting from USB drive

Most of these filesystems deleted the single large file in about half a second, though vfat and ext3 were both slow at 2.2 seconds. The small files were again more interesting, with ext3 and ext4 winning by a large margin.

Tags: ext3, ext4, fat, filesystem, flash, ntfs, usb | Posted at 20:15 | Comments (0)

First post!

Thursday, December 10, 2009


public class Hello
{
    public static void Main()
    {
        System.Console.WriteLine("Hello, world!");
    }
}

After lots and lots of needless work caused by my dislike of Wordpress, I've finally gotten my hand-rolled blog to a state ready for release. Yeah, sure, I have some bugs. No RSS feed? Postponed. No text search? Postponed. Can't go forward/back through individual blog posts like a doubly linked list? Postponed. Starting to sound familiar?

I just now for the first time, after two weeks of development, tested this site in IE6. I'm marking this joyous moment as the first time that I've ever made a site that worked on the first try in IE 6. This may actually be a record in all of web development...

Anyway, more interesting posts to follow.

Tags: meta | Posted at 00:17 | Comments (10)