1. 闲来无事又瞎折腾 binder 源码,以前 看binder理论 云里雾里的不知所云,于是就来折腾了,只为念头通透。
2. 从bindService 方法开始来了解 java binder 对象的传递过程.基于4.4源码:
ContextImpl.java
1.以此为入口 sd 是一个java binder。
ActivityManagerNative.getDefault().bindService(
mMainThread.getApplicationThread(), getActivityToken(),
service, service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, user.getIdentifier());
ActivityManagerProxy.java
2.
public int bindService(IApplicationThread caller, IBinder token,
Intent service, String resolvedType, IServiceConnection connection,
int flags, int userId) throws RemoteException {
....
data.writeStrongBinder(connection.asBinder()); //asBinder()返回 是本身
....
return res;
}
Parcel.java---》Android_os_Parcel.cpp
3.
static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jint nativePtr, jobject object)
{
...
const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object));
...
}
Android_utils_Binder.cpp
4.为java Object 对象创建 c层的Binder 对象,神来之笔简化了应用层.
sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj)
{
if (obj == NULL) return NULL;
//Binder.java
if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) {
//这个对jbh 对象创建是在java Binder构造时调用init()创建的
JavaBBinderHolder* jbh = (JavaBBinderHolder*)
env->GetIntField(obj, gBinderOffsets.mObject);
//这里获取到一个JavaBBinder
return jbh != NULL ? jbh->get(env, obj) : NULL;
}
//BinderProxy.java
if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) {
// mObject对象指向的 c层的一个BpBinder指针
return (IBinder*)
env->GetIntField(obj, gBinderProxyOffsets.mObject);
}
ALOGW("ibinderForJavaObject: %p is not a Binder object", obj);
return NULL;
}
Parcel.cpp
5.将Binder 写入 Parcel 缓冲区
status_t flatten_binder(const sp<ProcessState>& proc,
const sp<IBinder>& binder, Parcel* out)
{
flat_binder_object obj;
obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
if (binder != NULL) {
IBinder *local = binder->localBinder();//不为空 返回JavaBBinder 对象
if (!local) {
BpBinder *proxy = binder->remoteBinder();
if (proxy == NULL) {
ALOGE("null proxy");
}
...
} else {
//执行这个
obj.type = BINDER_TYPE_BINDER;
obj.binder = local->getWeakRefs();
obj.cookie = local; //JavaBBinder对象
}
} else {
obj.type = BINDER_TYPE_BINDER;
obj.binder = NULL;
obj.cookie = NULL;
}
//写入内存
return finish_flatten_binder(binder, obj, out);
}
2.1 代码不难,难点在于理解数据的存储结构.可以在service_manager.c,bctest.c 找到一些用于的信息,这些结构没有那么多业务数据易于理解:
1.bctest.c
int svcmgr_publish(struct binder_state *bs, void *target, const char *name, void *ptr)
{
unsigned status;
unsigned iodata[512/4];
struct binder_io msg, reply;
...
//格式化数据存储的格式
bio_init(&msg, iodata, sizeof(iodata), 4);
...
//
bio_put_obj(&msg, ptr);
if (binder_call(bs, &msg, &reply, target, SVC_MGR_ADD_SERVICE))
....
return status;
}
2.bio_init
void bio_init(struct binder_io *bio, void *data,
uint32_t maxdata, uint32_t maxoffs)
{
uint32_t n = maxoffs * sizeof(uint32_t);// 4*4
....
//数据是从偏移量16 开始的插入的
bio->data = bio->data0 = (char *) data + n;
//指向数组首地址
bio->offs = bio->offs0 = data;
//还剩多少数据可以用,这里不像 Parcel.cpp 还能扩容而且还没有限制
bio->data_avail = maxdata - n; //512-16
bio->offs_avail = maxoffs; // 能放四个Binder 对象或者其他东西,不管你存什么当Binder 驱动返回这些数据时能用就行,当然你先于你的代码,乱写系统就不认识了
bio->flags = 0;
}
binder.c
//存放Binder
3.调用bio_put_obj 方法插入类似binder对象的数据
void bio_put_obj(struct binder_io *bio, void *ptr)
{
struct binder_object *obj;
obj = bio_alloc_obj(bio);
....
obj->pointer = ptr; // 指针想存啥都行
...
}
4.bio_alloc_obj
static struct binder_object *bio_alloc_obj(struct binder_io *bio)
{
struct binder_object *obj;
obj = bio_alloc(bio, sizeof(*obj));
if (obj && bio->offs_avail) {
bio->offs_avail--;
// 前十六个字节用来表示这个,偏移量就是已存放数据的大小减去bio->data0(数组+4)
*bio->offs++ = ((char*) obj) - ((char*) bio->data0);
return obj;
}
bio->flags |= BIO_F_OVERFLOW;
return 0;
}
static void *bio_alloc(struct binder_io *bio, uint32_t size)
{
size = (size + 3) & (~3); // 在Parcel.cpp write 方法开头时 也用这样的方法,因为前面16个字节用来表示其他东西了 (一个int 用四字节表示,四个int).
if (size > bio->data_avail) {
bio->flags |= BIO_F_OVERFLOW;
return 0;
} else {
void *ptr = bio->data;
bio->data += size;
bio->data_avail -= size;
return ptr;
}
}
2.2 内存数据:
2.3 向binder 驱动传递数据:
1.向binder 驱动写数据
int binder_call(struct binder_state *bs,
struct binder_io *msg, struct binder_io *reply,
void *target, uint32_t code)
{
int res;
struct binder_write_read bwr; // binder 驱动第一次调用copy_from_user() bwr 数据
struct {
uint32_t cmd;
struct binder_txn txn; //等于 binder_transaction_data, binder 驱动第二次调用copy_from_user() txn 数据
} writebuf;
unsigned readbuf[32];
if (msg->flags & BIO_F_OVERFLOW) {
fprintf(stderr,"binder: txn buffer overflow\n");
goto fail;
}
writebuf.cmd = BC_TRANSACTION;
writebuf.txn.target = target;
writebuf.txn.code = code;
writebuf.txn.flags = 0;
writebuf.txn.data_size = msg->data - msg->data0;
writebuf.txn.offs_size = ((char*) msg->offs) - ((char*) msg->offs0);
writebuf.txn.data = msg->data0; // binder 驱动第三次调用copy_from_user() 拷贝用户传递数据
writebuf.txn.offs = msg->offs0;//binder 驱动第四次调用copy_from_user() 拷贝用户传递binder 数据
bwr.write_size = sizeof(writebuf);
bwr.write_consumed = 0;
bwr.write_buffer = (unsigned) &writebuf;
hexdump(msg->data0, msg->data - msg->data0);
for (;;) {
bwr.read_size = sizeof(readbuf);
bwr.read_consumed = 0;
bwr.read_buffer = (unsigned) readbuf;
//调用驱动
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
...
}
为什么调用copy_from_user()一次不能把所有数据拷贝过来呢,原因它传递的是指针,拷贝过来的也是指针。msg->data0 和msg->offs0最好的证明,还有Parcel.cpp 普通数据和flat_binder_object 对象 都是是通过调用malloc()方法分配内存的,指针是不一样的,并不像上面一样他们是连续的在一个数组中。唯一我不懂的是,上面offs 指向的是数组首地址,调用copy_from_user()也拷贝不了对相应binder对象的数据,而 下面tr.data.ptr.offsets 指向的是存放着所有flat_binder_object对象内存首地址,完全能拷贝binder 对象数据。
3.当数据写完时,接着构造驱动数据: BpBinder.transact(...)-> IPCThreadState->transact()->IPCThreadState->writeTransactionData(...)
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.handle = handle;
tr.code = code;
tr.flags = binderFlags;
tr.cookie = 0;
tr.sender_pid = 0;
tr.sender_euid = 0;
const status_t err = data.errorCheck();
if (err == NO_ERROR) {
tr.data_size = data.ipcDataSize(); // 普通数据的大小
tr.data.ptr.buffer = data.ipcData(); //普通数据首地址
tr.offsets_size = data.ipcObjectsCount()*sizeof(size_t);// flat_binder_object 对象的个数
tr.data.ptr.offsets = data.ipcObjects(); //存放flat_binder_object对象内存首地址
}
....
mOut.writeInt32(cmd);
mOut.write(&tr, sizeof(tr));
return NO_ERROR;
}
4.调用 IPCThreadState->waitForResponse(...) 进入binder 内核代码(只分析java binder 对象传递流程 ):
binder.c
1.binder_transaction{
...
//tr 数据结构看第三个代码段
//ALIGN 等于 data_size+3 为啥加+3 看第二个代码段
offp = (size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *)));
//data.ptr.buffer 指向存放着用户态的普通数据地址,拷贝到内核态
if (copy_from_user(t->buffer->data, tr->data.ptr.buffer, tr->data_size)) {
...
}
//data.ptr.offsets 指向存放用户态的flat_binder_object地址
if (copy_from_user(offp, tr->data.ptr.offsets, tr->offsets_size)) {
...
}
//以上两个操作将用户态 数据拷贝到内核态
off_end = (void *)offp + tr->offsets_size;
// 遍历flat_binder_object 对象
for (; offp < off_end; offp++) {
struct flat_binder_object *fp;
if (*offp > t->buffer->data_size - sizeof(*fp) ||
t->buffer->data_size < sizeof(*fp) ||
!IS_ALIGNED(*offp, sizeof(void *))) {
...
}
fp = (struct flat_binder_object *)(t->buffer->data + *offp);
switch (fp->type) {
//传递的是BINDER_TYPE_BINDER
case BINDER_TYPE_BINDER:
case BINDER_TYPE_WEAK_BINDER: {
struct binder_ref *ref;
//proc 调用者的进程 ,用户态fp->binder 弱指针 ,第一次进入 node 为null
struct binder_node *node = binder_get_node(proc, fp->binder);
if (node == NULL) {
//为当前进程 java binder对象 在Binder 驱动内建立binder_node 节点
node = binder_new_node(proc, fp->binder, fp->cookie);
if (node == NULL) {
return_error = BR_FAILED_REPLY;
goto err_binder_new_node_failed;
}
node->min_priority = fp->flags & FLAT_BINDER_FLAG_PRIORITY_MASK;
node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS);
}
...
// target_proc 为ActivityManagerService进程
// 为这个进程建立一个binder_ref指向binder_node.
ref = binder_get_ref_for_node(target_proc, node);
if (ref == NULL) {
return_error = BR_FAILED_REPLY;
goto err_binder_get_ref_for_node_failed;
}
//转变类型!!!!
if (fp->type == BINDER_TYPE_BINDER)
fp->type = BINDER_TYPE_HANDLE;
else
fp->type = BINDER_TYPE_WEAK_HANDLE;
// 拿到这个进程指向binder_node 的handle
//对于同一个进程handle 是唯一的,代码在binder_get_ref_for_node()可以得到结论.
fp->handle = ref->desc;
binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE,
&thread->todo);
binder_debug(BINDER_DEBUG_TRANSACTION,
" node %d u%p -> ref %d desc %d\n",
node->debug_id, node->ptr, ref->debug_id,
ref->desc);
} break;
...
}
...
}
5.binder 驱动处理完,唤醒对应的进程处理数据:
IPCThreadState.cpp
status_t IPCThreadState::executeCommand(int32_t cmd)
{
BBinder* obj;
RefBase::weakref_type* refs;
status_t result = NO_ERROR;
switch (cmd) {
...
case BR_TRANSACTION:
{
.....
// 在binder 驱动 binder_thread_read()中会通过target_node 把cookie赋值给ptr
//cookie是什么可以看看 第二个代码段
//这里 tr.target.ptr是ActivityManagerSerice的JavaBBinder
if (tr.target.ptr) {
sp<BBinder> b((BBinder*)tr.cookie);
const status_t error = b->transact(tr.code, buffer, &reply, tr.flags);
if (error < NO_ERROR) reply.setError(error);
}
....
return result;
}
2.调用JavaBBinder
virtual status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0)
{
JNIEnv* env = javavm_to_jnienv(mVM);
...
//mObject 指向ActivityManagerService
// 不知道调用哪个方法可以看看android_utils_Binder 的int_register_android_os_Binder方法
jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,
code, (int32_t)&data, (int32_t)reply, flags);
jthrowable excep = env->ExceptionOccurred();
...
}
3.执行 Binder.execTransact()-> ActivityManagerService->onTransact()->ActivityManager.onTransact
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
switch (code) {
...
case BIND_SERVICE_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder b = data.readStrongBinder();
IApplicationThread app = ApplicationThreadNative.asInterface(b);
IBinder token = data.readStrongBinder();
Intent service = Intent.CREATOR.createFromParcel(data);
String resolvedType = data.readString();
//怎么样写就怎么样读就对了 ,所以这里是读取ServiceConnection
b = data.readStrongBinder();
int fl = data.readInt();
int userId = data.readInt();
IServiceConnection conn = IServiceConnection.Stub.asInterface(b);
int res = bindService(app, token, service, resolvedType, conn, fl, userId);
reply.writeNoException();
reply.writeInt(res);
return true;
}
...
}
4. android_os_Parcel.cpp
static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jclass clazz, jint nativePtr)
{
...
//为binder对象创建Java 对象
return javaObjectForIBinder(env, parcel->readStrongBinder());
...
}
5.Parcel.cpp
status_t unflatten_binder(const sp<ProcessState>& proc,
const Parcel& in, sp<IBinder>* out)
{
const flat_binder_object* flat = in.readObject(false);
if (flat) {
switch (flat->type) {
case BINDER_TYPE_BINDER:
*out = static_cast<IBinder*>(flat->cookie);
return finish_unflatten_binder(NULL, *flat, in);
//从第四段驱动代码中BINDER_TYPE_BINDER转成BINDER_TYPE_HANDLE
//所以执行者这一段
case BINDER_TYPE_HANDLE:
*out = proc->getStrongProxyForHandle(flat->handle);
return finish_unflatten_binder(
static_cast<BpBinder*>(out->get()), *flat, in);
}
}
return BAD_TYPE;
}
6.ProcessState.cpp
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
sp<IBinder> result;
AutoMutex _l(mLock);
//第一次没有插入一handle_entry
handle_entry* e = lookupHandleLocked(handle);
if (e != NULL) {
IBinder* b = e->binder; //第一次为空
if (b == NULL || !e->refs->attemptIncWeak(this)) {
...
//创建一个BpBinder!!!
b = new BpBinder(handle);
e->binder = b;
if (b) e->refs = b->getWeakRefs();
result = b;
}
...
}
return result;
}
7. 为BpBiner对象创建一个BinderProxy java 对象
jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
{
if (val == NULL) return NULL;
// 这个是BpBinder 对象这个方法默认返回false
if (val->checkSubclass(&gBinderOffsets)) {
// One of our own!
jobject object = static_cast<JavaBBinder*>(val.get())->object();
LOGDEATH("objectForBinder %p: it's our own %p!\n", val.get(), object);
return object;
}
// For the rest of the function we will hold this lock, to serialize
// looking/creation of Java proxies for native Binder proxies.
AutoMutex _l(mProxyLock);
// 第一次进入,所以object 为null;
jobject object = (jobject)val->findObject(&gBinderProxyOffsets);
if (object != NULL) {
jobject res = jniGetReferent(env, object);
if (res != NULL) {
ALOGV("objectForBinder %p: found existing %p!\n", val.get(), res);
return res;
}
LOGDEATH("Proxy object %p of IBinder %p no longer in working set!!!", object, val.get());
android_atomic_dec(&gNumProxyRefs);
val->detachObject(&gBinderProxyOffsets);
env->DeleteGlobalRef(object);
}
// 创建一个BinderProxy 对象
//不知道创建什么可以看下 int_register_android_os_BinderProxy()方法
object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor);
if (object != NULL) {
env->SetIntField(object, gBinderProxyOffsets.mObject, (int)val.get());
val->incStrong((void*)javaObjectForIBinder);
// The native object needs to hold a weak reference back to the
// proxy, so we can retrieve the same proxy if it is still active.
jobject refObject = env->NewGlobalRef(
env->GetObjectField(object, gBinderProxyOffsets.mSelf));
// 添加弱引用,第二次进来就不为空了
val->attachObject(&gBinderProxyOffsets, refObject,
jnienv_to_javavm(env), proxy_cleanup);
....
}
return object;
}
6.IServiceConnection.Stub.asInterface(b) 获取代理对象,代码懒得找,自己创建一个adil 文件
// 随便创建一个adil 文件就行了
public static com.test.testbiner.IHellolInterface asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
//如果这里obj 是stub 对象, 那么就返回JavaBBinder对象
// 什么情况下会返回JavaBBinder对象 ,是在获取handle 引用时,获取的进程跟binder 注册的进程是同一个 将会返回,可以编译一个adil运行下,也可以看看binder 驱动 在遍历flat_biner_object对象 类型为BINDER_TYPE_HANDLE 的代码
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.test.testbiner.IHellolInterface))) {
return ((com.test.testbiner.IHellolInterface)iin);
}
// 例子执行的是这个
return new com.test.testbiner.IHellolInterface.Stub.Proxy(obj);
}
画个图来说明数据的流向:
ps:有人说java service端也有BnBinder接口 .