Zygote進程啓動流程

博客同步至github博客:Zygote進程啓動流程

使用到的相關源碼:https://github.com/JesusYoung/AndroidResourceCode9.0/tree/master

基於Android 9.0

1、Zygote進程

Zygote是在init進程啓動時創建的,它又稱爲孵化器,它可以通過fork(複製進程)的形式來創建應用程序進程和SystemServer進程,並且,Zygote進程在啓動的時候會創建DVM或者ART,因此通過fork而創建的應用程序進程和SystemServer進程可以在內部獲取一個DVM或者ART的實例副本;

2、Zygote進程啓動流程

2.1、Init進程調用

2.1.1、解析配置參數

Init進程啓動之後,解析init.rc配置文件,執行其配置,其中有啓動Zygote進程的參數配置,在app_main.cpp的main()方法中,先解析參數,例如在前面解析.rc文件時添加的參數“–zygote、----start-system-server”等,初始化各種標識位;

int main(int argc, char* const argv[]) {
	...
  ++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;
    }
  }
  ...
}

2.1.2、啓動Dalvik虛擬機

接着判斷className是否爲空,在Zygote模式下,調用maybeCreateDalvikCache()函數創建Dalvik虛擬機緩存,添加啓動systemServer的參數標識;

int main(int argc, char* const argv[]) {
	...
	if (!className.isEmpty()) {
    ...
  } else {
    // We're in zygote mode.
    maybeCreateDalvikCache();
    if (startSystemServer) {
      args.add(String8("start-system-server"));
    }
    char prop[PROP_VALUE_MAX];
    if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {
      LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.", ABI_LIST_PROPERTY);
      return 11;
    }
    String8 abiFlag("--abi-list=");
    abiFlag.append(prop);
    args.add(abiFlag);
    // In zygote mode, pass all remaining arguments to the zygote main() method.
    // 在Zygote模式下,將剩餘的參數全部傳遞過去
    for (; i < argc; ++i) {
      args.add(String8(argv[i]));
    }
    ...
}

2.2、啓動Zygote

2.2.1、創建AppRunTime對象

在main()函數中創建了AppRunTime對象,AppRunTime對象繼承自AndroidRunTime類;

int main(int argc, char* const argv[]) {
  ...
  AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
  ...
}

class AppRuntime : public AndroidRuntime {
  public:
  AppRuntime(char* argBlockStart, const size_t argBlockLength)
    : AndroidRuntime(argBlockStart, argBlockLength) , mClass(NULL) {
    }
  ...
}

2.2.2、AppRunTime啓動Zygote

隨後調用AppRunTime類的start()方法來啓動Zygote進程,在前面判斷中得知zygote參數爲true;

if (zygote) {
  runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
} else if (className) {
  runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
} else {
  ...
}

AppRunTime類繼承自AndroidRunTime類,AppRunTime類並沒有重載start()方法,所以這裏執行的是AndroidRunnTime類的start()方法;

2.2.3、註冊JNI

首先會初始化一些環境rootDir等,然後會啓動虛擬機,調用startReg()函數向虛擬機註冊Android Native方法;

拿到前面傳入的類名,即com.android.internal.os.ZygoteInit,通過JNI調用其main()方法,因爲此處爲C代碼,而ZygoteInit爲Java類,所以調用時需要使用JNI方式去調用,此時,正式從C層進入Java層;

class AppRuntime : public AndroidRuntime {}

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote) {
  ...
  // 啓動虛擬機
  if (startVm(&mJavaVM, &env, zygote) != 0) {
    return;
  }
  ...
  // 向虛擬機註冊Android Native方法
  if (startReg(env) < 0) {
    ALOGE("Unable to register all android natives\n");
    return;
  }
  ...
  char* slashClassName = toSlashClassName(className != NULL ? className : "");
  jclass startClass = env->FindClass(slashClassName);
  if (startClass == NULL) {
    ...
  } else {
    // 找到main()方法
    jmethodID startMeth = env->GetStaticMethodID(startClass, "main", "([Ljava/lang/String;)V");
    if (startMeth == NULL) {
      ...
    } else {
      // 調用ZygoteInit類的main()方法
      env->CallStaticVoidMethod(startClass, startMeth, strArray);
      #if 0
      if (env->ExceptionCheck())
        threadExitUncaughtException(env);
      #endif
    }
  }
  ...
}

2.2.4、啓動進入Java層Zygote

Zygote進程啓動,在ZygoteInit的main()方法中,通過調用ZygoteHooks類的startZygoteNoThreadCreation()函數來拋出異常,標識Zygote進程已經啓動;

public static void main(String argv[]) {
  ZygoteServer zygoteServer = new ZygoteServer();
  // Mark zygote start. This ensures that thread creation will throw
  // an error.
  ZygoteHooks.startZygoteNoThreadCreation();
  ...
}

2.3、創建Zygote進程Socket

2.3.1、創建服務端socket

在ZygoteInit的main()函數中,創建了ZygoteServer對象,作爲Zygote進程的socket通信的服務端,名爲zygote,用來接收SystemServer進程向Zygote進程發來的請求,例如AMS向Zygote進程請求創建新應用等,接着調用runSelectLoop()來等待SystemServer進程發來的請求;

public static void main(String argv[]) {
  ZygoteServer zygoteServer = new ZygoteServer();
  ...
  try {
    ...
    zygoteServer.registerServerSocketFromEnv(socketName);
    ...
    caller = zygoteServer.runSelectLoop(abiList);
  }
  ...
  if (caller != null) {
    caller.run();
  }
}

// ZygoteServer 
void registerServerSocketFromEnv(String socketName) {
  if (mServerSocket == null) {
    int fileDesc;
    final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
    try {
      String env = System.getenv(fullSocketName);
      fileDesc = Integer.parseInt(env);
    } catch (RuntimeException ex) {
      throw new RuntimeException(fullSocketName + " unset or invalid", ex);
    }
    try {
      FileDescriptor fd = new FileDescriptor();
      fd.setInt$(fileDesc);
      mServerSocket = new LocalServerSocket(fd);
      mCloseSocketFd = true;
    } catch (IOException ex) {
      throw new RuntimeException("Error binding to local socket '" + fileDesc + "'", ex);
    }
  }
}

2.3.2、執行客戶端請求

輪詢客戶端Socket消息,當客戶端有新消息到來時,創建一個新的連接去執行客戶端發來的請求,例如AMS請求創建新的進程;

新建一個peers列表,用於存儲每個客戶端的連接,將fd數據轉存到poolFds中,遍歷,當i=0時表示有客戶端與服務端連接成功,此時執行acceptCommandPeer()方法拿到新的連接,並將其存入到peers集合中,當i>0時,表示客戶端在向服務端傳輸數據,從peers中拿出與客戶端的連接,執行processOneCommand()函數得到一個Runnable對象,如果是fork子進程並且任務不爲null則返回該Runnable對象,在main()函數中,如果該對象不爲空,就去執行其run()方法;

Runnable runSelectLoop(String abiList) {
  ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
  ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
  fds.add(mServerSocket.getFileDescriptor());
  peers.add(null);
  while (true) {
    StructPollfd[] pollFds = new StructPollfd[fds.size()];
    for (int i = 0; i < pollFds.length; ++i) {
      pollFds[i] = new StructPollfd();
      pollFds[i].fd = fds.get(i);
      pollFds[i].events = (short) POLLIN;
    }
    ...
    for (int i = pollFds.length - 1; i >= 0; --i) {
      ...
      if (i == 0) {
        ZygoteConnection newPeer = acceptCommandPeer(abiList);
        peers.add(newPeer);
        fds.add(newPeer.getFileDesciptor());
      } else {
        try {
          ZygoteConnection connection = peers.get(i);
          final Runnable command = connection.processOneCommand(this);
          if (mIsForkChild) {
            // We're in the child. We should always have a command to run at this
            // stage if processOneCommand hasn't called "exec".
            if (command == null) {
              throw new IllegalStateException("command == null");
            }
            return command;
          } else {
            // We're in the server - we should never have any commands to run.
            if (command != null) {
              throw new IllegalStateException("command != null");
            }
            // We don't 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(i);
              fds.remove(i);
            }
          }
        }
        ...
      }
    }
  }
}

執行processOneCommand()方法時,創建fork子進程的Runnable對象,如果是在父進程中,則返回null,子進程中則會返回fork子進程的Runnable對象,去執行fork操作,並且清除掉fork過來的父進程中的socket信息;

Runnable processOneCommand(ZygoteServer zygoteServer) {
  ...
  pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                                 parsedArgs.runtimeFlags, rlimits, parsedArgs.mountExternal, 
                                 parsedArgs.seInfo, parsedArgs.niceName, fdsToClose, 
                                 fdsToIgnore, parsedArgs.startChildZygote,
                                 parsedArgs.instructionSet, parsedArgs.appDataDir);
  try {
    if (pid == 0) {
      // in child
      zygoteServer.setForkChild();
      zygoteServer.closeServerSocket();
      IoUtils.closeQuietly(serverPipeFd);
      serverPipeFd = null;
      return handleChildProc(parsedArgs, descriptors, childPipeFd, parsedArgs.startChildZygote);
    } 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;
    }
    ...
}

2.4、啓動SystemServer

Zygote進程啓動後,執行ZygoteInit類的main()方法,啓動會調用forkSystemServer()方法去通過fork自身的方式去創建SystemServer進程;

public static void main(String argv[]) {
	...
  try {
  	...
    if (startSystemServer) {
      Runnable r = forkSystemServer(abiList, socketName, 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;
      }
    }
    ...
  }
  ...
}
發佈了32 篇原創文章 · 獲贊 14 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章