Binder 框架及 Native 层

Binder机制使本地对象可以像操作当前对象一样调用远程对象,可以使不同的进程间互相通信。Binder 使用 Client/Server 架构,客户端通过服务端代理,经过 Binder 驱动与服务端交互。

Binder 机制实现进程间通信的奥秘在于 kernel 中的 Binder 驱动。

JNI 的代码位于 frameworks/base/core/jni 目录下,主要是 android_util_Binder.cpp 文件和头文件 android_util_Binder.h

Binder JNI 代码是 Binder Java 层操作到 Binder Native 层的接口封装,最后会被编译进 libandroid_runtime.so 系统库。

Binder 本地层的代码在 frameworks/native/libs/binder 目录下, 此目录在 Android 系统编译后会生成 libbinder.so 文件,供 JNI 调用。libbinder 封装了所有对 binder 驱动的操作,是上层应用与驱动交互的桥梁。头文件则在 frameworks/native/include/binder 目录下。

Binder Native 的入口

IInterface.cpp 是 Binder 本地层入口,与 java 层的 android.os.IInterface 对应,提供 asBinder() 的实现,返回 IBinder 对象。

在头文件中有两个类 BnInterface (Binder Native Interface) 和 BpInterface (Binder Proxy Interface), 对应于 java 层的 Stub和 Proxy

sp<IBinder> IInterface::asBinder(const IInterface* iface)
{
if (iface == NULL) return NULL;
return const_cast<IInterface*>(iface)->onAsBinder();
}
template<typename INTERFACE>
class BnInterface : public INTERFACE, public BBinder
{
public:
virtual sp<IInterface> queryLocalInterface(const String16& _descriptor);
virtual const String16& getInterfaceDescriptor() const; protected:
virtual IBinder* onAsBinder();
}; // ---------------------------------------------------------------------- template<typename INTERFACE>
class BpInterface : public INTERFACE, public BpRefBase
{
public:
BpInterface(const sp<IBinder>& remote); protected:
virtual IBinder* onAsBinder();
};

其中 BnInterface 是实现Stub功能的模板,扩展BBinder的onTransact()方法实现Binder命令的解析和执行。BpInterface是实现Proxy功能的模板,BpRefBase里有个mRemote对象指向一个BpBinder对象。

Binder 本地层的整个函数/方法调用过程

1. Java 层 IRemoteService.Stub.Proxy 调用 android.os.IBinder (实现在 android.os.Binder.BinderProxy) 的 transact() 发送 Stub.TRANSACTION_addUser 命令。

2. 由 BinderProxy.transact() 进入 native 层。

3. 由 jni 转到 android_os_BinderProxy_transact() 函数。

4. 调用 IBinder->transact 函数。

static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
jint code, jobject dataObj, jobject replyObj, jint flags) // throws RemoteException
{
IBinder* target = (IBinder*)
env->GetLongField(obj, gBinderProxyOffsets.mObject);
status_t err = target->transact(code, *data, reply, flags);
}

而 gBinderProxyOffsets.mObject 则是在 java 层调用 IBinder.getContextObject() 时在 javaObjectForIBinder 函数中设置的

static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)
{
sp<IBinder> b = ProcessState::self()->getContextObject(NULL);
return javaObjectForIBinder(env, b);
} jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
{
...
LOGDEATH("objectForBinder %p: created new proxy %p !\n", val.get(), object);
// The proxy holds a reference to the native object.
env->SetLongField(object, gBinderProxyOffsets.mObject, (jlong)val.get());
val->incStrong((void*)javaObjectForIBinder);
...
}

经过 ProcessState::getContextObject() 和 ProcessState::getStrongProxyForHandle()

sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
return getStrongProxyForHandle();
} sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
sp<IBinder> result;
...
b = new BpBinder(handle);
result = b;
...
return result;
}

可见 android_os_BinderProxy_transact() 函数实际上调用的是 BpBinder::transact() 函数。

5. BpBinder::transact() 则又调用了 IPCThreadState::self()->transact() 函数。

status_t IPCThreadState::transact(int32_t handle,
uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags)
{
status_t err = data.errorCheck(); flags |= TF_ACCEPT_FDS; if (err == NO_ERROR) {
LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(),
(flags & TF_ONE_WAY) == ? "READ REPLY" : "ONE WAY");
err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
} if ((flags & TF_ONE_WAY) == ) {
if (reply) {
err = waitForResponse(reply);
} else {
Parcel fakeReply;
err = waitForResponse(&fakeReply);
}
} else {
err = waitForResponse(NULL, NULL);
} return err;
} status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
{
binder_transaction_data tr; tr.target.ptr = ; /* Don't pass uninitialized stack data to a remote process */
tr.target.handle = handle;
tr.code = code;
... mOut.writeInt32(cmd);
mOut.write(&tr, sizeof(tr)); return NO_ERROR;
}

由函数内容可以看出, 数据再一次通过 writeTransactionData() 传递给 mOut 进行写入操作。 mOut 是一个 Parcel 对象, 声明在 IPCThreadState.h 文件中。之后则调用 waitForResponse() 函数。

6. IPCThreadState::waitForResponse() 在一个 while 循环里不断的调用 talkWithDriver() 并检查是否有数据返回。

status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
uint32_t cmd;
int32_t err; while () {
if ((err=talkWithDriver()) < NO_ERROR) break;
... cmd = (uint32_t)mIn.readInt32(); switch (cmd) {
case BR_TRANSACTION_COMPLETE:
... case BR_REPLY:
{
binder_transaction_data tr;
err = mIn.read(&tr, sizeof(tr));
ALOG_ASSERT(err == NO_ERROR, "Not enough command data for brREPLY");
if (err != NO_ERROR) goto finish; if (reply) {
if ((tr.flags & TF_STATUS_CODE) == ) {
reply->ipcSetDataReference(
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(binder_size_t),
freeBuffer, this);
} else {
err = *reinterpret_cast<const status_t*>(tr.data.ptr.buffer);
freeBuffer(NULL,
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(binder_size_t), this);
}
} else {
freeBuffer(NULL,
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(binder_size_t), this);
continue;
}
}
goto finish;
} default:
err = executeCommand(cmd);
if (err != NO_ERROR) goto finish;
break;
}
}
...
}

7. IPCThreadState::talkWithDriver() 函数是真正与 binder 驱动交互的实现。ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) 就是使用系统调用函数 ioctl 向 binder 设备文件 /dev/binder 发送 BINDER_WRITE_READ命令。

status_t IPCThreadState::talkWithDriver(bool doReceive)
{
if (mProcess->mDriverFD <= ) {
return -EBADF;
} binder_write_read bwr; // Is the read buffer empty?
const bool needRead = mIn.dataPosition() >= mIn.dataSize(); // We don't want to write anything if we are still reading
// from data left in the input buffer and the caller
// has requested to read the next data.
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : ; bwr.write_size = outAvail;
bwr.write_buffer = (uintptr_t)mOut.data(); // This is what we'll read.
if (doReceive && needRead) {
bwr.read_size = mIn.dataCapacity();
bwr.read_buffer = (uintptr_t)mIn.data();
} else {
bwr.read_size = ;
bwr.read_buffer = ;
} // Return immediately if there is nothing to do.
if ((bwr.write_size == ) && (bwr.read_size == )) return NO_ERROR; bwr.write_consumed = ;
bwr.read_consumed = ;
status_t err; #if defined(HAVE_ANDROID_OS)
// 使用系统调用 ioctl 向 /dev/binder 发送 BINDER_WRITE_READ 命令
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= )
err = NO_ERROR;
else
err = -errno;
#else
err = INVALID_OPERATION;
#endif do {
if (mProcess->mDriverFD <= ) {
err = -EBADF;
}
} while (err == -EINTR); if (err >= NO_ERROR) {
if (bwr.write_consumed > ) {
if (bwr.write_consumed < mOut.dataSize())
mOut.remove(, bwr.write_consumed);
else
mOut.setDataSize();
}
if (bwr.read_consumed > ) {
mIn.setDataSize(bwr.read_consumed);
mIn.setDataPosition();
}
return NO_ERROR;
} return err;
}

经过 IPCThreadState::talkWithDriver() ,就将数据发送给了 Binder 驱动。

继续追踪 IPCThreadState::waitForResponse() ,可以从 第6步 发现 IPCThreadState 不断的循环读取 Binder 驱动返回,获取到返回命令后执行了 executeCommand(cmd) 函数。

8. IPCThreadState::executeCommand() 处理 Binder 驱动返回命令

status_t IPCThreadState::executeCommand(int32_t cmd)
{
BBinder* obj;
RefBase::weakref_type* refs;
status_t result = NO_ERROR; switch ((uint32_t)cmd) {
... case BR_TRANSACTION:
{
binder_transaction_data tr;
result = mIn.read(&tr, sizeof(tr));
...
Parcel buffer;
buffer.ipcSetDataReference(
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(binder_size_t), freeBuffer, this);
... Parcel reply;
status_t error;
if (tr.target.ptr) {
sp<BBinder> b((BBinder*)tr.cookie);
error = b->transact(tr.code, buffer, &reply, tr.flags); } else {
error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
}
...
}
break;
...
}

9. 可以看出其调用了 BBinder::transact() 函数,将数据返回给上层。

status_t BBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
data.setDataPosition(); status_t err = NO_ERROR;
switch (code) {
case PING_TRANSACTION:
reply->writeInt32(pingBinder());
break;
default:
err = onTransact(code, data, reply, flags);
break;
} if (reply != NULL) {
reply->setDataPosition();
} return err;
}

10. 而这里的 b->transact(tr.code, buffer, &reply, tr.flags) 中的 b (BBinder) 是 JavaBBinder 的实例,所以会调用 JavaBBinder::onTransact() 函数

// frameworks/base/core/jni/android_util_Binder.cpp
virtual status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = )
{
JNIEnv* env = javavm_to_jnienv(mVM);
...
jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,
code, reinterpret_cast<jlong>(&data), reinterpret_cast<jlong>(reply), flags);
} static int int_register_android_os_Binder(JNIEnv* env)
{
...
gBinderOffsets.mExecTransact = GetMethodIDOrDie(env, clazz, "execTransact", "(IJJI)Z");
...
}

11. 可见 JNI 通过 gBinderOffsets.mExecTransact 最后执行了 android.os.Binder 的 execTransact() 方法。

execTransact() 方法是 jni 回调的入口。

// Entry point from android_util_Binder.cpp's onTransact
private boolean execTransact(int code, long dataObj, long replyObj,
int flags) {
Parcel data = Parcel.obtain(dataObj);
Parcel reply = Parcel.obtain(replyObj);
...
try {
res = onTransact(code, data, reply, flags);
}
...
}

12. 而我们则在服务端 IRemoteService.Stub 重载了 onTransact() 方法,所以数据最后会回到我们的服务端并执行服务端实现的 addUser() 方法。

public static abstract class Stub extends android.os.Binder
implements org.xdty.remoteservice.IRemoteService {
...
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply,
int flags) throws android.os.RemoteException {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_basicTypes: {
...
return true;
}
case TRANSACTION_addUser: {
data.enforceInterface(DESCRIPTOR);
org.xdty.remoteservice.User _arg0;
if (( != data.readInt())) {
_arg0 = org.xdty.remoteservice.User.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
this.addUser(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
}

Binder 设备文件的打开和读写

我们看到 JNI 过程中调用了 ProcessState::getContextObject() 函数, 在 ProcessState 初始化时会打开 binder 设备

// ProcessState.cpp
ProcessState::ProcessState()
: mDriverFD(open_driver())
...
{
...
}

open_driver() 函数内容如下

// ProcessState.cpp
static int open_driver()
{
// 打开设备文件
int fd = open("/dev/binder", O_RDWR);
if (fd >= ) {
fcntl(fd, F_SETFD, FD_CLOEXEC);
int vers = ;
// 获取驱动版本
status_t result = ioctl(fd, BINDER_VERSION, &vers);
if (result == -) {
ALOGE("Binder ioctl to obtain version failed: %s", strerror(errno));
close(fd);
fd = -;
}
// 检查驱动版本是否一致
if (result != || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
ALOGE("Binder driver protocol does not match user space protocol!");
close(fd);
fd = -;
}
// 设置最多 15 个 binder 线程
size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
if (result == -) {
ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
}
} else {
ALOGW("Opening '/dev/binder' failed: %s\n", strerror(errno));
}
return fd;
}

设备的读写

打开设备文件后,文件描述符被保存在 mDriverFD, 通过系统调用 ioctl 函数操作 mDriverFD 就可以实现和 binder 驱动的交互。

对 Binder 设备文件的所有读写及关闭操作则都在 IPCThreadState中,如上一小节提及到的 IPCThreadState::talkWithDriver函数

talkWithDriver() 函数封装了 BINDER_WRITE_READ 命令,会向 binder 驱动写入或从驱动读取封装在 binder_write_read 结构体中的本地或远程对象。

// IPCThreadState.cpp
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
binder_write_read bwr;
const bool needRead = mIn.dataPosition() >= mIn.dataSize();
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : ; // 写入数据
bwr.write_size = outAvail;
bwr.write_buffer = (uintptr_t)mOut.data(); // 读取数据
if (doReceive && needRead) {
bwr.read_size = mIn.dataCapacity();
bwr.read_buffer = (uintptr_t)mIn.data();
} else {
bwr.read_size = ;
bwr.read_buffer = ;
}
...
// 使用 ioctl 系统调用发送 BINDER_WRITE_READ 命令到 biner 驱动
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= )
err = NO_ERROR;
...
}

BpBinder.cpp

BpBinder(Base proxy Binder) 对应于 Java 层的 Service Proxy,

先查看头文件 BpBinder.h 代码片断

class BpBinder : public IBinder
{
public: inline int32_t handle() const { return mHandle; } virtual status_t transact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = ); virtual status_t linkToDeath(const sp<DeathRecipient>& recipient,
void* cookie = NULL,
uint32_t flags = );
virtual status_t unlinkToDeath( const wp<DeathRecipient>& recipient,
void* cookie = NULL,
uint32_t flags = ,
wp<DeathRecipient>* outRecipient = NULL);
};

可以看到 BpBinder 中声明了 transact() linkToDeath() 等重要函数。再看具体实现

status_t BpBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
...
status_t status = IPCThreadState::self()->transact(
mHandle, code, data, reply, flags);
... return DEAD_OBJECT;
} status_t BpBinder::linkToDeath(
const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags)
{
...
IPCThreadState* self = IPCThreadState::self();
self->requestDeathNotification(mHandle, this);
self->flushCommands();
...
return DEAD_OBJECT;
}

可以看出 BPBinder 是最终是通过调用 IPCThreadState 的函数来完成数据传递操作。

IPCThreadState.cpp

AppOpsManager.cpp

APPOpsManager (APP Operation Manager) 是 应用操作管理者,实现对客户端操作的检查、启动、完成等

 

Binder Native 层(二)的更多相关文章

  1. Bn Bp Binder native层关系

    Servicemanager 源码在/frameworks/base/cmds/servicemanager/service_manager.c 编译成 systemmanager 可执行文件 sys ...

  2. Android Native层异步消息处理框架

     *本文系作者工作学习总结,尚有不完善及理解不恰当之处,欢迎批评指正* 一.前言 在NuPlayer中,可以发现许多类似于下面的代码: //============================== ...

  3. Android逆向之旅---Native层的Hook神器Cydia Substrate使用详解

    一.前言 在之前已经介绍过了Android中一款hook神器Xposed,那个框架使用非常简单,方法也就那几个,其实最主要的是我们如何找到一个想要hook的应用的那个突破点.需要逆向分析app即可.不 ...

  4. Android Framework 分析---2消息机制Native层

    在Android的消息机制中.不仅提供了供Application 开发使用的java的消息循环.事实上java的机制终于还是靠native来实现的.在native不仅提供一套消息传递和处理的机制,还提 ...

  5. Native层和so接口和Java层

    一.Java层加载so文件 Android在Java层加载so的接口是System.loadLibrary()逐级调用的过程: System.loadLibrary()系统源码: 987    pub ...

  6. {django模型层(二)多表操作}一 创建模型 二 添加表记录 三 基于对象的跨表查询 四 基于双下划线的跨表查询 五 聚合查询、分组查询、F查询和Q查询

    Django基础五之django模型层(二)多表操作 本节目录 一 创建模型 二 添加表记录 三 基于对象的跨表查询 四 基于双下划线的跨表查询 五 聚合查询.分组查询.F查询和Q查询 六 xxx 七 ...

  7. Android Java层,Native层,Lib层打印Log简介【转】

    本文转载自:https://blog.csdn.net/AndroidMage/article/details/52225068 说明: 这里我根据个人工作情况说明在各个层打印log.如有问题欢迎拍砖 ...

  8. 在Android Native层中创建Java虚拟机实例

    前言 Android应用中JNI代码,是作为本地方法运行的.而大部分情况下,这些JNI方法均需要传递Dalvik虚拟机实例作为第一个参数.例如,你需要用虚拟机实例来创建jstring和其他的Java对 ...

  9. SQLite数据库学习小结——native层实现

    1. SQlite概述 SQLite是一款轻量.快速.跨平台的嵌入式数据库,是遵守ACID(注:ACID指数据库事务正确执行的四个基本要素的缩写.包含:原子性(Atomicity).一致性(Consi ...

随机推荐

  1. BZOJ 2243 染色 (线段树+树链剖分)

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 9895  Solved: 3735[Submit][Status ...

  2. post上传文件限制--另一种解决途径

    问题:项目之前的上传功能是没有问题的,但是今天同样的代码上传一个压缩包的时候出现了问题,报的是struts.xml的错,说是找不到返回的映射, 问题截图: 很奇怪的问题,之前都没问题的,仔细对比后发现 ...

  3. 51nod 1421 最大MOD值(高妙的调和级数复杂度)

    有一个a数组,里面有n个整数.现在要从中找到两个数字(可以是同一个) ai,aj ,使得 ai mod aj 最大并且 ai ≥ aj. Input 单组测试数据. 第一行包含一个整数n,表示数组a的 ...

  4. 移动距离——第六届蓝桥杯C语言B组(省赛)第八题

    原创  问题描述: 移动距离 X星球居民小区的楼房全是一样的,并且按矩阵样式排列.其楼房的编号为1,2,3...当排满一行时,从下一行相邻的楼往反方向排号.比如:当小区排号宽度为6时,开始情形如下: ...

  5. django 'set' object does not support indexing

    在定义Model之后使用syncdb 同步的时候报出这个错误,检查之后发现是用错了.在model的Meta里面,排序这些用的应该是 ordering = ['last','first','middle ...

  6. solr入门教程-较详细

    Solr调研总结 开发类型 全文检索相关开发 Solr版本 4.2 文件内容 本文介绍solr的功能使用及相关注意事项;主要包括以下内容:环境搭建及调试;两个核心配置文件介绍;维护索引;查询索引,和在 ...

  7. Win RT Webview获取cookie

    方法1: HttpBaseProtocolFilter filter = new HttpBaseProtocolFilter(); var cookis = filter.CookieManager ...

  8. c# 类的反射实例 (GetType().Invoke().GetMethod().CreateInstance())

    原文:http://www.cnblogs.com/chenwei19/archive/2009/02/04/1384034.html Class1和Form 窗体在同一个命名空间 using Sys ...

  9. WinForm中DataGridView的使用(四) - 区分单双击事件

    虽然DataGridView单双击事件都有,但双击事件其实也会触发单击事件的处理,所以如果双击事件和单击事件的行为不同,或者双击时不想触发单击事件,或者单击事件会阻塞双击事件的处理时(比如单击后会有弹 ...

  10. 使用docker部署java项目

    在接触了docker后,干什么都想用docker来弄.最近刚做完毕业设计,本来是说将项目简单在本地部署就行了,结果老师说如果部署在服务器的话有加加分,于是果断用docker来搞,多加点分. java项 ...