Android App进程创建过程分析

本文深入分析Android App进程的创建过程,重点探讨Zygote Socket的创建、服务端与客户端的交互,以及App进程如何由Zygote进程孵化。详细梳理了从system_server发送创建请求,到Zygote响应并使用fork()创建新进程的完整流程。
摘要由CSDN通过智能技术生成

在分析Activity启动的文章《Android Activity启动过程分析》中,我们遗留了一个小尾巴——App冷启动的情况下,当时没有讲解进程创建的过程,现在我们就把这个尾巴接上,一起看看Android中App进程创建的过程(本文分析过程是基于Android Q源码)。

 先给结论:在Android系统中创建App进程是由zygote进程负责创建的;在一个App种冷启动另一个App时,首先会经过system_server进程种的ActivityManagerSrevice生成创建进程的请求,创建进程的请求由system_server进程发给zygote进程的;system_server和zygote进程之间是通过socket(UNIX Domain Socket)进行通信的。

在这里插入图片描述

在了解上面逻辑后,我们先看下看下zygote socket是如何创建的。

Zygote Socket创建

  zyoget socket创建是在解析init.zygote32.rc(也可能是init.zygote64.rc、init.zygote32_64.rc等文件)后创建的,我们看下这个文件的内容:

//文件位置:system/core/rootdir/init.zygote32.rc
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
    class main
    priority -20
    user root
    group root readproc reserved_disk
    socket zygote stream 660 root system
    socket usap_pool_primary stream 660 root system
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
    onrestart restart audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart netd
    onrestart restart wificond
    writepid /dev/cpuset/foreground/tasks

关于init.zygote32.rc文件的解析可参考《Android系统启动之Zygote》,这里就不再重复了。socket zygote stream 660 root systemsocket usap_pool_primary stream 660 root system 这两个命令被解析后会创建两个本地socket,分别对应Android设备的/dev/socket/zygote/dev/socket/usap_pool_primary两个节点。Socket创建和绑定过程如下:
在这里插入图片描述

//system/init/descriptors.cpp
void DescriptorInfo::CreateAndPublish(const std::string& globalContext) const {
  // Create
  const std::string& contextStr = context_.empty() ? globalContext : context_;
  //创建Socket并返回文件描述符,Create()函数会调用system/init/util.cpp中的CreateSocket()函数
  int fd = Create(contextStr);
  if (fd < 0) return;
  std::string publishedName = key() + name_;
  LOG(INFO) << "CreateAndPublish publishedName: " << publishedName << "";
  std::for_each(publishedName.begin(), publishedName.end(),
                [] (char& c) { c = isalnum(c) ? c : '_'; });

  std::string val = std::to_string(fd);
  //将文件描述符保存在环境变量中。
  setenv(publishedName.c_str(), val.c_str(), 1);

  // make sure we don't close on exec
  fcntl(fd, F_SETFD, 0);
}

DescriptorInfo::CreateAndPublish()函数主要作用是创建socket和将socket节点的文件描述符存入环境变量中。我们看下CreateSocket()函数

//system/init/util.cpp
/*
 * 在/dev/socket目录下创建unix domain socket
 */
int CreateSocket(const char* name, int type, bool passcred, mode_t perm, uid_t uid, gid_t gid,
                 const char* socketcon) {
    if (socketcon) {
        if (setsockcreatecon(socketcon) == -1) {
            PLOG(ERROR) << "setsockcreatecon(\"" << socketcon << "\") failed";
            return -1;
        }
    }
    //创建socket
    android::base::unique_fd fd(socket(PF_UNIX, type, 0));
    if (fd < 0) {
        PLOG(ERROR) << "Failed to open socket '" << name << "'";
        return -1;
    }

    if (socketcon) setsockcreatecon(NULL);

    struct sockaddr_un addr;
    memset(&addr, 0 , sizeof(addr));
    addr.sun_family = AF_UNIX;
    snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s",
             name);

    if ((unlink(addr.sun_path) != 0) && (errno != ENOENT)) {
        PLOG(ERROR) << "Failed to unlink old socket '" << name << "'";
        return -1;
    }

    std::string secontext;
    if (SelabelLookupFileContext(addr.sun_path, S_IFSOCK, &secontext) && !secontext.empty()) {
        setfscreatecon(secontext.c_str());
    }

    if (passcred) {
        int on = 1;
        if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on))) {
            PLOG(ERROR) << "Failed to set SO_PASSCRED '" << name << "'";
            return -1;
        }
    }
    //绑定socket,为socket分配地址
    int ret = bind(fd, (struct sockaddr *) &addr, sizeof (addr));
    int savederrno = errno;

    if (!secontext.empty()) {
        setfscreatecon(nullptr);
    }

    if (ret) {
        errno = savederrno;
        PLOG(ERROR) << "Failed to bind socket '" << name << "'";
        goto out_unlink;
    }

    if (lchown(addr.sun_path, uid, gid)) {
        PLOG(ERROR) << "Failed to lchown socket '" << addr.sun_path << "'";
        goto out_unlink;
    }
    if (fchmodat(AT_FDCWD, addr.sun_path, perm, AT_SYMLINK_NOFOLLOW)) {
        PLOG(ERROR) << "Failed to fchmodat socket '" << addr.sun_path << "'";
        goto out_unlink;
    }

    LOG(INFO) << "Created socket '" << addr.sun_path << "'"
              << ", mode " << std::oct << perm << std::dec
              << ", user " << uid
              << ", group " << gid;

    return fd.release();

out_unlink:
    unlink(addr.sun_path);
    return -1;
}

CreateSocket()函数实现了创建socket节点并为其分配地址;至此Zygote socket就创建完成了。

Zygote Socket 服务端

 在知道zygote socket是怎么创建后,我们看下zygote socket的服务端是怎么创建并监听的。

在这里插入图片描述

socket服务端是在ZygoteInit.main()方法中创建并初始化的,整个流程可参考上面的时序图;整个过程分为两步:一、创建LocalServerSocket,并监听/dev/socket/zygote节点;二、进入一个死循环,等待客户端发送数据。我们先看下创建LocalServerSocket的过程:

//ZygoteServer.java
ZygoteServer(boolean isPrimaryZygote) {
   
    mUsapPoolEventFD = Zygote.getUsapPoolEventFD();
    //isPrimaryZygote是在ZygoteInit.main()方法中传入的,
    //如果没有init.zygote32.rc中没有通过`--socket-name=`指定socket名字,则该值为true.
    if (isPrimaryZygote) {
   
        mZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.PRIMARY_SOCKET_NAME);
        mUsapPoolSocket =
                Zygote.createManagedSocketFromInitSocket(
                        Zygote.USAP_POOL_PRIMARY_SOCKET_NAME);
    } else {
   
        mZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.SECONDARY_SOCKET_NAME);
        mUsapPoolSocket =
                Zygote.createManagedSocketFromInitSocket(
                        Zygote.USAP_POOL_SECONDARY_SOCKET_NAME);
    }

    fetchUsapPoolPolicyProps();

    mUsapPoolSupported = true;
}

在ZygoteServer构造方法中主要是初始化mZygoteSocket、mUsapPoolSocket;我们看下createManagedSocketFromInitSocket()方法的实现

//Zygote.java
static LocalServerSocket createManagedSocketFromInitSocket(String socketName) {
   
    int fileDesc;
    final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;

    try {
   
        //从系统环境变量中获取socket的文件描述符,该描述符是在创建socket节点后写入了系统环境变量中;
        String env = System.getenv(fullSocketName);
        fileDesc = Integer.parseInt(env);
    } catch (RuntimeException ex) {
   
        throw new RuntimeException("Socket unset or invalid: " + fullSocketName, ex);
    }

    try {
   
        FileDescriptor fd = new FileDescriptor();
        fd.setInt$(fileDesc);
        //创建LocalServerSocket对象,并返回该对象
        return new LocalServerSocket(fd);
    } catch (IOException ex) {
   
        throw new RuntimeException(
            "Error building socket from file descriptor: " + fileDesc, ex);
    }
}

注释中已经做了说明,我们继续看LocalServerSocket构造方法

//LocalServerSocket.java
public LocalServerSocket(FileDescriptor fd) throws IOException
{
      //创建LocalSocketImpl对象,LocalSocketImpl为Socekt功能实现类;
    impl = new LocalSocketImpl(fd);
    //监听`/dev/socket/zygote`
    impl.listen(LISTEN_BACKLOG);
    localAddress = impl.getSockAddress();
}

上面就是服务端LocalServerSocket创建并监听/dev/socket/zygote的过程,现在我们看下等待客户端连接和处理客户端命令的实现,这个实现是在ZygoteServer.runSelectLoop()方法中。

//ZygoteServer.java
Runnable runSelectLoop(String abiList) {
   
    ArrayList<FileDescriptor> socketFDs = new ArrayList<FileDescriptor>();
    ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();

    socketFDs.add(mZygoteSocket.getFileDescriptor());
    peers.add(null);

    while (true) {
   
        fetchUsapPoolPolicyPropsWithMinInterval();

        int[] usapPipeFDs = null;
        StructPollfd[] pollFDs = null;

        if (mUsapPoolEnabled) {
   
            usapPipeFDs = Zygote.getUsapPipeFDs();
            pollFDs = new StructPollfd[socketFDs.size() + 1 + usapPipeFDs.length];
        } else {
   
            pollFDs = new StructPollfd[socketFDs.size()];
        }

        int pollIndex = 0;
        for (FileDescriptor socketFD : socketFDs) {
   
            pollFDs[pollIndex] = new StructPollfd();
            pollFDs[pollIndex].fd = socketFD;
            pollFDs[pollIndex].events = (short) POLLIN;
            ++pollIndex;
        }
        //省略部分代码.....

        try {
   
            //阻塞等待文件描述符上的POLLIN事件发生,最终是通过linux系统函数poll实现;
            Os.poll(pollFDs, -1);
        } catch (ErrnoException ex) {
   
            throw new RuntimeException("poll failed", ex);
        }

        boolean usapPoolFDRead = false;

        while (--pollIndex >= 0) {
   
            if ((pollFDs[pollIndex].revents & POLLIN) == 0) {
   
                continue;
            }

            if (pollIndex == 0) {
   
                // 和客户端建立连接
                ZygoteConnection newPeer = acceptCommandPeer(abiList);
                peers.add(newPeer);
                socketFDs.add(newPeer.getFileDescriptor());

            } else if (pollIndex < usapPoolEventFDIndex) {
   

                try {
   
                    ZygoteConnection connection = peers.get(pollIndex);
                    // 处理客户端发送过来的命令
                    final Runnable command = connection.processOneCommand(this);
                    // 如果创建了子进程,mIsForkChild为true,然后返回command命令
                    if (mIsForkChild) {
   

                        if (command == null) {
   
                            throw new IllegalStateException("command == null");
                        }

                        return command;
                    } else {
   

                        if (command != null) {
   
                            throw new IllegalStateException("command != null");
                        }

                        if (connection.isClosedByPeer()) {
   
                            connection.closeSocket();
                            peers.remove(pollIndex);
                            socketFDs.remove(pollIndex);
                        }
                    }
                } catch (Exception e
  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值