Android学习---zygote(上)

news2024/11/24 11:13:36

Zygote意思是受精卵,它在Java世界中起到了很重要的作用,Android是基于Linux内核的,SDK是基于Java世界的,native语言是基于C和C++,起初一定是先存在native世界,那么Java世界是如何创建的?这就与zygote和system_server有关。

 

Zygote是一个native应用程序,原名是app_process,是在Android.mk文件中指定的,但是在运行的时候通过Linux下的pctrl系统调用将自己的名字改成了zygote,在0frameworks/base/cmds/app_process目录下,app_main函数中:

        if (0 == strcmp("--zygote", arg)) {
            bool startSystemServer = (i < argc) ? 
                    strcmp(argv[i], "--start-system-server") == 0 : false;
            setArgv0(argv0, "zygote");
            set_process_name("zygote");//设置本进程名字是zygote
            runtime.start("com.android.internal.os.ZygoteInit",
                startSystemServer);
        } 

上面的函数中,调用了AppRuntime中的start方法,AppRuntime继承AndroidRuntime,调用的start也是AndroidRuntime里的方法。

AndroidRuntime.cpp

①//创建虚拟机
if (startVm(&mJavaVM, &env) != 0) 
        goto bail; 

②注册JNI函数
  if (startReg(env) < 0) {
        LOGE("Unable to register all android natives\n");
        goto bail;
}

③ 通过JNI调用ZygoteInit下的main函数 进入Java世界
env->CallStaticVoidMethod(startClass, startMeth, strArray);

1 创建虚拟机

int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)//大部分是设置虚拟机参数
{ 
//设置JNI check选项的 检查资源是否被正确释放 字符集的要求等 缺点:耗时
property_get("dalvik.vm.checkjni", propBuf, "");

 //设置虚拟机的heapsize 默认是16MB 太小会导致操作大图片的时候无法分配内存

    strcpy(heapsizeOptsBuf, "-Xmx");
    property_get("dalvik.vm.heapsize", heapsizeOptsBuf+4, "16m");
}

2 注册JNI函数

/*static*/ int AndroidRuntime::startReg(JNIEnv* env)
{   //设置Thread类的线程创建函数是javaCreateThreadEtc
    androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);
    env->PushLocalFrame(200);
   // 注册JNI函数 gRegJNI是一个全局数组
/*register_jni_procs函数里调用数组的Proc方法,Proc方法是为了注册JNI函数,数组是gRegJNI包含了所需要注册的JNI函数*/
    if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
        env->PopLocalFrame(NULL);
        return -1;
    }
    env->PopLocalFrame(NULL);
    //createJavaThread("fubar", quickTest, (void*) "hello");

    return 0;
}

 

接下来就进入了Java世界,Java世界的入口---frameworks/base/core/java/com/android/internal/os  ZygoteInit.java

public static void main(String argv[]) {
try{
registerZygoteSocket(); //① 注册zygote用到的socket

preloadClasses(); //②预加载类和资源
preloadResources();

if (argv[1].equals("true")) {
   startSystemServer(); //③启动SystemServer
 }

if (ZYGOTE_FORK_MODE) {
     runForkMode(); //④
} else {
     runSelectLoopMode();
 }
}catch(MethodAndArgsCaller caller){
caller.run(); //⑤ 
}
}
  • 建立IPC通信服务端registerZygoteSocket

IPC---InterProcess Communication 进程间通信,指的是在不同进程之间传播交换信息,不同进程之间用户空间独立,共享内存区是公用的,常见的IPC通信有:管道、消息队列、 信号量、共享内存、socket、Streams等

    private static void registerZygoteSocket() {
        if (sServerSocket == null) {
            int fileDesc;
            try { //从环境变量获取socket的fd(启动时传入)
                String env = System.getenv(ANDROID_SOCKET_ENV);
                fileDesc = Integer.parseInt(env);
            } ......
            try { //创建服务端socket
                sServerSocket = new LocalServerSocket(
                        createFileDescriptor(fileDesc));
            }......
        }
    }
  1. 预加载类和资源
 private static void preloadClasses() {
       //预加载的类信息存储在PRELOADED_CLASSES里
        InputStream is = ZygoteInit.class.getClassLoader().getResourceAsStream(
if (is == null) {
            Log.e(TAG, "Couldn't find " + PRELOADED_CLASSES + ".");
        } else { //准备工作      } 
//读取文件的每一行
         while ((line = br.readLine()) != null) {
                    // Skip comments and blank lines.
                    line = line.trim();
                    if (line.startsWith("#") || line.equals("")) {
                        continue;
                    }
               //通过Java反射来加载类 line中存储的是预加载的类名
                   Class.forName(line);           
}

在/AOSP/frameworks/base/preloaded-classes下是要加载的所有类,数量很多高达1200+行

 Preload_class文件由framework/base/tool/preload工具生成,他要判断每个类加载的时间是否大于1250us,超过这个时间写入到preload_classes文件中,由zygote预加载。由于要加载的类十分多,这也导致了android启动时间很长。

③启动system_server

StartSystemServer会创建Java世界中系统Service所驻留的进程,该进程是framework核心,他如果死了,zygote就会自杀。zygote压力大,分裂了一个子进程为他做一些事情。

private static boolean startSystemServer()
            throws MethodAndArgsCaller, RuntimeException {
//设置参数
              String args[] = {
            "--setuid=1000",
            "--setgid=1000",           "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,3001,3002,3003",
            "--capabilities=130104352,130104352",
            "--runtime-init",
            "--nice-name=system_server",//进程名
            "com.android.server.SystemServer",
        };
        ZygoteConnection.Arguments parsedArgs = null;
        int pid;

        try {
            parsedArgs = new ZygoteConnection.Arguments(args);
            int debugFlags = parsedArgs.debugFlags;
            if ("1".equals(SystemProperties.get("ro.debuggable")))
                debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;

            /* zygote分裂了一个子进程 */
            pid = Zygote.forkSystemServer(
                    parsedArgs.uid, parsedArgs.gid,
                    parsedArgs.gids, debugFlags, null,
                    parsedArgs.permittedCapabilities,
                    parsedArgs.effectiveCapabilities);
        } catch (IllegalArgumentException ex) {
            throw new RuntimeException(ex);
        }
        if (pid == 0) {//pid=0表明处于子进程中,开始执行system_server的工作
            handleSystemServerProcess(parsedArgs);
        }

        return true;
    }

④ runSelectLoopMode

当函数分裂了system_server进程后进入到了下一个关键函数runSelectLoopMode,这里将会使用到前面第一步创建的socket

private static void runSelectLoopMode() throws MethodAndArgsCaller {
        ArrayList<FileDescriptor> fds = new ArrayList();
        ArrayList<ZygoteConnection> peers = new ArrayList();
        FileDescriptor[] fdArray = new FileDescriptor[4];
//第一步创建的服务端socket
        fds.add(sServerSocket.getFileDescriptor());
        peers.add(null);
while (true) {
          int index=0;
            try {
//selectReadable内部调用select,使用多路复用IO模型,有客户端连接//或者有数据时//selectReadable就会返回
                fdArray = fds.toArray(fdArray);
                index = selectReadable(fdArray);
            } catch (IOException ex) {
                throw new RuntimeException("Error in select()", ex);
            }
//客户端代表的是ZygoteConnection,
else if (index == 0) {
                ZygoteConnection newPeer = acceptCommandPeer();
                peers.add(newPeer);
                fds.add(newPeer.getFileDesciptor());
            } else {
                boolean done;
// peers.get(index)返回的是ZygoteConnection,然后调用runOnce函数完成
                done = peers.get(index).runOnce();
}

总结:主要是处理客户连接和客户请求,客户在zygote中用ZygoteConnection 表示,客户的请求由runOnce函数完成。

至此Zygote便睡去了,默默守护在我们周围。当收到子孙后代的请求后,会被随时叫醒。

下一章节,将来学习Zygote的子进程SystemServer

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/43300.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

『LeetCode|每日一题』---->打家劫舍||

目录 1.每日一句 2.作者简介 『LeetCode|每日一题』打家劫舍|| 1.每日一题 2.解题思路 2.1 思路分析 2.2 核心代码 2.3 完整代码 2.4 运行结果 1.每日一句 任何事情把期待值降到最低&#xff0c;所有遇见的都是礼物 2.作者简介 &#x1f3e1;个人主页&#xff1a;XiaoXia…

github数据怎么Python爬取

爬虫流程 在上周写完用scrapy爬去知乎用户信息的爬虫之后&#xff0c;github上star个数一下就在公司小组内部排的上名次了&#xff0c;我还信誓旦旦的跟上级吹牛皮说如果再写一个&#xff0c;都不好意思和你再提star了&#xff0c;怕你们伤心。上级不屑的说&#xff0c;那就写…

网站页面SEO优化方案

如果可以实现记得点赞分享&#xff0c;谢谢老铁&#xff5e; 背景说明 针对网页面而提供相应的产品页面 SEO 优化部署方案&#xff0c;使其产品页面符合 SEO 规范&#xff0c;且能尽快获得产品词的较好排名。 产品相关页面URL命名 URL 结构对于网站页面的 seo 来说非常重要…

VirtualLab教程特辑

目录前言一、一些界面上的说明1、关于软边relative edge width2、catalog里器件参数改动3、系统光线分析仪的光线数4、编程手册从哪看以及哪里可以编程5、Multiple Light Source6、多波长与多模式分开显示7、harmonic fields set-manipulations8、detector results显示功率小9、…

阿尔茨海默病中的人类连接组及它与生物标记物和遗传学的关系

摘要 阿尔茨海默病(AD)损害了大脑的结构和功能网络&#xff0c;导致认知障碍。最近的连接组学研究结果已经将AD中结构和功能网络组织的变化与淀粉样蛋白-β和tau蛋白的积累和扩散模式联系起来&#xff0c;为该疾病的神经生物学机制提供了见解。此外&#xff0c;对基因相关的连接…

如何检索专利技术?

问题一&#xff1a;申请实用新型专利需要提交哪些文件呢&#xff1f; 主要有以下四点&#xff1a; 1、请求书&#xff1a;主要包括实用新型专利的名称、申请人的名称和地址等内容&#xff1b; 2、权利要求书&#xff1a;这里需要交代好每一项要保护的内容&#xff1b; 3、说…

CommonsCollections6利用链分析

目录 (一&#xff09;利用链 &#xff08;二&#xff09;代码分析 0x01 TiedMapEntry 0x02 HashMap &#xff08;三&#xff09;POC&#xff1a; (一&#xff09;利用链 先来看 ysoserial 中的利用链&#xff1a; /*Gadget chain:java.io.ObjectInputStream.readObject()…

[附源码]SSM计算机毕业设计线上图书销售管理系统JAVA

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

三大O(nlogn)算法分析

堆排序 demo 从第一个父节点开始&#xff0c;每一个都调换自己和所有子孙节点的上下层次调换&#xff0c;形成最大堆。然后进行堆分支调整 class Solution {public int[] sortArray(int[] nums) {maxHeap(nums);sort(nums);return nums;}public static void maxHeap(int[] n…

blender hardOps插件

hardOps将一些常用的功能整合在一起&#xff0c;方便调用&#xff0c;例如&#xff0c;平滑&#xff0c;倒角&#xff0c;标记锐边&#xff0c;添加修改器 打开hardOps 方法1&#xff1a;物体模式在舞台左侧选择hardOps图标 推荐用这个 方法2&#xff1a;这个插件的打开方式非…

C++【类型转换】

文章目录一、C语言的类型转换二、C的强制类型转换1.static_cast静态转换2.reinterpret_cast重新诠释3.const_cast小总结4.dynamic_cast动态转换一、C语言的类型转换 在C语言中&#xff0c;如果赋值运算符左右两侧类型不同&#xff0c;或者形参与实参类型不匹配&#xff0c;或者…

【PAT】数据结构树和图月考复习1

选择题 2-1 我们用一个有向图来表示航空公司所有航班的航线。下列哪种算法最适合解决找给定两城市间最经济的飞行路线问题&#xff1f; A.深度优先搜索 B.Kruskal算法 C.拓扑排序算法 D.Dijkstra算法 解析&#xff1a; 本题为单源最短路径问题&#xff0c;应选用dijsktra算…

【WMWare 克隆CentOS虚拟机 】解决克隆后 ip 冲突 主机名重复问题

前言&#xff1a; 当我需要搭建数据库主从复制集群时&#xff0c;不想再重新安装一遍 mysql &#xff0c;于是将安装好 mysql 的虚拟机克隆一份 一、克隆方法 鼠标右击虚拟机 ----> 管理 ----> 克隆 &#xff08;选择完全克隆&#xff0c;选择好位置&#xff0c;设置好…

python函数使用

目录 一.函数基本概念 1.函数是什么 2.使用函数的好处是: 3.为什么要学习、使用函数 二.函数使用 1.定义方法 2.函数的调用 3.注意事项 4.例子 三.函数中的参数 作用 注意 四.函数中的返回值 1.什么是函数返回值? 2.返回值的应用语法: 注意 五.None类型 一.函数…

Android茶叶进销存

功能描述: 该app主要实现了茶叶的进货、销售、供应商、客户的管理&#xff0c;是一个完整的小型进销存app&#xff0c;适合新手学习sqlite数据库的基本使用。具体功能如下&#xff1a; 一、个人业务管理子系统 1、客户信息登记、修改、注销&#xff08;客户管理&#xff09; …

[Linux](15)线程基础,线程控制,线程的互斥与同步

文章目录前言Linux 线程概念线程的优点线程的缺点线程异常线程用途使用pthread_createpthread_join线程退出线程id分离线程线程互斥问题&#xff1a;临界资源访问问题问题解决&#xff1a;互斥锁的使用RAII 风格的加锁方式可重入 & 线程安全死锁的概念线程同步条件变量生产…

[附源码]计算机毕业设计springboot春晓学堂管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

让我们进入面向对象的世界(四)

文章目录前言一. 初始多态1.1 多态是什么1.2 多态是怎么工作1.3多态的向上转型和向下转型二.多态的好处三.总结前言 前面我们讲过了&#xff0c;面向对象继承的特性&#xff0c;下面我们会根据多态来展开讨论&#xff0c;还是用熟悉的方式&#xff0c;让大家去了解这个疯狂的东…

软考证书具体用途--详细介绍

拿到软考证书的前提是对你自己今后的职业发展有帮助&#xff0c;用得到才能对你而言发挥它最大的好处。 软考证书的具体用途&#xff1a; 1.纳入我国高校人才培养和教学体系 目前&#xff0c;软考已经被纳入高校人才培养和教学体系。在很多高校中&#xff0c;软考纳入学分&a…

设置渐变边框色

如上图所示&#xff0c;需设置渐变边框色&#xff0c;左右边框颜色固定&#xff0c;上边框从左到右开始渐变&#xff0c;下边框从右到左开始渐变。 思考了很久&#xff0c;如果看作是一个div&#xff0c;则需要用到 border-image属性设置渐变色。也可以看作是两个div&#xff0…