从Activity的启动理解Binder通信

大学四年毕业以后就开始从事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更深入的文章。

*逆风的方向,更适合飞翔。*

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值