copy from : http://gityuan.com/2016/03/26/app-process-create/
基于AndroID 6.0的源码剖析, 分析AndroID进程是如何一步步创建的,本文涉及到的源码:
/frameworks/base/core/java/com/androID/internal/os/ - ZygoteInit.java - ZygoteConnection.java - RuntimeInit.java - Zygote.java/frameworks/base/core/java/androID/os/Process.java/frameworks/base/core/jni/com_androID_internal_os_Zygote.cpp/frameworks/base/core/jni/AndroIDRuntime.cpp/frameworks/base/cmds/app_process/App_main.cpp (内含AppRuntime类)/bionic/libc/bionic/fork.cpp/bionic/libc/bionic/pthread_atfork.cpp/libcore/dalvik/src/main/java/dalvik/system/ZygoteHooks.java/art/runtime/native/dalvik_system_ZygoteHooks.cc/art/runtime/Runtime.cc/art/runtime/Thread.cc/art/runtime/signal_catcher.cc
一. 概述准备知识本文要介绍的是进程的创建,先简单说说进程与线程的区别。
进程:每个App
在启动前必须先创建一个进程,该进程是由Zygote
fork出来的,进程具有独立的资源空间,用于承载App上运行的各种Activity/Service等组件。进程对于上层应用来说是完全透明的,这也是Google有意为之,让App程序都是运行在AndroID Runtime。大多数情况一个App
就运行在一个进程中,除非在AndroIDManifest.xml中配置AndroID:process
属性,或通过native代码fork进程。
线程:线程对应用开发者来说非常熟悉,比如每次new Thread().start()
都会创建一个新的线程,该线程并没有自己独立的地址空间,而是与其所在进程之间资源共享。从linux角度来说进程与线程都是一个task_struct结构体,除了是否共享资源外,并没有其他本质的区别。
在接下来的文章,会涉及到system_server进程和Zygote进程,下面简要这两个进程:
system_server
进程:是用于管理整个Java framework层,包含ActivityManager,PowerManager等各种系统服务;Zygote
进程:是AndroID系统的首个Java进程,Zygote是所有Java进程的父进程,包括 system_server
进程以及所有的App进程都是Zygote的子进程,注意这里说的是子进程,而非子线程。如果想更进一步了解system_server进程和Zygote进程在整个AndroID系统所处的地位,可查看我的另一个文章Android系统-开篇。
进程创建图对于大多数的应用开发者来说创建线程比较熟悉,而对于创建进程并没有太多的概念。对于系统工程师或者高级开发者,还是有很必要了解AndroID系统是如何一步步地创建出一个进程的。先来看一张进程创建过程的简要图:
图解:
App发起进程:当从桌面启动应用,则发起进程便是Launcher所在进程;当从某App内启动远程进程,则发送进程便是该App所在进程。发起进程先通过binder发送消息给system_server进程;system_server进程:调用Process.start()方法,通过socket向zygote进程发送创建新进程的请求;zygote进程:在执行ZygoteInit.main()
后便进入runSelectLoop()
循环体内,当有客户端连接时便会执行ZygoteConnection.runOnce()方法,再经过层层调用后fork出新的应用进程;新进程:执行handleChildProc方法,最后调用ActivityThread.main()方法。接下来,依次从system_server进程发起请求
到Zygote创建进程
,再到新进程的运行
这3大块展开讲解进程创建是一个怎样的过程。
[-> Process.java]
public static final ProcessstartResult start(final String processClass, final String nicename, int uID, int gID, int[] gIDs, int deBUGFlags, int mountExternal, int targetSdkVersion, String seInfo, String abi, String instructionSet, String appDataDir, String[] zygoteArgs) { try { //【见小节2】 return startViaZygote(processClass, nicename, uID, gID, gIDs, deBUGFlags, mountExternal, targetSdkVersion, seInfo, abi, instructionSet, appDataDir, zygoteArgs); } catch (ZygoteStartFailedEx ex) { throw new RuntimeException(""); }}
2. startViaZygote[-> Process.java]
private static ProcessstartResult startViaZygote(final String processClass, final String nicename, final int uID, final int gID, final int[] gIDs, int deBUGFlags, int mountExternal, int targetSdkVersion, String seInfo, String abi, String instructionSet, String appDataDir, String[] extraArgs) throws ZygoteStartFailedEx { synchronized(Process.class) { ArrayList<String> argsForZygote = new ArrayList<String>(); argsForZygote.add("--runtime-args"); argsForZygote.add("--setuID=" + uID); argsForZygote.add("--setgID=" + gID); argsForZygote.add("--target-sdk-version=" + targetSdkVersion); if (nicename != null) { argsForZygote.add("--nice-name=" + nicename); } if (appDataDir != null) { argsForZygote.add("--app-data-dir=" + appDataDir); } argsForZygote.add(processClass); if (extraArgs != null) { for (String arg : extraArgs) { argsForZygote.add(arg); } } //【见小节3】 return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote); }}
该过程主要工作是生成argsForZygote
数组,该数组保存了进程的uID、gID、groups、target-sdk、nice-name等一系列的参数。
[-> Process.java]
private static ProcessstartResult zygoteSendArgsAndGetResult( ZygoteState zygoteState, ArrayList<String> args) throws ZygoteStartFailedEx { try { //其中zygoteState 【见小节3.1】 final BuffereDWriter writer = zygoteState.writer; final DatainputStream inputStream = zygoteState.inputStream; writer.write(Integer.toString(args.size())); writer.newline(); int sz = args.size(); for (int i = 0; i < sz; i++) { String arg = args.get(i); if (arg.indexOf('\n') >= 0) { throw new ZygoteStartFailedEx( "embedded newlines not allowed"); } writer.write(arg); writer.newline(); } writer.flush(); ProcessstartResult result = new ProcessstartResult(); //等待socket服务端(即zygote)返回新创建的进程pID; //对于等待时长问题,Google正在考虑此处是否应该有一个timeout,但目前是没有的。 result.pID = inputStream.readInt(); if (result.pID < 0) { throw new ZygoteStartFailedEx("fork() Failed"); } result.usingWrapper = inputStream.readBoolean(); return result; } catch (IOException ex) { zygoteState.close(); throw new ZygoteStartFailedEx(ex); }}
这个方法的主要功能是通过socket通道向Zygote进程发送一个参数列表,然后进入阻塞等待状态,直到远端的socket服务端发送回来新创建的进程pID才返回。
3.1 openZygoteSocketIfNeededprivate static ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx { if (primaryZygoteState == null || primaryZygoteState.isClosed()) { try { //向主zygote发起connect() *** 作 primaryZygoteState = ZygoteState.connect(ZYGOTE_SOCKET); } catch (IOException ioe) { ... } } if (primaryZygoteState.matches(abi)) { return primaryZygoteState; } if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) { //当主zygote没能匹配成功,则采用第二个zygote,发起connect() *** 作 secondaryZygoteState = ZygoteState.connect(SECONDARY_ZYGOTE_SOCKET); } if (secondaryZygoteState.matches(abi)) { return secondaryZygoteState; } ...}
openZygoteSocketIfNeeded(abi)
方法是根据当前的abi来选择与zygote还是zygote64来进行通信。
既然system_server进程的zygoteSendArgsAndGetResult()方法通过socket向Zygote进程发送消息,这是便会唤醒Zygote进程,来响应socket客户端的请求(即system_server端),接下来的 *** 作便是在Zygote来创建进程【见小节4】
三. Zygote创建进程文章Android系统启动-zygote篇已介绍,简单来说就是Zygote进程是由由init进程而创建的,进程启动之后调用ZygoteInit.main()方法,经过创建socket管道,预加载资源后,便进程runSelectLoop()方法。
4. ZygoteInit.main[–>ZygoteInit.java]
public static voID main(String argv[]) { try { runSelectLoop(abiList); //【见小节5】 .... } catch (MethodAndArgsCaller caller) { caller.run(); //【见小节16】 } catch (RuntimeException ex) { closeServerSocket(); throw ex; }}
后续会讲到runSelectLoop()方法会抛出异常MethodAndArgsCaller
,从而进入caller.run()方法。
[-> ZygoteInit.java]
private static voID runSelectLoop(String abiList) throws MethodAndArgsCaller { ArrayList<fileDescriptor> fds = new ArrayList<fileDescriptor>(); ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>(); //sServerSocket是socket通信中的服务端,即zygote进程。保存到fds[0] fds.add(sServerSocket.getfileDescriptor()); peers.add(null); while (true) { StructPollfd[] pollFds = new StructPollfd[fds.size()]; for (int i = 0; i < pollFds.length; ++i) { pollFds[i] = new StructPollfd(); pollFds[i].fd = fds.get(i); pollFds[i].events = (short) PolliN; } try { //处理轮询状态,当pollFds有事件到来则往下执行,否则阻塞在这里 Os.poll(pollFds, -1); } catch (ErrnoException ex) { ... } for (int i = pollFds.length - 1; i >= 0; --i) { //采用I/O多路复用机制,当接收到客户端发出连接请求 或者数据处理请求到来,则往下执行; // 否则进入continue,跳出本次循环。 if ((pollFds[i].revents & PolliN) == 0) { continue; } if (i == 0) { //即fds[0],代表的是sServerSocket,则意味着有客户端连接请求; // 则创建ZygoteConnection对象,并添加到fds。//【见小节5.1】 ZygoteConnection newPeer = acceptCommandPeer(abiList); peers.add(newPeer); fds.add(newPeer.getfileDesciptor()); //添加到fds. } else { //i>0,则代表通过socket接收来自对端的数据,并执行相应 *** 作【见小节6】 boolean done = peers.get(i).runOnce(); if (done) { peers.remove(i); fds.remove(i); //处理完则从fds中移除该文件描述符 } } } }}
该方法主要功能:
客户端通过openZygoteSocketIfNeeded()来跟zygote进程建立连接。zygote进程收到客户端连接请求后执行accept();然后再创建ZygoteConnection对象,并添加到fds数组列表;建立连接之后,可以跟客户端通信,进入runOnce()方法来接收客户端数据,并执行进程创建工作。5.1 acceptCommandPeer[-> ZygoteInit.java]
private static ZygoteConnection acceptCommandPeer(String abiList) { try { return new ZygoteConnection(sServerSocket.accept(), abiList); } catch (IOException ex) { ... }}
接收客户端发送过来的connect() *** 作,Zygote作为服务端执行accept() *** 作。 再后面客户端调用write()写数据,Zygote进程调用read()读数据。
没有连接请求时会进入休眠状态,当有创建新进程的连接请求时,唤醒Zygote进程,创建Socket通道ZygoteConnection,然后执行ZygoteConnection的runOnce()方法。
6. runOnce[-> ZygoteConnection.java]
boolean runOnce() throws ZygoteInit.MethodAndArgsCaller { String args[]; Arguments parsedArgs = null; fileDescriptor[] descriptors; try { //读取socket客户端发送过来的参数列表 args = readArgumentList(); descriptors = mSocket.getAncillaryfileDescriptors(); } catch (IOException ex) { closeSocket(); return true; } PrintStream newStderr = null; if (descriptors != null && descriptors.length >= 3) { newStderr = new PrintStream(new fileOutputStream(descriptors[2])); } int pID = -1; fileDescriptor childPipeFd = null; fileDescriptor serverPipeFd = null; try { //将binder客户端传递过来的参数,解析成Arguments对象格式 parsedArgs = new Arguments(args); ... int [] fdsToClose = { -1, -1 }; fileDescriptor fd = mSocket.getfileDescriptor(); if (fd != null) { fdsToClose[0] = fd.getInt$(); } fd = ZygoteInit.getServerSocketfileDescriptor(); if (fd != null) { fdsToClose[1] = fd.getInt$(); } fd = null; //【见小节7】 pID = Zygote.forkAndSpecialize(parsedArgs.uID, parsedArgs.gID, parsedArgs.gIDs, parsedArgs.deBUGFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo, parsedArgs.nicename, fdsToClose, parsedArgs.instructionSet, parsedArgs.appDataDir); } catch (Exception e) { ... } try { if (pID == 0) { //子进程执行 IoUtils.closeQuIEtly(serverPipeFd); serverPipeFd = null; //【见小节13】 handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr); // 不应到达此处,子进程预期的是抛出异常ZygoteInit.MethodAndArgsCaller或者执行exec(). return true; } else { //父进程执行 IoUtils.closeQuIEtly(childPipeFd); childPipeFd = null; return handleParentProc(pID, descriptors, serverPipeFd, parsedArgs); } } finally { IoUtils.closeQuIEtly(childPipeFd); IoUtils.closeQuIEtly(serverPipeFd); }}
7. forkAndSpecialize[-> Zygote.java]
public static int forkAndSpecialize(int uID, int gID, int[] gIDs, int deBUGFlags, int[][] rlimits, int mountExternal, String seInfo, String nicename, int[] fdsToClose, String instructionSet, String appDataDir) { VM_HOOKS.prefork(); //【见小节8】 int pID = nativeForkAndSpecialize( uID, gID, gIDs, deBUGFlags, rlimits, mountExternal, seInfo, nicename, fdsToClose, instructionSet, appDataDir); //【见小节9】 ... VM_HOOKS.postForkCommon(); //【见小节11】 return pID;}
VM_HOOKS是Zygote对象的静态成员变量:VM_HOOKS = new ZygoteHooks();
7.1 Zygote进程先说说Zygote进程,如下图:
从图中可知Zygote进程有4个Daemon子线程分别是ReferenceQueueDaemon,FinalizerDaemon,FinalizerWatchdogDaemon,HeapTaskDaemon。图中线程名显示的并不完整是由于底层的进程结构体task_struct
是由长度为16的char型数组保存,超过15个字符便会截断。
可能有人会问zygote64进程不是还有system_server,com.androID.phone等子线程,怎么会只有4个呢?那是因为这些并不是Zygote子线程,而是Zygote的子进程。在图中用红色圈起来的是进程的VSIZE,virtual size),代表的是进程虚拟地址空间大小。线程与进程的最为本质的区别便是是否共享内存空间,图中VSIZE和Zygote进程相同的才是Zygote的子线程,否则就是Zygote的子进程。
8. preFork[-> ZygoteHooks.java]
public voID prefork() { Daemons.stop(); //停止4个Daemon子线程【见小节8.1】 waitUntilAllThreadsstopped(); //等待所有子线程结束【见小节8.2】 token = nativePrefork(); //完成gc堆的初始化工作【见小节8.3】}
8.1 Daemons.stoppublic static voID stop() { HeapTaskDaemon.INSTANCE.stop(); //Java堆整理线程 ReferenceQueueDaemon.INSTANCE.stop(); //引用队列线程 FinalizerDaemon.INSTANCE.stop(); //析构线程 FinalizerWatchdogDaemon.INSTANCE.stop(); //析构监控线程}
此处守护线程Stop方式是先调用目标线程interrrupt()方法,然后再调用目标线程join()方法,等待线程执行完成。
8.2 waitUntilAllThreadsstoppedprivate static voID waitUntilAllThreadsstopped() { file tasks = new file("/proc/self/task"); // 当/proc中线程数大于1,就出让cpu直到只有一个线程,才退出循环 while (tasks.List().length > 1) { Thread.yIEld(); }}
8.3 nativePreForknativePreFork通过JNI最终调用如下方法:
[-> dalvik_system_ZygoteHooks.cc]
static jlong ZygoteHooks_nativePreFork(jnienv* env, jclass) { Runtime* runtime = Runtime::Current(); runtime->PreZygotefork(); // 见下文 if (Trace::getmethodTracingMode() != TracingMode::kTracingInactive) { Trace::Pause(); } //将线程转换为long型并保存到token,该过程是非安全的 return reinterpret_cast<jlong>(ThreadForEnv(env));}
至于runtime->PreZygoteFork的过程:
voID Runtime::PreZygotefork() { // 堆的初始化工作。这里就不继续再往下追art虚拟机 heap_->PreZygotefork();}
VM_HOOKS.prefork()的主要功能便是停止Zygote的4个Daemon子线程的运行,等待并确保Zygote是单线程(用于提升fork效率),并等待这些线程的停止,初始化gc堆的工作, 并将线程转换为long型并保存到token
9. nativeForkAndSpecializenativeForkAndSpecialize()通过JNI最终调用调用如下方法:
[-> com_androID_internal_os_Zygote.cpp]
static jint com_androID_internal_os_Zygote_nativeForkAndSpecialize( jnienv* env, jclass, jint uID, jint gID, jintArray gIDs, jint deBUG_flags, jobjectArray rlimits, jint mount_external, Jstring se_info, Jstring se_name, jintArray fdsToClose, Jstring instructionSet, Jstring appDataDir) { // 将CAP_WAKE_ALARM赋予蓝牙进程 jlong capabilitIEs = 0; if (uID == AID_BLUetoOTH) { capabilitIEs |= (1LL << CAP_WAKE_ALARM); } //【见流程10】 return ForkAndSpecializeCommon(env, uID, gID, gIDs, deBUG_flags, rlimits, capabilitIEs, capabilitIEs, mount_external, se_info, se_name, false, fdsToClose, instructionSet, appDataDir);}
10. ForkAndSpecializeCommon[-> com_androID_internal_os_Zygote.cpp]
static pID_t ForkAndSpecializeCommon(jnienv* env, uID_t uID, gID_t gID, jintArray javaGIDs, jint deBUG_flags, jobjectArray javaRlimits, jlong permittedCapabilitIEs, jlong effectiveCapabilitIEs, jint mount_external, Jstring java_se_info, Jstring java_se_name, bool is_system_server, jintArray fdsToClose, Jstring instructionSet, Jstring dataDir) { //设置子进程的signal信号处理函数 SetSigChldHandler(); //fork子进程 【见流程10.1】 pID_t pID = fork(); if (pID == 0) { //进入子进程 DetachDescriptors(env, fdsToClose); //关闭并清除文件描述符 if (!is_system_server) { //对于非system_server子进程,则创建进程组 int rc = createProcessGroup(uID, getpID()); } SetGIDs(env, javaGIDs); //设置设置group SetRlimits(env, javaRlimits); //设置资源limit int rc = setresgid(gID, gID, gID); rc = setresuID(uID, uID, uID); SetCapabilitIEs(env, permittedCapabilitIEs, effectiveCapabilitIEs); SetSchedulerPolicy(env); //设置调度策略 //selinux上下文 rc = selinux_androID_setcontext(uID, is_system_server, se_info_c_str, se_name_c_str); if (se_info_c_str == NulL && is_system_server) { se_name_c_str = "system_server"; } if (se_info_c_str != NulL) { SetThreadname(se_name_c_str); //设置线程名为system_server,方便调试 } //在Zygote子进程中,设置信号SIGCHLD的处理器恢复为默认行为 UnsetSigChldHandler(); //等价于调用zygote.callPostForkChildHooks() 【见流程10.2】 env->CallStaticVoIDMethod(gZygoteClass, gCallPostForkChildHooks, deBUG_flags, is_system_server ? NulL : instructionSet); ... } else if (pID > 0) { //进入父进程,即Zygote进程 } return pID;}
10.1 fork()fork()采用copy on write技术,这是linux创建进程的标准方法,调用一次,返回两次,返回值有3种类型。
父进程中,fork返回新创建的子进程的pID;子进程中,fork返回0;当出现错误时,fork返回负数。(当进程数超过上限或者系统内存不足时会出错)fork()的主要工作是寻找空闲的进程号pID,然后从父进程拷贝进程信息,例如数据段和代码段,fork()后子进程要执行的代码等。 Zygote进程是所有AndroID进程的母体,包括system_server和各个App进程。zygote利用fork()方法生成新进程,对于新进程A复用Zygote进程本身的资源,再加上新进程A相关的资源,构成新的应用进程A。其中下图中Zygote进程的libc、vm、preloaded classes、preloaded resources是如何生成的,可查看另一个文章Android系统启动-zygote篇,见下图:
copy-on-write过程:当父子进程任一方修改内存数据时(这是on-write时机),才发生缺页中断,从而分配新的物理内存(这是copy *** 作)。
copy-on-write原理:写时拷贝是指子进程与父进程的页表都所指向同一个块物理内存,fork过程只拷贝父进程的页表,并标记这些页表是只读的。父子进程共用同一份物理内存,如果父子进程任一方想要修改这块物理内存,那么会触发缺页异常(page fault),linux收到该中断便会创建新的物理内存,并将两个物理内存标记设置为可写状态,从而父子进程都有各自独立的物理内存。
10.1.1 fork.cpp[-> bionic/fork.cpp]
#define FORK_FLAGS (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD)int fork() { __bionic_atfork_run_prepare(); //[见小节2.1.1] pthread_internal_t* self = __get_thread(); //fork期间,获取父进程pID,并使其缓存值无效 pID_t parent_pID = self->invalIDate_cached_pID(); //系统调用【见小节2.2】 int result = syscall(__NR_clone, FORK_FLAGS, NulL, NulL, NulL, &(self->tID)); if (result == 0) { self->set_cached_pID(gettID()); __bionic_atfork_run_child(); //fork完成执行子进程回调方法[见小节2.1.1] } else { self->set_cached_pID(parent_pID); __bionic_atfork_run_parent(); //fork完成执行父进程回调方法 } return result;}
功能说明:在执行syscall的前后都有相应的回调方法。
__bionic_atfork_run_prepare: fork完成前,父进程回调方法__bionic_atfork_run_child: fork完成后,子进程回调方法__bionic_atfork_run_paren: fork完成后,父进程回调方法以上3个方法的实现都位于bionic/pthread_atfork.cpp。如果有需要,可以扩展该回调方法,添加相关的业务需求。
10.2 Zygote.callPostForkChildHooks[-> Zygote.java]
private static voID callPostForkChildHooks(int deBUGFlags, boolean isSystemServer, String instructionSet) { //调用ZygoteHooks.postForkChild() VM_HOOKS.postForkChild(deBUGFlags, isSystemServer, instructionSet);}
[-> ZygoteHooks.java]
public voID postForkChild(int deBUGFlags, String instructionSet) { //【见流程10.3】 nativePostForkChild(token, deBUGFlags, instructionSet); Math.setRandomSeedInternal(System.currentTimeMillis());}
在这里,设置了新进程Random随机数种子为当前系统时间,也就是在进程创建的那一刻就决定了未来随机数的情况,也就是伪随机。
10.3 nativePostForkChildnativePostForkChild通过JNI最终调用调用如下方法:
[-> dalvik_system_ZygoteHooks.cc]
static voID ZygoteHooks_nativePostForkChild(jnienv* env, jclass, jlong token, jint deBUG_flags, Jstring instruction_set) { //此处token是由[小节8.3]创建的,记录着当前线程 Thread* thread = reinterpret_cast<Thread*>(token); //设置新进程的主线程ID thread->InitAfterfork(); .. if (instruction_set != nullptr) { ScopedUtfChars isa_string(env, instruction_set); InstructionSet isa = GetInstructionSetFromString(isa_string.c_str()); Runtime::NativeBrIDgeAction action = Runtime::NativeBrIDgeAction::kUnload; if (isa != kNone && isa != kRuntimeISA) { action = Runtime::NativeBrIDgeAction::kInitialize; } //【见流程10.4】 Runtime::Current()->DIDForkFromZygote(env, action, isa_string.c_str()); } else { Runtime::Current()->DIDForkFromZygote(env, Runtime::NativeBrIDgeAction::kUnload, nullptr); }}
10.4 DIDForkFromZygote[-> Runtime.cc]
voID Runtime::DIDForkFromZygote(jnienv* env, NativeBrIDgeAction action, const char* isa) { is_zygote_ = false; if (is_native_brIDge_loaded_) { switch (action) { case NativeBrIDgeAction::kUnload: UnloadNativeBrIDge(); //卸载用于跨平台的桥连库 is_native_brIDge_loaded_ = false; break; case NativeBrIDgeAction::kInitialize: InitialiZenativeBrIDge(env, isa);//初始化用于跨平台的桥连库 break; } } //创建Java堆处理的线程池 heap_->CreateThreadPool(); //重置gc性能数据,以保证进程在创建之前的GCs不会计算到当前app上。 heap_->resetGcPerformanceInfo(); if (jit_.get() == nullptr && jit_options_->UseJIT()) { //当flag被设置,并且还没有创建JIT时,则创建JIT CreateJit(); } //设置信号处理函数 StartSignalCatcher(); //启动JDWP线程,当命令deBUGer的flags指定"suspend=y"时,则暂停runtime Dbg::StartJDWp();}
关于信号处理过程,其代码位于signal_catcher.cc文件中,后续会单独讲解。
11. postForkCommon[-> ZygoteHooks.java]
public voID postForkCommon() { Daemons.start();}public static voID start() { ReferenceQueueDaemon.INSTANCE.start(); FinalizerDaemon.INSTANCE.start(); FinalizerWatchdogDaemon.INSTANCE.start(); HeapTaskDaemon.INSTANCE.start();}
VM_HOOKS.postForkCommon的主要功能是在fork新进程后,启动Zygote的4个Daemon线程,java堆整理,引用队列,以及析构线程。
12. forkAndSpecialize小结该方法主要功能:
preFork: 停止Zygote的4个Daemon子线程的运行,初始化gc堆;nativeForkAndSpecialize:调用fork()
创建新进程,设置新进程的主线程ID,重置gc性能数据,设置信号处理函数等功能。postForkCommon:启动4个Deamon子线程。其调用关系链:
Zygote.forkAndSpecialize ZygoteHooks.preFork Daemons.stop ZygoteHooks.nativePreFork dalvik_system_ZygoteHooks.ZygoteHooks_nativePreFork Runtime::PreZygoteFork heap_->PreZygotefork() Zygote.nativeForkAndSpecialize com_androID_internal_os_Zygote.ForkAndSpecializeCommon fork() Zygote.callPostForkChildHooks ZygoteHooks.postForkChild dalvik_system_ZygoteHooks.nativePostForkChild Runtime::DIDForkFromZygote ZygoteHooks.postForkCommon Daemons.start
时序图: 点击查看大图
到此App进程已完成了创建的所有工作,接下来开始新创建的App进程的工作。在前面ZygoteConnection.runOnce方法中,zygote进程执行完forkAndSpecialize()
后,新创建的App进程便进入handleChildProc()
方法,下面的 *** 作运行在App进程。
在前面[流程6]runOnce()过程中调用forkAndSpecialize()创建完新进程后,返回值pID=0(即运行在子进程)继续开始执行handleChildProc()方法。
13. handleChildProc[-> ZygoteConnection.java]
private voID handleChildProc(Arguments parsedArgs, fileDescriptor[] descriptors, fileDescriptor pipeFd, PrintStream newStderr) throws ZygoteInit.MethodAndArgsCaller { //关闭Zygote的socket两端的连接 closeSocket(); ZygoteInit.closeServerSocket(); if (descriptors != null) { try { Os.dup2(descriptors[0], STDIN_fileNO); Os.dup2(descriptors[1], STDOUT_fileNO); Os.dup2(descriptors[2], STDERR_fileNO); for (fileDescriptor fd: descriptors) { IoUtils.closeQuIEtly(fd); } newStderr = System.err; } catch (ErrnoException ex) { Log.e(TAG, "Error reopening stdio", ex); } } if (parsedArgs.nicename != null) { //设置进程名 Process.setArgV0(parsedArgs.nicename); } if (parsedArgs.invokeWith != null) { //据说这是用于检测进程内存泄露或溢出时场景而设计,后续还需要进一步分析。 WrapperInit.execApplication(parsedArgs.invokeWith, parsedArgs.nicename, parsedArgs.targetSdkVersion, vmruntime.getCurrentInstructionSet(), pipeFd, parsedArgs.remainingArgs); } else { //执行目标类的main()方法 【见流程14】 RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, null); }}
14. zygoteInit[–>RuntimeInit.java]
public static final voID zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) throws ZygoteInit.MethodAndArgsCaller { redirectLogStreams(); //重定向log输出 commonInit(); // 通用的一些初始化【见流程14.1】 nativeZygoteInit(); // zygote初始化 【见流程14.2】 applicationInit(targetSdkVersion, argv, classLoader); // 应用初始化【见流程14.3】}
14.1 commonInit[–>RuntimeInit.java]
private static final voID commonInit() { // 设置默认的未捕捉异常处理方法 Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler()); // 设置市区,中国时区为"Asia/Shanghai" TimezoneGetter.setInstance(new TimezoneGetter() { public String getID() { return SystemPropertIEs.get("persist.sys.timezone"); } }); TimeZone.setDefault(null); //重置log配置 LogManager.getLogManager().reset(); new AndroIDConfig(); // 设置默认的http User-agent格式,用于 httpURLConnection。 String userAgent = getDefaultUserAgent(); System.setProperty("http.agent", userAgent); // 设置socket的tag,用于网络流量统计 NetworkManagementSocketTagger.install();}
默认的http User-agent格式,例如:
"Dalvik/1.1.0 (linux; U; AndroID 6.0.1;LenovoX3c70 Build/LMY47V)".
14.2 nativeZygoteInitnativeZygoteInit()所对应的jni方法如下:
[–>AndroIDRuntime.cpp]
static voID com_androID_internal_os_RuntimeInit_nativeZygoteInit(jnienv* env, jobject clazz) { //此处的gCurRuntime为AppRuntime,是在AndroIDRuntime.cpp中定义的 gCurRuntime->onZygoteInit();}
14.2.1 onZygoteInit[–>app_main.cpp]
virtual voID onZygoteInit() { sp<Processstate> proc = Processstate::self(); proc->startThreadPool(); //启动新binder线程}
Processstate::self():主要工作是调用open()打开/dev/binder驱动设备,再利用mmap()映射内核的地址空间,将Binder驱动的fd赋值Processstate对象中的变量mDriverFD,用于交互 *** 作。startThreadPool()是创建一个新的binder线程,不断进行talkWithDriver().startThreadPool(): 启动Binder线程池, 详见进程的Binder线程池工作过程14.3 applicationInit[–>RuntimeInit.java]
private static voID applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) throws ZygoteInit.MethodAndArgsCaller { //true代表应用程序退出时不调用AppRuntime.onExit(),否则会在退出前调用 nativeSetExitWithoutCleanup(true); //设置虚拟机的内存利用率参数值为0.75 vmruntime.getRuntime().setTargetHeaputilization(0.75f); vmruntime.getRuntime().setTargetSdkVersion(targetSdkVersion); final Arguments args; try { args = new Arguments(argv); //解析参数 } catch (IllegalArgumentException ex) { return; } Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); //调用startClass的static方法 main() 【见流程15】 invokeStaticMain(args.startClass, args.startArgs, classLoader);}
此处args.startClass为”androID.app.ActivityThread”。
15. invokeStaticMain[–>RuntimeInit.java]
private static voID invokeStaticMain(String classname, String[] argv, ClassLoader classLoader) throws ZygoteInit.MethodAndArgsCaller { Class<?> cl = Class.forname(classname, true, classLoader); Method m = cl.getmethod("main", new Class[] { String[].class }); int modifIErs = m.getModifIErs(); ... //通过抛出异常,回到ZygoteInit.main()。这样做好处是能清空栈帧,提高栈帧利用率。【见流程16】 throw new ZygoteInit.MethodAndArgsCaller(m, argv);}
invokeStaticMain()方法中抛出的异常MethodAndArgsCaller
caller,该方法的参数m
是指main()方法, argv
是指ActivityThread. 根据前面的【流程4】中可知,下一步进入caller.run()方法,也就是MethodAndArgsCaller.run()。
[–>ZygoteInit.java]
public static class MethodAndArgsCaller extends Exception implements Runnable { public voID run() { try { //根据传递过来的参数,此处反射调用ActivityThread.main()方法【见流程17】 mMethod.invoke(null, new Object[] { mArgs }); } catch (illegalaccessexception ex) { throw new RuntimeException(ex); } catch (InvocationTargetException ex) { Throwable cause = ex.getCause(); if (cause instanceof RuntimeException) { throw (RuntimeException) cause; } else if (cause instanceof Error) { throw (Error) cause; } throw new RuntimeException(ex); } }}
到此,总算是进入到了ActivityThread类的main()方法。
17. ActivityThread.main[–> ActivityThread.java]
public static voID main(String[] args) { ... Environment.initForCurrentUser(); ... Process.setArgV0("<pre-initialized>"); //创建主线程looper Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); //attach到系统进程 thread.attach(false); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } //主线程进入循环状态 Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited");}
五. 总结Process.start()方法是阻塞 *** 作,等待直到进程创建完成并返回相应的新进程pID,才完成该方法。
当App第一次启动时或者启动远程Service,即AndroIDManifest.xml文件中定义了process:remote属性时,都需要创建进程。比如当用户点击桌面的某个App图标,桌面本身是一个app(即Launcher App),那么Launcher所在进程便是这次创建新进程的发起进程,该通过binder发送消息给system_server进程,该进程承载着整个java framework的核心服务。system_server进程从Process.start开始,执行创建进程,流程图(以进程的视角)如下:
点击查看大图
上图中,system_server
进程通过socket IPC通道向zygote
进程通信,zygote
在fork出新进程后由于fork调用一次,返回两次,即在zygote进程中调用一次,在zygote进程和子进程中各返回一次,从而能进入子进程来执行代码。该调用流程图的过程:
即流程1~3
):通过Process.start()方法发起创建新进程请求,会先收集各种新进程uID、gID、nice-name等相关的参数,然后通过socket通道发送给zygote进程;zygote进程(即流程4~12
):接收到system_server进程发送过来的参数后封装成Arguments对象,图中绿色框forkAndSpecialize()方法是进程创建过程中最为核心的一个环节(详见流程6),其具体工作是依次执行下面的3个方法:prefork():先停止Zygote的4个Daemon子线程(java堆内存整理线程、对线下引用队列线程、析构线程以及监控线程)的运行以及初始化gc堆;nativeForkAndSpecialize():调用linux的fork()出新进程,创建Java堆处理的线程池,重置gc性能数据,设置进程的信号处理函数,启动JDWP线程;postForkCommon():在启动之前被暂停的4个Daemon子线程。新进程(即流程13~15
):进入handleChildProc()方法,设置进程名,打开binder驱动,启动新的binder线程;然后设置art虚拟机参数,再反射调用目标类的main()方法,即Activity.main()方法。再之后的流程,如果是startActivity则将要进入Activity的onCreate/onStart/onResume等生命周期;如果是startService则将要进入Service的onCreate等生命周期。
system_server进程等待zygote返回进程创建完成(ZygoteConnection.handleParentProc), 一旦Zygote.forkAndSpecialize()方法执行完成, 那么分道扬镳, zygote告知system_server进程进程已创建, 而子进程继续执行后续的handleChildProc *** 作.
Tips: [小节11]RuntimeInit.java的方法nativeZygoteInit()会调用到onZygoteInit(),这个过程中有startThreadPool()创建Binder线程池。也就是说每个进程无论是否包含任何activity等组件,一定至少会包含一个Binder线程。
总结以上是内存溢出为你收集整理的理解Android进程创建流程全部内容,希望文章能够帮你解决理解Android进程创建流程所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)