前面的文章分析过Activity组件的启动流程,Service是四大组件之一,一种后台服务,它一般没有界面,我们感知不到它的存在。在Android开发时一种重要的组件,在主线程中运行,本文分析一下Service的启动流程,通常是以下代码启动一个Service。
Intent intent = new Intent(this, XxxService);
startService(intent);
Activty中的startService方法,调用父类ContextWrapper的startService方法。
@Override
public ComponentName startService(Intent service) {
return mBase.startService(service);
}
在ContextWrapper中,mBase是ContextImpl的具体实现类,下面是它的startService方法。
@Override
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, mUser);
}
调用startServiceCommon方法。
private ComponentName startServiceCommon(Intent service, UserHandle user) {
try {
...
ComponentName cn = ActivityManagerNative.getDefault().startService(
mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
getContentResolver()), getOpPackageName(), user.getIdentifier());
...
return cn;
} catch (RemoteException e) {
}
}
访问Ams服务,调用ActivityManagerService的#startService方法。
@Override
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, String callingPackage, int userId)
throws TransactionTooLargeException {
//service和callingPackage必须存在。否则抛异常。
synchronized(this) {
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
ComponentName res = mServices.startServiceLocked(caller, service,
resolvedType, callingPid, callingUid, callingPackage, userId);
Binder.restoreCallingIdentity(origId);
return res;
}
}
参数ApplicationThread,App回调,将启动的Service类Intent,resolveType。调用ActiveServices的startServiceLocked方法,Ams类将Service启动的相关流程委托给ActiveServices类管理。
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, String callingPackage, int userId)
throws TransactionTooLargeException {
final boolean callerFg;
if (caller != null) {
//根据IApplicationThread获取ProcessRecord,callerApp空报异常。
final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
callerFg = callerApp.setSchedGroup != Process.THREAD_GROUP_BG_NONINTERACTIVE;
} else {
callerFg = true;
}
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType, callingPackage,
callingPid, callingUid, userId, true, callerFg);
ServiceRecord r = res.record;
final ServiceMap smap = getServiceMap(r.userId);
...
return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
}
调用ActiveServices的startServiceInnerLocked方法。
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
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);
}
if (r.startRequested && addToStarting) {
boolean first = smap.mStartingBackground.size() == 0;
smap.mStartingBackground.add(r);
r.startingBgTimeout = SystemClock.uptimeMillis() + BG_START_TIMEOUT;
if (first) {
smap.rescheduleDelayedStarts();
}
} else if (callerFg) {
smap.ensureNotStartingBackground(r);
}
return r.name;
}
调用bringUpServiceLocked方法。
private final String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting) throws TransactionTooLargeException {
//如果app和thread存在,直接回调app进程onStartCommand方法,
if (r.app != null && r.app.thread != null) {
sendServiceArgsLocked(r, execInFg, false);
return null;
}
//不存在,继续走流程
realStartServiceLocked方法
}
ServiceRecord是Ams保存的服务记录,它和ActivityRecord类似。
在realStartServiceLocked方法。
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
//app.thread不能是空。
r.app = app;//设置ProcessRecord
boolean created = false;
try {
...
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);
created = true;
} catch (DeadObjectException e) {
throw e;
} finally {
...
}
...
sendServiceArgsLocked(r, execInFg, true);
}
该方法通过ApplicationThread回调App的scheduleCreateService方法,向主线程发送一个CREATE_SERVICE消息,然后,执行handleCreateService方法。
private void handleCreateService(CreateServiceData data) {
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
//构建Service对象
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = (Service) cl.loadClass(data.info.name).newInstance();
} catch (Exception e) {
}
try {
//创建Service内部真实类
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);
Application app = packageInfo.makeApplication(false, mInstrumentation);
//attach方法
service.attach(context, this, data.info.name, data.token, app,
ActivityManagerNative.getDefault());
//生命周期方法。
service.onCreate();
mServices.put(data.token, service);
try {
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
} catch (RemoteException e) {
}
} catch (Exception e) {
}
}
首先,类加载器ClassLoader加载对应的Service类,调用类的newInstance方法,创建Service对象。
然后,创建ContextImpl实现类,调用attach方法向Service内部赋值。执行Service的生命周期方法onCreate。
最后,根据IBinder类型的token,将新建Service保存到Map中,这些过程和Activity的启动流程一样。
我们再回到realStartServiceLocked方法,最后,调用sendServiceArgsLocked方法,该方法回调ApplicationThread的scheduleServiceArgs方法,发送的是SERVICE_ARGS消息。
private void handleServiceArgs(ServiceArgsData data) {
Service s = mServices.get(data.token);
if (s != null) {
try {
...
int res;
if (!data.taskRemoved) {
//调用onStartCommand方法
res = s.onStartCommand(data.args, data.flags, data.startId);
} else {
s.onTaskRemoved(data.args);
res = Service.START_TASK_REMOVED_COMPLETE;
}
} catch (Exception e) {
}
}
}
在主线程处理消息时,调用Service的onStartCommand方法。到这里,从无到有启动一个Service就已经完成了,在开发中遇到的方法都已经执行到。如果该Service组件已经存在,我们再次执行startService方法,这时,ServiceRecord的ProcessRecord已被赋值过,同时,ProcessRecord内部ApplicationThread也存在,在bringUpServiceLocked方法,会调用sendServiceArgsLocked方法,回调App进程,触发onStartCommand方法。
下面是一张Service启动时调用方法当流程图。 Service启动时调用方法当流程图.jpg总结流程
在服务启动过程中,经历两个方法,onCreate和onStartCommand方法,他们都是通过Ams服务回调App进程,消息通知主线程调用。
当多次启动服务时,实例化和创建方法只执行一次,开始方法会执行多次。
任重而道远
网友评论