博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Service销毁流程
阅读量:7055 次
发布时间:2019-06-28

本文共 8703 字,大约阅读时间需要 29 分钟。

文中的源代码版本为api23

Service销毁流程

stopService流程

流程简图如下

关闭Service我们通常使用
Context.stopService,该方法会经历以下方法调用
Context.stopService->
ContextImpl.stopService->
ContextImpl.stopServiceCommon->
ActivityManagerService.stopServcie->
ActiveServcie.stopServiceLocked

ActiveServcie.stopServiceLocked

int stopServiceLocked(IApplicationThread caller, Intent service,            String resolvedType, int userId) {    //...    // If this service is active, make sure it is stopped.    ServiceLookupResult r = retrieveServiceLocked(service, resolvedType, null,            Binder.getCallingPid(), Binder.getCallingUid(), userId, false, false);    if (r != null) {        if (r.record != null) {            final long origId = Binder.clearCallingIdentity();            try {                stopServiceLocked(r.record);            } finally {                Binder.restoreCallingIdentity(origId);            }            return 1;        }        return -1;    }    return 0;}private void stopServiceLocked(ServiceRecord service) {    //...    //设置startRequested为false,在后面的流程中有用    service.startRequested = false;    //...    service.callStart = false;    bringDownServiceIfNeededLocked(service, false, false);}复制代码

该方法逻辑比较简单,通过retrieveServiceLocked方法找到服务记录,然后调用重载方法stopServiceLocked继续下面的流程,该方法内部直接调用了bringDownServiceIfNeededLocked

ActiveServices.bringDownServiceIfNeededLocked

private final void bringDownServiceIfNeededLocked(ServiceRecord r,             boolean knowConn/*false*/,            boolean hasConn/*false*/) {    //...    //判断是否有bind    if (isServiceNeeded(r, knowConn, hasConn)) {        return;    }    // Are we in the process of launching?    if (mPendingServices.contains(r)) {        return;    }    bringDownServiceLocked(r);}复制代码

该方法做了三件事情

  1. 调用isServiceNeeded方法判断服务是否还有必要存在,如果有则直接返回
  2. 查看服务是否存在于待启动服务列表中,如果是则直接返回
  3. 上面的条件都不满足的话则会调用bringDownServiceLocked继续停止服务的流程
ActiveServices.isServiceNeeded
private final boolean isServiceNeeded(ServiceRecord r, boolean knowConn, boolean hasConn) {    // 该字段在stopServiceLocked方法中已经被置为false    if (r.startRequested) {        return true;    }    // knowConn此时为false,所以会走这个if流程    if (!knowConn) {        hasConn = r.hasAutoCreateConnections();    }    if (hasConn) {        return true;    }    return false;}//ServiceRecord.javapublic boolean hasAutoCreateConnections() {    // XXX should probably keep a count of the number of auto-create    // connections directly in the service.    for (int conni=connections.size()-1; conni>=0; conni--) {        ArrayList
cr = connections.valueAt(conni); for (int i=0; i

isServiceNeeded内部又调用了hasAutoCreateConnections hasAutoCreateConnections会检测当前服务的绑定记录(bindService记录),在这些记录中只要有使用了带有BIND_AUTO_CREATE标志的Intent则返回true,表示不允许关闭服务。从这点可以看出,调用stopService之后并不一定会真正的关闭服务。 假设服务未被绑定,我们继续下面的流程

ActiveServices.bringDownServiceLocked

private final void bringDownServiceLocked(ServiceRecord r) {    for (int conni=r.connections.size()-1; conni>=0; conni--) {        ArrayList
c = r.connections.valueAt(conni); for (int i=0; i
=0; i--) { IntentBindRecord ibr = r.bindings.valueAt(i); //... if (ibr.hasBound) { try { //... ibr.hasBound = false; //通过IPC触发Service.onUnbind方法 r.app.thread.scheduleUnbindService(r, ibr.intent.getIntent()); } catch (Exception e) { //... } } } } //... //清理服务记录 final ServiceMap smap = getServiceMap(r.userId); smap.mServicesByName.remove(r.name); smap.mServicesByIntent.remove(r.intent); r.totalRestartCount = 0; unscheduleServiceRestartLocked(r, 0, true); //从待启动流程中移除 for (int i=mPendingServices.size()-1; i>=0; i--) { if (mPendingServices.get(i) == r) { mPendingServices.remove(i); if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Removed pending: " + r); } } //... //一些清理工作 r.clearDeliveredStartsLocked(); r.pendingStarts.clear(); if (r.app != null) { //... r.app.services.remove(r); if (r.app.thread != null) { //... try { //... mDestroyingServices.add(r); r.destroying = true; mAm.updateOomAdjLocked(r.app); //通过IPC触发Service.onDestory r.app.thread.scheduleStopService(r); } catch (Exception e) { //... } } else { //... } } else { //... } //...}复制代码

停止服务的逻辑还是挺清晰的

  1. 关闭所有的客户端连接,这个阶段就是通过IPC触发客户端的ServiceConnection.onServiceDisconnected
  2. 通过IPC触发服务的onUnbind生命周期方法
  3. 清理一些资源
  4. 通过IPC触发服务的onDestory生命周期方法

此时服务就真正走向了生命的终点了。

unbindService流程

流程简图如下

Context.unbindService方法会经历以下调用链 Context.unbindService-> ContextImpl.unbindService-> ActivityManagerService.unbindService-> ActiveService.unbindServiceLocked

ActiveService.unbindServiceLocked

boolean unbindServiceLocked(IServiceConnection connection) {    //对应于客户端的ServiceConnection    IBinder binder = connection.asBinder();    //可以使用同一个ServiceConnection连接多个Service    //因此这里拿出来是一个List    ArrayList
clist = mServiceConnections.get(binder); //... final long origId = Binder.clearCallingIdentity(); try { while (clist.size() > 0) { ConnectionRecord r = clist.get(0); removeConnectionLocked(r, null, null); //... } } finally { Binder.restoreCallingIdentity(origId); } return true;}复制代码

客户端的一个ServiceConnection实例可以bind至多个Service,对应于AMS这边就会保存多个ConnectionRecordunbindServiceLocked内使用了一个while循环,依次对每个ConnectionRecord调用removeConnectionLocked

ActiveServices.removeConnectionLocked

void removeConnectionLocked(        ConnectionRecord c, ProcessRecord skipApp, ActivityRecord skipAct) {    IBinder binder = c.conn.asBinder();    AppBindRecord b = c.binding;    ServiceRecord s = b.service;    //移除ServiceRecord以及客户端ProcessRecord等内部维护的    //ConnectionRecord    ArrayList
clist = s.connections.get(binder); if (clist != null) { clist.remove(c); if (clist.size() == 0) { s.connections.remove(binder); } } b.connections.remove(c); if (c.activity != null && c.activity != skipAct) { if (c.activity.connections != null) { c.activity.connections.remove(c); } } if (b.client != skipApp) { b.client.connections.remove(c); //... } clist = mServiceConnections.get(binder); if (clist != null) { clist.remove(c); if (clist.size() == 0) { mServiceConnections.remove(binder); } } //... if (b.connections.size() == 0) { b.intent.apps.remove(b.client); } //此处serviceDead为false if (!c.serviceDead) { //... if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0 && b.intent.hasBound) { try { //... b.intent.hasBound = false; // Assume the client doesn't want to know about a rebind; // we will deal with that later if it asks for one. 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); } } //这个flags就是调用bindService时用的flags if ((c.flags&Context.BIND_AUTO_CREATE) != 0) { boolean hasAutoCreate = s.hasAutoCreateConnections(); //... bringDownServiceIfNeededLocked(s, true, hasAutoCreate); } }}复制代码

removeConnectionLocked首先会做一些清理工作,之后会调用ApplicationThread.scheduleUnbindService方法触发Service.onUnbind 其次,如果发起bind请求时所用的flags中包含BIND_AUTO_CREATE标志,还会触发bringDownServiceIfNeededLocked hasAutoCreateConnectionsbringDownServiceIfNeededLocked方法我们在分析stopService流程的时候已经分析过了,就不展开讲了,这里只讨论bringDownServiceIfNeededLocked入参变化而引起的一些变化。 假设当前没有其他客户端绑定至该服务,那么此时hasAutoCreate应该为false,那么bringDownServiceIfNeededLocked的形参,knowConntruehasConnfalse 这两个参数,只会在bringDownServiceIfNeededLocked内调用isServiceNeeded方法使用到,再贴一下这个方法的代码

private final boolean isServiceNeeded(ServiceRecord r, boolean knowConn/*true*/, boolean hasConn/*false*/) {    // startRequested只有在调用过startService才会被置为true    // 这里为false    if (r.startRequested) {        return true;    }    // Is someone still bound to us keepign us running?    if (!knowConn) {        hasConn = r.hasAutoCreateConnections();    }    if (hasConn) {        return true;    }    return false;}复制代码

可以看到isServiceNeeded此时返回false,因此销毁的流程还会继续进行下去。 后续的流程就跟stopService的一样了。

转载地址:http://eolol.baihongyu.com/

你可能感兴趣的文章
Elasticsearch数据
查看>>
共享雨伞漂流伞获近亿元战略投资,投资方为蚂蚁金服
查看>>
Cookie(1)
查看>>
Confluence 6 可以自定义的元素
查看>>
你让我怎么说
查看>>
服务器怎么租?阿里云实例规格怎么选?
查看>>
KodExplorer 4.40 发布,权限机制优化
查看>>
WPF 为资源字典 添加事件响应的后台类
查看>>
ASP.NET MVC-异常处理&自定义错误页
查看>>
官宣!阿里巴巴云效平台成功助力国内首个 DevOps 标准建设!
查看>>
分布式存储的六大优点
查看>>
Redis核心概念
查看>>
ansible 管理window主机,cmd模块
查看>>
SQL SERVER中的OLEDB等待事件
查看>>
OSI七层模型及对应协议
查看>>
WPF-WPF BitmapEffect (按钮凹凸效果)
查看>>
mysql5.7 创建新表时提示时间戳非法
查看>>
Android经典项目开发之天气APP实例分享
查看>>
一句话搞定高仿ios底部弹出提示框(Android)
查看>>
jdk7中HashMap知识点整理
查看>>