目录
前言
虚拟机创建完成后,接下去就可以用JNI反射调用Java了,其实接下来的语法用过JNI的都应该比较熟悉了,直接是CallStaticVoidMethod反射调用ZygoteInit的main函数,进入Java世界;
相关源码文件
platform/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
platform/frameworks/base/core/java/com/android/internal/logging/MetricsLogger.java
platform/frameworks/base/core/java/com/android/internal/logging/EventLogTags.logtags
platform/system/core/logcat/event.logtags
platform/build/tools/java-event-log-tags.py
platform/frameworks/base/core/jni/android_util_EventLog.cpp
platform/frameworks/base/core/java/android/os/Trace.java
platform/frameworks/base/core/jni/android_os_Trace.cpp
platform/system/core/libcutils/trace-dev.c
一、Art虚拟机启动
main(){
...
//这里的runtime.start的实现是在 frameworks/base/core/jni/AndroidRuntime.cpp 中的AndroidRuntime对象
if (zygote) {
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
} else if (className) {
runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
} else {
fprintf(stderr, "Error: no class name or --zygote supplied.\n");
app_usage();
LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
}
}
//frameworks/base/core/jni/AndroidRuntime.cpp 中的AndroidRuntime对象
// 参数 className 等于 "com.android.internal.os.ZygoteInit"
// 参数 options 就是虚拟机的各种args
void start(const char* className, const char* options){
// start the virtual machine Java在虚拟机中运行的
JNIEnv* env;
if (startVm(&mJavaVM, &env) != 0) {
return;
}
//向刚刚新建的虚拟机注册JNI本地接口
if (startReg(env) < 0) {
return;
}
// jni 调用 java 方法,获取对应类的静态main方法
jmethodID startMeth = env->GetStaticMethodID(startClass,
"main","([Ljava/lang/String;)V");
// jni调用 java方法,调用到ZygoteInit类的main函数
char* slashClassName = toSlashClassName(className);//将字符中的.转换为/
jclass startClass = env->FindClass(className);
//终于进入Java世界
env->CallStaticVoidMethod(startClass, startMeth, strArray);
//正常情况,如果zygoteInit.main 函数并不会退出,内部是实现死循环,后面的代码并不会执行,一旦main函数退出,那么就需要及时释放虚拟机占有的相关的内存资源
free(slashClassName);
ALOGD("Shutting down VM\n");
if (mJavaVM->DetachCurrentThread() != JNI_OK)//退出当前线程
ALOGW("Warning: unable to detach main thread\n");
if (mJavaVM->DestroyJavaVM() != 0) //创建一个DestroyJavaVM线程,该线程会等待所有子线程结束后关闭虚拟机
ALOGW("Warning: VM did not shut down cleanly\n");
}
二、首次进入Java世界
- 保证在Zygote主进程init过程中无法通过Java中的Thread类创建子线程
- 创建zygote socket并监听
- preload Android资源
- GC初始化并启动
- 移除Zygote进程中创建线程限制
- 启动System server进程
- 运行zygote进程的select loop
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) {
ZygoteServer zygoteServer = new ZygoteServer();
//当前是zygote 主线程, GC相关的子线程其实已经是创建ok了;
// Mark zygote start. This ensures that thread creation will throw an error.
// 后续的代码逻辑中试图通过new Thread() 会抛出异常;除非接触这个限制
// Zygote Init处理的时候无法java类Thread类来创建子线程;
ZygoteHooks.startZygoteNoThreadCreation();
// Zygote goes into its own process group.
// 设置zygote进程组id为zygote的pid
try {
Os.setpgid(0, 0);
} catch (ErrnoException ex) {
throw new RuntimeException("Failed to setpgid(0,0)", ex);
}
try {
......
boolean startSystemServer = false;
String socketName = "zygote";
String abiList = null;
......
zygoteServer.registerServerSocket(socketName);
// In some configurations, we avoid preloading resources and classes eagerly.
// In such cases, we will preload things prior to our first fork.
if (!enableLazyPreload) { //走这个分支
preload(bootTimingsTraceLog); //加载各种系统资源
} else {
Zygote.resetNicePriority();
}
gcAndFinalize();
......
//解除创建子线程限制
ZygoteHooks.stopZygoteNoThreadCreation();
if (startSystemServer) { //创建system_server进程
startSystemServer(abiList, socketName, zygoteServer);
}
//zygote进程等待AMS的socket请求,内部处理完之后,抛出异常Zygote.MethodAndArgsCaller,被catch后执行;
zygoteServer.runSelectLoop(abiList);
//下面的逻辑代码不会执行,zygote进程
zygoteServer.closeServerSocket();
} catch (Zygote.MethodAndArgsCaller caller) {
caller.run();
} catch (Throwable ex) {
Log.e(TAG, "System zygote died with exception", ex);
zygoteServer.closeServerSocket();
throw ex;
}
}
2.1 禁用子线程创建
ZygoteHooks.startZygoteNoThreadCreation();
严禁在zygote中创建多线程,除非后续放开
//Java中的通过Thread类的创建线程
static void Thread_nativeCreate(JNIEnv* env, jclass, jobject java_thread, jlong stack_size,jboolean daemon) {
// There are sections in the zygote that forbid thread creation.
Runtime* runtime = Runtime::Current();
//上面的ZygoteHooks_startZygoteNoThreadCreation作用就是下面的判断条件第二个,设置为ture
if (runtime->IsZygote() && runtime->IsZygoteNoThreadSection()) {
jclass internal_error = env->FindClass("java/lang/InternalError");
CHECK(internal_error != nullptr);
env->ThrowNew(internal_error, "Cannot create threads in zygote");
return;
}
Thread::CreateNativeThread(env, java_thread, stack_size, daemon == JNI_TRUE);
}
2.2 创建zygote socket并监听
void registerServerSocket(String socketName) {
if (mServerSocket == null) {
int fileDesc;
final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
try {
String env = System.getenv(fullSocketName);
fileDesc = Integer.parseInt(env);
} catch (RuntimeException ex) {
throw new RuntimeException(fullSocketName + " unset or invalid", ex);
}
try {
FileDescriptor fd = new FileDescriptor();
fd.setInt$(fileDesc);
//将对应的socket转换为fd, 作为server端,等待client 发送数据
mServerSocket = new LocalServerSocket(fd);
} catch (IOException ex) {
throw new RuntimeException("Error binding to local socket '" + fileDesc + "'", ex);
}
}
}
2.3 加载系统资源
在zygote init中,Android的相关资源被预加载到Zygote进程空间中。这些资源在后续所有的应用程序进程中都是共享的,因为Android Java层进程都是Zygote的子进程。
这里有个疑问, 为什么这些资源不放到init 进程,又或者说为什么不放到system_server进程呢?
可以思考下,欢迎大家追在评论中留言;
static void preload() {
...
preloadClasses();
preloadResources();
preloadOpenGL();
preloadSharedLibraries();
preloadTextResources();
WebViewFactory.prepareWebViewInZygote();
}
- preloadClasses:加载class类到虚拟机中,需要加载的类是由/system/etc/preloaded-classes文件指定。它是由相关preloaded-classes文件生成,如:
- \frameworks\base\preloaded-classes
- \frameworks\base\compiled-classes-phone
虚拟机会通过classloader把preloaded-classes文件中指定的类都加载到虚拟机中,方便应用程序的调用处理。此处会涉及到手机内存空间和手机开机性能问题,手机性能优化方面可以进一步深入研究。
- preloadResources:加载系统资源,比如 drawables colors
- preloadOpenGL: 加载显示资源
- preloadSharedLibraries: 加载共享库,包含android.so、compiler_rt.so和jnigraphics.so
- preloadTextResources:加载语言库
2.4 GC初始化并启动
/*package*/ static void gcAndFinalize() {
final VMRuntime runtime = VMRuntime.getRuntime();
/* runFinalizationSync() lets finalizers be called in Zygote,
* which doesn't have a HeapWorker thread.
*/
System.gc(); //先看GC部分
runtime.runFinalizationSync(); //再分析VmRuntime.runFinalizationSync
System.gc();
}
public static void gc() {
boolean shouldRunGC;
synchronized (LOCK) {
shouldRunGC = justRanFinalization;
if (shouldRunGC) {
justRanFinalization = false;
} else {
runGC = true;
}
}
if (shouldRunGC) {
Runtime.getRuntime().gc(); //
}
}
System.runFinalization();
///libcore/ojluni/src/main/java/java/lang/System.java
public static void runFinalization() {
boolean shouldRunGC;
synchronized (LOCK) {
shouldRunGC = runGC;
runGC = false;
}
if (shouldRunGC) {
Runtime.getRuntime().gc();
}
Runtime.getRuntime().runFinalization();
synchronized (LOCK) {
justRanFinalization = true;
}
}
/libcore/ojluni/src/main/java/java/lang/Runtime.java
private static native void runFinalization0();
2. 5启动System server进程
在startSystemServer()方法里,通过Zygote.forkSystemServer() native函数调用来创建system server 进程。从创建中可以看到,system server进程是zygote进程的子进程。内部调用fork函数
/* Hardcoded command line to start the system server */
String args[] = {
"--setuid=1000",
"--setgid=1000",
"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1032,3001,3002,3003,3006,3007,3009,3010",
"--capabilities=" + capabilities + "," + capabilities,
"--nice-name=system_server",
"--runtime-args",
"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 */
// 内部执行fork 函数,返回两次,其中pid = 0 表示子进程返回;
pid = Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids,
parsedArgs.debugFlags,
null,
parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities);
} catch (IllegalArgumentException ex) {
throw new RuntimeException(ex);
}
.....
//后续执行com.android.server.SystemServer的main函数;
后续重点介绍下System_server 进程的启动流程;
2.6 Zygote进入Looper处理socket消息
在runSelectLoop()方法中
监听socket,通过Os.poll函数来等待POLLIN事件的到来。
通过ZygoteConnection来读取socket传过来的command并创建进程。
zygote进程在运行select loop后,zygote进程就进入无限循环,一直等待socket的command,并做处理。
//zygote进程在此进入无限循环
while (true) {
StructPollfd[] pollFds = new StructPollfd[fds.size()];
for (int i = 0; i < pollFds.length; ++i) {
pollFds[i] = new StructPollfd();
pollFds[i].fd = fds.get(i);
pollFds[i].events = (short) POLLIN;
}
try {
//zygote进程被阻塞,直至以下条件达到时退出:
//a file descriptor becomes ready;
//the call is interrupted by a signal handler; or
//the timeout expires.
Os.poll(pollFds, -1);
} catch (ErrnoException ex) {
throw new RuntimeException("poll failed", ex);
}
for (int i = pollFds.length - 1; i >= 0; --i) {
if ((pollFds[i].revents & POLLIN) == 0) {
continue;
}
if (i == 0) {
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else {
//调用ZygoteConnection的runOnce()方法来fork进程。
boolean done = peers.get(i).runOnce();
if (done) {
peers.remove(i);
fds.remove(i);
}
}
}
}
至此,zygote进程启动处理完成,最后一直停留在select loop中运行。
三 关于Zygote的一些疑问
3.1 孵化应用进程这种事为什么不交给SystemServer来做,而专门设计一个Zygote?
我们知道,应用在启动的时候需要做很多准备工作,包括启动虚拟机,加载各类系统资源等等,这些都是非常耗时的,如果能在zygote里就给这些必要的初始化工作做好,子进程在fork的时候就能直接共享,那么这样的话效率就会非常高。这个就是zygote存在的价值,这一点呢SystemServer是替代不了的,主要是因为SystemServer里跑了一堆系统服务,这些是不能继承到应用进程的。而且我们应用进程在启动的时候,内存空间除了必要的资源外,最好是干干净净的,不要继承一堆乱七八糟的东西。所以呢,不如给SystemServer和应用进程里都要用到的资源抽出来单独放在一个进程里,也就是这的zygote进程,然后zygote进程再分别孵化出SystemServer进程和应用进程。孵化出来之后,SystemServer进程和应用进程就可以各干各的事了。
3.2 Zygote的IPC通信机制为什么不采用binder?如果采用binder的话会有什么问题么?
网上大部分答案都是采用binder,引入线程池,但fork在多线程的情况下,可能会产生死锁问题,这部分解析目前还不是很理解,后续完善;
3.3 Zygote进程是多线程还是单线程呢?
是多线程,除了zygote主线程之外,还有和GC 相关的其他几个线程;
在主线程中调用fork之后,子进程只会保留一个线程,其他几个GC 线程没有克隆过来,是后续创建的;
3.4 对3.3 的追加问题: GC 几个线程是什么时候创建出来的呢?
/art/runtime/runtime.cc
在虚拟机的启动过程中, 创建GC相关的线程;
bool Runtime::Start() {
...
StartDaemonThreads(); //启动GC 相关的几个线程;
....
return true;
}void Runtime::StartDaemonThreads() {
Thread* self = Thread::Current();
//进入Java 世界, Daemons.java 似乎比ZygoteInit.java
env->CallStaticVoidMethod(WellKnownClasses::java_lang_Daemons,WellKnownClasses::java_lang_Daemons_start);
}/libcore/libart/src/main/java/java/lang/Daemons.java
//启动4个GC 相关的线程
public static void start() {
ReferenceQueueDaemon.INSTANCE.start();
FinalizerDaemon.INSTANCE.start();
FinalizerWatchdogDaemon.INSTANCE.start();
HeapTaskDaemon.INSTANCE.start();
}
3.5 Zygote 进程启动的出现了GC,请问下System.gc() 和 Runtime. getRuntime(). gc()会做什么事情?
System.gc() 在内部调用 Runtime.gc()。
硬要说区别的话 Runtime.gc() 是 native method。存在于 /libcore/ojluni/src/main/native/Runtime.c
而 System.gc() 是非 native method,它依次调用 Runtime.gc();
System.gc 调用附带一个免责声明,无法保证垃圾收集器的调用。即gc()函数的作用只是提醒虚拟机,程序员希望进行一次垃圾回收。但是这次回收不能保证一定进行,具体什么时候回收取决于jvm。如果每次调用gc方法后想让gc必须执行,可以追加调用system. runFinalization方法。调用gc方法在默认情况下,会显示触发full gc,同时对老年代和新生代进行回收,尝试释放被丢弃对象占用的内存。