Service分为两种工作状态,启动状态和绑定状态,通过调用startService()可进入启动状态,通过bindService()可进入绑定状态,本篇文章主要讲解startService()启动Service的过程。(额,android的版本还是26)
我们平时通过startService()启动一个Service的时候,最终都是调用的ContextWrapper的startService(),我们来看下这个方法
@Override
public ComponentName startService(Intent service) {
return mBase.startService(service);
}
上述方法中调用了mBase对象的startService()方法,mBase的类型是Context,Context的实现类是ContextImpl,我们来看下ContextImpl的startService()方法
@Override
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, false, mUser);
}
private ComponentName startServiceCommon(Intent service, boolean requireForeground,
UserHandle user) {
try {
......
//调用了ActivityManagerService的startService()方法
ComponentName cn = ActivityManager.getService().startService(
mMainThread.getApplicationThread(), service,
service.resolveTypeIfNeeded(
getContentResolver()), requireForeground,
getOpPackageName(), user.getIdentifier());
......
return cn;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
我们可以看到在ContextImpl的startService()方法中,调用了startServiceCommon()方法,在startServiceCommon()中,通过ActivityManager.getService()获取到ActivityManagerService的对象,然后调用了ActivityManagerService的startService()方法
@Override
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, boolean requireForeground, String callingPackage, int userId)
throws TransactionTooLargeException {
......
synchronized(this) {
......
ComponentName res;
try {
res = mServices.startServiceLocked(caller, service,
resolvedType, callingPid, callingUid,
requireForeground, callingPackage, userId);
} finally {
Binder.restoreCallingIdentity(origId);
}
return res;
}
}
在上述方法中,通过mServices对象调用了startServiceLocked()方法,mServices是ActiveServices类的对象,可以看做是辅助ActivityManagerServices来管理Service的类,我们来看下它的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;
}
在该方法的最后,调用了startServiceInnerLocked()方法
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;
}
调用了bringUpServiceLocked()方法,该方法也是启动Service过程中比较重要的一个方法
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,boolean whileRestarting, boolean permissionsReviewRequired)
throws TransactionTooLargeException {
/*
* 个人理解:
* 由本方法的参数可知,r是ServiceRecord的对象,ServiceRecord代表着一个Service记录
* 联系整个Service的启动过程可知:
* 首次调用startService()启动一个Service时候,r.app应该为null,下面的if判断不成立
* 如果不是首次调用startService()方法,则下面的if判断成立,调用
sendServiceArgsLocked()方法,然后return,在sendServiceArgsLocked()方法中最终会调
用Service的onStartCommand()方法,这也是为什么非首次调用startService()方法时,不会
调用Service的onCreate(),而是每次都会调用onStartCommand()方法
* 此处不对sendServiceArgsLocked()方法做过多解释,稍后下文中会讲到,希望读者能理解该方法
的作用,并且理解对应同一个Service,为什么只有首次调用startService()时,才会调用
Service的onCreate()方法,但是每次都会调用onStartCommand()方法
*/
if (r.app != null && r.app.thread != null) {
sendServiceArgsLocked(r, execInFg, false);
return null;
}
......
ProcessRecord app;
if (!isolated) {
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);
//执行realStarServiceLocked(),开始正式执行Servcie的启动过过程
realStartServiceLocked(r, app, execInFg);
return null;
} catch (TransactionTooLargeException e) {
......
}
}
} else {
......
}
......
return null;
}
在上述方法的注释中,我已经讲的比较详细了,我再总结一下,在上述的bringUpServiceLocked()方法中,若不是首次执行startService()方法,会直接调用sendServiceArgsLocked()方法,在sendServiceArgsLocked()方法中,会最终执行Service的onStartCommand()方法,如果是首次调用startService()方法,会按照正常的启动Service的代码逻辑来执行,会调用realStartServiceLocked()方法来正式执行Service的启动过程过程,在realStartServiceLocked()中,其实也会调用sendServiceArgsLocked()方法,这也是我理解的为什么多次调用startService()方法,只有首次调用的时候会执行Service的onCreate()方法,但是每次都会执行onStartCommand()方法。下面我们来分析下realStartServiceLocked()方法的代码逻辑和执行过程,在分析的过程中同样会涉及到sendServiceArgsLocked()方法。
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
......
/* r是ServiceRecord的对象,对应了一个Service
* r.app是ProcessRecord的对象,对应了app所在的进程
* 首次调用startService()时,会执行本方法
* 而r.app = app的作用相当于把Service与进程关联起来
* 因此不是首次调用startService()方法的过程中,当执行到bringUpServiceLocked()方法
时,r.app != null && r.app.thread != null的判断会成立,会执行
sendServiceArgsLocked()方法,便不会执行到本方法中来
*/
r.app = app;
......
try {
......
//app.thread其实就是ActivityThread中ApplicationThread类的对象,
//调用ApplicationThread的scheduleCreateService()方法
//顾名思义,该方法就最终调用的应该就是Service的onCreate()方法
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);
......
} catch (DeadObjectException e) {
......
} finally {
......
}
/*
* 该方法是通过bindService()绑定Service的时候才去真正的调用,从而调用onBind()方法
* 当通过startService()方法来开启一个Service的时候,该方法内部的逻辑不成立
* 因startService()的过程基本不涉及到该方法,在下一篇讲解bindService()的绑定过程的
博客会详细讲解这块内容,本文中先忽略
*/
requestServiceBindingsLocked(r, execInFg);
......
/* 该方法通过startService()开启一个Service的时候会去真正的调用,从而调用
onStartCommon()方法
* 当通过bindService()来绑定一个Service的时候,该方法的内部逻辑不成立
* 稍后会讲到这个方法相关的内容
*/
sendServiceArgsLocked(r, execInFg, true);
......
}
需要提一句的是,不论是startService()方法或是bindService()方法最终都会调用这个方法,最大的不同之处我已经在注释里已经讲的很清楚了,这里我就不再多说了,下面我们先看下上述方法中提到的app.thread.scheduleCreateService()方法,其实就是ActivityThread中ApplicationThread的scheduleCreateService()方法,看下Service的onCreate()是怎么执行的,然后再看下sendServiceArgsLocked()方法是怎么执行的onStartCommand()方法
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);
}
如果看过我前几篇Activity启动相关博客的朋友,对上述方法这种类型的代码结构应该不陌生,基本上和Activity启动过程中调用的ApplicationThread方法都是一致的,调用sendMessage()方法,通过Handler发送一个消息,然后在Handler的handleMessage()方法中去处理这个消息,这一小块的相关代码我就不详细说了,也比较简单,不过还是把代码粘贴出来。
private void sendMessage(int what, Object obj) {
sendMessage(what, obj, 0, 0, false);
}
private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
if (DEBUG_MESSAGES) Slog.v(
TAG, "SCHEDULE " + what + " " + mH.codeToString(what)
+ ": " + arg1 + " / " + obj);
Message msg = Message.obtain();
msg.what = what;
msg.obj = obj;
msg.arg1 = arg1;
msg.arg2 = arg2;
if (async) {
msg.setAsynchronous(true);
}
mH.sendMessage(msg);
}
下面我们来看下在mH这个Handler的handleMessage()方法中是怎么处理这个事件的
public void handleMessage(Message msg) {
......
switch (msg.what) {
......
case CREATE_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, ("serviceCreate: " + String.valueOf(msg.obj)));
handleCreateService((CreateServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
......
}
......
}
由上述方法可知,在Handler的handleMessage()方法中,处于这个事件时,回去调用handleCreateService()方法,我们来看下这个方法
private void handleCreateService(CreateServiceData data) {
......
//通过getPackageInfoNoCheck()方法获取一个LoadedApk的对象
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
//通过反射的方式,调用ClassLoader的loadClass()方法,创建一个Service对象
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = (Service) cl.loadClass(data.info.name).newInstance();
} catch (Exception e) {
......
}
try {
......
//创建一个ContextImpl对象
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);
//获取Application对象
Application app = packageInfo.makeApplication(false, mInstrumentation);
//调用Service的attach()方法
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService());
//调用Service的onCreate()方法
service.onCreate();
mServices.put(data.token, service);
......
} catch (Exception e) {
......
}
}
上述方法的注释中已经解释的很清楚了,我就不多做解释了,不过需要提一点的是,在上述方法中有两个方法getPackageInfoNoCheck()以及packageInfo.makeApplication()这个两个方法,getPackageInfoNoCheck()方法获取的是一个LoadedApk对象,LoadedApk对象是apk文件在内存中的表示,apk文件的相关信息,比如apk文件中的资源,甚至是代码里面的Activity、Service等组件的信息都可以通过此对象获取,而且packageInfo.makeApplication()方法获取的是一个Application对象,若Application已经创建过,则直接return之前创建的Application对象,对这两个方法,这里我就简单的描述一下,就不贴出代码解释了,有想了解的朋友,可以看一下我之前的一篇博客 Android Activity启动(一) Application创建的过程以及原理分析,也涉及到相关的内容,讲解的也比较详细。到此为止,Service的onCreate()方法的执行流程已经介绍完毕了。
我们再次回到realStartServiceLocked()中来,总结一下该方法中app.thread.scheduleCreateService()方法,调用了ApplicationThread的scheduleCreateService()方法,通过Handler处理事件,调用了ActivityThread的handleCreateService()方法,通过反射的方式获取Service的对象,然后依次调用Service的attach()方法和onCreate()方法。
下面我们来继续看下realStartServiceLocked()方法中,先简单的看下requestServiceBindingLocked()方法执行后无作用。
private final void requestServiceBindingsLocked(ServiceRecord r, boolean execInFg)
throws TransactionTooLargeException {
//在startService()的过程中bindings.size() = 0,不会执行for循环
for (int i=r.bindings.size()-1; i>=0; i--) {
IntentBindRecord ibr = r.bindings.valueAt(i);
if (!requestServiceBindingLocked(r, ibr, execInFg, false)) {
break;
}
}
}
简单的说,就是因为在startService()的过程中没有对bindings添加值,而bindings.size() = 0,导致没有进入到for循环,bindlings是在bindService()过程中添加值的,有兴趣的朋友可以去了解一下,这里我就不多说了
然后我们看下之后执行的sendServiceArgsLocked()方法
private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
boolean oomAdjusted) throws TransactionTooLargeException {
/*
* 当通过bindService()的方式调用到本方法时,N的值是0,后面的逻辑也都不会执行
* 这也是为什么同样startService()和bindService()方法都会执行该方法,但是结果却不同
* 具体pendingStarts是在哪里赋值的,我就不再多提了,有兴趣的朋友可以了解一下,应该比较
容易就能找到答案了
*/
final int N = r.pendingStarts.size();
if (N == 0) {
return;
}
......
try {
//调用ActivityThread类中ApplicationThread的scheduleServiceArgs()方法
r.app.thread.scheduleServiceArgs(r, slice);
} catch (TransactionTooLargeException e) {
......
} catch (RemoteException e) {
......
} catch (Exception e) {
......
}
......
}
我们可以看到,在上述方法中,会调用ActivityThread类中ApplicationThread的scheduleServiceArgs()方法,我们来看下这个方法。
public final void scheduleServiceArgs(IBinder token, ParceledListSlice args) {
List list = args.getList();
for (int i = 0; i < list.size(); i++) {
ServiceStartArgs ssa = list.get(i);
ServiceArgsData s = new ServiceArgsData();
s.token = token;
s.taskRemoved = ssa.taskRemoved;
s.startId = ssa.startId;
s.flags = ssa.flags;
s.args = ssa.args;
sendMessage(H.SERVICE_ARGS, s);
}
}
private void sendMessage(int what, Object obj) {
sendMessage(what, obj, 0, 0, false);
}
private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
if (DEBUG_MESSAGES) Slog.v(
TAG, "SCHEDULE " + what + " " + mH.codeToString(what)
+ ": " + arg1 + " / " + obj);
Message msg = Message.obtain();
msg.what = what;
msg.obj = obj;
msg.arg1 = arg1;
msg.arg2 = arg2;
if (async) {
msg.setAsynchronous(true);
}
mH.sendMessage(msg);
}
又是相似的代码,在scheduleServiceArgs()方法中调用sendMessage()方法,最终通过mH这个Handler对象发送了一个事件,我们来看下载mH这个Handler对象的handleMessage()方法中是怎么处理的
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
......
case SERVICE_ARGS:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, ("serviceStart: " + String.valueOf(msg.obj)));
handleServiceArgs((ServiceArgsData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
......
}
......
}
我们可以看到,在handleMessage()方法中,针对该消息,最终会调用handleServiceArgs()来处理
private void handleServiceArgs(ServiceArgsData data) {
Service s = mServices.get(data.token);
if (s != null) {
try {
......
if (!data.taskRemoved) {
//调用Service的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的通过调用startService()的启动过程就介绍完毕了。
总结一下,在调用startService()来启动一个Service的时候,回去调用ContextImpl的startService()方法,从而调用ActivityManagerService的startService(),在启动的过程中,如果startService()方法不是首次调用的话,那么不会执行Service的onCreate()方法,只会执行Service的onStartCommand()方法,如果是首次调用startService(),则会有至少两次涉及到跨进程通信,首先是去调用ActivityThread中ApplicationThread里的方法来执行Service的onCreate()方法,执行完毕之后,同样会再执行ApplicationThread中的方法来执行Service的onStartCommand()方法。
本篇博客到此结束,欢迎批评指正,下一篇博客将介绍通过bindService()来绑定一个Service的过程。