1.Binder是什么?
- 機(jī)制:Binder是一種進(jìn)程間通信機(jī)制。
- 驅(qū)動:Binder是一個虛擬物理設(shè)備驅(qū)動
- 應(yīng)用層:Binder是一個能夠發(fā)起通信的java類
2.多進(jìn)程的使用以及優(yōu)勢
虛擬機(jī)分配給各個進(jìn)程的運行內(nèi)存是有限制的,LMK也會優(yōu)先回收對系統(tǒng)資源占用多的進(jìn)程
- 突破進(jìn)程內(nèi)存限制
- 功能穩(wěn)定性 ,獨立的通信進(jìn)程保持長連接的穩(wěn)定性。(極光推送,百度定位)
- 規(guī)避系統(tǒng)內(nèi)存泄漏:獨立的WebView進(jìn)程阻隔內(nèi)存泄漏導(dǎo)致的問題。
- 隔離風(fēng)險,對于不穩(wěn)定的功能放入到獨立進(jìn)程,避免導(dǎo)致主進(jìn)程的崩潰.
3.Linux中進(jìn)程間的通信機(jī)制有哪些?與傳統(tǒng)的IPC機(jī)制相比,有哪些優(yōu)勢?
[圖片上傳失敗...(image-27d811-1769743586604)]
Binder 共享內(nèi)存 socket 管道 消息隊列 信號 ,信號量
Binder:拷貝一次+內(nèi)存映射 基于CS架構(gòu),易用性強(qiáng)(Service>>binder >>分配uid 【如果是惡意軟件,通過uid找到,很安全】) ,雙向通信
共享內(nèi)存: 無需拷貝 控制復(fù)雜,易用性差 (多線程使用同一塊內(nèi)存時,可能出現(xiàn)死鎖,數(shù)據(jù)不同步問題,訪問接入點事開放的,不安全) mmap原理實現(xiàn) ,雙向通信
socket : 拷貝二次 基于CS架構(gòu),效率低,開銷大 (訪問接入點是開放的,不安全),雙向通信
管道Pipe: 拷貝二次,數(shù)據(jù)傳輸也是單向的,一個進(jìn)程向管道寫入數(shù)據(jù),另一個進(jìn)程從管道讀取數(shù)據(jù).
[圖片上傳失敗...(image-8e0eb8-1769743586604)]消息隊列:拷貝二次,消息隊列是消息的鏈表,存放在內(nèi)核中,每個消息隊列都有隊列id來標(biāo)識,獨立與發(fā)送和接收進(jìn)程,進(jìn)程終止時,消息隊列中的內(nèi)容不會被刪除,也可以實現(xiàn)隨機(jī)查詢,消息不一定要以先進(jìn)先出的次序讀取,也可以按照消息的類型或者優(yōu)先級讀取.
[圖片上傳失敗...(image-804230-1769743586604)]信號 (比如Vsync)是基于事件的異步通知,而不是數(shù)據(jù)的拷貝,當(dāng)某個時間發(fā)生時,內(nèi)核會向目標(biāo)進(jìn)程發(fā)送一個信號,信號會被添加到目標(biāo)進(jìn)程的信號隊列中,當(dāng)進(jìn)程從內(nèi)核態(tài)返回用戶態(tài)時,內(nèi)核會檢查信號隊列,并根據(jù)注冊的信號處理函數(shù)來處理信號.【無需拷貝】
注意:有些資料說是4次拷貝(發(fā)送進(jìn)程的用戶空間>>發(fā)送進(jìn)程內(nèi)核空間緩沖區(qū)>>內(nèi)存>>用戶進(jìn)程內(nèi)核緩沖區(qū)>>用戶進(jìn)程用戶空間),也可以簡化為2次拷貝(用戶空間 >>內(nèi)核緩沖區(qū)>>用戶空間)
4.Binder通信原理(一次拷貝+ 內(nèi)存映射)
- 具體過程:
- 數(shù)據(jù)接收方進(jìn)程在初始化的時候,會直接調(diào)用mmap函數(shù),通過Binder驅(qū)動,提前在內(nèi)核空間開辟一塊共享的物理內(nèi)存,并映射到自己的用戶空間.
- 發(fā)送方進(jìn)程(無需通過Binder驅(qū)動在內(nèi)核開辟共享的物理內(nèi)存)將數(shù)據(jù)直接拷貝到這一塊內(nèi)核緩沖區(qū),由于接收方的用戶空間已經(jīng)映射了同一塊內(nèi)核緩沖區(qū),它無需再次拷貝,可以直接讀取.
- 在完整的一次Binder遠(yuǎn)程方法調(diào)用中,客戶端和服務(wù)端的角色是動態(tài)轉(zhuǎn)換的
- 當(dāng)發(fā)起請求時:客戶端是數(shù)據(jù)發(fā)送進(jìn)程,服務(wù)端(AMS)是數(shù)據(jù)接收進(jìn)程。
- 當(dāng)返回結(jié)果時:服務(wù)端(AMS)是數(shù)據(jù)發(fā)送進(jìn)程,客戶端是數(shù)據(jù)接收進(jìn)程。
這就好比雙方在翻譯官(內(nèi)核)的辦公室里放了一個共享的公文袋(內(nèi)核緩沖區(qū)) 。客戶端直接把文件放進(jìn)公文袋,服務(wù)端伸手就從同一個袋子里拿,省去了翻譯官中間轉(zhuǎn)交的步驟。
[圖片上傳失敗...(image-5c04d9-1769743586604)]
5.MMAP(Memory Map)內(nèi)存映射的原理
虛擬內(nèi)存劃分
[圖片上傳失敗...(image-28658a-1769743586604)]內(nèi)存映射原理?
內(nèi)存映射簡單的講:數(shù)據(jù)接收方進(jìn)程在進(jìn)程是初始化內(nèi)核空間的一塊內(nèi)存區(qū)域映射到自己內(nèi)核空間,映射關(guān)系建立后,用戶對這塊內(nèi)存區(qū)域的修改可以直接反應(yīng)到內(nèi)核空間;反之內(nèi)核空間對這段區(qū)域的修改也能直接反應(yīng)到用戶空間提高了通信速度。
6.Binder通過Java代碼是如何實現(xiàn)的呢?
6.1.服務(wù)端,客戶端BookManager.aidl文件,根據(jù)aidl接口,系統(tǒng)自動幫忙生成Stub類繼承Binder并實現(xiàn)BookManager接口【服務(wù)端和客戶端生成的代碼是一樣的,只是調(diào)用邏輯不一樣而已】
interface BookManager{
List<Book> getBookList();
}
6.2.根據(jù)aidl接口,自動生成BookManager.java類(aidl就是對binder的封裝)
//SDK提供
public interface IBinder {
int FIRST_CALL_TRANSACTION = 1;
boolean isBinderAlive();
}
//SDK提供
public class Binder implements IBinder {
public boolean isBinderAlive() {
throw new RuntimeException("Stub!");
}
}
//SDK提供
public interface IInterface {
IBinder asBinder();
}
//系統(tǒng)生成
public interface BookManager extends android.os.IInterface {
public static abstract class Stub extends Binder implements BookManager {
//自動生成的TRANSACTION_getBookList
static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
private static final String DESCRIPTOR = "com.lypeer.ipcclient.BookManager";
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
//把IBinder對象轉(zhuǎn)BookManager接口的,如果需要的話,就生成一個Proxy代理類
public static BookManager asInterface(IBinder obj) {
if ((obj == null)) {
return null;
}
//此處得到的iin==null
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);//iin ==null
if (((iin != null) && (iin instanceof BookManager))) {
return ((com.lypeer.ipcclient.BookManager) iin); //null
}
//因為iin==null,所以此處只會生成一個代理類
return new com.lypeer.ipcclient.BookManager.Stub.Proxy(obj);
}
//返回IBinder的實現(xiàn)類
public android.os.IBinder asBinder() {
return this;
}
private static class Proxy implements BookManager{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
public IBinder asBinder() {
return mRemote;
}
//客戶端調(diào)用getBookList
public List<Book> getBookList() {
Parcel _data = android.os.Parcel.obtain();
Parcel _reply = android.os.Parcel.obtain();
List<Book> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
//直接調(diào)用服務(wù)端transact方法
boolean _status = mRemote.transact(Stub.TRANSACTION_getBooks, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
return getDefaultImpl().getBookList();
}
_reply.readException();
_result = _reply.createTypedArrayList(com.lypeer.ipcclient.Book.CREATOR);
}finally{
_reply.recycle();
_data.recycle();
}
return _result;
}
}
// 服務(wù)端執(zhí)行onTransact根據(jù)code碼進(jìn)行處理
public boolean onTransact(int code,Parcel data ,Parcel reply,int flags){
java.lang.String descriptor = DESCRIPTOR;
switch(code){
case TRASACTION_getBookLIst:{
//檢查客戶端調(diào)用的接口是否與服務(wù)端提供的接口一致
data.enforceInterface(descriptor);
List<com.lypeer.ipcclient.Book> _result = this.getBookList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
}
}
}
}
6.3.客戶端調(diào)用
public class AIDLActivity extends AppCompatActivity {
private BookManager mBookManager = null;
protected void onStart() {
attemptToBindService();
}
//嘗試與服務(wù)器建立連接
private void attemptToBindService() {
Intent intent = new Intent();
intent.setAction("com.lypeer.aidl");
intent.setPackage("com.lypeer.ipcserver");
bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
}
private ServiceConnection mServiceConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName name, IBinder service) {
Log.e(getLocalClassName(), "service connected");
mBookManager = BookManager.Stub.asInterface(service); //得到Proxy對象
mBound = true;
if (mBookManager != null) {
try {
mBooks = mBookManager.getBooks();
Log.e(getLocalClassName(), mBooks.toString());
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
public void onServiceDisconnected(ComponentName name) {
Log.e(getLocalClassName(), "service disconnected");
mBound = false;
}
};
//mBookManager.getBookList>>Proxy.getBookList>>Proxy.mRemote.onTransact(Stub.TRANSACTION_getBookList)
public getBookList(){
if(mBookManager!=null){
//回調(diào)Proxy類中的getBookList();
mBookManager.getBookList();
}
}
}
6.4.服務(wù)端實現(xiàn)代碼
public class AIDLService extends Service{
//包含Book對象的list
private List<Book> bookList = new ArrayList<>();
//實現(xiàn)抽象類Stub,Stub實現(xiàn)了BookManager接口
private final BookManager.Stub mBookManager=new BookManager.Stub(){
public List<Book> getBookList(){
return bookList;
}
}
public void onCreate() {
Book book = new Book();
book.setName("Android開發(fā)藝術(shù)探索");
book.setPrice(28);
bookList.add(book);
super.onCreate();
}
public IBinder onBind(Intent intent) {
return mBookManager;
}
}