Service启动流程:
Android四大组件的Service主要用于在后台执行长时间的任务,它没有自己的界面,Service启动之后,将在后台一直运行。应用组件也可以bindService,与Service进行交互甚至是IPC。
startService:
通常在AndroidManifest文件中声明完Service后,应用组件可以通过Context.startService这个方法传入Intent,启动意图Service;Context中的实现交给了mBase,在前面对Activity的工作流程分析中,分析过mBase的时机就是ContextImpl对象;所以startService的实现都是在ContextImpl中,一系列的实现都是调用startServiceCommon:
private ComponentName startServiceCommon(Intent service, boolean requireForeground,
UserHandle user) {
try {
// 在LOLLIPOP(5.1)之前会校验intent的getComponent()和package都为空则抛异常
validateServiceIntent(service);
service.prepareToLeaveProcess(this);
// 调用AMS的startService方法
ComponentName cn = ActivityManager.getService().startService(
mMainThread.getApplicationThread(), service,
service.resolveTypeIfNeeded(getContentResolver()), requireForeground,
getOpPackageName(), getAttributionTag(), user.getIdentifier());
// ...
return cn;
} catch (RemoteException e) {
// 从捕获的异常也可以知道这里其实是应用进程通过RPC机制,调用AMS的相关方法
throw e.rethrowFromSystemServer();
}
}
ActivityManagerService.startService:
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, boolean requireForeground, String callingPackage,
String callingFeatureId, int userId)
throws TransactionTooLargeException {
// ...
synchronized(this) {
// 保存调用进程的pid,uid
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
ComponentName res;
try {
res = mServices.startServiceLocked(caller, service,
resolvedType, callingPid, callingUid,
requireForeground, callingPackage, callingFeatureId, userId);
} finally {
Binder.restoreCallingIdentity(origId);
}
return res;
}
}
mService是ActiveServices实例,实现比较长,
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, boolean fgRequired, String callingPackage,
@Nullable String callingFeatureId, final int userId,
boolean allowBackgroundActivityStarts) throws TransactionTooLargeException {
// ...
// 查询传入的intent对应Service记录
// 如果没有找到,则通过PMS去找
ServiceLookupResult res =
retrieveServiceLocked(service, null, resolvedType, callingPackage,
callingPid, callingUid, userId, true, callerFg, false, false);
if (res == null) {
return null;
}
// 如果对应的Service记录没有找到
// 1.没有权限
// 2.对应的service就是对外暴露的
if (res.record == null) {
return new ComponentName("!", res.permission != null
? res.permission : "private to package");
}
// 和之前的ActivityRecord类似,这个结构体代表着一个应用Service
ServiceRecord r = res.record;
// ...
// 省略复杂的校验逻辑,延迟启动等逻辑
// 启动Service的核心
// smap是一个handler对象,Service的延迟启动也就是通过这个Handler
// 发送一个延迟消息,等时机到了,再调用startServiceInnerLocked
ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
// ...
return cmp;
}
startServiceInnerLocked实现如下:
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
// 一些tracker工作
String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
if (error != null) {
return new ComponentName("!!", error);
}
// ...
return r.name;
}
bringUpServiceLocked中关于Service启动的核心逻辑在后半段:
// 判断service是否在独立进程中
final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
// 获取service想要运行的进程的processName
final String procName = r.processName;
HostingRecord hostingRecord = new HostingRecord("service", r.instanceName);
ProcessRecord app;
//
if (!isolated) {
// 获取App的进程记录
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
if (app != null && app.thread != null) {
try {
// 把Service所声明的packageName添加到进程记录中
app.addPackage(r.appInfo.packageName, r.appInfo.longVersionCode, mAm.mProcessStats);
// 真正启动Service,和Activity类似,到了realXXXLocked,
// 快看到AMS通知应用进程ActivityThread干活的时机了
realStartServiceLocked(r, app, execInFg);
// 如果启动成功,这里就直接return了
return null;
} else {
// 如果Service声明需要在独立的进程运行
app = r.isolatedProc;
// ...
// 创建HostingRecord对象,指定其mHostingZygote字段为APP_ZYGOTE(int值2)
if ((r.serviceInfo.flags & ServiceInfo.FLAG_USE_APP_ZYGOTE) != 0) {
hostingRecord = HostingRecord.byAppZygote(r.instanceName, r.definingPackageName,
r.definingUid);
}
}
// 如果Service对应的App进程还没有被创建,会先记录这个Service,
// 然后等Service要求的进程启动之后,再去启动这个Service
if (app == null && !permissionsReviewRequired) {
// 而新进程的启动,和Activity涉及到新进程启动是一样的。
if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
hostingRecord, ZYGOTE_POLICY_FLAG_EMPTY, false, isolated, false)) == null) {
// ...
}
if (isolated) {
r.isolatedProc = app;
}
}
// ...
// 到这里,这个ServiceRecord记录其实还没有被启动,那么就添加到mPendingServices这个list中
// 等到了新进程的attachApplicationLocked的时候,会去取出mPendingServices
// 再次调用realStartServiceLocked,完成Service的启动。
if (!mPendingServices.contains(r)) {
mPendingServices.add(r);
}
// ...
return null;
}
其实通过前面对Activity启动流程的分析,我们这里也能大概猜到realStartServiceLocked中做的事儿其实就是发送事务给应用进程,进行Service的创建和启动:
// 我们关心的核心代码:
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
app.getReportedProcState());
app是IApplicationThread,thread是IActivityThread,实现都是在应用进程中,那么应用进程的ActivityThread中,scheduleCreateService做的事儿就是创建一个包含了要创建的Service的信息的CreateServiceData对象,然后发送一个消息给H:
sendMessage(H.CREATE_SERVICE, s);
--> H这个Handler的handlerMessage中对CREATE_SERVICE这条消息的处理
handleCreateService
handleCreateService的实现如下:
private void handleCreateService(CreateServiceData data) {
// LoadedApk是当前进程的一些信息封装
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
// 创建Service的context对象
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
// 如果还没有Application对象,创建Application对象
Application app = packageInfo.makeApplication(false, mInstrumentation);
// 获取应用进程的ClassLoader
java.lang.ClassLoader cl = packageInfo.getClassLoader();
// loadClass(data.info.name).newInstance,Service对象就创建出来了
service = packageInfo.getAppFactory()
.instantiateService(cl, data.info.name, data.intent);
// 将应用进程的ResourceLoader都添加给Service
context.getResources().addLoaders(
app.getResources().getLoaders().toArray(new ResourcesLoader[0]));
context.setOuterContext(service);
// attch还能做啥...
// 将上面创建的contextImpl对象赋值给Service的mBase字段
// 完成比如ActivityThread,Application对象的赋值,还有AMS也传给了Service
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService());
// 执行Service的onCreate回调
service.onCreate();
// 将这个启动的service放入进程的mService记录中
mServices.put(data.token, service);
try {
// 通知AMS,service创建完了,恢复一下Binder的id等工作
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} catch (Exception e) {
if (!mInstrumentation.onException(service, e)) {
throw new RuntimeException(
"Unable to create service " + data.info.name
+ ": " + e.toString(), e);
}
}
}
至此,Service的启动就算是完成了,可以看到,大体工作和Activity其实极为相似,而我们也可以看到一些经常被“谈论”的问题,service的onCreate是执行在应用进程的主线程的(H这个Handler关联的不就是ActivityThread所谓主线程的Looper么,handleCreateService当然是执行在主线程),所以Service不等于子线程。
再者,Service的启动流程和Activity实在是有太多相似(一致)的地方,怪不得,有一种说法称Service其实是一种无界面的Activity😹,也是能嗅到很多相似的味道的。