Android笔记-service启动过程分析:bindService源码分析、startService和bindService区别


前言:

Service的启动流程将会分为一个系列来讲述。
本系列开始将分析Service的启动过程。
看这个系列文章之前你所需要知道的知识点:
1. 熟悉service的基本用法。
2. 了解bind机制,知道android的客户端和AMS间通信流程。
3. 最好学习过activity的启动流程。

本系列将涉及到以下一些分支:
startService源码分析
bindService源码分析、startService和bindService区别
第二次startService为什么没有调用onCreate
为什么bindService和startService同时调用后需要同时调用unBind和stop才能使服务停止。
前台Service原理

今天这一篇将讲述bindService源码分析:


  • service启动过程分析
    • bindService源码分析
      • bindServicestartService区别
      • ServiceDispatchInnerConnection
      • AMS中的bindService
      • ServiceConnection的onServiceConnected流程
      • 总结

service启动过程分析

bindService源码分析

bindService、startService区别

分析bindService,不打算像startService一样,分析整个AMS流程。
因为两者的AMS流程很相似,所以打算结合startService流程,分析两者的不同之处。
首先我们要思考一下startService和bindService用法上有什么不同:
1. 服务端:

区别 startService bindService
生命周期 会调用onStartCommend 会调用onBind
返回值 onStartCommend没有返回值 onBind需要返回一个Bind类型的值

2. 客户端

区别 startService bindService
启动 用startService来启动startService 用bindService来启动bindService
参数 startService参数只需要一个Intent bindService参数多需要ServiceConnection
回调 没有回调 需要重写ServiceConnection的onServiceConnected方法

3、其他区别

区别 startService bindService
直接UI更新(非广播或eventbus等其他机制) 不可以 可以
跨进程 不可以 可以

区别大概就是以上几点。可以看出bindService和startService相比,多了一个bind机制,可以让Service和Activity之间相互通信。当然,主要目的是为了可以进行跨进程通信。

ServiceDispatch、InnerConnection

我们先从客户端的bindService方法开始看,
当然,客户端经过一系列调用最终会执行到ContextImpl的bindServiceCommon方法:

 private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
            handler, UserHandle user) {
        // Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
        IServiceConnection sd;//sd具体实现类是ServiceDispatch
        if (conn == null) {
            throw new IllegalArgumentException("connection is null");
        }
        if (mPackageInfo != null) {
        //新建一个ServiceDispatch.InnerConnection,第一个参数是:ServiceConnection
            sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
        } else {
            throw new RuntimeException("Not supported in system context");
        }
        //检查正确性
        validateServiceIntent(service);
        try {
            IBinder token = getActivityToken();
            if (token == null && (flags&BIND_AUTO_CREATE) == 0 && mPackageInfo != null
                    && mPackageInfo.getApplicationInfo().targetSdkVersion
                    < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                flags |= BIND_WAIVE_PRIORITY;
            }
            //Prepare this {@link Intent} to leave an app process. 跨进程通信准备
            service.prepareToLeaveProcess(this);
            //开始AMS通信,注意参数多了一个sd,该参数包含了ServiceConnection信息
            int res = ActivityManager.getService().bindService(
                mMainThread.getApplicationThread(), getActivityToken(), service,
                service.resolveTypeIfNeeded(getContentResolver()),
                sd, flags, getOpPackageName(), user.getIdentifier());
            if (res < 0) {
                throw new SecurityException(
                        "Not allowed to bind to service " + service);
            }
            return res != 0;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

bindServiceCommon相比startServiceCommend多了一步sd参数的生成。sd参数是什么?怎么生成的呢?
先来看下获取sd的方法mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);

 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) {
            //用ServiceConnection生成一个LoadedApk.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<>();
                    mServices.put(context, map);
                }
                map.put(c, sd);
            } else {
                sd.validate(context, handler);
            }
            return sd.getIServiceConnection();//获取InnerConnection
        }
    }

ServiceDispatcher的getIServiceConnection方法

        private final ServiceDispatcher.InnerConnection mIServiceConnection;
        ..
        IServiceConnection getIServiceConnection() {
            return mIServiceConnection;
        }

从上面两段代码我们看到sd原来是一个IServiceConnection。看上去是一个跨进程通信的玩意儿。

这里涉及到三个类(LoadedApk,ServiceDispatch,InnerConnection)、一个接口IServiceConnection:
LoadedApk,ServiceDispatch,InnerConnection关系如下:
Android笔记-service启动过程分析:bindService源码分析、startService和bindService区别_第1张图片
LoadedApk: Local state maintained about a currently loaded .apk.:保持当前加载的.apk的本地状态。
ServiceDispatch:它是LoadedApk内部类,其构造函数:

 ServiceDispatcher(ServiceConnection conn,
                Context context, Handler activityThread, int flags) {
            mIServiceConnection = new InnerConnection(this);//用自己新建一个InnerConnection
            mConnection = conn;//保存了ServiceConnection
            mContext = context;
            mActivityThread = activityThread;
            mLocation = new ServiceConnectionLeaked(null);
            mLocation.fillInStackTrace();
            mFlags = flags;
        }

InnerConnection:它是ServiceDispatch内部类,继承了IServiceConnection.Stub,可以跨进程通信,其源码:

  private static class InnerConnection extends IServiceConnection.Stub {//继承IServiceConnection.Stub,可以跨进程
            final WeakReference mDispatcher;

            InnerConnection(LoadedApk.ServiceDispatcher sd) {
                mDispatcher = new WeakReference(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);
                }
            }
        }

InnerConnection持有了一个ServiceDispatcher,且该connected方法执行的是ServiceDispatcher的connected方法。再看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);
            }
        }

可以看到connected方法会会执行RunConnection的run()方法或者doConnected方法,再看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;
        }

可以看到最终会执行doConnected方法,doConnected方法源码:

public void doConnected(ComponentName name, IBinder service, boolean dead) {
            ServiceDispatcher.ConnectionInfo old;
            ServiceDispatcher.ConnectionInfo info;

            ...省略一些代码

            // 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) {
                 //执行ServiceConnection的onServiceConnected
                 mConnection.onServiceConnected(name, service);
            }
        }

最终会执行ServiceConnection的onServiceConnected方法。
至于为什么这么麻烦的使用这么多类来生成一个sd,主要是因为涉及到跨进程通信,而ServiceConnection并不能进行跨进程通信,只能用ServiceDispatcher.InnerConnection来保存其信息,进行跨进程通信。

以上分析了ServiceConnection是如何被封装成ServiceDispatcher.InnerConnection的。
我们只要知道2点:
1. 由于ServiceConnection不能跨进程,所以使用了ServiceDispatcher.InnerConnection来保存ServiceConnection的信息,
2. ServiceDispatcher.InnerConnection执行connected方法会执行ServiceConnection的onServiceConnected方法。

记住以上两点,在后面的onServiceConnected我们流程中会用到,继续回头看,下面会进行跨进程通信。

AMS中的bindService

调用AMS的bindService,经过一系列调用最终同样会走到realStartServiceLocked。具体调用了哪些方法可以看时序图。总结如下:
bindService(ActivityManagerService)—bindServiceLocked(ActiveServices)—-bringUpServiceLocked(ActiveServices)—-realStartServiceLocked(ActiveServices)。
最终执行的realStartServiceLocked方法,其实在startService中最终也是realStartServiceLocked方法。很神奇,怎么都走了这个方法?为什么后面客户端的流程会不一样呢(startService执行了onStartCommend,bindService执行了onBind)?那么我们再来回顾一下realStartServiceLocked方法吧:

 private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {
        if (app.thread == null) {
            throw new RemoteException();
        }
        if (DEBUG_MU)
            Slog.v(TAG_MU, "realStartServiceLocked, ServiceRecord.uid = " + r.appInfo.uid
                    + ", ProcessRecord.uid = " + app.uid);
        r.app = app;
        r.restartTime = r.lastActivity = SystemClock.uptimeMillis();

        final boolean newService = app.services.add(r);
        bumpServiceExecutingLocked(r, execInFg, "create");
        mAm.updateLruProcessLocked(app, false, null);
        mAm.updateOomAdjLocked();

        boolean created = false;
        try {
            if (LOG_SERVICE_START_STOP) {
                String nameTerm;
                int lastPeriod = r.shortName.lastIndexOf('.');
                nameTerm = lastPeriod >= 0 ? r.shortName.substring(lastPeriod) : r.shortName;
                EventLogTags.writeAmCreateService(
                        r.userId, System.identityHashCode(r), nameTerm, r.app.uid, r.app.pid);
            }
            synchronized (r.stats.getBatteryStats()) {
                r.stats.startLaunchedLocked();
            }
            mAm.notifyPackageUse(r.serviceInfo.packageName,
                                 PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
            app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
           //会调用onCreate方法
            app.thread.scheduleCreateService(r, r.serviceInfo,
                    mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                    app.repProcState);
            r.postNotification();
            created = true;
        } catch (DeadObjectException e) {
            Slog.w(TAG, "Application dead when creating service " + r);
            mAm.appDiedLocked(app);
            throw e;
        } finally {
            if (!created) {
                // Keep the executeNesting count accurate.
                final boolean inDestroying = mDestroyingServices.contains(r);
                serviceDoneExecutingLocked(r, inDestroying, inDestroying);

                // Cleanup.
                if (newService) {
                    app.services.remove(r);
                    r.app = null;
                }

                // Retry.
                if (!inDestroying) {
                    scheduleServiceRestartLocked(r, false);
                }
            }
        }

        if (r.whitelistManager) {
            app.whitelistManager = true;
        }
//后续onBind方法会调用
        requestServiceBindingsLocked(r, execInFg);

        updateServiceClientActivitiesLocked(app, null, true);

        // If the service is in the started state, and there are no
        // pending arguments, then fake up one so its onStartCommand() will
        // be called.
        if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
            r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
                    null, null));
        }
//后续onStartCommend方法会调用
        sendServiceArgsLocked(r, execInFg, true);

        if (r.delayed) {
            if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "REM FR DELAY LIST (new proc): " + r);
            getServiceMap(r.userId).mDelayedStartList.remove(r);
            r.delayed = false;
        }

        if (r.delayedStop) {
            // Oh and hey we've already been asked to stop!
            r.delayedStop = false;
            if (r.startRequested) {
                if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
                        "Applying delayed stop (from start): " + r);
                stopServiceLocked(r);
            }
        }
    }

注意requestServiceBindingsLocked方法,它后续会调用bindService。


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

该方法用到了r.bindings。它是一个ArrayMap,保存了客户端的bind消息:

final ArrayMap<Intent.FilterComparison, IntentBindRecord> bindings
            = new ArrayMap<Intent.FilterComparison, IntentBindRecord>();

哈哈,前文中的卖得关子现在看到了,原来是用r.bindings来判断是否执行onBind方法的啊~。
具体保存方法在AMS一开始的方法bindServiceLocked中:

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

            ...
//该方法给bindings赋值
            AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);

            ....



        return 1;
    }
  public AppBindRecord retrieveAppBindingLocked(Intent intent,
            ProcessRecord app) {
        Intent.FilterComparison filter = new Intent.FilterComparison(intent);
        IntentBindRecord i = bindings.get(filter);
        if (i == null) {
            i = new IntentBindRecord(this, filter);
            bindings.put(filter, i);
        }
        AppBindRecord a = i.apps.get(app);
        if (a != null) {
            return a;
        }
        a = new AppBindRecord(this, i, app);
        i.apps.put(app, a);
        return a;
    }

这里可以看到bindings里面保存了IntentBindRecord记录。IntentBindRecord保存的是intent。
requestServiceBindingsLocked通过循环取出该记录,执行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 {
                bumpServiceExecutingLocked(r, execInFg, "bind");
                r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
               //调用客户端的scheduleBindService方法
                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) {
                // Keep the executeNesting count accurate.
                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while binding " + r, e);
                final boolean inDestroying = mDestroyingServices.contains(r);
                serviceDoneExecutingLocked(r, inDestroying, inDestroying);
                throw e;
            } catch (RemoteException e) {
                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while binding " + r);
                // Keep the executeNesting count accurate.
                final boolean inDestroying = mDestroyingServices.contains(r);
                serviceDoneExecutingLocked(r, inDestroying, inDestroying);
                return false;
            }
        }
        return true;
    }

这里值得注意的是:
1. startService流程也会执行到requestServiceBindingsLocked方法,可是由于没有给bindings赋值,所以不会执行循环里的requestServiceBindingLocked方法。即不会执行onBind方法
2. bindService流程执行requestServiceBindingsLocked后,会继续执行sendServiceArgsLocked方法,通过startService流程解析,我们知道该方法后续会执行onStartCommend。执行onStartCommend的标识是pendingStarts这个记录。在前文中有提到记录如何赋值的。bindService流程并没有给其赋值。所以bindService并不会执行onStartCommend方法。

我们再看requestServiceBindingLocked方法又开始执行客户端ActivityThread中的方法: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);
        }

ServiceConnection的onServiceConnected流程

后面的流程和startService在客户端流程一致,会调用到ActivityThread中的方法handleBindService:

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) {
            try {
                data.intent.setExtrasClassLoader(s.getClassLoader());
                data.intent.prepareToEnterProcess();
                try {
                    if (!data.rebind) {
                    //执行客户端-server的onBind方法,并返回IBinder
                        IBinder binder = s.onBind(data.intent);
                        //注意:又一个AMS流程,用返回的IBinder调用客户端-client的onServiceConnected
                        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) {
                    throw ex.rethrowFromSystemServer();
                }
            } catch (Exception e) {
                if (!mInstrumentation.onException(s, e)) {
                    throw new RuntimeException(
                            "Unable to bind to service " + s
                            + " with " + data.intent + ": " + e.toString(), e);
                }
            }
        }
    }

这里相比startService不同的是:ActivityManagerNative.getDefault().publishService(data.token, data.intent, binder);方法。该方法其实又是AMS流程,最终调用客户端-client的onServiceConnected方法。
那么我们看下具体是怎么实现的吧。经过一系列调用,最终会执行ActiveServices的publishServiceLocked方法:

void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
        final long origId = Binder.clearCallingIdentity();
        try {
            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "PUBLISHING " + r
                    + " " + intent + ": " + service);
            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--) {
                        ArrayList clist = r.connections.valueAt(conni);
                        for (int i=0; i
                            ConnectionRecord c = clist.get(i);
                            if (!filter.equals(c.binding.intent.intent)) {
                                if (DEBUG_SERVICE) Slog.v(
                                        TAG_SERVICE, "Not publishing to: " + c);
                                if (DEBUG_SERVICE) Slog.v(
                                        TAG_SERVICE, "Bound intent: " + c.binding.intent.intent);
                                if (DEBUG_SERVICE) Slog.v(
                                        TAG_SERVICE, "Published intent: " + intent);
                                continue;
                            }
                            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Publishing to: " + c);
                            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);
                            }
                        }
                    }
                }

                serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false);
            }
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
    }

关键代码是c.conn.connected(r.name, service);这里的c是一个ConnectionRecord。是从ServiceRecord中的connections获取的。connections是在哪里赋值的呢?其实还是在一开始的bindServiceLocked方法里:

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



            ...
            //生成ConnectionRecord作为value
            ConnectionRecord c = new ConnectionRecord(b, activity,
                    connection, flags, clientLabel, clientIntent);
            IBinder binder = connection.asBinder();//获取 InnerConnection,作为key
            ArrayList clist = s.connections.get(binder);
            if (clist == null) {
                clist = new ArrayList();
                s.connections.put(binder, clist);//给connections赋值
            }
            clist.add(c);
            ....



        return 1;
    }

注意这里的connection参数,其实它就是文章一开始说的InnerConnection。
ConnectionRecord类保存了该connection。最终在publishServiceLocked里面循环取出并调用connection的connected方法。文章开头已经知道该方法最终会执行ServiceConnection的onServiceConnected方法。

至此bindService整个流程结束。

总结:

  1. startService和bindService在AMS中最后都会执行到realStartServiceLocked方法。
  2. realStartServiceLocked中会依次执行requestServiceBindingsLocked、sendServiceArgsLocked方法
  3. requestServiceBindingsLocked:通过循环IntentBindRecord记录来执行onBind方法
  4. sendServiceArgsLocked:通过循环pendingStarts记录来执行onStartCommend方法
  5. IntentBindRecord记录在bindServiceLocked中赋值
  6. pendingStarts(StartItem)记录在startServiceLocked中赋值
  7. bindService流程执行onBind后,会比startService流程多一步,调用onServiceConnected方法,该步骤也是一个AMS调用过程。用到了ServiceDispatch类。

你可能感兴趣的:(android)