Framework原理分析之——Zygote进程流程分析_android zygote fork进程流程

            //调用main方法,开启愉快的Java之旅

1122 env->CallStaticVoidMethod(startClass, startMeth, strArray);
1123
1124#if 0
1125 if (env->ExceptionCheck())
1126 threadExitUncaughtException(env);
1127#endif
1128 }
1129 }
1130 free(slashClassName);
1137}


这个类就是我们之前在说架构时的AndroidRuntime部分代码,它其实是C++代码,在文中都注释了非常明白了,主要做了如下事:


1. **启动Java虚拟机**,想运行Java代码,必须要创建Java虚拟机程序,在这里会创建和启动java虚拟机。关于虚拟机的知识,后面文章会单独分析。
2. **注册JNI方法**,关于JNI的原理后面会细说,说白了就是Java可以调用C/C++程序,而C/C++程序可以调用Java代码,也就是通过JNI打通了Java世界和Native世界的屏障。这里注册JNI方法,其实就是为了后面使用JNI而做准备。  
 3.根据传入的Java类名,通过JNI找到Java类,然后把".“换成”/“,这是因为在JNI中是不允许以”."作为变量名的,后面细说;然后再通过JNI方法,调用该类的main函数。


由于ZygoteInit的main方法由Java编写,这样Zygote就从Native层进入了Java框架层。


### Java层流程分析


还是先来看一下大致调用流程图:


![](https://img-blog.csdnimg.cn/img_convert/2ecdf3a4a1e8650cf713c5fd3749dabe.png)


`话不多说,我们来看看Java世界的该方法:



/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) {
//新建ZygoteServer实例
699 ZygoteServer zygoteServer = new ZygoteServer();
700
701 …
747 //创建一个Server端的Socket,socketName就是"zygote"
748 zygoteServer.registerServerSocket(socketName);
749
751 if (!enableLazyPreload) {
752 bootTimingsTraceLog.traceBegin(“ZygotePreload”);
753 EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
754 SystemClock.uptimeMillis());
//预加载资源
755 preload(bootTimingsTraceLog);
756 EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
757 SystemClock.uptimeMillis());
758 bootTimingsTraceLog.traceEnd(); // ZygotePreload
759 } else {
760 Zygote.resetNicePriority();
761 }
762
763 …
780
781 if (startSystemServer) {
//创建和启动SystemServer进程
782 Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
786 if (r != null) {
787 r.run();
788 return;
789 }
790 }
791
792 //等待AMS请求
796 caller = zygoteServer.runSelectLoop(abiList);
797 } catch (Throwable ex) {
798 Log.e(TAG, “System zygote died with exception”, ex);
799 throw ex;
800 } finally {
//一直循环,这个只有Zygote进程死了才会执行
801 zygoteServer.closeServerSocket();
802 }
806 if (caller != null) {
807 caller.run();
808 }
809 }


这里简化了很多逻辑,我们只分析一些主要的流程,从上面注释我们可以知道,ZygoteInit的main函数主要做了如下几件事:


1.**创建了一个Server端的Socket**,该Socket的主要作用就一个,就是等待ActivityManagerService(AMS)的请求,**来创建新的进程**。关于AMS我们肯定听过,它负责Android四大组件的运行,而其中就有一个场景就是启动新的APP进程,这时就需要创建新进程,而创建新进程的工作就是这里。  
 2.**加载类和资源。**  
 3.**孵化和启动SystemServer进程**,该进程比较重要,我们熟悉的AMS、WMS等系统服务都是运行在该进程中,后面分析SystemServer进程时,我们再仔细分析。


上面就是Zygote进程在Java层所做的主要工作,我们来简单梳理一下。


#### 创建本地Server Socket


主要是通过调用ZygoteServer中的registerServerSocket方法:



/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) {
//新建ZygoteServer实例
699 ZygoteServer zygoteServer = new ZygoteServer();
700
701 …
747 //创建一个Server端的Socket,socketName就是"zygote"
748 zygoteServer.registerServerSocket(socketName);
749
751 if (!enableLazyPreload) {
752 bootTimingsTraceLog.traceBegin(“ZygotePreload”);
753 EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
754 SystemClock.uptimeMillis());
//预加载资源
755 preload(bootTimingsTraceLog);
756 EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
757 SystemClock.uptimeMillis());
758 bootTimingsTraceLog.traceEnd(); // ZygotePreload
759 } else {
760 Zygote.resetNicePriority();
761 }
762
763 …
780
781 if (startSystemServer) {
//创建和启动SystemServer进程
782 Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
786 if (r != null) {
787 r.run();
788 return;
789 }
790 }
791
792 //等待AMS请求
796 caller = zygoteServer.runSelectLoop(abiList);
797 } catch (Throwable ex) {
798 Log.e(TAG, “System zygote died with exception”, ex);
799 throw ex;
800 } finally {
//一直循环,这个只有Zygote进程死了才会执行
801 zygoteServer.closeServerSocket();
802 }
806 if (caller != null) {
807 caller.run();
808 }
809 }


这里注意创建本地Socket的代码是在ZygoteServer.java中,这个mServerSocket在后面会被使用,等会再说。


### 预加载资源


在Zygote进程的初始化过程中,会预加载一些必要的资源,方法如下:



/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
static void preload(TimingsTraceLog bootTimingsTraceLog) {
123 //预加载类,这里使用类加载器加载/system/ect/preload-class下定义的类
//该文件是一个文本文件,以全包名的方式写了几百个类
128 preloadClasses();
129 //预加载资源,主要是加载一些图片、颜色等资源到内存中
131 preloadResources();
132 //预加载OpenGL
137 preloadOpenGL();
138 //通过System.loadLibrary方式加载3个共享库
//分别是android、compiler_rt、jnigraphics
139 preloadSharedLibraries();
//加载文本等资源
140 preloadTextResources();
141 …
149 }


这里加载资源非常关键,由前面我们知道到目前**Zygote进程已经有虚拟机实例、预加载了部分资源和Java类,以及预加载了共享库**,这时创建子进程时,是通过fork形式的,即**复制自己,新的进程也会有这些内容**。


关于这部分加载类的细节,涉及类加载器、Class类等知识,后面文章会详细分析。


#### 启动SystemServer进程


Zygote进程的另一个重要工作就是启动SystemServer进程,我们来看看Java世界中是如何启动进程的:



/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
private static Runnable forkSystemServer(String abiList, String socketName,
621 ZygoteServer zygoteServer) {
622 long capabilities = posixCapabilitiesAsBits(
623 OsConstants.CAP_IPC_LOCK,
624 OsConstants.CAP_KILL,
625 OsConstants.CAP_NET_ADMIN,
626 OsConstants.CAP_NET_BIND_SERVICE,
627 OsConstants.CAP_NET_BROADCAST,
628 OsConstants.CAP_NET_RAW,
629 OsConstants.CAP_SYS_MODULE,
630 OsConstants.CAP_SYS_NICE,
631 OsConstants.CAP_SYS_PTRACE,
632 OsConstants.CAP_SYS_TIME,
633 OsConstants.CAP_SYS_TTY_CONFIG,
634 OsConstants.CAP_WAKE_ALARM
635 );

637 if (!SystemProperties.getBoolean(PROPERTY_RUNNING_IN_CONTAINER, false)) {
638 capabilities |= posixCapabilitiesAsBits(OsConstants.CAP_BLOCK_SUSPEND);
639 }
640 //设置参数
641 String args[] = {
642 “–setuid=1000”,
643 “–setgid=1000”,
644 “–setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,1032,3001,3002,3003,3006,3007,3009,3010”,
645 “–capabilities=” + capabilities + “,” + capabilities,
646 “–nice-name=system_server”,
647 “–runtime-args”,
648 “com.android.server.SystemServer”,
649 };
650 ZygoteConnection.Arguments parsedArgs = null;
651
652 int pid;
653
654 try {
//这里是为了把硬编码的参数转换成特定类对象
655 parsedArgs = new ZygoteConnection.Arguments(args);
656 ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
657 ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
658
659 //fork新进程
660 pid = Zygote.forkSystemServer(
661 parsedArgs.uid, parsedArgs.gid,
662 parsedArgs.gids,
663 parsedArgs.debugFlags,
664 null,
665 parsedArgs.permittedCapabilities,
666 parsedArgs.effectiveCapabilities);
667 } catch (IllegalArgumentException ex) {
668 throw new RuntimeException(ex);
669 }
670
671 //pid为0,说明当前是子进程
672 if (pid == 0) {
673 if (hasSecondZygote(abiList)) {
674 waitForSecondaryZygote(socketName);
675 }
676 //子进程即SystemServer进程不需要监听socket
677 zygoteServer.closeServerSocket();
//SystemServer进程处理它的事务
678 return handleSystemServerProcess(parsedArgs);
679 }
680
681 return null;
682 }


该部分是创建、启动SystemServer进程,首先是用代码来创建args数组,也就是启动参数,从参数我们可以看出SystemServer进程的用户id和用户组id被设置为1000,并且拥有1001-1010、1018、1021、1032、3001-3010用户组的权限;**进程名为system\_server,启动的类名为com.android.server.SystemServer**。


然后通过Zygote类的**forkSystemServer函数创建了一个子进程**,该方法底层调用了native方法,原理也就是Linux的fork系统调用。然后有个非常有意思的地方,就是pid为0表示是子进程,这里或许有点疑惑,这里是为什么?


这时就要从多进程和fork的含义来理解了,fork的意思是复制,即调用完fork后,**新的systemServer进程会有和Zygote进程一样的信息,比如虚拟机、预加载的资源等,那这时就相当于2个进程都运行到这里了,那如何分道扬镳呢 就看这个pid的值,如果是0就说明是运行在子进程中**。


这个还是很有意思的,关于Linux的fork系统调用,后面关于Linux知识时,再细说一下。


#### runSelectLoop


这个的设计也非常巧妙,runSelectLoop的作用就是**从前面创建的Socket服务端中循环取出其他进程发来的消息,当消息结果caller不为空时,执行这个消息**。


这里就要想个问题,因为是多进程,执行该方法也可能是其他进程,比如前面刚刚创建的systemServer进程,但是我们还记得创建的systemServer进程已经关闭socket了,所以这里的**选择循环会一直运行在Zygote进程中**。


该方法代码如下:



/frameworks/base/core/java/com/android/internal/os/ZygoteServer.java
Runnable runSelectLoop(String abiList) {
144 ArrayList fds = new ArrayList();
145 ArrayList peers = new ArrayList();
146 //这个mServerSocket就是前面创建的服务端Socket
147 fds.add(mServerSocket.getFileDescriptor());
148 peers.add(null);
149 //无限循环等待AMS请求Zygote进程创建新的应用进程。
150 while (true) {
151 StructPollfd[] pollFds = new StructPollfd[fds.size()];
152 for (int i = 0; i < pollFds.length; ++i) {
153 pollFds[i] = new StructPollfd();
154 pollFds[i].fd = fds.get(i);
155 pollFds[i].events = (short) POLLIN;
156 }
157 try {
158 Os.poll(pollFds, -1);
159 } catch (ErrnoException ex) {

最后

今天关于面试的分享就到这里,还是那句话,有些东西你不仅要懂,而且要能够很好地表达出来,能够让面试官认可你的理解,例如Handler机制,这个是面试必问之题。有些晦涩的点,或许它只活在面试当中,实际工作当中你压根不会用到它,但是你要知道它是什么东西。

最后在这里小编分享一份自己收录整理上述技术体系图相关的几十套腾讯、头条、阿里、美团等公司2021年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。

还有 高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

【算法合集】

【延伸Android必备知识点】

【Android部分高级架构视频学习资源】

**Android精讲视频领取学习后更加是如虎添翼!**进军BATJ大厂等(备战)!现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水,赶快领取吧!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水,赶快领取吧!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 22
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值