作者:浪人筆記
面試可能會問到的問題
- 從IPC的方式問到Binder的優勢
- 為什么zygote跟其他服務進程的通訊不使用Binder
- Binder線程池和Binder機制
等等這些問題都是基于你對Binder的理解還有對其他IPC通訊的理解
IPC方式有多少種
- 傳統的IPC方式有Socket、共享內存、管道、信號量等
- 安卓特有的是
Binder
,其他系統也有自己定義的比如window的wfc(Windows Communication Foundation)
Binder機制的優勢
傳統的ipc管道跟信號量都是比較輕的,基本不能用于復雜的IPC通訊,Socket有個缺點就是數據要復制兩遍,第一遍是進程A復制到Socket通道,第二遍是Socket通道復制到進程B。共享內存的缺點就是不方便管理,如果頻繁的對共享內存進行操作很可能會導致死鎖、饑餓等問題。
為了解決這個痛點,安卓設計了Binder的通訊機制,提供更高效、安全、可靠的方式。下圖是Binder機制圖。只需要在內核里面復制一遍,這里可以簡單的理解為單例模式,大家都只需要對Binder內存區域做操作,內存只有一份。
還有一些概念,比如我們應該都聽說Binder是內核里面的,Binder是怎么用到安卓系統里面的,再看一個圖
這里面有四個角色,其實很好理解,兩個進程、一個Binder內核空間、一個ServiceManager服務。兩個進程時采用的C/S結構一個客戶端一個服務端。
-
Binder
內核空間就是一塊存在于內核區的內存理解為一個通道 -
ServiceManager
是安卓的核心服務之一,AMS、PMS、WMS這些是一樣的。它里面提供了很多線程池。Binder線程池只是其中的一種。在這里可以理解為是管理Binder給外部用的提供了一個注冊機制用于識別不同的進程。下面是其他的幾個線程池- Activity Manager線程池:用于處理Activity啟動、停止等操作,保證UI界面的流暢性。
- JobScheduler線程池:用于調度執行后臺任務。
- MediaServer線程池:用于處理音視頻等媒體數據。
- SurfaceFlinger線程池:用于處理UI界面繪制等操作。
有沒有想過為什么要搞那么線程池,還要搞那么多個。其實也比較好理解,因為ServiceManager這個類的有很多地方用到,不可能是單線程處理的,這樣就堵塞了。為什么搞那么多線程池是因為不同的功能不同比如有些調用比較頻繁有些需要比較多的cpu。只有一個線程池的話很容易會導致占用時間過長等問題。
server進程
需要提供方法被別人調用,需要先在ServiceManager里面注冊。- server注冊完以后會提供接口給
client進程
調用
來到這里應該可以回答剩下的那兩個問題了。
Binder線程池和Binder機制
- Binder線程池是ServiceManager提供的,利用的是Binder內核機制。
- Binder機制是安卓為了提供更高效、穩定、可靠的方式實現的一套基于內核的IPC機制。
為什么zygote進程跟其他進程通訊使用socket而不是binder
- Binder雖然在內核,但是提供服務的是ServiceManager,這個時候如果要給AMS提供Binder IPC就需要等ServiceManager先初始化好,這個是沒辦法保證的,如果要保證這個先后順序又要搞多一套進程通訊就更麻煩了。
- 另外,由于Zygote進程只與少數幾個進程進行通訊,使用Socket通訊的開銷相對較小,因此選擇Socket通訊更加合適。而且這里面是優化過的LocalSocket效率會更高。
上面一直說內核空間,那內核空間跟用戶空間有什么區別呢?
-
內核程序運行在操作系統的內核空間,具有更高的權限和更快的執行速度,能夠實現更底層的操作,如硬件驅動、文件系統等,因此通常用于操作系統的核心功能的實現。
-
用戶程序運行在操作系統的用戶空間,具有更多的自由度和可移植性,能夠實現更豐富的功能,如應用程序、服務進程等,因此通常用于操作系統的外圍功能和應用程序的實現。
簡單的說就是內核空間有操作內存的方法,但是這一塊對用戶空間是封閉的,用戶空間里面操作的都是內核提供的服務。比如操作文件用到的文件系統模塊
和操作內存用到的內存管理模塊
。拿內存管理模塊里面用到的kmalloc
和kfree
來說。這兩個方法在用戶空間就調用不到,這是內核封裝的方法。
`kmalloc()` 和 `kfree()`: 內核內存分配器,用于在內核空間中動態分配和釋放內存。// 這個還并不是c/c++的原生方法,是內核自己封裝的
再看一下比如使用Binder的時候我們傳的是一個序列化的文件,那他是怎么映射到內存中的?
在內核中有vm_map_ram
和vm_insert_page
這些方法可以把文件插入到內存地址中。而如果在用戶空間需要跟這些打交道用到的還是內存管理模塊的mmap
這些。 mmap
的實現在內核中使用了 vm_area_struct
。意思是內存管理模塊提供給外面的一層封裝。所以與其這么麻煩還不如直接放到內核里面更合適。
這些方法其實都不重要,只需要知道一點,這些方法在用戶進程空間是拿不到的
基于Binder的IPC
這里是一些基礎,可以不看了。因為這些用的少,方便自己以后看
AIDL
服務端
// IMyService.aidl
interface IMyService {int add(int a, int b);
}// MyService.java
public class MyService extends Service {@Overridepublic IBinder onBind(Intent intent) {return new MyBinder();}private class MyBinder extends IMyService.Stub {@Overridepublic int add(int a, int b) throws RemoteException {return a + b;}}
}
客戶端
// MainActivity.java
public class MainActivity extends AppCompatActivity {private IMyService mService;private ServiceConnection mConnection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {mService = IMyService.Stub.asInterface(service);try {int result = mService.add(1, 2);Toast.makeText(MainActivity.this, "Result: " + result, Toast.LENGTH_SHORT).show();} catch (RemoteException e) {e.printStackTrace();}}@Overridepublic void onServiceDisconnected(ComponentName name) {mService = null;}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Intent intent = new Intent(this, MyService.class);bindService(intent, mConnection, Context.BIND_AUTO_CREATE);}@Overrideprotected void onDestroy() {super.onDestroy();unbindService(mConnection);}
}
Messager
輕量級的AIDL只能單線程 服務端 MessengerService.java:
public class MessengerService extends Service {private static class IncomingHandler extends Handler {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case 1:String clientMessage = (String) msg.obj;Log.i("MessengerService", "Received message from client: " + clientMessage);// Send a response back to the clientMessenger clientMessenger = msg.replyTo;Message replyMessage = Message.obtain(null, 2);Bundle bundle = new Bundle();bundle.putString("serverResponse", "Hello from server!");replyMessage.setData(bundle);try {clientMessenger.send(replyMessage);} catch (RemoteException e) {Log.e("MessengerService", "Failed to send message to client", e);}break;default:super.handleMessage(msg);}}}private final Messenger mMessenger = new Messenger(new IncomingHandler());@Overridepublic IBinder onBind(Intent intent) {return mMessenger.getBinder();}
}
客戶端 MessengerClient.java:
public class MessengerClient extends AppCompatActivity {private Messenger mMessenger;private static class IncomingHandler extends Handler {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case 2:String serverMessage = msg.getData().getString("serverResponse");Log.i("MessengerClient", "Received message from server: " + serverMessage);break;default:super.handleMessage(msg);}}}private final Messenger mClientMessenger = new Messenger(new IncomingHandler());@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Intent intent = new Intent(this, MessengerService.class);bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);}@Overrideprotected void onDestroy() {super.onDestroy();unbindService(mServiceConnection);}private final ServiceConnection mServiceConnection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {mMessenger = new Messenger(service);sendMessageToServer();}@Overridepublic void onServiceDisconnected(ComponentName name) {mMessenger = null;}};private void sendMessageToServer() {if (mMessenger == null) {return;}Message message = Message.obtain(null, 1);message.obj = "Hello from client!";message.replyTo = mClientMessenger;try {mMessenger.send(message);} catch (RemoteException e) {Log.e("MessengerClient", "Failed to send message to server", e);}}
}
廣播、內容提供者
……
關于Android 面試筆記的真理還有許多知識點在這不能一一的展示,為了方便大家進行復習查閱,這邊我整理成了文檔的形式了,大家可以進行參考一下:https://qr18.cn/CgxrRy