本文最后更新于 879 天前,其中的信息可能已经有所发展或是发生改变。
1. AIDL简单使用
2. in、out、inout的区别
in 表示客户端传入的参数 (如:book), 服务端可以完整接受到改对象,但对其修改不会会同步到 客户端传入的参数对象
out 表示客户端传入的参数 (如:book), 服务端接受到的对象为空对象,并且服务端重新new修改改对象,并不会影响客户端传入的参数对象
inout表示客户端传入的参数 (如:book), 服务端可以完整接受到改对象,并且对其修改会同步到 客户端传入的参数对象
// BookManager.aidl
interface BookManager {
//保证客户端与服务端是连接上的且数据传输正常
List<Book> getBooks();
//通过三种定位tag做对比试验,观察输出的结果
Book addBookIn(in Book book);
Book addBookOut(out Book book);
Book addBookInout(inout Book book);
}
@Override
public Book addBookIn(Book book) throws RemoteException {
synchronized (this) {
// xxx
//这里修改了并不影响客户端book对象,客户端的参数对象book的price属性不会被修改为2333
book.setPrice(2333);
if (!mBooks.contains(book)) {
mBooks.add(book);
}
return book;
}
}
@Override
public Book addBookOut(Book book) throws RemoteException {
synchronized (this) {
// xxx
// 即使客户端传入的book对象不是空对象,这里的book也会是空对象
if(book == null){
Log.e(TAG , "Book is null in Out");
book = new Book();
}
book.setPrice(2333);
if (!mBooks.contains(book)) {
mBooks.add(book);
}
return book;
}
}
@Override
public Book addBookInout(Book book) throws RemoteException {
synchronized (this) {
// xxx
if(book == null){
Log.e(TAG , "Book is null in Inout");
book = new Book();
}
//这里修改了会影响客户端book对象,客户端的参数对象book的price属性也被修改为2333
book.setPrice(2333);
if (!mBooks.contains(book)) {
mBooks.add(book);
}
return book;
}
}
3. oneway
interface IPlayer {
oneway void start();//异步,假设执行2秒 异步不定义返回值,客户端不使用
oneway void stop();//异步,假设执行2秒
int getVolume();// 同步,假设执行1秒
}
interface IPlayer2 {
oneway void start();//异步,假设执行2秒 异步不定义返回值,客户端不使用
oneway void stop();//异步,假设执行2秒
int getVolume();// 同步,假设执行1秒
}
两个进程 不能同时调用 IPlayer.start()和IPlayer.stop(), 需要排队执行
两个进程 能同时调用 IPlayer.start()和IPlayer2.stop(), 需要排队执行异步调用和串行化处理。异步调用是指应用向 binder 驱动发送数据后不需要挂起线程等待 binder 驱动的回复,而是直接结束。像一些系统服务调用应用进程的时候就会使用 oneway,比如 AMS 调用应用进程启动 Activity,这样就算应用进程中做了耗时的任务,也不会阻塞系统服务的运行
串行化处理是指对于一个服务端的 AIDL 接口而言,所有的 oneway 方法不会同时执行,binder 驱动会将他们串行化处理,排队一个一个调用
挂起相当于 Thread 的 sleep,是真正的”休眠”,底层调用的是 wait_event_interruptible() Linux 系统函数。Handler 机制的时候,Handler 中最关键的地方就是 Looper 的阻塞与唤醒,阻塞是调用了 nativePollOnce() 方法
/**
* binder_proc_transaction() - sends a transaction to a process and wakes it up
* @t: transaction to send
* @proc: process to send the transaction to
* @thread: thread in @proc to send the transaction to (may be NULL)
*/
static bool binder_proc_transaction(struct binder_transaction *t,
struct binder_proc *proc,
struct binder_thread *thread)
{
//找到Server端的对应Binder服务在Binder驱动中对应的对象binder_node
struct binder_node *node = t->buffer->target_node;
//判断这次Binder调用是不是oneway
bool oneway = !!(t->flags & TF_ONE_WAY);
//初始化为false,用于标记当前Server端的对应Binder服务是否正在执行oneway的方法
bool pending_async = false;
binder_node_lock(node);
//oneway == true
if (oneway) {
if (node->has_async_transaction) {
//第2次oneway调用执行这里
//发现对应Binder服务正在执行oneway的方法,设置pending_async为true
pending_async = true;
} else {
//第1次oneway调用执行这里
//发现对应Binder服务没有执行oneway的方法,设置has_async_transaction为1
node->has_async_transaction = 1;
}
}
binder_inner_proc_lock(proc);
//如果发现Server端已经死亡,就直接返回了,正常不会执行
if (proc->is_dead || (thread && thread->is_dead)) {
binder_inner_proc_unlock(proc);
binder_node_unlock(node);
return false;
}
//oneway的调用thread为空,第1次oneway调用,pending_async为false
if (!thread && !pending_async)
//第1次oneway调用会找到一个空闲的Server端线程,用于响应这次oneway调用
thread = binder_select_thread_ilocked(proc);
if (thread) {
//第1次oneway调用,thread不为空,直接把这次Binder work放到thread的工作队列去执行
binder_enqueue_thread_work_ilocked(thread, &t->work);
} else if (!pending_async) {
binder_enqueue_work_ilocked(&t->work, &proc->todo);
} else {
//第2次oneway调用,thread为空,pending_async为true,
//这次Binder work放到Binder Node的async_todo队列中,不会立刻执行
binder_enqueue_work_ilocked(&t->work, &node->async_todo);
}
if (!pending_async)
//第1次oneway调用,thread不为空,所以需要唤醒thread执行工作队列中的Binder work
binder_wakeup_thread_ilocked(proc, thread, !oneway /* sync */);
binder_inner_proc_unlock(proc);
binder_node_unlock(node);
return true;
}
释放与唤醒下一个任务
case BC_FREE_BUFFER: {
//准确释放进程B申请的buffer
if (buffer->async_transaction && buffer->target_node) {
struct binder_node *buf_node;
struct binder_work *w;
//先拿到这块buffer处理的binder node,也就是IPlayer1对应的binder node
buf_node = buffer->target_node;
binder_node_inner_lock(buf_node);
//检查一下buf_node是否有未处理的oneway的binder work
w = binder_dequeue_work_head_ilocked(
&buf_node->async_todo);
if (!w) {
//不执行
buf_node->has_async_transaction = 0;
} else {
//如果有未处理完的oneway的binder work,就将binder node保存的async_todo全部添加到进程A的todo。
binder_enqueue_work_ilocked(
w, &proc->todo);
//唤醒一个线程去处理todo中的binder work,也就是进程C的IPlayer1.start()
binder_wakeup_proc_ilocked(proc);
}
binder_node_inner_unlock(buf_node);
}
//释放进程B申请的buffer
trace_binder_transaction_buffer_release(buffer);
binder_transaction_buffer_release(proc, buffer, NULL);
binder_alloc_free_buf(&proc->alloc, buffer);
break;
}