如何用dw做网站设计,电商货源在哪里找,北关网站制作,宁德市人社局AIDL是Android Interface definition language的缩写,它是一种android内部进程通信接口的描述语言,通过它我们可以定义进程间的通信接口。android提供了很多进程间通信的组件#xff0c;像Activity、BroadcastReceiver和ContentProvider都可以实现进程间的通信。为什么还要用A… AIDL是Android Interface definition language的缩写,它是一种android内部进程通信接口的描述语言,通过它我们可以定义进程间的通信接口。android提供了很多进程间通信的组件像Activity、BroadcastReceiver和ContentProvider都可以实现进程间的通信。为什么还要用AIDL这个东西呢有开发过蓝牙或者WIFI应用的朋友肯定都知道要去操作它必须先获得一个管理类比如WIFI的管理类是WifiManager通过getSystemService(Context.WIFI_SERVICE)就可以得到wifi的管理权限这个服务「Context.WIFI_SERVICE」提供了很多的方法可以让用户去操作WIFI比如打开wifi可以调用setWifiEnabled(true)方法。WifiManager wifiManager (WifiManager)getSystemService(Context.WIFI_SERVICE); WifiManager wifiManager (WifiManager)getSystemService(wifi);
那这个Manager到底做了什么工作呢其实这个Manager只是一个管理类真正干活的另有其人是一个叫WifiService的系统服务。在Android系统中有很多的Managerwifi的管理类叫WifiManager蓝牙的管理类叫BluetoothManager但是只要有xxxManager.java就会有Ixxx.aidl并且有xxxService.java。AIDL的作用是什么aidl类是实现Manager和Service通信的桥梁。我们知道了AIDL的作用如果上面的讲解还不能让你知道AIDL是做什么的我建议你百度会快一些可以认为是中间接口但是中间接口不只是单纯的作为传话筒的作用比如HAL你认为他只是传话筒吗并不是知道有层次概念后对你的学习会帮助巨大当然了如果你是一个架构师知道层次的概念后对你的开发帮助更大。标题说的oneway是代码里的一个变量判断通过这个变量判断来决定binder的调用我转载的这篇文章作者对binder不仅仅是喜爱更是有深入的研究。以下是正文文章通过例子和代码告诉你binder系统是如何判断的各位兄台请笑纳~1 前言用AIDL的人应该都知道下面代码中start和stop方法定义成oneway代表这个Binder接口是异步调用。interface IPlayer {oneway void start();//异步假设执行2秒oneway void stop();//异步假设执行2秒int getVolume();// 同步假设执行1秒
}
1.1 什么是异步调用举个例子假如Client端调用IPlayer.start()而且Server端的start需要执行2秒由于定义的接口是异步的Client端可以快速的执行IPlayer.start()不会被Server端block住2秒。1.2 什么是同步调用举个例子假如Client端调用IPlayer. getVolume()而且Server端的getVolume需要执行1秒由于定义的接口是同步的Client端在执行IPlayer. getVolume()的时候会被Server端block住1秒。1.3 为什么会有同步调用和异步调用细心的读者已经发现了其实一般使用异步调用的时候Client并不需要得到Server端的执行Binder服务的状态或者返回值这时候使用异步调用可以有效的提高Client执行的效率。2 提问好像很多人都明白前面讲的意思我就出几个问题考考大家假设进程A中有如下两个Binder服务IPlayer1和IPlayer2这两个服务都有两个异步的接口start和stop。interface IPlayer1 {oneway void start();//异步执行2秒oneway void stop();//异步执行2秒
}
interface IPlayer2 {oneway void start();//异步执行2秒oneway void stop();//异步执行2秒
}
2.1 问题1如果进程B和进程C同一时刻分别调用IPlayer1.start()和IPlayer2.start()请问进程A能否同时响应这两次Binder调用并执行正确答案可以同时执行。2.2 问题2如果进程B和进程C同一时刻分别调用IPlayer1.start()和IPlayer1.start()请问进程A能否同时响应这两次Binder调用并执行正确答案不能同时执行需要一个一个排队执行。2.3 问题3如果进程B和进程C同一时刻分别调用IPlayer1.start()和IPlayer1.end()请问进程A能否同时响应这两次Binder调用并执行正确答案不能同时执行需要一个一个排队执行。如果回答正确并且知道原因的朋友这个文章就可以不看了。如果回答错误或者蒙对了不清楚原因的朋友请继续阅读文章帮你理解这些问题。3 代码分析话不多说先看源码我们首先来看看oneway的Binder调用在Binder Driver中的逻辑/*** 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_nodestruct binder_node *node t-buffer-target_node;//判断这次Binder调用是不是onewaybool oneway !!(t-flags TF_ONE_WAY);//初始化为false用于标记当前Server端的对应Binder服务是否正在执行oneway的方法bool pending_async false;binder_node_lock(node);//oneway trueif (oneway) {if (node-has_async_transaction) {//第2次oneway调用执行这里//发现对应Binder服务正在执行oneway的方法设置pending_async为truepending_async true;} else {//第1次oneway调用执行这里//发现对应Binder服务没有执行oneway的方法设置has_async_transaction为1node-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为falseif (!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 workbinder_wakeup_thread_ilocked(proc, thread, !oneway /* sync */);binder_inner_proc_unlock(proc);binder_node_unlock(node);return true;
}
对应到我们的三个问题我们首先有这样子的前提进程A中有两个Binder Server端IPlayer1和IPlayer2也就是在Binder驱动中有两个binder node的结构体并且进程A的Binder线程池处于空闲的状态。还有一点要明确的是就算进程B和进程C同时发起Binder调用但是在Binder驱动中还是有先后顺序因为有一把锁binder_inner_proc_lock(proc)。问题1解析因为进程B和进程C分别调用两个Binder服务也就是两个binder node所以进程B和进程C都会走如下的代码也就是说进程A会有两个线程分别处理进程B的IPlayer1.start()和进程C的IPlayer2.start()所以答案是同时执行static bool binder_proc_transaction(struct binder_transaction *t,struct binder_proc *proc,struct binder_thread *thread)
{struct binder_node *node t-buffer-target_node;bool oneway !!(t-flags TF_ONE_WAY);bool pending_async false;binder_node_lock(node);if (oneway) {//不管是是进程B还是进程C因为不是同一个binder_node所以都是走false的逻辑if (node-has_async_transaction) {//不执行} else {node-has_async_transaction 1;}}binder_inner_proc_lock(proc);if (!thread !pending_async)//oneway调用会找到一个空闲的Server端线程用于响应这次oneway调用thread binder_select_thread_ilocked(proc);if (thread) {//oneway调用,thread不为空直接把这次Binder work放到thread的工作队列去执行binder_enqueue_thread_work_ilocked(thread, t-work);} else if (!pending_async) {//不执行} else {//不执行}if (!pending_async)//oneway调用thread不为空所以需要唤醒thread执行工作队列中的Binder workbinder_wakeup_thread_ilocked(proc, thread, !oneway /* sync */);binder_inner_proc_unlock(proc);binder_node_unlock(node);return true;
}
问题2解析我们假设先处理进程B的IPlayer1.start()的调用进程B会执行和问题1中描述的代码一样的操作唤醒进程A中的一个线程处理这次进程B的IPlayer1.start()调用。但是进程C的IPlayer1.start()调用逻辑就不一样了应该是下面这个逻辑也就是说进程A不会立刻处理进程C的IPlayer1.start()的调用。所以答案就是不能同时执行需要一个一个排队执行。static bool binder_proc_transaction(struct binder_transaction *t,struct binder_proc *proc,struct binder_thread *thread)
{struct binder_node *node t-buffer-target_node;bool oneway !!(t-flags TF_ONE_WAY);bool pending_async false;binder_node_lock(node);//oneway trueif (oneway) {if (node-has_async_transaction) {//因为是进程C和进程B是同一个binder_node进程B已经将has_async_transaction设置truepending_async true;} else {//不执行}}binder_inner_proc_lock(proc);if (thread) {//不执行} else if (!pending_async) {//不执行} else {//这次Binder work放到binder_node的async_todo队列中,不会立刻执行binder_enqueue_work_ilocked(t-work, node-async_todo);}binder_inner_proc_unlock(proc);binder_node_unlock(node);return true;
}
那什么时候处理进程C的IPlayer1.start()看下面代码简单说就是会在处理完进程B的IPlayer1.start()之后在释放进程B调用IPlayer1.start()申请的buffer的时候处理进程C的IPlayer1.start()。 case BC_FREE_BUFFER: {//准确释放进程B申请的bufferif (buffer-async_transaction buffer-target_node) {struct binder_node *buf_node;struct binder_work *w;//先拿到这块buffer处理的binder node也就是IPlayer1对应的binder nodebuf_node buffer-target_node;binder_node_inner_lock(buf_node);//检查一下buf_node是否有未处理的oneway的binder workw 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申请的buffertrace_binder_transaction_buffer_release(buffer);binder_transaction_buffer_release(proc, buffer, NULL);binder_alloc_free_buf(proc-alloc, buffer);break;}
问题3解析虽然进程B和进程C同一时刻分别调用IPlayer1.start()和IPlayer1.end()两个不同的方法但是两个进程调用的Server端都是IPlayer1也就是binder node是同一个所以答案和问题2一样。4 思考一个问题假如一个进程B在短时间内例如一秒内调用1000次进程A的IPlayer1.start()会发生什么。第1次IPlayer1.start()唤醒进程A的一个线程处理IPlayer1.start()两秒之后完成第2-1000次IPlayer1.start()发现IPlayer1对应的binder node正在处理一个oneway的方法会把所有2~1000次的调用放到binder node的async_todo队列中等第一次IPlayer1.start()执行完成之后释放buffer的时候才能去统一处理这些async_todo中保存的第2-1000次。那么问题就来了虽然第2-1000次的调用不会立刻执行但是已经在进程A中申请了所有的2~1000次IPlayer1.start()所需要的buffer一个zygote进程A最大oneway请求的buffer上限为(1MB -8KB)/2 508KB不懂的可以看[007]一次Binder通信最大可以传输多大的数据这个博客假设一次IPlayer1.start()需要申请1KB的buffer也就意味这在第509次IPlayer1.start()的时候无法申请到buffer从而导致IPlayer1.start()的Binder调用失败。在[011]一个看似是系统问题的应用问题的解决过程中解决的就是这个问题。5 小结Binder机制是一个非常牛逼的机制里面有很多小的细节值得我们去深挖只有完全理解Binder驱动才能从微观的角度去解决宏观的问题。点击阅读原文在PC端获得更好的阅读体验