本文基于《Android艺术探索》中知识的总结而创
1 简介
1.1 简述
IPC 进程间通讯或跨进程通讯
- android中IPC方式 Binder(AIDL)、Socket、Bundle、文件共享、Messenger、ContentProvider
- IPC的基础场景是多进程:一般由两种,应用内多进程模式,应用间数据共享
1.2 进程与线程
- 线程是cpu调度的最小单位,是一种有限的系统资源
- 进程指一个执行单元,是一个独立的应用或者程序
- 一个进程可包含多个线程
- ANR 主线程无响应,以多线程解决
2 多进程模式
2.1 开启
- 一般只有一种方法 就是在AndroidMenifest文件中给四大组件指定android:process属性。
当然也可以通过JNI的natice层去fork。但是很少这么玩- 查看当前进程的命令:adb shell ps | grep com.gjg.text
- 进程名以":"开头的进程属于应用的私有进程,其它应用的组件不可以和它泡在同一个进程中,非":"开头的进程属于全局进程,其它应用可以要通过ShareUID方式(ShareUID相同且签名相同)和它跑在同一个进程中。
2.2 多进程模式运行机制
不同的进程有独立的虚拟机,Applicaition以及内存空间,所以开启了多进程模式的应用应注意一下问题:
1 静态成员和单利模式完全失效
2 线程同步机制完全失效
3 SharedPreferences的可靠性下降
4 Application会多次创建
3 IPC基础载体
3.1 Serializable
- serialVersionUID:用来辅助序列化和反序列化过程的,原则上序列化后的数据中的serialVersionUID只有和当前类的serialVersionUID相同才能够被正常的反序列化。
- 系统默认用hash值作为serialVersionUID,当变量数和类型改变时,hash会变化,所以系统默认情况下这种改变发生时反序列化会crash
public class User implements Serializable{
}
//序列化过程
User user = new User();
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("cache.txt"));
out.writeObject(user);
out.close();
//反序列化过程
ObjectInputStream in = new ObjectInputStream(new FileInputStream("cache.txt"));
User user = (User)in.readObject();
in.close();
3.2 Parcelable
public class User implements Parcelable{
private String name;
private int age;
public User() {
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
//反序列化
protected User(Parcel in) {
name = in.readString();
age = in.readInt();
}
//用于反序列化的创建器
public static final Creator<User> CREATOR = new Creator<User>() {
//从序列化的数据中创建原始对象
@Override
public User createFromParcel(Parcel in) {
return new User(in);
}
//创建指定长度的原始对象数组
@Override
public User[] newArray(int size) {
return new User[size];
}
};
/**
* 返回当前对象的内容描述
* 如果含有文件描述符,返回1(CONTENTS_FILE_DESCRIPTOR),否则返回0
* 多数都返回0
* @return
*/
@Override
public int describeContents() {
return 0;
}
/**
* 序列化操作
* @param dest
* @param flags
* 当为1(PARCELABLE_WRITE_RETURN_VALUE) 标示当前对象需要作为返回值返回,不能立即释放资源
* 几乎所有情况都为0
*/
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeInt(age);
}
/**
* Parcel
* 内部包装了可序列化的数据的native操作,例如
* @FastNative
* private static native void nativeWriteInt(long nativePtr, int val);
* @FastNative
* private static native void nativeWriteLong(long nativePtr, long val);
*/
}
- Serializabble 是java中的序列化接口,使用简单但开销大,序列化和反序列化过程需要大量IO操作,适用于序列化到设备或者网络传输中
- Parcelable 是android 中的序列化方式,使用麻烦但是效率高,主要用于内存序列化上。
3.3 Binder
(1)Binder 继承在IBinder。是IPC的框进程通讯方式
(2)还可以理解为一种虚拟的物理设备
(3)从android framework层来说Binder是ServiceManager连接各种Manager(ActivityManager WindowManager)和响应ManagerService的桥梁。
(4)从android 应用层来说是客户端和服务端进行通讯的媒介。当bindService时,返回段会返回一个包含服务端业务调用的Binder对象。
AIDL创建及核心源码解析
创建AIDL文件
//1.创建User.java 同上
//2.创建User在AIDL中的声明文件 User.aidl
package gjg.com.fundemo.dbg;
parcelable User;
//3.创建User的管理aidl文件
package gjg.com.fundemo.dbg;
//这里要注意使用全包名,且User有对应的User.aidl文件,否则会提示找不到
//aidl只支持方法生命,不支持静态变量
import gjg.com.fundemo.dbg.User;
interface IUserManager {
List<User> getUserList();
/**
* in 输入型参数
* out 输出型参数
* inout 输入输出型参数
*/
void addUser(in User user);
}
//4.重新编译后系统会生成IUserManager.java
package gjg.com.fundemo.dbg;
public interface IUserManager extends android.os.IInterface {
/**
* 集成Binder 实现了IUserManager接口本身
* 这是个抽象方法,并没有实现IUserManager具体方法,需要在服务端自定义Binder时实现
* 一般在服务端继承自改抽象类,并在onBind中返回其实现
*/
public static abstract class Stub extends android.os.Binder implements gjg.com.fundemo.dbg.IUserManager {
//Binder的唯一标示
private static final java.lang.String DESCRIPTOR = "gjg.com.fundemo.dbg.IUserManager";
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* 用于将服务端的Binder对象转换成客户端所需的AIDL接口类型的对象
*/
public static gjg.com.fundemo.dbg.IUserManager asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
//如果客户端和服务端在同一进程,返回的就是服务端的Stub对象本身Stub.Proxy对象
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof gjg.com.fundemo.dbg.IUserManager))) {
return ((gjg.com.fundemo.dbg.IUserManager) iin);
}
//如果客户端和服务端不在同一进程,返回的是封装后的
return new gjg.com.fundemo.dbg.IUserManager.Stub.Proxy(obj);
}
/**
* 用于返回当前Binder对象,在IInterface中定义的
*/
@Override
public android.os.IBinder asBinder() {
return this;
}
/**
* 该方法运行在服务端中Binder线程池中
* 当客户端发起请求时,远程请求会通过系统底层封装后交由此方法来处理
* 只有跨进程时才会调用此方法
* @param code
* 服务端通过code可以确定所请求的目标方法
* @param data
* data中存有目标方法所需的参数
* @param reply
* 当目标方法执行完后会将返回值写入reply中
* @param flags
* @return 返回false 证明客户端请求失败
* @throws android.os.RemoteException
*/
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_getUserList: {
data.enforceInterface(DESCRIPTOR);
//调用服务端方法得到返回值
java.util.List<gjg.com.fundemo.dbg.User> _result = this.getUserList();
reply.writeNoException();
//返回值写入reply
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addUser: {
data.enforceInterface(DESCRIPTOR);
gjg.com.fundemo.dbg.User _arg0;
if ((0 != data.readInt())) {
_arg0 = gjg.com.fundemo.dbg.User.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
//调用服务端方法得到返回值
this.addUser(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
/**
* 如果是跨进程通讯,该代理会被返回
*/
private static class Proxy implements gjg.com.fundemo.dbg.IUserManager {
//这个mRemote就是服务端继承自Stub的Binder对象
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
@Override
public android.os.IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor() {
return DESCRIPTOR;
}
//在客户端调用,最终会通过transact调服务端方法
@Override
public java.util.List<gjg.com.fundemo.dbg.User> getUserList() throws android.os.RemoteException {
//创建所需的输入型Parcel对象
android.os.Parcel _data = android.os.Parcel.obtain();
//创建输出型Parcel对象
android.os.Parcel _reply = android.os.Parcel.obtain();
//创建返回值对象
java.util.List<gjg.com.fundemo.dbg.User> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
//发起RPC(远程过程调用)请求,同时当前线程挂起
//transact被调用,知道RPC过程返回后,当前线程继续执行
//从reply中取出RPC过程的返回结果
mRemote.transact(Stub.TRANSACTION_getUserList, _data, _reply, 0);
_reply.readException();
//返回reply中的结果,反序列化,这里可以看出AIDL的对象需要细线parcelable接口
_result = _reply.createTypedArrayList(gjg.com.fundemo.dbg.User.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public void addUser(gjg.com.fundemo.dbg.User user) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((user != null)) {
_data.writeInt(1);
//将参数写入输出型parcel对象中
user.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_addUser, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_getUserList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_addUser = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
//接口的方法定义
public java.util.List<gjg.com.fundemo.dbg.User> getUserList() throws android.os.RemoteException;
//接口的方法定义
public void addUser(gjg.com.fundemo.dbg.User user) throws android.os.RemoteException;
}
// 5.给Binder设置死亡代理
// 当服务端Binder连接断裂时,客户端可以收到通知,一遍再次发起请求从而恢复连接的解决方案
//示例代码如下
//服务端Service
public class UserRemoteService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return binder;
}
//返回个客户端的Binder
IUserManager.Stub binder = new IUserManager.Stub() {
@Override
public List<User> getUserList() throws RemoteException {
return null;
}
@Override
public void addUser(User user) throws RemoteException {
}
};
}
public class UserTestActivity extends AppCompatActivity {
//客户端对IUserManager
private IUserManager mUserManager;
//服务端Binder死亡代理对象
private DeathRecipient mDeathRecipient = new DeathRecipient();
private ServiceConnection mSc = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//根据服务端Binder创建客户端IUserManager对象
mUserManager = IUserManager.Stub.asInterface(service);
try {
//绑定服务端Binder死亡代理
service.linkToDeath(mDeathRecipient,0);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = new Intent(this,UserRemoteService.class);
//绑定服务
bindService(intent,mSc,0);
if(mUserManager != null){
try {
List<User> users = mUserManager.getUserList();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
/**
* Binder死亡代理
* 一般在bindService中Connection后创建并设置
* IUserManager mServiceBinder = IUserManager.Stub.asInterface(binder);
* binder.linkToDeath(this,0);
*/
public class DeathRecipient implements IBinder.DeathRecipient {
//当Binder死亡是会回调此方法
@Override
public void binderDied() {
if(mUserManager == null){
return;
}
//解绑服务端Binder死亡代理对象
mUserManager.asBinder().unlinkToDeath(this,0);
mUserManager = null;
}
}
}
4 Android中的IPC方式
4.1 Bundle
Bundle implements Parcelable 所以可以方便的在不同进程进行通讯
4.2 使用文件共享
适合同步要求不高的进程间通讯
4.3 Messenger
是对AIDL的简单封装,以Message作为载体
4.4 AIDL
流程:
-->服务端创建AIDL文件,编译生成接口,服务端实现接口的.Stub返回
-->客户端绑定Service,绑定成功后,将服务端返回的Binder对象转成AIDL文件对应的接口对象
注意:
aidl文件中不是所有类型都支持,支持的类型如下:基本数据类型
String CharSequence
List-ArrayList,里面的每个元素必须被aidl支持,这里指服务端最终会返回ArrayList类型
Map-HashMap,里面的每个元素必须被aidl支持
Parcelable,所有实现了Parcelable接口的对象
AIDL:所有aidl接库本身也可以在aidl文件中使用
自定义的Parcelable对象,在aidl中使用时,必须新建一个和它同名的AIDL文件,并在其中生命它为parcleable类型。例如:
package com.gjg
parcelable User;
RemoteCallbackList
- 跨进程传输对象的最想都会经过反序列化,也就是说两端针对相同内容的对象却不是真正的同一个对象,所以就会导致跨进程解注册时会出现问题,而RemoteCallbackList就为解决此问题而生。
- RemoteCallbackList是专门提供的用于删除款进程listener的接口,它是一个泛型,支持管理任意的aidl接口,其声明如下:
public class RemoteCallbackList<E extends IInterface>
其本质就是利用了跨进程对象的相同对象在两端拥有相同的底层Binder对象
安全验证,在androidMenifest中声明,可在服务端onBind或者onTransact中进行验证是否有权限
4.5 ContentProvider
- 底层也是Binder机制
- 六个方法 onCreate() getType() CRUD
- CRUD 在Binder线程池
- android:authorities 声明 ContentResolver中Uri参数与之配对
- UriMatcher 实现外界访问的匹配功能
4.6 Socket
通过网络了。不光能跨进程,还能跨设备
5 Binder连接池
- 背景有很多aidl时不可能对应创建很多Service
- Binder连接池的作用就是将每个业务模块的Binder请求统一转发到远程的Service中去执行,从而避免重复创建Service的过程
//1. 创建两个简单aidl文件
package gjg.com.fundemo.binderchi;
interface ICompute {
int add(int a,int b);
}
package gjg.com.fundemo.binderchi;
interface ISecurityCenter {
String encrypt(String content);
String decrypt(String password);
}
//2. 创建aidl文件对应的实现
package gjg.com.fundemo.binderchi;
import android.os.RemoteException;
public class SecurityCenerImpl extends ISecurityCenter.Stub {
@Override
public String encrypt(String content) throws RemoteException {
return null;
}
@Override
public String decrypt(String password) throws RemoteException {
return null;
}
}
package gjg.com.fundemo.binderchi;
public class ComputeImpl extends ICompute.Stub {
@Override
public int add(int a, int b) throws RemoteException {
return 0;
}
}
//3. 创建IBinderPool的aidl文件
package gjg.com.fundemo.binderchi;
interface IBinderPool {
IBinder queryBinder(int binderCode);
}
//4. 创建IBinderPool的实现,作为BinderPool的内部类
public static class BinderPoolImpl extends IBinderPool.Stub{
@Override
public IBinder queryBinder(int binderCode) throws RemoteException {
IBinder binder = null;
switch (binderCode){
case BINDER_SECURITY_CENTER:
binder = new SecurityCenerImpl();
break;
case BINDER_COMPUTE:
binder = new ComputeImpl();
break;
}
return binder;
}
}
//5. 创建Binder连接池的Service
public class BinderPoolService extends Service {
private BinderPool.BinderPoolImpl mBinderPoolImpl = new BinderPool.BinderPoolImpl();
@Nullable
@Override
public IBinder onBind(Intent intent) {
//返回的是服务端的BinderPoolImpl
return mBinderPoolImpl;
}
}
// 6. 创建BinderPool
public class BinderPool {
public static final int BINDER_SECURITY_CENTER = 1;
public static final int BINDER_COMPUTE = 2;
private Context mContext;
private IBinderPool mBinderPool;
private static volatile BinderPool sInstance;
private CountDownLatch mCountDownLatch;//用于保证线程同步
private BinderPool(Context context){
this.mContext = context;
connectBinderPoolService();
}
public static BinderPool getsInstance(Context context){
if(sInstance == null){
synchronized (BinderPool.class){
sInstance = new BinderPool(context);
}
}
return sInstance;
}
public IBinder queryBinder(int binderCode){
IBinder iBinder = null;
if(mBinderPool != null){
try {
mBinderPool.queryBinder(binderCode);
} catch (RemoteException e) {
e.printStackTrace();
}
}
return iBinder;
}
private void connectBinderPoolService() {
mCountDownLatch = new CountDownLatch(1);
Intent service = new Intent(mContext,BinderPoolService.class);
mContext.bindService(service,mBinderPoolConnection,Context.BIND_AUTO_CREATE);
try {
mCountDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//连接
private ServiceConnection mBinderPoolConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mBinderPool = IBinderPool.Stub.asInterface(service);
try {
mBinderPool.asBinder().linkToDeath(mBinderPoolDeathRecipient,0);
} catch (RemoteException e) {
e.printStackTrace();
}
mCountDownLatch.countDown();
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
/**
* Binder死亡监控
*/
private IBinder.DeathRecipient mBinderPoolDeathRecipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
mBinderPool.asBinder().unlinkToDeath(mBinderPoolDeathRecipient,0);
mBinderPool = null;
connectBinderPoolService();
}
};
public static class BinderPoolImpl extends IBinderPool.Stub{
@Override
public IBinder queryBinder(int binderCode) throws RemoteException {
IBinder binder = null;
switch (binderCode){
case BINDER_SECURITY_CENTER:
binder = new SecurityCenerImpl();
break;
case BINDER_COMPUTE:
binder = new ComputeImpl();
break;
}
return binder;
}
}
}
// 7. 使用
public class BinderPoolTestActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
doWork();
}
private void doWork() {
BinderPool binderPool = BinderPool.getsInstance(this.getApplicationContext());
IBinder securityCenterBinder = binderPool.queryBinder(BinderPool.BINDER_SECURITY_CENTER);
ISecurityCenter securityCenter = SecurityCenerImpl.asInterface(securityCenterBinder);
try {
securityCenter.encrypt("");
} catch (RemoteException e) {
e.printStackTrace();
}
IBinder computeBinder = binderPool.queryBinder(BinderPool.BINDER_COMPUTE);
ICompute compute = ComputeImpl.asInterface(computeBinder);
try {
compute.add(1,2);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
网友评论