目录
- 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 原理剖析`