Android-Binder 简析

it2022-05-05  129

前言

对于Android来说,Binder的重要性怎么说都不为过。不管是我们的四大组件Activity、Service、BroadcastReceiver、ContentProvider,还是经常在应用中使用到的各种ServiceManager,其背后都是Binder在支撑。然而Binder机制又不是三言两语能够描述得清楚的,因此本文通过对一个简单的AIDL Demo进行分析,让读者对Binder有个初步的认识,要想深入了解Binder背后的原理,可以参考最后的延伸阅读。

Demo

首先我们通过AIDL新建一个跨进程通信的Demo,然后在代码中简单分析Binder的运行过程。

Server Module

我们先新建一个提供接口的AIDL服务端module,服务端主要提供AddBook和getBookList两个功能,其目录如下:

p2.png

IBookManager.AIDL

// IAIDLServer.aidl package com.nancyyihao.aidlserver; import com.nancyyihao.aidlserver.Book; // Declare any non-default types here with import statements interface IBookManager { List<Book> getBookList(); void addBook(in Book book); }

Book.java

package com.nancyyihao.aidlserver; import android.os.Parcel; import android.os.Parcelable; /** * Created by jumper on 2016/9/7. */ public class Book implements Parcelable { private String bookName; private int bookId; public Book(){} public Book(int bookId, String bookName){ this.bookId = bookId ; this.bookName = bookName ; } public Book(Parcel parcel){ bookName = parcel.readString(); bookId = parcel.readInt(); } public String getBookName() { return bookName; } public void setBookName(String bookName) { this.bookName = bookName; } public int getBookId() { return bookId; } public void setBookId(int bookId) { this.bookId = bookId; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(bookName); dest.writeInt(bookId); } public static final Parcelable.Creator<Book> CREATOR = new Creator<Book>(){ @Override public Book createFromParcel(Parcel source) { return new Book(source); } @Override public Book[] newArray(int size) { return new Book[size]; } }; }

Book.AIDL

package com.nancyyihao.aidlserver; parcelable Book;

BookManagerService

package com.nancyyihao.aidlserver; import android.app.Service; import android.content.Intent; import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; /** * Created by jumper on 2016/9/7. */ public class BookManagerService extends Service { private static final String TAG = "BMS"; private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<>(); @Override public IBinder onBind(Intent intent) { return mBinder; } @Override public void onCreate() { super.onCreate(); // to distinguish with client module, we set the book id different from client module mBookList.add(new Book(3,"Android")); mBookList.add(new Book(4,"iOS")); } 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); } } ; }

Client Module

把Server module的代码拷贝一份(AIDL包名不能变),然后新建一个MainActivity即可

MainActivity

package com.nancyyihao.aidlserver; import android.content.ComponentName; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.support.v7.app.AppCompatActivity; import android.util.Log; import com.nancyyihao.R; import java.util.List; public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { IBookManager bookManager = IBookManager.Stub.asInterface(service); Log.e("trace", "onServiceConnected"); try { List<Book> bookList = bookManager.getBookList(); Log.e(TAG, "query book list, list type:" + bookList.getClass().getCanonicalName()); Log.e(TAG, "query book list:" + bookList.toString()); } catch (Exception e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final Intent intent = new Intent(); intent.setAction("com.nancyyihao.startservice"); intent.setPackage("com.nancyyihao.aidlserver"); // server's package name Log.e("trace", "bindService"); bindService(intent, mConnection, BIND_AUTO_CREATE); } @Override protected void onDestroy() { super.onDestroy(); unbindService(mConnection); } }

分析

把代码写好后,build一下,就能看到自动生成了一个IBookManager.Java文件

IBookManager.Java

p3.png

package com.nancyyihao.aidlserver; // Declare any non-default types here with import statements public interface IBookManager extends android.os.IInterface { /** * Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements com.nancyyihao.aidlserver.IBookManager { private static final java.lang.String DESCRIPTOR = "com.nancyyihao.aidlserver.IBookManager"; // Binder Indentifier public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an com.nancyyihao.aidlserver.IBookManager interface, * generating a proxy if needed. */ public static com.nancyyihao.aidlserver.IBookManager asInterface(android.os.IBinder obj) { if ((obj == null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin != null) && (iin instanceof com.nancyyihao.aidlserver.IBookManager))) { return ((com.nancyyihao.aidlserver.IBookManager) iin); // local Binder } return new com.nancyyihao.aidlserver.IBookManager.Stub.Proxy(obj); // remote Binder } @Override public android.os.IBinder asBinder() { return this; } @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_getBookList: { data.enforceInterface(DESCRIPTOR); java.util.List<com.nancyyihao.aidlserver.Book> _result = this.getBookList(); reply.writeNoException(); reply.writeTypedList(_result); return true; } case TRANSACTION_addBook: { data.enforceInterface(DESCRIPTOR); com.nancyyihao.aidlserver.Book _arg0; if ((0 != data.readInt())) { _arg0 = com.nancyyihao.aidlserver.Book.CREATOR.createFromParcel(data); } else { _arg0 = null; } this.addBook(_arg0); reply.writeNoException(); return true; } } return super.onTransact(code, data, reply, flags); } private static class Proxy implements com.nancyyihao.aidlserver.IBookManager { 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; } @Override public java.util.List<com.nancyyihao.aidlserver.Book> getBookList() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); java.util.List<com.nancyyihao.aidlserver.Book> _result; try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0); _reply.readException(); _result = _reply.createTypedArrayList(com.nancyyihao.aidlserver.Book.CREATOR); } finally { _reply.recycle(); _data.recycle(); } return _result; } @Override public void addBook(com.nancyyihao.aidlserver.Book book) 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 ((book != null)) { _data.writeInt(1); book.writeToParcel(_data, 0); } else { _data.writeInt(0); } mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } } static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); } public java.util.List<com.nancyyihao.aidlserver.Book> getBookList() throws android.os.RemoteException; public void addBook(com.nancyyihao.aidlserver.Book book) throws android.os.RemoteException; }

Client先调用bindService启动服务,会调用BookManagerService的onCreate方法,接着调用onBind方法,该方法会返回远程的Binder---mBinder,该Binder包含getBookList和AddBook两个方法的具体实现。

@Override public IBinder onBind(Intent intent) { return mBinder; } 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); } } ;

当Client和server成功建立连接时,就会调用Client的onServiceConnected(name, service)方法把远程的mBinder回调给Client,此时的service就是远程的mBinder对象

private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { IBookManager bookManager = IBookManager.Stub.asInterface(service); Log.e("trace", "onServiceConnected"); try { List<Book> bookList = bookManager.getBookList(); } catch (Exception e) { e.printStackTrace(); } }

Client端通过asInterface方法把mBinder转成AIDL接口,如果是本进程内的Binder就直接返回,否则返回内部代理类proxy

public static com.nancyyihao.aidlserver.IBookManager asInterface(android.os.IBinder obj) { if ((obj == null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin != null) && (iin instanceof com.nancyyihao.aidlserver.IBookManager))) { return ((com.nancyyihao.aidlserver.IBookManager) iin); // local Binder } return new com.nancyyihao.aidlserver.IBookManager.Stub.Proxy(obj); // remote Binder }

接着执行

try { List<Book> bookList = bookManager.getBookList(); } catch (Exception e) { e.printStackTrace(); }

此时的bookManager通过asInterface方法转换后,返回的实际上是本地的proxy类

private static class Proxy implements com.nancyyihao.aidlserver.IBookManager { 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; } @Override public java.util.List<com.nancyyihao.aidlserver.Book> getBookList() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); java.util.List<com.nancyyihao.aidlserver.Book> _result; try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0); _reply.readException(); _result = _reply.createTypedArrayList(com.nancyyihao.aidlserver.Book.CREATOR); } finally { _reply.recycle(); _data.recycle(); } return _result; } @Override public void addBook(com.nancyyihao.aidlserver.Book book) 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 ((book != null)) { _data.writeInt(1); book.writeToParcel(_data, 0); } else { _data.writeInt(0); } mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } } static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); }

通过代码我们可以看到proxy类其实也是一个IBookManager接口,调用bookManager.getBookList()其实是调用Proxy.getBookList。

@Override public java.util.List<com.nancyyihao.aidlserver.Book> getBookList() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); java.util.List<com.nancyyihao.aidlserver.Book> _result; try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0); _reply.readException(); _result = _reply.createTypedArrayList(com.nancyyihao.aidlserver.Book.CREATOR); } finally { _reply.recycle(); _data.recycle(); } return _result; }

在Proxy.getBookList方法中调用了mRemote.trasact()

public final boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { if (false) Log.v("Binder", "Transact: " + code + " to " + this); if (data != null) { data.setDataPosition(0); } boolean r = onTransact(code, data, reply, flags); if (reply != null) { reply.setDataPosition(0); } return r; }

Client就是在这里和Server进行远程通信的!把需要的参数放data中,服务端执行完后把接口写到result里。从代码中可以看到transact方法中调用了onTransact方法。我们再看看onTransact方法有啥东西。

@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { ...... case TRANSACTION_getBookList: { data.enforceInterface(DESCRIPTOR); java.util.List<com.nancyyihao.aidlserver.Book> _result = this.getBookList(); reply.writeNoException(); reply.writeTypedList(_result); return true; } ...... }

直接调用了this.getBookList方法返回结果,这个this到底是哪个对象?前面提到mRemote其实是远程中的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); } } ;

this.getBookList其实就是mRemote.getBookList,就是上面代码中的mBinder.getBookList!然后把返回结果放到result中即可。至此,整个通信过程分析完毕。

总结

Client是通过本地的Proxy类像Server发起通信

Client通过ServerConnection接口回调收到Server远程Binder对象

IPC过程发生在transact方法中,该方法会挂起直到服务端返回结果,因此不能在主线程调用远程服务。

p1.jpg

图片和文中Demo来自《Android开发技术探索》

源码下载

Android-AIDL-Demo

延伸阅读

Binder学习指南

Android Bander设计与实现 - 设计篇

Android进程间通信(IPC)机制Binder简要介绍和学习计划

转载于:https://www.cnblogs.com/jasonkent27/p/5860680.html


最新回复(0)