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;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章