Android系统在新进程中启动自定义服务过程(startService)的原理分析

在编写Android应用程序时,我们一般将一些计算型的逻辑放在一个独立的进程来处理,这样主进程仍然可以流畅地响应界面事件,提高用户体验。Android系统为我们提供了一个Service类,我们可以实现一个以Service为基类的服务子类,在里面实现自己的计算型逻辑,然后在主进程通过startService函数来启动这个服务。在本文中,将详细分析主进程是如何通过startService函数来在新进程中启动自定义服务的。

在主进程调用startService函数时,会通过Binder进程间通信机制来通知ActivitManagerService来创建新进程,并且启动指定的服务。在Android系统中,Binder进程间通信机制使用非常广泛,因此,希望读者在继续阅读下面的内容之前,对Android系统和Binder进程间通信机制有一定的了解,具体可以参考前面Android进程间通信(IPC)机制Binder简要介绍和学习计划一文。

关于startService的具体用法,可以参考前面Android系统匿名共享内存Ashmem(Anonymous Shared Memory)简要介绍和学习计划一文中用到的实例,它是Activity类的一个成员函数:

这里的“shy.luo.ashmem.server”是在程序配置文件AndroidManifest.xml配置的Service的名字,用来告诉Android系统它所要启动的服务的名字:

这里,名字“shy.luo.ashmem.server”对应的服务类为shy.luo.ashmem.Server,下面语句:

就表示要在一个新的进程中启动shy.luo.ashmem.Server这个服务类,它必须继承于Android平台提供的Service类:

下面,我们来看看Activity类中的startService成员函数是如何实现的。

先来看看Activity的类图:

        从图中可以看出,Activity继承了ContextWrapper类,而在ContextWrapper类中,实现了startService函数。在ContextWrapper类中,有一个成员变量mBase,它是一个ContextImpl实例,而ContextImpl类和ContextWrapper类一样继承于Context类,ContextWrapper类的startService函数最终过调用ContextImpl类的startService函数来实现。这种类设计方法在设计模式里面,就称之为装饰模式(Decorator),或者包装模式(Wrapper)。

在ContextImpl类的startService类,最终又调用了ActivityManagerProxy类的startService来实现启动服务的操作,看到这里的Proxy关键字,回忆一下前面Android系统进程间通信Binder机制在应用程序框架层的Java接口源代码分析这篇文章,就会知道ActivityManagerProxy是一个Binder对象的远程接口了,而这个Binder对象就是我们前面所说的ActivityManagerService了。

这个ActivityManagerService类实现在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中,它是Binder进程间通信机制中的Server角色,它是随机启动的。随机启动的Server是在frameworks/base/services/java/com/android/server/SystemServer.java文件里面进行启动的,我们来看一下ActivityManagerService启动相关的代码:

首先是调用ActivityManagerService.main函数来创建一个ActivityManagerService实例,然后通过调用ActivityManagerService.setSystemProcess函数把这个Binder实例添加Binder进程间通信机制的守护进程ServiceManager中去:

这样,ActivityManagerService就启动起来了。

回到ActivityManagerProxy类的startService函数中,它定义在frameworks/base/core/java/android/app/ActivityManagerNative.java文件中:

参数service是一个Intent实例,它里面指定了要启动的服务的名称,就是前面我们所说的“shy.luo.ashmem.server”了。

参数caller是一个IApplicationThread实例,它是一个在主进程创建的一个Binder对象。在Android应用程序中,每一个进程都用一个ActivityThread实例来表示,而在ActivityThread类中,有一个成员变量mAppThread,它是一个ApplicationThread实例,实现了IApplicationThread接口,它的作用是用来辅助ActivityThread类来执行一些操作,这个我们在后面会看到它是如何用来启动服务的。

参数resolvedType是一个字符串,它表示service这个Intent的MIME类型,它是在解析Intent时用到的。在这个例子中,我们没有指定这个Intent 的MIME类型,因此,这个参数为null。

ActivityManagerProxy类的startService函数把这三个参数写入到data本地变量去,接着通过mRemote.transact函数进入到Binder驱动程序,然后Binder驱动程序唤醒正在等待Client请求的ActivityManagerService进程,最后进入到ActivityManagerService的startService函数中。

ActivityManagerService的startService函数的处理流程如下图所示:

点击查看大图

在这个序列图中,一共有20个步骤,下面说明每一步。

Step 1. ActivityManagerService.startService

这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:

这里的参数caller、service和resolvedType分别对应ActivityManagerProxy.startService传进来的三个参数。

Step 2. ActivityManagerService.startServiceLocked         这个函数同样定义在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:

  1. public final class ActivityManagerService extends ActivityManagerNative
  2. implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
  3. ......
  4. ComponentName startServiceLocked(IApplicationThread caller,
  5. Intent service, String resolvedType,
  6. int callingPid, int callingUid) {
  7. synchronized(this) {
  8. ......
  9. ServiceLookupResult res =
  10. retrieveServiceLocked(service, resolvedType,
  11. callingPid, callingUid);
  12. ......
  13. ServiceRecord r = res.record;
  14. ......
  15. if (!bringUpServiceLocked(r, service.getFlags(), false)) {
  16. return new ComponentName("!", "Service process is bad");
  17. }
  18. return r.name;
  19. }
  20. }
  21. ......
  22. }

函数首先通过retrieveServiceLocked来解析service这个Intent,就是解析前面我们在AndroidManifest.xml定义的Service标签的intent-filter相关内容,然后将解析结果放在res.record中,然后继续调用bringUpServiceLocked进一步处理。

Step 3. ActivityManagerService.bringUpServiceLocked        这个函数同样定义在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:

这里的appName便是我们前面在AndroidManifest.xml文件定义service标签时指定的android:process属性值了,即“.Server”。

接着调用startProcessLocked函数来创建一个新的进程,以便加载自定义的Service类。最后将这个ServiceRecord保存在成员变量mPendingServices列表中,后面会用到。

Step 4. ActivityManagerService.startProcessLocked

这个函数同样定义在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:

  1. public final class ActivityManagerService extends ActivityManagerNative
  2. implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
  3. ......
  4. private final void startProcessLocked(ProcessRecord app,
  5. String hostingType, String hostingNameStr) {
  6. ......
  7. try {
  8. ......
  9. int pid = Process.start("android.app.ActivityThread",
  10. mSimpleProcessManagement ? app.processName : null, uid, uid,
  11. gids, debugFlags, null);
  12. ......
  13. if (pid == 0 || pid == MY_PID) {
  14. ......
  15. } else if (pid > 0) {
  16. app.pid = pid;
  17. app.removed = false;
  18. synchronized (mPidsSelfLocked) {
  19. this.mPidsSelfLocked.put(pid, app);
  20. ......
  21. }
  22. } else {
  23. ......
  24. }
  25. } catch (RuntimeException e) {
  26. ......
  27. }
  28. }
  29. ......
  30. }

这里调用Process.start函数创建了一个新的进程,指定新的进程执行android.app.ActivityThread类。最后将表示这个新进程的ProcessRecord保存在mPidSelfLocked列表中,后面会用到。

Step 5. Process.start

这个函数定义在frameworks/base/core/java/android/os/Process.java文件中,这个函数我们就不看了,有兴趣的读者可以自己研究一下。在这个场景中,它就是新建一个进程,然后导入android.app.ActivityThread这个类,然后执行它的main函数。

Step 6. ActivityThread.main         这个函数定义在frameworks/base/core/java/android/app/ActivityThread.java文件中:

注意,执行到这里的时候,已经是在上一步创建的新进程里面了,即这里的进程是用来启动服务的,原来的主进程已经完成了它的命令,返回了。

前面我们提到,在Android应用程序中,每一个进程对应一个ActivityThread实例,所以,这个函数会创建一个thread实例,然后调用ActivityThread.attach函数进一步处理。

Step 7. ActivityThread.attach

这个函数定义在frameworks/base/core/java/android/app/ActivityThread.java文件中:

从Step 6中,这里传进来的参数system为false。成员变量mAppThread是一个ApplicationThread实例,我们在前面已经描述过这个实例的作用,它是用来辅助ActivityThread来执行一些操作的。

调用ActivityManagerNative.getDefault函数得到ActivityManagerService的远程接口,即ActivityManagerProxy,接着调用它的attachApplication函数。

Step 8. ActivityManagerProxy.attachApplication         这个函数定义在frameworks/base/core/java/android/app/ActivityManagerNative.java文件中:

这个函数主要是将新进程里面的IApplicationThread实例通过Binder驱动程序传递给ActivityManagerService。

Step 9. ActivityManagerService.attachApplication

这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:

这里通过调用attachApplicationLocked函数进一步处理。

Step 10. ActivityManagerService.attachApplicationLocked

这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:

回忆一下在上面的Step 4中,以新进程的pid值作为key值保存了一个ProcessRecord在mPidsSelfLocked列表中,这里先把它取出来,存放在本地变量app中,并且将app.processName保存在本地变量processName中。

再回忆一下在上面的Step 3中,在成员变量mPendingServices中,保存了一个ServiceRecord,这里通过进程uid和进程名称将它找出来,然后通过realStartServiceLocked函数来进一步处理。

Step 11. ActivityManagerService.realStartServiceLocked        这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:

这里的app.thread是一个ApplicationThread对象的远程接口,它是在上面的Step 6创建ActivityThread对象时作为ActivityThread对象的成员变量同时创建的,然后在Step 9中传过来的。然后调用这个远程接口的scheduleCreateService函数回到原来的ActivityThread对象中执行启动服务的操作。

Step 12. ApplicationThreadProxy.scheduleCreateService

这个函数定义在frameworks/base/core/java/android/app/ApplicationThreadNative.java文件中:

这里通过Binder驱动程序回到新进程的ApplicationThread对象中去执行scheduleCreateService函数。

Step 13. ApplicationThread.scheduleCreateService

这个函数定义在frameworks/base/core/java/android/app/ActivityThread.java文件中:

这里调用ActivityThread的queueOrSendMessage将一个CreateServiceData数据放到消息队列中去,并且分开这个消息。注意,这里已经是在上面Step 4创建的新进程中执行了。

Step 14. ActivityThread.queueOrSendMessage

这个函数定义在frameworks/base/core/java/android/app/ActivityThread.java文件中:

这里调用成员变量mH的sendMessage函数进行消息分发。这里的mH的类型为H,它继承于Handler类。

Step 15. H.sendMessage

这个函数继承于Handle类的sendMessage函数中,定义在frameworks/base/core/java/android/os/Handler.java文件中。这个函数我们就不看了,有兴趣的读者可以自己研究一下。消息分发以后,就进入到H.handleMessage函数进行处理了。

Step 16. H.handleMessage

这个函数定义在frameworks/base/core/java/android/app/ActivityThread.java文件中:

这里要处理的消息是CREATE_SERVICE,它调用ActivityThread类的handleCreateService成员函数进一步处理。

Step 17. ActivityThread.handleCreateService

这个函数定义在frameworks/base/core/java/android/app/ActivityThread.java文件中:

  1. public final class ActivityThread {
  2. ......
  3. private final void handleCreateService(CreateServiceData data) {
  4. unscheduleGcIdler();
  5. LoadedApk packageInfo = getPackageInfoNoCheck(
  6. data.info.applicationInfo);
  7. Service service = null;
  8. try {
  9. java.lang.ClassLoader cl = packageInfo.getClassLoader();
  10. service = (Service) cl.loadClass(data.info.name).newInstance();
  11. } catch (Exception e) {
  12. if (!mInstrumentation.onException(service, e)) {
  13. throw new RuntimeException(
  14. "Unable to instantiate service " + data.info.name
  15. + ": " + e.toString(), e);
  16. }
  17. }
  18. try {
  19. if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
  20. ContextImpl context = new ContextImpl();
  21. context.init(packageInfo, null, this);
  22. Application app = packageInfo.makeApplication(false, mInstrumentation);
  23. context.setOuterContext(service);
  24. service.attach(context, this, data.info.name, data.token, app,
  25. ActivityManagerNative.getDefault());
  26. service.onCreate();
  27. mServices.put(data.token, service);
  28. try {
  29. ActivityManagerNative.getDefault().serviceDoneExecuting(
  30. data.token, 0, 0, 0);
  31. } catch (RemoteException e) {
  32. }
  33. } catch (Exception e) {
  34. if (!mInstrumentation.onException(service, e)) {
  35. throw new RuntimeException(
  36. "Unable to create service " + data.info.name
  37. + ": " + e.toString(), e);
  38. }
  39. }
  40. }
  41. ......
  42. }

这里的data.info.name就是自定义的服务类shy.luo.ashmem.Server了。

Step 18. ClassLoader.loadClass

这一步实现在上面的ActivityThread.handleCreateService函数中:

Step 19. Obtain Service

这一步也是实现在上面的ActivityThread.handleCreateService函数中。上面通过ClassLoader.loadClass来导入自定义的服务类shy.luo.ashmem.Server并且创建它的一个实例后,就通过强制类型转换得到一个Service类实例。前面我们说过,自己的服务类必须要继承于Service类,这里就体现出来了为什么要这样做了。

Step 20. Service.onCreate

这一步继续实现在上面的ActivityThread.handleCreateService函数中:

因为这里的service实际上是一个shy.luo.ashmem.Server类实例,因此,这里就是执行shy.luo.ashmem.Server类的onCreate函数了:

至此,这个自定义的服务就启动起来了。

这样,Android系统在新进程中启动服务的过程就分析完成了,虽然很复杂,但是条理很清晰。它通过三次Binder进程间通信完成了服务的启动过程,分别是:

一. Step 1至Step 7,从主进程调用到ActivityManagerService进程中,完成新进程的创建;

二. Step 8至Step 11,从新进程调用到ActivityManagerService进程中,获取要在新进程启动的服务的相关信息;

三. Step 12至Step 20,从ActivityManagerService进程又回到新进程中,最终将服务启动起来。

学习完Android系统在新进程中启动服务的过程后,希望读者对Android系统的Service有一个深刻的理解。在编写Android应用程序的时候,尽量把一些计算型的逻辑以Service在形式来实现,使得这些耗时的计算能在一个独立的进程中进行,这样就能保持主进程流畅地响应界面事件,提高用户体验。

转自:http://blog.csdn.net/luoshengyang/article/details/6677029

时间: 2024-10-14 00:02:26

Android系统在新进程中启动自定义服务过程(startService)的原理分析的相关文章

Nios II 系统从EPCS器件中启动的设置过程

先Reset Vector EPCS Exception Vector Ram工程Program memory ,Read-only data memory...均为RAM.Hardware Image选择 EPCS编译.编译:先把POF文件下载到EPCS中.放到最底层后通过FLASH PROGRAMER 将工程和.SOF文件下载到EPCS中复位启动即可. Nios II 系统从EPCS器件中启动的设置过程,布布扣,bubuko.com

Android应用程序在新的进程中启动新的Activity的方法和过程分析

Android应用程序在新的进程中启动新的Activity的方法和过程分析 - 老罗的Android之旅 - 博客频道 - CSDN.NET ? ? ? ?前面我们在分析Activity启动过程的时候,看到同一个应用程序的Activity一般都是在同一个进程中启动,事实上,Activity也可以像Service一样在新的进程中启动,这样,一个应用程序就可以跨越好几个进程了,本文就分析一下在新的进程中启动Activity的方法和过程. ?? ? ? ?在前面Android进程间通信(IPC)机制B

Android Service组件在新进程中的启动过程

1.startService 在Android系统匿名共享内存(Anonymous Shared Memory)Java调用接口分析,http://blog.csdn.net/jltxgcy/article/details/31414509一文,Client调用了如下代码: public class Client extends Activity implements OnClickListener { public void onCreate(Bundle savedInstanceState

Android 子Activity组件在进程内的启动过程 && 子Activity组件在新进程中的启动过程

1.子Activity组件在进程内的启动过程 在Android Activity组件的启动过程http://blog.csdn.net/jltxgcy/article/details/35984557一文中,我们已经详细分析了Activity的启动过程,对于子Activity组件在进程内的启动过程,我们只分析它们之间的不同. 主要是2处,1是不需要创建新的任务栈,2是不需要创建新进程和子线程. 第1点,体现在如下代码上: -/Android/frameworks/base/services/ja

realarm Android系统编译后内核无法启动的解决方法

由于之前版本使用的内核并非uImage格式,而在编译时使用的是非uImage格式编译,所以照成无法启动. 解决方法是,在编译内核时使用make uImage方式编译. 修改根目录下的build_realv210.sh文件,如下图所示 另外注意上图中CPU_JOB_NUM这个参数,要根据自己的电脑配置来选择,该参数在该文件的起始处设置,可以设置成电脑CPU核心数的2倍,例如:如果核心数为2,那么设置成4即可. 完整脚本下载地址:http://download.csdn.net/detail/u01

AX 在增强入站端口中使用自定义服务 找不到服务操作

写好自定义服务A,添加好服务操作A1,A2,A3..... 在增强的入站端口,选择服务操作时,却找不到这些A1,A2,A3. 查找相关资料后,发现,要在服务A上右键,点"登记服务". 一段等待之后,重新打开入站端口,在选择服务操作时,就能找到A1,A2,A3了. AX 在增强入站端口中使用自定义服务 找不到服务操作,布布扣,bubuko.com

Android系统 小米/三星/索尼 应用启动图标未读消息数(BadgeNumber)动态提醒

摘要 Android系统 小米,三星,索尼手机发送桌面快键提醒数字图标,在Android系统中,众所周知不支持BadgeNumber,虽然第三方控件BadgeView可以实现应用内的数字提醒,但对于系统的图标,特别是app的logo图标很难实现数字标志,即使是绘图的方式不断修改,但这种方式天生弊端,实用性很差. BadgeNumber ShortCutNumber miui samsung sony sendBadgeNumber logo/icon数字提醒 Android系统 小米,三星,索尼

Android系统匿名共享内存Ashmem(Anonymous Shared Memory)驱动程序源代码分析

文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6664554 在上一文章Android系统匿名共享内存Ashmem(Anonymous Shared Memory)简要介绍和学习计划中, 我们简要介绍了Android系统的匿名共享内存机制,其中,简要提到了它具有辅助内存管理系统来有效地管理内存的特点,但是没有进一步去了解它是如何实 现的.在本文中,我们将通过分析Android系统的匿名共享内存

【Android】16.0 第16章 自定义服务和系统服务—本章示例主界面

分类:C#.Android.VS2015: 创建日期:2016-03-01 一.简介 本章主要演示Started Service.带Intent过滤器的Started Service.IntentService的基本用法,并简单介绍Android提供的系统服务. 二.本章示例主界面 1.运行截图 2.MainActivity.cs文件中对应的代码 chItems.Add(new Chapter() { ChapterName = "第16章 自定义服务和系统服务", ChapterIt