美文网首页Android技术知识Android开发Android开发经验谈
拒绝摆烂,Android AMS应该打卡学习的n件事

拒绝摆烂,Android AMS应该打卡学习的n件事

作者: 谁动了我的代码 | 来源:发表于2023-03-15 16:54 被阅读0次

    AMS(ActivityManagerService)介绍

    从java角度来看,ams就是一个java对象,实现了Ibinder接口,所以它是一个用于进程之间通信的接口,这个对象初始化是在systemServer.java 的run()方法里面

    public Lifecycle(Context context) { 
        super(context); 
        mService = new ActivityManagerService(context);
     }
    

    AMS是什么?

    1. 从java角度来看,ams就是一个java对象,实现了Ibinder接口,所以它是一个用于进程之间通信的 接口,这个对象初始化是在systemServer.java 的run()方法里面
    2. AMS是一个服务 ActivityManagerService从名字就可以看出,它是一个服务,用来管理Activity,而且是一个系统服务, 就是包管理服务,电池管理服务,震动管理服务等。
    3. AMS是一个Binder ams实现了Ibinder接口,所以它是一个Binder,这意味着他不但可以用于进程间通信,还是一个线程,因为一个Binder就是一个线程。

    启动流程

    • Init 初始化Linux 层,处理部分服务
    • 挂载和创建系统文件
    • 解析rc文件:
    • rc 文件中有很多action
    • 进入无限循环
    1. 执行action:zygote 进程就在这里启动
    • for循环去解析参数,根据rc 文件中的action 执行相应操作
    1. 检测并重启需要的进程
    2. 接收子进程的SIGCHLD信号,执行响应的方法
    • 防止子进程成为僵尸进程
    • zygote 层:
    • native 部分:
    • 初始化android 运行时环境(ART),因为Java 代码需要运行在虚拟机中;
    • 初始化 JNI ,因为native 层与 Java 层需要通信
    • 执行ZygoteInit.main 方法,进入Java 部分
    • Java 部分:
    • 创建 socket:实现通信
    • 执行预加载:加快进程的启动速度
    • 通过fork 创建 SystemServer 进程
    • 进入循环:等待AMS 的通知,并根据通知创建对应的进程

    引申问题:

    • zygote 中的Java 层是如何创建出SystemServer 的?
    • SystemServer 是怎么启动的?

    本文正文内容

    SystemServer 进程的创建时机

    • 一句话描述:
    • Zygote 进程通过forkSystemServer类 调用fork(),创建其子进程;这个子进程就是SystemServer 进程
    • 业务逻辑:


    SystemServer 进程的创建过程

    • 前情提要:
    • 从ZygoteInit.java 中的main 方法。进入forkSystemServer类;此时,属于Zygote 进程
    • 进程实际上是没有native,java之分的;我们常说Zygote 进程在native 层,SystemServer 进程在Java 层,这可看做一种约定。
    • 第一步:参数赋值
    • 通过字符串数组args 进行赋值:包含uid,gid,nice-name(进程名)
    • 第二步:创建子进程,拿到pid
    • 通过Zygote.forkSystemServer 调用fork(),创建子进程并返回pid

    怎样理解Zygote 进程与SystemServer 进程的关系?

    • 一句话描述:
    • Zygote 进程是SystemServer 进程的父进程,两进程共用一段代码;
    • 怎么理解进程号(pid) ?
    • pid 代表每个进程的进程号。但是,当pid 接收返回值时,其表示子进程的进程号。
    • pid的值:进程的唯一标识符
    • 子进程是父进程fork 出来的,可以看作是拷贝。通过pid 的值区分父子进程
    • 定义子进程处理逻辑
    • if(pid == 0){ 业务代码 }
    • 子进程的pid 比父进程的pid 大,是递增的
    • pid 的值可以看成是随机的,但是也不能这样说。
    • 举个例子:
    • 假如Zygote 的进程号为1000,SystemServer 的进程号是6000。那么,Zygote 中的pid 的返回值就是6000,也就是Zygote fork 出的子进程的进程号。而SystemServer 中的pid 的返回值为0,因为它没有子进程;

    怎么通过代码区别父子进程?

    • 前情提要:
    • 父子进程共用一段代码,这段代码在父子进程中各执行一次;
    • 业务需求:
    • 在共用代码中,让某段代码仅在子进程中执行
    java
        if(pid == 0){//子进程域
             //子进程执行逻辑
         }
    Copy
    

    SystemServer 进程的执行时机:

    • 基本环境:
    • 上文中我们知道了SystemServer 进程是Zygote 进程通过forkSystemServer 调用fork() 函数后创建出来的。那么SystemServer 进程具体执行时,应当调用SystemServer.main();
    • 调用时机:通过下列代码调用至forkSystemServer
    • 执行条件:if(pid == 0)
    • 在SystemServer进程中
    java
      //forkSystemServer 
       return handleSystemServerProcess(parsedArags);
    

    Copy

    源码阅读细节:有个方法是搜不到的

    • 问题描述:
    • 在forkSystemServer 类中想查看nativeForkSystemServer() 的执行细节。
    • 正常情况下,对于系统层函数在AndroidRuntime.cpp 中直接搜方法名就可以搜到具体的函数。但是,这对于nativeForkSystemServer() 是不行的。
    • 解决手段:在AndroidRuntime.cpp搜com_android_internal_os_Zygote
    • 找到这句代码并点击进入
        extern int register_com_android_internal_os_Zygote(JNIEnv *env);
    Copy
    
    • 在这个函数返回值处,进入gMethods[];native 函数都在这里。
    • 为什么会出现这种问题?
    • 这是JNI 层代码的命名规范,但是这个函数在当初代码编写的时候,违背了主流规范才导致我们直接搜是搜不到的。
    • JNI 层代码的命名规范:包名 具体的函数名

    SystemServer 进程的执行过程:

    • 前情提要:
    • 业务需求:需要启动SystemServer.main()
    • 代码入口:进入SystemServer 进程
        java
        if(pid == 0){//此时在SystemServer 进程中
             …………
             return handleSystemServerProcess(parsedArgs);    
         }
    Copy
    
    • handleSystemServerProcess() 通过反射启动SystemServer.main()
    • 源码依据:
    • 先是拿到了ClassLoader,接着调用了ZygoteInit.zygoteInit();

    zygoteInit() 干了什么?

    • 启动Binder 线程池:
    • ZygoteInit.nativeZygoteInit();
    • 运行SystemServer.main()
    • RuntimeInit.applicationInit();

    Binder 线程池是如何启动的?

    • 前情提要:
    • 源码入口:nativeZygoteInit()
    • 对应的JNI 层代码
    java
        com_android_internal_os_ZygoteInit_nativeZygoteInit()
    Copy
    
    • 重要代码解析:
    • 代码展示:
    java
         gCurRuntime->onZygoteInit();
    Copy
    
    • gCurRuntime 是什么?
    • 指AppRuntime,且AppRuntime 继承自AndroidRuntime;
    • 因为SystemServer 是Zygote 的子进程;
    • 由于代码共享,所以Zygote 有AndroidRuntime,那SystemServer 也有;并且,在Zygote 初始化的时候,会将AndroidRuntime 一同初始化。SystemServer 相当于继承了AndroidRuntime,因此具备安卓运行时环境;
    • onZygoteInit():在这里就启动了Binder 线程池
    • 代码展示:app_main.cpp
    java
         virtual void onZygoteInit()
         {
             sp<ProcessState> proc = ProcessState::self();
             ALOGV("App process: Starting thread poll.\n");
             proc->startThreadPool();
         }
    Copy
    
    • 经验总结:每个进程都是有Binder 机制的,因为SystemServer 进程执行时会开启Binder 线程池。

    SystemServer.main() 执行过程

    • 一句话描述:通过反射执行,在封装类中调用。
    • 前情提要:
    • 源码入口:RuntimeInit.applicationInit();
    • 核心代码:findStaticMain();
    • 通过反射执行SystemServer.main()
    • 拿到类:classname 就是SystemServer
    java
        cl = Class.forName(classname,true,classLoader);
    Copy
    
    • 拿到方法:SystemServer.main()
    m = cl.getMethod("main", new Class[] { String[].class });
    Copy
    
    • 先进行封装:
    return new MethodAndArgsCaller(m, argv);
    
    
    Copy
    
    • 在封装类中,调用代码:
    java
        static class MethodAndArgsCaller implements Runnable {//开启子线程执行
             public void run() {
                 try {
                     // 通过反射真正执行 SystemServer.main() 
                     mMethod.invoke(null, new Object[] { mArgs });
                 }
             }
    
    
    Copy
    
    • 这个run() 是什么时候执行的?
    • ZygoteInit.java中main执行的,forkSystemServer之后会返回一个r;这个r 就是MethodAndArgsCaller 这个封装类;
    • 代码展示:
    java
        if(startSystemServer){
             Runnable r = forkSystemServer(xxxxx);
             if(r != null){//如果是Zygote 进程,r 才为空;
                 r.run();
                 return;
             }
         }
    
    
    Copy
    

    SystemServer().run() 干了什么?

    • 一句话描述:SystemServer 通过标记,完成不同阶段的任务。总体来说,干了三件事。创建系统上下文,创建服务管理者,创建三类服务
    • 设置标记方法:
        mSystemServiceManager.startBootPhase(t, SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
    
    
    Copy
    
    • 业务流程图:


    • 前情提要:
    • 此时,我们分析的是SystemServer 进程的main() 方法;但,实际上调用的是SystemServer().run();
        public static void main(String[] args) {//SystemServer.main()
                 new SystemServer().run();
             }
    
    
    Copy
    
    • 创建系统上下文:
      createSystemContext();
    

    Copy

    • 创建系统服务管理者:
      mSystemServiceManager = new SystemServiceManager(mSystemContext);
    

    Copy

    • 创建三类服务:
    • 引导服务:AMS
        //引导服务:AMS
         startBootstrapServices(t);
    
    
    Copy
    
    • 核心服务:
        //核心服务:系统所需要的
         startCoreServices(t);
    
    
    Copy
    
    • 其他服务:WMS
        //其他服务:WMS等
         startOtherServices(t);
    

    文末

    AMS的主要作用:

    • 统一调度Activity
    • (1)AMS中的重要数据类:
    • (2)重要变量
    • (3)启动Activity
    • 内存管理
    • (1)关闭而不退出
    • (2)内存不够用时,Activity按优先级县回收后台的Activity,或使用OOM进程回收内存
    • 进程管理

    相关文章

      网友评论

        本文标题:拒绝摆烂,Android AMS应该打卡学习的n件事

        本文链接:https://www.haomeiwen.com/subject/oeglrdtx.html