[Android] bindService的binder通信过程分析

关于bindService方法

public class ContextWrapper extendsContext {

   Context mBase;

 

   public ContextWrapper(Context base) {

        mBase = base;

   }

 

   public boolean bindService(Intent service, ServiceConnection conn,

            int flags) {

       returnmBase.bindService(service, conn, flags);

   }

 

ContextImpl.java

   // bindService

   @Override

   public boolean bindService(Intent service, ServiceConnection conn, intflags) {

        warnIfCallingFromSystemProcess();

        return bindServiceCommon(service, conn,flags, Process.myUserHandle());

   }

 

   // bindServiceCommon

   private boolean bindServiceCommon(Intent service, ServiceConnectionconn, int flags, UserHandle user) {

        IServiceConnection sd;

        ...

//包装ServiceConnection

        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());

 

        ...

 

   }

 

这里是通过binder和AMS进行通信,一次binder调用。

 

在通信的时候,构造了一个InnerConnection的binder对象作为参数传给了AMS,以便于实现方法回调。

        private static class InnerConnectionextends IServiceConnection.Stub {

            finalWeakReference mDispatcher;

 

           InnerConnection(LoadedApk.ServiceDispatcher sd) {

                mDispatcher = newWeakReference(sd);

            }

 

            public void connected(ComponentNamename, IBinder service) throws RemoteException {

               LoadedApk.ServiceDispatcher sd = mDispatcher.get();

                if (sd != null) {

                    sd.connected(name,service);

                }

            }

        }

 

 

另外构造了ServiceDispatcher对象将ServiceConnection和InnerConnection进行了包装。

 

 

在回调的时候,AMS端作为Proxy调用connected方法。

 

在AMS中的调用比较复杂,时序图如下

AMS的bindService方法

    public intbindService(IApplicationThread caller, IBinder token, Intent service,

            String resolvedType,IServiceConnection connection, int flags, String callingPackage,

            int userId) throwsTransactionTooLargeException {

       enforceNotIsolatedCaller("bindService");

 

        // Refuse possible leaked filedescriptors

        if (service != null &&service.hasFileDescriptors() == true) {

            throw newIllegalArgumentException("File descriptors passed in Intent");

        }

 

        if (callingPackage == null) {

            throw newIllegalArgumentException("callingPackage cannot be null");

        }

 

        synchronized(this) {

            return mServices.bindServiceLocked(caller, token,service,

                    resolvedType, connection,flags, callingPackage, userId);

        }

   }

里面调用到mServices.bindServiceLocked

在ActivityManagerService.java中有定义

   final ActiveServices mServices;

 

继续调用到其realStartServiceLocked方法

public final class ActiveServices {

   private final void realStartServiceLocked(ServiceRecord r,

            ProcessRecord app, booleanexecInFg) 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);

 

 

    ...

   }

 

 

 

private final boolean requestServiceBindingLocked(ServiceRecordr, IntentBindRecord i,

            boolean execInFg, boolean rebind)throws TransactionTooLargeException {

        if (r.app == null || r.app.thread ==null) {

            // If service is not currentlyrunning, can't yet bind.

            return false;

        }

        if ((!i.requested || rebind) &&i.apps.size() > 0) {

            try {

                bumpServiceExecutingLocked(r,execInFg, "bind");

                r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);

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

                        r.app.repProcState);

                if (!rebind) {

                    i.requested = true;

                }

                i.hasBound = true;

                i.doRebind = false;

            } catch(TransactionTooLargeException e) {

       ……

            }

        }

        return true;

   }

 

由于AMS中已经保存了系统中已启动的应用和服务的信息,这里的r.app.thread是服务的一个proxy,通过这个binder调用,服务中的scheduleBindService方法被执行,里面调用了

        public final void scheduleBindService(IBindertoken, Intent intent,

                boolean rebind, intprocessState) {

            updateProcessState(processState,false);

            BindServiceData s = new BindServiceData();

            s.token = token;

            s.intent = intent;

            s.rebind = rebind;

 

            sendMessage(H.BIND_SERVICE, s);

        }

 

处理该消息时调用ActivityThread的

 

   private void handleBindService(BindServiceData data) {

        Service s = mServices.get(data.token);

 

        if (s != null) {

            try {

               data.intent.setExtrasClassLoader(s.getClassLoader());

               data.intent.prepareToEnterProcess();

                try {

                    if (!data.rebind) {

                        IBinder binder = s.onBind(data.intent);

                        ActivityManagerNative.getDefault().publishService(

                                data.token,data.intent, binder);

                    } else {

                       s.onRebind(data.intent);

                       ActivityManagerNative.getDefault().serviceDoneExecuting(

                                data.token,SERVICE_DONE_EXECUTING_ANON, 0, 0);

                    }

                    ensureJitEnabled();

                } catch (RemoteException ex) {

                    throwex.rethrowFromSystemServer();

                }

            } catch (Exception e) {

            }

        }

   }

 

在server进程中,通过调用AMS服务publishService把binder对象传给AMS

 

这里,再回顾下这个时序图

 

 

可以看出,进程间的调用都是binder通信调用。

 

 

 

在AMS调用scheduleBindService的时候,有一个很巧妙的设计,就是把RecordService作为参数传递给了server端,其实server端并没有实际使用RecordService,只是把RecordService再通过publishService又传递给了AMS,为什么这么曲折呢?

因为server端的sheduleBindService方法中进行了异步调用。采用这种方式,连接了RecordService和server端传递的服务binder的对应关系。AMS根据这个RecordService找到调用的client端,再通过调用connected方法把server的binder传送过去。

 

ActivityManagerService中有方法

   public void publishService(IBindertoken, Intent intent, IBinder service) {

        // Refuse possible leaked filedescriptors

        if (intent != null &&intent.hasFileDescriptors() == true) {

            throw newIllegalArgumentException("File descriptors passed in Intent");

        }

 

        synchronized(this) {

            if (!(token instanceofServiceRecord)) {

                throw newIllegalArgumentException("Invalid service token");

            }

            mServices.publishServiceLocked((ServiceRecord)token,intent, service);

        }

   }

 

ActiveServices.java

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

                ...

 

                    for (int conni=r.connections.size()-1;conni>=0; conni--) {

                       ArrayList clist = r.connections.valueAt(conni);

                        for (int i=0;i

                            ConnectionRecord c= clist.get(i);

 

                            ...

 

                            try {

//binder调用,AMS调用client的方法,把service的binder传过去

                                c.conn.connected(r.name, service);

                            } catch (Exceptione) {

                                Slog.w(TAG,"Failure sending service " + r.name +

                                      " toconnection " + c.conn.asBinder() +

                                      "(in " + c.binding.client.processName + ")", e);

                            }

                        }

                    }

               ...

   }

这里根据ServiceRecord找到对应的IServiceConnection

ServiceRecord中有定义

//IBinder -> ConnectionRecord of all bound clients

finalArrayMap> connections

        = new ArrayMap>();

由于一个service中可能会提供多个binder服务,每个binder又会有多个客户端连接,所以这里使用了ArrayMap>的定义,

再通过遍历connections找到对应的ConnectionRecord,ConnectionRecord中存储有客户端的IServiceConnection conn作为通信proxy。

 

 

ConnectionRecord.java

final class ConnectionRecord {

   final AppBindRecord binding;    //The application/service binding.

   final ActivityRecord activity;  //If non-null, the owning activity.

   final IServiceConnection conn; // The client connection.

 

你可能感兴趣的:(Android)