Android Service的绑定流程源码分析(8.0)

来源:互联网 发布:java绘制动态图 编辑:程序博客网 时间:2024/06/05 08:13

一,写在前面

       为了更好的理解Service的绑定流程,建议先了解Activity和Service的启动流程,本篇文章将不再对一些重复的细节进行阐述。建议阅读前,可以参考如下两篇文章:
Android Activity的启动流程源码解析(8.0)    Android Service的启动流程源码分析(8.0) 

二,绑定服务的开始

       在Activity中调用bindService(intent,ServiceConnection)绑定服务,其实是调用父类ContextWrapper的bindService方法。
       ContextWrapper$bindService方法源码如下:
@Override    public boolean bindService(Intent service, ServiceConnection conn,            int flags) {        return mBase.bindService(service, conn, flags);    }
       mBase是一个Context类型的对象,mBase的值是一个ContextImpl对象。ContextImpl的实例化是在启动Activity时完成的,并作为参数传入Activity$attach方法,具体细节就点到这里吧,详情可参考Android Activity的启动流程源码解析(8.0)。也就是说,绑定服务接着交给ContextImpl来处理。

       ContextImpl$bindService方法源码如下:
    @Override    public boolean bindService(Intent service, ServiceConnection conn,            int flags) {        warnIfCallingFromSystemProcess();        return bindServiceCommon(service, conn, flags, mMainThread.getHandler(),                Process.myUserHandle());    }    //继续查看...    private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler            handler, UserHandle user) {    IServiceConnection sd;        if (conn == null) {            throw new IllegalArgumentException("connection is null");        }        if (mPackageInfo != null) {            sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);        } else {            throw new RuntimeException("Not supported in system context");        }//...codeint res = ActivityManager.getService().bindService(                mMainThread.getApplicationThread(), getActivityToken(), service,                service.resolveTypeIfNeeded(getContentResolver()),                sd, flags, getOpPackageName(), user.getIdentifier());    //...code        }
       第5行,调用ContextImpl$bindServiceCommon方法;
       第14行,做一个ServiceConnection接口引用的判空检查;
       第17行,变量mPackageInfo是一个LoadedApk对象,在启动Activity的流程中也会用到这个类,这里做了判空检查;
       第18行,对conn也就是ServiceConnection接口进行封装,借助于一个Binder使ServiceConnection可以在进程间传递,下面会详细分析;
       第25行,ActivityManager.getService()是IActivityManager的代理对象,调用代理对象的bindService方法,会向系统服务ActivityManagerService发起请求,基于Binder机制,调用ActivityManagerService$bindService方法。至于为啥将绑定服务的操作交给AMS,可以参考文章 Android Activity的启动流程源码解析(8.0)  ,这里不再重复阐述。

       分析:
       第18行,调用了LoadedApk$getServiceDispatcher方法。 
       查看LoadedApk源码如下:
public final class LoadedApk {    //...code    private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mServices        = new ArrayMap<>();        //...code    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) {                if (DEBUG) Slog.d(TAG, "Returning existing dispatcher " + sd + " for conn " + c);                sd = map.get(c);            }            if (sd == null) {                sd = new ServiceDispatcher(c, context, handler, flags);                if (DEBUG) Slog.d(TAG, "Creating new dispatcher " + sd + " for conn " + c);                if (map == null) {                    map = new ArrayMap<>();                    mServices.put(context, map);                }                map.put(c, sd);            } else {                sd.validate(context, handler);            }            return sd.getIServiceConnection();        }    }    //...code    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;        //...code        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, boolean dead)                    throws RemoteException {                LoadedApk.ServiceDispatcher sd = mDispatcher.get();                if (sd != null) {                    sd.connected(name, service, dead);                }            }        }            //...codeServiceDispatcher(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;        }//...code        IServiceConnection getIServiceConnection() {            return mIServiceConnection;        }        //...code    }}
       第13行,定义了一个ServiceDispatcher类型的变量sd,ServiceDispatcher是LoadedApk的内部类,此时sd为null;
       第5行,创建了一个ArrayMap对象,key是Context对象,value是ServiceConnection和ServiceDispatcher的映射关系,以ArrayMap来体现;
       第14行,取出mServices中key对应的value,第5行只是创建了ArrayMap对象,并没有在集合中添加键值对,map为null;
       第19行,sd == null为true;
       第20~26行,创建ServiceDispatcher对象,并将ServiceConnection对象作为key,ServiceDispatcher对象作为value,存储在变量map集合中;将Context对象作为key,变量map作为value,存储在变量mServices集合中。 
       值得一提的是,在第20行,创建ServiceDispatcher对象时,初始化了变量mIServiceConnection。见第66行,它是一个InnerConnection类型的对象。
       第30行,调用ServiceDispatcher$getIServiceConnection方法,返回mIServiceConnection变量的值,也就是返回一个InnerConnection对象。
       第46行,InnerConnection是ServiceDispatcher的内部类,也就是LoadedApk$ServiceDispatcher$InnerConnection。它继承了IServiceConnection.Stub类,IServiceConnection是一个AIDL接口。这里用到了AIDL技术完成一次IPC调用,AIDL文件生成的Java文件也可以自己写,但是Android系统这里是采用了AIDL技术替代。于是,我们知道IServiceConnection接口的实现类是InnerConnection,后面分析会用到它。

       回到ContextImpl$bindService方法,上面对第18行进行了详细分析,下面继续第25行的流程分析。

三,绑定服务的操作,交给ActivityManagerService处理

       继续ContextImpl$bindService方法的第25行;
       查看ActivityManagerService$bindService
public int bindService(IApplicationThread caller, IBinder token, Intent service,            String resolvedType, IServiceConnection connection, int flags, String callingPackage,            int userId) throws TransactionTooLargeException {        //...code    synchronized(this) {        return mServices.bindServiceLocked(caller, token, service,                resolvedType, connection, flags, callingPackage, userId);    }    //...code                }
       第8行,mServices是一个ActiveServices类型的对象;

       查看ActiveServices$bindServiceLocked方法源码:
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,            String resolvedType, final IServiceConnection connection, int flags,            String callingPackage, final int userId) throws TransactionTooLargeException {       //...code      if ((flags&Context.BIND_AUTO_CREATE) != 0) {                s.lastActivity = SystemClock.uptimeMillis();                if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,                        permissionsReviewRequired) != null) {                    return 0;                }            }   //...code   if (s.app != null && b.intent.received) {                // Service is already running, so we can immediately                // publish the connection.                try {                    c.conn.connected(s.name, b.intent.binder, false);                } catch (Exception e) {                    Slog.w(TAG, "Failure sending service " + s.shortName                            + " to connection " + c.conn.asBinder()                            + " (in " + c.binding.client.processName + ")", e);                }                // If this is the first app connected back to this binding,                // and the service had previously asked to be told when                // rebound, then do so.                if (b.intent.apps.size() == 1 && b.intent.doRebind) {                    requestServiceBindingLocked(s, b.intent, callerFg, true);                }            } else if (!b.intent.requested) {                requestServiceBindingLocked(s, b.intent, callerFg, false);            }            //...code            }
       第9行,bringUpServiceLocked方法是不是很熟悉,在文章 Android Service的启动流程源码分析(8.0)中也是调用该方法启动服务的,最终会调用Service$onCreate方法,这里不再重复阐述。
       
       值得一提的是,绑定服务会回到onCreate,onBind,并回调ServiceConnection的方法。事实上,绑定服务有重新绑定这个过程,前提条件是同时调用startService启动了服务,且上一次解绑服务回调的onUnbind方法返回true。重新绑定服务时,会回调onRebind方法,而不再调用onBind方法。可以参考文章 Android Service的onRebind方法调用时机 ,这里不再重复阐述。
      
       第17行,若Service已经处于绑定状态,那么调用bindService只执行21行代码,c.conn.connected里最终回调ServiceConnection的方法。这里不详细描述,后面会给出分析。
       第31行,若重新绑定服务(上面已经分析该过程),则执行32行代码,最后一个参数为true,该过程不具体分析。
       第34行,若没有绑定服务的请求,则执行35行代码,最后一个参数为false,下面继续分析该过程

       查看ActiveServices$requestServiceBindingLocked源码:
private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,            boolean execInFg, boolean rebind) throws TransactionTooLargeException {    if (r.app == null || r.app.thread == null) {            // If service is not currently running, can't yet bind.            return false;    }        //...code    if ((!i.requested || rebind) && i.apps.size() > 0) {            //...coder.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,                        r.app.repProcState);                if (!rebind) {                    i.requested = true;                }                i.hasBound = true;                i.doRebind = false;//...code        }        return true;    }
       第10行,!i.requested为true,则(!i.requested || rebind)为true;i.apps.size()指应用程序进程的数量,i.apps.size() > 0为true。
       继续往下执行到第14行代码,r.app.thread是一个IApplicationThread类型的对象,这个比较熟悉了,它的实现类是ApplicationThread类。文章Android Activity的启动流程源码解析(8.0) 中,对ApplicationThread类进行了详细分析,这里不再重复阐述。

四,绑定服务的操作,交给ActivityThread处理

       查看ActivityThread$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);}
       查看ActivityThread相关方法的源码:
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);}private void sendMessage(int what, Object obj) {        sendMessage(what, obj, 0, 0, false);}//...继续查看private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {        if (DEBUG_MESSAGES) Slog.v(            TAG, "SCHEDULE " + what + " " + mH.codeToString(what)            + ": " + arg1 + " / " + obj);        Message msg = Message.obtain();        msg.what = what;        msg.obj = obj;        msg.arg1 = arg1;        msg.arg2 = arg2;        if (async) {            msg.setAsynchronous(true);        }        mH.sendMessage(msg);}//...继续查看private class H extends Handler {//...codepublic void handleMessage(Message msg) {            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));            switch (msg.what) {            //...codecase BIND_SERVICE:                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind");                    handleBindService((BindServiceData)msg.obj);                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);                    break;//...code}}//...继续查看private void handleBindService(BindServiceData data) {        Service s = mServices.get(data.token);        if (DEBUG_SERVICE)            Slog.v(TAG, "handleBindService s=" + s + " rebind=" + data.rebind);        if (s != null) {    //...code    if (!data.rebind) {               IBinder binder = s.onBind(data.intent);               ActivityManager.getService().publishService(                         data.token, data.intent, binder);            } else {               s.onRebind(data.intent);               ActivityManager.getService().serviceDoneExecuting(                      data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);            }    //...code}}
       第34行,调用mH.sendMessage(msg)发送一个消息。然后,第49行对消息进行处理,调用了handleBindService方法。
       第69行,若没有重新绑定服务,即初次绑定服务,则进入第70行。
       第70行,调用Service$onBind方法,返回Binder对象,并作为参数传递给publishService方法。
       第71行,在绑定服务以后,需要通知客户端已经成功连接Service了,这个操作由AMS的publishService方法来完成,后面会继续分析这里
       第74行,若重新绑定服务,则回调Service$onRebind方法。

五,通知客户端连接Service成功的操作,交给AMS

       查看ActivityManagerService$publishService方法源码:
public void publishService(IBinder token, Intent intent, IBinder service) {    //...    mServices.publishServiceLocked((ServiceRecord)token, intent, service);    //...}
       变量mServices是ActiveServices类型;

       查看ActiveServices$publishServiceLocked方法源码:
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {//...codec.conn.connected(r.name, service, false);//...code}
       c.conn是一个IServiceConnection类型的变量,还记得前面提到的InnerConnection类么,它便是AIDL接口IServiceConnection的实现类。
       查看LoadedApk$ServiceDispatcher$InnerConnection$connected源码:
public void connected(ComponentName name, IBinder service, boolean dead)    throws RemoteException {LoadedApk.ServiceDispatcher sd = mDispatcher.get();if (sd != null) {    sd.connected(name, service, dead);}}
       sd是ServiceDispatcher类型的变量;
       查看ServiceDispatcher$connected方法源码:
public void connected(ComponentName name, IBinder service, boolean dead) {    if (mActivityThread != null) {mActivityThread.post(new RunConnection(name, service, 0, dead));    } else {doConnected(name, service, dead);    }}
       mActivityThread是一个Handler类型的变量,mActivityThread的初始化在ServiceDispatcher构造方法中完成,它是最开始bindService时一步步传递过来的。mActivityThread就是ActivityThread的内部类H,因此mActivityThread不为空,代码执行到第3行,调用Handler$post方法。
       
       查看LoadedApk$ServiceDispatcher$RunConnection类的源码:
private final class RunConnection implements Runnable {    RunConnection(ComponentName name, IBinder service, int command, boolean dead) {mName = name;mService = service;mCommand = command;mDead = dead;    }    public void run() {if (mCommand == 0) {    doConnected(mName, mService, mDead);} else if (mCommand == 1) {    doDeath(mName, mService);}    }    final ComponentName mName;    final IBinder mService;    final int mCommand;    final boolean mDead;}
       RunConnection实现了接口Runnable,重写了run方法。ActivityThread是一个主线程,且执行final H mH = new H()创建了H对象,Looper对象是在ActivityThread$main方法中创建,于是run方法在主线程中执行。
       第11行,调用LoadedApk$ServiceDispatcher$doConnected方法;
       查看LoadedApk$ServiceDispatcher$doConnected源码:
public void doConnected(ComponentName name, IBinder service, boolean dead) {//...// If there is a new service, it is now connected.            if (service != null) {                mConnection.onServiceConnected(name, service);            }//...}
       第6行,回调ServiceConnection$onServiceConnected方法,通知客户端连接服务成功了。我们经常在该方法获取返回的Binder,调用远程服务接口的方法。值得一提的是,ServiceConnection$onServiceConnected方法的第二个参数service,就是返回给客户端的Binder对象。前面提到run方法在主线程中执行,因此ServiceConnection$onServiceConnected方法是在主线程中被回调。

六,最后
       到这里,绑定服务的流程分析就结束了。值得一提的是,先了解Activity,Service的启动流程对阅读本篇文章大有裨益哦~            ^_^
       Android Activity的启动流程源码解析(8.0)
       Android Service的启动流程源码分析(8.0)

                                             










       

        


       







阅读全文
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 梁山伯与祝英台民间故事 梁山伯与祝英台主要内容 梁山伯与祝英台完整故事 梁山伯与祝英台真实故事 民间故事梁山伯与祝英台 梁山伯与祝英台内容 梁山伯与祝英台全文 梁山伯与祝英台楼台会 梁山伯与祝英台故事缩写 梁山伯与祝英台故事全文 梁山伯与祝英台读后感 缩写梁山伯与祝英台 梁山伯与祝英台缩写300字 梁山伯祝英台的故事 祝英台与梁山伯故事 梁山伯与祝英台缩写400字 梁山伯与祝英台作者 梁山伯和祝英台故事 梁山伯与祝英台作文 梁山伯与祝英台缩写200 梁山伯祝英台真实故事 梁山伯与祝英台缩写400字左右 梁山伯与祝英台缩写作文 梁山伯与祝英台什么剧 梁山伯与祝英台100字心得体会 梁山伯与祝英台结局 梁山伯与祝英台有东方什么称 梁山伯与祝英台故事原文 梁山伯与祝英台图片 梁山伯与祝英台原文 七世夫妻之梁山伯与祝英台 梁山伯与祝英台剧种 越剧梁山伯与祝英台全剧老版 梁山伯与祝英台感想 祝英台与梁山伯的故事 梁山风景区门票多少钱 山东水泊梁山风景区 水泊梁山风景区好玩吗 山东梁山县 山东省梁山县邮编 梁山县属于山东哪个市