Android Binder機制詳解:手寫IPC通訊
想要掌握一樣東西,最好的方式就是閱讀理解它的原始碼。想要掌握Android Binder,最好的方式就是寫一個AIDL檔案,然後檢視其生成的程式碼。本文的思路也是來自於此。
簡介
Binder是Android常用的一種程序間通訊方式。當然,不使用Binder,你還可以使用Socket甚至檔案來進行通訊。
通常Android上的程序間通訊,指的就是遠端Service的呼叫。
開始
新建測試工程
開啟Android Studio新建IPCClient和IPCServer兩個app工程。
假設我們要做這樣一件事情:
-
Client向Server發起一個請求:請告訴我1+2等於多少
-
Server將答案返回給Client
建立遠端Service
IPCServer新建ManualCalculatorService作為遠端Service。
遠端Server需要重寫onBind。
public class ManualCalculatorService extends Service
{
@Nullable
@Override
public IBinder onBind(Intent intent)
{
return new Binder()
{
@Override
protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException
{
return super.onTransact(code, data, reply, flags);
}
};
}
}
然後在AndroidManifest中註冊這個Service。
<service android:name=".ManualCalculatorService"
android:exported="true"
android:process =":manualremote"/>
android:exported="true"表示這個Service對外是暴露的。
android:process=":manualremote"表示這個Service的執行程序的名稱
一個Service要作為遠端Service被其他Client呼叫,上面兩個缺一不可。
建立Client
Client呼叫bindService
即可和遠端Service建立聯絡。
Intent intent = new Intent();
intent.setComponent(new ComponentName("cn.zmy.ipcserver", "cn.zmy.ipcserver.ManualCalculatorService"));
bindService(intent, new ServiceConnection()
{
@Override
public void onServiceConnected(ComponentName name, IBinder service)
{
}
@Override
public void onServiceDisconnected(ComponentName name)
{
}
}, Context.BIND_AUTO_CREATE);
至此,兩個專案大體程式碼結構已經完成。
Client呼叫Server
Client可以通過onServiceConnected
中的IBinder
型別的service引數來呼叫遠端Service。
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInt(1);
data.writeInt(2);
try
{
service.transact(1000, data, reply, 0);
}
catch (RemoteException e)
{
e.printStackTrace();
}
int result = reply.readInt();
data.recycle();
reply.recycle();
Toast.makeText(MainActivity.this, "" + result, Toast.LENGTH_SHORT).show();
程式碼很簡單,最關鍵的是這一句:
service.transact(1000,
data, reply, 0);
第一個引數,1000。這是我隨便寫的個數字,你可以寫2000,3000都沒得問題。(實際專案中通常使用常量定義,這裡主要為了方便演示)
第二個引數,data。表示我想要傳遞給Server的資料。
第三個引數,reply。Server會把結果寫入這個引數。
第四個引數,0。這個引數只有兩個可選值:0和IBinder.FLAG_ONEWAY
。
0表示這是一個雙向的IPC呼叫,也就是Client向Server發起請求後,Server也會答覆Client。
IBinder.FLAG_ONEWA表示這是一個單向IPC呼叫,也就是Client向Server發起請求後,會直接返回,不接受Server的答覆。
Server處理Client請求
Client通過transact請求Server之後,Server可以在onTransact接收到Client的請求。
@Nullable
@Override
public IBinder onBind(Intent intent)
{
return new Binder()
{
@Override
protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException
{
switch (code)
{
case 1000:
{
int num1 = data.readInt();
int num2 = data.readInt();
reply.writeInt(num1 + num2);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
};
}
從data
中讀出資料,然後將結果寫入reply
中。整個過程就這樣。
執行
先後安裝Server和Client程式,Client中就可以看到結果。
Demo
專案程式碼:
原理分析
所謂原理分析就是追本溯源,接下來我們看一下Client的請求是如何一步步到達Server的。
## IBinder
回到Client呼叫Server的程式碼:
bindService(intent, new ServiceConnection(){
@Override
public void onServiceConnected(ComponentName name, IBinder service)
{
...
}
@Override
public void onServiceDisconnected(ComponentName name)
{
}
}, Context.BIND_AUTO_CREATE);
關鍵在於這個IBinder
,Client是通過IBinder.transact()將請求發給Server的。
這裡的IBinder
實際上是個BinderProxy
物件。(我怎麼知道的?打斷點,打日誌啊。。。)
BinderProxy處於{framework}/core/java/android/os/Binder.java中。
final class BinderProxy implements IBinder {
private long mObject;
public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
...
return transactNative(code, data, reply, flags);
}
public native boolean transactNative(int code, Parcel data, Parcel reply,
int flags) throws RemoteException;
...
}
Client呼叫BindProxy類的transact方法,實際邏輯還是交給transactNative方法處理的。
接下來找到transactNative的程式碼。
程式碼在{framework}/core/jni/android_util_Binder.cpp中
static const JNINativeMethod gBinderProxyMethods[] = {
...
{"transactNative", "(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z", (void*)android_os_BinderProxy_transact}
...
};
可以看的transactNative是動態註冊的。找到android_os_BinderProxy_transact方法,看看它的程式碼。
JNI方法註冊分為靜態註冊和動態註冊,感興趣的朋友可以自行搜尋瞭解。
static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
jint code, jobject dataObj, jobject replyObj, jint flags)
{
IBinder* target = (IBinder*)
env->GetLongField(obj, gBinderProxyOffsets.mObject);
status_t err = target->transact(code, *data, reply, flags);
if (err == NO_ERROR) {
return JNI_TRUE;
} else if (err == UNKNOWN_TRANSACTION) {
return JNI_FALSE;
}
}
可以看到,裡面又呼叫了target的transact方法,將請求傳送出去。
target是通過反射獲取BinderProxy類的mObject物件得到的。
final class BinderProxy implements IBinder {
private long mObject;
}
long是怎麼被強轉為IBinder的?
實際上這裡的long mObject儲存的是IBinder的指標。指標的大小和long的大小都是一樣的,都是4個位元組。
而名為target的這個IBinder實際上就是Server中onBind返回的這個Binder:
public class ManualCalculatorService extends Service
{
@Nullable
@Override
public IBinder onBind(Intent intent)
{
return new Binder()
{
...
};
}
}
到這裡,我們就差不多明白了。BinderProxy之所以叫BinderProxy,它代理的就是Server中onBind返回的Binder。
而Client經過一層層的呼叫,最終呼叫了Server中返回的Binder物件的transact方法。
我們看一下這個方法:
public final boolean transact(int code, Parcel data, Parcel reply,
int flags) throws RemoteException {
...
boolean r = onTransact(code, data, reply, flags);
...
return r;
}
這個方法實際上呼叫了onTransact方法進行具體的邏輯處理。這也是為什麼我們可以在onTransact中處理Client請求的原因。
結尾
關於target是怎麼來的?
target是通過反射獲取BinderProxy類的mObject物件得到的。
mObject儲存了server中IBinder的指標。
那麼這個指標又是哪裡來的?
這裡不得不提到另外一個類:ServiceManager
該類在{framework}/core/java/android/os/ServiceManager.java中
感興趣的朋友可以閱讀它的程式碼。
這裡簡單說一下:ServiceManager通過map儲存了Service和IBinder的關係。也就是通過Service的名稱就可以獲取到這個Service的IBinder。
相關推薦
Android Binder機制詳解:手寫IPC通訊
想要掌握一樣東西,最好的方式就是閱讀理解它的原始碼。想要掌握Android Binder,最好的方式就是寫一個AIDL檔案,然後檢視其生成的程式碼。本文的思路也是來自於此。 簡介 Binder是Android常用的一種程序間通訊方式。當然,不使用Binder,你還可以使用Socket甚至檔案來進行通訊。
Linux與android程序間的通訊及android Binder機制詳解
關於程序之間的通訊又很多種方式,不同的方式適用於不同的場景。 五種不同形式的IPC形式 1.訊息傳遞(管道,FIFO和訊息佇列) 2.同步(互斥量,條件變數,讀寫鎖,檔案和記錄鎖,訊號量) 3.共享記憶體(匿名的和具名的) 4.遠端過程呼叫(Solaris門和Sun R
Android快取機制詳解之硬碟快取DiskLruCache
簡介 防止多圖OOM的核心解決思路就是使用LruCache技術。但LruCache只是管理了記憶體中圖片的儲存與釋放,如果圖片從記憶體中被移除的話,那麼又需要從網路上重新載入一次圖片,這顯然非常耗時。對此,Google又提供了一套硬碟快取的解決方案:DiskLruCache(非Google官方編
Android-Handler機制詳解
Handler 1、handler是什麼? 答:handler 是更新UI介面的機制,也是訊息處理的機制,我們可以傳送訊息,也可以處理訊息 2、為什麼要有Handler? 答:Android在設計的時候,封裝了一套訊息建立,傳遞,處理機制,如果不遵循這樣的機制就沒法更新UI資訊,就會丟擲
【資料篇】Android混淆機制詳解學習資料
您將獲得以下內容: 通過 Gradle 編譯 Debug 和 Release 包的方式和介紹; 如何對程式碼進行混淆; Proguard 的特性介紹; Proguard 和 Dexguard 的區別;
Android 廣播機制詳解
一、廣播的簡介 首先,當我們一聽到廣播這個詞時。就可以想到小學是教室的廣播。不錯Android中的廣播機制與我們生活中的廣播是有異曲同工之妙的。Android中的傳送廣播也就像廣播室播廣播,可以讓很多註冊過廣播的地方收到這條廣播。接下來我們對其進行分析。 二、廣播的傳送 廣播的傳
Android Intent機制詳解
什麼是Intent Intent 是一個將要執行的動作的抽象描述,一般來說是作為引數來使用,由Intent來協助完成android各個元件之間的通訊。比如說呼叫startActivity()來啟動一個activity,或者由broadcaseIntent()來傳遞給
springmvc原理詳解(手寫springmvc)
最近在複習框架 在網上搜了寫資料 和原理 今天總結一下 希望能加深點映像 不足之處請大家指出 我就不畫流程圖了 直接通過程式碼來了解springmvc的執行機制和原理 回想用springmvc用到最多的是什麼?當然是controller和RequestMapping註解啦
關於AIDL使用和Binder機制詳解,你只需要看這一篇即可
本篇文章從AIDL的角度來闡述Binder機制呼叫遠端服務的內部執行原理。因此本篇文章的第一部分介紹AIDL的使用,第二部分從AIDL的使用上具體介紹Binder機制。關於Binder機制的原理,可以參考簡單理解Binder機制的原理,對其有個大概的瞭解。 一、AIDL
Android-Handler機制詳解並自定義Handler
之前研究過Android的Handler機制,但是一直沒有機會自己實現一次。最近又看到這個Handler機制,於是決定自己實現以下這個Handler機制。 首先,簡單介紹以下Handler機制。 Handler機制在Android中通常用來更新UI:子執行緒
我看樸靈評註阮一峰的《JavaScript 執行機制詳解:再談Event Loop》
阮一峰和樸靈對我來說都是大牛,他們倆的書我都買過,阮老師的譯作《軟體隨想錄》和樸靈的《深入淺出node.js》。這個事情已經過了4個月了,所以我拿來講應該也沒啥問題。 這件事情是這樣的,阮一峰在自己的部落格寫了篇文章《JavaScript 執行機制詳解:再談Event Lo
Binder機制詳解
class Proxy implements com.example.hezhe.myapplication.test.IBookManager { private android.os.IBinder mRemote; Proxy(android.os.IBinder remote) { mRemote =
js運行機制詳解:event loop
所有 主線程 web 當前 輸入 ask oop 用途 之前 總結 阮一峰老師的博客 一、為什麽JavaScript是單線程 JavaScript語言的一大特點就是單線程 那麽,為什麽JavaScript不能有多個線程呢?這樣能提高效率啊。 JavaScript的單
Android筆記02:Intent機制詳解
tar 中一 定義 tty 一段 AI new 例如 pac 一、什麽是Intent? Intent在Android中提供了Intent機制來協助應用間的交互與通訊,Intent負責對應用中一次操作的動作、動作涉及數據、附加數據進行描述,Android則根據此Intent的
詳解:Android巢狀滑動機制 (NestedScrolling)
從 Android 5.0 Lollipop 開始提供一套 API 來支援嵌入的滑動效果。同樣在最新的 Support V4 包中也提供了前向的相容。有了嵌入滑動機制,就能實現很多很複雜的滑動效果。在 Android Design Support 庫中非常總要
Java必知必會:異常機制詳解
賦值 輸出結果 類庫 負數 虛擬 類名 通過反射 基於 all 一、Java異常概述 在Java中,所有的事件都能由類描述,Java中的異常就是由java.lang包下的異常類描述的。 1、Throwable(可拋出):異常類的最終父類,它有兩個子類,Error與Exce
Android總結篇——Intent機制詳解及示例總結
ets mp3 pro domain 一般來說 ssa star wrap 無線 一.Intent介紹: Intent的中文意思是“意圖,意向”,在Android中提供了Intent機制來協助應用間的交互與通訊,Intent負責對應用中一次操作的動 作、動作涉及
Android RxJava操作符詳解系列: 變換操作符
urn 原因 轉換 需要 生產 依賴 reat 入門 所有 Rxjava,由於其基於事件流的鏈式調用、邏輯簡潔 & 使用簡單的特點,深受各大 Android開發者的歡迎。Github截圖 如果還不了解 RxJava,請看文章:Android:這是一篇 清晰 &
Android開發——事件分發機制詳解---微信魚蝦蟹源碼搭建
lai reset 微信 影響 ren 事件分發機制 lis forum hlist 轉載請註明出處:http://h5.hxforum.com深入學習事件分發機制,是為了解決在Android開發中遇到的滑動沖突問題做準備。事件分發機制描述了用戶的手勢一系列事件是如何被An
Android的so檔案載入機制詳解
今日科技快訊 10月30日,小米集團跌超4%,再創上市以來新低,市值下破2600億港元關口。此前,財政部發布的《2018年會計資訊質量檢查公告》顯示,在2017年度會計執法檢查中發現,部分企業跨境轉移利潤、逃避繳納稅收等問題比較突出。在被點名的網際網路企業中,就包括