一個Service是沒有界面且能長時間運行于后臺的應用組件.其它應用的組件可以啟動一個服務運行于后臺,即使用戶切換到另一個應用也會繼續運行.另外,一個組件可以綁定到一個service來進行交互,即使這個交互是進程間通訊也沒問題.例如,一個service可能處理網絡事物,播放音樂,執行文件I/O,或與一個內容提供者交互,所有這些都在后臺進行.
生命周期
左圖是startService()創建service,右圖是bindService()創建service。 startService與bindService都可以啟動Service,那么它們之間有什么區別呢?它們兩者的區別就是使Service的周期改變。由startService啟動的Service必須要有stopService來結束Service,不調用stopService則會造成Activity結束了而Service還運行著。bindService啟動的Service可以由unbindService來結束,也可以在Activity結束之后(onDestroy)自動結束。
關鍵方法
onStartCommand() 系統在其它組件比如activity通過調用startService()請求service啟動時調用這個方法.一旦這個方法執行,service就啟動并且在后臺長期運行.如果你實現了它,你需要負責在service完成任務時停止它,通過調用stopSelf()或stopService().(如果你只想提供綁定,你不需實現此方法).
OnBind() 當組件調用bindService()想要綁定到service時(比如想要執行進程間通訊)系統調用此方法.在你的實現中,你必須提供一個返回一個IBinder來以使客戶端能夠使用它與service通訊,你必須總是實現這個方法,但是如果你不允許綁定,那么你應返回null.
OnCreate() 系統在service第一次創建時執行此方法,來執行只運行一次的初始化工作(在調用它方法如onStartCommand()或onBind()之前).如果service已經運行,這個方法不會被調用.
OnDestroy() 系統在service不再被使用并要銷毀時調用此方法.你的service應在此方法中釋放資源,比如線程,已注冊的偵聽器,接收器等等.這是service收到的最后一個調用.
public abstract boolean bindService (Intent service, ServiceConnection conn, int flags)
BindService中使用bindService()方法來綁定服務,調用者和綁定者綁在一起,調用者一旦(all)退出服務也就終止了.
startService()
startService()方法會立即返回然后Android系統調用service的onStartCommand()方法.但是如果service尚沒有運行,系統會先調用onCreate(),然后調用onStartCommand().
protected abstract void onHandleIntent (Intent intent)
調用工作線程處理請求
public boolean onUnbind (Intent intent)
當所有client均從service發布的接口斷開的時候被調用。默認實現不執行任何操作,并返回false。
extends
Service
這是所有service的基類.當你派生這個類時,在service中創建一個新的線程來做所有的工作是十分重要的.因為這個service會默認使用你的應用的主線程(UI線程),這將拉低你的應用中所有運行的activity的性能
IntentService
這是一個Service的子類,使用一個工作線程來處理所有的啟動請求,一次處理一個.這是你不需你的service同時處理多個請求時的最好選擇.你所有要做的就是實現onHandleIntent(),這個方法接收每次啟動請求發來的intent,于是你可以做后臺的工作.
表現形式
Started
一個service在某個應用組件(比如一個activity)調用startService()時就處于"started"狀態(注意,可能已經啟動了).一旦運行后,service可以在后臺無限期地運行,即使啟動它的組件銷毀了.通常地,一個startedservice執行一個單一的操作并且不會返回給調用者結果.例如,它可能通過網絡下載或上傳一個文件.當操作完成后,service自己就停止了
Bound
一個service在某個應用組件調用bindService()時就處于"bound"狀態.一個boundservice提供一個client-server接口以使組件可以與service交互,發送請求,獲取結果,甚至通過進程間通訊進行交叉進行這些交互.一個boundservice僅在有其它應用的組件綁定它時運行.多個應用組件可以同時綁定到一個service,但是當所有的自由競爭組件不再綁定時,service就銷毀了.
Bound Service
當創建一個提供綁定的service時,你必須提供一個客戶端用來與service交互的IBinder.有三種方式你可以定義這個接口:
從類Binder派生
如果你的service是你自己應用的私有物,并且與客戶端運行于同一個進程中(一般都這樣),你應該通過從類Binder派生來創建你的接口并且從onBind()返回一它的實例.客戶端接收這個Binder然后使用它來直接操作所實現的Binder甚至Service的公共接口.
當你的service僅僅是一個后臺工作并且僅服務于自己的應用時,這是最好的選擇.唯一使你不能以這種方式創建你的接口的理由就是你的service被其它應用使使用或者是跨進程的.
使用一個Messenger
如果你需要你的接口跨進程工作,你可以為service創建一個帶有Messager的接口.在此方式下,service定義一個Handler來負責不同類型的Message對象.這個Handler是Messenger可以與客戶端共享一個IBinder的基礎,它允許客戶端使用Message對象發送命令給servic.客戶端可以定義一個自己的Messenger以使service可以回發消息.
這是執行IPC的最簡單的方法,因為Messenger把所有的請求都放在隊列中依次送入一個線程中,所以你不必把你的service設計為線程安全的
使用AIDL
AIDL(Android接口定義語言)執行把對象分解為操作系統能夠理解并能跨進程封送的基本體以執行IPC的所有的工作.上面所講的使用一個Messenger,實際上就是基于AIDL的.就像上面提到的,Messenger在一個線程中創建一個容納所有客戶端請求的隊列,使用service一個時刻只接收一個請求.然而,如果你想要你的service同時處理多個請求,那么你可以直接使用AIDL.在此情況下,你的service必須是多線程安全的.
要直接使用AIDL,你必須創建一個.aidl文件,它定義了程序的接口.AndroidSDK工具使用這個文件來生成一個實現接口和處理IPC的抽象類,之后你在你的service內派生它.
注:大多數應用不應使用AIDL來處理一個綁定的service,因為它可能要求有多線程能力并且導致實現變得更加復雜.同樣的,AIDL也不適合于大多數應用并且本文檔不會討論如何在你的service中使用它.如果你確定你需要直接使用AIDL,請看AIDL的文檔.
注意
如果你打算只在本應用內使用自己的service,那么你不需指定任何intent過濾器.不使用intent過濾器,你必須使用一個明確指定service的類名的intent來啟動你的service.
另外,你也可以通過包含android:exported屬性,并指定其值為“false”來保證你的service是私有的.即使你的service使用了intent過濾器,也會起作用.
當一個service被啟動后,它的生命期就不再依賴于啟動它的組件并且可以獨立運行于后臺,即使啟動它的組件死翹翹了.所以,service應該工作完成后調用stopSelf()自己停止掉,或者其它組件也可以調用stopService()停止service. 如果service沒有提供綁定功能,傳給startService()的intent是應用組件與service之間唯一的通訊方式.然而,如果你希望service回發一個結果,那么啟動這個service的客戶端可以創建一個用于廣播(使用getBroadcast())的PendingIntent然后放在intent中傳給service,service然后就可以使用廣播來回送結果.
service分類
私有service:不能被其他應用調用,相對安全
公開service:可以被任意應用調用
合作service:只能被信任合作公司的應用調用
內部service:只能被內部應用調用
intent-filter與exported組合建議
總結:
exported屬性明確定義
私有service不定義intent-filter并且設置exported為false
公開的service設置exported為true,intent-filter可以定義或者不定義
內部/合作service設置exported為true,intent-filter不定義
rule book
只被應用本身使用的service應設置為私有
service接收到的數據需需謹慎處理
內部service需使用簽名級別的protectionLevel來判斷是否未內部應用調用
不應在service創建(onCreate方法被調用)的時候決定是否提供服務,應在onStartCommand/onBind/onHandleIntent等方法被調用的時候做判斷.
當service又返回數據的時候,因判斷數據接收app是否又信息泄露的風險
有明確的服務需調用時使用顯示意圖
盡量不發送敏感信息
合作service需對合作公司的app簽名做效驗
service不像broadcast receicer只能靜態注冊,通過反編譯查看配置文件Androidmanifest.xml即可確定service,若有導出的service則進行下一步
方法查看service類,重點關注onCreate/onStarCommand/onHandleIntent方法
檢索所有類中startService/bindService方法及其傳遞的數據
根據業務情況編寫測試poc或者直接使用adb命令測試
案例1:權限提升
案例2:services劫持
攻擊原理:隱式啟動services,當存在同名services,先安裝應用的services優先級高
攻擊模型
案例3:拒絕服務
現在除了空指針異常crash外還多出了一類crash:intent傳入對象的時候,轉化出現異常.
Serializable:
Intent i = getIntent(); if(i.getAction().equals("serializable_action"))
{
i.getSerializableExtra("serializable_key");//未做異常判斷
}
Parcelable:
this.b =(RouterConfig) this.getIntent().getParcelableExtra("filed_router_config");//引發轉型異常崩潰
POC內傳入畸形數據即可引發crash,修復很簡單捕獲異常即可.
案例4:消息偽造
http://blog.csdn.net/niu_gao/article/details/7307462
http://developer.android.com/reference/android/app/Service.html
http://developer.android.com/guide/components/services.html