玉溪网站建设现状,石家庄手机网站制作多少钱,浙江平台网站建设找哪家,做淘宝店铺标志的网站frameworks 之Zygote Zygote.rc 解析Zygote 启动ZygoteInit.javaZygote.cppLiunx fork Zygote 中文意思为受精卵。 和其意思一样#xff0c;该功能负责android系统孵化service 和 app 进程。 本文讲解Zygote的大概流程。涉及的相同的类#xff0c;如下所示 system/core/rootd… frameworks 之Zygote Zygote.rc 解析Zygote 启动ZygoteInit.javaZygote.cppLiunx fork Zygote 中文意思为受精卵。 和其意思一样该功能负责android系统孵化service 和 app 进程。 本文讲解Zygote的大概流程。涉及的相同的类如下所示 system/core/rootdir/init.zygote32.rcframeworks/base/cmds/app_process/app_main.cppframeworks/base/core/jni/AndroidRuntime.cppsystem/core/init/main.cppframeworks/base/core/java/com/android/internal/os/ZygoteInit.javaframeworks/base/core/java/com/android/internal/os/Zygote.javaframeworks/base/core/jni/com_android_internal_os_Zygote.cpp
Zygote.rc 解析
启动init进程后会解析 Zygote.rc文件。该文件位于 system/core/rootdir 文件夹下 其中第一行 zygote 表示进程名 /system/bin/app_process 表示要启动的模块名 –zygote --start-system-server 表示参数, class main 表示入口方法。
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
priority -20
user root
group root readproc reserved_disk
socket zygote stream 660 root system
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
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
onrestart restart wificond
writepid /dev/cpuset/foreground/tasks
critical window${zygote.critical_window.minute:-off} targetzygote-fatalZygote 启动
根据上面的rc文件 全局搜索 grep app_process ./ -rn 可以看到该模块名为app_process的位于 base/cmds/app_process 下。 跳转到该文件夹下 打开 app_main.cpp 文件查看main 方法 main 方法前面是解析参数并对变量 zygote, startSystemServer 设置为true 通过 runtime.start 方法启动 start方法是在继承在 AndroidRuntime 类实现
int main(int argc, char* const argv[])
{// Parse runtime arguments. Stop at first unrecognized option.bool zygote false;bool startSystemServer false;bool application false;String8 niceName;String8 className;// 将变量为truei; // 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;}}// zygote 为true 通过runtime启动com.android.internal.os.ZygoteInit 为类名if (zygote) {runtime.start(com.android.internal.os.ZygoteInit, args, zygote);} else if (className) {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.);}
}通过 全局查找 grep “AndroidRuntime” ./ -rn 得到该类的位置 在 core/jni/AndroidRuntime.cpp 下 该方法前面大部分还是参数变量判断关键通过 jmethodID startMeth env-GetStaticMethodID(startClass, “main”, “([Ljava/lang/String;)V”); 启动 对应的main方法。根据上一步传进来的参数。可以得到启动了 ZygoteInit.java 类
void AndroidRuntime::start(const char* className, const VectorString8 options, bool zygote)
{/** 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;// 省略// 加载传进来的类名jni 加载对应的main方法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 {env-CallStaticVoidMethod(startClass, startMeth, strArray);#if 0if (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);
}ZygoteInit.java
查看对应的main方法 ,main 里面主要的方法有如下 preload(bootTimingsTraceLog); 预加载了类,资源opengl,so库等 初始化ZygoteServer forkSystemServer 启动 SystemServer runSelectLoop 循环等待消息
public static void main(String[] argv) {...// 初始化参数 startSystemServer 决定启动 systemServer 服务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])) {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]);}}...// 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());// 加载类资源 和so preload(bootTimingsTraceLog);EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,SystemClock.uptimeMillis());bootTimingsTraceLog.traceEnd(); // ZygotePreload}...// 创建systemServiver 服务zygoteServer new ZygoteServer(isPrimaryZygote);if (startSystemServer) {Runnable r forkSystemServer(abiList, zygoteSocketName, zygoteServer);// {code r null} in the parent (zygote) process, and {code r ! null} in the// child (system_server) process.if (r ! null) {r.run();return;}}...Log.i(TAG, Accepting command socket connections);// 等待服务// The select loop returns early in the child process after a fork and// loops forever in the zygote.caller zygoteServer.runSelectLoop(abiList);
}其中 preload 里面的 preloadClasses 加载android所需的类 加载 preloaded-classes 文件 通过Class.forName 加载类。可通过find -name preloaded-classes 查看该文件的位置该文件通过编译时候拷贝到 system/ect目录下 。
static void preload(TimingsTraceLog bootTimingsTraceLog) {preloadClasses();preloadResources();nativePreloadAppProcessHALs();preloadSharedLibraries();preloadTextResources();
}private static final String PRELOADED_CLASSES /system/etc/preloaded-classes;private static void preloadClasses() {// 加载文件InputStream is;try {is new FileInputStream(PRELOADED_CLASSES);} catch (FileNotFoundException e) {Log.e(TAG, Couldnt find PRELOADED_CLASSES .);return;}...// 循环遍历 通过 Class.forName 加载类文件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 {// 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) {if (line.contains($$Lambda$)) {if (LOGGING_DEBUG) {missingLambdaCount;}} else {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;} else if (t instanceof RuntimeException) {throw (RuntimeException) t;} else {throw new RuntimeException(t);}}Trace.traceEnd(Trace.TRACE_TAG_DALVIK);}
}runSelectLoop 里面是一个死循环poll等待消息 如果没消息来 就会卡在这 如果第一次进来调用 acceptCommandPeer接着 acceptCommandPeer 又会调用 createNewConnection方法 创建 ZygoteConnection。 ..// poll等待消息 如果没消息来 就会卡在这try {pollReturnValue Os.poll(pollFDs, pollTimeoutMs);} catch (ErrnoException ex) {throw new RuntimeException(poll failed, ex);}...//如果第一次进来调用 acceptCommandPeer创建 ZygoteConnectionif (pollIndex 0) {// Zygote server socketZygoteConnection newPeer acceptCommandPeer(abiList);peers.add(newPeer);socketFDs.add(newPeer.getFileDescriptor());} else if (pollIndex usapPoolEventFDIndex) {ZygoteConnection connection peers.get(pollIndex);boolean multipleForksOK !isUsapPoolEnabled() ZygoteHooks.isIndefiniteThreadSuspensionSafe();// 执行创建final Runnable command connection.processCommand(this, multipleForksOK);}processCommand 方法里面会调用 forkAndSpecialize 继续调用 nativeForkAndSpecialize 创建进程而 nativeForkAndSpecialize又会调用 ForkCommon 创建。
if (parsedArgs.mInvokeWith ! null || parsedArgs.mStartChildZygote|| !multipleOK || peer.getUid() ! Process.SYSTEM_UID) {// Continue using old code for now. TODO: Handle these cases in the other path.// 创建进程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.mIsTopApp, parsedArgs.mPkgDataInfoList,parsedArgs.mAllowlistedDataInfoList, parsedArgs.mBindMountAppDataDirs,parsedArgs.mBindMountAppStorageDirs);try {if (pid 0) {// in childzygoteServer.setForkChild();zygoteServer.closeServerSocket();IoUtils.closeQuietly(serverPipeFd);serverPipeFd null;return handleChildProc(parsedArgs, 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, serverPipeFd);return null;}} finally {IoUtils.closeQuietly(childPipeFd);IoUtils.closeQuietly(serverPipeFd);}}Zygote.cpp
forkSystemServer 会调用 Zygote.forkSystemServer 方法而forkSystemServer 又会调用 nativeForkSystemServer 方法 最终调用到 Zygote.cpp 里面的方法。直接查找 Zygote.cpp 可以看到该文件位于 frameworks/base/core/jni 。 /* Request to fork the system server process */pid Zygote.forkSystemServer(parsedArgs.mUid, parsedArgs.mGid,parsedArgs.mGids,parsedArgs.mRuntimeFlags,null,parsedArgs.mPermittedCapabilities,parsedArgs.mEffectiveCapabilities);static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {ZygoteHooks.preFork();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;}看到关键语句pid 可以看出该方法是fork 出进程id 调用的是liunx 自带fork方法 孵化出进程当返回的id为0时候 代表是新进程,可以看到会调用 ForkCommon 方法。
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);}查看 ForkCommon 方法。里面调用了 Fork方法 创建进程
// 创建进程
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);}// The child process.PreApplicationInit();// Clean up any descriptors which must be closed immediatelyDetachDescriptors(env, fds_to_close, fail_fn);// Invalidate the entries in the USAP table.ClearUsapTable();// Re-open all remaining open file descriptors so that they arent 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 socketgSystemServerSocketFd -1;} else {ALOGD(Forked child process %d, pid);}Liunx fork
fork函数是 Liunx fork() 返回的pid pid等于0 表示三fork新进程执行 不等于0 原来的进程执行代码。新建forkTest.c文件 touch forkTest.c 内容如下
#include unistd.h
#include stdio.hint main(void){printf(main current process pid %d \n, getpid());// 创建进程int pid fork();// 这里会分开2个线程 pid等于0 表示三fork新进程执行 不等于0 原来的进程执行代码if (pid 0) {printf(fork newProgress child process pid %d parent pid %d \n, getpid(), getppid());} else {printf(this process pid %d forkPid %d parent pid %d \n, getpid(),pid, getppid());}return 0;
}然后执行 gcc forkTest.c -o forkTest 编译为二进制文件 在执行 ./forkTest 命令执行 查看打印
main current process pid 7766
this process pid 7766 forkPid 7767 parent pid 7144
fork newProgress child process pid 7767 parent pid 7766