android共享內存
① android 為什麼不能用shmget
其實Anroid kernel本身在核心態是支持System V的功能,但是bionic這一層進行了處理,例如共享內存這塊bionic就把glibc的shmget等函數給剝除了,而採用android匿名共享內存方式。今天研究了一下bionic,發現這里其實還是保留了glibc的很多東西,只是把用戶態到內核函數的調用通路給斷開了。
② 為什麼Android要採用Binder作為IPC機制
1)從性能的角度
數據拷貝次數:Binder數據拷貝只需要一次,而管道、消息隊列、Socket都需要2次,但共享內存方式一次內存拷貝都不需要;從性能角度看,Binder性能僅次於共享內存。
(2)從穩定性的角度
Binder是基於C/S架構的,簡單解釋下C/S架構,是指客戶端(Client)和服務端(Server)組成的架構,Client端有什麼需求,直接發送給Server端去完成,架構清晰明朗,Server端與Client端相對獨立,穩定性較好;而共享內存實現方式復雜,沒有客戶與服務端之別, 需要充分考慮到訪問臨界資源的並發同步問題,否則可能會出現死鎖等問題;從這穩定性角度看,Binder架構優越於共享內存。
僅僅從以上兩點,各有優劣,還不足以支撐google去採用binder的IPC機制,那麼更重要的原因是:
(3)從安全的角度
傳統linux IPC的接收方無法獲得對方進程可靠的UID/PID,從而無法鑒別對方身份;而Android作為一個開放的開源體系,擁有非常多的開發平台,App來源甚廣,因此手機的安全顯得額外重要;對於普通用戶,絕不希望從App商店下載偷窺隱射數據、後台造成手機耗電等等問題,傳統Linux IPC無任何保護措施,完全由上層協議來確保。
Android為每個安裝好的應用程序分配了自己的UID,故進程的UID是鑒別進程身份的重要標志,前面提到C/S架構,Android系統中對外只暴露Client端,Client端將任務發送給Server端,Server端會根據許可權控制策略,判斷UID/PID是否滿足訪問許可權,目前許可權控制很多時候是通過彈出許可權詢問對話框,讓用戶選擇是否運行。Android 6.0,也稱為Android M,在6.0之前的系統是在App第一次安裝時,會將整個App所涉及的所有許可權一次詢問,只要留意看會發現很多App根本用不上通信錄和簡訊,但在這一次性許可權許可權時會包含進去,讓用戶拒絕不得,因為拒絕後App無法正常使用,而一旦授權後,應用便可以胡作非為。
針對這個問題,google在Android M做了調整,不再是安裝時一並詢問所有許可權,而是在App運行過程中,需要哪個許可權再彈框詢問用戶是否給相應的許可權,對許可權做了更細地控制,讓用戶有了更多的可控性,但同時也帶來了另一個用戶詬病的地方,那也就是許可權詢問的彈框的次數大幅度增多。對於Android M平台上,有些App開發者可能會寫出讓手機異常頻繁彈框的App,企圖直到用戶授權為止,這對用戶來說是不能忍的,用戶最後吐槽的可不光是App,還有Android系統以及手機廠商,有些用戶可能就跳果粉了,這還需要廣大Android開發者以及手機廠商共同努力,共同打造安全與體驗俱佳的Android手機。
③ 為什麼 Android 要採用 Binder 作為 IPC 機制
Android是基於linux內核的。所以linux支持的IPC,android都用到了。比如命名管道,共享內存。 除此外,android還使用了一套自己獨特的IPC方式 binder. 主要用於2個進程間的遠程調用。但是這里就牽扯遠程調用如何傳遞參數,如何回傳結果。 這需要調用者對數據進行打包和解包,是一個繁瑣的過程。為此,android引入了aidl(android interface description launguage). 開發人員定義好aidl,android會根據aidl的描述生產stub代碼,幫助調用者對數據打包,解包。開發人員所要做的事是繼承stub代碼,實現stub代碼中的函數。這些函數是你在aidl中定義的。
④ android為什麼不直接使用linux的共享內存機制來完成進程間的通訊,而是使用AIDL來公開服務介面
Android貌似共享用的底層是Binder驅動,這個驅動可以避免很多Linux下會出現共享內存的問題,具體我也沒分析過嘿嘿
⑤ Android中mmap原理及應用簡析
mmap是Linux中常用的系統調用API,用途廣泛,Android中也有不少地方用到,比如匿名共享內存,Binder機制等。本文簡單記錄下Android中mmap調用流程及原理。mmap函數原型如下:
幾個重要參數
返回值是void *類型,分配成功後,被映射成虛擬內存地址。
mmap屬於系統調用,用戶控制項間接通過swi指令觸發軟中斷,進入內核態(各種環境的切換),進入內核態之後,便可以調用內核函數進行處理。 mmap->mmap64->__mmap2->sys_mmap2-> sys_mmap_pgoff ->do_mmap_pgoff
而 __NR_mmap在系統函數調用表中對應的減值如下:
通過系統調用,執行swi軟中斷,進入內核態,最終映射到call.S中的內核函數:sys_mmap2
sys_mmap2最終通過sys_mmap_pgoff在內核態完成後續邏輯。
sys_mmap_pgoff通過宏定義實現
進而調用do_mmap_pgoff:
get_unmapped_area用於為用戶空間找一塊內存區域,
current->mm->get_unmapped_area一般被賦值為arch_get_unmapped_area_topdown,
先找到合適的虛擬內存(用戶空間),幾經周轉後,調用相應文件或者設備驅動中的mmap函數,完成該設備文件的mmap,至於如何處理處理虛擬空間,要看每個文件的自己的操作了。
這里有個很關鍵的結構體
它是文件驅動操作的入口,在open的時候,完成file_operations的綁定,open流程跟mmap類似
先通過get_unused_fd_flags獲取個未使用的fd,再通過do_file_open完成file結構體的創建及初始化,最後通過fd_install完成fd與file的綁定。
重點看下path_openat:
拿Binder設備文件為例子,在注冊該設備驅動的時候,對應的file_operations已經注冊好了,
open的時候,只需要根根inode節點,獲取到file_operations既可,並且,在open成功後,要回調file_operations中的open函數
open後,就可以利用fd找到file,之後利用file中的file_operations *f_op調用相應驅動函數,接著看mmap。
Binder機制中mmap的最大特點是一次拷貝即可完成進程間通信 。Android應用在進程啟動之初會創建一個單例的ProcessState對象,其構造函數執行時會同時完成binder mmap,為進程分配一塊內存,專門用於Binder通信,如下。
第一個參數是分配地址,為0意味著讓系統自動分配,流程跟之前分子類似,先在用戶空間找到一塊合適的虛擬內存,之後,在內核空間也找到一塊合適的虛擬內存,修改兩個控制項的頁表,使得兩者映射到同一塊物力內存。
Linux的內存分用戶空間跟內核空間,同時頁表有也分兩類,用戶空間頁表跟內核空間頁表,每個進程有一個用戶空間頁表,但是系統只有一個內核空間頁表。而Binder mmap的關鍵是:也更新用戶空間對應的頁表的同時也同步映射內核頁表,讓兩個頁表都指向同一塊地址,這樣一來,數據只需要從A進程的用戶空間,直接拷貝拷貝到B所對應的內核空間,而B多對應的內核空間在B進程的用戶空間也有相應的映射,這樣就無需從內核拷貝到用戶空間了。
binder_update_page_range完成了內存分配、頁表修改等關鍵操作:
可以看到,binder一次拷貝的關鍵是,完成內存的時候,同時完成了內核空間跟用戶空間的映射,也就是說,同一份物理內存,既可以在用戶空間,用虛擬地址訪問,也可以在內核空間用虛擬地址訪問。
普通文件的訪問方式有兩種:第一種是通過read/write系統調訪問,先在用戶空間分配一段buffer,然後,進入內核,將內容從磁碟讀取到內核緩沖,最後,拷貝到用戶進程空間,至少牽扯到兩次數據拷貝;同時,多個進程同時訪問一個文件,每個進程都有一個副本,存在資源浪費的問題。
另一種是通過mmap來訪問文件,mmap()將文件直接映射到用戶空間,文件在mmap的時候,內存並未真正分配,只有在第一次讀取/寫入的時候才會觸發,這個時候,會引發缺頁中斷,在處理缺頁中斷的時候,完成內存也分配,同時也完成文件數據的拷貝。並且,修改用戶空間對應的頁表,完成到物理內存到用戶空間的映射,這種方式只存在一次數據拷貝,效率更高。同時多進程間通過mmap共享文件數據的時候,僅需要一塊物理內存就夠了。
共享內存是在普通文件mmap的基礎上實現的,其實就是基於tmpfs文件系統的普通mmap,有機會再分析,不再啰嗦。
Android中mmap原理及應用簡析
僅供參考,歡迎指正
⑥ android 為什麼用aidl
AIDL:Android Interface Definition Language,即Android介面定義語言。
Android系統中的進程之間不能共享內存,因此,需要提供一些機制在不同進程之間進行數據通信。
為了使其他的應用程序也可以訪問本應用程序提供的服務,Android系統採用了遠程過程調用(Remote
Procere Call,RPC)方式來實現。與很多其他的基於RPC的解決方案一樣,Android使用一種介面定義語言(Interface
Definition
Language,IDL)來公開服務的介面。我們知道4個Android應用程序組件中的3個(Activity、BroadcastReceiver
和ContentProvider)都可以進行跨進程訪問,另外一個Android應用程序組件Service同樣可以。因此,可以將這種可以跨進程訪問
的服務稱為AIDL(Android Interface Definition Language)服務。
⑦ android Binder具體是干什麼用的
Binder主要能提供以下一些功能:
用驅動程序來推進進程間的通信。
通過共享內存來提高性能。
為進程請求分配每個進程的線程池。
針對系統中的對象引入了引用計數和跨進程的對象引用映射。
進程間同步調用。
Android Binder設計與實現 – 設計篇:
目前linux支持的IPC包括傳統的管道、System V IPC、即消息隊列/共享內存/信號量,以及socket中只有socket支持Client-Server的通信方式。
當然也可以在這些底層機制上架設一套協議來實現Client-Server通信,但這樣增加了系統的復雜性,在手機這種條件復雜,資源稀缺的環境下可靠性也難以保證。
另一方面是傳輸性能:
socket作為一款通用介面,其傳輸效率低,開銷大,主要用在跨網路的進程間通信和本機上進程間的低速通信。
消息隊列和管道採用存儲-轉發方式,即數據先從發送方緩存區拷貝到內核開辟的緩存區中,然後再從內核緩存區拷貝到接收方緩存區,
至少有兩次拷貝過程。共享內存雖然無需拷貝,但控制復雜,難以使用。
還有一點是出於安全性考慮:
Android作為一個開放式,擁有眾多開發者的平台,應用程序的來源廣泛,確保智能終端的安全是非常重要的。
終端用戶不希望從網上下載的程序在不知情的情況下偷窺隱私數據,連接無線網路,長期操作底層設備導致電池很快耗盡等等。傳統IPC沒有任何
安全措施,完全依賴上層協議來確保。首先傳統IPC的接收方無法獲得對方進程可靠的UID/PID(用戶ID/進程ID),從而無法鑒別對方身份。
Android為每個安裝好的應用程序分配了自己的UID,故進程的UID是鑒別進程身份的重要標志。使用傳統IPC只能由用戶在數據包里填入UID/PID,
但這樣不可靠,容易被惡意程序利用。可靠的身份標記只有由IPC機制本身在內核中添加。其次傳統IPC訪問接入點是開放的,無法建立私有通道。
比如命名管道的名稱、system V的鍵值、socket的ip地址或文件名都是開放的,只要知道這些接入點的程序都可以和對端建立連接,不管怎樣都無法
阻止惡意程序通過猜測接收方地址獲得連接。
基於以上原因,Android需要建立一套新的IPC機制來滿足系統對通信方式,傳輸性能和安全性的要求,這就是Binder。
Binder基於 Client-Server通信模式,傳輸過程只需一次拷貝,為發送發添加UID/PID身份,既支持實名Binder也支持匿名Binder,安全性高。
面向對象的 Binder IPC:
面向對象思想的引入將進程間通信轉化為通過對某個Binder對象的引用調用該對象的方法,而其獨特之處在於Binder對象是一個
可以跨進程引用的對象,它的實體位於一個進程中,而它的引用卻遍布於系統的各個進程之中。最誘人的是,這個引用和java里引用
一樣既可以是強類型,也可以是弱類型,而且可以從一個進程傳給其它進程,讓大家都能訪問同一Server,就像將一個對象或引用賦
值給另一個引用一樣。Binder模糊了進程邊界,淡化了進程間通信過程,整個系統彷彿運行於同一個面向對象的程序之中。
面向對象只是針對應用程序而言,對於Binder驅動和內核其它模塊一樣使用C語言實現,沒有類和對象的概念。
Binder驅動為面向對象的進程間通信提供底層支持。
⑧ 篇文章會先對照binder機制與linux的通信機制的區別,了解為什麼android會另起爐灶
1)從性能的角度
數據拷貝次數:Binder數據拷貝只需要一次,而管道、消息隊列、Socket都需要2次,但共享內存方式一次內存拷貝都不需要;從性能角度看,Binder性能僅次於共享內存。
(2)從穩定性的角度
Binder是基於C/S架構的,簡單解釋下C/S架構,是指客戶端(Client)和服務端(Server)組成的架構,Client端有什麼需求,直接發送給Server端去完成,架構清晰明朗,Server端與Client端相對獨立,穩定性較好;而共享內存實現方式復雜,沒有客戶與服務端之別, 需要充分考慮到訪問臨界資源的並發同步問題,否則可能會出現死鎖等問題;從這穩定性角度看,Binder架構優越於共享內存。
僅僅從以上兩點,各有優劣,還不足以支撐google去採用binder的IPC機制,那麼更重要的原因是:
(3)從安全的角度
傳統Linux IPC的接收方無法獲得對方進程可靠的UID/PID,從而無法鑒別對方身份;而Android作為一個開放的開源體系,擁有非常多的開發平台,App來源甚廣,因此手機的安全顯得額外重要;對於普通用戶,絕不希望從App商店下載偷窺隱射數據、後台造成手機耗電等等問題,傳統Linux IPC無任何保護措施,完全由上層協議來確保。
Android為每個安裝好的應用程序分配了自己的UID,故進程的UID是鑒別進程身份的重要標志,前面提到C/S架構,Android系統中對外只暴露Client端,Client端將任務發送給Server端,Server端會根據許可權控制策略,判斷UID/PID是否滿足訪問許可權,目前許可權控制很多時候是通過彈出許可權詢問對話框,讓用戶選擇是否運行。Android 6.0,也稱為Android M,在6.0之前的系統是在App第一次安裝時,會將整個App所涉及的所有許可權一次詢問,只要留意看會發現很多App根本用不上通信錄和簡訊,但在這一次性許可權許可權時會包含進去,讓用戶拒絕不得,因為拒絕後App無法正常使用,而一旦授權後,應用便可以胡作非為。
針對這個問題,google在Android M做了調整,不再是安裝時一並詢問所有許可權,而是在App運行過程中,需要哪個許可權再彈框詢問用戶是否給相應的許可權,對許可權做了更細地控制,讓用戶有了更多的可控性,但同時也帶來了另一個用戶詬病的地方,那也就是許可權詢問的彈框的次數大幅度增多。對於Android M平台上,有些App開發者可能會寫出讓手機異常頻繁彈框的App,企圖直到用戶授權為止,這對用戶來說是不能忍的,用戶最後吐槽的可不光是App,還有Android系統以及手機廠商,有些用戶可能就跳果粉了,這還需要廣大Android開發者以及手機廠商共同努力,共同打造安全與體驗俱佳的Android手機。
Android中許可權控制策略有SELinux等多方面手段,下面列舉從Binder的一個角度的許可權控制:
Android源碼的Binder許可權是如何控制? -Gityuan的回答
傳統IPC只能由用戶在數據包里填入UID/PID;另外,可靠的身份標記只有由IPC機制本身在內核中添加。其次傳統IPC訪問接入點是開放的,無法建立私有通道。從安全形度,Binder的安全性更高。
說到這,可能有人要反駁,Android就算用了Binder架構,而現如今Android手機的各種流氓軟體,不就是干著這種偷窺隱射,後台偷偷跑流量的事嗎?沒錯,確實存在,但這不能說Binder的安全性不好,因為Android系統仍然是掌握主控權,可以控制這類App的流氓行為,只是對於該採用何種策略來控制,在這方面android的確存在很多有待進步的空間,這也是google以及各大手機廠商一直努力改善的地方之一。在Android 6.0,google對於app的許可權問題作為較多的努力,大大收緊的應用許可權;另外,在Google舉辦的Android Bootcamp 2016大會中,google也表示在Android 7.0 (也叫Android N)的許可權隱私方面會進一步加強加固,比如SELinux,Memory safe language(還在research中)等等,在今年的5月18日至5月20日,google將推出Android N。
(4)從語言層面的角度
大家多知道Linux是基於C語言(面向過程的語言),而Android是基於Java語言(面向對象的語句),而對於Binder恰恰也符合面向對象的思想,將進程間通信轉化為通過對某個Binder對象的引用調用該對象的方法,而其獨特之處在於Binder對象是一個可以跨進程引用的對象,它的實體位於一個進程中,而它的引用卻遍布於系統的各個進程之中。可以從一個進程傳給其它進程,讓大家都能訪問同一Server,就像將一個對象或引用賦值給另一個引用一樣。Binder模糊了進程邊界,淡化了進程間通信過程,整個系統彷彿運行於同一個面向對象的程序之中。從語言層面,Binder更適合基於面向對象語言的Android系統,對於Linux系統可能會有點「水土不服」。
另外,Binder是為Android這類系統而生,而並非Linux社區沒有想到Binder IPC機制的存在,對於Linux社區的廣大開發人員,我還是表示深深佩服,讓世界有了如此精湛而美妙的開源系統。也並非Linux現有的IPC機制不夠好,相反地,經過這么多優秀工程師的不斷打磨,依然非常優秀,每種Linux的IPC機制都有存在的價值,同時在Android系統中也依然採用了大量Linux現有的IPC機制,根據每類IPC的原理特性,因時制宜,不同場景特性往往會採用其下最適宜的。比如在Android OS中的Zygote進程的IPC採用的是Socket(套接字)機制,Android中的Kill Process採用的signal(信號)機制等等。而Binder更多則用在system_server進程與上層App層的IPC交互。
(5) 從公司戰略的角度
總所周知,Linux內核是開源的系統,所開放源代碼許可協議GPL保護,該協議具有「病毒式感染」的能力,怎麼理解這句話呢?受GPL保護的Linux Kernel是運行在內核空間,對於上層的任何類庫、服務、應用等運行在用戶空間,一旦進行SysCall(系統調用),調用到底層Kernel,那麼也必須遵循GPL協議。
而Android 之父 Andy Rubin對於GPL顯然是不能接受的,為此,Google巧妙地將GPL協議控制在內核空間,將用戶空間的協議採用Apache-2.0協議(允許基於Android的開發商不向社區反饋源碼),同時在GPL協議與Apache-2.0之間的Lib庫中採用BSD證授權方法,有效隔斷了GPL的傳染性,仍有較大爭議,但至少目前緩解Android,讓GPL止步於內核空間,這是Google在GPL Linux下 開源與商業化共存的一個成功典範。
⑨ android 進程間的通信(IPC)方式有哪些
Android為了屏蔽進程的概念,利用不同的組件[Activity、Service]來表示進程之間的通信!組件間通信的核心機制是Intent,通過Intent可以開啟一個Activity或Service,不論這個Activity或Service是屬於當前應用還是其它應用的。
一、Intent包含兩部分:
1、目的[action]--要往哪裡去
2、內容[category、data]--路上帶了些什麼,區分性數據或內容性數據
二、Intent類型:
1、顯式--直接指定消息目的地,只適合同一進程內的不同組件之間通信
new Intent(this,Target.class)
2、隱式--AndroidMainifest.xml中注冊,一般用於跨進程通信
new Intent(String action)
IPC機制:有了Intent這種基於消息的進程內或進程間通信模型,我們就可以通過Intent去開啟一個Service,可以通過Intent跳轉到另一個Activity,不論上面的Service或Activity是在當前進程還是其它進程內即不論是當前應用還是其它應用的Service或Activity,通過消息機制都可以進行通信!