最近做了一个android monkey test到symbian的移植。算是草草学习了一下symbian系统吧。写一些东西做个记录,方便以后自己查阅。
symbian系统最有意思的设计应该是这个Active Object的设计模型了。他使用非抢占的多任务模型,固定优先级。这个非抢占我一开始理解得不够好。后来做monkey的时候,用的console程序。想在里面用CActive做进程监视,发现他的RunL函数永远都无法进入。跟公司的symbian大牛也讨论了好久都没有解决问题。最后还是自己悟了。这个所谓的非抢占,就是说你console的主函数不退出的话,这个Active scheduler是不会调度的。之所以那位大牛写的demo可以运行起来,是因为他用的是窗口工程,在一个窗口回调函数里面调用的SetActive。窗口回调函数退出之后自然而然Active scheduler就会调度了。而且估计这个窗口消息的处理,symbian也是采用Active Object来实现的。
我本来以为,只要我在主函数里面调用一个引发调度的函数就好了。我想当然地调用了sleep函数,然完全没有效果。还有后来改用User::After函数,也完全没有用。我后来想,论坛上经常有人提醒说,这个User::After函数是同步的。究竟有多同步,这我才知道了。就是说他也是不会引发AO调度的。这样一想也是可以理解的。因为他说的是非抢占嘛,就是说如果你睡眠了把CPU让给别人,等你到了该睡醒的时间,别人正在运行,那你就没有机会再把这个CPU抢占回来了。假如说做成双方都可以互相协作让CPU的,那基本上就算是协程了。这里的AO,如同网上一些讨论一样,应该算是“纤程”吧,可惜还没腾出时间去仔细研究他。本来想仔细去研究一下AO调度,究竟哪些函数(确切的说应该是系统调用)是可以引发AO调度的,但毕竟还是公司的任务优先吧,这个没有去细查,用了另外一个进程,乖乖写成窗口程序来做了。有机会的话以后再来改吧。
Symbian另外一个有意思的设定就是process崩溃之后不会立即退出。而是会继续保留一段时间,之后系统会把这些死进程统一回收。一开始还不是很理解他为什么要这么做,可是后来做进程监视的时候就发现,这个设定非常好用。你可以在进程崩溃之后,再去遍历系统的进程表,然后找到有问题的进程(他的退出码会是负数),然后找到具体的错误原因。其实这个工作就叫做“验尸”,而且symbian也提供了一些验尸工具去帮助调试。这样就给了系统调试很大的自由空间。否则的话,必须在一开始就确定监视哪些进程。假如有些进程,例如我现在在调试的这个(哔—),他是随着用户操作过程中而时而启动时而退出的,你很难去一直捕获着他,去监视他的运行情况。
还有一个就是本来对于symbian程序员来说是司空见惯的东西吧,就是这个清除栈CleanupStack,还有对象的所谓二次构造,以及symbian自有的一套类似于try catch的机制,是用的Leave和trap来实现。这些东西应该就是symbian的系统特点了吧,其他系统上是绝对见不到这些东西的。从异常安全的角度来说,这个二次构造真的是合理的设计吗?我觉得也不见得。不过他配合清除栈的使用,确实能够保证内存泄漏。这在内存紧缺同时开机时间甚至可能长达数年的嵌入式产品来说,的的确确是至关重要的。否则即使是非常微小的内存泄漏,假如连续开机数年(这里肯定不是手机啦,比如说是电冰箱咖啡壶什么的),还是会引起系统崩溃的。
最后就是监视到进程崩溃如何获取调用栈信息的问题。本来的想法甚至是去获取CPU寄存器的值,然后根据可以得到的线程列表中获取到的堆栈地址的信息,配合编译过程中生成的.exe.map,进行函数地址对比,从而得出调用信息。后来发现这种事情不用自己去做(而且在用户这个层次应该是很难获取到CPU寄存器的值的吧)。symbian提供了一个很好的内核调试工具,d_exc.exe,可以在系统中有任何进程崩溃时记录调用栈信息。需要的只是去把这个程序在测试开始之前运行起来就好了。至于symbian的内核端调试,nokia wiki上有一篇很好的文章,我还没找时间好好研究,这里也先记在这里kernel side debug。
好啦今天的笔记就做到这里。并非是API介绍,假如说有人有兴趣想知道具体的内容的话,这里特别推荐的是nokia官方论坛的wiki,内容非常充实,对于我这样的初学者来说,非常有帮助。
例如这篇process monitor,还有这篇process and threads, how to find them等等。