Service启动过程分析
Service是一种计算型组件,用于在后台执行一系列的计算任务。由于工作在后台,因此用户是无法直接感知到它的存在。Service组件和Activity组件略有不同,Activity组件只有一种运行模式,即Activity处于启动状态,但是Service组件却有两种状态:启动状态和绑定状态。当Service组件处于启动状态时,这个时候Service内部可以做一些后台计算,并且不需要和外界有直接的交互。
Service分为两种工作状态,一种是启动状态,主要用于执行后台计算,另一张是绑定状态,主要用于其他组件和Service的交互,需要注意的是Service的这两种状态是可以共存的,即Service既可以处于启动状态也可以同时处于绑定状态。
Service的启动过程
Service的启动过程从ContextWrapper的startService开始。
@Override
public ComponentName startService(Intent service) {
return mBase.startService(service);
}
这里的mBase的类型是ContextImpl,其实说到这,就得说下Activity被创建时会通过attach方法将一个ContextImpl对象关联起来,这也就是mBase。从ContextWrapper的实现可以看出,其中大部分操作都是通过mBase来实现的,在设计模式中这是一种典型的桥接模式。
@Override
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, mUser);
}
private ComponentName startServiceCommon(Intent service, UserHandle user) {
try {
validateServiceIntent(service);
service.prepareToLeaveProcess(this);
ComponentName cn = ActivityManagerNative.getDefault().startService(
mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
getContentResolver()), getOpPackageName(), user.getIdentifier());
if (cn != null) {
if (cn.getPackageName().equals("!")) {
throw new SecurityException(
"Not allowed to start service " + service
+ " without permission " + cn.getClassName());
} else if (cn.getPackageName().equals("!!")) {
throw new SecurityException(
"Unable to start service " + service
+ ": " + cn.getClassName());
}
}
return cn;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
从startServiceCommon方法中可以看出,是ActivityManagerNative.getDefault()这个方法的类启动的,其实ActivityManagerNative.getDefault()就是AMS,是通过AMS来启动服务的行为是一个远程过程调用。
@Override
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, String callingPackage, int userId)
throws TransactionTooLargeException {
enforceNotIsolatedCaller("startService");
// Refuse possible leaked file descriptors
if (service != null && service.hasFileDescriptors() == true) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
if (callingPackage == null) {
throw new IllegalArgumentException("callingPackage cannot be null");
}
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
"startService: " + service + " type=" + resolvedType);
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, callingPackage, userId);
Binder.restoreCallingIdentity(origId);
return res;
}
}
在上面的代码中,AMS会通过mServices这个对象来完成Service后续的启动过程,mServices对象的类型是ActiveService,ActiveService是一个辅助AMS进行Service管理的类,包括Service的启动、绑定和停止等。
最终是通过app.thread的scheduleCreateService方法来创建Service对象并调用onCreate,接着再通过sendServiceArgsLocked方法来调用Service的其他方法,比如onStartCommand,这两个过程均是进程间通信,到最后是通过ApplicationThread的scheduleCreateService方法来
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);
}
是通过发消息给Handler H,H会接收这个CREATE_SERVICE消息并通过handleCreateService方法来完成Service的最终启动。
private void handleCreateService(CreateServiceData data) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler();
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = (Service) cl.loadClass(data.info.name).newInstance();
} catch (Exception e) {
if (!mInstrumentation.onException(service, e)) {
throw new RuntimeException(
"Unable to instantiate service " + data.info.name
+ ": " + e.toString(), e);
}
}
try {
if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);
Application app = packageInfo.makeApplication(false, mInstrumentation);
service.attach(context, this, data.info.name, data.token, app,
ActivityManagerNative.getDefault());
service.onCreate();
mServices.put(data.token, service);
try {
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} catch (Exception e) {
if (!mInstrumentation.onException(service, e)) {
throw new RuntimeException(
"Unable to create service " + data.info.name
+ ": " + e.toString(), e);
}
}
}
handleCreateService主要完成了如下几件事:
- 通过类加载器创建Service的实例
- 创建Application对象并调用其onCreate,当然Application的创建过程只会有一次。
- 接着创建ConTextImpl对象并通过Service的attach方法建立二者之间的关系。
- 最后调用onCreate方法,并将Service对象存储到ActivityThreadd的一个列表中。
Service的绑定过程
和Service的启动过程一样,Service绑定过程也是从ContextWrapper开始的。
@Override
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
return mBase.bindService(service, conn, flags);
}
然后会调用bindServiceCommon方法,这个方法主要完成如下两件事情:
- 首先将客户端的ServiceConnection对象转化为ServiceDispatcher.InnerConnection对象。
- 接着bindServiceCommon会通过AMS来完成Service的具体绑定过程,对应于AMS的bindService方法。
最终也是调用handleBindService来处理。
private void handleBindService(BindServiceData data) {
Service s = mServices.get(data.token);
if (DEBUG_SERVICE)
Slog.v(TAG, "handleBindService s=" + s + " rebind=" + data.rebind);
if (s != null) {
try {
data.intent.setExtrasClassLoader(s.getClassLoader());
data.intent.prepareToEnterProcess();
try {
if (!data.rebind) {
IBinder binder = s.onBind(data.intent);
ActivityManagerNative.getDefault().publishService(
data.token, data.intent, binder);
} else {
s.onRebind(data.intent);
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
ensureJitEnabled();
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
} catch (Exception e) {
if (!mInstrumentation.onException(s, e)) {
throw new RuntimeException(
"Unable to bind to service " + s
+ " with " + data.intent + ": " + e.toString(), e);
}
}
}
}
最后,以借用一张流程图来说明:

阅读扩展
源于对掌握的Android开发基础点进行整理,罗列下已经总结的文章,从中可以看到技术积累的过程。
1,Android系统简介
2,ProGuard代码混淆
3,讲讲Handler+Looper+MessageQueue关系
4,Android图片加载库理解
5,谈谈Android运行时权限理解
6,EventBus初理解
7,Android 常见工具类
8,对于Fragment的一些理解
9,Android 四大组件之 " Activity "
10,Android 四大组件之" Service "
11,Android 四大组件之“ BroadcastReceiver "
12,Android 四大组件之" ContentProvider "
13,讲讲 Android 事件拦截机制
14,Android 动画的理解
15,Android 生命周期和启动模式
16,Android IPC 机制
17,View 的事件体系
18,View 的工作原理
19,理解 Window 和 WindowManager
20,Activity 启动过程分析
21,Service 启动过程分析
22,Android 性能优化
23,Android 消息机制
24,Android Bitmap相关
25,Android 线程和线程池
26,Android 中的 Drawable 和动画
27,RecylerView 中的装饰者模式
28,Android 触摸事件机制
29,Android 事件机制应用
30,Cordova 框架的一些理解
31,有关 Android 插件化思考
32,开发人员必备技能——单元测试
Service启动过程分析的更多相关文章
- 探索 OpenStack 之(11):cinder-api Service 启动过程分析 以及 WSGI / Paste deploy / Router 等介绍
OpenStack 中的每一个提供 REST API Service 的组件,比如 cinder-api,nova-api 等,其实是一个 WSGI App,其主要功能是接受客户端发来的 HTTP R ...
- Activity启动过程分析
Android的四大组件中除了BroadCastReceiver以外,其他三种组件都必须在AndroidManifest中注册,对于BroadCastReceiver来说,它既可以在AndroidMa ...
- ASP.Net Core MVC6 RC2 启动过程分析[偏源码分析]
入口程序 如果做过Web之外开发的人,应该记得这个是标准的Console或者Winform的入口.为什么会这样呢? .NET Web Development and Tools Blog ASP.NE ...
- 开机SystemServer到ActivityManagerService启动过程分析
开机SystemServer到ActivityManagerService启动过程 一 从Systemserver到AMS zygote-> systemserver:java入层口: /** ...
- Neutron分析(2)——neutron-server启动过程分析
neutron-server启动过程分析 1. /etc/init.d/neutron-server DAEMON=/usr/bin/neutron-server DAEMON_ARGS=" ...
- ActivityManagerService启动过程分析
之前讲Android的View的绘制原理和流程的时候,讲到过在Android调用setContentView之后,Android调用了一个prepreTravle的方法,这里面就提到了Activity ...
- Tomcat源码学习(2)——启动过程分析
Tomcat启动过程分析 启动 tomcat 时,Windows下执行 startup.bat :Linux下执行 startup.sh 文件,实际上最后都是调用 org.apache.catalin ...
- Net Core MVC6 RC2 启动过程分析
入口程序 如果做过Web之外开发的人,应该记得这个是标准的Console或者Winform的入口.为什么会这样呢?.NET Web Development and Tools Blog ASP.NET ...
- startActivity启动过程分析(转)
基于Android 6.0的源码剖析, 分析android Activity启动流程,相关源码: frameworks/base/services/core/java/com/android/serv ...
随机推荐
- maven的单元测试中没有
原因:BaseTest没有找到单元测试造成的 增加一个空的单元测试 @Testpublic void testNothing(){} 异常现象:在maven项目执行mvn install 或mvn t ...
- python 列表、元组、字典的区别
区别: 相互转换:https://www.cnblogs.com/louis-w/p/8391147.html 一.列表 list [1,[2,'AA'],5,'orderl'] 1.任意对象的有序集 ...
- c#随机生成英文名
private static string GenerateSurname() { string name = string.Empty; string[] currentConson ...
- unable to auto-detect email address
git错误:unable to auto-detect email address 2017年11月14日 08:51:08 陈君豪 阅读数:7914 idea 用git更新的时候报错,详细错误信 ...
- SpringBoot +Jpa+ Hibernate+Mysql工程
1 使用工具workspace-sts 3.9.5.RELEASE (1)新建一个SpringBoot 项目,选择加载项目需要的的组件.DevTools,JPA,Web,Mysql. Finish. ...
- 1、python环境安装及软件介绍
软件: python3.0 下载地址:https://www.python.org/downloads/windows/ pycharm 下载地址: https://www.jetbrains.com ...
- HTTPS SSL/TLS协议
要说清楚 HTTPS 协议的实现原理,至少需要如下几个背景知识.1. 大致了解几个基本术语(HTTPS.SSL.TLS)的含义2. 大致了解 HTTP 和 TCP 的关系(尤其是“短连接”VS“长连接 ...
- linux环境:创建数据库用户,表空间,启动数据库
1.启动数据库 首先使用oracle用户登录Linux,然后在shell命令行中执行下面的命令:第一步:打开Oracle监听(先查看状态:oracle监听是否启动:lsnrctl status)$ l ...
- 20175126《Java程序设计》第二周学习总结
# 20175126 2016-2017-2 <Java程序设计>第二周学习总结 ## LINUX系统安装好输入法后如何使用? - 相信很多同学在刚接触虚拟机LINUX系统时,会因无法输入 ...
- Python开发【第五篇】:模块
递归的案例:阶乘 1*2*3*4*5*6*7- def func(num): if num == 1: return 1 return num * func(num - ...