Android Framework AMS(09)service组件分析-3(bindService和unbindService关键流程分析)

news2024/10/21 18:25:20

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


本章关键点总结 & 说明:

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

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

  • AMS.bindService->service组件onCreate、onBind
  • AMS.unbindService->service组件onUnBind、onDestroy

接下来开始详细解读。

1 AMS.bindService流程解读(onCreate、onBind)

AMS.bindService代码实现如下:

//ActivityManagerService
    public int bindService(IApplicationThread caller, IBinder token,
                Intent service, String resolvedType,
                IServiceConnection connection, int flags, int userId) {
            // 检查调用者是否是隔离的进程,如果不是,则抛出安全异常
            enforceNotIsolatedCaller("bindService");
            //...
            synchronized(this) {
                return mServices.bindServiceLocked(caller, token, service, resolvedType,
                        connection, flags, userId);
            }
        }

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

//ActivityService
    //关键流程:step1
    int bindServiceLocked(IApplicationThread caller, IBinder token,
            Intent service, String resolvedType,
            IServiceConnection connection, int flags, int userId) {
        // 获取请求绑定服务的客户端应用记录
        final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
        //...

        // 如果token不为空,尝试获取对应的Activity记录
        ActivityRecord activity = null;
        if (token != null) {
            activity = ActivityRecord.isInStackLocked(token);
            //...
        }

        // 获取客户端为服务绑定设置的标签和PendingIntent
        int clientLabel = 0;
        PendingIntent clientIntent = null;

        // 如果调用者是系统进程,尝试获取客户端Intent和标签
        if (callerApp.info.uid == Process.SYSTEM_UID) {
            try {
                clientIntent = service.getParcelableExtra(Intent.EXTRA_CLIENT_INTENT);
            } catch (RuntimeException e) {
            }
            if (clientIntent != null) {
                clientLabel = service.getIntExtra(Intent.EXTRA_CLIENT_LABEL, 0);
                if (clientLabel != 0) {
                    // 如果设置了客户端标签,创建一个新的Intent用于服务绑定
                    service = service.cloneFilter();
                }
            }
        }

        // 如果设置了BIND_TREAT_LIKE_ACTIVITY标志,检查调用者是否有MANAGE_ACTIVITY_STACKS权限
        if ((flags & Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
            mAm.enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
                    "BIND_TREAT_LIKE_ACTIVITY");
        }

        // 判断调用者是否在前台运行
        final boolean callerFg = callerApp.setSchedGroup != Process.THREAD_GROUP_BG_NONINTERACTIVE;

        // 查找服务记录
        ServiceLookupResult res =
            retrieveServiceLocked(service, resolvedType,
                    Binder.getCallingPid(), Binder.getCallingUid(), userId, true, callerFg);
        // 如果服务记录为空或未找到服务,返回0或-1
        if (res == null) {
            return 0;
        }
        if (res.record == null) {
            return -1;
        }
        ServiceRecord s = res.record;

        // 清除调用者的身份信息,以便在操作过程中不泄露调用者的信息
        final long origId = Binder.clearCallingIdentity();

        try {
            // 如果服务需要重启,取消重启计划
            if (unscheduleServiceRestartLocked(s, callerApp.info.uid, false)) {}

            // 如果设置了BIND_AUTO_CREATE标志,更新服务最后活跃的时间
            if ((flags & Context.BIND_AUTO_CREATE) != 0) {
                s.lastActivity = SystemClock.uptimeMillis();
                if (!s.hasAutoCreateConnections()) {
                    ProcessStats.ServiceState stracker = s.getTracker();
                    if (stracker != null) {
                        stracker.setBound(true, mAm.mProcessStats.getMemFactorLocked(),
                                s.lastActivity);
                    }
                }
            }

            // 启动与服务的关联
            mAm.startAssociationLocked(callerApp.uid, callerApp.processName,
                    s.appInfo.uid, s.name, s.processName);

            // 检索服务的应用绑定记录
            AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
            // 创建新的连接记录
            ConnectionRecord c = new ConnectionRecord(b, activity,
                    connection, flags, clientLabel, clientIntent);

            // 获取连接的Binder
            IBinder binder = connection.asBinder();
            // 获取服务的连接列表
            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);
            // 如果有Activity记录,将其添加到Activity的连接列表中
            if (activity != null) {
                if (activity.connections == null) {
                    activity.connections = new HashSet<ConnectionRecord>();
                }
                activity.connections.add(c);
            }
            b.client.connections.add(c);
            // 如果设置了BIND_ABOVE_CLIENT标志,标记客户端有高于自身的服务绑定
            if ((c.flags & Context.BIND_ABOVE_CLIENT) != 0) {
                b.client.hasAboveClient = true;
            }
            // 如果服务的应用记录不为空,更新服务的客户端活动
            if (s.app != null) {
                updateServiceClientActivitiesLocked(s.app, c, true);
            }
            // 获取全局服务连接列表
            clist = mServiceConnections.get(binder);
            if (clist == null) {
                clist = new ArrayList<ConnectionRecord>();
                mServiceConnections.put(binder, clist);
            }
            clist.add(c);

            // 如果设置了BIND_AUTO_CREATE标志,启动服务
            if ((flags & Context.BIND_AUTO_CREATE) != 0) {
                s.lastActivity = SystemClock.uptimeMillis();
                //关键方法:拉起服务
                if (bringUpServiceLocked(s, service.getFlags(), callerFg, false) != null) {
                    return 0;
                }
            }

            // 如果服务的应用记录不为空,根据标志更新服务的属性
            if (s.app != null) {
                if ((flags & Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
                    s.app.treatLikeActivity = true;
                }
                // 更新服务的最近最少使用状态和内存调整
                mAm.updateLruProcessLocked(s.app, s.app.hasClientActivities
                        || s.app.treatLikeActivity, b.client);
                mAm.updateOomAdjLocked(s.app);
            }

            // 如果服务的应用记录不为空且Intent已接收,连接客户端
            if (s.app != null && b.intent.received) {
                try {
                    c.conn.connected(s.name, b.intent.binder);
                } catch (Exception e) {
                    // 异常处理代码...
                }

                // 如果Intent只有一个绑定且需要重新绑定,请求服务绑定
                if (b.intent.apps.size() == 1 && b.intent.doRebind) {
                    requestServiceBindingLocked(s, b.intent, callerFg, true);
                }
            } else if (!b.intent.requested) {
                // 如果Intent未请求,请求服务绑定
                requestServiceBindingLocked(s, b.intent, callerFg, false);
            }

            // 确保服务不在启动的后台服务列表中
            getServiceMap(s.userId).ensureNotStartingBackground(s);

        } finally {
            // 恢复调用者的身份信息
            Binder.restoreCallingIdentity(origId);
        }

        // 返回1表示服务绑定成功
        return 1;
    }
   //关键流程:step2
    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) {
            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;
    }
    //关键流程:step3
    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);
            // 关键方法:通过应用线程调度服务的创建
            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));
        }

        // 发送服务参数,回调执行 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.   bindServiceLocked 
  2. bringUpServiceLocked
  3. realStartServiceLocked  

  

最后的realStartServiceLocked才是实际启动服务的方法,主要作用是确保服务在正确的进程中被创建和启动。它涉及到与应用程序线程的通信,服务状态的更新,以及服务生命周期的管理。代码中的scheduleCreateService方法用于请求应用程序线程创建服务,requestServiceBindingsLocked方法用于请求服务的绑定。到这里我们主要关注2个关键方法:

  • scheduleCreateService(调用service的onCreate)
  • requestServiceBindingsLocked(调用到service的onBind)

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

这里实际上是以bindService到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 requestServiceBindingsLocked相关流程分析(bindService到onBind)

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

//ActivityService
    //关键流程:step1
    private final void requestServiceBindingsLocked(ServiceRecord r, boolean execInFg) {
        // 遍历服务记录中的所有绑定记录
        for (int i = r.bindings.size() - 1; i >= 0; i--) {
            // 获取服务的一个绑定记录
            IntentBindRecord ibr = r.bindings.valueAt(i);
            // 请求服务与客户端的绑定
            // 如果绑定失败,则中断循环,不再请求后续的绑定
            if (!requestServiceBindingLocked(r, ibr, execInFg, false)) {
                break;
            }
        }
    }
    //关键流程:step2
    private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
            boolean execInFg, boolean rebind) {
        if (r.app == null || r.app.thread == null) {
            return false;
        }
        // 如果服务尚未请求绑定,或者这是一次重新绑定,并且有待绑定的客户端
        if ((!i.requested || rebind) && i.apps.size() > 0) {
            try {
                // 增加服务执行的计数,并根据是否在前台执行来更新状态
                bumpServiceExecutingLocked(r, execInFg, "bind");
                // 强制服务所在进程的状态至少为服务状态
                r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
                // 关键方法:通过服务的应用线程,调度服务的绑定操作
                r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
                        r.app.repProcState);
                // 如果这不是重新绑定,则标记该服务的绑定已被请求
                if (!rebind) {
                    i.requested = true;
                }
                // 标记服务已被绑定,且设置不需要重新绑定的标志
                i.hasBound = true;
                i.doRebind = false;
            } catch (RemoteException e) {
                return false;
            }
        }
        return true;
    }

这里我们主要关注requestServiceBindingLocked方法,他的主要作用是检查服务是否能够被绑定(即服务及其应用线程是否存在),如果是,则通过服务的应用线程调度服务的绑定操作。代码中的IntentBindRecord对象包含了服务绑定的详细信息,如绑定的Intent、客户端信息等。整理下,关键步骤如下:

  1. 检查服务及其应用线程是否存在。
  2. 如果服务尚未请求绑定或这是一次重新绑定,且有待绑定的客户端,则继续处理。
  3. 增加服务执行的计数,并根据是否在前台执行来更新状态。
  4. 强制服务所在进程的状态至少为服务状态。
  5. 关键方法:通过服务的应用线程调度服务的绑定操作。
  6. 如果这不是重新绑定,则标记该服务的绑定已被请求,并标记服务已被绑定。

接下来我们主要解读步骤5,scheduleBindService主要是发送消息,代码实现如下:

//ActivityThread
    //ApplicationThread
        public final void scheduleBindService(IBinder token, Intent intent,
                boolean rebind, int processState) {
            updateProcessState(processState, false);
            BindServiceData s = new BindServiceData();
            s.token = token;
            s.intent = intent;
            s.rebind = rebind;
            sendMessage(H.BIND_SERVICE, s);
        }
    //消息处理
    private class H extends Handler {
        //...
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case BIND_SERVICE:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind");
                    handleBindService((BindServiceData)msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                //...
            }
        }
        //...
    }
    //...
    private void handleBindService(BindServiceData data) {
        Service s = mServices.get(data.token);
        // 如果服务实例不为空,继续处理绑定请求
        if (s != null) {
            try {
                // 设置Intent的类加载器为服务的类加载器,以便能正确解析其中的Serializable和Parcelable对象
                data.intent.setExtrasClassLoader(s.getClassLoader());
                // 准备Intent以进入当前进程
                data.intent.prepareToEnterProcess();
                // 尝试处理服务绑定
                try {
                    // 如果这不是重新绑定,调用服务的onBind方法并发布服务的IBinder给客户端
                    if (!data.rebind) {
                        // 关键方法:执行service组件的onBind操作
                        IBinder binder = s.onBind(data.intent);
                        // 发布服务,使客户端能够与服务进行通信
                        ActivityManagerNative.getDefault().publishService(
                                data.token, data.intent, binder);
                    } else {
                        // 如果是重新绑定,调用服务的onRebind方法
                        s.onRebind(data.intent);
                        // 通知AMS服务重新绑定操作已完成
                        ActivityManagerNative.getDefault().serviceDoneExecuting(
                                data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                    }
                    ensureJitEnabled();
                } catch (RemoteException ex) {
                    //...
                }
            } catch (Exception e) {
                //...
            }
        }
    }

这段代码的主要作用是处理服务的绑定请求,包括调用服务的onBind或onRebind方法,并发布服务的IBinder给客户端。代码中的BindServiceData对象包含了服务绑定请求所需的所有信息,如服务的token、Intent、是否为重新绑定等。

2 AMS.unbindService流程解读(onUnBind、onDestroy)

AMS.unbindService代码实现如下:

//ActivityManagerService
    public boolean unbindService(IServiceConnection connection) {
        synchronized (this) {
            return mServices.unbindServiceLocked(connection);
        }
    }

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

//ActivityService
    //关键流程:step1
    boolean unbindServiceLocked(IServiceConnection connection) {
        IBinder binder = connection.asBinder();
        // 从全局服务连接映射中获取与该Binder相关联的连接记录列表
        ArrayList<ConnectionRecord> clist = mServiceConnections.get(binder);
        // 如果连接记录列表为空,说明没有找到相应的服务连接,返回false
        if (clist == null) {
            return false;
        }

        final long origId = Binder.clearCallingIdentity();
        try {
            // 遍历连接记录列表,解绑所有相关服务
            while (clist.size() > 0) {
                // 获取列表中的第一个连接记录
                ConnectionRecord r = clist.get(0);
                // 关键方法:解除服务连接
                removeConnectionLocked(r, null, null);
                // 如果列表中的第一个连接记录仍然是r,说明没有被移除,手动移除它
                if (clist.size() > 0 && clist.get(0) == r) {
                    clist.remove(0);
                }

                // 如果服务绑定记录的服务应用不为空,更新相关设置
                if (r.binding.service.app != null) {
                    // 如果设置了BIND_TREAT_LIKE_ACTIVITY标志,更新服务应用的属性
                    if ((r.flags & Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
                        r.binding.service.app.treatLikeActivity = true;
                        // 更新服务应用的最近最少使用状态
                        mAm.updateLruProcessLocked(r.binding.service.app,
                                r.binding.service.app.hasClientActivities
                                || r.binding.service.app.treatLikeActivity, null);
                    }
                    // 更新服务应用的内存调整
                    mAm.updateOomAdjLocked(r.binding.service.app);
                }
            }
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
        return true;
    }
    //关键流程:step2
    void removeConnectionLocked(
        ConnectionRecord c, ProcessRecord skipApp, ActivityRecord skipAct) {
        IBinder binder = c.conn.asBinder();
        // 获取服务绑定记录
        AppBindRecord b = c.binding;
        // 获取服务记录
        ServiceRecord s = b.service;
        // 获取服务的连接列表
        ArrayList<ConnectionRecord> clist = s.connections.get(binder);
        // 如果连接列表不为空,移除对应的连接记录
        if (clist != null) {
            clist.remove(c);
            // 如果连接列表为空,从服务的连接映射中移除该Binder的条目
            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);
            // 如果设置了BIND_ABOVE_CLIENT标志,更新服务应用是否有高于自身的服务绑定
            if ((c.flags & Context.BIND_ABOVE_CLIENT) != 0) {
                b.client.updateHasAboveClientLocked();
            }
            // 如果服务应用不为空,更新服务应用的客户端活动
            if (s.app != null) {
                updateServiceClientActivitiesLocked(s.app, c, true);
            }
        }
        // 从全局服务连接映射中移除连接记录
        clist = mServiceConnections.get(binder);
        if (clist != null) {
            clist.remove(c);
            // 如果连接列表为空,从全局服务连接映射中移除该Binder的条目
            if (clist.size() == 0) {
                mServiceConnections.remove(binder);
            }
        }

        // 停止服务应用和客户端应用之间的关联
        mAm.stopAssociationLocked(b.client.uid, b.client.processName, s.appInfo.uid, s.name);

        // 如果服务绑定记录的连接列表为空,则从服务Intent的绑定应用列表中移除该应用
        if (b.connections.size() == 0) {
            b.intent.apps.remove(b.client);
        }

        // 如果服务没有死亡,执行进一步的清理操作
        if (!c.serviceDead) {
            // 如果服务应用不为空,且没有其他绑定的应用,执行服务的unbind操作
            if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
                    && b.intent.hasBound) {
                try {
                    // 增加服务执行的计数,并根据是否在前台执行来更新状态
                    bumpServiceExecutingLocked(s, false, "unbind");
                    // 如果服务应用的进程状态小于等于接收者状态,更新服务应用的最近最少使用状态
                    if (b.client != s.app && (c.flags & Context.BIND_WAIVE_PRIORITY) == 0
                            && s.app.setProcState <= ActivityManager.PROCESS_STATE_RECEIVER) {
                        mAm.updateLruProcessLocked(s.app, false, null);
                    }
                    // 更新服务应用的内存调整
                    mAm.updateOomAdjLocked(s.app);
                    // 标记服务Intent没有绑定的应用
                    b.intent.hasBound = false;
                    b.intent.doRebind = false;
                    // 关键方法:通知服务应用执行unbind操作
                    s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
                } catch (Exception e) {
                    //...
                    serviceProcessGoneLocked(s);
                }
            }

            // 如果设置了BIND_AUTO_CREATE标志,且没有其他自动创建的绑定,则关闭服务
            if ((c.flags & Context.BIND_AUTO_CREATE) != 0) {
                boolean hasAutoCreate = s.hasAutoCreateConnections();
                // 如果没有其他自动创建的绑定,则更新服务的状态跟踪器
                if (!hasAutoCreate) {
                    if (s.tracker != null) {
                        s.tracker.setBound(false, mAm.mProcessStats.getMemFactorLocked(),
                                SystemClock.uptimeMillis());
                    }
                }
                // 如果需要,执行服务的关闭逻辑
                bringDownServiceIfNeededLocked(s, true, hasAutoCreate);
            }
        }
    }

这里我们关注removeConnectionLocked方法,它的主要作用是移除服务连接,包括从服务的连接映射中移除连接记录、更新服务应用的客户端活动、执行服务的unbind操作以及关闭服务。代码中的ConnectionRecord对象包含了服务连接的详细信息,AppBindRecord对象包含了服务绑定的详细信息。到这里我们主要关注2个关键方法:

  • scheduleUnbindService(调用service的onUnbind)
  • bringDownServiceIfNeededLocked(调用到service的onDestroy)

2.1 scheduleUnbindService相关流程解读(unbindservice到onUnbind)

这里实际上是以unbindService到service组件调用onUnbind的流程分析为目的。这里主要是通过scheduleUnbindService方法发送消息,处理解绑操作。该方法代码实现如下:

//ActivityThread
    //ApplicationThread
        public final void scheduleUnbindService(IBinder token, Intent intent) {
            BindServiceData s = new BindServiceData();
            s.token = token;
            s.intent = intent;

            sendMessage(H.UNBIND_SERVICE, s);
        }
    //消息处理
    private class H extends Handler {
        //...
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case UNBIND_SERVICE:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceUnbind");
                    handleUnbindService((BindServiceData)msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                //...
            }
        }
        //...
    }
    //...
    private void handleUnbindService(BindServiceData data) {
        Service s = mServices.get(data.token);
        if (s != null) {
            try {
                // 设置Intent的类加载器为服务的类加载器,以便能正确解析其中的Serializable和Parcelable对象
                data.intent.setExtrasClassLoader(s.getClassLoader());
                // 准备Intent以进入当前进程
                data.intent.prepareToEnterProcess();
                // 调用服务的onUnbind方法,询问服务是否需要重新绑定
                boolean doRebind = s.onUnbind(data.intent);
                // 如果服务需要重新绑定,通知ActivityManager服务解绑已完成,并标记为需要重新绑定
                if (doRebind) {
                    ActivityManagerNative.getDefault().unbindFinished(
                            data.token, data.intent, doRebind);
                } else {
                    // 如果服务不需要重新绑定,通知ActivityManager服务解绑操作已完成
                    ActivityManagerNative.getDefault().serviceDoneExecuting(
                            data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                }
            } catch (Exception e) {
                //...
            }
        }
    }

handleUnbindService方法的主要作用是处理服务的解绑请求,包括调用服务的onUnbind方法,并根据服务的响应通知ActivityManager服务解绑已完成代码中的BindServiceData对象包含了服务解绑请求所需的所有信息,如服务的token、Intent等。

2.2 bringDownServiceIfNeededLocked相关流程解读(unbindservice到onDestroy)

这里实际上是以unbindService到service组件调用onDestroy的流程分析为目的。这里主要是通过bringDownServiceIfNeededLocked方法进行destroy相关操作。

注意:针对仅通过 bindService() 绑定的服务,在执行 unbindService() 操作时,onDestroy() 方法不一定会被调用。针对bind方式启动的service组件。onDestroy() 方法是否会被调用一般取决于以下条件:

  • 所有绑定都已解除:如果服务只通过 bindService() 绑定,并且所有绑定都已解除(即没有任何 ServiceConnection 再与该服务绑定),那么服务将被销毁,onDestroy() 方法会被调用。
  • 服务未延迟停止:如果服务没有设置延迟停止的标志(例如,没有在 onUnbind() 方法中返回 true),那么在所有绑定都解除后,服务将直接停止,onDestroy() 方法会被调用。
  • 如果服务在 onUnbind() 方法中返回 true,表示服务希望在解绑后重新绑定,那么服务不会立即销毁,onDestroy() 方法也不会被调用。在这种情况下,如果服务在未来被重新绑定,onBind() 方法将再次被调用。

总结来说,对于仅通过 bindService() 绑定的服务,如果所有绑定都已解除,并且没有其他机制(如 onUnbind() 返回 true)阻止服务销毁,那么 onDestroy() 方法会被调用。这是服务生命周期的一部分,确保服务在不再需要时能够正确地清理资源。

有了这个了解后,我们继续分析bringDownServiceIfNeededLocked方法,代码实现如下:

//ActivityService
    //关键流程:step1
    private final void bringDownServiceIfNeededLocked(ServiceRecord r, boolean knowConn, boolean hasConn) {
        // 检查服务是否仍然需要如果服务仍然需要,例如服务正在运行或者有待处理的启动请求,则不停止服务并直接返回
        if (isServiceNeeded(r, knowConn, hasConn)) {
            return;
        }

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

        // 如果服务不再需要且不在待处理列表中,则停止服务
        bringDownServiceLocked(r);
    }
    //关键流程:step2
    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);
    }

这里最后的bringDownServiceLocked才是实际关闭服务的方法,它的作用是关闭服务并执行相关的清理工作。它涉及到服务绑定的清理(如果bind则执行unbind操作,主要针对bindservice操作,本次分析不涉及)、服务执行计数的更新、服务状态的更新、服务通知的取消以及服务销毁逻辑的调用。接下来我们关注unbindService的通知应用销毁服务的关键方法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.bindService->service组件onCreate、onBind
  • AMS.unbindService->service组件onUnBind、onDestroy

结合上一章中分析的2个关键流程:

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

目前已经对service组件的生命周期和AMS中service组件相关流程有一定的了解。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2220209.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

北京大学冯惠:与卓越者同行,方能更快的成长 | OceanBase数据库大赛获奖选手访谈

本文邀请2022 OceanBase 数据库大赛的季军&#xff0c;来自北京大学的冯惠同学&#xff0c;与我们分享如何寻找自己的兴趣&#xff1b;在一番经历后&#xff0c;对于产品与研发的职业方向观察&#xff1b;以及如何在学生时期提升个人专业能力&#xff0c;和参加数据库大赛的个人…

【Python技术】利用akshare定时获取股票实时价,低于5日线钉钉通知报警

今天看了下大盘&#xff0c;临时有个想法&#xff0c;我想知道某个股票回踩5日线的价格&#xff0c;如果实时价格低于5日线通过钉钉报警通知我。 说干就干&#xff0c;临时撸了下简单的代码&#xff0c;仅做演示。 1、计算5日线思路 很多券商软件的MA5价格是近5个交易日收盘…

Java项目-基于springboot框架的医患档案管理系统项目实战(附源码+文档)

作者&#xff1a;计算机学长阿伟 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、ElementUI等&#xff0c;“文末源码”。 开发运行环境 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBoot、Vue、Mybaits Plus、ELementUI工具&#xff1a;IDEA/…

Hi3061M——VL53L0X激光测距(IIC)(同样适用于其他MCU)2

目录 前言资源下载移植基本使用IO配置调用测量 总结 前言 昨晚太晚了&#xff0c;草草结束了上一篇&#xff0c;今天更新下半部分。 昨天已经讲了VL53L0X的使用流程&#xff0c;无非就是进行6步的效准初始化&#xff0c;然后配置下模式和时间&#xff0c;开始采样&#xff0c;…

LDAP 部署手册

Centos 1. 安装openldap软件 # 安装openldap yum -y install openldap compat-openldap openldap-clients openldap-servers openldap-servers-sql openldap-devel migrationtoolscp /usr/share/openldap-servers/DB_CONFIG.example /var/lib/ldap/DB_CONFIG chown ldap:ldap…

Leetcode 跳跃游戏 二

核心任务是找出从数组的起点跳到终点所需的最小跳跃次数。 这段代码解决的是“跳跃游戏 II”&#xff08;Leetcode第45题&#xff09;&#xff0c;其核心任务是找出从数组的起点跳到终点所需的最小跳跃次数。 class Solution {public int jump(int[] nums) {//首先处理特殊情…

“智驭医疗·未来已来“:医疗保健知识中台的搭建与应用

前言 随着科技的飞速发展&#xff0c;医疗保健领域正在经历深刻的变革。知识中台作为促进医疗行业应用智能化升级的关键底座&#xff0c;正在逐渐成为提高医疗服务质量和效率的重要工具。本文将探讨医疗保健知识中台的内容构成、应用案例以及更新与维护机制。 一、医疗保健知识…

基于ASP.NET的小型超市商品管理系统

文章目录 前言项目介绍技术介绍功能介绍核心代码数据库参考 系统效果图 前言 示 文章底部名片&#xff0c;获取项目的完整演示视频&#xff0c;免费解答技术疑问 项目介绍 小型超市商品管理系统是一款针对小型超市日常运营需求设计的软件解决方案。该系统主要内容有商品类别…

【JS】无法阻止屏幕滚动

监听滚轮事件&#xff0c;阻止默认行为&#xff0c;但未生效&#xff0c;且控制台报错。 window.addEventListener(wheel, (e) > {e.preventDefault(); })这是因为现代浏览器使用 Passive 事件监听器&#xff0c;默认启用了 passive 模式以确保性能&#xff0c;不会调用 pr…

【软件安装与配置】Redis for Windows

1. 下载 Redis Redis 官方没有直接支持 Windows 的安装程序&#xff0c;但可以使用第三方的 Windows 版本。推荐使用 Memurai 或从 Microsoft archive 提供的 Redis for Windows 下载。 2. 安装 Redis 下载适合 Windows 的安装包&#xff0c;本文以Microsoft archive安装包为…

Git_IDEA集成Git

Git_IDEA集成Git 配置 Git 忽略文件 创建忽略规则文件 引用忽略配置文件 定位 Git 程序 初始化本地库 添加到暂存区 提交到本地库 切换版本 创建分支 切换分支 合并分支 解决冲突 配置 Git 忽略文件 创建忽略规则文件 引用忽略配置文件 在 .gitconfig 文件中进行&…

[Git]一文速通

概述 Git是一个分布式版本控制工具&#xff0c;主要用于管理开发过程中的源代码文件(Java类、xml文件、html页面等, )在软件开发过程中被广泛使用 Git的作用 代码回溯版本切换多人协作远程备份 通过Git 仓库来存储和管理代码 文件&#xff0c;Git 仓库分为两种: 本地仓库: 开…

C++和OpenGL实现3D游戏编程【连载15】——着色器初步

&#x1f525;C和OpenGL实现3D游戏编程【目录】 1、本节实现的内容 上一节我们介绍了通过VBO、VAO和EBO怎样将顶点发送到GPU显存&#xff0c;利用GPU与显存之间的高效处理速度&#xff0c;来提高我们的图形渲染效率。那么在此过程中&#xff0c;我们又可以通过着色器&#xff…

webstorm 编辑器配置及配置迁移

1.下载地址 WebStorm&#xff1a;JetBrains 出品的 JavaScript 和 TypeScript IDE 其他版本下载地址 2.安装 点击下一步安装&#xff0c;可根据需要是否删除已有版本 注意&#xff1a; 完成安装后需要激活 3.设置快捷键 以下为个人常用可跳过或根据需要设置 如&#xff1a…

字幕怎么自动生成?教你5种视频加字幕方法

在这个短视频时代&#xff0c;视频内容已成为传播信息、娱乐大众的重要载体。而字幕作为视频不可或缺的一部分&#xff0c;不仅能够提升观众的观看体验&#xff0c;还能跨越语言障碍&#xff0c;让所有观众都能享受视频的魅力。但怎么给视频加上字幕呢&#xff1f;下面给大家分…

vulnhub靶场之JOY

一.环境搭建 1.靶场描述 Does penetration testing spark joy? If it does, this machine is for you. This machine is full of services, full of fun, but how many ways are there to align the stars? Perhaps, just like the child in all of us, we may find joy in …

Java最全面试题->Java基础面试题->JavaSE面试题->异常面试题

异常 下边是我自己整理的面试题&#xff0c;基本已经很全面了&#xff0c;想要的可以私信我&#xff0c;我会不定期去更新思维导图 哪里不会点哪里 1.说一下Java中的异常体系&#xff1f; 2.Error和Exception的区别 Error&#xff1a;系统错误,编译时出现的错误,Exception&…

宝兰德加入华为鸿蒙生态,共谱智能运维新篇章

近日&#xff0c;华为HarmonyOS NEXT系统&#xff08;又称“纯血鸿蒙”&#xff09;正式开启公测&#xff0c;标志着国产操作系统的发展迈入了新的阶段。作为华为紧密的战略合作伙伴&#xff0c;宝兰德依托其在IT监控运维可观测性领域的技术优势&#xff0c;正式成为华为鸿蒙Ha…

RFC2616 超文本传输协议 HTTP/1.1

一、URL-俗称“网址” HTTP 使用 URL(Uniform Resource Locator&#xff0c;统一资源定位符)来定位资源&#xff0c;它是 URI(Uniform Resource Identifier&#xff0c;统一资源标识符)的子集&#xff0c;URL 在 URI 的基础上增加了定位能力 URI 除了包含 URL&#xff0c;还包…

gitee建立/取消关联仓库

目录 一、常用指令总结 二、建立关联具体操作 三、取消关联具体操作 一、常用指令总结 首先要选中要关联的文件&#xff0c;右击&#xff0c;选择Git Bash Here。 git remote -v //查看自己的文件有几个关联的仓库git init //初始化文件夹为git可远程建立链接的文件夹…