【思考】学习源码的三重境界

记得刚工作那会儿,看ART或者Binder的源码就像看天书一样,完全没有头绪。Binder还好一点,有许多相关的博客和书籍可以参考。而ART完全是摸黑,因为当时市面上没有任何一本介绍ART的书籍,只能从JVM的知识体系中找一些参考。

曾国藩曾用"结硬寨,打呆仗"六个字总结自己的治军方略,这六个字对于源码学习也同样适用。当一个知识缺乏外界参考时,反复地阅读源码也许是最好的办法。这让我想起之前和小米某位前辈的一次聊天,他说自己在职业早期凭借一招便树立了自己的技术招牌:当时从事的工作经常会碰到复杂的底层问题,而这些问题的调试严重依赖GDB的使用,因此他把厚厚的GDB官方手册从头到尾读了好多遍,烂熟于心,之后在复杂问题的调试时大放异彩,为人所知。这个观点我深刻认同,因为在学习这条路上,不走捷径就是最好的捷径。

在我看来,学习源码是一个漫长且艰辛的过程。随着时间的推移,方法和认知也会发生改变。以下便是我在学习源码的三个不同阶段的认知。

第一重境界:看山是山。

"看山是山",强调的是理解知识的细节,是"知其然"的过程。这一阶段的典型特征是在写博客时喜欢贴大段的源码,譬如我早期的博客。这就好比导游领着大家前往一座漂亮的宫殿,介绍着里面的每一处细节,让大家知道柱子是柱子,窗户是窗户。

这个过程从"不知"到"知",因此会有强烈的收获感,但同时也是局限的。我们可以拿着源码跟别人辩论:看,代码就是这么设计的。但如果别人反问我们:为什么要这么设计呢?我们多半会哑口无言。

第二重境界:看山不是山。

"看山不是山",具有两个维度的含义。一是跳出细节,从宏观的维度思考每一处的关联,以及为什么要这么设计;二是用历史的眼光来看待源码,了解它变化的过程,而不是单一孤立地局限在某个版本。它强调的是理解设计者的意图,以及冲破权威,思考设计者可能犯的错误。这一阶段是"知其所以然"的过程。前几年开始,我在写博客的时候就刻意去减少贴源码的行为,而是通过框图的形式来展开描述。这样会逼迫我去结构化地总结知识,并尽量用清晰明了的语言讲述出来。这个阶段,我们会慢慢感觉到很多代码的设计模式其实都脱胎于实际生活,以及算法在其中的重要性。

这里提两个技巧,能够帮助我们更快地理解设计背后的原因。一是借助cs.android.com,通过git blame和git history找到某一个机制引入的具体改动。接着在android-review.googlesource.com上查找这笔改动提交时的commit message和具体的讨论,帮助我们了解设计者的设计初衷。二是通过git history可以查看提交者的邮箱,如果有更进一步的问题,可以直接邮件联系原作者,而不用在那里猜测设计者的意图。

第三重境界:看山不如上山。

马克思曾说过:哲学家们只是用不同的方式解释世界,而问题在于改变世界。对于源码学习,最好的方式一定是在实践中学习,这是我近一年来才有的感悟。理解和学习其实是个被动的过程,缺乏实际的检验机制;而当我们主动去写一些新的代码、新的框架时,如果知识理解不到位,代码的运行就会有问题,因此这样的反馈机制可以帮助我们正确且深入地理解知识。

举两个例子。

一个是我之前给ART主线贡献的JNI优化,开发过程中碰到的问题有二十多个。有些问题报出来时自己都绝望了,因为根据当时对于源码的理解觉得不可能发生,而谷歌从有限的错误log中也看不出问题所在。硬着头皮一步步地去调试、比对、阅读源码,最后发现其实是自己理解的不够全面,忽略了某些情况的考虑。像这样的实践过程常常会陷入到无助的情绪中,但我一般都劝自己:今天解决不了,说不明明天就想通了。神奇的是,这样的心理暗示往往会有不错的效果。

另一个是我最近在弄的ART Java Hook方案。关于ART Java Hook,我几年前就有关注,但只局限在一些博客的阅读上,理解非常肤浅。最近之所以动手写一套,一是因为自己感兴趣,二是因为有朋友说他们有这样的诉求,目前市面上的ART Java Hook都不够稳定。写的过程中我重点参考了epic和pine的源码,也仔细学习了SandHook、FastHook、YAHFA的原理文章。在它们的基础上,叠加上我对于ART的理解,便产生出很多新的想法和思路。其中有些想法是朦胧的,为了验证是否可行,我需要再去研究ART源码中一些特定的细节,以及ART中优化对Hook方案可能产生的影响。总之,写一套可用的方案或许不难,但写一套考虑全面、具有较高稳定性和兼容性的方案比较难。后者需要对ART内部很多机制有细致的了解,而不仅仅是一个大致的概念。这个过程其实也是逼迫自己去加深源码理解的过程。

后记

如今的互联网资料众多,大多数人学习新知识时习惯从书籍、博客、视频入手,但我强烈建议大家也去看看源码。从这些优秀开源项目的源码中,我们可以学习到优秀的框架、精湛的算法以及优美的写法。孔子有云,见贤思齐焉,长期地从这些优秀项目中汲取养分,相信对于我们自身的能力提升也大有裨益。

相关推荐
studyForMokey5 小时前
kotlin 函数类型接口lambda写法
android·开发语言·kotlin
梁同学与Android8 小时前
Android --- 新电脑安装Android Studio 使用 Android 内置模拟器电脑直接卡死,鼠标和键盘都操作不了
android·ide·android studio
CHHC18809 小时前
开源商业级源码(快递柜/云停车/售货机)
物联网·源码
源码宝10 小时前
Java语言+后端+前端Vue,ElementUI 数字化产科管理平台 产科电子病历系统源码
java·程序员·源码·软件开发·产科电子病历系统源码·医院产科信息管理系统源码·数字化产科管理平台源码
山雨楼10 小时前
ExoPlayer架构详解与源码分析(14)——ProgressiveMediaPeriod
android·架构·音视频·源码·exoplayer·media3
IsaacBan12 小时前
XJBX-6-Android启动App进程
android
DoubleYellowIce12 小时前
Android Studio阅读frameworks源码的正确姿势
android·android studio
分享者花花12 小时前
最佳 iPhone 解锁软件工具,可免费下载用于电脑操作的
android·windows·macos·ios·pdf·word·iphone
源码宝14 小时前
基于B/S架构+java语言+ 开发工具Idea,vscode医院产科信息管理系统源码 如何标准化对接技术及各个模块
java·程序员·源码·软件开发·产科电子病历系统源码·医院产科信息管理系统源码·数字化产科管理平台源码
小菜琳17 小时前
Android显式启动activity和隐式启动activity分别都是怎么启动?请举例说明二者使用时的注意事项。
android