一般进程fork出子进程之后,会继续调用系统的exec,将一个新的可执行文件的内容替换当前的进程的代码段,数据段,堆和栈段,然后zogte只调用的了fork,没有调用exec,这是因为Android中执行的是java代码,java代码所执行的环境要求是一样的,就是虚拟机
这也是Zygote进程初始化时会创建虚拟机,同时把需要的系统类库和资源文件加载到内存,当他fork出子进程的时候 子进程也集成了能正常工作的虚拟机和各种资源文件,然后子进程把apk文件的字节码装载进去运行就行了,app的启动时间会少很多 Zgotevmresorcelib…————————————————————
Childvmresorcelib…APK字节码跟继承类似,子进程拥有父进程的资源
前篇博客有说到,init进程运行的时候会加载init.rc,根据里面的配置来fork一些进程等,有兴趣的童鞋可以去翻,里面分为两种类型,action 和 service Zygote进程就是以service的方式启动的,在5.0系统中,zygote的启动发生了一些变化,以前是直接写在init.rc的代码块中的,现在则通过import的方式引用过来了
import /init.${ro.zygote}.rc上面可以看到,init.rc并不是直接引用哪个固定的文件,而是根据ro.zyote的内容来引入不同的文件。这个主要是因为从5.0开始Android开始支持64位的编译(喜大普奔),所以zygote也会有32和64位版本的区别,在init.rc同一目录下,有这么四个文件
init.zygote32_64.rc init.zygote32.rc init.zygote64_32.rc init.zygote64.rc从这里看出 android支持四种运行模式, 纯32位,纯64位,32为主、64为辅,64为主,32为辅
上面的代码有过敲命令行的童鞋应该了解怎么回事了,他执行的是app_process32 sencondary执行的是64位的,这就好理解了。
app_process位于frameworks/base/cmds/app_process/app_main.cpp main函数如下,代码有些长,不过自己加了一点关键性的注释,希望能耐着性子看一下
static const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist32"; static const char ZYGOTE_NICE_NAME[] = "zygote"; int main(int argc, char* const argv[]) { ...... AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv)); // Process command line arguments // ignore argv[0] argc--; argv++; // Everything up to '--' or first non '-' arg goes to the vm. // // The first argument after the VM args is the "parent dir", which // is currently unused. // // After the parent dir, we expect one or more the following internal // arguments : // // --zygote : Start in zygote mode // --start-system-server : Start the system server. // --application : Start in application (stand alone, non zygote) mode. // --nice-name : The nice name for this process. // // For non zygote starts, these arguments will be followed by // the main class name. All remaining arguments are passed to // the main method of this class. // // For zygote starts, all remaining arguments are passed to the zygote. // main function. // // Note that we must copy argument string values since we will rewrite the // entire argument block when we apply the nice name to argv0. int i; for (i = 0; i < argc; i++) { if (argv[i][0] != '-') { break; } if (argv[i][1] == '-' && argv[i][2] == 0) { ++i; // Skip --. break; } runtime.addOption(strdup(argv[i])); } // Parse runtime arguments. Stop at first unrecognized option. bool zygote = false; bool startSystemServer = false; bool application = false; String8 niceName; String8 className; ++i; // Skip unused "parent dir" argument. while (i < argc) { const char* arg = argv[i++]; if (strcmp(arg, "--zygote") == 0) { zygote = true; niceName = ZYGOTE_NICE_NAME;//"zygote" } else if (strcmp(arg, "--start-system-server") == 0) { startSystemServer = true; } else if (strcmp(arg, "--application") == 0) { ...... } else if (strncmp(arg, "--nice-name=", 12) == 0) { ...... } else if (strncmp(arg, "--", 2) != 0) { ...... } else { --i; break; } } Vector<String8> args;//该参数接下来要传入AndroidRuntime.start函数 if (!className.isEmpty()) { ...... } else { // We're in zygote mode. maybeCreateDalvikCache(); if (startSystemServer) { args.add(String8("start-system-server")); } char prop[PROP_VALUE_MAX]; if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) { LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.", ABI_LIST_PROPERTY); return 11; } String8 abiFlag("--abi-list="); abiFlag.append(prop);//"--abi-list=ro.product.cpu.abilist32" args.add(abiFlag); // In zygote mode, pass all remaining arguments to the zygote // main() method. for (; i < argc; ++i) { args.add(String8(argv[i])); } } if (!niceName.isEmpty()) { runtime.setArgv0(niceName.string()); set_process_name(niceName.string());//将进程名修改成"zygote" } if (zygote) { runtime.start("com.android.internal.os.ZygoteInit", args); } else if (className) { runtime.start("com.android.internal.os.RuntimeInit", args); } else { ...... } }这个函数的主要功能就是:
解析init.rc里面的参数传到AndroidRuntime里面修改进程的名字为zygote,调用AndroidRuntime的start函数; /** AppRuntime 是内部类,继承AndroidRuntime **/ class AppRuntime : public AndroidRuntime { public: AppRuntime(char* argBlockStart, const size_t argBlockLength) : AndroidRuntime(argBlockStart, argBlockLength) , mClass(NULL) { }AppRuntime是一个内部类,就在app_main里面,继承了AndroidRuntime ,它位于 \frameworks\base\core\jni\AndroidRuntime.cpp文件中
static AndroidRuntime* gCurRuntime = NULL; AndroidRuntime::AndroidRuntime(char* argBlockStart, const size_t argBlockLength) : mExitWithoutCleanup(false), mArgBlockStart(argBlockStart), mArgBlockLength(argBlockLength) { SkGraphics::Init(); // There is also a global font cache, but its budget is specified in code // see SkFontHost_android.cpp // Pre-allocate enough space to hold a fair number of options. mOptions.setCapacity(20); assert(gCurRuntime == NULL); // one per process gCurRuntime = this; }这个gCurRuntime静态变量指向它本身,下面有个这样的方法
AndroidRuntime* AndroidRuntime::getRuntime() { return gCurRuntime; }接下来就该执行start方法了 如下:
/* * Start the Android runtime. This involves starting the virtual machine * and calling the "static void main(String[] args)" method in the class * named by "className". * * Passes the main function two arguments, the class name and the specified * options string. */ //这里的className为"com.android.internal.os.ZygoteInit" void AndroidRuntime::start(const char* className, const Vector<String8>& options) { ALOGD(">>>>>> START %s uid %d <<<<<<\n", className != NULL ? className : "(unknown)", getuid()); static const String8 startSystemServer("start-system-server"); /* * 'startSystemServer == true' means runtime is obsolete and not run from * init.rc anymore, so we print out the boot start event here. */ for (size_t i = 0; i < options.size(); ++i) { if (options[i] == startSystemServer) { /* track our progress through the boot sequence */ const int LOG_BOOT_PROGRESS_START = 3000; LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START, ns2ms(systemTime(SYSTEM_TIME_MONOTONIC))); } } //这里将rootDir的目录设置为/system,ANDROID_ROOT为/system const char* rootDir = getenv("ANDROID_ROOT"); if (rootDir == NULL) { rootDir = "/system"; if (!hasDir("/system")) { LOG_FATAL("No root directory specified, and /android does not exist."); return; } setenv("ANDROID_ROOT", rootDir, 1); } //const char* kernelHack = getenv("LD_ASSUME_KERNEL"); //ALOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack); /* start the virtual machine */ JniInvocation jni_invocation; jni_invocation.Init(NULL); JNIEnv* env; if (startVm(&mJavaVM, &env) != 0) {在这里打开了java虚拟机 return; } onVmCreated(env); /* * Register android functions. */ if (startReg(env) < 0) { //在这个不经意的一行代码中,注册了jni函数,原话是这样的Register android native functions with the VM. ALOGE("Unable to register all android natives\n"); return; } /* * We want to call main() with a String array with arguments in it. * At present we have two arguments, the class name and an option string. * Create an array to hold them. */ jclass stringClass; jobjectArray strArray; jstring classNameStr; stringClass = env->FindClass("java/lang/String"); assert(stringClass != NULL); strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL); assert(strArray != NULL); classNameStr = env->NewStringUTF(className); assert(classNameStr != NULL); env->SetObjectArrayElement(strArray, 0, classNameStr); for (size_t i = 0; i < options.size(); ++i) { jstring optionsStr = env->NewStringUTF(options.itemAt(i).string()); assert(optionsStr != NULL); env->SetObjectArrayElement(strArray, i + 1, optionsStr); } /* * Start VM. This thread becomes the main thread of the VM, and will * not return until the VM exits. */ char* slashClassName = toSlashClassName(className); jclass startClass = env->FindClass(slashClassName); if (startClass == NULL) { ALOGE("JavaVM unable to locate class '%s'\n", slashClassName); /* keep going */ } else { //获取"com.android.internal.os.ZygoteInit"类main函数 jmethodID startMeth = env->GetStaticMethodID(startClass, "main", "([Ljava/lang/String;)V"); if (startMeth == NULL) { ALOGE("JavaVM unable to find main() in '%s'\n", className); /* keep going */ } else { //运行ZygoteInit的main函数 env->CallStaticVoidMethod(startClass, startMeth, strArray); #if 0 if (env->ExceptionCheck()) threadExitUncaughtException(env); #endif } } free(slashClassName); ALOGD("Shutting down VM\n"); if (mJavaVM->DetachCurrentThread() != JNI_OK) ALOGW("Warning: unable to detach main thread\n"); if (mJavaVM->DestroyJavaVM() != 0) ALOGW("Warning: VM did not shut down cleanly\n"); }综上所述 AndroidRuntime.start函数主要做了三个工作:
启动虚拟机 调用AndroidRuntime.startVm启动虚拟机
注册jni函数 调用AndroidRuntime.startReg注册jni函数
调用ZygoteInit.main函数
下面咱们跑到ZygoteInit.java 下面 (我的天,终于跑到java上面去了,累死了) 目录:\frameworks\base\core\Java\com\android\internal\os\ZygoteInit.java
public static void main(String argv[]) { try { // Start profiling the zygote initialization. SamplingProfilerIntegration.start(); boolean startSystemServer = false; String socketName = "zygote"; String abiList = null; //解析调用的参数 for (int i = 1; i < argv.length; i++) { if ("start-system-server".equals(argv[i])) { startSystemServer = true; } else if (argv[i].startsWith(ABI_LIST_ARG)) { abiList = argv[i].substring(ABI_LIST_ARG.length()); } else if (argv[i].startsWith(SOCKET_NAME_ARG)) { socketName = argv[i].substring(SOCKET_NAME_ARG.length()); } else { throw new RuntimeException("Unknown command line argument: " + argv[i]); } } if (abiList == null) { throw new RuntimeException("No ABI list supplied."); } //注册Zygote的Socket监听端口,用来接收应用程序启动的消息 registerZygoteSocket(socketName); EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START, SystemClock.uptimeMillis()); //装载系统资源 preload(); EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END, SystemClock.uptimeMillis()); // Finish profiling the zygote initialization. SamplingProfilerIntegration.writeZygoteSnapshot(); // Do an initial gc to clean up after startup gc(); // Disable tracing so that forked processes do not inherit stale tracing tags from // Zygote. Trace.setTracingEnabled(false); //启动SystemServer进程 if (startSystemServer) { startSystemServer(abiList, socketName); } Log.i(TAG, "Accepting command socket connections"); //进入监听和接收消息的循环 runSelectLoop(abiList); closeServerSocket(); } catch (MethodAndArgsCaller caller) { caller.run(); } catch (RuntimeException ex) { Log.e(TAG, "Zygote died with exception", ex); closeServerSocket(); throw ex; } }ZygoteInit.main主要做了三项工作:
调用registerZygoteSocket,注册zygote的socket。调用startSystemServer,启动SystemServer。调用runSelectLoop,zygote无限循环等待创建进程的请求咱来一个个的分析 。。 首先是socket,registerZygoteSocket是ZygoteInit的一个方法
/** * Registers a server socket for zygote command connections * * @throws RuntimeException when open fails */ private static void registerZygoteSocket(String socketName) { if (sServerSocket == null) { int fileDesc; final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName; try { String env = System.getenv(fullSocketName); fileDesc = Integer.parseInt(env); } catch (RuntimeException ex) { throw new RuntimeException(fullSocketName + " unset or invalid", ex); } try { sServerSocket = new LocalServerSocket( createFileDescriptor(fileDesc)); } catch (IOException ex) { throw new RuntimeException( "Error binding to local socket '" + fileDesc + "'", ex); } } }这里根据zygote的socket的文件描述符创建了LocalServerSocket对象并保存在zygoteInit的类型LocalServerSocket的静态成员变量sServerSocket中,若又想反过来获得zygote的socket的文件描述符,只要调用LocalServerSocket.getFileDescriptor即可。具体的细节不去深入的分析了,有点复杂,有兴趣的童鞋可以自己去网上查找一些资料。
然后是调用startSystemServer
/** * Prepare the arguments and fork for the system server process. */ private static boolean startSystemServer(String abiList, String socketName) throws MethodAndArgsCaller, RuntimeException { long capabilities = posixCapabilitiesAsBits( OsConstants.CAP_BLOCK_SUSPEND, OsConstants.CAP_KILL, OsConstants.CAP_NET_ADMIN, OsConstants.CAP_NET_BIND_SERVICE, OsConstants.CAP_NET_BROADCAST, OsConstants.CAP_NET_RAW, OsConstants.CAP_SYS_MODULE, OsConstants.CAP_SYS_NICE, OsConstants.CAP_SYS_RESOURCE, OsConstants.CAP_SYS_TIME, OsConstants.CAP_SYS_TTY_CONFIG ); /* Hardcoded command line to start the system server */ String args[] = { "--setuid=1000", "--setgid=1000", "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1032,3001,3002,3003,3006,3007", "--capabilities=" + capabilities + "," + capabilities, "--runtime-init", "--nice-name=system_server", "com.android.server.SystemServer", }; ZygoteConnection.Arguments parsedArgs = null; int pid; try { parsedArgs = new ZygoteConnection.Arguments(args); ZygoteConnection.applyDebuggerSystemProperty(parsedArgs); ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs); /* Request to fork the system server process */ //对zygote进程进行fork,得到的子进程就是SystemServer进程,返回的子进程pid为0 pid = Zygote.forkSystemServer( parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.debugFlags, null, parsedArgs.permittedCapabilities, parsedArgs.effectiveCapabilities); } catch (IllegalArgumentException ex) { throw new RuntimeException(ex); } /* For child process */ if (pid == 0) { if (hasSecondZygote(abiList)) { waitForSecondaryZygote(socketName); } handleSystemServerProcess(parsedArgs); } return true; }这边就比较有意思了,开头说了 SystemServer也是安卓世界中非常重要的一部分。 同过fork,来fork出SystemServer进程,代码首先通过ZygoteConnection来解析出将来创建SystemServer进程时所需的参数。除了能够解析参数外,ZygoteConnection另外一个功能就是记录zygote的socket套接字连接。
在创建好SysteServer进程后,在SystemServer进程中调用handleSystemServerProcess处理,处理时会调用RuntimeInit的zygoteInit方法
/** * Main entry point for runtime initialization. Not for * public consumption. * @hide */ public class RuntimeInit { ...... /** * The main function called when started through the zygote process. This * could be unified with main(), if the native code in nativeFinishInit() * were rationalized with Zygote startup.<p> * @param targetSdkVersion target SDK version * @param argv arg strings */ public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) throws ZygoteInit.MethodAndArgsCaller { if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote"); redirectLogStreams(); commonInit();//常规的初始化 nativeZygoteInit();//bind通信机制的准备工作 applicationInit(targetSdkVersion, argv, classLoader); } ...... private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) throws ZygoteInit.MethodAndArgsCaller { // If the application calls System.exit(), terminate the process // immediately without running any shutdown hooks. It is not possible to // shutdown an Android application gracefully. Among other things, the // Android runtime shutdown hooks close the Binder driver, which can cause // leftover running threads to crash before the process actually exits. nativeSetExitWithoutCleanup(true); // We want to be fairly aggressive about heap utilization, to avoid // holding on to a lot of memory that isn't needed. VMRuntime.getRuntime().setTargetHeapUtilization(0.75f); VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion); final Arguments args; try { args = new Arguments(argv); } catch (IllegalArgumentException ex) { Slog.e(TAG, ex.getMessage()); // let the process exit return; } // Remaining arguments are passed to the start class's static main invokeStaticMain(args.startClass, args.startArgs, classLoader);//args.startClass为"com.android.server.SystemServer" } }为了大家方便我就把两段代码放一起了,最后发现,调用invokeStaticMain执行了SystemServer.main ,SystemServer就启动完成, 然后执行ZygoteInit.runSelectLoop函数
/** * Runs the zygote process's select loop. Accepts new connections as * they happen, and reads commands from connections one spawn-request's * worth at a time. * * @throws MethodAndArgsCaller in a child process when a main() should * be executed. */ private static void runSelectLoop(String abiList) throws MethodAndArgsCaller { ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>(); ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>(); FileDescriptor[] fdArray = new FileDescriptor[4]; fds.add(sServerSocket.getFileDescriptor()); peers.add(null); int loopCount = GC_LOOP_COUNT; while (true) { int index; /* * Call gc() before we block in select(). * It's work that has to be done anyway, and it's better * to avoid making every child do it. It will also * madvise() any free memory as a side-effect. * * Don't call it every time, because walking the entire * heap is a lot of overhead to free a few hundred bytes. */ if (loopCount <= 0) { gc(); loopCount = GC_LOOP_COUNT; } else { loopCount--; } try { fdArray = fds.toArray(fdArray); //selectReadable是一个native函数,内部调用select等待客户端连接,客户端连接上之后就会返回。 //返回值: //<0: 内部发生错误 //=0: 该客户端第一次连接到服务端 //>0: 客户端与服务端已经建立连接,并开始发送数据 index = selectReadable(fdArray); } catch (IOException ex) { throw new RuntimeException("Error in select()", ex); } if (index < 0) { throw new RuntimeException("Error in select()"); } else if (index == 0) {//客户端第一次请求服务端,服务端调用accept与客户端建立连接。客户端在zygote中以ZygoteConnection对象表示。 ZygoteConnection newPeer = acceptCommandPeer(abiList); peers.add(newPeer); fds.add(newPeer.getFileDescriptor()); } else {//返回>0,表明发送数据的客户端的index,peers.get(index)取得发送数据客户端的ZygoteConnection对象,之后调用runOnce 函数处理具体的请求。 boolean done; done = peers.get(index).runOnce(); //请求处理完成之后,移除与该客户端的连接 if (done) { peers.remove(index); fds.remove(index); } } } }runSelectLoop函数的逻辑比较简单,主要有两点: 1、 处理客户端的连接和请求。其中客户端在zygote进程中使用ZygoteConnection对象表示。 2、 客户的请求有ZygoteConnection的runOnce来处理。
接下来会分析Zygote如何启动应用程序,希望大家持续关注,你们的关注就是我前进的动力,有什么不足的地方,大家可以直接在我评论里说出,谢谢。