【Android原始碼】Service的啟動過程

指間沙似流年發表於2017-12-23

通常情況下,我們啟動或者繫結一個Service是通過如下程式碼:

Intent intent = new Intent(this, TestService.class);
startService(intent);
bindService(intent, mServiceConneftion, BIND_AUTO_CREATE);
複製程式碼

Service的啟動是從ContextWrapper的startService開始的:

@Override
public ComponentName startService(Intent service) {
   return mBase.startService(service);
}
複製程式碼

上面程式碼中的mBase的型別是Context,而從Activity的啟動流程我們知道了,ContextImpl物件就是Context的具體實現,Activity被建立的時候會通過attach方法將ContextImpl物件關聯起來,而這個ContextImpl就是mBase。

// ContextImpl.java
@Override
public ComponentName startService(Intent service) {
   warnIfCallingFromSystemProcess();
   return startServiceCommon(service, mUser);
}

private ComponentName startServiceCommon(Intent service, UserHandle user) {
   try {
       validateServiceIntent(service);
       service.prepareToLeaveProcess(this);
       ComponentName cn = ActivityManagerNative.getDefault().startService(
           mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
                       getContentResolver()), getOpPackageName(), user.getIdentifier());
       if (cn != null) {
           if (cn.getPackageName().equals("!")) {
               throw new SecurityException(
                       "Not allowed to start service " + service
                       + " without permission " + cn.getClassName());
           } else if (cn.getPackageName().equals("!!")) {
               throw new SecurityException(
                       "Unable to start service " + service
                       + ": " + cn.getClassName());
           }
       }
       return cn;
   } catch (RemoteException e) {
       throw e.rethrowFromSystemServer();
   }
}
複製程式碼

startService又會呼叫startServiceCommon,而在startServiceCommon中,又會通過ActivityManagerNative.getDefault().startService來啟動一個服務。 而ActivityManagerNative其實就是AMS:

@Override
public ComponentName startService(IApplicationThread caller, Intent service,
       String resolvedType, String callingPackage, int userId)
       throws TransactionTooLargeException {
   enforceNotIsolatedCaller("startService");
   // 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");
   }

   if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
           "startService: " + service + " type=" + resolvedType);
   synchronized(this) {
       final int callingPid = Binder.getCallingPid();
       final int callingUid = Binder.getCallingUid();
       final long origId = Binder.clearCallingIdentity();
       ComponentName res = mServices.startServiceLocked(caller, service,
               resolvedType, callingPid, callingUid, callingPackage, userId);
       Binder.restoreCallingIdentity(origId);
       return res;
   }
}
複製程式碼

其中通過mServices.startServiceLocked來完成後續的啟動過程,mServicesActiveServices,是一個輔助AMS來管理Service的類,包括啟動、繫結、停止等操作。

ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
       int callingPid, int callingUid, String callingPackage, final int userId)
       throws TransactionTooLargeException {
    return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
}

ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
       boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
   String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
   return r.name;
}

private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
       boolean whileRestarting, boolean permissionsReviewRequired)
       throws TransactionTooLargeException {
    realStartServiceLocked(r, app, execInFg);       
}
複製程式碼

通過不斷的呼叫最終呼叫到了realStartServiceLocked(r, app, execInFg)方法,通過名稱我們可以猜測這個就是最終建立Service的方法:

app.thread.scheduleCreateService(r, r.serviceInfo,
                    mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                    app.repProcState);
複製程式碼

通過app.threadscheduleCreateService來建立Service物件並呼叫onCreate。

public final void scheduleCreateService(IBinder token,
      ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
  updateProcessState(processState, false);
  CreateServiceData s = new CreateServiceData();
  s.token = token;
  s.info = info;
  s.compatInfo = compatInfo;

  sendMessage(H.CREATE_SERVICE, s);
}

 case CREATE_SERVICE:
     Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, ("serviceCreate: " + String.valueOf(msg.obj)));
     handleCreateService((CreateServiceData)msg.obj);
     Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
     break;
複製程式碼

這個和Activity的處理幾乎一樣,都是通過H這個Handler物件來傳送訊息,並處理的建立過程的:

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,
               ActivityManagerNative.getDefault());
       service.onCreate();
       mServices.put(data.token, service);
       try {
           ActivityManagerNative.getDefault().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);
       }
   }
}
複製程式碼

這個方法主要做了這樣幾件事:

  1. 通過類載入器建立Service例項。
  2. 建立Application物件,並通過service的attach方法關聯Application。
  3. 呼叫service的onCreate方法將Service物件存到ActivityThread的管理Service的列表中。

我們在回到realStartServiceLocked中,在scheduleCreateService之後又呼叫了sendServiceArgsLocked(r, execInFg, true)方法。 scheduleCreateService方法是建立Service物件,並呼叫onCreate方法。 sendServiceArgsLocked方法則是呼叫了onStartCommand方法。

r.app.thread.scheduleServiceArgs(r, si.taskRemoved, si.id, flags, si.intent);

public final void scheduleServiceArgs(IBinder token, boolean taskRemoved, int startId,
  int flags ,Intent args) {
  ServiceArgsData s = new ServiceArgsData();
  s.token = token;
  s.taskRemoved = taskRemoved;
  s.startId = startId;
  s.flags = flags;
  s.args = args;

  sendMessage(H.SERVICE_ARGS, s);
}

 case SERVICE_ARGS:
     Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, ("serviceStart: " + String.valueOf(msg.obj)));
     handleServiceArgs((ServiceArgsData)msg.obj);
     Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
     break;
     
private void handleServiceArgs(ServiceArgsData data) {
   Service s = mServices.get(data.token);
   if (s != null) {
       try {
           if (data.args != null) {
               data.args.setExtrasClassLoader(s.getClassLoader());
               data.args.prepareToEnterProcess();
           }
           int res;
           if (!data.taskRemoved) {
               res = s.onStartCommand(data.args, data.flags, data.startId);
           } else {
               s.onTaskRemoved(data.args);
               res = Service.START_TASK_REMOVED_COMPLETE;
           }

           QueuedWork.waitToFinish();

           try {
               ActivityManagerNative.getDefault().serviceDoneExecuting(
                       data.token, SERVICE_DONE_EXECUTING_START, data.startId, res);
           } catch (RemoteException e) {
               throw e.rethrowFromSystemServer();
           }
           ensureJitEnabled();
       } catch (Exception e) {
           if (!mInstrumentation.onException(s, e)) {
               throw new RuntimeException(
                       "Unable to start service " + s
                       + " with " + data.args + ": " + e.toString(), e);
           }
       }
   }
}
複製程式碼

這個時候呼叫了res = s.onStartCommand(data.args, data.flags, data.startId)方法,也就是說Service的啟動過程已經分析完了。

後篇: Service的繫結過程

相關文章