Android系统进程Zygote启动过程的源代码分析(2)

简介:

 Step 2. AndroidRuntime.start

        这个函数定义在frameworks/base/core/jni/AndroidRuntime.cpp文件中:

 
 
  1. /*  
  2. * Start the Android runtime.  This involves starting the virtual machine  
  3. and calling the "static void main(String[] args)" method in the class  
  4. * named by "className".  
  5. */   
  6. void AndroidRuntime::start(const char* className, const bool startSystemServer)   
  7. {   
  8.     ......   
  9.    
  10.     char* slashClassName = NULL;   
  11.     char* cp;   
  12.     JNIEnv* env;   
  13.    
  14.     ......   
  15.    
  16.     /* start the virtual machine */   
  17.     if (startVm(&mJavaVM, &env) != 0)   
  18.         goto bail;   
  19.    
  20.     /*  
  21.     * Register android functions.  
  22.     */   
  23.     if (startReg(env) < 0) {   
  24.         LOGE("Unable to register all android natives\n");   
  25.         goto bail;   
  26.     }   
  27.    
  28.     /*  
  29.     * We want to call main() with a String array with arguments in it.  
  30.     * At present we only have one argument, the class name.  Create an  
  31.     * array to hold it.  
  32.     */   
  33.     jclass stringClass;   
  34.     jobjectArray strArray;   
  35.     jstring classNameStr;   
  36.     jstring startSystemServerStr;   
  37.     stringClass = env->FindClass("java/lang/String");   
  38.     assert(stringClass != NULL);   
  39.     strArray = env->NewObjectArray(2, stringClass, NULL);   
  40.     assert(strArray != NULL);   
  41.     classNameStr = env->NewStringUTF(className);   
  42.     assert(classNameStr != NULL);   
  43.     env->SetObjectArrayElement(strArray, 0, classNameStr);   
  44.     startSystemServerStr = env->NewStringUTF(startSystemServer ?   
  45.         "true" : "false");   
  46.     env->SetObjectArrayElement(strArray, 1, startSystemServerStr);   
  47.    
  48.     /*  
  49.     * Start VM.  This thread becomes the main thread of the VM, and will  
  50.     * not return until the VM exits.  
  51.     */   
  52.     jclass startClass;   
  53.     jmethodID startMeth;   
  54.    
  55.     slashClassName = strdup(className);   
  56.     for (cp = slashClassName; *cp != '\0'; cp++)   
  57.         if (*cp == '.')   
  58.             *cp = '/';   
  59.    
  60.     startClass = env->FindClass(slashClassName);   
  61.     if (startClass == NULL) {   
  62.         ......   
  63.     } else {   
  64.         startMeth = env->GetStaticMethodID(startClass, "main",   
  65.             "([Ljava/lang/String;)V");   
  66.         if (startMeth == NULL) {   
  67.             ......   
  68.         } else {   
  69.             env->CallStaticVoidMethod(startClass, startMeth, strArray);   
  70.             ......   
  71.         }   
  72.     }   
  73.    
  74.     ......   
  75. }   

 

     这个函数的作用是启动Android系统运行时库,它主要做了三件事情,一是调用函数startVM启动虚拟机,二是调用函数startReg注册JNI方法,三是调用了com.android.internal.os.ZygoteInit类的main函数。

        Step 3. ZygoteInit.main

        这个函数定义在frameworks/base/core/java/com/android/internal/os/ZygoteInit.java文件中:

 
 
  1. public class ZygoteInit {   
  2.     ......   
  3.    
  4.     public static void main(String argv[]) {   
  5.         try {   
  6.             ......   
  7.    
  8.             registerZygoteSocket();   
  9.                
  10.             ......   
  11.    
  12.             ......   
  13.    
  14.             if (argv[1].equals("true")) {   
  15.                 startSystemServer();   
  16.             } else if (!argv[1].equals("false")) {   
  17.                 ......   
  18.             }   
  19.    
  20.             ......   
  21.    
  22.             if (ZYGOTE_FORK_MODE) {   
  23.                 ......   
  24.             } else {   
  25.                 runSelectLoopMode();   
  26.             }   
  27.    
  28.             ......   
  29.         } catch (MethodAndArgsCaller caller) {   
  30.             ......   
  31.         } catch (RuntimeException ex) {   
  32.             ......   
  33.         }   
  34.     }   
  35.    
  36.     ......   
  37. }   

 

  它主要作了三件事情,一个调用registerZygoteSocket函数创建了一个socket接口,用来和ActivityManagerService通讯,二是调用startSystemServer函数来启动SystemServer组件,三是调用runSelectLoopMode函数进入一个无限循环在前面创建的socket接口上等待ActivityManagerService请求创建新的应用程序进程。

 

         Step 4. ZygoteInit.registerZygoteSocket

         这个函数定义在frameworks/base/core/java/com/android/internal/os/ZygoteInit.java文件中:

 
 
  1. public class ZygoteInit {   
  2.     ......   
  3.    
  4.     /**  
  5.     * Registers a server socket for zygote command connections  
  6.     *  
  7.     * @throws RuntimeException when open fails  
  8.     */   
  9.     private static void registerZygoteSocket() {   
  10.         if (sServerSocket == null) {   
  11.             int fileDesc;   
  12.             try {   
  13.                 String env = System.getenv(ANDROID_SOCKET_ENV);   
  14.                 fileDesc = Integer.parseInt(env);   
  15.             } catch (RuntimeException ex) {   
  16.                 ......   
  17.             }   
  18.    
  19.             try {   
  20.                 sServerSocket = new LocalServerSocket(   
  21.                     createFileDescriptor(fileDesc));   
  22.             } catch (IOException ex) {   
  23.                 .......   
  24.             }   
  25.         }   
  26.     }   
  27.            
  28.     ......   
  29. }   

这个socket接口是通过文件描述符来创建的,这个文件描符代表的就是我们前面说的/dev/socket/zygote文件了。这个文件描述符是通过环境变量ANDROID_SOCKET_ENV得到的,它定义为:

  1. public class ZygoteInit {  
  2.     ......  
  3.   
  4.     private static final String ANDROID_SOCKET_ENV = "ANDROID_SOCKET_zygote";  
  5.           
  6.     ......  
  7. }  

    那么,这个环境变量的值又是由谁来设置的呢?我们知道,系统启动脚本文件system/core/rootdir/init.rc是由init进程来解释执行的,而init进程的源代码位于system/core/init目录中,在init.c文件中,是由service_start函数来解释init.rc文件中的service命令的:

  1. void service_start(struct service *svc, const char *dynamic_args)  
  2. {  
  3.     ......  
  4.   
  5.     pid_t pid;  
  6.   
  7.     ......  
  8.   
  9.     pid = fork();  
  10.   
  11.     if (pid == 0) {  
  12.         struct socketinfo *si;  
  13.   
  14.         ......  
  15.   
  16.         for (si = svc->sockets; si; si = si->next) {  
  17.             int socket_type = (  
  18.                 !strcmp(si->type, "stream") ? SOCK_STREAM :  
  19.                 (!strcmp(si->type, "dgram") ? SOCK_DGRAM : SOCK_SEQPACKET));  
  20.             int s = create_socket(si->name, socket_type,  
  21.                 si->perm, si->uid, si->gid);  
  22.             if (s >= 0) {  
  23.                 publish_socket(si->name, s);  
  24.             }  
  25.         }  
  26.   
  27.         ......  
  28.     }  
  29.   
  30.     ......  
  31. }  

 每一个service命令都会促使init进程调用fork函数来创建一个新的进程,在新的进程里面,会分析里面的socket选项,对于每一个socket选项,都会通过create_socket函数来在/dev/socket目录下创建一个文件,在这个场景中,这个文件便是zygote了,然后得到的文件描述符通过publish_socket函数写入到环境变量中去:

  1. static void publish_socket(const char *name, int fd)  
  2. {  
  3.     char key[64] = ANDROID_SOCKET_ENV_PREFIX;  
  4.     char val[64];  
  5.   
  6.     strlcpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1,  
  7.             name,  
  8.             sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX));  
  9.     snprintf(val, sizeof(val), "%d", fd);  
  10.     add_environment(key, val);  
  11.   
  12.     /* make sure we don't close-on-exec */  
  13.     fcntl(fd, F_SETFD, 0);  
  14. }  

这里传进来的参数name值为"zygote",而ANDROID_SOCKET_ENV_PREFIX在system/core/include/cutils/sockets.h定义为:#define ANDROID_SOCKET_ENV_PREFIX   "ANDROID_SOCKET_"     因此,这里就把上面得到的文件描述符写入到以"ANDROID_SOCKET_zygote"为key值的环境变量中。又因为上面的ZygoteInit.registerZygoteSocket函数与这里创建socket文件的create_socket函数是运行在同一个进程中,因此,上面的ZygoteInit.registerZygoteSocket函数可以直接使用这个文件描述符来创建一个Java层的LocalServerSocket对象。如果其它进程也需要打开这个/dev/socket/zygote文件来和Zygote进程进行通信,那就必须要通过文件名来连接这个LocalServerSocket了,参考Android应用程序进程启动过程的源代码分析一文中的Step 4,ActivityManagerService是通过Process.start函数来创建一个新的进程的,而Process.start函数会首先通过Socket连接到Zygote进程中,最终由Zygote进程来完成创建新的应用程序进程,而Process类是通过openZygoteSocketIfNeeded函数来连接到Zygote进程中的Socket的:

 
 
  1. public class Process {     
  2.     ......     
  3.     
  4.     private static void openZygoteSocketIfNeeded()     
  5.             throws ZygoteStartFailedEx {     
  6.    
  7.         ......   
  8.    
  9.         for (int retry = 0     
  10.             ; (sZygoteSocket == null) && (retry < (retryCount + 1))     
  11.             ; retry++ ) {     
  12.    
  13.                 ......   
  14.    
  15.                 try {     
  16.                     sZygoteSocket = new LocalSocket();     
  17.                     sZygoteSocket.connect(new LocalSocketAddress(ZYGOTE_SOCKET,     
  18.                         LocalSocketAddress.Namespace.RESERVED));     
  19.    
  20.                     sZygoteInputStream     
  21.                         = new DataInputStream(sZygoteSocket.getInputStream());     
  22.    
  23.                     sZygoteWriter =     
  24.                         new BufferedWriter(     
  25.                         new OutputStreamWriter(     
  26.                         sZygoteSocket.getOutputStream()),     
  27.                         256);     
  28.    
  29.                     ......     
  30.                 } catch (IOException ex) {     
  31.                     ......     
  32.                 }     
  33.         }     
  34.    
  35.         ......     
  36.     }     
  37.    
  38.     ......     
  39. }   

 这里的ZYGOTE_SOCKET定义为:

  1. public class Process {    
  2.     ......    
  3.    
  4.     private static final String ZYGOTE_SOCKET = "zygote";    
  5.   
  6.     ......    
  7. }   

   它刚好就是对应/dev/socket目录下的zygote文件了。

 

        Android系统中的socket机制和binder机制一样,都是可以用来进行进程间通信,读者可以自己对比一下这两者的不同之处,Binder进程间通信机制可以参考Android进程间通信(IPC)机制Binder简要介绍和学习计划一文。

       Socket对象创建完成之后,回到Step 3中的ZygoteInit.main函数中,startSystemServer函数来启动SystemServer组件。





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

目录
相关文章
|
2月前
|
监控 Java Android开发
深入探索Android系统的内存管理机制
本文旨在全面解析Android系统的内存管理机制,包括其工作原理、常见问题及其解决方案。通过对Android内存模型的深入分析,本文将帮助开发者更好地理解内存分配、回收以及优化策略,从而提高应用性能和用户体验。
|
2月前
|
存储 安全 Android开发
探索Android系统的最新安全特性
在数字时代,智能手机已成为我们生活中不可或缺的一部分。随着技术的不断进步,手机操作系统的安全性也越来越受到重视。本文将深入探讨Android系统最新的安全特性,包括其设计理念、实施方式以及对用户的影响。通过分析这些安全措施如何保护用户免受恶意软件和网络攻击的威胁,我们希望为读者提供对Android安全性的全面了解。
|
2月前
|
Java 开发工具 Android开发
安卓与iOS开发环境对比分析
在移动应用开发的广阔天地中,安卓和iOS两大平台各自占据半壁江山。本文深入探讨了这两个平台的开发环境,从编程语言、开发工具到用户界面设计等多个角度进行比较。通过实际案例分析和代码示例,我们旨在为开发者提供一个清晰的指南,帮助他们根据项目需求和个人偏好做出明智的选择。无论你是初涉移动开发领域的新手,还是寻求跨平台解决方案的资深开发者,这篇文章都将为你提供宝贵的信息和启示。
45 8
|
3月前
|
安全 Android开发 数据安全/隐私保护
深入探索Android与iOS系统安全性的对比分析
在当今数字化时代,移动操作系统的安全已成为用户和开发者共同关注的重点。本文旨在通过比较Android与iOS两大主流操作系统在安全性方面的差异,揭示两者在设计理念、权限管理、应用审核机制等方面的不同之处。我们将探讨这些差异如何影响用户的安全体验以及可能带来的风险。
113 21
|
3月前
|
安全 Android开发 iOS开发
深入探讨Android与iOS系统的差异及未来发展趋势
本文旨在深入分析Android和iOS两大移动操作系统的核心技术差异、用户体验以及各自的市场表现,进一步探讨它们在未来技术革新中可能的发展方向。通过对比两者的开放性、安全性、生态系统等方面,本文揭示了两大系统在移动设备市场中的竞争态势和潜在变革。
|
3月前
|
开发框架 前端开发 Android开发
Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势
本文深入探讨了 Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势。这对于实现高效的跨平台移动应用开发具有重要指导意义。
351 4
|
3月前
|
IDE Java 开发工具
移动应用与系统:探索Android开发之旅
在这篇文章中,我们将深入探讨Android开发的各个方面,从基础知识到高级技术。我们将通过代码示例和案例分析,帮助读者更好地理解和掌握Android开发。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的信息和技巧。让我们一起开启Android开发的旅程吧!
|
6月前
|
算法 Linux 调度
探索进程调度:Linux内核中的完全公平调度器
【8月更文挑战第2天】在操作系统的心脏——内核中,进程调度算法扮演着至关重要的角色。本文将深入探讨Linux内核中的完全公平调度器(Completely Fair Scheduler, CFS),一个旨在提供公平时间分配给所有进程的调度器。我们将通过代码示例,理解CFS如何管理运行队列、选择下一个运行进程以及如何对实时负载进行响应。文章将揭示CFS的设计哲学,并展示其如何在现代多任务计算环境中实现高效的资源分配。
|
7月前
|
弹性计算 Linux 区块链
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
220 4
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
|
7月前
|
运维 关系型数据库 MySQL
掌握taskset:优化你的Linux进程,提升系统性能
在多核处理器成为现代计算标准的今天,运维人员和性能调优人员面临着如何有效利用这些处理能力的挑战。优化进程运行的位置不仅可以提高性能,还能更好地管理和分配系统资源。 其中,taskset命令是一个强大的工具,它允许管理员将进程绑定到特定的CPU核心,减少上下文切换的开销,从而提升整体效率。
掌握taskset:优化你的Linux进程,提升系统性能

热门文章

最新文章

  • 1
    如何修复 Android 和 Windows 不支持视频编解码器的问题?
  • 2
    Android历史版本与APK文件结构
  • 3
    【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
  • 4
    【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
  • 5
    当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
  • 6
    APP-国内主流安卓商店-应用市场-鸿蒙商店上架之必备前提·全国公安安全信息评估报告如何申请-需要安全评估报告的资料是哪些-优雅草卓伊凡全程操作
  • 7
    【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
  • 8
    Android经典面试题之Kotlin中Lambda表达式和匿名函数的区别
  • 9
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
  • 10
    【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
  • 相关实验场景

    更多