android进程创建分析

来源:互联网 发布:新版淘宝收藏店铺在哪 编辑:程序博客网 时间:2024/05/17 01:49

摘要

         本文主要分析了当前热门手机平台android系统的进程创建分析。先简单介绍android的技术架构,然后概述android启动新程序的整体流程,接着详细分析程序启动中的进程创建。在分析中辅以代码解析,从而让读者能较为清晰的了解到android时如何通过进程创建来启动新程序的。

Android架构

         android是世界上最受欢迎的手机平台。它以linux为基础,辅以定制的C语言本地库和内嵌独有的Dalvik虚拟机的Android runtime环境。在此基础上,用java构建了大量丰富的android framework,为最上层用户application的构建提供了极大的便利和强大的功能支持。这样,开发人员可以用java语言,开发运行于Dalvik虚拟机上的应用程序,降低开发成本。

下面是android的技术架构图。


         由此可见,android的运行最终离不开linux,其底层原理也是和linux一致的。所以,android的内核进程的创建也必定和linux内核的进程创建有紧密联系,但在分析android进程创建之前,先了解下android在application和framework层是怎么创建新程序的。

Android 启动新程序

         在java语言为基础的application层,android涉及的概念和linux相差甚远,简单说下几个重要的概念:

ActivityThread类:该类为应用程序的主线程类,所有的应用程序都有且仅有一个ActivityThread类,程序的入口为该类中的static main()函数。

Activity类:该类为APK(AndroidPackage,是一种通过AndroidSDK编译的工程打包成的安装程序文件)程序的一个最小运行单元,一个APK程序中可以包含多个Activity对象,ActivityThread主类会根据用户操作选择运行哪个Activity对象。

         ActivityManagerService类:简称AMS,它的作用是管理所有应用程序中的Activity。

         具体过程如下;

1.      直接调用 startActivity()启动指定的 Activity。AmS 收到客户请求 startActivity()后,会首先暂停当前的 Activity

2.      当 A 进程完成暂停后,报告AmS,AmS判断需要运行的目标Activity是否已存在,如果存在则直接恢复执行而不需要创建新程序

3.      如果第二步中AmS检查到目标Activity不存在,则启动对应进程。

a)        AmS调用Process进程类启动一个新的应用进程

b)        新的应用进程会从ActivityThread 的 main()函数处开始执行,当目标进程启动后,再报告AmS 自己已经启动

c)        AmS 再通知目标进程启动目标Activity。

这样,经过了第三步后,目标activity就这样在新的进程上运行了。

上面从用户应用程序的角度分析了android程序如何启动新程序。下面分析下其如何调用底层创建新进程的方法。

Framework创建新进程

         对于应用程序的创建,最终通过ams调度Process.start()静态方法来启动新程序:

[java] view plaincopyprint?
  1. // 在ActivityManagerService.java中:   
  2. Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",  
  3.                     app.processName, uid, uid, gids, debugFlags,  
  4.                     app.info.targetSdkVersion, nullnull);  

         上面的函数参数说明将会在新程序(进程)中调用android.app.ActivityThread类,实际上最终将调用其main函数。

Process.start()内部又继续调用Process类的静态函数startViaZygote()来进行创建进程的命令发送。为什么说是命令发送呢,查看startViaZygote()函数最后一行:

[java] view plaincopyprint?
  1. return zygoteSendArgsAndGetResult(argsForZygote);  

zygoteSendArgsAndGetResult函数最终实现的,是向socket服务端写数据,把创建进程的请求通过socket通讯方式来让framework的进程孵化类zygote创建新进程。而数据就是argsForZygote——一个以字符串List形式的把Process.start()所有调用参数都包含在里面的变量。其过程如下图所示:


         至于为什么是通过socket来发送创建进程的命令,其创建过程是怎样的?而又如何和linux联系的?下面将分析Android进程孵化环境,来回答上面的问题。


Android进程孵化环境

         当Android内核启动后,此时系统的状态和普通的Linux系统基本相同,通过配置Android中的init.rc文件,可以指定内核启动后都要执行什么程序,而在此配置文件中指定的之后所要启动的程序才是Android系统和普通Linux应用系统的区别。Android系统里init.rc中所启动的一个重要进程被称作zygote进程,也称为“种子进程”,从进程的角度来看,种子进程仅仅是一个Linux进程而已,它和一个只包含main()函数的C程序所产生的进程是同一个级别,但种子进程里面所运行的程序基本上就是Android内核的精华所在,其内部主要完成了两件事情。第一件事情是装载了一段程序代码,这些代码都是用C语言写的,这段代码的作用只是为了能够执行Java编译器编译出的字节码,功能类似Java虚拟机,在Android中称为Dalvik虚拟机。第二件事情必须基于第一件事情之后,即当Dalvik虚拟机代码初始化完成后,开始执行ZygoteInit.java类中的main()函数。ZygoteInit.java这个Jar包的目录位置信息也是在init.rc中进行配置的,是使用一个“zygote”标志符,Dalvik虚拟机就会从init.rc配置项的键值对中得到ZygoteInit类所在的Jar包,而这个Jar包正是Android的另一个核心--framework.jar。

         接下ZygoteInit类中main()函数所做的事情和Linux本身就没多大关系了,该main()函数中才刚刚开始启动Android的核心功能。首先加载一些类文件,这些类将作为以后所有其它Apk程序共享的类,接着,会创建一个Socket服务端,该服务端将用于通过Socket启动新进程。zygote进程被称为“种子”进程的原因就是,当其内部的Socket服务端收到启动新的Apk进程的请求时,会使用Linux的一个系统调用folk()函数从自身复制出一个新的进程,新进程和Zygote进程将共享已经装载的类,这些类都是在framework.jar中定义的。

         Zygote进程、SystemServer进程、各APK进程和创建进程的socket服务端/客户端的关系如下图所示:

         

[java] view plaincopyprint?
  1. // ZygoteInit.java的main函数如下:   
  2. public static void main(String argv[]) {  
  3.     try {  
  4.         …  
  5.         registerZygoteSocket(); // 注册一个socket server来监听zygote命令  
  6.         preloadClasses();//预加载java class   
  7.         preloadResources();//预加载资源文件  
  8.         …  
  9. gc();/*初始化GC垃圾回收机制*/  
  10. if (argv[1].equals("true")) {  
  11. /* 通过main中传递过来的第二个参数startsystemserver=”true” 启动systemserver, 在startSystemServer()中会fork一个新的进程命名为system_server, 执行的是com.android.server包中的SystemServer.java文件中的main函数*/  
  12.         startSystemServer(); ///*************  
  13. else if(…)   
  14. …  
  15. if (ZYGOTE_FORK_MODE) {  
  16.             runForkMode();      /*将进入Zygote的子进程*/  
  17. else {  
  18.             runSelectLoopMode();/* Zygote进程进入无限循环,不再返回。接下来的zygote将会作为一个孵化服务进程来运行。*/  
  19. }  
  20. closeServerSocket();  
  21. }  
  22. …  
  23. }  

[java] view plaincopyprint?
  1. // com.android.server包中的SystemServer.java核心代码如下:   
  2. public static void main(String[] args) {  
  3. System.loadLibrary("android_servers");// libandroid_servers是由目录frameworks/base/services/jni下的源码编译所得  
  4. init1(args); // init1实际上是一个jni本地接口   
  5. }  
  6.   
  7. static void android_server_SystemServer_init1(JNIEnv* env, jobject clazz){  
  8.     // init1接口主要调用一个系统初始化方法   
  9.     system_init();  
  10. }  
[cpp] view plaincopyprint?
  1. // JNI的实际调用c函数:   
  2. extern "C" status_t system_init(){  
  3.     …  
  4.     char propBuf[PROPERTY_VALUE_MAX];  
  5.     property_get("system_init.startsurfaceflinger", propBuf, "1");  
  6.     if (strcmp(propBuf, "1") == 0) {  
  7.         // 启动SurfaceFlinger   
  8.         SurfaceFlinger::instantiate();  
  9.     }  
  10.   
  11.     if (!proc->supportsProcesses()) {  
  12.         …  
  13.         // 启动CameraService   
  14.         CameraService::instantiate();  
  15.         // 启动AudioPolicyService  
  16.         AudioPolicyService::instantiate();   
  17.     }  
  18.     …  
  19.     AndroidRuntime* runtime = AndroidRuntime::getRuntime();  
  20. // 执行com.android.server.SystemServer类的init2函数,主要负责开启一个ServerThread线程  
  21.     runtime->callStatic("com/android/server/SystemServer""init2")  
  22. …  
  23. }  
[java] view plaincopyprint?
  1. // JNI回调SystemServer.java的init2()函数   
  2. public static final void init2() {  
  3.     Thread thr = new ServerThread();  
  4.     thr.setName("android.server.ServerThread");  
  5.     thr.start();  
  6. }  
  7.   
  8. // ServerThread线程的run函数会启动系统中绝大部分的android service,并最后进入Loop.loop(),,,,(SystemServer.java)  
  9.   
  10. public void run() {  
  11.     …  
  12.     try {  
  13.         …  
  14.         Slog.i(TAG, "Power Manager");  
  15.         power = new PowerManagerService();  
  16.         ServiceManager.addService(Context.POWER_SERVICE, power);  
  17.         Slog.i(TAG, "Activity Manager");  
  18.         context = ActivityManagerService.main(factoryTest);  
  19.         Slog.i(TAG, "Package Manager");  
  20.         pm = PackageManagerService.main(context,  
  21.                 factoryTest != SystemServer.FACTORY_TEST_OFF);  
  22.         Slog.i(TAG, "Content Manager");  
  23.         ContentService.main(context,  
  24.              factoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL);  
  25.         Slog.i(TAG, "Battery Service");  
  26.         battery = new BatteryService(context);  
  27.         ServiceManager.addService("battery", battery);  
  28.         …  
  29. // 其余addservice的过程类似,只是启动的不同服务罢了,后面还启动了很多服务,如:Lights、Vibrator、Alarm、Sensor、Bluetooth、Input Method、NetStat、NetworkManagement、Connectivity、Mount、Notification、Audio等。在这些服务都启动完了之后,就是使用xxx.systemReady()通知各个服务,系统已经就绪。  
  30.  public void run() {  
  31.          if (batteryF != null) batteryF.systemReady();  
  32.          if (connectivityF != null) connectivityF.systemReady();  
  33.          if (dockF != null) dockF.systemReady();  
  34.          if (uiModeF != null) uiModeF.systemReady();  
  35.          if (recognitionF != null) recognitionF.systemReady();  
  36.          Watchdog.getInstance().start();  
  37.          …  
  38.         }  
  39.         });  
  40.         …  
  41.         Looper.loop(); // Run the message queue in this thread。  
  42.         …  
  43. }  


小结

         再从头梳理下android程序创建的整个流程:application层的程序发起创建应用程序的命令->Ams调度框架通过framework发起socket通讯通知新进程创建->zygote孵化进程接收socket信息并调用内核创建新进程。这样,这个流程就串起来了。

         综上所述,创建程序新进程的任务最关键就是zygote进程。Zygote进程起到一个承上启下的作用。对于framework,zygote进程接收上层应用通过socket发送过来的新进程创建命令,对于kernel而言,zygote进程主要调用了内核的fork()系统调用来进行新进程的创建,所以zygote在android系统中扮演一个非常重要的角色,是新进程创建的一个孵化器。

         至此,本文也通过代码和相关流程解释了为什么android程序进行最终还是建立在linux基础之上。

 

 

 

 

Android源码学习之六——ActivityManager框架解析

分类: Android 2010-11-26 10:29 25881人阅读 评论(11)收藏 举报
框架androidnulltokenlistsystem

目录(?)[+]

  1. ActivityManager的作用
  2. ActivityManager的静态类图
  3. Proxy模式
  4. 本地代理与远端代理的Binder
  5. 动态序列图
  6. Activity启动
  7. 总结

ActivityManager在操作系统中有重要的作用,本文利用操作系统源码,逐步理清ActivityManager的框架,并从静态类结构图和动态序列图两个角度分别进行剖析,从而帮助开发人员加强对系统框架及进程通信机制的理解。

ActivityManager的作用

参照SDK的说明,可见ActivityManager的功能是与系统中所有运行着的Activity交互提供了接口,主要的接口围绕着运行中的进程信息,任务信息,服务信息等。比如函数getRunningServices()的源码是:

    public List<RunningServiceInfo> getRunningServices(int maxNum)

            throws SecurityException {

        try {

            return (List<RunningServiceInfo>)ActivityManagerNative.getDefault()

                    .getServices(maxNum, 0);

        } catch (RemoteException e) {

            // System dead, we will be dead too soon!

            return null;

        }

    }

从中可以看到,ActivityManager的大多数功能都是调用了ActivityManagerNative类接口来完成的,因此,我们寻迹来看ActivityManagerNative的代码,并以此揭示ActivityManager的整体框架。

ActivityManager的静态类图

通过源吗,可以发现ActivityManagerNative类的继承关系如下:

public abstract class ActivityManagerNative extends Binder implements IActivityManager

继承自Binder类,同时实现了IActivityManager接口。

同样的,我们继续沿Binder和IActivityManager上溯,整理出如下图所示的类结构图。

 

在这张图中,绿色的部分是在SDK中开放给应用程序开发人员的接口,蓝色的部分是一个典型的Proxy模式,红色的部分是底层的服务实现,是真正的动作执行者。这里的一个核心思想是Proxy模式,我们接下来对此模式加以介绍。

Proxy模式

Proxy模式,也称代理模式,是经典设计模式中的一种结构型模式,其定义是为其他对象提供一种代理以控制对这个对象的访问,简单的说就是在访问和被访问对象中间加上的一个间接层,以隔离访问者和被访问者的实现细节。

结合上面的类结构图,其中ActivityManager是一个客户端,为了隔离它与ActivityManagerService,有效降低甚至消除二者的耦合度,在这中间使用了ActivityManagerProxy代理类,所有对ActivityManagerService的访问都转换成对代理类的访问,这样ActivityManager就与ActivityManagerService解耦了。这就是代理模式的典型应用场景。

为了让代理类与被代理类保持一致的接口,从而实现更加灵活的类结构,或者说完美的屏蔽实现细节,通常的作法是让代理类与被代理类实现一个公共的接口,这样对调用者来说,无法知道被调用的是代理类还是直接是被代理类,因为二者的接口是相同的。

这个思路在上面的类结构图里也有落实,IActivityManager接口类就是起的这个作用。

以上就是代理模式的思路,有时我们也称代理类为本地代理(Local Proxy),被代理类为远端代理(Remote Proxy)。

本地代理与远端代理的Binder

我们再来看一下Binder类的作用,Binder的含义可能译为粘合剂更为贴切,即将两侧的东西粘贴起来。在操作系统中,Binder的一大作用就是连接本地代理和远端代理。Binder中最重要的一个函数是:

    public final boolean transact(int code, Parcel data, Parcel reply,

            int flags) throws RemoteException {

                   ……

        boolean r = onTransact(code, data, reply, flags);

        if (reply != null) {

            reply.setDataPosition(0);

        }

        return r;

    }

它的作用就在于通过code来表示请求的命令标识,通过data和reply进行数据传递,只要远端代理能实现onTransact()函数,即可做出正确的动作,远端的执行接口被完全屏蔽了。

当然,Binder的实现还是很复杂的,不仅是类型转换,还要透过Binder驱动进入KERNEL层来完成进程通信,这些内容不在本文的范围之内,故此处不再深入解析相应的机制。此处我们只要知道Binder的transact()函数实现就可以了。

到此为止,我们对ActivityManager的静态类结构就分析完了,但这还不足以搞清在系统运行中的调用过程,因此,我们以下图的序列图为基础,结合源码探索一下ActivityManager运行时的机制。

动态序列图

 

 

我们以ActivityManager的getRunningServices()函数为例,对上述序列图进行解析。

    public List<RunningServiceInfo> getRunningServices(int maxNum)

            throws SecurityException {

        try {

            return (List<RunningServiceInfo>)ActivityManagerNative.getDefault()

                    .getServices(maxNum, 0);

        } catch (RemoteException e) {

            // System dead, we will be dead too soon!

            return null;

        }

    }

可以看到,调用被委托到了ActivatyManagerNative.getDefault()。

    static public IActivityManager asInterface(IBinder obj)

{

                   ……

        return new ActivityManagerProxy(obj);

    }

   

    static public IActivityManager getDefault()

{

……

        IBinder b = ServiceManager.getService("activity");

        gDefault = asInterface(b);

        return gDefault;

    }

从上述简化后的源码可以看到,getDefault()函数返回的是一个ActivityManagerProxy对象的引用,也就是说,ActivityManager得到了一个本地代理。

因为在IActivityManager接口中已经定义了getServices()函数,所以我们来看这个本地代理对该函数的实现。

    public List getServices(int maxNum, int flags) throws RemoteException {

        Parcel data = Parcel.obtain();

        Parcel reply = Parcel.obtain();

                   ……

        mRemote.transact(GET_SERVICES_TRANSACTION, data, reply, 0);

        ……

    }

从这个代码版段我们看到,调用远端代理的transact()函数,而这个mRemote就是ActivityManagerNative的Binder接口。

接下来我们看一下ActivityManagerNative的代码,因为该类是继承于Binder类的,所以transact的机制此前我们已经展示了代码,对于该类而言,重要的是对onTransact()函数的实现。

    public boolean onTransact(int code, Parcel data, Parcel reply, int flags)

            throws RemoteException {

        switch (code) {

        case GET_SERVICES_TRANSACTION: {

                            ……

            List list = getServices(maxNum, fl);

                            ……

            return true;

        }

……

        }

        return super.onTransact(code, data, reply, flags);

    }

在onTrasact()函数内,虽然代码特别多,但就是一个switch语句,根据不同的code命令进行不同的处理,比如对于GET_SERVICES_TRANSACTION命令,只是调用了getServices()函数。而该函数的实现是在ActivityManagerService类中,它是ActivityManagerNative的子类,对于该函数的实现细节,不在本文中详细分析。

Activity启动

在经过前文的学习以后,我们一起来整理一下Activity的启动机制。就从Activity的startActivity()函数开始吧。

startActivity()函数调用了startActivityForResult()函数,该函数有源码如下:

    public void startActivityForResult(Intent intent, int requestCode) {

        ……

            Instrumentation.ActivityResult ar =

                mInstrumentation.execStartActivity(

                    this, mMainThread.getApplicationThread(), mToken, this,

                    intent, requestCode);

                   ……

    }

可见,功能被委托给Instrumentation对象来执行了。这个类的功能是辅助Activity的监控和测试,在此我们不详细描述,我们来看它的execStartActivity()函数。

    public ActivityResult execStartActivity(

        Context who, IBinder contextThread, IBinder token, Activity target,

        Intent intent, int requestCode) {

                   ……

        try {

            int result = ActivityManagerNative.getDefault()

                .startActivity(whoThread, intent,

                        intent.resolveTypeIfNeeded(who.getContentResolver()),

                        null, 0, token, target != null ? target.mEmbeddedID : null,

                        requestCode, false, false);

            checkStartActivityResult(result, intent);

        } catch (RemoteException e) {

        }

        return null;

    }

在这个函数里,我们看到了前文熟悉的ActivityManagerNative.getDefault(),没错,利用了ActivityManagerService。通过前文的线索,利用Proxy模式,我们可以透过ActivityManagerProxy,通过Binder的transact机制,找到真正的动作执行者,即ActivityManagerService类的startActivity()函数,并沿此线索继续追踪源码,在startActivityLocked()函数里边看到了mWindowManager.setAppStartingWindow的语句调用,mWindowManager是WindowManagerService对象,用于负责界面上的具体窗口调试。

通过这样的源码追踪,我们了解到了Activity启动的底层实现机制,也加深了对Proxy模式和Binder机制的理解。从而为学习其他框架打下了基础。

总结

本文从静态类结构和动态类结构两个角度分析了ActivityManager的框架,兼顾了Binder机制和代理模式在进程间通信的机理,对帮助开发人员深化操作系统的结构和框架具有一定的指导作用。

 

0 0