系统进程启动流程分析(二)

Android系统启动始于init进程解析init.rc,启动Zygote进程,预加载类库和资源。Zygote fork出system_server,初始化系统服务如AMS、WMS。system_server启动后,加载应用并创建用户界面。Zygote采用Copy-On-Write避免多线程问题,确保系统高效运行。
摘要由CSDN通过智能技术生成

什么是Runtime ?

https://stackoverflow.com/questions/3900549/what-is-runtime

归纳起来的意思就是,Runtime 是支撑程序运行的基础库,它是与语言绑定在一起的。比如:

C Runtime:就是C standard lib, 也就是我们常说的libc。(有意思的是, Wiki会自动将“C
runtime” 重定向到 “C Standard Library”).
Java Runtime: 同样,Wiki将其重定向到” Java Virtual Machine”, 这里当然包括Java 的支撑类库
(.jar).
AndroidRuntime: 显而易见,就是为Android应用运行所需的运行时环境。这个环境包括以下东
东:
Dalvik VM: Android的Java VM, 解释运行Dex格式Java程序。每个进程运行一个虚拟机(什么
叫运行虚拟机?说白了,就是一些C代码,不停的去解释Dex格式的二进制码(Bytecode),把
它们转成机器码(Machine code),然后执行,当然,现在大多数的Java 虚拟机都支持JIT,也
就是说,bytecode可能在运行前就已经被转换成机器码,从而大大提高了性能。过去一个普
遍的认识是Java 程序比C,C++等静态编译的语言慢,但随着JIT的介入和发展,这个已经完全
是过去时了,JIT的动态性运行允许虚拟机根据运行时环境,优化机器码的生成,在某些情况
下,Java甚至可以比C/C++跑得更快,同时又兼具平台无关的特性,这也是为什么Java如今如
此流行的原因之一吧)。
Android的Java 类库, 大部分来自于 Apache Hamony, 开源的Java API 实现,如 java.lang,
java.util, java.net. 但去除了AWT, Swing 等部件。
JNI: C和Java互调的接口。
Libc: Android也有很多C代码,自然少不了libc,注意的是,Android的libc叫 bionic C

// \frameworks\base\core\jni\androidRuntime.cpp start() L1091
void AndroidRuntime::start(const char* className, const Vector<String8>&
options, bool zygote)
{
 ...
  JNIEnv* env;
  //JNI_CreateJavaVM L1015
  if (startVm(&mJavaVM, &env, zygote) != 0) {
    return;
 }
  onVmCreated(env);
  /*
  * Register android functions.
  */
  if (startReg(env) < 0) {
    ALOGE("Unable to register all android natives\n");
    return;
 }
...
}

Java虚拟机的启动大致做了以下一些事情:
1. 从property读取一系列启动参数。
2. 创建和初始化结构体全局对象(每个进程)gDVM,及对应与JavaVM和JNIEnv的内部结构体
JavaVMExt, JNIEnvExt.
3. 初始化java虚拟机,并创建虚拟机线程
4. 注册系统的JNI,Java程序通过这些JNI接口来访问底层的资源。

loadJniLibrary("javacore");
 loadJniLibrary("nativehelper");

5. 为Zygote的启动做最后的准备,包括设置SID/UID, 以及mount 文件系统
6. 返回JavaVM 给Native代码,这样它就可以向上访问Java的接口

// \frameworks\base\core\jni\androidRuntime.cpp startVm() L596
int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote)
{
...
// L1015
 /*
  * Initialize the VM.
  *
  * The JavaVM* is essentially per-process, and the JNIEnv* is per-
thread.
  * If this call succeeds, the VM is ready, and we can start issuing
  * JNI calls.
  */
  //startVM的前半部分是在处理虚拟机的启动参数,处理完配置参数后,会调用libart.so提供
的一个接口:JNI_CreateJavaVM函数
  if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {
    ALOGE("JNI_CreateJavaVM failed\n");
    return -1;
 }
...
// \art\runtime\java_vm_ext.cc JNI_CreateJavaVM() L1139
extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void*
vm_args) {
 ScopedTrace trace(__FUNCTION__);
 const JavaVMInitArgs* args = static_cast<JavaVMInitArgs*>(vm_args);
 if (JavaVMExt::IsBadJniVersion(args->version)) {
  LOG(ERROR) << "Bad JNI version passed to CreateJavaVM: " << args-
>version;
  return JNI_EVERSION;
}
 RuntimeOptions options;
 for (int i = 0; i < args->nOptions; ++i) {
  JavaVMOption* option = &args->options[i];
  options.push_back(std::make_pair(std::string(option->optionString),
option->extraInfo));
}
 bool ignore_unrecognized = args->ignoreUnrecognized;
 //通过Runtime的create方法创建单例的Runtime对象
 if (!Runtime::Create(options, ignore_unrecognized)) {
  return JNI_ERR;
}
 // Initialize native loader. This step makes sure we have
 // everything set up before we start using JNI.
 android::InitializeNativeLoader();
 Runtime* runtime = Runtime::Current();
 bool started = runtime->Start();
 if (!started) {
  delete Thread::Current()->GetJniEnv();
  delete runtime->GetJavaVM();
  LOG(WARNING) << "CreateJavaVM failed";
  return JNI_ERR;
}
 *p_env = Thread::Current()->GetJniEnv();
 *p_vm = runtime->GetJavaVM();
 return JNI_OK;
}

首先通过Runtime的create方法创建单例的Runtime对象,runtime负责提供art虚拟机的运行时环境,
然后调用其init方法来初始化虚拟机

// \art\runtime\runtime.cc Init() L1109
bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) {
...
// L1255 创建堆管理对象。
heap_ = new gc::Heap(runtime_options.GetOrDefault(Opt::MemoryInitialSize),
           runtime_options.GetOrDefault(Opt::HeapGrowthLimit),
           runtime_options.GetOrDefault(Opt::HeapMinFree),
           runtime_options.GetOrDefault(Opt::HeapMaxFree),
          
runtime_options.GetOrDefault(Opt::HeapTargetUtilization),
           foreground_heap_growth_multiplier,
           runtime_options.GetOrDefault(Opt::MemoryMaximumSize),
          
runtime_options.GetOrDefault(Opt::NonMovingSpaceCapacity),
           runtime_options.GetOrDefault(Opt::Image),
          
runtime_options.GetOrDefault(Opt::ImageInstructionSet),
           // Override the collector type to CC if the read
barrier config.
           kUseReadBarrier ? gc::kCollectorTypeCC :
xgc_option.collector_type_,
           kUseReadBarrier ?
BackgroundGcOption(gc::kCollectorTypeCCBackground)
                   :
runtime_options.GetOrDefault(Opt::BackgroundGc),
           runtime_options.GetOrDefault(Opt::LargeObjectSpace),
runtime_options.GetOrDefault(Opt::LargeObjectThreshold),
           runtime_options.GetOrDefault(Opt::ParallelGCThreads),
           runtime_options.GetOrDefault(Opt::ConcGCThreads),
           runtime_options.Exists(Opt::LowMemoryMode),
          
runtime_options.GetOrDefault(Opt::LongPauseLogThreshold),
          
runtime_options.GetOrDefault(Opt::LongGCLogThreshold),
           runtime_options.Exists(Opt::IgnoreMaxFootprint),
           runtime_options.GetOrDefault(Opt::UseTLAB),
           xgc_option.verify_pre_gc_heap_,
           xgc_option.verify_pre_sweeping_heap_,
           xgc_option.verify_post_gc_heap_,
           xgc_option.verify_pre_gc_rosalloc_,
           xgc_option.verify_pre_sweeping_rosalloc_,
           xgc_option.verify_post_gc_rosalloc_,
           xgc_option.gcstress_,
           xgc_option.measure_,
          
runtime_options.GetOrDefault(Opt::EnableHSpaceCompactForOOM),
          
runtime_options.GetOrDefault(Opt::HSpaceCompactForOOMMinIntervalsMs));
 ...
 // L1408创建java虚拟机对象
 std::string error_msg;
 java_vm_ = JavaVMExt::Create(this, runtime_options, &error_msg);
 if (java_vm_.get() == nullptr) {
  LOG(ERROR) << "Could not initialize JavaVMExt: " << error_msg;
  return false;
}
 // Add the JniEnv handler.
 // TODO Refactor this stuff.
 java_vm_->AddEnvironmentHook(JNIEnvExt::GetEnvHandler);
 Thread::Startup();
 // ClassLinker needs an attached thread, but we can't fully attach a
thread without creating
 // objects. We can't supply a thread group yet; it will be fixed later.
Since we are the main
 // thread, we do not get a java peer.
 // L1424 连接主线程
 Thread* self = Thread::Attach("main", false, nullptr, false);
 CHECK_EQ(self->GetThreadId(), ThreadList::kMainThreadId);
 CHECK(self != nullptr);        
...
 // L1437 创建类连接器
 if (UNLIKELY(IsAotCompiler())) {
  class_linker_ = new AotClassLinker(intern_table_);
} else {
  class_linker_ = new ClassLinker(intern_table_);
}
 if (GetHeap()->HasBootImageSpace()) {
  //初始化类连接器
  bool result = class_linker_->InitFromBootImage(&error_msg);
  if (!result) {
   LOG(ERROR) << "Could not initialize from image: " << error_msg;
   return false;
 }
 ...
 }
}
}

1. new gc::heap(),创建Heap对象,这是虚拟机管理对内存的起点。
2. new JavaVmExt(),创建Java虚拟机实例。
3. Thread::attach(),attach主线程
4. 创建ClassLinker
5. 初始化ClassLinker,成功attach到runtime环境后,创建ClassLinker实例负责管理java class

到这里,虚拟机的创建和初始化就完成了

// \art\runtime\threed.cc Attach() L775
template <typename PeerAction>
Thread* Thread::Attach(const char* thread_name, bool as_daemon, PeerAction
peer_action) {
 Runtime* runtime = Runtime::Current();
 if (runtime == nullptr) {
  LOG(ERROR) << "Thread attaching to non-existent runtime: " <<
   ((thread_name != nullptr) ? thread_name : "(Unnamed)");
  return nullptr;
}
 Thread* self;
{
  MutexLock mu(nullptr, *Locks::runtime_shutdown_lock_);
  if (runtime->IsShuttingDownLocked()) {
   LOG(WARNING) << "Thread attaching while runtime is shutting down: " <<
    ((thread_name != nullptr) ? thread_name : "(Unnamed)");
   return nullptr;
 } else {
   Runtime::Current()->StartThreadBirth();
   self = new Thread(as_daemon);
   bool init_success = self->Init(runtime->GetThreadList(), runtime-
>GetJavaVM());
   Runtime::Current()->EndThreadBirth();
   if (!init_success) {
    delete self;
    return nullptr;
  }
 }
}
 self->InitStringEntryPoints();
 CHECK_NE(self->GetState(), kRunnable);
 self->SetState(kNative);
 // Run the action that is acting on the peer.
 if (!peer_action(self)) {
  runtime->GetThreadList()->Unregister(self);
  // Unregister deletes self, no need to do this here.
  return nullptr;
}
if (VLOG_IS_ON(threads)) {
  if (thread_name != nullptr) {
   VLOG(threads) << "Attaching thread " << thread_name;
 } else {
   VLOG(threads) << "Attaching unnamed thread.";
 }
  ScopedObjectAccess soa(self);
  self->Dump(LOG_STREAM(INFO));
}
{
  ScopedObjectAccess soa(self);
  runtime->GetRuntimeCallbacks()->ThreadStart(self);
}
 return self;
}

除了系统的JNI接口(”javacore”, “nativehelper”), android framework 还有大量的Native实现,
Android将所有这些接口一次性的通过start_reg()来完成

// \frameworks\base\core\jni\androidRuntime.cpp startReg() L1511
int AndroidRuntime::startReg(JNIEnv* env)
{
  ATRACE_NAME("RegisterAndroidNatives");
  /*
  * This hook causes all future threads created in this process to be
  * attached to the JavaVM. (This needs to go away in favor of JNI
  * Attach calls.)
  */
  androidSetCreateThreadFunc((android_create_thread_fn)
javaCreateThreadEtc);
  ALOGV("--- registering native functions ---\n");
  /*
  * Every "register" function calls one or more things that return
  * a local reference (e.g. FindClass). Because we haven't really
  * started the VM yet, they're all getting stored in the base frame
  * and never released. Use Push/Pop to manage the storage.
  */
  env->PushLocalFrame(200);
  if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
    env->PopLocalFrame(NULL);
    return -1;
 }
  env->PopLocalFrame(NULL);
  //createJavaThread("fubar", quickTest, (void*) "hello");
  return 0;
}
// \system\core\libutils\Threads.cpp run() L662
status_t Thread::run(const char* name, int32_t priority, size_t stack)
{
  LOG_ALWAYS_FATAL_IF(name == nullptr, "thread name not provided to
Thread::run");
  Mutex::Autolock _l(mLock);
  if (mRunning) {
    // thread already started
    return INVALID_OPERATION;
 }
  // reset status and exitPending to their default value, so we can
  // try again after an error happened (either below, or in readyToRun())
  mStatus = NO_ERROR;
  mExitPending = false;
  mThread = thread_id_t(-1);
  // hold a strong reference on ourself
  mHoldSelf = this;
  mRunning = true;
  bool res;
  // L685 Android native层有两种Thread的创建方式
  if (mCanCallJava) {
    res = createThreadEtc(_threadLoop,
        this, name, priority, stack, &mThread);
 } else {
    res = androidCreateRawThreadEtc(_threadLoop,
        this, name, priority, stack, &mThread);
 }
  if (res == false) {
    mStatus = UNKNOWN_ERROR;  // something happened!
    mRunning = false;
    mThread = thread_id_t(-1);
    mHoldSelf.clear();  // "this" may have gone away after this.
    return UNKNOWN_ERROR;
 }
  // Do not refer to mStatus here: The thread is already running (may, in
fact
  // already have exited with a valid mStatus result). The NO_ERROR
indication
  // here merely indicates successfully starting the thread and does not
  // imply successful termination/execution.
  return NO_ERROR;
  // Exiting scope of mLock is a memory barrier and allows new thread to
run
}

它们的区别在是是否能够调用Java端函数,普通的thread就是对pthread_create的简单封装

// \system\core\libutils\Threads.cpp run() L117
int androidCreateRawThreadEtc(android_thread_func_t entryFunction,
               void *userData,
               const char* threadName __android_unused,
               int32_t threadPriority,
               size_t threadStackSize,
               android_thread_id_t *threadId)
{
 ...
  errno = 0;
  pthread_t thread;
  int result = pthread_create(&thread, &attr,
         (android_pthread_entry)entryFunction, userData);
 ...
  return 1;
}
// \frameworks\base\core\jni\androidRuntime.cpp javaCreateThreadEtc() L1271
int AndroidRuntime::javaCreateThreadEtc(
                android_thread_func_t entryFunction,
                void* userData,
                const char* threadName,
                int32_t threadPriority,
                size_t threadStackSize,
                android_thread_id_t* threadId)
{
  void** args = (void**) malloc(3 * sizeof(void*));  // javaThreadShell
must free
  int result;
  LOG_ALWAYS_FATAL_IF(threadName == nullptr, "threadName not provided to
javaCreateThreadEtc");
  args[0] = (void*) entryFunction;
  args[1] = userData;
  args[2] = (void*) strdup(threadName);  // javaThreadShell must free
  result = androidCreateRawThreadEtc(AndroidRuntime::javaThreadShell,
args,
    threadName, threadPriority, threadStackSize, threadId);
  return result;
}
// \frameworks\base\core\jni\androidRuntime.cpp javaThreadShell() L1242
int AndroidRuntime::javaThreadShell(void* args) {
  void* start = ((void**)args)[0];
  void* userData = ((void **)args)[1];
  char* name = (char*) ((void **)args)[2];     // we own this storage
  free(args);
  JNIEnv* env;
  int result;
  /* hook us into the VM */
  if (javaAttachThread(name, &env) != JNI_OK)
    return -1;
  /* start the thread running */
  result = (*(android_thread_func_t)start)(userData);
  /* unhook us */
  javaDetachThread();
  free(name);
  return result;
}
// \frameworks\base\core\java\com\android\internal\os\RuntimeInit.java
main() L325
public static final void main(String[] argv) {
    enableDdms();
    if (argv.length == 2 && argv[1].equals("application")) {
      if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application");
     
//将System.out 和 System.err 输出重定向到Android 的Log系统(定义在
android.util.Log)
      redirectLogStreams();
   } else {
      if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting tool");
   }
//commonInit(): 初始化了一下系统属性,其中最重要的一点就是设置了一个未捕捉异常的
handler,当代码有任何未知异常,就会执行它,调试过Android代码的同学经常看到的”*** FATAL
EXCEPTION IN SYSTEM PROCESS” 打印就出自这里
    commonInit();
    /*
    * Now that we're running in interpreted code, call back into native
code
    * to run the system.
    */
    nativeFinishInit();
   if (DEBUG) Slog.d(TAG, "Leaving RuntimeInit!");
 }
// \frameworks\base\core\jni\androidRuntime.cpp nativeFinishInit() L225
/*
* Code written in the Java Programming Language calls here from main().
*/
static void com_android_internal_os_RuntimeInit_nativeFinishInit(JNIEnv* env,
jobject clazz)
{
  gCurRuntime->onStarted();
}
// \frameworks\base\cmds\app_process\app_main.cpp onStarted() L78
virtual void onStarted()
 {
    sp<ProcessState> proc = ProcessState::self();
    ALOGV("App process: starting thread pool.\n");
    proc->startThreadPool();
    AndroidRuntime* ar = AndroidRuntime::getRuntime();
    ar->callMain(mClassName, mClass, mArgs);
    IPCThreadState::self()->stopProcess();
    hardware::IPCThreadState::self()->stopProcess();
 }

ZygotInit

// \frameworks\base\core\java\com\android\internal\os\ZygotInit.java main()
L750
public static void main(String argv[]) {
    ZygoteServer zygoteServer = new ZygoteServer(); //新建Zygote服务器端
    ...
    final Runnable caller;
    try {
     ...
      boolean startSystemServer = false;
      String socketName = "zygote";Dalvik VM进程系统
      String abiList = null;
      boolean enableLazyPreload = false;
      for (int i = 1; i < argv.length; i++) {
        //还记得app_main.cpp中传的start-system-server参数吗,在这里总有用
到了
        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)) {
          socketName =
argv[i].substring(SOCKET_NAME_ARG.length());
       } else {
          throw new RuntimeException("Unknown command line
argument: " + argv[i]);
       }
     }
      if (abiList == null) {
        throw new RuntimeException("No ABI list supplied.");
     }
      zygoteServer.registerServerSocketFromEnv(socketName);//注册Socket
      // In some configurations, we avoid preloading resources and
classes eagerly.
      // In such cases, we will preload things prior to our first
fork.
      // 在有些情况下我们需要在第一个fork之前进行预加载资源
      if (!enableLazyPreload) {
      
        preload(bootTimingsTraceLog);
      
     } else {
        Zygote.resetNicePriority();
     }
      // Do an initial gc to clean up after startup
      bootTimingsTraceLog.traceBegin("PostZygoteInitGC");
      //主动进行一次资源GC
      gcAndFinalize();
      bootTimingsTraceLog.traceEnd(); // PostZygoteInitGC
      bootTimingsTraceLog.traceEnd(); // ZygoteInit
      // Disable tracing so that forked processes do not inherit stale
tracing tags from
      // Zygote.
      Trace.setTracingEnabled(false, 0);
      Zygote.nativeSecurityInit();
      // Zygote process unmounts root storage spaces.
      Zygote.nativeUnmountStorageOnInit();
      ZygoteHooks.stopZygoteNoThreadCreation();
      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;
       }
     }
      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 exception", ex);
      throw ex;
   } finally {
      zygoteServer.closeServerSocket();
   }
    // We're in the child process and have exited the select loop.
Proceed to execute the
    // command.
    if (caller != null) {
      caller.run();
   }
 }

preload() 的作用就是提前将需要的资源加载到VM中,比如class、resource等

// \frameworks\base\core\java\com\android\internal\os\ZygotInit.java
preload() L123
static void preload(TimingsTraceLog bootTimingsTraceLog) {
    Log.d(TAG, "begin preload");
    bootTimingsTraceLog.traceBegin("BeginIcuCachePinning");
    beginIcuCachePinning();
    bootTimingsTraceLog.traceEnd(); // BeginIcuCachePinning
    bootTimingsTraceLog.traceBegin("PreloadClasses");
    //加载指定的类到内存并且初始化,使用的Class.forName(class, true, null);方式
    preloadClasses();
    bootTimingsTraceLog.traceEnd(); // PreloadClasses
    bootTimingsTraceLog.traceBegin("PreloadResources");
    //加载Android通用的资源,比如drawable、color...
    preloadResources();
    bootTimingsTraceLog.traceEnd(); // PreloadResources
    Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadAppProcessHALs");
    nativePreloadAppProcessHALs();
    Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
    Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadOpenGL");
    //加载OpenGL...
    preloadOpenGL();
    Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
    //加载共用的Library
    preloadSharedLibraries();
    //加载Text资源,字体等
    preloadTextResources();
    // Ask the WebViewFactory to do any initialization that must run in
the zygote process,
    // for memory sharing purposes.
    // 为了内存共享,WebViewFactory进行任何初始化都要在Zygote进程中
    WebViewFactory.prepareWebViewInZygote();
    endIcuCachePinning();
    warmUpJcaProviders();
    Log.d(TAG, "end preload");
    sPreloadComplete = true;

preloadClassess 将framework.jar里的preloaded-classes 定义的所有class load到内存里,
preloaded-classes 编译Android后可以在framework/base下找到。而preloadResources 将系统的
Resource(不是在用户apk里定义的resource)load到内存。资源preload到Zygoted的进程地址空间,
所有fork的子进程将共享这份空间而无需重新load, 这大大减少了应用程序的启动时间,但反过来增加了
系统的启动时间。通过对preload 类和资源数目进行调整可以加快系统启动。Preload也是Android启动
最耗时的部分之一

// \frameworks\base\core\java\com\android\internal\os\ZygotInit.java
gcAndFinalize() L439
static void gcAndFinalize() {
    final VMRuntime runtime = VMRuntime.getRuntime();
    /* runFinalizationSync() lets finalizers be called in Zygote,
    * which doesn't have a HeapWorker thread.
    */
    System.gc();
    runtime.runFinalizationSync();
    System.gc();
 }

gc()调用只是通知VM进行垃圾回收,是否回收,什么时候回收全由VM内部算法决定。GC的回收有一个
复杂的状态机控制,通过多次调用,可以使得尽可能多的资源得到回收。gc()必须在fork之前完成(接下
来的StartSystemServer就会有fork操作),这样将来被复制出来的子进程才能有尽可能少的垃圾内存没
有释放

// \frameworks\base\core\java\com\android\internal\os\ZygotInit.java
gcAndFinalize() L657
private static Runnable forkSystemServer(String abiList, String socketName,
      ZygoteServer zygoteServer) {
    long capabilities = posixCapabilitiesAsBits(
      OsConstants.CAP_IPC_LOCK,
      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_PTRACE,
      OsConstants.CAP_SYS_TIME,
      OsConstants.CAP_SYS_TTY_CONFIG,
      OsConstants.CAP_WAKE_ALARM,
      OsConstants.CAP_BLOCK_SUSPEND
   );
    /* Containers run without some capabilities, so drop any caps that
are not available. */
    StructCapUserHeader header = new StructCapUserHeader(
        OsConstants._LINUX_CAPABILITY_VERSION_3, 0);
    StructCapUserData[] data;
    try {
      data = Os.capget(header);
   } catch (ErrnoException ex) {
      throw new RuntimeException("Failed to capget()", ex);
  }
    capabilities &= ((long) data[0].effective) | (((long)
data[1].effective) << 32);
    /* Hardcoded command line to start the system server */
   
    //启动SystemServer的命令行,部分参数写死
    String args[] = {
      "--setuid=1000",
      "--setgid=1000",
      "--
setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,1
024,1032,1065,3001,3002,3003,3006,3007,3009,3010",
      "--capabilities=" + capabilities + "," + capabilities,
      "--nice-name=system_server",
      "--runtime-args",
      "--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
      "com.android.server.SystemServer",
   };
    ZygoteConnection.Arguments parsedArgs = null;
    int pid;
    try {
      parsedArgs = new ZygoteConnection.Arguments(args);
      ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
      ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);//会设
置InvokeWith参数,这个参数在接下来的初始化逻辑中会有调用
      boolean profileSystemServer = SystemProperties.getBoolean(
          "dalvik.vm.profilesystemserver", false);
      if (profileSystemServer) {
        parsedArgs.runtimeFlags |= Zygote.PROFILE_SYSTEM_SERVER;
     }
      /* Request to fork the system server process */
      /* 创建 system server 进程 */
      pid = Zygote.forkSystemServer(
          parsedArgs.uid, parsedArgs.gid,
          parsedArgs.gids,
          parsedArgs.runtimeFlags,
          null,
          parsedArgs.permittedCapabilities,
          parsedArgs.effectiveCapabilities);
   } catch (IllegalArgumentException ex) {
      throw new RuntimeException(ex);
   }
    /* For child process */
    if (pid == 0) {//如果是第一次创建的话pid==0
      if (hasSecondZygote(abiList)) {
        waitForSecondaryZygote(socketName);
     }
      zygoteServer.closeServerSocket();
      return handleSystemServerProcess(parsedArgs);
   }
   return null;
 }

ZygoteInit.forkSystemServer() 方法fork 出一个新的进程,这个进程就是SystemServer进程。fork出来
的子进程在handleSystemServerProcess 里开始初始化工作,主要工作分为:
1. prepareSystemServerProfile()方法中将SYSTEMSERVERCLASSPATH中的AppInfo加载到VM
中。
2. 判断fork args中是否有invokWith参数,如果有则进行WrapperInit.execApplication(不进行深入
讲解了)。如果没有则调用

// \frameworks\base\core\java\com\android\internal\os\ZygoteInit.java
handleSystemServerProcess() L453
private static Runnable handleSystemServerProcess(ZygoteConnection.Arguments
parsedArgs) {
   ...
      if (profileSystemServer && (Build.IS_USERDEBUG || Build.IS_ENG))
{
        try {
          //将SYSTEMSERVERCLASSPATH中的AppInfo加载到VM中
          prepareSystemServerProfile(systemServerClasspath);
       } catch (Exception e) {
          Log.wtf(TAG, "Failed to set up system server profile",
e);
       }
     }
   }
    if (parsedArgs.invokeWith != null) {
     ...
     //判断fork args中是否有invokWith参数,如果有则进行
WrapperInit.execApplication
     WrapperInit.execApplication(parsedArgs.invokeWith,
          parsedArgs.niceName, parsedArgs.targetSdkVersion,
          VMRuntime.getCurrentInstructionSet(), null, args);
      throw new IllegalStateException("Unexpected return from
WrapperInit.execApplication");
   } else {
 
     ...
      /*
      * Pass the remaining arguments to SystemServer.
      */
      //调用zygoteInit
      return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion,
parsedArgs.remainingArgs, cl);
   }
    /* should never reach here */
 }
// \frameworks\base\core\java\com\android\internal\os\RuntimeInit.java
applicationInit() L345
  protected static Runnable applicationInit(int targetSdkVersion, String[]
argv,
      ClassLoader classLoader) {
   ...
    // Remaining arguments are passed to the start class's static main
    //findStaticMain来运行args的startClass的main方法
    return findStaticMain(args.startClass, args.startArgs, classLoader);
 }
// \frameworks\base\core\java\com\android\internal\os\RuntimeInit.java
findStaticMain() L287
protected static Runnable findStaticMain(String className, String[] argv,
      ClassLoader classLoader) {
    Class<?> cl;
    try {
      cl = Class.forName(className, true, classLoader);
   } catch (ClassNotFoundException ex) {
      throw new RuntimeException(
          "Missing class when invoking static main " + className,
          ex);
   }
    Method m;
    try {
      m = cl.getMethod("main", new Class[] { String[].class });
   } catch (NoSuchMethodException ex) {
      throw new RuntimeException(
          "Missing static main on " + className, ex);
   } catch (SecurityException ex) {
      throw new RuntimeException(
          "Problem getting static main on " + className, ex);
   }
    return new MethodAndArgsCaller(m, argv);
 }

很明显这是一个耗时操作所以使用线程来完成:

// \frameworks\base\core\java\com\android\internal\os\RuntimeInit.java
MethodAndArgsCaller L479
static class MethodAndArgsCaller implements Runnable {
    /** method to call */
    private final Method mMethod;
    /** argument array */
    private final String[] mArgs;
    public MethodAndArgsCaller(Method method, String[] args) {
      mMethod = method;
      mArgs = args;
   }
    public void run() {
      try {
        mMethod.invoke(null, new Object[] { mArgs });
     } catch (IllegalAccessException ex) {
        throw new RuntimeException(ex);
     } catch (InvocationTargetException ex) {
        Throwable cause = ex.getCause();
        if (cause instanceof RuntimeException) {
          throw (RuntimeException) cause;
       } else if (cause instanceof Error) {
          throw (Error) cause;
       }
        throw new RuntimeException(ex);
     }
   }
 }

System Server 启动流程
System Server 是Zygote fork 的第一个Java 进程, 这个进程非常重要,因为他们有很多的系统线程,
提供所有核心的系统服务
看到大名鼎鼎的WindowManager, ActivityManager了吗?对了,它们都是运行在system_server的进程
里。还有很多“Binder-x”的线程,它们是各个Service为了响应应用程序远程调用请求而创建的。除此之
外,还有很多内部的线程,比如 ”UI thread”, “InputReader”, “InputDispatch” 等等,我,现在我们只关
心System Server是如何创建起来的。
SystemServer的main() 函数。

public static void main(String[] args) {
  new SystemServer().run();
}

记下来我分成4部分详细分析SystemServer run方法的初始化流程:
初始化必要的SystemServer环境参数,比如系统时间、默认时区、语言、load一些Library等等,
初始化Looper,我们在主线程中使用到的looper就是在SystemServer中进行初始化的
初始化Context,只有初始化一个Context才能进行启动Service等操作,这里看一下源码:

private void createSystemContext() {
  ActivityThread activityThread = ActivityThread.systemMain();
  mSystemContext = activityThread.getSystemContext();
  mSystemContext.setTheme(DEFAULT_SYSTEM_THEME);
  final Context systemUiContext = activityThread.getSystemUiContext();
  systemUiContext.setTheme(DEFAULT_SYSTEM_THEME);
}

看到没有ActivityThread就是这个时候生成的
继续看ActivityThread中如何生成Context:

public ContextImpl getSystemContext() {
  synchronized (this) {
   if (mSystemContext == null) {
     mSystemContext = ContextImpl.createSystemContext(this);
   }
   return mSystemContext;
  }
}

ContextImpl是Context类的具体实现,里面封装完成了生成几种常用的createContext的方法:

static ContextImpl createSystemContext(ActivityThread mainThread) {
   LoadedApk packageInfo = new LoadedApk(mainThread);
   //省略代码
   return context;
}
static ContextImpl createSystemUiContext(ContextImpl systemContext) {
  final LoadedApk packageInfo = systemContext.mPackageInfo;
  //省略代码
  return context;
}
static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk
packageInfo) {
  if (packageInfo == null) throw new
IllegalArgumentException("packageInfo");
  //省略代码
  return context;
}
static ContextImpl createActivityContext(ActivityThread mainThread,
  LoadedApk packageInfo, ActivityInfo activityInfo, IBinder
activityToken, int displayId,
    Configuration overrideConfiguration) {
    //省略代码
    return context;
}

初始化SystemServiceManager,用来管理启动service,SystemServiceManager中封装了启动Service的
startService方法启动系统必要的Service,启动service的流程又分成三步走:

// Start services.
try {
  traceBeginAndSlog("StartServices");
  startBootstrapServices();
  startCoreServices();
  startOtherServices();
  SystemServerInitThreadPool.shutdown();
} catch (Throwable ex) {
   //
} finally {
  traceEnd();
}

启动BootstrapServices,就是系统必须需要的服务,这些服务直接耦合性很高,所以干脆就放在一个方
法里面一起启动,比如PowerManagerService、RecoverySystemService、DisplayManagerService、
ActivityManagerService等等启动以基本的核心Service,很简单,只有三个BatteryService、
UsageStatsService、WebViewUpdateService启动其它需要用到的Service,比如
NetworkScoreService、AlarmManagerService
5. 善后工作是不是到此之后,Zygote的工作变得很轻松了,可以宜养天年了?可惜现代社会,哪个父
母把孩子养大就可以撒手不管了?尤其是像Sytem Server 这样肩负社会重任的大儿子,出问题了
父母还是要帮一把的。这里,Zygote会默默的在后台凝视这自己的大儿子,一旦发现System
Server 挂掉了,将其回收,然后将自己杀掉,重新开始新的一生, 可怜天下父母心啊。这段实现
在代码 :dalvik/vm/native/dalvik_system_zygote.cpp 中,

static void Dalvik_dalvik_system_Zygote_forkSystemServer(
      const u4* args, JValue* pResult){
   ...
    pid_t pid;
    pid = forkAndSpecializeCommon(args, true);
   ...
    if (pid > 0) {
      int status;
      gDvm.systemServerPid = pid;
      /* WNOHANG 会让waitpid 立即返回,这里只是为了预防上面的赋值语句没有完成之
前SystemServer就crash 了*/
      if (waitpid(pid, &status, WNOHANG) == pid) {
        ALOGE("System server process %d has died. Restarting
Zygote!", pid);
        kill(getpid(), SIGKILL);
     }
   }
    RETURN_INT(pid);
}
/* 真正的处理在这里 */
static void sigchldHandler(int s){
   ...
    pid_t pid;
    int status;
   ...
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
     ...
      if (pid == gDvm.systemServerPid) {
       ...
        kill(getpid(), SIGKILL);
     }
   }
   ...
}
static void Dalvik_dalvik_system_Zygote_fork(const u4* args, JValue*
pResult){
    pid_t pid;
   ...
    setSignalHandler(); //signalHandler 在这里注册
   ...
    pid = fork();
   ...
    RETURN_INT(pid);
}

在Unix-like系统,父进程必须用 waitpid 等待子进程的退出,否则子进程将变成”Zombie” (僵尸)进
程,不仅系统资源泄漏,而且系统将崩溃(没有system server,所有Android应用程序都无法运行)。
但是waitpid() 是一个阻塞函数(WNOHANG参数除外),所以通常做法是在signal 处理函数里进行无阻
塞的处理,因为每个子进程退出的时候,系统会发出 SIGCHID 信号。Zygote会把自己杀掉, 那父亲死
了,所有的应用程序不就成为孤儿了? 不会,因为父进程被杀掉后系统会自动给所有的子进程发生
SIGHUP信号,该信号的默认处理就是将杀掉自己退出当前进程。但是一些后台进程(Daemon)可以通
过设置SIG_IGN参数来忽略这个信号,从而得以在后台继续运行。
总结
1. init 根据init.rc 运行 app_process, 并携带‘–zygote’ 和 ’–startSystemServer’ 参数。
2. AndroidRuntime.cpp::start() 里将启动JavaVM,并且注册所有framework相关的系统JNI接口。
3. 第一次进入Java世界,运行ZygoteInit.java::main() 函数初始化Zygote. Zygote 并创建Socket的
server 端。
4. 然后fork一个新的进程并在新进程里初始化SystemServer. Fork之前,Zygote是preload常用的
Java类库,以及系统的resources,同时GC()清理内存空间,为子进程省去重复的工作。
5. SystemServer 里将所有的系统Service初始化,包括ActivityManager 和 WindowManager, 他们
是应用程序运行起来的前提。
6. 依次同时,Zygote监听服务端Socket,等待新的应用启动请求。
7. ActivityManager ready 之后寻找系统的“Startup” Application, 将请求发给Zygote。
8. Zygote收到请求后,fork出一个新的进程。
9. Zygote监听并处理SystemServer 的 SIGCHID 信号,一旦System Server崩溃,立即将自己杀死。
init会重启Zygote.

什么情况下Zygote进程会重启呢?
servicemanager进程被杀;
(onresart)surfaceflinger进程被杀;
(onresart)Zygote进程自己被杀;
(oneshot=false)system_server进程被杀; (waitpid)

fork函数

pid_t fork(void) 

1. 参数:不需要参数
2. 需要的头文件 <sys/types.h> 和  <unistd.h>
3. 返回值分两种情况:
返回0表示成功创建子进程,并且接下来进入子进程执行流程
返回PID(>0),成功创建子进程,并且继续执行父进程流程代码
返回非正数(<0),创建子进程失败,失败原因主要有:
进程数超过系统所能创建的上限,errno会被设置为EAGAIN系统内存不足,errno会被设置为
ENOMEM

使用  fork() 函数得到的子进程是父进程的一个复制品,它从父进程处继承了整个进程的地址空
间:包括进程上下文(进程执行活动全过程的静态描述)、进程堆栈、打开的文件描述符、信号控
制设定、进程优先级、进程组号等。子进程所独有的只有它的进程号,计时器等(只有小量信
息)。因此,使用  fork() 函数的代价是很大的

子进程与父进程的区别
1. 除了文件锁以外,其他的锁都会被继承
2. 各自的进程ID和父进程ID不同
3. 子进程的未决告警被清除;
4. 子进程的未决信号集设置为空集。

写时拷贝 (copy- on-write)
Linux 的  fork() 使用是通过写时拷贝 (copy- on-write) 实现。写时拷贝是一种可以推迟甚至避免拷贝
数据的技术。内核此时并不复制整个进程的地址空间,而是让父子进程共享同一个地址空间。只用在需
要写入的时候才会复制地址空间,从而使各个进行拥有各自的地址空间。也就是说,资源的复制是在需
要写入的时候才会进行,在此之前,只有以只读方式共享

孤儿进程、僵尸进程
fork系统调用之后,父子进程将交替执行,执行顺序不定。如果父进程先退出,子进程还没退出那么子
进程的父进程将变为init进程(托孤给了init进程)。(注:任何一个进程都必须有父进程)如果子进程
先退出,父进程还没退出,那么子进程必须等到父进程捕获到了子进程的退出状态才真正结束,否则这
个时候子进程就成为僵进程(僵尸进程:只保留一些退出信息供父进程查询)
多线程进程的Fork调用
在 POSIX 标准中,fork 的行为是这样的:复制整个用户空间的数据(通常使用 copy-on-write 的策略,
所以可以实现的速度很快)以及所有系统对象,然后仅复制当前线程到子进程。这里:所有父进程中别
的线程,到了子进程中都是突然蒸发掉的
假设这么一个环境,在 fork 之前,有一个子线程 lock 了某个锁,获得了对锁的所有权。fork 以
后,在子进程中,所有的额外线程都人间蒸发了。而锁却被正常复制了,在子进程看来,这个锁没
有主人,所以没有任何人可以对它解锁。当子进程想 lock 这个锁时,不再有任何手段可以解开
了。程序发生死锁

面试题
面试官:你了解 Android 系统启动流程吗?
A:当按电源键触发开机,首先会从 ROM 中预定义的地方加载引导程序 BootLoader 到 RAM 中,并执
行 BootLoader 程序启动 Linux Kernel, 然后启动用户级别的第一个进程: init 进程。init 进程会解析
init.rc 脚本做一些初始化工作,包括挂载文件系统、创建工作目录以及启动系统服务进程等,其中系统
服务进程包括 Zygote、service manager、media 等。在 Zygote 中会进一步去启动 system_server 进
程,然后在 system_server 进程中会启动 AMS、WMS、PMS 等服务,等这些服务启动之后,AMS 中就
会打开 Launcher 应用的 home Activity,最终就看到了手机的 "桌面"。
面试官:system_server 为什么要在 Zygote 中启动,而不是由 init 直接启动呢?
A:Zygote 作为一个孵化器,可以提前加载一些资源,这样 fork() 时基于 Copy-On-Write 机制创建的其
他进程就能直接使用这些资源,而不用重新加载。比如 system_server 就可以直接使用 Zygote 中的 JNI
函数、共享库、常用的类、以及主题资源。
面试官:为什么要专门使用 Zygote 进程去孵化应用进程,而不是让 system_server 去孵化呢?
A:首先 system_server 相比 Zygote 多运行了 AMS、WMS 等服务,这些对一个应用程序来说是不需要
的。另外进程的 fork() 对多线程不友好,仅会将发起调用的线程拷贝到子进程,这可能会导致死锁,而
system_server 中肯定是有很多线程的。
面试官:能说说具体是怎么导致死锁的吗?
在 POSIX 标准中,fork 的行为是这样的:复制整个用户空间的数据(通常使用 copy-on-write 的策略,
所以可以实现的速度很快)以及所有系统对象,然后仅复制当前线程到子进程。这里:所有父进程中别
的线程,到了子进程中都是突然蒸发掉的
对于锁来说,从 OS 看,每个锁有一个所有者,即最后一次 lock 它的线程。假设这么一个环境,在 fork
之前,有一个子线程 lock 了某个锁,获得了对锁的所有权。fork 以后,在子进程中,所有的额外线程都
人间蒸发了。而锁却被正常复制了,在子进程看来,这个锁没有主人,所以没有任何人可以对它解锁。
当子进程想 lock 这个锁时,不再有任何手段可以解开了。程序发生死锁
面试官:Zygote 为什么不采用 Binder 机制进行 IPC 通信?
A:Binder 机制中存在 Binder 线程池,是多线程的,如果 Zygote 采用 Binder 的话就存在上面说的
fork() 与 多线程的问题了。其实严格来说,Binder 机制不一定要多线程,所谓的 Binder 线程只不过是
在循环读取 Binder 驱动的消息而已,只注册一个 Binder 线程也是可以工作的,比如 service manager
就是这样的。实际上 Zygote 尽管没有采取 Binder 机制,它也不是单线程的,但它在 fork() 前主动停止
了其他线程,fork() 后重新启动了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值