目錄
- 1)多進程模式
- 2)IPC基礎概念
- 2.1)Serializable和Parcelable
- 2.2)Binder機制
- 2.2.1)自定義服務的Binder分析
- 2.2.2)系統服務的Binder分析
- 3)Android中的IPC
- 3.1)Bundle
- 3.2)文件共享
- 3.3)Messenger
- 3.4)AIDL
- 3.5)ContentProvider
- 3.6)Socket
- 3.7)廣播
- 4)Binder連接池
- 5)選擇合適的IPC方式
1)多進程模式
Android中使用多進程只有一種方法,就是給四大組件指定android:process屬性
可以在Monitor視圖中查看進程信息,還可以用shell來查看,命令為:adb shell ps 或者 adb shell ps|grep 包名
<activity
android:name=".SecondActivity"
<!-- 私有進程,進程名為 com.ryg.chapter_2:remote -->
android:process=":remote" />
<activity
android:name=".ThirdActivity"
<!-- 全局進程,進程名為 com.ryg.chapter_2.remote -->
android:process="com.ryg.chapter_2.remote" />
- 多進程的問題 (不同進程的組件會擁有獨立的虛擬機,Application和內存空間)
- 靜態變量和單例模式失效。(Android為每個應用分配了獨立的虛擬機,不同的虛擬機在內存分配上有不同的地址空間。導致需要內存來共享數據都會失敗)
- 線程同步機制失效(同上)
- SharedPreference不可靠(并發讀寫)
- Application多次創建(Android為新的進程分配獨立虛擬機,即啟動新應用,會創建新的Application)
2)IPC基礎概念
2.1) Serializable和Parcelable
類型 | 說明 |
---|---|
Serializable | Java的序列化接口,序列化過程中I/O開銷大,可用在將對象序列化存儲到設備中或網絡傳輸 |
Parcelable | Android的序列化接口,效率高,建議使用 |
//自動實現序列化過程
public class User implements Serializable{
private static final long serialVersionUID = 8723148825838841922L;
使用ObjectOutputStream和ObjectInputStream可輕松實現序列化和反序列化過程
// 序列化過程:
User user = new User(0,"jake",true);
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("cache.txt"));
out.writeObject(user);
out.close();
// 反序列化過程:
ObjectInputStream in = new ObjectInputStream(new FileInputStream("cache.txt"));
User newUser = (User)in.readObject();
in.close();
2.2) Binder機制
為什么 Android 要采用 Binder 作為 IPC 機制?
角度 | 說明 |
---|---|
性能 | Binder數據拷貝只需要一次,而管道、消息隊列需要2次(即數據先從發送方緩存區拷貝到內核開辟的緩存區中copy_from_user,然后再從內核緩存區拷貝到接收方緩存區copy_to_user()),共享內存不需要拷貝。Socket傳輸效率低開銷大,用于進程間低速通信和跨網絡通信。 |
穩定性 | Binder是基于C/S架構的,相對獨立,而共享內存沒有C/S之別, 需要考慮并發同步問題 |
安全性 | 為發送方添加UID/PID身份,Server端會根據權限控制策略,判斷應用進程的UID/PID是否滿足訪問權限 |
Binder是IPC的重要機制,AMS,WMS等系統服務背后都是Binder。
Binder的架構包括服務端,客戶端和Binder驅動
名稱 | 說明 |
---|---|
服務端 | 就是一個Binder對象,內部線程會接收Binder驅動發送的消息,收到消息后會執行onTranscat(),并按照參數執行不同的服務端代碼 |
Binder驅動 | 工作在內核態,服務端Binder對象創建后,會在驅動中創建mRemote對象,其也是Binder對象,以供客戶端訪問 |
客戶端 | 獲取驅動中的mRemote引用,然后調用transcat()即可向服務端發送消息 |
Binder IPC底層原理 -Binder為什么只需要拷貝一次
1、Binder驅動在內核空間創建數據接收緩存區
2、在內核空間中開辟一塊內核緩存區,建立內核緩存區與數據接收緩存區的映射 以及數據接收緩存區與接收進程用戶空間的映射關系。
3、發送方調用copy_from_user()函數將數據拷貝至內核緩存區,由于內核緩存區與接收進程用戶空間存在內存映射,即相當于把數據發送至接收進程的用戶空間,從而完成了進程通信。
PS:內存映射(mmap),mmap() 是操作系統中一種內存映射的方法,將用戶一塊內存區域映射至內核空間,建立映射關系后,用戶對內存區域的修改可直接反應到內核空間,反之亦然。
2.2.1) 自定義服務的Binder分析
通過Service
public boolean bindService(Intent service, ServiceConnection conn, int flags)
public interface ServiceConnection {
//第二個參數service即為遠程服務在Binder驅動中的binder引用
public void onServiceConnected(ComponentName name, IBinder service);
public void onServiceDisconnected(ComponentName name);
}
- 自定義服務-使用Binder進行IPC通信:
//code 標識要調用服務端的哪個函數
//data 對輸入參數打包
//reply 對返回值打包
//writeString<--->readString客戶端打包一個Parcel對象,在服務端讀取該Parcel對象數據
public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException;
客戶端
public class MainActivity extends Activity {
private boolean isBound;
private Button btn_add;
private IBinder mRemote = null;
private ServiceConnection serviceConn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//獲得該遠程服務所對應的Binder驅動中的引用
mRemote = service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bind();
btn_add = (Button)findViewById(R.id.btn_add);
btn_add.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
String result = null;
try {
result = strcat("abc", "def");
} catch (RemoteException e) {
Toast.makeText(MainActivity.this, "error", 0).show();
e.printStackTrace();
}
Toast.makeText(MainActivity.this, result, 0).show();
}
});
}
private void bind() {
Intent intent = new Intent(MainActivity.this, ComputeService.class);
isBound = bindService(intent, serviceConn, Context.BIND_AUTO_CREATE);
}
private void unbind() {
if (isBound) {
MainActivity.this.unbindService(serviceConn);
isBound = false;
}
}
private String strcat(String x, String y) throws RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
String _result;
try {
_data.writeString(x);
_data.writeString(y);
mRemote.transact(1, _data, _reply, 0);
_result = _reply.readString();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
protected void onDestroy() {
unbind();
super.onDestroy();
}
}
服務端:
public class ComputeService extends Service {
private IBinder binder = new Binder(){
protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
if (code == 1) {
String _arg0;
_arg0 = data.readString();
String _arg1;
_arg1 = data.readString();
String _result = this.strcat(_arg0, _arg1);
reply.writeString(_result);
return true;
}
return super.onTransact(code, data, reply, flags);
};
public String strcat(String x, String y){
return x + y;
}
};
@Override
public IBinder onBind(Intent arg0) {
return binder;
}
}
- 自定義服務-使用AIDL進行IPC通信:
AIDL(Android Interface Definition Language),編譯器通過*.aidl文件的描述信息生成符合通信協議的Java代碼
package org.qhyuan.aidl;
interface ICompute {
String strcat (String x,String y);
}
interface ICompute extends IInterface
{
strcat();
static abstract class Stub extends Binder implements ICompute {
static final int TRANSACTION_strcat;
static final String DESCRIPTOR;
static asInterface();
asBinder();
onTransact();
static class Proxy implements ICompute {
IBinder binder;
asBinder();
getInterfaceDescriptor();
strcat();
}
}
}
客戶端
public class MainActivity extends Activity {
private ICompute compute = null;
private boolean isBound;
private Button btn_add;
private ServiceConnection serviceConn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//asInterface 將一個Binder轉為實現接口
compute = ICompute.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bind();
btn_add = (Button)findViewById(R.id.btn_add);
btn_add.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
String result = null;
try {
result = compute.strcat("abc", "def");
} catch (RemoteException e) {
Toast.makeText(MainActivity.this, "error", 0).show();
e.printStackTrace();
}
Toast.makeText(MainActivity.this, result, 0).show();
}
});
}
private void bind() {
Intent intent = new Intent(MainActivity.this, ComputeService.class);
isBound = bindService(intent, serviceConn, Context.BIND_AUTO_CREATE);
}
private void unbind() {
if (isBound) {
MainActivity.this.unbindService(serviceConn);
isBound = false;
}
}
@Override
protected void onDestroy() {
unbind();
super.onDestroy();
}
}
服務端
public class ComputeService extends Service {
private IBinder binder = new ICompute.Stub() {
@Override
public String strcat(String x, String y) throws RemoteException {
return x+y;
}
};
@Override
public IBinder onBind(Intent arg0) {
return binder;
}
}
2.2.2)系統服務的Binder分析
SystemServer開啟各種服務時,調用ServiceManager.addService(String name,IBinder service)將其保存起來,這樣當查找服務的時候,就可ServiceManager.getService(String name)來獲取遠程服務的Binder。
public static void setSystemProcess() {
ActivityManagerService m = mSelf;
ServiceManager.addService("activity", m, true);
ServiceManager.addService("meminfo", new MemBinder(m));
ServiceManager.addService("gfxinfo", new GraphicsBinder(m));
ServiceManager.addService("dbinfo", new DbBinder(m));
// ....
}
AMS舉例,客戶端如何去獲取AMS的Binder。
我們知道Activity啟動,客戶端調用服務器端是通過IActivityManager接口來實現。
IActivityManager對應IXXX接口
ActivityManagerNative對應IXXX.Stub類,繼承自Binder類。
ActivityManagerProxy對應IXXX.Stub.Proxy類。
class ActivityManagerProxy implements IActivityManager{}
public final class ActivityManagerService extends ActivityManagerNative{}
public abstract class ActivityManagerNative extends Binder implements
只要客戶端獲取遠程服務的Binder就可以進行IPC通信了,在ActivityThread的attach方法里有下面兩行代碼
IActivityManager mgr = ActivityManagerNative.getDefault();
mgr.attachApplication(mAppThread);
static public IActivityManager getDefault() {
return gDefault.get();
}
private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
protected IActivityManager create() {
// 這里可以看到通過調用getService方法得到Binder
IBinder b = ServiceManager.getService("activity");
if (false) {
Log.v("ActivityManager", "default service binder = " + b);
}
//將一個IBinder對象轉化為它實現的接口
IActivityManager am = asInterface(b);
if (false) {
Log.v("ActivityManager", "default service = " + am);
}
return am;
}
};
3)Android中的IPC
- 3.1)Bundle (Intent傳輸)
- 3.2)文件共享(參考上面序列化與反序列化)
- 3.3)Messenger(輕量級IPC方案)
參考資料
簡單說Binder!
《Android開發藝術探索》筆記
郭霖Service AIDL
Android Binder機制原理(史上最強理解,沒有之一)
寫給 Android 應用工程師的 Binder 原理剖析`