相关源码文件:
// app 进程
/frameworks/base/core/java/android/app/Activity.java
/frameworks/base/core/java/android/app/Instrumentation.java
/frameworks/base/core/java/android/app/ActivityManagerNative.java
/frameworks/base/core/java/android/os/Binder.java
/frameworks/native/libs/binder/BpBinder.cpp
/frameworks/native/libs/binder/ProcessState.cpp
/frameworks/native/libs/binder/IPCThreadState.cpp
/frameworks/base/core/jni/android_os_Parcel.cpp
// ServiceManager 进程
/frameworks/native/cmds/servicemanager/service_manager.c
/frameworks/native/cmds/servicemanager/binder.c
// binder 驱动层
/drivers/android/binder.c
/drivers/staging/android/binder.c
Binder 驱动在 Android 中是无所不在的,比如最常见的 startActivity 和 startService 等等,都会经历多次进程间通信。那本文就基于 Activity 的启动流程,从 Java 层来跟踪分析服务的查找返回过程:
public void startActivityForResult(Intent intent, int requestCode,
@Nullable Bundle options) {
if (mParent == null) {
Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity(this,
mMainThread.getApplicationThread(), mToken, this,intent, requestCode, options);
...
} else {
...
}
}
public ActivityResult execStartActivity(Context who, IBinder contextThread,
IBinder token, Activity target,Intent intent, int requestCode, Bundle options) {
...
// 这里两次跨进程通讯,一次获取AMS,另一次通过AMS的startActivity
try {
int result = ActivityManagerNative.getDefault()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),token,
target != null ? target.mEmbeddedID : null,requestCode, 0, null, options);
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
return null;
}
static public IActivityManager getDefault() {
return gDefault.get();
}
private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
protected IActivityManager create() {
IBinder b = ServiceManager.getService("activity");
if (false) {
Log.v("ActivityManager", "default service binder = " + b);
}
IActivityManager am = asInterface(b);
if (false) {
Log.v("ActivityManager", "default service = " + am);
}
return am;
}
};
public static IBinder getService(String name) {
try {
IBinder service = sCache.get(name);
if (service != null) {
return service;
} else {
return getIServiceManager().getService(name);
}
} catch (RemoteException e) {
Log.e(TAG, "error in getService", e);
}
return null;
}
private static IServiceManager getIServiceManager() {
if (sServiceManager != null) {
return sServiceManager;
}
// Find the service manager,BinderInternal.getContextObject()返回的是BinderProxy,里面的mObject带有new bpBinder(0)地址
sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
return sServiceManager;
}
// 这里跟踪到 Native 层的源码里面
public static final native IBinder getContextObject();
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)
{
AutoMutex _l(mProxyLock);
// mClass = android/os/BinderProxy,其实就是 new 一个 java 的 BinderProxy
object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor);
if (object != NULL) {
// 把 BpBinder(0) 的地址设置给 BinderProxy 的 mObject 属性
env->SetLongField(object, gBinderProxyOffsets.mObject, (jlong)val.get());
}
return object;
}
这里会拿到BinderProxy对象。
final class BinderProxy implements IBinder {
public native boolean pingBinder();
public native boolean isBinderAlive();
public IInterface queryLocalInterface(String descriptor) {
return null;
}
public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
Binder.checkParcel(this, code, data, "Unreasonably large binder buffer");
return transactNative(code, data, reply, flags);
}
public native String getInterfaceDescriptor() throws RemoteException;
public native boolean transactNative(int code, Parcel data, Parcel reply,
int flags) throws RemoteException;
public native void linkToDeath(DeathRecipient recipient, int flags)
throws RemoteException;
public native boolean unlinkToDeath(DeathRecipient recipient, int flags);
public void dump(FileDescriptor fd, String[] args) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeFileDescriptor(fd);
data.writeStringArray(args);
try {
transact(DUMP_TRANSACTION, data, reply, 0);
reply.readException();
} finally {
data.recycle();
reply.recycle();
}
}
public void dumpAsync(FileDescriptor fd, String[] args) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeFileDescriptor(fd);
data.writeStringArray(args);
try {
transact(DUMP_TRANSACTION, data, reply, FLAG_ONEWAY);
} finally {
data.recycle();
reply.recycle();
}
}
BinderProxy() {
mSelf = new WeakReference(this);
}
@Override
protected void finalize() throws Throwable {
try {
destroy();
} finally {
super.finalize();
}
}
private native final void destroy();
private static final void sendDeathNotice(DeathRecipient recipient) {
if (false) Log.v("JavaBinder", "sendDeathNotice to " + recipient);
try {
recipient.binderDied();
}
catch (RuntimeException exc) {
Log.w("BinderNative", "Uncaught exception from death notification",
exc);
}
}
final private WeakReference mSelf;
private long mObject; //mObject即为native的new bpbinder(0)地址
private long mOrgue;
}
//transactNative通过jni调用android_os_BinderProxy_transact方法,位于android_util_Binder.cpp中
static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
jint code, jobject dataObj, jobject replyObj, jint flags) {
// 获取 native 层的 Parcel
Parcel* data = parcelForJavaObject(env, dataObj);
Parcel* reply = parcelForJavaObject(env, replyObj);
// 获取 BpBinder(0)
IBinder* target = (IBinder*) env->GetLongField(obj, gBinderProxyOffsets.mObject);
// 调用 BpBinder 的 transact 方法
status_t err = target->transact(code, *data, reply, flags);
return JNI_FALSE;
}
//调用 BpBinder 的 transact 方法,这里之前分析media添加过程也分析过,后面交给 IPCThreadState::self()对象发给binder驱动,通过binder驱动发给servicemanager。
BinderInternal.getContextObject()返回的是Java 层来看是一个 IBinder (BinderProxy)对象,BinderProxy中的元素mObject即 new BpBinder(0)的地址
static public IServiceManager asInterface(IBinder obj)
{
if (obj == null) {
return null;
}
IServiceManager in =
(IServiceManager)obj.queryLocalInterface(descriptor);
if (in != null) {
return in;
}
//这里返回一个ServiceManagerProxy的对象,obj即为BpBinder(0)的地址,通过java BinderProxy包装了一下。
return new ServiceManagerProxy(obj);
}
class ServiceManagerProxy implements IServiceManager {
public ServiceManagerProxy(IBinder remote) {
mRemote = remote;
}
public IBinder asBinder() {
return mRemote;
}
public IBinder getService(String name) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IServiceManager.descriptor);
data.writeString(name);
//mRemote是BinderProxy对象
mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
IBinder binder = reply.readStrongBinder();
reply.recycle();
data.recycle();
return binder;
}
public IBinder checkService(String name) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IServiceManager.descriptor);
data.writeString(name);
mRemote.transact(CHECK_SERVICE_TRANSACTION, data, reply, 0);
IBinder binder = reply.readStrongBinder();
reply.recycle();
data.recycle();
return binder;
}
public void addService(String name, IBinder service, boolean allowIsolated)
throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IServiceManager.descriptor);
data.writeString(name);
data.writeStrongBinder(service);
data.writeInt(allowIsolated ? 1 : 0);
mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);
reply.recycle();
data.recycle();
}
public String[] listServices() throws RemoteException {
ArrayList<String> services = new ArrayList<String>();
int n = 0;
while (true) {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IServiceManager.descriptor);
data.writeInt(n);
n++;
try {
boolean res = mRemote.transact(LIST_SERVICES_TRANSACTION, data, reply, 0);
if (!res) {
break;
}
} catch (RuntimeException e) {
// The result code that is returned by the C++ code can
// cause the call to throw an exception back instead of
// returning a nice result... so eat it here and go on.
break;
}
services.add(reply.readString());
reply.recycle();
data.recycle();
}
String[] array = new String[services.size()];
services.toArray(array);
return array;
}
public void setPermissionController(IPermissionController controller)
throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IServiceManager.descriptor);
data.writeStrongBinder(controller.asBinder());
mRemote.transact(SET_PERMISSION_CONTROLLER_TRANSACTION, data, reply, 0);
reply.recycle();
data.recycle();
}
private IBinder mRemote;
}
getIServiceManager 返回的其实就是 new BpBinder(0) ,只不过在 Java 层来看是一个 IBinder (BinderProxy)对象。我们接着往下跟踪 getService() 的具体实现。
public IBinder getService(String name) throws RemoteException {
// 构建一个发送数据的 Parcel 和一个接收数据的 Parcel
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
// 把请求数据写入 data
data.writeInterfaceToken(IServiceManager.descriptor);
data.writeString(name);
mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
IBinder binder = reply.readStrongBinder();
reply.recycle();
data.recycle();
return binder;
}
final class BinderProxy implements IBinder {
...
public native boolean transactNative(int code, Parcel data, Parcel reply,
int flags) throws RemoteException;
public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
return transactNative(code, data, reply, flags);
}
// mObject = new BpBinder(0)
private long mObject;
...
}
//根据gBinderProxyMethods变量transactNative会调用到android_os_BinderProxy_transact方法
//static const JNINativeMethod gBinderProxyMethods[] = {
/* name, signature, funcPtr */
// {"pingBinder", "()Z", (void*)android_os_BinderProxy_pingBinder},
// {"isBinderAlive", "()Z", (void*)android_os_BinderProxy_isBinderAlive},
// {"getInterfaceDescriptor", "()Ljava/lang/String;", (void*)android_os_BinderProxy_getInterfaceDescriptor},
// {"transactNative", "(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z", (void*)android_os_BinderProxy_transact},
// {"linkToDeath", "(Landroid/os/IBinder$DeathRecipient;I)V", (void*)android_os_BinderProxy_linkToDeath},
// {"unlinkToDeath", "(Landroid/os/IBinder$DeathRecipient;I)Z", (void*)android_os_BinderProxy_unlinkToDeath},
// {"destroy", "()V", (void*)android_os_BinderProxy_destroy},
//};
//位于frameworks\base\core\jni\android_util_Binder.cpp中
static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
jint code, jobject dataObj, jobject replyObj, jint flags) {
// 获取 native 层的 Parcel
Parcel* data = parcelForJavaObject(env, dataObj);
Parcel* reply = parcelForJavaObject(env, replyObj);
// 获取 BpBinder(0)
IBinder* target = (IBinder*) env->GetLongField(obj, gBinderProxyOffsets.mObject);
// 调用 BpBinder 的 transact 方法
status_t err = target->transact(code, *data, reply, flags);
return JNI_FALSE;
}
//位于frameworks\native\libs\binder\BpBinder.cpp
status_t BpBinder::transact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){
if (mAlive) {
status_t status = IPCThreadState::self()->transact(mHandle, code, data, reply, flags);
if (status == DEAD_OBJECT) mAlive = 0;
return status;
}
return DEAD_OBJECT;
}
// 在《Android Binder 驱动 - Media 服务的添加过程》一文中有详细介绍
status_t IPCThreadState::transact(int32_t handle,uint32_t code,
const Parcel& data,Parcel* reply, uint32_t flags){
...
}
下面主要来看下 ServiceManager 进程是如何回复我们的。
int main(int argc, char **argv)
{
struct binder_state *bs;
bs = binder_open(128*1024);
if (!bs) {
ALOGE("failed to open binder driver\n");
return -1;
}
if (binder_become_context_manager(bs)) {
ALOGE("cannot become context manager (%s)\n", strerror(errno));
return -1;
}
selinux_enabled = is_selinux_enabled();
sehandle = selinux_android_service_context_handle();
selinux_status_open(true);
if (selinux_enabled > 0) {
if (sehandle == NULL) {
ALOGE("SELinux: Failed to acquire sehandle. Aborting.\n");
abort();
}
if (getcon(&service_manager_context) != 0) {
ALOGE("SELinux: Failed to acquire service_manager context. Aborting.\n");
abort();
}
}
union selinux_callback cb;
cb.func_audit = audit_callback;
selinux_set_callback(SELINUX_CB_AUDIT, cb);
cb.func_log = selinux_log_callback;
selinux_set_callback(SELINUX_CB_LOG, cb);
binder_loop(bs, svcmgr_handler);
return 0;
}
//servicemanager进入binder_loop函数
void binder_loop(struct binder_state *bs, binder_handler func)
{
int res;
struct binder_write_read bwr;
uint32_t readbuf[32];
bwr.write_size = 0;
bwr.write_consumed = 0;
bwr.write_buffer = 0;
readbuf[0] = BC_ENTER_LOOPER;
binder_write(bs, readbuf, sizeof(uint32_t));
for (;;) {
bwr.read_size = sizeof(readbuf);
bwr.read_consumed = 0;
bwr.read_buffer = (uintptr_t) readbuf;
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
if (res < 0) {
ALOGE("binder_loop: ioctl failed (%s)\n", strerror(errno));
break;
}
res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
if (res == 0) {
ALOGE("binder_loop: unexpected reply?!\n");
break;
}
if (res < 0) {
ALOGE("binder_loop: io error %d %s\n", res, strerror(errno));
break;
}
}
}
int binder_parse(struct binder_state *bs, struct binder_io *bio,
uintptr_t ptr, size_t size, binder_handler func)
{
int r = 1;
uintptr_t end = ptr + (uintptr_t) size;
while (ptr < end) {
uint32_t cmd = *(uint32_t *) ptr;
ptr += sizeof(uint32_t);
switch(cmd) {
case BR_TRANSACTION: {
struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;
if ((end - ptr) < sizeof(*txn)) {
ALOGE("parse: txn too small!\n");
return -1;
}
binder_dump_txn(txn);
if (func) {
unsigned rdata[256/4];
struct binder_io msg;
struct binder_io reply;
int res;
bio_init(&reply, rdata, sizeof(rdata), 4);
bio_init_from_txn(&msg, txn);
// 先执行回调函数,fun函数是svcmgr_handler
res = func(bs, txn, &msg, &reply);
// 然后把执行结果写入 binder 驱动
binder_send_reply(bs, &reply, txn->data.ptr.buffer, res);
}
}
}
return r;
}
int svcmgr_handler(struct binder_state *bs,
struct binder_transaction_data *txn,
struct binder_io *msg,
struct binder_io *reply)
{
switch(txn->code) {
case SVC_MGR_GET_SERVICE:
case SVC_MGR_CHECK_SERVICE:
s = bio_get_string16(msg, &len);
if (s == NULL) {
return -1;
}
//找到handle的值
handle = do_find_service(bs, s, len, txn->sender_euid, txn->sender_pid);
if (!handle)
break;
bio_put_ref(reply, handle);
return 0;
...
}
bio_put_uint32(reply, 0);
return 0;
}
void bio_put_ref(struct binder_io *bio, uint32_t handle)
{
struct flat_binder_object *obj;
if (handle)
obj = bio_alloc_obj(bio);
else
obj = bio_alloc(bio, sizeof(*obj));
if (!obj)
return;
// 向 replay 中写入一个 flat_binder_object
obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
obj->type = BINDER_TYPE_HANDLE;
obj->handle = handle;
obj->cookie = 0;
}
void binder_send_reply(struct binder_state *bs,
struct binder_io *reply,
binder_uintptr_t buffer_to_free,
int status)
{
struct {
uint32_t cmd_free;
binder_uintptr_t buffer;
uint32_t cmd_reply;
struct binder_transaction_data txn;
} __attribute__((packed)) data;
// 第一个命令是BC_FREE_BUFFER,释放之前的数据占用的内存
data.cmd_free = BC_FREE_BUFFER;
data.buffer = buffer_to_free;
// 第二个命令是BC_REPLY,回复命令
data.cmd_reply = BC_REPLY;
data.txn.target.ptr = 0;
data.txn.cookie = 0;
data.txn.code = 0;
if (status) {
...
} else {
// 把回复的数据写入data.txn
data.txn.flags = 0;
data.txn.data_size = reply->data - reply->data0;
data.txn.offsets_size = ((char*) reply->offs) - ((char*) reply->offs0);
data.txn.data.ptr.buffer = (uintptr_t)reply->data0;
data.txn.data.ptr.offsets = (uintptr_t)reply->offs0;
}
binder_write(bs, &data, sizeof(data));
}
int binder_write(struct binder_state *bs, void *data, size_t len)
{
struct binder_write_read bwr;
int res;
bwr.write_size = len;
bwr.write_consumed = 0;
bwr.write_buffer = (uintptr_t) data;
bwr.read_size = 0;
bwr.read_consumed = 0;
bwr.read_buffer = 0;
// 向驱动层写入数据,read_size = 0
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
if (res < 0) {
fprintf(stderr,"binder_write: ioctl failed (%s)\n",
strerror(errno));
}
return res;
}
客户端是怎么进入等待的?。
客户端是因为在请求服务端的时候驱动层会写入一个 BINDER_WORK_TRANSACTION_COMPLETE , 然后会清空 writeData , 从新进入驱动层,进入读方法,因为todo队列里面没东西进入等待,等待服务端执行完毕唤醒客户端。流程如下:
status_t IPCThreadState::transact(int32_t handle,
uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags)
{
status_t err = data.errorCheck();
...
if (err == NO_ERROR) {
LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(),
(flags & TF_ONE_WAY) == 0 ? "READ REPLY" : "ONE WAY");
err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
}
...
if ((flags & TF_ONE_WAY) == 0) {
...
if (reply) {
//客户端在这里进入睡眠,等待服务端的回复
err = waitForResponse(reply);
} else {
Parcel fakeReply;
err = waitForResponse(&fakeReply);
}
#if 0
if (code == 4) { // relayout
ALOGI("<<<<<< RETURNING transaction 4");
} else {
ALOGI("<<<<<< RETURNING transaction %d", code);
}
#endif
IF_LOG_TRANSACTIONS() {
TextOutput::Bundle _b(alog);
alog << "BR_REPLY thr " << (void*)pthread_self() << " / hand "
<< handle << ": ";
if (reply) alog << indent << *reply << dedent << endl;
else alog << "(none requested)" << endl;
}
} else {
err = waitForResponse(NULL, NULL);
}
return err;
}
status_t IPCThreadState::transact(int32_t handle,
uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags)
{
...
flags |= TF_ACCEPT_FDS; //添加TF_ACCEPT_FDS
...
//等待响应
if ((flags & TF_ONE_WAY) == 0) { //检查本次通讯是否有TF_ONE_WAY标志,即没有响应
//reply是否为空
if (reply) {
err = waitForResponse(reply);
} else {
Parcel fakeReply;
err = waitForResponse(&fakeReply);
}
...
}
...
return err;
}
一般通讯都需要响应,所以我们就只看有响应的情况了,即flags中不包含TF_ONE_WAY标记。调用waitForResponse()函数时,如果没有reply,会创建一个fakeReplay。我们回顾一下:
transact(0, IBinder::PING_TRANSACTION, data, NULL, 0)
紧接着,我们就进入到IPCThreadState::waitForResponse()中了。
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
...
while (1) {
//真正和Binder驱动交互的是talkWithDriver()函数
if ((err=talkWithDriver()) < NO_ERROR) break;
...
}
...
}
这个方法中,一开始就有些隐蔽的调用了一个十分重要的方法IPCThreadState::talkWithDriver(),从名字也能看出来,真正和Binder驱动talk的逻辑是在这个函数中的。这个地方给差评!
IPCThreadState::talkWithDriver()这个函数的参数默认为true!
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
...
//读写结构体,它是用户空间和内核空间的信使
binder_write_read bwr;
...
//配置发送信息
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 = 0;
bwr.read_buffer = 0;
}
...
//设置消耗为0
bwr.write_consumed = 0;
bwr.read_consumed = 0;
status_t err;
do {
...
//通过ioctl操作与内核进行读写
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
err = NO_ERROR;
...
} while (err == -EINTR);
...
}
这个函数中,有一个重要结构被定义,就是binder_write_read。它能够储存一些必要的发送和接收的通讯信息,它就像用户空间和内核空间之间的一个信使一样,在两端传递信息。
在这个函数中,首先会把用户空间要传递/读取信息放到bwr中,然后通过一句关键的代码ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr)与Binder驱动talk。
注意这里我们给ioctl()函数传递的参数。
第一个参数,是从本进程中取出上面篇中打开并保存Binder设备文件描述符,通过它可以获取到之前生成的file文件结构,然后传给binder_ioctl()函数。没印象的同学先看看上篇回顾下这里。
第二个参数,是命令,它决定了待会到内核空间中要执行那段逻辑。
第三个参数,我们把刚刚定义的信使bwr的内存地址传到内核空间去。
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret;
// 从file结构体中取出进程信息
struct binder_proc *proc = filp->private_data;
struct binder_thread *thread;
unsigned int size = _IOC_SIZE(cmd);
//表明arg是一个用户空间地址
//__user标记该指针为用户空间指针,在当前空间内无意义
void __user *ubuf = (void __user *)arg;
...
//锁定同步
binder_lock(__func__);
//取出线程信息
thread = binder_get_thread(proc);
...
switch (cmd) {
//读写数据
case BINDER_WRITE_READ:
ret = binder_ioctl_write_read(filp, cmd, arg, thread);
...
}
...
}
...
//解锁
binder_unlock(__func__);
...
}
static int binder_ioctl_write_read(struct file *filp,
unsigned int cmd, unsigned long arg,
struct binder_thread *thread)
{
int ret = 0;
//获取发送进程信息
struct binder_proc *proc = filp->private_data;
unsigned int size = _IOC_SIZE(cmd);
//来自用户空间的参数地址
void __user *ubuf = (void __user *)arg;
//读写信息结构体
struct binder_write_read bwr;
...
//拷贝用户空间的通讯信息bwr到内核的bwr
if (copy_from_user(&bwr, ubuf, sizeof(bwr)))
...
if (bwr.write_size > 0) {
//写数据
ret = binder_thread_write(proc, thread,
bwr.write_buffer,
bwr.write_size,
&bwr.write_consumed);
...
}
首先自然是取出用户空间的进程信息,然后转换获得用户空间的参数地址(对应本次通讯中为bwr的地址),这些都跟在binder_ioctl()中做的差不多。
接下来,你可以看到一个binder_write_read结构的申明struct binder_write_read bwr,紧跟着通过copy_from_user(&bwr, ubuf, sizeof(bwr))把用户空间的bwr拷贝到了当前内核空间的bwr。现在,Binder内核空间的bwr就获取到了来自用户空间的通讯信息了。
获取到来自用户空间的信息后,先调用binder_thread_write()函数来处理,我看看是如何进行处理的。
static int binder_thread_write(struct binder_proc *proc,
struct binder_thread *thread,
binder_uintptr_t binder_buffer, size_t size,
binder_size_t *consumed)
{
uint32_t cmd;
void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
void __user *ptr = buffer + *consumed; //起始地址
void __user *end = buffer + size; //结束地址
while (ptr < end && thread->return_error == BR_OK) {
//从用户空间获取cmd命令
if (get_user(cmd, (uint32_t __user *)ptr)) -EFAULT;
ptr += sizeof(uint32_t);
switch (cmd) {
case BC_TRANSACTION:
case BC_REPLY: {
//用来储存通讯信息的结构体
struct binder_transaction_data tr;
//拷贝用户空间的binder_transaction_data
if (copy_from_user(&tr, ptr, sizeof(tr))) return -EFAULT;
ptr += sizeof(tr);
//处理通讯
binder_transaction(proc, thread, &tr, cmd == BC_REPLY);
break;
}
...
}
*consumed = ptr - buffer;
}
return 0;
}
首先,binder_buffer是啥?哪来的?快到到传参的地方方看看bwr.write_buffer,它是写的buffer。那么它里面装了啥?bwr.write_buffer = (uintptr_t)mOut.data(),嗯,它指向了mOut中的数据。那么问题又来了?mOut中的数据是啥?…
writeTransactionData(),就是通讯事务结构定义的那个地方。看到没,mOut中储存的就是一个通讯事务结构。如下:
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 = 0; //binder_node的地址
tr.target.handle = handle; //用于查找目标进程Binder的handle,对应binder_ref
tr.code = code; //表示事务类型
tr.flags = binderFlags;
tr.cookie= 0;
...
//Parcel mOut,与之相反的有Parcel mIn
//写入本次通讯的cmd指令
mOut.writeInt32(cmd);
//把本次通讯事务数据写入mOut中
mOut.write(&tr, sizeof(tr));
return NO_ERROR;
}
这个函数主要创建了一个用于储存通讯事务数据的binder_transaction_data结构t,
并把需要发送的事务数据放到其中,然后再把这个tr写入IPCThreadState的mOut中。
这样一来,后面就可以从mOut中取出这个通讯事务数据结构了。
回到binder_thread_write函数中
通过get_user(cmd, (uint32_t __user *)ptr)函数,我们可以将用户空间的tr的cmd拷贝到内核空间。get_user()和put_user()这对函数就是干这个的,拷贝一些简单的变量。回到第2步writeTransactionData()中,看看参数。没错,cmd为BC_TRANSACTION。所以,进到switch中,对应执行的就是case BC_TRANSACTION。
可以看到BC_TRANSACTION事务命令和BC_REPLAY响应命令,执行的是相同的逻辑。
binder_transaction()来处理事务,先看第一个使用到的参数replay。由于上一步中的cmd为BC_TRANSACTION,所以很明显,走的是false,所以我们直接看false里的逻辑。
static void binder_transaction(struct binder_proc *proc,
struct binder_thread *thread,
struct binder_transaction_data *tr, int reply){
// reply=(cmd==BC_REPLY)即false
...
if (reply) {
...
} else {
if (tr->target.handle) {
//如果参数事物信息中的进程的句柄不为0,即不是系统ServiceManager进程
//定义binder引用
struct binder_ref *ref;
//根据参数binder进程和句柄handle来查找对应的binder
ref = binder_get_ref(proc, tr->target.handle);
...
//设置目标binder实体为上面找到的参数进程的binder引用的binder实体
target_node = ref->node;
} else {
//如果参数事物信息中的进程的句柄为0,即是系统ServiceManager进程
//设置通讯目标进程的Binder实体为ServiceManager对应的Binder
target_node = binder_context_mgr_node;
}
//设置通讯目标进程为target_node对应的进程
target_proc = target_node->proc;
...
//判断目标线程是否为空
//首先看target_thread是否为空,由于我们没有走if(replay)的TRUE逻辑,所以这里target_thread是为空的。那么,从目标进程信息target_proc分别去除todo任务队列和wait对象,赋值给target_list和target_wait。同样需要记住!
if (target_thread) {
...
//目标线程的todo队列
target_list = &target_thread->todo;
target_wait = &target_thread->wait;
...
} else {
//获得通讯目标进程的任务队列
target_list = &target_proc->todo;
//获取通讯目标进程的等待对象
target_wait = &target_proc->wait;
}
...
/*其实这么多代码,主要使用在给binder事务t的成员赋值了。我们简单看几个我认为重要的赋值。
首先为事务t和work tcomplete申请了内存。然后设置事务t的from线程(也就是发送方线程)的值,如果不是BC_REPLAY事务,并且通讯标记没有TF_ONE_WAY(即本次通讯需要有响应),那么把参数thread赋值给t->from。前面说过,我们本次通讯是BC_TRANSACTION事务,所以事务t就需要储存发送方的线程信息,以便后面给发送方响应使用。
参数thread是那来的呢?顺着往回找,在binder_ioctl()中,我们从用户空间调用ioctl()函数的进程(即发送方进程)的进程信息中获取到了thread。
接着设置事务t的目标进程t->to_proc和目标进程的线程t->to_thread为前面处理好的target_proc和target_thread(本次通讯,target_thread为空哦)
然后把通讯事务数据tr中的code和flags赋值给事务t的code和flags。code和flags是什么呢?我们回到用户空间,定义通讯事务数据,即IPCThreadState::writeTransaction()中可以看到,code和flags均是传进来的参数。而的发源地是通讯的起始点IPCThreadState::self()->transact(0, IBinder::PING_TRANSACTION, data, NULL, 0),即code = IBinder::PING_TRANSACTION, flags = 0。记住了哦!后面还会用。
然后开始设置事务t的buffer信息。首先通过binder_alloc_buf()函数,在目标进程target_proc中为t->buffer申请了内存,即t->buffer指向了目标进程空间中的一段内存。然后配置一下t->buffer的信息,这些信息后面也会用到。记住了哦!
接着通过copy_from_user()函数,把用户空间的需要发送的数据拷贝到t->buffer的data中。
再往下到了if(replay),本次通讯会走false逻辑。于是,事务t会把发送方的事务栈transaction_stack储存在from_parent中,而发送方把自己的事务栈设置以成t开始。这些都需要记住,不然再往后你就会越来越迷糊!
*/
//为本次通讯事务t申请空间
t = kzalloc(sizeof(*t), GFP_KERNEL);
...
tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL);
...
if (!reply && !(tr->flags & TF_ONE_WAY))
//采用非one way通讯方式,即需要等待服务端返回结果的通讯方式
//设置本次通讯事务t的发送线程为用户空间的线程
t->from = thread;
else
t->from = NULL;
...
//设置本次通讯事务的接收进程为目标进程
t->to_proc = target_proc;
//设置本次通讯事务的接收线程为目标线程
t->to_thread = target_thread;
//设置本次通讯事务的命令为用户空间传来的命令
t->code = tr->code;
//设置本次通讯事务的命令为用户空间传来的flags
t->flags = tr->flags;
...
//开始配置本次通讯的buffer
//在目标进程中分配进行本次通讯的buffer的空间
t->buffer = binder_alloc_buf(target_proc, tr->data_size,
tr->offsets_size, !reply && (t->flags & TF_ONE_WAY));
t->buffer->allow_user_free = 0; //通讯buffer允许释放
t->buffer->transaction = t; //把本次通讯存入buffer中
//设置本次通讯的buffer的目标Binder实体为target_node
//如前面一样,通过这个buffer可以找到对应的进程
t->buffer->target_node = target_node;
...
offp = (binder_size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *)));
//将用户空间发送来的数据拷贝到本次通讯的buffer的data中
copy_from_user(t->buffer->data, (const void __user *)(uintptr_t)tr->data.ptr.buffer, tr->data_size);
...
//将用户空间发送来的偏移量offsets拷贝给起始offp
copy_from_user(offp, (const void __user *)(uintptr_t)tr->data.ptr.offsets, tr->offsets_size);
...
//计算结尾off_end
off_end = (void *)offp + tr->offsets_size;
...
//判断是否是BC_REPLY
if (reply) {
...
binder_pop_transaction(target_thread, in_reply_to);
} else if (!(t->flags & TF_ONE_WAY)) {
//如果没有ONE_WAY标记,即需要等待响应
t->need_reply = 1; //1标示这是一个同步事务,需要等待对方回复。0表示这是一个异步事务,不用等对方回复
//设置本次通讯事务的from_parent为发送方进程的事务
t->from_parent = thread->transaction_stack;
//设置发送方进程的事务栈为本次通讯事务
thread->transaction_stack = t;
}
...
/*先把事务t的work.type类型设置为BINDER_WORK_TRANSACTION类型,这决定了该事务后面走的流程,然后把事务t的任务添加到目标进程的任务栈target_list中。接着把work tcomplete的类型设置为BINDER_WORK_TRANSACTION_COMPLETE,用于告诉发送方,和Binder驱动的一次talk完成了,同样,需要把这个项任务添加到发送方的任务列表里。
最后,通过wake_up_interruptible(target_wait)函数唤醒休眠中的目标进程,让它开始处理任务栈中的任务,也就是刚刚我们添加到target_list中的任务。接着return结束该函数。*/
//将本次通讯事务的work类型设置为BINDER_WORK_TRANSACTION
t->work.type = BINDER_WORK_TRANSACTION;
//将本次通讯事务的work添加到目标进程的事务列表中
list_add_tail(&t->work.entry, target_list);
//设置work类型为BINDER_WORK_TRANSACTION_COMPLETE
tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
//将BINDER_WORK_TRANSACTION_COMPLETE类型的work添加到发送方的事务列表中
list_add_tail(&tcomplete->entry, &thread->todo);
if (target_wait)
//唤醒目标进程,开始执行目标进程的事务栈
wake_up_interruptible(target_wait);//当target_node = binder_context_mgr_node时,这里唤醒的是servicemanager
return;
}
/*上一个函数结束后回到binder_thread_write()函数中,retrun 0;,binder_thread_write()函数结束。然后回到binder_ioctl_write_read()函数中继续执行。*/
static int binder_ioctl_write_read(struct file *filp,
unsigned int cmd, unsigned long arg,
struct binder_thread *thread)
{
...
if (bwr.read_size > 0) {
//读数据
ret = binder_thread_read(proc, thread, bwr.read_buffer,
bwr.read_size,
&bwr.read_consumed,
filp->f_flags & O_NONBLOCK);
...
}
//Binder驱动会调用binder_thread_read()函数,为发送进程读取数据。我们看看是怎么读取的。
/*
我们先看这个片段,前面一堆代码掠过了。首先,需要看看能不能从发送进程的线程thread的任务栈中取出任务来,回顾binder_transaction()中,我们在最后往发送进程的线程thread的任务栈中添加了一个BINDER_WORK_TRANSACTION_COMPLETE类型的work。所以这里是能取到任务的,就直接执行下一步了。
*/
```cpp
static int binder_thread_read(struct binder_proc *proc,
struct binder_thread *thread,
binder_uintptr_t binder_buffer,
size_t size,
binder_size_t *consumed,
int non_block)
{
...
while (1) {
uint32_t cmd;
struct binder_transaction_data tr;
struct binder_work *w;
struct binder_transaction *t = NULL;
if (!list_empty(&thread->todo)) {
//获取线程的work队列
w = list_first_entry(&thread->todo, struct binder_work, entry);
} else if (!list_empty(&proc->todo) && wait_for_proc_work) {
//获取从进程获取work队列
w = list_first_entry(&proc->todo, struct binder_work, entry);
} else {
//没有数据,则返回retry
if (ptr - buffer == 4 &&
!(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN))
goto retry;
break;
}
...
switch (w->type) {
...
case BINDER_WORK_TRANSACTION_COMPLETE:
//设置cmd为BR_TRANSACTION_COMPLETE
cmd = BR_TRANSACTION_COMPLETE;
//将BR_TRANSACTION_COMPLETE写入用户进程空间的mIn中
put_user(cmd, (uint32_t __user *)ptr);
//从事务队列中删除本次work
list_del(&w->entry);
//释放
kfree(w);
break;
...
}
}
//接着又会回到binder_ioctl_write_read()函数。
static int binder_ioctl_write_read(struct file *filp,
unsigned int cmd, unsigned long arg,
struct binder_thread *thread)
{
...
//将内核的信使bwr拷贝到用户空间
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
...
}
/*上面函数最后会把内核中的信使拷贝到用户空间。然后,我们直接的再次的回到第3步的函数IPCThreadState::waitForResponse()中。经过刚刚的读取,这次mIn中可是有数据了哦!我们从mIn中取出cmd命令。这是什么命令呢?就是刚刚写到用户空间的BR_TRANSACTION_COMPLETE。在这段逻辑中,由于之前我们传入了一个fakeReplay进来,所以程序走bredk,然后继续循环,执行下一次talkWithDriver()函数。到此,我们和Binder内核的一次通讯算是完成了。
*/
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
...
while (1) {
//真正和Binder驱动交互的是talkWithDriver()函数
if ((err=talkWithDriver()) < NO_ERROR) break;
err = mIn.errorCheck();
...
if (mIn.dataAvail() == 0) continue;
//取出在内核中写进去的cmd命令
cmd = mIn.readInt32();
...
switch (cmd) {
//表示和内核的一次通讯完成
case BR_TRANSACTION_COMPLETE:
if (!reply && !acquireResult) goto finish;
break;
...
}
}
经过刚刚的读取,这次mIn中可是有数据了哦!我们从mIn中取出cmd命令。这是什么命令呢?就是刚刚写到用户空间的BR_TRANSACTION_COMPLETE。在这段逻辑中,由于之前我们传入了一个fakeReplay进来,所以程序走bredk,然后继续循环,执行下一次talkWithDriver()函数。到此,我们和Binder内核的一次通讯算是完成了。
通讯发起端的休眠ING
发起端进程在收到Binder内核响应的BR_TRANSACTION_COMPLETE后,再一次的进入了IPCThreadState::talkWithDriver()函数。这就意味着发起端需要和Binder内核再通讯一次。
而这一次通讯,由于没有需要发送的的数据,所以我们直接看Binder内核中的binder_thread_read()函数,在图中找到对应的位置进入状态了啊。那么我们看看这一次发起端进程在binder_thread_read()函数中被进行了怎样的处理
static int binder_thread_read(struct binder_proc *proc,
struct binder_thread *thread,
binder_uintptr_t binder_buffer,
size_t size,
binder_size_t *consumed,
int non_block)
{
...
//检查是否需要等待进程work完成
wait_for_proc_work = thread->transaction_stack == NULL && list_empty(&thread->todo);
...
if (wait_for_proc_work) {
...
} else {
if (non_block) {
...
} else
//如果不需要等待,进程进入休眠,等待唤醒
ret = wait_event_freezable(thread->wait, binder_has_thread_work(thread));
}
...
我们只看关键的。还记得binder_transaction()函数中,我们最后把添加到目标进程中的事务t同时赋值给了发送端进程的thread->transaction_stack。所以此处的thread->transaction_stack是不为NULL的。从而wait_for_proc_work就为false,于是就执行到了ret = wait_event_freezable(thread->wait, binder_has_thread_work(thread));这一句,然后发送端进程就进入了休眠。目的是为了等待目标进程处理完请求后给予它响应。
现在,发送端进程进入了休眠,是时候来看一看本次通讯的目标进程了。在binder_transaction()函数中,我们把发送端的诉求封装进了一个事务t中,然后把事务t添加到了目标进程的事务队列中,最后把目标进程唤醒了。
第一步 从沉睡中醒来
static int binder_thread_read(struct binder_proc *proc,
struct binder_thread *thread,
binder_uintptr_t binder_buffer,
size_t size,
binder_size_t *consumed,
int non_block)
{
...
ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread));
...
if (ret)
return ret;
...
}
由于是通过正常的wake_up_interruptible()函数进行唤醒,所以返回的ret = 0。接着,目标进程会进入switch,根据之前设置的cmd执行相应逻辑。
static int binder_thread_read(struct binder_proc *proc,
struct binder_thread *thread,
binder_uintptr_t binder_buffer,
size_t size,
binder_size_t *consumed,
int non_block)
{
...
while (1) {
uint32_t cmd;
struct binder_transaction_data tr;
struct binder_work *w;
struct binder_transaction *t = NULL;
if (!list_empty(&thread->todo)) {
//获取线程的work队列
w = list_first_entry(&thread->todo, struct binder_work, entry);
} else if (!list_empty(&proc->todo) && wait_for_proc_work) {
//获取从进程获取work队列
w = list_first_entry(&proc->todo, struct binder_work, entry);
} else {
//没有数据,则返回retry
if (ptr - buffer == 4 &&
!(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN))
goto retry;
break;
}
switch (w->type) {
case BINDER_WORK_TRANSACTION:
//根据队列中的work获取包含该work的事务
t = container_of(w, struct binder_transaction, work);
break;
...
}
...
}
这部分需要结合binder_transaction()函数来看,很多参数都是来自于那的。
根据之前的逻辑,我们并没有给目标进程的thread->todo赋值,而是给它的proc->todo赋了值。如下:
if (target_thread) {
e->to_thread = target_thread->pid;
target_list = &target_thread->todo;
target_wait = &target_thread->wait;
} else {
target_list = &target_proc->todo;
target_wait = &target_proc->wait;
}
因此,我们从proc->todo的任务队列中取出之前添加的任务。因为任务类型是BINDER_WORK_TRANSACTION,所以swicth中走了BINDER_WORK_TRANSACTION的逻辑,获取到通讯事务t。接着看下面的逻辑。
static int binder_thread_read(struct binder_proc *proc,
struct binder_thread *thread,
binder_uintptr_t binder_buffer,
size_t size,
binder_size_t *consumed,
int non_block)
{
...
while (1) {
uint32_t cmd;
struct binder_transaction_data tr;
struct binder_work *w;
struct binder_transaction *t = NULL;
...
//只有BINDER_WORK_TRANSACTION命令,即t不为空才能继续往下执行
if (!t)
continue;
//判断事物t中是否有目标进程的Binder实体
if (t->buffer->target_node) {
struct binder_node *target_node = t->buffer->target_node;
tr.target.ptr = target_node->ptr;
tr.cookie = target_node->cookie;
t->saved_priority = task_nice(current);
...
cmd = BR_TRANSACTION; //设置命令为BR_TRANSACTION
} else {
tr.target.ptr = NULL;
tr.cookie = NULL;
cmd = BR_REPLY; //设置命令为BR_REPLY
}
//给刚刚定义的事务信息体设置成员的值
tr.code = t->code;
tr.flags = t->flags;
tr.sender_euid = t->sender_euid;
...
tr.data_size = t->buffer->data_size;
tr.offsets_size = t->buffer->offsets_size;
tr.data.ptr.buffer = (void *)t->buffer->data +
proc->user_buffer_offset;
tr.data.ptr.offsets = tr.data.ptr.buffer +
ALIGN(t->buffer->data_size,
sizeof(void *));
//将cmd和数据写回用户空间的mIn
if (put_user(cmd, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
//刚刚赋值好的事务信息写会用户空间的mIn,ptr是servicemanager用户空间传来的地址
if (copy_to_user(ptr, &tr, sizeof(tr)))
return -EFAULT;
ptr += sizeof(tr);
//删除本次work
list_del(&t->work.entry);
...
kfree(t); //通信完成,则运行释放
break;
}
...
return 0;
}
对于if(!t),很明显,我们是有事务t,所以代码会接着往下执行。
我们之前有t->buffer->target_node = target_node;,所以这里t->buffer->target_node)是不为空的。然后,取出这个target_node,也就是目标进程的Binder实体。
接着,把目标进程的Binder实体的引用和cookie缓存保存到新定义的通讯数据tr中。然后,设置命令为BR_TRANSACTION,这些都需要记好了哦。
接下来就是把事务t中的数据储存到新定义的通讯数据tr中。然后把刚刚的cmd拷贝到目标进程空间,再把新定义的通讯数据tr也拷贝到目标进程空间。最后删除本次事务,释放内存,结束该函数。
退出ioctl()函数
上一步函数结束后,函数基本都是一路退出,直到Binder内核的binder_ioctl()函数。至此,由于我们的目标进程是ServiceManager,所以binder_ioctl()函数执行完后,返回的是/frameworks/native/cmds/servicemanager/binder.c中的binder_looper()。
至于为什么会回到binder_looper()函数,这与ServiceManager的机制有关。由于它在系统中既是一个Service,又是一个守护进程,它需要不断的循环等待Client的请求。处理完一个请求,就再次进入循环等待下一个请求。而这个函数就是为它提供这种能力的。这里我们先不讨论ServiceManager工作原理,继续把目光聚焦在我们本次通讯的流程上。
我们进入/frameworks/native/cmds/servicemanager/binder.c中的binder_looper()看看在这个流程中它有什么用?
void binder_loop(struct binder_state *bs, binder_handler func)
{
...
for (;;) {
bwr.read_size = sizeof(readbuf);
bwr.read_consumed = 0;
bwr.read_buffer = (uintptr_t) readbuf;
...
//和binder通讯,等待Client链接
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
...
//解析Client的数据
res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
...
}
}
可以看到,ServiceManager通过一个无限循环,反复的进行ioctl()和binder_parse()操作。还记得第一步中,在没有消息时,ServiceManager会在Binder内核的binder_thread_read()函数中被休眠。
这里,从ioctl()函数出来后,表明ServiceManager收到了Binder内核传递过来的信息,所以下一步就是要多信息进行处理。
int binder_parse(struct binder_state *bs, struct binder_io *bio,
uintptr_t ptr, size_t size, binder_handler func)
{
int r = 1;
uintptr_t end = ptr + (uintptr_t) size;
while (ptr < end) {
uint32_t cmd = *(uint32_t *) ptr;
ptr += sizeof(uint32_t);
...
switch(cmd) {
case BR_NOOP:
break;
//通知ServiceManager通讯事务完成
case BR_TRANSACTION_COMPLETE:
break;
...
//执行事务
case BR_TRANSACTION: {
//获取通讯事务数据
struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;
...
if (func) {
unsigned rdata[256/4];
// 用于保存"Binder驱动反馈的信息"
struct binder_io msg;
// 用来保存"回复给Binder驱动的信息"
struct binder_io reply;
int res;
// 初始化reply
bio_init(&reply, rdata, sizeof(rdata), 4);
// 根据txn(Binder驱动反馈的信息)初始化msg
bio_init_from_txn(&msg, txn);
// 消息处理
res = func(bs, txn, &msg, &reply);
// 反馈消息给Binder驱动
binder_send_reply(bs, &reply, txn->data.ptr.buffer, res);
}
ptr += sizeof(*txn);
break;
}
case BR_REPLY: {
...
break;
}
...
}
}
return r;
}
首先关注参数ptr,它是ServiceManager传到内核空间的信使binder_write_read bwr的读取缓冲区read_buffer。在第二步binder_thread_read()中,我们在这个buffer中装了一个命令BR_TRANSACTION和一个事物数据tr。忘了快回过头看看吧。
end变量可以指向这个缓冲区结束位置,而此时的ptr是指向缓冲区的头部。所以能够进入while循环。接着从缓冲区中取出刚刚存入的命令cmd,然后将ptr移动一个cmd的距离。
前面说过Binder驱动传过来的cmd是BR_TRANSACTION类型,所以我们只看相关逻辑。
在BR_TRANSACTION中,首先要做的就是获得从Binder内核读取到的信息。可以看到,将参数ptr转换成了binder_transaction_data指针。接下来初始化两个binder_io结构,msg用来储存从Binder内核读取的信息,replay用来储存待会儿需要反馈给请求端的信息。然后通过bio_init_from_txn(&msg, txn)函数将从Binder内核读取的信息,存入msg中。然后我们看到,这里调用了一个fun()函数,它是一个函数指针,代表着svcmgr_handler()函数。不难看出,它就是ServiceManager用于处理Binder内核消息的函数。
//位于frameworks\native\cmds\servicemanager\service_manager.c
int svcmgr_handler(struct binder_state *bs,
struct binder_transaction_data *txn,
struct binder_io *msg,
struct binder_io *reply)
{
struct svcinfo *si;
uint16_t *s;
size_t len;
uint32_t handle;
uint32_t strict_policy;
int allow_isolated;
...
//测试指令PING_TRANSACTION直接返回
if (txn->code == PING_TRANSACTION)
return 0;
...
}
我们知道,binder_transaction_data装有来自Binder内核的消息。它装有的消息基本就是请求发起进程发送的消息,也就是其发送的binder_transaction_data里的信息。这部分你需要看上面的binder_transaction()和这一篇中的第一步binder_thread_read(),它们中关于binder_transaction_data结构的赋值逻辑需要理清楚。
既然如此,那么我们就回过头看发起请求的进程在binder_transaction_data结构中装了什么信息。我们需要回到IPCThreadState::writeTransactionData()函数中,也就是初始化发送信使binder_transaction_data的地方。在这里,我们可以看到,信使中的code码是参数传进来的。我们沿着这条线往回找,可以发现,就是一开始我们发起这次Binder通讯的地方status_t status = IPCThreadState::self()->transact(0, IBinder::PING_TRANSACTION, data, NULL, 0) ,设置了code为IBinder::PING_TRANSACTION。真想大白,code为PING_TRANSACTION类型就什么也不干,直接退出这个函数。这就是为什么说我们发起这次请求只是测试一下ServiceManager是否已经注册的原因。
实际上,如果code为其它情况的话,在这里会进行一些其它的逻辑。比如,添加一个Service或者查找获得一个Service。在后面遇到了再回过头了说。
上一步,service_manager.c中的svcmgr_handler()函数中,对请求端的请求进行了处理。然后函数退出,回到binder.c的binder_parse()继续执行。下一步就是给予请求端处理结果,即这一次ServiceManager要给请求端发送消息了。
//位于frameworks\native\cmds\servicemanager\binder.c
void binder_send_reply(struct binder_state *bs,
struct binder_io *reply,
binder_uintptr_t buffer_to_free,
int status)
{
struct {
uint32_t cmd_free;
binder_uintptr_t buffer;
uint32_t cmd_reply;
struct binder_transaction_data txn;
} __attribute__((packed)) data;
//把回复数据放到data中
data.cmd_free = BC_FREE_BUFFER;
data.buffer = buffer_to_free;
data.cmd_reply = BC_REPLY;
data.txn.target.ptr = 0;
data.txn.cookie= 0;
data.txn.code = 0;
if (status) {
...
} else {
data.txn.flags = 0;
data.txn.data_size = reply->data - reply->data0;
data.txn.offsets_size = ((char*) reply->offs) - ((char*) reply->offs0);
data.txn.data.ptr.buffer = (uintptr_t)reply->data0;
data.txn.data.ptr.offsets = (uintptr_t)reply->offs0;
}
//发送响应
binder_write(bs, &data, sizeof(data));
}
上面这段代码不长,它主要干了两个事:
定义并初始化储存回复信息的data结构体。其中,cmd_replay是本次通讯的指令,后面进行什么逻辑,是更具这个值判断的。
调用binder_write()函数,准备和Binder内核通讯,从而将回复信息传递给发送端。
int binder_write(struct binder_state *bs, void *data, size_t len)
{
struct binder_write_read bwr;
int res;
//初始化信使
bwr.write_size = len;
bwr.write_consumed = 0;
bwr.write_buffer = (uintptr_t) data;
bwr.read_size = 0;
bwr.read_consumed = 0;
bwr.read_buffer = 0;
//通过Binder发送响应
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
...
return res;
}
和Binder内核的通讯同样是通过ioctl()函数进行的。这会让代码逻辑回到/drivers/staging/android/binder.c中的binder_ioctl()函数中。
我们回到/drivers/staging/android/binder.c中的binder_ioctl()函数中,在图中找到对应位置哦!
逻辑其实和上一篇读取发送端消息,然后在传输给接收端大致是差不多的。只是中间的一些cmd不同,某些步骤执行的操作有区别罢了。
在binder_ioctl()函数中,同样先获取到发送过来的消息参数,然后由于调用ioctl()的参数是BINDER_WRITE_READ,所以直接进入binder_ioctl_write_read()函数。大家在图中找到对应位置。在这个函数中,由于是发送消息,所以会进入binder_thread_write()函数。
binder_thread_write()函数还是和之前差不多,先读取发送端的消息信息等,然后根据信使binder_write_read的write_buffer中的cmd决定执行什么逻辑。而这个cmd的值你可以回到binder_send_reply()中看看,它是BC_REPLY类型的。那么就简单了,和上一篇发送端逻辑一样,会进入到binder_transaction()函数中。
binder_transaction()函数就是之前说的有些复杂的函数,大家在图中继续找到对应位置啊。通过上一篇的阅读,相信你已经知道了这个函数主要会根据发送端信息(此时为ServiceManager)和接收端(原本的发送端)的信息,构造两个事务分别添加到发送端和接收端进程的事务列表中。同样,一个事务是给发送端通知本次你发送的信息Binder内核已经转发给接收端了,另一个事务自然是将发送端的消息带到接收端中处理。
binder_transaction()函数执行完后,对ServiceManager而言,由于执行的事务是告知ServiceManager本次Transication完成了,消息已经发送出去,即BINDER_WORK_TRANSACTION_COMPLETE命令,所以逻辑同上一篇的基本一致。总之函数一路执行完毕,然后回到/frameworks/native/cmds/servicemanager/binder.c的binder_parse()中。你可以在这个函数中看到:
...
case BR_TRANSACTION_COMPLETE:
break;
...
在图中找找对应位置哦。收到BR_TRANSACTION_COMPLETE指令后,直接break。然后binder_parse()函数执行完毕。代码逻辑回到第三步的binder_loop()中,由于有一个for循环,所以会再次执行到
void binder_loop(struct binder_state *bs, binder_handler func)
{
...
for (;;) {
...
//和binder通讯,等待Client链接
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
...
}
}
这一次和Binder内核ioctl通讯,由于没数据要发,所以会一路进入/drivers/staging/android/binder.c的binder_thread_read()函数中。就在第一步醒来的地方再次进入休眠,等待下一次的唤醒。
//休眠,等待下一次唤醒
ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread));
至此,以我们本次通讯为例,ServiceManager的任务算是完成了。
以下分析通讯发起端收到来自接收端的响应
第一步 通讯发起端醒来
开篇我们说过,通讯发起端在/drivers/staging/android/binder.c的binder_thread_read()函数中的``ret = wait_event_freezable(thread->wait, binder_has_thread_work(thread));`未知休眠了,那么这一次被唤醒的自然是我们通讯发起端。
第二步 读取Servicemanager端的响应信息
同上面的逻辑一样,Client端在醒来后会从事务中读取来自S的响应信息。在binder_thread_read()函数中找到下面这段代码。
...
//判断事物t中是否有目标进程的Binder实体
if (t->buffer->target_node) {
...
} else {
tr.target.ptr = NULL;
tr.cookie = NULL;
cmd = BR_REPLY; //设置命令为BR_REPLY
}
...
//将cmd和数据写回用户空间的mIn
if (put_user(cmd, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
//刚刚赋值好的事务信息写会用户空间的mIn
if (copy_to_user(ptr, &tr, sizeof(tr)))
return -EFAULT;
...
由于在binder_transaction()函数中,由于S的cmd为BC_REPLAY,所以走的是reply的逻辑。这意味着t->buffer->target_node为NULL。所以这一步,会走上面的逻辑。注意,此时cmd被设置成了BR_REPLY。
第三步 Client读取Servicemanager的响应
上一步执行完毕后,C就一路退出,结束和Binder内核的通讯。即会从/frameworks/native/libs/binder/IPCThreadState.cpp的IPCThreadState::talkWithDriver()中退出,然后回到IPCThreadState::waitForResponse()中。
上一步中,我们知道cmd被赋值为BR_REPLY,然后写到了Client中。所以看看IPCThreadState::waitForResponse()中的switch逻辑吧,知道会往那执行了不?
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
...
while (1) {
//真正和Binder驱动交互的是talkWithDriver()函数
if ((err=talkWithDriver()) < NO_ERROR) break;
...
//取出在内核中写进去的cmd命令
cmd = mIn.readInt32();
...
switch (cmd) {
...
case BR_REPLY:
{
binder_transaction_data tr;
//读取内核中写入的事务数据
err = mIn.read(&tr, sizeof(tr));
...
if (reply) {
//通常这里的reply都不会为空
if ((tr.flags & TF_STATUS_CODE) == 0) {
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);
...
}
}
...
}
}
}
...
return err;
}
没错,走的是获取响应信息的BR_REPLY逻辑。首先会把内核中传递过来的事务tr读取出来,由于前面tr是有值的,所以这里err = NO_ERROR。接着,reply在上一篇中说过,它是初始化过的,所以不为NULL,进入reply逻辑。tr.flags的值是来自于servicemanager的,具体在上面的binder_send_reply()函数中,有这样一句data.txn.flags = 0。忘记了翻回去找找哦。因此,这里调用了reply的Parcel::ipcSetDataReference()函数,写入响应信息。然后该函数就该返回了。注意此时err仍然为NO_ERROR。
第四步 退出waitForResponse()函数
上一步waitForResponse()函数返回了一个NO_ERROR,然后回到IPCThreadState::transact()函数中。接着,这个函数也没什么逻辑需要执行了,就将err返回。
第五步 一次完整的通讯终于完成啦!
IPCThreadState::transact()函数结束后,我们终于回到了最初的地方(以PING_TRANSACTION为例),那个通讯发起的地方。
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
sp<IBinder> result;
...
//在handle对应的BpBinder第一次创建时
//会执行一次虚拟的事务请求,以确保ServiceManager已经注册
status_t status = IPCThreadState::self()->transact(0, IBinder::PING_TRANSACTION, data, NULL, 0);
if (status == DEAD_OBJECT)
//如果ServiceManager没有注册,直接返回
return NULL;
...
}
此时,status为NO_ERROR,即ServiceManager已经注册了。