Android原始碼之Service啟動流程
Service在開發中使用得或許沒有activity那麼頻繁,但它是Android四大元件之一,在Android中也是十分重要的,前面分析了activity的啟動流程,這裡也來分析一下Service是如何啟動的。
Service分為兩種工作狀態,一種是啟動狀態,主要用於執行後臺計算;另外一種是繫結狀態,主要用於其他元件與Service的互動。需要注意的是,Service的兩種狀態是可以共存的,即Service既可以處於啟動狀態也可以同時處於繫結狀態。通過Context的startService即可啟動Service。
Intent intent = new Intent (this, MyService.class);
startService(intent);
通過Context的bindService方法即可以繫結的方式啟動一個Service。
Intent intent = new Intent(this, MyService.class);
bindService(intent,mServiceConnection,BIND_AUTO_CREATE);
1、Service的啟動過程
startService方法存在於ContextWrapper
中,具體實現如下
public ComponentName startService(Intent service) {
return mBase.startService(service);
}
這裡呼叫了mBase的startService方法,那mBase是什麼尼?其實mBase的型別是ContextImpl,在activity的attach方法中會將一個ContextImpl物件傳給mBase。那就來ContextImpl中看startService的實現。
public ComponentName startService(Intent service) {
. ..
return startServiceCommon(service, false, mUser);
}
private ComponentName startServiceCommon(Intent service, boolean requireForeground,
UserHandle user) {
try {
...
ComponentName cn = ActivityManager.getService().startService(
mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
getContentResolver()), requireForeground,
getOpPackageName(), user.getIdentifier());
...
}
return cn;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
startService中呼叫了startServiceCommon這個方法,在startServiceCommon裡則通過Binder機制呼叫AMS中的startService方法。
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, boolean requireForeground, String callingPackage, int userId)
throws TransactionTooLargeException {
...
//分段鎖
synchronized(this) {
...
try {
res = mServices.startServiceLocked(caller, service,
resolvedType, callingPid, callingUid,
requireForeground, callingPackage, userId);
} finally {
...
}
return res;
}
}
startService這個方法很簡單,直接呼叫了ActiveServices
的startServiceLocked方法。
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
throws TransactionTooLargeException {
...
ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
return cmp;
}
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
...
String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
...
return r.name;
}
startServiceLocked最後會呼叫startServiceInnerLocked這個方法,這個也比較簡單,直接呼叫了bringUpServiceLocked,這個方法就比較重要了,Service的建立就在這裡面實現的。
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired)
throws TransactionTooLargeException {
...
//如果該Service已經啟動則直接呼叫Service的onStartCommand方法
if (r.app != null && r.app.thread != null) {
//這個很重要,具體就是呼叫Service的onStartCommand方法
sendServiceArgsLocked(r, execInFg, false);
return null;
}
...
if (!isolated) {
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
...
if (app != null && app.thread != null) {
try {
...
//建立Service
realStartServiceLocked(r, app, execInFg);
return null;
} catch (TransactionTooLargeException e) {
...
} catch (RemoteException e) {
...
}
}
} else {
...
}
//如果需要開啟程序,就先開啟程序
if (app == null && !permissionsReviewRequired) {
//開啟新的程序
if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
hostingType, r.name, false, isolated, false)) == null) {
....
//程序建立失敗做的清除操作,如解綁Service、停止Service
bringDownServiceLocked(r);
return msg;
}
...
}
...
return null;
}
bringUpServiceLocked中有四個方法非常重要,理解了這四個方法的實現就基本上理解了Service的啟動流程。
- sendServiceArgsLocked:會呼叫Service的onStartCommand方法,當Service已經存在時則直接呼叫onStartCommand,不再重新建立Service
- realStartServiceLocked:建立一個Service
- startProcessLocked:開啟一個新的程序。
- bringDownServiceLocked:主要是做解綁Service、停止Service的操作
先來看sendServiceArgsLocked的實現。
private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
boolean oomAdjusted) throws TransactionTooLargeException {
//當bindService時,N==0,所以bindService就不會呼叫onStartCommand
////直接採用繫結方式建立服務時這個是沒有的,start流程中才有新增過程
final int N = r.pendingStarts.size();
if (N == 0) {
return;
}
...
try {
r.app.thread.scheduleServiceArgs(r, slice);
} catch (TransactionTooLargeException e) {
...
} catch (RemoteException e) {
...
} catch (Exception e) {
...
}
...
}
該方法還是比較簡單的,直接呼叫了ApplicationThread的scheduleServiceArgs方法,然後通過系統Handler來呼叫ActivityThread的handleServiceArgs方法。
private void handleServiceArgs(ServiceArgsData data) {
Service s = mServices.get(data.token);
if (s != null) {
try {
...
int res;
if (!data.taskRemoved) {
//呼叫了Service的onStartCommand的方法
res = s.onStartCommand(data.args, data.flags, data.startId);
} else {
...
}
...
} catch (Exception e) {
...
}
}
}
在handleServiceArgs方法中就會呼叫Service的onStartCommand方法,onStartCommand方法想必都很熟悉吧。再回到ActiveServices的bringUpServiceLocked方法中,現在再來看realStartServiceLocked這個方法。
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
...
try {
...
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);
r.postNotification();
created = true;
} catch (DeadObjectException e) {
...
} finally {
//如果Service未建立成功,則清除
if (!created) {
// Keep the executeNesting count accurate.
final boolean inDestroying = mDestroyingServices.contains(r);
serviceDoneExecutingLocked(r, inDestroying, inDestroying);
// Cleanup.
if (newService) {
app.services.remove(r);
r.app = null;
}
// Retry.
if (!inDestroying) {
scheduleServiceRestartLocked(r, false);
}
}
}
...
//呼叫Service的onBind方法,後面梳理繫結Service時在詳細講解
requestServiceBindingsLocked(r, execInFg);
...
//這個方法前面就講解了,主要是呼叫Service的onStartCommand方法
sendServiceArgsLocked(r, execInFg, true);
...
}
realStartServiceLocked中首先呼叫了ApplicationThread的scheduleCreateService方法,scheduleCreateService中通過系統Handler來呼叫ActivityThread的handleCreateService方法。
private void handleCreateService(CreateServiceData data) {
...
try {
//拿到ClassLoader
java.lang.ClassLoader cl = packageInfo.getClassLoader();
//通過反射建立Service
service = (Service) cl.loadClass(data.info.name).newInstance();
} catch (Exception e) {
...
}
try {
...
//建立一個Service對應的ContextImpl
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);
Application app = packageInfo.makeApplication(false, mInstrumentation);
//呼叫Service的attach方法,主要是初始化一些引數
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService());
//呼叫Service的onCreate方法,這個想必都很熟悉了
service.onCreate();
...
} catch (Exception e) {
...
}
}
handleCreateService方法還是比較簡單的,該方法通過反射建立了Service並呼叫Service的onCreate方法。再回到ActiveServices的bringUpServiceLocked中,現在再來看startProcessLocked這個方法。這個方法在Android原始碼分析之Activity啟動流程這篇文章中有解介紹,這裡就不在詳細介紹了,只要知道它會建立一個新的程序,然後呼叫ActivityThread的main方法即可。接著呼叫attach方法,並最終呼叫AMS中的attachApplicationLocked方法。
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
...
// Find any services that should be running in this process...
if (!badApp) {
try {
didSomething |= mServices.attachApplicationLocked(app, processName);
...
} catch (Exception e) {
...
}
}
...
return true;
}
在該方法中呼叫了AMS的attachApplicationLocked方法,這個方法比較簡單。
boolean attachApplicationLocked(ProcessRecord proc, String processName)
throws RemoteException {
boolean didSomething = false;
// Collect any services that are waiting for this process to come up.
if (mPendingServices.size() > 0) {
ServiceRecord sr = null;
try {
for (int i=0; i<mPendingServices.size(); i++) {
sr = mPendingServices.get(i);
...
//建立Service
realStartServiceLocked(sr, proc, sr.createdFromFg);
didSomething = true;
if (!isServiceNeededLocked(sr, false, false)) {
// We were waiting for this service to start, but it is actually no
// longer needed. This could happen because bringDownServiceIfNeeded
// won't bring down a service that is pending... so now the pending
// is done, so let's drop it.
bringDownServiceLocked(sr);
}
}
} catch (RemoteException e) {
...
}
}
...
return didSomething;
}
上面的realStartServiceLocked方法是不是很熟悉啊,前面剛介紹完畢,這裡就不再繼續介紹。再回到ActiveServices的bringUpServiceLocked中,現在再來看bringDownServiceLocked這個方法。
private final void bringDownServiceLocked(ServiceRecord r) {
// Report to all of the connections that the service is no longer
// available.
for (int conni=r.connections.size()-1; conni>=0; conni--) {
ArrayList<ConnectionRecord> c = r.connections.valueAt(conni);
for (int i=0; i<c.size(); i++) {
ConnectionRecord cr = c.get(i);
//仍然存在與正在關閉的服務的連線。 把它標記為已死。
cr.serviceDead = true;
try {
cr.conn.connected(r.name, null, true);
} catch (Exception e) {
...
}
}
}
//與Service解除繫結
if (r.app != null && r.app.thread != null) {
for (int i=r.bindings.size()-1; i>=0; i--) {
IntentBindRecord ibr = r.bindings.valueAt(i);
if (ibr.hasBound) {
try {
...
//呼叫Service的onUnbind方法
r.app.thread.scheduleUnbindService(r,
ibr.intent.getIntent());
} catch (Exception e) {
serviceProcessGoneLocked(r);
}
}
}
}
//檢查Service是否在前臺執行
if (r.fgRequired) {
...
r.fgRequired = false;
r.fgWaiting = false;
mAm.mHandler.removeMessages(
ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG, r);
if (r.app != null) {
Message msg = mAm.mHandler.obtainMessage(
ActivityManagerService.SERVICE_FOREGROUND_CRASH_MSG);
msg.obj = r.app;
mAm.mHandler.sendMessage(msg);
}
}
...
//請注意,當通過bringUpServiceLocked()呼叫此方法時,則表示找不到該服務
if (found != null && found != r) {
// This is not actually the service we think is running... this should not happen,
// but if it does, fail hard.
smap.mServicesByName.put(r.name, found);
throw new IllegalStateException("Bringing down " + r + " but actually running "
+ found);
}
...
//開始清除Service的相關資訊
cancelForegroundNotificationLocked(r);
if (r.isForeground) {
decActiveForegroundAppLocked(smap, r);
}
r.isForeground = false;
r.foregroundId = 0;
r.foregroundNoti = null;
r.clearDeliveredStartsLocked();
r.pendingStarts.clear();
if (r.app != null) {
synchronized (r.stats.getBatteryStats()) {
r.stats.stopLaunchedLocked();
}
r.app.services.remove(r);
if (r.whitelistManager) {
updateWhitelistManagerLocked(r.app);
}
if (r.app.thread