19.怎么使用SourceInsight?
19.1用途
我们主要使用SourceInsight进行源码分析和查找,主要是查找我们所需要的文件/类的位置。对于一套源码,拥有几十万甚至更多个文件,我们可以将这套源码导入到SourceInsight的工程里,然后通过它的搜索功能,便能快速给出我们搜索结果:是否有这个文件,同时可以直接打开进行代码阅读和修改同步等操作。什么时候需要这么做呢?举一个例子帮助理解:
当我们需要解决一个PR或验证一个问题时,难免会涉及到一些并不熟悉的文件(布局、资源等xml文件等)/类,这时候,仅仅通过Eclipse或者直接去文件夹下面一个一个寻找的话,无异于于大海捞针费事费力还不一定能找到。这时候,通过SourceInsight便可以在几秒钟之内完成寻找任务,何其方便省事!
它的原理是对源码(你所选取的目录)下的所有文件建立索引,当你输入文件名进行搜索时,它便可以快速定位并显示出来。
19.2安装
因为我们是在Ubuntu下开发,而SourceInsight这个工具是Windows平台下的,因此涉及到安装问题。在这里特别说一下如何进行安装:使用wine进行安装。方法如下:
先下载SourceInsight的安装文件,一般均为后缀为.exe的执行文件,比如sourceinsight.exe,拷贝到一个存储目录,例如这里使用/local目录;
打开终端,输入安装命令:
$wine install /local/sourceinsight.exe
安装好以后打开,将SN码复制进注册框即可。
也就是说我们使用wine进行安装,以后要使用的时候,在Ubuntu系统的状态栏下的Application中,会看到Wine菜单,点击它会弹出Programs文件夹,在其中便可找到安装好的SourceInsight文件夹,点击它的logo即可运行。
19.3使用
最后讲一下使用SourceInsight的方法:
1.在最上面的菜单栏中,点击Project→New Project;
2.在弹出的对话框中,点击Browse,选择所需要导入的工程目录。
这里特别说明一下:导入整个工程或者导入一个模块均可,例如导入yarism-v1.0-dint或者下面的一个模块Settings。区别是导入的工程越大,它的初次导入时间越久(文件越多越花时间,可以理解)。但从使用经验来看,直接导入一整个项目后,在搜索的时候也不会有特别明显的卡顿。因此,作者个人一般是一整个工程全部导入的。
3.然后,起一个工程名(这个名字是用来在SourceInsight中标记的,并不影响实际源码,因此请放心随意起名),为了便于记忆区分,一般即使用源码工程名,例如使用eyelike-v1.0-dint。
然后点击OK,弹出一个确认的窗口,继续点击OK。这时弹出下面窗口:
图x SourceInsight导入源码示意图
默认选中的即为之前所选源码目录(注:作者在截图时导入的是Kitkat-v1.0-dint源码,因此图中非eyelike-v1.0-dint,请知悉不要疑惑)。点击右侧的Add Tree按钮,等待导入完全。(整个源码工程需要较长时间,需要耐心等待)。
4.导入完全后点击Close。然后,在下面输入框中输入任何想要查找的文件,即可看到文件路径等信息,单击所要查看的文件,即可在左侧打开该文件。
图x SourceInsight搜索文件示意图
以上搜索操作即可满足我们平日里的需求,是不是非常方便简单!当你关闭该工程后,可以再次点击菜单栏最上方的Project,选择Open Project,然后选择所要打开的工程即可。
20.如何单编一个模块?
前面讲了代码的全编译,但往往耗时较长(例如作者目前使用的i7处理器+8G内存,全编一次Android4.4 Kitkat源码需要5小时多)。实际开发中,我们一般只是对模块进行单独编译(单编之前必须先进行过全编译)。例如我只对设置模块做了修改,那么就只是单编设置模块,然后将该模块单独刷进手机里进行验证即可。
全编译分MTK平台代码和Google源码,单编也是一样的。
先讲在MTK平台下单编一个模块的方法:
1.进入源码目录,例如eyelike-v1.0-dint,输入如下命令(编译MTK所提供的基线代码为例):
$cd /local/eyelike-v1.0-dint/
2.输入编译命令:
$./makeMtk –t mm packages/apps/Settings/
说明:上面命令中packages/apps/Settings/为模块路径。
将单编后的模块刷进手机的方法如下:
$adb push out/target/……
省略号表示模块在系统中的路径,具体查看方法是:在单编完成后,终端会返回一些信息,其中包含了两个输出文件,均是全路径的格式进行显示,其中后缀为.APK的全路径是编译后的apk在out目录的全路径,其中的项目名称后面的部分即为该模块在手机系统中的存储路径。首先将out目录中的全路径复制到push命令之后,然后再将手机的存储路径复制到最后,中间用空格区分即可。
特别提示:有时候会报出权限不够,adb remount一下即可。
然后讲Google源码的单模块编译方法:
1.进入源码目录,例如kitkat-v1.0-dint,输入如下命令:
$cd /local/kitkat-v1.0-dint
2.输入命令:
$source build/envsetup.sh
说明:加载所有所需的系统环境变量。
3.输入编译命令:
$mmm packages/apps/Settings/
说明:上面命令mmm后面的部分为模块路径。
4.输入命令:
$make snod
说明:对于Google的源码验证只能在模拟器中进行。因为Google源码中是不包含硬件驱动等内容的,因此,不能向单编MTK平台代码直接将该模块push进手机进行验证测试。要使得编译后的单个模块在模拟器中生效,就必须了解加载模拟器的机制。简单讲,模拟器在开启的时候,会加载下面路径:
/local/kitkat-v1.0-dint/out/target/product/generic
中的system.img文件,而各模块的内容均包括在其中,如下图所示。因此,如果我们编译了一个模块后,只要保证将编译所做的修改更新到该system.img中,然后重新打开模拟器即可看到修改的效果。而上面命令的作用,就是使单编后的修改在system.img中更新生效。
图x system.img文件示意图
5.最后,重新启动模拟器即可,命令如下:
$./out/host/linux-x86/bin/emulator
特别说明:输入上面命令后即可启动模拟器。要关闭该模拟器,直接点击模拟器右上角的X按钮即可;也可以在当前终端中按下Ctrl+C组合键。另外,第2、3条命令,在一个终端中只需要输入一次即可,以后只需要键入第4条命令即可。但是,如果开启了新的终端,则需要重新输入以上所有命令,这点需要特别留意。
21.具备实际项目开发水平的必备技能?
至此,再停下来做一个小结:
我们已有了一个较为熟悉的模块,能够进行源码的下载、更新、全编、单编,能够查看PR,能够根据PR需求进行代码修改。好有成就感和踏实感是不是?此时,只要在阅读学习代码和演练PR的时候没有自我欺骗,应该已能初步负责一些简单实际项目任务了!恭喜你!
但是,还有一个重要的部分我们还没有涉及。是什么呢?——各种提交相关的操作。是的,包括代码提交、字符串提交、图片提交等等。难道不是吗?
22.如何提交字符串和图片?
我们使用MSGM网站来进行管理项目中的字符串和图片资源,网址为:http://eyelike.com/msgm/login.aspx。账号的申请,首先要在网站登录界面进行注册。如下图所示:
图x MSGM网站注册示意图
账号信息自己按提示填写即可,没有特殊规定。然后需要发邮件向集成组组长进行申请Approved。Approved通过后,登陆后进行尝试即可,其具体使用比较简单(不过还是推荐向资深同事请教,5分钟的时间将节省几小时的尝试,并能有效习得如何避免犯错)。
这时,大家肯定会产生疑惑:为什么要提交字符串和图片?请看下面内容。
23.为什么要提交字符串和图片?
23.1资源分离的原理
要解释这个问题,这就必须讲一下资源分离的机制了!
系统定制是我们公司作为国际性公司的特色(例如华为手机,明明是使用Android系统的手机,打开手机为什么会看到huawei?为什么会有各种huawei的应用和元素在里面?当然是因为我们做了文章和工作,这就是我们做了系统定制),而系统定制的一个重要目的是资源分离。资源分离的主要内容是将代码与资源(如图片、字符串、声音、相关定制值等)分离开。
如何分离开呢?首先讲未进行资源分离时的情形,比如Google Android源码,我们进行编译使用的是make命令,而make命令的运行机制即是通过多个.mk文件,将源码中分布在各个文件夹下面的内容一个个按照一定的逻辑顺序找到并转换为机器认识的形式。那么,我们将原来和代码在一起(离得比较近)的资源分离出来(统统抽出来放到一个特殊的文件夹/目录下面)。对于这些多个.mk文件造成的影响就是,它们找不到这些被移走的资源文件了。那么,我们便想办法对这些文件的内容进行修改,使得它们重新知道那些被移走的文件到哪里去了,进而在编译的时候能够找到它并生成完整的输出文件。
概括地讲,就是通过对编译系统的编译文件的修改,从而改变它的编译机制。我们因此最终实现创建了一个新的分区(partition)cuspack,将资源分离,并有了一套自己的解析定制资源的机制。
直观地讲,我们最终做到的效果是将一个代码和资源在一起的APK,分成只有代码的APK和只有资源的APK两部分。例如,本来Google源码中Settings编译后生成一个Settings.APK的文件;而在经过系统定制后,将编译生成Settings.APK(只有代码)和Settings_res.APK(只有资源)两个文件,其中Settings_res.APK将存放在cuspack分区当中。
上面的两种阐述,大概讲清了系统定制的核心内容。想要深入理解,最好请教集成组framework的同事。当你能非常熟稔地掌握各个编译控制文件的逻辑时,便完全可以在两个Team之间任意遨游了(要花很多时间学习熟悉,而且对C语言和脚本要求较多,因为大部分.mk文件是用C语言编写,而且牵扯较多脚本工具的使用;这个已经和我们的Android系统上层开发维护跑题甚远了,就此打住)。
23.2资源分离的优点:
最后说一下资源分离的优点:通过资源分离,我们将世界各个不同地区、不同运营商的不同要求所产生的各种修改问题,缩小到只需要修改定制的资源上来。如此一来,核心代码基本不需要进行修改,所有工作由Perso组代替完成,大大降低了修改不同需求所带来的人力消耗和维护成本。
23.3原因综述
正是因为有了这样的机制,诞生了一个组:Perso组,专门负责这些定制资源的管理。为了提高效率,他们使用一个叫做MSGM的网站。通过它,可以方便地与UE(美工/设计)、开发工程师进行资源的交流。因为不同地区的语言、风格等等差异,手机系统的上层应用会出现各种适配需求(翻译、图片等等),这些问题均由开发工程师在工程代码中进行验证、确认或修改。所以,提交字符串和图片便成了一项十分普遍和重要的工作了。
24.代码的目录结构?
作为上层开发者,在主代码根目录有四个文件夹操作比较频繁:packages(各模块代码主要位于此处)、frameworks(系统框架代码主要位于此处)、mediatek(MTK代码主要位于此处),而以“项目名_wimdata_ng”命名的文件夹,则是各定制资源所在。其下,又分若干文件夹:wcustores(主要存放图片、声音等资源)、wlanguage(主要存放字符串资源)、wprocedures(主要存放各plf定制值)。如下图标注。
图x 代码主要操作目录示意图
25.如何提交代码?
作为开发人员,解决的很大一部分问题是以PR进行记录的。而大部分PR的解决又是以修改代码为主要方式的。既然修改了代码,怎样才能提交到服务器?这部分特别重要,因此下面将花费较大篇幅进行详细讲解。
提交代码的步骤:
25.1提交前的确认工作:
首先我们要确保已经有代码被修改,其次确保修改后的代码可以编译通过,第三要确保所修改的代码着实可以满足PR需求。达到这三个要求,即可安心提交。否则,千万不能提交,一定要保持严谨的态度使得三个要求具备,缺一不可。
下面详细阐述这三个要求的具体内容:
一、很明显,如果代码没有被修改,提交是没有意义的,这点不多说了;
二、修改后的代码编译可以通过,可以保证不会影响整个源码的编译工作。即使你所修改的功能不正常,但一般不会影响别人的模块和功能。这对于团队协作的开发模式,尤其又是代码量巨大的工程来说是非常重要的。因为一旦你的提交导致源码编译报错,其他人的工作都会受到影响,从而降低整个团队的开发效率。
三、我们的修改是为了解决问题,如果所作代码的修改不能有效解决问题,那么提交上去只是多此一举。而且会面临被测试人员打回的风险(PR往往要送到测试部门的测试工程师那里去进行验证,既然没有满足修改需求,当然会被打回重新修改),而这是非常严重的质量问题。对于一个软件开发工程师来说,这无疑说明你的能力水平的低下,将严重影响你的绩效(和工资奖金挂钩的评比工具,大部分是以打分的形式进行);对于测试工程师来说,使得他增加测试工作量,浪费人力;对于整个项目来说,加长了PR生命周期,拖慢了整个项目进度。由此可以看出,真是有百害而无一利!
然而,怎么避免出现严重的质量问题呢?答案是仔细严谨地修改代码,并一定做好本地验证工作。
25.2提交代码的方法:
1.打开终端,进入存储目录(本例中进入/local目录),敲入下面命令:
$cd /local
2.新建代码提交目录,例如我们的本地源码目录为:kitkat-v1.0-dint,在其中进行了修改,那么可以建立一个目录名叫做kitkat-v1.0-dint-temp(名字随便起,便于标识区分是哪个项目的提交目录即可)的文件夹(不使用命令直接手动建立当然也是可以的):
$mkdir kitkat-v1.0-dint-temp
3.进入该代码提交目录:
$cd kitkat-v1.0-dint-temp
4.从服务器同步项目manifest文件,即代码下载命令的前面部分(本例的代码下载命令为:repo init -u [email protected]:aosp/manifest -m kitkat-v1.0-dint.xml && repo sync):
$repo init -u [email protected]:aosp/manifest -m kitkat-v1.0-dint.xml
说明:此时,在这个代码提交目录即有了我们的下载配置文件,与我们的源码目录kitkat-v1.0-dint中的一致,只是现在我们还未下载任何代码进来。下面是关键的一步,即下载我们需要提交的库。这里涉及到库的概念,即我们的一套源码,在服务器中是以库为单位进行存储的(类似于模块的概念,只是划分的维度可能会有所不同)。因此,我们的提交也是对应于库进行提交的,最直观地说明就是,我们必须在一个文件目录下面进行代码的提交,而这个文件目录,就是一个“库”。
我们上层开发主要涉及到的几个库为:frameworks/base(在源码目录/frameworks文件夹下的修改提交到该库)、packages/apps(在源码目录/packages文件夹下的修改提交到该库)、xxx(项目名)_wimdata_ng/wprocedures(在源码目录/ xxx(项目名)_wimdata_ng下修改了plf文件后提交到该库)。
本例中以修改SettingsProvider.java类后的提交为例进行说明,该类在源码目录/frameworks下面,因此,
5.我们键入下面命令,从服务器同步该库的代码:
$repo sync frameworks/base
说明:此时,我们的kitkat-v1.0-dint-temp目录即是服务器中该库的最新代码,我们可以想到,与我们本地的kitkat-v1.0-dint目录中的同样的库代码中,有一个类SettingsProvider.java的代码是不同的。我们的提交所希望达到的目的便是让服务器中的同样的库同样的类的代码与我们本地kitkat-v1.0-dint目录中的代码一致。下面便需要借助一个叫做Meld Diff Viewer的对比工具了(后面有教如何安装)。
6.键入命令:
$meld
说明:此时可以打开Meld工具的窗口界面。
6.1点击最上面菜单栏的File,点击New,出现如下图所示界面:
图x Meld代码导入示意图
6.2点击图中Original后面的Browse按钮,导入未修改的源码,这里即下载下来的kitkat-v1.0-dint-temp目录中的SettingsProvider.java类;
6.3点击图中Mine后面的Browse按钮,导入修改后的源码,这里即我们的本地源码kitkat-v1.0-dint目录中的SettingsProvider.java类。
6.4然后点击OK,即可看到两套代码中该类的对比,如下图所示:
图x Meld代码对比示意图
说明:上图中右侧即为本地修改的代码,而左侧即为服务器下载下来的未修改的代码,绿色标识出来的即为代码有差异的部分。中间有个黑色箭头,点击它即可将右边的修改插入到左边去。
6.5点击黑色箭头,将修改导入左侧代码中;
6.6点击最上面的Save按钮保存该修改。
说明:此时,kitkat-v1.0-dint-temp目录中的代码库便与kitkat-v1.0-dint中的对应的代码库相同了(本例中是frameworks/base库)。
至此,大家心中应该慢慢有所明了。我们接下来所需做的,便是将kitkat-v1.0-dint-temp中的代码同步到服务器上。
7.进入kitkat-v1.0-dint-temp目录下的frameworks/base/:
$cd frameworks/base/
8.查看确认所做修改:
$git status
说明:上面命令可以查看当前目录是否有修改,是否有提交更新到服务器,如果有修改会将修改的文件显示出来。
9.接着输入:
$git diff
说明:这个命令可以将修改的代码显示出来,同前面小节所讲在Gerrit网站查看修改记录的效果一致。
10.输入提交代码命令:
$ /automount/tools/scm_tools/tools/patch_delivery_cli.php -p ff
说明:至此,所有确认工作OK。
上面命令表示使用patch_delivery_cli.php脚本工具来提交代码。还记得前面讲如何查看别人的PR修改记录吗?当时提到我们提交代码成功后脚本工具会自动在Bugzilla上面的该PR的Comments中插入修改记录的链接,那个脚本工具就是这里的patch_delivery_cli.php。这下前后连贯起来了,是不是有中恍然觉悟豁然开朗的感觉?又该恭喜你了!
11.接着根据终端出现的提示,输入对应的信息:
11.1第一个是项目选择,它会提供所有项目的名称编号,根据我们的PR属于哪个项目,输入对应数字编号按Enter即可。
图x patch_delivery界面示意图
11.2接下来是输出Bug Number和patch comments等信息,如上图所示。这里特别注明:PR号一定要填写正确,Comments从Bugzilla网站上复制过来即可(我们在提交代码的时候,一般都同时开着Bugzilla,以复制这些必要信息)。其余根据提示填写即可,没有强制规定,但提倡使用严谨的语言风格。另外,在patch comments中填写完毕后,按Enter键,然后再出入一个“.”,然后再按Enter键才可以进入下一步。其他选填项如果不想填写,也均使用“.”表示结束,这点需要特别知会。
11.3最后,确认command输入yes。
说明:此时,代码提交的任务便提交到了Gerrit网站。又得回顾一下之前所讲,Gerrit网站是用来做代码审核的。
12.登陆Gerrit网站,此时可以看到我们刚才提交的代码已经对应生成了提交任务,点击该任务,设置代码reviewer,如下图所示:
图x Gerrit添加Reviewer示意图
在Add Reviewer按钮左侧的输入框输入reviewer的邮箱,然后点击该按钮即可完成添加。添加成功后可以在下图中红色方框标识的地方看到reviewer的信息。
图x Gerrit添加Reviewer成功示意图
这样Gerrit网站就会自动发邮件到你所设置的reviewer的邮箱,当他登陆Gerrit网站后就可以看到你的修改审核任务。
13.等待审核通过,通过后,重新登录Gerrit网站。便可以在Gerrit网站上发现一个Submit的按钮,如下图所示:
图x Gerrit审核通过示意图
14.点击Submit按钮,当该patch显示如下图红色方框信息后,表示大功告成!
图x Patch提交成功示意图
特别说明:
一、如果没有审核通过,你将会受到Gerrit网站自动发给你的邮件通知,你需要做的是重新查看并修改代码,然后再重新提交。这个操作就不用多赘述了吧!
二、有时候,我们提交代码比较着急,希望能尽早被审核通过,那么,提交后直接去代码reviewer座位上告诉他比较紧急请他尽快review,是最好的办法。
26.怎么安装Meld Diff Viewer?
Meld Diff Viewer是Linux平台下的一款对比工具,可以进行文件、目录的对比。当然,也有很多人使用另一款对比工具Beyond Compare,其为Windows平台下的一款强大的对比工具,但是收费需要破解。既然我们本身就是在Ubuntu下面工作,那么使用Meld便可以了。它十分简洁,而且免费,对于我们提交代码的对比工作,已经足够使用。
如果系统中还未安装,使用下面方式可以进行安装:
1.打开终端,输入下载命令:
$sudo apt-get install meld
2.提示输入密码:
$eyelike(本机的Ubuntu系统登录密码)
如果出现
“Sorry, user user is not allowed to execute ‘/usr/bin/apt-get install meld’ as root on aclgcl-ubnt22”
的错误时,说明sudo权限设置还不OK。进行如下设置(因为一般公司中出于安全考虑,管理员权限都没有下放到开发工程师个人,所以去请集成组同事帮忙设置一下,需要root权限):
1.先输入命令:
$su
2.然后输入密码:
$xxxxx(这个集成组管理系统配置的同事知道)
3.然后进入root账户,输入命令:
$vim /etc/sudoers
4.在其中添加添加user账户代码,如下:
“(复制root账户代码后粘贴,将root字段修改为user即可)”
5.然后保存退出,完成设置,即可正常安装软件。
27.怎么接手实际项目?
至此,已经可以独立提交代码了!这也预示着具备接手实际项目的能力了,心中难免激动又忐忑不安,这都是正常的。
其实,比较好的节奏是开始的时候接手一些预研任务。基本任何一个完整的项目,开始都有一段时间的预研,用来将参考项目(一般是之前已经开发的过的项目,很多问题类似,很多代码可以参考共用)的一些功能需求预先熟悉,导入到我们自己将要开发的项目代码中来(此时你是可以使用参考的代码修改来直接解决任务的)。预研任务的特点是难度系数较小,但是任务繁多,再适合熟悉代码和练手不过了!所以,不要太担心,你已经一步一步进入实际项目中开始有自己的产出了。
寄语
至此,一名合格的初级开发人员已然成型,假以时日熟悉各种操作和加深对模块代码的理解和熟悉,便可达到“海阔凭鱼跃,天高任鸟飞”的层次。本文只是将作者从初学到最终能够接手实际项目的学习过程中所遇到的问题、所认为必须了解掌握的内容整理而成。万事从无到有难,在茫茫不知所措时曾经极度渴望有人、有文章来指点江山;也曾遇到因为不了解一个小小的知识点而花费大量时间的时候。好在受到非常多的同事、负责的导师等人的帮助指点,最终完成了项目前的学习。这篇文章便是对他们的感谢,也是为像曾经的我一样怀着对Android开发的热爱和激情的后来者所写,希望其中的某些知识能实实在在帮助到他们,给予他们学习的动力。文中难免有勘误,希望自己没有犯出误导大家的根本性错误,这样便满足了。俗话说知识无止尽,还有非常多的东西没有抒写出来,也还有非常多的东西没有学习。但是,相信只要我们有了足够的基础,有足够多的耐心去学习摸索,那未讲的未知的终将变为自己熟悉的、自己能力的一部分,并产生出更多更大的价值。末尾,赠一句:“我们都在路上,加油,与君共勉!”
最后附上我整理精选后的一些常用快捷键和知识:
[email protected]