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就能發信號。比如殺掉應用進程就使用了信號。

 

 

 

 

 

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