我时不时会去
Mark Russinovich的博客逛逛,学些诊断软件问题的技巧。Mark的博客有一个特点,他有很多案例,专门分析在日常使用电脑时碰上的各种问题,里面有很多分析、解决问题的技巧是颇值得学习的。 我在想,从事软件开发这么多年来,自己也积累了大量的经验,如果能把这些经验做些整理写出来,对自己是一份很好的总结,对别人应该也有借鉴作用。因此我也打算写一些实际工作中遇到的比较典型的案例。 这一篇谈谈解决随机BUG的一些经验。我这里说的随机BUG是指那些你没法通过一些确定的步骤可靠地重现的BUG。我想做软件开发的人都会同意,即使不是最难,随机BUG应该也是最难解决的BUG类型之一。有人也许说,只要找到问题的根源就一定能可靠地重现问题,不能重现只是因为你还没找到问题的根源。这话也许没错,但也还是存在一些情况,即使找到了问题的根源也没法可靠地重现,比如我碰上的这个就属于这种情况。 问题是这样的,我们是一家设备制造商,有自己定制的主板,在主板上开发系统软件(Kernel+Drivers),再在系统软件上构建应用软件-这在嵌入式系统开发中是比较典型的一种模式。我们有一款产品使用的平台是StrongArm SA1110+Windows CE 4.1(这在当年是很常见的一种解决方案)。问题出在关机时,有时候屏幕已经黑了,看起来设备已经完全下电,但其实内部主板的电还没掉,这时按开机键没有反应-系统lockup了。结果是只能拔掉AC电源和电池让主板下电然后才能重新开机。恶劣的情况是,如果用户只使用电池供电,而且他没意识到系统处于lockup状态,过不了多久电量耗尽电池就会报废。 要找出这个问题,当然必须搞清楚系统挂在了哪里,然后才能寻找对策。因此首先搞清楚系统关机的机制。在Windows CE中,关机操作触发后,下电过程由电源管理模块执行,大概是这样:
- 广播关机消息给关注该消息的Application和Driver;
- 挂起图形界面子系统(GWES);
- 通知所有非块设备驱动(non-block drivers,这些driver可能需要访问注册表或文件因此需要在块设备驱动停止之前处理);
- 给Kernel发送IOCTL_HAL_PRESUSPEND消息(OEM开发商可以利用这一消息做一些关机前处理);
- 禁止除电源管理模块以外的所有其他模块使用注册表和文件系统;
- 通知所有块设备驱动(block drivers);
- 关闭图形子系统;
- 关闭文件系统;
- 调用OEMPowerOff。OEMPowerOff由OEM厂商实现,执行真正的硬件下电操作。