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就能发信号。比如杀掉应用进程就使用了信号。