对于软件的BUG来说,扼杀于摇篮当然是最根本的解决办法。尽量编写没有BUG的代码,必要时主动在代码中添加一些异常处理,让程序决断如何处理。很多语言都提供了异常处理的机制,但BUG似乎只能减少,而不可消灭。在嵌入式系统中,由于硬件及工作状态的差异,有些貌似万无一失的代码也常常出现BUG。所以,编写一个完全没有BUG的软件,是我们的理想与追求,但同时也需要我们做最坏的准备。也许某个三更半夜,就会被一个莫名的BUG折腾得焦头烂额。
产品发布之前,会有很系统的测试,包括硬件和软件。对一个产品来说,测试的重要性不言而喻。尽可能在测试阶段发现所有的问题,而不要将这些问题留给客户。前两天听开发组的同事惊呼“这个BUG也被你们发现了,你们的测试功夫实在了得”。原来是他调用一函数时用错了一个参数,测试组的同事愣是把它揪了出来。另外一个关于汉字排序出错的BUG,也被测试组发现了。但要不要改,开发组的几个人争得面红耳赤。最后老邓都有些火了,他的意思是即使BUG再不易重现,客户也许从不会碰到,但只要确实有问题,就得Fix掉。另外的人觉得Fix这个BUG,太繁琐,不值得花太多时间。最后估计还是得听老邓的,发现了的BUG一定彻底解决!但测试也只能是解决一部分问题,毕竟还有可能存在暂时没有发现的BUG。这些BUG最终会在客户手上爆发。
产品发布之后,平静了一段时间,终于有一天,客户抱怨来了,软件有BUG,出现系统崩溃的情况。询问再三,却没有更多的有利于Debug的信息。这不是客户的责任,毕竟他们不是专业的测试人员。要重现这个BUG也非常很困难。不过,幸运的是针对这种情况,WinCE提供了类似于桌面Windows的一套错误报告系统。通过它,我们能把一些软件BUG出现时的情况记录下来,有利于分析BUG的诱因,从而解决BUG。我发现M8似乎就采用了类似的机制,在Disk目录下,会看到一些LOG文件和edb_err.txt文件。
综上,解决软件BUG的问题,有三道关口,第一关,编写代码时,止于源头,第二关, 系统测试时,斩立决,第三关,用户发现后,须立等可取。这三点说起来简单,实际上都有很大的学问,即所谓道,是需要花大量时间,研习许多资料才能了解的。
以上说的是正道,下面再说点旁门左道,也是我目前碰到的问题。产品发布了,有少数用户报告有BUG,甚至发来如上所示的图。系统本身是有有看门狗的,但等看门狗复位系统的时间太长,需要几分钟。由于种种原因,现在也不可能到代码中去找错,有些部分甚至是没有源码的。目前的处理机制是,出现如上所示的对话框后,点击“OK”按钮,程序会关闭,然后另外的程序会再运行该出错关闭的程序。所以,我需要做的事情就是如何跳过这个提示对话框,让出错程序直接关闭。简单分析之后,有两个想法,一个是修改WinCE内核,修改异常处理部分的代码,出现此类异常时,直接关闭对应的进程。另一个是写个应用程序,模拟用户点击“OK”按钮的操作。第一种方法似乎可行,在Windows XP中可禁用错误报告,也可禁用通知,但在WinCE下没找到该开关。所以需要修改内核代码,并重新编译,这感觉有点不妥。第二种方法,直截了当,担心的问题是系统额外的消耗。很显然这个程序得一直运行着,并检测出错窗口,一旦出错,马上将其关掉。如果这个程序的系统消耗很小,那也不失为一个缓兵之计。当然,要从根本上解决问题,还得走正道。
简单写了个Savior.exe,在模拟器上测试了一下,系统消耗基本可以忽略,下图为证,包括了异常出现前后的两个时间段,可以看到,都在0.5%以下。如果能暂时缓解一下问题,这点消耗是完全可以接受的。
在模拟器中,配合Crash.exe测试了一下,基本实现了左道的功能。Savior.exe的源代码如下:
由于Crash.exe是一启动就出错的程序,所以,两个程序一起测试时,会陷入一个循环,出错重启,还出错还重启。在实际的项目中应该避免该情况,可以增加一个黑名单的功能,如果重启次数超过5次,就将该程序列入黑名单,关闭后不再重启。另外,针对出错信息形形色色,可以将其写入到文件或注册表中,便于后续增加错误信息的定义。左道的实际效果如何,还需拿到真机上测试。在某些无头设备中,用户没有办法点击弹出的出错提示框时,左道也能发挥作用,似乎还有些不可替代。
WinCE下应用程序错误的解决之道,漫漫,可正,可邪,须上下求索。