안드로이드/안드로이드 프레임워크

안드로이드에서 Zygote가 실행되는 순서 2

냥냥냥냥냥냥 2022. 5. 15. 23:54

안녕하세요 개발자 도도 입니다

지난 번 포스팅에서 ZygoteInit의 호출 전까지 어떤 과정을 통해 불리나 확인을 해봤었는데요

이번에는 ZygoteInit 부터 다시 한 번 보고자 합니다 ㅎ

자, 바로 시작해보겠습니다

 

 

 

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 {
            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++) {
                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]);
                }
                ...
                
              // Do an initial gc to clean up after startup
            bootTimingsTraceLog.traceBegin("PostZygoteInitGC");
            gcAndFinalize();
            bootTimingsTraceLog.traceEnd(); // PostZygoteInitGC

            bootTimingsTraceLog.traceEnd(); // ZygoteInit

            Zygote.initNativeState(isPrimaryZygote);

            ZygoteHooks.stopZygoteNoThreadCreation();

            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);
        } 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();
        }
    }

 

main 안이 꽤 복잡해 보이긴 하는데 필요한 부분 부터 하나씩 살펴 보겠습니다

main 에서 이루어 지는 동작은 크게 아래 두 가지로 나뉘어 질 것 같습니다

 

1) start-system-server boolean 설정

2) forkSystemServer 메서드 호출

 

 

Zygote가 시작되는 건 systerm-server일 때만 시작되는 건 아니지만 

이번에는 system server 부분의 zygote (처음 zygote 생성) 부분 위주로 보려고 합니다

 

1) start-system-server boolean true 설정

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]);
    }
}

기억하실 지 모르겠지만 init.zygote32(64).rc 에서 아래와 같은 명령어가 있었죠?

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server

결국 보면 argv 내에 들어있는 부분 true로 만들어 주겠죠?

여기선 start-system-server가 true가 될 것입니다 

 

 

 

2) forkSystemServer run

// ZygoteInit.java
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;
    }
}

 

2-1) forkSystemServer 메서드 내부

여기도 다소 생략된 부분이 많이 있습니다

이 부분에서 봐야할 부분도 두 가지 입니다

 

Zygote 내의 forkSystemServer 메서드 호출과

handleSystemServerProcess 메서드 호출입니다

// ZygoteInit::forkSystemServer
    private static Runnable forkSystemServer(String abiList, String socketName,
            ZygoteServer zygoteServer) {
            
            ...
            
         /* Hardcoded command line to start the system server */
        String[] args = {
                "--setuid=1000",
                "--setgid=1000",
                "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,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",
        };
        ZygoteArguments parsedArgs;

        int pid;

        try {
            ZygoteCommandBuffer commandBuffer = new ZygoteCommandBuffer(args); 
            try {
                parsedArgs = ZygoteArguments.getInstance(commandBuffer);
            }      
           ...
           
          Zygote.applyInvokeWithSystemProperty(parsedArgs);
          
          ...
            
            /* 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);
        }

        /* For child process */
        if (pid == 0) {
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName);
            }

            zygoteServer.closeServerSocket();
            return handleSystemServerProcess(parsedArgs);
        }

여기서 봐줘야할 곳은 아래 부분입니다

// ZygoteInit.java
Zygote.applyInvokeWithSystemProperty(parsedArgs);

// Zygote.java
static void applyInvokeWithSystemProperty(ZygoteArguments args) {
    if (args.mInvokeWith == null) {
        args.mInvokeWith = getWrapProperty(args.mNiceName);
    }
}

ZygoteInit의 forkSystemServer가 불릴 때, args에 --nice-name=system_server로 강제로 설정을 해줍니다

 

3) ForkSystemServer (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();

    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;
}

    private static native int nativeForkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
            int[][] rlimits, long permittedCapabilities, long effectiveCapabilities);

여기서 nativeForkSystemServer 메서드는 native 코드 호출 부분입니다

 

이것은 JNI 라고 부르며 설명은 나무위키에서 참조 하였으나 참고 부탁드리겠습니다

자바 네이티브 인터페이스(Java Native Interface, JNI)는 자바 가상 머신(JVM)위에서 실행되고 있는 자바코드가 네이티브 응용 프로그램(하드웨어와 운영 체제 플랫폼에 종속된 프로그램들) 그리고 C, C++ 그리고 어샘블리 같은 다른 언어들로 작성된 라이브러리들을 호출하거나 반대로 호출되는 것을 가능하게 하는 프로그래밍 프레임워크이다.

 

 

Zygote.java      <-------------- JNI --------------> com_android_internal_os_Zygote.cpp

 

 

 

아래 처럼 Zygote.java 파일과 com_android_internal_os_Zygote.cpp 파일은 서로 JNI로 연결되어 있으며

Zygote.java 의 nativeForkSystemServer  메서드를 호출하게 되면

com_android_internal_os_Zygote.cpp의 com_android_internal_os_Zygote_nativeForkSystemServer메서드에서 동작하게 됩니다

그렇다면 com_android_internal_os_Zygote.cpp 내의

com_android_internal_os_Zygote_nativeForkSystemServer를 보도록 하겠습니다

 

 

4) com_android_internal_os_Zygote_nativeForkSystemServer (com_android_internal_os_Zygote.cpp)

여기서도 봐야할 사항이 2가지로 보입니다

 

1) zygote::ForkCommon

2) pid 값에 따른 구분

 

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);

...

  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;
}

 

4-1) zygote::ForkCommon

ForkCommon 부터 먼저 보겠습니다

// com.android_internal_os_Zygote.cpp
// Utility routine to fork a process from the zygote.
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);

...

  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 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 {
    ALOGD("Forked child process %d", pid);
  }

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

  return pid;
}

여기서는 일단 Cpp의 fork 함수부터 아셔야합니다

 

Fork 함수 문법 간단히 설명

fork 함수는 자식 프로세스를 만드는 메서드로서
자식 만들기 실패(?) 시 -1의 pid,
자식은 0 번 pid
부모는 0 초과 번호의 pid
를 부여 하게 되는 메서드입니다

 

문제는 이 함수를 실행하게 되면 프로세스가 두 개이기 때문에 fork 이후 부터는 2번 실행 되는 것 처럼 보입니다

(물론 부모, 자식 pid가 다르기 때문에 pid에 따라 if 문 둬서 구분하는 방식으로 사용합니다)

 

즉 결국 위의 if 문에서 pid == 0은 자식프로세스에서 실행될테고

else 부분은 부모프로세스에서 실행되서 if, else 둘 다 실행되는 웃긴(?) 상황이 됩니다

 

 

4-2) pid 값에 따른 구분

위에서 결국 forkCommon을 통해 pid가 0 (자식), pid 0 초과하는 어떤 번호의 부모 (SystemServer)

이렇게 두 개의 프로세스가 실행되고 있는 상황이 될 것 입니다

 

// com_android_internal_os_Zygote.cpp
  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;

현재는 SpecializeCommon을 타게 되고 그 부분의 코드는 아래와 같습니다

// com_android_internal_os_Zygote.cpp
    if (is_system_server) {
        // Prefetch the classloader for the system server. This is done early to
        // allow a tie-down of the proper system server selinux domain.
        env->CallStaticObjectMethod(gZygoteInitClass, gGetOrCreateSystemServerClassLoader);
        if (env->ExceptionCheck()) {
            // Be robust here. The Java code will attempt to create the classloader
            // at a later point (but may not have rights to use AoT artifacts).
            env->ExceptionClear();
        }
        // Also prefetch standalone system server jars. The reason for doing this here is the same
        // as above.
        env->CallStaticVoidMethod(gZygoteInitClass, gPrefetchStandaloneSystemServerJars);
        if (env->ExceptionCheck()) {
            env->ExceptionClear();
        }
    }


    if (is_system_server) {
        env->CallStaticVoidMethod(gZygoteClass, gCallPostForkSystemServerHooks, runtime_flags);
        if (env->ExceptionCheck()) {
            fail_fn("Error calling post fork system server hooks.");
        }

        // TODO(b/117874058): Remove hardcoded label here.
        static const char* kSystemServerLabel = "u:r:system_server:s0";
        if (selinux_android_setcon(kSystemServerLabel) != 0) {
            fail_fn(CREATE_ERROR("selinux_android_setcon(%s)", kSystemServerLabel));
        }
    }

Zygote.java 의 callPosetForkSystemServerHooks의 코드를 호출해줍니다

// com_android_internal_os_Zyote.cpp
gCallPostForkSystemServerHooks = GetStaticMethodIDOrDie(env, gZygoteClass,
                                                        "callPostForkSystemServerHooks",
                                                        "(I)V");

ZygoteHooks의 코드는 libcore/dalvik/src/main/java/dalvik/system/ZygoteHooks.java 에 있는 부분의 코드입니다

nativeForkSystemServer가 불린 다음 ZygoteHooks.posetForkCommon이 불립니다

// libcore/dalvik/src/main/java/dalvik/system/ZygoteHooks.java
    @SystemApi(client = MODULE_LIBRARIES)
    public static void postForkSystemServer(int runtimeFlags) {
        nativePostForkSystemServer(runtimeFlags);
    }
    
    /**
     * Called by the zygote in both the parent and child processes after
     * every fork. In the child process, this method is called after
     * {@code postForkChild}.
     *
     * @hide
     */
    @SystemApi(client = MODULE_LIBRARIES)
    public static void postForkCommon() {
        // Notify the runtime before creating new threads.
        nativePostZygoteFork();
        Daemons.startPostZygoteFork();
    }

ZygoteHooks의 porkForkCommon을 호출 하면

Daemons의 startPoskZygoteFork를 호출 해주며 그 부분은 아래 코드가 있습니다

// libcore/libart/src/main/java/java/lang/Daemons.java
    public static void startPostZygoteFork() {
        postZygoteFork = true;
        for (Daemon daemon : DAEMONS) {
            daemon.startPostZygoteFork();
        }
    }
    
    ...
    
    private static abstract class Daemon implements Runnable {
        @UnsupportedAppUsage
        private Thread thread;
        private String name;
        private boolean postZygoteFork;
    
    ...
    
        public synchronized void startPostZygoteFork() {
            postZygoteFork = true;
            startInternal();
        }

        public void startInternal() {
            if (thread != null) {
                throw new IllegalStateException("already running");
            }
            thread = new Thread(ThreadGroup.systemThreadGroup, this, name);
            thread.setDaemon(true);
            thread.setSystemDaemon(true);
            thread.start();
        }

libcore 내에서 thread를 만들고 그 thread의 start를 해줍니다

이 과정들은 결국 최종적으로 ZygoteInit의  handleSystemServerProcess 를 불러주기 전에 해야하는 선행적인 작업이고

 

// ZygoteInit.java
/**
 * Finish remaining work for the newly forked system server process.
 */
private static Runnable handleSystemServerProcess(ZygoteArguments parsedArgs) {

...

        if (parsedArgs.mInvokeWith != null) {  // 아까 system_server로 채워줘서 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;
            }

            WrapperInit.execApplication(parsedArgs.mInvokeWith,
                    parsedArgs.mNiceName, parsedArgs.mTargetSdkVersion,
                    VMRuntime.getCurrentInstructionSet(), null, args);

결국 WrapperInitd의 execApplication을 호출 해주는데 이 부분 코드를 보면

 

// WrapperInit.java
public static void execApplication(String invokeWith, String niceName,
        int targetSdkVersion, String instructionSet, FileDescriptor pipeFd,
        String[] args) {
    StringBuilder command = new StringBuilder(invokeWith);

    final String appProcess;
    if (VMRuntime.is64BitInstructionSet(instructionSet)) {
        appProcess = "/system/bin/app_process64";
    } else {
        appProcess = "/system/bin/app_process32";
    }
    command.append(' ');
    command.append(appProcess);

    // Generate bare minimum of debug information to be able to backtrace through JITed code.
    // We assume that if the invoke wrapper is used, backtraces are desirable:
    //  * The wrap.sh script can only be used by debuggable apps, which would enable this flag
    //    without the script anyway (the fork-zygote path).  So this makes the two consistent.
    //  * The wrap.* property can only be used on userdebug builds and is likely to be used by
    //    developers (e.g. enable debug-malloc), in which case backtraces are also useful.
    command.append(" -Xcompiler-option --generate-mini-debug-info");

    command.append(" /system/bin --application");
    if (niceName != null) {
        command.append(" '--nice-name=").append(niceName).append("'");
    }
    command.append(" com.android.internal.os.WrapperInit ");
    command.append(pipeFd != null ? pipeFd.getInt$() : 0);
    command.append(' ');
    command.append(targetSdkVersion);
    Zygote.appendQuotedShellArgs(command, args);
    preserveCapabilities();
    Zygote.execShell(command.toString());
}

복잡해보이는데 결국 app_process (/system/bin/app_process(비트수에 따라 64, 혹은 32)) 를 실행하는데 

command에 --nice-name에 systemserver, com.android.internal.os.WrapperInit을 실행시킨다

그럼 결국 첫장에서 봤던 app_process에서는 코드를 타고 타서, WrapperInit의 main을 실행시켜주고

 

// WrapperInit.java
public static void main(String[] args) {
    // Parse our mandatory arguments.
    int fdNum = Integer.parseInt(args[0], 10);
    int targetSdkVersion = Integer.parseInt(args[1], 10);

    // Tell the Zygote what our actual PID is (since it only knows about the
    // wrapper that it directly forked).
    if (fdNum != 0) {
        FileDescriptor fd = new FileDescriptor();
        try {
            fd.setInt$(fdNum);
            DataOutputStream os = new DataOutputStream(new FileOutputStream(fd));
            os.writeInt(Process.myPid());
            os.close();
        } catch (IOException ex) {
            Slog.d(TAG, "Could not write pid of wrapped process to Zygote pipe.", ex);
        } finally {
            IoUtils.closeQuietly(fd);
        }
    }

    // Mimic system Zygote preloading.
    ZygoteInit.preload(new TimingsTraceLog("WrapperInitTiming",
            Trace.TRACE_TAG_DALVIK));

    // Launch the application.
    String[] runtimeArgs = new String[args.length - 2];
    System.arraycopy(args, 2, runtimeArgs, 0, runtimeArgs.length);
    Runnable r = wrapperInit(targetSdkVersion, runtimeArgs);

    r.run();
}

맨 하단의 wrapperInit이 결국 runtimeArgs에 main method를 호출해주는 runnable입니다

최종적인 sequence는 아래와 같습니다

 

 

그로 인해 결국 SystemServer.java의 main이 불리게 되고

이 SystemServer가 android 내의 많은 managerService들 (ActivityManager, WindowManager, PackageManager 등등)을 호출해주는 등 전체적인 시스템 서버의 역할을 하는 녀석입니다

이후에 SystemServer 내의 다양한 app framework들을 각각 한 번 알아볼 생각입니다)

 

감사합니다