Android 系统系列 Service启动流程

-

本文为Android 系统相关系列的一部分

使用service的方法要么是startService要么是bindService,要么混合使用,这里分别讲解两个方法的流程


startService 启动

  • 我们平时调用的startService方法,来自ContextWrapper,它是Activity和Service的父类,android中的Context是包装模式的一个实例,这里不讲解设计模式,还是直接看代码,该方法中使用的mBase,在上一篇中讲到是ContextImpl的实例
public class ContextWrapper extends Context{

Context mBase;

//...
@Override
    public ComponentName startService(Intent service) {
        return mBase.startService(service);
    }
//...
}
  • 这里ActivityManager.getService()获取到的是AMS的代理类IActivityManager,因此这里会调用到AMS的startService方法
/frameworks/base/core/java/android/app/ContextImpl.java
    @Override
    public ComponentName startService(Intent service) {
        warnIfCallingFromSystemProcess();
        return startServiceCommon(service, false, mUser);
    }

private ComponentName startServiceCommon(Intent service, boolean requireForeground,
            UserHandle user) {
        try {
            validateServiceIntent(service);
            service.prepareToLeaveProcess(this);
            ComponentName cn = ActivityManager.getService().startService(
                mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
                            getContentResolver()), requireForeground,
                            getOpPackageName(), user.getIdentifier());

//...           
          return cn;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
  • AMS的startService方法调用的是ActiveServices类的startServiceLocked方法,后者负责查找service的描述类ServiceRecord并启动service,ServiceRecord的作用和之前看到的ActivityRecord,TaskRecord,ProcessRecord类是类似的
@Override
public ComponentName startService(IApplicationThread caller, Intent service,
        String resolvedType, boolean requireForeground, String callingPackage, int userId)
        throws TransactionTooLargeException {

    //…
    synchronized(this) {
        final int callingPid = Binder.getCallingPid();
        final int callingUid = Binder.getCallingUid();
        final long origId = Binder.clearCallingIdentity();
        ComponentName res;
        try {
            res = mServices.startServiceLocked(caller, service,
                    resolvedType, callingPid, callingUid,
                    requireForeground, callingPackage, userId);
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
        return res;
    }
}
  • startServiceLocked的流程大致是,先从缓存中查找serviceRecord,这里的缓存是一个类型为ServiceMap的稀疏数组,数组的键为userId,ServiceMap则是一个handler,内部持有存放serviceRecord的ArrayMap,如果在缓存中找不到service,则会通过PackageManagerService去获取对应的参数,然后封装为serviceRecord。查找到service后会调用到bringUpServiceLocked
  final SparseArray<ServiceMap> mServiceMap = new SparseArray<>();

ServiceRecord getServiceByNameLocked(ComponentName name, int callingUser) {

        //…

        ServiceLookupResult res =
            retrieveServiceLocked(service, resolvedType, callingPackage,
                    callingPid, callingUid, userId, true, callerFg, false);
        if (res == null) {
            return null;
        }
        if (res.record == null) {
            return new ComponentName("!", res.permission != null
                    ? res.permission : "private to package");
        }

        ServiceRecord r = res.record;
        //…
   ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
        return cmp;
    }
  • bringUpServiceLocked方法会查找service需要运行在的进程,这里和启动Activity过程的startSpecificActivityLocked方法类似,获取进程的方法是AMS的getProcessRecordLocked,如果进程存在则通过realStartServiceLocked来启动service,如果需要的进程不存在则会调用AMS.startProcessLocked来创建进程,方法的参数则简单地从serviceRecord中获取,service的进程可以使用android:process来指定,我们前面分析过startProcessLocked会导AMS向Zygote发送请求fork一个子进程,并阻塞直到其被创建完成并写回一个pid,程已经fork完毕,注意这里并不是说应用进程就创建完毕了,因为这里是多进程的环境,我们不能在startProcessLocked返回时去处理启动或绑定service的逻辑,而是应该放到应用进程执行ActivityThread的attach方法绑定到AMS之后。这里我们只关注应用进程以及启动的情况,在bindService中我们会去看需要启动应用进程的情况
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
          boolean whileRestarting, boolean permissionsReviewRequired)
          throws TransactionTooLargeException {

      //...
      final String procName = r.processName;
      String hostingType = "service";
      ProcessRecord app;

      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.
          }
      } else {
          app = r.isolatedProc;
          if (WebViewZygote.isMultiprocessEnabled()
                  && r.serviceInfo.packageName.equals(WebViewZygote.getPackageName())) {
              hostingType = "webview_service";
          }
      }

      // Not running -- get it started, and enqueue this service record
      // to be executed when the app comes up.
      if (app == null && !permissionsReviewRequired) {
          if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
                  hostingType, r.name, false, isolated, false)) == null) {
              String msg = "Unable to launch app "
                      + r.appInfo.packageName + "/"
                      + r.appInfo.uid + " for service "
                      + r.intent.getIntent() + ": process is bad";
              Slog.w(TAG, msg);
              bringDownServiceLocked(r);
              return msg;
          }
          if (isolated) {
              r.isolatedProc = app;
          }
      }

  //…
      return null;
  }
  • 这里只考虑应用进程存在的情况,不管在哪个进程启动什么activity或service都需要跨进程,因为AMS运行在system server进程当中,这里直接调用的是realStartServiceLocked方法,这个方法不只是在startService时会调用,而是会视情况导致onCreate,onStart和onBind被执行,它调用app.thread的scheduleCreateService方法,上一篇讲过这个app.thread就是为IApplicationThread的binder对象,scheduleCreateService方法会导致service的onCreate被调用,再往后看出现了sendServiceArgsLocked,这个方法则会导致onStartCommand被调用,这里都是通过app.thread的scheduleXXX进行的,由于再ActivityThread中最终是用handler来实现生命周期方法的调用,按照sendMessage的先后顺序onCreate和onStartcommand也先后执行
private final void realStartServiceLocked(ServiceRecord r, ProcessRecord app, boolean execInFg) throws RemoteException {
    //…
    try {
    //…
        app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
        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 (r.whitelistManager) {
        app.whitelistManager = true;
    }

    requestServiceBindingsLocked(r, execInFg);

    updateServiceClientActivitiesLocked(app, null, true);

    if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
        r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
                null, null, 0));
    }

    sendServiceArgsLocked(r, execInFg, true);

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

    if (r.delayedStop) {
        r.delayedStop = false;
        if (r.startRequested) {
            if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
                    "Applying delayed stop (from start): " + r);
            stopServiceLocked(r);
        }
    }
}
  • ActivityThread中的handler处理消息的部分没有什么特别的地方,我们直接看处理创建service的请求的方法handleCreateService,这里和Activity的创建也有很多类似的地方,主要流程是,获取loadedApk,使用classloader创建service,创建ContextImpl并绑定到service的mbase成员,调用service的onCreate方法,将service放入ActivityThread的成员mServices中,到这里startservice的流程就结束了
private void handleCreateService(CreateServiceData data) {
    // If we are getting ready to gc after going to the background, well
    // we are back active so skip it.
    unscheduleGcIdler();

    LoadedApk packageInfo = getPackageInfoNoCheck(
            data.info.applicationInfo, data.compatInfo);
    Service service = null;
    try {
        java.lang.ClassLoader cl = packageInfo.getClassLoader();
        service = (Service) cl.loadClass(data.info.name).newInstance();
    } catch (Exception e) {
        if (!mInstrumentation.onException(service, e)) {
            throw new RuntimeException(
                "Unable to instantiate service " + data.info.name
                + ": " + e.toString(), e);
        }
    }

    try {
        if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);

        ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
        context.setOuterContext(service);

        Application app = packageInfo.makeApplication(false, mInstrumentation);
        service.attach(context, this, data.info.name, data.token, app,
                ActivityManager.getService());
        service.onCreate();
        mServices.put(data.token, service);
        try {
            ActivityManager.getService().serviceDoneExecuting(
                    data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    } catch (Exception e) {
        if (!mInstrumentation.onException(service, e)) {
            throw new RuntimeException(
                "Unable to create service " + data.info.name
                + ": " + e.toString(), e);
        }
    }
}


bindService 绑定

  • 我们调用的bindService同样由ContextWrapper实现,同样由contextImpl实现
@Override
public boolean bindService(Intent service, ServiceConnection conn,
        int flags) {
    return mBase.bindService(service, conn, flags);
}

@Override
public boolean bindService(Intent service, ServiceConnection conn,
        int flags) {
    warnIfCallingFromSystemProcess();
    return bindServiceCommon(service, conn, flags, mMainThread.getHandler(),
            Process.myUserHandle());
}
  • 这里的bindServiceCommon主要是通过LoadedApk对象的getServiceDispatcher方法来获取一个binder对象,之前的源码解析中AMS和ActivityThread的通信主要是依赖IApplicationThread,但这里还多了一个IServiceConnection,实现类为ServiceDispatcher.InnerConnection(方法名不是很直观,getServiceDispatcher返回这个对象),它主要封装了ServiceConnection对象,用来在AMS中跨进程调用onServiceConnected。获取完binder对象之后通过ActivityManager获取到AMS并调用bindService,和startService是一个模式了
    private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
            handler, UserHandle user) {
        // Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
        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");
        }
        validateServiceIntent(service);
        try {
//...
            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();
        }
    }
  • AMS的bindService方法比较简单,只是进行了异常判断然后调用了ActiveService的bindServiceLocked,说一下文件描述符这点,这里不允许向AMS传递fd是因为多进程共享fd时容易导致fd leaks,因为binder是可以传递文件描述符的,binder多进程共享fd实质上是由parcel去管理fd,接受未知的fd是毫无必要的,容易导致太多文件未关闭而抛出异常(一个进程一般最多只能用于1024个fd)
public int bindService(IApplicationThread caller, IBinder token, Intent service,
        String resolvedType, IServiceConnection connection, int flags, String callingPackage,
        int userId) throws TransactionTooLargeException {
    enforceNotIsolatedCaller("bindService");

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

    if (callingPackage == null) {
        throw new IllegalArgumentException("callingPackage cannot be null");
    }

    synchronized(this) {
        return mServices.bindServiceLocked(caller, token, service,
                resolvedType, connection, flags, callingPackage, userId);
    }
}
  • bindServiceLocked这是一个非常重要的方法,bindService的核心步骤在这里展开,因此该方法中调用的几个方法我们都需要关注,先来讲一下这个方法里发生了什么,这个方法里首先会调用retrieveServiceLocked来获取serviceRecord对象,这一步之前讲过了所以略去,之后的retrieveAppBindingLocked用于来获取一个AppBindRecord,AppBindRecord负责维护service与应用进程,然后调用bringUpServiceLocked来启动一个service,如果应用进程存在,直接调用IServviceConnection对象的connected实现onConnected的调用,最后调用requestServiceBindingLocked来实现onBind方法的调用,如果进程不存在则会走创建应用进程的流程,这里的s.app都为null,后面的大部分操作都不会执行
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
    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) {
            if (activity.connections == null) {
                activity.connections = new HashSet<ConnectionRecord>();
            }
            activity.connections.add(c);
        }
        b.client.connections.add(c);
        if ((c.flags&Context.BIND_ABOVE_CLIENT) != 0) {
            b.client.hasAboveClient = true;
        }
        if ((c.flags&Context.BIND_ALLOW_WHITELIST_MANAGEMENT) != 0) {
            s.whitelistManager = true;
        }
        if (s.app != null) {
            updateServiceClientActivitiesLocked(s.app, c, true);
        }
        clist = mServiceConnections.get(binder);
        if (clist == null) {
            clist = new ArrayList<ConnectionRecord>();
            mServiceConnections.put(binder, clist);
        }
        clist.add(c);

        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;
            }
            if (s.whitelistManager) {
                s.app.whitelistManager = true;
            }
            // This could have made the service more important.
            mAm.updateLruProcessLocked(s.app, s.app.hasClientActivities
                    || s.app.treatLikeActivity, b.client);
            mAm.updateOomAdjLocked(s.app, true);
        }

        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);
        }
        getServiceMapLocked(s.userId).ensureNotStartingBackgroundLocked(s);

    } finally {
        Binder.restoreCallingIdentity(origId);
    }
    return 1;
}
  • 先来看retrieveAppBindingLocked,AppBindRecord内部存储了绑定service的应用进程,被绑定的service,绑定时使用的intent,所有相关的connection,retrieveAppBindingLocked只负责获取已存在的AppBindRecord或创建新AppBindRecord并放入缓存,还是比较简单明了的
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;
    }


final class AppBindRecord {
    final ServiceRecord service;    // The running service.
    final IntentBindRecord intent;  // The intent we are bound to.
    final ProcessRecord client;     // Who has started/bound the service.

    final ArraySet<ConnectionRecord> connections = new ArraySet<>();
                                    // All ConnectionRecord for this client.
  • bringUpServiceLocked用于拉起一个service,如果是service所在进程已经启动,这里会调用realStartServiceLocked来启动service,这个方法我们上一节也讲过,他会导致onCreate被调用,onStartCommand视情况被调用(这里是bindService,所以不会调用)
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
        boolean whileRestarting, boolean permissionsReviewRequired)
        throws TransactionTooLargeException {
    //Slog.i(TAG, "Bring up service:");
    //r.dump("  ");

    if (r.app != null && r.app.thread != null) {
        sendServiceArgsLocked(r, execInFg, false);
        return null;
    }

    if (!whileRestarting && mRestartingServices.contains(r)) {
        // If waiting for a restart, then do nothing.
        return null;
    }

    if (DEBUG_SERVICE) {
        Slog.v(TAG_SERVICE, "Bringing up " + r + " " + r.intent + " fg=" + r.fgRequired);
    }

    // We are now bringing the service up, so no longer in the
    // restarting state.
    if (mRestartingServices.remove(r)) {
        clearRestartingIfNeededLocked(r);
    }

    // Make sure this service is no longer considered delayed, we are starting it now.
    if (r.delayed) {
        if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "REM FR DELAY LIST (bring up): " + r);
        getServiceMapLocked(r.userId).mDelayedStartList.remove(r);
        r.delayed = false;
    }

    // Make sure that the user who owns this service is started.  If not,
    // we don't want to allow it to run.
    if (!mAm.mUserController.hasStartedUserState(r.userId)) {
        String msg = "Unable to launch app "
                + r.appInfo.packageName + "/"
                + r.appInfo.uid + " for service "
                + r.intent.getIntent() + ": user " + r.userId + " is stopped";
        Slog.w(TAG, msg);
        bringDownServiceLocked(r);
        return msg;
    }

    // Service is now being launched, its package can't be stopped.
    try {
        AppGlobals.getPackageManager().setPackageStoppedState(
                r.packageName, false, r.userId);
    } catch (RemoteException e) {
    } catch (IllegalArgumentException e) {
        Slog.w(TAG, "Failed trying to unstop package "
                + r.packageName + ": " + e);
    }

    final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
    final String procName = r.processName;
    String hostingType = "service";
    ProcessRecord app;

    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.
        }
    } else {
        // If this service runs in an isolated process, then each time
        // we call startProcessLocked() we will get a new isolated
        // process, starting another process if we are currently waiting
        // for a previous process to come up.  To deal with this, we store
        // in the service any current isolated process it is running in or
        // waiting to have come up.
        app = r.isolatedProc;
        if (WebViewZygote.isMultiprocessEnabled()
                && r.serviceInfo.packageName.equals(WebViewZygote.getPackageName())) {
            hostingType = "webview_service";
        }
    }

    // Not running -- get it started, and enqueue this service record
    // to be executed when the app comes up.
    if (app == null && !permissionsReviewRequired) {
        if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
                hostingType, r.name, false, isolated, false)) == null) {
            String msg = "Unable to launch app "
                    + r.appInfo.packageName + "/"
                    + r.appInfo.uid + " for service "
                    + r.intent.getIntent() + ": process is bad";
            Slog.w(TAG, msg);
            bringDownServiceLocked(r);
            return msg;
        }
        if (isolated) {
            r.isolatedProc = app;
        }
    }

    if (!mPendingServices.contains(r)) {
        mPendingServices.add(r);
    }

    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 (in bring up): " + r);
            stopServiceLocked(r);
        }
    }

    return null;
}
  • 我们现在来看需要启动应用进程的情况是怎么实现的,在系统启动一篇中的应用进程启动中我们提到attachApplicationLocked(它是由ActivityThread的main方法间接调用的)使用mServices.attachApplicationLocked来关联service,这个mServices就是我们本文出现得最多的ActiveServices
if (!badApp) {
      try {
          didSomething |= mServices.attachApplicationLocked(app, processName);
          checkTime(startTime, "attachApplicationLocked: after mServices.attachApplicationLocked");
      } catch (Exception e) {
          Slog.wtf(TAG, "Exception thrown starting services in " + app, e);
          badApp = true;
      }
  }
  • attachApplicationLocked方法,这里获取了mPendingServices中的serviceRecord,这些serviceRecord是在bringUpServiceLocked是发现应用进程没有创建时加进去的,现在就一个个取出来调用 realStartServiceLocked来启动service
boolean attachApplicationLocked(ProcessRecord proc, String processName)
            throws RemoteException {
        boolean didSomething = false;
        // Collect any services that are waiting for this process to come up.
        if (mPendingServices.size() > 0) {
            ServiceRecord sr = null;
            try {
                for (int i=0; i<mPendingServices.size(); i++) {
                    sr = mPendingServices.get(i);
                    if (proc != sr.isolatedProc && (proc.uid != sr.appInfo.uid
                            || !processName.equals(sr.processName))) {
                        continue;
                    }

                    mPendingServices.remove(i);
                    i--;
                    proc.addPackage(sr.appInfo.packageName, sr.appInfo.versionCode,
                            mAm.mProcessStats);
                    realStartServiceLocked(sr, proc, sr.createdFromFg);
                    didSomething = true;
                    if (!isServiceNeededLocked(sr, false, false)) {
                        // We were waiting for this service to start, but it is actually no
                        // longer needed.  This could happen because bringDownServiceIfNeeded
                        // won't bring down a service that is pending...  so now the pending
                        // is done, so let's drop it.
                        bringDownServiceLocked(sr);
                    }
                }
            } catch (RemoteException e) {
                Slog.w(TAG, "Exception in new application when starting service "
                        + sr.shortName, e);
                throw e;
            }
        }
        // Also, if there are any services that are waiting to restart and
        // would run in this process, now is a good time to start them.  It would
        // be weird to bring up the process but arbitrarily not let the services
        // run at this point just because their restart time hasn't come up.
        if (mRestartingServices.size() > 0) {
            ServiceRecord sr;
            for (int i=0; i<mRestartingServices.size(); i++) {
                sr = mRestartingServices.get(i);
                if (proc != sr.isolatedProc && (proc.uid != sr.appInfo.uid
                        || !processName.equals(sr.processName))) {
                    continue;
                }
                mAm.mHandler.removeCallbacks(sr.restarter);
                mAm.mHandler.post(sr.restarter);
            }
        }
        return didSomething;
    }
  • realStartServiceLocked中onCreate的调用我们已经分析过了,现在来分析onBind,在realStartServiceLocked间接调用的requestServiceBindingLocked方法中i.requested表示该service是否被绑定过,rebind表示是否需要调用重新绑定,rebind会在unbind调用过之后被设置为真,然后它调用ActivityThread的scheduleBindService,注意这个时候Looper的loop方法可能还没有调用,不过由于消息队列的机制,onCreate总会在onBind之前调用
  private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
            boolean execInFg, boolean rebind) throws TransactionTooLargeException {


        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) {
                // 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) {
//...
            }
        }
        return true;
    }
  • ActivityThread的handleBindService中调用了service的onBind方法,然后再一下connected方法是在哪里被调用的,一个是在bindServiceLocked中,我们已经知道了,对应应用进程已启动的情况,在未启动的情况下,则由在AMS的publishService
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) {
                       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);
                   }
                   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);
               }
           }
       }
   }
  • AMS会调用ActivityServices的publishServiceLocked方法,这个方法的缩进比较迷,但我们还是可以清楚的看到c.conn.connected被调用了
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<ConnectionRecord> clist = r.connections.valueAt(conni);
                       for (int i=0; i<clist.size(); 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, false);
                           } 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);
       }
   }



到这里service的两种启动流程就介绍完了,startService和bindService根据应用进程是否已经启动可以分为四个流程,但其实大部分用到的方法都是相同的,和Activity的启动也有相似的地方,总得来说还是比较好理解的



本篇完