探索startActivity流程及在Activity间是如何传递Intent的


Android进阶之路系列:http://blog.csdn.net/column/details/16488.html


在activity中intent到底是怎么传递的,而且还可以跨进程甚至跨app来传递,下面我们从源码层面探索一下
从startActivity开始,源码如下:
@Override
public void startActivity(Intent intent) {
    this.startActivity(intent, null);
}

@Override
public void startActivity(Intent intent, @Nullable Bundle options) {
    if (options != null) {
        startActivityForResult(intent, -1, options);
    } else {
        startActivityForResult(intent, -1);
    }
}

调用到了startActivityForResult函数,源码如下:
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode) {
    startActivityForResult(intent, requestCode, null);
}

public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
        @Nullable Bundle options) {
    if (mParent == null) {
        options = transferSpringboardActivityOptions(options);
        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());
        }
        if (requestCode >= 0) {
            mStartedActivity = true;
        }

        cancelInputsAndStartExitTransition(options);
    } else {
        if (options != null) {
            mParent.startActivityFromChild(this, intent, requestCode, options);
        } else {
            mParent.startActivityFromChild(this, intent, requestCode);
        }
    }
}

可以看到如果有parent,那么调用parent的startActivityFromChild,没有直接进行处理。可以想象parent的 startActivityFromChild应该是同样的逻辑,有兴趣的可以去看看源码。
当没parent时则使用mInstrumentation的execStartActivity函数来处理, mInstrumentation是一个 Instrumentation对象,它的 execStartActivity源码如下:
public ActivityResult execStartActivity(
    Context who, IBinder contextThread, IBinder token, String 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
                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(who);
        int result = ActivityManagerNative.getDefault()
            .startActivity(whoThread, who.getBasePackageName(), intent,
                    intent.resolveTypeIfNeeded(who.getContentResolver()),
                    token, target, requestCode, 0, null, options);
        checkStartActivityResult(result, intent);
    } catch (RemoteException e) {
        throw new RuntimeException("Failure from system", e);
    }
    return null;
}

在最后几句代码可以看到调用了ActivityManagerNative.getDefault().startActivity, ActivityManagerNative.getDefault()会得到的一个 ActivityManagerProxy 对象( IActivityManager接口 ),这个类在 ActivityManagerNative中 ,它的 startActivity函数源码如下:
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;
}

在这个函数中将一系列信息包装到Parcel中(包括intent),然后调用了mRemote.transact函数。 同时,注意这里 transact的第一个参数传的是START_ACTIVITY_TRANSACTION,这是一个code,在下面会用到



这样我们就碰触到了IBinder机制, IBinder很多文章都分析过,这里根据我的理解大概简单讲一下。
IBinder机制主要实现在底层(c++),通过它来实现进程间的通信.
简单来说是一端作为service,另一端作为client(实际上都是service,只不过在不同的情况下角色不同,都可以转换)
(1)消息发出方,即客户端的service通过BpBinder(在这个流程中就是 代码中的mRemote )打开/dev/binder设备(linux的一块内核空间,实际上就是共享内存),并将信息写入(即IBinder的 transact函数)。
(2)消息接收方,即服务端的service会开启循环线程(其实从注册后就开始了),通过BBinder(在这个流程中是一个 ActivityManagerNative对象,下面会讲到)不停的从/dev/binder设备中读取信息,然后根据信息做相应的处理(IBinder的onT ransact函数)
(3)这时当原客户端从 /dev/binder设备得到对方已收到的信息后,角色转换为服务端,等待回复即replay(同样循环线程)。
(4)当原服务端处理后需要回复时,角色转为客户端,发送回复。
这样就实现了跨进程的通信。

因为是通过binder,所以我们的消息如intent之类都要包装成binder支持的Parcel,这也是intent只能传递可系列化对象的原因。同时因为这块共享内存大小的限制,也就导致了intent传递数据的大小限制(关于Parcel和大小限制请阅读:Android中Intent/Bundle的通信原理及大小限制一文)。
同样因为binder机制,我们不仅可以启动本app中的activity(自己同时是客户端和服务端),也可以启动其他app中公开的acitivity。



ActivityManagerNative类实际上继承了Binder(IBinder接口),也就是上面提到的BBinder的角色。当接收并解析binder消息后会调用它的 onTransact来进行处理, ActivityManagerNative中 onTransact非常庞大,根据code做不同的处理,我们只需要关注 START_ACTIVITY_TRANSACTION这个code即可。
@Override
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;
    }

    ...
}

拿到Parcel类型的数据,然后反系列化解析成Intent等,最后调用 startActivity,但是在 ActivityManagerNative并没有找到这个函数,那是因为 ActivityManagerNative是一个抽象类,真正的实现是在它的子类 ActivityManagerService中,然后通过ApplicationTreadProxy等类启动activity。这部分不是我们本文的重点,而且比较复杂,就不详细说了。借用网上一张时序图来展示一下这个流程。
探索startActivity流程及在Activity间是如何传递Intent的_第1张图片

Android进阶之路系列:http://blog.csdn.net/column/details/16488.html

你可能感兴趣的:(android,Android进阶之路)