You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3.9 KiB
3.9 KiB
Android Framework 里面用到了哪些 IPC 方式?
- 是否了解 Linux 常用的跨进程通信方式
- 是否研究过 Android Framework 并了解一些实现原理
- 是否了解 Framework 各组件之间的通信原理
Linux IPC 方式
- 管道
- Socket
- 共享内存
- 信号
管道
- 半双工,单向的
- 一般是在父子进程之间使用
管道使用起来还是很方便的,主要是可以和 epoll 相结合监听读写事件。
Framework 哪用到了管道?
Looper 里面用到了管道:
Looper::Looper(bool allowNonCallbacks){
int wakeFds[2];
// 创建一个管道(4.4)
int result = pipe(wakeFds);
mWakeReadPipeFd = wakeFds[0];
mWakeWritePipeFd = wakeFds[1];
mEpollFd = epoll_create(EPOLL_SIZE_HINT);
struct epoll_event eventItem;
eventItem.events = EPOLLIN;
eventItem.data.fd = mWakeReadPipeFd;
epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, & eventItem);
}
epoll 是如何监听读端事件的?
int Looper::pollInner(int timeoutMillis){
struct epoll_event eventItems[EPOLL_MAX_EVENTS];
// epoll_wait 阻塞在这
int eventCount = epoll_wait(mEpollFd, eventItems, ...);
for(int i=0;i<eventCount;i++){
int fd = eventItems[i].data.fd;
uint32_t epollEvents = eventItems[i].events;
if(fd == mWakeReadPipeFd){
if(epollEvents&EPOLLIN){
// 把管道里面的东西读出来
awoken();
}
}
}
return result;
}
管道在哪写的呢?
void Looper::wake(){
nWrite = write(mWakeWritePipeFd, "W", 1);
}
Socket 通信
- 全双工的,可读可写
- 两个进程之间无需存在亲缘关系
public static void main(String argv[]){
registerZygoteSocket(socketName);
runSelectLoop(abiList);
}
void runSelectLoop(String abiList){
while(true){
Os.poll(pollFds, -1);
for(int i=pollFds.length-1;i>=0;--i){
if(i==0){
// 处理新过来的连接
}else{
// 处理发过来的数据
peers.get(i).runOnce();
}
}
}
}
共享内存
- 很快,不需要多次拷贝
- 进程之间无需存在亲缘关系
- 传输大数据
涉及进程之间大数据量传输主要就是图像相关的了:
// 匿名共享内存
public MemoryFile(String name, int length){
mLength = length;
// ashmem_create_region(namestr, length);
// 创建一块匿名共享内存,返回一个 fd
mFD = native_open(name, length);
// mmap(NULL, length, prot, MAP_SHARED, fd, 0);
// 给这个 fd 映射到当前进程内存空间
mAddress = native_mmap(mFD, length, PROT_READ|PROT_WRITE);
}
MemoryFile 的读和写:
// 把共享内存的数据读到应用进程的 buffer 里面
jint android_os_MemoryFile_read(JNIEnv* env, jobject clazz, ...){
env->SetByteArrayRegion(buffer, destOffset, count, ...);
return count;
}
// 把应用层的 buffer 拷贝到共享内存里面
jint android_os_MemoryFile_write(JNIEnv* env, jobject clazz, ...){
env->GetByteArrayRegion(buffer, srcOffset, count, ...);
return count;
}
信号
- 单向的,发出去之后怎么处理是别人的事
- 只能带个信号,不能带别的参数
- 知道进程 pid 就能发信号了,也可以一次给一群进程发信号
杀掉应用进程,需要用到信号:
public class Process{
public static final void killProcess(int pid){
sendSignal(pid, SIGNAL_KILL);
}
}
// Zygote 监听的 SIGCHID 信号,Zygote 启动子进程完成之后需要关注子进程挂了没有
// 如果挂了,就需要回收相关资源,避免子进程成为一个僵尸进程
static void SetSigChldHandler(){
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.as_handler = SigChldHandler;
sigaction(SIGCHLD, &sa, NULL);
}