从Activity的启动细窥BinderIPC(2)

本文详细剖析了Zygote初始化过程中的关键函数runOnce(),并深入解读了其中涉及的forkAndSpecialize()方法及其在C++层的实现细节。着重介绍了如何通过fork系统调用来创建新进程,以及如何在新进程中设置必要的参数,如UID、GID、资源限制等。此外,还讨论了ActivityManagerService在新进程创建后的角色,以及如何通过调用main()方法启动应用。最后,文章阐述了新进程如何通过调用ActivityThread的main方法进入应用的生命周期,包括Activity的创建和管理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上次的源码分析出现了一个runOnce()函数,实际的孵化过程其实是在runOnce()里面,本文章我们再来看看这个函数的源代码

  boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
  //...
  try {
  //就是这个神奇的函数封装了孵化的过程,成功后就获得新进程的pid了
      pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
              parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
              parsedArgs.niceName);
  } 
  //...
  try {
      //这里就是一些异常的处理,可以直接对异常逃逸到main()函数
      if (pid == 0) {
          // in child
          IoUtils.closeQuietly(serverPipeFd);
          serverPipeFd = null;
          //handleChildProc是一个很重要的函数,在该函数里使用了异常进行逃逸
          handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
          //...  
      } else {
         //... 
      }
  } finally {
       //...
  }
}

至于forkAndSpecialize()方法,它实质上调用的一个本地方法nativeForkAndSpecialize(),这个函数实现用C++实现,可以对内核进行调用,在C++代码中,有个叫Dalvik_dalvik_system_Zygote_forkAndSpecialize()的函数,这个函数再调用forkAndSpecializeCommon()函数,然后就直接调用内核的fork系统调用创建一个新进程了。
还是来看看第一个函数调用的代码
说明:u4是一个指向从java层传过来的参数的指针,已经被dvm转换为运行在虚拟机的c++对象了,垃圾回收以及内存管理都按照dvm舒服的处理方式。
JValue* pResult是c++函数调用的结果。

static void Dalvik_dalvik_system_Zygote_forkAndSpecialize(const u4* args,
    JValue* pResult)
{
    pid_t pid;
    //还是调用这个函数                                                                                                                                     
    pid = forkAndSpecializeCommon(args, false);                                                                                                                         
    RETURN_INT(pid);
}

至于forkAndSpecializeCommon()函数,它的功能主要就是拿到fork的系统调用了,代码在dalvik_system_Zygote.c文件中
看看这个函数的实现代码:

static pid_t forkAndSpecializeCommon(const u4* args, bool isSystemServer)
{
    //uid,gid来自java层的参数parsedArgs.uid, parsedArgs.gid,都是从
    //ActivityManagerService发送过来的请求 
    //java层传过来的参数都会根据在参数列表中顺序保存在u4指向的这个数组
    pid_t pid;
    uid_t uid = (uid_t) args[0];
    gid_t gid = (gid_t) args[1];
    ArrayObject* gids = (ArrayObject *)args[2];
    u4 debugFlags = args[3];
    ArrayObject *rlimits = (ArrayObject *)args[4];
    int64_t permittedCapabilities, effectiveCapabilities;
    if (isSystemServer) {
        /*
         * Don't use GET_ARG_LONG here for now.  gcc is generating code
         * that uses register d8 as a temporary, and that's coming out
         * scrambled in the child process.  b/3138621
         */
        //permittedCapabilities = GET_ARG_LONG(args, 5);
        //effectiveCapabilities = GET_ARG_LONG(args, 7);
        permittedCapabilities = args[5] | (int64_t) args[6] << 32;
        effectiveCapabilities = args[7] | (int64_t) args[8] << 32;
    } else {
        permittedCapabilities = effectiveCapabilities = 0;
    }
   //在进程被创建出来后,gDvm.zygote会设为false,表示不是zygote进程,只有一个原来的版本啊,不能迭代fork
   //当然子进程中为false,在父进程即zygote进程gDvm.zygote还是保持true,还得继续fork给其他的app使用
    if (!gDvm.zygote) {
        ......
        return -1;
    }
    //......这里就进行了fork的系统调用啦
    pid = fork();
    //下面就是一些异常处理
    if (pid == 0) {
        int err;
        err = setgroupsIntarray(gids);
        err = setrlimitsFromArray(rlimits);
        err = setgid(gid);
        err = setuid(uid);
        //......
        err = setCapabilities(permittedCapabilities, effectiveCapabilities);
        //......
        enableDebugFeatures(debugFlags);
        //......
        gDvm.zygote = false;
        if (!dvmInitAfterZygote()) {
            //......
            dvmAbort();
        }
    } else if (pid > 0) {
        /* the parent process */
    }
    //最后返回的是fork进程的pid
    return pid;
}     

好咯,现在app的一个进程已经产生,实质为一个dalvik进程,继续看callstack(就是android的调用栈),可以发现在这个进程上调用了activity Thread的main方法,这是一个native的调用,不要忘了还要告诉ActivityManagerService一声app的进程已经建立,你就不用操心啦。同时ActivityManagerService会保留一个activity的代理对象(proxy),它的本质就是一个智能指针,里面封装了app在dalvik进程实例的内存数据(说到代理,就多说两句,binderIPC机制的server跟client间通信也是通过代理来成事,不过是同时实现manager的一个接口获取IBinder,即binder的一个智能指针,再通过binder封装远程调用的函数的函数参数以及返回值信息,顺便实现onTransact()的回调,kernel层也是通过binder driver通过内核空间的内存共享实现,这就是经典的RPC的套路),ActivityManagerService这下就可以控制我们的app啦,包括我们的task,backstack之类的(这些简单的东西就不多说了),下面就是创造一个activity来进入app咯,也是ActivityManagerService来完成,按activity的生命周期一次执行oncreate(),onStart()等方法,当然中间免不了建立main Thraed,并通过looper.mylooper()方法建立主线程的消息循环,接受消息加载activity的类,构造activity的rootViewGroup等消息。就是在栈中看到的关于looper,handler之类的调用咯,所以主线程就不劳烦我们自己创建looper啦。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值