什么是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 L1015if (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 startedreturn 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 ourselfmHoldSelf = 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 freeint 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 freeresult = 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 storagefree(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 startupbootTimingsTraceLog.traceBegin("PostZygoteInitGC");//主动进行一次资源GCgcAndFinalize();bootTimingsTraceLog.traceEnd(); // PostZygoteInitGCbootTimingsTraceLog.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(); // BeginIcuCachePinningbootTimingsTraceLog.traceBegin("PreloadClasses");//加载指定的类到内存并且初始化,使用的Class.forName(class, true, null);方式preloadClasses();bootTimingsTraceLog.traceEnd(); // PreloadClassesbootTimingsTraceLog.traceBegin("PreloadResources");//加载Android通用的资源,比如drawable、color...preloadResources();bootTimingsTraceLog.traceEnd(); // PreloadResourcesTrace.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);//加载共用的LibrarypreloadSharedLibraries();//加载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==0if (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.execApplicationWrapperInit.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.*///调用zygoteInitreturn ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion,
parsedArgs.remainingArgs, cl);}/* should never reach here */}
// \frameworks\base\core\java\com\android\internal\os\RuntimeInit.java
applicationInit() L345protected 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() 后重新启动了。

系统进程启动流程分析(二)相关推荐

  1. 系统进程启动流程分析(一)

    Android启动概览 众所周知,Android是谷歌开发的一款基于Linux的开源操作系统,下图所示为 Android 平台的主要组件 1. Linux 内核 Android 平台的基础是 Linu ...

  2. 内核启动流程分析(二)配置详解

    总体概述 配置详解 配置的最终目的,是生成了.config文件,查看下这个文件, # # Automatically generated make config: don't edit # Linux ...

  3. Exynos4412 Uboot 移植(二)—— Uboot 启动流程分析

    uboot启动流程分析如下: 第一阶段: a -- 设置cpu工作模式为SVC模式 b -- 关闭中断,mmu,cache v -- 关看门狗 d -- 初始化内存,串口 e -- 设置栈 f -- ...

  4. SpringBoot(十二)启动流程分析之创建应用上下文AnnotationConfigServletWebServerApplicationContext

    SpringBoot版本:2.1.1      ==>启动流程分析汇总 接上篇博客Spring Boot 2.1.1(十一)启动流程分析之设置系统属性spring.beaninfo.ignore ...

  5. 解析并符号 读取dll_Spring IOC容器之XmlBeanFactory启动流程分析和源码解析

    一. 前言 Spring容器主要分为两类BeanFactory和ApplicationContext,后者是基于前者的功能扩展,也就是一个基础容器和一个高级容器的区别.本篇就以BeanFactory基 ...

  6. c++builder启动了怎么停止_App 竟然是这样跑起来的 —— Android App/Activity 启动流程分析...

    在我的上一篇文章: AJie:按下电源键后竟然发生了这一幕 -- Android 系统启动流程分析​zhuanlan.zhihu.com 我们分析了系统在开机以后的一系列行为,其中最后一阶段 AMS( ...

  7. SpringBoot启动流程分析(四):IoC容器的初始化过程

    SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...

  8. GEF入门实例_总结_04_Eclipse插件启动流程分析

    一.前言 本文承接上一节:GEF入门实例_总结_03_显示菜单和工具栏 注意到app目录下的6个类文件. 这6个文件对RCP应用程序而言非常重要,可能我们现在对这几个文件的理解还是云里雾里,这一节我们 ...

  9. Android系统开机到Launcher启动流程分析

    本文基于Android10.0的源码. 由于google团队在对framework层代码进行大量重构,所以代码变动还是挺大的. 常见基础问题: SystemServer系统服务进程是如何创建的?Lau ...

最新文章

  1. 数据分析师的职业规划之路
  2. 虚数有物理意义:中科大潘建伟、南科大范靖云团队首次实验排除实数形式的标准量子力学...
  3. matlab整定串级pid,PID算法在Matlab串级控制中的应用
  4. 在MATLAB中,用Simulink搭建一个二阶传递函数模型
  5. 后端时间转js时间,主要用于取倒计时
  6. c语言malloc引用类型作参数,C语言动态内存函数的理解和总结
  7. POJ 2353 DP
  8. 利用python实现批量查询ip地址归属地址
  9. AD:使用C#批量创建帐号
  10. ggThemeAssist|鼠标调整主题,并返回代码
  11. java applet 换行_如何用java applet 画字符串,宽度大于设定值,自动换行
  12. SQL中JOIN操作后接ON和WHERE关键字的区别
  13. JavaWeb开发Filter学习
  14. 2018年5月26日笔记
  15. 微信小程序API-定位(位置)
  16. ftp服务器扫描不了文件内容,ftp服务器扫描不了文件
  17. Spring关于@required注解
  18. DeFi守护神是谁?
  19. shopnc linux im安装教程,shopnc编译安装IM服务器node.js
  20. AppStore发布流程(从证书创建到app发布一站式)

热门文章

  1. 降雨量(附我的SB调题过程)
  2. 8家最大的WooCommerce在线商店
  3. MSI(微星) GP62mvr Ubuntu16.04 + Opencv3.4.1配置教程
  4. 教你如何在wordpress中在你的网站页脚添加管局备案号
  5. 好心替同事接电话?小心接出事情来!
  6. (1)-Halcon入门学习路线
  7. java读取配置文件信息生成Map对象
  8. 韩顺平 2021零基础学Java 学习笔记
  9. 美女MVP教你轻松学习Excel VBA-方洁影-专题视频课程
  10. Allwinner T3 汽车级处理器为工业级 SoM 提供动力