前言

对于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 statementsinterface 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;}@Overridepublic int describeContents() {return 0;}@Overridepublic void writeToParcel(Parcel dest, int flags) {dest.writeString(bookName);dest.writeInt(bookId);}public static final Parcelable.Creator<Book> CREATOR = new Creator<Book>(){@Overridepublic Book createFromParcel(Parcel source) {return new Book(source);}@Overridepublic 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<>();@Overridepublic IBinder onBind(Intent intent) {return mBinder;}@Overridepublic void onCreate() {super.onCreate();// to distinguish with client module, we set the book id different from client modulemBookList.add(new Book(3,"Android"));mBookList.add(new Book(4,"iOS"));}private Binder mBinder = new IBookManager.Stub() {@Overridepublic List<Book> getBookList() throws RemoteException {return mBookList;}@Overridepublic 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() {@Overridepublic 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();}}@Overridepublic void onServiceDisconnected(ComponentName name) {}};@Overrideprotected 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 nameLog.e("trace", "bindService");bindService(intent, mConnection, BIND_AUTO_CREATE);}@Overrideprotected 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 statementspublic 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 Indentifierpublic 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}@Overridepublic android.os.IBinder asBinder() {return this;}@Overridepublic 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;}@Overridepublic android.os.IBinder asBinder() {return mRemote;}public java.lang.String getInterfaceDescriptor() {return DESCRIPTOR;}@Overridepublic 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;}@Overridepublic 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两个方法的具体实现。

    @Overridepublic IBinder onBind(Intent intent) {return mBinder;}private Binder mBinder = new IBookManager.Stub() {@Overridepublic List<Book> getBookList() throws RemoteException {return mBookList;}@Overridepublic void addBook(Book book) throws RemoteException {mBookList.add(book);}} ;

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

private ServiceConnection mConnection = new ServiceConnection() {@Overridepublic 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;}@Overridepublic android.os.IBinder asBinder() {return mRemote;}public java.lang.String getInterfaceDescriptor() {return DESCRIPTOR;}@Overridepublic 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;}@Overridepublic 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。

 @Overridepublic 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方法有啥东西。

  @Overridepublic 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() {@Overridepublic List<Book> getBookList() throws RemoteException {return mBookList;}@Overridepublic 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

Android-Binder 简析相关推荐

  1. android:installLocation简析

    2019独角兽企业重金招聘Python工程师标准>>> 在Froyo(android 2.2,API Level:8)中引入了android:installLocation.通过设置 ...

  2. Android fota简析

    1.Fota升级方式: 整包\差分包,网络\SD卡 差分包:原理是根据算法把新旧两个版本之间的差别做成一个软件包 2.Fota应用升级的调用接口及reboot update的流程: 1.FotaAPK ...

  3. Android PhoneGap简析

    前言 (转自) 上周研究了一下PhoneGap这个技术,主要是对它的API和插件机制的学习,总体来看这种技术还是有一定的市场,特别是对BS为主的开发来讲确实有很多吸引,当然,这种技术也有严重的短板,比 ...

  4. Android okio简析

    前言 看了两天源码,云里雾里的,最终看到这篇blog,才清晰的了解了okio的脉络,能坚持看完肯定有收获. 自从Google官方将OkHttp作为底层的网络请求之后,作为OkHttp底层IO操作的Ok ...

  5. Android Handler与Looper原理简析

    一直感觉自己简直就是一个弱智,最近越来越感觉是这样了,真的希望自己有一天能够认同自己,认同自己. 本文转载于:https://juejin.im/post/59083d7fda2f60005d14ef ...

  6. Android开机启动流程简析

    Android开机启动流程简析 (一) 文章目录 Android开机启动流程简析 (一) 前言 一.开机启动的流程概述 二.Android的启动过程分析 (1).总体流程 init简述 Zygote简 ...

  7. 《Android多媒体应用开发实战详解:图像、音频、视频、2D和3D》——2.3节简析Android安装文件...

    本节书摘来自异步社区<Android多媒体应用开发实战详解:图像.音频.视频.2D和3D>一书中的第2章,第2.3节简析Android安装文件,作者 王石磊 , 吴峥,更多章节内容可以访问 ...

  8. 【Android源码分析】Android系统关键服务启动简析

    一.关于Android系统重要的进程 (1).init进程:init进程是Linux内核启动完成之后,启动的第一个用户进程,Android系统就是在这个进程的基础上启动起来的,进程pid为1.init ...

  9. android 勿扰模式代码结构简析

    勿扰模式代码结构简析 标签: 勿扰模式 2017-08-08 11:05  60人阅读  评论(0)  收藏  举报   分类: android(59)  版权声明:本文为博主原创文章,未经博主允许不 ...

  10. Qualcomm Android camera 架构简析及如何debug

    一. Camera模组(CCM)介绍: CCM一般包含四大件: 镜头(lens).传感器(sensor).软板(FPC).图像处理芯片(DSP):     Camera的成像原理可以简单概括如下: 1 ...

最新文章

  1. c语言中比较两个数组函数,输入两个数组,调用large函数比较,计数,输出统计结果...
  2. C语言里面%2d 意思
  3. android sqlite 怎么写入存储时间
  4. C++程序的执行过程
  5. C#使用Xamarin开发可移植移动应用(4.进阶篇MVVM双向绑定和命令绑定)附源码
  6. Github | 商汤出品-可在视频里追踪单个对象PySOT
  7. 关于GaussDB(DWS)的正则表达式知多少?人人都能看得懂的详解来了!
  8. mongodb查询文件服务器的数据,服务器端知识库mongodb基础篇
  9. 语音识别的原理_语音识别原理_语音识别原理框图 - 云+社区 - 腾讯云
  10. 海康linux 密码忘记,linux下调用海康sdk
  11. IDEA eclipse快捷键大全
  12. AVI视频文件编码格式不受支持0xc00d5212怎么解决?
  13. css文字向右对齐_css怎么设置右对齐?
  14. 在react中使用codemirror
  15. 问题:微信小程序开发之 --- app.js文件介绍
  16. 小程序map的自定义图标不显示问题
  17. VS Code + Latex + SumatraPDF 环境(实用)
  18. 简单解释op(面向过程procedure- oriented)与oo(面向对象object-oriented)
  19. linux 无法生成缩略图,Thinkphp3.2 Linux下缩略图生成失败
  20. 西电李航 操作系统课程笔记 day11 IO softwarelayer

热门文章

  1. 解决Sublime Text3莫名的中文乱码问题
  2. Android JNI入门第五篇——基本数据类型使用
  3. VS2008调试总结
  4. vector的初始化及常用操作
  5. ansys怎么删除线段_科学网—ansys常用命令 - 刘敬寿的博文
  6. json php 数组读写_PHP如何将数据写入JSON?
  7. python传文件给java_python使用简单http协议来传送文件
  8. pythonwhile循环love_input和while循环——Python编程从入门到实践
  9. 街机linux有安卓好吗,Ubuntu下用xmame玩街机游戏
  10. 浏览器各个属性的作用