03.App核心概念分析
目录介绍
- 01.App进程启动流程
- 1.1 启动流程图
- 1.2 启动服务考点
- 02.ActivityThread
- 2.1 启动流程概述
- 2.2 流程说明介绍
- 03.Application流程
- 3.1 启动流程概述
- 3.2 流程说明介绍
- 04.Window创建流程
- 4.1 启动流程图
- 4.2 流程图说明
- 4.3 Window如何创建
- 05.DecorView说明
- 5.1 什么是DecorView
- 5.2 DecorView如何创建
- 06.Android组件设计
- 6.1 ActivityManagerService
- 6.2 Binder
00.问题答疑思考
- App进程:说一下App进程启动流程?Zygote进程的启动流程是什么样的?关于Zygote进程主要做了那些事情?
- App进程:SystemServer进程启动流程是什么样的?怎么创建单个进程(application)?如何启动ActivityThread?
- 启动入口:ActivityThread启动入口做了什么?如何创建上下文?为什么要创建上下文。说一下主线程创建时机?
- 启动流程:说一下application的启动流程,何时创建,什么时候调用onCreate和attachBaseContext方法?
- 启动顺序:Application中attachBaseContext方法,onCreate方法和ContentProvider中的onCreate方法执行的顺序是什么?
01.App进程启动流程
1.1 启动流程概述
- 将Android系统的启动分成八层(或者说八个大步骤)
- 按下电源时引导芯片从代码从预定义的地方(固化在在Rom)开始执行,加载引导程序BootLoaer到RAM。
- BootLoader程序把系统OS拉起来并运行。
- Linux内核启动,这里面我们最关心的是init进程的启动,它是所有用户进程的鼻祖。
- 初始化init进程,这里面最重要的是启动Zygote进程,它是所有APP 进程的鼻祖(或者说是Java进程)。
- 初始化Zygote进程,创建运行APP所需要的服务,例如Java虚拟机、注册JNI方法以及启动SystemServer进程。
- 初始化SystemServer进程,这里最重要的就是启动Binder线程池以及一些核心服务,比如PMS、WMS、AMS等。
- AMS是管理Android 四大组件的核心服务,系统启动后会让AMS将系统桌面(也就是Launcher)加载出来。
- Launcher作为所有APP 的入口,点击Launcher上的图标后就会启动APP(如果APP进程不在,会先Fork Zygote进程来创建新进程)。
1.2 启动服务考点
- Zygote进程是所有的android进程的父进程
- 包括SystemServer和各种应用进程都是通过Zygote进程fork出来的。Zygote(孵化)进程相当于是android系统的根进程,后面所有的进程都是通过这个进程fork出来的。
- 各个进程的先后顺序
- init进程 --> Zygote进程 --> SystemServer进程 -->各种应用进程
- Zygote进程的启动流程
ZygoteInit#main(),在入口main方法中,主要初始化资源,socket通信,fork出SystemServer进程,最后关闭socket通信。 ZygoteInit#preload(),在preload方法中,初始化需要的class类,初始化系统资源,初始化系统libraries,初始化文字资源,初始化web等。 ZygoteInit#forkSystemServer(),fork出SystemServer进程
- SystemServer进程启动流程
SystemServer#main(),只是new出一个SystemServer对象并执行其run方法 SystemServer#run(),初始化时间,语言,locale。接着设置虚拟机运行内存,加载运行库。然后初始化AMS,PMS,WMS等。 SystemServer#createSystemContext(),看到在SystemServer进程中也存在着Context对象,并且是通过ActivityThread.systemMain方法创建context的 SystemServer#startBootstrapServices(),这个是启动核心服务的方法 SystemServiceManager#startService启动各种服务,看源码可知,这个是通过反射器构造方法创建出服务类,最后再添加到SystemServiceManager的服务列表数据 mSystemServiceManager#startService(ActivityManagerService.Lifecycle.class),启动AMS服务,四大组件都需要通过其余系统交互 ActivityManagerService.Lifecycle#Lifecycle(),静态内部类,在其构造方法中会创建一个ActivityManagerService mSystemServiceManager.startService(PowerManagerService.class),启动PMS,主要是屏幕,电源等相关 PackageManagerService.main(mSystemContext, installer,……),启动PMS服务,该服务关联到apk文件的安装,解析,删除,卸载等等
- ActivityThread启动入口
- 这里面很多服务会用到mSystemContext上下文,那么这个上下文是做什么的呢?
- 通过ActivityThread创建,然后在获取Context对象,可以理解上下文Context为Android的基础环境信息。
- 这里很重要的一点是,在createSystemContext创建上下文时,启动了ActivityThread,该类既是App启动分析入口。
02.ActivityThread
2.1 启动流程概述
- ActivityThread起到什么作用
- 整个Android应用进程的体系非常复杂,ActivityThread是真正的核心类,它的main方法,是整个应用进程的入口。
- 为什么我们平时都将ActivityThread称之为ui线程或者是主线程
- 这里可以看出,应用进程被创建之后首先执行的是ActivityThread的main方法,所以我们将ActivityThread成为主线程。
2.2 流程说明介绍
- 看一下ActivityThread核心方法
ActivityThread#main(),程序启动入口,主要执行了一些初始化的逻辑,并且创建了一个UI线程消息队列 ActivityThread#Looper.prepareMainLooper(),初始化Looper,App其实就是一个大的轮训器,处理所有的handler消息。 ActivityThread#thread.attach(),在attach方法中,使用AMS启动核心逻辑,创建Application并执行生命周期onCreate调用
- APP启动流程可以分三个阶段:
- Launcher请求AMS阶段。
- AMS到ApplicationThread的调用过程。
- ActivityThread启动Activity过程。
03.Application流程
3.1 启动流程概述
- App点击桌面图片启动过程
image
3.2 流程说明
- 大概流程如下所示
ActivityManagerService#startProcessLocked() Process#start() ActivityThread#main(),入口分析的地方 ActivityThread#attach(),这个里面的逻辑很核心 ActivityManagerService#attachApplication(),通过Binder机制调用了ActivityManagerService的attachApplication ActivityManagerService#attachApplicationLocked(),整个应用进程已经启动起来了 ActivityManagerService#thread.bindApplication,具体回到ActivityThread ActivityThread.ApplicationThread#bindApplication(),最后看到sendMessage处理bind逻辑 ActivityThread#handleBindApplication(),设置进程的pid,初始化进程信息 ActivityThread#mInstrumentation.callApplicationOnCreate,看到Application进入onCreate()方法中,这就是从最开始main()方法开始到最后的Application的onCreate()的创建过程
04.Window创建流程
4.1 启动流程图
- Window是什么?
- 表示一个窗口的概念,是所有View的直接管理者,任何视图都通过Window呈现(点击事件由Window->DecorView->View; Activity的setContentView底层通过Window完成)
- Window是一个抽象类,具体实现是PhoneWindow。PhoneWindow中有个内部类DecorView,通过创建DecorView来加载Activity中设置的布局
R.layout.activity_main
。 - 创建Window需要通过WindowManager创建,通过WindowManager将DecorView加载其中,并将DecorView交给ViewRoot,进行视图绘制以及其他交互。
- WindowManager是外界访问Window的入口
- Window具体实现位于WindowManagerService中
- WindowManager和WindowManagerService的交互是通过IPC完成
- 如何通过WindowManager添加Window(代码实现)?
- 如下所示
//1. 控件 Button button = new Button(this); button.setText("Window Button"); //2. 布局参数 WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, 0, 0, PixelFormat.TRANSPARENT); layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; layoutParams.gravity = Gravity.LEFT | Gravity.TOP; layoutParams.x = 100; layoutParams.y = 300; // 必须要有type不然会异常: the specified window type 0 is not valid layoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR; //3. 获取WindowManager并添加控件到Window中 WindowManager windowManager = getWindowManager(); windowManager.addView(button, layoutParams);
- 如下所示
- WindowManager的主要功能是什么?
- 添加、更新、删除View
public interface ViewManager{ public void addView(View view, ViewGroup.LayoutParams params); //添加View public void updateViewLayout(View view, ViewGroup.LayoutParams params); //更新View public void removeView(View view); //删除View }
- 添加、更新、删除View
4.2 流程图说明
- window启动流程
image
4.3 Window如何创建
- 从上面的performLaunchActivity可以看出,在创建Activity实例的同时,会调用Activity的内部方法attach
- 在attach该方法中完成window的初始化。源码如下所示,Activity类中源码
final void attach(Context context, ActivityThread aThread, Instrumentation instr, IBinder token, int ident, Application application, Intent intent, ActivityInfo info, CharSequence title, Activity parent, String id, NonConfigurationInstances lastNonConfigurationInstances, Configuration config, String referrer, IVoiceInteractor voiceInteractor, Window window, ActivityConfigCallback activityConfigCallback) { //创建 PhoneWindow mWindow = new PhoneWindow(this, window, activityConfigCallback); }
05.DecorView说明
5.1 什么是DecorView
- DecorView是FrameLayout的子类,它可以被认为是Android视图树的根节点视图。
- DecorView作为顶级View,一般情况下它内部包含一个竖直方向的LinearLayout,在这个LinearLayout里面有上下三个部分,上面是个ViewStub,延迟加载的视图(应该是设置ActionBar,根据Theme设置),中间的是标题栏(根据Theme设置,有的布局没有),下面的是内容栏。 具体情况和Android版本及主体有关,以其中一个布局为例,如下所示:
<LinearLayout > <ViewStub android:id="@+id/action_mode_bar_stub"/> <FrameLayout> <TextView android:id="@android:id/title"/> </FrameLayout> <FrameLayout android:id="@android:id/content"/> </LinearLayout>
- 在Activity中通过setContentView所设置的布局文件其实就是被加到内容栏之中的,成为其唯一子View,就是上面的id为content的FrameLayout中,在代码中可以通过content来得到对应加载的布局。
ViewGroup content = (ViewGroup)findViewById(android.R.id.content); ViewGroup rootView = (ViewGroup) content.getChildAt(0);
- Activity 与 PhoneWindow 与 DecorView 关系图
image
- Activity 与 PhoneWindow 与 DecorView 之间什么关系?
- 一个 Activity 对应一个 Window 也就是 PhoneWindow,一个 PhoneWindow 持有一个 DecorView 的实例,DecorView 本身是一个 FrameLayout。
5.2 DecorView如何创建
- 从Activity中的setContentView()开始。
- 在Activity中的attach()方法中,生成了PhoneWindow实例。既然有了Window对象,那么我们就可以**设置DecorView给Window对象了。
- 从中获取mContentParent。获得到之后,然后通过installDecor方法,然后生成DecorView,不过这里操作很复杂,大概流程先从主题中获取样式,然后根据样式,加载对应的布局到DecorView中,为mContentParent添加View,即Activity中的布局。
06.Android组件设计
- 组件化设计实现
- 程序由组件组成;组件与进程剥离;组件皆程序入口
- 程序由组件组成
- Activity:前台交互;Service:后台计算;Broadcast Receiver:广播通信;Content Provider:数据封装
- 组件与进程剥离
- 组件关闭时,进程可以继续存在,提高重新启动时的速度;进程关闭时,组件可以继续存在,保护被杀进程里面的组件。
- 将组件与进程进行剥离,使得进程对组件透明,听起来很好,但是如何解决以下四个问题?
- 谁来负责组件的启动和关闭?
- 谁来维护组件的状态?
- 谁来管理组件运行时所需要的进程?
- 组件之间如何进行通信?
6.1 ActivityManagerService
- 启动组件
- 组件启动时,检查其所要运行在的进程是否已创建。如果已经创建,就直接通知它加载组件。否则,先将该进程创建起来,再通知它加载组件。
- 关闭组件
- 组件关闭时,其所运行在的进程无需关闭,这样就可以让组件重新打开时得到快速启动。
- 维护组件状态
- 维护组件在运行过程的状态,这样组件就可以在其所运行在的进程被回收的情况下仍然继续生存。
- 进程管理
- 在适当的时候主动回收空进程和后台进程,以及通知进程自己进行内存回收
- 组件的UID和Process Name唯一决定了其所要运行在的进程。
- 每次组件onStop时,都会将自己的状态传递给AMS维护。
- AMS在以下四种情况下会调用trimApplications来主动回收进程:
- A.activityStopped,停止Activity
- B.setProcessLimit,设置进程数量限制
- C.unregisterReceiver,注销Broadcast Receiver
- D.finishReceiver,结束Broadcast Receiver
- WMS也会主动回收进程:
- WindowManagerService在处理窗口的过程中发生Out Of Memroy时,会调用reclaimSomeSurfaceMemoryLocked来回收某些Surface占用的内存,reclaimSomeSurfaceMemoryLocked的逻辑如下所示:
- (1).首先检查有没有泄漏的Surface,即那些Session已经不存在但是还没有销毁的Surface,以及那些宿主Activity已经不可见但是还没有销毁的Surface。如果存在的话,就将它们销毁即可,不用KillPids。
- (2).如果不存在没有泄漏的Surface,那么那些存在Surface的进程都有可能被杀掉,这是通过KillPids来实现的。
6.2 Binder
- 为组件间通信提供支持
- 进程间;进程内
- 高效的IPC机制
- 进程间的组件通信时,通信数据只需一次拷贝
- 进程内的组件通信时,跳过IPC进行直接的通信
- 传统的IPC,通信数据需要执行两次,一次是从源进程的用户空间拷贝到内核空间,二次是从内核空间拷贝到目标进程的用户空间