模拟Android系统Zygote启动流程

版权声明:本文为梦想全栈程序猿原创文章,转载请附上原文出处链接和本声明

前言:

        转眼时间过去了10年了,回顾整个10年的工作历程,做了3年的手机,4年左右的Android指纹相关的工作,3年左右的跟传感器相关的工作,其实,我个人还是想了解Android底层的相关知识,目前对于啥都了解一点,都不太深入的,让我很焦虑,记录自己学习的相关知识,这个系列的文章思路是抽丝剥茧,记录Android相关知识的关键部分,目前是从Android8.0开始。

一.前置学习:了解Android的启动流程

文笔不好,只是记录下来给自己回顾,或者分享给志同道合的人一起交流跟学习;学习本文章,你需要了解Android基本的启动流程,在这里不讲,需要自行去查看相关的资料

二.Android如何进入Zygote的java代码

这个是Framework的模拟相关代码,基本上是一比一还原

通过相关Android启动流程的相关知识,可以清楚知道,系统在执行执行并解析init.rc的过程中,启动了路径为/system/bin/app_process的可执行文件;我们知道,在Linux中,死的可执行文件称为程序,活的可执行文件称为进程;可执行文件的程序入口是main函数(这个不是很严谨)

app_process.cpp文件

int main(int argc, char* const argv[])
{

    char* argBlockStart = "test";
    size_t argBlockLength = 5;

    AppRuntime runtime(argBlockStart, argBlockLength);
    runtime.start("com.huahua.moon.android.ZygoteInit", true);

    return 0;
}

所以根据目前的main函数,需要去看下runtime.start方法,下面是app_process.cpp的整个文件内容

#include "AndroidRuntime.h"

#include <stdlib.h>

#include <stdio.h>
#include <unistd.h>

class AppRuntime : public AndroidRuntime
{
public:
    AppRuntime(char* argBlockStart, size_t argBlockLength)
        : AndroidRuntime(argBlockStart, argBlockLength)
    {

    }

};

int main(int argc, char* const argv[])
{

    char* argBlockStart = "test";
    size_t argBlockLength = 5;

    AppRuntime runtime(argBlockStart, argBlockLength);
    runtime.start("com.huahua.moon.android.ZygoteInit", true);

    return 0;
}

可以看到,runtime是AppRuntime类的对象,这个类继承自AndroidRuntime类,AppRuntime类中没有看到start函数的相关声明跟定义,所以,这个肯定是在其父类AndroidRuntime中声明跟定义的所以需要看AppRuntime跟AndroidRuntime相关的类;

这个是AndroidRuntime.h文件

#include <stddef.h>
#include <stdlib.h>

#include <jni.h>

#include <vector>

using namespace std;
using std::vector;

class AndroidRuntime
{
public:
    AndroidRuntime(char* argBlockStart, size_t argBlockSize);
    virtual ~AndroidRuntime();

    void addOption(const char* optionString, void* extra_info = NULL);

    void start(const char* className, bool zygote);

    void exit(int mode);

    static AndroidRuntime* getRuntime();

    static char* toSlashClassName(const char* className);

private:
    int startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote);

    vector<JavaVMOption> mOptions;
    char* const mArgBlockStart;
    const size_t mArgBlockLength;
    static JavaVM* mJavaVM;
};

这个是AndroidRuntime.cpp部分文件

void AndroidRuntime::start(const char* className, bool zygote)
{
    printf("AndroidRuntime start className = %s, zygote = %d \n", className, zygote);

     JNIEnv* env;
     if (startVm(&mJavaVM, &env, zygote) != 0)
     {
        return;
     }

     jstring classNameStr = env->NewStringUTF(className);
     char* slashClassName = toSlashClassName(className);

     printf("JavaVM slashClassName '%s'\n", slashClassName);
     jclass startClass = env->FindClass(slashClassName);
     if (startClass == NULL)
     {
        printf("JavaVM unable to locate class '%s'\n", slashClassName);
     }
     else
     {
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main", "([Ljava/lang/String;)V");
        if (startMeth != NULL)
        {
            jobjectArray strArray;
            env->CallStaticVoidMethod(startClass, startMeth, strArray);
        }
     }
}

所以上面app_process.cpp的main函数中,最终调用的是AndroidRuntime.cpp中的start函数,传递的参数className = ("com.huahua.moon.android.ZygoteInit"  zygote = true;因为我这篇文章是模拟,只是概述关键点,所有有其他的很多东西没有提及到;这里跟我上一次的文章是有联系的,具体也可以参考我上篇博客linux运行可执行文件,通过c语言调用java的main方法

上面的代码,主要是一下几点:

  • 启动JVM虚拟机
  • 转换class Name的格式
  • 找到对应的class
  • 获取对应class的main函数
  • 执行main函数

这里有一个细节,就是我们传递的进来的class名是"com.huahua.moon.android.ZygoteInit",这个名字是不符合JAVA相关的JNI规范的,需要修改成"com/huahua/moon/android/ZygoteInit"这种名字

startVm函数是启动java虚拟机

int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote)
{
    JavaVMInitArgs initArgs;

#if 0
    addOption("-Djava.class.path=.");

    initArgs.version = JNI_VERSION_1_4;
    //initArgs.options = mOptions.editArray();
    //initArgs.nOptions = mOptions.size();
    initArgs.ignoreUnrecognized = JNI_FALSE;
#endif


    JavaVMOption options[1];
    options[0].optionString = "-Djava.class.path=.";

    initArgs.version = JNI_VERSION_1_4;
    initArgs.nOptions = 1;
    initArgs.options = options;

    if (JNI_CreateJavaVM(pJavaVM, (void **)pEnv, &initArgs) < 0)
    {
        printf("JNI_CreateJavaVM failed \n");
        return -1;
    }
    else
    {
        printf("JNI_CreateJavaVM create success  \n");
    }

    return 0;
}

toSlashClassName函数是把"com.huahua.moon.android.ZygoteInit"转化成"com/huahua/moon/android/ZygoteInit"这种格式

char* AndroidRuntime::toSlashClassName(const char* className)
{
    char* result = strdup(className);
    for (char* cp = result; *cp != '\0'; cp++) {
        if (*cp == '.') {
            *cp = '/';
        }
    }
    return result;
}

三.模拟结果

通过执行app_process 可执行文件, 输出了java 代码的main函数中的系统输出,证明了Android 进入了Zygote的java代码

ZygoteInit.java 的代码如下图所示

三.注意问题

模拟代码是一个稍微完整的工程代码,本篇文章只是包含了其中的一部分

四.如何编译测试

1.用本工程的java代码编译出class文件,使用java命令或者intellij idea 工具编译都行

2.使用本工程的cpp部分代码,编译出app_process 可执行文件,目前本工程的构建工具是Cmake

3.拷贝到out目前, 请注意目录结构

五.思考问题

真的只有面向对象语言有封装的特性吗? 

此工程中的cpp代码从封装性,跟C语言的代码对比而言.(ps:在这个头文件中竟然能看到类的相关私有数据成员)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【数据库】GROUP BY 详解、示例、注意事项

一、基本介绍 GROUP BY 语句在 SQL 中用于将来自数据库表的记录分组&#xff0c;以便可以对每个组执行聚合函数&#xff08;如 COUNT(), MAX(), MIN(), SUM(), AVG() 等&#xff09;。使用 GROUP BY 时&#xff0c;数据库会根据一个或多个列的值将结果集分为多个分组&#xff…

BootStrap 5 保姆级教程(三):表格 图片

一、表格 1.1 基础表格 Bootstrap5 通过 .table 类来设置基础表格的样式&#xff0c;实例如下: <div class"container mt-3"><h2>基础表格</h2><p>.table 类来设置基础表格的样式:</p> <table class"table"…

掌握 C# 爬虫技术:使用 HttpClient 获取今日头条内容

摘要/导言&#xff1a; 在本文中&#xff0c;我们将探讨如何使用 C# 中的 HttpClient 类和爬虫代理IP技术来获取今日头条的内容。我们还将实现多线程技术&#xff0c;以提高数据采集的效率。 背景/引言&#xff1a; 随着信息时代的到来&#xff0c;数据已经成为了一种非常宝…

电脑离线调用微信 ocr.exe 使用 python 调用 WeChatOCR.exe 附python代码

微信的OCR识别能力还是可以的,并且可以得到位置,速度也快,我想要把微信的这个exe 单独提取出来,可以供其他项目使用,目前已有的应该都是需要依赖微信运行状态的,我这个独一份 相当于把微信运行它的OCR的环境完全剥离出来,只需要几个代码文件加上几个模型文件就可以离线…

【算法刷题 | 回溯思想 01】4.11(回溯算法理论、组合、组合总和 ||| )

文章目录 回溯1.回溯算法理论基础1.1什么是回溯法&#xff1f;1.2回溯法的效率1.3回溯法解决的问题1.4如何理解回溯法&#xff1f;1.5回溯法模板 2.组合2.1问题2.2解法一&#xff1a;暴力解法&#xff08;循环次数不确定&#xff09;2.3解法二&#xff1a;回溯2.3.1回溯思路&am…

如何申请做快团团购帮卖团长?免费试用教程一学就会!

新手小白想要自己做快团团&#xff0c;有两种方法。 1、自己提供货源&#xff0c;自己开团做团长。 这种方法流程非常简单&#xff0c;从微信小程序中找到快团团&#xff0c;点击右上角“一键开团”&#xff0c;然后“创建普通团购”&#xff0c;按照操作设置就可以开团了。 …

【2024MathorCup妈妈杯建模】赛题 B:甲骨文智能识别中原始拓片单字自动分割与识别研究

【2024MathorCup妈妈杯建模】赛题 B&#xff1a;甲骨文智能识别中原始拓片单字自动分割与识别研究 加群可以享受定制等更多服务&#xff0c;或者搜索B站&#xff1a;数模洛凌寺 联络组织企鹅&#xff1a;904117571 问题重述 问题 1&#xff1a;对于附件 1&#xff08;Pre_…

实习记录小程序|基于SSM的实习记录小程序设计与实现(源码+数据库+文档)

知识管理 目录 基于SSM的习记录小程序设计与实现 一、前言 二、系统设计 三、系统功能设计 1、小程序端&#xff1a; 2、后台 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1a;✌️大厂码农|毕…

Linux:软件包管理器 - yum

Linux&#xff1a;软件包管理器 - yum Linux的软件安装方式源代码安装rpm包安装yum安装 yum三板斧yum listyum installyum remove yum生态yum源 Linux的软件安装方式 源代码安装 在Linux下安装软件, 一个通常的办法是下载到程序的源代码, 并进行编译, 得到可执行程序 源代码安…

ARM内核、内核寄存器及作用、ARM最小系统、半导体器件、存储器、ARM工作方式、ARM寄存器个数、立即数、汇编指令的s/c后缀

我要成为嵌入式高手之4月10日51单片机第五天&#xff01;&#xff01; ———————————————————————————— 单片机最小系统板&#xff1a; 单片机内部的CPU&#xff1a; CPU定义的变量都在ram中、编写的程序代码都在rom中 CPU在次细化&#xff1a;ker…

AMD Tensile 简介与示例

按照知其然&#xff0c;再知其所以然的认知次序进行 1&#xff0c;下载代码 git clone --recursive https://github.com/ROCm/Tensile.git 2&#xff0c;安装 Tensile cd Tensile mkdir build cd build ../Tensile/bin/Tensile ../Tensile/Configs/rocblas_dgemm_nn_asm_full…

MongoDB快照(LVM)业务场景应用实战

MongoDB和LVM快照概述 MongoDB的重要性&#xff1a;MongoDB支持的灵活的文档模型&#xff0c;使其成为处理大量分散数据的理想选择&#xff0c;特别是在需要快速迭代和频繁更改数据结构的应用中。 LVM&#xff08;逻辑卷管理&#xff09;快照技术基本概念&#xff1a;LVM允许…

CY7.5-COOH荧光属性Cyanine7.5花菁染料

CY7.5-COOH&#xff0c;作为一种Cyanine 7.5花菁染料&#xff0c;在荧光属性上表现出色。其独特的化学结构赋予了它荧光性质&#xff0c;使其在生物标记、荧光成像和光学传感等领域具有诸多应用前景。 CY7.5-COOH具有出色的荧光量子产率&#xff0c;这意味着在激发光的照射下&…

C#/.NET/.NET Core拾遗补漏合集(24年4月更新)

前言 在这个快速发展的技术世界中&#xff0c;时常会有一些重要的知识点、信息或细节被忽略或遗漏。《C#/.NET/.NET Core拾遗补漏》专栏我们将探讨一些可能被忽略或遗漏的重要知识点、信息或细节&#xff0c;以帮助大家更全面地了解这些技术栈的特性和发展方向。 GitHub开源地…

微信小程序搜索排名优化的八个套路

微信小程序的搜索优化排名是一个综合性的工作&#xff0c;需要针对多个维度进行操作。小柚给各位新老客户列出一些关键步骤和策略&#xff0c;帮助老板利用微信小程序的搜索排名规则进行优化。 1.选择合适的关键词 深入研究目标用户的搜索习惯&#xff0c;选择高搜索量、低竞争…

Java List基础篇

目录 前言一、常用List1.1 List1.1.1 特点1.1.2 常用API 1.2 ArrayList1.2.1 特点1.2.2 使用 1.3 LinkedList1.3.1 特点1.3.2 使用 1.4 CopyOnWriteArrayList1.4.1 特点1.4.2 使用 1.5 Arrays.asList()1.5.1 特点1.5.2 使用 二、对比总结 前言 一、常用List 1.1 List List是…

Day93:云上攻防-云服务篇对象存储Bucket桶任意上传域名接管AccessKey泄漏

目录 云服务-对象存储-权限配置不当 权限控制-公共读或公共读写&#xff1a;可完整访问但不显示完整结构目录 权限控制-Bucket授权策略&#xff1a;设置ListObject显示完整结构目录 权限控制-Bucket公共读写权限&#xff1a;公共读写直接PUT文件任意上传 云服务-对象存储-…

手写ArrrayList

需求 自定义的MyArrayList import java.util.Arrays; import java.util.Objects;public class MyArrayList<E> {private Object[] elementData ; // 存储元素的数组private int size; // 记录 的元素个数private static final int DEFAULT_CAPACITY 10; // 默认容量// …

Java高频面试之JVM篇

说一下 Jvm 的主要组成部分&#xff1f;及其作用&#xff1f; 类加载器执行器运行时数据区域本地接口 谈谈对运行时数据区的理解&#xff1f; 堆和栈的区别是什么&#xff1f; 堆中存什么&#xff1f;栈中存什么&#xff1f; 堆总存对象,栈中存局部变量,引用 为什么要把堆…

最新php投票系统源码下载 二维码投票生成器系统 源码开源可二开

在当今数字化时代&#xff0c;投票系统已成为各类活动、选举、调查等场景中不可或缺的工具。为了满足广大用户对于高效、便捷投票系统的需求&#xff0c;分享一款最新版的PHP投票系统源码&#xff0c;带二维码投票生成器功能&#xff0c;为用户提供了更为灵活和多样化的投票体验…