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

Android Framework 里面用到了哪些 IPC 方式?
  1. 是否了解 Linux 常用的跨进程通信方式
  2. 是否研究过 Android Framework 并了解一些实现原理
  3. 是否了解 Framework 各组件之间的通信原理

Linux IPC 方式

  1. 管道
  2. Socket
  3. 共享内存
  4. 信号
管道
  1. 半双工,单向的
  2. 一般是在父子进程之间使用

管道使用起来还是很方便的,主要是可以和 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 通信
  1. 全双工的,可读可写
  2. 两个进程之间无需存在亲缘关系
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();
            }
        }
    }
}
共享内存
  1. 很快,不需要多次拷贝
  2. 进程之间无需存在亲缘关系
  3. 传输大数据

涉及进程之间大数据量传输主要就是图像相关的了:

// 匿名共享内存
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;
}
信号
  1. 单向的,发出去之后怎么处理是别人的事
  2. 只能带个信号,不能带别的参数
  3. 知道进程 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);
}