本篇和接下来的几篇我们来浅析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与其客户真个绑定如何实现,即跨进程调用问题。