从Activity的启动理解Binder通信
2016-08-18 11:38
543 查看
大学四年毕业以后就开始从事Android 软件开发,说好的我要一个人的毕业旅行也不得不因为很多的原因被搁置,正式进入公司从事了”挨踢”男的工作。不管怎样,毕竟兴趣就这个,开始好好工作吧。
随着对android的深入,很多疑惑也越来越多,比如framework怎么和android系统服务(system service)进行通信的,这就牵扯到android的通信机制了,即Binder(IPC)通信机制。
1.Binder的通信模型
Binder框架定义了四个角色:Server,Client,ServiceManager(以后简称SMgr)以及Binder驱动。其中Server,Client,SMgr运行于用户空间,驱动运行于内核空间。这四个角色的关系和互联网类似:Server是服务器,Client是客户终端,SMgr是域名服务器(DNS),驱动是路由器。
由于android初级开发者从Framework 层理解Binder通信原理会感觉十分困难,我也是慢慢从初级向中级前进,于是我做了一个简化的图这样便于大家的理解。
上图是从一个android Application启动activity来引出Binder的通信机制,下面我们随着源码一步一步的分析。
2.源码分析
首先给一个关于Application是怎么启动Activity的整体时序图,跟着时序图这样有助于源码步骤的理解。
当一个应用程序启动一个界面展示的时候依托的就是Activity,我们跟着时序图进入Activity中查看关键代码
当调用startActivity时候,实际上调用的是Instrumentation里面的execStartActivity()方法,于是我们继续跟踪代码;
紧接着调用ActivityManagerNative.getDefault().startActivity();那ActivityManagerNative.getDefault()这个对象到底是什么呢?我们继续跟踪源码可以知道原来是通过ServiceManager得到一个activity的服务,最后通过asInterface(b)返回一个IActivityManager 接口。
那我们接下来看看asInterface()方法里面做了什么
通过源码我们可以知道,原来返回的是一个ActivityManagerProxy类,这个类的作用就是实现Client 和Service之间通信的代理。那接下来继续跟踪ActivityManagerProxy发现他是IActivityManager 的实现类。
这里很关键的一句代码 mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);这个mRemote就是Binder对象了,就是通信的关键,在这重载transact();具体实现如下:
1.向服务端线程以消息机制发送调用信息;
2.挂起当前线程,等待服务端执行完毕发送通知(notify);
3.接到通知,继续客户端线程,并返回执行结果。
值得注意的是,客户端视乎直接调用服务端的Binder,而事实上是通过Binder驱动进行了中转,就存在两个Binder对象,一个是服务端的Binder对象,另一个是Binder驱动中的Binder对象,不同之处在于Binder驱动中的对象不会产生额外的线程。
同时要进行Binder的远程服务调用时,服务函数的参数要么是一个原子类,要么必须继承Parcel类,否则不会传递。而且传递的数据添加到包裹中和包裹返回的数据必须是有序的,这个顺序是服务端和客户端事先约定好的。
传递数据的插入过程:
从mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0)发送的消息START_ACTIVITY_TRANSACTION跟踪我可以知道服务端对数据的处理是在ActivityManagerNative类中
Binder的解析数据的方法是enforceInterface();而插入数据使用的writeInterfaceToken();最后通过消息机制调用startActivity()方法进入到ActivityManagerService,即system service;
这就是囫囵吞枣的Binder的分析,由于能力有限,后续会更加深入的去学习Binder(IPC)通信机制,个人觉得以Activity的启动流程来掌握Binder通信,这样更容易上手和接受,由于Binder通信在android初级开发者理解起来是最困难的,以此博客,记录自己的学习心得。后续会写对Binder更深入的文章。
*逆风的方向,更适合飞翔。*
随着对android的深入,很多疑惑也越来越多,比如framework怎么和android系统服务(system service)进行通信的,这就牵扯到android的通信机制了,即Binder(IPC)通信机制。
1.Binder的通信模型
Binder框架定义了四个角色:Server,Client,ServiceManager(以后简称SMgr)以及Binder驱动。其中Server,Client,SMgr运行于用户空间,驱动运行于内核空间。这四个角色的关系和互联网类似:Server是服务器,Client是客户终端,SMgr是域名服务器(DNS),驱动是路由器。
由于android初级开发者从Framework 层理解Binder通信原理会感觉十分困难,我也是慢慢从初级向中级前进,于是我做了一个简化的图这样便于大家的理解。
上图是从一个android Application启动activity来引出Binder的通信机制,下面我们随着源码一步一步的分析。
2.源码分析
首先给一个关于Application是怎么启动Activity的整体时序图,跟着时序图这样有助于源码步骤的理解。
当一个应用程序启动一个界面展示的时候依托的就是Activity,我们跟着时序图进入Activity中查看关键代码
public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) { if (mParent == null) { Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity( this, mMainThread.getApplicationThread(), mToken, this, intent, requestCode, options); if (ar != null) { mMainThread.sendActivityResult( mToken, mEmbeddedID, requestCode, ar.getResultCode(), ar.getResultData()); } //省略下面代码...... }
当调用startActivity时候,实际上调用的是Instrumentation里面的execStartActivity()方法,于是我们继续跟踪代码;
public ActivityResult execStartActivity( Context who, IBinder contextThread, IBinder token, Fragment target, Intent intent, int requestCode, Bundle options) { IApplicationThread whoThread = (IApplicationThread) contextThread; if (mActivityMonitors != null) { synchronized (mSync) { final int N = mActivityMonitors.size(); for (int i=0; i<N; i++) { final ActivityMonitor am = mActivityMonitors.get(i); if (am.match(who, null, intent)) { am.mHits++; if (am.isBlocking()) { return requestCode >= 0 ? am.getResult() : null; } break; } } } } try { intent.migrateExtraStreamToClipData(); intent.prepareToLeaveProcess(); int result = ActivityManagerNative.getDefault() .startActivity(whoThread, who.getBasePackageName(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target != null ? target.mWho : null, requestCode, 0, null, options); checkStartActivityResult(result, intent); } catch (RemoteException e) { } return null; }
紧接着调用ActivityManagerNative.getDefault().startActivity();那ActivityManagerNative.getDefault()这个对象到底是什么呢?我们继续跟踪源码可以知道原来是通过ServiceManager得到一个activity的服务,最后通过asInterface(b)返回一个IActivityManager 接口。
private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() { protected IActivityManager create() { IBinder b = ServiceManager.getService("activity"); if (false) { Log.v("ActivityManager", "default service binder = " + b); } IActivityManager am = asInterface(b); if (false) { Log.v("ActivityManager", "default service = " + am); } return am; } };
那我们接下来看看asInterface()方法里面做了什么
/** * Cast a Binder object into an activity manager interface, generating * a proxy if needed. */ static public IActivityManager asInterface(IBinder obj) { if (obj == null) { return null; } IActivityManager in = (IActivityManager)obj.queryLocalInterface(descriptor); if (in != null) { return in; } return new ActivityManagerProxy(obj); }
通过源码我们可以知道,原来返回的是一个ActivityManagerProxy类,这个类的作用就是实现Client 和Service之间通信的代理。那接下来继续跟踪ActivityManagerProxy发现他是IActivityManager 的实现类。
class ActivityManagerProxy implements IActivityManager { public ActivityManagerProxy(IBinder remote) { mRemote = remote; } public IBinder asBinder() { return mRemote; } public int startActivity(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeStrongBinder(caller != null ? caller.asBinder() : null); data.writeString(callingPackage); intent.writeToParcel(data, 0); data.writeString(resolvedType); data.writeStrongBinder(resultTo); data.writeString(resultWho); data.writeInt(requestCode); data.writeInt(startFlags); if (profilerInfo != null) { data.writeInt(1); profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE); } else { data.writeInt(0); } if (options != null) { data.writeInt(1); options.writeToParcel(data, 0); } else { data.writeInt(0); } mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);//重点代码 reply.readException(); int result = reply.readInt(); reply.recycle(); data.recycle(); return result; } ...... }
这里很关键的一句代码 mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);这个mRemote就是Binder对象了,就是通信的关键,在这重载transact();具体实现如下:
1.向服务端线程以消息机制发送调用信息;
2.挂起当前线程,等待服务端执行完毕发送通知(notify);
3.接到通知,继续客户端线程,并返回执行结果。
值得注意的是,客户端视乎直接调用服务端的Binder,而事实上是通过Binder驱动进行了中转,就存在两个Binder对象,一个是服务端的Binder对象,另一个是Binder驱动中的Binder对象,不同之处在于Binder驱动中的对象不会产生额外的线程。
同时要进行Binder的远程服务调用时,服务函数的参数要么是一个原子类,要么必须继承Parcel类,否则不会传递。而且传递的数据添加到包裹中和包裹返回的数据必须是有序的,这个顺序是服务端和客户端事先约定好的。
传递数据的插入过程:
Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeStrongBinder(caller != null ? caller.asBinder() : null); data.writeString(callingPackage); intent.writeToParcel(data, 0); data.writeString(resolvedType); data.writeStrongBinder(resultTo); data.writeString(resultWho); data.writeInt(requestCode); data.writeInt(startFlags);
从mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0)发送的消息START_ACTIVITY_TRANSACTION跟踪我可以知道服务端对数据的处理是在ActivityManagerNative类中
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { switch (code) { case START_ACTIVITY_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); IBinder b = data.readStrongBinder(); IApplicationThread app = ApplicationThreadNative.asInterface(b); String callingPackage = data.readString(); Intent intent = Intent.CREATOR.createFromParcel(data); String resolvedType = data.readString(); IBinder resultTo = data.readStrongBinder(); String resultWho = data.readString(); int requestCode = data.readInt(); int startFlags = data.readInt(); ProfilerInfo profilerInfo = data.readInt() != 0 ? ProfilerInfo.CREATOR.createFromParcel(data) : null; Bundle options = data.readInt() != 0 ? Bundle.CREATOR.createFromParcel(data) : null; int result = startActivity(app, callingPackage, intent, resolvedType, resultTo, resultWho, requestCode, startFlags, profilerInfo, options); reply.writeNoException(); reply.writeInt(result); return true; } ...... }
Binder的解析数据的方法是enforceInterface();而插入数据使用的writeInterfaceToken();最后通过消息机制调用startActivity()方法进入到ActivityManagerService,即system service;
@Override public int startActivity(IBinder whoThread, String callingPackage, Intent intent, String resolvedType, Bundle options) { checkCaller(); int callingUser = UserHandle.getCallingUserId(); TaskRecord tr; IApplicationThread appThread; synchronized (ActivityManagerService.this) { tr = recentTaskForIdLocked(mTaskId); if (tr == null) { throw new IllegalArgumentException("Unable to find task ID " + mTaskId); } appThread = ApplicationThreadNative.asInterface(whoThread); if (appThread == null) { throw new IllegalArgumentException("Bad app thread " + appThread); } } return mStackSupervisor.startActivityMayWait(appThread, -1, callingPackage, intent, resolvedType, null, null, null, null, 0, 0, null, null, null, options, callingUser, null, tr); }
这就是囫囵吞枣的Binder的分析,由于能力有限,后续会更加深入的去学习Binder(IPC)通信机制,个人觉得以Activity的启动流程来掌握Binder通信,这样更容易上手和接受,由于Binder通信在android初级开发者理解起来是最困难的,以此博客,记录自己的学习心得。后续会写对Binder更深入的文章。
*逆风的方向,更适合飞翔。*
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories