• bindService流程源码分析


    bindService流程源码分析

    一、简介

    bindService是应用用来与service进行绑定的。该方式启动的service系统认为只有在调用者的context存在时service才有必要运行,比如在activity中调用该方法且该activity处于stopped状态,那么其绑定的服务在activity返回前台前不会运行。
    还有就是不能在未注册的BroadcastReceiver调用该方法(只能通过startService来启动service),通过registerReceiver注册的广播可以调用因为此时BroadcastReceiver的生命周期已经和注册对象绑定了。

    二、源码分析

    bindService是在Context类中定义的具体实现则是在ContextImpl类中。

    public abstract boolean bindService(@RequiresPermission Intent service,
            @NonNull ServiceConnection conn, @BindServiceFlags int flags);
    
    public boolean bindService(Intent service, ServiceConnection conn,
            int flags) {
        warnIfCallingFromSystemProcess();
        return bindServiceCommon(service, conn, flags, mMainThread.getHandler(),
                Process.myUserHandle());
    }
    
    

    ContextImpl类中的bindService调用了bindServiceCommon做进一步处理。注意下传入的mMainThread.getHandler()参数,mMainThread是一个ActivityThread实例,所以此处获取的是ActivityThread所在线程的Handler,后面我们就可以通过这个handler把消息分发到ActivityThread线程的消息队列中。

    在bindServiceCommon中主要做了两件事一是获取一个IServiceConnection接口,二是调用AMS的远程接口bindService

    private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
            handler, UserHandle user) {
        // Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
        IServiceConnection sd;
        //1、调用getServiceDispatcher来获取一个IServiceConnection接口
        if (mPackageInfo != null) {
            sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
        } else {
            throw new RuntimeException("Not supported in system context");
        }
        try {
         //2、调用AMS的bindService
            service.prepareToLeaveProcess(this);
            int res = ActivityManager.getService().bindService(
                    mMainThread.getApplicationThread(), getActivityToken(), service,
                    service.resolveTypeIfNeeded(getContentResolver()),
                    sd, flags, getOpPackageName(), user.getIdentifier());
            return res != 0;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
    

    我们来分析下getServiceDispatcher获取IServiceConnection接口的过程。
    getServiceDispatcher主要做了以下事情:
    根据传入的context在mServices中查找是否已经存在对应的ServiceDispatcher实例,如果没有则创建并存入mServices,最后调用getIServiceConnection返回一个IServiceConnection,此处实际是一个InnerConnection实例,它是一个binder对象,后续AMS会用它和ServiceConnection通信

    public final IServiceConnection getServiceDispatcher(ServiceConnection c,
                                                         Context context, Handler handler, int flags) {
        synchronized (mServices) {
            LoadedApk.ServiceDispatcher sd = null;
            //1、根据传入的context在mServices中查找是否已经存在对应的ServiceDispatcher实例
            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) {
                //2、mServices中没有对应的ServiceDispatcher实例创建新实例
                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<>();
                    //3、存入mServices
                    mServices.put(context, map);
                }
                map.put(c, sd);
            } else {
                sd.validate(context, handler);
            }
            //4、getIServiceConnection返回一个IServiceConnection,此处实际是一个InnerConnection实例,它是一个binder对象后续AMS会用它和ServiceConnection通信
            return sd.getIServiceConnection();
        }
    }
    

    我们继续看下ServiceDispatcher的getIServiceConnection,他返回的是ServiceDispatcher.InnerConnection实例,这个是在ServiceDispatcher构造函数内创建的。

    static final class ServiceDispatcher {
        private final ServiceDispatcher.InnerConnection mIServiceConnection;
    //….
    IServiceConnection getIServiceConnection() {
        return mIServiceConnection;
    }
    
    ServiceDispatcher(ServiceConnection conn,
            Context context, Handler activityThread, int flags) {
        mIServiceConnection = new InnerConnection(this);//创建InnerConnection实例
        mConnection = conn;
        mContext = context;
        mActivityThread = activityThread;
        mLocation = new ServiceConnectionLeaked(null);
        mLocation.fillInStackTrace();
        mFlags = flags;
    }
    
    }
    

    最后贴下InnerConnection

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

    getServiceDispatcher之后就是调用AMS的bindService,如下所示:

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

    bindService做了一些检查后调用ActiveServices的bindServiceLocked。
    bindServiceLocked比较长我们只看关键部分。它的主要操作可以分为4步具体可以看下面的注释。

    int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
                          String resolvedType, final IServiceConnection connection, int flags,
                          String callingPackage, final int userId) throws TransactionTooLargeException {
        //…
        //1、首先会根据token找到其对应的ActivityRecord,我们之前说过ActivityRecord表示的是一个activity记录,此处指的是调用bindService的activity
        ActivityRecord activity = null;
        if (token != null) {
            activity = ActivityRecord.isInStackLocked(token);
            if (activity == null) {
                Slog.w(TAG, “Binding with unknown activity: “ + token);
                return 0;
            }
        }
        //…
        //2、调用retrieveServiceLocked解析传入的intent等参数获得一个ServiceRecord对象
        ServiceLookupResult res =
                retrieveServiceLocked(service, resolvedType, callingPackage, Binder.getCallingPid(),
                        Binder.getCallingUid(), userId, true, callerFg, isBindExternal);
        ServiceRecord s = res.record;
    
        //...
        //3、把传入的connection封装成一个ConnectionRecord对象,connection就是步骤3获得的InnerConnection,
        // 因为后续AMS需要使用它来告诉activity service已经启动起来了,所以要把它保存起来,这里保存在好几个地方
        //AppBindRecord中存储了当前ServiceRecord, intent以及发起方的进程信息。
        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是ServiceRecord.connections的成员变量
        clist.add(c);
         //b是指AppBindRecord
        b.connections.add(c);
        if (activity != null) {
            if (activity.connections == null) {
                activity.connections = new HashSet<ConnectionRecord>();
            }
            activity.connections.add(c);
        }
        b.client.connections.add(c);
    
        //...
        //4、最初绑定service时传入的flag是BIND_AUTO_CREATE,所以此处符合条件进而调用bringUpServiceLocked启动要绑定的service
        if ((flags&Context.BIND_AUTO_CREATE) != 0) {
            s.lastActivity = SystemClock.uptimeMillis();
            if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
                    permissionsReviewRequired) != null) {
                return 0;
            }
        }
        //…
        if (s.app != null) {
                if ((flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
                    s.app.treatLikeActivity = true;
                }
                //5、更新service所在进程的优先级
                mAm.updateLruProcessLocked(s.app, s.app.hasClientActivities
                        || s.app.treatLikeActivity, b.client);
                mAm.updateOomAdjLocked(s.app);
            }
    
            if (s.app != null && b.intent.received) {
                try {
                    //6、Service已经正在运行,则调用InnerConnection的代理对象
                    c.conn.connected(s.name, b.intent.binder);
                } catch (Exception e) {
                    ...
                }
                //7、当第一个app连接到该binding, 且之前已被bind过, 则回调onRebind()方法
                if (b.intent.apps.size() == 1 && b.intent.doRebind) {
                    requestServiceBindingLocked(s, b.intent, callerFg, true);
                }
            } else if (!b.intent.requested) {
                //8、最终回调onBind()方法
                requestServiceBindingLocked(s, b.intent, callerFg, false);
            }
        return 1;
    }
    

    bindServiceLocked做的事情比较多,我们再来梳理一下,首先在注释1处查找请求绑定的Activity是否存在,之后在注释2处通过retrieveServiceLocked查找对应的service。在注释3处创建AppBindRecord和ConnectionRecord,AppBindRecord记录着当前ServiceRecord, intent以及发起方的进程信息,ConnectionRecord则是对connection进行封装。创建完成后会把ConnectionRecord存到ServiceRecord和AppBindRecord中。注释4处通过bringUpServiceLocked来启动service,之后在注释5处更新service所在进程的优先级,在注释6处Service已经正在运行,调用InnerConnection的代理对象。注释7处判断是否回调onRebind方法。注释8处requestServiceBindingLocked最终回调onBind()方法。

    我们先来看下retrieveServiceLocked查找对应的service的过程,然后再看service绑定过程,至于service启动过程我们之前在startService的源码分析中已经说到过,具体可以参考startService过程源码分析.md

    retrieveServiceLocked如下所示:

        private ServiceLookupResult retrieveServiceLocked(Intent service,
                String resolvedType, String callingPackage, int callingPid, int callingUid, int userId,
                boolean createIfNeeded, boolean callingFromFg, boolean isBindExternal) {
                 ServiceRecord r = null;
                    if (comp != null) {
                //根据service名称查找ServiceRecord
                r = smap.mServicesByName.get(comp);
                if (DEBUG_SERVICE && r != null) Slog.v(TAG_SERVICE, "Retrieved by component: " + r);
            }
            ...
             if (r == null && !isBindExternal) {
                Intent.FilterComparison filter = new Intent.FilterComparison(service);
                //根据Intent查找相应的ServiceRecord
                r = smap.mServicesByIntent.get(filter);
                if (DEBUG_SERVICE && r != null) Slog.v(TAG_SERVICE, "Retrieved by intent: " + r);
            }
            ...
             //通过PKMS来查询相应的service
                    ResolveInfo rInfo = mAm.getPackageManagerInternalLocked().resolveService(service,
                            resolvedType, ActivityManagerService.STOCK_PM_FLAGS
                                    | PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
                            userId, callingUid);
                            
               ...
               //创建ServiceRecord对象
               r = new ServiceRecord(mAm, ss, name, filter, sInfo, callingFromFg, res);
               res.setService(r);
               smap.mServicesByName.put(name, r);
               smap.mServicesByIntent.put(filter, r);
               
               ...
               
                //各种权限检查,不满足条件则返回为null的service
                if (mAm.checkComponentPermission(r.permission,
                        callingPid, callingUid, r.appInfo.uid, r.exported) != PERMISSION_GRANTED) {
                    //当exported=false则不允许启动
                    if (!r.exported) {
                        Slog.w(TAG, "Permission Denial: Accessing service " + r.name
                                + " from pid=" + callingPid
                                + ", uid=" + callingUid
                                + " that is not exported from uid " + r.appInfo.uid);
                        return new ServiceLookupResult(null, "not exported from uid "
                                + r.appInfo.uid);
                    }
                    
      }
    

    Service查找过程:

    1. 根据服务名从ServiceMap.mServicesByName中查找相应的ServiceRecord,如果没有找到,则往下执行;
    2. 根据Intent从ServiceMap.mServicesByIntent中查找相应的ServiceRecord,如果还是没有找到,则往下执行;
    3. 通过PKMS来查询相应的ServiceInfo,如果仍然没有找到,则不再往下执行。

    接下来看下service的绑定:service的启动最终是在realStartServiceLocked里

    private final void realStartServiceLocked(ServiceRecord r,
                                              ProcessRecord app, boolean execInFg) throws RemoteException {
        //…
        //1、创建service
        app.thread.scheduleCreateService(r, r.serviceInfo,
                mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                app.repProcState);
        //...
        //2、调用requestServiceBindingsLocked
        requestServiceBindingsLocked(r, execInFg);
    
        //...
    
    }
    

    requestServiceBindingsLocked调用requestServiceBindingLocked来进一步处理,通过bindService方式启动的服务, 那么该serviceRecord的bindings则一定不会空。requestServiceBindingLocked里依次调用requestServiceBindingLocked。

    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函数如下所示:

    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;
        }
    
        if ((!i.requested || rebind) && i.apps.size() > 0) {
            try {
               //发送bind开始的消息
                bumpServiceExecutingLocked(r, execInFg, "bind");
                //调用ApplicationThread的scheduleBindService进入bind流程
                r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
                        r.app.repProcState);
            } catch (TransactionTooLargeException e) {
              //...               
            } catch (RemoteException e) {
                //… 
            }
        }
        return true;
    }
    

    我们看到它先发送了bind消息然后调用了ApplicationThread的scheduleBindService进入bind流程。

    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;
        //发送BIND_SERVICE message
        sendMessage(H.BIND_SERVICE, s);
    }
    
    public void handleMessage(Message msg) {
        case BIND_SERVICE:
        //BIND_SERVICE消息处理
        handleBindService((BindServiceData) msg.obj);
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    }
    

    在函数中发送了BIND_SERVICE消息,该消息的的处理是在handleBindService函数中,如下所示

    private void handleBindService(BindServiceData data) {
        //1、根据token获取要绑定的service
        Service s = mServices.get(data.token);
        if (s != null) {
            try {
                data.intent.setExtrasClassLoader(s.getClassLoader());
                data.intent.prepareToEnterProcess();
                try {
                    if (!data.rebind) {
                        //2、回调service的onBind
                        IBinder binder = s.onBind(data.intent);
                        //3、把步骤2得到的binder(即onBind的返回值)传递给AMS
                        ActivityManager.getService().publishService(
                                data.token, data.intent, binder);
                    } else {
                        s.onRebind(data.intent);
                        ActivityManager.getService().serviceDoneExecuting(
                                data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                    }
                    ensureJitEnabled();
                } catch (RemoteException ex) {
                    throw ex.rethrowFromSystemServer();
                }
            } catch (Exception e) {
               //…
            }
        }
    }
    

    在该函数中首先根据token获取要绑定的service,之后回调service的onBind拿到一个binder对象(这个binder就是onBind的返回值),最后传递给AMS。

    AMS的publishService如下所示:

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

    调用ActiveServices的publishServiceLocked方法

    void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
        final long origId = Binder.clearCallingIdentity();
        try {
            if (r != null) {
                Intent.FilterComparison filter
                        = new Intent.FilterComparison(intent);
                IntentBindRecord b = r.bindings.get(filter);
                if (b != null && !b.received) {
                    b.binder = service;
                    b.requested = true;
                    b.received = true;
                    for (int conni=r.connections.size()-1; conni>=0; conni—) {
                        //1、从ServiceRecord.connections中取出ConnectionRecord
                        ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
                        for (int I=0; I<clist.size(); I++) {
                            ConnectionRecord c = clist.get(i);
                            try {
                                //2、调用ConnectionRecord.conn.connected,此处的ConnectionRecord.conn是之前创建的LoadedApk.ServiceDispatcher.InnerConnection对象
                                c.conn.connected(r.name, service, false);
                            } catch (Exception e) {
                                //...
                            }
                        }
                    }
                }
            }
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
    }
    

    InnerConnection的connected函数如下所示:

    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) {
                //调用ServiceDispatcher的connected
                sd.connected(name, service, dead);
            }
        }
    }
    

    它调用了ServiceDispatcher的connected,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,通过该Handler post消息。

    RunConnection的run如下

    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进行绑定
                doConnected(mName, mService, mDead);
            } else if (mCommand == 1) {
                doDeath(mName, mService);
            }
        }
    
        final ComponentName mName;
        final IBinder mService;
        final int mCommand;
        final boolean mDead;
    } 
    

    doConnected函数如下:

    public void doConnected(ComponentName name, IBinder service, boolean dead) {
    
     if (service != null) {
                        // A new service is being connected... set it all up.
                        info = new ConnectionInfo();
                        info.binder = service;
                        //创建死亡监听对象
                        info.deathMonitor = new DeathMonitor(name, service);
                        try {
                           //建立死亡通知
                            service.linkToDeath(info.deathMonitor, 0);
                            mActiveConnections.put(name, info);
                        } catch (RemoteException e) {
                            // This service was dead before we got it...  just
                            // don't do anything with it.
                            mActiveConnections.remove(name);
                            return;
                        }
    
                    } else {
                        // The named service is being disconnected... clean up.
                        mActiveConnections.remove(name);
                    }
    
                    if (old != null) {
                        old.binder.unlinkToDeath(old.deathMonitor, 0);
                    }
                }
    
                // If there was an old service, it is now disconnected.
                if (old != null) {
                    mConnection.onServiceDisconnected(name);
                }
                if (dead) {
                    mConnection.onBindingDied(name);
                }
                // If there is a new service, it is now connected.
                if (service != null) {
                //回调onServiceConnected,至此我们就在绑定端的onServiceConnected回调函数中拿到service返回的binder了
                    mConnection.onServiceConnected(name, service);
                }
    }
    

    在doConnected函数中首先会创建死亡监听对象并建立死亡通知,之后会回调onServiceConnected。

    至此bindService的过程就结束了,总结来整个过程大概分为以下几步:
    1、首先调用bindService通知AMS绑定service,AMS会先启动service回调其onCreate函数。
    2、AMS启动service完成之后继续调用service的onBind函数,获取service返回的binder。
    3、AMS把上一步获得的Binder对象通过绑定时传入的ServiceConnection的onServiceConnected函数传给调用端,这样调用端就可以通过binder来调用service提供的相关方法。

    1. Client进程: 通过getServiceDispatcher获取Client进程的匿名Binder服务端,即LoadedApk.ServiceDispatcher.InnerConnection,该对象继承于IServiceConnection.Stub; 再通过bindService调用到system_server进程;
    2. system_server进程: 依次通过scheduleCreateService和scheduleBindService方法, 远程调用到target进程;
    3. target进程: 依次执行onCreate()和onBind()方法; 将onBind()方法的返回值IBinder(作为target进程的binder服务端)通过publishService传递到system_server进程;
    4. system_server进程: 利用IServiceConnection代理对象向Client进程发起connected()调用, 并把target进程的onBind返回Binder对象的代理端传递到Client进程;
    5. Client进程: 回调到onServiceConnection()方法, 该方法的第二个参数便是target进程的binder代理端. 到此便成功地拿到了target进程的代理, 可以畅通无阻地进行交互.

    参考:

    bindService启动过程分析

  • 相关阅读:
    实验楼挑战赛(1)-实现不可修改字典
    python django前端界面实现数据库数据excel导出
    python2中range和xrange的异同
    python的json模块的dumps,loads,dump,load方法介绍
    ajax500错误
    伪元素小tips
    使用css3制作蚂蚁线
    chardet坑——比蜗牛还慢
    Flask的socket.error:10053
    chrome插件开发-消息机制中的bug与解决方案
  • 原文地址:https://www.cnblogs.com/Robin132929/p/13786514.html
Copyright © 2020-2023  润新知