您的位置:首页 > 移动开发 > Android开发

从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中查看关键代码

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更深入的文章。

*逆风的方向,更适合飞翔。*
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android Binder 通信 框架