首页 > 其他分享 >Android Framework AMS(08)service组件分析-2(startService和StopService关键流程分析)

Android Framework AMS(08)service组件分析-2(startService和StopService关键流程分析)

时间:2024-10-17 23:21:16浏览次数:3  
标签:StopService 服务 service 启动 app false null 08

该系列文章总纲链接:专题总纲目录 Android Framework 总纲


本章关键点总结 & 说明:

说明:上一章节主要解读应用层service组件启动的2种方式startService和bindService,以及从APP层到AMS调用之间的打通。本章节主要关注service组件启动方式的一种:startService启动方式,分析关键API为service组件的startService和stopService方法。

我们从AMS.startService和AMS.stopService分别来分析,分析的主要流程为:

  • AMS.startService->service组件onCreate、onStartCommand
  • AMS.stopService->service组件onDestroy

接下来开始详细解读。

1 AMS.startService流程解读(onCreate、onStartCommand)

AMS.startService代码实现如下:

//ActivityManagerService
    @Override
    public ComponentName startService(IApplicationThread caller, Intent service,
            String resolvedType, int userId) {
        // 检查调用者是否是隔离的进程,如果不是,则抛出安全异常
        enforceNotIsolatedCaller("startService");
        
        synchronized(this) {
            final int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            final long origId = Binder.clearCallingIdentity();
            ComponentName res = mServices.startServiceLocked(caller, service,
                    resolvedType, callingPid, callingUid, userId);
            Binder.restoreCallingIdentity(origId);
            return res;
        }
    }
    //...

这里调用了ActivityService的startServiceLocked方法,代码实现如下:

//ActivityService
    //关键流程:step1
    ComponentName startServiceLocked(IApplicationThread caller,
            Intent service, String resolvedType,
            int callingPid, int callingUid, int userId) {

        // 判断调用者是否在前台运行
        final boolean callerFg;
        if (caller != null) {
            // 获取调用者的应用记录
            final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
            // 判断调用者是否在前台运行,如果不是后台非交互线程组,则认为是前台
            callerFg = callerApp.setSchedGroup != Process.THREAD_GROUP_BG_NONINTERACTIVE;
        } else {
            // 如果没有调用者,也认为是前台
            callerFg = true;
        }

        // 检索服务,如果服务不存在或者没有权限,则返回相应的结果
        ServiceLookupResult res = retrieveServiceLocked(service, resolvedType,
                    callingPid, callingUid, userId, true, callerFg);
        
        // 如果服务记录为空,说明服务不存在或者没有权限,返回错误信息
        if (res.record == null) {
            return new ComponentName("!", res.permission != null
                    ? res.permission : "private to package");
        }

        // 获取服务记录
        ServiceRecord r = res.record;

        // 检查用户是否存在
        if (!mAm.getUserManagerLocked().exists(r.userId)) {
            return null;
        }

        // 检查调用者是否有权限授予URI权限
        NeededUriGrants neededGrants = mAm.checkGrantUriPermissionFromIntentLocked(
                    callingUid, r.packageName, service, service.getFlags(), null, r.userId);
        
        // 如果服务已经在重启计划中,取消重启
        if (unscheduleServiceRestartLocked(r, callingUid, false)) {}
        
        // 更新服务最后活跃的时间
        r.lastActivity = SystemClock.uptimeMillis();
        // 设置服务启动请求为真
        r.startRequested = true;
        // 设置服务不是延迟停止的
        r.delayedStop = false;
        // 添加一个新的启动项到服务的待启动列表中
        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.mStartedUsers.get(r.userId) != null) {
            // 获取服务要运行的进程记录
            ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid, false);
            // 如果进程记录为空,或者进程状态大于接收者状态,执行以下操作
            if (proc == null || proc.curProcState > ActivityManager.PROCESS_STATE_RECEIVER) {
                // 如果服务是延迟的,直接返回服务名称
                if (r.delayed) {
                    return r.name;
                }
                // 如果正在启动的后台服务数量超过了最大限制,将服务添加到延迟启动列表
                if (smap.mStartingBackground.size() >= mMaxStartingBackground) {
                    smap.mDelayedStartList.add(r);
                    r.delayed = true;
                    return r.name;
                }
                // 标记服务需要添加到启动列表
                addToStarting = true;
            } else if (proc.curProcState >= ActivityManager.PROCESS_STATE_SERVICE) {
                // 如果进程状态大于或等于服务状态,也标记服务需要添加到启动列表
                addToStarting = true;
            }
        }
        
        // 调用内部方法来实际启动服务
        return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
    }
    //关键流程:step2
    ComponentName startServiceInnerLocked(ServiceMap smap, Intent service,
            ServiceRecord r, boolean callerFg, boolean addToStarting) {
        // 获取服务状态跟踪器
        ProcessStats.ServiceState stracker = r.getTracker();
        // 如果服务状态跟踪器存在,设置服务为已启动状态,并更新内存因素和最后活动时间
        if (stracker != null) {
            stracker.setStarted(true, mAm.mProcessStats.getMemFactorLocked(), r.lastActivity);
        }
        // 设置服务的callStart标志为false,表示服务尚未调用 onStartCommand
        r.callStart = false;
        synchronized (r.stats.getBatteryStats()) {
            r.stats.startRunningLocked();
        }
        // 关键方法:实际启动服务,如果启动失败,返回错误信息
        String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false);
        if (error != null) {
            return new ComponentName("!!", error);
        }

        // 如果服务请求启动并且需要添加到正在启动的服务列表中
        if (r.startRequested && addToStarting) {
            // 如果当前没有其他后台服务正在启动,标记为第一个启动的后台服务
            boolean first = smap.mStartingBackground.size() == 0;
            // 将服务添加到正在启动的后台服务列表中
            smap.mStartingBackground.add(r);
            // 设置服务的后台启动超时时间
            r.startingBgTimeout = SystemClock.uptimeMillis() + BG_START_TIMEOUT;
            // 如果是第一个启动的后台服务,重新调度延迟启动的服务
            if (first) {
                smap.rescheduleDelayedStarts();
            }
        } else if (callerFg) {
            // 如果调用者在前台,确保服务不是正在启动的后台服务
            smap.ensureNotStartingBackground(r);
        }

        // 返回服务的组件名称
        return r.name;
    }
    //关键流程:step3
    private final String bringUpServiceLocked(ServiceRecord r,
            int intentFlags, boolean execInFg, boolean whileRestarting) {

        // 如果服务的应用记录不为空且应用线程不为空,说明服务已经在运行,直接发送服务参数
        if (r.app != null && r.app.thread != null) {
            sendServiceArgsLocked(r, execInFg, false);
            return null;
        }

        // 如果服务不在重启中,并且重启延迟时间大于0,则不启动服务
        if (!whileRestarting && r.restartDelay > 0) {
            return null;
        }

        // 如果服务在重启中,从重启服务列表中移除该服务
        if (mRestartingServices.remove(r)) {
            clearRestartingIfNeededLocked(r);
        }

        // 如果服务是延迟启动的,从延迟启动列表中移除该服务,并设置服务不再延迟
        if (r.delayed) {
            getServiceMap(r.userId).mDelayedStartList.remove(r);
            r.delayed = false;
        }

        // 如果用户未启动,关闭服务并返回
        if (mAm.mStartedUsers.get(r.userId) == null) {
            bringDownServiceLocked(r);
            return msg;
        }

        try {
            // 设置包停止状态为非停止状态
            AppGlobals.getPackageManager().setPackageStoppedState(
                    r.packageName, false, r.userId);
        } catch (RemoteException e) {
            //...
        }

        // 判断服务是否运行在隔离进程中
        final boolean isolated = (r.serviceInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
        final String procName = r.processName;
        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);
                    //关键方法:实际启动服务
                    realStartServiceLocked(r, app, execInFg);
                    return null;
                } catch (RemoteException e) {
                    //...
                }
            }
        } else {
            // 如果服务运行在隔离进程中,尝试获取隔离进程记录
            app = r.isolatedProc;
        }

        // 如果进程记录为空,尝试启动新进程
        if (app == null) {
            //这里是不是眼熟,和startActivity的思路是一致的,创建进程。
            if ((app = mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
                    "service", r.name, false, isolated, false)) == null) {
                bringDownServiceLocked(r);
                return msg;
            }
            // 如果服务运行在隔离进程中,保存隔离进程记录
            if (isolated) {
                r.isolatedProc = app;
            }
        }

        // 如果服务不在待处理列表中,添加到待处理列表
        if (!mPendingServices.contains(r)) {
            mPendingServices.add(r);
        }

        // 如果服务已经请求停止,取消停止请求
        if (r.delayedStop) {
            r.delayedStop = false;
            if (r.startRequested) {
                stopServiceLocked(r);
            }
        }
        return null;
    }
    //关键流程:step4
    private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {
        // 如果进程记录的应用线程为空,抛出远程异常
        if (app.thread == null) {
            throw new RemoteException();
        }
        // 设置服务的应用记录
        r.app = app;
        // 更新服务的最后活动时间和重启时间
        r.restartTime = r.lastActivity = SystemClock.uptimeMillis();

        // 将服务添加到应用的服务体系表中
        app.services.add(r);
        // 增加服务执行的计数,并根据是否在前台执行来更新状态
        bumpServiceExecutingLocked(r, execInFg, "create");
        // 更新进程的最近最少使用(LRU)状态
        mAm.updateLruProcessLocked(app, false, null);
        // 更新内存调整
        mAm.updateOomAdjLocked();

        boolean created = false;
        try {
            // 同步电池统计数据的更新
            synchronized (r.stats.getBatteryStats()) {
                r.stats.startLaunchedLocked();
            }
            // 确保包的dex文件已经优化
            mAm.ensurePackageDexOpt(r.serviceInfo.packageName);
            // 强制进程状态至少为服务状态
            app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
            // 关键方法1:通过应用线程调度服务的创建
            app.thread.scheduleCreateService(r, r.serviceInfo,
                    mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                    app.repProcState);
            r.postNotification();
            // 标记服务已创建
            created = true;
        } catch (DeadObjectException e) {
            //...
        } finally {
            // 如果服务未创建成功,进行清理操作
            if (!created) {
                app.services.remove(r);
                r.app = null;
                // 安排服务重启
                scheduleServiceRestartLocked(r, false);
                return;
            }
        }

        // 请求服务的绑定
        requestServiceBindingsLocked(r, execInFg);
        // 更新服务客户端活动
        updateServiceClientActivitiesLocked(app, null, true);
        // 如果服务请求启动并且需要调用 onStartCommand,添加一个启动项
        if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
            r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),null, null));
        }

        // 关键方法2:发送服务参数,回调执行 onStartCommand
        sendServiceArgsLocked(r, execInFg, true);

        // 如果服务是延迟启动的,从延迟启动列表中移除
        if (r.delayed) {
            getServiceMap(r.userId).mDelayedStartList.remove(r);
            r.delayed = false;
        }

        // 如果服务已经请求延迟停止,取消延迟停止请求
        if (r.delayedStop) {
            r.delayedStop = false;
            if (r.startRequested) {
                stopServiceLocked(r);
            }
        }
    }
    //...

这一条调用关系线下来,从调用关系上依次为:

  1. startServiceLocked
  2. startServiceInnerLocked
  3. bringUpServiceLocked
  4. realStartServiceLocked

最后的realStartServiceLocked才是实际启动服务的方法,主要作用是确保服务在正确的进程中被创建和启动。它涉及到与应用程序线程的通信,服务状态的更新,以及服务生命周期的管理。代码中的scheduleCreateService方法用于请求应用程序线程创建服务,requestServiceBindingsLocked方法用于请求服务的绑定(下一节会涉及),sendServiceArgsLocked方法用于发送服务的参数。ServiceRecord对象表示一个服务的记录,它包含了服务的状态和配置信息。ProcessRecord对象表示一个进程的记录,它包含了进程的状态和配置信息。到这里我们主要关注2个关键方法:

  • scheduleCreateService(调用service的onCreate)
  • sendServiceArgsLocked(调用到service的onStartCommand)

1.1 scheduleCreateService相关流程解读(startService到onCreate)

这里实际上是以startService到service组件调用onCreate的流程分析为目的。代码实现如下:


//ActivityThread
    //ApplicationThread
        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);
        }
    //消息处理
    private class H extends Handler {
        //...
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case CREATE_SERVICE:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceCreate");
                    handleCreateService((CreateServiceData)msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                //...
            }
        }
        //...
    }
    //...
    private void handleCreateService(CreateServiceData data) {
        // 取消调度GC Idler,以确保在服务创建期间不会进行垃圾回收,影响服务启动性能
        unscheduleGcIdler();

        // 获取服务所在应用的LoadedApk对象,它包含了应用的加载信息
        LoadedApk packageInfo = getPackageInfoNoCheck(
                data.info.applicationInfo, data.compatInfo);

        Service service = null;
        try {
            // 获取ClassLoader对象,用于加载服务类
            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);
            // 服务attach到上下文环境
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManagerNative.getDefault());
            // 调用服务的onCreate()生命周期方法
            service.onCreate();
            // 将服务实例存储在映射中,以便后续访问
            mServices.put(data.token, service);
            // 通知AMS服务已执行完成
            try {
                ActivityManagerNative.getDefault().serviceDoneExecuting(
                        data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
            } catch (RemoteException e) {
                //...
            }
        } catch (Exception e) {
            //...
        }
    }

这段代码的主要作用是创建服务实例并初始化服务的上下文环境。它涉及到类加载、服务实例化、上下文环境的设置以及服务生命周期的管理(主要是onCreate)。代码中的CreateServiceData对象包含了创建服务所需的所有信息,如服务信息、兼容性信息等。ContextImpl对象表示服务的上下文环境,它提供了服务所需的各种资源和信息。Service对象是服务的实际实例,它实现了服务的具体功能。

1.2 sendServiceArgsLocked相关流程分析(startService到onStartCommand)

这里实际上是以startService到service组件调用onStartCommand的流程分析为目的。代码实现如下:

//ActivityService
    private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
            boolean oomAdjusted) {
        final int N = r.pendingStarts.size();
        if (N == 0) {
            return;
        }

        while (r.pendingStarts.size() > 0) {
            try {
                // 从待处理列表中取出第一个启动项
                ServiceRecord.StartItem si = r.pendingStarts.remove(0);
                // 如果启动项的Intent为空,并且不是唯一的启动项,则跳过处理
                if (si.intent == null && N > 1) {
                    continue;
                }
                // 记录启动项的交付时间
                si.deliveredTime = SystemClock.uptimeMillis();
                // 将启动项添加到已交付列表中
                r.deliveredStarts.add(si);
                // 增加启动项的交付次数
                si.deliveryCount++;
                // 如果启动项需要授予URI权限,进行授权
                if (si.neededGrants != null) {
                    mAm.grantUriPermissionUncheckedFromIntentLocked(si.neededGrants,
                            si.getUriPermissionsLocked());
                }
                // 增加服务执行的计数,并根据是否在前台执行来更新状态
                bumpServiceExecutingLocked(r, execInFg, "start");
                // 如果服务的OOM优先级尚未调整,则进行调整
                if (!oomAdjusted) {
                    oomAdjusted = true;
                    mAm.updateOomAdjLocked(r.app);
                }
                // 设置启动服务的标志
                int flags = 0;
                if (si.deliveryCount > 1) {
                    flags |= Service.START_FLAG_RETRY;
                }
                if (si.doneExecutingCount > 0) {
                    flags |= Service.START_FLAG_REDELIVERY;
                }
                // 关键方法:传递应用线程调度服务的启动参数,发送消息启动服务
                r.app.thread.scheduleServiceArgs(r, si.taskRemoved, si.id, flags, si.intent);
            } catch (Exception e) {
                //...
                break;
            }
        }
    }

这段代码的主要作用是处理服务的启动参数,并将这些参数发送给服务。它涉及到服务启动项的处理、URI权限的授权、服务执行计数的增加以及服务启动参数的调度。代码中的ServiceRecord对象表示一个服务的记录,它包含了服务的状态和配置信息。ServiceRecord.StartItem对象表示一个服务启动项,它包含了启动服务所需的参数。最后调用scheduleServiceArgs发送消息,代码实现如下:

//ActivityThread
    //ApplicationThread
        public final void scheduleServiceArgs(IBinder token, boolean taskRemoved, int startId,
            int flags ,Intent args) {
            ServiceArgsData s = new ServiceArgsData();
            s.token = token;
            s.taskRemoved = taskRemoved;
            s.startId = startId;
            s.flags = flags;
            s.args = args;

            sendMessage(H.SERVICE_ARGS, s);
        }
    //消息处理
    private class H extends Handler {
        //...
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case SERVICE_ARGS:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceStart");
                    handleServiceArgs((ServiceArgsData)msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                //...
            }
        }
        //...
    }
    //...
    private void handleServiceArgs(ServiceArgsData data) {
        // 根据服务的token获取服务实例
        Service s = mServices.get(data.token);
        if (s != null) {
            try {
                // 如果有启动参数Intent,设置它的ClassLoader为服务的ClassLoader,并准备进入进程
                if (data.args != null) {
                    data.args.setExtrasClassLoader(s.getClassLoader());
                    data.args.prepareToEnterProcess();
                }
                // 定义服务启动命令的返回结果变量
                int res;
                // 如果服务是因为任务栈被移除而启动的,调用onTaskRemoved方法
                if (!data.taskRemoved) {
                    //关键方法:调用服务的onStartCommand方法,并传递启动参数
                    res = s.onStartCommand(data.args, data.flags, data.startId);
                } else {
                    // 如果服务是因为任务栈被移除而启动的,调用onTaskRemoved方法
                    s.onTaskRemoved(data.args);
                    // 设置返回结果为任务移除完成
                    res = Service.START_TASK_REMOVED_COMPLETE;
                }

                // 等待队列中的工作完成
                QueuedWork.waitToFinish();

                // 关键方法:通知AMS已经完成
                try {
                    ActivityManagerNative.getDefault().serviceDoneExecuting(
                            data.token, SERVICE_DONE_EXECUTING_START, data.startId, res);
                } catch (RemoteException e) {
                    //...
                }
                // 确保JIT(即时编译)被启用
                ensureJitEnabled();
            } catch (Exception e) {
                //...
            }
        }
    }

这段代码的主要作用是接收服务的启动参数,调用服务的onStartCommand方法,并处理服务执行完成后的清理工作。它涉及到服务实例的获取、启动参数的处理、服务方法的调用以及服务执行状态的反馈。代码中的ServiceArgsData对象包含了服务启动所需的所有参数,如启动Intent、启动标志、启动ID等。

2 AMS.stopService流程解读(onDestroy)

AMS.stopService代码实现如下:

//ActivityManagerService
    @Override
    public int stopService(IApplicationThread caller, Intent service,
            String resolvedType, int userId) {
        enforceNotIsolatedCaller("stopService");
        //...
        synchronized(this) {
            return mServices.stopServiceLocked(caller, service, resolvedType, userId);
        }
    }

这里调用了ActivityService的stopServiceLocked方法,代码实现如下:

//ActivityService
    //关键流程:step1
    int stopServiceLocked(IApplicationThread caller, Intent service,
            String resolvedType, int userId) {
        // 获取调用者的进程记录
        final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
        //...

        // 查找要停止的服务记录
        ServiceLookupResult r = retrieveServiceLocked(service, resolvedType,
                Binder.getCallingPid(), Binder.getCallingUid(), userId, false, false);
        // 如果找到了服务记录,并且记录不为空
        if (r != null && r.record != null) {
            final long origId = Binder.clearCallingIdentity();
            try {
                // 关键方法:调用停止服务的内部方法
                stopServiceLocked(r.record);
            } finally {
                Binder.restoreCallingIdentity(origId);
            }
            // 返回1表示服务成功停止
            return 1;
        }
        // 如果服务记录为空,返回-1表示服务未找到
        return -1;
    }
    //关键流程:step2
    private void stopServiceLocked(ServiceRecord service) {
        // 如果服务是延迟停止的,设置延迟停止标志并返回
        if (service.delayed) {
            service.delayedStop = true;
            return;
        }
        // 同步电池统计数据的更新
        synchronized (service.stats.getBatteryStats()) {
            // 停止服务的电池统计数据
            service.stats.stopRunningLocked();
        }
        // 标记服务不再被请求启动
        service.startRequested = false;
        // 如果服务有状态跟踪器,设置服务为未启动状态
        if (service.tracker != null) {
            service.tracker.setStarted(false, mAm.mProcessStats.getMemFactorLocked(),
                    SystemClock.uptimeMillis());
        }
        // 标记服务的onStartCommand方法不再被调用
        service.callStart = false;
        // 如果需要,执行服务的停止逻辑
        bringDownServiceIfNeededLocked(service, false, false);
    }
    //关键流程:step3
    private final void bringDownServiceIfNeededLocked(ServiceRecord r, boolean knowConn, boolean hasConn) {
        // 检查服务是否仍然需要如果服务仍然需要,例如服务正在运行或者有待处理的启动请求,则不停止服务并直接返回
        if (isServiceNeeded(r, knowConn, hasConn)) {
            return;
        }

        // 如果服务在待处理列表中,说明服务的启动请求还在处理中,因此不停止服务
        if (mPendingServices.contains(r)) {
            return;
        }

        // 如果服务不再需要且不在待处理列表中,则停止服务
        bringDownServiceLocked(r);
    }
    //关键流程:step4
    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 {
                    // 通知客户端服务已经死亡
                    cr.conn.connected(r.name, null);
                } catch (Exception e) {
                    //...
                }
            }
        }

        // 如果服务已经被应用bind,通知应用服务已经被unbind
        // 本次分析不涉及bind和unbind操作,因此忽略即可
        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 {
                        // 增加服务执行的计数,并根据是否在前台执行来更新状态
                        bumpServiceExecutingLocked(r, false, "bring down unbind");
                        // 更新内存调整
                        mAm.updateOomAdjLocked(r.app);
                        // 标记服务为未绑定状态
                        ibr.hasBound = false;
                        // 通知应用服务已经被解绑
                        r.app.thread.scheduleUnbindService(r, ibr.intent.getIntent());
                    } catch (Exception e) {
                        // 异常处理代码...
                        serviceProcessGoneLocked(r);
                    }
                }
            }
        }

        // 记录服务销毁的时间
        r.destroyTime = SystemClock.uptimeMillis();
        // 获取服务映射对象
        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);
            }
        }

        // 取消服务的通知
        r.cancelNotification();
        // 标记服务不在前台
        r.isForeground = false;
        // 重置前台服务的ID
        r.foregroundId = 0;
        // 重置前台通知
        r.foregroundNoti = null;

        // 清除已交付的启动请求
        r.clearDeliveredStartsLocked();
        // 清除待处理的启动请求
        r.pendingStarts.clear();

        // 如果服务所属的应用还存在
        if (r.app != null) {
            // 同步电池统计数据的更新
            synchronized (r.stats.getBatteryStats()) {
                r.stats.stopLaunchedLocked();
            }
            // 从应用的服务列表中移除服务
            r.app.services.remove(r);
            // 如果应用线程还存在,更新服务的前台状态
            if (r.app.thread != null) {
                updateServiceForegroundLocked(r.app, false);
                try {
                    // 增加服务执行的计数,并根据是否在前台执行来更新状态
                    bumpServiceExecutingLocked(r, false, "destroy");
                    // 添加服务到正在销毁的服务列表中
                    mDestroyingServices.add(r);
                    // 标记服务为正在销毁状态
                    r.destroying = true;
                    // 更新内存调整
                    mAm.updateOomAdjLocked(r.app);
                    // 关键方法:通知应用销毁服务
                    r.app.thread.scheduleStopService(r);
                } catch (Exception e) {
                    // 异常处理代码...
                }
            }
        }

        // 清除服务的绑定
        if (r.bindings.size() > 0) {
            r.bindings.clear();
        }

        // 如果服务有重启器,设置服务为null
        if (r.restarter instanceof ServiceRestarter) {
            ((ServiceRestarter) r.restarter).setService(null);
        }

        int memFactor = mAm.mProcessStats.getMemFactorLocked();
        long now = SystemClock.uptimeMillis();
        // 如果服务有状态跟踪器,设置服务为未启动和未绑定状态
        if (r.tracker != null) {
            r.tracker.setStarted(false, memFactor, now);
            r.tracker.setBound(false, memFactor, now);
            // 如果服务的执行嵌套计数为0,清除当前所有者
            if (r.executeNesting == 0) {
                r.tracker.clearCurrentOwner(r, false);
                r.tracker = null;
            }
        }

        // 确保服务不在启动的后台服务列表中
        smap.ensureNotStartingBackground(r);
    }

这一条调用关系线下来,从调用关系上依次为:

  1. stopServiceLocked
  2. stopServiceLocked
  3. bringDownServiceIfNeededLocked
  4. bringDownServiceLocked

最后的bringDownServiceLocked才是实际关闭服务的方法,它的作用是关闭服务并执行相关的清理工作。它涉及到服务绑定的清理(如果bind则执行unbind操作,主要针对bindservice操作,本次分析不涉及)、服务执行计数的更新、服务状态的更新、服务通知的取消以及服务销毁逻辑的调用。接下来我们主要关注对应startService的通知应用销毁服务的关键方法:scheduleStopService,代码实现如下:

//ActivityThread
    //ApplicationThread
        public final void scheduleStopService(IBinder token) {
            sendMessage(H.STOP_SERVICE, token);
        }
    //消息处理
    private class H extends Handler {
        //...
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case STOP_SERVICE:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceStop");
                    handleStopService((IBinder)msg.obj);
                    maybeSnapshot();
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                //...
            }
        }
        //...
    }
    //...
    private void handleStopService(IBinder token) {
        Service s = mServices.remove(token);
        if (s != null) {
            try {
                // 关键方法:调用服务的onDestroy生命周期方法
                s.onDestroy();
                // 获取服务的上下文环境
                Context context = s.getBaseContext();
                // 如果上下文环境是ContextImpl的实例,安排最终的清理工作
                if (context instanceof ContextImpl) {
                    final String who = s.getClassName();
                    // 安排清理服务关联的资源和数据
                    ((ContextImpl) context).scheduleFinalCleanup(who, "Service");
                }

                // 等待队列中的工作完成,确保所有异步任务完成
                QueuedWork.waitToFinish();

                // 通知ActivityManager服务已经执行完成停止操作
                try {
                    ActivityManagerNative.getDefault().serviceDoneExecuting(
                            token, SERVICE_DONE_EXECUTING_STOP, 0, 0);
                } catch (RemoteException e) {
                    //...
                }
            } catch (Exception e) {
                //...
            }
        }
    }

这段代码的主要作用是处理服务的停止请求,包括调用服务的onDestroy方法、清理服务关联的资源和数据,以及通知AMS服务已经停止。代码中的mServices是一个保存服务实例的映射,它使用服务的token作为键。代码中的ContextImpl是Android中上下文环境的实现类,它提供了额外的功能,如安排最终的清理工作。

至此,我们就分析清楚了2个关键流程:

  • AMS.startService->service组件onCreate、onStartCommand
  • AMS.stopService->service组件onDestroy

下一章节,我们专注分析bindService启动及停止相关流程,以及如何执行到组件的回调,尤其是bind和unbind。

标签:StopService,服务,service,启动,app,false,null,08
From: https://blog.csdn.net/vviccc/article/details/142988285

相关文章

  • Android Framework AMS(09)service组件分析-3(bindService和unbindService关键流程分析)
    该系列文章总纲链接:专题总纲目录AndroidFramework总纲本章关键点总结&说明:说明:上上一章节主要解读应用层service组件启动的2种方式startService和bindService,以及从APP层到AMS调用之间的打通。上一章节我们关注了service组件启动方式的一种:startService启动方式。本章......
  • 多校A层冲刺NOIP2024模拟赛08 排列
    多校A层冲刺NOIP2024模拟赛08排列一种连续段dp的解法。题面小Y最近在研究组合数学,他学会了如何枚举排列。小Z最近在研究数论,他学会了求最大公约数。于是小Y和小Z联手出了一个有趣的题目:有多少个长度为\(n\)且任意相邻两个数的最大公约数都不为\(k\)的排列?......
  • 多校A层冲刺NOIP2024模拟赛08
    GGT1传送(teleport)签到题,但是你怎么知道我场上因为dis[j]=bi[i].w调了一个小时。就是这肯定是一张完全图,但是肯定不能把所有的边都连上然后去跑dij,那么就要考虑那些边是没用的。对于从$(1,2)$到$(5,4)$,最优的是直接通过$Y$轴转过去,但是也可以先到$(3,3)......
  • 多校 A 层冲刺 NOIP2024 模拟赛 08
    多校A层冲刺NOIP2024模拟赛08T1传送(teleport)签到题性质题,注意到对于一个点而言有意义的传送的只有分别按\(x,y\)排序后与其相邻的点,证明考虑贪心手模即可。然后就能上最短路了,dj的时间复杂度为\(O((n+m)logn)\)。T2排列(permutation)签到题状压,注意到\(\dfrac......
  • 多校A层冲刺NOIP2024模拟赛08
    挂分了,垫底啦!!!rank8挂成rank27啦!!!rank27,T128,T20,T30,T40T2内存限制256MB,我打了一个257MB的,然后MLE了。T3暴力挂了9pts?T1传送(teleport)是简单题,但我不会对\(X,Y\)分开看,如果我们在最优解中⾛了某⼀步,可以看做是在对应维度上⾛了⼀段。那么这⼀段上的点可以看做是依......
  • CSP2024 前集训:多校A层冲刺NOIP2024模拟赛08
    前言光顾着想T2了,但是不知道哪儿假了,只有\(\dfrac{n}{k}\le5\)的点是对的,然后居然只有二十分,发现数据放错了,找喵喵改了成五十了。然后T1因为重边挂没了。T3没调出来,确切的说是省的时间不多了打不完,就写了个部分分。T4咕了。机房凳子没靠椅,一直坐着腰快折了肿么办。......
  • Service 的实现
    服务(Service)将在集群中运行的应用通过同一个面向外界的端点公开出去,即使工作负载分散于多个后端也完全可行。Kubernetes中Service是将运行在一个或一组Pod上的网络应用程序公开为网络服务的方法。Kubernetes中Service的一个关键目标是无需修改现有应用以使用某种不熟悉......
  • 08_实现 reactive
    目录编写reactive的函数签名处理对象的其他行为拦截in操作符拦截for...in循环delete操作符处理边界新旧值发生变化时才触发依赖的情况处理从原型上继承属性的情况处理一个对象已经是代理对象的情况处理一个原始对象已经被代理过一次之后的情况浅响应与深响应代......
  • 『模拟赛』多校A层冲刺NOIP2024模拟赛08
    Rank还行A.传送(teleport)签。单元最短路,先想Dijkstra。发现这道题还有个不同寻常的移动方式,可以以\(min\left(|x_i-x_j|,|y_i-y_j|\right)\)的代价从\(i\)移动到\(j\)。暴力连边是\(\mathcal{O(n^2)}\)的,时间空间都过不去。被叫去整内务在楼梯上想到,一个点不应......
  • 多校A层冲刺NOIP2024模拟赛08
    多校A层冲刺NOIP2024模拟赛08\(T1\)A.传送(teleport)\(0pts\)弱化版:[ABC065D]Built?|luoguP8074[COCI2009-2010#7]SVEMIR|“迎新春,过大年”多校程序设计竞赛H二次元世界之寻找珂朵莉先不管后面加入的\(m\)条边。对于两点间的路径\(i\toj\),经过中......