androidbinder机制(androidbinder面试详解简书)
Android Binder原理
以前看源码经常会看到Binder的东西,比如AMS,ActivityThread等,之前虽然对Binder有所了解,但也是模模糊糊的,这次终于下定决心好好的弄一弄它的原理,揭开它头上的那块面纱。
androidbinder机制(androidbinder面试详解简书)
androidbinder机制(androidbinder面试详解简书)
首先,Binder主要是Android 跨进程通信的一种方式,它是一个Android 中的一个类,实现了IBinder接口,主要是用在Serv中。Android 跨进程通信有几种方式,Bundle、AIDL、Messenger、ContentProvider、socket等。而AIDL跟Messenger内部都是用的是Binder机制。下面就来分析一下Binder的工作机制。
首先我们需要建立三个类,一个是实体类User.kt, 继承Percelable接口
以及User.aidl, 里面定义了
parcelable User
IUserMar.aidl 定义了端可调用的接口
inteceIUserMar{
List
void addUser(in User user)
}
然后build 工程,系统会在build路径下自动生成IuserMar.ja文件,我们具体介绍一下里面的方法。
Binder的标识,一般用类名表示
用于将服务端的Binder对象转换成客户端aidl接口类型的对象,如果客户端跟端在同一个进程里面,返回的是端本身,否则返回的是内部定义的Stub.Proxy()对象
该方法运行在端的binder线程池中,通过code可以确定客户端请求的目标方法,然后从data中取出目标方法所需要的参数,然后再执行目标方法,执行完毕后,把结果写入reply中,如果return false,客户端请求会失败,可以用来做一些权限校验。
该方法运行在客户端,首先用android.os.Parcel.obtain()创建两个Parcel 对象 data(输入), reply(输出),如果该方法有参数的话,把参数写入data,
data.writeInt(1)
user.writeToParcel(data,0)
然后调用服务端的transact方法来触发RPC请求,mRemote.transact(),同时当前线程挂起,然后服务端的onTransact方触发,直到RPC过程返回,当前线程继续执行,从reply中获取返回结果。
有两个地方需要注意,首先客户端发起远程请求时,客户端线程会被挂起,所以这个作可能是一个耗时作,不能在UI线程中发起请求。其次,服务端的Binder方法是运行在Binder线程池中,所以Binder方法不管是否耗时,都应该用同步的方式去实现。
另外,在进程间通信的时候,我们的binder有可能会断开,这个时候我们需要设置一个亡。我们定义一个DeathRecipient对象,里面有一个回调方法binderDied(), 当Binder亡的时候该方回调,然后我们可以调用unlinkToDeath()移除之前的,并重新绑定远程serv
binder.linkToDead(mDeathRecipient,0)
还有方法isBinderAlive()也可以判断binder是否亡。
,我们用AIDL中,经常需要做一些权限的校验。具体有两种方法,一种是permission校验,我们可以定义一种permission, 并且在onBind()方法中调用checkCallingOrselfPermission()对permission进行校验,客户端想绑定我们的服务必须在AndroidMenifest.xml文件中加上这个权限。
第二种方法,我们可以在onTransact方法中处理。可以用种方法的permission校验,也可以采用uid和pid进行校验,验证不通过,直接返回false就可以了。
Android Binder机制,共享内存实现原理
Binder机制,共享内存实现原理
Android匿名共享内存是基于Linux共享内存的,都是在tmpfs文件系统上新建文件,并将其映射到不同的进程空间,从而达到共享内存的目的,只是,Android在Linux的基础上进行了改造,并借助Binder+fd文件描述符实现了共享内存的传递。
如何在Android下使用Binder
1概述
Binder是基于OpenBinder,在Android系统上使用的进程间通信机制。
Binder基于-通信模式,本质上可以理解为它实现了对对象的远程调用。比如,有某个binder对象A位于中,该对象提供了一套函数用以实现对服务的请求,而在一个或多个中包含对象A的引用,通过该引用可以调用远端中对象A的接口函数,这种远端调用对而言,与调用本地对象并无区别。
2 通信模型
Binder机制定义了四个组件,分别是,,ServMar和binder驱动,其中,,ServMar运行于用户空间,binder驱动运行于内核空间。
binder驱动
binder驱动是内核中的一个字符设备驱动/dev/binder,它是整个Binder通信机制的核心。,,ServMar通过open()和ioctl()文件作函数与binder驱动进行通信,从而实现了向发送请求,处理请求并返回结果到。具体来说,它负责进程之间Binder通信的建立,Binder在进程之间的传递,Binder引用计数管理,数据包在进程之间的传递和交互等一系列底层支持。
ServMar
ServMar是一个守护进程,负责管理服务,即所有的需要向ServMar注册服务。同时,ServMar向提供查询和获取的接口。
3 binder通信实例
实现一个binder通信实例,需要经过以下步骤:
(1)获得ServMar的对象引用
(2)向ServMar注册新的Serv
(3)在中通过ServMar获得Serv对象引用
(3)在中发送请求,由Serv返回结果。
下面看具体的代码如何实现。
3.1 libmyserv代码实现
(1)新建目录frameworks/base/myserv/libserv,进入该目录
view plain
$ cd frameworks/base
$ mkdir myserv
$ cd myserv
$ mkdir libmyserv
$ cd libmyserv
(2)编写libmyserv/myservic.h文件
view plain
#include
#include
#include
#include
#include
namespace android {
class MyServ : public BBinder
{
mutable Mutex mLock;
int32_t mNextConnId;
public:
static int instantiate();
MyServ();
virtual ~MyServ();
virtual status_t onTransact(uint32_t, const Parcel&, Parcel, uint32_t);
};
}; //namespace
(2)编写libserv/myserv.cpp文件
view plain
#include "myserv.h"
#include
#include
namespace android {
static struct sigaction oldact;
static pthread_key_t sigbuskey;
int MyServ::instantiate()
{
LOGE("MyServ instantiate");
// defaultServMar ()获得ServMar的对象引用,addServ()可向ServMar注册新的服务
int r = defaultServMar()->addServ(String16("android.myserv"), new MyServ());
LOGE("MyServ r = %d/n", r);
return r;
}
MyServ::MyServ()
{
LOGV("MyServ created");
mNextConnId = 1;
pthread_key_create(&sigbuskey, NULL);
}
MyServ::~MyServ()
{
pthread_key_delete(sigbuskey);
LOGV("MyServ destroyed");
}
// 每个系统服务都继承自BBinder类,都应重写BBinder的onTransact虚函数。当用户发送请求到达Serv时,系统框架会调用Serv的onTransact函数,该函数分析接收到的数据包,调用相应的接口函数处理请求
status_t MyServ::onTransact(uint32_t code, const Parcel& data, Parcel reply, uint32_t flags)
{
switch(code)
{
case 0: {
pid_t pid = data.readInt32();
int num = data.readInt32();
num = num + 100;
reply->writeInt32(num);
return NO_ERROR;
}
break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
}
}; //namespace
(3)编写libserv/Android.mk文件
view plain
# File: Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := myserv.cpp
LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)
LOCAL_SHARED_LIBRARIES := libutils libbinder
LOCAL_MODULE_TAGS := optional
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE := libmyserv
include $(BUILD_SHARED_LIBRARY)
(4)编译libmyserv.so动态库
在android源码主目录下
view plain
$ source build/envsetup.sh
including dev/htc/passion/vendorsetup.sh
including dev/samsung/crespo4g/vendorsetup.sh
including dev/samsung/crespo/vendorsetup.sh
$ mmm frameworks/base/myserv/libmyserv/
编译成功后生成文件:out/target/product/generic//lib/libmyserv.so
3.2 myserver代码实现
(1)新建目录myserv/myserver,并进入该目录
(2)编写myserver/myserver.cpp文件
view plain
#include
#include
#include
#include
#include
#include
#include
#include
#include "../libmyserv/myserv.h"
using namespace android;
int main(int argc, char argv)
{
sp
sp
LOGI("ServMar: %p", .get());
MyServ::instantiate();
//执行addServ()函数,注册服务
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
//进入循环,等待客户端的请求
return 0;
}
(3)编写myserver/Android.mk文件
view plain
# File: Android.mk
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:=
myserver.cpp
LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)
LOCAL_SHARED_LIBRARIES :=
libutils libbinder libmyserv
LOCAL_MODULE_TAGS := optional
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE := myserver
include $(BUILD_EXECUTABLE)
(4)编译myserver可执行程序
在android源码主目录下执行:
view plain
$mmm frameworks/base/myserv/myserver/
编译成功后生成文件:out/target/product/generic/symbols//bin/myserver
3.3 My客户端代码实现
(1)新建目录myserv/myclient,进入该目录
(2)编写myclient/myclient.h文件
view plain
namespace android
{
class My {
public:
void add100(int n);
private:
static const void getMyServ();
//通过ServMar获取服务接口
};
}; //namespace
(3)编写myclient/myclient.cpp文件
view plain
#include
#include
#include "myclient.h"
namespace android
{
sp
void My::add100(int n)
{
getMyServ();
Parcel data, reply;
int answer;
data.writeInt32(getpid());
data.writeInt32(n);
LOGE("BpMyServ::create remote()->transact()/n");
binder->transact(0, data, &reply);
answer = reply.readInt32();
printf("answner=%d/n", answer);
return;
}
const void My::getMyServ()
{
sp
binder = ->getServ(String16("android.myserv"));
LOGE("My::getMyServ %p/n",.get());
if (binder == 0) {
LOGW("MyServ not published, waiting...");
return;
}
}
}; //namespace
using namespace android;
int main(int argc, char argv)
{
My p = new My();
p->add100(1);
return 0;
}
(4)编写myclient/Android.mk文件
view plain
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:=
myclient.cpp
LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)
LOCAL_SHARED_LIBRARIES :=
libutils libbinder libmyserv
LOCAL_MODULE_TAGS := optional
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE := myclient
include $(BUILD_EXECUTABLE)
(5)编译myclient可执行程序
在android源码主目录下,执行:
view plain
$ mmm frameworks/base/myserv/myclient/
编译成功后生成可执行文件:out/target/product/generic/symbols//bin/myclient
3.4在模拟器上运行
(1)启动模拟器
view plain
$ cd ~/software/android/android-sdk-linux/tools
$ ./emulator -d gbread -partition-size 512
(2)拷贝libmyserv.so到模拟器的//lib目录
view plain
$cd out/target/product/generic/obj/lib
$adb remount
$ adb push libmyserv.so //lib
159 KB/s (10084 bytes in 0.061s)
(3)拷贝myserver到模拟器的//bin目录
view plain
$cd out/target/product/generic/symbols//bin
$ adb push myserver //bin
668 KB/s (27508 bytes in 0.040s)
(4)拷贝myclient到//bin目录
view plain
$ adb push myclient //bin
1549 KB/s (46840 bytes in 0.029s)
(5)在模拟器上启动服务,并执行客户端程序。
view plain
# adb shell
# cd /bin
# ls my
myclient
myserver
# ./myserver
# ./myclient
answner=101/n#
由客户端程序的执行结果可知,由服务端返回的执行结果是正确的。
Android之Binder通信篇
Binder跨进程通信的本质是依赖内核驱动将属于不同Binder进程的数据,从原始进程到目标进程,这样就完成了跨进程通信了。
Binder通过独特的内存映射机制,在跨进程通信时,可以做到一次拷贝,两个空间同时使用!如下图:
Binder跨进程通信是要传递数据的,既然有数据必然要占用内存空间,Android系统规定每一个进程都有一块Binder内存区,也就是图1中的 共享内存 ,系统最多只能给该区域分配4M的物理内存,由于申请这块内存是通过系统的mmap函数完成的,所以整个映射机制又被称为mmap机制
为了把这部分说明白,就再盗图一张,命名图2吧!
对于Binder驱动,通过 binder_procs 链表记录所有创建的 binder_proc 结构体,binder 驱动层的每一个 binder_proc 结构体都与用户空间的一个用于 binder 通信的进程一一对应,且每个进程有且只有一个 ProcessState 对象,这是通过单例模式来保证的。在每个进程中可以有很多个线程,每个线程对应一个 IPCThreadState 对象,IPCThreadState 对象也是单例模式,即一个线程对应一个 IPCThreadState 对象,在 Binder 驱动层也有与之相对应的结构,那就是 Binder_thread 结构体。在 binder_proc 结构体中通过成员变量 rb_root threads,来记录当前进程内所有的 binder_thread。
Binder 线程池:每个 进程在启动时创建一个 binder 线程池,并向其中注册一个 Binder 线程;之后 进程也可以向 binder 线程池注册新的线程,或者 Binder 驱动在探测到没有空闲 binder 线程时主动向 进程注册新的的 binder 线程。对于一个 进程有一个 Binder 线程数限制,默认为16个 binder 线程,例如 Android 的 _server 进程就存在16个线程。对于所有 端进程的 binder 请求都是交由 端进程的 binder 线程来处理的。
Binder机制概述
Android进程间通讯是通过Binder机制来实现的,Android是基于linux系统因此有必要了解Linux系统进程相关知识.
Linux系统中(其他系统也是这样)不同进程之间不允许直接作或访问另一进程.也就是进程隔离.
为了保证用户进程不能直接访问内核,作系统从逻辑上将虚拟空间划分为用户空间和内核空间.内核程序运行在内核空间(kernel space),应用程序运行在用户空间(user space).为了安全,他们之间是隔离的,即使用户程序奔溃了,也不会影响内核.内核空间数据是可以共享的,用户空间不可以.
用户空间访问内核空间只能通过系统调用,系统调用是用户空间访问内核空间的方式,保证所有资源访问在内核控制下,避免了用户对系统资源的越权访问,提高了系统安全性和稳定性.
copy_from_user:将用户空间数据拷贝到内核空间
copy_to_user:将内核空间数据拷贝到用户空间
由于用户进程不能直接访问硬件地址,所以系统提供了一种机制:内存映射(Memory Map).在Linux中通过调用函数mmap实现内存映射,将用户空间一块内存地址映射到内核空间.映射关系建立后,对用户空间内存的修改可以反应到内核空间.内存映射可减少拷贝次数.
如果没有内存映射,用户进程需要访问硬盘文件时,需要在内核空间创建一片页缓存,将硬盘文件数据拷贝到页缓存然后用户进程在拷贝页缓存数据,需要两次拷贝.通过内存映射后硬盘文件可以和内核的虚拟内存直接映射,减少一次拷贝.
如图
inter-process-communication进程间通信,指进程间交换数据的过程.
Linux提供了很多进程间通讯的机制,主要有管道(pipe)、消息队列(Message)、信号(sinal)、信号量(semophore)、套接字(socket)等
内核程序在内核空间分配并开辟一块内核缓冲区,发送进程将数据通过copy_from_user拷贝到内核空间的数据缓冲区,内核空间通过copy_to_user将数据拷贝到接收进程,这样就实现了一次进程间通信.如图
Linux的IPC机制有两个问题:
1.数据通过用户空间->内核空间->用户空间,经过两次拷贝,效率不高
2.接收进程无法预先知道数据大小,只能尽可能大创建数据缓冲区,或通过api消息头获取消息体的大小,浪费了空间或时间.
Android进程间通信通过Binder实现,下面介绍Binder机制通信原理,为什么是Binder
内核程序创建一个数据接收缓存区,同时创建一个内核缓冲区.并建立内核缓冲区和数据接收缓冲区内存映射,以及数据内核缓冲区和接收进程用户空间的映射关系.发送进程通过copy_from_user将数据拷贝到内核数据接收缓冲区,因为内核数据接收缓冲区和内核缓冲区以及接收进程用户空间存在映射关系,相当于将数据发送到了接收进程.完成了一次进程间通信.如图
Binder机制是c/s架构的,由、server、ServMar和Binder组成.client、server和servMar都是的进程,由于Linux进程隔离的原因,所以需要借助Binder进行通信.
Binder通信主要有三个步骤:注册服务、获取服务、使用服务.如下图
从上一条Binder实现原理示例图中可以看到,Binder可分为Ja Binder、Native Binder和Kernal Binder.应用开发需要了解Ja Binder和Nive Binder.这里只介绍Binder基本原理.具体可查看文章结尾的链接.
感谢
all first_rank_ecpm_v3~rank_business_v1-1-73560642.ecpm_v3_rank_business_v1&utm_term=Binder&spm=1018.2118.3001.4187
Android通信方式篇(七)-Binder机制(Native层(下))
本篇文章针对向ServMar注册服务 和 获取服务两个流程来做总结。在这两个过程中,ServMar都扮演的是服务端,与客户端之间的通信也是通过Binder IPC。
在此之前先了解下Binder的进程与线程的关系:
用户空间 :ProcessState描述一个进程,IPCThreadState对应一个进程中的一个线程。
内核空间 :binder_proc描述一个进程,统一由binder_procs全局链表保存,binder_thread对应进程的一个线程。
ProcessState与binder_proc是一一对应的。
Binder线程池 :每个进程在启动时会创建一个binder线程池,并向其中注册一个Binder线程;之后进程也可以向binder线程池注册新的线程,或者Binder驱动在探测到没有空闲binder线程时会主动向进程注册新的的binder线程。对于一个进程有一个Binder线程数限制15,(#define DEFAULT_MAX_BINDER_THREADS 15)。对于所有端进程的binder请求都是交由端进程的binder线程来处理的。我的理解是:binder线程是进程进行binder ipc时的一条数据处理路径。
MediaPlayerServ向ServMar注册过程如下:
相关类:
整个过程总结如下:
1 获取BpServMar 与 BpBinder
由defaultServMar()返回的是BpServMar,同时会创建ProcessState对象和BpBinder对象。然后通过BpBinder执行transact,把真正工作交给IPCThreadState来处理。
2 BpBinder transact
Binder类调用transact()方法,真正工作还是交给IPCThreadState来进行transact工作。
3 通过IPCThreadState 包装并转换数据并进行transact事务处理
每个线程都有一个IPCThreadState,每个IPCThreadState中都有一对Parcel变量:mIn、mOut。相当于两根数据管道:
执行talkWithDriver。
writeTransactionData:将BC Protocol + binder_transaction_data结构体 写入mOut, 然后执行waitForResponse:
由talkWithDriver将数据进一步封装到binder_write_read结构体,通过ioctl(BINDER_WRITE_READ)与驱动通信。同时等待驱动返回的接收BR命令,从mIn取出返回的数据。
mIn包装的数据结构(注册服务handle = 0 ,code 为ADD_SERVICE_TRANSACTION):
4 Binder Driver
把binder_write_read结构体write_buffer里数据取出来,分别得到BC命令和封装好数据的事务binder_transaction_data, 然后根据handler,在当前binder_proc中,找到相应的binder_ref,由binder_ref再找到目标binder_node实体,由目标binder_node再找到目标进程binder_proc。然后就是插入数据:当binder驱动可以找到合适的线程,就会把binder_transaction插入到servciemar的线程的todo队列中,如果找不到合适的线程,就把之间插入servciemar的binder_proc的todo队列。
5 ServMar
经过Binder Driver的处理,数据已经到了ServMar进程,在BR_TRANSACTION的下,在binder_loop()中执行binder_parser()取出数据,执行do_add_serv()作,最终向 svc 列表中添加已经注册的服务(没有数据的返回)。发送 BR_REPLY 命令唤醒等待的线程,通知注册成功。结束MediaPlayerServ进程 waitForResponse()的状态,整个注册过程结束。
获取服务的过程与注册类似,首先 ServMar 向 Binder 驱动发送 BC_TRANSACTION 命令携带 CHECK_SERVICE_TRANSACTION 命令,同时获取服务的线程进入等待状态 waitForResponse()。Binder 驱动收到请求命令向 ServMar 的发送 BC_TRANSACTION 查询已注册的服务,会区分请求服务所属进程情况。
查询到直接响应 BR_REPLY 唤醒等待的线程。若查询不到将与 binder_procs 链表中的服务进行一次通讯再响应。
以startServ为例来简单总结下执行流程:
3.1 从方法执行流程来看:
:
1 AMP.startServ 标记方法以及通过Parcel包装数据;
2 BinderProxy.transact 实际调用native的 android_os_BinderProxy_transact 传递数据;
3 获取BpServMar 与 BpBinder 同时会创建ProcessState。然后通过BpBinder执行transact,把真正工作交给IPCThreadState来处理;
4 IPC.transact 主要执行writeTransactionData,将上层传来的数据重新包装成binder_transaction_data,并将BC Protocol + binder_transaction_data结构体 写入mOut;
5 IPC waitForResponse talkWithDriver + 等待返回数据;
6 talkWithDriver 将数据进一步封装成binder_write_read,通过ioctl(BINDER_WRITE_READ)与驱动通信;
Kernel :
7 binder ioctl 接收BINDER_WRITE_READ ioctl命令;
8 binder_ioctl_write_read 把用户空间数据ubuf拷贝到内核空间bwr;
9 binder_thread_write 当bwr写缓存有数据,则执行binder_thread_write;当写失败则将bwr数据写回用户空间并退出;
10 binder_transaction 找到目标进程binder_proc并插入数据到目标进程的线程todo队列,最终执行到它
时,将发起端数据拷贝到接收端进程的buffer结构体;
11 binder_thread_read 根据binder_transaction结构体和binder_buffer结构体数据生成新的binder_transaction_data结构体,写入bwr的read_buffer,当bwr读缓存有数据,则执行binder_thread_read;当读失败则再将bwr数据写回用户空间并退出;,把内核数据bwr拷贝到用户空间ubuf。
12 binder_thread_write + binder_ioctl BR命令和数据传递
:
13 IPC.executeCommand 解析kernel传过来的binder_transaction_data数据,找到目标BBinder并调用其transact()方法;
14 IPC.joinThreadPool 采用循环不断地执行getAndExecuteCommand()方法, 处理事务。当bwr的读写buffer都没有数据时,则阻塞在binder_thread_read的wait_nt过程. 另外,正常情况下binder线程一旦创建则不会退出.
15 BBinder.transact 到Binder.exeTransact 调用 AMN.onTransact
16 AMN.onTransact 把数据传递到AMS.starServ去执行
17 AMS.starServ 处理了的请求了
然后原路replay回去,talkWithDriver 到Kernel ,然后找到进程,把数据拷贝到read_buffer里,最终唤醒IPC,把反馈传递回AMP.startServ。完成启动服务。
3.2 从通信协议流程来看:
非oneWay:
oneway:
oneway与非oneway区别: 都是需要等待Binder Driver的回应消息BR_TRANSACTION_COMPLETE. 主要区别在于oneway的通信收到BR_TRANSACTION_COMPLETE则返回,而不会再等待BR_REPLY消息的到来. 另外,oneway的binder IPC则接收端无法获取对方的pid.
3.3 从数据流来看
从用户空间开始:
进入驱动后:
回到用户空间:
参考:
androidbinder机制(androidbinder面试详解简书)
Carson带你学Android:全面剖析Binder跨进程通信原理
从而全方位地介绍 Binder ,希望你们会喜欢。
在本文的讲解中,按照 大角度 -> 小角度 去分析 Binder ,即:
从而全方位地介绍 Binder ,希望你们会喜欢。
在讲解 Binder 前,我们先了解一些 Linux 的基础知识
具体请看文章: 作系统:图文详解 内存映射
Binder 跨进程通信机制 模型 基于 - 模式
此处重点讲解 Binder 驱动作用中的跨进程通信的原理:
原因:
所以,原理图可表示为以下:
所以,在进行跨进程通信时,开发者只需自定义 & 进程 并 显式使用上述3个步骤,最终借助 Android 的基本架构功能就可完成进程间通信
注册服务后, Binder 驱动持有 进程创建的 Binder 实体
此时, 进程与 进程已经建立了连接
进程 根据获取到的 Serv 信息( Binder 对象),通过 Binder 驱动 建立与 该 Serv 所在 进程通信的链路,并开始使用服务
步骤1: 进程 将参数(整数a和b)发送到 进程
步骤2: 进程根据 进要求 调用 目标方法(即加法函数)
步骤3: 进程 将目标方法的结果(即加法后的结果)返回给 进程
对比 Linux ( Android 基于 Linux )上的其他进程通信方式(管道、消息队列、共享内存、
信号量、 Socket ), Binder 机制的优点有:
特别地,对于从模型结构组成的Binder驱动来说:
不定期分享关于 安卓开发 的干货,追求 短、平、快 ,但 却不缺深度 。
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系 836084111@qq.com 删除。