IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> 应用程序进程启动过程 -> 正文阅读

[移动开发]应用程序进程启动过程

应用程序进程简介

要想启动一个应用程序,首先要保证这个应用程序所需要的应用进程已经启动。AMS 在启动应用程序时会检查这个应用程序需要的应用程序进程是否存在,不存在就会请求 Zygote 进程启动需要的应用程序进程。在应用程序进程创建的过程中除了获取虚拟机实例外,还创建了 Binder 线程池和消息循环,这样运行在进程中的应用程序就可以方便地使用 Binder 进行进程间通信以及处理消息了

应用进程启动过程介绍

应用程序进程创建过程分为两个部分来讲解,分别是 AMS 发送启动应用程序进程请求,以及 Zygote 接收请求并创建应用程序进程

AMS发送启动应用程序进程请求

AMS 会通过调用 startProcessLocked 方法向 Zygote 进程发送请求

frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

  1. statrtProcessLocked

    1. int uid = app.uid: 获取要创建的应用程序进程的用户ID

    2. if(ArrayUtils.isEmpty(permGids)){...}

      ...

      gids[2] = UserHandle.getUserGid(UserHandle.getUserId(uid)): 对用户组ID(gids) 进行创建和赋值

    3. if(entryPoint == null) entryPoint = "android.app.ActivityThread": 这个值是应用程序进程主线程的类名

    4. stratResult = Process.start(entryPoint, app.processName, uid,uid,gids,debugFlags,mountExternal,app.info.targetSdkVersion,seInfo,requiredAbi,instructionSet,app.info.dataDir,invokeWith,entryPointArgs): 启动应用程序进程,将得到的应用程序进程用户ID 和 用户组ID传进去

  2. 在 Process 的 start 方法中只调用了 ZygoteProecess 的 start 方法,其中 ZygoteProcess 类用于保持与 Zygote 进程的通信状态

  3. ZygoteProcess 的 start 方法调用了 startViaZygote 方法

    1. ArrayList<String> argsForZygote = new ArrayList<String>(): 创建字符串列表 argsForZygote, 并将启动应用进程的启动参数保存在 argsForZygote 中,方法的最后会调用 zygoteSendArgsAndGetResult 方法

    2. zygoteSendArgsAndGetResult 方法的第一个参数调用了 openZygoteSocketIfNeeded 方法,而第二个参数是保存应用进程的启动参数的 argsForZygote

  4. zygoteSendArgsAndGetResult 方法的主要作用就是将传入应用进程的启动参数 argsForZygote 写入 ZygoteState 中,ZygoteState 是 ZygoteProcess 的静态内部类,用于表示与 Zygote 进程通信的状态,ZygoteState是由 openZygoteSocketIfNeeded 方法返回的

  5. ZygoteProcess.openZygoteSocketIfNeeded(String abi)

    1. primaryZygoteState = ZygoteState.connect(mSocket): 与 Zygote 进程建立 Socket 连接, 与名称为 ZYGOTE _SOCKET ("zygote")的 Scoket 建立连接

    2. if(primaryZygoteState.matches(abi)){}: 连接 Zygote 主模式返回的 ZygoteState 是否与启动应用程序进程所需要的 ABI 匹配,如果不匹配则会走步骤3

    3. secondaryZygoteState = ZygoteState.connect(mSecondarySocket): 连接 name 为 “zygote_secondary” 的 Socket

    4. if(secindaryZygoteState.matches(abi)){}: 连接 Zygote 辅模式返回的 ZygoteState 是否与应用程序进程所需要的 ABI 匹配,如果不匹配则抛出 ZygoteStartFailedEx 异常

在第二章讲过 Zygote 的启动脚本有四种,如果采用的是 init.zygote32_64.rc 或者init.zygote64_32.rc 则 name 为 “zygote” 的为主模式,name 为 "zygote_secondary“ 的为辅模式

Zygote 接收请求并创建应用程序进程

Socket 连接成功并匹配 ABI 后会返回 ZygoteState 类型对象,在 zygoteSendArgsAndGetResult 方法中,会将应用进程的启动参数 argsForZygote 写入 ZygoteState 中,这样 Zygote 进程就会收到一个创建新的应用程序进程的请求.

根据第2章我们学习 Zygote 启动流程最后会调到 zygoteServer.runSelectLoop(abList) 来等待 AMS

请求创建新的应用进程。

  1. ZygoteServer.runSelectLoop()

    1. ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnetion>()

    2. boolean done = peers.get(i).runOnce(this): 调用 ZygoteConnection的 runOnce 方法来处理请求数据

  2. ZygoteConnection.runOnce()

    1. args = readArgumentList(): 获取应用程序进程的启动参数

    2. parsedArgs = new Arguments(args): 将 readArgumentList 方法返回的字符串数组 args 封装到 Argument 类型的 parseArgs 对象中

    3. pid = Zygote.forkAndSpecialize(...): 通过 fork 当前进程来创建一个子进程,如果 pid 等于 0,则说明当前代码逻辑运行在新创建的子进程中,这时就会调用 handleChildProc 方法来处理应用程序进程

  3. ZygoteConnection.handleChildProc():

    1. handleChildProc 方法中调用了 ZygoteInit 的 zygoteInit 方法,zygtoeInit方法中会使用 ZygoteInit.nativeZygoteInit() 在新创建的应用程序进程中创建 Binder 线程池,并调用 RuntimeInit.applicationInit(targetSdkVersion,argv,classLoader)

    2. applicationInit() 方法中会调用 invokeStaticMain 方法

      1. cl = Class.forName(className, true, classLoader): 通过反射获取 android.app.ActivityThread 类

      2. m = cl.getMethod("main", new Class[]{ String[].class}): 获取 ActivityThread 的 main 方法

      3. throw new Zygote.MethodAndArgsCaller(m, argv): 将获取到的 main 方法传入到 Zygote 中的 MethodAndArgsCaller 类的构造方法中(抛异常的处理会清除所有的设置过程中需要的堆栈帧,并让 ActivityThread 的 main 方法看起来更像是应用程序的入口方法)

    3. ZygoteInit.main()

      当 ZygoteInit.main 方法捕获到 MethodAndArgsCaller 异常时,会调用 MethodAndArgsCaller的 run 方法

    4. MethodAndArgsCaller.run(): (MethodAndArgsCaller 是 Zygote.java 的静态内部类)

      mMethod.invoke(null, new Object[]{mArgs}): mMethod 指的就是 ActivityThread 的 main 方法,调用了 mMethod 的 invoke 方法后,ActivityThread 的 main 方法就会被动态调用,应用程序进程就进入了 ActivityThread 的 main 方法中

      到了这一步应用程序进程就创建完成了并且运行了主线程的管理类 ActivityThread

Binder 线程池启动过程

  1. 上面说过应用进程创建的过程中会启动 Binder 线程池,在 ZygoteInit.zygoteInit() 方法中

    ZygoteInit.nativeZygoteInit(): 在新创建的应用程序进程中创建 Binder 线程池

  2. nativeZygoteInit 是一个 JNI 方法,对应的函数在 AndroidRuntime.cpp 中

    const JNINativeMethod methods[] ={
    ? ?  {"nativeZygoteInit", "()V", (void) com_android_internal_os_ZygoteInit_nativeZygoteInit}
    ?
    }
  3. com_android_internal_os_ZygoteInit_nativeZygoteInit()

    gCurRuntime -> onZygoteInit()'

    gCurRuntime 是 AndroidRuntime 类型的指针,它在 AndroidRuntime 初始化时就创建的;AppRuntime 继承自 AndroidRuntime,AppRuntime 创建时就会调用 AndroidRuntime 的构造函数,gCurRuntime 就会被初始化,它指向的是 AppRuntime

  4. AppRuntime.onZygoteInit()

     proc -> startThreadPool()//启动Binder线程池
  5. ProcessState.startThreadPool()

    if(!mThreadPoolStarted){//确保 Binder 线程池只会被启动一次
     ? ?mThreadPoolStarted = true; 
     ? ?spawnPooledThread(true);//创建线程池中的第一个线程,也就是线程池的主线程
    }

    支持 Binder 通信的进程中都有一个 ProcessState 类,里面有一个 mThreadPoolStarted 变量,用来表示 Binder 线程池是否已经被启动过,默认值为 false

  6. Process.spawnPoolThread()

    if(mThreadPoolStarted){
        String8 name = makeBinderThreadName();
        ALOGV("Spawning new pooled thread, name=%s\n", name.string())
        sp<Thread> t = new PoolThread(isMain);
        t->run(name.string)//1
    }

    Binder 线程为一个 PoolThread,在注释1处调用 PoolThread 的 run 函数来启动一个新的线程

  7. Porcess:PoolThread

    virtual bool threadLoop(){
        IPCThreadState::self() -> joinThreadPool(mIsMain);//1
        return fals;
    }

    PoolThread 类继承了 Thread 类,在注释1处调用 IPCThreadState 的 joinThreadPool 函数,将当前线程注册到 Binder 驱动程序中,这样我们创建的线程就加入了 Binder 线程池中,新创建的应用程序就支持 Binder 进程间通信了,我们只需要创建的当前进程的 Binder 对象,并将它注册到 ServiceManager 中就可以实现 Binder 进程间通信

消息循环创建过程

  1. 在上面讲的 RuntimeInit 的 invokeStaticMain 方法中,会抛出一个 MethodAndArgsCaller 异常,这个异常会被 ZygoteInit 的 main 方法捕获,捕获到 MethodAndArgsCaller 时会执行 caller 的 run 方法

    public void run(){
        mMethod.invoke(null, new Object[]{mArgs})//调用 ActivityThread 的 main 方法
    }
  2. ActivityThread 类用于管理当前应用进程的主线程

    public static void main(String[] args){
     ?  ...
     ? ?//创建
     ? ?Looper.prepareMainLooper();//创建主线程的消息循环Looper
     ? ?ActivityThread thread = new ActivityThread();//创建 ActivityThread
     ? ?thread.attach(false);
     ? ?if(sMatinThreadHandler == null){//判断 Handler 类型的 sMainThreadHandler 是否为 null
     ? ? ? ?sMainThreadHandler = thread.getHandler();//获取 H 类并赋值给 sMainThreadHandler,这个H类继承自 Handler,是 ActivityThread 的内部类,用于处理主线程的消息循环
     ?  }
     ?  ...
     ? ?Looper.loop();//调用 Looper 的 loop 方法,使得 Looper 开始处理消息
    }

    可以看出系统在应用程序进程启动完成后,就会创建一个消息循环,这样运行在应用程序进程中的应用程序可以方便地使用消息处理机制

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-10-13 11:33:29  更:2021-10-13 11:34:31 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 23:30:02-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码