Android FrameWork(二)—— Binder浅析(上)
经过上一篇博客的介绍,相信大家已经对于 binder 机制有了一定的了解,这篇博客将会解读 AMS 与 SM 通信的代码流程,篇幅会很长,请大家耐心看完!
(以下分析的是 Android 6.0 的源码)
SM 是怎么启动的?
AMS 在启动后会注册到 ServiceManager(之后简称为SM)中。那么 SM 是如何启动的?
SM 是由 init 进程通过解析 init.rc 文件而创建的,其所对应的可执行程序 servicemanager,
所对应的源文件是 service_manager.c,进程名为 servicemanager。
启动 SM 的入口函数是 service_manager.c 中的 main
方法。
int main(int argc, char **argv)
{
struct binder_state *bs;
// 打开binder驱动,映射 128K 大小的内存空间
bs = binder_open(128*1024);
......
// 把当前进程注册成为 SM
if (binder_become_context_manager(bs))
{
ALOGE("cannot become context manager (%s)\n", strerror(errno));
return -1;
}
......
// 进入 loop 无限循环,监听处理 AMS 端发来的请求
binder_loop(bs, svcmgr_handler);
return 0;
}
复制代码
我们先来看 binder_open
函数具体做了什么。
// frameworks/native/cmds/servicemanager/binder.c
struct binder_state *binder_open(size_t mapsize)
{
struct binder_state *bs;
struct binder_version vers;
......
// 打开binder驱动,得到文件描述符,通过系统调用到 binder 驱动中的 binder_open 函数
bs->fd = open("/dev/binder", O_RDWR);
......
// 映射内存大小:128K
bs->mapsize = mapsize;
// 通过系统调用到 binder 驱动中的 binder_mmap 函数,
// 在当前进程的用户空间和内核空间之间映射 128K 大小的内存空间
bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
......
return bs;
......
}
复制代码
我们接着来看 binder_become_context_manager
函数具体做了什么。
// frameworks/native/cmds/servicemanager/binder.c
int binder_become_context_manager(struct binder_state *bs)
{
// 通过系统调用到 binder 驱动中的 binder_ioctl 函数,指令为 BINDER_SET_CONTEXT_MGR
return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
}
// kernel/drivers/staging/android/binder.c
static long binder_ioctl(struct file *filp,
unsigned int cmd, // cmd 就是我们传入的 BINDER_SET_CONTEXT_MGR
unsigned long arg
){
......
switch (cmd)
{
......
case BINDER_SET_CONTEXT_MGR:
ret = binder_ioctl_set_ctx_mgr(filp);
......
break;
......
}
......
return ret;
}
static int binder_ioctl_set_ctx_mgr(struct file *filp)
{
// 获取 binder 驱动的设备节点实体,可以通过 filp->private_data 获取
struct binder_proc *proc = filp->private_data;
......
// 保证只创建一次 binder_context_mgr_node,不为null就直接返回
if (context->binder_context_mgr_node)
{
......
goto out;
}
......
// uid 是否有效,当前是无效的
if (uid_valid(context->binder_context_mgr_uid))
{
if (!uid_eq(context->binder_context_mgr_uid, curr_euid))
{
......
goto out;
}
}
else
{
// 设置当前线程的 euid 作为 SM 的 uid
context->binder_context_mgr_uid = curr_euid;
}
// 创建 SM 在 binder 驱动中的 binder 节点实体
context->binder_context_mgr_node = binder_new_node(proc, 0, 0);
......
out:
return ret;
}
static struct binder_node *binder_new_node(struct binder_proc *proc, // binder 驱动的设备节点实体
binder_uintptr_t ptr,
binder_uintptr_t cookie
){
struct rb_node **p = &proc->nodes.rb_node;
struct rb_node *parent = NULL;
struct binder_node *node;
......
// 给新创建的 binder_node 分配内核空间的内存
node = kzalloc(sizeof(*node), GFP_KERNEL);
......
// 将新创建的 binder_node 添加到设备节点的 binder_node 红黑树中
rb_link_node(&node->rb_node, parent, p);
rb_insert_color(&node->rb_node, &proc->nodes);
......
// 初始化新创建的 binder_node
node->proc = proc;
node->ptr = ptr;
node->cookie = cookie;
node->work.type = BINDER_WORK_NODE;
INIT_LIST_HEAD(&node->work.entry);
INIT_LIST_HEAD(&node->async_todo);
......
return node;
}
复制代码
在 binder_become_context_manager
函数中主要是创建了 SM 在 binder 驱动中的节点实体。
我们接着来看 binder_loop
函数具体做了什么。
// frameworks/native/cmds/servicemanager/binder.c
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;
// 发送指令 BC_ENTER_LOOPER 给 binder 驱动,
// 给当前线程的 looper 添加标志 BINDER_LOOPER_STATE_ENTERED
binder_write(bs, readbuf, sizeof(uint32_t));
for (;;)
{
bwr.read_size = sizeof(readbuf);
bwr.read_consumed = 0;
bwr.read_buffer = (uintptr_t) readbuf;
// 通过系统调用到 binder 驱动中的 binder_ioctl 函数,指令为 BINDER_WRITE_READ
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
......
}
}
// kernel/drivers/staging/android/binder.c
static long binder_ioctl(struct file *filp,
unsigned int cmd, // cmd 就是我们传入的 BINDER_WRITE_READ
unsigned long arg // arg 就是我们传入的 bwr
){
// 获取 binder 驱动的设备节点
struct binder_proc *proc = filp->private_data;
struct binder_thread *thread;
......
// 创建 binder_thread
thread = binder_get_thread(proc);
......
switch (cmd)
{
case BINDER_WRITE_READ:
ret = binder_ioctl_write_read(filp, cmd, arg, thread);
......
break;
......
}
......
return ret;
}
static int binder_ioctl_write_read(struct file *filp,
unsigned int cmd, unsigned long arg,
struct binder_thread *thread
){
struct binder_proc *proc = filp->private_data;
......
void __user *ubuf = (void __user *)arg;
struct binder_write_read bwr;
// 将描述数据的 binder_write_read 结构体(ubuf)从用户空间拷贝到内核空间(bwr)中去
if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
......
// 此时 bwr.write_size = 0,if不命中
if (bwr.write_size > 0)
{
......
}
// 此时 bwr.read_size > 0,if命中
if (bwr.read_size > 0)
{
// 读取binder驱动返回的数据
ret = binder_thread_read(proc, thread, bwr.read_buffer,
bwr.read_size,
&bwr.read_consumed,
filp->f_flags & O_NONBLOCK);
......
}
......
return ret;
}
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
){
void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
// 指向 binder_loop 中 bwr.read_buffer 内存起始地址的指针
void __user *ptr = buffer + *consumed;
// 指向 binder_loop 中 bwr.read_buffer 内存结束地址的指针
void __user *end = buffer + size;
int ret = 0;
int wait_for_proc_work;
// 此时 consumed = 0,if命中
if (*consumed == 0)
{
// 将指令 BR_NOOP 拷贝到用户空间中
if (put_user(BR_NOOP, (uint32_t __user *)ptr))
return -EFAULT;
// 指针后移
ptr += sizeof(uint32_t);
}
// 此时 thread->todo = NULL,wait_for_proc_work = true
wait_for_proc_work = thread->transaction_stack == NULL && list_empty(&thread->todo);
......
if (wait_for_proc_work)
{
......
// 入参的时候 filp->f_flags & O_NONBLOCK 已经赋值
// 此时 non_block > 0,执行else
if (non_block)
{
......
}
else
// 此时 thread->todo = NULL,binder_has_proc_work 返回 false,将 SM 线程挂起
ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread));
}
else
{
......
}
}
复制代码
执行到这后 SM 就会被挂起,等待别的进程与之通信将其唤醒。
唤醒后的 SM 继续执行未完成的 binder_thread_read
函数。
AMS 是如何注册的?
SM 启动完成后就会等待 AMS 与之通信。将 AMS 注册到 SM 中的过程也是 AMS 与 SM 通信的过程。
AMS 的注册是在 SystemServer#main
中执行的。
// frameworks/base/services/java/com/android/server/SystemServer.java
public static void main(String[] args)
{
new SystemServer().run();
}
private void run()
{
......
// 创建 SystemServiceManager
mSystemServiceManager = new SystemServiceManager(mSystemContext);
......
startBootstrapServices();
}
private void startBootstrapServices()
{
......
// 通过反射创建 ActivityManagerService.Lifecycle 并获取 AMS 对象
mActivityManagerService = mSystemServiceManager.startService(
ActivityManagerService.Lifecycle.class).getService();
......
// 为 AMS 启动系统进程
mActivityManagerService.setSystemProcess();
}
// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public void setSystemProcess()
{
......
// 将 AMS 注册到 SM 中
ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);
......
}
复制代码
我们接着来看 ServiceManager#addService
函数。
// frameworks/base/core/java/android/os/ServiceManager.java
public static void addService(String name, IBinder service, boolean allowIsolated)
{
......
getIServiceManager().addService(name, service, allowIsolated);
......
}
private static IServiceManager getIServiceManager()
{
if (sServiceManager != null)
{
return sServiceManager;
}
// 创建 ServiceManagerProxy
sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
return sServiceManager;
}
// frameworks/base/core/java/com/android/internal/os/BinderInternal.java
public static final native IBinder getContextObject();
// frameworks/base/core/jni/android_util_Binder.cpp
static const JNINativeMethod gBinderInternalMethods[] = {
......
{ "getContextObject", "()Landroid/os/IBinder;", (void*)android_os_BinderInternal_getContextObject },
......
};
static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)
{
// ProcessState::self():打开 binder驱动并创建 ProcessState(ProcessState是单例的)
// ProcessState::getContextObject(NULL):创建 BpBinder 对象并返回
sp<IBinder> b = ProcessState::self()->getContextObject(NULL);
// 创建 BinderProxy 对象并返回
return javaObjectForIBinder(env, b);
}
复制代码
我们首先来看 ProcessState::self
函数具体做了什么。
// frameworks/native/libs/binder/ProcessState.cpp
sp<ProcessState> ProcessState::self()
{
Mutex::Autolock _l(gProcessMutex);
// 单例模式
if (gProcess != NULL)
{
return gProcess;
}
// 创建 ProcessState
gProcess = new ProcessState;
return gProcess;
}
// BINDER_VM_SIZE 的大小为 1M-8K
#define BINDER_VM_SIZE ((1*1024*1024) - (4096 *2))
ProcessState::ProcessState()
: mDriverFD(open_driver()) // 开启 binder 驱动
......
{
// 如果开启 binder 驱动成功,得到了 binder 驱动设备节点
if (mDriverFD >= 0)
{
// 通过系统调用到 binder 驱动中的 binder_mmap 函数,
// 在当前进程的用户空间和内核空间之间映射 BINDER_VM_SIZE (1M-8K)大小的内存空间
mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
......
}
......
}
复制代码
可以看到在 ProcessState 创建的时候就会开辟共享内存用于之后与 SM 的通信。
我们接着来看 ProcessState::getContextObject
函数具体做了什么。
// frameworks/native/libs/binder/ProcessState.cpp
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
// BpBinder 对象的 handle 值是0
return getStrongProxyForHandle(0);
}
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
sp<IBinder> result;
AutoMutex _l(mLock);
// 查找 handle 对应的资源项
handle_entry* e = lookupHandleLocked(handle);
if (e != NULL)
{
IBinder* b = e->binder;
// 当 handle 值所对应的 IBinder 不存在或弱引用无效时,当前不存在
if (b == NULL || !e->refs->attemptIncWeak(this))
{
// 当前 handle 值为0,if命中
if (handle == 0)
{
Parcel data;
// 通过 ping 操作测试 binder 是否准备就绪
status_t status = IPCThreadState::self()->transact(
0, IBinder::PING_TRANSACTION, data, NULL, 0);
if (status == DEAD_OBJECT)
return NULL;
}
// 创建 BpBinder 对象,handle 值为0
b = new BpBinder(handle);
e->binder = b;
if (b) e->refs = b->getWeakRefs();
result = b;
}
......
}
return result;
}
复制代码
我们返回到前面的 android_os_BinderInternal_getContextObject
函数中,接着来看 javaObjectForIBinder
函数具体做了什么。
jobject javaObjectForIBinder(JNIEnv* env,
const sp<IBinder>& val // 此时的 val 是 BpBinder
){
......
// 从 gBinderProxyOffsets 中查找 BinderProxy 对象
// 因为此时 BinderProxy 没有创建过,此时 object 为 null
jobject object = (jobject)val->findObject(&gBinderProxyOffsets);
if (object != NULL)
{
jobject res = jniGetReferent(env, object);
if (res != NULL)
{
......
// 如果当前进程中创建过了 BinderProxy 对象就直接返回
return res;
}
......
}
......
// 创建 BinderProxy
object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor);
if (object != NULL)
{
// 将 gBinderProxyOffsets 结构体中的成员变量 mObject 赋值(BpBinder),
// 记录 BpBinder 对象
env->SetLongField(object, gBinderProxyOffsets.mObject, (jlong)val.get());
......
// 将 BinderProxy 对象信息添加到 BpBinder 的成员变量 mObjects 中,
// 将 BinderProxy 与 BpBinder 互相绑定
val->attachObject(&gBinderProxyOffsets, refObject, jnienv_to_javavm(env), proxy_cleanup);
......
// BinderProxy.mOrgue 成员变量记录死亡通知对象
env->SetLongField(object, gBinderProxyOffsets.mOrgue, reinterpret_cast<jlong>(drl.get()));
......
}
return object;
}
复制代码
可以看到 BinderProxy 每个进程中只会创建一次。
每个 BinderProxy 对象都会绑定一个 IBinder 对象。此时绑定的是 BpBinder 对象且该 BpBinder 对象的 handle 值是0。
到此 getIServiceManager
函数做了什么我们已经分析完了,现在我们返回 ServiceManager#addService
函数,接着来看 ServiceManagerProxy#addSevice
具体做了什么。
// frameworks/base/core/java/android/os/ServiceManagerNative.java$ServiceManagerProxy.java
public void addService(String name, IBinder service, boolean allowIsolated) throws RemoteException
{
// 创建 data
Parcel data = Parcel.obtain();
// 创建 reply
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IServiceManager.descriptor);
data.writeString(name);
// 将 AMS 写入 data
data.writeStrongBinder(service);
data.writeInt(allowIsolated ? 1 : 0);
// mRemote = BinderProxy,相当于调用到 BinderProxy#transact
mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);
reply.recycle();
data.recycle();
}
复制代码
AMS 是如何将数据打包的?
我们先来看看 AMS 是如何写入 data 的。
// frameworks/base/core/java/android/os/Parcel.java
public final void writeStrongBinder(IBinder val)
{
nativeWriteStrongBinder(mNativePtr, val);
}
// frameworks/base/core/jni/android_os_Parcel.cpp
static const JNINativeMethod gParcelMethods[] = {
......
{"nativeWriteStrongBinder", "(JLandroid/os/IBinder;)V", (void*)android_os_Parcel_writeStrongBinder},
......
}
static void android_os_Parcel_writeStrongBinder(JNIEnv* env,
jclass clazz, jlong nativePtr,
jobject object // object 就是传入的 AMS
){
// 将 Java 层的 Parcel 类型(Java的Parcel)对象强制类型转换成 Native 层的 Parcel 类型对象(Native的Parcel)
// reinterpret_cast<A*>的作用:将 nativePtr 指向的内存拷贝一份并转换成 A 类型的对象
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel != NULL)
{
const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object));
......
}
}
// frameworks/base/core/jni/android_util_Binder.cpp
sp<IBinder> ibinderForJavaObject(JNIEnv* env,
jobject obj // obj 就是传入的 AMS
){
if (obj == NULL)
return NULL;
// 如果 obj 的类型是 Binder,此时 obj 的类型是 Binder,if命中
if (env->IsInstanceOf(obj, gBinderOffsets.mClass))
{
// 从 gBinderOffsets.mObject 成员属性获取 JavaBBinderHolder 对象
JavaBBinderHolder* jbh = (JavaBBinderHolder*) env->GetLongField(obj, gBinderOffsets.mObject);
// 通过 JavaBBinderHolder#get 函数创建 JavaBBinder
return jbh != NULL ? jbh->get(env, obj) : NULL;
}
......
return NULL;
}
复制代码
AMS 在创建的时候会相应的创建一个 JavaBBinderHolder 对象,并保存在 gBinderOffsets.mObject 中。
在调用 JavaBBinderHolder#get
函数的时候就会创建一个 JavaBBinder。
这个 JavaBBinder 对象的 mObject 字段持有了 AMS。
我们接着来看 Parcel#writeStrongBinder
函数具体干了什么。
status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
{
return flatten_binder(ProcessState::self(), val, this);
}
status_t flatten_binder(const sp<ProcessState>& /*proc*/,
const sp<IBinder>& binder, // binder 就是 ibinderForJavaObject 中返回的 JavaBBinder 对象
Parcel* out // out 就是 ServiceManagerProxy#addSevice 函数中的 data
){
// 记录 AMS 的信息
flat_binder_object obj;
......
if (binder != NULL)
{
// 判断 binder 对象是 BpBinder 还是 BBinder,
// JavaBBinder 是 BBinder,local 不为 NULL,执行 else
IBinder *local = binder->localBinder();
if (!local)
{
......
}
else
{
// 保存 AMS 的信息
obj.type = BINDER_TYPE_BINDER;
// local->getWeakRefs() 就是 JavaBBinder 对象
obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
obj.cookie = reinterpret_cast<uintptr_t>(local);
}
}
else
{
......
}
return finish_flatten_binder(binder, obj, out);
}
inline static status_t finish_flatten_binder(const sp<IBinder>& /*binder*/,
const flat_binder_object& flat, Parcel* out)
{
// 将 flat_binder_object 对象写入
return out->writeObject(flat, false);
}
复制代码
因此我们知道了 ServiceManagerProxy#addSevice
函数中的 data 写入的其实是 JavaBBinder 对象,该 JavaBBinder 对象的 mObject 字段持有了 AMS。
AMS 是如何将数据发送给 SM 的?
我们接着来看 BinderProxy#transact
函数具体做了什么。
// android\frameworks\base\core\java\android\os\Binder.java
public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
......
return transactNative(code, data, reply, flags);
}
public native boolean transactNative(int code, Parcel data, Parcel reply,
int flags) throws RemoteException;
// android\frameworks\base\core\jni\android_util_Binder.cpp
static const JNINativeMethod gBinderProxyMethods[] = {
......
{"transactNative", "(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z",
(void*)android_os_BinderProxy_transact},
......
};
复制代码
可以看到在 BinderProxy#transact
函数调用了一个 native 函数 transactNative
,transactNative
函数对应的是 android_os_BinderProxy_transact
函数。
// android\frameworks\base\core\jni\android_util_Binder.cpp
static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
jint code, // code 就是 ADD_SERVICE_TRANSACTION
jobject dataObj, // dataObj 就是 ServiceManagerProxy#addSevice 中传入的 data
jobject replyObj, // replyObj 就是 ServiceManagerProxy#addSevice 中传入的 reply
jint flags
){
......
// 将 dataObj 的类型转成 Parcel
Parcel* data = parcelForJavaObject(env, dataObj);
......
// 将 replyObj 的类型转成 Parcel
Parcel* reply = parcelForJavaObject(env, replyObj);
......
// 获取 gBinderProxyOffsets.mObject 中保存的 BpBinder 对象
IBinder* target = (IBinder*) env->GetLongField(obj, gBinderProxyOffsets.mObject);
......
// 调用到 BpBinder 对象的 transact 函数
status_t err = target->transact(code, *data, reply, flags);
......
}
复制代码
我们接着来看 BpBinder#transact
函数。
// android\frameworks\native\libs\binder\BpBinder.cpp
status_t BpBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
......
// mHandle = 0
status_t status = IPCThreadState::self()->transact(mHandle, code, data, reply, flags);
......
}
复制代码
我们接着看 IPCThreadState#self
函数做了什么。
// android\frameworks\native\libs\binder\BpBinder.cpp
IPCThreadState* IPCThreadState::self()
{
......
// 创建 IPCThreadState 对象
return new IPCThreadState;
......
}
IPCThreadState::IPCThreadState()
: mProcess(ProcessState::self()), // 调用 ProcessState::self 函数
......
{
......
mIn.setDataCapacity(256); // 设置 mIn 的大小
mOut.setDataCapacity(256); // 设置 mOut 的大小
}
复制代码
在 IPCThreadState#self
函数中主要是完成了 IPCThreadState 和 ProcessState 对象的初始化,并通过系统调用到 binder 驱动中的 binder_mmap 函数完成对共享内存的初始化。
接着我们继续看 IPCThreadState#transact
函数中做了什么。
// android\frameworks\native\libs\binder\IPCThreadState.cpp
status_t IPCThreadState::transact(int32_t handle, // handle = 0
uint32_t code, // code 就是 ADD_SERVICE_TRANSACTION
const Parcel& data, // data 就是 ServiceManagerProxy#addSevice 中传入的 data
Parcel* reply, // reply 就是 ServiceManagerProxy#addSevice 中传入的 reply
uint32_t flags
){
// 数据错误检查
status_t err = data.errorCheck();
// TF_ACCEPT_FDS = 0x10:允许回复中包含文件描述符
// TF_ONE_WAY:当前业务是异步的,不需要等待
// TF_ROOT_OBJECT:所包含的内容是根对象
// TF_STATUS_CODE:所包含的内容是 32-bit 的状态值
flags |= TF_ACCEPT_FDS;
......
// 整理数据,将数据写入 mOut 中。
err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
......
// 判断当前业务是否为异步操作。
// AIDL默认是同步操作,除非你定义AIDL接口时使用了oneway关键字。
if ((flags & TF_ONE_WAY) == 0)
{
......
// reply 不为空
if (reply)
{
// 等待 Binder 驱动回应事件
err = waitForResponse(reply);
}
else
{
Parcel fakeReply;
// 等待 Binder 驱动回应事件
err = waitForResponse(&fakeReply);
}
......
}
else
{
// 不等待 Binder 驱动回应事件
err = waitForResponse(NULL, NULL);
}
......
}
复制代码
mOut 中打包了命令 BC_TRANSACTION (在 mOut 中的地址高位)和我们要发送给 SM 的数据(在 mOut 中的地址低位)。
继续看到 IPCThreadState#waitForResponse
函数。
// android\frameworks\native\libs\binder\IPCThreadState.cpp
status_t IPCThreadState::waitForResponse(
Parcel *reply, // reply 就是 ServiceManagerProxy#addSevice 中传入的 reply
status_t *acquireResult
){
uint32_t cmd;
int32_t err;
// 循环等待结果
while (1)
{
// 调用 talkWithDriver 函数发送指令给 binder 驱动
if ((err=talkWithDriver()) < NO_ERROR) break;
......
// 如果 mIn 中没有数据,就 continue
if (mIn.dataAvail() == 0) continue;
......
}
......
}
复制代码
我们接着来看 IPCThreadState#talkWithDriver
函数中是如何发送指令给 binder 驱动的。
// android\frameworks\native\libs\binder\IPCThreadState.cpp
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
......
// mIn 是宏定义的 Parcel 变量,此时 mIn 未进行赋值
// mIn.dataPosition() = mIn.dataSize() = 0,needRead为true
const bool needRead = mIn.dataPosition() >= mIn.dataSize();
......
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
bwr.write_size = outAvail;
// 在 bwr 中填写需要写的指令大小和内容
bwr.write_buffer = (uintptr_t)mOut.data();
// 如果需要读数据
if (doReceive && needRead)
{
// dataCapacity = 256
bwr.read_size = mIn.dataCapacity();
// 此时的 mIn.data() = 0
bwr.read_buffer = (uintptr_t)mIn.data();
}
else // 不需要读数据就设置为零。
// 这样在 binder_ioctl_write_read 函数中就不会执行 binder_thread_read
{
bwr.read_size = 0;
bwr.read_buffer = 0;
}
......
bwr.write_consumed = 0;
bwr.read_consumed = 0;
// 循环发送指令给 binder 驱动直至成功
do {
......
// 给 Binder 驱动发送命令 BC_TRANSACTION,
// 通过系统调用到 Binder 驱动的 binder_ioctl 方法,进入内核态
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
err = NO_ERROR;
else
err = -errno;
......
} while (err == -EINTR); // 只有当 ioctl 发生错误后while循环条件才会成立,
// 因此如果发送成功就只执行一次
......
}
复制代码
当调用了 ioctl
函数后,经过系统调用(Syscall)到 Binder 驱动中的 binder_ioctl
函数,命令为 BINDER_WRITE_READ。
// kernel\drivers\staging\android\binder.c
static long binder_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg // arg 是用来描述 mOut 的 bwr 的地址值
){
......
void __user *ubuf = (void __user *)arg;
......
// 获取命令(BINDER_WRITE_READ)
trace_binder_ioctl(cmd, arg);
......
switch (cmd)
{
case BINDER_WRITE_READ:
ret = binder_ioctl_write_read(filp, cmd, arg, thread);
......
}
}
复制代码
继续看到 binder_ioctl_write_read
函数。
// kernel\drivers\staging\android\binder.c
static int binder_ioctl_write_read(struct file *filp,
unsigned int cmd, unsigned long arg,
struct binder_thread *thread)
{
struct binder_proc *proc = filp->private_data;
......
void __user *ubuf = (void __user *)arg;
struct binder_write_read bwr;
// 将 binder_write_read 结构体(ubuf)从用户空间拷贝到内核空间(bwr)中去
if (copy_from_user(&bwr, ubuf, sizeof(bwr)))
{
ret = -EFAULT;
goto out;
}
......
// 此时 bwr.write_size > 0,if命中
if (bwr.write_size > 0)
{
// 发送指令给 binder 驱动
ret = binder_thread_write(proc, thread,
bwr.write_buffer,
bwr.write_size,
&bwr.write_consumed);
......
}
// 此时 bwr.read_size > 0,if命中
if (bwr.read_size > 0)
{
// 读取 binder 驱动返回的指令
ret = binder_thread_read(proc, thread, bwr.read_buffer,
bwr.read_size,
&bwr.read_consumed,
filp->f_flags & O_NONBLOCK);
......
}
......
out:
return ret;
}
复制代码
我们先来看 binder_thread_write
函数具体做了什么。
// kernel\drivers\staging\android\binder.c
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;
struct binder_context *context = proc->context;
void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
// 指向 mOut 内存起始地址的指针
void __user *ptr = buffer + *consumed;
// 指向 mOut 内存结束地址的指针
void __user *end = buffer + size;
// 遍历 mOut 内存,取出指令
while (ptr < end && thread->return_error == BR_OK)
{
// 将 mOut 中写入的命令从用户空间拷贝到内核空间中的 cmd,
// 此时 cmd = BC_TRANSACTION
if (get_user(cmd, (uint32_t __user *)ptr))
return -EFAULT;
// 指针后移
ptr += sizeof(uint32_t);
......
switch (cmd)
{
......
case BC_TRANSACTION:
case BC_REPLY:
{
struct binder_transaction_data tr;
// 将要发送给 SM 的数据从用户空间拷贝到内核空间中的 binder_transaction_data 结构体
if (copy_from_user(&tr, ptr, sizeof(tr)))
return -EFAULT;
// 指针后移
ptr += sizeof(tr);
// 调用 binder_transaction 函数
binder_transaction(proc, thread, &tr, cmd == BC_REPLY, 0);
break;
}
......
}
......
}
......
}
复制代码
前面在 binder_ioctl_write_read
函数中拷贝的只是用于描述 mOut 的结构体,结构体中保存的只是 mOut 的起始地址。而 binder_thread_write
函数中才真正将 mOut 中打包的数据拷贝到内核空间。
这里还不是真正意义上的一次拷贝。
继续看到 binder_transaction
函数。
// kernel\drivers\staging\android\binder.c
static void binder_transaction(struct binder_proc *proc,
struct binder_thread *thread,
struct binder_transaction_data *tr,
int reply, // 此时 reply = false
binder_size_t extra_buffers_size)
{
......
struct binder_transaction *t;
struct binder_work *tcomplete;
......
struct binder_proc *target_proc;
struct binder_thread *target_thread = NULL;
struct binder_node *target_node = NULL;
struct list_head *target_list;
wait_queue_head_t *target_wait;
......
// 此处 reply 为 false(cmd == BC_TRANSACTION)
if (reply)
{
......
}
else
{
// tr->target.handle = 0,执行 else
if (tr->target.handle)
{
......
}
else
{
// 获取 SM 的 binder_node 节点
target_node = context->binder_context_mgr_node;
......
}
......
// 获取 SM 的 binder_proc
target_proc = target_node->proc;
......
}
// 获取 SM 的 todo 队列和 wait 队列
target_list = &target_proc->todo;
target_wait = &target_proc->wait;
......
// 生成一个 binder_transaction 变量(即变量 t),
// 用于描述本次要进行的 transaction(最后将其加入 target_thread->todo)。
// 这样当目标对象被唤醒时,它就可以从这个队列中取出需要做的工作。
t = kzalloc(sizeof(*t), GFP_KERNEL);
......
// 生成一个 binder_work 变量(即变量 tcomplete),用于说明 AMS 有一个未完成的工作
tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL);
......
// 此时 if 命中
if (!reply && !(tr->flags & TF_ONE_WAY))
// 非 oneway(同步)的通信方式,把当前 thread 保存到 transaction 的 from 字段
t->from = thread;
else
t->from = NULL;
......
// 记录此次通信的目标进程
t->to_proc = target_proc;
......
// 此次通信 code = ADD_SERVICE_TRANSACTION
t->code = tr->code;
// 此次通信 flags = 0
t->flags = tr->flags;
......
// 从 SM 进程中分配 buffer
// (为完成本条 transaction 申请内存,从 binder_mmap 开辟的空间中申请内存)
t->buffer = binder_alloc_buf(target_proc, tr->data_size,
tr->offsets_size, extra_buffers_size,
!reply && (t->flags & TF_ONE_WAY));
......
// 记录 SM 的 binder_node
t->buffer->target_node = target_node;
......
// 拷贝用户空间的 binder_transaction_data 中 ptr.buffer 指针到内核空间
if (copy_from_user(t->buffer->data, (const void __user *)(uintptr_t)
tr->data.ptr.buffer, tr->data_size))
......
// 拷贝用户空间的 binder_transaction_data 中 ptr.offsets 指针到内核空间
if (copy_from_user(offp, (const void __user *)(uintptr_t)
tr->data.ptr.offsets, tr->offsets_size))
......
// 此时 cmd = BC_TRANSACTION,cmd != BC_REPLY,reply = false
if (reply)
{
......
}
else if(!(t->flags & TF_ONE_WAY)) // 操作是同步的,命中
{
......
// 记录本次的 transaction,以备后期查询
// (SM 通过这个知道是谁调用的,从而返回数据)
thread->transaction_stack = t;
}
else
{
......
}
// 设置 t 的类型为 BINDER_WORK_TRANSACTION
t->work.type = BINDER_WORK_TRANSACTION;
// 将 t 加入 SM 进程的 todo 队列
list_add_tail(&t->work.entry, target_list);
// 设置 binder_work 的类型为 BINDER_WORK_TRANSACTION_COMPLETE
tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
// 将 tcomplete 加入 AMS 线程的 todo 队列
list_add_tail(&tcomplete->entry, &thread->todo);
// 此时 SM 被挂起,target_wait != NULL,if命中
if (target_wait)
// 唤醒 SM 进程
wake_up_interruptible(target_wait);
return;
......
}
复制代码
在 binder_transaction
函数中主要做了几件事:
- 获取到服务端进程的 binder_proc 结构体。
- 生成一个 binder_transaction 变量(给 Service 的)和一个 binder_work 变量(给 Client 的)来保存信息。
- 将 mOut 中打包的数据拷贝到经过 binder_mmap 开辟的共享内存中(重点,一次拷贝是在这)。
- 将 binder_transaction 变量添加到目标服务端进程的 work 队列,唤醒目标服务端进程。
- 将 binder_work 变量添加到当前调用方线程的 todo 队列,让当前调用方线程挂起等待。
所以在这个函数中才真正的做到了 IPC 通信传输。
我们知道 SM 和 AMS 两个进程是异步执行代码的,因此我们先来看 AMS 进程接下来做了什么。
在 AMS 进程中,当 binder_transaction
函数执行完成返回后,binder_thread_write
函数执行结束,接着执行 binder_thread_read
函数。
// kernel\drivers\staging\android\binder.c
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)
{
void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
// 指向 mIn 内存起始地址的指针
void __user *ptr = buffer + *consumed;
// 指向 mIn 内存结束地址的指针
void __user *end = buffer + size;
int ret = 0;
int wait_for_proc_work;
......
retry:
// 1. thread->todo 不为空,wait_for_proc_work 为 false
// 2. thread->todo 为空,wait_for_proc_work 为 true
wait_for_proc_work = thread->transaction_stack == NULL && list_empty(&thread->todo);
// 1. 执行 else
// 2. 执行 if
if (wait_for_proc_work)
{
......
if (non_block) // 入参的时候 filp->f_flags & O_NONBLOCK 已经赋值
// 此时 non_block > 0,执行else
{
......
}
else
// 2. thread->todo 为空,binder_has_thread_work 返回 false,将 AMS 线程挂起
ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread));
}
else
{
if (non_block) // 入参的时候 filp->f_flags & O_NONBLOCK 已经赋值
// 此时 non_block > 0,执行else
{
......
}
else
// 1. thread->todo 不为空,binder_has_thread_work 返回 true,不会将 AMS 线程挂起
ret = wait_event_freezable(thread->wait, binder_has_thread_work(thread));
}
......
// 1. 线程没有挂起,继续执行 while 循环
while (1)
{
uint32_t cmd;
struct binder_transaction_data tr;
struct binder_work *w;
struct binder_transaction *t = NULL;
// 1. 在 binder_transaction 函数中添加了一个 binder_work,此时 thread->todo 不为空,if 命中
// 2. 在执行 BINDER_WORK_TRANSACTION_COMPLETE 指令的时候将 binder_work 删除了,
// 此时 thread->todo 为空,执行else
if (!list_empty(&thread->todo))
{
// 1. 取出 binder_work
w = list_first_entry(&thread->todo, struct binder_work, entry);
}
else
{
// 2. 此时 if 命中
if (ptr - buffer == 4 && !(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN))
// 2. 返回 retry 处执行代码
goto retry;
break;
}
......
// 1. 此时 w->type 为 BINDER_WORK_TRANSACTION_COMPLETE
switch (w->type)
{
......
case BINDER_WORK_TRANSACTION_COMPLETE:
{
// 1. 更改指令 BR_TRANSACTION_COMPLETE
cmd = BR_TRANSACTION_COMPLETE;
// 1. 将指令拷贝到 mIn 中
if (put_user(cmd, (uint32_t __user *)ptr))
return -EFAULT;
// 1. 指针后移
ptr += sizeof(uint32_t);
......
// 1. 将当前的 binder_work 从 thread->todo 中删除
list_del(&w->entry);
// 1. 释放 binder_work 的内存
kfree(w);
......
} break;
......
}
// 1. 此时 t = null,if 命中
if (!t)
continue;
......
}
*consumed = ptr - buffer;
......
return 0;
}
复制代码
在 binder_thread_read
函数中 while 循环会执行两次,所以代码中的注释写了序号,序号对应着第几次 while 循环。
此时 AMS 就被挂起了,等待 SM 进程返回数据后唤醒。当 AMS 被唤醒后就从此处的 binder_thread_read
函数开始继续执行。
SM 进程被唤醒后做了什么?
我们接下来看 SM 进程被唤醒后做了什么。
在 SM 进程中,当 binder_transaction
函数执行完成返回后,SM 进程被唤醒,继续执行未完成的 binder_thread_read
函数。
// kernel\drivers\staging\android\binder.c
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_transaction 函数中添加了一个 binder_transaction,此时 proc->todo 不为空
else if (!list_empty(&proc->todo) && wait_for_proc_work)
{
// 取出 binder_transaction
w = list_first_entry(&proc->todo, struct binder_work, entry);
}
......
// 此时 w->type 为 BINDER_WORK_TRANSACTION
switch (w->type)
{
......
case BINDER_WORK_TRANSACTION:
{
t = container_of(w, struct binder_transaction, work);
} break;
......
}
// 此时 t != null,if不命中
if (!t)
continue;
......
// 此时 t->buffer->target_node 不为空,if命中
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;
......
// 指令更改为 BR_TRANSACTION
cmd = BR_TRANSACTION;
}
else
{
......
}
// t->code = ADD_SERVICE_TRANSACTION
tr.code = t->code;
// t->flags = 0
tr.flags = t->flags;
// 此时 t->from 不为 NULL,if 命中
if (t->from)
{
struct task_struct *sender = t->from->proc->tsk;
// 获取 AMS 线程的 pid 并记录
tr.sender_pid = task_tgid_nr_ns(sender, task_active_pid_ns(current));
}
else
{
......
}
// 将 binder_transaction 结构体(t)拷贝到 binder_transaction_data 结构体(tr)
tr.data_size = t->buffer->data_size;
tr.offsets_size = t->buffer->offsets_size;
tr.data.ptr.buffer = (binder_uintptr_t)((uintptr_t)t->buffer->data + proc->user_buffer_offset);
tr.data.ptr.offsets = tr.data.ptr.buffer + ALIGN(t->buffer->data_size, sizeof(void *));
// 将指令 BR_TRANSACTION 拷贝到用户空间(binder_loop 中的 bwr.read_buffer)
if (put_user(cmd, (uint32_t __user *)ptr))
return -EFAULT;
// 指针后移
ptr += sizeof(uint32_t);
// 将描述数据的 tr 结构体拷贝到用户空间(binder_loop 中的 bwr.read_buffer)
if (copy_to_user(ptr, &tr, sizeof(tr)))
return -EFAULT;
// 指针后移
ptr += sizeof(tr);
......
// 此时 if 命中
if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY))
{
t->to_parent = thread->transaction_stack;
t->to_thread = thread;
// 将 t 保存在 SM 线程中的 transaction_stack 中
thread->transaction_stack = t;
}
else
{
......
}
// 跳出循环
break;
......
}
*consumed = ptr - buffer;
......
return 0;
}
复制代码
当 binder_thread_read
函数执行完成后,binder_ioctl_write_read
函数也执行完成返回,我们返回到 binder_loop
函数,继续执行。
// frameworks/native/cmds/servicemanager/binder.c
void binder_loop(struct binder_state *bs, binder_handler func)
{
......
for (;;)
{
......
res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
......
}
}
复制代码
我们接着看到 binder_parse
函数。
// frameworks/native/cmds/servicemanager/binder.c
int binder_parse(struct binder_state *bs,
struct binder_io *bio,
uintptr_t ptr, // ptr 就是指向 binder_loop 中 bwr.read_buffer 的起始地址
size_t size, // size 就是 binder_loop 中的 bwr.read_size
binder_handler func
){
int r = 1;
// 指向 binder_loop 中的 bwr.read_buffer 内存结束地址的指针
uintptr_t end = ptr + (uintptr_t) size;
while (ptr < end)
{
// bwr.read_buffer 中前 uint32_t 大小的内存是指令,当前指令是 BR_TRANSACTION
uint32_t cmd = *(uint32_t *) ptr;
// 指针后移
ptr += sizeof(uint32_t);
......
switch(cmd)
{
......
case BR_TRANSACTION:
{
// 将 binder_loop 中 bwr.read_buffer 指向的剩余内存转换成 binder_transaction_data 结构体
struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;
......
// 此时 func = service_manager#svcmgr_handler,if 命中
if (func)
{
unsigned rdata[256/4];
struct binder_io msg;
struct binder_io reply;
int res;
// 初始化 reply
bio_init(&reply, rdata, sizeof(rdata), 4);
// 初始化 msg,将 txn 中的数据拷贝到 msg 中
bio_init_from_txn(&msg, txn);
// 执行 service_manager#svcmgr_handler 函数
res = func(bs, txn, &msg, &reply);
// 将 reply 发给 binder 驱动
binder_send_reply(bs, &reply, txn->data.ptr.buffer, res);
}
// 指针后移
ptr += sizeof(*txn);
break;
}
......
}
}
return r;
}
复制代码
我们接着看到 service_manager#svcmgr_handler
函数。
// 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;
......
// 此时 txn->code = ADD_SERVICE_TRANSACTION = 3 = SVC_MGR_ADD_SERVICE
switch(txn->code)
{
......
case SVC_MGR_ADD_SERVICE:
// 获取 AMS 的名称
s = bio_get_string16(msg, &len);
......
// 获取 AMS 的 handle 值
handle = bio_get_ref(msg);
allow_isolated = bio_get_uint32(msg) ? 1 : 0;
// 在 SM 中记录 AMS
if (do_add_service(bs, s, len, handle, txn->sender_euid,
allow_isolated, txn->sender_pid))
return -1;
break;
......
}
// 此时 reply 中没有数据
bio_put_uint32(reply, 0);
return 0;
}
int do_add_service(struct binder_state *bs,
const uint16_t *s, size_t len,
uint32_t handle, uid_t uid, int allow_isolated,
pid_t spid
){
// 在 SM 中用 svcinfo 结构体保存注册过的 Service 的信息
struct svcinfo *si;
......
// 查找 AMS 是否在 SM 注册过
si = find_svc(s, len);
// 如果 AMS 已经注册过了
if (si)
{
if (si->handle)
{
......
// 将当前这个 svcinfo 结构体中的记录的 handle 值清空
svcinfo_death(bs, si);
}
// 对当前这个 svcinfo 结构体中的 handle 值重新赋值
si->handle = handle;
}
else // 如果 AMS 没注册过
{
// 创建一个新的 svcinfo 结构体
si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));
......
si->handle = handle;
si->len = len;
// 拷贝 AMS 信息
memcpy(si->name, s, (len + 1) * sizeof(uint16_t));
si->name[len] = '\0';
si->death.func = (void*) svcinfo_death;
si->death.ptr = si;
si->allow_isolated = allow_isolated;
// 将创建的 svcinfo 结构体添加到 svclist 中
si->next = svclist;
svclist = si;
}
// 以 BC_ACQUIRE 命令,handle 为目标的信息,通过 ioctl 发送给 binder 驱动,
// 使 binder_ref 强引用加1操作
binder_acquire(bs, handle);
// 以 BC_REQUEST_DEATH_NOTIFICATION 命令的信息,通过 ioctl 发送给 binder 驱动,
// 主要进行清理内存等收尾工作
binder_link_to_death(bs, handle, &si->death);
return 0;
}
复制代码
在 service_manager#svcmgr_handler
函数中主要将 AMS 记录到了 SM 中。
我们接着来看 binder_send_reply
函数。
// frameworks/native/cmds/servicemanager/binder.c
void binder_send_reply(struct binder_state *bs,
struct binder_io *reply, // 此时 reply 中没有数据
binder_uintptr_t buffer_to_free, // 用户空间中开辟的共享内存的起始地址
int status // status = 0
){
struct {
uint32_t cmd_free; // 占高位
binder_uintptr_t buffer;
uint32_t cmd_reply; // 占低位
struct binder_transaction_data txn;
} __attribute__((packed)) data;
data.cmd_free = BC_FREE_BUFFER; // free buffer 命令
data.buffer = buffer_to_free;
data.cmd_reply = BC_REPLY; // reply 命令
data.txn.target.ptr = 0;
data.txn.cookie = 0;
data.txn.code = 0;
// status = 0,执行 else
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 驱动通信,执行指令
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;
// 通过系统调用到 binder 驱动中的 binder_ioctl 函数,指令为 BINDER_WRITE_READ
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
......
return res;
}
// kernel/drivers/staging/android/binder.c
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;
......
void __user *ubuf = (void __user *)arg;
struct binder_write_read bwr;
......
// 将 binder_write_read 结构体(ubuf)从用户空间拷贝到内核空间(bwr)中去
if (copy_from_user(&bwr, ubuf, sizeof(bwr)))
{
ret = -EFAULT;
goto out;
}
......
if (bwr.write_size > 0)
{
// 发送指令给 binder 驱动
ret = binder_thread_write(proc, thread,
bwr.write_buffer,
bwr.write_size,
&bwr.write_consumed);
......
}
// 此时 bwr.read_size = 0,if 不命中
if (bwr.read_size > 0)
{
......
}
......
out:
return ret;
}
static int binder_thread_write(struct binder_proc *proc,
struct binder_thread *thread,
binder_uintptr_t binder_buffer, // binder_buffer 就是 binder_send_reply 中的 data
size_t size, // size 就是 binder_send_reply 中的 data 的内存大小
binder_size_t *consumed
){
uint32_t cmd;
struct binder_context *context = proc->context;
void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
// 指向 data 内存起始地址的指针
void __user *ptr = buffer + *consumed;
// 指向 data 内存结束地址的指针
void __user *end = buffer + size;
while (ptr < end && thread->return_error == BR_OK)
{
// 从 data 中读取指令
if (get_user(cmd, (uint32_t __user *)ptr))
return -EFAULT;
// 指针后移
ptr += sizeof(uint32_t);
// cmd 先是 BC_FREE_BUFFER,再是 BC_REPLY
switch (cmd)
{
......
case BC_FREE_BUFFER:
{
// 在这里会将 data.buffer 所指向的内存区域中的数据清空,在这里就不多分析了
......
break;
}
......
case BC_TRANSACTION:
case BC_REPLY:
{
struct binder_transaction_data tr;
// 将要发送给 AMS 的数据从用户空间拷贝到内核空间中的 binder_transaction_data 结构体
if (copy_from_user(&tr, ptr, sizeof(tr)))
return -EFAULT;
// 指针后移
ptr += sizeof(tr);
// 调用 binder_transaction 函数
binder_transaction(proc, thread, &tr, cmd == BC_REPLY, 0);
break;
}
......
}
......
}
return 0;
}
复制代码
到了这里就会再次调用 binder_transaction
函数与 AMS 进程进行通信,通知 AMS 注册成功。
// kernel\drivers\staging\android\binder.c
static void binder_transaction(struct binder_proc *proc,
struct binder_thread *thread,
struct binder_transaction_data *tr,
int reply, // 此时 reply = true
binder_size_t extra_buffers_size)
{
......
struct binder_transaction *t;
struct binder_work *tcomplete;
......
struct binder_proc *target_proc;
struct binder_thread *target_thread = NULL;
struct binder_node *target_node = NULL;
struct list_head *target_list;
wait_queue_head_t *target_wait;
......
// 此处 reply 为 true(cmd == BC_REPLY)
if (reply)
{
// 获取记录在 thread->transaction_stack 中的 binder_transaction 结构体
in_reply_to = thread->transaction_stack;
......
thread->transaction_stack = in_reply_to->to_parent;
// in_reply_to->from = AMS 线程
target_thread = in_reply_to->from;
......
target_proc = target_thread->proc;
}
else
{
......
}
// 此时 target_thread != NULL,if 命中
if (target_thread)
{
// 获取 AMS 线程的 pid 值
e->to_thread = target_thread->pid;
// 获取 AMS 线程的 todo 队列和 wait 队列
target_list = &target_thread->todo;
target_wait = &target_thread->wait;
}
else
{
......
}
......
// 生成一个 binder_transaction 变量(即变量 t),
// 用于描述本次要进行的 transaction(最后将其加入 target_thread->todo)。
// 这样当目标对象被唤醒时,它就可以从这个队列中取出需要做的工作。
t = kzalloc(sizeof(*t), GFP_KERNEL);
......
// 生成一个 binder_work 变量(即变量 tcomplete),用于说明 AMS 有一个未完成的工作
tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL);
......
// 此时 if 不命中,执行 else
if (!reply && !(tr->flags & TF_ONE_WAY))
......
else
t->from = NULL;
......
// 记录此次通信的目标进程(AMS)
t->to_proc = target_proc;
......
// 此次通信 code = 0
t->code = tr->code;
// 此次通信 flags = 0
t->flags = tr->flags;
......
// 从 AMS 进程中分配 buffer
// (为完成本条 transaction 申请内存,从 binder_mmap 开辟的空间中申请内存)
t->buffer = binder_alloc_buf(target_proc, tr->data_size,
tr->offsets_size, extra_buffers_size,
!reply && (t->flags & TF_ONE_WAY));
......
// 记录 AMS 的 binder_node,此时 target_node = NULL
t->buffer->target_node = target_node;
......
// 拷贝用户空间的 binder_transaction_data 中 ptr.buffer 指针到内核空间
if (copy_from_user(t->buffer->data, (const void __user *)(uintptr_t)
tr->data.ptr.buffer, tr->data_size))
......
// 拷贝用户空间的 binder_transaction_data 中 ptr.offsets 指针到内核空间
if (copy_from_user(offp, (const void __user *)(uintptr_t)
tr->data.ptr.offsets, tr->offsets_size))
......
// 此时 cmd = BC_REPLY,reply = true
if (reply)
{
......
// 清空数据,释放缓存
binder_pop_transaction(target_thread, in_reply_to);
}
else if(!(t->flags & TF_ONE_WAY))
{
......
}
else
{
......
}
// 设置 t 的类型为 BINDER_WORK_TRANSACTION
t->work.type = BINDER_WORK_TRANSACTION;
// 将 t 加入 AMS 线程的 todo 队列
list_add_tail(&t->work.entry, target_list);
// 设置 binder_work 的类型为 BINDER_WORK_TRANSACTION_COMPLETE
tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
// 将 tcomplete 加入 SM 进程的 todo 队列
list_add_tail(&tcomplete->entry, &thread->todo);
// 此时 AMS 被挂起,target_wait != NULL,if命中
if (target_wait)
// 唤醒 AMS 进程
wake_up_interruptible(target_wait);
return;
......
}
复制代码
我们先来看 SM 进程接下来做了什么。
在 SM 进程中,当 binder_transaction
函数执行完成返回后,一直返回到 binder_loop
函数,经过循环再次调用 ioctl
函数读取 binder 驱动的指令。
我们直接看到 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
){
void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
// 指向 binder_loop 中的 bwr.read_buffer 内存起始地址的指针
void __user *ptr = buffer + *consumed;
// 指向 binder_loop 中的 bwr.read_buffer 内存结束地址的指针
void __user *end = buffer + size;
int ret = 0;
int wait_for_proc_work;
......
retry:
// 1. thread->todo 不为空,wait_for_proc_work 为 false
// 2. thread->todo 为空,wait_for_proc_work 为 true
wait_for_proc_work = thread->transaction_stack == NULL && list_empty(&thread->todo);
......
// 1. 执行 else
// 2. 执行 if
if (wait_for_proc_work)
{
......
if (non_block) // 入参的时候 filp->f_flags & O_NONBLOCK 已经赋值
// 此时 non_block > 0,执行else
{
......
}
else
// 2. thread->todo 为空,binder_has_thread_work 返回 false,将 SM 线程挂起
ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread));
}
else
{
if (non_block) // 入参的时候 filp->f_flags & O_NONBLOCK 已经赋值
// 此时 non_block > 0,执行 else
{
......
}
else
// 1. thread->todo 不为空,binder_has_thread_work 返回 true,不会将 SM 线程挂起
ret = wait_event_freezable(thread->wait, binder_has_thread_work(thread));
}
......
// 1. 线程没有挂起,继续执行 while 循环
while (1)
{
uint32_t cmd;
struct binder_transaction_data tr;
struct binder_work *w;
struct binder_transaction *t = NULL;
// 1. 在 binder_transaction 函数中添加了一个 binder_work,此时 thread->todo 不为空,if 命中
// 2. 在执行 BINDER_WORK_TRANSACTION_COMPLETE 指令的时候将 binder_work 删除了,
// 此时 thread->todo 为空,执行else
if (!list_empty(&thread->todo))
{
// 1. 取出 binder_work
w = list_first_entry(&thread->todo, struct binder_work, entry);
}
else
{
// 2. 此时 if 命中
if (ptr - buffer == 4 && !(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN))
// 2. 返回 retry 处执行代码
goto retry;
break;
}
......
// 1. 此时 w->type 为 BINDER_WORK_TRANSACTION_COMPLETE
switch (w->type)
{
......
case BINDER_WORK_TRANSACTION_COMPLETE:
{
// 1. 更改指令 BR_TRANSACTION_COMPLETE
cmd = BR_TRANSACTION_COMPLETE;
// 1. 将指令拷贝到 binder_loop 中的 bwr.read_buffer
if (put_user(cmd, (uint32_t __user *)ptr))
return -EFAULT;
// 1. 指针后移
ptr += sizeof(uint32_t);
......
// 1. 将当前的 binder_work 从 thread->todo 中删除
list_del(&w->entry);
// 1. 释放 binder_work 的内存
kfree(w);
......
} break;
......
}
// 1. 此时 t = null,if 命中
if (!t)
continue;
......
}
*consumed = ptr - buffer;
......
return 0;
}
复制代码
在 binder_thread_read
函数中 while 循环会执行两次,所以代码中的注释写了序号,序号对应着第几次 while 循环。
此时 SM 就被挂起了,等待其他进程与之通信后唤醒。当 SM 被唤醒后就从此处的 binder_thread_read
函数开始继续执行。
AMS 进程被唤醒后做了什么?
我们接下来看 AMS 进程被唤醒后做了什么。
在 AMS 进程中,当 binder_transaction
函数执行完成返回后,AMS 进程被唤醒,继续执行未完成的 binder_thread_read
函数。
// kernel\drivers\staging\android\binder.c
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_transaction 函数中添加了一个 binder_transaction,此时 proc->todo 不为空
else if (!list_empty(&proc->todo) && wait_for_proc_work)
{
// 取出 binder_transaction
w = list_first_entry(&proc->todo, struct binder_work, entry);
}
......
// 此时 w->type 为 BINDER_WORK_TRANSACTION
switch (w->type)
{
......
case BINDER_WORK_TRANSACTION:
{
t = container_of(w, struct binder_transaction, work);
} break;
......
}
// 此时 t != null,if不命中
if (!t)
continue;
......
// 此时 t->buffer->target_node 为空,if 不命中
if (t->buffer->target_node)
{
......
}
else
{
tr.target.ptr = 0;
tr.cookie = 0;
// 指令更改为 BR_REPLY
cmd = BR_REPLY;
}
// t->code = 0
tr.code = t->code;
// t->flags = 0
tr.flags = t->flags;
// 此时 t->from 为 NULL,if 不命中
if (t->from)
{
......
}
else
{
tr.sender_pid = 0;
}
// 将 binder_transaction 结构体(t)拷贝到 binder_transaction_data 结构体(tr)
tr.data_size = t->buffer->data_size;
tr.offsets_size = t->buffer->offsets_size;
tr.data.ptr.buffer = (binder_uintptr_t)((uintptr_t)t->buffer->data + proc->user_buffer_offset);
tr.data.ptr.offsets = tr.data.ptr.buffer + ALIGN(t->buffer->data_size, sizeof(void *));
// 将指令 BR_REPLY 拷贝到用户空间(mIn)
if (put_user(cmd, (uint32_t __user *)ptr))
return -EFAULT;
// 指针后移
ptr += sizeof(uint32_t);
// 将描述数据的 tr 结构体拷贝到用户空间(mIn)
if (copy_to_user(ptr, &tr, sizeof(tr)))
return -EFAULT;
// 指针后移
ptr += sizeof(tr);
......
// 此时 if 不命中
if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY))
{
......
}
else
{
t->buffer->transaction = NULL;
// 释放内存
kfree(t);
}
// 跳出循环
break;
......
}
*consumed = ptr - buffer;
......
return 0;
}
复制代码
当 binder_thread_read
函数执行完成返回后,一直返回到 IPCThreadState#waitForResponse
函数,继续执行。
// android\frameworks\native\libs\binder\IPCThreadState.cpp
status_t IPCThreadState::waitForResponse(
Parcel *reply, // reply 就是 ServiceManagerProxy#addSevice 中传入的 reply
status_t *acquireResult
){
uint32_t cmd;
int32_t err;
// 循环等待结果
while (1)
{
......
// 读取 mIn 中的指令(BR_REPLY)
cmd = (uint32_t)mIn.readInt32();
......
switch(cmd)
{
......
case BR_REPLY:
{
binder_transaction_data tr;
// 取出 mIn 中的 binder_transaction_data 结构体
err = mIn.read(&tr, sizeof(tr));
......
// reply 不为空,if 命中
if (reply)
{
if ((tr.flags & TF_STATUS_CODE) == 0)
{
// 将 mIn 中描述的数据写入 reply 中
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
{
......
}
}
else
{
......
}
}
// 跳出循环
goto finish;
......
}
}
finish:
if (err != NO_ERROR)
{
if (acquireResult) *acquireResult = err;
if (reply) reply->setError(err);
mLastError = err;
}
return err;
}
复制代码
当 IPCThreadState#waitForResponse
函数执行完成返回后,一直返回到 ServiceManagerProxy#addSevice
函数。到此,AMS 的注册流程结束。
总结
按照指令的顺序,AMS 的注册流程大致如下图
大家结合这个流程图来看代码流程会更加清晰。
AMS 注册流程在 Binder IPC 机制中只算是冰山一角,但是借助跟踪 AMS 注册流程我们可以更加清晰的看到 Binder IPC 机制是如何运行的,这对于我们理解 Binder IPC 机制是很有帮助的。