摘要

本文主要分析了当前热门手机平台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()静态方法来启动新程序:

// 在ActivityManagerService.java中:Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",                    app.processName, uid, uid, gids, debugFlags,                    app.info.targetSdkVersion, null, null);

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

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

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服务端/客户端的关系如下图所示:


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

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


小结

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

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

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


参考资料:

1 android.googlesource.com

2 柯元旦《android内核剖析》电子工业出版社

3 韩超,梁泉《android系统原理及开发要点详解》电子工业出版社

4 Google IO 《Android Anatomy and Physiology》

5 Robert Love《Linux.Kernel.Development.2nd.Edition》Novell Press

更多相关文章

  1. Android应用程序启动过程源代码分析
  2. Android(安卓)内存管理
  3. Android的dumpsys命令
  4. Android启动之bluetooth
  5. Android根文件系统的启动过程
  6. Android(安卓)应用程序快速启动的秘诀
  7. Android跨进程通信IPC
  8. Android(安卓)SDCard Mount 流程分析(一)
  9. 更改Android(安卓)AVD模拟器创建路径位置的方法

随机推荐

  1. Android 垂直的Slidebar 代码
  2. ch028 Android 断点续传
  3. My Android Camera Notes
  4. Android:GridView+AbsoluteLayout作一个
  5. Android 数据库技术
  6. android ImageView scaleType属性
  7. RadioButton修改标志图片
  8. android 主题
  9. Android下单元测试
  10. 最近总结的android疑惑