详细分析Android中实现Zygote的源码

概述

在Android系统中,所有的应用程序进程,以及用来运行系统关键服务的System进程都是由zygote进程负责创建的。因此,我们将它称为进程孵化器。zygote进程是通过复制自身的方式来创建System进程和应用程序进程的。由于zygote进程在启动时会在内部创建一个虚拟机实例,因此,通过复制zygote进程而得到的System进程和应用程序进程可以快速地在内部获得一个虚拟机实例拷贝。
zygote进程在启动完成之后,会马上将System进程启动起来,以便它可以将系统的关键服务启动起来。下面我们将介绍zygote进程的启动脚本,然后分析它和System进程的启动过程。
zygote分析

zygote进程的启动脚本如下:

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
  class main
  socket zygote stream 660 root system
  onrestart write /sys/android_power/request_state wake
  onrestart write /sys/power/state on
  onrestart restart media
  onrestart restart netd

在我之前的一篇博客中已经分析了init进程是如何启动service服务了,需要了解的同学可以参考这篇文章:Android init进程——解析配置文件

通过zygote服务的启动脚本,我们可以知道,zygote进程的实际是二进制文件app_process的调用,我们就从这个应用程序的main函数入手去分析一下zygote进程的启动过程,源码如下(/frameworks/base/cmds/app_process/app_main.cpp):

/**
 * 将-Xzygote加入到JavaVMOption中,返回/system/bin参数指向的下标
 */
int AndroidRuntime::addVmArguments(int argc, const char* const argv[])
{
  int i;

  for (i = 0; i < argc; i ++) {
    if (argv[i][0] != '-') {
      return i;
    }
    if (argv[i][1] == '-' && argv[i][2] == 0) {
      return i + 1;
    }

    JavaVMOption opt;
    memset(&opt, 0, sizeof(opt));
    opt.optionString = (char*)argv[i];
    mOptions.add(opt);
  }
  return i;
}

int main(int argc, char* const argv[])
{
  // zygote call parameters
  // /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server

  // These are global variables in ProcessState.cpp
  mArgC = argc;
  mArgV = argv;

  mArgLen = 0;
  for (int i = 0; i < argc; i ++) {
    mArgLen += strlen(argv[i]) + 1;
  }
  // 去除末尾的空格
  mArgLen--;

  AppRuntime runtime;
  const char* argv0 = argv[0];

  // Process command line arguments
  // ignore argv[0]
  argc --;
  argv ++;

  // Everything up tp '--' or first non '-' arg goes to the vm
  int i = runtime.addVmArguments(argc, argv);

  // Parse runtime arguments. Stop at first unrecognized option.
  bool zygote = false;
  bool startSystemServer = false;
  bool application = false;
  const char* parentDir = NULL;
  const char* niceName = NULL;
  const char* className = NULL;
  while (i < argc) {
    const char* arg = argv[i ++];
    if (!parentDir) {
      parentDir = arg;
    } else if (strcmp(arg, "--zygote") == 0) {
      zygote = true;
      niceName = "zygote";
    } 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)) {
      niceName = arg + 12;
    } else {
      className = arg;
      break;
    }
  }

  if (niceName && *niceName) {
    setArgv0(argv0, niceName);
    set_process_name(niceName);
  }

  runtime.mParentDir = parentDir;

  if (zygote) {
    // 进入到AppRuntime的start函数
    runtime.start("com.android.internal.os.ZygoteInit",
      startSystemServer? "start-system-server" : "");
  } else if (className) {
    runtime.mClassName = className;
    runtime.mArgc = argc - i;
    runtime.mArgv = argv + i;
    runtime.start("com.android.internal.os.RuntimeInit", application ? "application" : "tool");
  } else {
    fprintf("stderr", "Error: no class name or --zygote supplied.\n");
    app_usage();
    LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied");
    return 10;
  }
}

在zygote的main函数中,通过AppRuntime runtime代码创建了一个AppRuntime对象runtime,接下来Zygote进程就是通过它来进一步启动的。
init.rc中关于启动zygote命令中包含了–zygote参数,所以在if(strcmp(arg, “–zygote”) == 0)判断的时候,会将niceName赋值为”zygote”,然后通过set_process_name(niceName)函数将当前进程的名称设置为zygote。这也是为什么调用的脚本为/system/bin/app_process,而进程名为zygote的原因。set_process_name函数的源码如下(/system/core/libcutils/process_name.c):

static const char* process_name = "unknown";
void set_process_name(const char* new_name)
{
  if (new_name == NULL) {
    return;
  }

  int len = strlen(new_name);
  char* copy = (char*)malloc(len + 1);
  strcpy(copy, new_name);
  process_name = (const char*) copy;
}

从init.rc文件中关于zygote进程的配置参数可知,Zygote进程传递给应用程序app_process的启动参数arg还包含一个”–start-system-server”选项。因此,在调用AppRuntime对象runtime的成员函数start时,第二个参数为”start-system-server”,表示zygote进程启动完成之后,需要将system进程启动起来。
AppRuntime分析

AppRuntime类的成员函数start是从父类AndroidRuntime继承下来的,因此,接下来我们就继续分析AndroidRuntime类的成员函数start的实现,函数源码位置:/frameworks/base/core/jni/AndroidRuntime.cpp:

char* AndroidRuntime::toSlashClassName(const char* className)
{
  char* result = strdup(className);
  for (char* cp = result; *cp != '\0'; cp ++) {
    if (*cp == '.') {
      *cp = '/';
    }
  }

  return result;
}

/**
 * Start the Android runtime. This involves starting the virtual machine
 * and calling the "static void main(String[] args)" method int the class
 * named by "className".
 *
 * 这两个参数的值分别为:
 * const char* className = "com.android.internal.os.ZygoteInit";
 * const char* options = "start-system-server";
 */
void AndroidRuntime::start(const char* className, const char* options)
{
  ALOGD("\n>>>>> AndroidRuntime START %s <<<<<<\n",
    className != NULL ? className : "(unknown)");

  /**
   * 'startSystemServer == true' means runtime is obsolete and not run from
   * init.rc anymore, so we print out the boot start event here.
   */
  if (strcmp(options, "start-system-server") == 0) {
    const int LOG_BOOT_PROGRESS_START = 3000;
    LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START, ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
  }

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

  JniInvocation jni_invocation;
  jni_invocation.Init(NULL);
  JNIEnv* env;
  // 1. 创建虚拟机
  if (startVm(&mJavaVM, &env) != 0) {
    return;
  }
  onVmCreated(env);

  // 2. 注册JNI函数
  if (startReg(env) < 0) {
    ALOGE("Unable to register all android natives\n");
    return;
  }

  jclass stringClass;
  jobjectArray strArray;
  jstring classNameStr;
  jstring optionsStr;

  stringClass = env->FindClass("java/lang/String");
  assert(stringClass != NULL);
  // 创建一个有两个元素的String数组,用Java代码表示为:String[] strArray = new String[2];
  strArray = env->NewObjectArray(2, stringClass, NULL);
  assert(strArray != NULL);
  classNameStr = env->NewStringUTF(className);
  assert(classNameStr != NULL);
  // 设置第一个元素为"com.android.internal.os.ZygoteInit"
  env->SetObjectArrayElement(strArray, 0, classNameStr);
  optionsStr = env->NewStringUTF(options);
  // 设置第二个元素为"start-system-server"
  env->SetObjectArrayElement(strArray, 1, optionsStr);

  // 将字符串"com.android.internal.os.ZygoteInit"转换为"com/android/internal/os/ZygoteInit"
  char* slashClassName = toSlashClassName(className);
  jclass startClass = env->FindClass(slashClassName);
  if (startClass == NULL) {
    ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
  } else {
    jmethodID startMeth = env->GetStaticMethodID(startClass, "main", "([Ljava/lang/String;)V");
    if (startMeth == NULL) {
      ALOGE("JavaVM unable to find main() in '%s\n'", className);
    } else {
      // 3.
      // 通过JNI调用java函数,注意调用的是main函数,所属的类是"com.android.internal.os.ZygoteInit".
      // 传递的参数是"com.android.internal.os.ZygoteInit true"
      env->CallStaticVoidMethod(startClass, startMeth, strArray);
    }
  }
  free(slashClassName);

  ALOGD("Shutting down VM\n");
  if (mJavaVM->DetachCurrentThread() != JNI_OK) {
    ALOGW("Warning: unable to detach main thread\n");
  }
  if (mJavaVM->DestoryJavaVM() != 0) {
    ALOGW("Warning: VM did not shut down cleanly\n");
  }
}

上述代码有几处关键点,分别是:

  1. 创建虚拟机。
  2. 注册JNI函数。
  3. 进入Java世界。

接下来,我们分别分析这三个关键点。
创建虚拟机——startVm

startVm并没有特别之处,就是调用JNI的虚拟机创建函数,但是创建虚拟机时的一些参数却是在startVm中确定的,其源码如下:

#define PROPERTY_VALUE_MAX 92
/**
 * Start the Dalvik Virtual Machine.
 *
 * Various arguments, most determined by system properties, are passed in.
 * The "mOptions" vector is updated.
 *
 * Returns 0 on success.
 */
int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIENV** pEnv)
{
  int result = -1;
  JavaVMInitArgs initArgs;
  JavaVMOption opt;
  char propBuf[PROPERTY_VALUE_MAX];
  char stackTraceFileBuf[PROPERTY_VALUE_MAX];
  char dexoptFlagsBuf[PROPERTY_VALUE_MAX];
  char enableAssertBuf[sizeof("-ea:")-1 + PROPERTY_VALUE_MAX];
  char jniOptsBuf[sizeof("-Xjniopts:")-1 + PROPERTY_VALUE_MAX];
  char heapstartsizeOptsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];
  char heapsizeOptsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];
  char heapgrowthlimitOptsBuf[sizeof("-XX:HeapGrowthLimit=")-1 + PROPERTY_VALUE_MAX];
  char heapminfreeOptsBuf[sizeof("-XX:HeapMinFree=")-1 + PROPERTY_VALUE_MAX];
  char heapmaxfreeOptsBuf[sizeof("-XX:HeapMaxFree=")-1 + PROPERTY_VALUE_MAX];
  char heaptargetutilizationOptsBuf[sizeof("-XX:HeapTargetUtilization=")-1 + PROPERTY_VALUE_MAX];
  char jitcodecachesizeOptsBuf[sizeof("-Xjitcodecachesize:")-1 + PROPERTY_VALUE_MAX];
  char extraOptsBuf[PROPERTY_VALUE_MAX];
  char* stackTraceFile = NULL;
  bool checkJni = false;
  bool checkDexSum = false;
  bool logStdio = false;
  enum {
    KEMDefault,
    KEMIntPortable,
    KEMIntFast,
    KEMJitCompiler,
  } executionMode = KEMDefault;

  /**
   * 这段代码是用了设置JNI_check选项的。JNI_check指的是Native层调用JNI函数时,系统所做的一些检查动作。
   * 这个选项虽然能增加可靠性,但是还有一些副作用:
   * 1. 因为检查工作比较耗时,所以会影响系统运行速度。
   * 2. 有些检查工作比较耗时,一旦出错,整个进程会abort。
   * 所以,JNI_check选项一般只在eng版本设置。
   */
  property_get("dalvik.vm.checkjni", propBuf, "");
  if (strcmp(propBuf, "true") == 0) {
    checkJni = true;
  } else if (strcmp(propBuf, "false") != 0) {
    property_get("ro.kernel.android.checkjni", propBuf, "");
    if (propBuf[0] == '1') {
      checkJni = true;
    }
  }

  property_get("dalvik.vm.execution-mode", propBuf, "");
  if (strcmp(propBuf, "int:portable") == 0) {
    executionMode = KEMIntPortable;
  } else if (strcmp(propBuf, "int:fast") == 0) {
    executionMode = KEMIntFast;
  } else if (strcmp(propBuf, "int:jit") == 0) {
    executionMode = KEMJitCompiler;
  }

  // ... 省略大部分参数设置

  /**
   * 设置虚拟机的heapsize,默认为16m。绝大多数厂商都会在build.prop文件里修改这个属性,一般是256m。
   * heapsize不能设置得过小,否则在操作大尺寸的图片时无法分配所需的内存。
   */
  strcpy(heapsizeOptsBuf, "-Xmx");
  property_get("dalvik.vm.heapsize", heapsizeOptsBuf+4, "16m");
  opt.optionString = heapsizeOptsBuf;
  mOptions.add(opt);

  // ......

  if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {
    ALOGE("JNI_CreateJavaVM failed\n");
    goto bail;
  }

  result = 0;

bail:
  free(stackTraceFile);
  return result;
}

更多虚拟机参数的设置,我这里就不做特殊说明了,大家感兴趣可以自行google。(ps:因为我不太懂虚拟机这一块…)
注册JNI函数——startReg

上面讲了如何创建虚拟机,接下来需要给这个虚拟机注册一些JNI函数。正是因为后续的Java世界用到的一些函数是采用native方式实现的,所以才必须提前注册这些函数。

接下来,我们来看一下startReg函数的源码实现:

int AndroidRuntime::startReg(JNIEnv* env)
{
  // 设置Thread类的线程创建函数为javaCreateThreadEtc
  androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);

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

  env->PushLocalFrame(200);

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

  return 0;
}

关键是需要注册JNI函数,具体实现是由register_jni_procs函数实现的,我们来看一下这个函数的具体实现(/frameworks/base/core/jni/AndroidRuntime.cpp):

static int register_jni_procs(const RegJNIRec array[], size_T count, JNIEnv* env)
{
  for (size_t i = 0; i < count; i ++) {
    if (array[i].mProc(env) < 0) {
#ifndef NDEBUG
      ALOGD("------!!! %s failed to load\n", array[i].mName);
#endif
      return -1;
    }
  }

  return 0;
}

通过源码,我们可以看到,register_jni_procs只是对array数组的mProc函数的封装,而array数组指向的是gRegJNI数组,我们来看一下这个数组的实现:

static const RegJNIRec gRegJNI[] = {
  REG_JNI(register_android_debug_JNITest),
  REG_JNI(register_com_android_internal_os_RuntimeInit),
  REG_JNI(register_android_os_SystemClock),
  REG_JNI(register_android_util_EventLog),
  REG_JNI(register_android_util_Log),
  REG_JNI(register_android_util_FloatMath),
  REG_JNI(register_android_text_format_Time),
  REG_JNI(register_android_content_AssetManager),
  REG_JNI(register_android_content_StringBlock),
  REG_JNI(register_android_content_XmlBlock),
  REG_JNI(register_android_emoji_EmojiFactory),
  REG_JNI(register_android_text_AndroidCharacter),
  REG_JNI(register_android_text_AndroidBidi),
  REG_JNI(register_android_view_InputDevice),
  REG_JNI(register_android_view_KeyCharacterMap),
  REG_JNI(register_android_os_Process),
  REG_JNI(register_android_os_SystemProperties),
  REG_JNI(register_android_os_Binder),
  REG_JNI(register_android_os_Parcel),
  REG_JNI(register_android_view_DisplayEventReceiver),
  REG_JNI(register_android_nio_utils),
  REG_JNI(register_android_graphics_Graphics),
  REG_JNI(register_android_view_GraphicBuffer),
  REG_JNI(register_android_view_GLES20DisplayList),
  REG_JNI(register_android_view_GLES20Canvas),
  REG_JNI(register_android_view_HardwareRenderer),
  REG_JNI(register_android_view_Surface),
  REG_JNI(register_android_view_SurfaceControl),
  REG_JNI(register_android_view_SurfaceSession),
  REG_JNI(register_android_view_TextureView),
  REG_JNI(register_com_google_android_gles_jni_EGLImpl),
  REG_JNI(register_com_google_android_gles_jni_GLImpl),
  REG_JNI(register_android_opengl_jni_EGL14),
  REG_JNI(register_android_opengl_jni_EGLExt),
  REG_JNI(register_android_opengl_jni_GLES10),
  REG_JNI(register_android_opengl_jni_GLES10Ext),
  REG_JNI(register_android_opengl_jni_GLES11),
  REG_JNI(register_android_opengl_jni_GLES11Ext),
  REG_JNI(register_android_opengl_jni_GLES20),
  REG_JNI(register_android_opengl_jni_GLES30),

  REG_JNI(register_android_graphics_Bitmap),
  REG_JNI(register_android_graphics_BitmapFactory),
  REG_JNI(register_android_graphics_BitmapRegionDecoder),
  REG_JNI(register_android_graphics_Camera),
  REG_JNI(register_android_graphics_CreateJavaOutputStreamAdaptor),
  REG_JNI(register_android_graphics_Canvas),
  REG_JNI(register_android_graphics_ColorFilter),
  REG_JNI(register_android_graphics_DrawFilter),
  REG_JNI(register_android_graphics_Interpolator),
  REG_JNI(register_android_graphics_LayerRasterizer),
  REG_JNI(register_android_graphics_MaskFilter),
  REG_JNI(register_android_graphics_Matrix),
  REG_JNI(register_android_graphics_Movie),
  REG_JNI(register_android_graphics_NinePatch),
  REG_JNI(register_android_graphics_Paint),
  REG_JNI(register_android_graphics_Path),
  REG_JNI(register_android_graphics_PathMeasure),
  REG_JNI(register_android_graphics_PathEffect),
  REG_JNI(register_android_graphics_Picture),
  REG_JNI(register_android_graphics_PorterDuff),
  REG_JNI(register_android_graphics_Rasterizer),
  REG_JNI(register_android_graphics_Region),
  REG_JNI(register_android_graphics_Shader),
  REG_JNI(register_android_graphics_SurfaceTexture),
  REG_JNI(register_android_graphics_Typeface),
  REG_JNI(register_android_graphics_Xfermode),
  REG_JNI(register_android_graphics_YuvImage),
  REG_JNI(register_android_graphics_pdf_PdfDocument),

  REG_JNI(register_android_database_CursorWindow),
  REG_JNI(register_android_database_SQLiteConnection),
  REG_JNI(register_android_database_SQLiteGlobal),
  REG_JNI(register_android_database_SQLiteDebug),
  REG_JNI(register_android_os_Debug),
  REG_JNI(register_android_os_FileObserver),
  REG_JNI(register_android_os_MessageQueue),
  REG_JNI(register_android_os_SELinux),
  REG_JNI(register_android_os_Trace),
  REG_JNI(register_android_os_UEventObserver),
  REG_JNI(register_android_net_LocalSocketImpl),
  REG_JNI(register_android_net_NetworkUtils),
  REG_JNI(register_android_net_TrafficStats),
  REG_JNI(register_android_net_wifi_WifiNative),
  REG_JNI(register_android_os_MemoryFile),
  REG_JNI(register_com_android_internal_os_ZygoteInit),
  REG_JNI(register_android_hardware_Camera),
  REG_JNI(register_android_hardware_camera2_CameraMetadata),
  REG_JNI(register_android_hardware_SensorManager),
  REG_JNI(register_android_hardware_SerialPort),
  REG_JNI(register_android_hardware_UsbDevice),
  REG_JNI(register_android_hardware_UsbDeviceConnection),
  REG_JNI(register_android_hardware_UsbRequest),
  REG_JNI(register_android_media_AudioRecord),
  REG_JNI(register_android_media_AudioSystem),
  REG_JNI(register_android_media_AudioTrack),
  REG_JNI(register_android_media_JetPlayer),
  REG_JNI(register_android_media_RemoteDisplay),
  REG_JNI(register_android_media_ToneGenerator),

  REG_JNI(register_android_opengl_classes),
  REG_JNI(register_android_server_NetworkManagementSocketTagger),
  REG_JNI(register_android_server_Watchdog),
  REG_JNI(register_android_ddm_DdmHandleNativeHeap),
  REG_JNI(register_android_backup_BackupDataInput),
  REG_JNI(register_android_backup_BackupDataOutput),
  REG_JNI(register_android_backup_FileBackupHelperBase),
  REG_JNI(register_android_backup_BackupHelperDispatcher),
  REG_JNI(register_android_app_backup_FullBackup),
  REG_JNI(register_android_app_ActivityThread),
  REG_JNI(register_android_app_NativeActivity),
  REG_JNI(register_android_view_InputChannel),
  REG_JNI(register_android_view_InputEventReceiver),
  REG_JNI(register_android_view_InputEventSender),
  REG_JNI(register_android_view_InputQueue),
  REG_JNI(register_android_view_KeyEvent),
  REG_JNI(register_android_view_MotionEvent),
  REG_JNI(register_android_view_PointerIcon),
  REG_JNI(register_android_view_VelocityTracker),

  REG_JNI(register_android_content_res_ObbScanner),
  REG_JNI(register_android_content_res_Configuration),

  REG_JNI(register_android_animation_PropertyValuesHolder),
  REG_JNI(register_com_android_internal_content_NativeLibraryHelper),
  REG_JNI(register_com_android_internal_net_NetworkStatsFactory),
};

#ifdef NDEBUG
  #define REG_JNI(name) {name}
  struct RegJNIRec {
    int (*mProc)(JNIEnv*);
  };
#else
  #define REG_JNI(name) {name, #name}
  struct RegJNIRec {
    int (*mProc)(JNIEnv*);
    const char* mName;
  };
#endif

可以看到,REG_JNI是一个宏,宏里面包括的就是那个参数为JNIEnv*,返回值为int的函数指针mProc,我们以register_android_debug_JNITest为例,源码位置为/frameworks/base/core/jni/android_debug_JNITest.cpp:

#define NELEM(x) (sizeof(x)/sizeof(*(x)))

int register_android_debug_JNITest(JNIEnv* env)
{
  return jniRegisterNativeMethods(env, "android/debug/JNITest", gMethods, NELEM(gMethods));
}

可以看到,mProc其实就是为Java类注册JNI函数。
进入JAVA世界

可以看到CallStaticVoidMethod最终将调用com.android.internal.os.ZygoteInit的main函数,下面就来看一下这个Java世界的入口函数。源码位置:/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java,源码如下:

public static void main(String argv[])
{
  try {
    SamplingProfilerIntegration.start();

    // 1. 注册zygote用的socket
    registerZygoteSocket();
    EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START, SystemClock.uptimeMillis());

    // 2. 预加载类和资源
    preload();
    EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END, SystemClock.uptimeMillis());

    SamplingProfilerIntegration.writeZygoteSnapshot();

    // 强制执行一次垃圾收集
    gc();

    Trace.setTracingEnabled(false);

    if (argv.length != 2) {
      throw new RuntimeException(argv[0] + USAGE_STRING);
    }

    if (argv[1].equals("start-system-server")) {
      // 3. 启动system-server
      startSystemServer();
    } else if (!argv[1].equals("")) {
      throw new RuntimeException(argv[0] + USAGE_STRING);
    }

    Log.i(TAG, "Accepting command socket connections");

    // 4. 进入请求应答模式
    runSelectLoop();
    closeServerSocket();

  } catch(MethodAndArgsCaller caller) {
    caller.run();
  } catch(RuntimeException ex) {
    Log.e(TAG, "Zygote died with exception", ex);
    closeServerSocket();
    throw ex;
  }
}

上述代码中有5个重要的点,我已经通过标号标记出来了,接下来我们分别分析一下这5点函数的具体实现。
建立IPC通信服务端——registerZygoteSocket

zygote及系统中其他程序的通信没有使用Binder,而是采用了基于AF_UNIX类型的socket。registerZygoteSocket函数的使命正是建立这个Socket,实现代码如下:

private static void registerZygoteSocket()
{
  if (sServerSocket == null) {
    int fileDesc;
    try {
      String env = System.getenv(ANDROID_SOCKET_ENV);
      fileDesc = Integer.parseInt(env);
    } catch (RuntimeException ex) {
      throw new RuntimeException(ANDROID_SOCKET_ENV + " unset or invalid", ex);
    }

    try {
      sServerSocket = new LocalServerSocket(createFileDescriptor(fileDesc));
    } catch(IOException ex) {
      throw new RuntimeException("Error binding to local socket '" + fileDesc + "'", ex);
    }
  }
}

public class LocalServerSocket {
  private final LocalSocketImpl impl;
  private final LocalSocketAddress localAddress;

  private static final int LISTEN_BACKLOG = 50;

  /**
   * Create a LocalServerSocket from a file descriptor that's already
   * been created and bound. listen() will be called immediately on it.
   * Used for cases where file descriptors are passed in via environment
   * variables.
   */
  public LocalServerSocket(FileDescriptor fd) throws IOException {
    impl = new LocalSocketImpl(fd);
    impl.listen(LISTEN_BACKLOG);
    localAddress = impl.getSockAddress();
  }
}

registerZygoteSocket很简单,就是创建一个服务端的socket。
预加载类和资源——preload

我们先来看一下preload函数实现:

static void preload()
{
  preloadClasses();
  preloadResources();
  preloadOpenGL();
}

preload函数里面分别调用了三个预加载函数,我们分别来分析一下这几个函数的实现。

首先是preloadClasses,函数实现如下:

private static final int UNPRIVILEGED_UID = 9999;
private static final int UNPRIVILEGED_GID = 9999;

private static final int ROOT_UID = 0;
private static final int ROOT_GID = 0;

private static void preloadClasses()
{
  final VMRuntime runtime = VMRuntime.getRuntime();

  InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream(PRELOADED_CLASSES);
  if (is == null) {
    Log.e(TAG, "Couldn't find " + PRELOADED_CLASSES + ".");
  } else {
    Log.i(TAG, "Preloading classes...");
    long startTime = SystemClock.uptimeMillis();

    setEffectiveGroup(UNPRIVILEGED_GID);
    setEffectiveGroup(UNPRIVILEGED_UID);

    float defaultUtilization = runtime.getTargetHeapUtilization();
    runtime.setTargetHeapUtilization(0.8f);

    System.gc();
    runtime.runFinalizationSync();
    Debug.startAllocCounting();

    try {
      // 创建一个缓冲区为256字符的输入流
      BufferedReader br = new BufferdReader(new InputStreamReader(is), 256);
      int count = 0;
      String line;
      while ((line = br.readLine()) != null) {
        // skip comments and blank lines.
        line = line.trim();
        if (line.startsWith("#") || line.equals("")) {
          continue;
        }

        try {
          if (false) {
            Log.v(TAG, "Preloading " + line + "...");
          }
          Class.forName(line);
          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);
        }
      }
      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);
      runtime.setTargetHeapUtilization(defaultUtilization);

      runtime.preloadDexCaches();
      Debug.stopAllocCounting();

      setEffectiveUser(ROOT_UID);
      setEffectiveGroup(ROOT_GID);
    }
  }
}

preloadClasses看起来很简单,但是实际上它有很多的类需要加载。可以查看一下/frameworks/base/preloaded-classes文件,这里面都是需要预加载的类。

接下来,分析一下preloadResources函数的源码:

private static final boolean PRELOAD_RESOURCES = true;
private static void preloadResources()
{
  final VMRuntime runtime = VMRuntime.getRuntime();
  Debug.startAllocCounting();

  try {
    System.gc();
    runtime.runFinalizationSync();
    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(runtime, 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(runtime, ar);
      ar.recycle();
      Log.i(TAG, "...preloaded " + N + " resources in " + (SystemClock.uptimeMillis() - startTime) + "ms.");
    }
    mResources.finishPreloading();
  } catch (RuntimeException e) {
    Log.w(TAG, "Failure preloading resources", e);
  } finally {
    Debug.stopAllocCounting();
  }
}

接下来,是预加载OpenGL。源码如下:

private static void preloadOpenGL()
{
  if (!SystemProperties.getBoolean(PROPERTY_DISABLE_OPENGL_PRELOADING, false)) {
    EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
  }
}

启动system_server

现在我们要分析第三个关键点:startSystemServer。这个函数会创建java世界中系统Service所驻留的进程system_server,该进程是framework的核心。如何system_server挂掉,会导致zygote自杀。我们来看一下startSystemServer()实现源码。

/**
 * Prepare the arguments and fork for the system server process.
 */
private static boolean startSystemServer() throws MethodAndArgsCaller, RuntimeException
{
  long capabilities = posixCapabilitiesAsBits(
    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_RESOURCE,
    OsConstants.CAP_SYS_TIME,
    OsConstants.CAP_SYS_TTY_CONFIG
  );

  // 设置参数
  String args[] = {
    "--setuid=1000",
    "--setgid=1000",
    "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1032,3001,3002,3003,3006,3007",
    "--capabilities=" + capabilities + "," + capabilities,
    "--runtime-init",
    "--nice-name=system_server", // 进程名为system_server
    "com.android.server.SystemServer",
  };

  ZygoteConnection.Arguments parsedArgs = null;

  int pid;

  try {
    parsedArgs = new ZygoteConnection.Arguments(args);
    ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
    ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);

    /* Request to fork the system server process */
    pid = Zygote.forkSystemServer(
        parsedArgs.uid, parsedArgs.gid,
        parsedArgs.gids,
        parsedArgs.debugFlags,
        null,
        parsedArgs.permittedCapabilities,
        parsedArgs.effectiveCapabilities
    );
  } catch (IllegalArgumentException ex) {
    throw new RuntimeException(ex);
  }

  /* For child process */
  if (pid == 0) {
    handleSystemServerProcess(parsedArgs);
  }

  return true;
}

有求必应之等待请求——runSelectLoop

zygote从startSystemServer返回后,将进入第四个关键的函数:runSelectLoop。我们来看一下这个函数的实现:

static final int GC_LOOP_COUNT = 10;
private static void runSelectLoop() throws MethodAndArgsCaller {
  ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
  ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
  FileDescriptor[] fdArray = new FileDescriptor[4];

  fds.add(sServerSocket.getFileDescriptor());
  peers.add(null);

  int loopCount = GC_LOOP_COUNT;
  while (true) {
    int index;
    if (loopCount <= 0) {
      gc();
      loopCount = GC_LOOP_COUNT;
    } else {
      loopCount --;
    }

    try {
      fdArray = fds.toArray(fdArray);
      index = selectReadable(fdArray);
    } catch(IOException ex) {
      throw new RuntimeException("Error in select()", ex);
    }

    if (index < 0) {
      throw new RuntimeException("Error in select()");
    } else if (index == 0) {
      ZygoteConnection newPeer = acceptCommandPeer();
      peers.add(newPeer);
    }
  }
}
(0)

相关推荐

  • 详细分析Android中实现Zygote的源码

    概述 在Android系统中,所有的应用程序进程,以及用来运行系统关键服务的System进程都是由zygote进程负责创建的.因此,我们将它称为进程孵化器.zygote进程是通过复制自身的方式来创建System进程和应用程序进程的.由于zygote进程在启动时会在内部创建一个虚拟机实例,因此,通过复制zygote进程而得到的System进程和应用程序进程可以快速地在内部获得一个虚拟机实例拷贝. zygote进程在启动完成之后,会马上将System进程启动起来,以便它可以将系统的关键服务启动起来.

  • 详细分析Android中onTouch事件传递机制

    onTach介绍 ontach是Android系统中整个事件机制的基础.Android中的其他事件,如onClick.onLongClick等都是以onTach为基础的. onTach包括从手指按下到离开手机屏幕的整个过程,在微观形式上,具体表现为action_down.action_move和action_up等过程. onTach两种主要定义形式如下: 1.在自定义控件中,常见的有重写onTouchEvent(MotionEvent ev)方法.如在开发中经常可以看到重写的onTouchEv

  • 简略分析Android的Retrofit应用开发框架源码

    面对一个项目,对于Android应用开发框架的选择,我想过三种方案: 1.使用Loader + HttpClient + GreenDao + Gson + Fragment,优点是可定制性强,由于使用Google家自己的Loader和LoaderManager,代码健壮性强. 缺点是整套代码学习成本较高,使用过程中样板代码较多,(比如每一个Request都需要产生一个新类) 2.Volley,作为Google在IO大会上得瑟过的一个网络库,其实不算什么新东西(2013 IO发布),使用较为简单

  • 分析Android中线程和线程池

    目录 前言 HandlerThread IntentService 线程池的好处 ThreadPoolExecutor 线程池的分类 FixedThreadPool CachedThreadPool ScheduledThreadPool SingleThreadExecutor 前言 由于内容过多,所以将分为上下两部分,第一部分主要和大家谈谈Android中的线程,以及在Android中的常用的线程池.第二部分我们一起来了解一下AsyncTask的使用和工作原理. HandlerThread

  • 分析Android中应用的启动流程

    前言 在我们开始之前,希望您能最好已经满足以下条件: 1.有一份编译后的Android源码(亲自动手实践才会有更深入的理解) 2.对Binder机制有一定的了解 本文启动流程分析基于Android 5.1的源码.为什么是5.1的源码呢?因为手边编译完的代码只有这个版本-另外,用什么版本的源码并不重要,大体的流程并无本质上的区别,仅仅是实现细节的调整,找一个你熟悉的版本就好. 1.启动时序图 作为一个轻微强迫症的人,整理的时序图,相信大家按图索骥,一定能搞明白整个启动流程: 说明:为了让大家更清楚

  • 详细分析sqlserver中的小数类型(float和decimal)

    在SQL Server中实际上只有两种小数数值类型,分别是float(近似数值)和decimal(精确数值),这两种类型能表示所有的小数数值类型. float(近似数值类型) float表示的是近似数值,存在一定的精度缺失. float(n) 这里的n是以科学计数法存储浮点数尾数的位数,因此此参数决定了精度和存储的大小.其是可选的,默认值是53,即float等价于float(53),占用8bytes.如果指定了n,则它必须是介于1至53之间的值.实际上,虽然n的取值范围定义是1至53,但实际上f

  • Postgres中UPDATE更新语句源码分析

    目录 PG中UPDATE源码分析 整体流程分析 解析部分——生成语法解析树UpdateStmt 解析部分——生成查询树Query 优化器——生成执行计划 执行器 事务 总结 PG中UPDATE源码分析 本文主要描述SQL中UPDATE语句的源码分析,代码为PG13.3版本. 整体流程分析 以update dtea set id = 1;这条最简单的Update语句进行源码分析(dtea不是分区表,不考虑并行等,没有建立任何索引),帮助我们理解update的大致流程. SQL流程如下: parse

  • YOLOv5中SPP/SPPF结构源码详析(内含注释分析)

    目录 一.SPP的应用的背景 二.SPP结构分析 三.SPPF结构分析 四.YOLOv5中SPP/SPPF结构源码解析(内含注释分析) 总结 一.SPP的应用的背景 在卷积神经网络中我们经常看到固定输入的设计,但是如果我们输入的不能是固定尺寸的该怎么办呢? 通常来说,我们有以下几种方法: (1)对输入进行resize操作,让他们统统变成你设计的层的输入规格那样.但是这样过于暴力直接,可能会丢失很多信息或者多出很多不该有的信息(图片变形等),影响最终的结果. (2)替换网络中的全连接层,对最后的卷

  • Android Handler,Message,MessageQueue,Loper源码解析详解

    本文主要是对Handler和消息循环的实现原理进行源码分析,如果不熟悉Handler可以参见博文< Android中Handler的使用>,里面对Android为何以引入Handler机制以及如何使用Handler做了讲解. 概括来说,Handler是Android中引入的一种让开发者参与处理线程中消息循环的机制.我们在使用Handler的时候与Message打交道最多,Message是Hanlder机制向开发人员暴露出来的相关类,可以通过Message类完成大部分操作Handler的功能.但

  • Android线程间通信Handler源码详解

    目录 前言 01. 用法 02.源码 03.结语 前言 在[Android]线程间通信 - Handler之使用篇主要讲了 Handler 的创建,发送消息,处理消息 三个步骤.那么接下来,我们也按照这三个步骤,从源码中去探析一下它们具体是如何实现的.本篇是关于创建源码的分析. 01. 用法 先回顾一下,在主线程和非主线程是如何创建 Handler 的. //主线程 private val mHandler: Handler = object : Handler(Looper.getMainLo

随机推荐