Android的服務(Service)(一)生命周期
來源:程序員人生 發布時間:2014-12-22 09:09:52 閱讀次數:3649次
本篇和接下來的幾篇我們來淺析1下Android的另外1個非常重要的組件:Service,看到這里我們的腦海里都會出現出甚么詞語呢?諸如:無用戶交互界面,耗時后臺操作,服務(級別)進程,遠程調用。
1、看看Service的代碼,好干凈的感覺,沒錯,它就定義了1些生命周期的方法和1些成員,注意這些成員中并沒有Window,所以Service是沒有用戶界面的。
2、Service能進行后臺耗時操作只是由于她的進程級別,其實不是由于這個組件本身,由于履行后臺操作的根本是工作線程。做利用和系統的都很了解進程的5個級別。那就是前臺進程,可見進程,服務進程,后臺進程和空進程??梢赃@么說:Service的進程級別永久是服務進程級別和以上級別。
3、遠程調用是1種完善實現CS模型的設計,全部系統Android系統中充斥著各種Service,比如ActivityManagerService。而我們的利用程序都是1個客戶端使用這些服務提供的功能時就是遠程調用。這里有兩種調用,1種是利用開發經常使用的bindService方式也就是AIDL,還有1個固然也是這類代理模式的實現,但是不同的是獲得到其本地代理的方式不同,它通過ServiceManager來間接取得。
以上只是關于Service的1些概述的東西,下面將參考源碼將我們常說Service的1些特性進行說明:
(1)、Service的生命周期
啟動服務開始,ContextImpl.startService()終究是ActivityManagerService服務真個startService方法在完成實際操作,而這個操作又是交給ActiveServices
來完成的。
ComponentName startServiceLocked(IApplicationThread caller,
Intent service, String resolvedType,
int callingPid, int callingUid, int userId) {
................
// 檢索需要啟動服務的信息
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType,
callingPid, callingUid, userId, true, callerFg);
if (res == null) {
return null;
}
if (res.record == null) {
return new ComponentName("!", res.permission != null
? res.permission : "private to package");
}
ServiceRecord r = res.record;
final ServiceMap smap = getServiceMap(r.userId);
boolean addToStarting = false;
//下面判斷當前啟動服務的進程狀態來肯定是不是需要延時啟動這個服務
if (!callerFg && r.app == null && mAm.mStartedUsers.get(r.userId) != null) {
ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid, false);
if (proc == null || proc.curProcState > ActivityManager.PROCESS_STATE_RECEIVER) {
// If this is not coming from a foreground caller, then we may want
// to delay the start if there are already other background services
// that are starting. This is to avoid process start spam when lots
// of applications are all handling things like connectivity broadcasts.
// We only do this for cached processes, because otherwise an application
// can have assumptions about calling startService() for a service to run
// in its own process, and for that process to not be killed before the
// service is started. This is especially the case for receivers, which
// may start a service in onReceive() to do some additional work and have
// initialized some global state as part of that.
if (r.delayed) {
// This service is already scheduled for a delayed start; just leave
// it still waiting.
if (DEBUG_DELAYED_STATS) Slog.v(TAG, "Continuing to delay: " + r);
return r.name;
}
//還有斟酌到后臺啟動服務的數目上線
if (smap.mStartingBackground.size() >= mMaxStartingBackground) {
// Something else is starting, delay!
Slog.i(TAG, "Delaying start of: " + r);
smap.mDelayedStartList.add(r);
r.delayed = true;
return r.name;
}
addToStarting = true;
} else if (proc.curProcState >= ActivityManager.PROCESS_STATE_SERVICE) {
// We slightly loosen when we will enqueue this new service as a background
// starting service we are waiting for, to also include processes that are
// currently running other services or receivers.
addToStarting = true;
if (DEBUG_DELAYED_STATS) Slog.v(TAG, "Not delaying, but counting as bg: " + r);
}
}
return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
}
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service,
ServiceRecord r, boolean callerFg, boolean addToStarting) {
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);
if (error != null) {
return new ComponentName("!!", error);
}
.................
return r.name;
}
private final String bringUpServiceLocked(ServiceRecord r,
int intentFlags, boolean execInFg, boolean whileRestarting) {
//如果服務已啟動過了,履行以下操作
//對到生命周期來講,就是重復的startService不會重復履行oncreate,只是會重復履行onStartCommand
if (r.app != null && r.app.thread != null) {
sendServiceArgsLocked(r, execInFg, false);
return null;
}
.......................
// Service is now being launched, its package can't be stopped.
try {
AppGlobals.getPackageManager().setPackageStoppedState(
r.packageName, false, r.userId);
} catch (RemoteException e) {
} catch (IllegalArgumentException e) {
Slog.w(TAG, "Failed trying to unstop package "
+ r.packageName + ": " + e);
}
final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
final String procName = r.processName;
ProcessRecord app;
if (!isolated) {
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid
+ " app=" + app);
//如果進程已存在,直接啟動服務
if (app != null && app.thread != null) {
try {
app.addPackage(r.appInfo.packageName, mAm.mProcessStats);
realStartServiceLocked(r, app, execInFg);
return null;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting service " + r.shortName, e);
}
// If a dead object exception was thrown -- fall through to
// restart the application.
}
}
......................
return null;
}
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
if (app.thread == null) {
throw new RemoteException();
}
if (DEBUG_MU)
Slog.v(TAG_MU, "realStartServiceLocked, ServiceRecord.uid = " + r.appInfo.uid
+ ", ProcessRecord.uid = " + app.uid);
r.app = app;
r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
app.services.add(r);
bumpServiceExecutingLocked(r, execInFg, "create");
mAm.updateLruProcessLocked(app, false, null);
mAm.updateOomAdjLocked();
boolean created = false;
//這是服務的首次啟動流程,先履行scheduleCreateService,其實到了本地端就是實例化服務類,然后調用了其onCreate方法
try {
String nameTerm;
int lastPeriod = r.shortName.lastIndexOf('.');
nameTerm = lastPeriod >= 0 ? r.shortName.substring(lastPeriod) : r.shortName;
EventLogTags.writeAmCreateService(
r.userId, System.identityHashCode(r), nameTerm, r.app.uid, r.app.pid);
synchronized (r.stats.getBatteryStats()) {
r.stats.startLaunchedLocked();
}
mAm.ensurePackageDexOpt(r.serviceInfo.packageName);
//調劑進程的狀態也就是優先級了
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);
r.postNotification();
created = true;
} finally {
if (!created) {
app.services.remove(r);
r.app = null;
scheduleServiceRestartLocked(r, false);
}
}
//這里是處理bind服務的要求
requestServiceBindingsLocked(r, execInFg);
// If the service is in the started state, and there are no
// pending arguments, then fake up one so its onStartCommand() will
// be called.
if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
null, null));
}
//然后再履行后續的sendServiceArgsLocked方法
sendServiceArgsLocked(r, execInFg, true);
if (r.delayed) {
if (DEBUG_DELAYED_STATS) Slog.v(TAG, "REM FR DELAY LIST (new proc): " + r);
getServiceMap(r.userId).mDelayedStartList.remove(r);
r.delayed = false;
}
if (r.delayedStop) {
// Oh and hey we've already been asked to stop!
r.delayedStop = false;
if (r.startRequested) {
if (DEBUG_DELAYED_STATS) Slog.v(TAG, "Applying delayed stop (from start): " + r);
stopServiceLocked(r);
}
}
}
private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
boolean oomAdjusted) {
//這個方法在后面流程可以注意到,在bindservice時也有進來,所以呢,這個pendingStarts就成了是不是履行實際操作的判斷條件
//直接采取綁定方式創建服務時這個是沒有的,start流程中才有添加進程
final int N = r.pendingStarts.size();
if (N == 0) {
return;
}
while (r.pendingStarts.size() > 0) {
try {
ServiceRecord.StartItem si = r.pendingStarts.remove(0);
//這里scheduleServiceArgs方法調用的是本地端服務的onStartCommand方法,這里的本地端是相對ActivityManagerService來講的。
r.app.thread.scheduleServiceArgs(r, si.taskRemoved, si.id, flags, si.intent);
} catch (RemoteException e) {
// Remote process gone... we'll let the normal cleanup take
// care of this.
if (DEBUG_SERVICE) Slog.v(TAG, "Crashed while scheduling start: " + r);
break;
} catch (Exception e) {
Slog.w(TAG, "Unexpected exception", e);
break;
}
}
}
從start的啟動流程看,得到結論是正常啟動會先履行onCreate然后履行onStartCommand,重復啟動服務只是會重復履行onStartCommand,其實不會屢次履行onCreate。特殊的是,如果之前有客戶端綁定但是未自動創建服務的情況下,startService會履行完onCreate后履行onBind最后是onStartCommand,注意后面介紹中的綁定流程。
下面來看下1種情況,直接bindservice看看又是如何履行的呢,其他調用流程省略,只看關鍵的部份
int bindServiceLocked(IApplicationThread caller, IBinder token,
Intent service, String resolvedType,
IServiceConnection connection, int flags, int userId) {
....................
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType,
Binder.getCallingPid(), Binder.getCallingUid(), userId, true, callerFg);
....................
try {
if (unscheduleServiceRestartLocked(s, callerApp.info.uid, false)) {
if (DEBUG_SERVICE) Slog.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
+ s);
}
...................
<pre name="code" class="java"> //bindings中添加1起綁定要求,后續requestServiceBindingsLocked()流程中處理綁定接口
AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
....................
if ((flags&Context.BIND_AUTO_CREATE) != 0) {
s.lastActivity = SystemClock.uptimeMillis();
//如果攜帶的標志位中包括自動啟動,則進行創建服務的操作,代碼可以看前面,如果已啟動了,實際上是甚么操作也不干的
if (bringUpServiceLocked(s, service.getFlags(), callerFg, false) != null) {
return 0;
}
}
if (s.app != null) {
// This could have made the service more important.
mAm.updateLruProcessLocked(s.app, s.app.hasClientActivities, b.client);
mAm.updateOomAdjLocked(s.app);
}
if (s.app != null && b.intent.received) {
// Service is already running, so we can immediately
// publish the connection.
// 如果服務已啟動并且有綁定過了,直接返回binder對象,這個放到后面跨進程部份來講
try {
c.conn.connected(s.name, b.intent.binder);
} catch (Exception e) {
Slog.w(TAG, "Failure sending service " + s.shortName
+ " to connection " + c.conn.asBinder()
+ " (in " + c.binding.client.processName + ")", e);
}
// If this is the first app connected back to this binding,
// and the service had previously asked to be told when
// rebound, then do so.
// 從這里可以看出,1般情況下,onBind只會履行1次,除非要求doRebind
// 這個標志位是舊的客戶端全部unbind以后自動設置上的,這個后面將Unbind的時候會看到
if (b.intent.apps.size() == 1 && b.intent.doRebind) {
requestServiceBindingLocked(s, b.intent, callerFg, true);
}
} else if (!b.intent.requested) {
//服務還沒有綁定者,則履行后續操作將調用到onBind操作
requestServiceBindingLocked(s, b.intent, callerFg, false);
}
getServiceMap(s.userId).ensureNotStartingBackground(s);
} finally {
Binder.restoreCallingIdentity(origId);
}
return 1;
}
private final void requestServiceBindingsLocked(ServiceRecord r, boolean execInFg) {
//這個方法在正常的start流程中也有履行到,就得靠bindings來作為判斷履行條件,這里面存的是bindservice的要求,只有在bind服務時才會添加
for (int i=r.bindings.size()⑴; i>=0; i--) {
IntentBindRecord ibr = r.bindings.valueAt(i);
if (!requestServiceBindingLocked(r, ibr, execInFg, false)) {
break;
}
}
}
private final boolean requestServiceBindingLocked(ServiceRecord r,
IntentBindRecord i, boolean execInFg, boolean rebind) {
if (r.app == null || r.app.thread == null) {
// If service is not currently running, can't yet bind.
return false;
}
if ((!i.requested || rebind) && i.apps.size() > 0) {
try {
bumpServiceExecutingLocked(r, execInFg, "bind");
r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
// 哇,又要去本地履行onBind方法咯
r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
r.app.repProcState);
if (!rebind) {
i.requested = true;
}
i.hasBound = true;
i.doRebind = false;
} catch (RemoteException e) {
if (DEBUG_SERVICE) Slog.v(TAG, "Crashed while binding " + r);
return false;
}
}
return true;
}
好了,到這里我們已有了1定的結論,直接綁定服務時會先履行onCreate,然后履行onBind但不會履行onStartCommand(注意前面介紹中的sendServiceArgsLocked()方法注釋);已啟動的服務直接履行onBind。剩下的bind后面的事情就留在講授后面兩個問題的時候再說吧就是返回binder對象和如何跨進程的事情。
其他的生命周期分析方式類似,這里邊有1個典型操作:綁定的服務先stopService然后unbind的履行次序,沒開始之前可以猜1下結果。
履行stop操作履行到這里來
private void stopServiceLocked(ServiceRecord service) {
if (service.delayed) {
// If service isn't actually running, but is is being held in the
// delayed list, then we need to keep it started but note that it
// should be stopped once no longer delayed.
if (DEBUG_DELAYED_STATS) Slog.v(TAG, "Delaying stop of pending: " + service);
service.delayedStop = true;
return;
}
..............
service.startRequested = false;
service.callStart = false;
bringDownServiceIfNeededLocked(service, false, false);
}
private final void bringDownServiceIfNeededLocked(ServiceRecord r, boolean knowConn,
boolean hasConn) {
// 先判斷是不是還需要這個服務存在
if (isServiceNeeded(r, knowConn, hasConn)) {
return;
}
// Are we in the process of launching?
if (mPendingServices.contains(r)) {
return;
}
bringDownServiceLocked(r);
}
private final boolean isServiceNeeded(ServiceRecord r, boolean knowConn, boolean hasConn) {
// Are we still explicitly being asked to run?
if (r.startRequested) {
return true;
}
// Is someone still bound to us keepign us running?
// 這個knowConn變量名起的成心思,是不是知道有人連接,后面可以看到在消除綁定的時候再來這里,這個值就是true的
if (!knowConn) {
// 如果不知道是不是有人綁定,則去獲得1下是不是有,這里很重要,大家看獲得的是AutoCreate,也就是說綁定時帶了Context.BIND_AUTO_CREATE標志位來的
// 更多根其相干的r.bindings,這個在前面也有提出,在正常的start流程中履行oncreate以后會檢測這個然后去履行onBind操作。
hasConn = r.hasAutoCreateConnections();
}
if (hasConn) {
//邏輯就是如果還有人綁定著就需要服務存在,bringDownServiceIfNeededLocked()這個方法也就直接返回了。
return true;
}
return false;
}
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()⑴; conni>=0; conni--) {
ArrayList<ConnectionRecord> c = r.connections.valueAt(conni);
for (int i=0; i<c.size(); i++) {
ConnectionRecord cr = c.get(i);
// There is still a connection to the service that is
// being brought down. Mark it as dead.
cr.serviceDead = true;
try {
cr.conn.connected(r.name, null);
} catch (Exception e) {
Slog.w(TAG, "Failure disconnecting service " + r.name +
" to connection " + c.get(i).conn.asBinder() +
" (in " + c.get(i).binding.client.processName + ")", e);
}
}
}
// Tell the service that it has been unbound.
if (r.app != null && r.app.thread != null) {
for (int i=r.bindings.size()⑴; i>=0; i--) {
IntentBindRecord ibr = r.bindings.valueAt(i);
if (DEBUG_SERVICE) Slog.v(TAG, "Bringing down binding " + ibr
+ ": hasBound=" + ibr.hasBound);
if (ibr.hasBound) {
try {
bumpServiceExecutingLocked(r, false, "bring down unbind");
mAm.updateOomAdjLocked(r.app);
ibr.hasBound = false;
r.app.thread.scheduleUnbindService(r,
ibr.intent.getIntent());
} catch (Exception e) {
Slog.w(TAG, "Exception when unbinding service "
+ r.shortName, e);
serviceProcessGoneLocked(r);
}
}
}
}
..................
unscheduleServiceRestartLocked(r, 0, true);
// Also make sure it is not on the pending list.
for (int i=mPendingServices.size()⑴; i>=0; i--) {
if (mPendingServices.get(i) == r) {
mPendingServices.remove(i);
if (DEBUG_SERVICE) Slog.v(TAG, "Removed pending: " + r);
}
}
..................
// Clear start entries.
r.clearDeliveredStartsLocked();
r.pendingStarts.clear();
if (r.app != null) {
synchronized (r.stats.getBatteryStats()) {
r.stats.stopLaunchedLocked();
}
r.app.services.remove(r);
if (r.app.thread != null) {
updateServiceForegroundLocked(r.app, false);
try {
bumpServiceExecutingLocked(r, false, "destroy");
mDestroyingServices.add(r);
mAm.updateOomAdjLocked(r.app);
r.app.thread.scheduleStopService(r);
} catch (Exception e) {
Slog.w(TAG, "Exception when destroying service "
+ r.shortName, e);
serviceProcessGoneLocked(r);
}
}
....................
}
......................
if (r.bindings.size() > 0) {
r.bindings.clear();
}
if (r.restarter instanceof ServiceRestarter) {
((ServiceRestarter)r.restarter).setService(null);
}
.....................
}
再來看看消除綁定的操作時哪些
boolean unbindServiceLocked(IServiceConnection connection) {
IBinder binder = connection.asBinder();
ArrayList<ConnectionRecord> clist = mServiceConnections.get(binder);
if (clist == null) {
Slog.w(TAG, "Unbind failed: could not find connection for "
+ connection.asBinder());
return false;
}
final long origId = Binder.clearCallingIdentity();
try {
while (clist.size() > 0) {
ConnectionRecord r = clist.get(0);
removeConnectionLocked(r, null, null);
if (r.binding.service.app != null) {
// This could have made the service less important.
mAm.updateOomAdjLocked(r.binding.service.app);
}
}
} finally {
Binder.restoreCallingIdentity(origId);
}
return true;
}
void removeConnectionLocked(
ConnectionRecord c, ProcessRecord skipApp, ActivityRecord skipAct) {
...................
//這里在沒解綁1個就是取消1個connection
//這個在本方法的最后,如果所有的都解綁connections為空,s.hasAutoCreateConnections()返回值是false的,
//這個在判斷服務是不是還需要保存時會判斷為不保存直接燒毀
ArrayList<ConnectionRecord> clist = s.connections.get(binder);
if (clist != null) {
clist.remove(c);
if (clist.size() == 0) {
s.connections.remove(binder);
}
}
b.connections.remove(c);
if (c.activity != null && c.activity != skipAct) {
if (c.activity.connections != null) {
c.activity.connections.remove(c);
}
}
..................
if (!c.serviceDead) {
if (DEBUG_SERVICE) Slog.v(TAG, "Disconnecting binding " + b.intent
+ ": shouldUnbind=" + b.intent.hasBound);
if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
&& b.intent.hasBound) {
try {
bumpServiceExecutingLocked(s, false, "unbind");
if (b.client != s.app && (c.flags&Context.BIND_WAIVE_PRIORITY) == 0
&& s.app.setProcState <= ActivityManager.PROCESS_STATE_RECEIVER) {
// If this service's process is not already in the cached list,
// then update it in the LRU list here because this may be causing
// it to go down there and we want it to start out near the top.
mAm.updateLruProcessLocked(s.app, false, null);
}
mAm.updateOomAdjLocked(s.app);
b.intent.hasBound = false;
// Assume the client doesn't want to know about a rebind;
// we will deal with that later if it asks for one.
b.intent.doRebind = false;
s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
} catch (Exception e) {
Slog.w(TAG, "Exception when unbinding service " + s.shortName, e);
serviceProcessGoneLocked(s);
}
}
if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
boolean hasAutoCreate = s.hasAutoCreateConnections();
if (!hasAutoCreate) {
if (s.tracker != null) {
s.tracker.setBound(false, mAm.mProcessStats.getMemFactorLocked(),
SystemClock.uptimeMillis());
}
}
//如果是綁定時創建的,還需要看看是不是需要履行stop。
bringDownServiceIfNeededLocked(s, true, hasAutoCreate);
}
}
}
好了,看完應當也有結論了,那就是如果服務是先創建,然后被綁定的,直接stop后,會通知每一個綁定客戶端服務將燒毀,然后履行onUnbind,最后履行onDestroy燒毀服務
如果是綁定時創建的服務,直接stop是不會燒毀的,直到所有的帶有auto_create標志的客戶端都消除綁定以后會直接履行onDestroy進行燒毀。1句話:服務的各種異常死法都跟這個標志Context.BIND_AUTO_CREATE有關,有了它,管你誰先誰后我都是老大,沒有它start操作才最NB,由于單純bind壓根起不來還得等待start來。
到這里我覺得生命周期的1些特殊問題已論述的差不多了,在上面的代碼中時不時就會出現關于ReStart的字眼,這就是我下篇將要說的1個問題,服務的重啟問題。
后續內容預告:
(2)、Service的自動重啟問題
(3)、Service與其客戶真個綁定如何實現,即跨進程調用問題。
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈