在分析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 system
和socket 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