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).
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):
- Call
RIL_Initialize()
, passing it some parameters including theCellTowerInfoCallback
whichGetCellTowerInfo()
will later call. - 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. - Wait for
GetCellTowerInfo()
to invoke theCellTowerInfoCallback
. Sometimes this times out, but that is no big deal and doesn't break anything. - 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(); } }
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).
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.
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.
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.