Android Service完整實現流程分析
前言
一開始的目標是解決各種各樣的ANR問題的,我們知道,ANR總體上分有四種類型,這四種類型有三種是和四大組件相對應的,所以,如果想瞭解ANR發生的根因,對安卓四大組件的實現流程是必須要瞭解的,都不明白ANR如何觸發的,怎麼能完美的解決ANR的問題呢?
所以會寫一系列的文章,來分析四大組建的實現原理,同時也順帶講解四種類型的ANR是如何發生的。
本篇主要介紹service的完整實現流程,下一篇文章介紹Service中的ANR是如何產生的。
一.APP側啟動Service
其實啟動service和啟動Activity是很相似的,都是APP通知系統側,由系統側完成的整個流程。
1.1前臺和後臺啟動
無論是Activity,還是service,還是Application,都繼承自Context的抽象類,所以可以使用Context的各種功能,就比如這瞭要介紹的啟動前臺/後臺service。
Context在安卓中,使用瞭一種典型的代理模式,我們調用的startService或者startForegroundService方法,最終都會委托給ContextImpl中的startService和startForegroundService來處理的。我們就來看下ContextImpl中的這兩個方法:
@Override public ComponentName startService(Intent service) { warnIfCallingFromSystemProcess(); return startServiceCommon(service, false, mUser); } @Override public ComponentName startForegroundService(Intent service) { warnIfCallingFromSystemProcess(); return startServiceCommon(service, true, mUser); }
果然和我猜測的差不多,無論前臺還是後臺啟動,其實最終都會走到一個方法中,隻是配置參數的區別而已。最終都會走執行startServiceCommon方法。
1.2startServiceCommon
該方法中,通過binder通知系統的AMS完成對應的service的啟動操作:
ComponentName cn = ActivityManager.getService().startService( mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(getContentResolver()), requireForeground, getOpPackageName(), getAttributionTag(), user.getIdentifier());
接下來,我們就看下系統側是如何處理Service啟動流程的。
二.系統側分發處理Service的啟動邏輯
系統側的處理我主要分為3塊來講:
1.系統接受APP側的通知並轉發
2.系統側委托ActiveServices負責完成的處理流程
3.收到APP側執行完成的回調,進行收尾操作
2.1AMS接受啟動service的通知
APP側持有system_server進程的binder,上面講到,它會通過binder方法startService完成對系統側的通知。所以AMS的startService會收到這個通知。
我們看下代碼,發現AMS會把整個service的邏輯全部交由ActiveServices來處理,代碼如下:
try { res = mServices.startServiceLocked(caller, service, resolvedType, callingPid, callingUid, requireForeground, callingPackage, callingFeatureId, userId); } finally { Binder.restoreCallingIdentity(origId); }
系統代碼startServiceLocked方法中,代碼雖然很長,但是卻遵循著一個不變的宗旨:位語句,即前面處理各種異常的分支邏輯,把核心流程留到方法的最終來處理。
所以我們直接看startServiceLocked方法的最後一部分即可:
final ComponentName realResult = startServiceInnerLocked(r, service, callingUid, callingPid, fgRequired, callerFg, allowBackgroundActivityStarts, backgroundActivityStartsToken);
startServiceInnerLocked方法中,處理邏輯也是比較簡單的,最終會交給bringUpServiceLocked方法來進行處理。而bringUpServiceLocked方法中則最終會交給realStartServiceLocked完成整個流程。好像系統代碼都喜喜歡用realStart,Activity啟動的流程中也有一個方法叫realStartActivity。
2.2realStartServiceLocked流程
realStartServiceLocked方法中,我們總結為三個流程:
1.bumpServiceExecutingLocked,啟動超時檢查。
2.thread.scheduleCreateService通知APP一側去創建Service。
3.sendServiceArgsLocked通知APP執行Service的生命流程。
private void realStartServiceLocked(ServiceRecord r, ProcessRecord app, IApplicationThread thread, int pid, UidRecord uidRecord, boolean execInFg, boolean enqueueOomAdj) throws RemoteException { //1.啟動超時檢查 bumpServiceExecutingLocked(r, execInFg, "create", null /* oomAdjReason */); ... //2.通知APP創建service thread.scheduleCreateService(r, r.serviceInfo, mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo), app.mState.getReportedProcState()); r.postNotification(); created = true; ... //3.通知執行service生命流程 sendServiceArgsLocked(r, execInFg, true); ... }
三.系統側通知APP啟動Service
一般情況下,APP側會收到系統側發過來兩種類型的通知,
第一種:創建Service的任務通知
第二種:執行Service生命流程的通知,通知Service執行onStartCommand方法。
ApplicationThread接受通知並創建Service
系統側持有APP側的binder,會通過scheduleCreateService這個binder方法通知APP一側進行相應的操作。而APP側,完成這個工作接收的就是ApplicationThread中的scheduleCreateService方法。該方法收到通知後,通過handler切換到主線程處理:
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); }
handle中,會切換到主線程執行ActivityThread的handleCreateService方法。
主要執行瞭如下的幾段邏輯:
1.如果是首次創建App進程的話,則需要重新創建Application;
2.創建Service對象;
3.調用service的attach方法進行關聯;
4.調用service的onCreate生命周期方法;
5.創建完成後,通過serviceDoneExecuting通知系統側創建完成。
try { if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name); Application app = packageInfo.makeApplication(false, mInstrumentation); final java.lang.ClassLoader cl; if (data.info.splitName != null) { cl = packageInfo.getSplitClassLoader(data.info.splitName); } else { cl = packageInfo.getClassLoader(); } service = packageInfo.getAppFactory() .instantiateService(cl, data.info.name, data.intent); ContextImpl context = ContextImpl.getImpl(service .createServiceBaseContext(this, packageInfo)); if (data.info.splitName != null) { context = (ContextImpl) context.createContextForSplit(data.info.splitName); } if (data.info.attributionTags != null && data.info.attributionTags.length > 0) { final String attributionTag = data.info.attributionTags[0]; context = (ContextImpl) context.createAttributionContext(attributionTag); } // Service resources must be initialized with the same loaders as the application // context. context.getResources().addLoaders( app.getResources().getLoaders().toArray(new ResourcesLoader[0])); context.setOuterContext(service); service.attach(context, this, data.info.name, data.token, app, ActivityManager.getService()); service.onCreate(); mServicesData.put(data.token, data); mServices.put(data.token, service); try { ActivityManager.getService().serviceDoneExecuting( data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } }
ApplicationThread接受通知並執行Service的生命流程
同樣的,這裡完成接受的是,仍然是ApplicationThread中的方法。這個流程中的接受方法是scheduleServiceArgs方法。
ApplicationThread中,收到通知後,通過handler把任務轉交到主線程。
public final void scheduleServiceArgs(IBinder token, ParceledListSlice args) { List<ServiceStartArgs> list = args.getList(); for (int i = 0; i < list.size(); i++) { ServiceStartArgs ssa = list.get(i); ServiceArgsData s = new ServiceArgsData(); s.token = token; s.taskRemoved = ssa.taskRemoved; s.startId = ssa.startId; s.flags = ssa.flags; s.args = ssa.args; sendMessage(H.SERVICE_ARGS, s); } }
接下來handler中切換到主線程會執行ActivityThread的handleServiceArgs方法。
handleServiceArgs方法主要會完成以下幾件事:
1.找到對應的service,調用起onStartCommand方法;
2.通知系統側回調完成。
private void handleServiceArgs(ServiceArgsData data) { CreateServiceData createData = mServicesData.get(data.token); Service s = mServices.get(data.token); if (s != null) { try { if (data.args != null) { data.args.setExtrasClassLoader(s.getClassLoader()); data.args.prepareToEnterProcess(isProtectedComponent(createData.info), s.getAttributionSource()); } 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 { ActivityManager.getService().serviceDoneExecuting( data.token, SERVICE_DONE_EXECUTING_START, data.startId, res); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } catch (Exception e) { if (!mInstrumentation.onException(s, e)) { throw new RuntimeException( "Unable to start service " + s + " with " + data.args + ": " + e.toString(), e); } } } }
發我們發現,不論是創建service,還是通知執行service的生命流程,最終都執行瞭一個完成的通知,這有何意圖呢?是的,這個意圖就是和ANR相關的,我們下一章來講瞭。
四.總結
前面一一講瞭實現的原理,我們最後再來做一個總結,盡量用一張圖+幾句話的方式來概括。
1.無論前臺啟動還是後臺啟動,最終都會走到ContextImpl這個最終實現類中的方法,完成和AMS的交互。
2.AMS中主要是ActiveServices完成的整個流程。其核心方法是realStartServiceLocked。
他首先啟動一個延時消息,通過延時消息進行超時的監測。
然後通知APP去生成Service。
通知APP側去完成Service的生命周期流程onStartCommand。
3.收到APP側執行完成的通知後,則取消註冊延時消息。
到此這篇關於Android Service完整實現流程分析的文章就介紹到這瞭,更多相關Android Service內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- Android Service啟動綁定流程詳解
- ContentProvider啟動流程示例解析
- Android那兩個你碰不到但是很重要的類之ActivityThread
- Android Broadcast原理分析之registerReceiver詳解
- Android BindService使用案例講解