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启动过程分析的更多相关文章

  1. 探索 OpenStack 之(11):cinder-api Service 启动过程分析 以及 WSGI / Paste deploy / Router 等介绍

    OpenStack 中的每一个提供 REST API Service 的组件,比如 cinder-api,nova-api 等,其实是一个 WSGI App,其主要功能是接受客户端发来的 HTTP R ...

  2. Activity启动过程分析

    Android的四大组件中除了BroadCastReceiver以外,其他三种组件都必须在AndroidManifest中注册,对于BroadCastReceiver来说,它既可以在AndroidMa ...

  3. ASP.Net Core MVC6 RC2 启动过程分析[偏源码分析]

    入口程序 如果做过Web之外开发的人,应该记得这个是标准的Console或者Winform的入口.为什么会这样呢? .NET Web Development and Tools Blog ASP.NE ...

  4. 开机SystemServer到ActivityManagerService启动过程分析

    开机SystemServer到ActivityManagerService启动过程 一 从Systemserver到AMS zygote-> systemserver:java入层口: /** ...

  5. Neutron分析(2)——neutron-server启动过程分析

    neutron-server启动过程分析 1. /etc/init.d/neutron-server DAEMON=/usr/bin/neutron-server DAEMON_ARGS=" ...

  6. ActivityManagerService启动过程分析

    之前讲Android的View的绘制原理和流程的时候,讲到过在Android调用setContentView之后,Android调用了一个prepreTravle的方法,这里面就提到了Activity ...

  7. Tomcat源码学习(2)——启动过程分析

    Tomcat启动过程分析 启动 tomcat 时,Windows下执行 startup.bat :Linux下执行 startup.sh 文件,实际上最后都是调用 org.apache.catalin ...

  8. Net Core MVC6 RC2 启动过程分析

    入口程序 如果做过Web之外开发的人,应该记得这个是标准的Console或者Winform的入口.为什么会这样呢?.NET Web Development and Tools Blog ASP.NET ...

  9. startActivity启动过程分析(转)

    基于Android 6.0的源码剖析, 分析android Activity启动流程,相关源码: frameworks/base/services/core/java/com/android/serv ...

随机推荐

  1. ZStack串口通信

    要使用ZStack就不得不先了解ZStack的OSAL工作原理 http://blog.csdn.net/qinpeng_zbdx/article/details/20990797 http://we ...

  2. install mysql from source and troubleshooting example

    I tried to install MySQL 5.7 from source file and upgrading previous MySQL version to the lastest 5. ...

  3. ArcGIS自定义工具箱-字段分割

    ArcGIS自定义工具箱-字段分割 联系方式:谢老师,135-4855-4328,xiexiaokui#qq.com 目的:用指定分割符分割字段, 用例:湖南省长沙市=>湖南/长沙 数据源: 使 ...

  4. python入门(三):循环

    1.for i in xxx xxx: 序列(列表,元祖,字符串) xxx: 可迭代对象 >>> for i in "abc": ...     print(i) ...

  5. Secondary Indices

    [Secondary Indices] EOSIO has the ability to sort tables by up to 16 indices.  A table's struct cann ...

  6. linux shell条件与循环举例

    1. if/else 语句 语法: if condition; then commands;elif condition; then commands;else commands;fi 示例:需求:脚 ...

  7. Java 虚拟机概述

    虚拟机是一种抽象化的计算机,通过在实际的计算机上仿真模拟各种计算机功能来实现的.Java虚拟机有自己完善的硬体架构,如处理器.堆栈.寄存器等,还具有相应的指令系统.Java虚拟机屏蔽了与具体操作系统平 ...

  8. elasticsearch5安装

    环境: centos7 es 5.4.3 es安装 一.下载 wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsear ...

  9. php json 写入 mysql 的例子

    $a['aaa']='aaaa'; $a['bbb']='bbb'; $a['ccc']='ccc'; $arr['step_name']='kfkf'; $arr['process_name']=' ...

  10. Es6(Symbol,set,map,filter)

    首先再讲这几个新东西之前,先说一个Es6中新出的扩展运算符(...) 1.展开运算符,就是把东西展开,可以用在array和object上 比如: let a=[,] let b=[,...a,]//[ ...