Android Service的啟動過程

xuyinhuan發表於2016-11-08

剛開始學習Service的時候以為它是一個執行緒的封裝,也可以執行耗時操作。其實不然,Service是執行在主執行緒的。直接執行耗時操作是會阻塞主執行緒的。長時間就直接ANR了。

我們知道Service可以執行一些後臺任務,是後臺任務不是耗時的任務,後臺和耗時是有區別的喔。
這樣就很容易想到音樂播放器,天氣預報這些應用是要用到Service的。當然如果要在Service中執行耗時操作的話,開個執行緒就可以了。

關於Service的執行狀態有兩種,啟動狀態和繫結狀態,兩種狀態可以一起。
啟動一個Service只需呼叫Context的startService方法,傳進一個Intent即可。看起來好像很簡單的說,那是因為Android為了方便開發者,做了很大程度的封裝。那麼你真的有去學習過Service是怎麼啟動的嗎?Service的onCreate方法回撥前都做了哪些準備工作?

先上一張圖大致瞭解下,灰色背景框起來的是同一個類中的方法,如下圖:

20161014212119951

那接下來就從原始碼的角度來分析Service的啟動過程。

當然是從Context的startService方法開始,Context的實現類是ContextImpl,那麼我們就看到ContextImpl的startService方法即可,如下:

會轉到startServiceCommon方法,那跟進startServiceCommon方法方法瞧瞧。

可以看到呼叫了ActivityManagerNative.getDefault()的startService方法來啟動Service,ActivityManagerNative.getDefault()是ActivityManagerService,簡稱AMS。

那麼現在啟動Service的過程就轉移到了ActivityManagerService,我們關注ActivityManagerService的startService方法即可,如下:

在上述的程式碼中,呼叫了ActiveServices的startServiceLocked方法,那麼現在Service的啟動過程從AMS轉移到了ActiveServices了。

繼續跟進ActiveServices的startServiceLocked方法,如下:

在startServiceLocked方法中又會呼叫startServiceInnerLocked方法,

我們瞧瞧startServiceInnerLocked方法,

startServiceInnerLocked方法內部呼叫了bringUpServiceLocked方法,此時啟動過程已經快要離開ActiveServices了。繼續看到bringUpServiceLocked方法。如下:

省略了大部分if判斷,相信眼尖的你一定發現了核心的方法,那就是
realStartServiceLocked,沒錯,看名字就像是真正啟動Service。那麼事不宜遲跟進去探探吧。如下:

找到了。app.thread呼叫了scheduleCreateService來啟動Service,而app.thread是一個ApplicationThread,也是ActivityThread的內部類。此時已經到了主執行緒。
那麼我們探探ApplicationThread的scheduleCreateService方法。如下:

對待啟動的Service元件資訊進行包裝,然後傳送了一個訊息。我們關注這個CREATE_SERVICE訊息即可。

在handleMessage方法中接收到這個訊息,然後呼叫了handleCreateService方法,跟進handleCreateService探探究竟:

終於擊破,這個方法很核心的。一點點分析

首先獲取到一個LoadedApk物件,在通過這個LoadedApk物件獲取到一個類載入器,通過這個類載入器來建立Service。如下:

接著呼叫ContextImpl的createAppContext方法建立了一個ContextImpl物件。

之後再呼叫LoadedApk的makeApplication方法來建立Application,這個建立過程如下:

當然Application是隻有一個的,從上述程式碼中也可以看出。

在回來繼續看handleCreateService方法,之後service呼叫了attach方法關聯了ContextImpl和Application等

最後service回撥了onCreate方法,

並將這個service新增進了一個了列表進行管理。

至此service啟動了起來,以上就是service的啟動過程。

你可能還想要知道onStartCommand方法是怎麼被回撥的?可能細心的你發現了在ActiveServices的realStartServiceLocked方法中,那裡還有一個sendServiceArgsLocked方法。是的,那個就是入口。

那麼我們跟進sendServiceArgsLocked方法看看onStartCommand方法是怎麼回撥的。

可以看到onStartCommand方法回撥過程和onCreate方法的是很相似的,都會轉到app.thread。那麼現在就跟進ApplicationThread的scheduleServiceArgs。
你也可能猜到了應該又是封裝一些Service的資訊,然後傳送一個訊息, handleMessage接收。是的,原始碼如下:

咦,真的是這樣。謎底應該就在handleServiceArgs方法了,那麼趕緊瞧瞧,原始碼如下:

可以看到回撥了onStartCommand方法。

以上就是Service的啟動過程的原始碼分析。

從中,我理解了Service的啟動過程的同時,閱讀原始碼的能力也提高了,分析原始碼的時候我沒能力把每一個變數,每一個方法都搞懂,我關注的都是一些關鍵的字眼,比如這篇文章就是start呀,service呀。會有那種感覺,就是這裡沒錯了。當然如果陷入衚衕了也要兜出來。

這樣的分析也能夠摸清整體的過程,對於細節,等我有紮實的功底了在去研究吧。

相關文章