测试的自动化虽然产生了大量的测试样本,使问题重现变得容易。但是问题的根源并不因此变得显而易见。要找出问题还必须做一些跟踪调试和测量。但是在这么底层的地方,软件级的调试器显然是没法用的,基于JTAG的硬件调试器的intrusive本质,会影响信号状态,因而也不应使用。能够利用的只能是通过示波器和逻辑分析仪直接测量管脚的信号状态。做了很多对比实验,对主板上一些信号测量的结果表明出现问题时,CPU的一些GPIO管脚状态和我们的预期不符。

  比如说有一根GPIO管脚控制着LCD背光,在关机时它显然应该处于使背光关闭的状态,但是出问题时偶尔却会处于打开状态。这似乎表明在关机时它的状态失去了控制!随后更多的实验表明不单是这只管脚,其他管脚的状态似乎也不受控制!这是一个很严重的情况,因为GPIO控制着很多重要的外围设备,如果失去控制,会导致设备的物理损害甚至危害到人身安全。

  比如有一根GPIO管脚控制Flash memory的可写性,失去控制将会导致Flash上的软件系统损坏,使整个设备变“砖”。我们测试的时候也真的出现了这种状况!由于系统关机也由 GPIO控制,看起来这个问题的根源可能在这里:GPIO在关机时失去控制,导致整个系统陷入未定义状态,关机操作无法完成。那么应该怎样避免关机时 GPIO的状态混乱?有人提出一个解决方法,在关机前把这些处于输出状态的GPIO设为输入,这样GPIO的状态由外部电路决定,也许能解决问题。这个方案貌似合理,但是实验结果表明问题依然存在。绞尽脑汁地思考,有人提出另外一个想法,GPIO状态的混乱可能是由于CPU的Core电压突然掉电引起的, 因此可以在关机之前先让CPU进入sleep mode,在sleep mode中这些输出管脚的状态可以由PGSR寄存器设定。之后再掉CPU Core电压应该没问题。后来的实验证明了这种想法是正确的,我们确实观测到了CPU Core电压在掉到1伏多的时候有一个关键的GPIO管脚状态发生了翻转,导致本该接着往下掉的CPU Core电压又升上来了,于是后面对主板下电的动作也没法执行,而且这时CPU似乎进入一种未定义状态,系统在这里挂住了。

  随后大量的自动化测试也证明了让CPU进入sleep mode是正确的解决方案。到这里解决方案已经找到,但是随着而来的问题是:CPU的内部状态不可控制,显然这个问题无法可靠重现,那你怎么验证你的解决 方案呢?换句话说,做多少次重复实验才能算通过,这个标准在哪里?100次够不够?还是1000次甚至10000次?这个问题没有标准的答案,我个人的标准是,先测出问题发生的概率水平(以我的经验,这种随机的BUG一般都有一个比较稳定的概率),解决方案的测试次数必须比这个概率高一个数量级才能算基本通过;如果测试次数能提高两个数量级,我会对这个解决方案非常有信心。

  在这个例子中,我们测出来的概率水平大约在1/2000(这种概率水平的问题在 LAB里很难发现,但是在用户那里又很容易出现)。后验证方案的测试大约做了十几万次。

  总结:解决一个问题,对技术细节不清楚不重要,重要的是要有清醒的头脑和解决问题的方向感,也是说任何时候你都应该知道下一步应该做什么。其实我在接手这个问题时,对嵌入式系统还很陌生,我甚至都不知道有脉冲发生器和逻辑分析仪这种设备,对ARM架构和WINCE都一窍不通,但这并不影响我对问题的分析和思考,随着研究的深入,技术细节可以通过翻阅资料和与同事交流慢慢获得。一般来说,我解决问题的思路是这样的:对问题产生的原因进行猜测,根据猜测提出 解决方案,然后设计实验证明或者证否方案,再基于新的实验结果进行猜测,提出新的解决方案,逐步缩小范围,归纳出其中的规律。对于随机BUG,我的思路是 一定要针对问题设计自动化测试;确定问题出现的概率水平;验证解决方案的测试次数必须比问题出现的概率高至少一个数量级。