--- Service 组件的启动过程 --- #### Service 组件在新进程中的启动过程 在我们调用 Context 的 startService 时,其实是调用到 ContextImpl 的 startService: ```java class ContextImpl extends Context { @Override public ComponentName startService(Intent service) { ComponentName cn = ActivityManagerNative.getDefault().startService( mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(getContextResolver())); return cn; } } ``` 获取 AMS 的代理对象去处理 startService 的请求: ```java // ActivityManagerProxy public ComponentName startService(IApplicationThread caller, Intent service, String resolvedType) { Parcel data = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeStrongBinder(caller); mRemote.transact(START_SERVICE_TRANSACTION, data, ...); } ``` 接着再通过 ActivityManagerProxy 类内部的一个 Binder 代理对象 mRemote 向 AMS 发送一个类型为 START_SERVICE_TRANSACTION 的进程间通信请求。 接下来就是在 AMS 中去处理 Client 组件发送来的类型为 START_SERVICE_TRANSACTION 的进程间通信请求。 ```java // AMS public ComponentName startService(IApplicationThread caller, Intent service, String resolvedType) { ComponentName res = startServiceLocked(caller, service, ...); return res; } ComponentName startServiceLocked(IApplicationThread caller, Intent service, ...) { ServiceLookupResult res = retrieveServiceLocked(service, ...); ServiceRecord r = res.record; bringUpServiceLocked(r, service.getFlags()); return r.name; } ``` 在 AMS 中,每一个 Service 组件都使用一个 ServiceRecord 对象来描述,就像每一个 Activity 组件都使用一个 ActivityRecord 对象来描述一样。 首先调用 retrieveServiceLocked 在 AMS 中查找是否存在与参数 service 对应的一个 ServiceRecord 对象。如果不存在,AMS 就会到 PKMS 中去获取与参数 service 对应的一个 Service 组件的信息,然后再将这些信息封装成一个 ServiceRecord 对象,最后调用 bringUpServiceLocked 来启东 ServiceRecord 对象 r 所描述的一个 Service 组件。 ```java // AMS private final boolean bringUpServiceLocked(ServiceRecord r, ...) { final String appName = r.processName; ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid); if (app != null && app.thread != null) { realStartServiceLocked(r, app); return true; } if (startProcessLocked(appName, r.appInfom, "service", ...)) { return false; } if (!mPendingServices.contains(r)) { mPendingServices.add(r); } return true; } ``` 首先判断该 Service 组件所在的进程是否已经创建了,如果没有创建,就会去执行 startProcessLocked 去创建一个应用程序进程,并且把该 Service 添加到 mPendingService 列表中。 startProcessLocked 就是调用 Process 类的 start 来创建一个新的应用程序进程,创建完成之后,新的应用程序进程会把 ApplicationThread 传递给 AMS,以便 AMS 可以和这个新创建的应用程序进程通信。新创建的应用程序进程会向 AMS 发送一个 ATTACH_APPLICATION_TRANSACTION 的进程间通信请求。 ```java // AMS private final boolean attachApplicationLocked(IApplicationThread thread, int pid) { ProcessRecord app = mPidsSlefLocked.get(pid); app.thread = thread; if (mPendingServices.size() > 0) { ServiceRecord sr = null; for (int i=0;i map = mService.get(context); if (map != null) { sd = map.get(c); } if (sd == null) { sd = new ServiceDispatcher(c, context, handler, flags); if (map == null) { map = new HashMap<>(); mServices.put(context, map); } map.put(c, sd); } return sd.getIServiceConnection(); } ``` 每一个绑定过 Service 组件的 Activity 组件在 LoadedApk 类中都有一个对应的 ServiceDispatcher 对象,它负责将这个被绑定的 Service 与绑定它的 Activity 组件关联在一起。这些 ServiceDispatcher 对象保存在一个 HashMap 中,并且以它们所关联的 ServiceConnection 对象为关键字。最后,用来保存这些 ServiceDispatcher 对象的 HashMap 又以它们所关联的 Activity 组件的 Context 接口为关键字保存在 LoadedApk 类的成员变量 mServices 中。 首先在 mServices 中查找是否存在一个以 ServiceConnection 为 key 的 ServiceDispatcher 对象 sd。如果不存在就先创建 sd 然后存入 map 中。最后通过 ServiceDispatcher 的 getIServiceConnection 来获得一个实现了 IServiceConnection 接口的 Binder 本地对象,它的实现如下: ```java // LoadedApk static final class ServiceDispatcher { private final ServiceDispatcher.InnerConnection mIServiceConnection; private final ServiceConnection mConnection; private final Handler mActivityThread; private final Context mContext; private static class InnerConnection extends IServiceConnection.Stub { fianl WeakReference mDispatcher; InnerConnection(LoadedApk.ServiceDispatcher sd) { mDispatcher = new WeakReference<>(sd); } } ServiceDispatcher(ServiceConnection conn, Context context, Handler activityThread, int flags) { mIServiceConnection = new InnerConnection(this); mConnection = conn; mContext = context; mActivityThread = activityThread; } IServiceConnection getIServiceConnection() { return mIServiceConnection; } } ```