標籤:
在之前已經介紹了一篇關於如何編寫簡單的驅動以及訪問該驅動的小程式,最後將程式編譯到Android核心源碼中通過程式訪問驅動驗證是可以通過的,那麼本文就繼續這個知識點,把這個驅動程式通過JNI串連建立一個系統服務,提供給上層應用訪問改服務功能,可以看到前一篇介紹驅動程式的功能是屬於核心層的,而本文介紹的內容是Framework層的知識。
聲明:本文內容參考羅昇陽的書籍:《Android系統原始碼情景分析》 如果想瞭解更詳細的內容非常建議購買此書
非常感謝羅神的這本書,給我帶來很多未知的知識,大神的部落格地址:http://blog.csdn.net/luoshengyang
一、編寫JNI層服務代碼
第一步:建立JNI目錄
進入到系統的JNI目錄中:frameworks/base/services/jni 在這個目錄中包含了系統服務的所有JNI實現的程式:
第二步:編寫JNI代碼
實現代碼也比較簡單,直接存取之前編譯好的驅動即可,然後在提供給外部一個讀寫的方法,最後在進行JNI方法的手動註冊:
第三步:修改編譯指令碼
在同一目錄中有一個Android.mk檔案,需要添加我們的這個服務,後續要將這個服務編譯到源碼中:
第四步:添加服務JNI功能的載入配置
上面已經編寫好了我們的系統服務功能,也手動註冊了一些讀寫方法,那麼還需要把這個註冊功能添加到系統的onload.cpp檔案中被調用,不然系統編譯之後也是找不到那個JNI方法的,而這個onload.cpp程式,是系統啟動的時候去運行,內部是專門註冊系統服務的JNI方法的:
第五步:編譯framework層源碼
上面幾步已經完成了代碼編寫和指令碼配置,下面就可以直接編譯源碼,把這個服務的JNI功能編譯到源碼中,可以直接使用mmm命令進行單獨模組的編譯:
mmm frameworks/base/services/jni
make snod
這樣編譯之後的system.img中就包含了我們定義的系統JNI服務實現邏輯,接下來我們就可以編寫Java代碼來訪問這個JNI暴露的讀寫方法了。
二、編寫Java層服務代碼
第一步:建立服務的AIDL檔案
進入系統服務的AIDL檔案目錄:frameworks/base/core/java/android/os 這裡存放了系統所有服務的AIDL定義
關於AIDL內容,也是很簡單的,提供讀寫方法:
第二步:編譯AIDL檔案
我們在使用AIDL的時候都知道,定義完檔案之後,必須編譯一下,產生對應的Java代碼,這樣後續才能使用類似於XXX.Stub類,才能在遠端服務實現具體功能。這裡也是一樣的,所以我們得先編譯這個aidl檔案:
mmm frameworks/base
單獨編譯framework模組代碼,這樣就會產生對應的IFregService.Stub類了。
第三步:實現具體服務功能
上面已經編譯aidl檔案,產生了對應的java代碼,下面如果想實現具體的功能,就必須繼承Stub類,這個檔案存放的目錄為:frameworks/base/services/java/com/android/server 系統中所有具體服務實現都是在這個目錄中:
代碼實現也比較簡單:
在這裡會定義讀寫的native方法,和之前的JNI層實現的方法對應:
第四步:將服務添加到ServiceManager中
為了讓上次訪問到這個服務,和系統其它服務一樣,咋們必須得把服務註冊到ServiceManager中,而這個註冊功能是在SystemServer類中,因為在系統啟動的時候,Zygote進程產生的第一個進程就是system_server,在這個進程中做了系統服務的註冊工作,我們在服務的同一目錄中找到SystemServer.java類,在ServerThread::run函數中註冊:
這樣註冊之後,上層應用就可以通過ServiceManager直接擷取到這個服務了,就可以直接存取具體功能了。
第六步:編譯Framework源碼
上面都已經完成了Java層服務代碼的實現了,而到這裡,我們似乎已經看到了熟悉的代碼了,比如服務的AIDL定義,實現和註冊服務功能,和之前介紹的 Binder機制以及遠程服務調用機制的知識 越來越接近了,下面在最後一步,編譯源碼:
mmm frameworks/base/services/java
make snod
編譯之後得到system.img檔案就包含了我們在Framework定義的FregService服務了,而這個服務的名稱是freg,下面繼續介紹如何編寫一個程式來訪問這個服務功能。
三、編寫系統應用訪問服務功能
前面已經介紹了編寫Framework中的服務功能,在JNI層實現了訪問驅動的native代碼,然後實現了Java層代碼調用這些native方法實現驅動的讀寫功能,並且定義了一個系統服務,封裝這些功能,最後把這個服務註冊到系統中,這裡我們就來編寫一個簡單的Android系統程式,來訪問這個服務功能:
第一步:建立程式項目
建立系統程式項目都是在這個目錄中:packages/experimental,我們定義一個Freg項目:
這個項目結構和正常的Android程式結構一樣,沒什麼好說的,因為這裡不是依賴於IDE編譯,所以咋們還得編寫編譯指令碼Android.mk檔案:
關於Android程式碼也比較簡單,直接通過ServiceManager來訪問這個服務即可:
第二步:編譯應用程式
上面的程式建立完成之後,接下來再次編譯源碼,把這個應用打包到系統中:
mmm packages/experimental/Freg
make snod
編譯完成之後,產生的system.img檔案就包含了這個系統應用程式
第三步:啟動模擬器驗證程式
接下來咋們就可以啟動模擬器,來運行這個小程式了:
emulator -kernel kernel/common/arch/arm/boot/zImage &
我們找到這個程式之後,開啟的效果:
開啟這個程式之後,我們可以進行讀寫操作了:
四、流程總結
到這裡我們就成功了完成了手動編寫一個簡單的系統服務並且添加到系統中,結合之前的一篇文章內容,下面就來總結整個過程,先來一張圖壓壓驚:
有了這張圖咋們再來總結一下:
1、編寫驅動
1>在 kernel/driver 目錄下建立freg驅動程式
2>make menuconfig 編譯驅動程式到核心源碼中
2、編寫Framework層服務的JNI程式
1>在 frameworks/base/services/jni 目錄下建立了服務的jni代碼
2>在onload.cpp中添加服務jni方法的註冊邏輯
3>mmm frameworks/base/services/jni 編譯jni程式到系統源碼中
3、編寫Framework層服務的Java程式
1>在 frameworks/base/core/java/android/os 目錄下建立了服務的AIDL檔案
2>mmm frameworks/base 編譯AIDL檔案,產生對應的Java代碼
3>在 frameworks/base/services/java/com/android/server 目錄中編寫具體服務的實現功能
4>最後在同一目錄下找到SystemServer.java檔案中註冊該服務(ServiceManager.addService方法)
5>mmm frameworks/base/services/java 編譯java層服務
4、編寫系統Android應用程式
1>在 packages/experimental 目錄下建立Android項目,在程式中直接使用ServiceManager來得到遠端服務即可
2>mmm packages/experimental/Freg 編譯器到系統中
3>啟動模擬器驗證結果 :emulator -kernel kernel/common/arch/arm/boot/zImage &
說到底,其實這個實驗有的同學可能非常感興趣,可能想立馬就實驗一把,但是這裡現在最大的問題就是你得必須先編譯過Android源碼,這個是最核心的也是最基本的,然後在按照這些流程走的話就很簡單了,所以作為一個Android開發人員畢生還是要編譯一次Android源碼的。所以感興趣的同學應該趕快動起手來編譯Android源碼。
項目地址下載:http://download.csdn.net/detail/jiangwei0910410003/9642835
五、總結
到這裡就結束了如何手動編寫系統服務並且添加到系統中的工作了,同時也暫時結束了這段時間介紹的Android系統篇的系列知識,其實我本來只是想介紹如何Hook掉系統的AMS服務攔截應用啟動的知識,可是誰都想不到引出了這麼一大串的知識出來,沒辦法我也只能慢慢的一篇一篇介紹了。
更多內容:點擊這裡
關注公眾號,最新技術乾貨即時推送
Android系統篇之----編寫系統服務並且將其編譯到系統源碼中