在前面文章我们分析了四大组件中的两个:Broadcast和Activity,这章我们分析四大组件中的服务(Service)的启动过程。Service的启动方式有两种:一种是startService,一种是bindService;第一种通常是开启一个服务执行后台任务,不进行通信,第二章通过是启动服务进行通信。下面我们就根据这两种启动方式来讲Service的启动流程以及unbindService和stopService流程。
Service启动流程-startService
首先来看启动流程时序图:
Step0.ContextImpl.startService
@Override
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, mUser);
}
复制代码
调用当前类中的startServiceCommon方法。
Step1.ContextImpl.startServiceCommon
private ComponentName startServiceCommon(Intent service, UserHandle user) {
try {
// 检验Intent,组件和包名不能为空
validateServiceIntent(service);
service.prepareToLeaveProcess(this);
// 通过getDefault方法获取AMS的一个代理对象(ActivityManagerProxy),然后调用这个代理对象
// 的startService方法来请求AMS启动Service
ComponentName cn = ActivityManagerNative.getDefault().startService(
mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
getContentResolver()), getOpPackageName(), user.getIdentifier());
...
return cn;
} catch (RemoteException e) {
...
}
}
复制代码
首先验证Intent中传递的组件名是否为空,为什么判断下面我们介绍,接着通过代理对象ActivityManagerProxy,通过Binder调用AMS(ActivityManagerService)中的对应方法startService。我们先看包名验证。
Step2.ContextImpl.validateServiceIntent
private void validateServiceIntent(Intent service) {
if (service.getComponent() == null && service.getPackage() == null) {
if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) {
IllegalArgumentException ex = new IllegalArgumentException(
"Service Intent must be explicit: " + service);
throw ex;
} else {
Log.w(TAG, "Implicit intents with startService are not safe: " + service
+ " " + Debug.getCallers(2, 3));
}
}
}
复制代码
这里给出了如果系统在Android5.0及以上版本,启动服务必须为显式启动,否则抛出异常,这个情况我们在刚开始在高于5.0系统都会遇到过,限制就在这里,所以,5.0及以上系统必须用显式的方式启动服务。
3.AMP.startService
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, String callingPackage, int userId) throws RemoteException {
...
// 通过Binder对象mRemote向AMS发送一个类型为START_SERVICE_TRANSACTION的进程间通信请求,
// 然后会调用AMS中的对应的startService方法
mRemote.transact(START_SERVICE_TRANSACTION, data, reply, 0);
...
return res;
}
复制代码
看过前面文章的对这一段代码应该很熟悉了,这个就是通过Binder调用AMS中对应方法的。所以我们直接看AMS。
4.AMS.startService
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, String callingPackage, int userId)
throws TransactionTooLargeException {
...
synchronized (this) {
...
ComponentName res = mServices.startServiceLocked(caller, service,
resolvedType, callingPid, callingUid, callingPackage, userId);
Binder.restoreCallingIdentity(origId);
return res;
}
}
复制代码
这里的mServices是ActiveServices,因此调用的是ActiveServices中的startServiceLocked方法。
5.ActiveServices.startServiceLocked
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, String callingPackage, final int userId)
throws TransactionTooLargeException {
...
// 解析service这个Intent,就是解析在AndroidManifest.xml定义的Service标签的intent-filter相关内容
// 并将其内容保存在Service的record(ServiceRecord)中
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType, callingPackage,
callingPid, callingUid, userId, true, callerFg, false);
...
// 每一个Service组件都使用一个ServiceRecord对象来描述,就像每一个Activity都是用一个ActivityRecord
// 对象来描述一样
ServiceRecord r = res.record;
...
// 加入启动服务列表
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
service, neededGrants));
final ServiceMap smap = getServiceMap(r.userId);
boolean addToStarting = false;
// 如果是非前台(后台)进程调用
if (!callerFg && r.app == null
&& mAm.mUserController.hasStartedUserState(r.userId)) {
// 获取启动服务所在进程
ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid, false);
...
} else if (DEBUG_DELAYED_STARTS) {
...
}
return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
}
复制代码
这里做的主要是启动服务前的准备工作,首先是解析Intent携带的参数,并将这些内容保存在用来描述Service的ServiceRecord对象中保存起来,并将该对象放到等待启动服务的列表中。然后调用startServiceInnerLocked启动服务。在上面调用retrieveServiceLocked函数解析的过程中先去判断AMS中是否存在参数为service对应的ServiceRecord对象,如果存在说明已经启动过该服务,如果不存在,说明是第一次启动该服务。
8.ActiveServices.startServiceInnerLocked
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
ServiceState stracker = r.getTracker();// 获取服务状态
...
r.callStart = false;// 是否调用onStart方法
...
// 启动ServiceRecord对象r所描述的一个Service组件,即Server组件
String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
...
return r.name;
}
复制代码
这里比较简单主要是调用bringUpServiceLocked唤起服务。
Step9.ActiveServices.bringUpServiceLocked
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired)
throws TransactionTooLargeException {
// 这里的r.app.thread是一个ApplicationThread对象,ApplicationThread是用来AMS和应用进程通信的工具,
// 如果服务中的这个thread不为空说明已经和该Service存在通信了,也就是说已经启动了该服务了。
// 如果服务已经存在,调用startService的时候会执行Service.onStartCommand,
// 只有首次启动服务才会调用onCreate方法
if (r.app != null && r.app.thread != null) {
// 执行Service.onStartCommand方法过程
sendServiceArgsLocked(r, execInFg, false);
return null;
}
...
// Make sure that the user who owns this service is started. If not,
// we don't want to allow it to run.
// 确保正在启动服务的用户已经启动,否则不允许执行
if (!mAm.mUserController.hasStartedUserState(r.userId)) {
...
bringDownServiceLocked(r);
return msg;
}
...
// 是不是独立进程
final boolean isolated = (r.serviceInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
// 首先获取ServiceRecord对象r所描述的Service组件的android:process属性,并保存在procName中
final String procName = r.processName;
ProcessRecord app;
if (!isolated) {// 要启动的服务不是独立进程
// 如果不是独立进程,通过进程名称和uid查找是否已经存在一个对应的ProcessRecord对象app,如果存在,
// 说明用来运行这个Service组件的应用进程已经存在了,因此下面的realStartServiceLocked函数在
// ProcessRecord对象app所描述的应用程序进程中启动这个Service组件。
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
if (app != null && app.thread != null) {// 进程存在,并且该进程已经与AMS通信过,那么直接启动服务
try {
...
// 启动服务
realStartServiceLocked(r, app, execInFg);
return null;
} catch (TransactionTooLargeException e) {
...
}
// If a dead object exception was thrown -- fall through to
// restart the application.
}
} else {// 如果要启动的进程是独立进程
...
}
// 如果要启动的Service所在进程没有启动
if (app == null && !permissionsReviewRequired) {
// 启动Service所需要的进程
if ((app = mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
"service", r.name, false, isolated, false)) == null) {
...
// 启动失败
bringDownServiceLocked(r);
return msg;
}
...
}
...
if (r.delayedStop) {// 如果是延迟停止的服务
// Oh and hey we've already been asked to stop!
r.delayedStop = false;
if (r.startRequested) {
// 停止服务
stopServiceLocked(r);
}
}
return null;
}
复制代码
这里是启动服务最重要的部分,根据不同的情况进行不同的处理。首先是判断服务所在进程是否存在,如果存在调用sendServiceArgsLocked方法,最终根据条件,如果服务存在调用服务的onStartCommand方法;然后判断被启动服务的用户是否已经被启动,如果没有则停止服务,也就是调用bringDownServiceLocked方法,最终调用服务的onDestroy方法;然后判断非独立进程的服务,如果进程存在并且服务未启动的开始正式启动服务,调用realStartServiceLocked方法,最终调用onCreate方法;然后判断如果进程不存在,要启动进程,并且在app启动后启动服务,这里会调用启动失败,停止启动,因为进程启动后会启动该服务,这个过程在前面我们讲过,这里不再分析这种情况。最后是如果是延迟停止的服务这里直接停止该服务。下面我们按顺序分析这几种情况。
Step10.ActiveServices.sendServiceArgsLocked
private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
boolean oomAdjusted) throws TransactionTooLargeException {
// 等待启动服务个数
final int N = r.pendingStarts.size();
if (N == 0) {
return;
}
while (r.pendingStarts.size() > 0) {
...
try {
..
// 标记启动服务开始
bumpServiceExecutingLocked(r, execInFg, "start");
...
// 发送消息,传动到ApplicationThread中的scheduleServiceArgs方法,最终会调用onStartCommand
r.app.thread.scheduleServiceArgs(r, si.taskRemoved, si.id, flags, si.intent);
} catch (TransactionTooLargeException e) {
...
}
}
}
复制代码
上面Step5提到启动的服务都要先放到等待启动服务列表中,因此这里先判断服务列表是否存在要启动的服务,如果不存在则不再继续执行,如果存在,循环启动服务,这里调用scheduleServiceArgs方法,其实在前面分析了很多遍,最终会发送消息ActivityThread中的Handler中的handleMessage中进行处理,然后调用ActivityThread中的handleServiceArgs方法。
Step13.ActivityThread.handleServiceArgs
private void handleServiceArgs(ServiceArgsData data) {
// 获取Service对象
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对应的token去缓存中获取服务,如果有该服务那么调用服务的onStartCommand方法,如果不存在那么就要继续往下走创建服务。
Step15.ActiveServices.bringDownServiceLocked
这个方法主要是处理停止服务的方法,里面主要是断开连接,解除绑定,然后销毁服务,因为这个过程是在服务停止时会调用,所以在后面介绍,这里先不介绍了。
Step16.ActiveServices.realStartServiceLocked
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
...
boolean created = false;
...
// 发送信息到主线程,准备调用Service.onCreate方法
// 请求ProcessRecord对象app描述的应用程序进程将ServiceRecord独享r所描述的Service组件启动起来。
// ServiceRecord对象r所描述的Service组件启动完成之后,AMS就需要将它连接到一个请求绑定它的一个
// Activity组件中,这是通过调用AMS类的另一个成员函数requestServiceBindingLocked来实现的
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);
...
// 准备调用Service.onBind方法
requestServiceBindingsLocked(r, execInFg);
...
// 准备调用Service.onStartCommand方法
sendServiceArgsLocked(r, execInFg, true);
...
}
复制代码
启动服务调用三个方法,首先是通过app.thread.scheduleCreateService方法调用onCreate方法,然后通过requestServiceBindingsLocked方法调用Service.onBind方法,然后通过sendServiceArgsLocked方法调用Service.onStartCommand方法,其中最后一个方法我们分析过了,所以我们只分析前两个。第一很简单了,最终调用ActivityThread中的handleCreateService方法。
Step18.ActivityThread.handleCreateService
private void handleCreateService(CreateServiceData data) {
...
// 获取一个用来描述即将要启动的Service组件所在的应用程序的LoadedApk对象,并将它保存在packageInfo
// 变量中(每一个应用程序都使用一个LoadedApk对象来描述,通过它就能方位到它所描述的应用程序的资源)
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
...
// 获取类加载器
java.lang.ClassLoader cl = packageInfo.getClassLoader();
// 通过类加载器将CreateServiceData对象data描述的一个Service组件加载的内存中,并且创建它的一个
// 实例,保存在Service对象service中。因为CreateServiceData对象data描述的Service组件即为应用
// 程序的Ashmem中的Server组件,因此,Service对象service指向的Service组件实际上是一个Server组件
service = (Service) cl.loadClass(data.info.name).newInstance();
...
// 初始化一个ContextImpl对象context,用来为前面所创建的Service对象service的运行上下文环境,
// 通过它可以访问特定的应用程序资源,以及启动其他应用程序组件
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);
// 创建一个Application对象app,用来描述Service对象service所属的应用程序。
Application app = packageInfo.makeApplication(false, mInstrumentation);
// 使用Application对象app,ContextImpl对象context和CreateServiceData对象data来初始化
// Service对象service
service.attach(context, this, data.info.name, data.token, app,
ActivityManagerNative.getDefault());
// 调用Service的onCreate方法
service.onCreate();
// 以token为关键字保存Service对象service到mServices中,服务启动完成
mServices.put(data.token, service);
...
} catch (Exception e) {
...
}
}
复制代码
首先获取LoadedApk对象,然后通过类加载器加载Service类,初始化Context,获取对应的Application,如果存在直接返回,如果该应用还没启动则直接创建该Application,然后通过Service的attach方法将对应的信息放置到Service中,这里面就包含ActivityThread,因此我们在Step9中可以通过这个来判断Service是不是被启动了,然后调用onCreate方法,创建完成后,将该服务以token为键,Service为值放入到缓存中,这样我们前面获取的时候就只从这里获取的,因此如果服务启动了换粗就会存在,否则不存在。下面我们分析onBind方法。
Step20.ActiveServices.requestServiceBindingsLocked
// 参数r指向一个ServiceRecord,表示一个已经启动的Service组件
private final void requestServiceBindingsLocked(ServiceRecord r, boolean execInFg)
throws TransactionTooLargeException {
for (int i = r.bindings.size() - 1; i >= 0; i--) {
// 每一个IntentBindRecord对象都用来描述若干个需要将ServiceRecord对象r所描述的Service组件
// 绑定到它们里面的应用程序进程
IntentBindRecord ibr = r.bindings.valueAt(i);
if (!requestServiceBindingLocked(r, ibr, execInFg, false)) {
break;
}
}
}
复制代码
for循环调用onBind。
Step21.ActiveServices.requestServiceBindingLocked
// 参数rebind表示是否需要将ServiceRecord对象r所描述的Service组件重新绑定到IntentBindRecord对象i
// 所描述的应用程序进程中如果为false,则说明为第一绑定
private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
boolean execInFg, boolean rebind) throws TransactionTooLargeException {
...
// 检查AMS是否已经为IntentBindRecord对象i所描述的应用程序进程请求过ServiceRecord对象r所描述的
// Service组件返回其内部的一个Binder本地对象。如果还没有请求requested为false并且apps的数量大于0
if ((!i.requested || rebind) && i.apps.size() > 0) {
try {
...
//会执行到Service的onBind方法
r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
r.app.repProcState);
if (!rebind) {
// 设置为true,防止重复请求
i.requested = true;
}
...
}
}
return true;
}
复制代码
这里通过调用r.app.thread.scheduleBindService方法,最终调用到ActivityThread中的handleBindService方法。
Step23.ActivityThread.handleBindService
private void handleBindService(BindServiceData data) {
// 通过token来获得一个描述Service组件的Service对象
Service s = mServices.get(data.token);
if (s != null) {
try {
...
if (!data.rebind) {// 首次绑定
// 获取一个实现了IBinder接口的Binder对象
IBinder binder = s.onBind(data.intent);
...
} else {
s.onRebind(data.intent);
...
}
...
} catch (Exception e) {
...
}
}
}
复制代码
现获取服务,然后判断是再次绑定还是首次绑定,如果是首次绑定调用Service.onBind方法,如果是再次绑定调用Service.onRebind方法。到这里服务的启动就完成了,其他一些操作就不分析了。下面我们先分析另外一个启动流程bindService,最后分析停止服务流程。
Service启动流程-bindService
首先来看绑定流程时序图:
Step1.ContextImpl.bindService
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
warnIfCallingFromSystemProcess();
return bindServiceCommon(service, conn, flags, mMainThread.getHandler(),
Process.myUserHandle());
}
复制代码
这里是绑定服务的入口位置,调用bindServiceCommon方法。
Step2.ContextImpl.bindServiceCommon
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
handler, UserHandle user) {
IServiceConnection sd;
...
// mPackageInfo类型是LoadedApk
if (mPackageInfo != null) {
// 将ServiceConnection对象conn封装成一个实现了IServiceConnection接口的Binder本地对象sd
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
} else {
...
}
...
try {
IBinder token = getActivityToken();
...
// 通过调用代理对象ActivityManagerProxy的bindService方法将前面获得的sd对象,以及Intent对象
// service等信息发送给AMS,以便AMS可以将ServiceConnection组件启动起来
int res = ActivityManagerNative.getDefault().bindService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, getOpPackageName(), user.getIdentifier());
...
return res != 0;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
复制代码
首先调用LoadedApk中的getServiceDispatcher方法获取实现IServiceConnection接口的Binder对象ServiceDispatcher.InnerConnection。然后调用AMP中的bindService方法,然后通过Binder通信调用AMS中的bindService方法。
Step3.LoadedApk.getServiceDispatcher
// 每一个绑定过Service组件的Activity组件在LoadedApk类中都有一个对应的ServiceDispatcher对象,它负责将
// 这个被绑定的Service组件与绑定它的Activity组件关联起来,这些ServiceDispatcher保存在map中
public final IServiceConnection getServiceDispatcher(ServiceConnection c,
Context context, Handler handler, int flags) {
synchronized (mServices) {
LoadedApk.ServiceDispatcher sd = null;
ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
// 检查成员变量mServices中是否存在一个以ServiceConnection对象c为关键字的ServiceDispatcher
// 对象sd,如果不存在,则创建一个并且以context为关键字保存到mServices中
if (map != null) {
sd = map.get(c);
}
if (sd == null) {
sd = new ServiceDispatcher(c, context, handler, flags);
if (map == null) {
map = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
mServices.put(context, map);
}
map.put(c, sd);
} else {
sd.validate(context, handler);
}
// 调用前面获取到的ServiceDispatcher对象sd的成员函数getIServiceConnection来获取一个实现了
// IServiceConnection接口的本地Binder对象
return sd.getIServiceConnection();
}
}
复制代码
首先根据ServiceConnection取缓存中获取,如果没有要初始化一个ServiceDispatcher对象,然后获取ServiceDispatcher.InnerConnection对象并且返回。
Step6.AMP.bindService
public int bindService(IApplicationThread caller, IBinder token,
Intent service, String resolvedType, IServiceConnection connection,
int flags, String callingPackage, int userId) throws RemoteException {
...
// 通过Binder对象mRemote向AMS发送一个类型为BIND_SERVICE_TRANSACTION的进程间通信请求
mRemote.transact(BIND_SERVICE_TRANSACTION, data, reply, 0);
...
return res;
}
复制代码
这里通过Binder调用AMS中对应的方法。
Step7.AMS.bindService
public int bindService(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, IServiceConnection connection, int flags, String callingPackage,
int userId) throws TransactionTooLargeException {
...
synchronized (this) {
return mServices.bindServiceLocked(caller, token, service,
resolvedType, connection, flags, callingPackage, userId);
}
}
复制代码
这里调用ActiveServices.bindServiceLocked方法。
Step8.ActiveServices.bindServiceLocked
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, final IServiceConnection connection, int flags,
String callingPackage, final int userId) throws TransactionTooLargeException {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "bindService: " + service
+ " type=" + resolvedType + " conn=" + connection.asBinder()
+ " flags=0x" + Integer.toHexString(flags));
// 根据caller来获取一个ProcessRecord对象callerApp用来描述AMS执行绑定Service组件操作的一个Activity
// 组件所运行在的应用程序进程
final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
...
ActivityRecord activity = null;
if (token != null) {
// 通过token来获得一个ActivityRecord对象activity,用来描述正在请求AMS执行绑定Service组件
// 操作的一个Activity组件
activity = ActivityRecord.isInStackLocked(token);
if (activity == null) {
Slog.w(TAG, "Binding with unknown activity: " + token);
return 0;
}
}
...
final boolean callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
// 是否是绑定了外部服务,这个服务不是应用中的服务,而是外部独立的服务(我们通常启动服务都是应用内部的服务)
final boolean isBindExternal = (flags & Context.BIND_EXTERNAL_SERVICE) != 0;
// 根据参数service来得到一个ServiceRecord对象s,用来描述即将被绑定的Service组件
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType, callingPackage, Binder.getCallingPid(),
Binder.getCallingUid(), userId, true, callerFg, isBindExternal);
...
// 调用ServiceRecord对象s的成员函数retrieveAppBindingLocked来得到一个AppBindRecord对象b,
// 表示ServiceRecord对象s所描述的Service组件是绑定在ProcessRecord对象callerApp所描述的一个
// 应用程序进程中的
AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
// 将前面获得的APPBindRecord对象、ActivityRecord对象Activity以及参数connection封装成一个
// ConnectionRecord对象s所描述的一个Service组件,并且这个Activity组件是运行在
// ProcessRecord对象callerApp所描述的一个应用进程中的
ConnectionRecord c = new ConnectionRecord(b, activity,
connection, flags, clientLabel, clientIntent);
// 由于一个Service组件可能会被同一个应用程序进程中的多个Activity组件使用同一个InnerConnection
// 对象来绑定,因此,在AMS中,用来描述该Service组件的ServiceRecord对象就有可能会对应有多个
// ConnectionRecord对象。在这种情况下,这些ConnectionRecord对象就会被保存在一个列表中。
// 这个列表最终会保存在对应的ServiceRecord对象的成员变量Connection所描述的HashMap中,并且以
// 它里面的ConnectionRecord对象共同使用的一个InnerConnection代理对象的IBinder接口为关键字
// 参数connection是一个InnerConnection代理对象,因此可以获取它的一个IBinder接口binder
IBinder binder = connection.asBinder();
// 检测在ServiceRecord对象s中是否存在一个以IBinder接口binder为关键字的列表clist,如果不存在
// 创建一个,并且将clist以binder为关键字放到ServiceRecord对象成员变量connections中
ArrayList<ConnectionRecord> clist = s.connections.get(binder);
if (clist == null) {// 没有绑定过
clist = new ArrayList<ConnectionRecord>();
s.connections.put(binder, clist);
}
clist.add(c);// 添加绑定列表
b.connections.add(c);// 添加到关联应用和服务的对象AppBindRecord中记录绑定列表中
if (activity != null) {
if (activity.connections == null) {// 这里判断Activity里面是否绑定过服务
activity.connections = new HashSet<ConnectionRecord>();
}
// 添加到描述Activity的ActivityRecord对象中记录绑定服务的列表中
activity.connections.add(c);
}
...
// 从记录该服务所有绑定列表中获取是否存在绑定列表
clist = mServiceConnections.get(binder);
if (clist == null) {
clist = new ArrayList<ConnectionRecord>();
mServiceConnections.put(binder, clist);
}
clist.add(c);// 添加都所有列表中
// 从前面可知flags的Context.BIND_AUTO_CREATE位等于1,因此会调用bringUpServiceLocked来启动
// ServiceRecord对象s所描述的一个Service组件,等到这个Service组件启动以后,AMS再将它与
// ActivityRecord对象Activity所描述的一个Activity绑定自来
if ((flags & Context.BIND_AUTO_CREATE) != 0) {
s.lastActivity = SystemClock.uptimeMillis();
if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
permissionsReviewRequired) != null) {
return 0;
}
}
...
if (s.app != null && b.intent.received) {
// Service is already running, so we can immediately
// publish the connection.
try {
// 这里的c.conn是ServiceDispatcher.InnerConnection对象,这里最终调用
// ServiceDispatcher中的doConnected方法
c.conn.connected(s.name, b.intent.binder);
} catch (Exception e) {
Slog.w(TAG, "Failure sending service " + s.shortName
+ " to connection " + c.conn.asBinder()
+ " (in " + c.binding.client.processName + ")", e);
}
// If this is the first app connected back to this binding,
// and the service had previously asked to be told when
// rebound, then do so.
if (b.intent.apps.size() == 1 && b.intent.doRebind) {// 重新绑定
requestServiceBindingLocked(s, b.intent, callerFg, true);
}
} else if (!b.intent.requested) {// 首次绑定
requestServiceBindingLocked(s, b.intent, callerFg, false);
}
getServiceMap(s.userId).ensureNotStartingBackground(s);
} finally {
Binder.restoreCallingIdentity(origId);
}
return 1;
}
复制代码
这里代码比较多,所以写的注释也比较多,前面主要是判断是否绑定过该服务,并对InnerConnection进行缓存,放置到各个列表中,让Activity,Service进行联系。最后调用requestServiceBindingLocked方法,这个方法调用两次,一次是首次绑定,一个是重新绑定。
Step9.AMS.requestServiceBindingLocked
// 参数rebind表示是否需要将ServiceRecord对象r所描述的Service组件重新绑定到IntentBindRecord对象i
// 所描述的应用程序进程中如果为false,则说明为第一绑定
private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
boolean execInFg, boolean rebind) throws TransactionTooLargeException {
...
// 检查AMS是否已经为IntentBindRecord对象i所描述的应用程序进程请求过ServiceRecord对象r所描述的
// Service组件返回其内部的一个Binder本地对象。如果还没有请求requested为false并且apps的数量大于0
if ((!i.requested || rebind) && i.apps.size() > 0) {
try {
bumpServiceExecutingLocked(r, execInFg, "bind");
r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
// 会执行到Service的onBind方法
r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
r.app.repProcState);
if (!rebind) {
// 设置为true,防止重复请求
i.requested = true;
}
i.hasBound = true;
i.doRebind = false;
...
}
return true;
}
复制代码
这里是判断首次绑定还是重新绑定,这两种绑定都会执行绑定步骤,这里有个参数i.requested,代表是否是首次绑定,如果默认值是false,如果不是重新绑定,那么执行完绑定就会设置为true。然后调用thread.scheduleBindServic方法,这个方法讲了很多次了,最终调用ApplicationThread.scheduleBindService方法,然后通过handler调用ActivityThread.handleBindService方法。
Step10.ActivityThread.handleBindService
private void handleBindService(BindServiceData data) {
// 通过token来获得一个描述Service组件的Service对象
Service s = mServices.get(data.token);
...
if (!data.rebind) {// 首次绑定
// 获取一个实现了IBinder接口的Binder对象
IBinder binder = s.onBind(data.intent);
// 调用AMS代理对象的成员函数publishService,将前面得到的Binder本地对象传递给AMS
ActivityManagerNative.getDefault().publishService(
data.token, data.intent, binder);
} else {
s.onRebind(data.intent);
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
}
复制代码
这里如果是首次绑定调用onBind方法,否则调用onRebind方法,在首次调用绑定后还有publishService方法,自己看一下,不在详细分析了。这样绑定流程就分析完了,难度不大。下面我们开分析解绑过程。
Service解绑流程-unbindService
首先来看解绑流程时序图:
Step1.ContextImpl.unbindService
public void unbindService(ServiceConnection conn) {
...
if (mPackageInfo != null) {
// 获取将ServiceConnection对象conn封装成一个实现了IServiceConnection接口的Binder
// 本地对象sd(ServiceDispatcher.InnerConnection)
IServiceConnection sd = mPackageInfo.forgetServiceDispatcher(
getOuterContext(), conn);
try {
ActivityManagerNative.getDefault().unbindService(sd);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} else {
throw new RuntimeException("Not supported in system context");
}
}
复制代码
IServiceConnection对象的获取我们前面分析过了,这里直接过,然后调用AMP.unbindService方法,最终调用AMS.unbindService方法。
Step3.AMS.unbindService
public boolean unbindService(IServiceConnection connection) {
synchronized (this) {
return mServices.unbindServiceLocked(connection);
}
}
复制代码
这里调用ActiveServices.unbindServiceLocked方法。
Step4.ActiveServices.unbindServiceLocked
boolean unbindServiceLocked(IServiceConnection connection) {
IBinder binder = connection.asBinder();
// 获取缓存中绑定列表
ArrayList<ConnectionRecord> clist = mServiceConnections.get(binder);
...
try {
while (clist.size() > 0) {
ConnectionRecord r = clist.get(0);
removeConnectionLocked(r, null, null);
if (clist.size() > 0 && clist.get(0) == r) {
// In case it didn't get removed above, do it now.
Slog.wtf(TAG, "Connection " + r + " not removed for binder " + binder);
clist.remove(0);
}
....
}
} finally {
Binder.restoreCallingIdentity(origId);
}
return true;
}
复制代码
首先从AMS中获取绑定过的列表,如果存在说明绑定过,然后调用removeConnectionLocked移除连接。
Step5.ActiveServices.removeConnectionLocked
void removeConnectionLocked(
ConnectionRecord c, ProcessRecord skipApp, ActivityRecord skipAct) {
// 获取连接中的Binder对象
IBinder binder = c.conn.asBinder();
// 获取连接应用、服务和连接列表的客户端
AppBindRecord b = c.binding;
// 获取描述服务的对象
ServiceRecord s = b.service;
// 根据Binder对象获取服务绑定的连接列表
ArrayList<ConnectionRecord> clist = s.connections.get(binder);
if (clist != null) {
clist.remove(c);// 移除该连接对象
if (clist.size() == 0) {// 如果列表为空,移除该列表
s.connections.remove(binder);
}
}
// 从连接应用、服务和连接列表的客户端中的连接列表中移除
b.connections.remove(c);
...
// 从总的缓存列表中移除
clist = mServiceConnections.get(binder);
if (clist != null) {
clist.remove(c);
if (clist.size() == 0) {
mServiceConnections.remove(binder);
}
}
mAm.stopAssociationLocked(b.client.uid, b.client.processName, s.appInfo.uid, s.name);
// 如果连接应用、服务和连接列表的客户端中的连接列表为空了,说明没有绑定了,那么移除该客户端
if (b.connections.size() == 0) {
b.intent.apps.remove(b.client);
}
if (!c.serviceDead) {// 服务还存在
if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
&& b.intent.hasBound) {
try {
...
b.intent.doRebind = false;
s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
} catch (Exception e) {
Slog.w(TAG, "Exception when unbinding service " + s.shortName, e);
serviceProcessGoneLocked(s);
}
}
...
}
}
复制代码
在绑定服务的时候进行各种缓存,加入各种列表,那么在接触绑定的时候就有从之前加入的列表中删除,然后执行接触绑定。
Step7.ActivityThread.handleUnbindService
private void handleUnbindService(BindServiceData data) {
Service s = mServices.get(data.token);
if (s != null) {
try {
...
boolean doRebind = s.onUnbind(data.intent);// 调用解绑回调
...
} catch (Exception e) {
...
}
}
}
复制代码
调用Service的onUnbind接触绑定。到这里接触绑定就分析完了,过程比较简单,只是上面的各种列表搞清楚要多看看。最后就剩下了stopService,我们一口气就将它分析完。
Service停止流程-stopService
首先来看停止服务流程时序图:
Step1.ContextImpl.stopSevice
// 停止服务
@Override
public boolean stopService(Intent service) {
warnIfCallingFromSystemProcess();
return stopServiceCommon(service, mUser);
}
复制代码
调用stopServiceCommon停止服务。
Step2.ContextImpl.stopServiceCommon
private boolean stopServiceCommon(Intent service, UserHandle user) {
try {
// 检验Intent,组件和包名不能为空
validateServiceIntent(service);
service.prepareToLeaveProcess(this);
int res = ActivityManagerNative.getDefault().stopService(
mMainThread.getApplicationThread(), service,
service.resolveTypeIfNeeded(getContentResolver()), user.getIdentifier());
...
return res != 0;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
复制代码
这里最终调用AMS的stopService方法。
Step3.AMS.stopService
public int stopService(IApplicationThread caller, Intent service,
String resolvedType, int userId) {
...
synchronized (this) {
return mServices.stopServiceLocked(caller, service, resolvedType, userId);
}
}
复制代码
这里就是简单的调用ActiveServices.stopServiceLocked方法。
Step4.ActiveServices.stopServiceLocked
int stopServiceLocked(IApplicationThread caller, Intent service,
String resolvedType, int userId) {
// 根据caller获取调用者进程
final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
...
if (r != null) {
...
stopServiceLocked(r.record);
...
return -1;
}
return 0;
}
复制代码
简单的调用了stopServiceLocked方法。
Step6.ActiveServices.stopServiceLocked
private void stopServiceLocked(ServiceRecord service) {
...
bringDownServiceIfNeededLocked(service, false, false);
}
复制代码
我们前面分析过bringUp的是启动服务,因此对应的bringDown的是结束服务。
Step7.ActiveServices.bringDownServiceIfNeededLocked
// 停止服务
private final void bringDownServiceIfNeededLocked(ServiceRecord r, boolean knowConn,
boolean hasConn) {
...
bringDownServiceLocked(r);
}
复制代码
这里只是简单的调用了bringDownServiceLocked方法,这个方法我们在服务启动时也遇到过,只是没有分析,我们放到了停止服务的流程中来分析,下面我们看看详细代码。
Step8.ActiveServices.bringDownServiceLocked
private final void bringDownServiceLocked(ServiceRecord r) {
for (int conni = r.connections.size() - 1; conni >= 0; conni--) {
ArrayList<ConnectionRecord> c = r.connections.valueAt(conni);
for (int i = 0; i < c.size(); i++) {
...
// 断开服务连接
cr.conn.connected(r.name, null);
...
}
}
// Tell the service that it has been unbound.
if (r.app != null && r.app.thread != null) {
for (int i = r.bindings.size() - 1; i >= 0; i--) {
IntentBindRecord ibr = r.bindings.valueAt(i);
if (ibr.hasBound) {// 所有服务与客户端已经解绑
try {
...
// 调用Service的onUnbind方法
r.app.thread.scheduleUnbindService(r,
ibr.intent.getIntent());
} catch (Exception e) {
...
}
}
}
}
...
if (r.app != null) {// 服务进程存在
...
if (r.app.thread != null) {
updateServiceForegroundLocked(r.app, false);
try {
...
// 停止服务,调用onDestroy方法
r.app.thread.scheduleStopService(r);
} catch (Exception e) {
...
...
}
复制代码
这里主要有三步,第一步,断开服务连接,这个方法我们前面提到过,可以根据前面提到的去看看如何断开连接的;第二步,如果已经绑定了服务要解除绑定,这个在上面解除绑定的时候分析了该过程,因此这里就不再重复了;第三步,如果服务存在,则停止服务。我们开始分析第三步,第三步这里最终调用ActivityThread的handleStopService方法。
Step13.ActivityThread.handleStopService
private void handleStopService(IBinder token) {
Service s = mServices.remove(token);
...
s.onDestroy();
...
}
复制代码
这里如果服务存在则调用服务的onDestroy方法,到这里服务的停止也就结束了。从上面看服务的整个流程相对于Activity简单的多。很容易就看懂了。其实还有一个IntentService,整个服务继承Service,只不过里面多了一个Handler,我们看看这段代码:
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
复制代码
如果有Handler就有发送消息的地方,那么发送消息在哪里呢,我们知道当你调用服务的时候会走onStartCommand方法:
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
复制代码
这里会调用onStart方法:
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
复制代码
这里就是发送消息的时候,消息发出后会由上面的ServiceHandler来处理,我们看到构造函数里传入了一个Looper,这个是在onCreate方法中初始化的:
public void onCreate() {
// TODO: It would be nice to have an option to hold a partial wakelock
// during processing, and to have a static startService(Context, Intent)
// method that would launch the service & hand off a wakelock.
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
复制代码
这里创建了一个Handler线程,并且获取了它的Looper,用来循环处理消息,因此我们知道同时只能处理一个消息,等前一个消息处理完了才会处理第二个,以此类推,因此需要同时处理的不能用这个Service,另外在ServiceHandler中有个stopSelf用来在消息处理完成后停止自己,因此该服务可以说是用完自动停止,不会一直存在,占用资源。
代码地址:
直接拉取导入开发工具(Intellij idea或者Android studio)
注:
首发地址:www.codemx.cn
Android开发群:192508518
微信公众账号:Code-MX
注:本文原创,转载请注明出处,多谢。