IPC之AIDL
来源:互联网 发布:手机淘宝直通车在哪 编辑:程序博客网 时间:2024/06/05 18:30
Binder
Binder是Android中的一个类,继承了IBinder接口,是一种跨进程通信方式。
从Framework角度看:Binder是ServiceManager连接各种Manager(ActivityManager WindowManager等)和相应的ManagerService的桥梁;当bindService的时候,服务端会返回一个包含了服务端业务调用的Binder对象,通过该对象,客户端就可以获取服务端提供的服务或数据,这里的服务包括普通服务和基于AIDL的服务。
通过Service利用AIDL进行通信。
AIDL(Android Interface Definition Language)是一种接口定义语言,由于Android的每个进程都运行在独立的虚拟机中,所以进程之间通信会比较麻烦。我们可以利用AIDL将一个进程的数据拆分成Android系统可识别的数据单元,然后系统再重新将数据单元合成传递给另一个进程。这样就实现了进程间的通信。
实现功能:服务端有一个书库,客户端可以向服务端添加书本、查阅书目;服务端可以向注册了监听的客户端推送新书(客户端可以随时解除注册的监听)。在此基础上,服务端还会对客户端进行权限检查
创建 Book类实现Parcelable接口
只有实现了该接口才能在不同的进程间传递
创建Book.aidl
用于声明Book类
package cqupt.second.aidl;parcelable Book;
创建IOnNewBookArrivedListener.aidl
让客户端实现监听的接口package cqupt.second.aidl;import cqupt.second.aidl.Book;interface IOnNewBookArrivedListener { void onNewBookArrived(in Book newBook);}
创建IBookManager.aidl文件
暴露服务端的方法给客户端,暴露客户端的监听给服务端package cqupt.second.aidl;import cqupt.second.aidl.Book;import cqupt.second.aidl.IOnNewBookArrivedListener;interface IBookManager { List<Book> getBookList(); void addBook(in Book book); void registerListener(IOnNewBookArrivedListener listener); void unregisterListener(IOnNewBookArrivedListener listener);}
服务端的实现代码:
- 使用CopyOnWriteArrayList保存Book是因为其支持并发的读写
- RemoteCallbackList专门提供用于删除进程间listener的接口
- 权限检查:checkCallingOrSelfPermission
- 服务端和客户端如果是两个工程,则在Service的onBind方法中无法验证客户端的权限。原因是onBind方法并不是一个Binder调用,它运行在服务端的UI线程中,故在onBind中只能验证服务端的权限,然而这是没有意义的。推荐在onTransact方法中对客户端进行权限验证。
public class BookManagerServicec extends Service { private static final String TAG = "BookManagerServicec"; private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<>(); private RemoteCallbackList<IOnNewBookArrivedListener> mListeners = new RemoteCallbackList<>(); private AtomicBoolean isServicceDestoryed = new AtomicBoolean(false); @Nullable @Override public IBinder onBind(Intent intent) { //权限的检查,此处的不通过,直接不能完成绑定 int check = checkCallingOrSelfPermission("cqupt.second.permission.ACCESS_BOOK_SERVICE"); Log.d(TAG, "onbind check=" + check); if (check == PackageManager.PERMISSION_DENIED) { return null; } return mBinder; } @Override public void onCreate() { super.onCreate(); mBookList.add(new Book(1, "Android")); mBookList.add(new Book(2, "Ios")); mBookList.add(new Book(3, "Java")); new Thread(new ServiceWorker()).start(); } //Binder需要实现AIDL文件中的接口的方法,以便该Binder对象给客户端让客户端调用该方法 private Binder mBinder = 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(IOnNewBookArrivedListener listener) throws RemoteException { mListeners.register(listener); } //解除注册监听 @Override public void unregisterListener(IOnNewBookArrivedListener listener) throws RemoteException { mListeners.unregister(listener); } //设置权限的第二种方式。此处权限检测失败不会执行AIDL中的方法 @Override public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { int check = checkCallingOrSelfPermission("cqupt.second.permission.ACCESS_BOOK_SERVICE"); if (check == PackageManager.PERMISSION_DENIED) { return false; } String packageName = null; String[] packagesForUid = getPackageManager().getPackagesForUid(getCallingUid()); if (packagesForUid != null && packagesForUid.length > 0) { packageName = packagesForUid[0]; } if (!packageName.startsWith("cqupt.second")) { return false; } return super.onTransact(code, data, reply, flags); } }; //把新书发送给注册了监听的客户端 private void onNewBookArrived(Book book) throws RemoteException { mBookList.add(book); //注意RemoteCallbackList的使用方式 int i = mListeners.beginBroadcast(); for (int j = 0; j < i; j++) { IOnNewBookArrivedListener item = mListeners.getBroadcastItem(j); if (item != null) { item.onNewBookArrived(book); } } mListeners.finishBroadcast(); } //服务端模拟自动增加新书 private class ServiceWorker implements Runnable{ @Override public void run() { while (!isServicceDestoryed.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(); } } } } @Override public void onDestroy() { super.onDestroy(); isServicceDestoryed.set(true); }}客户端代码实现
public class BookManagerActivity extends AppCompatActivity { private static final String TAG = "BookManagerActivity"; private IBookManager remoteBookManager; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_book_manager); //在此方法中绑定远程服务 Intent intent = new Intent(this, BookManagerServicec.class); bindService(intent, mConnection, BIND_AUTO_CREATE); } private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { //通过IBookManager.Stub.asInterface(service)方法将服务器返回的Binder转换成AIDL接口 IBookManager bookManager = IBookManager.Stub.asInterface(service); //另一个AIDL接口 remoteBookManager = bookManager; try { //设置Binder死亡监听 remoteBookManager.asBinder().linkToDeath(mDeathRecipient, 0); List<Book> list = bookManager.getBookList(); Log.d(TAG, "query book list,list type:" + list.getClass().getCanonicalName()); Log.d(TAG, "query book list:" + list.toString()); Book book = new Book(4, "Android 开发艺术之旅"); bookManager.addBook(book); List<Book> newList = bookManager.getBookList(); Log.d(TAG, newList.toString()); //客户端注册监听到远程服务端 bookManager.registerListener(mOnNewBookArrivedListener); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { remoteBookManager = null; } }; //服务端有新书更新时回调客户端的此方法,该方法在客户端的Binder线程池中执行,需要更新UI则需要Handler private IOnNewBookArrivedListener mOnNewBookArrivedListener = new IOnNewBookArrivedListener.Stub() { @Override public void onNewBookArrived(Book newBook) throws RemoteException { Message message = new Message(); message.what = 1; message.obj = newBook; mHandler.sendMessage(message); } }; Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case 1: Log.d(TAG, "receive new book:" + msg.obj); break; } super.handleMessage(msg); } }; //设置死亡Binder死亡监听,如果死亡,重新绑定 private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() { @Override public void binderDied() { Log.d(TAG, "binder died. tname:" + Thread.currentThread().getName()); if (remoteBookManager == null) return; remoteBookManager.asBinder().unlinkToDeath(mDeathRecipient, 0); remoteBookManager = null; // TODO:这里重新绑定远程Service } }; @Override protected void onDestroy() { if (remoteBookManager != null && remoteBookManager.asBinder().isBinderAlive()) { try { remoteBookManager.unregisterListener(mOnNewBookArrivedListener); } catch (RemoteException e) { e.printStackTrace(); } } unbindService(mConnection); super.onDestroy(); }}权限设置
<permission android:name="cqupt.second.permission.ACCESS_BOOK_SERVICE" android:protectionLevel="normal" /><uses-permission android:name="cqupt.second.permission.ACCESS_BOOK_SERVICE"/>
系统会自动生成IBookManager.java文件,文件中的大致内容
- DESCRIPTOR:Binder的唯一标识
- asInterface:将服务端的Binder对象转换成客户端所需要的AIDL接口类型对象
- 服务端与客户端在同一进程:返回服务端的Stub对象本身
- 服务端与客户端不在同一进程:但会系统封装之后的Stub.proxy
- asBinder:返回当前Binder对象
- onTransact:运行在服务端的Binder线程池中,处理客户端的请求
- 方法原型: onTransact(int code, android.os.Parcel data,android.os.Parcel reply, int flags)
- code:服务端用于确定客户端请求的哪一个方法
- data:目标方法所需参数
- reply:目标方法的返回值
- 方法原型: onTransact(int code, android.os.Parcel data,android.os.Parcel reply, int flags)
- Proxy类中的getBookList():运行在客户端,内部实现如下:
- 创建该方法所需要的输入型对象、输出型对象、返回值对象
- 将该方法的参数写入输输入型对象
- 调用transact 方法发起远程过程调用RPC,同时当前线程被挂起
- 服务端调用onTransact 方法直到RPC结束,当前线程继续执行
- 从输出型对象中取出RPC过程的结果
- 返回输出型对象中的数据
阅读全文
0 0
- Android IPC之AIDL
- Android IPC 之AIDL
- Android IPC之AIDL
- IPC之AIDL简析
- Android IPC 之 AIDL
- IPC通信之AIDL
- IPC之AIDL
- Android IPC之AIDL
- IPC之AIDL(1)实现AIDL
- Android IPC之AIDL浅谈
- IPC机制之AIDL、Messenger
- IPC学习之AIDL小试牛刀
- IPC之AIDL&binder关系
- android IPC机制之 AIDL
- android进程间通信(IPC)之AIDL
- 【Android机制】IPC机制之AIDL
- Android IPC 之 AIDL(一)
- Android IPC 之 AIDL (二)
- JAVA 猜拳游戏
- HTML5概述
- 自己总结的eclipse快捷键
- AB1601的波特率注意事项
- 是的冯绍峰
- IPC之AIDL
- git具体使用中遇到的问题
- django学习2
- 详解android之activity的生命周期
- zb的生日
- 阈值化分割(二)OTSU法-附Python实现
- System
- Switch Game<开灯问题>关于n以内的完全平方数个数求解
- 谈一谈头文件引用(#include,#import,@import,@class)