Android剖析Framework

Zygote进程是怎么启动的?

首先Init进程是Linux进程启动后用户空间的第一个进程,然后去加载inti.rc配置文件,看需要加载哪些服务,Zygote就是其中之一。还有ServiceManager进程。 父进程fork出子进程,如果子进程挂了,那么父进程会收到子进程发送过来的SIGCHLD信号,进而做处理。比如Zygote进程挂了,那么Init进程就收到SIGCHLD信号,继而重启Zygote进程。

Zygote的作用是什么?

1.孵化应用进程。

2.启动systemserver进程。因为启动systemserver进程的时候需要Zygote里面的一些资源,比如常用类,JNI函数,主题资源,共享库等,这样可以避免重复加载资源,提升性能。

 

Zygote进程启动之后做了什么?

1.Zygote的native层:启动Android虚拟机,注册Android的JNI函数,进入Java层。

2.Zygote的Java层:预加载资源(包括主题资源,共享库等),fork出SystemServer,然后进入loop循环.

 

Zygote注意事项:

Zygote的IPC没有采用Binder机制,而是Socket,所以我们应用的Binder机制不是从Zygote继承过来的,而是应用程序创建之后自己启动的Binder机制。

 

孵化应用进程为什么不交给SystemServer来做,而让Zygote来做?

因为SystemServer主要用来提供系统服务,比如AMS,PMS等,如果SystemServer直接孵化应用进程的话,应用进程也会继承这些并不需要的服务,同时职责也变得混乱。

Zygote的IPC通信机制为什么不采用Binder机制?如果这样做有什么问题?

1.Zygote与IPC通信对象systemServer或应用进程为父子关系,使用socket更合适,反而使用binder机制反而复杂繁琐。

2.如果这样做,Zygote和systemServer都有binder机制,会导致相关资源冲突,比如描述符,映射内存。

 

Zygote工作流程图如下:

 

Android系统启动流程?

init.rc里面需要加载的进程有zygote,servicemanager,surfaceflinger和media等。主要需要了解zygote的启动流程,如上。还要了解systemserver的启动流程。下面来看看systemserver启动流程。

zygote启动systemserver进程后,在systemserver进程中初始化相关系统服务AMS,PMS,包括启动bind线程。因为systemserver里面的系统服务需要与我们的应用进程通信,而通信就是通过bind机制。还包括调用Java类的入口函数main(),在main()函数里面加载loop,共享库,创建上下文等。

系统服务是怎么启动的?

把系统服务的binder注册到serviceManager里面,通过这种方式发布系统服务。系统服务跑在什么线程?bind线程。

systemServer启动系统服务时怎么解决相互依赖?

分批启动,分阶段启动。

 

如何使用系统服务?

通过getSystemService(name)方法获取ServiceFetcher,并调用其getService方法。

如何注册系统服务?

通过调用ServiceManager的addService方法。

什么时候注册的系统服务?

SystemServer启动的时候。系统服务不完全是在SystemServer进程里面,还有一小部分单独开辟进程,比如ServiceManager。

系统服务和bind的应用服务有什么区别?

启动方式上的区别:系统服务大部分跑在SystemServer进程里面,也是在SystemServer里面启动的,如AMS,WMS,PMS。大部分服务跑在binder线程,少部分服务才跑在自己的工作线程。这里启动服务主要是服务初始化工作。而应用服务是客户端主动请求。

注册方式上的区别:先看系统服务的注册,无论是跑在SystemServer进程,还是独立进程,都要把binder实体对象注册到ServiceManager,是在启动的注册。而应用服务则是客户端向AMS发起bindService调用,AMS根据该bind对象是否已经注册进行不同的处理。

使用方式上的区别:系统服务通过上下文的getSystemServer()方法。而应用服务通过bindService发送请求,然后通过回调返回binder。

ServiceManager的启动:

1.启动进程:init进程读取init.rc配置文件,然后开启ServiceManager进程。

2.启用binder机制:

3.发布自己的服务:

4.等待并响应请求:

进程启动方式:

1.fork,子进程共享父进程资源

2.fork + execve(path,...),子进程资源由path指定。

什么时候触发应用进程启动?

启动组件时,如果没有该组件所在的进程没有启动,则启动进程,这是由framework层实现。

 

如何启动应用进程,即APP?

当我们启动应用组件(比如Activity)时,如果应用进程还未启动,则通过binder调用向AMS请求启动应用进程, AMS通过socket向zygote发消息,zygote收到消息后去启动应用进程。zygote fork出应用进程后,执行ActivityThread的main函数。应用进程启动后向AMS报告,注册ApplicationThread。

 

如何启动binder机制?

binder启动时机,应用进程启动流程中,zygote启动应用进程后,应用进程自己启动了binder机制。

1.打开binder驱动;

2.映射内存,分配缓冲区;

3.注册binder线程;

4.进入binder loop;

 

谈谈你对Application的理解。

Application的作用。

1.保存应用的全局变量。

2.初始化操作。

3.提供应用上下文。应用开启几个进程,就创建几个Application对象。

Application的继承关系。

Application继承ContextWrapper,ContextWrapper继承Context。

Application的生命周期。

1.Application构造函数。

2.attachBaseContext,获取上下文的方法,因此如果在上面Application构造方法里面使用了上下文就会报错。

3.onCreate。

注意,如果在Application里使用static静态变量,如果APP出现“内存重启”(由于系统内存不够,可能会回收Application和Activity),重启后该静态变量的值可能未初始化,可能导致bug。

 

谈谈对Context的理解

Application继承关系:Application继承ContextWrapper,ContextWrapper继承Context。

Application调用顺序:先调用Application构造函数,然后调用attachBaseContext,最后调用onCreate。

Activiy的继承关系:Activity继承ContextThemeWrapper,ContextThemeWrapper继承ContextWrapper。

Activiy调用顺序:先调用Activiy构造函数,然后调用attachBaseContext,最后调用onCreate。

Service继承关系:Service继承ContextWrapper,ContextWrapper继承Context。

Service调用顺序:先调用Service构造函数,然后调用attachBaseContext,最后调用onCreate。

第一个问题:应用里面有多少个Context?不同的Context之间有什么区别?

只有Application,Activity和Service有Context,而广播和ContentProvider没有。所以,Application,Activity和Service这三者的数量加起来,就是Context的数量。Activity由于需要显示UI,所以继承的是ContextThemeWrapper,而Application和Service继承的是ContextWrapper。

第二个问题:Activity里面的this和getBaseContext有什么区别?

this返回的是Context。 getBaseContext返回的是ContextWrapper里面的mBase。

第三个问题:getApplication和getApplicationContext有什么区别?

都是返回Application对象,getApplicationContext是Context里面的抽象方法,而getApplication是Activity和Service特有的,在别的地方不能用,比如广播不能用。

第四个问题:应用组件的构造函数,attachBaseContext,onCreate的调用顺序?

先调用构造函数,然后调用attachBaseContext,最后调用onCreate。

第五个问题:Context的作用。

Context是组件的上下文,便于访问系统资源,调用系统服务等。

 

Activity的启动流程?

创建Activity对象,获取Application,创建ContextImpl,attach上下文,生命周期回调onCreate()以及其他。

第一个问题:启动Activity会经历哪些生命周期回调?

第二个问题:冷启动大致流程,涉及哪些组件,通信过程是怎样的?

第三个问题:启动过程中,生命周期的回调原理?

 

Activity的显示原理?

WMS给应用端的Window分配并管理Surface,当应用端在Surface绘制完后,SurfaceFlinger就把Surface的

这些图像数据根据WMS提供的数据来进行合成,最后写到屏幕的缓冲区显示出来。

DecorView对应一个ViewRootIml对象(负责DecorView的绘制),这个ViewRootImp对象能和WMS通信,ViewRootImp通过IWindowSession

向WMS发起binder调用,而WMS通过IWindow向ViewRootImp发起binder调用。

第一个问题:PhoneWindow是什么,怎么创建的?

第二个问题:setContentView的原理,DecorView是什么?

第三个问题:ViewRoot是什么?有什么作用?

第四个问题:View的显示原理是什么?WMS发挥什么作用?

 

应用的UI线程是怎么启动的?

第一个问题:什么是UI线程?

UI线程就是刷新UI所在的线程,而且是单线程。

UI线程==主线程吗?

对于Activity来说,UI线程就是主线程。

对于View来说,UI线程就是View对应的VIewRootImpl创建时所在的线程。

Activity的DecorView对应VIewRootImpl是在主线程创建的。 

因此,如果VIewRootImpl不是在主线程创建,也可以刷新UI。

第二个问题:UI线程的启动流程,消息循环是怎么创建的?

第三个问题:了解Android的UI显示原理,UI线程和UI之间是怎么关联的?

 

Service启动原理

 

BinderService绑定原理

应用向AMS发起bindService调用,如果binder句柄存在,则AMS直接回调binder句柄,然后应用拿到bindre句柄去调用Service。

如果应用向AMS发起bindService调用时,binder句柄不存在,则AMS先向Service请求binder句柄,Service返回binder句柄给AMS,然后AMS回调binder句柄给应用,应用拿到bindre句柄去调用Service。当然,这个流程的前提是Service已经存在,如果Service不存在,则进入启动Service流程。

动态广播的注册和收发原理

1.注册广播封装了一个binder到AMS;

2.发广播的时候通过intent找到对应的receiver;

3.普通动态广播在系统端是并行分发,应用端串行分发;

 

静态广播是怎么注册的?

先在配置文件配置广播,然后android系统启动的时候,PMS扫描所有应用的配置文件,解析里面的广播,然后注册到PMS里面。静态广播是串行分发的,如果应用进程未启动,则先启动应用进程,如果分发超时,则废弃该广播。

 

Content Provider启动原理

应用A向AMS请求provider的binder对象,如果provider组件没有启动,则先启动该组件。provider启动后通过attachApplication向AMS报告自己启动完毕,AMS收到后向provider发起bindApplication让provider创建application同时初始化provider。然后provider通过publishContentProvider将binder对象发布给AMS,AMS收到后将该binder对象返回给应用A。应用A就可以向provider发起CRUD调用。流程图如下:

应用A向AMS请求provider的binder对象,如果provider已经启动,则AMS通过scheduleInstallProvider初始化Binder,然后将Binder对象发布给AMS,然后AMS将Provider返回被应用A。

 

 

屏幕刷新机制

首先View调用requestLayout()方法要重绘,也就是把Runnable放入choreographer的消息队列,choreographer并没有马上去处理该消息,而是向SurfaceFliger请求下一个Vsync信号,当下一个Vsync信号到来时向choreographer发通知,choreographer收到该通知后才处理消息队列里的消息。流程如下:

丢帧一般是什么原因引起的?

主线程有耗时操作,耽误了 View的绘制。

Android刷新频率60帧每秒,每隔16ms调用onDraw绘制一次?

刷新频率是指Vsync发出的频率,但不一定每次都去绘制。需要应用层主动发起绘制,在下一个Vsync信号来临时才绘制。

 onDraw完后屏幕会立即刷新吗?

不会,要等下一个Vsync信号。 

如果界面没有重绘,还会每隔16ms刷新屏幕吗?

会,只是看不出来。界面没有重绘表示应用层不会收到Vsync信号,但是屏幕还是每隔16ms发出Vsync信号。

如果在屏幕快要刷新的时候才去绘制会丢帧吗?

不一定,要等下一个Vsync信号。

 

Android Framework用到了哪些IPC方式?

1.管道:两次拷贝,半双工,单向,一般在父子进程之间使用,一般用于数据量不大的跨进程通信。

2.socket通信,两次拷贝,全双工,既可以读,也可以写,可以用于两个无亲缘关系的进程,Zygoge与AMS通信使用了socket。

3.共享内存,很快,不需要拷贝,可以用于两个无亲缘关系的进程,适用于进程间大数据传输,如图像。

4.信号,单向的,发出去后就不管了,只能带一个信号,不能带别的参数。知道进程的pid就能发信号。比如杀掉应用进程就使用了信号。

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章