IPC通信机制理解
⼀个⽉以前,就把IPC看完了,但是这⼏天看到Window这⼀块和Activity的启动过程以后,就发现ipc⽤的地⽅太多了,没办法,⼜回来复习了⼀遍,并做了⼀点笔记。
《android技术开发探索》
多进程:
在Menifest⽂件中给组件指定android:process属性,有两种情况,1进程名为“ample.ipcdemo:remote”这是当前应⽤的私有进程,其他应⽤的组件不可以和他跑在同⼀个进程中。2 进程名为“”则属于全局进程,其他应⽤通过ShareUID ⽅式就可以和他跑在同⼀个进程中了(前提是两个应⽤的ShareUID相同并且签名也得相同),这样就可以互相访问对⽅的私有数据、组件信息。
android为每⼀个进程分配了⼀个独⽴的虚拟机,不同的虚拟机在内存上有不同的地址空间,这就导致了不同的虚拟机在访问同⼀个类的对象会拆⽣多份副本。⼀般来说,多进程会造成如下⼏⽅⾯的问题;
静态成员和单例模式完全失效
线程同步机制完全失效
SharedPreferences的可靠性下降
Application会多次创建
序列化:
Serializable接⼝(java提供的)和Parcelable接⼝(android⾃带的)
Serializable需要提供⼀个serialVersionUID,这是为了反序列化可以被成功
Serializable接⼝:
静态变量不会参与序列化过程,因为他属于类⽽不是对象
⽤transient关键字标记的成员变量不参与序列化过程。
Parcelable接⼝:
只要实现这个接⼝,⼀个类的对象就可以实现序列化并可以通过Intent和Binder传递了
两者都可以进⾏Intent间的数据传输,Serializeable主要⽤于存储设备和⽹络传输,⽽Praceable主要⽤于内存上。
声明⼀个aidl接⼝,他会⾃动给你⽣成⼀个java类,在java类中,有⼏个⽅法⽐较重要:
asInterface()将服务端Binder对象转化成客户端所需要的AIDL接⼝类型的对象,如果是本进程就返回服务端Stub本⾝,否则返回
Stub.proxy对象
asBinder:此⽅法⽤于返回Binder对象。进程通信方式
onTransact:这个⽅法运⾏在服务端的Binder线程池中,当客户端发起请求时,远程请求通过系统底层封装后交由此⽅法来处理。服务端通过code确定客户端所请求的⽬标⽅法是什么?接着从data取出⽬标参数,然后执⾏⽬标⽅法,执⾏完毕,如果有返回值就想reply中写⼊返回值。
proxy#getBookList: 这个⽅法运⾏在客户端,当客户端远程调⽤此⽅法时,它⾸先创建该⽅法所需要的输⼊性Parcel对象_data,输出型_reply 和返回值对象List,然后把参数写⼊_data中,接着调⽤transact⽅法来发起RPC(远程过程调⽤),transact⽅法都做些了什么呢?它其实是⼀个本地⽅法,他的实现在Native层,⾥⾯进⾏⼀系列的函数调⽤,最终调⽤了talkWithDriver函数,通信过程交给了驱动来完成,这个函数通过ioctl系统调⽤,Client陷⼊了内核态,同时将当前线程挂起。驱动完成⼀系列的操作之后唤醒Server进程,然后服务端的onTransact⽅法会被调
⽤,这个⽅法将结果返回给驱动,驱动将唤醒挂起的Client进程,当前线程继续执⾏,并从_reply 中取出结果。
————————————————————————————
⽹上的博客:
进程隔离:为了保护操作系统进程互不⼲扰⽽设计的⼀组不同硬件和软件的技术。为了避免进程A写⼊进程B的情况发⽣。
⽤户空间/内核控件:
Kernel是⼀个⾼安全级别的东西,所以⽤户代码⼀般是不能访问Kernel的,⼀般的解决⽅案都是系统调⽤,通过⼀个统⼀的⼊⼝接⼝,所有的资源访问都是在内核控制下执⾏的。当⼀个任务执⾏系统调⽤⽽陷⼊内核代码时,我们就称为进程处于内核态。
内核模块/驱动:
Linux的动态可加载模块(Loadable Kernel Module)解决这个问题,模块是具有独⽴功能的程序,它可以被单独编译,但是不能被独⽴运⾏。它在运⾏时被链接到内核作为的⼀部分在内核空间运⾏。这样,
android系统可以添加⼀个模块运⾏在内核空间,⽤户进程之间通过这个模块作为桥梁,就可以完成通信了。
在android系统中,运⾏在内空间的、负责各个⽤户进程间的通信通过Binder的内核模块叫做Binder驱动。(驱动⼀般是指设备驱动程序,是⼀种可以是计算机和设备通信的特殊程序)驱动就是操作硬件的接⼝,为了⽀持Binder通信过程,Binder使⽤了⼀种“硬件”,因此这个模块被称为驱动。
Binder通信模型:
假设A要给B打电话(相当于ClientA要和ServerB通信),肯定需要⼀个电话本(相当于ServiceManager)和⼀个(Binder驱动)。
进程A和进程B是如何通信的呢?内核可以访问A和B的所有数据,所以最简单的⽅式就是通过内核中专。先把A数据copy到内核,再从内核copy 到B中,⽤户空间要操作内和空间,就得需要系统调⽤,即copy_from_user,copy_to_user。
但是Binder不是这么⼲的!
⾸先,Server进程向SM(ServiceManager)注册,然后client向SM查询,需要⼀个Server,但是进程间的通信都要经过内核,即Binder驱动,它不会返回给client⼀个真实的object,⽽是⼀个objectProxy,它和真实的object有同样的功能,它唯⼀做的事情就是把参数包装然后交给驱动。然后驱动再把参数给真的Server,然后把结果返回来交给驱动,驱动给client。由于驱动返回的objectProxy太真实了,所以就有⼀种假象直接把Server进程⾥⾯的对象object传给了client进程,因此,我们可以说Binder对象是可以进⾏跨进程传递的对象。
由于SM和server不在⼀个进程⾥,所以Server进程向SM注册的过程也是跨进程通信,这⼉是暗箱操作;SM中存在的也是Client的代理,然后Client向SM查询的时候,驱动会返回Client另外⼀个代理,Server进程的对象只有⼀个,其他的都是他的代理。
⼀句话总结:client只不过是Server的代理,代理对象协助驱动完成了进程通信。
我们使⽤AIDL接⼝经常会碰到这些类,每个类代表什么?
IBinder:是⼀个接⼝,代表了⼀种跨进程的能⼒,只要实现了这个接⼝,就能将对象进⾏跨进程传输了,这是驱动底层⽀持的,数据流经过驱动的时候,驱动会⾃动识别IBinder类型的数据,从⽽完成不同进程Binder本地对象以及Binder代理对象的转换。
IInterface代表的是Server对象具有什么能⼒,具体的说,就是aidl⾥⾯的接⼝。
Binder和BinderProxy都继承IBinder,具有远程传输的能⼒,BinderProxy是Binder的⼀个内部类,在跨进程时,驱动会⾃动完成两个对象的转换。
编译⼯具会给我们⽣成⼀个Stub静态的内部类,它继承了Binder,说明是⼀个Binder本地对象,它实现了IInterface接⼝,说明他有远程server 承诺给client的能⼒。
我们在bind⼀个Service之后,在onServiceConnection的回调⾥⾯,就是通过asInterface⽅法拿到⼀个远程service的
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论