首页 > 其他分享 >android u开机流程详细分析(中) - zygote

android u开机流程详细分析(中) - zygote

时间:2024-07-29 22:57:10浏览次数:20  
标签:fork process system zygote 进程 android main 详细分析

5、zygote

Zygote进程是Android中所有Java进程的父进程。Zygote进程在Init进程启动过程中被以service服务的形式启动。从android5.0开始,android开始支持64位的编译,zygote本身也就有了32位和64位的区别,所以在这里用ro.zygote属性来控制启动不同版本的zygote进程。init.rc位于/system/core/rootdir下。在这个路径下还包括四个关于zygote的rc文件。分别是Init.zygote32.rc,Init.zygote32_64.rc,Init.zygote64.rc,Init.zygote64_32.rc。由硬件决定调用哪个文件。由于现在新款手机大多只支持64位应用,以init.zygote64.rc为例,其内容如下

// /system/core/rootdir/init.zygote64.rc
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
    class main //伴随着main class的启动而启动
    priority -20
    user root
    group root readproc reserved_disk
    socket zygote stream 660 root system //创建socket
    socket usap_pool_primary stream 660 root system
    onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse
    onrestart write /sys/power/state on
    # NOTE: If the wakelock name here is changed, then also
    # update it in SystemSuspend.cpp
    onrestart write /sys/power/wake_lock zygote_kwl
    onrestart restart audioserver
    onrestart restart cameraserver
    onrestart restart media //当zygote重启时,则会重启media
    onrestart restart media.tuner
    onrestart restart netd // 当zygote重启时,则会重启netd网络管理
    onrestart restart wificond
    task_profiles ProcessCapacityHigh MaxPerformance
    critical window=${zygote.critical_window.minute:-off} target=zygote-fatal

在Init.zygote64.rc文件中,定义了两个zygote服务:zygote和zygote_secondary。由关键字service告诉init进程创建一个名为zygote的进程,这个进程的要执行的程是/system/bin/app_process64,给这个进程传递了有五个参数,分别是

  • Xzygote
    /system/bin
    –zygote
    –start-system-server
    –socket-name=zygote

zygote最初的名字是app_process,他对应的源代码是app_main(),init进程解析init.zygote64.rc配置文件之后,会调用app_process

在这里插入图片描述

5.1app_main

// /frameworks/base/cmds/app_process/app_main.cpp

int main(int argc, char* const argv[])
{
    if (!LOG_NDEBUG) {
      String8 argv_String;
      for (int i = 0; i < argc; ++i) {
        argv_String.append("\"");
        argv_String.append(argv[i]);
        argv_String.append("\" ");
      }
      ALOGV("app_process main with argv: %s", argv_String.string());
    }
    
    // 创建了android运行时环境
    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.
    //
    // As an exception to the above rule, anything in "spaced commands"
    // goes to the vm even though it has a space in it.
    const char* spaced_commands[] = { "-cp", "-classpath" };
    // Allow "spaced commands" to be succeeded by exactly 1 argument (regardless of -s).
    bool known_command = false;

    int i;
    for (i = 0; i < argc; i++) {
        if (known_command == true) {
          runtime.addOption(strdup(argv[i]));
          // The static analyzer gets upset that we don't ever free the above
          // string. Since the allocation is from main, leaking it doesn't seem
          // problematic. NOLINTNEXTLINE
          ALOGV("app_process main add known option '%s'", argv[i]);
          known_command = false;
          continue;
        }

        for (int j = 0;
             j < static_cast<int>(sizeof(spaced_commands) / sizeof(spaced_commands[0]));
             ++j) {
          if (strcmp(argv[i], spaced_commands[j]) == 0) {
            known_command = true;
            ALOGV("app_process main found known command '%s'", argv[i]);
          }
        }

        if (argv[i][0] != '-') {
            break;
        }
        if (argv[i][1] == '-' && argv[i][2] == 0) {
            ++i; // Skip --.
            break;
        }

        runtime.addOption(strdup(argv[i]));
        // The static analyzer gets upset that we don't ever free the above
        // string. Since the allocation is from main, leaking it doesn't seem
        // problematic. NOLINTNEXTLINE
        ALOGV("app_process main add option '%s'", 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;
        } else if (strcmp(arg, "--start-system-server") == 0) {
            startSystemServer = true;
        } else if (strcmp(arg, "--application") == 0) {
            application = true;
        } else if (strncmp(arg, "--nice-name=", 12) == 0) {
            niceName.setTo(arg + 12);
        } else if (strncmp(arg, "--", 2) != 0) {
            className.setTo(arg);
            break;
        } else {
            --i;
            break;
        }
    }

    Vector<String8> args;
    if (!className.isEmpty()) {
        // We're not in zygote mode, the only argument we need to pass
        // to RuntimeInit is the application argument.
        //
        // The Remainder of args get passed to startup class main(). Make
        // copies of them before we overwrite them with the process name.
        args.add(application ? String8("application") : String8("tool"));
        runtime.setClassNameAndArgs(className, argc - i, argv + i);

        if (!LOG_NDEBUG) {
          String8 restOfArgs;
          char* const* argv_new = argv + i;
          int argc_new = argc - i;
          for (int k = 0; k < argc_new; ++k) {
            restOfArgs.append("\"");
            restOfArgs.append(argv_new[k]);
            restOfArgs.append("\" ");
          }
          ALOGV("Class name = %s, args = %s", className.string(), restOfArgs.string());
        }
    } 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);
        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(), true /* setProcName */);
    }

    if (zygote) {
        //执行ZygoteInit.java的start方法
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } else if (!className.isEmpty()) {
        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
    } else {
        fprintf(stderr, "Error: no class name or --zygote supplied.\n");
        app_usage();
        LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
    }
}

5.2start()

执行到frameworks/base/core/jni/AndroidRuntime.cpp的start()方法

// /frameworks/base/core/jni/AndroidRuntime.cpp

/*
 * 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.
 */
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
    ALOGD(">>>>>> START %s uid %d <<<<<<\n",
            className != NULL ? className : "(unknown)", getuid());

    static const String8 startSystemServer("start-system-server");
    // Whether this is the primary zygote, meaning the zygote which will fork system server.
    bool primary_zygote = false;

    //根据options参数判断是否是第一次启动zygote
    /*
     * '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) {
            primary_zygote = true;
           /* 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)));
        }
    }

    //设置android root目录环境变量
    const char* rootDir = getenv("ANDROID_ROOT");
    if (rootDir == NULL) {
        rootDir = "/system";
        if (!hasDir("/system")) {
            LOG_FATAL("No root directory specified, and /system does not exist.");
            return;
        }
        setenv("ANDROID_ROOT", rootDir, 1);
    }

    const char* artRootDir = getenv("ANDROID_ART_ROOT");
    if (artRootDir == NULL) {
        LOG_FATAL("No ART directory specified with ANDROID_ART_ROOT environment variable.");
        return;
    }

    const char* i18nRootDir = getenv("ANDROID_I18N_ROOT");
    if (i18nRootDir == NULL) {
        LOG_FATAL("No runtime directory specified with ANDROID_I18N_ROOT environment variable.");
        return;
    }

    const char* tzdataRootDir = getenv("ANDROID_TZDATA_ROOT");
    if (tzdataRootDir == NULL) {
        LOG_FATAL("No tz data directory specified with ANDROID_TZDATA_ROOT environment variable.");
        return;
    }

    //const char* kernelHack = getenv("LD_ASSUME_KERNEL");
    //ALOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);

    /* start the virtual machine */
    //启动虚拟机,并执行相应初始化操作的函数。startVm函数会启动一个Java虚拟机,并将其保存在mJavaVM变量中。该函数会返回一个JNIEnv指针,用于后续与Java层进行交互。
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    JNIEnv* env;
    if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {
        return;
    }
    //在虚拟机启动完成后执行一些初始化操作
    onVmCreated(env);

    /*
     * Register android functions.
     */
    //注册 Android 相关的本地方法
    if (startReg(env) < 0) {
        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 != NULL ? className : "");
    jclass startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
        /* keep going */
    } else {
        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");
}

startVm启动Dalvik虚拟机

// /frameworks/base/core/jni/AndroidRuntime.cpp start()方法下面

/*
 * Start the Dalvik Virtual Machine.
 *
 * Various arguments, most determined by system properties, are passed in.
 * The "mOptions" vector is updated.
 *
 * CAUTION: when adding options in here, be careful not to put the
 * char buffer inside a nested scope.  Adding the buffer to the
 * options using mOptions.add() does not copy the buffer, so if the
 * buffer goes out of scope the option may be overwritten.  It's best
 * to put the buffer at the top of the function so that it is more
 * unlikely that someone will surround it in a scope at a later time
 * and thus introduce a bug.
 *
 * Returns 0 on success.
 */
int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote, bool primary_zygote)
{
    JavaVMInitArgs initArgs;
    // 省略的代码非常长,主要是为ART虚拟机准备启动参数
    ...
    initArgs.version = JNI_VERSION_1_4;
    initArgs.options = mOptions.editArray();
    initArgs.nOptions = mOptions.size();
    initArgs.ignoreUnrecognized = JNI_FALSE;

    /*
     * Initialize the VM.
     *
     * The JavaVM* is essentially per-process, and the JNIEnv* is per-thread.
     * If this call succeeds, the VM is ready, and we can start issuing
     * JNI calls.
     */
     // 前半部分是在处理虚拟机的启动参数,处理完配置参数后,会调用libart.so提供的一个接口:JNI_CreateJavaVM函数
    if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {
        ALOGE("JNI_CreateJavaVM failed\n");
        return -1;
    }

    return 0;
}
// /art/runtime/jni/java_vm_ext.cc

// JNI Invocation interface.

extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
  ScopedTrace trace(__FUNCTION__);
  const JavaVMInitArgs* args = static_cast<JavaVMInitArgs*>(vm_args);
  if (JavaVMExt::IsBadJniVersion(args->version)) {
    LOG(ERROR) << "Bad JNI version passed to CreateJavaVM: " << args->version;
    return JNI_EVERSION;
  }
  RuntimeOptions options;
  for (int i = 0; i < args->nOptions; ++i) {
    JavaVMOption* option = &args->options[i];
    options.push_back(std::make_pair(std::string(option->optionString), option->extraInfo));
  }
  bool ignore_unrecognized = args->ignoreUnrecognized;
  // 通过Runtime的create方法创建单例的Runtime对象,它就是ART虚拟机的前身
  if (!Runtime::Create(options, ignore_unrecognized)) {
    return JNI_ERR;
  }

  // When `ART_CRASH_RUNTIME_DELIBERATELY` is defined (which happens only in the
  // case of a test APEX), we crash the runtime here on purpose, to test the
  // behavior of rollbacks following a failed ART Mainline Module update.
#ifdef ART_CRASH_RUNTIME_DELIBERATELY
  LOG(FATAL) << "Runtime crashing deliberately for testing purposes.";
#endif

  // Initialize native loader. This step makes sure we have
  // everything set up before we start using JNI.
  android::InitializeNativeLoader();

  // 获取刚刚创建的runtime对象
  Runtime* runtime = Runtime::Current();
  // 启动runtime
  bool started = runtime->Start();
  if (!started) {
    delete Thread::Current()->GetJniEnv();
    delete runtime->GetJavaVM();
    LOG(WARNING) << "CreateJavaVM failed";
    return JNI_ERR;
  }

  *p_env = Thread::Current()->GetJniEnv();
  *p_vm = runtime->GetJavaVM();
  return JNI_OK;
}

startReg注册JNI方法

// /frameworks/base/core/jni/AndroidRuntime.cpp

static const RegJNIRec gRegJNI[] = {
				// 本地实现函数
        REG_JNI(register_com_android_internal_os_RuntimeInit),
        REG_JNI(register_com_android_internal_os_ZygoteInit_nativeZygoteInit),
        ...
};

/*
 * Register android native functions with the VM.
 */
/*static*/ int AndroidRuntime::startReg(JNIEnv* env)
{
    ATRACE_NAME("RegisterAndroidNatives");
    /*
     * This hook causes all future threads created in this process to be
     * attached to the JavaVM.  (This needs to go away in favor of JNI
     * Attach calls.)
     */
    androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);

    ALOGV("--- registering native functions ---\n");

    /*
     * Every "register" function calls one or more things that return
     * a local reference (e.g. FindClass).  Because we haven't really
     * started the VM yet, they're all getting stored in the base frame
     * and never released.  Use Push/Pop to manage the storage.
     */
    env->PushLocalFrame(200);

    if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
        env->PopLocalFrame(NULL);
        return -1;
    }
    env->PopLocalFrame(NULL);

    //createJavaThread("fubar", quickTest, (void*) "hello");

    return 0;
}

AndroidRuntime.cpp的start方法主要做了以下工作:

  • 加载libart.so
  • 启动虚拟机
  • 加载注册JNI方法
  • 启动Zygote

5.3main()

执行ZygoteInit.java的main()方法,首次进入Java世界

// /frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

    /**
     * This is the entry point for a Zygote process.  It creates the Zygote server, loads resources,
     * and handles other tasks related to preparing the process for forking into applications.
     *
     * This process is started with a nice value of -20 (highest priority).  All paths that flow
     * into new processes are required to either set the priority to the default value or terminate
     * before executing any non-system code.  The native side of this occurs in SpecializeCommon,
     * while the Java Language priority is changed in ZygoteInit.handleSystemServerProcess,
     * ZygoteConnection.handleChildProc, and Zygote.childMain.
     *
     * @param argv  Command line arguments used to specify the Zygote's configuration.
     */
    @UnsupportedAppUsage
    public static void main(String[] argv) {
        ZygoteServer zygoteServer = null;

        // Mark zygote start. This ensures that thread creation will throw
        // an error.
        ZygoteHooks.startZygoteNoThreadCreation();

        // Zygote goes into its own process group.
        try {
            //设置进程组id
            Os.setpgid(0, 0);
        } catch (ErrnoException ex) {
            throw new RuntimeException("Failed to setpgid(0,0)", ex);
        }

        Runnable caller;
        try {
            // Store now for StatsLogging later.
            final long startTime = SystemClock.elapsedRealtime();
            final boolean isRuntimeRestarted = "1".equals(
                    SystemProperties.get("sys.boot_completed"));

            String bootTimeTag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing";
            TimingsTraceLog bootTimingsTraceLog = new TimingsTraceLog(bootTimeTag,
                    Trace.TRACE_TAG_DALVIK);
            bootTimingsTraceLog.traceBegin("ZygoteInit");
            //创建子进程之前执行一些预先的初始化操作
            RuntimeInit.preForkInit();

            boolean startSystemServer = false;
            String zygoteSocketName = "zygote";
            String abiList = null;
            boolean enableLazyPreload = false;
            for (int i = 1; i < argv.length; i++) {
                //通过jni调用时设置,还记得app_main.cpp中传的start-system-server参数吗,在这里终于用到了
                if ("start-system-server".equals(argv[i])) {
                    startSystemServer = true;
                } else if ("--enable-lazy-preload".equals(argv[i])) {
                    enableLazyPreload = 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)) {
                    zygoteSocketName = argv[i].substring(SOCKET_NAME_ARG.length());
                } else {
                    throw new RuntimeException("Unknown command line argument: " + argv[i]);
                }
            }

            final boolean isPrimaryZygote = zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME);
            if (!isRuntimeRestarted) {
                if (isPrimaryZygote) {
                    FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
                            BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__ZYGOTE_INIT_START,
                            startTime);
                } else if (zygoteSocketName.equals(Zygote.SECONDARY_SOCKET_NAME)) {
                    FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
                            BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__SECONDARY_ZYGOTE_INIT_START,
                            startTime);
                }
            }

            if (abiList == null) {
                throw new RuntimeException("No ABI list supplied.");
            }

            // In some configurations, we avoid preloading resources and classes eagerly.
            // In such cases, we will preload things prior to our first fork.
            if (!enableLazyPreload) {
                bootTimingsTraceLog.traceBegin("ZygotePreload");
                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                        SystemClock.uptimeMillis());
                //加载动态库,后续进行jni调用
                preload(bootTimingsTraceLog);
                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                        SystemClock.uptimeMillis());
                bootTimingsTraceLog.traceEnd(); // ZygotePreload
            }

            // Do an initial gc to clean up after startup
            bootTimingsTraceLog.traceBegin("PostZygoteInitGC");
            // 主动进行一次资源GC
            gcAndFinalize();
            bootTimingsTraceLog.traceEnd(); // PostZygoteInitGC

            bootTimingsTraceLog.traceEnd(); // ZygoteInit

            //初始化函数,用于在Zygote进程中初始化本地状态
            Zygote.initNativeState(isPrimaryZygote);

            ZygoteHooks.stopZygoteNoThreadCreation();

            //创建ZygoteServer,ZygoteServer用来监听来自应用程序的请求,并根据请求创建相应的子进程
            zygoteServer = new ZygoteServer(isPrimaryZygote);
            //zygote进程会fork出system_server进程
            if (startSystemServer) {
                Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);

                // zygote进程中,r == null;zygote子进程(如system_server进程)中, r != null
                // {@code r == null} in the parent (zygote) process, and {@code r != null} in the
                // child (system_server) process.
                if (r != null) {
                    //通过反射调用systemserver的main方法
                    r.run();
                    return;
                }
            }

            Log.i(TAG, "Accepting command socket connections");
            
            // zygote进程会在select loop死循环;而非zygote进程中之前已return。
            // The select loop returns early in the child process after a fork and
            // loops forever in the zygote.
            caller = zygoteServer.runSelectLoop(abiList);
        } catch (Throwable ex) {
            Log.e(TAG, "System zygote died with fatal exception", ex);
            throw ex;
        } finally {
            if (zygoteServer != null) {
                zygoteServer.closeServerSocket();
            }
        }

        // We're in the child process and have exited the select loop. Proceed to execute the
        // command.
        if (caller != null) {
            caller.run();
        }
    }

preload() 的作用就是提前将需要的资源加载到VM中,比如class、resource等

// /frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

    static void preload(TimingsTraceLog bootTimingsTraceLog) {
        Log.d(TAG, "begin preload");
        bootTimingsTraceLog.traceBegin("BeginPreload");
        beginPreload();
        bootTimingsTraceLog.traceEnd(); // BeginPreload
        bootTimingsTraceLog.traceBegin("PreloadClasses");
        // 加载指定的类到内存并且初始化,使用的Class.forName(class, true, null);方式
        preloadClasses();
        bootTimingsTraceLog.traceEnd(); // PreloadClasses
        bootTimingsTraceLog.traceBegin("CacheNonBootClasspathClassLoaders");
        cacheNonBootClasspathClassLoaders();
        bootTimingsTraceLog.traceEnd(); // CacheNonBootClasspathClassLoaders
        bootTimingsTraceLog.traceBegin("PreloadResources");
        // 加载Android通用的资源,比如drawable、color...
        preloadResources();
        bootTimingsTraceLog.traceEnd(); // PreloadResources
        Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadAppProcessHALs");
        nativePreloadAppProcessHALs();
        Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
        Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadGraphicsDriver");
        maybePreloadGraphicsDriver();
        Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
        // 加载共用的Library
        preloadSharedLibraries();
        // 加载Text资源,字体等
        preloadTextResources();
        // Ask the WebViewFactory to do any initialization that must run in the zygote process,
        // for memory sharing purposes.
        // 为了内存共享,WebViewFactory进行任何初始化都要在Zygote进程中
        WebViewFactory.prepareWebViewInZygote();
        endPreload();
        warmUpJcaProviders();
        Log.d(TAG, "end preload");

        sPreloadComplete = true;
    }

preloadClassess 将framework.jar里的preloaded-classes 定义的所有class load到内存里,preloaded-classes 编译Android后可以在framework/base下找到。而preloadResources 将系统的Resource(不是在用户apk里定义的resource)load到内存。资源preload到Zygoted的进程地址空间,所有fork的子进程将共享这份空间而无需重新load, 这大大减少了应用程序的启动时间,但反过来增加了系统的启动时间。通过对preload 类和资源数目进行调整可以加快系统启动。Preload也是Android启动最耗时的部分之一

// /frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

    /**
     * Runs several special GCs to try to clean up a few generations of softly- and final-reachable
     * objects, along with any other garbage. This is only useful just before a fork().
     */
    private static void gcAndFinalize() {
        ZygoteHooks.gcAndFinalize();
    }

gc()调用只是通知VM进行垃圾回收,是否回收,什么时候回收全由VM内部算法决定。GC的回收有一个复杂的状态机控制,通过多次调用,可以使得尽可能多的资源得到回收。gc()必须在fork之前完成(接下来的StartSystemServer就会有fork操作),这样将来被复制出来的子进程才能有尽可能少的垃圾内存没有释放

5.4forkSystemServer

// /frameworks/base/core/java/com/android/internal/os/ZygoteInit.java 在main上面

    /**
     * Prepare the arguments and forks for the system server process.
     *
     * @return A {@code Runnable} that provides an entrypoint into system_server code in the child
     * process; {@code null} in the parent.
     */
    private static Runnable forkSystemServer(String abiList, String socketName,
            ZygoteServer zygoteServer) {
        long capabilities = posixCapabilitiesAsBits(
                OsConstants.CAP_IPC_LOCK,
                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_PTRACE,
                OsConstants.CAP_SYS_TIME,
                OsConstants.CAP_SYS_TTY_CONFIG,
                OsConstants.CAP_WAKE_ALARM,
                OsConstants.CAP_BLOCK_SUSPEND
        );
        /* Containers run without some capabilities, so drop any caps that are not available. */
        StructCapUserHeader header = new StructCapUserHeader(
                OsConstants._LINUX_CAPABILITY_VERSION_3, 0);
        StructCapUserData[] data;
        try {
            data = Os.capget(header);
        } catch (ErrnoException ex) {
            throw new RuntimeException("Failed to capget()", ex);
        }
        capabilities &= Integer.toUnsignedLong(data[0].effective) |
                (Integer.toUnsignedLong(data[1].effective) << 32);

        /* Hardcoded command line to start the system server */
        //systemServer创建时需要的信息,命令行来启动SystemServer
        String[] args = {
                "--setuid=1000",
                "--setgid=1000",
                "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,"
                        + "1024,1032,1065,3001,3002,3003,3005,3006,3007,3009,3010,3011,3012",
                "--capabilities=" + capabilities + "," + capabilities,
                "--nice-name=system_server",
                "--runtime-args",
                "--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
                "com.android.server.SystemServer",
        };
        // 处理与 zygote spawner 相关的 args 的参数解析
        ZygoteArguments parsedArgs;

        int pid;

        try {
            ZygoteCommandBuffer commandBuffer = new ZygoteCommandBuffer(args);
            try {
                //将args转化成ZygoteArguments对象
                parsedArgs = ZygoteArguments.getInstance(commandBuffer);
            } catch (EOFException e) {
                throw new AssertionError("Unexpected argument error for forking system server", e);
            }
            commandBuffer.close();
            //检查是否设置了调试器相关的系统属性
            Zygote.applyDebuggerSystemProperty(parsedArgs);
            //检查是否使用了 --invoke-with 参数来运行应用程序。 会设置InvokeWith参数,这个参数在接下来的初始化逻辑中会有调用
            Zygote.applyInvokeWithSystemProperty(parsedArgs);

            if (Zygote.nativeSupportsMemoryTagging()) {
                String mode = SystemProperties.get("arm64.memtag.process.system_server", "");
                if (mode.isEmpty()) {
                  /* The system server has ASYNC MTE by default, in order to allow
                   * system services to specify their own MTE level later, as you
                   * can't re-enable MTE once it's disabled. */
                  mode = SystemProperties.get("persist.arm64.memtag.default", "async");
                }
                if (mode.equals("async")) {
                    parsedArgs.mRuntimeFlags |= Zygote.MEMORY_TAG_LEVEL_ASYNC;
                } else if (mode.equals("sync")) {
                    parsedArgs.mRuntimeFlags |= Zygote.MEMORY_TAG_LEVEL_SYNC;
                } else if (!mode.equals("off")) {
                    /* When we have an invalid memory tag level, keep the current level. */
                    parsedArgs.mRuntimeFlags |= Zygote.nativeCurrentTaggingLevel();
                    Slog.e(TAG, "Unknown memory tag level for the system server: \"" + mode + "\"");
                }
            } else if (Zygote.nativeSupportsTaggedPointers()) {
                /* Enable pointer tagging in the system server. Hardware support for this is present
                 * in all ARMv8 CPUs. */
                parsedArgs.mRuntimeFlags |= Zygote.MEMORY_TAG_LEVEL_TBI;
            }

            /* Enable gwp-asan on the system server with a small probability. This is the same
             * policy as applied to native processes and system apps. */
            parsedArgs.mRuntimeFlags |= Zygote.GWP_ASAN_LEVEL_LOTTERY;

            if (shouldProfileSystemServer()) {
                parsedArgs.mRuntimeFlags |= Zygote.PROFILE_SYSTEM_SERVER;
            }

            /* Request to fork the system server process */
            // 请求 fork SystemServer进程
            pid = Zygote.forkSystemServer(
                    parsedArgs.mUid, parsedArgs.mGid,
                    parsedArgs.mGids,
                    parsedArgs.mRuntimeFlags,
                    null,
                    parsedArgs.mPermittedCapabilities,
                    parsedArgs.mEffectiveCapabilities);
        } catch (IllegalArgumentException ex) {
            throw new RuntimeException(ex);
        }

        /* For child process */
        // 如果是第一次创建的话pid==0
        if (pid == 0) {
            // 这里已经是子进程了
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName);
            }

            // SyetemServer进程是复制了Zygote进程的地址空间,因此也会得到Zygote进程创建的Socket,这个Socket对于SyetemServer进程没有用处,因此,需要关闭该Socket
            zygoteServer.closeServerSocket();
            return handleSystemServerProcess(parsedArgs);
        }

        return null;
    }

我们把方法前的英文注释翻译一下:为system server进程准备参数和forks。在子进程中返回一个提供进入system server代码入口点的Runnable并且在父进程中返回null。

在这里引申一下,我么经常说fork一个进程。那么,什么是fork?fork是一个分叉函数,一个现有进程可以调用fork函数创建一个新进程。由fork创建的新进程被称为子进程。fork函数被调用一次但返回两次,两次返回的唯一区别是子进程中返回0值而父进程中返回子进程ID。
forkSystemServer方法的主要工作流程是:
(1)获取POSIX(可移植操作系统接口)功能列表的相关位数:posixCapabilitiesAsBits
(2)放弃一些容器运行时不可用的功能:逻辑运算符&和|
(3)硬编码命令行启动system server
(4)发送fork一个system server 子进程的请求:Zygote.forkSystemServer
(5)如果pid是0,说明system server启动成功。关闭socket,并且做一些启动system server剩余的工作:handleSystemServerProcess(parsedArgs)

// /frameworks/base/core/java/com/android/internal/os/Zygote.java

    /**
     * Special method to start the system server process. In addition to the
     * common actions performed in forkAndSpecialize, the pid of the child
     * process is recorded such that the death of the child process will cause
     * zygote to exit.
     *
     * @param uid the UNIX uid that the new process should setuid() to after
     * fork()ing and and before spawning any threads.
     * @param gid the UNIX gid that the new process should setgid() to after
     * fork()ing and and before spawning any threads.
     * @param gids null-ok; a list of UNIX gids that the new process should
     * setgroups() to after fork and before spawning any threads.
     * @param runtimeFlags bit flags that enable ART features.
     * @param rlimits null-ok an array of rlimit tuples, with the second
     * dimension having a length of 3 and representing
     * (resource, rlim_cur, rlim_max). These are set via the posix
     * setrlimit(2) call.
     * @param permittedCapabilities argument for setcap()
     * @param effectiveCapabilities argument for setcap()
     *
     * @return 0 if this is the child, pid of the child
     * if this is the parent, or -1 on error.
     */
    static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
            int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
        ZygoteHooks.preFork();

        // 通过jni调用native方法,最终fork一个进程
        int pid = nativeForkSystemServer(
                uid, gid, gids, runtimeFlags, rlimits,
                permittedCapabilities, effectiveCapabilities);

        // Set the Java Language thread priority to the default value for new apps.
        Thread.currentThread().setPriority(Thread.NORM_PRIORITY);

        ZygoteHooks.postForkCommon();
        return pid;
    }

native方法的实现,都是在cpp文件中,现在我们来看一下这个源码:

// /frameworks/base/core/jni/com_android_internal_os_Zygote.cpp

NO_STACK_PROTECTOR
static jint com_android_internal_os_Zygote_nativeForkSystemServer(
        JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
        jint runtime_flags, jobjectArray rlimits, jlong permitted_capabilities,
        jlong effective_capabilities) {
  std::vector<int> fds_to_close(MakeUsapPipeReadFDVector()),
                   fds_to_ignore(fds_to_close);

  fds_to_close.push_back(gUsapPoolSocketFD);

  if (gUsapPoolEventFD != -1) {
    fds_to_close.push_back(gUsapPoolEventFD);
    fds_to_ignore.push_back(gUsapPoolEventFD);
  }

  if (gSystemServerSocketFd != -1) {
      fds_to_close.push_back(gSystemServerSocketFd);
      fds_to_ignore.push_back(gSystemServerSocketFd);
  }

  pid_t pid = zygote::ForkCommon(env, true,
                                 fds_to_close,
                                 fds_to_ignore,
                                 true);
  if (pid == 0) {
      // System server prcoess does not need data isolation so no need to
      // know pkg_data_info_list.
      SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, permitted_capabilities,
                       effective_capabilities, MOUNT_EXTERNAL_DEFAULT, nullptr, nullptr, true,
                       false, nullptr, nullptr, /* is_top_app= */ false,
                       /* pkg_data_info_list */ nullptr,
                       /* allowlisted_data_info_list */ nullptr, false, false);
  } else if (pid > 0) {
      // The zygote process checks whether the child process has died or not.
      ALOGI("System server process %d has been created", pid);
      gSystemServerPid = pid;
      // There is a slight window that the system server process has crashed
      // but it went unnoticed because we haven't published its pid yet. So
      // we recheck here just to make sure that all is well.
      int status;
      if (waitpid(pid, &status, WNOHANG) == pid) {
          ALOGE("System server process %d has died. Restarting Zygote!", pid);
          RuntimeAbort(env, __LINE__, "System server process has died. Restarting Zygote!");
      }

      if (UsePerAppMemcg()) {
          // Assign system_server to the correct memory cgroup.
          // Not all devices mount memcg so check if it is mounted first
          // to avoid unnecessarily printing errors and denials in the logs.
          if (!SetTaskProfiles(pid, std::vector<std::string>{"SystemMemoryProcess"})) {
              ALOGE("couldn't add process %d into system memcg group", pid);
          }
      }
  }
  return pid;
}

ForkAndSpecializeCommon是一个非常长的方法,我们可以看到代码分为两个逻辑,一个是if(pid ==0),另一个是if(pid>0)。前面我们说到过,fork进程成功后,返回两次,子进程返回0,父进程返回子进程的id。到此system_server进程已完成了创建的所有工作。

  1. fork函数最终返回了一个pid,在这里会对pid判断,这里伙伴们需要注意,虽然fork只会执行一次,但是在返回值上会有两次返回,这是什么原因呢
  2. 因为我们在fork进程的时候,我们会在父进程中执行fork函数,同时会将父进程的信息全部拷贝一份,包括堆栈信息,也就是代码会在子进程中再次执行一次,所以从现象上来看,在forkSystemServer方法执行时,会有两次返回,一次是从父进程返回,一次从子进程中返回,那么如何判断是在哪个进程呢?
  3. 在ForkCommon函数中给了我们答案,当pid = 0时,因为在子进程中没有创建进程,因此返回0;而在父进程中则是会返回创建的子进程pid;如果返回一个负值,那么说明创建进程失败了
  4. 因此,在ZygoteInit调用forkSystemServer之后,会判断其返回值,如果pid = 0,那么就说明创建进程成功了,而且是子进程,那么就会执行handleSystemServerProcess方法,此时运行system_server进程
// /frameworks/base/core/jni/com_android_internal_os_Zygote.cpp

// Utility routine to fork a process from the zygote.
NO_STACK_PROTECTOR
pid_t zygote::ForkCommon(JNIEnv* env, bool is_system_server,
                         const std::vector<int>& fds_to_close,
                         const std::vector<int>& fds_to_ignore,
                         bool is_priority_fork,
                         bool purge) {
  SetSignalHandlers();

  // Curry a failure function.
  auto fail_fn = std::bind(zygote::ZygoteFailure, env,
                           is_system_server ? "system_server" : "zygote",
                           nullptr, _1);

  // Temporarily block SIGCHLD during forks. The SIGCHLD handler might
  // log, which would result in the logging FDs we close being reopened.
  // This would cause failures because the FDs are not allowlisted.
  //
  // Note that the zygote process is single threaded at this point.
  BlockSignal(SIGCHLD, fail_fn);

  // Close any logging related FDs before we start evaluating the list of
  // file descriptors.
  __android_log_close();
  AStatsSocket_close();

  // If this is the first fork for this zygote, create the open FD table,
  // verifying that files are of supported type and allowlisted.  Otherwise (not
  // the first fork), check that the open files have not changed.  Newly open
  // files are not expected, and will be disallowed in the future.  Currently
  // they are allowed if they pass the same checks as in the
  // FileDescriptorTable::Create() above.
  if (gOpenFdTable == nullptr) {
    gOpenFdTable = FileDescriptorTable::Create(fds_to_ignore, fail_fn);
  } else {
    gOpenFdTable->Restat(fds_to_ignore, fail_fn);
  }

  android_fdsan_error_level fdsan_error_level = android_fdsan_get_error_level();

  if (purge) {
    // Purge unused native memory in an attempt to reduce the amount of false
    // sharing with the child process.  By reducing the size of the libc_malloc
    // region shared with the child process we reduce the number of pages that
    // transition to the private-dirty state when malloc adjusts the meta-data
    // on each of the pages it is managing after the fork.
    if (mallopt(M_PURGE_ALL, 0) != 1) {
      mallopt(M_PURGE, 0);
    }
  }

  pid_t pid = fork();

  if (pid == 0) {
    if (is_priority_fork) {
      setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MAX);
    } else {
      setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MIN);
    }

#if defined(__BIONIC__) && !defined(NO_RESET_STACK_PROTECTOR)
    // Reset the stack guard for the new process.
    android_reset_stack_guards();
#endif

    // The child process.
    PreApplicationInit();

    // Clean up any descriptors which must be closed immediately
    DetachDescriptors(env, fds_to_close, fail_fn);

    // Invalidate the entries in the USAP table.
    ClearUsapTable();

    // Re-open all remaining open file descriptors so that they aren't shared
    // with the zygote across a fork.
    gOpenFdTable->ReopenOrDetach(fail_fn);

    // Turn fdsan back on.
    android_fdsan_set_error_level(fdsan_error_level);

    // Reset the fd to the unsolicited zygote socket
    gSystemServerSocketFd = -1;
  } else if (pid == -1) {
    ALOGE("Failed to fork child process: %s (%d)", strerror(errno), errno);
  } else {
    ALOGD("Forked child process %d", pid);
  }

  // We blocked SIGCHLD prior to a fork, we unblock it here.
  UnblockSignal(SIGCHLD, fail_fn);

  return pid;
}

fork函数

现在我们来看看它是怎么工作的

// /system/bionic/libc/bionic/fork.cpp

/**
 * __clone_for_fork 函数用于执行实际的进程克隆操作
 *
 * @return 若克隆成功,在子进程中返回 0,在父进程中返回子进程的进程 ID;若克隆失败,返回 -1
 */
int __clone_for_fork() {
    // 获取当前线程的内部结构指针
    pthread_internal_t* self = __get_thread();  

    // 使用 clone 系统调用 创建新进程
    // CLONE_CHILD_SETTID 和 CLONE_CHILD_CLEARTID 用于设置和清除子进程的线程 ID
    // SIGCHLD 表示子进程结束时发送 SIGCHLD 信号
    // 其他参数为 NULL,表示使用默认设置
    int result = clone(nullptr, nullptr, (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD),
                       nullptr, nullptr, nullptr, &(self->tid));  

    // 如果克隆成功(返回值为 0)
    if (result == 0) {  
        // 在子进程中更新缓存的进程 ID,因为 clone 系统调用不会直接设置它(但内核会更新 self->tid)
        self->set_cached_pid(gettid());  
    }

    return result;  
}

/**
 * fork 函数用于创建一个新的进程
 *
 * @return 若成功创建子进程,在子进程中返回 0,在父进程中返回子进程的进程 ID;若创建失败,返回 -1
 */
int fork() {
    // 执行 fork 前的准备工作
    __bionic_atfork_run_prepare();  

    int result = __clone_for_fork();  

    // 如果结果为 0,表示当前处于新创建的子进程中
    if (result == 0) {  
        // 禁用 fork 后的文件描述符安全检查(fdsan),避免错误触发
        // 对于那些先 fork,然后关闭所有文件描述符并执行 exec 的进程
        android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_DISABLED);  
        // 全局禁用文件跟踪(fdtrack)
        android_fdtrack_set_globally_enabled(false);  

        // 重置栈和线程本地存储(TLS)的虚拟内存区域(VMA)名称,防止使用父进程的 tid
        __set_stack_and_tls_vma_name(true);  

        // 在子进程中执行特定的操作
        __bionic_atfork_run_child();  
    } else {  // 如果结果不为 0,表示当前处于父进程中
        // 在父进程中执行特定的操作
        __bionic_atfork_run_parent();  
    }
    return result;  
}

子进程与父进程的区别

  1. 除了文件锁以外,其他的锁都会被继承
  2. 各自的进程ID和父进程ID不同
  3. 子进程的未决告警被清除;
  4. 子进程的未决信号集设置为空集。

写时拷贝 (copy- on-write)
Linux 的 fork() 使用是通过写时拷贝 (copy- on-write) 实现。写时拷贝是一种可以推迟甚至避免拷贝
数据的技术。内核此时并不复制整个进程的地址空间,而是让父子进程共享同一个地址空间。只用在需要写入的时候才会复制地址空间,从而使各个进行拥有各自的地址空间。也就是说,资源的复制是在需要写入的时候才会进行,在此之前,只有以只读方式共享
孤儿进程、僵尸进程
fork系统调用之后,父子进程将交替执行,执行顺序不定。如果父进程先退出,子进程还没退出那么子进程的父进程将变为init进程(托孤给了init进程)。(注:任何一个进程都必须有父进程)如果子进程先退出,父进程还没退出,那么子进程必须等到父进程捕获到了子进程的退出状态才真正结束,否则这个时候子进程就成为僵进程(僵尸进程:只保留一些退出信息供父进程查询)
多线程进程的Fork调用
在 POSIX 标准中,fork 的行为是这样的:复制整个用户空间的数据(通常使用 copy-on-write 的策略,所以可以实现的速度很快)以及所有系统对象,然后仅复制当前线程到子进程。这里:所有父进程中别的线程,到了子进程中都是突然蒸发掉的
假设这么一个环境,在 fork 之前,有一个子线程 lock 了某个锁,获得了对锁的所有权。fork 以
后,在子进程中,所有的额外线程都人间蒸发了。而锁却被正常复制了,在子进程看来,这个锁没
有主人,所以没有任何人可以对它解锁。当子进程想 lock 这个锁时,不再有任何手段可以解开
了。程序发生死锁

man clone

int clone(int (*fn)(void *), void *child_stack,
          int flags, void *arg, ...
          /* pid_t *ptid, void *newtls, pid_t *ctid */ );
/*
以下是clone函数的参数说明:
fn:指向子进程要执行的函数的指针。
child_stack:为子进程分配的堆栈地址。
flags:用于设置子进程的属性,如是否与父进程共享地址空间、文件系统、文件描述符、信号处理程序等。
arg:传递给子进程的参数。
通过设置不同的flags标志,可以控制子进程与父进程之间的资源共享情况。例如,设置CLONE_VM标志可以共享地址空间,设置CLONE_FS标志可以共享文件系统信息等。
clone函数的返回值表示创建的子进程的PID(进程标识符)。在子进程中,clone函数返回0;在父进程中,返回子进程的PID。
*/

ZygoteInit.forkSystemServer() 方法fork 出一个新的进程,这个进程就是SystemServer进程。fork出来
的子进程在handleSystemServerProcess 里开始初始化工作,主要工作分为:

  1. prepareSystemServerProfile()方法中将SYSTEMSERVERCLASSPATH中的AppInfo加载到VM
    中。
  2. 判断fork args中是否有invokWith参数,如果有则进行WrapperInit.execApplication。如果没有则调用

5.5handleSystemServerProcess

	// /frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
	
    /**
     * Finish remaining work for the newly forked system server process.
     */
    private static Runnable handleSystemServerProcess(ZygoteArguments parsedArgs) {
        // set umask to 0077 so new files and directories will default to owner-only permissions.
        Os.umask(S_IRWXG | S_IRWXO);

        if (parsedArgs.mNiceName != null) {
            Process.setArgV0(parsedArgs.mNiceName);
        }

        final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
        if (systemServerClasspath != null) {
            // Capturing profiles is only supported for debug or eng builds since selinux normally
            // prevents it.
            if (shouldProfileSystemServer() && (Build.IS_USERDEBUG || Build.IS_ENG)) {
                try {
                    Log.d(TAG, "Preparing system server profile");
                    final String standaloneSystemServerJars =
                            Os.getenv("STANDALONE_SYSTEMSERVER_JARS");
                    final String systemServerPaths = standaloneSystemServerJars != null
                            ? String.join(":", systemServerClasspath, standaloneSystemServerJars)
                            : systemServerClasspath;
                    // 将SYSTEMSERVERCLASSPATH中的AppInfo加载到VM中
                    prepareSystemServerProfile(systemServerPaths);
                } catch (Exception e) {
                    Log.wtf(TAG, "Failed to set up system server profile", e);
                }
            }
        }

        if (parsedArgs.mInvokeWith != null) {
            String[] args = parsedArgs.mRemainingArgs;
            // If we have a non-null system server class path, we'll have to duplicate the
            // existing arguments and append the classpath to it. ART will handle the classpath
            // correctly when we exec a new process.
            if (systemServerClasspath != null) {
                String[] amendedArgs = new String[args.length + 2];
                amendedArgs[0] = "-cp";
                amendedArgs[1] = systemServerClasspath;
                System.arraycopy(args, 0, amendedArgs, 2, args.length);
                args = amendedArgs;
            }

            //判断fork args中是否有invokWith参数,如果有则进行WrapperInit.execApplication
            WrapperInit.execApplication(parsedArgs.mInvokeWith,
                    parsedArgs.mNiceName, parsedArgs.mTargetSdkVersion,
                    VMRuntime.getCurrentInstructionSet(), null, args);

            throw new IllegalStateException("Unexpected return from WrapperInit.execApplication");
        } else {
            ClassLoader cl = getOrCreateSystemServerClassLoader();
            if (cl != null) {
                Thread.currentThread().setContextClassLoader(cl);
            }

            /*
             * Pass the remaining arguments to SystemServer.
             */
            // 调用zygoteInit。com.android.server.SystemServer即解析到的parsedArgs.mRemainingArgs
            return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
                    parsedArgs.mDisabledCompatChanges,
                    parsedArgs.mRemainingArgs, cl);
        }

        /* should never reach here */
    }
	// /frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

    /**
     * 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>
     *
     * Current recognized args:
     * <ul>
     * <li> <code> [--] &lt;start class name&gt;  &lt;args&gt;
     * </ul>
     *
     * @param targetSdkVersion target SDK version
     * @param disabledCompatChanges set of disabled compat changes for the process (all others
     *                              are enabled)
     * @param argv             arg strings
     */
    public static Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges,
            String[] argv, ClassLoader classLoader) {
        if (RuntimeInit.DEBUG) {
            Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
        }

        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
        RuntimeInit.redirectLogStreams();

        RuntimeInit.commonInit();
        ZygoteInit.nativeZygoteInit();
        return RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv,
                classLoader);
    }

5.6 nativeZygoteInit

在看applicationInit方法之前,首先先看一下ZygoteInit中的nativeZygoteInit,这个方法比较重要,我们跟进看一下。这是一个native方法,我们看下C++的代码

通过JNI的gRegJNI数组,可以看出nativeZygoteInit函数对应的是JNI文件AndroidRuntime.cpp的register_com_android_internal_os_ZygoteInit_nativeZygoteInit函数:

// /frameworks/base/core/jni/AndroidRuntime.cpp

int register_com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env)
{
    const JNINativeMethod methods[] = {
        { "nativeZygoteInit", "()V",
            (void*) com_android_internal_os_ZygoteInit_nativeZygoteInit },
    };
    return jniRegisterNativeMethods(env, "com/android/internal/os/ZygoteInit",
        methods, NELEM(methods));
}

最终执行的是AndroidRuntime的onZygoteInit函数。

// /frameworks/base/core/jni/AndroidRuntime.cpp

static void com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
{
    // 调用AndroidRuntime的纯虚函数onZygoteInit()
    gCurRuntime->onZygoteInit();
}

gCurRuntime是指什么?在app_main.cpp 中

// /frameworks/base/core/jni/AndroidRuntime.cpp

// 全局静态AndroidRuntime对象指针,在构造函数里赋值并保证进程单例
static AndroidRuntime* gCurRuntime = NULL;
...
AndroidRuntime::AndroidRuntime(char* argBlockStart, const size_t argBlockLength) :
        mExitWithoutCleanup(false),
        mArgBlockStart(argBlockStart),
        mArgBlockLength(argBlockLength)
{
    init_android_graphics();

    // Pre-allocate enough space to hold a fair number of options.
    mOptions.setCapacity(20);

    assert(gCurRuntime == NULL);        // one per process
    // gCurRuntime 被设置为AndroidRuntime对象自己
    gCurRuntime = this;
}

故:此时启动App_main.cpp中onZygoteInit()函数

每个App在启动前必须先创建一个进程,该进程是由Zygote进程fork出来,进程具有独立的资源空间,用于承载app上运行的各种Activity/Service等组件,进程在创建时候打开Binder驱动,然后才能进行Binder IPC通讯,如startActivity()调用流程AMS先检测目标进程是否启动,若没则创建目标进程。

// /frameworks/base/cmds/app_process/app_main.cpp
    virtual void onZygoteInit()
    {
        // 创建sp智能指针引用的ProcessState对象,在其作用域结束后将自动释放
        sp<ProcessState> proc = ProcessState::self();
        ALOGV("App process: starting thread pool.\n");
        // 创建Binder驱动并启动Binder线程池,用于binder通信
        proc->startThreadPool();
    }
// /frameworks/native/libs/binder/ProcessState.cpp

sp<ProcessState> ProcessState::self()
{
    // 上面已经看过这个函数,注意这里调用的第二次参数是false
    return init(kDefaultDriver, false /*requireDefault*/);
}

// /frameworks/native/libs/binder/ProcessState.cpp

// 每个支持 Binder 进程间通信机制的进程内都有一个唯一的processState对象
void ProcessState::startThreadPool()
{
    AutoMutex _l(mLock);
    // 防止重复启动线程池
    if (!mThreadPoolStarted) {
        if (mMaxThreads == 0) {
            ALOGW("Extra binder thread started, but 0 threads requested. Do not use "
                  "*startThreadPool when zero threads are requested.");
        }
        mThreadPoolStarted = true;
        spawnPooledThread(true);
    }
}
...
void ProcessState::spawnPooledThread(bool isMain)
{
    if (mThreadPoolStarted) {
        //创建binder线程名字  binder-xxx
        String8 name = makeBinderThreadName();
        ALOGV("Spawning new pooled thread, name=%s\n", name.string());
        sp<Thread> t = sp<PoolThread>::make(isMain);
        t->run(name.string());
        pthread_mutex_lock(&mThreadCountLock);
        mKernelStartedThreads++;
        pthread_mutex_unlock(&mThreadCountLock);
    }
}

主要就是创建PoolThread对象并调用其run函数启动一个新线程,而PoolThread 继承Thread并重写了线程入口函数threadLoop

// /frameworks/native/libs/binder/ProcessState.cpp

class PoolThread : public Thread
{
public:
    explicit PoolThread(bool isMain)
        : mIsMain(isMain)
    {
    }

protected:
    virtual bool threadLoop()
    {
        IPCThreadState::self()->joinThreadPool(mIsMain);
        return false;
    }

    const bool mIsMain;
};
// /frameworks/native/libs/binder/IPCThreadState.cpp

void IPCThreadState::joinThreadPool(bool isMain)
{
    LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());
    pthread_mutex_lock(&mProcess->mThreadCountLock);
    mProcess->mCurrentThreads++;
    pthread_mutex_unlock(&mProcess->mThreadCountLock);
    // 将协议写入到IPCThreadState的输出缓冲区
    mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);

    mIsLooper = true;
    status_t result;
    do {
        processPendingDerefs();
        // now get the next command to be processed, waiting if necessary
        result = getAndExecuteCommand();

        if (result < NO_ERROR && result != TIMED_OUT && result != -ECONNREFUSED && result != -EBADF) {
            LOG_ALWAYS_FATAL("getAndExecuteCommand(fd=%d) returned unexpected error %d, aborting",
                  mProcess->mDriverFD, result);
        }

        // Let this thread exit the thread pool if it is no longer
        // needed and it is not the main process thread.
        if(result == TIMED_OUT && !isMain) {
            break;
        }
    } while (result != -ECONNREFUSED && result != -EBADF);

    LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%d\n",
        (void*)pthread_self(), getpid(), result);

    mOut.writeInt32(BC_EXIT_LOOPER);
    mIsLooper = false;
    // false代表bwr数据的read_buffer为空
    talkWithDriver(false);
    pthread_mutex_lock(&mProcess->mThreadCountLock);
    LOG_ALWAYS_FATAL_IF(mProcess->mCurrentThreads == 0,
                        "Threadpool thread count = 0. Thread cannot exist and exit in empty "
                        "threadpool\n"
                        "Misconfiguration. Increase threadpool max threads configuration\n");
    mProcess->mCurrentThreads--;
    pthread_mutex_unlock(&mProcess->mThreadCountLock);
}

若talkWithDriver函数长期没有等到IPC请求或者getAndExecuteCommand函数执行超时,且isMain为false时就跳出循环,并向Binder驱动发送BC_EXIT_LOOPER协议告知Binder驱动,前面创建的这个线程它要退出Binder线程池了。
所以这里就有一个面试题,Binder驱动是什么时候启动的?其实就是在fork进程成功之后,处理进程启动的时候完成的,具体函数就是在ZygoteInit的nativeZygoteInit方法。

5.7applicationInit

// /frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

    protected static Runnable applicationInit(int targetSdkVersion, long[] disabledCompatChanges,
            String[] argv, ClassLoader classLoader) {
        // 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);

        VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
        VMRuntime.getRuntime().setDisabledCompatChanges(disabledCompatChanges);

        final Arguments args = new Arguments(argv);

        // The end of of the RuntimeInit event (see #zygoteInit).
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

        // Remaining arguments are passed to the start class's static main
        // findStaticMain来运行args的startClass的main方法
        return findStaticMain(args.startClass, args.startArgs, classLoader);
    }
// /frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

    /**
     * Invokes a static "main(argv[]) method on class "className".
     * Converts various failing exceptions into RuntimeExceptions, with
     * the assumption that they will then cause the VM instance to exit.
     *
     * @param className Fully-qualified class name
     * @param argv Argument vector for main()
     * @param classLoader the classLoader to load {@className} with
     */
    protected static Runnable findStaticMain(String className, String[] argv,
            ClassLoader classLoader) {
        Class<?> cl;

        try {
            // 反射获取main方法
            cl = Class.forName(className, true, classLoader);
        } catch (ClassNotFoundException ex) {
            throw new RuntimeException(
                    "Missing class when invoking static main " + className,
                    ex);
        }

        Method m;
        try {
            m = cl.getMethod("main", new Class[] { String[].class });
        } catch (NoSuchMethodException ex) {
            throw new RuntimeException(
                    "Missing static main on " + className, ex);
        } catch (SecurityException ex) {
            throw new RuntimeException(
                    "Problem getting static main on " + className, ex);
        }

        int modifiers = m.getModifiers();
        if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
            throw new RuntimeException(
                    "Main method is not public and static on " + className);
        }

        /*
         * This throw gets caught in ZygoteInit.main(), which responds
         * by invoking the exception's run() method. This arrangement
         * clears up all the stack frames that were required in setting
         * up the process.
         */
        // 返回一个 Runnable,在 Zygote 的 main() 方法中执行器 run() 方法
        // 之前的版本是抛出一个异常,在 main() 方法中捕获,注释误导人
        return new MethodAndArgsCaller(m, argv);
    }

在return语句上面有一段注释,意思是:这个会在ZygoteInit.main方法被捕获,他通过调用异常的run方法来响应。也就是findStaticMain()方法中抛出的异常MethodAndArgsCaller,从而进入caller.run()方法。下面是MethodAndArgsCaller的源码:

很明显这是一个耗时操作所以使用线程来完成:

// /frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

    /**
     * Helper class which holds a method and arguments and can call them. This is used as part of
     * a trampoline to get rid of the initial process setup stack frames.
     */
    static class MethodAndArgsCaller implements Runnable {
        /** method to call */
        private final Method mMethod;

        /** argument array */
        private final String[] mArgs;

        public MethodAndArgsCaller(Method method, String[] args) {
            mMethod = method;
            mArgs = args;
        }
        
        // MethodAndArgsCaller继承自Runnable并实现了run方法,在ZygoteInit.java中调用forkSystemServer(abiList, zygoteSocketName, zygoteServer)返回Runnable对象后回调他的run方法
        // run方法的实现,通过反射调用systemserver的main方法
        public void run() {
            try {
                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);
            }
        }
    }

通过如上代码,我们可以看出,通过反射的方式,进入SystemServer的main方法。(为什么旧版本要通过抛出异常的方式进入main方法呢?因为从ZygoteInit的main开始fork一个进程出来,经过了层层调用,系统中累积了不少栈帧,为了一个创建一个干干净净的进程,需要清除里面的栈帧,故抛出这个异常。)

Zygote进程主要做了以下工作

  • 加载虚拟机,并为JVM注册JNI方法
  • 提前加载类PreloadClasses
  • 提前加载资源PreLoadResouces
  • fork system_server
  • 调用runSelectLoop方法,等待进程孵化请求

zygote进程在fork子进程的时候可以共享虚拟机和资源,从而加快进程的启动速度,节省内存。

接下来请阅读:android u开机流程详细分析(下) - system service

标签:fork,process,system,zygote,进程,android,main,详细分析
From: https://blog.csdn.net/qq_45845172/article/details/140783171

相关文章

  • android 14开机流程详细分析(上) - Boot ROM,Boot loader,kernel,init
    androidu开机流程详细分析本文基于android-14.0.0_r2源码AOSP架构AOSP的软件堆栈包含以下层:图1.AOSP软件堆栈架构下面列出了图1中使用的术语的定义:Android应用完全使用AndroidAPI开发的应用。GooglePlay商店广泛用于查找和下载Android应用,不过也......
  • android studio 调用第三方无源代码so
    androidstudio调用第三方无源代码so在AndroidStudio中调用第三方无源码的SO(共享库),你需要遵循以下步骤:将SO文件放置在项目中合适的位置。配置app的build.gradle文件,确保Gradle在构建应用时知道SO文件的位置。在Java/Kotlin代码中使用JNI接口加载SO库。......
  • Android 8.0 源码分析 (四) Activity 启动
    链接:https://juejin.cn/post/6844903983442558989前言我们熟知一般Android工程师都是在应用层上���发,不会涉及系统源码,但是如果你想往底层发展,或者深入插件化、Framework系统层等开发工作,如果不了解Android源码可是不行的,那么接下来我基于自己的理解跟学习来记录跟Android......
  • Android 8.0 源码分析 (二) Launcher 启动
    链接https://juejin.cn/post/6844903981504790541前言我们熟知一般Android工程师都是在应用层上开发,不会涉及系统源码,但是如果你想往底层发展,或者深入插件化、Framework系统层等开发工作,如果不了解Android源码可是不行的,那么接下来我基于自己的理解跟学习来记录跟Androi......
  • 记录一次IPhone和Android手机usb网卡驱动的移植过程
    记录一次IPhone和Android手机USB网卡的移植过程移植环境IPhoneUSB网卡的快速移植1.**添加驱动支持**2.USB连接IPhone手机,留意手机的`信任弹窗`并点击确定和输入密码3.检查USB网卡是否生成4.如果生成的网卡没有自动分配IP,安装udhcpc5.验证测试AndroidUSB网卡的快......
  • Android 10.0 Launcher 启动流程
    在前面SystemUI启动流程中说到,在SystemServer中会去启动各种系统服务,这里的launcher也是启动的其中一个服务ActivityManagerService去启动的。在android10之前,系统四大组件的启动都是在ActivityManagerService中,在android10中,单独抽出了一个ActivityTaskManagerService,主要......
  • 基于Android平台开发,仿头条新闻app新闻分类分类列表实现(四)
    1.项目涉及到的技术点列表控件RecyclerView的使用调用API获取网络数据Glide加载图片Handler的使用okhttp的使用2.代码实现过程在上集中,已经使用TabLayout+ViewPager2把新闻分类滑动实现了,这集具体实现新闻列表新闻布局fragment_tab_news.xml<?xmlversion="1.0"en......
  • Android 应用、驱动开发(六十九)MaterialButton存储应用
    一、运行效果:二、主函数MainActivity.java:packagecom.example.a087_materialbuttonapp;importandroidx.appcompat.app.AppCompatActivity;importandroid.content.Intent;importandroid.os.Bundle;importandroid.view.View;importandroid.widget.Button;impo......
  • Android 四大控件
    一、Activity  在Android应用中,Activity是一个非常核心的组件,用于表示应用的一个单一屏幕,是用户与应用交互的主界面。每个Activity提供一个窗口,用于绘制界面和接收与用户的交互事件。理解Activity的创建、生命周期和其基本用法对于开发Android应用至关重要。 一个......
  • 如何在不丢失数据的情况下解锁锁定的Android手机
    你有没有发现自己处于无法访问你的Android手机的情况,因为它被锁定了?这可能是一种令人沮丧的经历,特别是如果您的设备上存储了不想丢失的重要数据。在这篇博文中,我们将探讨不同的方法,这些方法可以帮助您解锁锁定的Android手机,而不会丢失任何有价值的数据。我们了解在重新获得设备......