Service销毁流程

文中的源代码版本为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.java
public 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<ConnectionRecord> cr = connections.valueAt(conni);
        for (int i=0; i<cr.size(); i++) {
            if ((cr.get(i).flags&Context.BIND_AUTO_CREATE) != 0) {
                return true;
            }
        }
    }
    return false;
}
复制代码

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<ConnectionRecord> c = r.connections.valueAt(conni);
        for (int i=0; i<c.size(); i++) {
            ConnectionRecord cr = c.get(i);
            cr.serviceDead = true;
            try {
                //断开客户端连接
                //通过IPC触发ServiceConnectino.onServiceDisconnected
                cr.conn.connected(r.name, null);
            } catch (Exception e) {
                //...
            }
        }
    }


    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 {
                    //...
                    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<ConnectionRecord> 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<ConnectionRecord> 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的一样了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
`bindService()` 方法用于向 Service 绑定客户端,使得客户端可以与 Service 进行交互。其工作流程如下: 1. 客户端调用 `bindService()` 方法并传递一个 `ServiceConnection` 对象,该对象用于监听与 Service 的连接状态。 2. 系统会检查传递给 `bindService()` 方法的 `Intent` 中是否指定了要绑定的 Service。如果指定了,系统会启动该 Service(如果尚未启动)并将其与客户端进行绑定。如果没有指定,则系统会抛出异常。 3. 如果 Service 已经启动并且未终止,则系统会调用 `onBind()` 方法来获取与客户端进行通信的 `IBinder` 对象。该对象将传递给客户端的 `ServiceConnection` 对象的 `onServiceConnected()` 方法。 4. 如果 Service 尚未启动,则系统会在调用 `bindService()` 方法时启动该 Service。在 Service 启动后,系统会调用 `onBind()` 方法以获取 `IBinder` 对象并将其传递给 `ServiceConnection` 对象。 5. 当客户端与 Service 成功绑定时,系统会调用 `ServiceConnection` 对象的 `onServiceConnected()` 方法。在该方法中,客户端可以获取 `IBinder` 对象并使用它与 Service 进行通信。 6. 当客户端不再需要与 Service 交互时,它可以调用 `unbindService()` 方法来解除绑定。当 Service 上没有任何客户端与其绑定时,系统会调用 `onUnbind()` 方法。如果 Service 此时已停止,则系统会调用 `onDestroy()` 方法来销毁Service

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值