做手机的一点体会
整个android系统是一个完整的生态系统,谷歌提供开放的android平台,下游有各种生产硬件的厂家提供各种手机的硬件,像富士康这样的工厂提供手机的代加工,
然后是高通这样的公司提供手机的核心芯片和自己的解决方案,然后网上做手机的公司,相当于是做一个大的"集成",做手机的公司需要从各种运营商那里拿到订单,然后根据
运营商的需求来做手机,运营商卖好了手机,和手机公司之间分成,或者是 手机公司通过其他的渠道售卖自己的手机,功能要么是全网通,兼容各个运营商,要么是兼容某一个
运营商。相比之下,运营商卖手机肯定是占了很大的一部分。在运营商的上头,就是市场需求,即每一个普通的用户需求,用户对手机的需求(低端 中端 高端),用户对于运营商的选择(联通, 移动还是电信)等等。 这样就形成了一个完整的生态圈。 当然这个生态圈,不止有中国市场,更有北美,欧洲,非洲,日本等等市场。 就我知道的, TCL接过的北美T-mobile运营商的业务,诸如此类,其他的就不细说了。
例如 笔者曾经供职的公司就是 做手机的公司,客户是 大牌手机公司的 第三方公司,例如 是 SOMC TCL 等等品牌公司的第三方公司。为什么运营商不肯把业务交给他们呢?很显然,实力不到嘛,运营商哪能放心地把这么大一块肥肉给你吃呢,再说了,你也吃不下嘛。于是,这类公司,就是 对上要 和运营商接洽,针对运营商的需求,例如:界面设计,稳定性,新功能开发,双卡双待等等新功能,在android源码的基础上进行新功能的开发,开发完了之后,再针对运营商的需求,和测试用例,针对不过的测试用例,逐个解BUG,对下要和高通这样的厂商接洽,在解BUG中遇到的问题,追查到底层,涉及芯片内部的工作等等(因为底层核心代码,高通肯定是不会对外开放的),需要将问题发生的情况提case给高通,帮助一起解决。这样的公司起了一个衔接的作用,而且接活也很容易,上下都可以赚,而且各个运营商的需求大同小异,基本上一个项目做完了,你负责的那一块,例如telephony, bt ,wifi,该改的代码上一个项目已经改过了,现在重新拿过来复用一下就行了,基本出现的BUG也是类似,上一个项目分析过这个问题,现在同样的问题再次出现,也是看看就会的。
还有一个原因就是:谷歌对于android系统的不断升级,笔者刚毕业的时候,android版本最新的还是4.4 现在已经到O了,每一次升级系统,连带着整个生态圈大地震,可以说android系统的升级是整个生态圈齿轮转动的原动力。每一次升级,市面上所有的手机都要跟着升级。
或者是 硬件 或者高通这样的厂商开发了新的平台,例如:硬件可以做的更省电,摄像头可以 做的更小,拍照更清晰,新技术的出现导致硬件价格下降, 新的解决方案可以弥补之前存在的问题等等诸如此类。
总之一句话:硬件和软件的升级 带动整个生态圈向前发展,并且衍生出除了智能手机以外的其他范畴,例如:可穿戴设备,机器人,自动化,车载等等。
说完了生态圈,笔者再来写一写作为一个普通的移动终端开发者的一些体会。
笔者是做android软件开发,专门负责系统里的某一个模块,从最上层的app,到最底层的硬件都有涉及。
平时使用的工具:ubuntu系统,git+repo+gerrit+opengrok+cmweb+bugzilla+jenkins+jira eclipse android studio 使用的语言 java C++ C shell脚本 arm汇编指令 gdb调试等等
简记为一句话就是 测试给我提BUG 我分析BUG,给出解决方案(1.BUG需要提patch解决 2.BUG本身是work as design,就是这么设计的 3.BUG是其他模块导致的,直接踢给别人 4.BUG是由自己之前的改动导致的 5.BUG之前解决了,现在又重新复现了 6.BUG和某一个或几个其他的BUG是同一个问题,原因相同,可以合并 7.BUG是由于高通等等没有及时给出反馈,目前等待中的 等等) 然后测试关闭BUG
平时做的最多的就是提patch 去修复问题,一个完整的patch(组)应该是下面这样
找到问题发生的根本原因,root cause,给出自己的patch,做代码修改,这个改动首先是保证修复当前的问题,编译能通过,这个改动进库后不会引入新的问题,不会破坏其他的模块,代码格式遵循android编码规范,下面逐一说明:
修复当前的问题:这个是最基本的,如果它不能彻底修复当前的问题,或者它进库后BUG的发生概率明显降低,或者问题很难解决,仅仅是为了避开这个问题而做的改动,只能算是临时的workaround, 注意:workaround在平时解决问题也是经常用到的,尤其是 发布前期,或者短时间没有好的解决方案 或者是其他模块没有完成,暂且避开编译问题等等。
编译能通过:这个非常重要,因为android开发是一个多人协作开发的项目。就我现在知道的 就 二三十人开发,遇到编译不过的问题,稍微分析一下就知道是谁的问题了,可以给他提醒,让他马上更改,让编译通过。 但是笔者之前接的活是大牌公司,核心开发团队在日本东京,测试团队在东京和大陆,BUG解决团队在大陆北京(包括衍生的其他大陆城市),部分开发团队在 伦敦, 整个完整的开发和测试在不同的国家和不同的城市,其中时差相隔,用的是同一套系统,发布版本都是自动化编译,并且有不同的分支。 举个例子:我作为其中一个普通的开发者,如果我提了一个编译不能通过的patch入库了,会导致什么问题。自动发布版本的编译系统不能编译出版本,当天所有人在jenkins上想验证自己的patch是否有问题,所有起的jenkins都编译失败而停止了,第二天,所有负责开发的人员来到公司,想验证自己patch的 在jenkins上无法编译,所有的测试想在最新的版本上测试自己的case却因为无新版本发布,他们一整天都无所事事。一个人的失误导致 不同国家不同城市的人 在接下来的1天或者2天都不能按时完成工作。
关于编译能通过:我上面用了一个patch(组), 尤其是patch组,例如你在frameworks层做了改动,在hal层有一个改动和这个是一起的 那么这两个改动要同时进库。或者 为了降低耦合性, 在同一个project下为了修复一个问题,提了多个patch,它们也是要一起进库。
改动进库后不会引入新的问题,不会破坏其他的模块:改动进库后,不会导致本模块有新的问题产生,同时与本模块相连的其他模块也不会有新的问题发生。笔者曾经遇到过一件事:其他模块的人为了解决一个问题,在手机进入飞行模式后,彻底禁用了手机SIM卡,结果这个傻帽导致我这边在飞行模式下想读取SIM下的信息失败了。
代码遵循android编码规范:这个也很重要,好的格式可以让人一眼就看出了改动的部分。尤其是在gerrit上查看时。具体如下:commit message写的尽可能详细,通常写法如下:标题简短的一句话说明修复了什么问题,可以包含模块的名字。内容分为三个部分:一、描述问题,问题发生的场景带来的后果 二、当前这个改动是怎么解决这个问题的 三、列出这个问题的BUG号及来历(例如从其他的patch cherry-pick而来的)。内容部分:命名,括号,空格,代码缩进(一律不用TAB键,而用4个空格),空行等等,总之保持同源码一样的风格,头文件 包名按照字母顺序从上到下,不该加的空行 空格一行一个都别加。
好记性不如烂笔头,经常做笔记。
最后一点 解决问题的思路:
1.所有的分析都是基于代码和log 不要凭空猜测和捏造
2.对于和其他模块相关的,发现是自己的问题,就不要推给别人,更不要自己做了改动影响别人,推给别人的问题一定要基于log有自己的分析,有理有据
3.在解决某一个问题时,发现除了这个问题,还有异常的log,也要分析异常的log,不要测试没有报出来,就了事
4.解决BUG的最好方式就是从源头上根治,就是新添加的代码不要影响原有的功能
5.实在解决不了的问题,最简单的办法就是做回退测试,找到差异的patch, 进而找出原因
6.除了自己负责的部分,与自己相关的部分也要熟悉
7.多与其他人交流,不要自己闷在那里对着log毫无头绪
8.按照上述 提一个好的patch(组),除了自己严格要求自己,还要将相关的人加进来review你的代码和patch
9.很多其他的模块的patch 自己可以review别人的代码,来提高自己
10.生活永远比工作重要,不要为了解BUG而熬到深夜