显示标签为“总结”的博文。显示所有博文
显示标签为“总结”的博文。显示所有博文

2013年2月27日星期三

Fwd: Android(程序)性能分析 Traceview



Android(程序)性能分析 Traceview



  • 介绍Traceview
     “Traceview是android平台配备的一个很好的性能分析工具。它可以通过图形界面的方式让我们了解我们要跟踪的程序的性能,并且能具体到method。”
     Traceview程序是(Eclipse)android开发环境自带工具存在...\android-sdks\tools\;
     Traceview图形界面如下: 
     
图1. Traceview界面
   

    •      a. 时间轴面板
          显示不同线程的执行情况,线上有不同颜色部分是代表线程执行不同函数。右上角显示时间轴的时间总长,左上角显示当前选中时间点的性能数据。
          注:在图形上点击鼠标拖拽就可以有放大效果,恢复原图只要双击最上面的时间轴横线即可。


    •      b. Profile面板
          纵轴显示程序执行到的不同函数。横轴显示对应函数的性能数据,包括这些字段:Incl Cpu Time %,Incl Cpu Time,Excl Cpu Time %,Excl Cpu Time,Incl Real Time %,Incl Real Time,Excl Real Time %,Excl Real Time,Calls+RecurCalls/Total,Cpu Time/Call,Real Time/Call。
          大体上介绍一下以上字段含义:
          Incl是Inclusive(包含的),表示该函数的调用包括所有子函数的调用。
          Excl是Exclusive(独有的),表示该函数的调用仅包括基本操作,不包括子函数的调用。
          Cpu Time,就是真正在占用CPU的时间,Elapsed Real Time = CPU Time + Wait Time。详细参考http://en.wikipedia.org/wiki/CPU_time
          Real Time,就是时钟计时的时间(时长)。
          "Elapsed real time is always same or more than CPU time for computer program which use only one CPU for processing. If no wait is involved for I/O or other resources, elapsed real time and CPU time are very similar."
          %,占有的百分比。
          所以,字段“Incl Cpu Time %”就表示对应函数的Cpu Time在整个时间轴的函数调用中占的百分比。


    •      c. 搜索框

     搜索框根据函数名称搜索显示对应的性能数据。

还有,可以参考Traceview 官网说明 http://developer.android.com/tools/debugging/debugging-tracing.html


  • 抓取分析数据
     上面内容介绍了Traceview工具,光有工具而没有分析数据,哪来的性能分析。所以这部分内容讲述抓取分析数据。
    该部分说明如何抓取分析数据,即创建分析数据文件(Trace File)。其方法有三种:

    •      1. 使用Eclipse的DDMS功能
         该方法是最简便也最实用,没有之一。而且不需要去修改代码也不管程序是否有读写SDCard权限(如方法2)。具体操作如下:
          a. Eclipse切换至DDMS页面,选中需要分析的程序(如xlwireless.wirelessadhocnetwork),点击右上角按钮“Start Method Profiling”,如下图:

          
图2. DDMS启动Traceview

          b. 停止操作时点击同一按钮,则Eclipse会自动弹出中Traceview图形界面,直接显示了Trace(文件)的分析结果。
          c. 若想保持分析数据(trace文件),只要操作Eclipse菜单File -> Save As ... 即可。
          的确是实在太简洁的操作吧!

          注意:该方法不支持Android 1.5设备,Android 2.1或更早版本需SDCard机器权限,而Android 2.2之后即使没有SDCard也行。(引用自官方说明)
    • If you are using DDMS, Android 1.5 devices are not supported.
    • If you are using DDMS, Android 2.1 and earlier devices must have an SD card present and your application must have permission to write to the SD card.
    • If you are using DDMS, Android 2.2 and later devices do not need an SD card. The trace log files are streamed directly to your development machine.


    •      2. 使用Debug Class代码添加功能
         MainActivity的OnCreate方法添加:
  Debug.startMethodTracing("xl-adhoc-trace");
         MainActivity的OnDestory方法添加:
  Debug.stopMethodTracing();
         或者,你也可以换成在MainActivity的OnStart与OnStop方法。有人出现这样情况:“但是在实际的测试时发现这种方式其实并不好用,因为通常情况下我们的activity的onDestroy()是由系统决定何时调用的,因此可能等了很长时间都不会得到这个trace文件。因此决定在onStop()中来调用Debug.stopMethodTracing()。这样当我们切换到其它activity或者点击home键的时候onStop()就会被调用,我们也就可以得到完整的trace file。”

        使用该方式获取trace数据需注意:程序须有SD卡读写权限,当然还有代码权限。
        程序运行结束后,会在SD卡下生成对应trace文件(如xl-adhoc-trace.tracing),使用adb pull命令拉取trace文件或其他可视化拷贝都可以。


    •      3. adb 命令行启动
        命令如下:
         adb shell am profile start
         adb shell am profile stop
        但该方法没有去做过尝试。



  • 分析性能
     工具 + 数据 = 分析结果

     通过已保存有的trace文件,用命令行启动Traceview分析程序性能。
     1. 把Traceview目录添加到系统的环境变量Path,如c:\users\<user-name>\android-sdks\tools\;
     2. CMD命令行:traceview  ***.trace (注意:全路径的trace 文件,否则可能不行)。
     3. 自动弹出traceview图形界面,通过这个图形界面就开始分析程序的性能。

     结合图形,做简单的示例分析:
     a. 日志版的自组网程序刚启动时间(2s左右)的性能结果:
         
         从上图分析结果:打印日志的逻辑占了程序性能很大比例。

     b. 非日志版分享文件时的性能结果:
          
          从上图分析结果:可以优化的地方包括Wifi列表更新操作的refreshWifiScanResult,文件分享(发送方)的onRequestFileRange。


  •      具体函数的分析
          针对分享文件数据(上图的)详细分析一下,查找refreshWifiScanResult与onRequestFileRange函数在具体地方占用其性能比例在哪里?
          见下图显示,用红圈标注出了性能的关键地方。
          
          
          
          

     
(完)

2012年12月15日星期六

另一种“荒野求生”

另一种的“荒野求生”
  源自知乎的一个话题(问题)。


  • 话题:

五年编程经验,跳槽到新公司后,月薪 6000 元,但工作内容就是写注释,写了一年注释,这种情况在编程行业普遍吗?

我有五年的编程经验,其中一年是实习,其余四年在一家小公司做外包。由于我不习惯公司整天把我外派到别的公司做技术,于是我就跳了槽。
现在这家公司是一家所谓的大企业,已上市,技术团队几百人,公司名字就不说了。月薪6000元,我上一份工作月薪是4500元。
但工作内容就是给代码写中文注释,整天就是跟//打交道,写了一年注释。
我另一个同事更离谱,整天看代码然后用txt文档记录可能出错的地方,别说开发,他一年多都没配过ide。就算他找出错给总监,总监也不理,测试那组几十个人,也轮不到他,他找到的人家早就找到了。
现在这份工作总的来说,能看到别人写的非常牛X的代码,很多非常牛X的算法,但没有办法参与到开发过程中去,该不该跳槽?首先我承认我技术不如别人,但同样拿6000的很多人都在做开发。

  • 一楼:
从描述看,这是一家“荒野求生”型公司。这样的公司特点是,新员工被仍在一个荒岛上自生自灭,优胜劣汰之后,剩下几个“幸存者”都是技术和性格非常强悍的人。
这类公司挑战员工的有:
1. 目标感,不告诉你什么时候来救你。你必须对长期在岛上生活做充分的准备。一个明确的目标使得你不至于放弃求生的希望——我要学习什么样的技术;
2. 发现食物的能力,没有现成的吃得给你,你必须把各种野菜变成食物充饥。
3. 竞争意识, 食物少或者没有食物,大家必须靠抢夺食物为生。你必须要主动的解决项目中暴露的问题,而不能等待它 assign 给你。
这样的公司不是适合所有的人。但一旦你挺过来了, winner 的感觉会伴随你以后的工作。



  • 二楼:

我觉得你对自己的定位有问题,说白了只能说你是个合格的员工,公司叫你写注释你就只写注释?
如果你以这种思维跳槽,你到其他公司也不会有大的发展,我觉得你在这岗位上应该突破自己的职责做出些贡献。
比如现在的岗位
@梁涛说的:“要是你把所有的代码和注释画成流程图”,那公司肯定把你奉为牛人;
另外你通过看代码可以了解这个产品和系统最核心的东西,也许你可以发现缺陷,提供改进方案;也许你可以从某个方面设计出优化系统的办法;公司一定会给你更合适的岗位;

你还可以通过看代码了解代码编写者的能力和缺点,在你对每个人了解后很适合在以后提出好的意见,也很可能获得提升走上管理岗位;
......
太多了,努力吧,哥们;


(其他评论)……


  • 我的评论:
看了楼主的问题,还有楼上诸位的一些评论!我也在此说几句吧,希望可以给楼主一些好的意见!
均同意一楼和二楼的意见,小总结一下:
1, “荒野求生存”,你需要更加主动给自己想主意啊,把事情(理清代码逻辑,不单单是添加注释)做全面、精彩了!挺过来了那么你的“生存能力”必然很大提升!
2, 明确你的定位,@yaocoder就举出了几个方面颇好!
还有,一些我的感触:
a. 楼主现在的公司环境还算比较宽松啊,可以分配给你这么一闲差。既然这样,好像更有空间给自己充电啊!
b. 都五年的编程经验了,你一定可以有更好的发展的,完全不局限于此!加油。
刚好,昨晚在微博转发了这么一条:
#管理者说#无论你从事哪一行,你都不只是别人的员工——你还是自己的职业生涯的员工。——曾任英特尔公司董事长安迪·格鲁夫(Andrew S·Grove)


补充一下:
不要单单局限于当下的简单工作(任务),尽量发挥自己的主观能动性吧,适当有点危机感,营造另一种“荒野求生”吧。何况现在自己还很年轻,对自己允许苛刻一些,不枉少年!
有的人会说,“人生不必太累了,何必呢?“ 哼,苛刻不代表就累了,真的。恰恰很多人也这么说,“每当回忆过去最美好的时候,都是那些吃苦的日子。”

(完)

2012年12月5日星期三

做技术,做深做透,不急不躁!


做技术,做深做透,不急不躁!
===
故事从这里说起,先引用RTX内容如下:
---------------------------
longshen 17:04:08
刚刚测试了下motorola电信定制版,创建软AP问题。
主要是其WifiConfiguration比其他多出 wifi_ap_gateway、dhcp_start_addr、dhcp_end_addr 三个字段。
需要用reflect进行设置,否则会导致motorola重启。
设置这三个字段后,motorola可以创建软AP,正常通信了。

team leader 17:04:31
好的,幸苦了
team leader  17:04:44
以后我们技术,就参考快牙和快传吧。
技术这东西,还是努力做深做透彻,不要急于做结论。
有个学习和深入的过程。

junkunhuang 17:05:46
嗯,我当时没做深入进去。


===
今天,在工作上遇到一件尴尬的事情,不妨在此讲述故事并做小小的总结一番,与大家分享。虽说当时让我有点儿找不着台阶下的感觉,TL说的那些多少是落在我份上的,但我不得不承认先前我没保持足够的好奇心与专注把功能做深下去做好。

数月(2-3月)前,繁忙于无线项目开发工作,团队人员稀少(加上Team Leader共5位),分工明确且任务繁多。干活如打仗似的一场续一场的
……
当时我负责做Android系统的Wifi热点功能主要包括创建于关闭热点,得到的解决方案除了那台MOTO电信定制机(系统),都可以在其他机器上正常完成功能。开发时间仓促,当时与TL沟通后,最后就索性判断,若系统为电信定制则认为不支持该功能(创建Wifi热点)。
……
过了数月,突然发现某一流行的应用竟在那台MOTO系统上顺利创建热点,完成数据传输。那一定是我们的程序做的不完善,遇到的问题没有给予解决。
继而TL与longshen就该问题讨论起……在longshen同学很给力地进一步“追踪”尝试之下,最终顺利找到了电信定制(android)系统的私有窍门。
再然后我便知道了这事情,当时甚为尴尬,像犯了过错似的。我想最好把这件事情当是一课,记录下来提醒日后自己做事严谨,同时分享大家!

===
最早的时候,或许保持足够的好奇心与专注继续探究问题下去,那么只要一两小时的事情,问题便得以解决!不会有今日之尴尬,早知今日何必当初,所以谨记:做技术,需做深做透彻,且不急着做结论!稍作修剪作为文章标题:做技术,做深做透,不急不躁!
感谢你们,我的团队,我的战友们,我的TL!

(完)

2012年10月31日星期三

艰难项目(二)


  • 艰难项目(二)
    • 故事(段子)篇


  • 段子一
2012-10-12 Google+ 上的一条微博,如下:
“唉!领导疯了,进度疯了,任务疯了,我疯了,工作疯了,生活疯了!我的状态没了。威总是幸福的孩子!”


PS. 以下内容,从(引用)TL说过的话说起,算是些不经意的言辞吧脱口而出的,其实没啥不必太过在意,在此就只是讲故事罢了,不如说剧情需要吧。
  • 段子二
时间是晚上十点钟左右,大家还在公司工作着,也差不多一日的工作安排(任务)接近尾声了,TL说道“差不多了,大家早点回了吧,早点休息。”
     -- 都TM晚上十点多了,还早点呀,有没有搞错啊。
听了TL说了几次,总觉得怪怪的,后面干脆回复了,“都这时候了,还早点啊。”哈哈,TL想想下却是有些不着调了。其实,跟TL一直关系很好,这么回复他一下,不碍事的。

  • 段子三
国庆节假,提前三天(10-05)到了公司上班,没有加班费一说,最后只能是后面工作事情不多了争取调休回来吧。接着就是连日连夜加班两天,晚上都是到了十点回家的。原来期待着10-07最后一天的假期可以休息一下,结果TL看着项目进度不够排期还是很紧,“照现在的项目进度,我们明天继续加班!”。怪不得,长假一回来TL就跟大家打了预防针,打了鸡血(其他没啥鸡血),后面我们有硬仗要打,希望大家努力做好工作同时又照顾好身体!
连续三天加班,然后第四天直接工作日上班了,再连续六天的上班,苦逼倒了,明天是最后一天的!哎呦呀,现在看来这“后面”到底啥时候是个头啊!闷头继续努力吧,兄弟们共勉。

  • 段子四
“最近公司很重视无线项目,公司四处调人往无线事业做项目,看得出倾力在做这个事情。努力做好这个项目(无线组网),大家都会有好处的。”
唉,听着这样的话,也照这样想只自我安慰了!不然箭在弦上不得不发,就是这种感觉了,别无他法!加油吧。虽然如上说的,听着有着那么忽悠人的感觉!我们已经苦逼很久了,连续的加班至晚上十点之后,这样的日子将近三月了,苦逼艹!

  • 段子五
“辛酸史”是这样的:
     2012-08-13 开始从事无线组网的研究与开发,首先从Android的Wifi-Direct(Wifi P2P)入手,同时研究智能手机的超声波传输数据。我们为了尽快做出一个比较理想的Demo,希望可以得到CEO以及其他领导们的看重与支持,顺利加入基础研发中心项目并领取津贴。项目组加上TL一共五人,为了这个目标奋战了一个月多。如何奋战呢,这期间多得是会议讨论与头脑风暴,然后各种编码各种尝试。从刚入门Android开发起,三天时间就开始项目开发了(虽说是已有了Java基础)。每天天晚上加班至十点半,没有周末,仅休息一天(虽说后面可调休回来)。
     接着,2012-09-10(周一) 在基础研发中心的月报告会议中,我们的Demo演示和TL的PPT演讲均顺利,并得到老板的鼓掌(认同)。当时心想既然CEO认同了,那目标有望实现了,顺利领取加入基础研发中心项目并领取津贴。
     然后,万万没想到的结果就在之后第三天(周三)TL接到上层领导通知,要求我们团队直接调往无线事业部参与无线项目的开发工作。这样情况,那个目标就只是泡影了,与津贴无缘。而且是CEO发号施令,要TL搬到他的办公室,我们必须再次搏一把努力一回,正所谓”箭在弦上不得不发“,别无他法。引用同事的一句话,“距离心脏最近的血液就越是新鲜。” 要明白,这是用来打鸡血的~!要吧,兄弟们,继续努力,后面的机会更多,面包有的,金子银子也会有的!
     ……

(完)


2012年10月18日星期四

艰难项目(一)


  • 艰难项目(一)
    • 谈谈艰难项目中团队协作的项目管理感悟

    • 前奏
      • 2012-08-13 开始从事无线组网的研究与开发,至今(2012-10-18)已两个多月,整个项目组成员(加上TL共五人)为了项目还一直在奋战,周末若单休已很奢侈了,恰逢国庆长假而提前三天(2012-10-5)回到公司报到继续加班,然后不休息继续开始正常的工作日上班至周六(2012-10-13),连续上班九天下来。两月多上班的晚上几乎都是十点后下班的。后头想想,我们都是被狠狠打了一把一把鸡血的,而无怨无悔。“路漫漫其修远兮,吾将上下而求索。”
      • 这样的高强度的工作压力与十分紧凑的项目进度,结合同事间团队协作以及项目管理者(TL)的项目推荐工作,在此仅做尽可能简单的工作总结。其实不该叫工作总结,工作感悟会比较贴切一些。详情如下,开始吧。
    • 情节
      • 额,该如何形容上面说的最近艰难的项目呢,想想:
几个形容词:
紧张,紧凑,高压,努力,艰难,浮躁,激动,发泄,不满,体谅,坚持,……
几个名词:
领导,项目,进度,任务,排期,版本,文档,方案,会议,团队,情绪,Demo,夜晚 ……
几个动词:
赶,计划,推进,讨论,争议,加班,编码,调试,连调,解Bug,重构,协调 ……



    • 感悟
      • 额,艰难的项目开发中,得有几点感悟,说说:
1. 模块清晰,分工明确。
     尽快对项目的开发与测试工作进行模块划分。
     这些划分就是服务于后续项目工作给同事们的分工,需保证项目具有持续、并行的进展。

2. 严格把控项目进度。     
     该点最为重要,项目管理者需要明确分配任务,并知道每位同事现在手上的任务及进度情况。做好项目推进工作,若意外出现了滞后部分需及时协调过来。

3. 营造紧张而顺畅的讨论范围。
     紧张,问题讨论紧凑,针对性强,尽快解决。顺畅,讨论过程彼此理性对待问题,保持和气。
     会议或讨论时候需控制好各自的情绪,免得伤了和气。否则难免影响到大家的士气。
     都是同一条船上战斗的,和气很重要。伤了和气,很容易削弱团队士气,打击同事的积极性,影响大家协同工作,难免会滞后项目进度。种种坏处在此就不多描述了,你我想想便知!
     这里,我与TL有过几次的情绪冲突,事后想想其实没必要。还好,俩人都是性情中人,除了上下级的同事关系也是好朋友,乃良师益友。

4. 领导与下属关系融洽。
     最好,保持与同事们的沟通。有障碍则尽快化解,可能有时领导需委身妥协,有时下属需多多谅解领导。

(待续)……

2012年9月13日星期四

高管VP会议什么样子!

高管VP会议什么样子!
     -- 公司VP会议初体验心得.20120828.AM


20120828的上午,已经是一个难忘的时间了,一次至今难得的体验经历,虽然这种经历不是令人所爱的。
经历情绪波折,百感交集(夸张了点:D),欲知详情,且听下文描述 ……

简单的故事情节如下:
     由于项目工作需要,有幸跟着Team Leader一起到公司高管会议报告项目进展与Demo演示。而我们其他兄弟几个仅是赶场旁听,就坐在后面的一排的角落位置。

     公司大老板对于报告表示了不满,提出了几点批评与建议。直接的说其情况就是我们几个兄弟在后面看着TL在上面挨着老板的批评,场面挺尴尬的,我们在会后都有些佩服TL可以这样挺过来呢,不容易了啊!我们心里当然都很不爽不开心啊,毕竟这段时间确实努力地辛苦地付出。可能方向错误的原因吧。大老板与TL之间其实还隔着两三层的组织关系呢,领导的想法与我们的行动达不到一致。
     其实,这过程我心里有些紧张的,有这样的假设,上面TL若是我,我将什么个情况 …… 负责的心情啊。

     由于PPT报告结果不理想(糟糕的),所以我们没有做Demo演示,拿不出台面有两个原因:
          1. Demo程序过于简单,演示效果不明显。
          2. Demo的功能点与CEO & VP们的期望不一致。

     最后,总结几点关于CEO以及VP们对于项目报告的期望点在哪里,包括:
          1. 功能新颖的Demo演示。个人觉得这里可以不必太追求程序稳定。
          2. 配合简洁的(加漂亮的)PPT演说。功能点说明清晰,可借鉴乔布斯的产品发布演示视频。
          3. 搜集罗列说明下业界相关的产品情况与技术进展。
          4. 尽量不要展望(画饼),要低调。不过,可私下与CEO交流。
          5. 涉及到开发实现的东西,一律不必在PPT或会议提及。

     作为基础研发的项目,老邹(CEO)强调要基于未来一年两年之内的产品发展方向,而非从事当前产品研发,但可从现有产品中存在的问题,难以一时填补的问题摄取出发点,着眼于未来一两年时间。

     有幸见识到公司CEO主持会议的风范。但也总听说起他一贯的霸气,有点‘独裁’的说辞,其他的较多的旁听的份儿。小辈子的我们,确实可以从中学习到很多东西。以上描述到的这些心得总结,算是其中一小部分。


     后续努力,同事们再接再厉吧!

--
     20120910.PM 续
     “今天下午在项目汇报研讨会上,我们的项目汇报进展顺利,接近满意效果。能拿出来演示的基本都顺利在DEMO演示效果表现出来,而且我们TL演讲效果良好,所以整个项目汇报效果比较良好。至少我们这么觉得,包括身边的其他开发同事以及HR同事。”

(完)

2012年8月21日星期二

Android开发笔记(一)


Android开发笔记(一)
     -- 入门新手篇


1. android开发环境的搭建。
     a. Eclipse 官网链接,选择下面两款安装包:
Eclipse IDE for Java Developers
Eclipse IDE for Java EE Developers,
          下载页面链接

     b. JDK,下载页面链接 。
      选择更加稳定的,适用于android开发即可,我现在(201208)选择的是 Java SE 6 Update 34。

     c. android开发SDK 链接
     Eclipse IDE有这样的功能,你提供url链接,IDE会自动获取android sdk,安装并更新。

     PS. 整个环境搭建的流程可以参见某博客:链接1链接2

2. android开发文档
     a. SDK官方文档,链接
     b. 几篇不错的PDF文档,罗列如下:
Android开发指南中文版.pdf
Android中文翻译组——Android中文API合集(7).chm
Android基础教程.pdf
Google Android开发入门与实战.pdf
Google.Android.SDK开发范例大全.第2版.pdf
wifi无线网络协议(链路层)
IEEE Standards 802.11-2007.pdf
wp_Wi-Fi_Direct_20101022_Consumer_Simplified_Chinese.pdf
802.11无线网络权威指南+第二版(中文版).pdf
还有,建议网上搜索《android开发视频教程》下载。


3. android编程开发基础
     a. Java 语言基础。参考维基,链接
     b. 面向对象技术。参考维基,链接

4. android程序的几要点, 包括:
     a. Activity, 为用户操作展示的可视化用户界面. 包括所有android程序界面.
     b. Service, 提供用户允许提交给系统后台允许的android服务, 如后台播放音乐, 后台下载.
     c. BroadcastReceiver, 广播接收器是一个专注于接收广播通知消息, 并做出对应处理的组件.
     d. ContentProvider, 内容提供者将一些特定的应用程序数据提供给其他程序使用, 用于跨进程间的数据通信.
     e. Intent, 其对象保存着消息的内容, 以异步消息的形式可以激活activity, Service, BroadcastReceiver对象.
     f. AndroidManifest.xml, android程序的一个很重要的配置文件,比较简单,值得研究.
     g. 不能在主线程(即android UI线程)以外的线程里创建AsynTask实例,引用API里的原话“The task instance must be created on the UI thread.”。
          类似这样的错误,程序会抛异常如:CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
     PS. 以上描述内容可参考《Android开发指南中文版.pdf》的详细说明。

5. 网络通信
     android网络通讯编程涉及内容包括wifi, wifi-direct, 蓝牙, NFC, 3G2G等.
     参见官网SDK的API说明,链接
     相关的Android程序示例,在安卓巴士网站上围观看看,链接

     注意:目前(201208)以上的网络通讯操作,需要在android真机上面运行测试,模拟器上暂没有支持这些。
     
6. 调试工具
   首选DDMS,android手机以调试模式连接开发机,方便调试的程序在Eclipse输出Log, 有助于调试程序。关于DDMS说明可参考链接1链接2


 笔记. 20120818. Junkun Huang.
(完)

     

2012年8月11日星期六

一个设计漏洞引发的故事


一个设计漏洞引发的故事
     -- 根据链接URL的字段值判断采用的下载调度策略


讲故事吧,想说明一个漏洞案例是具体如何被触成的而已。引以为鉴!
“秦人不暇自哀,而后人哀之;后人哀之而不鉴之,亦使后人而复哀后人也”

==
2010年,为了节省会员CDN带宽与服务器压力,在客户端程序针对会员CDN的连接,做了流量优化的下载调度策略(保证速度的前提下尽量少去CDN请求下载数据),以达到目的。
PS. 会员CDN即XL公司自己架设的服务器专门提供给迅雷会员加速下载的。

诶,好不容易做了一套效果勉强还行(?)的策略,成了。就这样!那时候我才刚刚接手下载调度模块,显然策略的设计者不是我,而是跨部门A的某同事,但是后面我就一直充当其维护者。
题外话:由于某下载调度老前辈升职去了其他部门A结果就顺着带下载调度模块过去,而我当时任务就是尽快熟悉下载调度并拿回来下载调度模块……

当时,百思不得其解,优化策略其中的一奇怪逻辑判断该资源来自于会员CDN根据其URL是否包含某字段值。 如:
若下载资源对应的URL包含关键字段为"xxx.vip.xxx",则任务该资源为会员CDN,即参与资源流量优化调度策略。
不明白为啥这么做,我也问过相关同事(跨部门),得到的说法只是设计简单实用。

好吧,程序就在那持续的跑着,没问题。

====
2011年,刚好另一部门B的其他下载产品同样需要做流量优化。该部门的某同事偷偷在其他同事那边打听到了上面描述的”奇怪逻辑“。然后,他就在其产品的下载任务URL上面增加了关键字段"xxx.vip.xxx"。唉,恰到好处确实可行。我估计,该同事当时肯定偷着乐到了。(其实我是事后2012最近才知道这事情的。)
好吧,程序就在那持续的跑着,没关系。

====
2012年,(上面提到的)另一部门B发现那套优化策略已不适用,存在不合理地方,主要由于其产品演变包括用户数剧增,产品特性变化等。既然不适用了那么就需要找人继续优化了。找谁,找其他部门因为他们不持有该策略的研发(downloadlib),正是我现在所在的部门。
经多方面讨论,决定使用已有的那套优化策略服务部门B的CDN,为节省器服务器带宽。这样的决定,说明了我们都不知晓“2011那段故事”。
直到我们完成了功能的开发设计,在做程序连调时候无意间在LOG上发现存在怪异情况,即使没有新加的逻辑,程序也已经在为部门B的CDN资源做流量优化了啊。
……在此省去很多气愤与无奈的表达……
最后,召集大家一起讨论,说清具体事实情况,才知晓了“2011那段故事”。
其实,那套流量优化策略不仅在为部门A的会员CDN服务着,还默默地为部门B的CDN服务着。

好吧,程序就在那持续的跑着,没关系。

====
显然,那奇怪逻辑就是一个设计漏洞。很容易被外者利用以触发原本不该走到的逻辑。还好上面说的外者是自家的兄弟部门。
若是外面其他公司的CDN知道该漏洞,并加以利用了,那么我们不就白白为他人做了巨大的省钱活儿了吗!
所以,需尽快改正回来!

(完)

2012年8月6日星期一

谈谈团队建设


谈谈团队建设
     -- 有感于XL下载库团队


最近半年时间下来,在某些方面(团队良好建设方面)隐隐觉得总有或多或少有些体会与感悟,(题外话:有时疲惫的时候脑子装东西多,容易浑起来就慢慢担心过了就忘了,所以就想找个办法帮忙记录下来,此时笔记倒是一项良好的辅助记忆的解决手段。)所以,就此写一篇小小总结博文记录之,希望可以积累下来。

不妨,挑选一些重点(细节)讨论分享吧,尽量保持简洁,罗列下面几点:
1. 氛围活跃
     需要营造良好的相互学习与技术交流的氛围。
     最好每个成员都有自己的专长,能够整理出属于自己独特的知识与大家分享,这样做同时可以让大家在心理上建议一种平等,因为程序员们是相对骄傲的一类群体。可以每周(每月长了点)定期组织一次由某成员发起的具有针对某主题的分享、交流、讨论会议。

2. 存在权威
需要一个权威成员,不管是来自技术还是管理层面都可行,只要能够在多成员间存在争议时拍板做最终决定。
     引用几句有点意思的话,某权威同事说,“就这样决定了,服从就是绩效。”,哈够强悍吧,显然他既涉及技术也是管理人员。

3. 共同爱好
     团队需要有一个共同的业余爱好,交流融洽。
     比如午休时间玩玩三国杀,或每周一次的篮球运动或游泳或其他运动、娱乐项目。这种活动对于团队的默契以及成员间的友好作用不凡。
     让同事们除了在工作中协同合作,还在生活玩的项目上协作吧,收获乐趣的过程中就释放了工作中的压力与疲惫,同时收获友情!下班时间,同事们可以互相调侃,玩笑,聊聊生活趣事,尽量不必谈及工作的事情。

4. 良性发展
     整个团队需要有良好的发展与支持(物质与精神上)。
     作为团队的Leader(TL @jieouy),必须(应该)尽力去为下面的同事们争取各种福利,包括升职加薪机会,工作与学习资源,还有团队活动经费等。这点对于TL而言,很重要不仅大大提高其在兄弟们心中的分量,而且之后兄弟们一定是更愿意尽心尽力去做事。

5. 能力拓展
     培养团队成员们都具有一定的产品与项目管理意识,最好都有尝试去做好的机会。
     该点也是为了同事们都有更好的发展,不必疑问说“有些人不合适做产品或项目管理呢“。不好意思我想说的是,不管是产品或是项目管理涉及的范围都是多方面的,只要你用心去发现去做,正常人都会从中获益的。这样的结果,大家都有一定成就感在其中,可以有提高团队凝聚力,尤其在与其他团队PK某竞争时候。

6. ……
   (待续,再想想应该还有不少点可以加以总结,但暂时未想到更好的,就先占坑放着吧。)

注:以上内容可认为纯属笔者YY的结果。

最后,感谢所在团队的同事们,感谢欧爷@jieouy!
(完)


2012年7月16日星期一

谈谈内存越界读写的危险

谈谈内存越界读写的危险
  -- 记某一次低级而糟糕的程序犯错。


# 故事
这是发生在上周的事情了。当时就有想法,要写篇文章以表示‘铭记’。

想必,这个话题对于C/C++程序员一定很熟悉,都有过或多或少,或轻微或严重(惨痛)的经历吧。

最近正在开发的项目,正在内部开发人员自己测试阶段,突然爆出好多的程序崩溃,大概估摸了下这些崩溃的规律如下:

     1,程序崩溃不确定性但必崩,只要你多操作几次,或重启程序再来试试。
     2,这些崩溃基本都不一样,(从堆栈看来)分散在不同的几个模块;
     3,分析程序崩溃堆栈看到崩溃在正常的代码上(显然不可能),亦看不出错误代码地方了。
     4,由于有辅助程序可在程序崩溃时候帮助自动抓取程序堆栈。但是有时程序崩溃无堆栈或堆栈数据无效。
……

最后,辛苦地安分地回头好好Review最近提交的代码,(……由于这几次提交改动均无法自己做到完整的测试保证,只能自己简单的功能程序和代码Review……),涉及的代码量较大,所以花了不少时间才找到了错误所在,有地方内存越界读写了。虽然找到了错误并很快纠正过来了,但是那样的低级错误让吾情何以堪?也正是为了纪念这么一‘尴尬’,我才想整理一篇博文表示‘罪过’。前车之鉴,后车之师。


个人觉得,上面总结的规律四点不妨可作为“内存越界读写”这样错误的表象。若以后还是遇见这样情况,不如先怀疑怀疑你的内存被越界读写了,赶紧回头仔细Review代码吧,相信你已很快顺利找到错误地方……

# 示例
下面内容就简单描述一下如何导致程序乱蹦,即越界“乱踩”内存了!示例代码如下:

struct A {
     ...
};
struct B {
     ...
     A a;
     ...
};

// 错误程序如下:
void some_func(struct B* b_ptr) {
     ...
     memset(&(b_ptr->a), 0, sizeof(*b_ptr)); // Error: memory overwrite.
     ...
}

// 修正程序如下:
void some_func(struct B* b_ptr) {
     ...
     memset(&(b_ptr->a), 0, sizeof(b_ptr->a));    // 1. ok
     // memset(&(b_ptr->a), 0, sizeof(struct A)); // 2. or else, also well.
     ...
}

果然吧,错误的程序那么低级,So stupid,而找到了错误修正程序那么简单的!程序就恢复正常了。
我想当时写程序脑子犯晕了吧。好了,不再多说了。还是我以前的那么句话,“以后写程序时候头脑得时刻保持精神点,否则后果有你好受的。”

# 借鉴
最后顺便引用一段关于内存越界的描述吧,延伸看看,想想。
--
对Memory overwrite 和memory corruption有什么好办法哪?常见的,就是设置CPU的breakpoint,也就是对某一地址的写操作,dump出stack,然后找是哪个模块写坏的。或者可以把整个page设置成只读,在操作系统层面检查,然后dump。这些对只读的变量或者page还还用,但是对可读写的变量又该怎么办哪?如何区分合法的读写和非法的读写?
对于非法的读写,也有在语言层次进行控制的,比如c++/java/c#等面向对象的语言,就有对对象的保护。但是这些语言并没有排除全局变量,也就是说,在语言层次的控制并不彻底。基于语言的静态检查是个好办法,但是对大规模代码,检查也需要时间和精力。任何经过仔细review的代码都是好代码,但是,有哪些公司能够坚持严格的代码review哪?
对于第三方和legacy的代码,review也基本是不现实的,但是静态检查是第一道防线,一定要坚持。
在操作系统层面,没有对象的概念,导致在操作系统层面没法保护。或者说,操作系统层面的保护代价太大了。我觉得还是操作系统的设计思想没有体现保护,隔离的要求,传统操作系统在这方面,做的很不够。
新的操作系统应该能够在更细粒度上做到隔离,保护,但是性能,通信等等又如何解决?

-- 

还有,在stackoverflow上面关于内存越界的一段讨论,这里

(完)




2012年7月7日星期六

Buffer overrun detected!

Buffer overrun detected!
     -- 一个C++栈缓冲区溢出警告(弹窗)

> 问题现象
先看看,程序运行过程中弹窗报错,如下图所示:


===
有人见过这种情况吗?最近有些(迅雷)用户遇到这种情况,很诡异。奇怪的地方在与我们开发与测试这边的环境下都不曾出现过这样的错误情况(否则早已解决了☺)。只有在极个别的用户机器上才出现这样的弹窗报错情况,但程序又不崩溃只是弹窗警告,点击确定程序即继续正常工作了,诡异的是这样弹窗报错竟然还有一定的周期性,大概10分钟一次。无语了。


> 网上说法
 从网上搜索得到下面几种说法,包括:
 a,安全程序(软件)包括防火墙,杀毒软件,安全卫生,管家等,可能引起程序的不兼容导致这样的情况。
 b,系统升级打补丁,导致之前正常运行的程序出现这样的错误,只要针对XP系统sp3。
 c,驱动程序由于升级版本与之前正常运行的程序出现不兼容,导致程序报错。
 ……


 具体的网上参考链接,有:
http://topic.csdn.net/u/20080617/17/0d16e504-0af9-40d5-911e-eee9fcdfdb75.html
http://topic.csdn.net/u/20080617/10/f3b02b0a-fa29-49c4-b4fc-c21ccc
http://answers.microsoft.com/en-us/windows/forum/windows_other-gaming/microsoft-visual-c-runtime-library-buffer-overrun/bb1cb707-622d-4fc6-b46d-c2bb4dec6207

其中,微软的官网论坛有这么句描述问题的,如下:
"The problem is due to a known bug in the ATI drivers - there are several threads on it on the AMD site. The thread I read was closed by a moderator with the statement "It will be fixed soon". I'm running the 10.11 drivers on a 4870 and I have the problem too."

===

> 问题分析
经过与出现该问题的用户的多次沟通,以上(网上得来的)说法均在用户环境一一确认,我们的情况不然,所以,这些说法都可以排除掉。
后来,好不容易从一个用户那重新问题,并顺利抓取了出错程序的堆栈信息(dmp文件)。这里还有一个小小的意外故事,当时让用户将dmp文件传过来,过程中刚好公司意外断点了,结果泡影了,所以赶紧手机登录上线让用户发到qqmail……还好,这位用户比较热心,帮dmp文件发到了邮箱。

再后来,分析了dmp文件,显然有了堆栈信息问题明确好多了。弹窗报错的原因在这里,详见下面说明:
(引用自\Microsoft Visual Studio .NET 2003\Vc7\crt\src\secchk.c)
/***
*seccook.c - checks buffer overrun security cookie
*
*       Copyright (c) Microsoft Corporation.  All rights reserved.
*
*Purpose:
*       Defines compiler helper __security_check_cookie, used by the /GS
*       compile switch to detect local buffer variable overrun bugs/attacks.
*
*       When compiling /GS, the compiler injects code to detect when a local
*       array variable has been overwritten, potentially overwriting the
*       return address (on machines like x86 where the return address is on
*       the stack).  A local variable is allocated directly before the return
*       address and initialized on entering the function.  When exiting the
*       function, the compiler inserts code to verify that the local variable
*       has not been modified.  If it has, then an error reporting routine
*       is called.
*
*       NOTE: The ATLMINCRT library includes a version of this file.  If any
*       changes are made here, they should be duplicated in the ATL version.
*
*******************************************************************************/
……

但是,具体的错误根源,虽然找到了错误点(疑点),但还需程序验证确认问题解决了,不出现弹窗报错方知真相。
程序错误点其实很简单,只是隐藏在大几十万行代码里头,不好找出来,而且奇怪的是那里的代码一直也没啥改动的啊?
===


> 解决方案
该程序逻辑涉及一个Windows API 读取注册表一个键值,接口如下:
LONG WINAPI RegQueryValueEx(
  __in          HKEY hKey,
  __in          LPCTSTR lpValueName,
  LPDWORD lpReserved,
  __out         LPDWORD lpType,
  __out         LPBYTE lpData,
  __in_out      LPDWORD lpcbData
);

(该函数的具体说明参考MSDN
注意,最后一个参数lpcbData为__in_out类型,既是输入又是输出参数。

其中错误程序,描述如下:
void function() 
{
     ...
     char buffer[MAX_PATH]
     unsigned size; // Error:这里没有初始化。
     if (ERROR_SUCCESS == RegQueryValueEx(..., buffer, size)) {
          ...
     }
     // Error:这里也再没有初始化size,此时size为上次RegQueryValueEx操作的读取字节数。
     if (ERROR_SUCCESS == RegQueryValueEx(..., buffer, size)) {
          ...
     }
     ...
} // BTW,从堆栈信息看来,运行出错的程序是在这里函数退出时,弹窗报错的!

修正程序,如下:
     char buffer[MAX_PATH]
     unsigned size = MAX_PATH;
     if (ERROR_SUCCESS == RegQueryValueEx(..., buffer, size)) {
          ...
     }
     size = MAX_PATH;
     if (ERROR_SUCCESS == RegQueryValueEx(..., buffer, size)) {
          ...
     }





结果程序运行正常了,不再报错了!


===
最后,仍然心存疑问的是,“为啥这样的程序出错不是必须的,而且是很稀罕的?”。
猜想:因为变量size未初始化,其值为未确定状态。导致程序出错的概率,很可能跟系统(C++运行时)内存栈环节有关。


(完)

2012年6月30日星期六

单链表删除节点的技巧

单链表删除节点的技巧
     -- 注:删除节点非尾节点!
 


在此分享一个小小技巧,在单向链表中删除节点时不必知道其前面节点(若存在前面节点的话),亦可高效地完成删除节点。

===
从一篇别人的博文说起吧,引用自这里,内容很少,仅此如下:

标题:学习数据结构的感想
在链表中删除动作比较多的时候,用双联表比用单链表效率要高,双链表不用从头开始遍历去删除,而是可以直接删除。
用单链表删除的时候,每次知道需要删除元素的前一个指针就好了。不过这个好像很难知道。

我是在无意之间,看到那位朋友的上面问题,先是无意间网上搜到他转载了我的一篇博文《STL稳定排序源码分析》,好奇之下到了他的csdn博客的。
所以我就一时兴致勃勃回复了其问题,与之讨论,内容如下:

===
单向链表删除节点时候,可做到不需要知道(若有的话)上一个节点同样完成删除操作。你可以这么做,描述如下:
原来的链表 ... A -> B[b_ptr] -> C[c_ptr] -> D[d_ptr] ...
现在要删除节点 B,其对于指针为b_ptr注:删除节点非尾节点,重要

首先你可以使用B得到C,D指针,c_ptr和d_ptr,然后你可以用C去覆盖掉B,即*b_ptr = *c_ptr,那么这时你可以删除C即可达到你要的结果即删除节点B。具体操作:
*b_ptr = *c_ptr;
b_ptr->next = d_ptr;
delete c_ptr;

结果的链表 ... A -> C[b_ptr] -> D[d_ptr] ...
按照以上的操作,这样就不需要从头去遍历链表定位上一个节点A了,简单有效吧☺。

===
但是,删除节点不应该为尾节点(链表的最后一个节点),因为B作为尾节点,虽然你可以删除节点B,但无法给节点A的next赋值NULL。若删除的节点为尾节点,那就得老老实实从头遍历链表了,将其前面节点A的next赋NULL。

===
当然你说的“用双(向)链表比用单链表效率要高”,是对的。确切说应该叫实用性高吧,但是其实现的逻辑要复杂不少,可参见STL链表的实现源码。像C++ STL里面的链表(包括单向双向)底层的实现都是以双向链表形式的。可以参考sgi stl源码std::liststd::slist

(完)