Android native程序間通訊例項-binder篇之——HAL層訪問JAVA層的服務
有一天在群裡聊天的時候,有人提出一個問題,怎樣才能做到HAL層訪問JAVA層的介面?剛好我不會,所以做了一點研究。
之前的文章末尾部分說過了service call 可以用來除錯系統的binder服務。 傳送門: Android native程序間通訊例項-binder篇之——簡單的單工通訊
這次可以用到這個命令了!
1. 隨機選取一個java層的服務。
adb shell 中輸入命令 service list,選取一個服務來做研究,這次看中的是 textservices, 注意第一個服務 bysysui 後面的 "[ ]" 裡面沒有內容,不能選取這樣的服務來做這次的研究。
2. 搜尋這個服務相關的原始碼。
frameworks/base/services/core/java/com/android/server/TextServicesManagerService.java
frameworks/base/core/java/com/android/internal/textservice/ITextServicesManager.aidl
out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/com/android/internal/textservice/ITextServicesManager.java
3. 選擇一個介面用於被 HAL 層的程式碼訪問
可以知道TextServicesManagerService.java 中 有一行 public class TextServicesManagerService extends ITextServicesManager.Stub,
所以我從 ITextServicesManager.aidl 來選擇要訪問的介面, 這次選的就是 boolean isSpellCheckerEnabled(); 這個函式應該就是返回一個bool變數而已,越簡單越好。
4. 搜尋 binder 中 transact 需要輸入的 code
因為吧啦吧啦的原因(可以自行去別的博文搜尋原理,本系列博文側重實際操作),所以在out目錄下可以獲取到每個服務中各個介面訪問鎖需要傳入的code。
在out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/com/android/internal/textservice/ITextServicesManager.java中可以發現熟悉的onTransact介面,
同時發現呼叫 sSpellCheckerEnabled 的code為TRANSACTION_isSpellCheckerEnabled,
它的定義是:static final int TRANSACTION_isSpellCheckerEnabled = (android.os.IBinder.FIRST_CALL_TRANSACTION + 7);
因為android.os.IBinder.FIRST_CALL_TRANSACTION的值是1, 所以可知code為 8
5. 使用service call 來撩一下 isSpellCheckerEnabled
可以看到Parcel有兩個值,第一個是00000000,第二個是00000001.
再看看ITextServicesManager.java中TRANSACTION_isSpellCheckerEnabled這個code的處理,果然write了兩次,而第二次writeInt的值就是我們需要獲取的bool值了!
ITextServicesManager.java
case TRANSACTION_isSpellCheckerEnabled: { data.enforceInterface(DESCRIPTOR); boolean _result = this.isSpellCheckerEnabled(); reply.writeNoException(); reply.writeInt(((_result)?(1):(0))); return true; }
按照之前分析的方法,傳送門:Android native程序間通訊例項-binder篇之——用parcel傳輸陣列
1. 首先data.enforceInterface 傳進去了一個組字串 private static final java.lang.String DESCRIPTOR = "com.android.internal.textservice.ITextServicesManager";
感覺這組字串是和校驗有關了,查看了Parcel.cpp 原始碼, 發現enforceInterface果然是對比字串用的,在這個介面的上面有個介面名字叫做 writeInterfaceToken,
所以到時候要用 writeInterfaceToken 來寫這組字串用於比對校驗。
2. writeNoException 和 writeInt 最終呼叫的是 Parcel.cpp 裡面writeInt32,所以reply部分要 readInt32 兩次。
6. HAL層程式碼怎麼寫
就直接在之前寫的mybinderclient.cpp 上面貼原始碼吧transct 前寫校驗字串,然後傳入code 值為8,最後readInt32 兩次,第二次就是要讀取的JAVA 層服務isSpellCheckerEnabled 的值啦!
#include <binder/IServiceManager.h> #include <binder/IPCThreadState.h> #include <binder/Parcel.h> #include <binder/IInterface.h> #include<stdio.h> #define LOG_TAG "binderclient" using namespace android; int main(int argc, char** argv) { static int TRANSACTION_isSpellCheckerEnabled = (/*android.os.IBinder.FIRST_CALL_TRANSACTION*/1 + 7); sp<IBinder> ITextServicesBinder = defaultServiceManager()->getService(String16("textservices")); Parcel ITextServicesData, ITextServicesReply; ITextServicesData.writeInterfaceToken(String16("com.android.internal.textservice.ITextServicesManager")); ITextServicesBinder->transact(TRANSACTION_isSpellCheckerEnabled, ITextServicesData, &ITextServicesReply); int ret = ITextServicesReply.readInt32(); int ret2 = ITextServicesReply.readInt32(); printf("ret = %d, isSpellCheckerEnabled = %d\n", ret, ret2); return 0; }
執行結果:
這次在HAL層通過binder 訪問 JAVA 層服務的簡單例子就講解到這裡,希望大家看完以後能夠觸類旁通,在這個例子上面得到啟發。
希望大家多多吐槽,大家一起共同進步!!
&n