當前位置:首頁 » 安卓系統 » android啟動service

android啟動service

發布時間: 2024-01-15 10:36:35

1. AndroidFramework 之啟動 ServiceManager

本文源碼基於 Android 10 ,涉及相關源碼如下。

ServiceManagaer 是 Binder 的守護進程,在 Binder 機制中起著重要的作用。本文將從源碼的角度對其進行分析,整體流程如下:

時序圖如下。

先來看看 ServiceManager 是如何啟動的:

在 Zygote 一文中說過, init 進程啟動的第二階段會解析 init.rc 文件。

在這之後會觸發 trigger init 。

結合 init.rc 看看 action init 做了什麼。

當觸發 trigger init 後,會啟動 servicemanager 服務,其聲明如下。

對應的執行文件為 /system/bin/servicemanager ,在編譯前位於 frameworks/native/cmds/servicemanager 下,來看看 Android.bp 。

其對應的源碼為 service_manager.c 和 binder.c ,入口函數 main() 位於 servicemanager.c 。

啟動完 ServiceManager 後會打開 Binder 驅動。

在 main() 中首先調用 binder_open() 。

binder_open() 主要做了如下事情:

給結構體 binder_state 分配內存。

系統調用 open() 打開 /dev/binder ,如果打開驅動失敗,則執行 fail_open 釋放內存。

簡單的解釋一下什麼是系統調用?

由於需要限制不同的程序之間的訪問能力,防止程序獲取別的程序的內存數據, CPU 劃分出兩個許可權等級, 用戶態 內核態

所有的用戶程序都是運行在用戶態,但有時需要做一些內核態的事情,而唯一可以做這些事情的就是操作系統,所以程序需要向操作系統發起請求,以程序的名字來執行這些操作。這時就需要一個從用戶態切換到內核態但不能控制內核態中執行的機制,這種機制就是 系統調用

系統調用 ioctl() 傳入 BINDER_VERSION 命令獲取 Binder 驅動版本,對比版本是否一致,不一致則執行 fail_open 釋放內存。

系統調用 mmap() 映射 128kb 的內存空間,即把 Binder 驅動文件的 128kb 映射到內存空間供 ServiceManager 使用,內存映射失敗則執行 fail_map ,關閉 fd 並釋放內存。

ServiceManager 進程 mmap 的內存大小可以通過 adb shell 命令查看。

可以看到內存映射地址為 0xf10f8000 ~ 0xf1118000 ,差為 0x20000 即十進制的 128kb 。

打開 Binder 驅動後會將 ServiceManager 設置為上下文管理者。

調用 binder_become_context_manager() 。

android 10 新增 BINDER_SET_CONTEXT_MGR_EXT 命令來設置安全的上下文管理者,如果設置失敗,則使用原有的 BINDER_SET_CONTEXT_MGR 命令來設置上下文管理者,兩者區別在於是否攜帶參數。

最後會進入循環,從 Binder 驅動讀取和解析數據。

調用 binder_loop() 進入循環,不斷地通過系統調用 ioctl() 從 Binder 驅動讀取數據,並通過 binder_parse() 進行數據解析。

注意這里調用 binder_loop() 傳入的 svcmgr_handler() ,後面會使用到。

binder_write() 會封裝 struct binder_write_read ,並通過系統調用 ioctl() 將對應的命令傳遞給 Binder 驅動。

binder_parse() 用來解析從 Binder 驅動讀取到的數據,然後根據不同的命令執行對應的操作。

因為 cmd 命令可能有多個,所以通過 while 循環每次處理一個 cmd 命令,多 cmd 的結構大致如下圖所示。

這里重點看下 BR_TRANSACTION 命令。

BR_TRANSACTION 是 Binder 驅動向 Server 端發送請求數據。

binder_transaction_data 的結構如下,其表明了 transcation 傳輸的具體語義,語義碼記錄在 code 中,不同語義碼攜帶的數據是不同的,這些數據由 data 指定。

在解析完 binder_transaction_data 的具體語義後,會調用前面傳給 binder_loop() 的 svcmgr_handler() ,其實就是 switch case 語義碼做不同的事情。

ServiceManager 的功能其實很簡單:

至此 ServiceManager 就分析完了。

2. Android中怎麼啟動關閉Service及功能解釋

下面根據問題,作出詳細解答:

  1. Service不是分離開的進程,除非其他特殊情況,它不會運行在自己的進程,而是作為啟動運行它的進程的一部分。

  2. Service不是線程,這意味著它將在主線程里勞作。


啟動service有兩種方法:

  1. Context.startService()調用者與服務之間沒有關聯,即使調用者退出,服務仍可運行

  2. Context.bindService() 調用者與服務綁定在一起,調用者一旦退出,服務也就終止

Service的生命周期

如果使用startService()啟動service,系統將通過傳入的Intent在底層搜索相關符合Intent裡面信息的service。如果服務沒有啟動則先運行onCreate,然後運行onStartCommand (可在裡面處理啟動時傳過來的Intent和其他參數),直到明顯調用stopService或者stopSelf才將停止Service。無論運行startService多少次,只要調用一次stopService或者stopSelf,Service都會停止。使用stopSelf(int)方法可以保證在處理好intent後再停止。

控制service運行的主要方式有兩種,主要是根據onStartCommand方法返回的數值。方法:

  1. START_STICKY

  2. START_NOT_STICKY or START_REDELIVER_INTENT


這里主要解釋這三個變數的意義:

  1. START_STICKY

    在運行onStartCommand後service進程被kill後,那將保留在開始狀態,但是不保留那些傳入的intent。不久後service就會再次嘗試重新創建,因為保留在開始狀態,在創建 service後將保證調用onstartCommand。如果沒有傳遞任何開始命令給service,那將獲取到null的intent

  2. START_NOT_STICKY

    在運行onStartCommand後service進程被kill後,並且沒有新的intent傳遞給它。Service將移出開始狀態,並且直到新的明顯的方法(startService)調用才重新創建。因為如果沒有傳遞任何未決定的intent那麼service是不會啟動,也就是期間onstartCommand不會接收到任何null的intent。

  3. START_REDELIVER_INTENT

    在運行onStartCommand後service進程被kill後,系統將會再次啟動service,並傳入最後一個intent給onstartCommand。直到調用stopSelf(int)才停止傳遞intent。如果在被kill後還有未處理好的intent,那被kill後服務還是會自動啟動。因此onstartCommand不會接收到任何null的intent。


客戶端也可以使用bindService來保持跟service持久關聯。謹記:如果使用這種方法,那麼將不會調用onstartCommand(跟startService不一樣,下面例子注釋也有解析,大家可試試)。客戶端將會在onBind回調中接收到IBinder介面返回的對象。通常IBinder作為一個復雜的介面通常是返回aidl數據。


Service也可以混合start和bind一起使用。

要運行service,首先必須在AndroidManifest.xml里申明<service>標簽。

Service能夠保護個人的IPC調用,所以在執行實現該調用時前先使用checkCallingPermission(String) 方法檢查是否有這個許可權。

進程生命周期

當service運行在低內存的環境時,將會kill掉一下存在的進程。因此進程的優先順序將會很重要:

  1. 如果service當前正在執行onCreate、onStartCommand、onDestroy方法,主進程將會成為前台進程來保證代碼可以執行完成避免被kill

  2. 如果service已經啟動了,那麼主進程將會比其他可見的進程的重要性低,但比其他看不見的進程高。因為只有少部分進程始終是用戶可見的,因此除非在極度低內存的時候,不然 service是不會被kill的。

  3. 如果有客戶端關聯到service,那麼service永遠比客戶端重要。也就是說客戶端可見,那麼service也可見(我理解這里的可見並不是可以看到,而是重要性,因為可見往往就表示重要性高)。

  4. Service可以使用startForeground API將service放到前台狀態。這樣在低內存時被kill的幾率更低,但是文檔後面又寫了,如果在極度極度低內存的壓力下,該service理論上還是會被kill掉。但這個情況基本不用考慮。

當然如果service怎麼保持還是被kill了,那你可以通過重寫onStartCommand返回變數來設置它的啟動方式。比如:START_STICKY、START_REDELIVER_INTENT等等,前面已經討論了它們的作用,這里就不再累贅了

另外:

service 的onCreate和onStartCommand 是運行在主線程的,所以如果裡面有處理耗時間的任務。兩種處理:

  1. 請將它們都挪到新的線程里。

  2. 用系統提供的IntentService,它繼承了Service,它處理數據是用自身新開的線程。

3. 如何在android系統中開啟自己的服務

Android開機啟動Service,需要使用BroadcastReceiver,Android系統,開機會發送一個開機廣播,可以通過BroadcastReceiver來接收開機廣播。
具體代碼:
1.在配置文件AndroidManifest.xml中向系統注冊receiver
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>

2.需要添加相應許可權
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

3.在Receiver中就可以添加開機需要進行的操作
public class BootCompletedReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {

}
}

4.執行開機後的操作,Intent intent = new Intent(context,Service.class); context.startService(intent); 這樣即可開機啟動Service了。

4. Android中怎麼啟動關閉Service及功能解釋

啟動:
//首先注冊服務
<service
android:name="com.wangdeyu.service.MusicService"
android:exported="false" >
<intent-filter>
<action android:name="com.abc" />
</intent-filter>
</service>

//啟動服務
Intent service=new Intent(" com.abc");
startService(service);
//Service生命周期
①onCreate() 創建Service
②onStart(Intent intent, int startId) 啟動Service
③onDestroy() 銷毀Service
//關閉服務
stopService(service);

Service的生命周期方法比Activity少一些,只有onCreate, onStart, onDestroy
我們有兩種方式啟動一個Service,他們對Service生命周期的影響是不一樣的。
1 通過startService,就是上面這種
Service會經歷 onCreate --> onStart
stopService的時候直接onDestroy
如果是 調用者 直接退出而沒有調用stopService的話,Service會一直在後台運行。
下次調用者再起來仍然可以stopService。
2 通過bindService
Service只會運行onCreate, 這個時候 調用者和Service綁定在一起
調用者退出了,Srevice就會調用onUnbind-->onDestroyed
所謂綁定在一起就共存亡了。
注意:Service的onCreate的方法只會被調用一次,
就是你無論多少次的startService又 bindService,Service只被創建一次。
如果先是bind了,那麼start的時候就直接運行Service的onStart方法,
如果先是start,那麼bind的時候就直接運行onBind方法。如果你先bind上了,就stop不掉了,
只能先UnbindService, 再StopService,所以是先start還是先bind行為是有區別的。
Android中的服務和windows中的服務是類似的東西,服務一般沒有用戶操作界面,它運行於系統中不容易被用戶發覺,可以使用它開發如監控之類的程序。
服務不能自己運行,需要通過調用Context.startService()或Context.bindService()方法啟動服務。
這兩個方法都可以啟動Service,但是它們的使用場合有所不同。使用startService()方法啟用服務,調用者與服務之間沒有關連,
即使調用者退出了,服務仍然運行。使用bindService()方法啟用服務,調用者與服務綁定在了一起,調用者一旦退出,服務也就終止,大有「不求同時生,必須同時死」的特點。
如果打算採用Context.startService()方法啟動服務,在服務未被創建時,系統會先調用服務的onCreate()方法,
接著調用onStart()方法。如果調用startService()方法前服務已經被創建,多次調用startService()方法並不會導致多次創建服務,
但會導致多次調用onStart()方法。採用startService()方法啟動的服務,只能調用Context.stopService()方法結束服務,服務結束時會調用onDestroy()方法。
如果打算採用Context.bindService()方法啟動服務,在服務未被創建時,系統會先調用服務的onCreate()方法,
接著調用onBind()方法。這個時候調用者和服務綁定在一起,調用者退出了,系統就會先調用服務的onUnbind()方法,
接著調用onDestroy()方法。如果調用bindService()方法前服務已經被綁定,
多次調用bindService()方法並不會導致多次創建服務及綁定(也就是說onCreate()和onBind()方法並不會被多次調用)。
如果調用者希望與正在綁定的服務解除綁定,可以調用unbindService()方法,調用該方法也會導致系統調用服務的onUnbind()-->onDestroy()方法.

5. Android 10.0 ActivityManagerService的啟動流程

我們講完了SystemServer的啟動過程,本節主要來講解ActivityManagerService的啟動過程。ActivityManagerService簡稱AMS,管理Activity行為,控制Activity的生命周期,派發消息事件,內存管理等功能。

ActivityManagerService啟動由SystemServer中startBootstrapService啟動

ATM啟動最終調用的是ActivityTaskManagerService.Lifecycle.onStart()來啟動ATM服務的
源碼:ActivityTaskManagerService.java#Lifecycle.class

將ActivityTaskManagerInternal添加到本地服務的全局注冊表中。
ActivityTaskManagerInternal為抽象類,其實現類為ActivityTaskManagerService#LocalService.class

構造函數初始化主要工作就是初始化一些變數,供之後的service,broadcast,provider的管理和調度

start中做了兩件事

AMS的systemReady處理分為三個階段

同時獲取一些配置參數。 需要注意的是,由於只有Java進程才會向AMS注冊,而一般的Native進程不會向AMS注冊,因此此處殺死的進程是Java進程。

主要是調用一些關鍵服務的初始化函數,然後殺死那些沒有FLAG_PERSISTENT 卻在AMS啟動完成前已經存在的進程,同時獲取一些配置參數。需要注意的是,由於只有Java進程才會向AMS注冊,而一般的Native進程不會向AMS注冊,因此此處殺手的進程是Java進程。

執行goingCallback的處理,主要的工作就是通知一些服務可以進行systemReady相關的工作,並進行啟動服務或應用進程的工作

監控Native的crash,啟動WebView,執行一些服務的systemReady和systemRunning方法

啟動Home Activity,當啟動結束,發送ACTION_BOOT_COMPLETED廣播時,AMS的啟動過程告一段落

啟動Home Activity

AMS的啟動主要經歷了如下幾個階段:

熱點內容
linuxpython2與3共存 發布:2024-11-28 21:43:41 瀏覽:904
短視頻平台上傳視頻規范 發布:2024-11-28 21:41:22 瀏覽:553
c語言統計素數的個數 發布:2024-11-28 21:38:24 瀏覽:837
我的世界伺服器管理員沒了怎麼辦 發布:2024-11-28 21:37:22 瀏覽:183
請求分段存儲 發布:2024-11-28 21:23:20 瀏覽:458
zip偽加密 發布:2024-11-28 21:23:17 瀏覽:226
linuxshell路徑 發布:2024-11-28 21:13:05 瀏覽:994
存儲為web所用格式切片 發布:2024-11-28 21:11:23 瀏覽:452
伺服器電腦主機怎麼裝 發布:2024-11-28 21:06:41 瀏覽:222
android調用aidl 發布:2024-11-28 21:05:46 瀏覽:867