Android 进程间通信之LocalSocket

我们知道在Android上和网络的服务器通信手段有很多种, 通常我们的业务数据承载应用层协议(http等)或传输层协议上(tcp/udp)进行交互。 那么在传输层的Android上的技术接口无非就是socket,socket就是一套接口,可以使用网络,文件或内存来做为媒介进行通信,但是在android中都可以使用namespace来选择使用哪种方式进行通信。

我们都知道,其实在Linux中‘一切皆是文件’,包括socket。ipc socket进行通信的媒介有以下三种:

1.网络端口;

   通过本地环回的虚接口(loopback),使用127.0.0.1作为回环地址,来收发数据。

2.文件系统;

  通过文件来做为收发数据的中转,数据交换的媒介。

3. 内存映射;

  通过在内存中开辟一块空间来做为收发数据的中转,也是通过文件的API接口完成的。

以上三种方式都可以作为在android中的ipc socket进行通信,在android中的localsocket 支持以上的#2和#3,从执行效率上来看,#3的效率要更高。

在android中使用LocalSocket的事例就是应用程序APP进程的创建过程。

当我们使用Context#startActivity启动一个Activity时,是需要先创建APP进程,而APP进程的创建是通过android zygote进程来创建的,那么AMS进程需要和zygote进程进行通信,

通信的媒介就是基于LocalSocketAddress$Namespace#RESERVED(也就是会在/dev/socket目录下创建一个socket文件)。

与zygote进程建立连接的关键方法:Process#openZygoteSocketIfNeeded

private static final String ZYGOTE_SOCKET = "zygote";

private static void openZygoteSocketIfNeeded() 
            throws ZygoteStartFailedEx {
            ...
            try {
                sZygoteSocket = new LocalSocket(); 
                sZygoteSocket.connect(new LocalSocketAddress(ZYGOTE_SOCKET,   //
                        LocalSocketAddress.Namespace.RESERVED));
                ...
                break;
            } catch (IOException ex) {
                ...
            }
    }
LocalSocket可以直接通过new关键字进行创建,调用LocalSocket#connect,需要传递LocalSSocketAddress对象,这个对象需要传递一个名称,这个名称和服务端约定好。

第二参数既是Namespace,是一个enum类型的。连接成功之后,就可以向使用普通的socket对象一样,获取inputstream和outputstream和服务器进行通信,交互数据。

public class LocalSocketAddress
{
    public enum Namespace {
        /** A socket in the Linux abstract namespace */
        ABSTRACT(0),
        /**
         * A socket in the Android reserved namespace in /dev/socket.
         * Only the init process may create a socket here.
         */
        RESERVED(1),
        /**
         * A socket named with a normal filesystem path.
         */
        FILESYSTEM(2);
    }
}

zygote对应的服务端代码如下:

private static final String ANDROID_SOCKET_ENV = "ANDROID_SOCKET_zygote";
/**
     * Registers a server socket for zygote command connections
     *
     * @throws RuntimeException when open fails
     */
    private static void registerZygoteSocket() {
        if (sServerSocket == null) {
            int fileDesc;
            try {
                String env = System.getenv(ANDROID_SOCKET_ENV);
                fileDesc = Integer.parseInt(env);
            } catch (RuntimeException ex) {
                throw new RuntimeException(
                        ANDROID_SOCKET_ENV + " unset or invalid", ex);
            }

            try {
                sServerSocket = new LocalServerSocket(
                        createFileDescriptor(fileDesc));
            } catch (IOException ex) {
                throw new RuntimeException(
                        "Error binding to local socket '" + fileDesc + "'", ex);
            }
        }
    }
static native FileDescriptor createFileDescriptor(int fd) throws IOException;

你可能感兴趣的:(Android,通信,android进程通信,LocalSocket)