Android应用程序进程启动过程的源代码分析(2)

简介:
     Step 5. ZygoteInit.runSelectLoopMode
        这个函数定义在frameworks/base/core/java/com/android/internal/os/ZygoteInit.java文件中:
 
 
  1. public class ZygoteInit {   
  2.     ......   
  3.    
  4.     /**  
  5.     * Runs the zygote process's select loop. Accepts new connections as  
  6.     * they happen, and reads commands from connections one spawn-request's  
  7.     * worth at a time.  
  8.     *  
  9.     * @throws MethodAndArgsCaller in a child process when a main() should  
  10.     * be executed.  
  11.     */   
  12.     private static void runSelectLoopMode() throws MethodAndArgsCaller {   
  13.         ArrayList<FileDescriptor> fds = new ArrayList();   
  14.         ArrayList<ZygoteConnection> peers = new ArrayList();   
  15.         FileDescriptor[] fdArray = new FileDescriptor[4];   
  16.    
  17.         fds.add(sServerSocket.getFileDescriptor());   
  18.         peers.add(null);   
  19.    
  20.         int loopCount = GC_LOOP_COUNT;   
  21.         while (true) {   
  22.             int index;   
  23.             /*  
  24.             * Call gc() before we block in select().  
  25.             * It's work that has to be done anyway, and it's better  
  26.             * to avoid making every child do it.  It will also  
  27.             * madvise() any free memory as a side-effect.  
  28.             *  
  29.             * Don't call it every time, because walking the entire  
  30.             * heap is a lot of overhead to free a few hundred bytes.  
  31.             */   
  32.             if (loopCount <= 0) {   
  33.                 gc();   
  34.                 loopCount = GC_LOOP_COUNT;   
  35.             } else {   
  36.                 loopCount--;   
  37.             }   
  38.    
  39.    
  40.             try {   
  41.                 fdArray = fds.toArray(fdArray);   
  42.                 index = selectReadable(fdArray);   
  43.             } catch (IOException ex) {   
  44.                 throw new RuntimeException("Error in select()", ex);   
  45.             }   
  46.    
  47.             if (index < 0) {   
  48.                 throw new RuntimeException("Error in select()");   
  49.             } else if (index == 0) {   
  50.                 ZygoteConnection newPeer = acceptCommandPeer();   
  51.                 peers.add(newPeer);   
  52.                 fds.add(newPeer.getFileDesciptor());   
  53.             } else {   
  54.                 boolean done;   
  55.                 done = peers.get(index).runOnce();   
  56.    
  57.                 if (done) {   
  58.                     peers.remove(index);   
  59.                     fds.remove(index);   
  60.                 }   
  61.             }   
  62.         }   
  63.     }   
  64.    
  65.     ......   
  66. }   
        当Step 4将数据通过Socket接口发送出去后,就会下面这个语句:
 
 
  1. done = peers.get(index).runOnce();   
        这里从peers.get(index)得到的是一个ZygoteConnection对象,表示一个Socket连接,因此,接下来就是调用ZygoteConnection.runOnce函数进一步处理了。
 
        Step 6. ZygoteConnection.runOnce
        这个函数定义在frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java文件中:
 
 
  1. class ZygoteConnection {   
  2.     ......   
  3.    
  4.     boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {   
  5.         String args[];   
  6.         Arguments parsedArgs = null;   
  7.         FileDescriptor[] descriptors;   
  8.    
  9.         try {   
  10.             args = readArgumentList();   
  11.             descriptors = mSocket.getAncillaryFileDescriptors();   
  12.         } catch (IOException ex) {   
  13.             ......   
  14.             return true;   
  15.         }   
  16.    
  17.         ......   
  18.    
  19.         /** the stderr of the most recent request, if avail */   
  20.         PrintStream newStderr = null;   
  21.    
  22.         if (descriptors != null && descriptors.length >= 3) {   
  23.             newStderr = new PrintStream(   
  24.                 new FileOutputStream(descriptors[2]));   
  25.         }   
  26.    
  27.         int pid;   
  28.            
  29.         try {   
  30.             parsedArgs = new Arguments(args);   
  31.    
  32.             applyUidSecurityPolicy(parsedArgs, peer);   
  33.             applyDebuggerSecurityPolicy(parsedArgs);   
  34.             applyRlimitSecurityPolicy(parsedArgs, peer);   
  35.             applyCapabilitiesSecurityPolicy(parsedArgs, peer);   
  36.    
  37.             int[][] rlimits = null;   
  38.    
  39.             if (parsedArgs.rlimits != null) {   
  40.                 rlimits = parsedArgs.rlimits.toArray(intArray2d);   
  41.             }   
  42.    
  43.             pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid,   
  44.                 parsedArgs.gids, parsedArgs.debugFlags, rlimits);   
  45.         } catch (IllegalArgumentException ex) {   
  46.             ......   
  47.         } catch (ZygoteSecurityException ex) {   
  48.             ......   
  49.         }   
  50.    
  51.         if (pid == 0) {   
  52.             // in child   
  53.             handleChildProc(parsedArgs, descriptors, newStderr);   
  54.             // should never happen   
  55.             return true;   
  56.         } else { /* pid != 0 */   
  57.             // in parent...pid of < 0 means failure   
  58.             return handleParentProc(pid, descriptors, parsedArgs);   
  59.         }   
  60.     }   
  61.    
  62.     ......   
  63. }   
 
      真正创建进程的地方就是在这里了:
 
 
  1. pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid,   
  2.     parsedArgs.gids, parsedArgs.debugFlags, rlimits);   
       有Linux开发经验的读者很容易看懂这个函数调用,这个函数会创建一个进程,而且有两个返回值,一个是在当前进程中返回的,一个是在新创建的进程中返回,即在当前进程的子进程中返回,在当前进程中的返回值就是新创建的子进程的pid值,而在子进程中的返回值是0。因为我们只关心创建的新进程的情况,因此,我们沿着子进程的执行路径继续看下去:
 
 
  1.    if (pid == 0) {   
  2. // in child   
  3. handleChildProc(parsedArgs, descriptors, newStderr);   
  4. // should never happen   
  5. return true;   
  6.    } else { /* pid != 0 */   
  7. ......   
  8.    }   
       这里就是调用handleChildProc函数了。
        Step 7. ZygoteConnection.handleChildProc
        这个函数定义在frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java文件中:
 
 
  1. class ZygoteConnection {   
  2.     ......   
  3.    
  4.     private void handleChildProc(Arguments parsedArgs,   
  5.             FileDescriptor[] descriptors, PrintStream newStderr)   
  6.             throws ZygoteInit.MethodAndArgsCaller {   
  7.         ......   
  8.    
  9.         if (parsedArgs.runtimeInit) {   
  10.             RuntimeInit.zygoteInit(parsedArgs.remainingArgs);   
  11.         } else {   
  12.             ......   
  13.         }   
  14.     }   
  15.    
  16.     ......   
  17. }   
 
     由于在前面的Step 3中,指定了"--runtime-init"参数,表示要为新创建的进程初始化运行时库,因此,这里的parseArgs.runtimeInit值为true,于是就继续执行RuntimeInit.zygoteInit进一步处理了。
        Step 8. RuntimeInit.zygoteInit
        这个函数定义在frameworks/base/core/java/com/android/internal/os/RuntimeInit.java文件中:
  1. public class RuntimeInit {  
  2.     ......  
  3.   
  4.     public static final void zygoteInit(String[] argv)  
  5.             throws ZygoteInit.MethodAndArgsCaller {  
  6.         // TODO: Doing this here works, but it seems kind of arbitrary. Find  
  7.         // a better place. The goal is to set it up for applications, but not  
  8.         // tools like am.  
  9.         System.setOut(new AndroidPrintStream(Log.INFO, "System.out"));  
  10.         System.setErr(new AndroidPrintStream(Log.WARN, "System.err"));  
  11.   
  12.         commonInit();  
  13.         zygoteInitNative();  
  14.   
  15.         int curArg = 0;  
  16.         for ( /* curArg */ ; curArg < argv.length; curArg++) {  
  17.             String arg = argv[curArg];  
  18.   
  19.             if (arg.equals("--")) {  
  20.                 curArg++;  
  21.                 break;  
  22.             } else if (!arg.startsWith("--")) {  
  23.                 break;  
  24.             } else if (arg.startsWith("--nice-name=")) {  
  25.                 String niceName = arg.substring(arg.indexOf('=') + 1);  
  26.                 Process.setArgV0(niceName);  
  27.             }  
  28.         }  
  29.   
  30.         if (curArg == argv.length) {  
  31.             Slog.e(TAG, "Missing classname argument to RuntimeInit!");  
  32.             // let the process exit  
  33.             return;  
  34.         }  
  35.   
  36.         // Remaining arguments are passed to the start class's static main  
  37.   
  38.         String startClass = argv[curArg++];  
  39.         String[] startArgs = new String[argv.length - curArg];  
  40.   
  41.         System.arraycopy(argv, curArg, startArgs, 0, startArgs.length);  
  42.         invokeStaticMain(startClass, startArgs);  
  43.     }  
  44.   
  45.     ......  
  46. }  
        这里有两个关键的函数调用,一个是zygoteInitNative函数调用,一个是invokeStaticMain函数调用,前者就是执行Binder驱动程序初始化的相关工作了,正是由于执行了这个工作,才使得进程中的Binder对象能够顺利地进行Binder进程间通信,而后一个函数调用,就是执行进程的入口函数,这里就是执行startClass类的main函数了,而这个startClass即是我们在Step 1中传进来的"android.app.ActivityThread"值,表示要执行android.app.ActivityThread类的main函数。
 
        我们先来看一下zygoteInitNative函数的调用过程,然后再回到RuntimeInit.zygoteInit函数中来,看看它是如何调用android.app.ActivityThread类的main函数的。
        step 9. RuntimeInit.zygoteInitNative
        这个函数定义在frameworks/base/core/java/com/android/internal/os/RuntimeInit.java文件中:
 
[java]  view plain copy
  1. public class RuntimeInit {  
  2.     ......  
  3.   
  4.     public static final native void zygoteInitNative();  
  5.   
  6.     ......  
  7. }  
        这里可以看出,函数zygoteInitNative是一个Native函数,实现在frameworks/base/core/jni/AndroidRuntime.cpp文件中:
 
 
[cpp]  view plain copy
  1. static void com_android_internal_os_RuntimeInit_zygoteInit(JNIEnv* env, jobject clazz)  
  2. {  
  3.     gCurRuntime->onZygoteInit();  
  4. }  
 
        这里它调用了全局变量gCurRuntime的onZygoteInit函数,这个全局变量的定义在frameworks/base/core/jni/AndroidRuntime.cpp文件开头的地方:
 
[cpp]  view plain copy
  1. static AndroidRuntime* gCurRuntime = NULL;  
        这里可以看出,它的类型为AndroidRuntime,它是在AndroidRuntime类的构造函数中初始化的,AndroidRuntime类的构造函数也是定义在frameworks/base/core/jni/AndroidRuntime.cpp文件中:
 
 
[cpp]  view plain copy
  1. AndroidRuntime::AndroidRuntime()  
  2. {  
  3.     ......  
  4.   
  5.     assert(gCurRuntime == NULL);        // one per process  
  6.     gCurRuntime = this;  
  7. }  
        那么这个AndroidRuntime类的构造函数又是什么时候被调用的呢?AndroidRuntime类的声明在frameworks/base/include/android_runtime/AndroidRuntime.h文件中,如果我们打开这个文件会看到,它是一个虚拟类,也就是我们不能直接创建一个AndroidRuntime对象,只能用一个AndroidRuntime类的指针来指向它的某一个子类,这个子类就是AppRuntime了,它定义在frameworks/base/cmds/app_process/app_main.cpp文件中:
 
 
[cpp]  view plain copy
  1. int main(int argc, const charconst argv[])  
  2. {  
  3.     ......  
  4.   
  5.     AppRuntime runtime;  
  6.       
  7.     ......  
  8. }  
        而AppRuntime类继续了AndroidRuntime类,它也是定义在frameworks/base/cmds/app_process/app_main.cpp文件中:
[cpp]  view plain copy
  1. class AppRuntime : public AndroidRuntime  
  2. {  
  3.     ......  
  4.   
  5. };  
        因此,在前面的com_android_internal_os_RuntimeInit_zygoteInit函数,实际是执行了AppRuntime类的onZygoteInit函数。
 




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

目录
相关文章
|
14天前
|
弹性计算 运维 监控
基于进程热点分析与系统资源优化的智能运维实践
智能服务器管理平台提供直观的可视化界面,助力高效操作系统管理。核心功能包括运维监控、智能助手和扩展插件管理,支持系统健康监控、故障诊断等,确保集群稳定运行。首次使用需激活服务并安装管控组件。平台还提供进程热点追踪、性能观测与优化建议,帮助开发人员快速识别和解决性能瓶颈。定期分析和多维度监控可提前预警潜在问题,保障系统长期稳定运行。
55 17
|
3月前
|
调度 开发者
核心概念解析:进程与线程的对比分析
在操作系统和计算机编程领域,进程和线程是两个基本而核心的概念。它们是程序执行和资源管理的基础,但它们之间存在显著的差异。本文将深入探讨进程与线程的区别,并分析它们在现代软件开发中的应用和重要性。
120 4
|
4月前
|
运维 JavaScript jenkins
鸿蒙5.0版开发:分析CppCrash(进程崩溃)
在HarmonyOS 5.0中,CppCrash指C/C++运行时崩溃,常见原因包括空指针、数组越界等。系统提供基于posix信号机制的异常检测能力,生成详细日志辅助定位。本文详解CppCrash分析方法,涵盖异常检测、问题定位思路及案例分析。
144 4
|
4月前
|
运维 监控 JavaScript
鸿蒙next版开发:分析JS Crash(进程崩溃)
在HarmonyOS 5.0中,JS Crash指未处理的JavaScript异常导致应用意外退出。本文详细介绍如何分析JS Crash,包括异常捕获、日志分析和典型案例,帮助开发者定位问题、修复错误,提升应用稳定性。通过DevEco Studio收集日志,结合HiChecker工具,有效解决JS Crash问题。
164 4
|
5月前
|
Java API Android开发
安卓应用程序开发的新手指南:从零开始构建你的第一个应用
【10月更文挑战第20天】在这个数字技术不断进步的时代,掌握移动应用开发技能无疑打开了一扇通往创新世界的大门。对于初学者来说,了解并学习如何从无到有构建一个安卓应用是至关重要的第一步。本文将为你提供一份详尽的入门指南,帮助你理解安卓开发的基础知识,并通过实际示例引导你完成第一个简单的应用项目。无论你是编程新手还是希望扩展你的技能集,这份指南都将是你宝贵的资源。
217 5
|
5月前
|
NoSQL Linux 程序员
进程管理与运行分析
进程管理与运行分析
42 0
|
6月前
|
并行计算 API 调度
探索Python中的并发编程:线程与进程的对比分析
【9月更文挑战第21天】本文深入探讨了Python中并发编程的核心概念,通过直观的代码示例和清晰的逻辑推理,引导读者理解线程与进程在解决并发问题时的不同应用场景。我们将从基础理论出发,逐步过渡到实际案例分析,旨在揭示Python并发模型的内在机制,并比较它们在执行效率、资源占用和适用场景方面的差异。文章不仅适合初学者构建并发编程的基础认识,同时也为有经验的开发者提供深度思考的视角。
|
19天前
|
Linux Shell
Linux 进程前台后台切换与作业控制
进程前台/后台切换及作业控制简介: 在 Shell 中,启动的程序默认为前台进程,会占用终端直到执行完毕。例如,执行 `./shella.sh` 时,终端会被占用。为避免不便,可将命令放到后台运行,如 `./shella.sh &`,此时终端命令行立即返回,可继续输入其他命令。 常用作业控制命令: - `fg %1`:将后台作业切换到前台。 - `Ctrl + Z`:暂停前台作业并放到后台。 - `bg %1`:让暂停的后台作业继续执行。 - `kill %1`:终止后台作业。 优先级调整:
35 5
|
8月前
|
运维 关系型数据库 MySQL
掌握taskset:优化你的Linux进程,提升系统性能
在多核处理器成为现代计算标准的今天,运维人员和性能调优人员面临着如何有效利用这些处理能力的挑战。优化进程运行的位置不仅可以提高性能,还能更好地管理和分配系统资源。 其中,taskset命令是一个强大的工具,它允许管理员将进程绑定到特定的CPU核心,减少上下文切换的开销,从而提升整体效率。
掌握taskset:优化你的Linux进程,提升系统性能
|
8月前
|
弹性计算 Linux 区块链
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
255 4
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)

热门文章

最新文章

相关实验场景

更多