Binder原理

Binder是Android底層實現(xiàn)進程通訊的一種方式怀挠,由于它的調(diào)用過程比較復(fù)雜埃唯。本篇暫不涉及源碼撩匕,只是做一個原理上的講解,而具體的源碼調(diào)用墨叛,會在后面用一個系列的篇章來分析止毕。

Binder這種進程通訊是Android系統(tǒng)特有的,也就是說漠趁,進程間的通訊其實還有許多實現(xiàn)方式扁凛,通常稱為傳統(tǒng)的進程通訊方式。

傳統(tǒng)IPC方式:

  • 管道(Pipe) :操作簡單闯传,但只能在父子進程間通訊谨朝,并且只能單向通訊。
  • FiFO:解決了Pipe需要父子進程的問題甥绿,但長期存在于系統(tǒng)之中字币,使用不當容易出錯。
  • 信號量(Signal):不適用數(shù)據(jù)量大的傳輸共缕。
  • 消息隊列(Message):信息的復(fù)制需要消耗CPU的時間.不適用信息量大或操作頻繁的情形洗出。
  • Socket:傳輸效率低,開銷大图谷,主要用在網(wǎng)絡(luò)通訊翩活。
  • 共享內(nèi)存(Share Memory):共享內(nèi)存無須拷貝阱洪,可操作大數(shù)據(jù)量,但實現(xiàn)復(fù)雜菠镇。

傳統(tǒng)IPC原理:

對于 32 位系統(tǒng)冗荸,它的尋址空間(虛擬存儲空間)就是 2 的 32 次方,即 4GB利耍。分內(nèi)核空間和用戶空間:

  • 內(nèi)核空間:最高的 1GB 字節(jié)供內(nèi)核使用蚌本,權(quán)限為0級;
  • 用戶空間:低的 3GB 字節(jié)供各進程使用堂竟,權(quán)限為3級魂毁。

用戶空間是每個進程私有的,其他進程不能夠訪問出嘹。而用戶空間訪問內(nèi)核資源的資源席楚,無法直接訪問,需要借助系統(tǒng)調(diào)用來實現(xiàn)税稼。系統(tǒng)調(diào)用指的是烦秩,根據(jù)系統(tǒng)對外暴露的api接口,來訪問系統(tǒng)資源郎仆,換句話說只祠,系統(tǒng)封裝了一層實現(xiàn),如果用戶空間要訪問內(nèi)核資源扰肌,需要交給這一層實現(xiàn)抛寝,來幫我們訪問。

系統(tǒng)調(diào)用主要通過如下兩個函數(shù)來實現(xiàn):

//將數(shù)據(jù)從用戶空間拷貝到內(nèi)核空間
copy_from_user() 

//將數(shù)據(jù)從內(nèi)核空間拷貝到用戶空間
copy_to_user() 

消息發(fā)送方曙旭,將要發(fā)送的數(shù)據(jù)存放在用戶空間的內(nèi)存緩存區(qū)中盗舰,接著通過系統(tǒng)調(diào)用進入內(nèi)核態(tài),內(nèi)核程序在內(nèi)核空間分配內(nèi)存桂躏,開辟一塊內(nèi)核緩存區(qū)钻趋。然后調(diào)用 copy_from_user() 函數(shù),將數(shù)據(jù)從用戶空間的內(nèi)存緩存區(qū)剂习,拷貝到內(nèi)核空間的內(nèi)核緩存區(qū)中蛮位。同樣的,接收方進程在接收數(shù)據(jù)時鳞绕,在用戶空間開辟一塊內(nèi)存緩存區(qū)失仁,接著內(nèi)核程序調(diào)用 copy_to_user() 函數(shù),將數(shù)據(jù)從內(nèi)核緩存區(qū)拷貝到接收進程的用戶空間內(nèi)存緩存區(qū)们何。

可以看到萄焦,整個發(fā)送和接收的通訊過程,內(nèi)核需要做2次數(shù)據(jù)的拷貝垂蜗。這里的2次楷扬,指的是從用戶空間切換到內(nèi)核空間,和從內(nèi)核空間用戶空間贴见,每做一次切換烘苹,系統(tǒng)都需要比較大的開銷,因此片部,應(yīng)盡量減少切換的次數(shù)镣衡,這是第一個問題。

第二個問題是档悠,接收數(shù)據(jù)的緩存區(qū)由數(shù)據(jù)接收進程提供廊鸥,但是接收進程并不知道需要多大的空間,來存放將要傳遞過來的數(shù)據(jù)辖所,因此只能開辟盡可能大的內(nèi)存空間或者先調(diào)用 API 接收消息頭惰说,來獲取消息體的大小,這兩種做法不是浪費空間就是浪費時間缘回。

Binder原理

傳統(tǒng)的方式在用戶和內(nèi)核態(tài)間切換吆视,至少要拷貝2次數(shù)據(jù),共享內(nèi)存雖無需拷貝酥宴,但實現(xiàn)復(fù)雜啦吧。而Binder只要拷貝1次,性能僅次于共享內(nèi)存拙寡。

傳統(tǒng)的方式接收方無法獲得對方可靠的進程用戶ID/進程ID(UID/PID)授滓,從而無法鑒別對方身份。而android系統(tǒng)為每個安裝好的 APP 分配了自己的 UID肆糕,故而進程的 UID 是鑒別進程身份的可靠標志般堆。而且 Binder 既支持實名 Binder,又支持匿名 Binder擎宝,安全性高郁妈。

傳統(tǒng)的 IPC 方式如Pipe、Socket 都是內(nèi)核的一部分绍申,通過內(nèi)核支持來實現(xiàn)進程間通信噩咪,自然沒問題。但是 Binder 并不是 Linux 系統(tǒng)內(nèi)核的一部分极阅,因此胃碾,需要借助 Linux 的動態(tài)內(nèi)核可加載模塊(Loadable Kernel Module,LKM)的機制筋搏,動態(tài)添加一個內(nèi)核模塊運行在內(nèi)核空間中仆百,這個內(nèi)核模塊就是Binder 驅(qū)動(Binder Dirver)

內(nèi)存映射

Binder Dirver是通過內(nèi)存映射奔脐,來進行進程通訊的俄周。系統(tǒng)對外提供了一個函數(shù)mmap()吁讨,來做內(nèi)存映射。它的原理是峦朗,將用戶空間的一塊內(nèi)存區(qū)域映射到內(nèi)核空間建丧。用戶對這塊內(nèi)存區(qū)域的修改,就可以直接反應(yīng)到內(nèi)核空間波势;同樣的翎朱,內(nèi)核空間對這塊內(nèi)存的修改,也能直接反應(yīng)到用戶空間尺铣。

但mmap通常用在有物理介質(zhì)的文件系統(tǒng)上拴曲。因為,進程中的用戶空間是不能直接訪問物理設(shè)備的凛忿,所以澈灼,通常情況下,我們對磁盤上一個文件進行I/O讀寫侄非,是系統(tǒng)先把磁盤的數(shù)據(jù)拷貝到內(nèi)核空間蕉汪,再從內(nèi)核空間把數(shù)據(jù)拷貝到用戶區(qū)域。這種情況下逞怨,就可以通過mmap來做映射者疤,用內(nèi)存讀寫取代I/O讀寫,剩去了數(shù)據(jù)拷貝叠赦,提高效率驹马。

int main(void){
   //打開磁盤上的文件
   int fd =  open("test",O_RDWR|O_TRUNC|O_CREAT,0664);
   //拓展10字節(jié)
   ftruncate(fd,10);
   //獲取文件長度
   int len = lseek(fd,0,SEEK_END);
   //映射地址
   char *memp;
   //內(nèi)存映射
   memp = mmap(NULL,len,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
    //映射失敗
    if(memp==MAP_FAILED){
         perror("mmap error");
         exit(1);
     }

    //關(guān)閉文件
    close(fd);
    //將數(shù)據(jù)寫入內(nèi)存
    strcpy(memp,"hello world\n");
    
    //關(guān)閉內(nèi)存映射
    int ret = munmap(memp,len);  
    if(ret==-1){
       perror("mmap error");
       exit(1);
    }

   return 0;
 }

打開test文件:

hello world

如上代碼,我們將一個文件映射到內(nèi)存中除秀,然后往內(nèi)存中寫入一串數(shù)據(jù)糯累,數(shù)據(jù)將會同步寫入文件中。

上面的示例雖然使用了物理介質(zhì)(磁盤文件)來做映射册踩,但用mmap做內(nèi)存映射泳姐,物理介質(zhì)并不是必須的。也就是說暂吉,我們可以在內(nèi)核中創(chuàng)建一塊內(nèi)存空間胖秒,并將這塊內(nèi)存映射到接收進程的用戶空間(等同于磁盤文件),當我們往這塊內(nèi)存中寫數(shù)據(jù)時慕的,也就同步傳遞到接收進程的用戶空間中阎肝。大致的創(chuàng)建流程分三步:

image.png
  • Binder 驅(qū)動先在內(nèi)核空間創(chuàng)建一個數(shù)據(jù)接收緩存區(qū)
  • 接著在內(nèi)核空間開辟一塊內(nèi)核緩存區(qū)肮街,將接收緩存區(qū)接收進程用戶空間地址進行映射风题;
  • 發(fā)送方進程通過系統(tǒng)調(diào)用 copy_from_user() 將數(shù)據(jù)拷貝到內(nèi)核中的內(nèi)核緩存區(qū),內(nèi)核緩存區(qū)會將數(shù)據(jù)寫到接收緩存區(qū)中,由于接收緩存區(qū)映射到了接收進程用戶空間地址沛硅,因此接收進程就同步收到了數(shù)據(jù)眼刃,整個過程只經(jīng)歷用戶到內(nèi)核的1次拷貝。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末摇肌,一起剝皮案震驚了整個濱河市鸟整,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌朦蕴,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,914評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件弟头,死亡現(xiàn)場離奇詭異吩抓,居然都是意外死亡,警方通過查閱死者的電腦和手機赴恨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評論 2 383
  • 文/潘曉璐 我一進店門疹娶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人伦连,你說我怎么就攤上這事雨饺。” “怎么了惑淳?”我有些...
    開封第一講書人閱讀 156,531評論 0 345
  • 文/不壞的土叔 我叫張陵额港,是天一觀的道長。 經(jīng)常有香客問我歧焦,道長移斩,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,309評論 1 282
  • 正文 為了忘掉前任绢馍,我火速辦了婚禮向瓷,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘舰涌。我一直安慰自己猖任,他們只是感情好,可當我...
    茶點故事閱讀 65,381評論 5 384
  • 文/花漫 我一把揭開白布瓷耙。 她就那樣靜靜地躺著朱躺,像睡著了一般。 火紅的嫁衣襯著肌膚如雪哺徊。 梳的紋絲不亂的頭發(fā)上室琢,一...
    開封第一講書人閱讀 49,730評論 1 289
  • 那天,我揣著相機與錄音落追,去河邊找鬼盈滴。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的巢钓。 我是一名探鬼主播病苗,決...
    沈念sama閱讀 38,882評論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼症汹!你這毒婦竟也來了硫朦?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,643評論 0 266
  • 序言:老撾萬榮一對情侶失蹤背镇,失蹤者是張志新(化名)和其女友劉穎咬展,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體瞒斩,經(jīng)...
    沈念sama閱讀 44,095評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡破婆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,448評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了胸囱。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片祷舀。...
    茶點故事閱讀 38,566評論 1 339
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖烹笔,靈堂內(nèi)的尸體忽然破棺而出裳扯,到底是詐尸還是另有隱情,我是刑警寧澤谤职,帶...
    沈念sama閱讀 34,253評論 4 328
  • 正文 年R本政府宣布饰豺,位于F島的核電站,受9級特大地震影響允蜈,放射性物質(zhì)發(fā)生泄漏哟忍。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,829評論 3 312
  • 文/蒙蒙 一陷寝、第九天 我趴在偏房一處隱蔽的房頂上張望锅很。 院中可真熱鬧,春花似錦凤跑、人聲如沸爆安。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽扔仓。三九已至,卻和暖如春咖耘,著一層夾襖步出監(jiān)牢的瞬間翘簇,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評論 1 264
  • 我被黑心中介騙來泰國打工儿倒, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留版保,地道東北人呜笑。 一個月前我還...
    沈念sama閱讀 46,248評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像彻犁,于是被迫代替她去往敵國和親叫胁。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,440評論 2 348

推薦閱讀更多精彩內(nèi)容