1. 程式人生 > >Android安全/開發基礎--6--程序間通訊機制(IPC)

Android安全/開發基礎--6--程序間通訊機制(IPC)

6-1、多程序

1、多程序分為兩種:

第一種情況是一個應用因為某些原因自身需要採用多執行緒模式來實現。 另一種情況是當前應用需要向其他應用獲取資料。

2、Android中的多程序模式:

通過給四大元件指定android:process屬性,可以開啟多程序模式,使其執行在一個獨立的程序中。屬性詳細如下:

程序名以”:”開頭的程序屬於當前應用的私有程序,”:”左邊是包名,其他應用的元件不能和它跑在同一程序,而程序名不以”:”開頭的程序屬於全域性程序,其他應用通過ShareUID方式能和它跑在同一個程序中。Android系統會為每個應用分配一個唯一的UID,具有相同UID的應用才能共享資料。

多程序所帶來的主要影響:所有執行在不同程序中的四大元件,只要它們之間需要通過記憶體來共享資料,都會共享失敗。

6-2、IPC基礎概念

IPC是Inter-Process Communication的縮寫。含義為程序間通訊或跨程序通訊,是指兩個程序之間進行資料交換的過程。

Serializable介面:是Java所提供的一個序列化介面,它是一個空介面,為物件提供標準的序列化和反序列化操作。實現起來簡單但開銷很大。

Parcelable介面:是Android所提供的一個序列化介面,只要實現這個介面,一個類的物件就可以實現序列化並可以通過Intent的Binder傳遞。實現起來麻煩但效率很高。

Binder:從IPC角度來說,Binder是一種跨程序通訊方式。從Android Framework角度來說,Binder是ServiceManager連線各種Manager和相應ManagerService的橋樑。從Android應用層來說,Binder是客戶端和服務端進行通訊的媒介。

在這裡插入圖片描述

6-3、Android中的IPC方式

跨程序通訊方式:Intent、共享檔案、Binder、ContentProvider、Socket

1、使用Bundle。Bundle實現了Parcelable介面,Activity、Service和Receiver都支援在Intent中傳遞Bundle資料。

2、使用檔案共享。兩個程序通過讀/寫同一個檔案來交換資料,比如A把資料寫入檔案,B通過讀取該檔案來獲取資料。還可以序列化一個物件到檔案系統中的同時從另一個程序中恢復這個物件。

3、使用Messenger。通過它可以在不同程序中傳遞Message物件,在Message中放入我們要傳遞的資料即可實現資料的程序間傳遞。它是以序列的方式處理客戶端發來的訊息。

4、使用AIDL。AIDL是Messenger是的底層實現,因此Messenger本質上也是AIDL。大致流程:首先建一個Service和一個AIDL介面,接著建立一個類繼承自AIDL介面中的Stub類並實現Stub中的抽象方法,在Service的onBind方法中返回這個類的物件,然後客戶端就可以繫結服務端Service,建立連線後就可以訪問遠端服務端的方法了。AIDL是一種最常見的程序間通訊方式。

5、使用ContentProvider。主要以表格的形式來組織資料,並且可以包含多個表。還支援檔案資料,比如圖片、視訊等。對底層的資料儲存方式沒有任何要求,可以是SQLite、檔案,甚至是記憶體中的一個物件都行。

6、使用Socket。也稱為套接字,流式套接字對應TCP協議,使用者資料報套接字對應UDP協議。TCP協議是面向連線的協議,提供穩定的雙向通訊功能,TCP連線的建立需要經過“三次握手”才能完成,為了提供穩定的資料傳輸功能,其本身提供了超時重傳功能,因此具有很高的穩定性。UDP是無連線的,提供不穩定的單向通訊功能,當然UDP也可以實現雙向通訊功能,在效能上,UDP具有更好的效率,其缺點是不保證資料能夠正確傳輸,尤其是在網路擁塞的情況下。

選用合適的IPC方式 在這裡插入圖片描述

6-4、Binder

1、Binder基礎

Binder程序間通訊機制是在OpenBinder的基礎上實現的,它採用C/S通訊方式,其中提供服務的程序稱為Server程序,訪問服務的程序稱為Client程序。同一個Server程序可以同時執行多個元件來向Client程序提供服務,這些元件稱為Service元件。同一個Client程序也可以同時向多個Service元件請求服務,每個請求都對應有一個Client元件,或稱為Service代理物件。

Client、Service、Service Manager執行在使用者空間中,而Binder驅動程式執行在核心空間中。其中Service Manager和Binder驅動程式由系統負責提供,而Client和Service元件由應用程式來實現。

Android中更高層次的IPC抽象,比如Intent(跨程序元件間傳遞帶有關聯資料的命令)、Messenger(支援跨程序訊息通訊的物件)、ContentProvider(暴露跨程序資料管理介面的元件),均是基於Binder實現的。此外,要暴露給其它程序的服務介面可以使用Android介面定義語言(AIDL)來定義。

在更高的一個層次上,每個通過Binder框架實現IBinder介面,允許被訪問呼叫的物件都可以被叫做Binder物件。對Binder物件的呼叫在一個Binder事務處理內部實現,其中包括一個對目標物件的引用、需執行方法的ID和一個數據緩衝區。Binder驅動會將呼叫程序的ID(PID)和有效使用者ID(EUID)自動新增到事務處理資料。因為PID和EUID均是由核心寫的,所以呼叫者程序不能通過偽造身份標識來獲取超出系統允許的許可權,即Binder可以防止提權。

在基於Binder通訊的C/S架構體系中,除了C/S架構所包括的Client端和Server端外,Android還有一個全域性的ServiceManager端,它的作用是管理系統中的各種服務。

關於Client、Server、ServiceManager三者之間的互動關係:

1、Server程序要先註冊一些Service到ServiceManager中,所以Server是ServiceManager的客戶端,而ServiceManager就是服務端了。 2、如果某個Client程序要使用某個Service,必須先到ServiceManager中獲取該Service的相關資訊,所以Client是ServiceManager的客戶端。 3、Client根據得到的Service資訊與Service所在的Server程序建立通訊的通路,然後就可以直接與Service互動了,所以Client也是Server的客戶端。 4、三者的互動都是基於Binder通訊的。

ServiceManager的意義: 1、ServiceManager能集中管理系統內的所有服務,它能施加許可權控制,並不是任何程序都能註冊服務的。 2、ServiceManager支援通過字串名稱來查詢對應的Service。這個功能就像DNS。 3、Server程序可能生死無常,如果讓每個Client都去檢測則壓力太大,ServiceManager統一管理後Client只需要查詢ServiceManager就能把握最新動向。

2、Binder連線池

當專案越來越龐大後,需要使用到的AIDL介面檔案也越來越多,但我們不能有多少個AIDL就新增多少個Service,而是應該把所有AIDL放在一個Service中去管理。

Binder連線池的主要作用就是將每個業務模組的Binder請求統一轉發到遠端Service去執行,從而避免了重複建立Service的過程。

匿名Service:就是沒有註冊的Service。沒有註冊意味著這個Service沒有在ServiceManager上註冊。但它又是一個Service又表示它確實是一個基於Binder通訊的C/S結構。

3、物件互動

在Client程序和Server程序的一次通訊過程中,涉及了四種類型的物件,它們分別是:

位於Binder驅動程式中的Binder實體物件(binder_node)和Binder引用物件(binder_ref)。位於Binder庫中的Binder本地物件(BBinder)和Binder代理物件(BpBinder)。

Client程序和Server程序互動過細節程如下:

1、執行在Client程序中的Binder代理物件通過Binder驅動程式向執行在Server程序中的Binder本地物件發出一個程序間通訊請求,Binder驅動程式接著就根據Client程序傳遞過來的Binder代理物件的控制代碼值來找到對應的Binder引用物件。

2、Binder驅動程式根據前面找到的Binder引用物件找到對應的Binder實體物件,並且建立一個事務(binder_transaction)來描述該次程序間通訊過程。

3、Binder驅動程式根據前面找到的Binder實體物件來找到執行在Server程序中的Binder本地物件,並且將Client程序傳遞過來的通訊資料傳送給它處理。

4、Binder本地物件處理完成Client程序的通訊請求之後,就將通訊結果返回給Binder驅動程式,Binder驅動程式接著就找到前面所建立的一個事務。

5、Binder驅動程式根據前面找到的事務的相關屬性來找到發出通訊請求的Client程序,並且通知Client程序將通訊結果返回給對應的Binder代理物件處理。

在這裡插入圖片描述

6-5、Intent

1、Intent基本概念

Intent是Android程式中各元件之間進行互動的一種重要方式,它不僅可以指明當前元件想要執行的動作,還可以在不同元件之間傳遞資料。Intent可被用於啟動活動、啟動服務以及傳送廣播等場景。Intent可以分為顯式Intent和隱式Intent。

顯式Intent:需要明確的指定被啟動物件的元件資訊,包括包名和類名,從而使得可以傳送一個定向的Intent到唯一的元件。

隱式Intent:元件的完全限定名稱是未知的,該元件可以通過指定需要與它進行的操作的接收元件,進行隱式呼叫。隱式呼叫需要Intent能夠匹配目標元件的IntentFilter中所設定的過濾資訊,如果不匹配將無法啟動目標元件。IntentFilter中的過濾資訊有action、category、data。

掛起Intent是一個應用程式給予另一個應用程式的標記,以便於其它應用程式可以利用原始應用程式的許可權和標識執行某段程式碼。即使傳送應用程式被停止或破壞,掛起Intent仍會執行。

一個Intent主要包含以下4類訊息:

Commponent Name(元件名稱):就一個顯式Intent來說,元件名稱是必須的 Action String(操作字串):一個操作字串是被執行的操作 Data(資料):這是資料和MIME型別的URI Category(分類):分類提供了附加的關於元件可以接收的Intent種類的資訊,增加進一步的限制

2、隱式Intent

在顯式intent中,指定要啟動的activity類,作業系統會負責啟動它。 在隱式intent中,只要描述要完成的任務,作業系統就會找到合適的應用,並在其中啟動相應的activity。即利用隱式intent啟動其他應用的activity。

隱式intent的主要組成部分:

1、要執行的操作:通常以Intent類中的常量來表示 2、待訪問資料的位置:是裝置以外的資源,如某個網頁的URL 3、操作涉及的資料型別:是MIME形式的資料型別,如text/html或audio/mpeg3 4、可選類別:通常用來描述你打算何時、何地或者如何使用某個activity

3、隱式Intent應用舉例:

一個檢視某個網址的簡單隱式intent會包括一個Intent.ACTION_VIEW操作,以及某個具體URL網址的Uri資料。基於以上資訊,作業系統將啟動適用的activity。通過配置檔案中的intent過濾器設定,activity會對外宣稱自己是適合處理ACTION_VIEW的activity。

為了響應ACTION_VIEW操作,在activity宣告中包含以下intent過濾器:

<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />

必須在intent過濾器中明確地設定DEFAULT類別。action元素告訴作業系統,activity能夠勝任指定任務。DEFAULT類別告訴作業系統,activity願意處理某項任務。DEFAULT類別實際隱含於所有隱式intent中。

使用隱式intent啟動activity時,也可以建立每次都顯示的activity選擇器。和以前一樣建立隱式intent後,呼叫以下Intent方法並傳入建立的隱式intent以及用作選擇器標題的字串:

public static Intent createChooser(Intent target, String title)

然後,將createChooser()方法返回的intent傳入startActivity()方法。

4、使用Intent拍照

相機所拍攝的照片動輒幾MB大小,不會儲存在SQLite資料庫中的。而是儲存在私有儲存空間中。使用類似Context.getFileStreamPath(String)和Context.getFilesDir()這樣的方法,結果就是照片檔案儲存在databases子目錄相鄰的某個子目錄中。

Context類提供的基本檔案和目錄處理方法如下:

File getFilesDir():   獲取/data/data/<包名>/files目錄。
FileInputStream openFileInput(String name):    開啟現有檔案進行讀取。
FileOutputStream openFileOutput(String name, int mode):    開啟檔案進行寫入,如果不存在就建立它。
File getDir(String name, int mode):    獲取/data/data/<包名>/目錄的子目錄(如果不存在就先建立它)。
String[] fileList():    獲取主檔案目錄下的檔案列表。可與其他方法配合使用,如openFileInput(String)。
File getCacheDir():    獲取/data/data/<包名>/cache目錄。應注意及時清理該目錄,並節約使用。

如果儲存的檔案僅供應用內部使用,使用上述各類方法就夠了。

如果想共享檔案給其他應用,或是接收其他應用的檔案,可以通過ContentProvider把要共享的檔案暴露出來。ContentProvider允許你暴露內容URI給其他應用。

使用相機intent需要的操作是定義在MediaStore類中的ACTION_IMAGE_CAPTURE。

MediaStore類定義了一些公共介面,可用於處理影象、視訊以及音樂這些常見的多媒體任務。ACTION_IMAGE_CAPTURE開啟相機應用,預設只能拍攝縮圖這樣的低解析度照片,而且照片會儲存在onActivityResult()返回的Intent物件裡。要想獲得全尺寸照片,就要讓它使用檔案系統儲存照片。這通過傳入儲存在MediaStore.EXTRA_OUTPUT中的指向儲存路徑的Uri來完成。這個Uri會指向FileProvider提供的位置。

5、Intent和任務

startActivity(Intent)方法意味著“啟動匹配隱式intent的預設activity”,如果希望intent過濾器匹配startActivity()方法傳送的隱式intent,就必須在對應的intent過濾器中包含DEFAULT類別。

任務是一個activity棧。棧底部的activity通常稱為基activity。棧頂的activity使用者能看得到。如果按後退鍵,棧頂activity會彈出棧外。如果使用者看到的是基activity,按後退鍵,系統就會回到主螢幕。預設情況下,新activity都在當前任務中啟動。

程序是作業系統建立的、供應用物件生存以及應用執行的地方。程序通常會佔用由作業系統管理著的系統資源,如記憶體、網路埠以及開啟的檔案等。程序還擁有至少一個(可能多個)執行執行緒。在Android系統中,每個程序都需要一個虛擬機器來執行。