我們知道在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;