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

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介:
在编写Android应用程序时,我们一般将一些计算型的逻辑放在一个独立的进程来处理,这样主进程仍然可以流畅地响应界面事件,提高用户体验。Android系统为我们提供了一个Service类,我们可以实现一个以Service为基类的服务子类,在里面实现自己的计算型逻辑,然后在主进程通过startService函数来启动这个服务。在本文中,将详细分析主进程是如何通过startService函数来在新进程中启动自定义服务的。

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

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


  
  
  1. package shy.luo.ashmem;  
  2.  
  3. ......  
  4.  
  5. public class Client extends Activity implements OnClickListener {  
  6.     ......  
  7.     IMemoryService memoryService = null;  
  8.     ......  
  9.  
  10.     @Override  
  11.     public void onCreate(Bundle savedInstanceState) {  
  12.         ......  
  13.  
  14.         IMemoryService ms = getMemoryService();  
  15.         if(ms == null) {          
  16.             startService(new Intent("shy.luo.ashmem.server"));  
  17.         } else {  
  18.             Log.i(LOG_TAG, "Memory Service has started.");  
  19.         }  
  20.  
  21.         ......  
  22.  
  23.         Log.i(LOG_TAG, "Client Activity Created.");  
  24.     }  
  25.  
  26.     ......  

 

 

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


  
  
  1. <manifest xmlns:android="http://schemas.android.com/apk/res/android" 
  2.     package="shy.luo.ashmem" 
  3.     android:sharedUserId="android.uid.system" 
  4.     android:versionCode="1" 
  5.     android:versionName="1.0">  
  6.         <application android:icon="@drawable/icon" android:label="@string/app_name">  
  7.             ......  
  8.             <service   
  9.                 android:enabled="true"   
  10.                 android:name=".Server" 
  11.                 android:process=".Server" >  
  12.                     <intent-filter>  
  13.                         <action android:name="shy.luo.ashmem.server"/>  
  14.                         <category android:name="android.intent.category.DEFAULT"/>  
  15.                     </intent-filter>  
  16.             </service>  
  17.         </application>  
  18. </manifest>  

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


  
  
  1. startService(new Intent("shy.luo.ashmem.server")); 

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


  
  
  1. package shy.luo.ashmem;  
  2.  
  3. ......  
  4.  
  5. public class Server extends Service {  
  6.       
  7.     ......  
  8.  
  9.     @Override  
  10.     public IBinder onBind(Intent intent) {  
  11.             return null;  
  12.     }  
  13.  
  14.     @Override  
  15.     public void onCreate() {  
  16.         ......  
  17.  
  18.     }  
  19.  
  20.     ......  

        下面,我们来看看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启动相关的代码:
 


  
  
  1. class ServerThread extends Thread {  
  2.       
  3.     ......  
  4.  
  5.     @Override  
  6.     public void run() {  
  7.  
  8.         ......  
  9.  
  10.         // Critical services...  
  11.         try {  
  12.  
  13.             ......  
  14.  
  15.             context = ActivityManagerService.main(factoryTest);  
  16.  
  17.             ......  
  18.  
  19.             ActivityManagerService.setSystemProcess();  
  20.  
  21.             ......  
  22.           
  23.         } catch (RuntimeException e) {  
  24.             Slog.e("System""Failure starting core service", e);  
  25.         }  
  26.  
  27.         ......  
  28.       
  29.     }  
  30.  
  31.     ......  
  32.  

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


  
  
  1. public final class ActivityManagerService extends ActivityManagerNative  
  2.         implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {  
  3.  
  4.     ......  
  5.  
  6.     static ActivityManagerService mSelf;  
  7.  
  8.     ......  
  9.  
  10.     public static void setSystemProcess() {  
  11.         try {  
  12.             ActivityManagerService m = mSelf;  
  13.  
  14.             ServiceManager.addService("activity", m);  
  15.               
  16.             ......  
  17.  
  18.         } catch (PackageManager.NameNotFoundException e) {  
  19.             ......  
  20.         }  
  21.     }  
  22.  
  23.     ......  
  24.  
  25.     public static final Context main(int factoryTest) {  
  26.           
  27.         ......  
  28.  
  29.         ActivityManagerService m = thr.mService;  
  30.         mSelf = m;  
  31.  
  32.         ......  
  33.  
  34.     }  

         这样,ActivityManagerService就启动起来了。
 

 

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


  
  
  1. class ActivityManagerProxy implements IActivityManager  
  2. {  
  3.     ......  
  4.  
  5.     public ComponentName startService(IApplicationThread caller, Intent service,  
  6.         String resolvedType) throws RemoteException  
  7.     {  
  8.         Parcel data = Parcel.obtain();  
  9.         Parcel reply = Parcel.obtain();  
  10.         data.writeInterfaceToken(IActivityManager.descriptor);  
  11.         data.writeStrongBinder(caller != null ? caller.asBinder() : null);  
  12.         service.writeToParcel(data, 0);  
  13.         data.writeString(resolvedType);  
  14.         mRemote.transact(START_SERVICE_TRANSACTION, data, reply, 0);  
  15.         reply.readException();  
  16.         ComponentName res = ComponentName.readFromParcel(reply);  
  17.         data.recycle();  
  18.         reply.recycle();  
  19.         return res;  
  20.     }  
  21.  
  22.     ......  

         参数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文件中:


  
  
  1. public final class ActivityManagerService extends ActivityManagerNative  
  2.                            implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {  
  3.  
  4.     ......  
  5.  
  6.     public ComponentName startService(IApplicationThread caller, Intent service,  
  7.             String resolvedType) {        
  8.           // Refuse possible leaked file descriptors  
  9.           if (service != null && service.hasFileDescriptors() == true) {  
  10.               throw new IllegalArgumentException("File descriptors passed in Intent");  
  11.           }  
  12.  
  13.           synchronized(this) {  
  14.               final int callingPid = Binder.getCallingPid();  
  15.               final int callingUid = Binder.getCallingUid();  
  16.               final long origId = Binder.clearCallingIdentity();  
  17.               ComponentName res = startServiceLocked(caller, service,  
  18.                   resolvedType, callingPid, callingUid);  
  19.               Binder.restoreCallingIdentity(origId);  
  20.               return res;  
  21.           }  
  22.     }  
  23.  
  24.     ......  
  25.  

         这里的参数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.     ......  
  5.  
  6.     ComponentName startServiceLocked(IApplicationThread caller,  
  7.             Intent service, String resolvedType,  
  8.             int callingPid, int callingUid) {  
  9.         synchronized(this) {  
  10.             ......  
  11.  
  12.             ServiceLookupResult res =  
  13.                 retrieveServiceLocked(service, resolvedType,  
  14.                 callingPid, callingUid);  
  15.               
  16.             ......  
  17.               
  18.             ServiceRecord r = res.record;  
  19.               
  20.             ......  
  21.  
  22.             if (!bringUpServiceLocked(r, service.getFlags(), false)) {  
  23.                 return new ComponentName("!""Service process is bad");  
  24.             }  
  25.             return r.name;  
  26.         }  
  27.     }  
  28.  
  29.     ......  
  30.  

        函数首先通过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文件中:


  
  
  1. public final class ActivityManagerService extends ActivityManagerNative  
  2.                             implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {  
  3.  
  4.     ......  
  5.  
  6.     private final boolean bringUpServiceLocked(ServiceRecord r,  
  7.                     int intentFlags, boolean whileRestarting) {  
  8.  
  9.         ......  
  10.  
  11.         final String appName = r.processName;  
  12.  
  13.         ......  
  14.  
  15.         // Not running -- get it started, and enqueue this service record  
  16.         // to be executed when the app comes up.  
  17.         if (startProcessLocked(appName, r.appInfo, true, intentFlags,  
  18.                     "service", r.name, false) == null) {  
  19.  
  20.             ......  
  21.  
  22.             return false;  
  23.         }  
  24.  
  25.         if (!mPendingServices.contains(r)) {  
  26.             mPendingServices.add(r);  
  27.         }  
  28.  
  29.         return true;  
  30.  
  31.     }  
  32.  
  33.     ......  
  34.  

 

        这里的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.     ......  
  5.  
  6.     private final void startProcessLocked(ProcessRecord app,  
  7.                 String hostingType, String hostingNameStr) {  
  8.  
  9.         ......  
  10.  
  11.         try {  
  12.  
  13.             ......  
  14.  
  15.             int pid = Process.start("android.app.ActivityThread",  
  16.                             mSimpleProcessManagement ? app.processName : null, uid, uid,  
  17.                             gids, debugFlags, null);  
  18.  
  19.             ......  
  20.  
  21.             if (pid == 0 || pid == MY_PID) {  
  22.                   
  23.                 ......  
  24.  
  25.             } else if (pid > 0) {  
  26.                 app.pid = pid;  
  27.                 app.removed = false;  
  28.                 synchronized (mPidsSelfLocked) {  
  29.                     this.mPidsSelfLocked.put(pid, app);  
  30.                     ......  
  31.                 }  
  32.             } else {  
  33.                   
  34.                 ......  
  35.             }  
  36.  
  37.         } catch (RuntimeException e) {  
  38.  
  39.             ......  
  40.  
  41.         }  
  42.  
  43.     }  
  44.  
  45.     ......  
  46.  

 

         这里调用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文件中:


  
  
  1. public final class ActivityThread {  
  2.       
  3.     ......  
  4.  
  5.     public static final void main(String[] args) {  
  6.  
  7.         ......  
  8.  
  9.         Looper.prepareMainLooper();  
  10.       
  11.         ......  
  12.  
  13.         ActivityThread thread = new ActivityThread();  
  14.         thread.attach(false);  
  15.  
  16.         ......  
  17.  
  18.         Looper.loop();  
  19.  
  20.         ......  
  21.  
  22.         thread.detach();  
  23.       
  24.         ......  
  25.     }  

 

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

 

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

        Step 7. ActivityThread.attach

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


  
  
  1. public final class ActivityThread {  
  2.       
  3.     ......  
  4.  
  5.     private final void attach(boolean system) {  
  6.           
  7.         ......  
  8.  
  9.         if (!system) {  
  10.  
  11.             ......  
  12.  
  13.             IActivityManager mgr = ActivityManagerNative.getDefault();  
  14.             try {  
  15.                 mgr.attachApplication(mAppThread);  
  16.             } catch (RemoteException ex) {  
  17.             }  
  18.         } else {  
  19.           
  20.             ......  
  21.  
  22.         }  
  23.  
  24.         ......  
  25.  
  26.     }  
  27.  
  28.     ......  
  29.  

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

 

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

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


  
  
  1. class ActivityManagerProxy implements IActivityManager  
  2. {  
  3.     ......  
  4.  
  5.     public void attachApplication(IApplicationThread app) throws RemoteException  
  6.     {  
  7.         Parcel data = Parcel.obtain();  
  8.         Parcel reply = Parcel.obtain();  
  9.         data.writeInterfaceToken(IActivityManager.descriptor);  
  10.         data.writeStrongBinder(app.asBinder());  
  11.         mRemote.transact(ATTACH_APPLICATION_TRANSACTION, data, reply, 0);  
  12.         reply.readException();  
  13.         data.recycle();  
  14.         reply.recycle();  
  15.     }  
  16.  
  17.     ......  
  18.  

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

        Step 9. ActivityManagerService.attachApplication

        这个函数定义在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.     ......  
  5.           
  6.     public final void attachApplication(IApplicationThread thread)   
  7.     {  
  8.         synchronized (this) {  
  9.             int callingPid = Binder.getCallingPid();  
  10.             final long origId = Binder.clearCallingIdentity();  
  11.             attachApplicationLocked(thread, callingPid);  
  12.             Binder.restoreCallingIdentity(origId);  
  13.         }  
  14.     }  
  15.       
  16.     ......  
  17.  

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





本文转自 Luoshengyang 51CTO博客,原文链接:http://blog.51cto.com/shyluo/965584,如需转载请自行联系原作者

目录
相关文章
|
1月前
|
IDE Java 开发工具
移动应用与系统:探索Android开发之旅
在这篇文章中,我们将深入探讨Android开发的各个方面,从基础知识到高级技术。我们将通过代码示例和案例分析,帮助读者更好地理解和掌握Android开发。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的信息和技巧。让我们一起开启Android开发的旅程吧!
|
21天前
|
监控 Java Android开发
深入探索Android系统的内存管理机制
本文旨在全面解析Android系统的内存管理机制,包括其工作原理、常见问题及其解决方案。通过对Android内存模型的深入分析,本文将帮助开发者更好地理解内存分配、回收以及优化策略,从而提高应用性能和用户体验。
|
22天前
|
存储 安全 Android开发
探索Android系统的最新安全特性
在数字时代,智能手机已成为我们生活中不可或缺的一部分。随着技术的不断进步,手机操作系统的安全性也越来越受到重视。本文将深入探讨Android系统最新的安全特性,包括其设计理念、实施方式以及对用户的影响。通过分析这些安全措施如何保护用户免受恶意软件和网络攻击的威胁,我们希望为读者提供对Android安全性的全面了解。
|
28天前
|
安全 Android开发 iOS开发
深入探讨Android与iOS系统的差异及未来发展趋势
本文旨在深入分析Android和iOS两大移动操作系统的核心技术差异、用户体验以及各自的市场表现,进一步探讨它们在未来技术革新中可能的发展方向。通过对比两者的开放性、安全性、生态系统等方面,本文揭示了两大系统在移动设备市场中的竞争态势和潜在变革。
|
6月前
|
监控 Linux 应用服务中间件
探索Linux中的`ps`命令:进程监控与分析的利器
探索Linux中的`ps`命令:进程监控与分析的利器
137 13
|
5月前
|
运维 关系型数据库 MySQL
掌握taskset:优化你的Linux进程,提升系统性能
在多核处理器成为现代计算标准的今天,运维人员和性能调优人员面临着如何有效利用这些处理能力的挑战。优化进程运行的位置不仅可以提高性能,还能更好地管理和分配系统资源。 其中,taskset命令是一个强大的工具,它允许管理员将进程绑定到特定的CPU核心,减少上下文切换的开销,从而提升整体效率。
掌握taskset:优化你的Linux进程,提升系统性能
|
5月前
|
弹性计算 Linux 区块链
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
192 4
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
|
4月前
|
算法 Linux 调度
探索进程调度:Linux内核中的完全公平调度器
【8月更文挑战第2天】在操作系统的心脏——内核中,进程调度算法扮演着至关重要的角色。本文将深入探讨Linux内核中的完全公平调度器(Completely Fair Scheduler, CFS),一个旨在提供公平时间分配给所有进程的调度器。我们将通过代码示例,理解CFS如何管理运行队列、选择下一个运行进程以及如何对实时负载进行响应。文章将揭示CFS的设计哲学,并展示其如何在现代多任务计算环境中实现高效的资源分配。
|
5月前
|
存储 缓存 安全
【Linux】冯诺依曼体系结构与操作系统及其进程
【Linux】冯诺依曼体系结构与操作系统及其进程
180 1
|
5月前
|
小程序 Linux
【编程小实验】利用Linux fork()与文件I/O:父进程与子进程协同实现高效cp命令(前半文件与后半文件并行复制)
这个小程序是在文件IO的基础上去结合父子进程的一个使用,利用父子进程相互独立的特点实现对数据不同的操作
130 2

相关实验场景

更多