iis服务器助手广告广告
返回顶部
首页 > 资讯 > 移动开发 >AndroidService完整实现流程分析
  • 490
分享到

AndroidService完整实现流程分析

AndroidServiceAndroidService实现原理 2023-01-02 12:01:26 490人浏览 安东尼
摘要

目录前言一.APP侧启动Service1.1 前台和后台启动1.2startServiceCommon二.系统侧分发处理Service的启动逻辑2.1 AMS接受启动service的

前言

一开始的目标是解决各种各样的ANR问题的,我们知道,ANR总体上分有四种类型,这四种类型有三种是和四大组件相对应的,所以,如果想了解ANR发生的根因,对安卓四大组件的实现流程是必须要了解的,都不明白ANR如何触发的,怎么能完美的解决ANR的问题呢?

所以会写一系列的文章,来分析四大组建的实现原理,同时也顺带讲解四种类型的ANR是如何发生的。

本篇主要介绍service的完整实现流程,下一篇文章介绍Service中的ANR是如何产生的。

一.APP侧启动Service

其实启动service和启动Activity是很相似的,都是APP通知系统侧,由系统侧完成的整个流程。

1.1 前台和后台启动

无论是Activity,还是service,还是Application,都继承自Context的抽象类,所以可以使用Context的各种功能,就比如这了要介绍的启动前台/后台service。

Context在安卓中,使用了一种典型的代理模式,我们调用的startService或者startForegroundService方法,最终都会委托给ContextImpl中的startService和startForegroundService来处理的。我们就来看下ContextImpl中的这两个方法:

@Override
    public ComponentName startService(Intent service) {
        warnIfCallingFromSystemProcess();
        return startServiceCommon(service, false, mUser);
    }
    @Override
    public ComponentName startForegroundService(Intent service) {
        warnIfCallingFromSystemProcess();
        return startServiceCommon(service, true, mUser);
    }

果然和我猜测的差不多,无论前台还是后台启动,其实最终都会走到一个方法中,只是配置参数的区别而已。最终都会走执行startServiceCommon方法。

1.2startServiceCommon

该方法中,通过binder通知系统的AMS完成对应的service的启动操作:

 ComponentName cn = ActivityManager.getService().startService(
                    mMainThread.getApplicationThread(), service,
                    service.resolveTypeIfNeeded(getContentResolver()), requireForeground,
                    getOpPackageName(), getAttributionTag(), user.getIdentifier());

接下来,我们就看下系统侧是如何处理Service启动流程的。

二.系统侧分发处理Service的启动逻辑

系统侧的处理我主要分为3块来讲:

1.系统接受APP侧的通知并转发

2.系统侧委托ActiveServices负责完成的处理流程

3.收到APP侧执行完成的回调,进行收尾操作

2.1 AMS接受启动service的通知

APP侧持有system_server进程的binder,上面讲到,它会通过binder方法startService完成对系统侧的通知。所以AMS的startService会收到这个通知。

我们看下代码,发现AMS会把整个service的逻辑全部交由ActiveServices来处理,代码如下:

 try {
                res = mServices.startServiceLocked(caller, service,
                        resolvedType, callingPid, callingUid,
                        requireForeground, callingPackage, callingFeatureId, userId);
            } finally {
                Binder.restoreCallingIdentity(origId);
            }

系统代码startServiceLocked方法中,代码虽然很长,但是却遵循着一个不变的宗旨:位语句,即前面处理各种异常的分支逻辑,把核心流程留到方法的最终来处理。

所以我们直接看startServiceLocked方法的最后一部分即可:

final ComponentName realResult =
                startServiceInnerLocked(r, service, callingUid, callingPid, fgRequired, callerFg,
                allowBackgroundActivityStarts, backgroundActivityStartsToken);

startServiceInnerLocked方法中,处理逻辑也是比较简单的,最终会交给bringUpServiceLocked方法来进行处理。而bringUpServiceLocked方法中则最终会交给realStartServiceLocked完成整个流程。好像系统代码都喜喜欢用realStart,Activity启动的流程中也有一个方法叫realStartActivity。

2.2realStartServiceLocked流程

realStartServiceLocked方法中,我们总结为三个流程:

1.bumpServiceExecutingLocked,启动超时检查。

2.thread.scheduleCreateService通知APP一侧去创建Service。

3.sendServiceArgsLocked通知APP执行Service的生命流程。

private void realStartServiceLocked(ServiceRecord r, ProcessRecord app,
            IApplicationThread thread, int pid, UidRecord uidRecord, boolean execInFg,
            boolean enqueueOomAdj) throws RemoteException {
        //1.启动超时检查
        bumpServiceExecutingLocked(r, execInFg, "create", null );
        ...
        //2.通知APP创建service
            thread.scheduleCreateService(r, r.serviceInfo,
                    mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
                    app.mState.getReportedProcState());
            r.postNotification();
            created = true;
        ...
        //3.通知执行service生命流程
        sendServiceArgsLocked(r, execInFg, true);
       ...
    }

三.系统侧通知APP启动Service

一般情况下,APP侧会收到系统侧发过来两种类型的通知,

第一种:创建Service的任务通知

第二种:执行Service生命流程的通知,通知Service执行onStartCommand方法。

ApplicationThread接受通知并创建Service

系统侧持有APP侧的binder,会通过scheduleCreateService这个binder方法通知APP一侧进行相应的操作。而APP侧,完成这个工作接收的就是ApplicationThread中的scheduleCreateService方法。该方法收到通知后,通过handler切换到主线程处理:

 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);
        }

handle中,会切换到主线程执行ActivityThread的handleCreateService方法。

主要执行了如下的几段逻辑:

1.如果是首次创建App进程的话,则需要重新创建Application;

2.创建Service对象;

3.调用service的attach方法进行关联;

4.调用service的onCreate生命周期方法;

5.创建完成后,通过serviceDoneExecuting通知系统侧创建完成。

try {
            if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
            Application app = packageInfo.makeApplication(false, mInstrumentation);
            final java.lang.ClassLoader cl;
            if (data.info.splitName != null) {
                cl = packageInfo.getSplitClassLoader(data.info.splitName);
            } else {
                cl = packageInfo.getClassLoader();
            }
            service = packageInfo.getAppFactory()
                    .instantiateService(cl, data.info.name, data.intent);
            ContextImpl context = ContextImpl.getImpl(service
                    .createServiceBaseContext(this, packageInfo));
            if (data.info.splitName != null) {
                context = (ContextImpl) context.createContextForSplit(data.info.splitName);
            }
            if (data.info.attributionTags != null && data.info.attributionTags.length > 0) {
                final String attributionTag = data.info.attributionTags[0];
                context = (ContextImpl) context.createAttributionContext(attributionTag);
            }
            // Service resources must be initialized with the same loaders as the application
            // context.
            context.getResources().addLoaders(
                    app.getResources().getLoaders().toArray(new ResourcesLoader[0]));
            context.setOuterContext(service);
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManager.getService());
            service.onCreate();
            mServicesData.put(data.token, data);
            mServices.put(data.token, service);
            try {
                ActivityManager.getService().serviceDoneExecuting(
                        data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }

ApplicationThread接受通知并执行Service的生命流程

同样的,这里完成接受的是,仍然是ApplicationThread中的方法。这个流程中的接受方法是scheduleServiceArgs方法。

ApplicationThread中,收到通知后,通过handler把任务转交到主线程。

 public final void scheduleServiceArgs(IBinder token, ParceledListSlice args) {
            List<ServiceStartArgs> list = args.getList();
            for (int i = 0; i < list.size(); i++) {
                ServiceStartArgs ssa = list.get(i);
                ServiceArgsData s = new ServiceArgsData();
                s.token = token;
                s.taskRemoved = ssa.taskRemoved;
                s.startId = ssa.startId;
                s.flags = ssa.flags;
                s.args = ssa.args;
                sendMessage(H.SERVICE_ARGS, s);
            }
        }

接下来handler中切换到主线程会执行ActivityThread的handleServiceArgs方法。

handleServiceArgs方法主要会完成以下几件事:

1.找到对应的service,调用起onStartCommand方法;

2.通知系统侧回调完成。

private void handleServiceArgs(ServiceArgsData data) {
        CreateServiceData createData = mServicesData.get(data.token);
        Service s = mServices.get(data.token);
        if (s != null) {
            try {
                if (data.args != null) {
                    data.args.setExtrasClassLoader(s.getClassLoader());
                    data.args.prepareToEnterProcess(isProtectedComponent(createData.info),
                            s.getAttributionSource());
                }
                int res;
                if (!data.taskRemoved) {
                    res = s.onStartCommand(data.args, data.flags, data.startId);
                } else {
                    s.onTaskRemoved(data.args);
                    res = Service.START_TASK_REMOVED_COMPLETE;
                }
                QueuedWork.waitToFinish();
                try {
                    ActivityManager.getService().serviceDoneExecuting(
                            data.token, SERVICE_DONE_EXECUTING_START, data.startId, res);
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            } catch (Exception e) {
                if (!mInstrumentation.onException(s, e)) {
                    throw new RuntimeException(
                            "Unable to start service " + s
                            + " with " + data.args + ": " + e.toString(), e);
                }
            }
        }
    }

发我们发现,不论是创建service,还是通知执行service的生命流程,最终都执行了一个完成的通知,这有何意图呢?是的,这个意图就是和ANR相关的,我们下一章来讲了。

四.总结

前面一一讲了实现的原理,我们最后再来做一个总结,尽量用一张图+几句话的方式来概括。

1.无论前台启动还是后台启动,最终都会走到ContextImpl这个最终实现类中的方法,完成和AMS的交互。

2.AMS中主要是ActiveServices完成的整个流程。其核心方法是realStartServiceLocked。

他首先启动一个延时消息,通过延时消息进行超时的监测。

然后通知APP去生成Service。

通知APP侧去完成Service的生命周期流程onStartCommand。

3.收到APP侧执行完成的通知后,则取消注册延时消息。

到此这篇关于Android Service完整实现流程分析的文章就介绍到这了,更多相关Android Service内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: AndroidService完整实现流程分析

本文链接: https://www.lsjlt.com/news/176421.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • AndroidService完整实现流程分析
    目录前言一.APP侧启动Service1.1 前台和后台启动1.2startServiceCommon二.系统侧分发处理Service的启动逻辑2.1 AMS接受启动service的...
    99+
    2023-01-02
    Android Service Android Service实现原理
  • golang如何实现报销?完整流程浅析
    在众多编程语言中,Go语言(简称golang)因其高效、简单且易于维护而备受青睐。随着该语言的流行度不断提高,它被越来越多的企业用于开发各种应用程序,包括报销流程的应用程序。一个完整的golang报销流程,包含以下几个步骤:登录用户首先登录...
    99+
    2023-05-14
  • Webpack完整打包流程深入分析
    目录前言一、准备工作二、初始化阶段2.1、读取与合并配置信息2.2、创建编译器(compiler)对象2.3、插件注册三、编译阶段3.1、创建 compilation 编译对象3.2...
    99+
    2022-12-10
    webpack打包的整个过程 webpack打包过程 webpack打包机制
  • Node中完整的 node addon 实现流程
    目录背景介绍为什么要写 node addonnode addon 是什么addon 实现方式的变迁Chrome V8 APINAN 时代符合 ABI 的 N-API编码阶段如何写出正...
    99+
    2024-04-02
  • Javaweb实现完整个人博客系统流程
    目录一、项目背景二、项目功能三、项目的基本流程1.准备工作2.数据库设计3.准备前端页面4.实现前端匹配的Servlet所需功能5.项目难点一、项目背景 在学习完JavaWeb相关知...
    99+
    2024-04-02
  • C语言实现简易通讯录完整流程
    目标:通讯录可以存放1000个人信息,人的信息:性别名字年龄电话住址 菜单打印 1.增加联系人 2.删除联系人 3.查找联系人(修改) 4.名字排序联系人 5.展示 6.清空 分析:...
    99+
    2024-04-02
  • JavaScriptTypeScript实现贪吃蛇游戏完整详细流程
    目录项目背景及简介多模块需求分析场景模块需求食物类模块需求记分牌模块需求蛇类模块需求控制模块需求项目搭建ts转译为js代码package.json包配置文件webpack.confi...
    99+
    2024-04-02
  • PHP实现分页功能的完整教程
    PHP实现分页功能的完整教程 在网站开发中,常常会遇到需要分页展示大量数据的情况,为了提升用户体验和减少服务器负担,我们可以通过PHP来实现分页功能。本文将为大家介绍如何使用PHP实现...
    99+
    2024-02-29
    分页 教程 php
  • SpringBoot整合LDAP的流程分析
    依赖 <dependency> <groupId>org.springframework.boot</groupId> <...
    99+
    2024-04-02
  • Javaweb如何实现完整个人博客系统流程
    这篇文章主要讲解了“Javaweb如何实现完整个人博客系统流程”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Javaweb如何实现完整个人博客系统流程”吧!项目的基本流程1.准备工作pom....
    99+
    2023-06-29
  • mysql innodb存储引擎中一个事务的完整流程分析
    这篇文章主要讲解了“mysql innodb存储引擎中一个事务的完整流程分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“mysql innodb存储引擎中...
    99+
    2024-04-02
  • 完整的python项目流程
        最近看了python项目的打包,有点小感触。感觉自己还不是一个真正的pythoner。没有在开源项目网站留下什么,而又到处宣扬python的简洁与强大,有点小讽刺。于是乎,我想理清自己的思路,不怕迷茫,懂得坚持自己的目标才好!   ...
    99+
    2023-01-31
    流程 完整 项目
  • Spring整合SpringMVC与Mybatis(SSM)实现完整登录功能流程详解
    目录项目演示1 创建工程完成配置2 表设计3 实体类4 mapper5 serviceImpl 实现类异常6 controller7 工具类MD5统一返回对象8 前端页面总结项目演示...
    99+
    2024-04-02
  • springboot+camunda实现工作流的流程分析
    1.在camunda modeler工具里面写流程,任务执行指明Java类 2.保存文件放在resources目录下,并建立一个processes.xml的空文件 3.依赖配置 ...
    99+
    2024-04-02
  • JavaScript仿小米商城官网完整页面实现流程
    目录一、首页的制作1.下载APP的制作2.导航栏的制作3.轮播图的制作二、登录、注册页面的制作1.盒子布局2.复选框样式更改三、页面跳转不知不觉学习前端已经快4个月啦,之前没学Jav...
    99+
    2024-04-02
  • PHP 中的 RASP 实现流程分析
    一、什么是 RASP RASP 全称是 Runtime Application self-protection,即运行时应用自我保护,这是一种嵌入到应用程序内部,实时检测来自外部的请...
    99+
    2024-04-02
  • Springboot整合Redis实现超卖问题还原和流程分析(分布式锁)
    目录超卖简单代码超卖问题单服务器单应用情况下设置synchronizedRedis实现分布式锁 通过超时间解决上述问题通过key设置值匹配的方式解决形同虚设问题 ...
    99+
    2024-04-02
  • 微信小程序支付完整流程
    1、注册微信支付商户号(由上级或法人注册) 注册链接:https://pay.weixin.qq.com/index.php/apply/applyment_home/guide_normal 此商户...
    99+
    2023-09-21
    微信小程序 小程序 javascript
  • Python3 完整实现DNN
        完整实现DNN,包括前向传播和反向传播。实现一个2次函数的拟合。#!/usr/bin/env python3 # -*- coding: ut...
    99+
    2023-01-31
    完整 DNN
  • Canvas实现放大镜效果完整案例分析(附代码)
    小编给大家分享一下Canvas实现放大镜效果完整案例分析(附代码),相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!一张模糊的图片:鼠标点击任意位置,产生放大效果:哇...
    99+
    2023-06-09
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作