Android 启动流程和AMS简单初步分析

对于内核来讲没有线程和进程这种划分

init 是用户空间的鼻祖

init通过fork创建java空间的鼻祖

在这里init bin 

android 之前使用Android.mk来编译,现在使用Android.bp来编译 是一个脚本文件

init做了几件事

FirstStageMain

1.挂载 创建 文件

2.重定向 输入输出

3.初始化内核

4.启动selina_setup

权限和安全策略走完后会走

SecondStageMain

初始化属性域

先通过硬件拉起系统的创建,创建之后通过init来创建挂载文件,设置安全策略,开启服务,解析init.rc, 循环处理脚本启动zygote,循环等待

在init.rc 会导入zygote 的引用,触发zygote start

会分操作系统会执行不同的文件,例如32位就是init.zygote32.rc

init.zygote32.rc就会执行app_process 文件

而app_process 就会执行app_main.cpp启动

所以实际上Android的运行环境就是zygote创建出来的

app_main.cpp 里 main方法

会先进行参数校验,携带-就跳过

如果是zygote进程,就走到这边进行启动,因为是个while循环,会把system-server进行启动为true

走到Appruntime 的 start方法

zygote native启动执行了几个方法,启动虚拟机,启动jni,然后启动zygote里的所有方法

方法其实是在启动虚拟机进行内存管理,虚拟机是为了跨平台而建设的Android 把文件编译成.dex可以跨平台执行

进程的模型是什么样子?

 内核空间是共享的

每一个进程都是zygote孵化出来,复制出来,所以每个进程都有自己的JVM,也都有自己的虚拟机

那么虚拟机实现了什么功能?其实就是内存管理这个功能

提出疑问我们什么时候进入的zygote进程?其实就是开启了zygote这个文件

那么这个文件是不是就代表了这个进程?

所谓fork一个进程也就是复制一个进程是不是就是复制了这个文件?

继zygote 进行拷贝是显示拷贝,什么意思,就是如果有人复制这个数据是单独新开辟一个空间进行拷贝而不是在原来基础上改变

物理内存是共享的,但是是硬件概念上的

那么这里注册JNI是在干什么?

JNI是什么?那么有个问题,java和native是怎么通信的?为什么java代码可以调用C的代码?

那么就需要一个桥梁,也就是jni

java的本地方法和native方法关联起来

这里在静态注册函数指针 jni可以native调java,也可以java调native

启动zygoteInit.java 也就是java层代码 接下来还在当前进程,因为没有出现fork方法、

 ZygoteServer 创建一个socket,可以与AMS进行通信

ZygoteServer 使用 socket 而不是 binder 是因为 socket 是一种通用的网络通信机制,它可以在不同进程之间进行通信,而 binder 是 Android 系统特有的进程间通信(IPC)机制。ZygoteServer 是 Android 系统的一个关键组件,它负责预加载和孵化新的应用进程。为了确保 ZygoteServer 能够和各个应用进程进行通信,使用 socket 可以提供更广泛的兼容性和灵活性。

另外,使用 socket 还可以跨越不同设备和网络进行通信,而 binder 主要用于在同一设备内的进程间通信。因此,在跨设备或跨网络的场景下,使用 socket 更为合适。总的来说,选择 socket 而不是 binder 是为了提供更好的通用性和跨平台支持。

binder是一个多线程 fork容易死锁

 这里只是创建一个初始化的socket 

进行类加载在Zygote进程,进行预加载 使用的资源和类相关

 

启动systemServer 

String args[] = {
    "--setuid=1000",
    "--setgid=1000",
    "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,1032,3001,3002,3003,3006,3007,3009,3010",
    "--capabilities=" + capabilities + "," + capabilities,
//进程名
    "--nice-name=system_server",
    "--runtime-args",
//全类名
    "com.android.server.SystemServer",
};

这段代码在两边进程其实都会执行,那么如何判断当前是哪个进程?通过pid是否等于0来进行判断,当pid等于0时候就证明是当前进程 也就是从这里往下的代码都是新进程,也就是SystemServer进程,为什么?因为只有pid为0才会走到这里,Zygote里的代码所有进程共享,当SystemServer进程走到这里的时候就会开启自己的main方法

调用native方法 再调用内部的clone方法,具体clone如何实现的后面解析 

 通过反射启动SystemServer.main

nativeZygoteInit 实际上调用的是 

而gCurRuntime 实际上是AndroidRuntime 

接下来通过反射执行了systemServer的main方法 

 走到这里就与之前所学联系到了一起,SystemServer是如何创建的?为什么很多系统服务都从这里开始?

startBootstrapServices(); 引导服务
startCoreServices(); 核心服务
startOtherServices(); 其他服务

那么问题来了,一个app可以多个进程,一个进程可以多个app么?

答案是也是可以的 后面补充

那么还有个问题,我们可以看到 systemserver里也有一个handler和loop,那么这里的handler和loop和 app里的loop是一个嘛?

不是,app里的loop是ActivityThread 创建的,而 这里的loop是SystemServer的,不是一个东西

接下来反射创建application 后是不会进行create的 因为系统层传入为空

接下来startBootstrapService 引导服务 创建ATMS android10以后新增ATMS管理 Acitvity,之前均放在AMS中 

 ATMS和AMS一样,均有Lifecycle管理生命周期 

创建后 ServiceManager addService 管理服务的生命周期

这就是所谓注册binder服务

继续流程,启动launcher 启动systemUI

 然后先追一下 AMS的 systemReady 

在这里topActivity mAtmInternal 实际上是ATMS

systemReady实际上是 启动launcher 经过一系列调用链到达

然后再经过一系列调用链走到 

 在这里启动一个新的进程

会走到 openZygoteSocketIfNeeded 与 zygote流程一样,设置很多东西

 分成主zygote 和从 zygote

 分成两种 64/32位  然后进行socket connect

所以open。。方法所做的就是与zygote进程建立连接

那么socket 通知 zygote后 zygote怎么处理的?

在loop fork新的进程,通过反射去启动ActivityThread main方法(与    类似)

也就是再次回到了ActivityThread

走了Activity的生命周期 

 private class ApplicationThread extends IApplicationThread.Stub {
        private static final String DB_INFO_FORMAT = "  %8s %8s %14s %14s  %s";

        public final void scheduleReceiver(Intent intent, ActivityInfo info,
                CompatibilityInfo compatInfo, int resultCode, String data, Bundle extras,
                boolean sync, int sendingUser, int processState) {
            updateProcessState(processState, false);
            ReceiverData r = new ReceiverData(intent, resultCode, data, extras,
                    sync, false, mAppThread.asBinder(), sendingUser);
            r.info = info;
            r.compatInfo = compatInfo;
            sendMessage(H.RECEIVER, r);
        }

这里讲下 ApplicationThread 本身就是binder 所以,这里已经进行了跨进程通讯了

接下来一个问题,我们Android程序主线程在哪启动的?作为android开发确实很多时候对java的一些简单基础会忽略掉

所以java,执行main方法的时候,其实会启动一个线程对不对

是的,您说得对。在Java中,当执行main方法时,实际上会启动一个线程来运行main方法。这个线程称为"main"线程,也被称为"主线程",它是Java程序的入口点。

当您运行一个Java应用程序时,Java虚拟机(JVM)会自动创建一个名为"main"的线程,并从main方法开始执行。这个线程负责执行main方法中的代码,包括初始化应用程序、创建对象、执行业务逻辑等任务。

请注意,"main"线程是Java应用程序的一部分,它不同于Android应用程序的主线程。在Android应用程序中,主线程是指负责处理与用户界面相关的任务,例如UI渲染、用户输入响应等的线程。而在Java应用程序中,"main"线程是指从main方法开始执行的线程。

总结:在Java应用程序中,执行main方法会启动一个名为"main"的线程,负责执行main方法中的代码。这个线程是Java程序的入口点,而在Android应用程序中,主线程是指负责处理与用户界面相关的任务的线程。

我们做个总结,当一个进程 fork的时候会clone一个进程,会把zygote 的代码重新走一遍,当走到java层的时候,上面有说,会通过反射创建自己进程的main方法,并且初始化loop,也就是主线程loop,那么当AMS跨进程通讯来的时候就会通过这个loop,切换线程到主线程

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值