当前位置: 首页 > news >正文

一个公司做两个网站的多吗网站怎样设计网址

一个公司做两个网站的多吗,网站怎样设计网址,鸿蒙os用什么语言开发app,域名格式前言 上一篇文档中我们描述了 Android 启动中的 init 启动部分#xff0c;本片文档将会继续 Android 启动流程的逻辑#xff0c;继续梳理 Zygote 部分功能。 说明框架 对于 Zygote 进程#xff0c;要从以下框架说明#xff1a; 第一点#xff0c;编译#xff0c;zygo…前言 上一篇文档中我们描述了 Android 启动中的 init 启动部分本片文档将会继续 Android 启动流程的逻辑继续梳理 Zygote 部分功能。 说明框架 对于 Zygote 进程要从以下框架说明 第一点编译zygote 运行的二进制编译文件 ​ zygote32、zygote64 文件对应 app_process32、app_precess64 文件区别对应的功能。 第二点功能zygote 的重要功能描述 从上面两个点展开说明可以说到 AndroidRuntime 虚拟机、预加载资源、app_process 命令的使用等。 正文 对于 Zygote 进程的功能描述准备从以下方面展开描述 首先会对于 Zygote 进程运行的二进制文件描述从代码路径到编译结构展开对 Zygote 进程的功能文件进行整理 然后整理 Zygote 进程在启动中的时序图。 接着从功能的角度对 Zygote 进程的运行进行整理重要的部分详细描述 最后总结 Zygote 进程的知识点。 在上一篇介绍 init 进程的文档中我们提到在 init 的第二阶段会扫描系统路径下的 rc 文件并解析执行所有的 rc 文件中定义功能。在 Android 中很多的服务是在这个阶段被启动作为系统的 Native 服务或者说是守护进程运行在这些服务中对于启动流程而言必须要提到的一个服务进程就是 Zygote 进程。 1、rc 文件 Zygote 进程在 init 进程中以 service 的方式启动的。从 Android 5.0 开始Zygote 还是有变动的之前是直接放入 init.rc 中的代码块中现在是放到了单独的文件中通过 init.rc 中通过 “import” 的方式引入文件。 如下所示 从上面的语句可以看到init.rc 并不是直接引入某个固定的文件而是根据属性 ro.zygote 的内容来引入不同的文件。这是因为从 Android 5.0 开始Android 系统开始支持 64 位的编译Zygote 进程本身也会有 32 位和 64 位版本的区别因此这里通过 ro.zygote 属性来控制启动不同版本的 Zyogte 进程。 ro.zygote 属性的取值可能有以下情况zygote32zygote64zygote32_64zygote64_32在系统路径 /system/core/rootdir 同级目录下对应四个关于 zygote 的 rc 文件匹配 zygote 的启动。 /android/system/core/rootdir$ ls -l -rw-r--r-- 1 domain users 959 Nov 9 2022 init.zygote32_64.rc -rw-r--r-- 1 domain users 563 Nov 9 2022 init.zygote32.rc -rw-r--r-- 1 domain users 981 Nov 9 2022 init.zygote64_32.rc -rw-r--r-- 1 domain users 565 Nov 9 2022 init.zygote64.rc那么现在我们的版本中对于 ro.zygote 属性值是如何定义的呢如下所示 项目:/ $ getprop | grep -i ro.zygote [ro.zygote]: [zygote64_32]现在的项目中使用的是 ro.zygote zygote64_32也就是对应使用 init.zygote64_32.rc 文件启动 Zygote 进程。 这四个 rc 文件对应了 Android 中支持的四种运行模式。 init.zygote32.rc 纯32位模式 init.zygote32_64.rc 混32位模式即32位为主64位为辅 init.zygote64.rc 纯64位模式 init.zygote64_32.rc 混64位模式即64位为主32位为辅1.1 init.zygote32.rc 下面是 init.zygote32.rc 文件内容系统使用此 rc 文件zygote 将会以 32 位模式运行。 service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-serverclass mainpriority -20user rootgroup root readproc reserved_disksocket zygote stream 660 root systemsocket usap_pool_primary stream 660 root systemonrestart write /sys/android_power/request_state wakeonrestart write /sys/power/state ononrestart restart audioserveronrestart restart cameraserveronrestart restart mediaonrestart restart netdonrestart restart wificondwritepid /dev/cpuset/foreground/tasks1.2 init.zygote32_64.rc 下面是 init.zygote32_64.rc 文件文件内容系统使用此 rc 文件会启动两个 zygote 进程32 位和 64 位两种服务32 位为主64 位为辅。 service zygote /system/bin/app_process32 -Xzygote /system/bin --zygote --start-system-server --socket-namezygoteclass mainpriority -20user rootgroup root readproc reserved_disksocket zygote stream 660 root systemsocket usap_pool_primary stream 660 root systemonrestart write /sys/android_power/request_state wakeonrestart write /sys/power/state ononrestart restart audioserveronrestart restart cameraserveronrestart restart mediaonrestart restart netdonrestart restart wificondwritepid /dev/cpuset/foreground/tasksservice zygote_secondary /system/bin/app_process64 -Xzygote /system/bin --zygote --socket-namezygote_secondaryclass mainpriority -20user rootgroup root readproc reserved_disksocket zygote_secondary stream 660 root systemsocket usap_pool_secondary stream 660 root systemonrestart restart zygotewritepid /dev/cpuset/foreground/tasks1.3 init.zygote64.rc 下面是 init.zygote64.rc 文件内容系统使用此 rc 文件zygote 将会运行在 64 位模式。 service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-serverclass mainpriority -20user rootgroup root readproc reserved_disksocket zygote stream 660 root systemsocket usap_pool_primary stream 660 root systemonrestart write /sys/android_power/request_state wakeonrestart write /sys/power/state ononrestart restart audioserveronrestart restart cameraserveronrestart restart mediaonrestart restart netdonrestart restart wificondwritepid /dev/cpuset/foreground/tasks1.4 init.zygote64_32.rc 下面是 init.zygote64_32.rc 文件内容系统使用此 rc 文件将会启动两个zygote 进程64 位和 32 位64 位为主32 位为辅。 service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-namezygoteclass mainpriority -20user rootgroup root readproc reserved_disksocket zygote stream 660 root systemsocket usap_pool_primary stream 660 root systemonrestart write /sys/android_power/request_state wakeonrestart write /sys/power/state ononrestart restart audioserveronrestart restart cameraserveronrestart restart mediaonrestart restart netdonrestart restart wificondwritepid /dev/cpuset/foreground/tasksservice zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-namezygote_secondary --enable-lazy-preloadclass mainpriority -20user rootgroup root readproc reserved_disksocket zygote_secondary stream 660 root systemsocket usap_pool_secondary stream 660 root systemonrestart restart zygotewritepid /dev/cpuset/foreground/tasks项目上现在使用的 rc 文件是 init.zygote64_32.rc 文件我们来简单分析下文件内容 从 rc 文件中我们可以看出定义了两个 zygote 服务zygote 和 zygote_secondary。 zygote 是作为主服务用于处理 64 位的程序对应启动的可执行文件是 app_process64 启动的参数是“-Xzygote /system/bin --zygote --start-system-server --socket-namezygote” 定义了名为 zygote 的 Socket onrestart 指的是当 zygote 进程重启时执行后面的指令比如写入电源状态、重启系统服务等 当创建子进程时在 /dev/cpuset/foreground/tasks 里写入 pid。 zygote_secondary 是作为辅服务用于处理 32 位的程序对应启动的可执行文件是 app_process32 启动的参数是“-Xzygote /system/bin --zygote --socket-namezygote_secondary --enable-lazy-preload” 定义了名为 zygote_secondary 的 Socket 当 zygote_secondary 进程重启时重启 zygote 服务 当创建子进程时在 /dev/cpuset/foreground/tasks 下写入 pid。 2、app_process app_process 是启动 zygote 时执行的程序。app_process 是 Android 上一个原生程序是 APP 进程的主入口点不仅是说可以启动 zygote 进程还可以启动任何其他的 APP简单理解为是一个可以使用虚拟机运行 main 函数的程序。 2.1 代码路径 app_process 的代码路径位于 /android/frameworks/base/cmds/app_process 路径下。文件结构如下 ubuntu16-017:~/workspace/src/android/frameworks/base/cmds/app_process$ ls -l total 28 -rw-r--r-- 1 domain users 1992 Nov 9 2022 Android.mk -rw-r--r-- 1 domain users 12019 Nov 9 2022 app_main.cpp -rw-r--r-- 1 domain users 0 Nov 9 2022 MODULE_LICENSE_APACHE2 -rw-r--r-- 1 domain users 10695 Nov 9 2022 NOTICE2.2 编译 编译文件是 /android/frameworks/base/cmds/app_process/Android.mk下面我们来看下编译 LOCAL_PATH: $(call my-dir)// 编译所需依赖库 app_process_common_shared_libs : \libandroid_runtime \libbinder \libcutils \libdl \libhidlbase \liblog \libnativeloader \libutils \# This is a list of libraries that need to be included in order to avoid # bad apps. This prevents a library from having a mismatch when resolving # new/delete from an app shared library. # See b/21032018 for more details. app_process_common_shared_libs \libwilhelm \app_process_common_static_libs : \libsigchain \// 编译的文件 app_process_src_files : \app_main.cpp \app_process_cflags : \-Wall -Werror -Wunused -Wunreachable-codeapp_process_ldflags_32 : \-Wl,--version-script,art/sigchainlib/version-script32.txt -Wl,--export-dynamic app_process_ldflags_64 : \-Wl,--version-script,art/sigchainlib/version-script64.txt -Wl,--export-dynamicinclude $(CLEAR_VARS)LOCAL_SRC_FILES: $(app_process_src_files)LOCAL_LDFLAGS_32 : $(app_process_ldflags_32) LOCAL_LDFLAGS_64 : $(app_process_ldflags_64)LOCAL_SHARED_LIBRARIES : $(app_process_common_shared_libs)LOCAL_WHOLE_STATIC_LIBRARIES : $(app_process_common_static_libs)// 编译模块名为 app_process LOCAL_MODULE: app_process /* * LOCAL_MULTILIB 可以指定模块编译 32 位或者 64 位或者都编译 * 值可选 * “both”: build both 32-bit and 64-bit. * “32”: build only 32-bit. * “64”: build only 64-bit. * “first”: build for only the first arch (32-bit in 32-bit devices and 64-bit in 64-bit devices). * “”: the default; the build system decides what arch to build based on the module class and other LOCAL_ variables, such as LOCAL_MODULE_TARGET_ARCH, LOCAL_32_BIT_ONLY, etc. */ LOCAL_MULTILIB : both // 32 位可执行文件名为 app_process32 LOCAL_MODULE_STEM_32 : app_process32 // 64 位可执行文件名为 app_process64 LOCAL_MODULE_STEM_64 : app_process64LOCAL_CFLAGS $(app_process_cflags)# In SANITIZE_LITE mode, we create the sanitized binary in a separate location (but reuse # the same module). Using the same module also works around an issue with make: binaries # that depend on sanitized libraries will be relinked, even if they set LOCAL_SANITIZE : never. # # Also pull in the asanwrapper helper. ifeq ($(SANITIZE_LITE),true) LOCAL_MODULE_PATH : $(TARGET_OUT_EXECUTABLES)/asan LOCAL_REQUIRED_MODULES : asanwrapper endif// 编译可执行文件 include $(BUILD_EXECUTABLE)# Create a symlink from app_process to app_process32 or 64 # depending on the target configuration. ifneq ($(SANITIZE_LITE),true) include $(BUILD_SYSTEM)/executable_prefer_symlink.mk endif 2.3 使用介绍 从参数介绍到进程的启动创建虚拟机通过反射启动。 用法如下 app_process [vm-options] [工作目录] [options] 类名 [类的main方法参数] [类的main方法参数] ....参数如下 vm-options – VM 选项 work-dir –工作目录(如/system/bin,/data/app,/data/...) options –运行的参数 :–-zygote 启动 zygote 进程用的–-start-system-server–-application (api14) 启动应用程序–-nice-namenice_proc_name (api14) (只有非--zygote模式下该选项才会生效) [启动类名] –包含main方法的主类 (如com.android.internal.os.WrapperInit) main-options –启动时候传递到main方法中的参数到这里我们简单来概述一下app_process 是用来启动程序的工具可以启动 zygote 这样的系统服务也可以启动 apk 这样的应用进程也可以执行 java 程序。这里根据传入的参数可以分为 zygote 模式和 非 zygote 模式。有以下注意点 传入 –zygote 会启动 com.android.internal.os.ZygoteInit否则启动 com.android.internal.os.RuntimeInit。–start-system-server 只在启动 zygote 时有效。在非 zygote 模式中有无 –application 的选项的区别只是是否将 stdout 和 stderr 重定向到 AndroidPrintStream。只有在非 zygote 的情况下–nice-name 选项有效。 示例 1、启动 zygote 进程命令 app_process -Xzygote /system/bin --zygote --start-system-server --socket-namezygote2、启动 com.android.test 应用命令 app_process -Djava.class.path/sdcard/classes.dex /data/local/tmp --application --nice-namehelloservice com.android.test.HelloWorld 1 2 a2、启动 com.android.test 应用命令通过 apk 的方式 app_process -Djava.class.path/sdcard/app.apk /data/local com.android.test.HelloWorld2.4 代码分析 2.4.1 app_main app_process 程序的执行文件是 app_main.cpp 文件入口是 main() 函数。文件路径为/android/frameworks/base/cmds/app_process/app_main.cpp。 #if defined(__LP64__) // 如果为 64 位进程则进程名为 zygote64否则为 zygote static const char ABI_LIST_PROPERTY[] ro.product.cpu.abilist64; static const char ZYGOTE_NICE_NAME[] zygote64; #else static const char ABI_LIST_PROPERTY[] ro.product.cpu.abilist32; static const char ZYGOTE_NICE_NAME[] zygote; #endif----------------------------------------------------------------------------------------- -----------------------------------------------------------------------------------------int main(int argc, char* const argv[]) {----------------------------------------------------------------------------------------- 1、创建 AppRuntime 对象AppRuntime 类用于创建和初始化虚拟机。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());}// 创建 AppRuntime 对象AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));// Process command line arguments argv[0] /system/bin/app_process// ignore argv[0] 跳过 argv[0] 参数argc--;argv;----------------------------------------------------------------------------------------- 2、从给定参数中解析 Java-Option 参数并把参数添加到 AppRuntime 中// Everything up to -- or first non - arg goes to the vm.// 直到遇到 - 或第一个非 - 的参数为止的所有内容都将提供给虚拟机作为 options。// 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 启动到 zygote 模式// --start-system-server : Start the system server. 启动 system server// --application : Start in application (stand alone, non zygote) mode. 以应用程序模式启动 (独立启动, 非 zygote)// --nice-name : The nice name for this process. 给进程起一个名字//// 对于非 zygote 启动这些参数后面将是主类名所有其余的参数都传递给此类的 main 方法// 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.// // 对于 zygote 启动所有剩余的参数都传递给 zygote 的 main 方法。// 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 dont ever free the above// string. Since the allocation is from main, leaking it doesnt seem// problematic. NOLINTNEXTLINEALOGV(app_process main add known option %s, argv[i]);known_command false;continue;}for (int j 0;j static_castint(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;}// 将参数添加到 AppRuntime 中runtime.addOption(strdup(argv[i]));// The static analyzer gets upset that we dont ever free the above// string. Since the allocation is from main, leaking it doesnt seem// problematic. NOLINTNEXTLINEALOGV(app_process main add option %s, argv[i]);}-----------------------------------------------------------------------------------------这里继续解析参数将信息保存在 zygote、startSystemServer、application 等变量中。// 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;}}----------------------------------------------------------------------------------------- 3、准备 ZygoteInit 或 RuntimeInit 启动所需要的参数VectorString8 args;// 没有处于 zygote 模式if (!className.isEmpty()) {// Were 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 {// Were in zygote mode.// className 为空处于 zygote 模式// 创建 /data/dalvik-cache/ 目录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 列表args.add(abiFlag);// In zygote mode, pass all remaining arguments to the zygote// main() method.// 在 zygote 模式下将所有剩余参数传递给 zygote 的 main() 方法。for (; i argc; i) {args.add(String8(argv[i]));}}----------------------------------------------------------------------------------------- 4、设置进程名称if (!niceName.isEmpty()) {runtime.setArgv0(niceName.string(), true /* setProcName */);}----------------------------------------------------------------------------------------- 5、启动 ZygoteInit 或者 RuntimeInit 程序。if (zygote) {// 启动 zygote 服务runtime.start(com.android.internal.os.ZygoteInit, args, zygote);} else if (className) {// 启动 application 服务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.);} }那么这里总结 app_process 程序的功能 初始化 AppRuntime 对象从命令行中解析参数并把参数都添加到 AppRuntime 中判断启动功能zygote、application并且准备对应启动参数设置进程名称调用 AppRuntime.start 函数启动 zygote 或者 application 2.4.2 AndroidRuntime/AppRuntime AppRuntime 直译的话叫做应用运行时开发时我们写好 Java/Kotlin 代码通过对应的编译器将代码编译为字节码AppRuntime 的作用就是创建一个可以执行字节码的环境这个环境主要由两部分内容构成 一部分负责对象的创建与回收譬如类的加载器垃圾回收器等一部分负责程序逻辑的运行譬如即时编译系统解释器等 AppRuntime 类定义在 app_main.cpp 中继承了 AndroidRuntime 类app_process 启动程序是会初始化一个 AndroidRuntime 对象下面是 AndroidRuntime 对象的构造函数 AndroidRuntime::AndroidRuntime(char* argBlockStart, const size_t argBlockLength) :mExitWithoutCleanup(false),mArgBlockStart(argBlockStart),mArgBlockLength(argBlockLength) {// 初始化 skia 图形系统SkGraphics::Init();// Pre-allocate enough space to hold a fair number of options.// 预先分配空间来存放传入虚拟机的参数mOptions.setCapacity(20);// 每个进程只能初始化一次assert(gCurRuntime NULL); // one per processgCurRuntime this; }app_process 调用 AppRuntime.start 函数会调用到 AndroidRuntime 中AppRuntime 是在 app_main.cpp 文件中定义的 AndroidRuntime 的子类。 AndroidRuntime 的代码在 /android/frameworks/base/core/jni/AndroidRuntime.cpp 文件中下面来看下 start 函数的功能 // AndroidRuntime.cppvoid AndroidRuntime::start(const char* className, const VectorString8 options, bool zygote) {// 打印启动服务日志ALOGD( START %s uid %d \n,className ! NULL ? className : (unknown), getuid());static const String8 startSystemServer(start-system-server);for (size_t i 0; i options.size(); i) {if (options[i] startSystemServer) {const int LOG_BOOT_PROGRESS_START 3000;LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START, ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));}}// 获取 system 启动目录// 系统目录从环境变量 ANDROID_ROOT 中读取。如果说取失败则默认设置目录为/system。如果连/system也没有则 Zygote 进程会退出。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);}// 通过 jni_invocation.Init(NULL) 完成 jni 接口的初始化JniInvocation jni_invocation;jni_invocation.Init(NULL);JNIEnv* env;// 创建虚拟机if (startVm(mJavaVM, env, zygote) ! 0) {return;}// onVimCreate() 是一个虚函数调用它实际上调用的是继承类的 AppRuntime 中的重载函数。onVmCreated(env);// 注册系统类 JNI 方法// startReg() 函数通过调用 register_jni_procs() 函数将全局的 gRegJNI 中的本地 JNI 函数在虚拟机中注册if (startReg(env) 0) {ALOGE(Unable to register all android natives\n);return;}// 为启动 Java 类的 main 函数做准备jclass stringClass;jobjectArray strArray;jstring classNameStr;stringClass env-FindClass(java/lang/String);assert(stringClass ! NULL);// Java: strArray new String[options.size() 1];strArray env-NewObjectArray(options.size() 1, stringClass, NULL);assert(strArray ! NULL);classNameStr env-NewStringUTF(className);assert(classNameStr ! NULL);// Java: strArray[0] com.android.internal.os.ZygoteInit;env-SetObjectArrayElement(strArray, 0, classNameStr);// 将相关参数收集至 options 中下面会传递给 ZygoteInit// --start-system-server, --abi-listarm64-v8a ...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);}// 转换为 JNI 格式类名com/android/internal/os/ZygoteInitchar* slashClassName toSlashClassName(className);jclass startClass env-FindClass(slashClassName);if (startClass NULL) {ALOGE(JavaVM unable to locate class %s\n, slashClassName);} else {// 通过 GetStaticMethodID 函数来获取 main() 方法的 idjmethodID startMeth env-GetStaticMethodID(startClass, main,([Ljava/lang/String;)V);if (startMeth NULL) {ALOGE(JavaVM unable to find main() in %s\n, className);} else {// 调用 ZygoteInit.main() 调用 Java 层方法;env-CallStaticVoidMethod(startClass, startMeth, strArray);}}free(slashClassName);ALOGD(Shutting down VM\n);// 关闭 Java 虚拟机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() 函数的功能如下 创建了一个 JniInvocation 的实例并且调用它的成员函数 init 来初始化 JNI 环境。startVm 函数创建虚拟机及对应的 JNI 接口即 JavaVM 接口和 JNIEnv 接口。startVm 函数中主要是 设置虚拟机配置参数 以及 创建虚拟机实例创建虚拟机后每一个进程应该具有一个 JavaVM 指针而每一个线程都具有一个 JNIEnv 指针。startReg 函数注册系统 JNI 方法收集 options 参数加载指定的 class JavaVMJava Virtual Machine和 JNIEnvJava Native Interface Environment是 Java Native InterfaceJNI中两个重要的概念它们在实现 Java 与本地代码之间的交互时起着重要的作用。JavaVMJavaVM 是一个代表 Java 虚拟机的结构体指针它提供了一系列 JNI 函数可以用于创建 Java 虚拟机、获取当前 Java 虚拟机等操作。JavaVM 提供了一种机制可以在本地方法中获取对 Java 虚拟机的访问从而可以在本地代码中操作 Java 对象、调用 Java 方法等功能。JavaVM 的作用是为本地代码提供对 Java 虚拟机的操作接口使得本地代码能够与 Java 虚拟机进行交互。JNIEnvJNIEnv 是一个代表 JNI 环境的指针类型它是通过 JavaVM 获取到的每个线程都会有一个对应的 JNIEnv。JNIEnv 提供了一系列 JNI 函数可以用于在本地代码中访问 Java 对象、调用 Java 方法、处理异常等操作。通过 JNIEnv本地代码可以与 Java 代码进行通信操作 Java 对象并实现 Java 与本地代码之间的数据传递和交互。总的来说JavaVM 提供了对 Java 虚拟机的操作接口而 JNIEnv 则提供了 JNI 环境的相关操作接口这两者协同工作使得本地代码能够与 Java 代码进行交互实现 Java 与本地代码的互通。时序图 这里考虑把时序图放在前面总结描述。 这里可以画一张 app_main 和 AndroidRuntime 的初始化和交互逻辑图包括再到 JNI 并通过反射找到对应函数的时序。 3、zygote 启动 zygote 启动时传入的参数是com.android.internal.os.ZygoteInit。那么在通过 app_process 程序启动时最终会通过反射找到 ZygoteInit 文件作为 Zygote 的入口文件。 本节将会从 ZygoteInit 文件开始描述 Zygote 在启动过程中提供的功能。 3.1 时序图 时序图如下所示 时序图简要描述 从时序图中我们可以大致整理 Zygote 进程在 Android 初始化过程中提供的功能。 首先第一点预加载资源。Android 中有很多资源是可以共享的在启动阶段进行预加载可以在后续的进程中共享资源也就避免了后续再去加载的动作这样对于后续进程的启动、运行有很大的提升。这里的预加载并没有一次性完成而是在线程中分步完成。这里是一次修改变更由原来在一个函数中完成资源的预加载变更为开启不同的子线程去加载不同的资源等待子线程完成预加载之后zygote 进程再去执行后续的动作。 第二点初始化 ZygoteServer 类。ZygoteServer 会去创建 Zygote 所需的 Socket 对象用于后续的 socket 通信。 第三点fork SystemServer 进程。启动 SystemServer 服务。 第四点开启循环监听 Socket 通信。 3.2 Zygote 启动流程 前面提到在 app_process 会找到 ZygoteInit 作为 Zygote 的入口文件执行 main() 函数。 ZygoteInit 文件路径为/android/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java public static void main(String argv[]) {----------------------------------------------------------------------------------------- 1、设置进程 group id记录时间和 Trace 信息启动 DDMS 虚拟机监控服务ZygoteServer zygoteServer null;// Mark zygote start. This ensures that thread creation will throw// an error.// 调用此方法后虚拟机会拒绝线程的创建如果此时创建线程会产生异常ZygoteHooks.startZygoteNoThreadCreation();// Zygote goes into its own process group.// 设置 zygote 进程的 group idtry {Os.setpgid(0, 0);} catch (ErrnoException ex) {throw new RuntimeException(Failed to setpgid(0,0), ex);}Runnable caller;try {// Report Zygote start time to tron unless it is a runtime restart// 记录一些时间信息用于性能分析if (!1.equals(SystemProperties.get(sys.boot_completed))) {MetricsLogger.histogram(null, boot_zygote_init,(int) SystemClock.elapsedRealtime());}// 记录 trace 信息String bootTimeTag Process.is64Bit() ? Zygote64Timing : Zygote32Timing;TimingsTraceLog bootTimingsTraceLog new TimingsTraceLog(bootTimeTag,Trace.TRACE_TAG_DALVIK);bootTimingsTraceLog.traceBegin(ZygoteInit);// 启动 DDMS 虚拟机监控调试服务RuntimeInit.enableDdms();----------------------------------------------------------------------------------------- 2、解析参数预加载资源boolean startSystemServer false;String zygoteSocketName zygote;String abiList null;boolean enableLazyPreload false;for (int i 1; i argv.length; i) {if (start-system-server.equals(argv[i])) {// 判断是否开启 SystemServerstartSystemServer true;} else if (--enable-lazy-preload.equals(argv[i])) {// 是否启动延时加载enableLazyPreload true;} else if (argv[i].startsWith(ABI_LIST_ARG)) {// 获取 abi 类型一个 CPU 对应一个 abiabiList argv[i].substring(ABI_LIST_ARG.length());} else if (argv[i].startsWith(SOCKET_NAME_ARG)) {// 获取 zygote socket 的名字zygoteSocketName argv[i].substring(SOCKET_NAME_ARG.length());} else {throw new RuntimeException(Unknown command line argument: argv[i]);}}// 通过 zygote socket 的名字判断是否是主 zygote。final boolean isPrimaryZygote zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME);// 没有指定 abi 会有异常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());//multithread to do preload start//preload(bootTimingsTraceLog);// 预加载资源partialPreload(bootTimingsTraceLog);//multithread to do preload endEventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,SystemClock.uptimeMillis());bootTimingsTraceLog.traceEnd(); // ZygotePreload} else {Zygote.resetNicePriority();}bootTimingsTraceLog.traceEnd(); // ZygoteInit// Disable tracing so that forked processes do not inherit stale tracing tags from// Zygote.Trace.setTracingEnabled(false, 0);----------------------------------------------------------------------------------------- 3、初始化 ZygoteServer 服务类用于注册 socket 监听创建 SystemServer 进程// 执行一些初始化操作Zygote.initNativeState(isPrimaryZygote);// 与 startZygoteNoThreadCreation 函数对应虚拟机可以创建线程了ZygoteHooks.stopZygoteNoThreadCreation();// 初始化 ZygoteServer 进程管理 socket 注册监听zygoteServer new ZygoteServer(isPrimaryZygote);if (startSystemServer) {// fork SystemServer 进程Runnable r forkSystemServer(abiList, zygoteSocketName, zygoteServer);// {code r null} in the parent (zygote) process, and {code r ! null} in the// child (system_server) process.// 如果 r 为空说明是父进程 zygote无任何处理继续执行// 如果 r 不为空说明是子进程 SystemServer启动后直接返回if (r ! null) {r.run();return;}}----------------------------------------------------------------------------------------- 4、在线程中预加载资源包括 Class、Resources、SharedLibraries、openGL 资源等。开启一个无限循环处理 socket 信息Log.i(TAG, Accepting command socket connections);//multithread to do preload startif (!enableLazyPreload) {Thread loadClassThread new Thread(new Runnable() {public void run() {// 在线程中预加载 Classes 资源preloadClasses();}});loadClassThread.start();Thread loadResourceThread new Thread(new Runnable() {public void run() {// 在线程中预加载 Resources 资源preloadResources();}});loadResourceThread.start();Thread loadLibraryThread new Thread(new Runnable() {public void run() {// 在线程中预加载 SharedLibraries 资源preloadSharedLibraries();// 在线程中预加载 openGL 资源maybePreloadGraphicsDriver();}});loadLibraryThread.start();try {loadClassThread.join();loadResourceThread.join();loadLibraryThread.join();// Do an initial gc to clean up after startupbootTimingsTraceLog.traceBegin(PostZygoteInitGC);gcAndFinalize();bootTimingsTraceLog.traceEnd(); // PostZygoteInitGC} catch(Exception e){}}//multithread to do preload end// The select loop returns early in the child process after a fork and// loops forever in the zygote.// 调用 ZygoteServer 开启一个无限循环处理 socket 信息caller zygoteServer.runSelectLoop(abiList);} catch (Throwable ex) {Log.e(TAG, System zygote died with exception, ex);throw ex;} finally {if (zygoteServer ! null) {zygoteServer.closeServerSocket();}}// Were in the child process and have exited the select loop. Proceed to execute the// command.// 执行新进程的主函数if (caller ! null) {caller.run();} }说明点 1、预加载资源由原来的全部加载变为线程中加载可以提高运行效率减少开机时间。控制参数是 --enable-lazy-preload仅有在 init.zygote64_32.rc 中的 zygote64 中有此参数说明在现有代码逻辑中仅有 zygote64 才会在启动时预加载资源。 首先第一点预加载资源。Android 中有很多资源是可以共享的在启动阶段进行预加载可以在后续的进程中共享资源也就避免了后续再去加载的动作这样对于后续进程的启动、运行有很大的提升。这里的预加载并没有一次性完成而是在线程中分步完成。这里是一次修改变更由原来在一个函数中完成资源的预加载变更为开启不同的子线程去加载不同的资源等待子线程完成预加载之后zygote 进程再去执行后续的动作。 第二点初始化 ZygoteServer 类。ZygoteServer 会去创建 Zygote 所需的 Socket 对象用于后续的 socket 通信。 第三点fork SystemServer 进程。启动 SystemServer 服务。 第四点开启循环监听 Socket 通信。 3.2.1 预加载资源 预加载资源主要是进行一些 类、资源、共享库的预加载工作以提升运行时效率。封装的函数包括 preloadClasses()、preloadResources()、preloadSharedLibraries() 等我们来简单看一下对于这些资源是如何加载的。 private static void preloadClasses() {final VMRuntime runtime VMRuntime.getRuntime();InputStream is;try {// /system/etc/preloaded-classesis new FileInputStream(PRELOADED_CLASSES);} catch (FileNotFoundException e) {Log.e(TAG, Couldnt find PRELOADED_CLASSES .);return;}Log.i(TAG, Preloading classes...);long startTime SystemClock.uptimeMillis();// Drop root perms while running static initializers.final int reuid Os.getuid();final int regid Os.getgid();// We need to drop root perms only if were already root. In the case of wrapped// processes (see WrapperInit), this function is called from an unprivileged uid// and gid.boolean droppedPriviliges false;if (reuid ROOT_UID regid ROOT_GID) {try {Os.setregid(ROOT_GID, UNPRIVILEGED_GID);Os.setreuid(ROOT_UID, UNPRIVILEGED_UID);} catch (ErrnoException ex) {throw new RuntimeException(Failed to drop root, ex);}droppedPriviliges true;}// Alter the target heap utilization. With explicit GCs this// is not likely to have any effect.float defaultUtilization runtime.getTargetHeapUtilization();runtime.setTargetHeapUtilization(0.8f);try {BufferedReader br new BufferedReader(new InputStreamReader(is), Zygote.SOCKET_BUFFER_SIZE);int count 0;String line;while ((line br.readLine()) ! null) {// Skip comments and blank lines.line line.trim();if (line.startsWith(#) || line.equals()) {continue;}Trace.traceBegin(Trace.TRACE_TAG_DALVIK, line);try {if (false) {Log.v(TAG, Preloading line ...);}// Load and explicitly initialize the given class. Use// Class.forName(String, boolean, ClassLoader) to avoid repeated stack lookups// (to derive the callers class-loader). Use true to force initialization, and// null for the boot classpath class-loader (could as well cache the// class-loader of this class in a variable).Class.forName(line, true, null);count;} catch (ClassNotFoundException e) {Log.w(TAG, Class not found for preloading: line);} catch (UnsatisfiedLinkError e) {Log.w(TAG, Problem preloading line : e);} catch (Throwable t) {Log.e(TAG, Error preloading line ., t);if (t instanceof Error) {throw (Error) t;}if (t instanceof RuntimeException) {throw (RuntimeException) t;}throw new RuntimeException(t);}Trace.traceEnd(Trace.TRACE_TAG_DALVIK);}Log.i(TAG, ...preloaded count classes in (SystemClock.uptimeMillis() - startTime) ms.);} catch (IOException e) {Log.e(TAG, Error reading PRELOADED_CLASSES ., e);} finally {IoUtils.closeQuietly(is);// Restore default.runtime.setTargetHeapUtilization(defaultUtilization);// Fill in dex caches with classes, fields, and methods brought in by preloading.Trace.traceBegin(Trace.TRACE_TAG_DALVIK, PreloadDexCaches);runtime.preloadDexCaches();Trace.traceEnd(Trace.TRACE_TAG_DALVIK);// Bring back root. Well need it later if were in the zygote.if (droppedPriviliges) {try {Os.setreuid(ROOT_UID, ROOT_UID);Os.setregid(ROOT_GID, ROOT_GID);} catch (ErrnoException ex) {throw new RuntimeException(Failed to restore root, ex);}}}}上面是加载 类 资源加载逻辑是读取 /system/etc/preloaded-classes 文件并通过 Class.forName() 方法逐行加载文件中声明的类。提前预加载系统常用的类可以提升运行效率但是这个预加载的过程耗时等资源消耗比较多。在源码目录 /android/frameworks/base/config 下存在 preloaded-classes 文件存放着启动启动时需要加载的常用类。下面是部分资源加载内容 android.app.Activity android.app.ActivityManager$1 android.app.ActivityManager$AppTask android.app.ActivityManager$MemoryInfo$1 android.app.ActivityManager$MemoryInfo android.app.ActivityManager$OnUidImportanceListener android.app.ActivityManager$RecentTaskInfo$1 android.app.ActivityManager$RecentTaskInfo android.app.ActivityManager$RunningAppProcessInfo$1 android.app.ActivityManager$RunningAppProcessInfo android.app.ActivityManager$RunningServiceInfo$1 android.app.ActivityManager$RunningServiceInfo android.app.ActivityManager$RunningTaskInfo$1 android.app.ActivityManager$RunningTaskInfo android.app.ActivityManager$TaskDescription$1 android.app.ActivityManager$TaskDescription android.app.ActivityManager$UidObserver android.app.ActivityManager下面是预加载资源 preloadResources() 函数 private static void preloadResources() {final VMRuntime runtime VMRuntime.getRuntime();try {mResources Resources.getSystem();mResources.startPreloading();if (PRELOAD_RESOURCES) {Log.i(TAG, Preloading resources...);long startTime SystemClock.uptimeMillis();TypedArray ar mResources.obtainTypedArray(com.android.internal.R.array.preloaded_drawables);int N preloadDrawables(ar);ar.recycle();Log.i(TAG, ...preloaded N resources in (SystemClock.uptimeMillis() - startTime) ms.);startTime SystemClock.uptimeMillis();ar mResources.obtainTypedArray(com.android.internal.R.array.preloaded_color_state_lists);N preloadColorStateLists(ar);ar.recycle();Log.i(TAG, ...preloaded N resources in (SystemClock.uptimeMillis() - startTime) ms.);if (mResources.getBoolean(com.android.internal.R.bool.config_freeformWindowManagement)) {startTime SystemClock.uptimeMillis();ar mResources.obtainTypedArray(com.android.internal.R.array.preloaded_freeform_multi_window_drawables);N preloadDrawables(ar);ar.recycle();Log.i(TAG, ...preloaded N resource in (SystemClock.uptimeMillis() - startTime) ms.);}}mResources.finishPreloading();} catch (RuntimeException e) {Log.w(TAG, Failure preloading resources, e);}}预加载资源是定义在 /android/frameworks/base/core/res/res/values/arrays.xml 文件下的预加载资源如下 com.android.internal.R.array.preloaded_drawables com.android.internal.R.array.preloaded_color_state_lists com.android.internal.R.bool.config_freeformWindowManagement下面是 /android/frameworks/base/core/res/res/values/arrays.xml 文件中定义的部分内容 array namepreloaded_drawablesitemdrawable/action_bar_item_background_material/itemitemdrawable/activated_background_material/item... /arrayarray namepreloaded_color_state_listsitemcolor/primary_text_dark/itemitemcolor/primary_text_dark_disable_only/item... /arrayarray namepreloaded_freeform_multi_window_drawablesitemdrawable/decor_maximize_button_dark/itemitemdrawable/decor_maximize_button_light/item /array下面是预加载共享库 preloadSharedLibraries() 函数 private static void preloadSharedLibraries() {Log.i(TAG, Preloading shared libraries...);System.loadLibrary(android);System.loadLibrary(compiler_rt);System.loadLibrary(jnigraphics);}预加载共享库函数是预加载了三个共享库libandroid.so、libcompiler_rt.so 和 libjnigraphics.so。 3.2.2 初始化 ZygoteServer Zygote 通过 ZygoteServer 封装了对于 socket 通信的操作。 下面是 ZygoteServer 初始化函数 ZygoteServer(boolean isPrimaryZygote) {mUsapPoolEventFD Zygote.getUsapPoolEventFD();// 这里通过 Zygote.createManagedSocketFromInitSocket 创建 LocalServerSocket 对象。if (isPrimaryZygote) {mZygoteSocket Zygote.createManagedSocketFromInitSocket(Zygote.PRIMARY_SOCKET_NAME);mUsapPoolSocket Zygote.createManagedSocketFromInitSocket(Zygote.USAP_POOL_PRIMARY_SOCKET_NAME);} else {mZygoteSocket Zygote.createManagedSocketFromInitSocket(Zygote.SECONDARY_SOCKET_NAME);mUsapPoolSocket Zygote.createManagedSocketFromInitSocket(Zygote.USAP_POOL_SECONDARY_SOCKET_NAME);}fetchUsapPoolPolicyProps();mUsapPoolSupported true;}ZygoteServer 函数创建 LocalServerSocket 对象来进行 Socket 通信。 static LocalServerSocket createManagedSocketFromInitSocket(String socketName) {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(Socket unset or invalid: fullSocketName, ex);}try {FileDescriptor fd new FileDescriptor();fd.setInt$(fileDesc);return new LocalServerSocket(fd);} catch (IOException ex) {throw new RuntimeException(Error building socket from file descriptor: fileDesc, ex);}}下面是 Android Socket 的通信架构图 LocalSocket 就是作为客户端建立于服务端的连接发送数据。LocalServerSocket 作为服务端使用建立服务端的 socket 监听客户端请求。 3.2.3 复制 SystemServer 进程 Zygote 进程在会复制 SystemServer 继续 Android 的启动。调用函数是 forkSystemServer 函数。 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 ((long) data[0].effective) | (((long) data[1].effective) 32);// 启动参数/* Hardcoded command line to start the system server */String args[] {--setuid1000,--setgid1000,--setgroups1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023, 1024,1032,1065,3001,3002,3003,3006,3007,3009,3010,--capabilities capabilities , capabilities,--nice-namesystem_server,--runtime-args,--target-sdk-version VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,com.android.server.SystemServer,};ZygoteArguments parsedArgs null;int pid;try {parsedArgs new ZygoteArguments(args);Zygote.applyDebuggerSystemProperty(parsedArgs);Zygote.applyInvokeWithSystemProperty(parsedArgs);boolean profileSystemServer SystemProperties.getBoolean(dalvik.vm.profilesystemserver, false);if (profileSystemServer) {parsedArgs.mRuntimeFlags | Zygote.PROFILE_SYSTEM_SERVER;}// fork SystemServer 进程/* Request to fork the system server process */pid Zygote.forkSystemServer(parsedArgs.mUid, parsedArgs.mGid,parsedArgs.mGids,parsedArgs.mRuntimeFlags,null,parsedArgs.mPermittedCapabilities,parsedArgs.mEffectiveCapabilities);} catch (IllegalArgumentException ex) {throw new RuntimeException(ex);}// pid 0 表示子进程从这里开始进入 SystemServer 进程。/* For child process */if (pid 0) {if (hasSecondZygote(abiList)) {waitForSecondaryZygote(socketName);}// 关闭并释放从 Zygote copy 过来的 socketzygoteServer.closeServerSocket(); // 完成新创建的 system_server 进程的剩余工作return handleSystemServerProcess(parsedArgs);}/*** 注意 fork() 函数式一次执行两次返回两个进程对同一程序的两次执行。* pid 0 说明还是父进程。pid 0 说明进入了子进程* 所以这里的 return null 依旧会执行 */return null;}从上面的启动参数可以看到SystemServer 进程的 uid 和 gid 都是 1000进程名是 system_server其最后要加载的类名是 com.android.server.SystemServer。准备好一系列参数之后通过 ZygoteConnection.Arguments() 拼接接着调用 Zygote.forkSystemServer() 方法真正的 fork 出子进程 system_server。 public static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {ZygoteHooks.preFork();// Resets nice priority for zygote process.resetNicePriority();// 这里最终调用 nativeForkSystemServer 去执行 fork 操作。int pid nativeForkSystemServer(uid, gid, gids, runtimeFlags, rlimits,permittedCapabilities, effectiveCapabilities);// Enable tracing as soon as we enter the system_server.if (pid 0) {Trace.setTracingEnabled(true, runtimeFlags);}ZygoteHooks.postForkCommon();return pid;}最后的 fork() 操作是在 native 层完成的。再回到 ZygoteInit.forkSystemServer() 中执行 fork() 之后的逻辑处理。对于 SystemServer 进程来说fork 函数返回值是 0会继续执行 handleSystemServerProcess() 函数执行 SystemServer 的逻辑。对于 Zygote 进程会启动下一步内容。 3.2.4 开启循环进行 Socket 通信 Zygote 进程在复制 SystemServer 进程后SystemServer 继续执行启动逻辑Zygote 进程会调用 zygoteServer.runSelectLoop() 函数开启循环进行 Socket 通信。 Runnable runSelectLoop(String abiList) {ArrayListFileDescriptor socketFDs new ArrayListFileDescriptor();ArrayListZygoteConnection peers new ArrayListZygoteConnection();// mServerSocket 是之前在 Zygote 中创建的socketFDs.add(mZygoteSocket.getFileDescriptor());peers.add(null);while (true) {fetchUsapPoolPolicyPropsWithMinInterval();int[] usapPipeFDs null;StructPollfd[] pollFDs null;// Allocate enough space for the poll structs, taking into account// the state of the USAP pool for this Zygote (could be a// regular Zygote, a WebView Zygote, or an AppZygote).if (mUsapPoolEnabled) {usapPipeFDs Zygote.getUsapPipeFDs();pollFDs new StructPollfd[socketFDs.size() 1 usapPipeFDs.length];} else {pollFDs new StructPollfd[socketFDs.size()];}/** For reasons of correctness the USAP pool pipe and event FDs* must be processed before the session and server sockets. This* is to ensure that the USAP pool accounting information is* accurate when handling other requests like API blacklist* exemptions.*/int pollIndex 0;for (FileDescriptor socketFD : socketFDs) {pollFDs[pollIndex] new StructPollfd();pollFDs[pollIndex].fd socketFD;pollFDs[pollIndex].events (short) POLLIN;pollIndex;}final int usapPoolEventFDIndex pollIndex;if (mUsapPoolEnabled) {pollFDs[pollIndex] new StructPollfd();pollFDs[pollIndex].fd mUsapPoolEventFD;pollFDs[pollIndex].events (short) POLLIN;pollIndex;for (int usapPipeFD : usapPipeFDs) {FileDescriptor managedFd new FileDescriptor();managedFd.setInt$(usapPipeFD);pollFDs[pollIndex] new StructPollfd();pollFDs[pollIndex].fd managedFd;pollFDs[pollIndex].events (short) POLLIN;pollIndex;}}try {// 有事件来时往下执行没有时就阻塞Os.poll(pollFDs, -1);} catch (ErrnoException ex) {throw new RuntimeException(poll failed, ex);}boolean usapPoolFDRead false;while (--pollIndex 0) {if ((pollFDs[pollIndex].revents POLLIN) 0) {continue;}if (pollIndex 0) {// 有新客户端连接// Zygote server socketZygoteConnection newPeer acceptCommandPeer(abiList);peers.add(newPeer);socketFDs.add(newPeer.getFileDescriptor());} else if (pollIndex usapPoolEventFDIndex) {// Session socket accepted from the Zygote server sockettry {// 处理客户端请求ZygoteConnection connection peers.get(pollIndex);final Runnable command connection.processOneCommand(this);// TODO (chriswailes): Is this extra check necessary?if (mIsForkChild) {// Were in the child. We should always have a command to run at this// stage if processOneCommand hasnt called exec.if (command null) {throw new IllegalStateException(command null);}return command;} else {// Were in the server - we should never have any commands to run.if (command ! null) {throw new IllegalStateException(command ! null);}// We dont know whether the remote side of the socket was closed or// not until we attempt to read from it from processOneCommand. This// shows up as a regular POLLIN event in our regular processing loop.if (connection.isClosedByPeer()) {connection.closeSocket();peers.remove(pollIndex);socketFDs.remove(pollIndex);}}} catch (Exception e) {if (!mIsForkChild) {// Were in the server so any exception here is one that has taken place// pre-fork while processing commands or reading / writing from the// control socket. Make a loud noise about any such exceptions so that// we know exactly what failed and why.Slog.e(TAG, Exception executing zygote command: , e);// Make sure the socket is closed so that the other end knows// immediately that something has gone wrong and doesnt time out// waiting for a response.ZygoteConnection conn peers.remove(pollIndex);conn.closeSocket();socketFDs.remove(pollIndex);} else {// Were in the child so any exception caught here has happened post// fork and before we execute ActivityThread.main (or any other main()// method). Log the details of the exception and bring down the process.Log.e(TAG, Caught post-fork exception in child process., e);throw e;}} finally {// Reset the child flag, in the event that the child process is a child-// zygote. The flag will not be consulted this loop pass after the Runnable// is returned.mIsForkChild false;}} else {// Either the USAP pool event FD or a USAP reporting pipe.// If this is the event FD the payload will be the number of USAPs removed.// If this is a reporting pipe FD the payload will be the PID of the USAP// that was just specialized.long messagePayload -1;try {byte[] buffer new byte[Zygote.USAP_MANAGEMENT_MESSAGE_BYTES];int readBytes Os.read(pollFDs[pollIndex].fd, buffer, 0, buffer.length);if (readBytes Zygote.USAP_MANAGEMENT_MESSAGE_BYTES) {DataInputStream inputStream new DataInputStream(new ByteArrayInputStream(buffer));messagePayload inputStream.readLong();} else {Log.e(TAG, Incomplete read from USAP management FD of size readBytes);continue;}} catch (Exception ex) {if (pollIndex usapPoolEventFDIndex) {Log.e(TAG, Failed to read from USAP pool event FD: ex.getMessage());} else {Log.e(TAG, Failed to read from USAP reporting pipe: ex.getMessage());}continue;}if (pollIndex usapPoolEventFDIndex) {Zygote.removeUsapTableEntry((int) messagePayload);}usapPoolFDRead true;}}// Check to see if the USAP pool needs to be refilled.if (usapPoolFDRead) {int[] sessionSocketRawFDs socketFDs.subList(1, socketFDs.size()).stream().mapToInt(fd - fd.getInt$()).toArray();final Runnable command fillUsapPool(sessionSocketRawFDs);if (command ! null) {return command;}}}}mServerSocket 是 ZygoteInit.main() 中一开始就建立的服务端 socket用于处理客户端请求。一看到 while(true) 就肯定会有阻塞操作。Os.poll() 在有事件来时往下执行否则就阻塞。当有客户端请求过来时调用 ZygoteConnection.processOneCommand() 方法来处理。 Runnable processOneCommand(ZygoteServer zygoteServer) {String args[];ZygoteArguments parsedArgs null;FileDescriptor[] descriptors;try {args Zygote.readArgumentList(mSocketReader);// TODO (chriswailes): Remove this and add an assert.descriptors mSocket.getAncillaryFileDescriptors();} catch (IOException ex) {throw new IllegalStateException(IOException on command socket, ex);}// readArgumentList returns null only when it has reached EOF with no available// data to read. This will only happen when the remote socket has disconnected.if (args null) {isEof true;return null;}int pid -1;FileDescriptor childPipeFd null;FileDescriptor serverPipeFd null;parsedArgs new ZygoteArguments(args);if (parsedArgs.mAbiListQuery) {handleAbiListQuery();return null;}if (parsedArgs.mPidQuery) {handlePidQuery();return null;}if (parsedArgs.mUsapPoolStatusSpecified) {return handleUsapPoolStatusChange(zygoteServer, parsedArgs.mUsapPoolEnabled);}if (parsedArgs.mPreloadDefault) {handlePreload();return null;}if (parsedArgs.mPreloadPackage ! null) {handlePreloadPackage(parsedArgs.mPreloadPackage, parsedArgs.mPreloadPackageLibs,parsedArgs.mPreloadPackageLibFileName, parsedArgs.mPreloadPackageCacheKey);return null;}if (canPreloadApp() parsedArgs.mPreloadApp ! null) {byte[] rawParcelData Base64.getDecoder().decode(parsedArgs.mPreloadApp);Parcel appInfoParcel Parcel.obtain();appInfoParcel.unmarshall(rawParcelData, 0, rawParcelData.length);appInfoParcel.setDataPosition(0);ApplicationInfo appInfo ApplicationInfo.CREATOR.createFromParcel(appInfoParcel);appInfoParcel.recycle();if (appInfo ! null) {handlePreloadApp(appInfo);} else {throw new IllegalArgumentException(Failed to deserialize --preload-app);}return null;}if (parsedArgs.mApiBlacklistExemptions ! null) {return handleApiBlacklistExemptions(zygoteServer, parsedArgs.mApiBlacklistExemptions);}if (parsedArgs.mHiddenApiAccessLogSampleRate ! -1|| parsedArgs.mHiddenApiAccessStatslogSampleRate ! -1) {return handleHiddenApiAccessLogSampleRate(zygoteServer,parsedArgs.mHiddenApiAccessLogSampleRate,parsedArgs.mHiddenApiAccessStatslogSampleRate);}if (parsedArgs.mPermittedCapabilities ! 0 || parsedArgs.mEffectiveCapabilities ! 0) {throw new ZygoteSecurityException(Client may not specify capabilities: permitted0x Long.toHexString(parsedArgs.mPermittedCapabilities) , effective0x Long.toHexString(parsedArgs.mEffectiveCapabilities));}Zygote.applyUidSecurityPolicy(parsedArgs, peer);Zygote.applyInvokeWithSecurityPolicy(parsedArgs, peer);Zygote.applyDebuggerSystemProperty(parsedArgs);Zygote.applyInvokeWithSystemProperty(parsedArgs);int[][] rlimits null;if (parsedArgs.mRLimits ! null) {rlimits parsedArgs.mRLimits.toArray(Zygote.INT_ARRAY_2D);}int[] fdsToIgnore null;if (parsedArgs.mInvokeWith ! null) {try {FileDescriptor[] pipeFds Os.pipe2(O_CLOEXEC);childPipeFd pipeFds[1];serverPipeFd pipeFds[0];Os.fcntlInt(childPipeFd, F_SETFD, 0);fdsToIgnore new int[]{childPipeFd.getInt$(), serverPipeFd.getInt$()};} catch (ErrnoException errnoEx) {throw new IllegalStateException(Unable to set up pipe for invoke-with, errnoEx);}}/*** In order to avoid leaking descriptors to the Zygote child,* the native code must close the two Zygote socket descriptors* in the child process before it switches from Zygote-root to* the UID and privileges of the application being launched.** In order to avoid bad file descriptor errors when the* two LocalSocket objects are closed, the Posix file* descriptors are released via a dup2() call which closes* the socket and substitutes an open descriptor to /dev/null.*/int [] fdsToClose { -1, -1 };FileDescriptor fd mSocket.getFileDescriptor();if (fd ! null) {fdsToClose[0] fd.getInt$();}fd zygoteServer.getZygoteSocketFileDescriptor();if (fd ! null) {fdsToClose[1] fd.getInt$();}fd null;// 这里调用 Zygote.forkAndSpecialize 去执行 fork 进程的逻辑。pid Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid, parsedArgs.mGids,parsedArgs.mRuntimeFlags, rlimits, parsedArgs.mMountExternal, parsedArgs.mSeInfo,parsedArgs.mNiceName, fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,parsedArgs.mInstructionSet, parsedArgs.mAppDataDir, parsedArgs.mTargetSdkVersion);try {if (pid 0) {// in childzygoteServer.setForkChild();zygoteServer.closeServerSocket();IoUtils.closeQuietly(serverPipeFd);serverPipeFd null;return handleChildProc(parsedArgs, descriptors, childPipeFd,parsedArgs.mStartChildZygote);} else {// In the parent. A pid 0 indicates a failure and will be handled in// handleParentProc.IoUtils.closeQuietly(childPipeFd);childPipeFd null;handleParentProc(pid, descriptors, serverPipeFd);return null;}} finally {IoUtils.closeQuietly(childPipeFd);IoUtils.closeQuietly(serverPipeFd);}}这里的进程复制跟 SystemServer 进程的复制类似SystemServer 进程复制调用的是 Zygote.forkSystemServer 函数Socket 通信时进程的复制调用的是 Zygote.forkAndSpecialize 函数在 native 层的是实现逻辑类似。通过对应的 Socket 指令去执行对应的功能。 对于进程的复制可以从下图中对 init 进程复制进程、zygote 进程复制进程的联系 总结 本篇文档主要描述了 Android 启动流程中 Zygote 进程的内容。描述了从 Zygote 的启动app_process 程序的启动以及 Zygote 初始化、预加载、进程的赋值等内容。
http://www.hkea.cn/news/14469925/

相关文章:

  • 学计算机工资一月多少南京百度提升优化
  • 承建网站注册好了域名怎么开始做网站
  • 网站建设相关职业岗位企业销售型网站是什么
  • 自己做电商网站吗网络公司网站案例
  • 做的网站提示不安全深圳品牌网站设计电话
  • 重庆网站排名公司宁波做网站公司
  • 天津外贸网站建设免费制作网站net域名
  • 网站建设要知道的wordpress环境安装
  • 深圳网a深圳网站建设东营垦利
  • 玩具网站建设策划书流程怎么做网站关键词视频
  • 杭州公司建设网站北京网站建设公司哪家好
  • 松阳建设局网站电子商务毕业设计网站建设
  • 三网合一网站系统建筑材料网站建设
  • 个人自建网站ps如何做网站
  • 南京网站开发哪家好绿色模板网站
  • 公众号购物做网站还是小程序甘肃网站建设制作商
  • 网站开发 语言net重庆在线课程
  • 牡丹江市住房和城乡建设局网站网站seo推广方案
  • offic做网站的软件网站打开速度概念
  • 培训教育行业网站建设方案wordpress深度修改
  • 建设建设网站的网站建设算什么行业
  • 常用的网站建设技术有什么和平区网站建设
  • 宁夏建设网站公司网页小游戏怎么玩
  • 用discuz做网站一个空间可以建多个网站
  • 成都营销型网站广州网站运营
  • 网站流媒体播放如何做网站ueo
  • 深圳网站设计公司哪家专业网站上的平面海报怎么做
  • 定制开发生产管理软件推荐重庆网站优化排名
  • wordpress评论表单关键词优化快排
  • 东营网站搜索引擎优化软件设计思路