IPC(Inter-Process Communication) 跨进程通信
本节主要是熟悉Android IPC中的AIDL实现方式
导读: IPC -> Binder -> 示例 未包含对aidl创建规则的讲解,可以查看
一、任何一个操作系统都有对应的IPC机制
-
windows : 通过剪切版、管道、油槽(windows中最简单的一种进程间通信)等进行通信
-
Linux : 通过命名管道、共享内存、信号量(本质可以理解为数据操作锁) 等进行通信
-
Android : 并不是完全继承自Linux,通信方式一般优选Binder、Socket等等
二、Android Binder机制
-
Android的进程架构(每个Android进程都是独立的,由用户空间和内核空间组成)
设计优点:
-
稳定性、安全性高:每一个Android进程都拥有自己独立的虚拟地址空间,一方面可以限制其它进程访问自己的虚拟地址空间,另一方面,当一个进程崩溃时不至于牵连其它的进程
-
便于复用与管理:内核共享有助于系统维护和并发操作、节省空间
-
-
Binder机制优点
-
传输效率高、可操作性强
-
对于消息队列、Socket和管道而言,数据先从发送方的缓存区拷贝到内核开辟的缓存区中,再从内核缓存区拷贝到接收方的缓存区,一共拷贝两次
-
对于Binder来说,数据从发送方的缓存区拷贝到内核的缓存区,而接收方的缓存区与内核的缓存区是映射到一块物理地址的
-
-
实现C/S架构方便
-
Client和Server端相对独立、很稳定
-
-
安全性高
-
Binder机制为每个进程分配了UID/PID,且在Binder通信时会根据UID/PID进行检测
-
-
-
Binder定义了四个角色:Server、Client、ServiceManager和Binder驱动
-
其中Server、Client、ServiceManager运行于用户空间,Binder驱动运行于内核空间
-
ServiceManager工作流程 : Service在ServiceManager注册,然后Client通过Binder名字获取Binder实体引用或代理类
-
Binder驱动
-
与硬件设备没有关系,工作于内核态
-
提供open()、mmap()、poll()、ioctl()等标准文件操作
-
负责进程之间binder通信的建立、传递、计数管理以及数据的传递交互等底层支持
-
驱动和应用程序之间定义了一套接口协议,主要功能由ioctl()接口实现
-
代码位于linux目录的drivers/misc/binder.c中
-
-
-
Binder工作原理
-
-
transact方法和onTransact方法,可以通过自己编写aidl文件,然后ReBuild一下,然后去查看具体aidl生成的java源码,如接下来的IBookManagerService中的IBookManager类文件
-
三、 实现Binder进程通信,以书为例子,实现C端查看S端书籍,S端书籍增加时通知C端
通过AS新建AIDL文件会自动生成aidl文件夹,这里需要注意包名,尽量将所有aidl相关放在同一个包内
这里需要需要注意对象的跨进程传输实际是反序列化操作,具体代码内会标准,所以如果想要实现监听事件,通知Client,需要使用到Android自带的RemoteCallbackList类,毕竟跨进程传输底层的Binder对象是同一个
注意耗时操作,Server端操作的方法都是在服务端Binder线程池中,非UI线程,而onServiceConnected和onServiceDisconnected都是在UI线程中
-
Book.java
package aidldemo; public class Book implements Parcelable { public int bookId; public String bookName; public Book(int bookId,String bookName){ this.bookId = bookId; this.bookName = bookName; } protected Book(Parcel in) { bookId = in.readInt(); bookName = in.readString(); } public static final Creator<Book> CREATOR = new Creator<Book>() { @Override public Book createFromParcel(Parcel in) { return new Book(in); } @Override public Book[] newArray(int size) { return new Book[size]; } }; @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(bookId); dest.writeString(bookName); } @Override public String toString() { return "Book{" + "bookId=" + bookId + ", bookName='" + bookName + '\'' + '}'; } }
-
Book.aidl
package aidldemo; parcelable Book;
-
IBookManager.aidl
package aidldemo; // Declare any non-default types here with import statements import aidldemo.Book; import aidldemo.IOnNewArrivedListener; interface IBookManager { List<Book> getBookList(); void addBook(in Book book); //注册监听,主要是通知Client,更新书籍了 void registerListener(IOnNewArrivedListener listener); void unRegisterListener(IOnNewArrivedListener listener); }
-
IOnNewArrivedListener.aidl
import aidldemo.Book; //监听 interface IOnNewArrivedListener{ void onNewBookArrived(in Book newBook); }
-
BookManagerService.java Server端
public class BookManagerService extends Service { private static final String TAG = "XXXXXXXX"; private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<>(); private AtomicBoolean mIsServiceDestoryed = new AtomicBoolean(false); //private CopyOnWriteArrayList<IOnNewArrivedListener> mListener = new CopyOnWriteArrayList<>(); private RemoteCallbackList<IOnNewArrivedListener> mListener = new RemoteCallbackList<>(); private Binder mBind = new IBookManager.Stub() { @Override public List<Book> getBookList() throws RemoteException { return mBookList; } @Override public void addBook(Book book) throws RemoteException { mBookList.add(book); } @Override public void registerListener(IOnNewArrivedListener listener) throws RemoteException { mListener.register(listener); Log.d(TAG," BMS registerListener"); } @Override public void unRegisterListener(IOnNewArrivedListener listener) throws RemoteException { mListener.unregister(listener); Log.d(TAG,"BMS unRegisterListener"); } }; @Nullable @Override public IBinder onBind(Intent intent) { return mBind; } @Override public void onCreate() { super.onCreate(); mBookList.add(new Book(1, "Android")); mBookList.add(new Book(2, "IOS")); new Thread(new ServiceWork()).start(); } @Override public void onDestroy() { mIsServiceDestoryed.set(true); super.onDestroy(); } private void onNewBookArrived(Book book) throws RemoteException { mBookList.add(book); final int N = mListener.beginBroadcast();//和finishBroadcast成对出现,否则出错 for (int i = 0; i < N; ++i) { Log.d(TAG, "BMS OnNewBookArrived,notify listeners : "+i); IOnNewArrivedListener l = mListener.getBroadcastItem(i); if (l != null) { l.onNewBookArrived(book); } } mListener.finishBroadcast(); } private class ServiceWork implements Runnable { @Override public void run() { while (!mIsServiceDestoryed.get()) { try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } int bookId = mBookList.size() + 1; Book newBook = new Book(bookId, "new Book#" + bookId); try { onNewBookArrived(newBook); } catch (RemoteException e) { e.printStackTrace(); } } } } }
-
MainActivity.java Client端
public class MainActivity extends AppCompatActivity { private static final String TAG = "XXXXXXXX"; private static final int MESSAGE_NEW_BOOK_ARRIVED = 1; private IBookManager mRemoteBookManager; @SuppressLint("HandlerLeak") private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case MESSAGE_NEW_BOOK_ARRIVED: Log.d(TAG, "Client receive new book : " + msg.obj.toString()); break; default: super.handleMessage(msg); } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Intent intent = new Intent(this, BookManagerService.class); bindService(intent, conn, Context.BIND_AUTO_CREATE); } //这个listener是运行在客户端的Binder线程池里,操作UI需要注意 private IOnNewArrivedListener mBookArrivedListener = new IOnNewArrivedListener.Stub() { @Override public void onNewBookArrived(Book newBook) throws RemoteException { mHandler.obtainMessage(MESSAGE_NEW_BOOK_ARRIVED, newBook).sendToTarget(); } }; private ServiceConnection conn = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { //UI线程 IBookManager bookManager = IBookManager.Stub.asInterface(service); try { mRemoteBookManager = bookManager; List<Book> list = bookManager.getBookList(); Log.d(TAG, "Client query book list ,list type : " + list.getClass().getCanonicalName()); Log.d(TAG, list.toString()); bookManager.registerListener(mBookArrivedListener); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { } }; @Override protected void onDestroy() { if(mRemoteBookManager != null && mRemoteBookManager.asBinder().isBinderAlive()){ try { mRemoteBookManager.unRegisterListener(mBookArrivedListener); Log.d(TAG,"Client unRegisterListener"); } catch (RemoteException e) { e.printStackTrace(); } } unbindService(conn); super.onDestroy(); } }
四、注意在注册Service时,清单文件里process属性,要不然不是进程间通信。最后运行完事。