Android跨進(jìn)程通信-socket

Socket的使用和原理

socket套接字本來(lái)是設(shè)計(jì)給基于TCP/IP協(xié)議的網(wǎng)絡(luò)通信使用的,但由于它是一種C/S架構(gòu)模型,即客戶(hù)端服務(wù)器端架構(gòu),這種模型能帶來(lái)很大的安全性以及快速的響應(yīng)能力,所以也常常用在進(jìn)程之間的通信上。

Socket的使用方式比上面前面提到的其他IPC都要復(fù)雜很多,我們先通過(guò)下圖了解它的使用流程。

236c1533b78642b5bf5e3d6c5959b12e_tplv-k3u1fbpfcp-zoom-1.png

我們?cè)诳纯淳唧w的函數(shù)

#include <sys/socket.h>
#include <unistd.h>
#include <unistd.h>
int socket(int protofamily, int type, int protocol);//創(chuàng)建socket
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);//綁定socket
int listen(int sockfd, int backlog);//監(jiān)聽(tīng)端口號(hào)
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);//客戶(hù)端請(qǐng)求建立連接
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);//服務(wù)端接收連接請(qǐng)求
ssize_t send(int sockfd, const void *buf, size_t len, int flags); //IO寫(xiě)函數(shù)
ssize_t recv(int sockfd, void *buf, size_t len, int flags);//IO讀函數(shù)
int close(int fd); //關(guān)閉函數(shù)

Linux系統(tǒng)中萬(wàn)物皆文件,所以Socket也是一個(gè)虛擬文件,socket文件的數(shù)據(jù)結(jié)構(gòu)中包含了當(dāng)前主機(jī)的ip地址,當(dāng)前主機(jī)進(jìn)程的端口號(hào),發(fā)送端主機(jī)的ip地址等信息,通過(guò)這些信息,我們可以在虛擬文件系統(tǒng)中唯一定位到一個(gè)Socket文件,通過(guò)對(duì)這個(gè)文件的讀寫(xiě)達(dá)到通信的目的。

Socket在Android系統(tǒng)中的使用場(chǎng)景

當(dāng)我們使用socket來(lái)進(jìn)行進(jìn)程間的通信時(shí),實(shí)際是通過(guò)將IP設(shè)置為127.0.0.1這個(gè)本地IP來(lái)實(shí)現(xiàn)的,Android系統(tǒng)為我們提供了LocalSocket來(lái)進(jìn)行進(jìn)程間的通信,LocalSocket的實(shí)質(zhì)也是對(duì)Socket的封裝,通過(guò)直接使用LocalSocket,我們省掉了設(shè)置本機(jī)IP等一系列繁瑣的操作。

我們看一個(gè)LocalSocket的使用場(chǎng)景:當(dāng)我們啟動(dòng)一個(gè)App應(yīng)用時(shí),如果當(dāng)前的應(yīng)用的進(jìn)程不存在,AMS會(huì)通過(guò)Socket通知Zygote去Fork新進(jìn)程。

//文件-->frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
// 服務(wù)端
public static void main(String argv[]) {
    ZygoteServer zygoteServer = new ZygoteServer();
    ……
    zygoteServer.registerServerSocket(socketName);
    ……
    Log.i(TAG, "Accepting command socket connections");
    zygoteServer.runSelectLoop(abiList);
    zygoteServer.closeServerSocket();
    ……
}

ZygoteInit啟動(dòng)時(shí),會(huì)創(chuàng)建一個(gè)ZygoteServer,然后fork生成System Server進(jìn)程,接著啟動(dòng)整個(gè)Framwork的Server,最終執(zhí)行zygoteServer的runSelectLoop函數(shù),始終等待其他進(jìn)程發(fā)送過(guò)來(lái)的fork進(jìn)程的消息。

我們接著看registerServerSocket函數(shù)和runSelectLoop函數(shù)的實(shí)現(xiàn)

//文件-->/frameworks/base/core/java/com/android/internal/os/ZygoteServer.java
void registerServerSocket(String socketName) {
    if (mServerSocket == null) {
        int fileDesc;
        final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
        try {
            String env = System.getenv(fullSocketName);
            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);
        } catch (IOException ex) {
            throw new RuntimeException(
                    "Error binding to local socket '" + fileDesc + "'", ex);
        }
    }
}
?
void runSelectLoop(String abiList) throws Zygote.MethodAndArgsCaller {
    ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
    ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
?
    fds.add(mServerSocket.getFileDescriptor());
    peers.add(null);
?
    while (true) {
        StructPollfd[] pollFds = new StructPollfd[fds.size()];
        for (int i = 0; i < pollFds.length; ++i) {
            pollFds[i] = new StructPollfd();
            pollFds[i].fd = fds.get(i);
            pollFds[i].events = (short) POLLIN;
        }
        try {
            Os.poll(pollFds, -1);
        } catch (ErrnoException ex) {
            throw new RuntimeException("poll failed", ex);
        }
        for (int i = pollFds.length - 1; i >= 0; --i) {
            if ((pollFds[i].revents & POLLIN) == 0) {
                continue;
            }
            if (i == 0) {
                ZygoteConnection newPeer = acceptCommandPeer(abiList);
                peers.add(newPeer);
                fds.add(newPeer.getFileDesciptor());
            } else {
                boolean done = peers.get(i).runOnce(this);
                if (done) {
                    peers.remove(i);
                    fds.remove(i);
                }
            }
        }
    }
}

可以看到registerServerSocket函數(shù)實(shí)際是創(chuàng)建了LocalServerSocket,這個(gè)LocalServerSocket的名字就叫“zygote”,runSelectLoop函數(shù)將ServerSocket加入多路復(fù)用模型里,當(dāng)收到消息時(shí)便調(diào)用runOnce方法去fork進(jìn)程。

//文件-->/frameworks/base/core/java/android/os/Process.java 
//客戶(hù)端  
public static final ProcessStartResult start(final String processClass,
                                  final String niceName,
                                  int uid, int gid, int[] gids,
                                  int debugFlags, int mountExternal,
                                  int targetSdkVersion,
                                  String seInfo,
                                  String abi,
                                  String instructionSet,
                                  String appDataDir,
                                  String invokeWith,
                                  String[] zygoteArgs) {
        return zygoteProcess.start(processClass, niceName, uid, gid, gids,
                    debugFlags, mountExternal, targetSdkVersion, seInfo,
                    abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
    }
?
//文件-->/frameworks/base/core/java/android/os/ZygoteProcess.jav
public final Process.ProcessStartResult start(final String processClass,
                                          final String niceName,
                                          int uid, int gid, int[] gids,
                                          int debugFlags, int mountExternal,
                                          int targetSdkVersion,
                                          String seInfo,
                                          String abi,
                                          String instructionSet,
                                          String appDataDir,
                                          String invokeWith,
                                          String[] zygoteArgs) {
  try {
      return startViaZygote(processClass, niceName, uid, gid, gids,
              debugFlags, mountExternal, targetSdkVersion, seInfo,
              abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
  } catch (ZygoteStartFailedEx ex) {
      Log.e(LOG_TAG,
              "Starting VM process through Zygote failed");
      throw new RuntimeException(
              "Starting VM process through Zygote failed", ex);
  }
}
?
private Process.ProcessStartResult startViaZygote(final String processClass,
                                              final String niceName,
                                              final int uid, final int gid,
                                              final int[] gids,
                                              int debugFlags, int mountExternal,
                                              int targetSdkVersion,
                                              String seInfo,
                                              String abi,
                                              String instructionSet,
                                              String appDataDir,
                                              String invokeWith,
                                              String[] extraArgs)
                                              throws ZygoteStartFailedEx {
……
synchronized(mLock) {
    //連接服務(wù)端socket,并發(fā)送數(shù)據(jù)
    return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
}
}
?
private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
  if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
      try {
          primaryZygoteState = ZygoteState.connect(mSocket);
      } catch (IOException ioe) {
          throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
      }
  }
  ……
}
?
public static ZygoteState connect(String socketAddress) throws IOException {
    DataInputStream zygoteInputStream = null;
    BufferedWriter zygoteWriter = null;
    final LocalSocket zygoteSocket = new LocalSocket();
    zygoteSocket.connect(new LocalSocketAddress(socketAddress,
            LocalSocketAddress.Namespace.RESERVED));
?
    zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream());
?
    zygoteWriter = new BufferedWriter(new OutputStreamWriter(
            zygoteSocket.getOutputStream()), 256);
?
    return new ZygoteState(zygoteSocket, zygoteInputStream, zygoteWriter,
            Arrays.asList(abiListString.split(",")));
}
?
private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
    ZygoteState zygoteState, ArrayList<String> args)
    throws ZygoteStartFailedEx {
      int sz = args.size();
      for (int i = 0; i < sz; i++) {
          if (args.get(i).indexOf('\n') >= 0) {
              throw new ZygoteStartFailedEx("embedded newlines not allowed");
          }
      }
      final BufferedWriter writer = zygoteState.writer;
      final DataInputStream inputStream = zygoteState.inputStream;
?
      writer.write(Integer.toString(args.size()));
      writer.newLine();
?
      for (int i = 0; i < sz; i++) {
          String arg = args.get(i);
          writer.write(arg);
          writer.newLine();
      }
?
      writer.flush();
      Process.ProcessStartResult result = new Process.ProcessStartResult();
      result.pid = inputStream.readInt();
      result.usingWrapper = inputStream.readBoolean();
?
      if (result.pid < 0) {
          throw new ZygoteStartFailedEx("fork() failed");
      }
      return result;
}

從上面的代碼實(shí)現(xiàn)可以看到,當(dāng)AMS調(diào)用Process的start()函數(shù)時(shí),最終執(zhí)行到了ZygoteProcess類(lèi)中的openZygoteSocketIfNeeded() 函數(shù),連接socket,然后調(diào)用zygoteSendArgsAndGetResult() 函數(shù)通過(guò)LocalSocket 往LocalServerSocket發(fā)送消息 。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容