Android Service啟動過程完整分析
剛開始學(xué)習(xí)Service的時(shí)候以為它是一個(gè)線程的封裝,也可以執(zhí)行耗時(shí)操作。其實(shí)不然,Service是運(yùn)行在主線程的。直接執(zhí)行耗時(shí)操作是會阻塞主線程的。長時(shí)間就直接ANR了。
我們知道Service可以執(zhí)行一些后臺任務(wù),是后臺任務(wù)不是耗時(shí)的任務(wù),后臺和耗時(shí)是有區(qū)別的喔。
這樣就很容易想到音樂播放器,天氣預(yù)報(bào)這些應(yīng)用是要用到Service的。當(dāng)然如果要在Service中執(zhí)行耗時(shí)操作的話,開個(gè)線程就可以了。
關(guān)于Service的運(yùn)行狀態(tài)有兩種,啟動狀態(tài)和綁定狀態(tài),兩種狀態(tài)可以一起。
啟動一個(gè)Service只需調(diào)用Context的startService方法,傳進(jìn)一個(gè)Intent即可??雌饋砗孟窈芎唵蔚恼f,那是因?yàn)锳ndroid為了方便開發(fā)者,做了很大程度的封裝。那么你真的有去學(xué)習(xí)過Service是怎么啟動的嗎?Service的onCreate方法回調(diào)前都做了哪些準(zhǔn)備工作?
先上一張圖大致了解下,灰色背景框起來的是同一個(gè)類中的方法,如下圖:
那接下來就從源碼的角度來分析Service的啟動過程。
當(dāng)然是從Context的startService方法開始,Context的實(shí)現(xiàn)類是ContextImpl,那么我們就看到ContextImpl的startService方法即可,如下:
@Override public ComponentName startService(Intent service) { warnIfCallingFromSystemProcess(); return startServiceCommon(service, mUser); }
會轉(zhuǎn)到startServiceCommon方法,那跟進(jìn)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ù)跟進(jìn)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方法,此時(shí)啟動過程已經(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。那么事不宜遲跟進(jìn)去探探吧。如下:
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是一個(gè)ApplicationThread,也是ActivityThread的內(nèi)部類。此時(shí)已經(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組件信息進(jìn)行包裝,然后發(fā)送了一個(gè)消息。我們關(guān)注這個(gè)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方法中接收到這個(gè)消息,然后調(diào)用了handleCreateService方法,跟進(jìn)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); } } }
終于擊破,這個(gè)方法很核心的。一點(diǎn)點(diǎn)分析
首先獲取到一個(gè)LoadedApk對象,在通過這個(gè)LoadedApk對象獲取到一個(gè)類加載器,通過這個(gè)類加載器來創(chuàng)建Service。如下:
java.lang.ClassLoader cl = packageInfo.getClassLoader(); service = (Service) cl.loadClass(data.info.name).newInstance();
接著調(diào)用ContextImpl的createAppContext方法創(chuàng)建了一個(gè)ContextImpl對象。
之后再調(diào)用LoadedApk的makeApplication方法來創(chuàng)建Application,這個(gè)創(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是只有一個(gè)的,從上述代碼中也可以看出。
在回來繼續(xù)看handleCreateService方法,之后service調(diào)用了attach方法關(guān)聯(lián)了ContextImpl和Application等
最后service回調(diào)了onCreate方法,
service.onCreate(); mServices.put(data.token, service);
并將這個(gè)service添加進(jìn)了一個(gè)了列表進(jìn)行管理。
至此service啟動了起來,以上就是service的啟動過程。
你可能還想要知道onStartCommand方法是怎么被回調(diào)的?可能細(xì)心的你發(fā)現(xiàn)了在ActiveServices的realStartServiceLocked方法中,那里還有一個(gè)sendServiceArgsLocked方法。是的,那個(gè)就是入口。
那么我們跟進(jìn)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)在就跟進(jìn)ApplicationThread的scheduleServiceArgs。
你也可能猜到了應(yīng)該又是封裝一些Service的信息,然后發(fā)送一個(gè)消息, 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的啟動過程的同時(shí),閱讀源碼的能力也提高了,分析源碼的時(shí)候我沒能力把每一個(gè)變量,每一個(gè)方法都搞懂,我關(guān)注的都是一些關(guān)鍵的字眼,比如這篇文章就是start呀,service呀。會有那種感覺,就是這里沒錯了。當(dāng)然如果陷入胡同了也要兜出來。
這樣的分析也能夠摸清整體的過程,對于細(xì)節(jié),等我有扎實(shí)的功底了在去研究吧。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- android?Service基礎(chǔ)(啟動服務(wù)與綁定服務(wù))
- Android ServiceManager的啟動和工作原理
- Android 系統(tǒng)服務(wù)TelecomService啟動過程原理分析
- Android Service的啟動過程分析
- Android實(shí)現(xiàn)開機(jī)自動啟動Service或app的方法
- Android Service自啟動注意事項(xiàng)分析
- Android中實(shí)現(xiàn)開機(jī)自動啟動服務(wù)(service)實(shí)例
- android開發(fā)教程之開機(jī)啟動服務(wù)service示例
- Android?Service啟動流程刨析
相關(guān)文章
Android 實(shí)現(xiàn)數(shù)字九宮格軟鍵盤
最近項(xiàng)目在對接美團(tuán)外賣功能,實(shí)現(xiàn)外面小哥憑取貨碼取貨,對接完功能后用戶反饋彈出的軟鍵盤很難輸入,數(shù)字太小了,于是便著手優(yōu)化一下2021-05-05Android 實(shí)現(xiàn)將Bitmap 保存到本地
這篇文章主要介紹了Android 實(shí)現(xiàn)將Bitmap 保存到本地,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-03-03Android BroadcastReceiver常見監(jiān)聽整理
這篇文章主要介紹了Android BroadcastReceiver常見監(jiān)聽整理的相關(guān)資料,需要的朋友可以參考下2016-10-10Android實(shí)現(xiàn)文字垂直滾動、縱向走馬燈效果的實(shí)現(xiàn)方式匯總
本文給大家分享了三種方式實(shí)現(xiàn)Android文字垂直滾動、縱向走馬燈效果,文中給大家介紹了相關(guān)屬性及注意事項(xiàng),需要的朋友參考下吧2017-12-12Flutter網(wǎng)絡(luò)請求庫DIO的基本使用
這篇文章主要介紹了Flutter網(wǎng)絡(luò)請求庫DIO的基本使用,幫助大家更好的理解和學(xué)習(xí)使用Flutter,感興趣的朋友可以了解下2021-04-04Android開發(fā)之搜索框SearchView用法示例
這篇文章主要介紹了Android開發(fā)之搜索框SearchView用法,結(jié)合實(shí)例形式分析了Android搜索框SearchView的基本功能、用法及相關(guān)操作注意事項(xiàng),需要的朋友可以參考下2019-03-03Android四大組件之Service服務(wù)詳細(xì)講解
Android的服務(wù)是開發(fā)Android應(yīng)用程序的重要組成部分。不同于活動Activity,服務(wù)是在后臺運(yùn)行,服務(wù)沒有接口,生命周期也與活動Activity非常不同。通過使用服務(wù)我們可以實(shí)現(xiàn)一些后臺操作,比如想從遠(yuǎn)程服務(wù)器加載一個(gè)網(wǎng)頁等,下面來看看詳細(xì)內(nèi)容,需要的朋友可以參考下2022-07-07Android Studio使用教程(一):下載與安裝及創(chuàng)建HelloWorld項(xiàng)目
這篇文章主要介紹了Android Studio使用教程(一):下載與安裝及創(chuàng)建HelloWorld項(xiàng)目,本文用詳細(xì)的圖文說明講解了Android Studio初步使用,需要的朋友可以參考下2015-05-05Flutter使用RepositoryProvider解決跨組件傳值問題
在實(shí)際開發(fā)過程中,經(jīng)常會遇到父子組件傳值的情況。本文將利用RepositoryProvider解決跨組件傳值的問題,感興趣的小伙伴可以了解一下2022-04-04