前言
之前做一道面试题:startService 和 bindService 有什么不同?为什么 bindService 能和 Activity 的生命周期联动?
前一个问题可以很快回答出来:生命周期不同,结束方式不同,交互方式不同。
后一个问题也能很快想到应该是 Activity 在销毁的时候顺带把 Service 销毁了。那么为什么 startService 不行呢?具体是怎么实现的呢?如果不对源码研究一番,似乎无法给出让人信服的回答,于是就有了这篇文章。
启动和绑定的区别
无论是启动 Activity,还是 Service,基本的流程都是 Context -> ActivtityManagerService -> 某些中间类(Activity 是 ActivityStarter、ActivityStack 等,Service 是 ActiveServices) -> ActivityThread。具体的代码流程比较长,而且很多和本文要探讨的主题无关,因此这里不会详细分析启动或绑定的流程,而只会保留与本文相关的部分源码。
startService
从 ContextImpl 的 startService 方法开始说起:
class ContextImpl extends Context {
@Override
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, false, mUser);
}
private ComponentName startServiceCommon(Intent service, boolean requireForeground,
UserHandle user) {
try {
// 检查 Intent
validateServiceIntent(service);
service.prepareToLeaveProcess(this);
// 启动 Service
ComponentName cn = ActivityManager.getService().startService(
mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
getContentResolver()), requireForeground,
getOpPackageName(), user.getIdentifier());
// 检查结果
if (cn != null) {
...
}
return cn;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
ActivityManager.getService() 返回的就是 AMS 本身,而 AMS 只起到一个中转的作用,除了一些参数判断之外,AMS 直接调用了 ActiveServices 的 startServiceLocked:
public final class ActiveServices {
final ActivityManagerService mAm;
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
throws TransactionTooLargeException {
// 和 Activity 同样有一个 Record 记录对应的组件
ServiceRecord r = res.record;
... // 主要是检查,发现错误则抛出异常,或返回 null 等结果
// 设置 ServiceRecord 的数据域
r.lastActivity = SystemClock.uptimeMillis();
r.startRequested = true;
r.delayedStop = false;
r.fgRequired = fgRequired;
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
service, neededGrants, callingUid));
... // 主要是检查,发现错误则抛出异常,或返回 null 等结果
// 启动
ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
return cmp;
}
}
好了,startService 的流程暂时分析到这里,后面也没什么特别的,最后还是会由 ActivityThread 来创建 Service 对象,回调相关的生命周期方法等。
bindService
下面看 bindService 的实现:
class ContextImpl extends Context {
final @NonNull LoadedApk mPackageInfo;
private final @Nullable IBinder mActivityToken;
@Override
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
warnIfCallingFromSystemProcess();
return bindServiceCommon(service, conn, flags, mMainThread.getHandler(),
Process.myUserHandle());
}
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
handler, UserHandle user) {
...
IServiceConnection sd;
if (mPackageInfo != null) {
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
} else {
throw new RuntimeException("Not supported in system context");
}
try {
// 这个 token 是 Activity 启动时创建的,对应