国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android Service的啟動過程分析

2019-12-12 03:11:16
字體:
來源:轉載
供稿:網友

Android Service的啟動過程分析

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

我們知道Service可以執行一些后臺任務,是后臺任務不是耗時的任務,后臺和耗時是有區別的喔。

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

關于Service的運行狀態有兩種,啟動狀態和綁定狀態,兩種狀態可以一起。

啟動一個Service只需調用Context的startService方法,傳進一個Intent即可。看起來好像很簡單的說,那是因為Android為了方便開發者,做了很大程度的封裝。那么你真的有去學習過Service是怎么啟動的嗎?Service的onCreate方法回調前都做了哪些準備工作?

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

Service啟動過程

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

當然是從Context的startService方法開始,Context的實現類是ContextImpl,那么我們就看到ContextImpl的startService方法即可,如下:

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

會轉到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); }}

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

那么現在啟動Service的過程就轉移到了ActivityManagerService,我們關注ActivityManagerService的startService方法即可,如下:

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

在上述的代碼中,調用了ActiveServices的startServiceLocked方法,那么現在Service的啟動過程從AMS轉移到了ActiveServices了。

繼續跟進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方法中又會調用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方法內部調用了bringUpServiceLocked方法,此時啟動過程已經快要離開ActiveServices了。繼續看到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判斷,相信眼尖的你一定發現了核心的方法,那就是
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調用了scheduleCreateService來啟動Service,而app.thread是一個ApplicationThread,也是ActivityThread的內部類。此時已經到了主線程。

那么我們探探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組件信息進行包裝,然后發送了一個消息。我們關注這個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方法中接收到這個消息,然后調用了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對象獲取到一個類加載器,通過這個類加載器來創建Service。如下:

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

接著調用ContextImpl的createAppContext方法創建了一個ContextImpl對象。

之后再調用LoadedApk的makeApplication方法來創建Application,這個創建過程如下:

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

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

在回來繼續看handleCreateService方法,之后service調用了attach方法關聯了ContextImpl和Application等

最后service回調了onCreate方法,

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

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

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

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

那么我們跟進sendServiceArgsLocked方法看看onStartCommand方法是怎么回調的。

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方法回調過程和onCreate方法的是很相似的,都會轉到app.thread。那么現在就跟進ApplicationThread的scheduleServiceArgs。

你也可能猜到了應該又是封裝一些Service的信息,然后發送一個消息, 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;  //代碼省略}

咦,真的是這樣。謎底應該就在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);   }  } }}

可以看到回調了onStartCommand方法。

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

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

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

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 东平县| 和田县| 古浪县| 收藏| 上栗县| 望城县| 高阳县| 淅川县| 许昌市| 来安县| 津市市| 黄龙县| 石阡县| 余江县| 武川县| 精河县| 韩城市| 潼关县| 漯河市| 吉首市| 曲水县| 湘潭县| 花莲县| 侯马市| 灌南县| 抚松县| 崇州市| 高唐县| 防城港市| 峨山| 岳普湖县| 济宁市| 兴文县| 凉城县| 济南市| 林甸县| 泰兴市| 北安市| 专栏| 阿拉善盟| 北安市|