Android framework学习

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/LucasXu01/article/details/81328868

一:概述

       众所周知,Android是一个基于Linux实现的操作系统。但对于Linux内核来说,Android也仅仅只是一个运行在内核之上的应用程序,与其他运行在内核之上的应用程序没有任何区别。所以Android也需要运行环境,需要Linux内核在启动完成后加载Android Framework运行所需要的资源。当Framework完成初始化后才能继续启动相应的APK应用程序。

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


二:Framework的整体理解

     其实我们写的App并不是一个完整的程序。我们写的只是一个套件组,就是一堆Activity,Service等等的组件。这个套件组给Framework框架组合在一起才是一个完整的程序。

        在这里先说一个概念,也就是EIT模型。E是Engine发动机,I是Interface接口,T是tire轮胎。也就是发动机通过接口接上轮胎,然后车子才能跑。然后框架提供的就是E&I,一般框架都是提供发动机和接口,让我们来做轮胎,然后装上就可以跑起来了。(这里的I也可以理解为抽象函数,因为抽象函数就相当于接口嘛)抽象类也就是把发动机和接口,放在一个类里。

        像Activity,提供了一个接口函数(卡隼函数)onCreate(),我们写myActivity,就要重写onCreate(),Activity这个抽象类就是发动机,onCreate()就是接口,myActivity就是轮胎。当框架要Activity运行的时候调onCreate()方法,就带动了myActivity的运行。我们写在onCreate()中的代码就得到了执行。

      Android框架这样做的好处就是牢牢掌握控制权,要求开发者必须在我给你的接口中装填代码,我框架内容千变万化你都不用管,你老老实实在我给你的接口填代码就行了,整个生命周期都由我框架来掌控。试想,如果不通过这种模式,不是给App开发者提供接口,而是直接的函数调用,那框架就要受制于App开发者,这个函数用的人越多,函数改动的成本就越高。框架就被迫不能改变,慢慢也就死了。而通过EIT模型,提供给开发者的只是一个接口,框架对App开发者就是透明的,你只需要在接口中做事就行了,这样就更规范和灵活。关于什么时候new Activity的对象是由Framework框架来控制的。Manifest文件里把Activity注册上,是因为Framework框架要new Activity的时候知道去哪找这个子类。而且这个对象有什么初始值,比如响应什么样的intent。这样App的启动也就好理解了,点击桌面图标,由FrameWork框架捕获这个事件,去找这个图标对应的App的Manifest里面找到要启动的第一个Activity,就是那个在Manifest里注明是main和luncher的。然后由Framework框架new出这个myActivity对象。自然也就new出了基类Activity对象,然后Framework框架调用Activity的onCreate(),实际对象是myActivity,执行的也就是myActivity的onCreate()。这时候App就启动了。

      由此可见,任何控制类程序都有一个入口,安卓应用程序同样也是。 


三:Framework启动分析

       Framework运行的第一个Java虚拟机进程为zygote(对应具体程序为app_process,该程序位于system/bin目录下),zygote是APK应用程序的父进程,此后所有的虚拟机进程都由zygote创建。

zygote有两个功能:
1.接受请求创建新的Dalvik进程
2.共享类和资源(需要加载的资源在preload-classes文本文件中声明)

3.1 Dalvik虚拟机进程间的关系

       对于Android来说,每一个应用程序对应着一个Linux 进程,每一个进程都是一个Dalvik虚拟机,Dalvik虚拟机是一种类似Java虚拟机的实现。

         zygote进程在启动时会预先装载共享类和共享资源,这些类及资源实际上就是SDK中定义的大部分类和资源。当zygote进程创建新进程时,新的APK进程只需装载自身类和资源即可。共享的资源位于同一段物理内存空间中,zygote进程及其创建的Dalvik进程都可以访问,这就解决了多个APK共享Framework资源的问题。

       zygote创建的第一个进程名为SystemServer,SystemServer创建了一个Socket客户端,并创建了ActivityManagerService线程来管理该客户端。之后所有的Dalvik进程都是由该客户端启动的。当需要启动新的APK进程时,AmS会通过该Socket客户端向zygote进程的Socket服务端发送一个启动命令,然后zygote就会创建(使用fork()创建新进程)出新的应用程序进程。

3.2 系统服务

     SystemServer进程内部运行着APK应用中能够直接交互的大部分系统服务。比如WindowManagerService(简称WmS),ActivityManagerService(简称AmS),PackageManagerService(简称PmS)等。这些系统服务都是以一个线程的方式生存在SystemServer进程中。SystemServer启动的各种服务线程如下所示:

  • PowerManagerService电源管理服务
  • ActivityManagerService管理Activity
  • PackageManagerService程序包管理服务
  • BatteryService电池管理服务
  • LightService自然光强度感应传感器服务
  • VibratorService震动传感器服务
  • ClipboardService剪切板服务
  • NetworkManagerService网络管理服务
  • InputMethodManagerService输入法管理服务
  • BluetoothService蓝牙服务
  • ...

3.3 Dalvik与Android Runtime(ART)

Dalvik是一种类Java虚拟机的实现,其执行的是class优化后的dex字节码文件。Dalvik通过一个JIT(Just-In-Time)编译器去解释字节码,但执行效率并不理想。

自动Android 4.4后安卓就内置了ART实现,从5.0开始更是直接抛弃了Dalvik全面使用ART。ART通过AOT机制(Ahead-Of-Time)在应程序安装时将字节码编译成机器语言,因此执行速度更快。并且ART也完全兼容Dalvik。


四:应用程序启动分析

       在计算机的世界里每个程序都有一个main()方法,程序代码都是从main()方法开始执行,Android应用程序也不例外。

       当应用程序启动时系统首先会为其创建一个Dalvik虚拟机进程,并加载APK应用程序类及资源。然后,APK应用程序从ActivityThred的main()方法处开始执行。

      首先main()方法为UI线程创建一个消息队列(MessageQueue)。然后创建ActivityThread对象,ActivityThread初始化时会创建一个Handler和一个Binder。Binder负责接收远程AmS的IPC调用,接收到调用后通过Handler将消息发送到消息队列,UI主线程会异步地从消息队列中取出消息并执行相应操作,比如start,stop,pause等。

       接着UI主线程调用Looper.loop()方法进入消息循环体,进入后就会不断从消息队列中读取并处理消息。

       ActivityThread是APK程序的UI线程,也就是我们所说的主线程。主线程要求执行时间不能超过5秒,超过就会报ANR,这个5秒就是UI线程消息队列循环一次的最大时间阈值。

     当ActivityThread接收到AmS发送的start某个Activity消息后,就会创建指定Activity对象。Activity又会创建PhoneWindow类,PhoneWindow创建DecorView,DecorView内部包含Activity.setContentView(R.layout.xxx)指定的布局。

      创建完成后,Activity需要将布局显示在屏幕上,于是调用WindowManager.addView()方法。WindowManager为Activity对应的窗口(Window)创建一个ViewRoot对象(每一个窗口对应一个ViewRoot对象),然后调用WmS提供的远程接口将窗口(布局)显示到屏幕上。至此应用程序中的Activity就显示在屏幕上了。

4.1 APK中的线程

      在现在操作系统中,任何应用程序都运行在线程之中。客户端在启动时系统会首先为其分配一个线程,然后该线程从程序的入口处开始执行。对于包含Activity的客户端程序,至少包含三个线程:

  1. 主线程,又称UI线程,也就是应用程序本身所在的线程,主要用于处理用户消息以及绘制程序界面。
  2. ViewRoot.W对象对应的线程,Activity启动后会创建一个ViewRoot.W对象,W对象继承自Binder,因此会启动一个对象负责接收Linux Binder驱动的IPC调用。
  3. ApplicationThread对象所对应的线程,该对象也继承自Binder,因此也会启动一个线程用于IPC调用。

4.2 自定义Thread与UI线程的区别

        客户端小伙伴至少包含三个线程小弟,Activity启动后会创建一个ViewRoot.W对象,同时ActivityThread会创建一个ApplicationThread对象,这两个对象继承消息总管Binder,每个Binder对应一个线程,负责接收Linux Binder驱动发送的IPC调用。还有一个是UI线程呗。

    对于UI线程,在启动时已经创建了消息队列(MessageQueue),既在ActivityThread的main()方法中已经使用Looper.prepareMainLooper()方法为UI线程添加了Looper对象。程序员可以直接在Activity中定义Handler对象发送处理消息。

      而对于普通线程,需要手动调用Looper.prepareLooper()方法为Thread创建消息队列,这样才能定义Handler处理消息。即不能直接在Thread中定义Handler。

       从使用场景上说,就是不能直接给Thread对象发消息,但是却可以给UI线程发消息。

       UI线程是从ActivityThread运行的,在该类的main()方法中已经使用了Looper.prepareMainLooper()为该线程添加了Looper对象,已经为该线程创建了消息队列,是自带秘书光环的。因此,我们才可以在Activity中去定义Handler对象,因为创建Handler对象时其线程必须已经创建了消息队列,装卸工得配运输带要不然没法干活。而普通的Thread则没有默认创建消息队列,所以不能直接在Thread中直接定义Handler,这个就是我们不懂程序运行原理导致的困惑。

具体Handler的使用及解释请移步Android异步通信机制详解


五:一些重要的类

下面是一些系统中常见的类及其功能介绍,通读一遍会对理解Android源码很有帮助。

两个重要的系统服务

  • WindowManagerService,管理所有的窗口,包括创建删除窗口,隐藏显示窗口,决定窗口的层级顺序,指定当前正在与应用程序交互的窗口。
  • ActivityManagerService,内存管理,进程管理,统一调度所有应用程序中的Activity。所有Activity的启动必须通知AmS,AmS也决定了某个进程会不会被杀死。

两个消息处理类

  • KeyQ类:该类是WmS的内部类,继承自KeyInputQueue,一旦创建就立即启动一个线程,该线程会不断读取用户UI操作消息,比如按键、触摸屏、等,并把这些消息放到一个消息队列QueueEvent类中。
  • InputDispatcherThread类:该类一旦创建也会启动一个线程,该线程会不断地从QueueEvent中读取用户消息,并进行一定的过滤,过滤后发送给当前活动的而应用程序中。

其他常用类

  • ActivityThread类,应用程序主线程类,所有的APK都有且仅有一个ActivityThread类,程序的入口为该类中的static main()方法,ActivityThread所在的线程即为UI线程或主线程。
  • ViewRoot类,WmS管理客户端窗口时,需要通知客户端进行某种操作,这些都是通过IPC调用来完成的,而客户端在接收到IPC后,都需要将该调用转换成本地异步调用。ViewRoot继承自Handler,其作用就是将远程接口调用转换成本地异步调用。
  • W类,ViewRoot内部类,继承自Binder,Wms通知客户端时就是该类进行IPC调用。该类内部会向其所在的ViewRoot发送一个Handler消息,以便进行异步处理。
  • Window类,是一个抽象类,提供了一套操作窗口的通用方法(Callback接口)。Activity就是通过实现这个Callback接口来获得对消息的处理机会。因为消息首先会由WmS传递给窗口中的View树,View树不处理消息的话才会传递给Window,这时候就会回调Activity实现的Callback方法使Activity有机会处理事件。
  • PhoneWindow类,是Window的具体实现类,其内部保存有DecorView对象。
  • DecorView类,应用程序视图的根布局View,该类继承自FrameLayout。客户端使用WindowManager添加窗口就是将该类(及其子View)添加到WmS中,并将其所代表的视图绘制到屏幕上。
  • Activity类,该类APK程序最小运行单元。ActivityThread根据用户的操作选择加载哪个Activity。
  • WindowManager类,该类是WindowManagerService在客户端的管理类,客户端通过WindowManager申请创建一个窗口,而具体创建窗口的任务是由WMS来完成的。

六:Android framework形象化理解之:三个小伙伴

Android framework包含三个小伙伴:服务端、客户端、linux驱动。

服务端

服务端主要包含两个很重要的类:WindowManagerService(WMS)和ActivityManagerService(AMS)。(两个大佬管理者服务)

客户端

客户端包含以下类:

ActivityThread:是安卓应用程序的主线程类,也就是UI线程或者称为主线程,所有的处理用户消息,以及绘制页面的工作都在该线程中完成。

Activity: ActivityThread会根据用户的操作选择让哪个Activity对象上它的船。

PhoneWindow:富二代,继承于牛气的Window类,自己屋里住着一个DecorView对象,像它老爸喜欢制定规则提供了一些通用窗口操作API。

Window:富一代,长得比较抽象,喜欢制定规则提供了一些通用的窗口操作API。它不喜欢被人管。所以呢,注意:WindowManagerService管理的窗口不是Window类,其实是View和ViewGroup。

DecorView:很能干的家伙,家产来自FrameLayout,比较注重外在喜欢打扮,DecorView是对FrameLayout进行了一些修饰,从名字就可以看出来。

ViewRoot:小管家。继承于Handler,主要作用是把WMS的IPC调用转换为本地的一个异步调用。

W类:ViewRoot小助手,继承于binder,是ViewRoot内部类。主要帮助ViewRoot实现把WMS的IPC调用转换为本地的一个异步调用。

WindowManager:客户端如果想创建一个窗口得先告诉WindowManager一声,然后它再和WindowManagerService交流一下看看能不能创建,客户端不能直接和WMS交互。

Linux驱动

Linux驱动和Framework相关的主要是两个部分:画家SurfaceFlingger和快递员Binder。

每一个窗口都对应一个画Surface,SF主要是把各个Surface显示到同一屏幕上。Binder是提供跨进程的消息传递。

从apk程序的运行过程去看看上面各个组件在啥时候干啥活的

ActivityThread从main()函数中就开始动起来,然后调用prepareMainLooper()为UI线程创建一个消息快递通道即MessageQueue。

接着创建ActivityThread对象,创建过程会创建一个消息装卸工Handler对象和一个快递员Binder对象,其中Binder负责接收远程Ams的IPC调用,接收到调用后让Handler把消息装到消息快递队列,UI线程很忙的都是异步的从消息快递队列中取出消息并执行相应操作,比如 start、stop、pause。

然后UI线程让队列调用Looper.loop()方法进入消息循环体,进入后就会不断地从消息队列中读取并处理消息。

当ActivityThread接收到Ams发送start某个Activity的快递后就会创建指定的Activity对象。Activity会先按窗户再去按玻璃和贴窗花,所以先创建PhoneWindow->DecorView->创建相应的View或ViewGroup。创建完成后就可以让大家欣赏了,调用WindowManager把界面显示到屏幕上,然后创建ViewRoot,然后调用Wms提供的远程接口添加一个窗口并显示到屏幕上。

接下来就是用户的操作,事件线程不断的把消息快递发到事件队列中去,然后事件分发线程秘书逐个取出消息,然后调用Wms中的相应函数处理该消息。

文章的优秀参考资料:

  1. https://blog.csdn.net/zheng_weichao/article/details/79403180
  2. https://www.jianshu.com/p/37e5a8e45d6b
  3. https://www.zhihu.com/question/46486807?sort=created
  4. https://blog.csdn.net/yuanzeyao/article/details/42418977
  5. https://developer.android.com/design/

猜你喜欢

转载自blog.csdn.net/LucasXu01/article/details/81328868