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