Android IPC机制
跨进程有多种方式:
- 基于Binder的AIDL、Messager、ContentProvider
- 能够携带Bundle的intent
- 跨进程文件共享
- 基于socket的网络通信
基于Binder的AIDL、Messager、ContentProvider
Binder的原理
我首先定义了Book.aidl、BookStoreInterface.aidl两个接口,先看下其结构:
public interface BookStoreInterface extends android.os.IInterface{
public static abstract class Stub extends android.os.Binder implements leo.com.bookstoredemo.BookStoreInterface
{
public Stub(){
this.attachInterface(this, DESCRIPTOR);
}
public static leo.com.bookstoredemo.BookStoreInterface asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof leo.com.bookstoredemo.BookStoreInterface))) {
return ((leo.com.bookstoredemo.BookStoreInterface)iin);
}
return new leo.com.bookstoredemo.BookStoreInterface.Stub.Proxy(obj);
}
public android.os.IBinder asBinder()
{
return this;
}
private static class Proxy implements leo.com.bookstoredemo.BookStoreInterface
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
public android.os.IBinder asBinder()
{
return mRemote;
}
public java.util.List<leo.com.bookstoredemo.Book> getBooks()
public void addBook(leo.com.bookstoredemo.Book book)
}
public java.util.List<leo.com.bookstoredemo.Book> getBooks() throws android.os.RemoteException;
public void addBook(leo.com.bookstoredemo.Book book) throws android.os.RemoteException
}
再加上一张结构图就更加清楚
image.png
整体流程是这样的:
客户端获取服务端的Stub.asInterface作为调用接口:
- 客户端服务端在不同进程,该接口实现为Stub.proxy代理对象;
- 客户端服务端在同一进程,该接口实现为Stub对象本身。
服务端的Stub就是具体服务实现类。
两端在不同进程的话,就通过Binder简建立持久连接。
暴露的方法会被编码为int类型的静态常量,客户端和服务端就通过方法code形参确认调用的是哪个方法。
proxy对象中的方法运行在客户端,当客户端调用某个function时候,代理中的_data获取方法参数(如果有),接着调用transact方法发起远程过程调用,同时当前线程挂起,服务端的OnTransact方法就会在服务端的Binder线程池中被调用,通过code确定目标方法,data获取方法参数,然后执行方法,完事后将结果存入reply中(如果有),如果该请求调用成功就返回true,否则就false,这个机制也可以用来做客户端权限验证。
然后客户端收到服务端的返回数据,当前线程继续执行,并从reply中获取返回值(如果有)。
这里注意服务端执行方法时候客户端线程是挂起状态,所以如果远端方法太耗时就不能在UI线程中发起远端请求。同时远端服务是一对多的状态,必须要处理好线程同步的问题。
image.png由上可知,当客户端和服务端在同一进程时候,方法调用不会走transact过程。
使用Messenger
理解成跨进程的handler,底层通过AIDL实现,服务端传送Binder,客户端获取后能够利用该Binder生成Messenger
https://www.jianshu.com/p/90330b9f0819
使用AIDL
https://www.jianshu.com/p/8c944d2284fd
注意并发同步时候使用List用CopyOnWriteArrayList、hashMap使用ConcurrentHashMap
? 如何实现定时任务循环执行
?连接挂了怎么办
?Binder线程原理是什么
ContentProvider
底层实现也是binder,onCreate, query, update, delete, insert, getType, 运行在contentProvider所在进程,除了onCreate是系统调用运行在主线程,其他的方法均由外界调用并运行在Binder线程池中。
外界对provider方法的调用会在不同线程中被执行,同时注意增删改查方法是支持多线程并发访问的,这点和AIDL服务端方法类似,需要手动控制好同步。
加锁?
如果被共享的数据是list和map使用CopyOnWriteList和ConcurrentHashMap就能实现自动同步
如果只有一个SQLiteDatabase就能自动同步数据,因为其内部对数据库的操作有同步处理,但是如果有多个SQLiteDatebase链接就不能保证同步。
能够携带Bundle的intent
使用bundle携带实现了ParceLable|Serializable接口的对象或者基本程序对象。使用这些数据启动其他组件,传递消息。
跨进程文件共享
Socket
有两种,流式套接字和用户数据包套接字,分别对应TCP和UDP,Socket本身支持传输任意字节流,注意不能在主线程中访问网络。当客户端连接时候就会生成一个新的socket,利用它可以和客户端通信
socket还能实现不同设备之间的通信(双方IP地址可见)。
? Binder机制到底是什么