欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android Service的啟動過程分析

 更新時間:2017年04月05日 11:48:36   作者:Yinhuan_  
這篇文章主要介紹了Android Service的啟動過程分析的相關(guān)資料,需要的朋友可以參考下

Android Service的啟動過程分析

剛開始學(xué)習(xí)Service的時候以為它是一個線程的封裝,也可以執(zhí)行耗時操作。其實不然,Service是運行在主線程的。直接執(zhí)行耗時操作是會阻塞主線程的。長時間就直接ANR了。

我們知道Service可以執(zhí)行一些后臺任務(wù),是后臺任務(wù)不是耗時的任務(wù),后臺和耗時是有區(qū)別的喔。

這樣就很容易想到音樂播放器,天氣預(yù)報這些應(yīng)用是要用到Service的。當(dāng)然如果要在Service中執(zhí)行耗時操作的話,開個線程就可以了。

關(guān)于Service的運行狀態(tài)有兩種,啟動狀態(tài)和綁定狀態(tài),兩種狀態(tài)可以一起。

啟動一個Service只需調(diào)用Context的startService方法,傳進一個Intent即可??雌饋砗孟窈芎唵蔚恼f,那是因為Android為了方便開發(fā)者,做了很大程度的封裝。那么你真的有去學(xué)習(xí)過Service是怎么啟動的嗎?Service的onCreate方法回調(diào)前都做了哪些準(zhǔn)備工作?

先上一張圖大致了解下,灰色背景框起來的是同一個類中的方法,如下圖:

Service啟動過程

那接下來就從源碼的角度來分析Service的啟動過程。

當(dāng)然是從Context的startService方法開始,Context的實現(xiàn)類是ContextImpl,那么我們就看到ContextImpl的startService方法即可,如下:

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

會轉(zhuǎn)到startServiceCommon方法,那跟進startServiceCommon方法方法瞧瞧。

private ComponentName startServiceCommon(Intent service, UserHandle user) {
 try {
  validateServiceIntent(service);
  service.prepareToLeaveProcess();
  ComponentName cn = ActivityManagerNative.getDefault().startService(
   mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
      getContentResolver()), getOpPackageName(), user.getIdentifier());

 //代碼省略

  return cn;
 } catch (RemoteException e) {
  throw new RuntimeException("Failure from system", e);
 }
}

可以看到調(diào)用了ActivityManagerNative.getDefault()的startService方法來啟動Service,ActivityManagerNative.getDefault()是ActivityManagerService,簡稱AMS。

那么現(xiàn)在啟動Service的過程就轉(zhuǎn)移到了ActivityManagerService,我們關(guān)注ActivityManagerService的startService方法即可,如下:

@Override
public ComponentName startService(IApplicationThread caller, Intent service,
  String resolvedType, 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 = mServices.startServiceLocked(caller, service,
    resolvedType, callingPid, callingUid, callingPackage, userId);
  Binder.restoreCallingIdentity(origId);
  return res;
 }
}

在上述的代碼中,調(diào)用了ActiveServices的startServiceLocked方法,那么現(xiàn)在Service的啟動過程從AMS轉(zhuǎn)移到了ActiveServices了。

繼續(xù)跟進ActiveServices的startServiceLocked方法,如下:

ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
  int callingPid, int callingUid, String callingPackage, int userId)
  throws TransactionTooLargeException {

 //代碼省略

 ServiceLookupResult res =
  retrieveServiceLocked(service, resolvedType, callingPackage,
    callingPid, callingUid, userId, true, callerFg);

 //代碼省略


 ServiceRecord r = res.record;

 //代碼省略

 return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
}

在startServiceLocked方法中又會調(diào)用startServiceInnerLocked方法,

我們瞧瞧startServiceInnerLocked方法,

ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
  boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
 ProcessStats.ServiceState stracker = r.getTracker();
 if (stracker != null) {
  stracker.setStarted(true, mAm.mProcessStats.getMemFactorLocked(), r.lastActivity);
 }
 r.callStart = false;
 synchronized (r.stats.getBatteryStats()) {
  r.stats.startRunningLocked();
 }
 String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false);

 //代碼省略

 return r.name;
}

startServiceInnerLocked方法內(nèi)部調(diào)用了bringUpServiceLocked方法,此時啟動過程已經(jīng)快要離開ActiveServices了。繼續(xù)看到bringUpServiceLocked方法。如下:

private final String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
  boolean whileRestarting) throws TransactionTooLargeException {

  //代碼省略

  if (app != null && app.thread != null) {
   try {
    app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
    realStartServiceLocked(r, app, execInFg);
    return null;
   } 

  //代碼省略

  return null;
}

省略了大部分if判斷,相信眼尖的你一定發(fā)現(xiàn)了核心的方法,那就是
realStartServiceLocked,沒錯,看名字就像是真正啟動Service。那么事不宜遲跟進去探探吧。如下:

private final void realStartServiceLocked(ServiceRecord r,
  ProcessRecord app, boolean execInFg) throws RemoteException {

 //代碼省略

 boolean created = false;
 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;
 } 

 //代碼省略

 sendServiceArgsLocked(r, execInFg, true);

 //代碼省略

}

找到了。app.thread調(diào)用了scheduleCreateService來啟動Service,而app.thread是一個ApplicationThread,也是ActivityThread的內(nèi)部類。此時已經(jīng)到了主線程。

那么我們探探ApplicationThread的scheduleCreateService方法。如下:

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

對待啟動的Service組件信息進行包裝,然后發(fā)送了一個消息。我們關(guān)注這個CREATE_SERVICE消息即可。

public void handleMessage(Message msg) {

  //代碼省略

  case CREATE_SERVICE:
   Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceCreate");
   handleCreateService((CreateServiceData)msg.obj);
   Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
   break;

  //代碼省略

}

在handleMessage方法中接收到這個消息,然后調(diào)用了handleCreateService方法,跟進handleCreateService探探究竟:

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) {
   // nothing to do.
  }
 } catch (Exception e) {
  if (!mInstrumentation.onException(service, e)) {
   throw new RuntimeException(
    "Unable to create service " + data.info.name
    + ": " + e.toString(), e);
  }
 }
}

終于擊破,這個方法很核心的。一點點分析

首先獲取到一個LoadedApk對象,在通過這個LoadedApk對象獲取到一個類加載器,通過這個類加載器來創(chuàng)建Service。如下:

java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = (Service) cl.loadClass(data.info.name).newInstance();

接著調(diào)用ContextImpl的createAppContext方法創(chuàng)建了一個ContextImpl對象。

之后再調(diào)用LoadedApk的makeApplication方法來創(chuàng)建Application,這個創(chuàng)建過程如下:

public Application makeApplication(boolean forceDefaultAppClass,
  Instrumentation instrumentation) {
 if (mApplication != null) {
  return mApplication;
 }

 Application app = null;

 String appClass = mApplicationInfo.className;
 if (forceDefaultAppClass || (appClass == null)) {
  appClass = "android.app.Application";
 }

 try {
  java.lang.ClassLoader cl = getClassLoader();
  if (!mPackageName.equals("android")) {
   initializeJavaContextClassLoader();
  }
  ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
  app = mActivityThread.mInstrumentation.newApplication(
    cl, appClass, appContext);
  appContext.setOuterContext(app);
 } catch (Exception e) {
  if (!mActivityThread.mInstrumentation.onException(app, e)) {
   throw new RuntimeException(
    "Unable to instantiate application " + appClass
    + ": " + e.toString(), e);
  }
 }
 mActivityThread.mAllApplications.add(app);
 mApplication = app;

 if (instrumentation != null) {
  try {
   instrumentation.callApplicationOnCreate(app);
  } catch (Exception e) {
   if (!instrumentation.onException(app, e)) {
    throw new RuntimeException(
     "Unable to create application " + app.getClass().getName()
     + ": " + e.toString(), e);
   }
  }
 }

 // Rewrite the R 'constants' for all library apks.
 SparseArray<String> packageIdentifiers = getAssets(mActivityThread)
   .getAssignedPackageIdentifiers();
 final int N = packageIdentifiers.size();
 for (int i = 0; i < N; i++) {
  final int id = packageIdentifiers.keyAt(i);
  if (id == 0x01 || id == 0x7f) {
   continue;
  }

  rewriteRValues(getClassLoader(), packageIdentifiers.valueAt(i), id);
 }

 return app;
}

當(dāng)然Application是只有一個的,從上述代碼中也可以看出。

在回來繼續(xù)看handleCreateService方法,之后service調(diào)用了attach方法關(guān)聯(lián)了ContextImpl和Application等

最后service回調(diào)了onCreate方法,

service.onCreate();
mServices.put(data.token, service);

并將這個service添加進了一個了列表進行管理。

至此service啟動了起來,以上就是service的啟動過程。

你可能還想要知道onStartCommand方法是怎么被回調(diào)的?可能細心的你發(fā)現(xiàn)了在ActiveServices的realStartServiceLocked方法中,那里還有一個sendServiceArgsLocked方法。是的,那個就是入口。

那么我們跟進sendServiceArgsLocked方法看看onStartCommand方法是怎么回調(diào)的。

private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
  boolean oomAdjusted) throws TransactionTooLargeException {
 final int N = r.pendingStarts.size();

  //代碼省略

  try {

  //代碼省略

   r.app.thread.scheduleServiceArgs(r, si.taskRemoved, si.id, flags, si.intent);
  } catch (TransactionTooLargeException e) {
   if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Transaction too large: intent="
     + si.intent);
   caughtException = e;
  } catch (RemoteException e) {
   // Remote process gone... we'll let the normal cleanup take care of this.
   if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while sending args: " + r);
   caughtException = e;
  } 

  //代碼省略
}

可以看到onStartCommand方法回調(diào)過程和onCreate方法的是很相似的,都會轉(zhuǎn)到app.thread。那么現(xiàn)在就跟進ApplicationThread的scheduleServiceArgs。

你也可能猜到了應(yīng)該又是封裝一些Service的信息,然后發(fā)送一個消息, handleMessage接收。是的,源碼如下:

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

public void handleMessage(Message msg) {

  //代碼省略

  case SERVICE_ARGS:
   Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceStart");
   handleServiceArgs((ServiceArgsData)msg.obj);
   Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
   break;

  //代碼省略
}

咦,真的是這樣。謎底應(yīng)該就在handleServiceArgs方法了,那么趕緊瞧瞧,源碼如下:

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) {
    // nothing to do.
   }
   ensureJitEnabled();
  } catch (Exception e) {
   if (!mInstrumentation.onException(s, e)) {
    throw new RuntimeException(
      "Unable to start service " + s
      + " with " + data.args + ": " + e.toString(), e);
   }
  }
 }
}

可以看到回調(diào)了onStartCommand方法。

以上就是Service的啟動過程的源碼分析。

從中,我理解了Service的啟動過程的同時,閱讀源碼的能力也提高了,分析源碼的時候我沒能力把每一個變量,每一個方法都搞懂,我關(guān)注的都是一些關(guān)鍵的字眼,比如這篇文章就是start呀,service呀。會有那種感覺,就是這里沒錯了。當(dāng)然如果陷入胡同了也要兜出來。

感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!

相關(guān)文章

最新評論