您的位置:首页 > 其它

IPC通讯 内部进程通信

2016-06-07 14:41 295 查看

IPC:进程间通讯、跨进程通信

android中的IPC方式

1.bundle

2.使用文件共享,两个进程通过读/写同一个文件完成数据的共享,使用对象流序列化到文件中,反序列化出来。

3.使用Messenger,通过它可以实现不同

4.使用AIDL方式

1.Messenger 实现IPC

原理:

进程间通过messenge(信使)完成数据的传输。底层是采用AIDL实现/binder实现。

建立两端 站 ,由信使携带 message 信息 进行传输。

1.客户端和服务端的通讯

Messenger 和 Message 都实现了Parcelable接口,都可以跨进程通信

通过Messenger 发送的Message对象,只能支持的载体是 what ,arg1,arg2,Bundle和replyTo .

服务端:
Messenger mMessenger = new Messenger(new ServerHander());

public static ServerHander extends Handler{
public void handlerMessage(Message msg){
switch(msg.what){
case 0:
`Log.i("messenger","client send to server :"+ msg.getData().getString("key").toString());
//Contants.FROM_SERVER 是msg.what,用来判断客户段接受的handler.msg.what .

Message ms = Message.obtai(null,Contants.FROM_SERVER);
Bundle data = new Bundle();
data.putString("key","server send to message : ;;;");

ms.setData(data);

try {
msg.replyTo.send(ms);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
`
break;
}
}

}

客户端:
`public Messenger msger = new Messenger(new MessengerHandler());

public class MessengerHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case Contant.FROM_SERVER:
Toast.makeText(MainActivity.this, msg.getData().get("key").toString(), 0).show();

break;
}
super.handleMessage(msg);
}
}

@Override
public void onClick(View v) {
// TODO Auto-generated method stub

// try {
// int add = binder.add(new Data(10, 20));
// btn.setText(add + "");
//
// } catch (RemoteException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }

// messenger ipc method
Message msg = Message.obtain(null, Contant.FROM_CLIENT);

Bundle data = new Bundle();
data.putString("key", "client send 的信息");
msg.setData(data);

//服务段要发送给客户端则需要将客户端的messenger传给服务端。
!!!!!!!!
msg.replyTo =msger;
try {
mMessenger.send(msg);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}


CopyOnWriteArrayList 支持并发读/写,不是ArrayList

ConCurrentHashMap

binder 机制

在服务端可能由于某些原因导致异常终止,这个时候我们到服务端的Binder连

接断裂,我们称之为 Binder死亡,
会导致我们的远程调用失效。这时我们需要重新连接

服务。


有两种方法:

1.geibinder设置DeathRecipient监听,当Binder死亡时,我们会收到binderDied方法的回调。在binderDied方法中我们可以重连远程服务,

2在onServiceDisconnected中重连远程服务。

区别:

onServiceDisconnected在ui线程被回调,而binderDied在binder线程池中回调。

也就是说 binderDied不能再主线程回调。

##实现客户端和服务端的观察者模式
- 当服务端的数据有新的内容的时候,通知客户端进行更新。
- 创建一个aidl接口,IOnNewDataReviceListener 定义一个onNewDataRevice
- ( Data data) 方法  ,用来新数据添加到服务端时,实现通知客户端
- 在IDataManager.aidl中声明两个方法;registerListener
- (IOnNewDataReviceListener  listener)和unRegisterListener
- (IOnNewDataReviceListener listener);
-在service类中 定义 IDataManager.stub的子类,重写几个方法,onBind()返回该子类的实例。

- 客户端创建的时候,要将IOnNewDataReviceListener监听注册到服务器中。
- 退出时要解除注册。
- 服务端当有新数据时,会回调客户端的IOnNewDataReviceListener中的
- onNewDataRevice(Data data)方法。但是这个方法是在客户端的binder线程池
- 中运行的,因此,为了方便ui操作,我们将用一个Handler 可以切换到可以护
- 短的主线程进行操作。

- 进行客户端的解注册时,binder会将客户端传递过来的对象重新转换成一个
- 新对象。服务端接收到客户端的对象是新的一个对象,所以就不能解注册。
-RemoteCallbackList<E extends  IInterface> 类  ,使系统专门用于跨进程删除
Listener的接口,支持管理任意的aidl接口
原理:内部是一个Map结构专门用来保存aidl接口,它的key是IBinder类型,value是Callback类型。
key的值:IBinder key = listener.asBinder();
value的值:Callback value  = new Callback(listener,cookie);

多次跨进程传递对象在服务端生成一个不同的对象,但是这些新生成的对象有
一个共同点就是,他们使用的底层binder是同一个binder,所以当客户端解注
册的时候,只需要遍历服务端的所有的Listener,找到和解注册listener相同
binder的listener,移除掉就可以了,这就是remoteCallbackList为我们做的。
- 同时RemoteCallbackList还有一个很好用的功能,就是当客户端终止进程时,
- 它能自动的移除客户端注册的listener,并且,它实现了多线程同步机制。我
- 们不需要进行额外的线程同步工作。

客户端调用远程服务端的方法时,,被调用的方法是在服务端的binder线程池
执行的,客户端的程序挂起,等待服务端的方法返回信息。如果服务端的方法
是一个比较耗时的操作,那么,客户端就会长时间的阻塞在这里,如果客户端
是主线程的话就会导致ANR,因为onServiceConnected 和
onServiceDisconnected 方法都是运行在主线程中的。
因为服务端本身就是运行在服务端的Binder线程池中,所以服务端的方法可以
执行大量的好事操作,这个时候.就要避免在服务端方法中开线程执行异步任
务,除非明确知道自己在干什么,否则不建议做。

##Aidl的  给服务加上权限验证功能
权限验证失败无法调用服务的方法。

- 1 可以在onBind()中进行验证,验证不通过就返回null,这样验证失败客户端直接无法绑定服务。验证方式有多种,如。permission验证
- 1.先在 AndroidMenifest中声明所需的权限,如:
> <permission

>android:name = "com.mrk.myqqq.permission.ACCESS_MY_SERVICE"

>android:protextionLevel = "normal" />
- 定义了之后就可以在我们的Service中的onBinde()方法中做权限验证。
>{
>
>int check  = checkCallingOrSelfPermission("com.mrk.myqqq.permission.ACCESS_MY_SERVICE"");

>if(check == PackageManager.PERMISSION_DENIED){
>
>.return null;
>
>}

>return mBinder;

}
- 客户端只有在menifest文件中写入权限即可

><uses-permission android : name = "com.mrk.myqqq.permission.ACCESS_MY_SERVICE";

- 2 可以在服务端的onTransact方法中进行权限验证,如果验证失败返回false;这样服务端就不会终止执行AIDL中的方法从而达到保护服务端的效果。
- 可以采用permission验证
- 采用Uid和Pid来做验证。
>通过getCallingUid()和getCallingPid()可以拿到客户端所属的Uid 和Pid,通过这两个参数我们可以做一些验证的工作

服务端获取包名。
> String name  = null;

> String[] packages = getPackageManager().getPackagesForUid(getCallingUid());

>if(package != null && packages.length>0){

>packageName = packages[0];

>}

>if(!packageName.startsWith("com.mrk")){
>return false;}

>return super.onTransact(code,data,reply,flags);
>


ContentProvider

- 是android中提供的专门用于不同应用间进行数据共享的方式,从这一点来看,它
- 天生就是和进程间通信。和Messenger一样,contentProvider的底层实现同样也
- 是Binder,由此可见,Binder在Android系统中是何等的重要。


继承ContentProvider类实现6个抽象方法。

注册这个类,必须要声明android:authorities的标识,这是contentProvider的唯一标识.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: