Android进阶笔记:bindService的流程--源码解析

Android进阶笔记:bindService的流程–源码解析

    第一次写博客,目的也是为了记录自己在Android学习过程中自己发现的一些值得学习反复琢磨的东西也希望能和大家一起分享,如果写的有什么不对的地方还请大家多多指点。

    首先想要知道bindService这一过程是怎么样实现的,得先找到个路口,这个路口也很明显,就是Activity中的bindService方法。代码如下:
bindService(serviceIntent,serviceConnection, Service.BIND_AUTO_CREATE);

参数很简单都很简单,用过的应该都了解。第一个参数就是一个启动service的Intent而第二个参数是一个ServiceConnection的对象。这个对象的实现一般需要实现两个接口,如下所示:

        ServiceConnection serviceInatent = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name,  IBinder service) {

            }

            @Override
            public void onServiceDisconnected(ComponentName name) {

            }
        };

实现的方法中会返回两个参数一个是ComponentName 另外一个是IBinder类型的实例。这个ComponentName其实就是记录一个应用的包名已经相关的组件名(例如:包名”com.android.myservice”,组件名”com.android.myservice”),而这个IBinder类型的对象就是Service中OnBind方法中返回的Binder对象,如下:

 public IBinder onBind(Intent intent) {
        return null;
    }

具体这中间到底怎么实现的我们还是来看看源码吧。Ctrl按住点击bindService方法看到的代码如下:

public class ContextWrapper extends Context {
    ...
    Context mBase;
    @Override
    public boolean bindService(Intent service, ServiceConnection conn,
            int flags) {
        return mBase.bindService(service, conn, flags);
    }
    ...
}

这里很清楚直接就就调用了Context的bindService那就直接点进去呗。然后你会看到如下:

    public abstract boolean bindService(Intent service, @NonNull ServiceConnection conn,
            @BindServiceFlags int flags);

反正我自己一开看的时候就蒙了,这是一个abstract的方法,意思就是真正实现其实在他的子类。这这这。。这你让我去哪里看怎么实现bindService过程,还能不能看代码了?
其实,看到这里你应该就要往回想想,这个方法是刚刚的mBase对象调用的,那这个mBase对象一定就是已经实现了这个方法的子类对象,那我们只要知道这个mBase到底是啥就可以看到这个bindService方法真正实现的过程了。这里直接给出答案这个mBase其实就是ContextImpl类的对象,你要问我咋知道的。很简单这个mBase既然是Activity对象的内部成员,那只要了解Activity创建的过程肯定就知道这是什么了。(具体想知道可以查查Activity创建启动这块的资料,当然我以后也可能会写的哈哈)。

上面写了这么多其实也是为了提供了一个看源码的思路,当然我也是可以直接就告诉你这个方法在哪实现。但是这样就失去了一种过程感,感觉就是在灌输东西死记硬背。有一些东西你“知其所以然”以后印象肯定就非常的深了(这个也是写给我自己的“知其然并且知其所以然”,这也是我开始看源码的目的。我又忍不住废话多了,骚瑞。。。)。

好了继续上面的过程,既然我们知道这个bindService方法具体在哪个类里面实现的我就直接去找到它点进去看看就是了

位置:platform\frameworks\base\core\java\android\app\ContextImpl.java

    // bindService
    @Override
    public boolean bindService(Intent service, ServiceConnection conn, int flags) {
        warnIfCallingFromSystemProcess();
        return bindServiceCommon(service, conn, flags, Process.myUserHandle());
    }

    // bindServiceCommon
    private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, UserHandle user) {
        IServiceConnection sd;
        ...

        sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
                mMainThread.getHandler(), flags);


        ...

        int res = ActivityManagerNative.getDefault().bindService(
                mMainThread.getApplicationThread(), getActivityToken(), service,
                service.resolveTypeIfNeeded(getContentResolver()),
                sd, flags, getOpPackageName(), user.getIdentifier());

        ...

    }

这里已经把一些不太重要的代码省略了,首先进入bindService方法,然后直接进入了bindServiceCommon方法当中。而这个bindServiceCommon主要是实现了两个步骤,第一个是实现了一个叫做IServiceConnection的对象,如果有看过一些源码的应该知道就这尿性这命名多半是一个IBinder类的子类。这里我们先“存档”一下,记住等下要回来的!!!千万别绕着绕着就忘记刚刚是从哪绕进来的了(这应该也算是这个方法吧,源码毕竟很多,很容易就看到后面忘记前面了)。

这里首先我们要去看mPackageInfo.getServiceDispatcher这个方法,mPackageInfo这个很简单(看一下声明就知道了)是一个LoadedApk类的实现对象,那么我们就去找到这个对象咯。

位置:platform\frameworks\base\core\java\android\app\LoadedApk.java

    public final IServiceConnection getServiceDispatcher(ServiceConnection c, Context context, Handler handler, int flags) {
        synchronized (mServices) {
            LoadedApk.ServiceDispatcher sd = null;
            ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
            if (map != null) {
                sd = map.get(c);
            }
            if (sd == null) {
                sd = new ServiceDispatcher(c, context, handler, flags);
                if (map == null) {
                    map = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
                    mServices.put(context, map);
                }
                map.put(c, sd);
            } else {
                sd.validate(context, handler);
            }
            return sd.getIServiceConnection();
        }
    }

找到getServiceDispatcher方法可以看到其实上面一坨都是判断一下是不是空啊,是不是要创建一下啊,是不是要保存一下啦,都是浮云。重要的是最后sd(LoadedApk.ServiceDispatcher)对象调用了getIServiceConnection()这个方法。那我们继续跟踪一下看看这个方法的实现。

  IServiceConnection getIServiceConnection() {
            return mIServiceConnection;
        }

这个方法是属于LoadedApk的一个内部类ServiceDispatcher 的一个方法,主要就是返回一个IServiceConnection 类型的对象,那这个IServiceConnection 类型的对象到底是什么呢,我们就接下来看看ServiceDispatcher这个类到底是怎么样的。

static final class ServiceDispatcher {
    private final ServiceDispatcher.InnerConnection mIServiceConnection;
    private final ServiceConnection mConnection;
    private final Context mContext;
    private final Handler mActivityThread;
    private final ServiceConnectionLeaked mLocation;
    private final int mFlags;


    ServiceDispatcher(ServiceConnection conn, Context context, Handler activityThread, int flags) {
        mIServiceConnection = new InnerConnection(this);
        mConnection = conn;
        mContext = context;
        mActivityThread = activityThread;
        mLocation = new ServiceConnectionLeaked(null);
        mLocation.fillInStackTrace();
        mFlags = flags;
    }

    private static class InnerConnection extends IServiceConnection.Stub {
        final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;

        InnerConnection(LoadedApk.ServiceDispatcher sd) {
            mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
        }

        public void connected(ComponentName name, IBinder service) throws RemoteException {
            LoadedApk.ServiceDispatcher sd = mDispatcher.get();
            if (sd != null) {
                sd.connected(name, service);
            }
        }
    }

 IServiceConnection getIServiceConnection() {
            return mIServiceConnection;
        }
    ...

}

这里是一个很有有意思的地方,这个ServiceDispatcher 是LoadedApk的内部类,他内部还有一个叫做InnerConnection 的内部类。看一下声明:

 private final ServiceDispatcher.InnerConnection mIServiceConnection;

...

 IServiceConnection getIServiceConnection() {
            return mIServiceConnection;
        }

看声明你就能发现很明显一开始的getIServiceConnection()方法返回的就是这货!这又是一个ServiceDispatcher.InnerConnection类型的实例,那我们要的是IServiceConnection 类型的实例,那稍微想想就知道ServiceDispatcher.InnerConnection肯定直接或者间接的继承了IServiceConnection 。那我们就接着看看InnerConnection这个内部类咯。

InnerConnection类他继承的是一个.stub类型的类(IServiceConnection.Stub类其实又extend了IServiceConnection这个类),了解过aidl的同学应该明白这是什么(不懂的可以去学习一下AIDL的相关知识),这里说白了他就是一个IBinder类的子类主要是用来支持IPC(跨进程通信),说人话。。。就是用来跨进程调用一些方法。这个类总共只有两个方法。

首先看这个类的第一个方法————构造方法。

        InnerConnection(LoadedApk.ServiceDispatcher sd) {
            mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
        }

他引用(弱引用)了一个他的上级类(ServiceDispatcher )的实例并且保存下来了。这里注意,InnerConnection内部类他引用了他的上级类的实例,也就是说InnerConnection可以通过ServiceDispatcher 实例来调用ServiceDispatcher 类中的公有方法,InnerConnection又是一个支持跨进程的类,也就是说InnerConnection可以实现跨进程来调用ServiceDispatcher 和InnerConnection这两个类中的所有公有方法,形象的说就是一个桥梁来连接两个进程之间方法的调用,这里也是我觉得他很有意思的原因。

说完了构造方法,那我们再去看看另外一个方法connected(ComponentName name, IBinder service)

public void connected(ComponentName name, IBinder service) throws RemoteException {
                LoadedApk.ServiceDispatcher sd = mDispatcher.get();
                if (sd != null) {
                    sd.connected(name, service);
                }
            }

瞅瞅方法名,再瞅瞅参数,怎么就那么眼熟呢?没错,这个方法其实就是对我们之前ServiceConnection类中onServiceConnected方法的封装,最后还是会调用到ServiceConnection.onServiceConnected这个方法的,不信再跟踪一下源码看看:

//ServiceDispatcher.connected
    public void connected(ComponentName name, IBinder service) {
        if (mActivityThread != null) {
            mActivityThread.post(new RunConnection(name, service, 0));
        } else {
            doConnected(name, service);
        }
    }

//ServiceDispatcher.doConnected
    public void doConnected(ComponentName name, IBinder service) {
        ...
        // If there is a new service, it is now connected.
        if (service != null) {
            mConnection.onServiceConnected(name, service);
        }
    }

很明显吧这个mConnection其实就是一开始ServiceDispatcher 的构造函数中传进来的ServiceConnection实例,看一下他的声明就明白了。最后就是调用了 mConnection.onServiceConnected(name, service)这个方法。这个地方要有一点印象,因为后面会通过InnerConnection实例来远程回调这个方法。

分析完ServiceDispatcher 这个类以及他的内部类 InnerConnection,也可以稍微的总结一下。
我们一开始时为了获得一个IServiceConnection类的实例,而这个类的实例是通过LoadedApk.getIServiceConnection()方法获得的,这个方法又调用了他的内部类LoadedApk.ServiceDispatcher 的 InnerConnection实例,这个实例通过一系列的继承最后父类就是IServiceConnection;是不是有点晕。。。。稍微画一下这三个类的关系结构

public final class LoadedApk {

    static final class ServiceDispatcher {

        private static class InnerConnection extends IServiceConnection.Stub {
            //IServiceConnection.Stub extend IServiceConnection
            final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;
        }

    }

}

这下这三个类的关系应该很明确了吧。最后拿到的其实就是InnerConnection 这东西。

好了休息一下,还记得前面我有说存档一下吗?现在我们也该回到前面说的“存档”点了,可别绕晕了啊。

  sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
                mMainThread.getHandler(), flags);

上面我们分析了这个sd到底是什么东西(有远程调用功能的一个东西),有什么用(保存数据,实现连接方面的方法,远程调用)。那么我们就继续来分析接下来的一块:

            int res = ActivityManagerNative.getDefault().bindService(
                mMainThread.getApplicationThread(), getActivityToken(), service,
                service.resolveTypeIfNeeded(getContentResolver()),
                sd, flags, getOpPackageName(), user.getIdentifier());

其实就调用了一个方法ActivityManagerNative.getDefault().bindService()剩下的那一坨都是参数,要知道一下的是第一个参数其实是一个ApplicationThread类型的实例,他是AtivityThread的内部类,而ApplicationThread继承了IApplicationThread 也是一个IBinder类型实例,也就是说我们可以运用它来远程的调用ApplicationThread类中的方法。还有别忘记刚刚我们拿到的sd也跟着传进去了,至于那个service其实是一个intent。

那问题来了ActivityManagerNative.getDefault()到底是一个什么东西呢?其实这是一个ActivityManagerService的Binder驱动,也是一个IBinder类型的对象。主要是通过这个Binder驱动来跨进程调用ActivityManagerService中的方法,这里就是调用了ActivityManagerService.bindService方法。
这里我还是给出了ActivityManagerNative类的位置吧。
位置:platform\frameworks\base\core\java\android\app\ActivityManagerNative.java

那我们就继续去看看ActivityManagerService.bindService这个方法。
位置:platform\frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java

    public int bindService(IApplicationThread caller, IBinder token, Intent service, String resolvedType, IServiceConnection connection, int flags, String callingPackage,
                           int userId) throws TransactionTooLargeException {
        ...

        synchronized(this) {
            return mServices.bindServiceLocked(caller, token, service,
                    resolvedType, connection, flags, callingPackage, userId);
        }
    }

很简单没什么好说的就是调用了ActiveServices中的bindServiceLocked这个方法。
位置:platform\frameworks\base\services\core\java\com\android\server\am\ActiveServices.java

    int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
                               String resolvedType, IServiceConnection connection, int flags,
                               String callingPackage, int userId) throws TransactionTooLargeException {

    final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);

    ActivityRecord activity = null;
    if (token != null) {
        activity = ActivityRecord.isInStackLocked(token);
    }

    ServiceLookupResult res =
            retrieveServiceLocked(service, resolvedType, callingPackage,
                    Binder.getCallingPid(), Binder.getCallingUid(), userId, true, callerFg);

    ServiceRecord s = res.record;

    try {
        AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
        ConnectionRecord c = new ConnectionRecord(b, activity,
                connection, flags, clientLabel, clientIntent);

        IBinder binder = connection.asBinder();
        ArrayList<ConnectionRecord> clist = s.connections.get(binder);
        if (clist == null) {
            clist = new ArrayList<ConnectionRecord>();

            s.connections.put(binder, clist);

        }

        clist.add(c);
        b.connections.add(c);

        if (activity != null) {
            ...

            activity.connections.add(c);
        }
        b.client.connections.add(c);


        if ((flags&Context.BIND_AUTO_CREATE) != 0) {
            s.lastActivity = SystemClock.uptimeMillis();
            if (bringUpServiceLocked(s, service.getFlags(), callerFg, false) != null) {
                return 0;
            }
        }

        ...

        return 1;
    }

这里我做了删减,这个代码其实耐心的看一下还是很清晰的就是s(ServiceRecord )、b(AppBindRecord )、c(ConnectionRecord )、callerApp (ProcessRecord) 这四个类型的一些保存啊之类的操作,方便以后调用。可以观察一下这三个类的命名,都很有规则都是有一个Record后缀,其实就一个对应的描述类保存了后面要用到的信息(如:ServiceRecord ,这里面就存放了将来要创建Service时所需要的所有信息)

这里还是要说明一下ServiceRecord 是对Service(需要绑定的Service)信息存放,c是对一开始我们传进来的IServiceConnection 封装,各种地方都保存了这个c方便调用。

IBinder binder = connection.asBinder();

而这个binder其实可以简单的看做成IServiceConnection ,后面可以通过它asInterface方法获取binder驱动来远程调用IServiceConnection (其实就是IServiceConnection–>InnerConnection –>ServiceDispatcher )里面的方法。然后把这个binder放到了s(ServiceRecord )的connections的集合中,clist就是一个connectionRecord的集合,应为可能不止一个activity或者组件需要绑定这个service。

s.connections.put(binder, clist);

接下来我们根据设置的flag(一般都是设置成这个)会进入到if语句块,然后调用bringUpServiceLocked这个方法

 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
            s.lastActivity = SystemClock.uptimeMillis();
            if (bringUpServiceLocked(s, service.getFlags(), callerFg, false) != null) {
                return 0;
            }
        }

这里很明确既然调用了那我们继续动手点进去看看呗。

    private final String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg, boolean whileRestarting) throws TransactionTooLargeException {

        ...

        if (!isolated) {
            app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
            if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid
                        + " app=" + app);
            if (app != null && app.thread != null) {
                try {
                    app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
                    realStartServiceLocked(r, app, execInFg);
                    return null;
                } catch (TransactionTooLargeException e) {
                    throw e;
                } catch (RemoteException e) {
                    Slog.w(TAG, "Exception when starting service " + r.shortName, e);
                }

                // If a dead object exception was thrown -- fall through to
                // restart the application.
            }
        }

        ...

        return null;
    }

这块代码源码那边其实稍微有点多,但是大多是都是进行一些空值或者变量的判断,一些重要的变量如果异常则直接返回不再执行。如果正常则会执行到如上所示的方法。

  • r 就是ServiceRecord刚刚bindServiceLocked方法中封装了的对service的描述实例(用来创建service可以简单的理解就是一个不成型的service)。
  • app 就是刚刚提到的processRecord变量,刚刚也提到过是用来存储一些数据(其实也就是当前应用相关的数据)。
  • mAm 就是ActivityManagerService的实例

然后最后会执行到realStartServiceLocked,看名字real,说明这里是真正的开始启动一个Service的地方,那就继续点进去看看咯。

    private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {

      ...

        r.app = app;

       ...

            app.thread.scheduleCreateService(r, r.serviceInfo,
                    mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                    app.repProcState);
            r.postNotification();

     ...

        requestServiceBindingsLocked(r, execInFg);

        updateServiceClientActivitiesLocked(app, null, true);


     ...
    }

上面app就是之前传过来的,而这个app.thread到底是什么呢,我们去ProcessRecord类里面去看看。

final class ProcessRecord {

...

    IApplicationThread thread;  // the actual proc...  may be null only if
                                // 'persistent' is true (in which case we
                                // are in the process of launching the app)
...

}

其实就是之前说到的ApplicationThread的远程接口IApplicationThread ,就是说可以跨进程的通过它来调用ApplicationThread里面的方法。

既然这样IApplicationThread 调用了scheduleCreateService这个方法,看名字就知道是打算真正的来创建这个Service了。那很简单我们只要直接去ActivityThread类(ApplicationThread是ActivityThread的内部类所以别找错地方哦)里面去找就行了。

        public final void scheduleCreateService(IBinder token,
                ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
            updateProcessState(processState, false);
            CreateServiceData s = new CreateServiceData();
            s.token = token;
            s.info = info;
            s.compatInfo = compatInfo;

            sendMessage(H.CREATE_SERVICE, s);
        }

这个方法全部也只有这几行很小,主要做的工作就是发送一个消息并且通过token和info来创建了一个新的ServiceRecord(真正的东西其实都在toke和info里面,这里之所以他们能被跨进程传过来其实是因为toke是Ibinder类型而info实现了parcelable接口)传递给H(ActivityThread内部的一个Handler)处理来创建一个Service。那我们就继续去找这个Handler他收到消息具体去干什么了。

        //Handler的回调函数handleMessage
        public void handleMessage(Message msg) {
            switch (msg.what) {
                    ...
                    case CREATE_SERVICE:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceCreate");
                    handleCreateService((CreateServiceData)msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    ...
            }
        }

    //Hander通过handlerMessage回调的方法
    private void handleCreateService(CreateServiceData data) {

        LoadedApk packageInfo = getPackageInfoNoCheck(
                data.info.applicationInfo, data.compatInfo);
        Service service = null;

            ...

            java.lang.ClassLoader cl = packageInfo.getClassLoader();
            service = (Service) cl.loadClass(data.info.name).newInstance();

            Application app = packageInfo.makeApplication(false, mInstrumentation);
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManagerNative.getDefault());
            //service.onCreate真正回调的地方
            service.onCreate();
            mServices.put(data.token, service);
          ...
    }

这里也很简单发送消息给Handler,让handerMessage方法来处理消息,然后回调了handleCreateService这个方法。这个方法里面就开始真正的创建了一个Service实例。data其实就是ServiceRecord。到这一步一个service的创建算是完成了。但是我们要做的事情还没完啊!我们讨论的是bindService。回过去看看,我们之前是从app.thread.scheduleCreateService方法一路走到service的创建,那么下面其实还有一个方法没有完成,就是requestServiceBindingsLocked。

    private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {

      ...

        r.app = app;

       ...

            app.thread.scheduleCreateService(r, r.serviceInfo,
                    mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                    app.repProcState);
            r.postNotification();

     ...
     //就是这个方法
        requestServiceBindingsLocked(r, execInFg);

        updateServiceClientActivitiesLocked(app, null, true);


     ...
    }

看名字就知道是请求绑定service,那就继续呗。离胜利不远了!

    private final void requestServiceBindingsLocked(ServiceRecord r, boolean execInFg)
            throws TransactionTooLargeException {
        for (int i=r.bindings.size()-1; i>=0; i--) {
            IntentBindRecord ibr = r.bindings.valueAt(i);
            if (!requestServiceBindingLocked(r, ibr, execInFg, false)) {
                break;
            }
        }
    }

这里就很简单了,就是调用了一下requestServiceBindingLocked。这里为什么弄个循环去做这件事情呢,我想也是应为一个Service可能会被多个Activity去绑定所以需要一个循环来处理(具体还没研究过)。

    private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
            boolean execInFg, boolean rebind) throws TransactionTooLargeException {

       ...

                r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
                        r.app.repProcState);
       ...

        return true;
    }

看看方法里面怎么实现的。其实还是那个尿性,就是把需要的东西全部都通过binder驱动来远程传给ActivtyThread(ApplicationThread)的scheduleBindService方法去实现那么老样子这里直接去找一下这个方法是怎么实现的就好了。

        public final void scheduleBindService(IBinder token, Intent intent,
                boolean rebind, int processState) {
            updateProcessState(processState, false);
            BindServiceData s = new BindServiceData();
            s.token = token;
            s.intent = intent;
            s.rebind = rebind;

            if (DEBUG_SERVICE)
                Slog.v(TAG, "scheduleBindService token=" + token + " intent=" + intent + " uid="
                        + Binder.getCallingUid() + " pid=" + Binder.getCallingPid());
            sendMessage(H.BIND_SERVICE, s);
        }

没错!老套路,还是发消息,这里我就不具体贴代码了最后通过handlerMessage方法来调用handleBindService方法,参数也仍然是ServiceRecord对象,这里我们就直接看看这个方法吧。

     private void handleBindService(BindServiceData data) {
        Service s = mServices.get(data.token);
            ...
                    if (!data.rebind) {
                        IBinder binder = s.onBind(data.intent);
                        ActivityManagerNative.getDefault().publishService(
                                data.token, data.intent, binder);
                    } 
            ...
    }

这里因为之前Service已经创建过了并且保存在了mServices这个集合里面了

    private void handleCreateService(CreateServiceData data) {

            ...
            mServices.put(data.token, service);
          ...
    }

所以直接取出来了就可以了。好了,回过头然后方法里面通过调用Service的onBind方法来获得一个binder对象,这个方法只要继承了Service并且要实现绑定的话是肯定要重写的,这里面返回的Binder对象是自己传入的可以是null。最后又是通过ActivityManagerNative.getDefault()(之前也解释过,这个其实就是一个ActivityManagerService的远程驱动)来调用publishService这个方法,那我们就再回去,在去ActivityManagerService里面找这个方法;

    public void publishService(IBinder token, Intent intent, IBinder service) {
        // Refuse possible leaked file descriptors
        if (intent != null && intent.hasFileDescriptors() == true) {
            throw new IllegalArgumentException("File descriptors passed in Intent");
        }

        synchronized(this) {
            if (!(token instanceof ServiceRecord)) {
                throw new IllegalArgumentException("Invalid service token");
            }
            mServices.publishServiceLocked((ServiceRecord)token, intent, service);
        }
    }

没什么营养,反正就是各种异常判断一下最后调用了mServices(ActiveServices类的实例)的publishServiceLocked方法。

    void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {

                ...

                    for (int conni=r.connections.size()-1; conni>=0; conni--) {
                        ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
                        for (int i=0; i<clist.size(); i++) {
                            ConnectionRecord c = clist.get(i);

                            ...

                            try {
                                c.conn.connected(r.name, service);
                            } catch (Exception e) {
                                Slog.w(TAG, "Failure sending service " + r.name +
                                      " to connection " + c.conn.asBinder() +
                                      " (in " + c.binding.client.processName + ")", e);
                            }
                        }
                    }
               ...
    }

这里就是从ServiceRecord里面取出了ConnectionRecord 然后调用了 c.conn.connected(r.name, service);这么一个方法。至于细心的同学应该想起来之前bindServiceLocked里面创建完ServiceRecord的时候有这么一段代码

 if (clist == null) {
                clist = new ArrayList<ConnectionRecord>();
                s.connections.put(binder, clist);
            }

没错,这个ConnectionRecord 就是那时候存进去的。

c.conn.connected(r.name, service)这个方法里面的service就是刚刚创建的Service.onBind(我们自己从来的方法)返回回来的binder对象,而这个r.name其实是一个ComponentName的对象。怎么样,是不是感觉这个方法的参数有一点熟悉啊!这不就是ServiceConnection对象里面的onServiceConnected(ComponentName name, IBinder service)方法要的参数嘛。那这个方法百分之八十就是辗转调用到了这个方法咯。那我们就去看看这个c.conn到底是什么

    final class ConnectionRecord {

        ...

        final IServiceConnection conn;  // The client connection.

        ...

    }

看吧,这就是我之前说的那个Inn什么的记起来了嘛(InnerConnection),我之前也提到过“最后就是调用了 mConnection.onServiceConnected(name, service)这个方法。这个地方要有一点印象,因为后面会通过InnerConnection实例来远程回调这个方法。”忘记在哪个步骤的可以ctrl+f搜一下这句话回过去再看看。

到上面的步骤其实bindService的流程已经分析的差不多了,可能有一些多,凡是思路还是很清晰的。
总结一下其实就是把一些真正需要创建Service要用的东西全部都给ActivityManagerService来做(跨进程)然后做完了在丢给ActivityThread(ApplicationThread)去真正的创建。

从上面的源码其实也可以看出ServiceConnection.onServiceConnected这个回调是通过跨进程来调用的,而最后通过IServiceConnection 来调用 connected方法(这个方法真正回调了onServiceConnected方法)
而connected方法所在的类的实例是创建在UI线程的

//ContextImpl.java
 sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
                    mMainThread.getHandler(), flags);


public final IServiceConnection getServiceDispatcher(ServiceConnection c,
            Context context, Handler handler, int flags) {
...
   sd = new ServiceDispatcher(c, context, handler, flags);
...
}



 ServiceDispatcher(ServiceConnection conn, Context context, Handler activityThread, int flags) {
            mIServiceConnection = new InnerConnection(this);
          ...
        }



 private static class InnerConnection extends IServiceConnection.Stub {
        ...
            public void connected(ComponentName name, IBinder service) throws RemoteException {
                LoadedApk.ServiceDispatcher sd = mDispatcher.get();
                if (sd != null) {
                    sd.connected(name, service);
                }
            }
        }


 public void connected(ComponentName name, IBinder service) {
            if (mActivityThread != null) {
                mActivityThread.post(new RunConnection(name, service, 0));
            } else {
                doConnected(name, service);
            }
        }

 public void doConnected(ComponentName name, IBinder service) {
           ...
            // If there is a new service, it is now connected.
            if (service != null) {
                mConnection.onServiceConnected(name, service);
            }
 }

因此onServiceConnected这个方法其实是运行在主线程中的,如果Server端的方法是耗时操作最好起一个线程来调用,因为在调用IBinder的transact方法时当前线程是会挂起的!

第一次写博客可能有点乱,这之中也花了好多时间,不管怎么样写出来了也方便以后自己查看。省的我那天脑子一抽又忘记了。

  • 7
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值