Android Framework 如何学习,如何从应用深入到Framework?

论坛 期权论坛 知乎     
知乎de用户   2019-8-18 00:57   34789   5
转载声明:本文由互联网用户自发贡献,部分转载来源来自知乎(zhihu.com),强烈建议您访问知乎查看完整内容。本社区不拥有所有权,也不承担任何法律责任。如有侵权,请联系optbbs@163.com。一经查实,即刻删除。
看了深入理解安卓1,看到第7章,看了安卓源码情景分析,看到日志那章,还看了一点安卓内核剖析,看着看着就看不动了,现在又拐回来看应用,关于系统方面的书前面讲原理的比较多,以至于工作中感觉接触到AMS,PMS,电源服务还没看到,就不想看了,我还没有跳读的习惯,每本书都想从头看到尾,但又限于水平有限,很多都不能充分理解,看着看着就看不动了,应用的层的书籍又很少涉及Framework方面的知识,就感觉应用的时候实现难度还不大,一到修改系统方面知识的时候就感觉难度很大,方法调用的跨度太大,一些界面实现管理跟应用差别很大,就想问下怎么才能找到正确的入门方向?
----------------------------
9.20号更新一下。
深入理解安卓卷1没有必要看完,看下1到6,9和10就行了,也可直接看卷2和卷3.
分享到 :
1 人收藏

5 个回复

倒序浏览
2#
热心回应  16级独孤 | 2019-8-18 00:58:00 发帖IP地址来自
犹豫了整整两天要不要写这个回答,结果看到500+的关注,只有寥寥15个回答,觉得还是分享一下自己觉得高效又无痛的方法罢。( 最高票的@Groffa 先生总结非常到位,观点本身没什么问题,但观点的展开有点潦草)

首先放个地图炮,任何光讲源码的书都是耍流氓,无一例外。作者或许是大神,或许对于每一个地方的每一处源码都烂熟于心,但并不代表他们可以写出一部好书。原因很多时候在于,Android的功夫,在Android之外。这是理解Android源码的“道”,也是我近几年来愈发强烈的感受。

至于“术”,我只想说大神博客也好,书也好,90%的讲述方式都是错误的——作者展示出Android源码,然后告诉你这段是干嘛的,然后下一段……这样的书或博客,我个人看得非常痛苦,一开始我不明白为什么,工作了第三年,猛然明白,读起来痛苦的原因是倒转了因果。


几乎所有代码or模块or系统的开发初衷,都是为了解决某一问题。如果你光看源码,哦这个是干嘛的,那里调用了哪个API,这样看毫无意义,这样的所谓“讲解”书也毫无意义。大把的《深入XXX》实际上都没有深入,因为他们并没有搞清或说清,这里有个什么样的问题,而这个部分模块or源码怎样解决了这个问题,以及曾经其余的系统上如何解决这个问题——更有甚者,他们讲完解决方案,然后再编个问题出来,且说的好像这个问题只有这唯一一种方案可解一样……


就比如题主和很多答主提到的Binder机制,所有人都能说出来它是跨进程通信用的,可是你依然会看得想要吐血。包括很多blog讲起这部分,都有一种先有答案后编个问题出来的嫌疑,理解并不深入(尤其是上来就将Media部分的,大部分根本只讲了“怎么用”,完全没有“为什么”的部分,这也好意思起名字叫“深入理解XXX”)。

你想搞明白,首先要忘了Binder。然后想想看,有什么样的方案实现一个跨进程通信的方式?最容易想到的,一个是“共享内存”的方式或是“共享磁盘文件”的方式。其余的方式呢?

想不到去看看旧有的Linux系统上的演变过程,当你看到管道(Pipe)方式的实现,就会开始恍然大悟——原来还可以通过这样。然后你会更加理解UDS(Unix Domain Socket,非TCP/IP里面的那个socket,很多人会困惑与此)的出现,此刻你心里对于Server-Client端互相建立起IPC链接的过程才将变得明朗,甚至可以推出RPC(Remote Procedure Calls)的实现模型。

到这里,你再去看Binder的实现,从宏观的模型开始,一切都变得异常清晰起来。对于Binder Client和Binder Service各自的角色有了理解,Binder驱动与ServiceManager的联动,就变得更加清楚——和UDS或者RPC是不是很类似?甚至更容易理解一些,如果更加抽象的形容,ServiceManager就像DNS一样,负责Client查询到BinderService的IP地址(这也就理解了为何ServiceManager的通信标志恒为0),而Binder驱动则是路由器的角色。

然后细化下去,针对每一个模块本身的职责,询问更细节的实现,永远记住,先有的问题,之后才有的代码——这样才能理解为何Parcel是必要的(跨进程通信的高效序列化数据载体),为何IBinder或BpBinder是必须的,AIDL又是什么用——代码实现是新鲜的,但是有了之前的铺垫和对问题的预期,它们的出现才是可理解的。这是理解Android源码之“术”。

当然,说起来容易,做起来难

整套模块看下来,抛开信息检索能力不谈,你需要补一些C++的基础,需要补计算机系统的基础,甚至需要理解设计模式——但不是说你成为任何一方的专家才能理解,只是随着一点点深入问题,随时去补课罢了。所以说跳着看书的能力是必须的,不是你想不想或者喜不喜欢的问题,它就是必须的——你唯一的问题就是愿不愿意让自己适应它,还是找个借口绕路。

所以这个问题又回到了最初提出的观点——Android的功夫,在Android之外。你要想“理解”而非单纯的“知道”,想“学习”而非单纯的“记诵”,我觉得没有他路可走。

总结起来就是:
  • 先理解模块对应的要解决的“问题”是什么,再去给问题找解决方案的思路去理解源码。
  • 理解源码的功夫不止在Android本身,也要提高Android之外的姿势水平。


最后,继续鄙视那些玩了几个app、听说Android开发语言用Java就对Android嗤之以鼻的自大狂们——对于Android这个庞大的知识库来说,90%的人离入门都还差得远呢。
3#
热心回应  16级独孤 | 2019-8-18 00:58:01 发帖IP地址来自
谢邀,不太赞同最高票的答案。
Android的功夫,在Android之外。
这句话我很认同,Android Framework只不过是对底层系统的封装,要想深入理解它,必须熟悉JNI、读得懂C++、理解Java虚拟机、Linux系统甚至汇编、指令集等等。但是,这并不意味着想要理解Android Framework就必须熟悉这些东西!逆命题与原命题并不是等价的。等你学完上述那些知识,Android说不定已经黄了(当然如果你真的掌握了这些,下一代操作系统是什么已经不重要了)举个例子,回想一下你小时候学习说话的时候,大人教你会先教你语法吗?我可以肯定世界上所有的语言教育都不会这么做,大家都是先教你喊爸爸妈妈,进而一些简单的词汇,然后一些简单的句子,等你都熟练了,再让你学习语法,一样的道理。对于一个有一定语言知识的人,也是一样,你学英语的时候,也是先学习how are you, I am fine, thank you的吧?如果一个领域对你来说是全新的,你就硬着头皮去打基础,有了一定的认知,再去通过你的元认知能力去深入学习。所以,我觉得不要等到万事俱备的时候才去做某一件事,一旦决定去做,天亮就出发。

另外,我不觉得那些讲源码的书有多烂;要想搞清楚一个系统的构架、设计以及当时碰到的问题以及做出的抉择,恐怕只有系统的设计者才能讲的清楚;据我所知,按照这个观点只有《C++的设计与演化》才能算得上所谓的「好书」。那些写书写博客的人,作为传经布道者,很有可能也无法理解某些设计——很多抉择都是处于当时的特殊场景以及历史原因;但是这并不妨碍他们给你讲解这方面的知识。在看《深入理解XXX》这种书的时候,我有两个经验:
  • 不要记那些所谓的API调用链,哪里调用了哪里,又从哪里跳转到了哪里;根本没用,而且你也记不住。你要思考以及关心的是,作者是怎么跟踪调用的?一个上千行的函数体,作者是如何知道哪里是下一个关键入口的?比如从Java的native函数,如何找到正确的C++实现?一个Binder Client的调用,怎么知道他的Server在哪里?然后你自己可以尝试跟踪一下,看看自己会不会跟丢;如果你可以做到,那么你差不多就可以自己分析源码了。
  • 既然你记不住细节,那么你就需要理解,需要思考;想一想这里为什么这么做,这样实现是优雅还是谬误,如果是你,你怎么做?当然,并不是所有的地方都需要这样,那些没有味道的代码,还是略过吧。把它当作参考书;自己理解一遍之后,再碰到这种问题,直接翻书,不要自己跟了浪费时间。
简单总结一下就是,看那些讲源码的书或者博客的时候,除非你要了解某个细节,那么不要过于关心那些复杂的函数调用链,学习跟踪方法以及把握整理流程最为重要。Android源码树异常庞大,如果你想一行不漏地看,不可能;就算你这么干了,效果也不见得好——只见树木,不见森林。打个简单的比方,Activity的启动流程,你不用关心在AMS里面这里跳到那里是干什么,还有ActivityStack以及它的那个SuperXX跳来跳去是在搞毛,你需要了解的是:在Context里面,通过AMS的Client ActivityManagerNative发起Binder调用进入system_server进程,在AMS里面绕了一圈(处理Activity栈以及生命周期相关),然后通过IApplicationThread这个Binder调用回到App进程的Binder线程池,在线程池里面通过Handler发送Message到App主线程,最终通过ClassLoader加载Activity类,创建对象,回调对应的生命周期,整个过程结束。

作为一个过来人,我很认同 @Van Bruce Android的功力在Android之外这个观点;同时作为一个初学者,我也相信,要了解Android Framework也没有想象中的那么难。

扯了这么多,来正面回答一下这个问题吧。

先纠正题主几个错误:

1. 「没有跳读的习惯,每本书都想从头看到尾」这个是绝对错误的,技术书与文学等其它类别的书籍不同,你没有必要每一章都看,必须纠正这个习惯。第一,不是所有的书每一章每一节每一段每一句都是精华,花时间去看那些价值不大的,就是浪费时间;而且,越到后面,你需要掌握的知识以及要看的书也越来越多,个人压根儿没有精力也不可能全部看完;挑一些重点的,自己感兴趣的看就可以了,如果你不知道什么是重点,向前辈请教或者来社区这种地方提问就行。
2. 「很多都不能充分理解,看着看着就看不动了」,这个也是不对的。没有人能够一看就懂,一学就会。都是一点点理解、摸索然后再融会贯通的;一次不理解没有关系,多看几次,慢慢就有感觉了。犹记得我当初不理解Binder,老罗的博客,《Binder设计与实现》还有源代码,我前前后后完整地看了不下六遍;熟能生巧,如果你能把书中看到的,自己思考的,源码里面学到的这些散落的东西连成串,有了自己感觉,那么前面就是通途了。

-------------------------------手动分割-------------------------------------

如何学习Android Framework?路只有一条:Read the f*cking source code。至于如何「平稳」过渡,其实我觉得学习曲线并没有那么陡峭——Android Framework的代码不也是代码?不理解是因为没有整体把握而已。

不论是看书,看博客,你的最终目的只有一个「学会看源码」,而不是「学会源码」。关于如何阅读源码,这不是一个简单的问题,我有几点经验:
  • 看不懂的多读。上面已经说过了,没有人一学就会;特别是对于初学者,你刚看系统源码,肯定一头雾水;万事开头难,在你觉得艰深晦涩的时候,你就当在背课文;Android Framework的代码时遵循一定规范的,你在背了一篇课文之后,再去读别的课文,读到一半的时候就算你看不懂,很有可能你就会知道下面要讲什么了,虽然下面要讲的你也不懂。背熟了之后,你就可以想每一句是什么意思了;而这里面的「段落」、「句子」不就是普通的代码吗?就这样,一步一步串联起来,聚沙成塔,积少成多,就水到渠成了。「书读百遍,其义自现」讲的就是这道理。如果你真的想要学习Framework,一定要多读,硬着头皮读,不要放弃,否则都是扯淡。
  • 不重要的少读。看不懂的很容易知道是什么,那么怎么知道哪些代码是不重要的呢?这里有两层意思:其一,强调的是大局观,在初学习一个模块的时候,你需要先把握整体,再了解局部;这个场景下,所有的细节都是不重要的。其二,那些真正不重要的逻辑;你刚学习的时候肯定没有办法知道哪些是影响不大的逻辑,所以你需要跟着书籍,博客,让前人带路;如果跟着它们的脚步走通了这条路,那你就自己独立走一遍,这时候你肯定会走丢,然后你跟踪、尝试,接着到达终点;这时候你自然就知道,哪些重要,哪些不重要。
  • 边读边思考。学而不思则罔,思而不学则怠。带着问题去阅读源码,这里是什么意思?为什么需要这么做?这样的实现是优雅还是俗套?有没有更好的实现办法?如果我来写,我会怎么写?诸如此类,有了思考就有了自己的理解。
  • 不是所有的都需要思考。接上条,Framework的代码也是人写的,有精华,自然有糟粕,也有食之无味的。你不用对着每一段代码都问个十万个为什么。一个问题通常有很多种解决方案,当时的设计者选择目前这种实现,有兼容问题有历史原因,还有它自己的理解;不是所有的实现在现在看来都是很好的实现,所以,追问这些问题很多时候都没有意义,不要过度解读。举个例子,Android的IPC机制为什么用Binder?也许有人说,Socket不安全,效率不够高;共享内存使用不方便,等等。但是你去看看这个问题:为什么 Android 要采用 Binder 作为 IPC 机制? - Android 开发 你就知道,很多时候并没有那么多为什么。
  • 记得做笔记。做笔记的重要性在于,它可以记下你自己在某个阶段自己的理解,当你更进一步的时候回头再看当初的理解,想想哪里是对的,哪里又有问题,这是一个相当有意思的过程。我想每一个人在看自己之前写的代码,都会有在某个地方觉得自己是沙比的时候。根据你学习过程简单总结一下,这样你的元认知能力就得到了提升。
最后自荐一下我的博客:Weishu's Notes 里面有我对于Binder以及Framework的理解和学习过程,一定会有帮助 ^_^ 至于其它细节问题,可以参考一下我其他的答案。

最后,文明交流,拒绝撕逼。
4#
热心回应  16级独孤 | 2019-8-18 00:58:02 发帖IP地址来自
做过三年framework,自身总结了一套学习方法,大致如下三点。勤加练习,一般性模块可以看的非常快。
1、高度抽象,构建框架
2、重要函数,深究细节
3、善用工具,及时总结
下班再补充具体细节~

----------------
5月29更新
非常抱歉拖了这么久,真的比较忙。。。

Android源码非常庞大,但设计很精妙。纵向分层,横向模块化,使得整个源码更易更新和维护。在手机厂商做framework的更倾向于说自己是做Android系统的,维护的模块主要包括ActivityManagerService、WindowManagerService、PackageManagerService、PowerManagerService、SurfaceFlinger、通信模块、多媒体模块等。Android系统良好的模块化设计使得各个模块负责人只需搞懂自己的模块就可以胜任工作。但是搞定自己的模块并不那么容易,对于新人一般要大概做半年才能掌握其精要,有的做了一年发现还有很多点没有掌握,这也是很常见的。

对于应用开发者来说,他们并不需要修改系统代码,学习framework只是为了了解并理解某个API调用底层的运行机制,要学到这个深度级别还是比较容易的。

首先必须了解一些背景知识。1Android系统采用C/S架构;2绝大部分IPC通信采用Binder通信;3核心Service大多运行在System_server进程;4核心Service代码大部分都在frameworks/base/services目录下;⑤别一上来就看Binder!!!6别一开始看源码就钻牛角尖!!!

以下便是我的学习方法,不保证适合其他人,供参考。

首先,大概了解下该Service是干什么的。我会搜一些好的分析文章收藏起来,大概浏览下该Service为上层应用提供了什么功能?(这些文章并不会去挨个读,这跟绝大多数人习惯不一样,他们一般是一边看分析文章一边看源码)。在源码里找到源码文件,大概看下核心几个文件开头的注释,注释一般会说的非常清楚这个是干嘛的。(我用source insight看源码)

然后,可以尝试写一个小demo,方便调试Service内部方法或抓取系统日志来追踪代码流程。运行在system_server进程中的Java代码均可使用Android studio调试,当然必须是自己编译的image才行。MTK平台手机部分service是可以通过adb shell dumpsys XXX log XX来开启对应service的log。

接着,从核心API调用入手,一步一步分析源码,理出一个从应用端到Service端,最后回到应用端的函数调用链。这条调用链必定很长很长,有非常多的分支,还会出现非常多的类,这个时候就要抓住主线不放,细枝末节可以不管。借助UML工具了,一般画两个图就够了,一个是类图,一个是时序图。画图要精简,只画重要的主线分支时序图和主要的类关系。这个步骤最难的是理出主线分支调用,切记钻牛角尖偏离目标任务,只需理出一个client-->service-->client的框架即可。将时序图画出来后,整个框架便构建出来了。(我用starUML工具)

然后,在上面的框架中必定有几个非常关键的函数,把它搞定。搞定方法就是一行一行读代码,读懂每一行并不容易,需要联系上下文进行理解。从重要函数中要理清service是如何管理target的,比如AMS是使用Stack和Task来管理Activity的,使用两个队列来处理广播,扮演连接者将client和目标ContentProvider建立起连接等。这个过程也是最花时间的,因为你需要从源码里面尽可能地还原作者的设计思想,还原的越彻底,理解的越透彻。一般我是一边理解一边用笔记记录自己的理解。(我用有道云笔记)

最后,整理出一篇笔记,方便以后回顾。在前面两步做完,图有了,分析也有了,稍微整理下便成了一篇文档。一般情况下是这样的,今天你理解的差不多了,一个月后你估计只记得大概个轮廓,细节全忘了,两个月后估计连轮廓都忘了。相信我,这时最管用的就是那两个图了,一看就能让你想起80%,所以我非常喜欢画类图和时序图。

最后的最后,将最开始搜集的那些文章利用零碎时间看一遍,相信我你会发现很多文章分析并不那么准确。做完这些以后有什么想更进一步理解的点,只需花极少时间便能搞定,对于写作能力好的,便可以发文章了。
5#
热心回应  16级独孤 | 2019-8-18 00:58:03 发帖IP地址来自
谢邀
看了一下这个问题,对于题主说的一些问题有些不同的看法.
看书大家喜欢一次性看完,这个包括我自己都是有这样的习惯,但是对于Android Framework来说,整个Framework体系的庞大真的不建议所有模块都想要全部吃掉.在Framework这边做定制化开发一年多,感觉自己也就对于WM, AM, View, Activity相关的部分理解的比较深入.感觉还是从工作涉及的部分出发比较好.如果没有特别的侧重,可以先从Activity, View, Window整个创建机制和逻辑结构入手,对于APP开发也会提升很多.

关于应该看什么参考方面,我自己是看老罗CSDN的Android之旅,深入理解Android.虽然这些内容基于的Android版本还是比较老,有些在Android新版本实现转移了位置甚至整体改变了思路,但是Android这么长时间整个的框架基本没有太多的变化.对照现有的代码,如果有条件的话有一台可以运行AOSP的设备自己做实验,相信对于Android Framework的学习可以增速很多.

看题主是从应用往Framework过度的,可以自己指定一些计划来学习,比如:
Activity的生命周期是怎么实现的, (Activity, AMS, ActivityThread相关)
系统是如何添加一个顶级View或者Window的(WMS, Window, ViewRootImpl相关)
Activity,app是如何进行切换的,后台Activity如何恢复到前台(AMS, ActivityStack, ActivityStackSupervisor相关)
RecentTask是怎么管理的(AMS, ASSupervisor)
........

怎么看Android代码方面,如果仅仅只是期望能看代码,而且电脑是在Windows环境,SourceInsight确实是一个不错的选择,网上相关的配置也比较多,不做赘述.也有一个在线的平台AndroidXRef可以看代码,支持关键字跳转,在线看看也挺方便.

不过如果想要自己能够编译一套Android代码,同时真机调试.最好的选择是在Linux环境下进行,同时去https://source.android.com/source/requirements.html 按照教程下载编译一套代码(整个过程时间可能非常长,一般代码有大几十GB).IDE环境方面,我自己是用Intellij来看的,因为官方支持生成idea的module(mmm development/tools/idegen),导入到intellij也比较方便.而intellij看方法的Hiearchy调用,打断点调试都非常爽.
6#
热心回应  16级独孤 | 2019-8-18 00:58:04 发帖IP地址来自
谢邀,这只是我个人现在可以想到的一点总结,大家可以多交流一下。

1、首先还是经常说到的计算机的基础知识,要对基本的硬件,内存的类型有一个大概的了解。有一本书《Linux C一站式编程》,里面有操作系统标准的Posix接口和IO多路复用及文件描述符等介绍,Android的Lib层都是基于这些操作系统接口实现的,如果看不懂可以多看几遍,阅读总是有收获的。另外还有一半《深入理解计算机体系》也建议阅读,这本书有点厚。

2、Framework层可以简单些直接在Android Studio中调试,包括ViewGroup和View对事件的处理,可以查看堆栈信息。另外从ActivityThread的main函数入手,查看Activity是怎么创建的,生命周期如何回调,View RootImpl是如何创建管理的,都可以从ActivityThread入手。

3、最主要的一点是平时在开发中遇到问题,多阅读源码,理解为什么会这样,利用源码解决问题。而不是直接网上找到答案(当然能够理解到问题所在也不错)。个人开发过Metro和iOS,Android最大的优势就是开源,能够根本的理解到原理。

先写这么多了,Pad上打的字,有点累。另外我有几篇文章,感兴趣可以看下,欢迎讨论。
Penner - 简书
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:55334
帖子:27423
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP