原标题:从源码出发深入理解 Android Service

原文链接:

建议在浏览器上打开,删除了大量代码细节,:)

本文是 Android 系统学习系列文章中的第三章节的内容,介绍了 Android Service 相关的基础知识,然后从源码的角度上分析 Service 的一些实现原理。对此系列感兴趣的同学,可以收藏这个链接 ,也可以点击 进行订阅

0X00 Service 基础知识

Service 作为 Android 提供的四大组件之一,主要负责一些没有前台显示的后台任务。即使应用本身不再可见,Service 的属性也能使得其在后台运行。除此之外,Service 也可以通过 Binder 机制,与界面甚至其他应用进行进程间通信,以实现相应的交互。这里需要简单说明的是,既然是后台任务,为什么不选用 Thread 了?选用 Service 和 Thread 的主要区别在于需不需要在应用不可见的时候依然保留。举例来说,新闻详情页面的数据请求,只用在当前页面生效,而音乐播放这些后台任务就可以通过 Service 的方式来实现。

关于如何使用 Service,官方教程已经说明得足够详细了,如果对这些用法,还有不清晰的地方,请戳这里进行查看,-> 。官方教程里面包括,startService 和 bindService 的区别,在不同场景下应该选用哪种 Service 实现方式。

0X01 startService 调用流程

从前面的教程里面,可以知道 Service 的启动一般有两种方式,分别是 bindService 和 startService。这里主要说明 startService, 具体的实现逻辑在 ContextImpl 中,我们看看源码是怎么实现的。

接下来,看看方法内部具体是怎么实现的。

从上面的代码可以看到,这里是通过 ActivityManagerNative 来执行的。如果看过我的另一篇文章,, 可能会觉得很熟悉。事实上这里采用的机制就是同样的。

ActivityManagerNative 的 getDefault 方法是这么实现的。可以看到,gDefault 是类型为 IActivityManager 的 Binder 对象。而这个 Binder 对象可以看做是在 System Server 中的 ActivityManagerService 的句柄,通过这个 Binder 对象,可以跨进程调用 ActivityManagerService。

如果上述内容不容易理解的话,我们可以类比地来看这个问题。我们遥控电视的时候,例如进行增加音量的操作,这个操作实际不是由遥控器完成的,而是电视中的电子元件完成的。遥控器会和电视进行协商,先声明有哪些操作可以执行,然后将这些协商后的操作在遥控器端和电视端 �� 都实现,区别在于电视机是真的实现,而遥控器只是发送操作指令而已。前面代码中提及的 gDefault 就是 ActivityManagerService 的遥控器。

接着往下看看电视端是具体怎么操作的,这里的电视端就是 ActivityManagerService.

看起来具体的逻辑,都在类型为 ActiveServices 的 mServices 对象中。ActiveServices 是 AMS 专门用来管理 Service 的类,大部分和 Services 相关的逻辑都在这里面。

可以看到 startServiceLocked 主要进行了权限校验和为性能进行的调度,具体的逻辑,还在 startServiceInnerLocked 方法里面。

接下来看看 bringUpServiceLocked 是如何实现的,这里就是实际启动 Service 的地方。

上面的代码较为复杂,这里进行下初步的总结。首先判断服务是否已经启动,或者正在重启中,则直接返回。其后,当前 Service 进程正在启动中,也直接返回。最后判断应用进程是否启动,如果没有启动进程,则先启动进程。

上面代码的重点在于 app.thread, 这个 IApplicationThread 对象同样也是一个 Bindle 接口,与前文提交的 gDefault 不同之处在于两者的方向是相反的。前者是应用进程操作AMS,而后者则是AMS操作应用进程。IApplicationThread 对应的实现是 ApplicationThread,我们看看这个类是如何处理 scheduleCreateService 这个方法的。

原来还是通过 mH Handler 这种方式来执行的呀,这与前面文章提及的知识是完全一样的。如果大家想详细地了解的话,建议看看这些系列文章 。在 Handler 中的 handleMessage 是如何处理 CREATE_SERVICE 这个消息的?

继续看 handleCreateService 方法的实现。

方法实现相对简单,首先通过 ClassLoader 加载相关的 class 对象,然后将 Service 和 Application 绑定在一起,最后调用 Service 的 onCreate 方法。到此为止,Service 就完全启动了。

如果使用 Service 的方式是 startService,那么在 Service 启动后,就可以执行 sendServiceArgsLocked 方法,从而在 Service 的 onStartCommand 里面可以执行相应的后台代码,需要特别说明的是,这个是执行在 UI 线程上的,因而建议不要执行耗时的任务,如果是耗时的任务,需要通过多线程的方式来避免主线程的阻塞。即使应用当前不在前台,阻塞 UI 线程,也是很不好的情况。

我们看看 sendServiceArgsLocked 是如何实现的。

这里通过循环的方式,将在队列中的消息,依次通过 app.thread 发布到应用进程中去,如果中途发生了 TransactionTooLargeException 异常,则会提前终止这个过程。app.thread 的 scheduleServiceArgs 方法,也是通过 mH 这个 Handler 来执行的,发送的消息为 SERVICE_ARGS。

handleServiceArgs 方法中,s.onStartCommand 就是我们书写后台代码的地方,当这个方法执行完成后,又通过 gDefault 这个遥控器通知 AMS 来任务完成了。

对于 startService 这种方式而言,是需要手动调用 stopSelf 方法来结束 Service 的,背后的原理与 startService 方法类似,这里就不再赘述。

0X01 bindService 调用流程

bindService 相较于 startService 要复杂一些,通过这种方式实现的 Service,容易多个组件绑定到它,通过 ServiceConnection 的方式来进行通信。当没有任何其他组件,连接到这个 Service 时,该 Service 会自动销毁。

bindService 方法是这样声明的。

可以看到同样是通过 gDefault 这个遥控器来通知 AMS 进行相应的操作的,原理与上面 startService 相同,接收到遥控器的指令后,ActiveServices 的 bindSericeLocked 方法开始执行。bindSericeLocked 在进行一些校验,确认进程创建成功等等步骤后,还是通过 app.thread 发送 BIND_SERVICE 消息,来执行对应的逻辑。

在 onBind 方法,给调用者返回 Binder 对象,通过 publishService 方法通过到 AMS 内部去,我们看看接下来发生了什么。

ActiveServices 中的代码也相对简单, 遍历建立起的 ServiceConnection,并调用它们的 connected 方法,这也是我们需要编写后台代码的地方。

0X02 总结

Service 作为四大组件之一,提供了不需要前台页面情况下,在后台继续执行任务的能力。Service 一般有两种使用方式,分别是通过 startService 和 bindService,前者适合执行一次性的任务,而后者则具备一定交互的能力,可以用作处理相对复杂的后台逻辑。

关于更多详细的用法,还是建议阅读官方教程,.

文档信息

版权声明:自由转载-非商用-非衍生-保持署名()

发表日期:2016年9月20日

社交媒体:

Feed订阅:

一周好

责任编辑:

android 浏览器源码分析,从源码出发深入理解 Android Service相关推荐

  1. 【Android 电量优化】JobScheduler 源码分析 ( JobServiceContext 源码分析 | 闭环操作总结 | 用户提交任务 | 广播接收者接受相关广播触发任务执行 )★

    文章目录 一.JobServiceContext 引入 二.JobServiceContext 源码分析 三.用户在应用层如何使用 JobScheduler 四.用户提交任务 五.广播接收者监听广播触 ...

  2. Android源码分析--MediaServer源码分析(二)

    在上一篇博客中Android源码分析–MediaServer源码分析(一),我们知道了ProcessState和defaultServiceManager,在分析源码的过程中,我们被Android的B ...

  3. Android 事件分发机制分析及源码详解

    Android 事件分发机制分析及源码详解 文章目录 Android 事件分发机制分析及源码详解 事件的定义 事件分发序列模型 分发序列 分发模型 事件分发对象及相关方法 源码分析 事件分发总结 一般 ...

  4. Linux内核 eBPF基础:kprobe原理源码分析:源码分析

    Linux内核 eBPF基础 kprobe原理源码分析:源码分析 荣涛 2021年5月11日 在 <Linux内核 eBPF基础:kprobe原理源码分析:基本介绍与使用>中已经介绍了kp ...

  5. k8s源码分析--kube-scheduler源码(一)

    版本:v1.13.0 启动分析 kubernetes基础组件的入口均在cmd目录下,kube-schduler入口在scheduler.go下. kubernetes所有的组件启动采用的均是comma ...

  6. k8s client-go源码分析 informer源码分析(3)-Reflector源码分析

    k8s client-go源码分析 informer源码分析(3)-Reflector源码分析 1.Reflector概述 Reflector从kube-apiserver中list&watc ...

  7. xf86-video-intel源码分析1 —— 源码目录结构概览

    在<Spectacle/Flameshot/X11 Xlib截屏问题现象及解决方法>一文(链接如下)中提到, Spectacle/Flameshot/X11 Xlib截屏问题现象及解决方法 ...

  8. 【Android 热修复】热修复原理 ( 类加载分析 | 分析 PathClassLoader 源码 | 分析 BaseDexClassLoader 源码 | 分析 PathDexList 源码 )

    文章目录 一.分析 PathClassLoader 源码 二.分析 BaseDexClassLoader 源码 三.分析 PathDexList 源码 四. 源码资源 一.分析 PathClassLo ...

  9. 【Android 电量优化】JobScheduler 相关源码分析 ( JobSchedulerService 源码分析 | 任务检查 | 任务执行 )

    文章目录 一.回调 StateChangedListener 接口 二.JobHandler 处理 ( 任务检查 ) 三.maybeRunPendingJobsH 方法 四.assignJobsToC ...

最新文章

  1. python 重载_python模块重载的五种方法
  2. GitHub 总星 4w+!删库?女装?表情包?这些沙雕中文项目真是我每天快乐的源泉!...
  3. layoutSubviews何时被调用
  4. 常见python面试题总结
  5. java 输入输出头文件_引入的标准头文件与标准输出以及FOR循环
  6. 「后端小伙伴来学前端了」Vue中全局事件总线(GlobalEventBus)原理及探究过程
  7. Linux 下比较文件内容并相同部分、不同部分
  8. mysql与java的计算效率_java mysql数据库查询效率问题
  9. mysql合并多条纪录字段_mysql合并多条记录的单个字段去一条记录
  10. ​ [RHEL7.1]重新封装系统(制作模板)
  11. 使用 Clang Tools —— ClangFormat
  12. 如何连接到sqlplus
  13. 高分GF与环境HJ系列国产卫星遥感影像数据图像免费批量下载方法
  14. 网络编程-----网络通信协议
  15. 【ANSYS命令流】定义单元类型与实常数
  16. wordpress炫酷主题Salient最新版13.0.5 汉化版免费下载
  17. 组网学习之什么是链路冗余(二)
  18. 基于node.js的网页聊天系统设计与实现
  19. IDEA使用Git大全
  20. php微信银行卡rsa加密,如何使用微信公钥加密银行卡号和姓名

热门文章

  1. Charles抓取微信小程序数据 以及 其它应用网站数据
  2. Java中isAssignableFrom的用法
  3. 如何一步一步用DDD设计一个电商网站(七)—— 实现售价上下文
  4. 优化内核报错及解决方法
  5. python--lambda和def函数
  6. 《排序算法系列一、简单选择排序》
  7. RIS服务器的安装和远程自动安装操作系统(二)
  8. 关于Uri.Segments 属性的理解
  9. [转]DPM2012系列之四:配置邮件报警功能
  10. 微服务和容器技术有风险,望君三思而后行