registerServerSocket

本文主要讲解 zygoteServer.registerServerSocket(socketName)是如何利用socket 通信,通信的 /dev/socket/zygote 如何创建
registerServerSocket 在zygote中的位置:

zygote

registerServerSocket 分析:

registerServerSocket-flow

1,socket 基本原理

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;
}

开启两个终端,执行结果:(执行的正式上面的流程)

make_create
# ./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"
register flow

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;
}

你可能感兴趣的:(registerServerSocket)