Android Service啟動(dòng)過(guò)程完整分析
剛開(kāi)始學(xué)習(xí)Service的時(shí)候以為它是一個(gè)線程的封裝,也可以執(zhí)行耗時(shí)操作。其實(shí)不然,Service是運(yùn)行在主線程的。直接執(zhí)行耗時(shí)操作是會(huì)阻塞主線程的。長(zhǎng)時(shí)間就直接ANR了。
我們知道Service可以執(zhí)行一些后臺(tái)任務(wù),是后臺(tái)任務(wù)不是耗時(shí)的任務(wù),后臺(tái)和耗時(shí)是有區(qū)別的喔。
這樣就很容易想到音樂(lè)播放器,天氣預(yù)報(bào)這些應(yīng)用是要用到Service的。當(dāng)然如果要在Service中執(zhí)行耗時(shí)操作的話,開(kāi)個(gè)線程就可以了。
關(guān)于Service的運(yùn)行狀態(tài)有兩種,啟動(dòng)狀態(tài)和綁定狀態(tài),兩種狀態(tài)可以一起。
啟動(dòng)一個(gè)Service只需調(diào)用Context的startService方法,傳進(jìn)一個(gè)Intent即可??雌饋?lái)好像很簡(jiǎn)單的說(shuō),那是因?yàn)锳ndroid為了方便開(kāi)發(fā)者,做了很大程度的封裝。那么你真的有去學(xué)習(xí)過(guò)Service是怎么啟動(dòng)的嗎?Service的onCreate方法回調(diào)前都做了哪些準(zhǔn)備工作?
先上一張圖大致了解下,灰色背景框起來(lái)的是同一個(gè)類中的方法,如下圖:

那接下來(lái)就從源碼的角度來(lái)分析Service的啟動(dòng)過(guò)程。
當(dāng)然是從Context的startService方法開(kāi)始,Context的實(shí)現(xiàn)類是ContextImpl,那么我們就看到ContextImpl的startService方法即可,如下:
@Override
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, mUser);
}
會(huì)轉(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方法來(lái)啟動(dòng)Service,ActivityManagerNative.getDefault()是ActivityManagerService,簡(jiǎn)稱AMS。
那么現(xiàn)在啟動(dòng)Service的過(guò)程就轉(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的啟動(dòng)過(guò)程從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方法中又會(huì)調(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í)啟動(dòng)過(guò)程已經(jīng)快要離開(kāi)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,沒(méi)錯(cuò),看名字就像是真正啟動(dòng)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來(lái)啟動(dòng)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);
}
對(duì)待啟動(dòng)的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對(duì)象,在通過(guò)這個(gè)LoadedApk對(duì)象獲取到一個(gè)類加載器,通過(guò)這個(gè)類加載器來(lái)創(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對(duì)象。
之后再調(diào)用LoadedApk的makeApplication方法來(lái)創(chuàng)建Application,這個(gè)創(chuàng)建過(guò)程如下:
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è)的,從上述代碼中也可以看出。
在回來(lái)繼續(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啟動(dòng)了起來(lái),以上就是service的啟動(dòng)過(guò)程。
你可能還想要知道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)過(guò)程和onCreate方法的是很相似的,都會(huì)轉(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的啟動(dòng)過(guò)程的源碼分析。
從中,我理解了Service的啟動(dòng)過(guò)程的同時(shí),閱讀源碼的能力也提高了,分析源碼的時(shí)候我沒(méi)能力把每一個(gè)變量,每一個(gè)方法都搞懂,我關(guān)注的都是一些關(guān)鍵的字眼,比如這篇文章就是start呀,service呀。會(huì)有那種感覺(jué),就是這里沒(méi)錯(cuò)了。當(dāng)然如果陷入胡同了也要兜出來(lái)。
這樣的分析也能夠摸清整體的過(guò)程,對(duì)于細(xì)節(jié),等我有扎實(shí)的功底了在去研究吧。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- android?Service基礎(chǔ)(啟動(dòng)服務(wù)與綁定服務(wù))
- Android ServiceManager的啟動(dòng)和工作原理
- Android 系統(tǒng)服務(wù)TelecomService啟動(dòng)過(guò)程原理分析
- Android Service的啟動(dòng)過(guò)程分析
- Android實(shí)現(xiàn)開(kāi)機(jī)自動(dòng)啟動(dòng)Service或app的方法
- Android Service自啟動(dòng)注意事項(xiàng)分析
- Android中實(shí)現(xiàn)開(kāi)機(jī)自動(dòng)啟動(dòng)服務(wù)(service)實(shí)例
- android開(kāi)發(fā)教程之開(kāi)機(jī)啟動(dòng)服務(wù)service示例
- Android?Service啟動(dòng)流程刨析
相關(guān)文章
Android監(jiān)聽(tīng)Home鍵實(shí)例詳解
這篇文章主要介紹了Android監(jiān)聽(tīng)Home鍵的方法,結(jié)合實(shí)例形式詳細(xì)分析了Android編程實(shí)現(xiàn)監(jiān)聽(tīng)Home鍵的具體步驟與相關(guān)功能代碼,需要的朋友可以參考下2016-02-02
Android實(shí)現(xiàn)字幕滾動(dòng)的方法
這篇文章主要介紹了Android實(shí)現(xiàn)字幕滾動(dòng)的方法,很實(shí)用的功能,需要的朋友可以參考下2014-07-07
Android優(yōu)化查詢加載大數(shù)量的本地相冊(cè)圖片
本文介紹了Android優(yōu)化查詢加載大數(shù)量的本地相冊(cè)圖片,可以方便的照片的查詢,,感興趣的小伙伴們可以參考一下。2016-10-10
Android SDK命令行工具M(jìn)onkey參數(shù)及使用解析
這篇文章主要介紹了Android SDK命令行工具M(jìn)onkey參,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值數(shù)及使用解析,需要的朋友可以參考下2020-10-10
Android中的指紋識(shí)別demo開(kāi)發(fā)實(shí)例
這篇文章主要介紹了Android中的指紋識(shí)別demo開(kāi)發(fā)實(shí)例的相關(guān)知識(shí),非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-09-09
Android進(jìn)階之從IO到NIO的模型機(jī)制演進(jìn)
這篇文章主要為大家介紹了Android進(jìn)階之從IO到NIO的模型機(jī)制演進(jìn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01
Android View 測(cè)量流程(Measure)全面解析
這篇文章主要為大家全面解析了Android View 測(cè)量流程Measure,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-02-02

