程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 具體剖析Android中完成Zygote的源碼

具體剖析Android中完成Zygote的源碼

編輯:關於C++

具體剖析Android中完成Zygote的源碼。本站提示廣大學習愛好者:(具體剖析Android中完成Zygote的源碼)文章只能為提供參考,不一定能成為您想要的結果。以下是具體剖析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世界。
  4. 接上去,我們分離剖析這三個症結點。
    創立虛擬機——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;
    }
    
    


    更多虛擬機參數的設置,我這裡就不做特別解釋了,年夜家感興致可以自行谷歌。(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_谷歌_android_gles_jni_EGLImpl),
      REG_JNI(register_com_谷歌_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);
        }
      }
    }
    
    

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved