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 != null) {
updateServiceForegroundLocked(r.app, false);
try {
bumpServiceExecutingLocked(r, false, "destroy");
mDestroyingServices.add(r);
r.destroying = true;
mAm.updateOomAdjLocked(r.app, true);
//销毁Service并调用Service的onDestory方法
r.app.thread.scheduleStopService(r);
} catch (Exception e) {
...
serviceProcessGoneLocked(r);
}
} else {
...
}
} else {
...
}
//后面就是将一些信息置为null,方便回收
if (r.bindings.size() > 0) {
r.bindings.clear();
}
if (r.restarter instanceof ServiceRestarter) {
((ServiceRestarter)r.restarter).setService(null);
}
int memFactor = mAm.mProcessStats.getMemFactorLocked();
long now = SystemClock.uptimeMillis();
if (r.tracker != null) {
r.tracker.setStarted(false, memFactor, now);
r.tracker.setBound(false, memFactor, now);
if (r.executeNesting == 0) {
r.tracker.clearCurrentOwner(r, false);
r.tracker = null;
}
}
smap.ensureNotStartingBackgroundLocked(r);
}
从上面看出bringDownServiceLocked主要就是销毁、解绑Service。关于启动Service的启动流程就梳理完毕了。
2、Service的绑定过程
bindService方法也存在于ContextWrapper
中,具体实现如下
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
return mBase.bindService(service, conn, flags);
}
这里调用了mBase的bindService方法,前面说了mBase代表一个ContextImpl对象,那么就来ContextImpl中看bindService的实现。
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
...
return bindServiceCommon(service, conn, flags, mMainThread.getHandler(),
Process.myUserHandle());
}
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
handler, UserHandle user) {
// Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
IServiceConnection sd;
...
if (mPackageInfo != null) {
//将ServiceConnection 进行了转换,因为IServiceConnection 能够进程间通信
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
} else {
throw new RuntimeException("Not supported in system context");
}
validateServiceIntent(service);
try {
...
//调用AMS的bindService方法
int res = ActivityManager.getService().bindService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, getOpPackageName(), user.getIdentifier());
if (res < 0) {
throw new SecurityException(
"Not allowed to bind to service " + service);
}
return res != 0;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
在bindService中调用了bindServiceCommon这个方法,在该方法中首先将ServiceConnection对象转化为ServiceDispatcher.InnerConnection对象。之所以不能直接使用ServiceConnection对象,这是因为服务的绑定可能是跨进程的,因此ServiceConnection必须借助于Binder才能让远程服务端回调自己的方法,而ServiceDispatcher的内部类InnerConnection刚好充当起Binder这个角色。
public final IServiceConnection getServiceDispatcher(ServiceConnection c,
Context context, Handler handler, int flags) {
synchronized (mServices) {
LoadedApk.ServiceDispatcher sd = null;
ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
if (map != null) {
sd = map.get(c);
}
if (sd == null) {
sd = new ServiceDispatcher(c, context, handler, flags);
if (map == null) {
map = new ArrayMap<>();
mServices.put(context, map);
}
map.put(c, sd);
} else {
sd.validate(context, handler);
}
return sd.getIServiceConnection();
}
}
转换成功后就调用AMS中的bindService方法。
public int bindService(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, IServiceConnection connection, int flags, String callingPackage,
int userId) throws TransactionTooLargeException {
...
synchronized(this) {
return mServices.bindServiceLocked(caller, token, service,
resolvedType, connection, flags, callingPackage, userId);
}
}
然后调用ActiveService的bindServiceLocked方法。
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, final IServiceConnection connection, int flags,
String callingPackage, final int userId) throws TransactionTooLargeException {
...
//判断是否进行权限检查
if (mAm.mPermissionReviewRequired) {
//进行权限检查
if (mAm.getPackageManagerInternalLocked().isPermissionsReviewRequired(
s.packageName, s.userId)) {
...
RemoteCallback callback = new RemoteCallback(
new RemoteCallback.OnResultListener() {
@Override
public void onResult(Bundle result) {
synchronized(mAm) {
final long identity = Binder.clearCallingIdentity();
try {
if (!mPendingServices.contains(serviceRecord)) {
return;
}
// If there is still a pending record, then the service
// binding request is still valid, so hook them up. We
// proceed only if the caller cleared the review requirement
// otherwise we unbind because the user didn't approve.
//权限审核
if (!mAm.getPackageManagerInternalLocked()
.isPermissionsReviewRequired(
serviceRecord.packageName,
serviceRecord.userId)) {
try {
//创建Service
bringUpServiceLocked(serviceRecord,
serviceIntent.getFlags(),
callerFg, false, false);
} catch (RemoteException e) {
/* ignore - local call */
}
} else {
unbindServiceLocked(connection);
}
} finally {
Binder.restoreCallingIdentity(identity);
}
}
}
});
...
}
}
final long origId = Binder.clearCallingIdentity();
try {
...
if ((flags&Context.BIND_AUTO_CREATE) != 0) {
s.lastActivity = SystemClock.uptimeMillis();
//创建Service
if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
permissionsReviewRequired) != null) {
return 0;
}
}
if (s.app != null) {
...
}
if (s.app != null && b.intent.received) {
//如果Service已经在运行,直接调用ServiceConnection中的onServiceConnected
try {
c.conn.connected(s.name, b.intent.binder, false);
} catch (Exception 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.
if (b.intent.apps.size() == 1 && b.intent.doRebind) {
requestServiceBindingLocked(s, b.intent, callerFg, true);
}
} else if (!b.intent.requested) {
requestServiceBindingLocked(s, b.intent, callerFg, false);
}
...
} finally {
Binder.restoreCallingIdentity(origId);
}
return 1;
}
从上面看出bindServiceLocked里最终都是调用的bringUpServiceLocked方法。关于bringUpServiceLocked在前面已经讲解过,就不在叙述了。记得在realStartServiceLocked中的requestServiceBindingsLocked这个方法没有讲解,那是为什么尼?因为这个只有在Service绑定过程中才会用到。所以先来看看requestServiceBindingsLocked的实现。
private final void requestServiceBindingsLocked(ServiceRecord r, boolean execInFg)
throws TransactionTooLargeException {
for (int i=r.bindings.size()-1; 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) throws TransactionTooLargeException {
...
if ((!i.requested || rebind) && i.apps.size() > 0) {
try {
...
r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
r.app.repProcState);
...
} catch (TransactionTooLargeException e) {
...
} catch (RemoteException e) {
...
}
}
return true;
}
requestServiceBindingsLocked比较简单,直接调用了requestServiceBindingLocked这个方法,在requestServiceBindingLocked中调用了ApplicationThread的scheduleBindService方法,再通过系统Handler调用ActivityThread的handleBindServic方法。
private void handleBindService(BindServiceData data) {
Service s = mServices.get(data.token);
if (s != null) {
try {
...
try {
if (!data.rebind) {
IBinder binder = s.onBind(data.intent);
//调用ServiceConnection中的onServiceConnected
ActivityManager.getService().publishService(
data.token, data.intent, binder);
} else {
s.onRebind(data.intent);
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
...
} catch (RemoteException ex) {
...
}
} catch (Exception e) {
...
}
}
}
}
在上面代码就调用了Service的onBind方法,这个也是不是很熟悉啊。原则上来说,Service的onBind方法调用后,Service就处于绑定状态了,但是onBind方法还是Service的方法,这个时候客户端并不知道已经成功连接Service了,所以还必须调用客户端的ServiceConnection中的onServiceConnected,这个过程就是通过AMS中的publishService来完成的。
public void publishService(IBinder token, Intent intent, IBinder service) {
...
synchronized(this) {
...
mServices.publishServiceLocked((ServiceRecord)token, intent, service);
}
}
publishService中调用了ActiveService的publishServiceLocked方法。
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
final long origId = Binder.clearCallingIdentity();
try {
if (r != null) {
...
if (b != null && !b.received) {
...
for (int conni=r.connections.size()-1; conni>=0; conni--) {
ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
for (int i=0; i<clist.size(); i++) {
ConnectionRecord c = clist.get(i);
...
try {
c.conn.connected(r.name, service, false);
} catch (Exception e) {
...
}
}
}
}
...
}
} finally {
...
}
}
其实publishServiceLocked的核心代码就是c.conn.connected(r.name, service, false);
其中c的类型是ConnectionRecord,c.conn的类型是ServiceDispatcher.InnerConnection,这个类型是不是很熟悉啊,因为前面就是将ServiceConnection转换成ServiceDispatcher.InnerConnection的。
private static class InnerConnection extends IServiceConnection.Stub {
final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;
InnerConnection(LoadedApk.ServiceDispatcher sd) {
mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
}
public void connected(ComponentName name, IBinder service, boolean dead)
throws RemoteException {
LoadedApk.ServiceDispatcher sd = mDispatcher.get();
if (sd != null) {
sd.connected(name, service, dead);
}
}
}
ServiceDispatcher.InnerConnection的connected方法很简单,就是调用了LoadedApk.ServiceDispatcher的connected方法。
public void connected(ComponentName name, IBinder service, boolean dead) {
if (mActivityThread != null) {
mActivityThread.post(new RunConnection(name, service, 0, dead));
} else {
doConnected(name, service, dead);
}
}
private final class RunConnection implements Runnable {
...
public void run() {
if (mCommand == 0) {
doConnected(mName, mService, mDead);
} else if (mCommand == 1) {
doDeath(mName, mService);
}
}
...
}
其实在RunConnection中也是调用的doConnected方法,所以来看一下doConnected的实现。
public void doConnected(ComponentName name, IBinder service, boolean dead) {
// If there was an old service, it is now disconnected.
if (old != null) {
mConnection.onServiceDisconnected(name);
}
if (dead) {
mConnection.onBindingDied(name);
}
// If there is a new service, it is now connected.
if (service != null) {
mConnection.onServiceConnected(name, service);
}
}
上面的mConnection.onServiceDisconnected(name);
、mConnection.onBindingDied(name);
、mConnection.onServiceConnected(name, service);
是不是很熟悉啊。到此,Service的绑定流程也就介绍完毕了。
从总体上来说Service的启动流程及绑定流程是不是比Activity要简单很多啊,但也有不少东西尼,至于Service的停止及解绑过程就不在介绍了。跟启动流程类似的。