本文主要讲解 zygoteServer.registerServerSocket(socketName)是如何利用socket 通信,通信的 /dev/socket/zygote 如何创建
registerServerSocket 在zygote中的位置:
registerServerSocket 分析:
1,socket 基本原理
UNIX Domain Socket用于IPC更有效率:
不需要经过网络协议栈,不需要打包拆包、计算校验和、维护序号和应答等,只是将应用层数据从一个进程拷贝到另一个进程socket()创建一个socket文件描述符,address family指定为AF_UNIX(文件方式)或AF_INET:(基于IP端口)type可以选择SOCK_DGRAM或SOCK_STREAM,protocol参数仍然指定为0即可。
tcp_client.c, socket client
#include
#include
#include
#include
#include
#include
int main()
{
/* create a socket */
int sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
struct sockaddr_un address;
address.sun_family = AF_UNIX;
strcpy(address.sun_path, "socket_zygote");
/* connect to the server */
int result = connect(sockfd, (struct sockaddr *)&address, sizeof(address));
if(result == -1)
{
perror("connect failed: ");
exit(1);
}
/* exchange data */
char ch = '0';
printf("send char from socket_client: %c\n", ch);
write(sockfd, &ch, 1);
read(sockfd, &ch, 1);
printf("get char from socket_server: %c\n", ch);
/* close the socket */
close(sockfd);
return 0;
}
tcp_server.c, socket service
#include
#include
#include
#include
#include
#include
int main()
{
/* delete the socket file */
unlink("socket_zygote");
/* create a socket */
int server_sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
struct sockaddr_un server_addr;
server_addr.sun_family = AF_UNIX;
strcpy(server_addr.sun_path, "socket_zygote");
/* bind with the local file */
bind(server_sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
/* listen */
listen(server_sockfd, 100);
char ch;
int client_sockfd;
struct sockaddr_un client_addr;
socklen_t len = sizeof(client_addr);
while(1)
{
printf("zygote waiting:ActivityManagerService client_socket connecting!\n");
/* accept a connection */
client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_addr, &len);
/* exchange data */
read(client_sockfd, &ch, 1);
printf("get char from socket_client: %c\n", ch);
++ch;
write(client_sockfd, &ch, 1);
/* close the socket */
close(client_sockfd);
}
return 0;
}
开启两个终端,执行结果:(执行的正式上面的流程)
# ./tcp_client
send char from socket_client: 0
get char from socket_server: 1
# ./tcp_server
zygote waiting:ActivityManagerService client_socket connecting!
get char from socket_client: 0
zygote waiting:ActivityManagerService client_socket connecting!
对通信过程中的函数进行说明:
int socket(int domain, int type, int protocol)
domain:指定socket所属的域,常用的是AF_UNIX或AF_INET
AF_UNIX表示以文件方式创建socket,AF_INET表示以端口方式创建socket(我们会在后面详细讲解AF_INET)
type:指定socket的类型,可以是SOCK_STREAM或SOCK_DGRAM
SOCK_STREAM表示创建一个有序的,可靠的,面向连接的socket,因此如果我们要使用TCP,就应该指定为SOCK_STREAM
SOCK_DGRAM表示创建一个不可靠的,无连接的socket,因此如果我们要使用UDP,就应该指定为SOCK_DGRAM
protocol:指定socket的协议类型,我们一般指定为0表示由第一第二两个参数自动选择。
socket()函数返回新创建的socket,出错则返回-1
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen)
sockfd=socket函数返回的一个ID
addr=定义的一个struct sockaddr_in结构体的地址需要强制转换
addrlen=addr的sizeof(addr)
struct sockaddr {
sa_family_t sa_family;
char sa_data[14];
}
struct sockaddr_un
{
sa_family_t sun_family; /* AF_UNIX */
char sun_path[]; /* pathname */
}
struct sockaddr_in
{
short int sin_family; /* AF_INET */
unsigned short int sin_port; /* port number */
struct in_addr sin_addr; /* internet address */
}
int listen(int socket, int backlog)
backlog:等待连接的最大个数,如果超过了这个数值,则后续的请求连接将被拒绝
listen()函数正确返回0,出错返回-1
int accept(int socket, struct sockaddr * address, size_t * address_len)
accept()函数成功时返回新创建的socket描述符,出错时返回-1
address是一个传出参数,它保存着接受连接的客户端的地址,如果我们不需要,将address置为NULL即可。
address_len:我们期望的地址结构的长度,注意,这是一个传入和传出参数,传入时指定我们期望的地址结构的长度,如果多于这个值,则会被截断,而当accept()函数返回时,address_len会被设置为客户端连接的地址结构的实际长度。
accept()函数是阻塞式
int connect(int socket, const struct sockaddr * address, size_t address_len)
address参数,我们同样需要强制类型转换, 参考tcp_client
address_len指明了地址结构的长度
connect()函数成功时返回0,出错时返回-1
2,registerServerSocket
本文的第一张图片,就知道是在zygote 启动是由就注册了local socket, 采用的方式AF_UNIX, 在注册过程中 listen fd 是/dev/socket/zygote, 并没有create socket 与bind , 也就是说/dev/socket/zygote 之前就已经创建好了
system/core/init/init.cpp
system/core/init/service.cpp
system/core/init/descriptors.cpp
system/core/init/util.cpp
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
frameworks/base/core/java/com/android/internal/os/ZygoteServer.java
frameworks/base/core/java/com/android/server/LocalServices.java
#define ANDROID_SOCKET_ENV_PREFIX "ANDROID_SOCKET_"
#define ANDROID_SOCKET_DIR "/dev/socket"
2.1 , registerServerSocket 进行listen
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) {
ZygoteServer zygoteServer = new ZygoteServer();
// Mark zygote start. This ensures that thread creation will throw
// an error.
ZygoteHooks.startZygoteNoThreadCreation();
// Zygote goes into its own process group.
try {
Os.setpgid(0, 0);
} catch (ErrnoException ex) {
throw new RuntimeException("Failed to setpgid(0,0)", ex);
}
final Runnable caller;
try {
// Report Zygote start time to tron unless it is a runtime restart
if (!"1".equals(SystemProperties.get("sys.boot_completed"))) {
MetricsLogger.histogram(null, "boot_zygote_init",
(int) SystemClock.elapsedRealtime());
}
String bootTimeTag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing";
TimingsTraceLog bootTimingsTraceLog = new TimingsTraceLog(bootTimeTag,
Trace.TRACE_TAG_DALVIK);
bootTimingsTraceLog.traceBegin("ZygoteInit");
RuntimeInit.enableDdms();
boolean startSystemServer = false;
String socketName = "zygote";
String abiList = null;
boolean enableLazyPreload = false;
for (int i = 1; i < argv.length; i++) {
if ("start-system-server".equals(argv[i])) {
startSystemServer = true;
} else if ("--enable-lazy-preload".equals(argv[i])) {
enableLazyPreload = true;
} else if (argv[i].startsWith(ABI_LIST_ARG)) {
abiList = argv[i].substring(ABI_LIST_ARG.length());
} else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
socketName = argv[i].substring(SOCKET_NAME_ARG.length());
} else {
throw new RuntimeException("Unknown command line argument: " + argv[i]);
}
}
if (abiList == null) {
throw new RuntimeException("No ABI list supplied.");
}
zygoteServer.registerServerSocket(socketName);---->名字是registerServiceSocket ,实际上只有listen, 因为socket 文件的创建与绑定,在zyote 启动之前解析的时候就已经创建了/dev/socket/zygote, 这里仅仅是listen. 不要被名字忽悠了
// In some configurations, we avoid preloading resources and classes eagerly.
// In such cases, we will preload things prior to our first fork.
if (!enableLazyPreload) {
bootTimingsTraceLog.traceBegin("ZygotePreload");
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
preload(bootTimingsTraceLog);
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
bootTimingsTraceLog.traceEnd(); // ZygotePreload
} else {
Zygote.resetNicePriority();
}
.......
frameworks/base/core/java/com/android/internal/os/ZygoteServer.java
registerServerSocket:
/**
* Registers a server socket for zygote command connections
*
* @throws RuntimeException when open fails
*/
void registerServerSocket(String socketName) {
if (mServerSocket == null) {
int fileDesc;
final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
try {
String env = System.getenv(fullSocketName);----->获取在解析rc文件时候创建的ANDROID_SOCKET_zygote 环境变量
fileDesc = Integer.parseInt(env);
} catch (RuntimeException ex) {
throw new RuntimeException(fullSocketName + " unset or invalid", ex);
}
try {
FileDescriptor fd = new FileDescriptor();
fd.setInt$(fileDesc);
mServerSocket = new LocalServerSocket(fd);--》 根据fd 进行了listen --mServerSocket 创建完成
} catch (IOException ex) {
throw new RuntimeException(
"Error binding to local socket '" + fileDesc + "'", ex);
}
}
}
2.2 , 首先看zygote 如何创建/dev/socket/zygote,添加环境变量
system/core/rootdir/init.zygote64.rc:
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
class main
........
socket zygote stream 660 root system
........
system/core/init/init.cpp
static void restart_processes()
{
process_needs_restart_at = 0;
ServiceManager::GetInstance().ForEachServiceWithFlags(SVC_RESTARTING, [](Service* s) {
s->RestartIfNeeded(&process_needs_restart_at);
});
}
system/core/init/service.cpp
RestartIfNeeded---->Start:
bool Service::Start() {
// Starting a service removes it from the disabled or reset state and
// immediately takes it out of the restarting state if it was in there.
flags_ &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START));
// Running processes require no additional work --- if they're in the
// process of exiting, we've ensured that they will immediately restart
// on exit, unless they are ONESHOT.
if (flags_ & SVC_RUNNING) {
return false;
}
bool needs_console = (flags_ & SVC_CONSOLE);
if (needs_console) {
if (console_.empty()) {
console_ = default_console;
}
// Make sure that open call succeeds to ensure a console driver is
// properly registered for the device node
int console_fd = open(console_.c_str(), O_RDWR | O_CLOEXEC);
if (console_fd < 0) {
PLOG(ERROR) << "service '" << name_ << "' couldn't open console '" << console_ << "'";
flags_ |= SVC_DISABLED;
return false;
}
close(console_fd);
}
struct stat sb;
if (stat(args_[0].c_str(), &sb) == -1) {
PLOG(ERROR) << "cannot find '" << args_[0] << "', disabling '" << name_ << "'";
flags_ |= SVC_DISABLED;
return false;
}
std::string scon;
if (!seclabel_.empty()) {
scon = seclabel_;
} else {
scon = ComputeContextFromExecutable(name_, args_[0]);
if (scon == "") {
return false;
}
}
LOG(INFO) << "starting service '" << name_ << "'...";
pid_t pid = -1;
if (namespace_flags_) {
pid = clone(nullptr, nullptr, namespace_flags_ | SIGCHLD, nullptr);
} else {
pid = fork();
}
if (pid == 0) {
umask(077);
if (namespace_flags_ & CLONE_NEWPID) {
// This will fork again to run an init process inside the PID
// namespace.
SetUpPidNamespace(name_);
}
for (const auto& ei : envvars_) {
add_environment(ei.name.c_str(), ei.value.c_str());
}
std::for_each(descriptors_.begin(), descriptors_.end(),
std::bind(&DescriptorInfo::CreateAndPublish, std::placeholders::_1, scon));-----> 开机进行socket 节点的创建
// See if there were "writepid" instructions to write to files under /dev/cpuset/.
auto cpuset_predicate = [](const std::string& path) {
return StartsWith(path, "/dev/cpuset/");
};
auto iter = std::find_if(writepid_files_.begin(), writepid_files_.end(), cpuset_predicate);
if (iter == writepid_files_.end()) {
// There were no "writepid" instructions for cpusets, check if the system default
// cpuset is specified to be used for the process.
std::string default_cpuset = GetProperty("ro.cpuset.default", "");
if (!default_cpuset.empty()) {
// Make sure the cpuset name starts and ends with '/'.
// A single '/' means the 'root' cpuset.
if (default_cpuset.front() != '/') {
default_cpuset.insert(0, 1, '/');
}
if (default_cpuset.back() != '/') {
default_cpuset.push_back('/');
}
writepid_files_.push_back(
StringPrintf("/dev/cpuset%stasks", default_cpuset.c_str()));
}
.......
system/core/init/descriptors.cpp
CreateAndPublish:
void DescriptorInfo::CreateAndPublish(const std::string& globalContext) const {
// Create
const std::string& contextStr = context_.empty() ? globalContext : context_;
int fd = Create(contextStr);----->真正调用creat socket
if (fd < 0) return;
// Publish
std::string publishedName = key() + name_;--->获取到了env name
std::for_each(publishedName.begin(), publishedName.end(),
[] (char& c) { c = isalnum(c) ? c : '_'; });
std::string val = std::to_string(fd);
add_environment(publishedName.c_str(), val.c_str());
// make sure we don't close on exec
fcntl(fd, F_SETFD, 0);
}
const std::string SocketInfo::key() const {
return ANDROID_SOCKET_ENV_PREFIX;
}
system/core/init/util.cpp
SocketInfo::Create-->CreateSocket
/*
* CreateSocket - creates a Unix domain socket in ANDROID_SOCKET_DIR
* ("/dev/socket") as dictated in init.rc. This socket is inherited by the
* daemon. We communicate the file descriptor's value via the environment
* variable ANDROID_SOCKET_ENV_PREFIX ("ANDROID_SOCKET_foo").
*/
int CreateSocket(const char* name, int type, bool passcred, mode_t perm, uid_t uid, gid_t gid,
const char* socketcon, selabel_handle* sehandle) {
if (socketcon) {
if (setsockcreatecon(socketcon) == -1) {
PLOG(ERROR) << "setsockcreatecon(\"" << socketcon << "\") failed";
return -1;
}
}
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;-->/dev/socket/zygote指定文件形式, 非NET 方式
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;
}
char *filecon = NULL;
if (sehandle) {
if (selabel_lookup(sehandle, &filecon, addr.sun_path, S_IFSOCK) == 0) {
setfscreatecon(filecon);
}
}
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;
}
}
int ret = bind(fd, (struct sockaddr *) &addr, sizeof (addr));----->bind 时候创建
int savederrno = errno;
setfscreatecon(NULL);
freecon(filecon);
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();----》实际也是返回的fd 的值(释放了中间资源)
out_unlink:
unlink(addr.sun_path);
return -1;
}