【移動應用開發(fā)技術】Android 添加系統服務的方法詳解_第1頁
【移動應用開發(fā)技術】Android 添加系統服務的方法詳解_第2頁
【移動應用開發(fā)技術】Android 添加系統服務的方法詳解_第3頁
【移動應用開發(fā)技術】Android 添加系統服務的方法詳解_第4頁
【移動應用開發(fā)技術】Android 添加系統服務的方法詳解_第5頁
免費預覽已結束,剩余2頁可下載查看

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

【移動應用開發(fā)技術】Android添加系統服務的方法詳解

一、前言

系統服務是Android中非常重要的一部分,像ActivityManagerService,PackageManagerService,WindowManagerService,這些系統服務都是Framework層的關鍵服務,本篇文章主要講一下如何基于Android源碼添加一個系統服務的完整流程,除了添加基本系統服務,其中還包含添加JNI部分代碼和App通過AIDL調用的演示Demo,調用包含App調用服務端,也包含服務端回調App,也就是完成一個簡單的雙向通信.注:測試代碼基于Android7.1.1,其他Android版本都是大同小異.二、編寫AIDL文件

添加服務首先是編寫AIDL文件,AIDL文件路徑如下:frameworks/base/core/java/com/example/utils/

1.ISystemEvent.aidl內容如下:

2.IEventCallback.aidl內容如下

AIDL文件編寫,教程很多,我這里就不詳細說明了,需要注意的是,由于我們要實現回調功能,所以必須寫一個回調接口IEventCallback,另外AIDL文件中oneway關鍵字表明調用此函數不會阻塞當前線程,調用端調用此函數會立即返回,接收端收到函數調用是在Binder線程池中的某個線程中.可以根據實際項目需求選擇是否需要加oneway關鍵字.AIDL只支持傳輸基本java類型數據,要想傳遞自定義類,類需要實現Parcelable接口,另外,如果傳遞基本類型數組,需要指定inout關鍵字,比如

voidtest(inbyte[]input,outbyte[]output)

,用in還是out,只需要記住:數組如果作為參數,通過調用端傳給被調端,則使用in,如果數組只是用來接受數據,實際數據是由被調用端來填充的,則使用out,這里之所以沒有說服務端和客戶端,是因為inout關鍵字用哪個和是服務端還是客戶端沒有聯系,遠程調用和被調用更適合描述.文件寫完后,添加到編譯的Android.mk中LOCAL_SRC_FILES后面:3.frameworks/base/Android.mk

編譯代碼,

編譯前需執(zhí)行makeupdate-api,更新接口,然后編譯代碼,確保AIDL編寫沒有錯誤,編譯后會生成對應java文件,服務端要實現對應接口.三、編寫Manager類

我們可以看到,AndroidAPI中有很多Manager類,這些類一般都是某個系統服務的客戶端代理類,其實我們不寫Manager類,只通過AIDL文件自動生成的類,也可以完成功能,但封裝一下AIDL接口使用起來更方便,我們測試用的Manager類為SystemEventManager,代碼如下:

frameworks/base/core/java/com/example/utils/SystemEventManager.java代碼很簡單,就封裝了下AIDL接口,定義了系統服務注冊時用的名字.構造函數中的ISystemEvent參數在后面注冊Manager時候會通過Binder相關接口獲取.編譯代碼,確保沒有錯誤,下面編寫系統服務.四、編寫系統服務

路徑以及代碼如下:

frameworks/base/services/core/java/com/android/server/example/SystemEventService.java服務端繼承自ISystemEvent.Stub,實現對應的三個方法即可,需要注意的是,由于有回調功能,所以要把注冊的IEventCallback加到鏈表里面,這里使用了RemoteCallbackList,之所以不能使用普通的List或者Map,原因是,跨進程調用,App調用registerCallback和unregisterCallback時,即便每次傳遞的都是同一個IEventCallback對象,但到服務端,經過跨進程處理后,就會生成不同的對象,所以不能通過直接比較是否是同一個對象來判斷是不是同一個客戶端對象,Android中專門用來處理跨進程調用回調的類就是RemoteCallbackList,RemoteCallbackList還能自動處理App端異常死亡情況,這種情況會自動移除已經注冊的回調.RemoteCallbackList使用非常簡單,注冊和移除分別調用register()和unregister()即可,遍歷所有Callback稍微麻煩一點,代碼參考上面的sendEventToRemote()方法.可以看到,我們測試用的的系統服務邏輯很簡單,注冊和移除Callback調用RemoteCallbackList對應方法即可,sendEvent()方法在App端調用的基礎上,在字符串后面加上"remote"后回調給App,每個方法也加了log方便理解流程,服務端代碼就完成了.五、注冊系統服務

代碼寫好后,要注冊到SystemServer中,所有系統服務都運行在名為system_server的進程中,我們要把編寫好的服務加進去,SystemServer中有很多服務,我們把我們的系統服務加到最后面,對應路徑和代碼如下:

frameworks/base/services/java/com/android/server/SystemServer.java通過ServiceManager將服務加到SystemServer中,名字使用SystemEventManager.SERVICE,后面獲取服務會通過名字來獲取.此時,如果直接編譯運行,開機后會出現如下錯誤:

ESystemServer:java.lang.SecurityException

ESELinux:avc:

denied

{add}forservice=test_systemeventpid=1940uid=1000scontext=u:r:system_server:s0tcontext=u:object_r:default_android_service:s0tclass=service_managerpermissive=0

ESystemServer:java.lang.SecurityExceptionESELinux:avc:

denied

{add}forservice=test_systemeventpid=1940uid=1000scontext=u:r:system_server:s0tcontext=u:object_r:default_android_service:s0tclass=service_managerpermissive=0這個是沒有Selinux權限,我們需要加上添加服務的權限,代碼如下:首先定義類型,test_systemevent要和添加服務用的名字保持一致

system/sepolicy/service_contextssystem/sepolicy/service.te加入上面代碼后,編譯刷機開機后,服務就能正常運行了.六、注冊Manager

系統服務運行好了,接下來就是App怎么獲取的問題了,App獲取系統服務,我們也用通用接口:

在調用getSystemService()之前,需要先注冊,代碼如下:frameworks/base/core/java/android/app/SystemServiceRegistry.java注冊后,如果你在App里面通過getSystemService(SystemEventManager.SERVICE);獲取Manager并調用接口,會發(fā)現又會出錯,又是Selinux權限問題:

ESELinux:avc:

denied

{find}forservice=test_systemeventpid=4123uid=10035scontext=u:r:untrusted_app:s0:c512,c768tcontext=u:object_r:test_systemevent_service:s0tclass=service_managerpermissive=0

ESELinux:avc:

denied

{find}forservice=test_systemeventpid=4123uid=10035scontext=u:r:untrusted_app:s0:c512,c768tcontext=u:object_r:test_systemevent_service:s0tclass=service_managerpermissive=0說是沒有find權限,因此又要加權限,修改代碼如下:

system/sepolicy/untrusted_app.te這個Selinux的知識有興趣自己去學一下,報了什么權限,就按照錯誤信息去對應文件添加權限.至此,系統代碼修改完成了,編譯系統刷機,下面通過App調用.七、App調用

文件拷貝和準備:

我們需要復制三個文件到App中,兩個AIDL文件,一個Manager文件:

IEventCallback.aidl

ISystemEvent.aidl

SystemEventManager.java

IEventCallback.aidl

ISystemEvent.aidl

SystemEventManager.java所有AIDL文件和java文件,在App工程中的包名和路徑都需要和系統保持一致,這三個文件App不能做任何修改,除非系統源碼中也做對應修改,總的來說,這三個文件App和系統中要完全保持一致,類名包名和包路徑都需一致,復制這三個文件到工程中后,編譯后,調用方式如下.獲取服務:這里AndroidStudio可能會報getSystemService()參數不是Context里面的某個服務的錯誤,可以直接忽略,不影響編譯.注冊/取消注冊:調用:測試Log如下:

DSystemEventManager:SystemEventManagerinit

DSystemEventService:registerpid:3944uid:10035result:true

DSystemEventService:remotecallbackcount:1

DSystemEvent:type:1value:teststringremote

DSystemEventService:unregisterpid:3944uid:10035result:true

DSystemEventManager:SystemEventManagerinit

DSystemEventService:registerpid:3944uid:10035result:true

DSystemEventService:remotecallbackcount:1

DSystemEvent:type:1value:teststringremote

DSystemEventService:unregisterpid:3944uid:10035result:true可以看到調用了服務端并成功收到服務端拼接的字符串.八、添加JNI部分代碼

我們一般添加系統服務,可能是為了調用驅動里面的代碼,所有一般要用JNI部分代碼,這里不是講怎么編寫JNI代碼,而是說下系統服務中已有的JNI代碼,我們可以直接在這基礎上增加我們的功能.JNI部分代碼位置為:

frameworks/base/services/core/jni/

frameworks/base/services/core/jni/

編譯對應mk為:

frameworks/base/services/Android.mk

frameworks/base/services/core/jni/Android.mk

frameworks/base/services/Android.mk

frameworks/base/services/core/jni/Android.mk

此部分代碼直接編譯為libandroid_servers動態(tài)庫,在SystemServer進行加載:

frameworks/base/services/java/com/android/server/SystemServer.java如果需要添加JNI部分代碼,直接在

frameworks/base/services/core/jni/目錄下增加對應文件,

在frameworks/base/services/core/jni/Android.

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論