不停地疯

Work as a hacker, hack as a artist.

简单总结ROS下通过VPN解决DNS污染时所遇到的问题

| Comments

之前参照ROS透明经济翻墙在家中搭建了无痛网络,但是期间在解决DNS污染问题上纠缠了一阵,现简单总结一下所遇到的问题。原因有几个方面:

  1. 在配置ROS路由器时,本地流量不受标记影响,所以路由器本地是不走vpn的。而电脑DNS之前指定的是ROS自带的DNS,所以虽然在ROS上指定了上级DNS为Google DNS,但由于ROS本地没走vpn,所以域名仍然会被污染。
  2. 后来在另外一台路由器上使用了dnsmasq,但是由于沿用了之前配置,所以忘了将114DNS从主查询DNS中删除,更关键在于,污染的域名没有强制使用Google DNS进行解析,所以,虽然添加了Google DNS作为上级查询,但是114DNS的反馈要快好多,所以使用中还是会遇到污染。
  3. 接下来,尝试使用了openDNS的非标端口,解决污染有效,但是openDNS不够稳定,所以继续探索。
  4. 最后,经过多次尝试后才发现是第一步中所遇到的污染问题是由于ROS本地流量标记的问题。于是还是决定使用dnsmasq来解决,最后在配置文件中将被污染的域名设置为强制走Google DNS,这样在ROS自动路由的情况下,Google DNS走vpn,被污染的域名就可以从Google DNS获得干净的ip地址了。这样就解决了污染问题。不过这个解决方案仍然需要人为维护,至少需要维护dnsmasq配置文件中被污染的域名列表。

最近,看到shadowsocks的作者@clowwindy又搞出了个china-DNS的玩意,看上去非常不错,可以很傻瓜免维护的解决DNS,准备有时间再搞一搞。

又一年

| Comments

不经意间,距离上一次更新博客,已经又一年过去。至于为何这么长时间没有更新博客,个人原因可能是最万能的一种回答方式吧。一方面工作的繁忙,加上家中新添的一员,各个方面都影响着懒惰的自己改变着现有的状态。儿子在这一年内成长很快,突然间牙齿就已经14颗了,爸爸妈妈也叫的很欢。这一年间,我学会了德淘奶粉,学会了日淘家用品。为了小孩,曾经看似无关的事情,现在也算小有经验了。

其实在这一年里自己做的其他事情也蛮多,只是还不那么出彩罢了。数下来,林林总总十几件,不过相对近且重要的还是以下几件:

  1. 买了routerboard 450G,规整了家里网络。将家内的网线口都通上了数据,另外实现了全局自动科学上网。
  2. 熬夜观看了04年的WWDC,热血异常,随后注册了iOS开发者计划。
  3. 来了场说走就走的旅行,去香港购入了Retina MacBook Pro,拥有了人生中第一款pro级mac设备。
  4. 域名从狗爹的转移到了google domain,不用再忍受狗爹的“优质”用户体验。
  5. 开始正式使用dropbox和1password,加强个人账户的安全性。
  6. 写了些小工具,改进工作流,提升工作生活的效率。
  7. 自己动手改造了703N路由器为16M双Flash+64M内存。

另外,总觉得长时间不更新博客不符合个人行事风格,而且域名也续费到了2017年,说什么也不该浪费,但一直不知道该从什么时候开始恢复。借着新电脑的到来,重新配置了octopress环境,再次开始博客的写作。考虑之前使用org文件写博客只能使用电脑(因为要用emacs),操作太局限,现尝试使用dropbox同步博客文章,并使用markdown格式进行写作。希望以后至少不会用没空之类理由来搪塞不更新博客的理由,毕竟markdown这种格式兼容性相对较好,iOS设备上也能找到很多工具进行编辑,应该勉强能够随时随地写博客了。

此外,随着儿子的成长,我希望未来能有更多的时间陪伴家人。同时,也希望能够通过自己的努力,在能预见的未来里,为家人带来更多的幸福。

Limbo地狱边境

| Comments

最近在appstore上花钱花得比较凶,感觉好的以及之前想买的软件统统都入了手。那天在头版看到有一款名叫Limbo的游戏被编辑推荐了,点进去看效果似乎不错,于是也就顺带入了手。而在下载并体验了这款游戏之后,我确定我已经是它的fans了,在心目中的地位与马里奥以及Braid平起平坐。

说实话,Limbo是什么意思,我没有一点概念,通过词典可以查到大概是遗忘之地以及地狱边境的意思。据说这个词在盗梦空间中也有出现,就是最后梦境崩塌之后意识所存留的地方。在这款游戏中,Limbo似乎就是本意,令人绝望的地域边境。游戏全篇使用黑白渲染,你没看错,全篇只有黑白色调,黑白胶片般的感觉!游戏中没有一句对话和多余的提示,甚至如何操作也需要在游戏中自己探索。游戏主角是一个小男孩,睁着大大的眼睛,在草丛中醒来后就是一个人,对身边的世界说不上陌生,但绝谈不上熟悉。随着游戏情节的发展,逐渐可以发现小男孩所处的这个世界是一个到处充满着险恶的地方,一路上坏小孩们,诡异的大蜘蛛,巨石,迷惑人的花,沼泽,电锯等等都会突如其来的出现。整个游戏过程就像在看一部黑色的童话,黑得很压抑很绝望,怀着仅有的一丝希望一路向前寻找着出路。

Limbo属于横版动作解谜游戏,每个关卡设计的非常巧妙,基本上都要动一番脑筋,包括运用器械知识以及物理知识等等。而且这款游戏有一个很有意思的设定,那就是如果解谜失败主角挂了之后,游戏会重新从最后的一个解谜点开始,这才使得整个游戏和解谜的过程显得不那么绝望,让人有不断尝试以及通关的欲望。同时iOS版的软件支持icloud同步游戏进度,像我这样出门iPhone,回家iPad的人来说非常方便。

Limbo的游戏时间并不长,初次玩的话估计3个小时可以搞定,在玩过一遍的情况下1个多小时差不多。好在游戏拥有成就系统,而且这些成就并不容易拿到,所以使得这款游戏的耐玩度有一定提升。我在拿到这款游戏之后,花了大概3个小时完成了整个游戏,而且只达成2个成就。在最后,游戏的主角似乎找到了自己的妹妹,但是从叙事上还存在一些不确定和伏笔,也许是为了续集作铺垫。就像常说的1000个读者眼中有1000个哈姆雷特,对于这款游戏结局的解读,每个人也有不同的说法。具体如何解读,只有自己玩了之后才知道。总体来说,这款游戏绝对值得一玩,绝对5星作品。游戏爱好者自然不用说,但即便你是UI/UX,程序员,这款游戏也绝对有足够的资本让你眼前一亮,将黑白玩的如此出彩的不多。

./images/blog/./1102O3a.png

./images/blog/./1102bBh.png

Windows上的alfred

| Comments

Mac上我一直使用alfred 快速索引文件以及快速操作什么的,而Windows上则没有找到一款比较好用的类似软件。加上Windows半残废的查找功能,每天在上面工作真是有种自虐的感觉。后来使用免费的everything ,查找文件快捷方便,弥补了Windows查找功能的不足。但是everything不能像alfred一样对搜索的结果直接进行操作,而且选择结果后everything也不会自动退出,经常造成多个窗口飘在桌面上,感觉不是很爽。直到最近,我在查找everything配置的过程中发现了另外一款Windows上的全盘索引软件:Listary ,借助它的索引和查找功能,不仅可以很方便的快速定位文件,而且可以对结果进行后续操作,有点alfred的影子,于是立马下载安装试用。

Listary安装好后直接就运行了,运行后会有一段简单的使用指引,跟着它做可以快速了解Listary的主要功能。第一次安装运行后可能会对全盘进行索引,需要花点时间,但是速度还是比较快的,特别是相比Windows自带的那个残废来说。Listary属于后台程序,默认使用Win+s激活,也可以自行设置快捷键。应用图标在右下角状态栏中可以找到,通过应用图标可以查看版本信息,查看帮助,或者设置软件。如果选择进入设置菜单,我们可以看到Listary目前支持的所有功能,如图:

./images/blog/./951HFA.png

可以看到Listary支持快速切换,模糊导航以及第三方文件管理器。这些都非常有用,除了模糊查找外,快速切换也是很有用的,可以非常方便的在打开文件对话框中快速定位到刚才打开的文件夹,而不用一层层的去选取进入,大大提高工作效率。此外,工程也是一个比较有用的概念。简单说,这个功能可以将一些常用的目录定义为一个搜索前缀,然后搜索时先打相应的搜索前缀,那么之后的搜索内容都会在之前定义的目录中去查找了。这比较适合我这种懒人,我一般将所有文档都放在一个固定目录下,但是却懒得整理,使用工程功能将该目录设定为doc前缀,之后搜索文档时只需要快捷键呼出Listary并敲入doc,然后空格并输入需要查找的文档名称就可以了。结果的展现只是一瞬间的事情,方便至极。中文名称?没问题!直接拼音缩写就行了。

另外,Listary也支持everything的数据库,据说速度会更快一些,但是我没有发现差别,出于功能兼容方面的考虑,我使用Listary自带的索引引擎。外观功能据说在下个版本会提供主题的设置,目前只是简单的字体大小设置而已,以后可以关注下。可以说这个软件目前可以设置的功能就上图这么些了,没什么特别复杂的内容。

对搜索结果的二次操作时alfred的一大特点,Listary对此也有支持,只是功能稍弱。默认是在搜索结果上按方向右键进入(结果如图),而且目前不能用户自定义该触发热键(喂,作者你就不能设置一个手指不用移这么远的按键么?)。未来也会支持对搜索结果的快捷键操作,目前只在开发测试版中可以用到。搜索快捷键使用vim的风格,通过ctrl键触发和关闭。在快捷键模式中可以通过数字直接选择结果,或者使用u/d键上下翻页,或者使用alt+数字键进入结果的二次操作功能。

./images/blog/./951UPG.png

说到这里相信各位也有点感兴趣了吧?这款软件分免费版和付费版两个版本,免费版可以在非商业环境下使用,有部分功能限制,比如之前说的工程功能以及二次操作功能等。我为了用上完整功能,从异次元软件代理处购买了该软件的license。好在该软件的license是终身的,也就是说之后的所有版本升级都可以免费得到,同时一个license可以支持三台电脑安装,符合我上班工作的需要。

除此之外,Listary还有以下缺点:

  1. 相比alfred没有自定义脚本的功能
  2. 某些特定场景下快速切换无效
  3. 不支持索引Outlook等内容(这是巨硬的问题,苹果至少有spotlight做内容索引),所以邮件搜索还得靠残废的Windows Search
  4. 快捷键支持不是很完美,特别是开发者还是vimer,所以快捷键都是vim风格的,没有emacs风格用着爽
  5. 快捷键模式中进入二次操作界面后不能使用搜索快速定位功能选项
  6. 存在一些诡异的Bug

好在软件的开发者还比较活跃,隔几天会有一个新版本发布,而且也可以去官方论坛上提一些改进要求什么的。目前对我来说,这个软件的存在至少让我在windows上工作时多少有点在mac下的感觉。

简述一种电池电量表的取得方法

| Comments

一般来说,常用的电池电量的计算方法有两种:一种是使用叫做库仑计的ADC器件对电池的电流进行时间积分统计,然后除以电池的总毫安时容量,从而得出电池当前的电量;而另一种是使用电压采样ADC获取电池当前的端电压,并通过软件计算出电池的开路电压,然后根据电池的电压-容量表1来对应查找到当前电压下的电池容量。显而易见,从理论上来讲前一种方法更加准确。但在实际上,前一种方式往往受限于库仑计设备的采样精度以及程序员编写驱动程序的水平;同时,在硬件方面也增加了器件成本,应用上并没多少优势。像Marvell的88pm860x PMIC芯片中是有库仑计器件的,实际使用中统计值和实际偏差较大,需要在驱动程序中通过其它办法对所得值进行补偿校准后才有一定的使用价值。而高通的PM8029 PMIC芯片中则没有库仑计功能,驱动中的逻辑也比较单纯,仅仅是简单的获取VBATT值,并通过电流和电池内阻对VBATT进行校正后得到电池开路电压,然后根据电压-容量表查到当前电池的电量。使用对比下来,高通平台所使用的这种方法简单且有效,只需要根据不同电池制作一份电压-容量表即可完成电池的电量计算。

但是,使用电压-容量表也不是没有缺点的,为了说得更清楚点,这里先简单介绍一下电压-容量表。这里所说的电压-容量表中的“电压”指的是电池的开路电压OCV,而不是直接由ADC所采样到的电池端的原生电压VBATT的值。学过中学物理的可以知道,所有电池是有阻抗的,一般我们人为将其抽象为电池内阻,因此一个电池通常可以被抽象为一块原电池和电池内阻的串联体。这样,如果电池有电流流出的话,输出的电流越大,通过欧姆定律可以得出电池内阻的分压也会越大。这意味着在输出电流状态下,外部测得的电池端电压就会比实际开路电压小;相反,如果电池在充电中,电流方向和放电时相反,电流为流入电池。此时测得的端电压就会比开路电压略大。简而言之,从外部所测的的电池端电压很不稳定,它是电池内阻、电流以及温度等因素的函数。因此,开路电压的概念就变得重要了,如果继续基于之前所说的抽象电池来讲,开路电压是在电路中没有电流回路的情况下测得的电池端电压,也即是原电池的端电压。计算开路电压时,一般会估算一个电池内阻值,然后根据欧姆定律使用ADC采样到的电池端电压以及电池电流来计算出开路电压。至于电压-容量对应表,则是基于另外一个假设:电池的不同电量都对应一个唯一的电压值。但是,假设毕竟是假设,事实情况总要复杂一些。先不提容量与电压的非线性关系,不同供应商提供的不同型号的电池,其电压-容量特性都是不一致的,而且有时会出现某一阶段电压特别耐用的情况,这直接导致有时计算得到的电压-容量表中会出现同一电压对应多个容量的情况。如下图中,随着时间的增长,有时电压会保持比较平稳的状态。加上电压-电量表计算时一般都是使用供应商提供的电池充放电数据,这种数据一般使用比较标准的电流对电池进行恒流充放电后统计得到的,和手机实际使用的情况存在一定差异,而且数据采样设备在精度上也有较大的差别。这也造成了如果直接使用供应商数据计算得到的电压-容量表,在实际使用时效果不够好的情况。针对这种情况,人为会对所得结果做一些补偿和修正。但是这种问题一般都要花比较长的时间测试后才有可能发现,而且补偿的效果同样需要花费较长的时间才能验证。那么能不能通过简单的方法有效避免这类问题呢?

./images/blog/./1656aA2.png

考虑到数据采样设备以及环境的差异问题,如果直接使用手机内部的ADC采样电池数据,然后使用这个数据计算电量表会不会好一点?实际验证下来,这种方法确实有一定的效果改进。采样之前,将手机环境至于标准功耗模式(最大亮度常亮,循环播放MP3),然后再进行采样,这样可以最大限度的模拟手机使用过程中电池的实际情况。采样的数据包括放电时长以及电池开路电压。至于电量表的计算,在这种情况下更为简单。因为在采样过程中手机处于标准功耗模式中,可以近似认为电流恒定,所以电量的损耗和时间是函数关系。将采样全程时长分为100份,然后分别得到每份所对应的电压值,电量表就做出来了。这种方法有个很大的优势,那就是思路简单,很适合脚本化操作。采样脚本外加计算电量表脚本,使用bash一会儿就可以搞定。

可是,出于之前所说的一个问题,电池的电量和电压并没有一个绝对的对应关系,极端时甚至会出现得到的电量表中同一个电压值对应了多个电量。为了解决这个问题,我们引入了数学方法,使用样条差值的办法拟合采样的数据点,然后在拟合的曲线上重新进行电压电量对应关系的获取。使用了这个方法之后,电池电量方面的问题少了很多。而且由于使用了时间分割电量,所以在实际使用中,每格电量的使用时间都很接近,符合用户对电量的认知。拟合曲线的效果如图:

./images/blog/./1656N2v.png

改进后的电量表采样及计算脚本在:battery analyzer 。脚本中的样条差值部分使用了octave程序实现,效果蛮不错的。

Footnotes:

1 指开路电压与电池容量的对应关系表。

搞了个半自动化的Vim

| Comments

平时单位里Linux下使用wine+sourceinsight查看代码,用emacs写代码。最近公司搞正版化,自然sourceinsight也就不能再使用了,本想自定义一下emacs做类似功能,但苦于自己三脚猫的Lisp,加上之前的配置有点杂乱,所以想着先用vim顶两天,然后再自己抽空重构一下emacs的配置结构和功能,顺便也能从vim那里偷点师。几天下来,vim也被我配置得可以替代sourceinsight大部分的功能,使用起来还算不错。推荐给同事们使用,也都很满意。这里简单讲讲我的配置思路。

对于工作中的编辑器,我有以下几个基本要求:

  1. 文件查找方便
  2. 格式自动化
  3. 自动补全
  4. 符号跳转
  5. 函数列表
  6. tab/buffer支持
  7. session保存

对于第一个需求,我使用了有口皆碑的lookupfile插件,这个插件可以从tag文件中快速查找文件,也可以在自己生成的文件列表中查找。我自己是使用文件列表的方式来查找,速度同样很快。之前也有使用过另外一个类似功能的插件,ctrlp。但是这个插件第一次使用时都要将当前目录下的所有文件遍历一遍,对于大型项目来说,速度还是有点慢。所以ctrlp被我抛弃了;第二个需求,vim貌似原生支持就不赖,直接=就可以;第三个需求,我选择了强大的YouCompleteMe插件。YCM插件使用了Clang编译器做后端,可以在编写程序时快速的分析代码,提供准确的自动补全列表。对于第四个需求符号跳转,本来使用的是cscope,功能很强大也够用,但是修改文件后更新符号文件比较慢,所以经常也就懒得更新符号文件,导致跳转的地方经常有偏差。后来发现有个GNU global可以非常快速的更新符号文件,加上和现有的cscope插件可以很好的兼容,所以我也就换成了用GNU global做符号跳转支持了。同时,我还加入了hook在保存程序文件后自动调用global进行更新符号文件。从此以后就再也不用担心更新符号文件的问题了,保存文件后符号立马生效。第五个需求使用地球人都知道的taglist就好,绑定F8快捷弹出;第六个需求,vim同样原生支持,自己配个好用的快捷键就OK;最后一个需求很有用,vim原生也有支持,但是原生的session不支持tabbar状态的保存,于是我使用了xolox/vim-session这个插件。使用这个插件后,不但可以保存打开文件的状态,光标位置,查找上下文的状态,tabbar的状态也都可以完美保存。这样,在退出vim后,下次打开时还能快速回到上次关闭前的状态,就像在sourceinsight中重新开启工程一样。

除此之外,我还添加了一些辅助类插件,比如nerdtree,nerdcommenter,easymotion,powerline等,方便目录浏览,注释等操作。用的不多,但是在某些时候还是有点用的。插件装好之后还不是很顺手,要想方便使用,自己还做了些定制。其中我写了一个脚本,为了帮助快速得建立工程。脚本中从建立lookupfile所用的文件列表到生成更新global符号文件,全部一气呵成。另外,在配置文件中我还添加了几个hook,除了保存特定文件后自动更新符号文件得hook,还有退出vim后自动保存session的hook。最后,将常用功能都绑定到快捷键上,这样使用起来就省力多了。到此,半自动化的vim就算完成了。

配置好的内容可以在: https://github.com/xeonxu/vim_configs 找到,其中有两个分支,master对应Linux的版本,而macos对应Mac版本。两者的差别便是YCM中二进制文件的格式分别是对应两种系统单独编译的。由于YCM的特殊性,必须要使用最新版的vim才能正常运行,而各大系统的发行版中的vim版本都不是很新,所以需要自己通过vim源代码编译一个才行,这算是唯一的遗憾了。公司里我写了个一键安装脚本,方便同事们的部署,大家使用标准的源码编译安装方式伺候即可。

作为一名emacser,跑来研究vim配置说起来也挺难为情。不过配置过程中给我印象最深的是vim的插件配置起来都挺方便,基本都是设置几个变量就好。加上vundle这个插件,很容易让人沉浸在插件的世界里。另外就是vim的启动速度确实快,这让我们这些emacs用户嫉妒不已。还有,lookupfile插件的思路蛮好,emacs上应该可以实现个更好的。另外下次配置emacs时,也要坚持换用global做符号跳转支持了,因为实在是太快太方便了。根据程序员时髦指南的解释,同时使用emacs和vim的人应该烧死,所以我看我还是尽快搞定自己的emacs配置吧。

再谈自动生成ISO文件的客制化问题

| Comments

由于最近项目中又有要求说要对手机自带的虚拟驱动光盘的内容做客户定制化,于是基于上篇文章中使用make系统动态构建ISO镜像文件的方法,我又加入了客制化脚本的支持。实现的方法很简单,思路是在make工程下规定一个目录专门做客制化目录,目录下包含以不同项目名称命名的子目录,而相应子目录下便是客户定制的具体内容;同时,每个项目子目录中还包含有一个客制化脚本,用于对光盘文件系统进行重命名或者删减的操作。

由于之前已经有了自动生成ISO文件的make系统,基于以上的思路实现下来,加入的代码并不多。首先是改造主makefile:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# Author: Zhiqiang Xu
# Version: 1.2
# Date: 2013.05.09
# Change Log:
# 1.1 Makefile to generate cdrom iso file. Only generate iso file without icon in default.
# 1.2 Add script support to customize cdrom's contents.

CDROM_FS            ?= ./CDROM_OBJ
TARGET_CDROM        ?= ./cdrom_install.iso
PRODUCT_DRIVERNAME  ?= Phicomm
CDROM_ROOT          ?= ./

ICON_NAME       := "$(PRODUCT_DRIVERNAME).ico"
ORIGIN_ICON     := $(CDROM_ROOT)/custom/$(PRODUCT_DRIVERNAME)/$(ICON_NAME)
CUSTOMIZE       := $(CDROM_ROOT)/custom/$(PRODUCT_DRIVERNAME)
CUSTOMIZE_SCRIPT := $(CDROM_FS)/custom.sh
AUTORUN_FILE     := $(CDROM_FS)/autorun.inf

all:$(CDROM_FS)
    mkisofs -input-charset utf-8 -V "$(PRODUCT_DRIVERNAME) Driver" -J -r -l -v -o $(TARGET_CDROM) $(CDROM_FS)

clean:
    @rm -f $(TARGET_CDROM)
    @rm -rf $(CDROM_FS)

cdrom_new:clean
    @mkdir -p $(CDROM_FS)
    @if [ -e $(CUSTOMIZE) ]; then \
    cp -rf $(CUSTOMIZE)/* $(CDROM_FS)/; \
    fi

$(AUTORUN_FILE):cdrom_new
    @if [ -e $(ORIGIN_ICON) ]; then \
    cp -f $(ORIGIN_ICON) $(CDROM_FS)/; \
    echo "[autorun]\r" > $(AUTORUN_FILE); \
    echo "icon=\"\\$(ICON_NAME)\"\r" >> $(AUTORUN_FILE); \
    fi

$(CDROM_FS):$(AUTORUN_FILE)
    @cp -rf $(CDROM_ROOT)/driver/* $(CDROM_FS)
    @if [ -e $(CUSTOMIZE_SCRIPT) ]; then \
        sh $(CUSTOMIZE_SCRIPT) "$(CDROM_FS)"; \
    fi
相较之前的版本,我在其中新增了两个变量 CUSTOMIZECUSTOMIZE_SCRIPT ,这两个变量分别用来指定不同项目所用的客制化目录和客制化脚本。注意, ORIGIN_ICON 变量的内容和原来相比也有变化,路径由原来的 custom 目录变为了相应的项目子目录,这样对于不同的项目来说也容易管理一些。另外,在 cdrom_new tag段,加入了拷贝客制化内容到iso文件系统的语句。对于主makefile最核心的修改实在最后一个tag段,也就是 $(CDROM_FS) 段的最后一句if判断,判断客制化脚本是否存在,如果存在,则以iso文件系统路径为参数执行该脚本。makefile的改动就这么些,接下来看客制化脚本 custom.sh 的内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/sh
# Author: Zhiqiang Xu
# Version: 1.0
# Script which is used to customize contents of cdrom.

SCRIPT_FILE=$0
CDROM_FS=$1

rm -f $CDROM_FS/PC_Modem_Drivers_Install_Help.pdf
rm -f $CDROM_FS/PHICOMM_USB_Drivers_Install_Help.pdf

#Do not REMOVE!
rm $SCRIPT_FILE

对于一般的项目,默认都是使用 driver/ 目录下的内容作为驱动光盘的内容,其中默认包含两份中文pdf说明。但是对于外单项目来讲,肯定不能使用中文说明,那么我们就需要将其从光盘文件系统中删除。以上的脚本就做了这么一件事情,删除了光盘文件系统中的两份pdf文件。脚本最后将脚本自身从光盘文件系统中删除,否则最后生成的iso文件中还包含制作脚本,那将是一件很怪异可笑的事情。从makefile中看,客制化脚本会在生成ISO文件前一步执行,因此,客制化脚本的权限是相当大的,基本上可以实现你想对光盘文件系统执行的一切操作。

到此,客制化光盘的需求就完全解决了,前后实现起来也就10分钟时间。最后吐槽一遍,Android的make系统太复杂太慢,如果不是我之前在这个模块中直接使用传统make系统,对应这个简单的需求困怕也要多花费2-3倍的时间。

使用Make系统自动生成手机驱动光盘

| Comments

蔽厂为了方便用户在拿到手机后能够顺利安装手机的电脑驱动,将相应的驱动文件打包成一个iso,然后借助Linux Usb Gadget的支持,在手机连接到电脑后会虚拟出一个驱动光盘来。实际效果蛮不错,但是问题在于,将驱动文件打包为iso的过程基本都靠人工手动完成。这于我这样喜爱偷懒的人来说,是极不科学的。于是我考虑将打包iso文件的操作自动化起来,实现步骤考虑是这样的,首先写下制作iso文件的Makefile,然后通过Android的编译系统调用改Makefile,这样在每次编译生成Android系统镜像的时候,就会自动生成相应iso文件了。

为了命令行中生成iso文件,首先需要找到相应的命令行程序。这点对于linux系统来说一点不难,现成的mkisofs就可搞定。接下来,需要制定生成相应iso的命令参数。这点也不难,通过查看mkisofs的man帮助即可快速找到所需要的各种参数。最后我决定使用的命令为: mkisofs -input-charset utf-8 -V "Android Driver" -J -r -l -v -o cdrom.iso cdrom_fs/ 。这其中,我指定使用utf-8的编码作为输入编码,使用Android Driver作为光盘的卷标,添加joliet格式和rock ridge支持,冗余输出,将 cdrom_fs/ 目录下的所有内容生成为cdrom.iso文件。

有了基础命令行,就可以写Makefile了。我写好的Makefile如下,其中还添加了光驱icon的支持:

makefile生成iso
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# Author: Zhiqiang Xu
# Version: 1.1
# Date: 2013.03.22
# makefile to generate cdrom iso file. Only generate iso file without icon in default.

CDROM_FS            ?= ./CDROM_OBJ
TARGET_CDROM        ?= ./cdrom_install.iso
PRODUCT_DRIVERNAME  ?= Phicomm
CDROM_ROOT          ?= ./

ICON_NAME       := "$(PRODUCT_DRIVERNAME).ico"
ICON_PATH       :=
ORIGIN_ICON     := $(CDROM_ROOT)/custom/$(ICON_NAME)
AUTORUN_FILE    := $(CDROM_FS)/autorun.inf

all:$(CDROM_FS)
        mkisofs -input-charset utf-8 -V "$(PRODUCT_DRIVERNAME) Driver" -J -r -l -v -o $(TARGET_CDROM) $(CDROM_FS)

clean:
        @rm -f $(TARGET_CDROM)
        @rm -rf $(CDROM_FS)

cdrom_new:clean
        @mkdir -p $(CDROM_FS)/$(ICON_PATH)

$(AUTORUN_FILE):cdrom_new
        @if [ -e $(ORIGIN_ICON) ]; then \
        cp -f $(ORIGIN_ICON) $(CDROM_FS)/$(ICON_PATH)/; \
        echo "[autorun]\r" > $(AUTORUN_FILE); \
        echo "icon=\"$(ICON_PATH)\\$(ICON_NAME)\"\r" >> $(AUTORUN_FILE); \
        fi

$(CDROM_FS): $(AUTORUN_FILE)
        @cp -rf $(CDROM_ROOT)/driver/* $(CDROM_FS)
我在这个makefile中定义了几个默认变量,目的就是为了在没有定义这些变量的时候,能有一个默认值。同时假定用来生成iso的文件都存放在driver目录下,以及需要使用的光盘图标文件都存放在当前目录的custom目录下。如果发现有和 $(PRODUCT_DRIVERNAME) 同名的图标文件,则在光盘根目录中生成相应的autorun.inf文件,以显示相应的光盘图标。写好了makefile,直接执行make就可以生成相应的iso文件。不过我的目的是和Android编译系统联动,所以还需要再做些工作。

参考Android中kernel的编译方法,我编写了AndroidCdrom.mk文件,如下:

AndroidCdrom.mk
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Author: Zhiqiang Xu
# Version: 1.1
# Date: 2013.03.22
# Android makefile to generate cdrom iso file

# cdrom variant output
# Set Default name to Phicomm
PRODUCT_DRIVERNAME      ?= Phicomm
PHICOMM_TARGET_CDROM    := $(TARGET_OUT)/etc/cdrom_install.iso
PHICOMM_CDROM_ROOT      := device/qcom/msm7627a/cdrom/
PHICOMM_CDROM_FS        := $(TARGET_OUT_INTERMEDIATES)/CDROM_OBJ/

$(PHICOMM_TARGET_CDROM):
        $(MAKE) -C $(abspath $(PHICOMM_CDROM_ROOT)) CDROM_FS=$(abspath $(PHICOMM_CDROM_FS)) TARGET_CDROM=$(abspath $(PHICOMM_TARGET_CDROM)) PRODUCT_DRIVERNAME="$(PRODUCT_DRIVERNAME)"
内容相当简单,其实就是将Android编译系统中的一些环境变量和目录信息传递给刚才写的makefile中,传入的路径都转换为绝对路径,防止Android编译路径的变换造成文件生成失败。

最后一步,将该AndroidCdrom.mk文件添加到android的编译环境中。同样参照kernel的编译方法,在AndroidBoard.mk文件中添加如下两行:

AndroidBoard.mk
1
2
3
4
# 2013.3.20 zhiqiang.xu Add for generate cdrom iso
include device/qcom/msm7627a/cdrom/AndroidCdrom.mk

droidcore: $(PHICOMM_TARGET_CDROM)
这其中的意思是将 $(PHICOMM_TARGET_CDROM) 这个目标依赖到droidcore目标上,而droidcore是生成android核心的标签,于是每次编译android时都会首先编译 $(PHICOMM_TARGET_CDROM) 目标,从而自动生成相应的iso文件。实际测试下来,效果非常好,每次修改了光盘中相应文件后,都不需要再自己手动生成iso文件了,编译Android时从头到尾一气呵成。

搞定!

使用ccache优化Android的编译时间

| Comments

最近在Android编译过程中发现,使用ccache也能很好的提升C/C++编译感受,虽然比不上分布式编译所带来的成倍编译速度的体验,但是减少一半编译时间还是绰绰有余的。其实在Android的编译系统中已经自带了对ccache的支持,之前我那篇讲解如何使用distcc编译Android的文章 中其实就是在ccache的支持基础上进行修改的。但是Android编译系统中的ccache只对Android系统的库文件等进行优化,并不包括Kernel和LK的编译。没搞明白为什么原生的编译系统没有包含这两部分的ccache支持,为此我自己修改了Android编译系统中Kernel和LK的Makefile文件。使用修改后的Makefile文件编译Kernel和LK时,第二次可以节省3-4分钟的时间。看上去时间不长,但是考虑到原来编译Kernel和LK时需要用时8分钟左右,这点提升也是有意义的。

修改非常简单,对于Kernel只需要修改

AndroidKernel.mk
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
--- a/kernel/AndroidKernel.mk
+++ b/kernel/AndroidKernel.mk
@@ -62,30 +62,30 @@ $(KERNEL_OUT):
        mkdir -p $(KERNEL_OUT)

 $(KERNEL_CONFIG): $(KERNEL_OUT)
-       $(MAKE) -C kernel O=../$(KERNEL_OUT) ARCH=arm CROSS_COMPILE=arm-eabi- $(KERNEL_DEFCONFIG)
+       $(MAKE) -C kernel O=../$(KERNEL_OUT) ARCH=arm CROSS_COMPILE="ccache arm-eabi-" $(KERNEL_DEFCONFIG)

 $(KERNEL_OUT)/piggy : $(TARGET_PREBUILT_INT_KERNEL)
        $(hide) gunzip -c $(KERNEL_OUT)/arch/arm/boot/compressed/piggy.gzip > $(KERNEL_OUT)/piggy

 $(TARGET_PREBUILT_INT_KERNEL): $(KERNEL_OUT) $(KERNEL_CONFIG) $(KERNEL_HEADERS_INSTALL)
-       $(MAKE) -C kernel O=../$(KERNEL_OUT) ARCH=arm CROSS_COMPILE=arm-eabi- CONFIG_NO_ERROR_ON_MISMATCH=y
-       $(MAKE) -C kernel O=../$(KERNEL_OUT) ARCH=arm CROSS_COMPILE=arm-eabi- modules
-       $(MAKE) -C kernel O=../$(KERNEL_OUT) INSTALL_MOD_PATH=../../$(KERNEL_MODULES_INSTALL) ARCH=arm CROSS_COMPILE=arm-eabi- modules_install
+       $(MAKE) -C kernel O=../$(KERNEL_OUT) ARCH=arm CROSS_COMPILE="ccache arm-eabi-" CONFIG_NO_ERROR_ON_MISMATCH=y
+       $(MAKE) -C kernel O=../$(KERNEL_OUT) ARCH=arm CROSS_COMPILE="ccache arm-eabi-" modules
+       $(MAKE) -C kernel O=../$(KERNEL_OUT) INSTALL_MOD_PATH=../../$(KERNEL_MODULES_INSTALL) ARCH=arm CROSS_COMPILE="ccache arm-eabi-" modules_install
        $(mv-modules)
        $(clean-module-folder)
        $(append-dtb)

 $(KERNEL_HEADERS_INSTALL): $(KERNEL_OUT) $(KERNEL_CONFIG)
-       $(MAKE) -C kernel O=../$(KERNEL_OUT) ARCH=arm CROSS_COMPILE=arm-eabi- headers_install
+       $(MAKE) -C kernel O=../$(KERNEL_OUT) ARCH=arm CROSS_COMPILE="ccache arm-eabi-" headers_install

 kerneltags: $(KERNEL_OUT) $(KERNEL_CONFIG)
-       $(MAKE) -C kernel O=../$(KERNEL_OUT) ARCH=arm CROSS_COMPILE=arm-eabi- tags
+       $(MAKE) -C kernel O=../$(KERNEL_OUT) ARCH=arm CROSS_COMPILE="ccache arm-eabi-" tags

 kernelconfig: $(KERNEL_OUT) $(KERNEL_CONFIG)
        env KCONFIG_NOTIMESTAMP=true \
-            $(MAKE) -C kernel O=../$(KERNEL_OUT) ARCH=arm CROSS_COMPILE=arm-eabi- menuconfig
+            $(MAKE) -C kernel O=../$(KERNEL_OUT) ARCH=arm CROSS_COMPILE="ccache arm-eabi-" menuconfig
        env KCONFIG_NOTIMESTAMP=true \
-            $(MAKE) -C kernel O=../$(KERNEL_OUT) ARCH=arm CROSS_COMPILE=arm-eabi- savedefconfig
+            $(MAKE) -C kernel O=../$(KERNEL_OUT) ARCH=arm CROSS_COMPILE="ccache arm-eabi-" savedefconfig
        cp $(KERNEL_OUT)/defconfig kernel/arch/arm/configs/$(KERNEL_DEFCONFIG)

 endif
对于LK,修改文件AndroidBoot.mk
AndroidBoot.mk
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
--- a/AndroidBoot.mk
+++ b/AndroidBoot.mk
@@ -23,6 +23,10 @@ else
   USER_SYSTEM := USER_SYSTEM=0
 endif

+ifeq ($(USE_CCACHE), 1)
+  CCACHE := CCACHE=$(ANDROID_BUILD_TOP)/prebuilts/misc/linux-x86/ccache/ccache
+endif
+
 # NAND variant output
 TARGET_NAND_BOOTLOADER := $(PRODUCT_OUT)/appsboot.mbn
 NAND_BOOTLOADER_OUT := $(TARGET_OUT_INTERMEDIATES)/NAND_BOOTLOADER_OBJ
@@ -50,11 +54,11 @@ $(EMMC_BOOTLOADER_OUT): emmc_appsbootldr_clean

 # Top level for NAND variant targets
 $(TARGET_NAND_BOOTLOADER): $(NAND_BOOTLOADER_OUT)
-       $(MAKE) -C bootable/bootloader/lk BOOTLOADER_OUT=../../../$(NAND_BOOTLOADER_OUT) $(BOOTLOADER_PLATFORM) $(SIGNED_KERNEL)
+       $(MAKE) -C bootable/bootloader/lk BOOTLOADER_OUT=../../../$(NAND_BOOTLOADER_OUT) $(BOOTLOADER_PLATFORM) $(SIGNED_KERNEL) $(CCACHE)

 # Top level for eMMC variant targets
 $(TARGET_EMMC_BOOTLOADER): $(EMMC_BOOTLOADER_OUT)
-       $(MAKE) -C bootable/bootloader/lk BOOTLOADER_OUT=../../../$(EMMC_BOOTLOADER_OUT) $(BOOTLOADER_PLATFORM) EMMC_BOOT=1 $(SIGNED_KERNEL)
+       $(MAKE) -C bootable/bootloader/lk BOOTLOADER_OUT=../../../$(EMMC_BOOTLOADER_OUT) $(BOOTLOADER_PLATFORM) EMMC_BOOT=1 $(SIGNED_KERNEL) $(CCACHE)

 # Keep build NAND & eMMC as default for targets still using TARGET_BOOTLOADER
 TARGET_BOOTLOADER := $(PRODUCT_OUT)/EMMCBOOT.MBN
@@ -77,4 +81,4 @@ $(NANDWRITE_OUT): nandwrite_clean

 $(TARGET_NANDWRITE): $(NANDWRITE_OUT)
        @echo $(BOOTLOADER_PLATFORM)_nandwrite
-       $(MAKE) -C bootable/bootloader/lk BOOTLOADER_OUT=../../../$(NANDWRITE_OUT) $(BOOTLOADER_PLATFORM)_nandwrite BUILD_NANDWRITE=1
+       $(MAKE) -C bootable/bootloader/lk BOOTLOADER_OUT=../../../$(NANDWRITE_OUT) $(BOOTLOADER_PLATFORM)_nandwrite BUILD_NANDWRITE=1 $(CCACHE)
使用时,和Android编译环境默认开启ccache支持一样,只需要在编译环境中定义 USE_CCACHE=1 即可。

iPhone终于还是被我越狱了

| Comments

由于iOS6的完美越狱前段时间才释放出来,有洁癖情节的我纠结了几日,最终还是没能忍受住越狱的诱惑,给自己的iPhone越了狱。托大神们的福,越狱的过程非常傻瓜化,等待几分钟加一次点击就搞定。

越狱后,肯定是要装一些实用的软件才能更爽。经过网友们的推荐,经过几天的使用,感觉非常不错。现总结如下:

  1. bitesms 非常好用的短信替代软件,支持快捷发送/快捷回复短信
  2. zephyr 快捷好用的手势任务管理软件
  3. ncsetting 通知中心的快捷插件,非常简洁,同时拥有手电筒和VPN开关
  4. kuaidial 非常好用的拨号工具,来电归属地,黑白名单以及快捷拨号
  5. bulletin 锁屏界面下激活通知中心的下拉
  6. activator 快捷手势设定软件,功能非常强大,可以通过手势来呼出应用或开关某个功能
  7. music controls pro 方便的音乐播放器控制软件,未来还会支持remote server
  8. flex 非常好用的tweak软件,可以自己编辑插件,修改某些软件的功能
  9. ifile 最好用的文件管理软件

以上除了3,4,6项是免费的以外,其余的软件均需要在cydia上付钱购买。不过,花钱购买的这些软件绝对值这个价钱,真的非常好用,提高了不少效率。唯独需要注意的是kuaidial目前还没有iOS6.0的正式版,只有一个Beta版本,不过用下来非常稳定,还没遇到过什么严重的问题。另外安装这款软件需要在cydia中单独添加源:cydia.51ipa.com

越狱的成果就是这些,如有更新再添加吧。