android Service启动过程
本文源码基于Android 8.1.0。
startService(intent);
这行代码执行后,发生了什么?
ContextWrapper.java
@Override
public ComponentName startService(Intent service) {
return mBase.startService(service);
}
ContextImpl.java
@Override
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, false, mUser);
}
private ComponentName startServiceCommon(Intent service, boolean requireForeground,
UserHandle user) {
try {
validateServiceIntent(service);
service.prepareToLeaveProcess(this);
ComponentName cn = ActivityManager.getService().startService(
mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
getContentResolver()), requireForeground,
getOpPackageName(), user.getIdentifier());
return cn;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
这里调用了AMS在App进程中的代理对象,它实现了IActivityManager接口,而这个IActivityManager继承了IInterface。
,而这个代理对象最终会通过Binder跨进程来到ActivityManagerService中,
ActivityManagerService.java
@Override
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, boolean requireForeground, String callingPackage, int userId)
throws TransactionTooLargeException {
synchronized(this) {
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, userId);
} finally {
Binder.restoreCallingIdentity(origId);
}
return res;
}
}
这个mServices为ActiveServices对象。
ActiveService.java
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;
}
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired)
throws TransactionTooLargeException {
// 这里调用Service的onStartCommand()方法
if (r.app != null && r.app.thread != null) {
sendServiceArgsLocked(r, execInFg, false);
return null;
}
if (!isolated) {
//根据进程名和uid,查询ProcessRecord
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
if (app != null && app.thread != null) {
try {
app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
// 启动服务
realStartServiceLocked(r, app, execInFg);
return null;
} catch (TransactionTooLargeException e) {
throw e;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting service " + r.shortName, e);
}
}
} else {
app = r.isolatedProc;
}
//对于进程没有启动的情况
if (app == null) {
//启动service所要运行的进程
if ((app = mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
"service", r.name, false, isolated, false)) == null) {
String msg = ""
bringDownServiceLocked(r); // 进程启动失败
return msg;
}
if (isolated) {
r.isolatedProc = app;
}
}
- 当目标进程已存在,则直接执行realStartServiceLocked();
- 当目标进程不存在,则先执行startProcessLocked()创建进程, 经过层层调用最后会调用到AMS.attachApplicationLocked, 然后再执行realStartServiceLocked()。
- 对于非前台进程调用而需要启动的服务,如果已经有其他的后台服务正在启动中,那么我们可能希望延迟其启动。这是用来避免启动同时启动过多的进程(非必须的)。
目标进程不存在的情况我们先略过,来看看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);
created = true;
} catch (DeadObjectException e) {
}
这里跟Activity的流程又类似了,它将会夸进程调用IApplicationThread的实现类,也就是我们ActivityThread的内部类ApplicationThread,来到App进程。
ActivityThread.java
public final void scheduleCreateService(IBinder token,
ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
updateProcessState(processState, false);
CreateServiceData s = new CreateServiceData();
s.token = token;
s.info = info;
s.compatInfo = compatInfo;
sendMessage(H.CREATE_SERVICE, s);
还是使用了ActivityThread的内部类H,通过发送消息来调用启动service的方法
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
case CREATE_SERVICE:
handleCreateService((CreateServiceData)msg.obj);
break;
}
Object obj = msg.obj;
}
很简单,就是调用了handleCreateService(),
private void handleCreateService(CreateServiceData data) {
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = (Service) cl.loadClass(data.info.name).newInstance();
} catch (Exception e) {
}
try {
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);
Application app = packageInfo.makeApplication(false, mInstrumentation);
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService());
service.onCreate();
mServices.put(data.token, service);
}
到这里,先是从LoadedApk中获取ClassLoader,然后用它来创建了Service,之后再为Service创建了一个ContextImpl实例,然后又尝试去创建一个Application,当然如果已经存在,就直接返回了。
之后就是调用了Service的attach()方法,主要传入一些环境等信息。然后就调用了Service的onCreate()方法,Service正式完成启动。
Service.java
public final void attach(
Context context,
ActivityThread thread, String className, IBinder token,
Application application, Object activityManager) {
attachBaseContext(context);
mThread = thread; // NOTE: unused - remove?
mClassName = className;
mToken = token;
mApplication = application;
mActivityManager = (IActivityManager)activityManager;
mStartCompatibility = getApplicationInfo().targetSdkVersion
< Build.VERSION_CODES.ECLAIR;
}
小结
可以看出,Service的启动过程比Activity的启动过程要简单很多,它的调用链没那么长。总结起来,它主要做了以下几件事:
- Activity调用ContextImpl的startServcie方法
- ContextImpl直接就开始调用AMS的代理对象,通过Binder向远程AMS发起启动服务的请求
- AMS收到请求后,会先判断是否需要开启新进程,如果是本地服务,那么直接调用realStartServiceLocked()方法,然后夸进程来到ApplicationThread中,调用scheduleCreateService(),最终创建Service
- 如果是远程服务,则会先创建新进程,然后再执行realStartServiceLocked,最终完成创建。
如果更深一步,这里面涉及到的进程交互,gityuan大神的博客可供参考。这是他博客中的图: