资深Android开发带你入门Framework

              本文重点:资深Android开发带你入门Framework

              今天,跟大家聊聊,的那些事。

              系统应用开发,现在来说,已经开始脱离系统,单独拿出来开发,系统定制接口,已提供给应用调用,用来增强功能。 原生的桌面,拨号,设置,已经没法做出差异化优势,因此都费尽心机,来进行应用深度开发。

              对于之前维护系统应用模块的人来讲,修修补补,真的没有什么成长。 每天的工作来说,没有很深的技术壁垒,很容易被别人攻陷。

              比如设置,比如联系人,在小的改动,修改故障的时候,没有非常高的要求,做过应用开发的,都可以过来参合一脚,改改问题。 而让一个应用开发得去修改系统接口,估计改的心累,并且犹豫不决。 Framework的核心技术这节,小编从自身的角度,讲讲系统应用开发,该如何向Framework进军,进行学习,掌握更加核心的技术。

              这里有人会说,我做应用风生水起,也游刃有余,不比你们做系统Framework的差,何必把系统应用开发的贬的一文不值。 这里要说一下,文中没有这个意思,你的应用做的有声有色,赚的盆满钵满,这里肯定有其因素。 比如它的性能,它的界面绚丽,百变主题。 或者它有智能识别,等等。 这些都叫做差异化产品,有其亮点,特色,才能杀出重围。 而系统应用开发,我这里偏向于手机整机开发中的OEM厂商,主要做出系统,能够保证功能正常,不会花费大量人力精力去做应用深度开发,系统重构的。 这里主要会以追求速度,同时满足客户的硬件要求,比如多个霍尔器件,多个温度传感器,多个皮套功能,等等,但很少去大量改动应用架构,以免影响最终量产。 以上,就是特指的这个应用开发人员。 操作系统Android启动过程框架跟linux如出一辙,所以很容易迁移过来,同时,差异化的init进程,完成初始任务,创建安卓世界的孵化器,既然这里要进入安卓世界,而安卓世界的基础语言是java,那么就需要一个Java虚拟机,于是孵化器就要构造一个虚拟机,用来解析执行Java编译出来的字节流。

              而孵化器本身是由ccpp语言实现,于是Java虚拟机就是由ccpp语言写出来的,linux操作系统也是c(还有一些汇编)写出来的,于是Java虚拟机运行的Java语言,就需要跟ccpp打交道,于是就有了JNI。 完成Java虚拟机的构造完成JNI对接Java与c的桥梁加载公共的共享库等待别人发消息,创建新进程在这期间,孵化器要做一件事情,便是创建system_server,这个进程要做什么呢?我们创建了一个可以运行Java的虚拟机,这时我们就要提供一堆系统接口,用来协助应用开发,比如请求网络啦,比如创建界面啦,比如定位啦,获取存储卡啦,等等支持,方便用户开发功能。 一个平台的好坏,往往取决于它的功能是否强大,是否有丰富的技术文档,以及开发调试工具。 所以就有了一堆线程,比如AMS,WMS,PMS,BT,WIFI,这些都可以在/proc/{system_server_pid}/tast找到记录。

              有了这些线程,那么我们就可以轻松的去实现很多功能啦。 这时我们就要配套的开发工具,比如AS编辑器,可以编辑,编译出来APK,安装到手机运行。 进程,线程概念互斥,死锁机制与原理,如何避免死锁内存管理机制,虚拟内存静态库与动态库的区别进程之间的内存屏障,如何通信(IPC)binder的通信优势这里先想到这些,注意不是要完成懂所有机制,要的是整体理解即可。

              如下问题,请思考下,看是否能够答上来。

              如果我写了一个应用,名字叫做,在主activity里面,加载一个布局,layout_,布局里面写入了一个TextView,那么我想调试这个TextView,要在这个进程下断点,还是在system_server进程下断点呢?如果是想调试的话?应该在哪个进程下断点呢?以上答案,都是下断点,那么我们再来思考下,我现在要去追应用的启动过程,startActivity的流程,要在哪个地方下断点呢?我们知道这个流程,最终核心的都在Activitymanagerserver里面,而它是在systemserver进程里面,以一个线程的状态存在,于是我们要调试,就要在systemserver上面下断点了。 搞清楚了systemserver后,以我们熟悉的AMSWMSPMS举例。 这些服务线程,完成应用的请求任务,将结果返回给应用。

              比如查看当前运行的所有Activity,就是应用发起请求,从操作系统那里,先找到servermanager,这个手里拿到一堆服务的句柄,也可以说令牌,你只能通过这个找到它。

              当servermanager一看你有权限,就帮你把对应的AMS的句柄给你,这个句柄操作系统也认识,对应到systemserver的AMS引用上,也就是你通过这个句柄,调用它的方法,操作系统就会将你的请求,传递到systemserver中去,同时操作系统知道这个句柄是AMS的第20号(这个20号代表查询当前运行的所有Activity的方法),然后就唤醒systemserver,同时从binder线程池,这个线程跟AMS一样,是个线程,从线程池拿出一个,调用AMS的20号方法。 调用完成后,从操作系统层面,把数据交给调用的应用,实现数据传输。 这里面定义的传递数据格式是包裹,也就是序列化数据。

              了解进程通信好了,这块就说这么多,主要是说下进程通信,以及binder这种通信的简单逻辑。 因为操作系统设计,管理的软件单元是进程,进程间本身不联系,彼此看不见。 一个进程想跟另一个说话,他两都认识的人是操作系统。 因为他们是由操作系统管理的。 操作系统通过从硬盘将程序装载进入内存,同时给每一个分配了进程号,于是他们就都在系统里面有了标记,同时每个都起了名字,一个叫我就喜欢吃,一个叫我就喜欢喝。

              喜欢喝的一个人孤单,他不认识喜欢吃的,他就问操作系统,有没有人喜欢吃的,操作系统一查,说有啊,然后把喜欢吃的的进程号给他,他就可以找到喜欢吃的了。

              然后操作系统给他了一辆车,让他把想给喜欢吃的的东西,装在车上寄过去。 这个车子是操作系统提供的,这个车子就是通信方式。

              比如汽车,飞机,步行。 于是进程间的通信方式就是,从操作系统找到目标,然后拿到通信方式,用操作系统给的通信工具,进行通信。

              数据结构和算法这块完成了,我们再来讲一个内容:我们发现,这里MP3格式,OGG格式,都属于一个文件的格式声明,这个我们可以用HEX工具打开MP3文件,可以看到刚开始的位置,这块属于描述后面的内容该如何解析,比如文件名字,文件大小,文件格式,系统根据这个描述,尝试用对应的解码器解码,解码完成后进行播放。

              这里解码器如何解码,就是算法。 而文件头,就是描述这个文件的数据结构。 于是,我们就知道比如我要写个贪吃蛇,如何描述蛇的状态,长度,当前轨迹,这些都是需要表征出来,然后围绕着这个描述内容,进行操作,这块就属于算法。

              完成的程序,运行起来,就是进程。

              所以进程是一个存在于内存的东西,操作系统用一个表格记录进程数据,比如进程号,父类进程,进程打开的文件句柄,进程当前状态,进程的上下文(上下文是保存当前CPU的寄存器,保存现场用的,因为寄存器是只有一份,当一个进程被打断时候,另个进程运行,那么之前的就要把它当前的寄存器存下来,防止被别人盖掉,等到下次自己运行的时候,再恢复回来,保证自己运行正常),程序是存在硬盘或者其他存储设备,掉电不会丢失,而进程是内存的,所以掉电就不再了。 这就又回到开头的地方,数据结构加算法,也叫文件头和文件内容。 源码经过编译链接,变成一个文件,我们亲切的叫它可执行文件。 那么我们来说说它。

              我们常见的两种可执行文件,windows上面称为PE格式,linux称为ELF,两者都是从COFF格式演化来的,这块参考《链接器与加载器》,喜欢感兴趣,可以下载阅读此书。

              程序是如何在CPU执行的?那么有了格式描述,操作系统就知道如何解析它了,然后把对应的代码段,数据段,堆栈区域配置好,将代码装载进入内存中,然后将下一条执行位置,也就是PC寄存器,指向这个可执行文件配置的text入口,这个就是程序的入口点,这个我们去写的main方法,可以简单理解成入口,实际情况是在这个前面,系统加入了一些代码,为运行此程序做准备,准备OK才会真正调用到main方法,这段代码叫创建此进程的环境,比如参数,堆栈初始化。 数字电路的与或非逻辑电路,开启了新世界的大门。 我们用断点,通电,表示两个状态。 我们不能说,好像有电,好像没电,所以,计算机的世界,定义了二进制,因为是非可以界定,孰是孰非不好界定。

              于是,在我们的电路板上,规定了,代表了没电,,代表了有电,中间的数值,代表了器件的错误,不稳定性。

              于是没电用0表示,有电用1表示,实际世界就是两个区间电压。 CPU在石英晶振的推动下,执行一条条指令。 指令是什么呢?就是一串串数字,每一串代表一个具体含义。 所以,CPU能够执行多少条指令,是考量它是否强大的一个重要参数,另一个是它执行一天指令的时间,也叫指令周期,越短越好。

              也就是两个CPU同时做一个加法,谁用时短谁就强。

              CPU拿到一条指令,就会在石英晶振的推动下,将这条指令执行完,然后将PC寄存器加1,读取下一条指令。 我们经常遇到的非法指令,就是因为CPU拿到了一个不认识的数据串,导致异常。 比如它的指令集里面,有加法,有减法,你给他说你给我翻个跟头(非法指令),他骂了一句去你的吧,老子不会(异常报错)。

              一般这种情况是指令不识别,比如你用了新的arm指令,又在旧的arm板子运行这个程序,就会挂掉,提示非法指令。 刚开始的操作系统,嵌入式的操作系统,是没有做内存保护,就是程序段可以跳到数据段执行,当然现在加入了内存管理单元,会将数据段内存描述成可读可写不可执行,如果PC(程序寄存器)指向了这个地方,去读取执行的时候,就会报非法访问。

              如果没有保护,你去读取数据段的数据,作为指令执行,出现指令异常就太正常了。