系列文章目录
可跳转到下面链接查看下表所有内容https://blog.csdn.net/handsomethefirst/article/details/138226266?spm=1001.2014.3001.5501文章浏览阅读2次。系列文章大全https://blog.csdn.net/handsomethefirst/article/details/138226266?spm=1001.2014.3001.5501
目录
系列文章目录
1.简介
1.1 时序图
1.1流程介绍
2 meidaservice的启动——源码分析
2.1 获取ProcessState对象
2.1.1 ProcessState::ProcessState
2.1.2 ProcessState::init
2.1.3 open_driver
2.1.4 binder_open
2.1.5 获取版本号binder_ioctl
2.1.6 设置binder最大线程数binder_ioctl
2.1.7 binder_mmap
2.1.8 binder_update_page_range
2.2 获取bpServiceManager对象
2.2.1 defaultServiceManager
2.2.2 ProcessState::getContextObject
2.2.3 ProcessState::getStrongProxyForHandle
2.2.4 ProcessState::lookupHandleLocked
2.2.5 BpBinder::create
2.2.6 BpBinder::BpBinder
2.2.7 IPCThreadState::self
2.2.8 IPCThreadState::IPCThreadState
2.2.9 IPCThreadState::incWeakHandle
2.2.10 interface_cast
2.2.11 asInterface
2.2.12 queryLocalInterface
2.2.13 BpServiceManager::BpServiceManager
2.2.14 BpInterface::BpInterface
2.2.15 BpRefBase::BpRefBase
2.3 注册多媒体服务到servicemanager
2.3.1 MediaPlayerService::instantiate
2.3.2 IServiceManager::addService
2.3.3 writeStrongBinder
2.3.4 flatten_binder
2.3.5 BpBinder::transact
2.3.6 IPCThreadState::transact
2.3.7 IPCThreadState::writeTransactionData
2.3.8 IPCThreadState::waitForResponse向驱动发送请求add服务的消息
2.3.9 IPCThreadState::talkWithDriver
2.3.10 binder_ioctl
2.3.11 binder_thread_write(增加SM对应的句柄0的引用计数)
2.3.12 binder_thread_write(处理media服务请求add的消息)
2.3.13 binder_transaction
2.4 mediapalyservice服务陷入休眠
2.4.1 binder_ioctl
2.4.2 binder_thread_read
2.4.3 IPCThreadState::talkWithDriver
2.4.4 IPCThreadState::waitForResponse
2.4.5 talkWithDriver第三次循环(同步消息才会有):
2.4.6 binder_ioctl
2.4.7 binder_thread_read
2.5 ServiceManager被唤醒
2.5.1 binder_thread_read
2.5.2 binder_ioctl
2.5.3 binder_loop
2.5.4 binder_parse
2.5.5 bio_init
2.5.6 bio_init_from_txn
2.5.7 svcmgr_handler
2.5.8 bio_get_ref
2.5.9 do_add_service
2.5.10 find_svc
2.5.11 binder_acquire
2.5.12 binder_write
2.5.13 binder_ioctl
2.5.14 binder_thread_write
2.5.15 binder_link_to_death
2.5.16 binder_write
2.5.17 binder_ioctl
2.5.18 binder_thread_write
2.6 Servicemanager服务发送reply消息给meidaservice
2.6.1 bio_put_uint32
2.6.2 bio_alloc
2.6.3 binder_send_reply
2.6.4 binder_write
2.6.5 binder_ioctl
2.6.6 binder_thread_write
2.6.7 binder_transaction
2.7 servicemanager处理未完成事务,并再次陷休眠
2.7.1 binder_loop
2.7.2 binder_ioctl
2.7.3 binder_thread_read
2.7.4 binder_parse
2.7.5 sm主线程再次休眠,等待来自驱动的消息
2.8 唤醒meidaservice服务,meida服务处理reply消息
2.8.1 binder_thread_read
2.8.2 binder_ioctl
2.8.3 talkWithDriver
2.8.4 waitForResponse
2.8.5 Parcel::ipcSetDataReference
2.9 ProcessState::startThreadPool
2.9.1 ProcessState::spawnPooledThread
2.9.2 threadLoop
2.9.3 IPCThreadState::joinThreadPool
2.9.4 IPCThreadState::getAndExecuteCommand
2.9.5 IPCThreadState::talkWithDriver
2.9.6 binder_ioctl
2.9.7 binder_thread_write
2.9.8 死循环用于获取来自驱动的消息
2.9.9 getAndExecuteCommand
2.9.10 talkWithDriver
2.9.11 binder_ioctl
2.9.12 binder_thread_read
2.10 joinThreadPool
2.10.1 IPCThreadState::joinThreadPool
2.10.2 IPCThreadState::getAndExecuteCommand
2.10.3 IPCThreadState::talkWithDriver
2.10.4 binder_ioctl
2.10.5 binder_thread_write
2.10.6 死循环用于获取来自驱动的消息
2.10.7 getAndExecuteCommand
2.10.8 talkWithDriver
2.10.9 binder_ioctl
2.10.10 binder_thread_read
1.简介
此篇我们便从源码的角度来看注册服务的过程,此篇以MediaPlayerService注册进入到servicemanager中为例子。
1.1 时序图
(为了保证流程的完整性,较为模糊,可保存到本地,放大仔细观看)
1.1流程介绍
此处举例为MediaPlayerService注册进入到servicemanager中。
第一步:首先mediaservice会获取ProcessState实例对象,此ProcessState对象会打开binder驱动,驱动中会创建meidaservice服务对应的porc进程信息对象。同时meidaservice作为服务,会申请一块内存,通过mmap的进行内存映射,将meidaservice服务的用户空间映射到驱动中,从而会减少数据的拷贝。
第二步:获取BpServiceManager对象,即通过handle0获取ServiceManager的binder代理对象,用于和servicemanager对象通信。
第三步:初始化MediaPlayerService服务,内部首先会创建MediaPlayerService对象,此对象是一个BnMediaPlayerService(binder实体对象),然后调用BpServiceManager代理对象的addservice将此服务注册到中。
第四步:在BpServiceManager代理对象的addservice函数中,会构建Parcel对象,并将meidapalyservice服务的binder实体对象,服务名称,等信息写入Parcel对象中。然后调用bpbinder的通信接口transact函数。
第五步:然后transact函数会将数据再次进行封装,然后调用ioctl函数向驱动发送请求add服务的消息,此时进入内核态。
第六步:ioctl函数对应驱动的binder_ioctl函数,驱动会先将mediapalyservice服务的用户空间的数据拷贝到内核空间,并取出add的标志,处理add服务的消息。然后会走到binder_transaction中。
第七步:binder_transaction函数中首先会找到目标的进程的proc对象和目标进程的线程,然后取出meidapalyservice服务塞入Parcel对象中binder实体对象,并在驱动中创建meidapalyservice服务对应的bbbinder实体,并将此bbbinder实体添加到meidiaplayservice服务的比红黑树中,然后在目标进程(SM进程)的binder_proc中创建对应的binder_ref红黑树节点,将mediaservice的引用添加到SM进程的引用的红黑树中。然后在sm之前映射的进程中分配一块内核buffer空间,将add添加服务的消息数据放入sm进程的缓冲区中。然后将此add服务的消息添加到sm进程的todo队列中。然后唤醒目标进程(SM进程的队列)队列。同时也会生成一个完成的事务消息放入到meidaplayservice的进程队列中。
第八步:meidaplayservice服务作为客户端,会陷入休眠,等待服务端返回reply消息。
第九步:我们知道SM启动后,在向驱动成为binder的管理者后,就会循环从驱动中读取数据,由于驱动无数据,所以会陷入休眠状态等待在todo队列上。在第七步我们已经唤醒了sm进程。此时sm进程会从队列中读取到消息。然后处理add服务的消息。
第十步:sm将meidaplayservice服务的hanle和服务名称保存到svclist,完成注册。然后sm向驱动发送回复消息。同样也是通过binder_transaction函数去找到meidaplayservice服务的porc对象,并向meida服务的todo队列中插入回复消息,并唤醒mediaservice服务。并且往自己的队列中插入未完成事务。然后sm处理完后,再次陷入等待,等待来自驱动的消息。
第十一步:meidaplayservice服务处理reply消息。
第十二步:mediaplayservice服务创建一个新的线程加入binder线程池中,并向驱动发送要进入线程循环的指令,
然后此新线程进入死循环,用于读取来自驱动的消息,如果没有消息,则会休眠阻塞。
第十三步:mediaplayservice服务主线程也加入binder线程池中,也会进入死循环,用于读取来自驱动的消息,如果没有消息,则会休眠阻塞。用于不让主服务退出。
2
meidaservice的启动——源码分析
此例子以meidaservice注册到servcicemanager为例。
//此函数的作用是:驱动多媒体服务,并注册到serivcemanager中
int main(int argc __unused, char **argv __unused)
{
signal(SIGPIPE, SIG_IGN);
sp<ProcessState> proc(ProcessState::self()); //获得ProcessState实例对象
sp<IServiceManager> sm(defaultServiceManager()); //获取BpServiceManager对象
ALOGI("ServiceManager: %p", sm.get());
AIcu_initializeIcuOrDie();
MediaPlayerService::instantiate(); //注册多媒体服务
ResourceManagerService::instantiate();
registerExtensions();
ProcessState::self()->startThreadPool(); //启动Binder线程池
IPCThreadState::self()->joinThreadPool(); //当前线程加入到线程池
}
注意:startThreadPool,本质上是创建了一个新的线程,并向binder驱动注册为主线程。然后一直循环。joinThreadPool是将当前线程加入到binder主线程。此时有两个binder主线程。
2.1 获取ProcessState对象
2.1.1 ProcessState::ProcessState
1.此处是单例模式。在一个进程中,只会创建一次。ProcessState作为进程状态的记录器,主要用来打开Binder驱动获取句柄,mmap申请一块(1M-8K)的内存空间,设置Binder线程最大个数。
sp<ProcessState> ProcessState::self()
{
Mutex::Autolock _l(gProcessMutex);
if (gProcess != nullptr) {
return gProcess;
}
gProcess = new ProcessState(kDefaultDriver);//sp<ProcessState> gProcess;
//根据VNDK的宏定义来决定当前进程使用"/dev/binder" 还是"/dev/vndbinder"kDefaultDriver此时值是= "/dev/binder";
return gProcess;
}
2.1.2 ProcessState::init
1.创建了ProcessState对象。此对象用于打开binder驱动,并完成内存的映射,将用户空间的一块内存映射到内核空间,映射关系建立后,用户对这块内存区域的修改可直接反映到内核空间,反之内核空间对其修改也能反映到用户空间。
ProcessState::ProcessState(const char *driver)
: mDriverName(String8(driver))//driver是/dev/binder
, mDriverFD(open_driver(driver))//打开binder驱动返回的fd文件描述符
, mVMStart(MAP_FAILED)
, mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)//保护线程数量的锁,pthread_mutex_t mThreadCountLock;
, mThreadCountDecrement(PTHREAD_COND_INITIALIZER)//条件变量。pthread_cond_t mThreadCountDecrement;
, mExecutingThreadsCount(0)//当前执行命令的binder线程数
, mMaxThreads(DEFAULT_MAX_BINDER_THREADS)//最大线程数15
, mStarvationStartTimeMs(0)//线程池被清空的时间
, mManagesContexts(false)
, mBinderContextCheckFunc(nullptr)
, mBinderContextUserData(nullptr)
, mThreadPoolStarted(false)
, mThreadPoolSeq(1)
, mCallRestriction(CallRestriction::NONE)//无呼叫限制
{
if (mDriverFD >= 0) {
//mmap binder,内存映射。128k的内存地址,申请128k的内存地址用来接收事务,对应binder驱动的binder_mmap函数。
//启动分析中有,故不再分析
mVMStart = mmap(nullptr, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
/**
if (mVMStart == MAP_FAILED) {//如果内存映射失败
// *sigh*
ALOGE("Using %s failed: unable to mmap transaction memory.\n", mDriverName.c_str());
close(mDriverFD);
mDriverFD = -1;
mDriverName.clear();
}
*/
}
LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver could not be opened. Terminating.");
}
2.1.3 open_driver
主要作用为:
1.open打开binder驱动,通过系统调用_open,最后会调用到binder_open,陷入内核态。获取fd。
2.通过ioctl,获取binder驱动版本号,用vers保存。然后对比版本号是否一致。
3.通过ioctl设置binder驱动最大线程数。
static int open_driver(const char *driver)
{
int fd = open(driver, O_RDWR | O_CLOEXEC);//driver值是/dev/binder,打开binder驱动,陷入内核,此
//open对应_open,然后对应binder驱动层的binder_open,binder_open中主要是为/dev/binder这个驱动设备节点,创建
//对应的proc对象,然后通过fd返回。这样就可以和驱动进行通信。
if (fd >= 0) {//大于0代表打开成功
int vers = 0;
status_t result = ioctl(fd, BINDER_VERSION, &vers);//获取binder驱动的版本信息,用vers保存
/**正常不执行
if (result == -1) {//如果获取信息失败,则关闭binder驱动
ALOGE("Binder ioctl to obtain version failed: %s", strerror(errno));
close(fd);
fd = -1;
}
*/
/**
if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {//如果获取的版本信息不匹配,则关闭binder驱动
ALOGE("Binder driver protocol(%d) does not match user space protocol(%d)! ioctl() return value: %d",
vers, BINDER_CURRENT_PROTOCOL_VERSION, result);
close(fd);
fd = -1;
}
*/
size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;//设置最大线程数15
result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);//设置binder驱动最大线程数
/**
if (result == -1) {
ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
}
*/
uint32_t enable = DEFAULT_ENABLE_ONEWAY_SPAM_DETECTION;//DEFAULT_ENABLE_ONEWAY_SPAM_DETECTION值是1,表示默认启用更新垃圾检测
result = ioctl(fd, BINDER_ENABLE_ONEWAY_SPAM_DETECTION, &enable);//设置到binder驱动中
/**
if (result == -1) {
ALOGD("Binder ioctl to enable oneway spam detection failed: %s", strerror(errno));
}
*/
}
/**
else {
ALOGW("Opening '%s' failed: %s\n", driver, strerror(errno));
}
*/
return fd;
}
2.1.4 binder_open
1.为当前sm服务进程分配保存binder_proc的对象。binder_proc结构体保存的是sm服务的进程的信息。
2.对sm服务的binder_proc的对象进行初始化,如初始化todo队列,设置进程优先级等。
3.将sm服务的binder_proc添加到binder_procs队列中,驱动有一个全局的binder_procss的列表,用于存储所有进程的binder_proc对象。
//主要作用:binder驱动为用户进程创建了用户进程自己的binder——proc实体
static int binder_open(struct inode *nodp, struct file *filp)
{
struct binder_proc *proc;//proc表示驱动中binder进程
proc = kzalloc(sizeof(*proc), GFP_KERNEL);//为binder_proc结构体在分配kernel内存空间
if (proc == NULL)
return -ENOMEM;
//下面是对binder_proc进行初始化,binder_proc用于管理数据的记录体
get_task_struct(current);
proc->tsk = current;//current代表当前线程。当前线程此时是servicemanager的主线程,当前线程的task保存在binder进程的tsk
INIT_LIST_HEAD(&proc->todo);//初始化to列表
init_waitqueue_head(&proc->wait);//初始化wait列表
proc->default_priority = task_nice(current);//当前进程的nice值转化为进程优先级
binder_lock(__func__);
binder_stats_created(BINDER_STAT_PROC);//BINDER_PROC对象创建+1
hlist_add_head(&proc->proc_node, &binder_procs);//将proc_node节点添加到binder_procs为表头的队列
proc->pid = current->group_leader->pid;
INIT_LIST_HEAD(&proc->delivered_death);
filp->private_data = proc;//将 proc 保存到filp中,这样下次可以通过filp找到此proc
binder_unlock(__func__);
if (binder_debugfs_dir_entry_proc) {
char strbuf[11];
snprintf(strbuf, sizeof(strbuf), "%u", proc->pid);
proc->debugfs_entry = debugfs_create_file(strbuf, S_IRUGO,
binder_debugfs_dir_entry_proc, proc, &binder_proc_fops);
}
return 0;
}
//进程相关的参数
struct binder_proc {
struct hlist_node proc_node;//hlist_node表示哈希表中的一个节点。哈希表中的一个节点,用于标记该进程
struct rb_root threads;// rb_root表示红黑树。Binder线程池每一个Binder进程都有一个线程池,
//由Binder驱动来维护,Binder线程池中所有线程由一个红黑树来组织,RB树以线程ID为关键字 */
//上述红黑树的根节点
struct rb_root nodes;// 一系列Binder实体对象(binder_node)和Binder引用对象(binder_ref) */
//在用户空间:运行在Server端称为Binder本地对象,运行在Client端称为Binder代理对象*/
//在内核空间:Binder实体对象用来描述Binder本地对象,Binder引用对象来描述Binder代理对象 */
//Binder实体对象列表(RB树),关键字 ptr
struct rb_root refs_by_desc;//记录binder引用, 便于快速查找,binder_ref红黑树的根节点(以handle为key),它是Client在Binder驱动中的体现。
//Binder引用对象,关键字 desc
struct rb_root refs_by_node;//记录binder引用, 便于快速查找,binder_ref红黑树的根节点(以ptr为key),它是Client在Binder驱动中的体现,
//Binder引用对象,关键字 node
struct list_head waiting_threads;
int pid;//进程组pid
struct task_struct *tsk;//任务控制模块
const struct cred *cred;
struct hlist_node deferred_work_node;
int deferred_work;
bool is_dead;
struct list_head todo;//待处理队列,进程每接收到一个通信请求,Binder将其封装成一个工作项,保存在待处理队列to_do中 */
struct binder_stats stats;
struct list_head delivered_death;
int max_threads;// Binder驱动程序最多可以请求进程注册线程的最大数量,
//进程可以调用ioctl注册线程到Binder驱动程序中,当线程池中没有足够空闲线程来处理事务时,Binder驱动可以主动要求进程注册更多的线程到Binder线程池中 */
// Binder驱动程序最多可以请求进程注册线程的最大数量
int requested_threads;
int requested_threads_started;
int tmp_ref;
long default_priority;
struct dentry *debugfs_entry;
struct binder_alloc alloc;
struct binder_context *context;//存储binder_node和binder_context_mgr_uid以及name
spinlock_t inner_lock;
spinlock_t outer_lock;
struct dentry *binderfs_entry;
};
2.1.5 获取版本号binder_ioctl
主要作用为:
1.此时用于获取版本号。
//获取binder版本号分析
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret;
struct binder_proc *proc = filp->private_data;
struct binder_thread *thread;//binder线程
unsigned int size = _IOC_SIZE(cmd);
void __user *ubuf = (void __user *)arg;
trace_binder_ioctl(cmd, arg);
ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);//binder_stop_on_user_error值是0,
//binder_stop_on_user_error < 2为假时,休眠,故此处不休眠
if (ret)
goto err_unlocked;
binder_lock(__func__);
thread = binder_get_thread(proc);//获取当前sm的proc实体对象的binder_thread
if (thread == NULL) {
ret = -ENOMEM;
goto err;
}
switch (cmd) {
case BINDER_VERSION://获取版本号
if (size != sizeof(struct binder_version)) {
ret = -EINVAL;
goto err;
}
if (put_user(BINDER_CURRENT_PROTOCOL_VERSION, &((struct binder_version *)ubuf)->protocol_version)) {
//将驱动程序的BINDER_CURRENT_PROTOCOL_VERSION变量地址,拷贝sizeof(*ptr)的ubuf用户空间地址。
//分析,此处是有一次拷贝的。
ret = -EINVAL;
goto err;
}
break;
default:
ret = -EINVAL;
goto err;
}
ret = 0;
err:
if (thread)
thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;
binder_unlock(__func__);
wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);//不休眠
if (ret && ret != -ERESTARTSYS)
printk(KERN_INFO "binder: %d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret);
err_unlocked:
trace_binder_ioctl_done(ret);
return ret;
}
2.1.6 设置binder最大线程数binder_ioctl
//设置binder最大线程数分析
//ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);maxThreads值为15
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret;
struct binder_proc *proc = filp->private_data;
struct binder_thread *thread;//binder线程
unsigned int size = _IOC_SIZE(cmd);
void __user *ubuf = (void __user *)arg;//ubuf是15的地址
trace_binder_ioctl(cmd, arg);
ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);//不休眠
if (ret)
goto err_unlocked;
binder_lock(__func__);
thread = binder_get_thread(proc);//获取当前sm的proc实体的binder_thread
if (thread == NULL) {
ret = -ENOMEM;
goto err;
}
switch (cmd) {
case BINDER_SET_MAX_THREADS://设置binder最大线程数量
if (copy_from_user(&proc->max_threads, ubuf, sizeof(proc->max_threads))) {//拷贝用户空间的地址到内核空间
ret = -EINVAL;
goto err;
}
break;
ret = 0;
err:
if (thread)
thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;
binder_unlock(__func__);
wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
if (ret && ret != -ERESTARTSYS)
printk(KERN_INFO "binder: %d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret);
err_unlocked:
trace_binder_ioctl_done(ret);
return ret;
}
2.1.7 binder_mmap
主要作用为:
1.get_vm_area分配一个连续的内核虚拟空间,与用户进程虚拟空间大小一致。
2.binder_update_page_range,分配物理页面,同时映射到内核空间和用户进程空间。
即,此时servermanager服务在其内部分配了一块地址映射进入了内核空间。减少了拷贝。
//filp对应fp,vma代表用户地址空间
static int binder_mmap(struct file *filp, struct vm_area_struct *vma)//vma描述了应用程序使用的用户虚拟空间
{
int ret;
struct vm_struct *area;//内核虚拟空间
struct binder_proc *proc = filp->private_data;//取出sm进程对应的binder_proc对象
const char *failure_string;
struct binder_buffer *buffer;//用于binder传输数据的缓冲区
if ((vma->vm_end - vma->vm_start) > SZ_4M)//保证映射内存大小不超过4M
vma->vm_end = vma->vm_start + SZ_4M;
if (vma->vm_flags & FORBIDDEN_MMAP_FLAGS) {//判断是否禁止mmap
ret = -EPERM;
failure_string = "bad vm_flags";
goto err_bad_arg;
}
vma->vm_flags = (vma->vm_flags | VM_DONTCOPY) & ~VM_MAYWRITE;
mutex_lock(&binder_mmap_lock);
if (proc->buffer) {//如果buffer不为空,则代表已经mmap过了
ret = -EBUSY;
failure_string = "already mapped";
goto err_already_mapped;
}
area = get_vm_area(vma->vm_end - vma->vm_start, VM_IOREMAP);//分配一个连续的内核虚拟空间,与用户进程虚拟空间大小一致
if (area == NULL) {
ret = -ENOMEM;
failure_string = "get_vm_area";
goto err_get_vm_area_failed;
}
proc->buffer = area->addr;//binder_proc对象的buffer指向内核虚拟空间的地址
proc->user_buffer_offset = vma->vm_start - (uintptr_t)proc->buffer;//计算偏移量,地址偏移量=用户空间地址-内核空间地址
mutex_unlock(&binder_mmap_lock);
proc->pages = kzalloc(sizeof(proc->pages[0]) * ((vma->vm_end - vma->vm_start) / PAGE_SIZE), GFP_KERNEL);//分配
//分配物理页的指针数组,大小等于用户虚拟内存/4K,此数组用于指示binder申请的物理页的状态
if (proc->pages == NULL) {
ret = -ENOMEM;
failure_string = "alloc page array";
goto err_alloc_pages_failed;
}
proc->buffer_size = vma->vm_end - vma->vm_start;//计算大小
vma->vm_ops = &binder_vm_ops;
vma->vm_private_data = proc;
if (binder_update_page_range(proc, 1, proc->buffer, proc->buffer + PAGE_SIZE, vma)) {//分配物理页面,同时映射到内核空间和进程空间,
//目前只分配1个page的物理页
ret = -ENOMEM;
failure_string = "alloc small buf";
goto err_alloc_small_buf_failed;
}
buffer = proc->buffer;//binder_buffer对象,指向proc的buffer地址,proc的buffer地址又指向内核虚拟空间的地址
INIT_LIST_HEAD(&proc->buffers);
list_add(&buffer->entry, &proc->buffers);//将内核虚拟空间的地址加入到所属进程的buffer队列
buffer->free = 1;
binder_insert_free_buffer(proc, buffer);//将空闲的buffer放入proc->free_buffer中
proc->free_async_space = proc->buffer_size / 2;
barrier();
proc->files = get_files_struct(proc->tsk);
proc->vma = vma;//binder_proc对象保存了用户空间的地址
proc->vma_vm_mm = vma->vm_mm;
/*printk(KERN_INFO "binder_mmap: %d %lx-%lx maps %p\n",
proc->pid, vma->vm_start, vma->vm_end, proc->buffer);*/
return 0;
错误跳转
err_alloc_small_buf_failed:
kfree(proc->pages);
proc->pages = NULL;
err_alloc_pages_failed:
mutex_lock(&binder_mmap_lock);
vfree(proc->buffer);
proc->buffer = NULL;
err_get_vm_area_failed:
err_already_mapped:
mutex_unlock(&binder_mmap_lock);
err_bad_arg:
printk(KERN_ERR "binder_mmap: %d %lx-%lx %s failed %d\n",
proc->pid, vma->vm_start, vma->vm_end, failure_string, ret);
return ret;
}
2.1.8 binder_update_page_range
主要作用为:
1.分配物理内存空间。
2.将物理空间映射到内核空间。
3.将物理空间映射到用户进程空间。
当然binder_update_page_range 既可以分配物理页面,也可以释放物理页面。
//binder_update_page_range 主要完成工作:分配物理内存空间,将物理空间映射到内核空间,将物理空间映射到进程空间。
//当然binder_update_page_range 既可以分配物理页面,也可以释放物理页面
static int binder_update_page_range(struct binder_proc *proc, int allocate,
void *start, void *end,
struct vm_area_struct *vma)
//参数说明:
//proc对应的进程的proc对象
//allocate表示是申请还是释放
//start,表示内核虚拟空间起始地址
//end,内核虚拟空间末尾地址
//用户空间地址
{
void *page_addr;
unsigned long user_page_addr;
struct vm_struct tmp_area;
struct page **page;
struct mm_struct *mm;
if (end <= start)
return 0;
trace_binder_update_page_range(proc, allocate, start, end);
if (vma)
mm = NULL;
else
mm = get_task_mm(proc->tsk);
if (mm) {
down_write(&mm->mmap_sem);
vma = proc->vma;
if (vma && mm != proc->vma_vm_mm) {
pr_err("binder: %d: vma mm and task mm mismatch\n",
proc->pid);
vma = NULL;
}
}
if (allocate == 0)
goto free_range;
if (vma == NULL) {
printk(KERN_ERR "binder: %d: binder_alloc_buf failed to "
"map pages in userspace, no vma\n", proc->pid);
goto err_no_vma;
}
//前面都在判断参数是否合法
//
for (page_addr = start; page_addr < end; page_addr += PAGE_SIZE) {
int ret;
struct page **page_array_ptr;
page = &proc->pages[(page_addr - proc->buffer) / PAGE_SIZE];
BUG_ON(*page);
//分配物理内存
*page = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO);
if (*page == NULL) {
printk(KERN_ERR "binder: %d: binder_alloc_buf failed "
"for page at %p\n", proc->pid, page_addr);
goto err_alloc_page_failed;
}
tmp_area.addr = page_addr;//tmp_area是内核地址,此时指向物理地址
tmp_area.size = PAGE_SIZE + PAGE_SIZE /* guard page? */;
page_array_ptr = page;
ret = map_vm_area(&tmp_area, PAGE_KERNEL, &page_array_ptr);//映射物理页地址到内核地址tmp_area
if (ret) {
printk(KERN_ERR "binder: %d: binder_alloc_buf failed "
"to map page at %p in kernel\n",
proc->pid, page_addr);
goto err_map_kernel_failed;
}
user_page_addr =
(uintptr_t)page_addr + proc->user_buffer_offset;
ret = vm_insert_page(vma, user_page_addr, page[0]);//映射物理页地址到虚拟用户地址空间vma
if (ret) {
printk(KERN_ERR "binder: %d: binder_alloc_buf failed "
"to map page at %lx in userspace\n",
proc->pid, user_page_addr);
goto err_vm_insert_page_failed;
}
/* vm_insert_page does not seem to increment the refcount */
}
if (mm) {
up_write(&mm->mmap_sem);
mmput(mm);
}
return 0;
free_range:
for (page_addr = end - PAGE_SIZE; page_addr >= start;
page_addr -= PAGE_SIZE) {
page = &proc->pages[(page_addr - proc->buffer) / PAGE_SIZE];
if (vma)
zap_page_range(vma, (uintptr_t)page_addr +
proc->user_buffer_offset, PAGE_SIZE, NULL);
err_vm_insert_page_failed:
unmap_kernel_range((unsigned long)page_addr, PAGE_SIZE);
err_map_kernel_failed:
__free_page(*page);
*page = NULL;
err_alloc_page_failed:
;
}
err_no_vma:
if (mm) {
up_write(&mm->mmap_sem);
mmput(mm);
}
return -ENOMEM;
}
2.2 获取bpServiceManager对象
2.2.1 defaultServiceManager
1.此处最重要的是gDefaultServiceManager = interface_cast<IServiceManager>(
ProcessState::self()->getContextObject(nullptr));
因此我们需要查看getContextObject和interface_cast的作用。
可以提前说一下,最终sm是bpServiceManager对象。我们看一下是如何分析的。
sp<IServiceManager> defaultServiceManager()
{
if (gDefaultServiceManager != nullptr) return gDefaultServiceManager;
{
AutoMutex _l(gDefaultServiceManagerLock);
while (gDefaultServiceManager == nullptr) {
gDefaultServiceManager = interface_cast<IServiceManager>(
ProcessState::self()->getContextObject(nullptr));
if (gDefaultServiceManager == nullptr)
sleep(1);//当ServiceManager还未准备好,等待1秒后重新获取ServiceManager对象
}
}
return gDefaultServiceManager;//gDefaultServiceManager是一个bpServiceManager
}
2.2.2 ProcessState::getContextObject
1.最终获取了servicemanager的句柄对应的BpBinder对象。
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
return getStrongProxyForHandle(0);//0就是servicemanager的句柄
}
2.2.3 ProcessState::getStrongProxyForHandle
1.创建了一个handle为0的BpBinder,即SM的bpbinder
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)//传入的是0,代表serviceManager的句柄
{
sp<IBinder> result;
AutoMutex _l(mLock);
handle_entry* e = lookupHandleLocked(handle);//查找SM的handle对应的资源项。
if (e != nullptr) {
IBinder* b = e->binder;//此时b为空
if (b == nullptr || !e->refs->attemptIncWeak(this)) {
if (handle == 0) {
//执行一个伪事务以确保上下文管理器已注册。通过ping操作测试binder是否准备就绪
Parcel data;
status_t status = IPCThreadState::self()->transact(
0, IBinder::PING_TRANSACTION, data, nullptr, 0);
if (status == DEAD_OBJECT)
return nullptr;
}
b = BpBinder::create(handle);//创建了一个handle为0的BpBinder,即SM的bpbinder
e->binder = b;
if (b) e->refs = b->getWeakRefs();
result = b;
} else {
result.force_set(b);
e->refs->decWeak(this);
}
}
return result;//返回一个handle为0的BpBinder
}
2.2.4 ProcessState::lookupHandleLocked
ProcessState::handle_entry* ProcessState::lookupHandleLocked(int32_t handle)//此时值是0,0代表sm的binder代理对象的句柄
{
const size_t N=mHandleToObject.size();//第一次N=0
if (N <= (size_t)handle) {
handle_entry e;
e.binder = nullptr;
e.refs = nullptr;
status_t err = mHandleToObject.insertAt(e, N, handle+1-N);//mHandleToObject是保存handle_entry的容器
if (err < NO_ERROR) return nullptr;
}
return &mHandleToObject.editItemAt(handle);//返回了一个空的handle_entry
}
2.2.5 BpBinder::create
1.创建了SM对应的BpBinder对象。
BpBinder* BpBinder::create(int32_t handle) {
int32_t trackedUid = -1;
//sCountByUidEnabled默认是false
/**
if (sCountByUidEnabled) {
trackedUid = IPCThreadState::self()->getCallingUid();
AutoMutex _l(sTrackingLock);
uint32_t trackedValue = sTrackingMap[trackedUid];
if (CC_UNLIKELY(trackedValue & LIMIT_REACHED_MASK)) {
if (sBinderProxyThrottleCreate) {
return nullptr;
}
} else {
if ((trackedValue & COUNTING_VALUE_MASK) >= sBinderProxyCountHighWatermark) {
ALOGE("Too many binder proxy objects sent to uid %d from uid %d (%d proxies held)",
getuid(), trackedUid, trackedValue);
sTrackingMap[trackedUid] |= LIMIT_REACHED_MASK;
if (sLimitCallback) sLimitCallback(trackedUid);
if (sBinderProxyThrottleCreate) {
ALOGI("Throttling binder proxy creates from uid %d in uid %d until binder proxy"
" count drops below %d",
trackedUid, getuid(), sBinderProxyCountLowWatermark);
return nullptr;
}
}
}
sTrackingMap[trackedUid]++;
}
*/
return new BpBinder(handle, trackedUid);//创建了BpBinder对象
}
2.2.6 BpBinder::BpBinder
BpBinder::BpBinder(int32_t handle, int32_t trackedUid)//此时handle=0,trackedUid是-1
: mHandle(handle)//是0,代表SM的Bpbinder的句柄
, mAlive(1)
, mObitsSent(0)
, mObituaries(nullptr)
, mTrackedUid(trackedUid)
{
ALOGV("Creating BpBinder %p handle %d\n", this, mHandle);
extendObjectLifetime(OBJECT_LIFETIME_WEAK);//扩展生命周期为弱引用管理
IPCThreadState::self()->incWeakHandle(handle, this);//增加BPbinder的弱引用计数
}
2.2.7 IPCThreadState::self
IPCThreadState* IPCThreadState::self()
{
/**不执行
if (gHaveTLS.load(std::memory_order_acquire)) {//定义时是false。static std::atomic<bool> gHaveTLS(false);
restart:
const pthread_key_t k = gTLS;
IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k);
if (st) return st;
return new IPCThreadState;
}
// Racey, heuristic test for simultaneous shutdown.
if (gShutdown.load(std::memory_order_relaxed)) {//定义是false。static std::atomic<bool> gShutdown = false;
ALOGW("Calling IPCThreadState::self() during shutdown is dangerous, expect a crash.\n");
return nullptr;
}
*/
pthread_mutex_lock(&gTLSMutex);
if (!gHaveTLS.load(std::memory_order_relaxed)) {
int key_create_value = pthread_key_create(&gTLS, threadDestructor);//分配用于表示进程中线程特定数据的键,键对进程中的所有线程来说是全局的.
//pthread_key_create第一个参数为指向一个键值的指针,第二个参数指明了一个destructor函数,
//如果这个参数不为空,那么当每个线程结束时,系统将调用这个函数来释放绑定在这个键上的内存块。
//key_create_value成功返回0,其他是失败
/**
if (key_create_value != 0) {
pthread_mutex_unlock(&gTLSMutex);
ALOGW("IPCThreadState::self() unable to create TLS key, expect a crash: %s\n",
strerror(key_create_value));
return nullptr;
}
*/
gHaveTLS.store(true, std::memory_order_release);//将gHaveTLS值设置为true。static std::atomic<bool> gHaveTLS(false);
}
pthread_mutex_unlock(&gTLSMutex);
goto restart;
}
2.2.8 IPCThreadState::IPCThreadState
IPCThreadState::IPCThreadState()
: mProcess(ProcessState::self()),//保存当前的ProcessState对象
mServingStackPointer(nullptr),
mWorkSource(kUnsetWorkSource),
mPropagateWorkSource(false),
mIsLooper(false),
mIsFlushing(false),
mStrictModePolicy(0),
mLastTransactionBinderFlags(0),
mCallRestriction(mProcess->mCallRestriction) {
pthread_setspecific(gTLS, this);//将自己即IPCThreadState对象存储到gTLS中。
clearCaller();
mIn.setDataCapacity(256);//设置输入缓存区大小
mOut.setDataCapacity(256);//设置输出缓存区大小
}
2.2.9 IPCThreadState::incWeakHandle
void IPCThreadState::incWeakHandle(int32_t handle, BpBinder *proxy)
{
LOG_REMOTEREFS("IPCThreadState::incWeakHandle(%d)\n", handle);
mOut.writeInt32(BC_INCREFS);//向驱动请求增加binder的引用计数
mOut.writeInt32(handle);//此时是0,代表SM的句柄
if (!flushIfNeeded()) {//flushIfNeeded返回值是false,因为当前线程还没有进入循环,故无法贺binder驱动通信。
// Create a temp reference until the driver has handled this command.
proxy->getWeakRefs()->incWeak(mProcess.get());
mPostWriteWeakDerefs.push(proxy->getWeakRefs());
}
}
所以gDefaultServiceManager = interface_cast<IServiceManager>(ProcessState::self()->getContextObject(nullptr));
就变成了
gDefaultServiceManager = interface_cast<IServiceManager>(BpBinder(0,trackedUid));
我们接下来继续查看interface_cast的作用。
2.2.10 interface_cast
这个是一个模板类。
template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
return INTERFACE::asInterface(obj);
}
此时INTERFACE的值是IServiceManager,转换后为:
inline sp<IServiceManager> interface_cast(const sp<IBinder>& obj)
{
return IServiceManager::asInterface(obj);//此时obj是BpBinder(0,trackedUid)
//真正返回的是BpServiceManager(BpBinder(0,trackedUid)) 对象
}
继续查看asInterface的作用。
2.2.11 asInterface
#define DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE(INTERFACE, NAME)\
const ::android::String16 I##INTERFACE::descriptor(NAME); \
const ::android::String16& \
I##INTERFACE::getInterfaceDescriptor() const { \
return I##INTERFACE::descriptor; \
} \
::android::sp<I##INTERFACE> I##INTERFACE::asInterface( \
const ::android::sp<::android::IBinder>& obj) \
{ \
::android::sp<I##INTERFACE> intr; \
if (obj != nullptr) { \
intr = static_cast<I##INTERFACE*>( \
obj->queryLocalInterface( \
I##INTERFACE::descriptor).get()); \
if (intr == nullptr) { \
intr = new Bp##INTERFACE(obj); \
} \
} \
return intr; \
}
替换后为:
#define DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager")
const ::android::String16 IServiceManager::descriptor("android.os.IServiceManager");
::android::sp<IServiceManager> IServiceManager::asInterface(
const ::android::sp<::android::IBinder>& obj)
{
::android::sp<IServiceManager> intr;
if (obj != nullptr) {//此时obj是BpBinder(0,trackedUid)
intr = static_cast<IServiceManager*>(
obj->queryLocalInterface(IServiceManager::descriptor).get());//查询"android.os.IServiceManager"对应的本地服务
if (intr == nullptr) {
intr = new BpServiceManager(obj);
}
}
return intr; //返回的是BpServiceManager(BpBinder(0,trackedUid))
}
2.2.12 queryLocalInterface
//此时obj是BpBinder对象,查看其queryLocalInterface方法。
sp<IInterface> IBinder::queryLocalInterface(const String16& /*descriptor*/)
{
return nullptr;//返回为空
}
所以此时
gDefaultServiceManager = interface_cast<IServiceManager>(ProcessState::self()->getContextObject(nullptr));
就变成了
gDefaultServiceManager = interface_cast<IServiceManager>(BpBinder(0,trackedUid));
等价于
gDefaultServiceManager =new BpServiceManager(new BpBinder(0,trackedUid));
2.2.13 BpServiceManager::BpServiceManager
explicit BpServiceManager(const sp<IBinder>& impl)//此时impl是BpBinder(0,trackedUid)
: BpInterface<IServiceManager>(impl)
{
}
2.2.14 BpInterface::BpInterface
class BpInterface : public INTERFACE, public BpRefBase
inline BpInterface<IServiceManager>::BpInterface(const sp<IBinder>& remote)//remote是BpBinder(0,trackedUid)
: BpRefBase(remote)
{
}
替换后,等价于
class BpInterface : public IServiceManager, public BpRefBase
inline BpInterface<IServiceManager>::BpInterface(const sp<IBinder>& remote)//remote是BpBinder(0,trackedUid)
: BpRefBase(remote)
{
}
2.2.15 BpRefBase::BpRefBase
BpRefBase::BpRefBase(const sp<IBinder>& o)//o是BpBinder(0,trackedUid)
: mRemote(o.get()), mRefs(nullptr), mState(0)//mRemote就是BpBinder(0,trackedUid)
{
extendObjectLifetime(OBJECT_LIFETIME_WEAK);//扩展对象生命周期为弱周期管理
if (mRemote) {
mRemote->incStrong(this); //增加对象引用计数
mRefs = mRemote->createWeak(this); //持有一个mRemote的弱引用对象
}
}
2.3 注册多媒体服务到servicemanager
2.3.1 MediaPlayerService::instantiate
主要作用为:
1.MediaPlayerService调用Bpservicemanager对象的addService接口。
void MediaPlayerService::instantiate() {
defaultServiceManager()->addService(String16("media.player"), new MediaPlayerService());//BpServiceManager的addService方法
}
2.3.2 IServiceManager::addService
1.生成发送到驱动的数据data和请求恢复的reply。
2.将MediaPlayerService这个binder实体对象,对应的string名称,写入data。
3.通过bpbinder的transact接口将消息发送出去,并等待回复的消息。
[/frameworks/native/libs/binder/IServiceManager.cpp]
virtual status_t addService(const String16& name, const sp<IBinder>& service,
bool allowIsolated, int dumpsysPriority) {
//参数:name是"media.player",service是new MediaPlayerService,也是一个BBbinder实体
//allowIsolated是fasle,dumpsysPriority是8,默认优先级
Parcel data, reply;//发送到驱动的data,和请求回复的reply
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());//写入RPC头信息"android.os.IServiceManager"
data.writeString16(name);//写入"media.player"
data.writeStrongBinder(service);//把一个binder实体“打扁”并写入parcel, 服务的实体对象:new MediaPlayerService
data.writeInt32(allowIsolated ? 1 : 0);//写入0
data.writeInt32(dumpsysPriority);//写入8
status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);//remote() 函数{ return mRemote; }
//故mRemote是SM对应的BpBinder(0,-1)的transact方法。ADD_SERVICE_TRANSACTION是3
return err == NO_ERROR ? reply.readExceptionCode() : err;
}
status_t Parcel::writeInterfaceToken(const String16& interface)
{
const IPCThreadState* threadState = IPCThreadState::self();//获取IPCThreadState对象
writeInt32(threadState->getStrictModePolicy() | STRICT_MODE_PENALTY_GATHER);
updateWorkSourceRequestHeaderPosition();
writeInt32(threadState->shouldPropagateWorkSource() ?
threadState->getCallingWorkSourceUid() : IPCThreadState::kUnsetWorkSource);
// currently the interface identification token is just its name as a string
return writeString16(interface);//interface是"android.os.IServiceManager"
}
2.3.3 writeStrongBinder
status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
{
return flatten_binder(ProcessState::self(), val, this);//ProcessState是进程状态,val是new MediaPlayerService,BBinder实体。
//this是Parcel对象data
}
2.3.4 flatten_binder
1.parcel对象内部会有一个buffer,记录着parcel中所有扁平化的数据,有些扁平数据是普通数据,而另一些扁平数据则记录着binder对象。所以parcel中会构造另一个mObjects数组,专门记录那些binder扁平数据所在的位置,
status_t flatten_binder(const sp<ProcessState>& /*proc*/,
const sp<IBinder>& binder, Parcel* out)
{
flat_binder_object obj;
if (IPCThreadState::self()->backgroundSchedulingDisabled()) {
/* minimum priority for all nodes is nice 0 */
obj.flags = FLAT_BINDER_FLAG_ACCEPTS_FDS;
} else {
/* minimum priority for all nodes is MAX_NICE(19) */
obj.flags = 0x13 | FLAT_BINDER_FLAG_ACCEPTS_FDS;
}
if (binder != nullptr) {
BBinder *local = binder->localBinder();//如果是BBinder则返回BBinder,如果是Bpbinder则返回空
/**
if (!local) {//如果是bpbinder,代理
BpBinder *proxy = binder->remoteBinder();//返回Bpbinder
if (proxy == nullptr) {
ALOGE("null proxy");
}
const int32_t handle = proxy ? proxy->handle() : 0;//记录此Binder代理的句柄
obj.hdr.type = BINDER_TYPE_HANDLE;//设置type为binder句柄
obj.binder = 0; /* Don't pass uninitialized stack data to a remote process
obj.handle = handle;//将此binder代理的句柄,放入flat_binder_object中。
obj.cookie = 0;
}
*/
else {//是binder实体
if (local->isRequestingSid()) {
obj.flags |= FLAT_BINDER_FLAG_TXN_SECURITY_CTX;//安全上下文
}
obj.hdr.type = BINDER_TYPE_BINDER;//设置type为binder实体
obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());//存储BBbinder
obj.cookie = reinterpret_cast<uintptr_t>(local);//cookie记录Binder实体的指针
}
}
/**
else {
obj.hdr.type = BINDER_TYPE_BINDER;
obj.binder = 0;
obj.cookie = 0;
}
*/
return finish_flatten_binder(binder, obj, out);//参数binder是new MediaPlayerService的BBbinder实体,obj是扁平的flat_binder_object,out是Parcel对象。
//finish_flatten_binder()函数。这个函数内部会记录下刚刚被扁平化的flat_binder_object在parcel中的位置。
//说得更详细点儿就是,parcel对象内部会有一个buffer,记录着parcel中所有扁平化的数据,
//有些扁平数据是普通数据,而另一些扁平数据则记录着binder对象。
//所以parcel中会构造另一个mObjects数组,专门记录那些binder扁平数据所在的位置,
}
BBinder* BBinder::localBinder()//如果是BBinder则返回BBinder,
{
return this;
}
BBinder* IBinder::localBinder()//如果是Bpbinder则返回空
{
return nullptr;
}
BpBinder* BpBinder::remoteBinder()//返回Bpbinder
{
return this;
}
2.3.5 BpBinder::transact
//transact(ADD_SERVICE_TRANSACTION, data, &reply);
status_t BpBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
//参数分析:
//code是3,也是ADD_SERVICE_TRANSACTION
//data中包含要注册的media服务的名字和media服务的BBinder实体。
//reply为空
//flag是0
{
// Once a binder has died, it will never come back to life.
if (mAlive) {//291行,BpBinder构造函数中是1,表示是否活着
status_t status = IPCThreadState::self()->transact(
mHandle, code, data, reply, flags);
//mHandle是0,代表SMBPbinder的句柄,
//code是code是3,也是ADD_SERVICE_TRANSACTION
//data是data中包含要注册的media服务的名字和media服务的BBinder实体。
//reply为空
//flag是0
if (status == DEAD_OBJECT) mAlive = 0;
return status;
}
return DEAD_OBJECT;
}
2.3.6 IPCThreadState::transact
status_t IPCThreadState::transact(int32_t handle,
uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags)
//mHandle是0,代表SMBPbinder的句柄,
//code是code是3,也是ADD_SERVICE_TRANSACTION
//data是data中包含要注册的media服务的名字和media服务的BBinder实体。
//reply为空
//flag是0
{
status_t err;
flags |= TF_ACCEPT_FDS;//TF_ACCEPT_FDS表示允许使用文件描述符进行答复
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, nullptr);//将消息打包成结构体写入mout中
/**
if (err != NO_ERROR) {//如果出错
if (reply) reply->setError(err);
return (mLastError = err);
}
*/
if ((flags & TF_ONE_WAY) == 0) {//如果是同步的。
if (UNLIKELY(mCallRestriction != ProcessState::CallRestriction::NONE)) {
if (mCallRestriction == ProcessState::CallRestriction::ERROR_IF_NOT_ONEWAY) {
ALOGE("Process making non-oneway call but is restricted.");
CallStack::logStack("non-oneway call", CallStack::getCurrent(10).get(),
ANDROID_LOG_ERROR);
} else /* FATAL_IF_NOT_ONEWAY */ {
LOG_ALWAYS_FATAL("Process may not make oneway calls.");
}
}
if (reply) {//reply存在,则waitForResponse
err = waitForResponse(reply);
} else {//如果reply不存在,则构造一个出来
Parcel fakeReply;
err = waitForResponse(&fakeReply);
}
} else {
err = waitForResponse(nullptr, nullptr);
}
return err;
}
2.3.7 IPCThreadState::writeTransactionData
1.再对数据封装填充到binder_transaction_data结构体中。
2.将要发送给驱动的数据写入mout中。
status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
//参数分析:
//cmd是BC_TRANSACTION,代表请求运输
//binderFlags是允许使用文件描述符进行答复,值是0X10
//mHandle是0,代表SM 的BPbinder的句柄,
//code是code是3,也是ADD_SERVICE_TRANSACTION
//data是data中包含要注册的media服务的名字和media服务的BBinder实体。
//statusBuffer是空
{
binder_transaction_data tr;//此结构体可查看驱动结构体全代码分析
tr.target.ptr = 0; //不用ptr,因为此时要发送的是SM服务的handle句柄
tr.target.handle = handle;//SM服务的handle句柄0
tr.code = code;//code是3,也是ADD_SERVICE_TRANSACTION
tr.flags = binderFlags;//允许使用文件描述符进行答复,值是0X10
tr.cookie = 0;//实体的cookie才有用
tr.sender_pid = 0;//发送方pid
tr.sender_euid = 0;//发送方uid
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(binder_size_t);//ipcObjectsCount函数返回的是mObjectsSize,而mObjects
//存储的是多个扁平的binder对象的位置。是offsets_size的偏移大小
tr.data.ptr.offsets = data.ipcObjects();//指向mObjects数组的首地址。mObjects里面记录了所有binder实体或引用在buffer中的位置。
}
/**
else if (statusBuffer) {
tr.flags |= TF_STATUS_CODE;
*statusBuffer = err;
tr.data_size = sizeof(status_t);
tr.data.ptr.buffer = reinterpret_cast<uintptr_t>(statusBuffer);
tr.offsets_size = 0;
tr.data.ptr.offsets = 0;
} else {
return (mLastError = err);
}
*/
mOut.writeInt32(cmd);//mOut中写入BC_TRANSACTION,注意309行,此时还有一个BC_INCREFS的命令
mOut.write(&tr, sizeof(tr));//写入tr结构体
return NO_ERROR;
}
2.3.8 IPCThreadState::waitForResponse向驱动发送请求add服务的消息
//第一次循环时,向驱动发送请求add服务的消息,mout中有值
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)//acquireResult默认是nullptr
{
uint32_t cmd;
int32_t err;
while (1) {
if ((err=talkWithDriver()) < NO_ERROR) break;//第一次循环时,向驱动发送请求add消息,mout中有值
//后面则是对reply回复消息的处理
err = mIn.errorCheck();
if (err < NO_ERROR) break;
if (mIn.dataAvail() == 0) continue;
cmd = (uint32_t)mIn.readInt32();
IF_LOG_COMMANDS() {
alog << "Processing waitForResponse Command: "
<< getReturnString(cmd) << endl;
}
switch (cmd) {
case BR_TRANSACTION_COMPLETE:
if (!reply && !acquireResult) goto finish;
break;
case BR_DEAD_REPLY:
err = DEAD_OBJECT;
goto finish;
case BR_FAILED_REPLY:
err = FAILED_TRANSACTION;
goto finish;
case BR_ACQUIRE_RESULT:
{
ALOG_ASSERT(acquireResult != NULL, "Unexpected brACQUIRE_RESULT");
const int32_t result = mIn.readInt32();
if (!acquireResult) continue;
*acquireResult = result ? NO_ERROR : INVALID_OPERATION;
}
goto finish;
case BR_REPLY:
{
binder_transaction_data tr;
err = mIn.read(&tr, sizeof(tr));
ALOG_ASSERT(err == NO_ERROR, "Not enough command data for brREPLY");
if (err != NO_ERROR) goto finish;
if (reply) {
if ((tr.flags & TF_STATUS_CODE) == 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);
freeBuffer(nullptr,
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(binder_size_t), this);
}
} else {
freeBuffer(nullptr,
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(binder_size_t), this);
continue;
}
}
goto finish;
default:
err = executeCommand(cmd);
if (err != NO_ERROR) goto finish;
break;
}
}
finish:
if (err != NO_ERROR) {
if (acquireResult) *acquireResult = err;
if (reply) reply->setError(err);
mLastError = err;
}
return err;
}
2.3.9 IPCThreadState::talkWithDriver
status_t IPCThreadState::talkWithDriver(bool doReceive)//doReceive默认是true
{
/**
if (mProcess->mDriverFD < 0) {
return -EBADF;
}
*/
binder_write_read bwr;
//struct binder_write_read {
//binder_size_t write_size;//要写入的字节数,write_buffer的总字节数
//binder_size_t write_consumed;//驱动程序占用的字节数,write_buffer已消费的字节数
//binder_uintptr_t write_buffer;//写缓冲数据的指针
//binder_size_t read_size;//要读的字节数,read_buffer的总字节数
//binder_size_t read_consumed;//驱动程序占用的字节数,read_buffer已消费的字节数
//binder_uintptr_t read_buffer;//读缓存数据的指针
//};
// Is the read buffer empty?
const bool needRead = mIn.dataPosition() >= mIn.dataSize();//此时needRead是ture
//因为mIn.dataPosition返回值和mIn.dataSize相等
//当我们正在从min中读取数据,或者调用方打算读取下一条数据(doReceive为true时),我们不会写入任何内容。
//此时outAvail值等于mOut.dataSize()
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
bwr.write_size = outAvail;//write_size是mOut.dataSize()
bwr.write_buffer = (uintptr_t)mOut.data();
if (doReceive && needRead) {//当我们需要从驱动中读的时候。
bwr.read_size = mIn.dataCapacity();//设置大小为256字节
bwr.read_buffer = (uintptr_t)mIn.data();
}
/*
else {//当不读的时候,设置读的大小和buffer为0
bwr.read_size = 0;
bwr.read_buffer = 0;
}*/
// 如果读缓冲区和写缓冲区都为0,代表无事可做,立即返回,此时write_size中有数据。
/**
if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
*/
bwr.write_consumed = 0;
bwr.read_consumed = 0;
status_t err;
do {
#if defined(__ANDROID__)
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)//向binder驱动区写,因为此时是add服务,所以mout有数据
err = NO_ERROR;
else
err = -errno;
#else
err = INVALID_OPERATION;
#endif
/**
if (mProcess->mDriverFD < 0) {
err = -EBADF;
}
*/
} while (err == -EINTR);
if (err >= NO_ERROR) {//代表驱动收到了消息
if (bwr.write_consumed > 0) {
if (bwr.write_consumed < mOut.dataSize())//如果驱动消费的数据大小小于mout的大小,则说明驱动没有消费mout数据
LOG_ALWAYS_FATAL("Driver did not consume write buffer. "
"err: %s consumed: %zu of %zu",
statusToString(err).c_str(),
(size_t)bwr.write_consumed,
mOut.dataSize());
else {//代表mout被正确消费
mOut.setDataSize(0);//重置数据大小为0
processPostWriteDerefs();//主要是将写的引用计数减少1,释放
}
}
/**
if (bwr.read_consumed > 0) {//如果驱动读的数据大小大于0
mIn.setDataSize(bwr.read_consumed);//设置mIn的大小
mIn.setDataPosition(0);//设置min数据起始位置
}
*/
return NO_ERROR;
}
///return err;
}
2.3.10 binder_ioctl
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret;
struct binder_proc *proc = filp->private_data;//取出media服务进程对应的porc对象
struct binder_thread *thread;//media服务进程的binder线程
unsigned int size = _IOC_SIZE(cmd);
void __user *ubuf = (void __user *)arg;//__user表示用户空间的指针
trace_binder_ioctl(cmd, arg);
ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);//条件成立,立即返回0,不休眠
if (ret)
goto err_unlocked;
binder_lock(__func__);
thread = binder_get_thread(proc);//获取binder_thread
if (thread == NULL) {
ret = -ENOMEM;
goto err;
}
switch (cmd) {
case BINDER_WRITE_READ: {//如果命令是BINDER_WRITE_READ
struct binder_write_read bwr;
if (size != sizeof(struct binder_write_read)) {//判断大小
ret = -EINVAL;
goto err;
}
if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {//从用户空间拷贝数据到内核空间
ret = -EFAULT;
goto err;
}
if (bwr.write_size > 0) {//此时写大于0
ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed);
trace_binder_write_done(ret);
if (ret < 0) {
bwr.read_consumed = 0;
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
goto err;
}
}
if (bwr.read_size > 0) {//此时读的大小大于0,代表我们需要从驱动中读取消息
ret = binder_thread_read(proc, thread, (void __user *)bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK);
//此函数下面会有大量展开参数分析:
//proc,meidaservice服务的proc
//bwr.read_buffer,read_buffer的地址
//read_size>0
//read_consumed,代表已消费的字节数0
//最后一个参数是0
trace_binder_read_done(ret);
/**if (!list_empty(&proc->todo))
wake_up_interruptible(&proc->wait);
if (ret < 0) {
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
goto err;
}*/
}
binder_debug(BINDER_DEBUG_READ_WRITE,
"binder: %d:%d wrote %ld of %ld, read return %ld of %ld\n",
proc->pid, thread->pid, bwr.write_consumed, bwr.write_size,
bwr.read_consumed, bwr.read_size);
if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
ret = -EFAULT;
goto err;
}
break;
}
}
ret = 0;
err:
if (thread)
thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;
binder_unlock(__func__);
wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
if (ret && ret != -ERESTARTSYS)
printk(KERN_INFO "binder: %d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret);
err_unlocked:
trace_binder_ioctl_done(ret);
return ret;
}
2.3.11 binder_thread_write(增加SM对应的句柄0的引用计数)
1.此时是存在两个消息,一个是请求增加SM对应的句柄0的引用计数,一个是meida服务请求add到servicemanager中的消息。
下面为第一次循环,用于处理请求增加SM对应的句柄0的引用计数。
//因为里面有两个数据,一个是请求增加SM对应的句柄0的引用计数,一个是meida服务请求add到servicemanager中的消息。
//此时先分析第一个循环:取出请求增加SM对应的句柄0的引用计数的消息,BC_INCREFS表示binder_ref弱引用计数加1
int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,
void __user *buffer, int size, signed long *consumed)
//参数分析:
//proc代表meida服务进程的proc对象
//thread为此meida服务进程的binder线程
//bwr.write_buffer,内核数据的起始地址,数据有两个一个是BC_INCREFS和其携带的数据handle,还有一个是请求add_service的消息,包含BBbinder等消息。
//write_size,字节,数据大小
//consumed=0,驱动程序已消费的数据大小
{
uint32_t cmd;
void __user *ptr = buffer + *consumed;//是首地址,因为consumed是0
void __user *end = buffer + size;//尾地址
while (ptr < end && thread->return_error == BR_OK) {//死循环,第一次循环获取的cmd是BC_INCREFS
if (get_user(cmd, (uint32_t __user *)ptr))//从buffer的首地址中获取命令,并赋值给cmd
return -EFAULT;
ptr += sizeof(uint32_t);//指针后移,跳过此命令
trace_binder_command(cmd);
if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.bc)) {//记录信息。
binder_stats.bc[_IOC_NR(cmd)]++;
proc->stats.bc[_IOC_NR(cmd)]++;
thread->stats.bc[_IOC_NR(cmd)]++;
}
switch (cmd) {
case BC_INCREFS: //binder_ref的弱引用计数+1
case BC_ACQUIRE: //binder_ref的强引用计数+1
case BC_RELEASE: //binder_ref的强引用计数-1
case BC_DECREFS: { //binder_ref的弱引用计数-1
uint32_t target;
struct binder_ref *ref;
const char *debug_string;
if (get_user(target, (uint32_t __user *)ptr))//此时ptr指向的是0这个数据。所以target等于0
return -EFAULT;
ptr += sizeof(uint32_t);
if (target == 0 && binder_context_mgr_node &&
(cmd == BC_INCREFS || cmd == BC_ACQUIRE)) {//此时走这里,如果是SM的代理,并且sm的实体存在。
ref = binder_get_ref_for_node(proc,
binder_context_mgr_node);//找到了SM的代理
if (ref->desc != target) {
binder_user_error("binder: %d:"
"%d tried to acquire "
"reference to desc 0, "
"got %d instead\n",
proc->pid, thread->pid,
ref->desc);
}
} else
ref = binder_get_ref(proc, target);
if (ref == NULL) {
binder_user_error("binder: %d:%d refcou"
"nt change on invalid ref %d\n",
proc->pid, thread->pid, target);
break;
}
switch (cmd) {
case BC_INCREFS:
debug_string = "IncRefs";
binder_inc_ref(ref, 0, NULL);//弱引用计数加1
break;
}
binder_debug(BINDER_DEBUG_USER_REFS,
"binder: %d:%d %s ref %d desc %d s %d w %d for node %d\n",
proc->pid, thread->pid, debug_string, ref->debug_id,
ref->desc, ref->strong, ref->weak, ref->node->debug_id);
break;
}
}
*consumed = ptr - buffer;//驱动已消费的大小
}//注意此时for循环未结束,开始第二个循环。
return 0;
}
2.3.12 binder_thread_write(处理media服务请求add的消息)
下面为第二次循环,用于处理media服务请求add的消息
//第二个循环,取出第二个media服务请求add的消息
int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,
void __user *buffer, int size, signed long *consumed)
{
uint32_t cmd;
void __user *ptr = buffer + *consumed;
void __user *end = buffer + size;
//第二个循环
while (ptr < end && thread->return_error == BR_OK) {
if (get_user(cmd, (uint32_t __user *)ptr))//此时cmd是BC_TRANSACTION
return -EFAULT;
ptr += sizeof(uint32_t);//跳过命令的位置
trace_binder_command(cmd);
if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.bc)) {
binder_stats.bc[_IOC_NR(cmd)]++;
proc->stats.bc[_IOC_NR(cmd)]++;
thread->stats.bc[_IOC_NR(cmd)]++;
}
switch (cmd) {
case BC_TRANSACTION:
case BC_REPLY: {
struct binder_transaction_data tr;
if (copy_from_user(&tr, ptr, sizeof(tr)))//从用户空间拷贝数据到内核空间,
return -EFAULT;
ptr += sizeof(tr);//指针后移,此时应该是到末尾了
binder_transaction(proc, thread, &tr, cmd == BC_REPLY);//参数分析:
//mediaservice服务对应的proc,
//meidia服务对应的binder thread
//tr消息
//cmd是BC_TRANSACTION,所以此时是0
break;
}
}
*consumed = ptr - buffer;
}
return 0;
}
2.3.13 binder_transaction
主要作用为:
1.首先会找到目标的进程的proc对象和目标进程的线程。
2.然后取出meidapalyservice服务塞入Parcel对象中binder实体对象,并在驱动中创建meidapalyservice服务对应的bbbinder实体,并将此bbbinder实体添加到meidiaplayservice服务的比红黑树中,然后在目标进程(SM进程)的binder_proc中创建对应的binder_ref红黑树节点,将mediaservice的引用添加到SM进程的引用的红黑树中。
3.然后在sm之前映射的进程中分配一块内核buffer空间,将add添加服务的消息数据放入sm进程的缓冲区中。
4.然后将此add服务的消息添加到sm进程的todo队列中。并且唤醒sm进程。
5.同时也会生成一个未完成的事务消息放入到meidaservice的进程队列的todo队列中。
然后就分两个流程走了。
第一个流程是客户端(meidaservice服务)BINDER_WORK_TRANSACTION_COMPLETE事务,然后陷入休眠,等待服务端返回的reply。
第二个流程是binder驱动唤醒sm服务端,然后sm服务处理来自meidaservice的add请求,并将回复发送给驱动,驱动再唤醒等待的meidaservice服务,然后meidaservice服务从驱动中读取reply。
static void binder_transaction(struct binder_proc *proc,
struct binder_thread *thread,
struct binder_transaction_data *tr, int reply)
//reply是0
//tr的数据如下
//tr.target.ptr = 0; //不用ptr,因为此时要发送的是SM服务的handle句柄
//tr.target.handle = handle;//SM服务的handle句柄0
//tr.code = code;//code是3,也是ADD_SERVICE_TRANSACTION
//tr.flags = binderFlags;//允许使用文件描述符进行答复,值是0X10
//tr.cookie = 0;//实体的cookie才有用
//tr.sender_pid = 0;//发送方pid
//tr.sender_euid = 0;//发送方uid
//tr.data_size = data.ipcDataSize();//设置数据的大小
//tr.data.ptr.buffer = data.ipcData();//指向数据的首地址
//tr.offsets_size = data.ipcObjectsCount()*sizeof(binder_size_t);//ipcObjectsCount函数返回的是mObjectsSize,而mObjects
//存储的是多个扁平的binder对象的位置。是offsets_size的偏移大小
//tr.data.ptr.offsets = data.ipcObjects();//指向mObjects数组的首地址。mObjects里面记录了所有binder实体或引用在buffer中的位置。
{
struct binder_transaction *t;//描述Binder进程中通信过程,这个过程称为一个transaction(事务),保存了源线程和目标线程等消息。
struct binder_work *tcomplete;//用来描述的处理的工作事项
size_t *offp, *off_end;
struct binder_proc *target_proc;//目标进程的proc,此处是ServiceManager的proc,因为是向SM去请求add服务
struct binder_thread *target_thread = NULL;//sm的binder线程
struct binder_node *target_node = NULL;//sm的binder实体
struct list_head *target_list;
wait_queue_head_t *target_wait;//目标等待队列,当Binder处理事务A依赖于其他Binder线程处理事务B的情况
// 则会在sleep在wait所描述的等待队列中,直到B事物处理完毕再唤醒
struct binder_transaction *in_reply_to = NULL;
struct binder_transaction_log_entry *e;//log事务
uint32_t return_error;
if (reply) {//此时reply为0
..........
}
else {
/**
if (tr->target.handle) {
此时是0,故不执行
struct binder_ref *ref;
ref = binder_get_ref(proc, tr->target.handle);// 由handle 找到相应 binder_ref, 由binder_ref 找到相应 binder_node
if (ref == NULL) {
binder_user_error("binder: %d:%d got "
"transaction to invalid handle\n",
proc->pid, thread->pid);
return_error = BR_FAILED_REPLY;
goto err_invalid_target_handle;
}
target_node = ref->node;//由binder_ref 找到相应 binder_node
}
*/
else {
target_node = binder_context_mgr_node;//找到目标binder实体节点,即SM的节点
if (target_node == NULL) {
return_error = BR_DEAD_REPLY;
goto err_no_context_mgr_node;
}
}
e->to_node = target_node->debug_id;//log事务。
target_proc = target_node->proc;//找到目标进程的proc,即SM进程的proc
/*
if (target_proc == NULL) {
return_error = BR_DEAD_REPLY;
goto err_dead_binder;
}*/
if (security_binder_transaction(proc->tsk, target_proc->tsk) < 0) {//检查Client进程是否有权限向Server进程发送请求
return_error = BR_FAILED_REPLY;
goto err_invalid_target_handle;
}
/*
if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) {//如果flag不是oneway,并且线程的transaction_stack存在内容
struct binder_transaction *tmp;
tmp = thread->transaction_stack;
if (tmp->to_thread != thread) {
binder_user_error("binder: %d:%d got new "
"transaction with bad transaction stack"
", transaction %d has target %d:%d\n",
proc->pid, thread->pid, tmp->debug_id,
tmp->to_proc ? tmp->to_proc->pid : 0,
tmp->to_thread ?
tmp->to_thread->pid : 0);
return_error = BR_FAILED_REPLY;
goto err_bad_call_stack;
}
while (tmp) {
if (tmp->from && tmp->from->proc == target_proc)
target_thread = tmp->from;
tmp = tmp->from_parent;
}
}*/
}
/*
if (target_thread) {//首次执行target_thread为空
e->to_thread = target_thread->pid;
target_list = &target_thread->todo;
target_wait = &target_thread->wait;
}*/
else {
target_list = &target_proc->todo;//sm进程的todo队列
target_wait = &target_proc->wait;//sm进程的wait队列
}
e->to_proc = target_proc->pid;//log事务
/* TODO: reuse incoming transaction for reply */
t = kzalloc(sizeof(*t), GFP_KERNEL);//在内核创建binder_transaction的空间
/*
if (t == NULL) {
return_error = BR_FAILED_REPLY;
goto err_alloc_t_failed;
}*/
binder_stats_created(BINDER_STAT_TRANSACTION);//记录信息
tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL);//创建binder_work
/*
if (tcomplete == NULL) {
return_error = BR_FAILED_REPLY;
goto err_alloc_tcomplete_failed;
}*/
binder_stats_created(BINDER_STAT_TRANSACTION_COMPLETE);
t->debug_id = ++binder_last_id;//调试信息,此时是1
e->debug_id = t->debug_id;
if (reply)//reply为真,代表是BC_REPLY
binder_debug(BINDER_DEBUG_TRANSACTION,
"binder: %d:%d BC_REPLY %d -> %d:%d, "
"data %p-%p size %zd-%zd\n",
proc->pid, thread->pid, t->debug_id,
target_proc->pid, target_thread->pid,
tr->data.ptr.buffer, tr->data.ptr.offsets,
tr->data_size, tr->offsets_size);
else//reply为假,代表是BC_TRANSACTION
binder_debug(BINDER_DEBUG_TRANSACTION,
"binder: %d:%d BC_TRANSACTION %d -> "
"%d - node %d, data %p-%p size %zd-%zd\n",
proc->pid, thread->pid, t->debug_id,
target_proc->pid, target_node->debug_id,
tr->data.ptr.buffer, tr->data.ptr.offsets,
tr->data_size, tr->offsets_size);
if (!reply && !(tr->flags & TF_ONE_WAY))
t->from = thread;//设置源线程为mediaservice的线程
else
t->from = NULL;
t->sender_euid = proc->tsk->cred->euid;//设置源线程的用户id为mediaservice的进程的uid
t->to_proc = target_proc;//目标进程的proc,此时是SM的proc对象,// 负责处理该事务的进程--ServiceManager
t->to_thread = target_thread;//负责处理该事务的线程--ServiceManager的线程,但此时为空
t->code = tr->code;//code是ADD_SERVICE_TRANSACTION,3
t->flags = tr->flags;//允许使用文件描述符进行答复,值是0X10
t->priority = task_nice(current);//priority是mediaservice服务的线程优先级
trace_binder_transaction(reply, t, target_node);
t->buffer = binder_alloc_buf(target_proc, tr->data_size,
tr->offsets_size, !reply && (t->flags & TF_ONE_WAY));//从目标进程(SM进程)的target_proc中分配一块内核buffer空间,此buffer是映射了的地址空间。
if (t->buffer == NULL) {
return_error = BR_FAILED_REPLY;
goto err_binder_alloc_buf_failed;
}
t->buffer->allow_user_free = 0;
t->buffer->debug_id = t->debug_id;
t->buffer->transaction = t;
t->buffer->target_node = target_node;
trace_binder_transaction_alloc_buf(t->buffer);
if (target_node)
binder_inc_node(target_node, 1, 0, NULL);//引用计数+1
offp = (size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *)));//计算meidaservice服务的binder对象的偏移量
if (copy_from_user(t->buffer->data, tr->data.ptr.buffer, tr->data_size)) {//拷贝用户空间的binder_transaction_data中ptr.buffer到目标进程的buffer-data的缓冲区。
binder_user_error("binder: %d:%d got transaction with invalid "
"data ptr\n", proc->pid, thread->pid);
return_error = BR_FAILED_REPLY;
goto err_copy_data_failed;
}
if (copy_from_user(offp, tr->data.ptr.offsets, tr->offsets_size)) {//拷贝用户空间的ptr.offsets中ptr.buffer到目标进程(SM服务)的buffer缓冲区。
binder_user_error("binder: %d:%d got transaction with invalid "
"offsets ptr\n", proc->pid, thread->pid);
return_error = BR_FAILED_REPLY;
goto err_copy_data_failed;
}
if (!IS_ALIGNED(tr->offsets_size, sizeof(size_t))) {
binder_user_error("binder: %d:%d got transaction with "
"invalid offsets size, %zd\n",
proc->pid, thread->pid, tr->offsets_size);
return_error = BR_FAILED_REPLY;
goto err_bad_offset;
}
off_end = (void *)offp + tr->offsets_size;//计算偏移大小的末端
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 *))) {
binder_user_error("binder: %d:%d got transaction with "
"invalid offset, %zd\n",
proc->pid, thread->pid, *offp);
return_error = BR_FAILED_REPLY;
goto err_bad_offset;
}
fp = (struct flat_binder_object *)(t->buffer->data + *offp);//取出flat_binder_object对象,里面存储的是meidaservice的BBbinder实体
switch (fp->type) {//是BINDER_TYPE_BINDER,表示存储的是实体
case BINDER_TYPE_BINDER:
case BINDER_TYPE_WEAK_BINDER: {
struct binder_ref *ref;//binder引用
struct binder_node *node = binder_get_node(proc, fp->binder);//从mediaservice服务的proc对象中获取里面获取此meidaservice的binder实体
//此时是没有的,因为之前并未创建meidaservice对应的驱动层binder实体对象。
if (node == NULL) {//mediaservice服务的proc对象中无此BBbinder节点
node = binder_new_node(proc, fp->binder, fp->cookie);//为mediaservice服务的binder实体创建binder_node,
//并添加到meidaservice的proc红黑树proc->nodes.rb_node中
/*
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);
}
if (fp->cookie != node->cookie) {//检查缓存
binder_user_error("binder: %d:%d sending u%p "
"node %d, cookie mismatch %p != %p\n",
proc->pid, thread->pid,
fp->binder, node->debug_id,
fp->cookie, node->cookie);
goto err_binder_get_ref_for_node_failed;
}
if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) {//检查权限
return_error = BR_FAILED_REPLY;
goto err_binder_get_ref_for_node_failed;
}
ref = binder_get_ref_for_node(target_proc, node);//在目标进程(SM进程)的binder_proc中创建对应的binder_ref红黑树节点,
//即将mediaservice的引用添加到SM进程的引用的红黑树中。
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;//将类型变为binder引用类型
else
fp->type = BINDER_TYPE_WEAK_HANDLE;
fp->handle = ref->desc;//记录meidaservice服务的句柄是1,binder_get_ref_for_node函数中会将desc进行+1,保证其唯一性。
binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE,
&thread->todo);
trace_binder_transaction_node_to_ref(t, node, ref);
} break;
}
/*
if (reply) {//此时为false
BUG_ON(t->buffer->async_transaction != 0);
binder_pop_transaction(target_thread, in_reply_to);
}*/
else if (!(t->flags & TF_ONE_WAY)) {
BUG_ON(t->buffer->async_transaction != 0);
t->need_reply = 1;//是双向的,所以需要回复
t->from_parent = thread->transaction_stack;//等于当前线程(mediaservice服务)的transaction_stack
thread->transaction_stack = t;//将传递数据保存在请求线程的中,以便后续缓存释放等
}
/**
else {
BUG_ON(target_node == NULL);
BUG_ON(t->buffer->async_transaction != 1);
if (target_node->has_async_transaction) {
target_list = &target_node->async_todo;
target_wait = NULL;
} else
target_node->has_async_transaction = 1;
}
*/
t->work.type = BINDER_WORK_TRANSACTION;//将BINDER_WORK_TRANSACTION添加到目标队列(SM进程的队列),即target_proc->todo队列
list_add_tail(&t->work.entry, target_list);
tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;//未完成的事务
list_add_tail(&tcomplete->entry, &thread->todo);//将BINDER_WORK_TRANSACTION_COMPLETE添加到当前线程队列(mediaservice服务的todo队列),即thread->todo
//注意此处非常重要,查阅大量书籍得知,当向当前线程的todo队列中插入一个未完成的事务时,min中就有了数据。
if (target_wait)
wake_up_interruptible(target_wait);//唤醒等待队列,本次通信的目标进程(SM进程的队列)队列为target_proc->wait
return;
/**
err_get_unused_fd_failed:
err_fget_failed:
err_fd_not_allowed:
err_binder_get_ref_for_node_failed:
err_binder_get_ref_failed:
err_binder_new_node_failed:
err_bad_object_type:
err_bad_offset:
err_copy_data_failed:
trace_binder_transaction_failed_buffer_release(t->buffer);
binder_transaction_buffer_release(target_proc, t->buffer, offp);
t->buffer->transaction = NULL;
binder_free_buf(target_proc, t->buffer);
err_binder_alloc_buf_failed:
kfree(tcomplete);
binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE);
err_alloc_tcomplete_failed:
kfree(t);
binder_stats_deleted(BINDER_STAT_TRANSACTION);
err_alloc_t_failed:
err_bad_call_stack:
err_empty_call_stack:
err_dead_binder:
err_invalid_target_handle:
err_no_context_mgr_node:
binder_debug(BINDER_DEBUG_FAILED_TRANSACTION,
"binder: %d:%d transaction failed %d, size %zd-%zd\n",
proc->pid, thread->pid, return_error,
tr->data_size, tr->offsets_size);
{
struct binder_transaction_log_entry *fe;
fe = binder_transaction_log_add(&binder_transaction_log_failed);
*fe = *e;
}
BUG_ON(thread->return_error != BR_OK);
if (in_reply_to) {
thread->return_error = BR_TRANSACTION_COMPLETE;
binder_send_failed_reply(in_reply_to, return_error);
} else
thread->return_error = return_error;
*/
}
2.4 mediapalyservice服务陷入休眠
此时我们先分析第一个流程。
第一个流程是客户端(meidaservice服务)BINDER_WORK_TRANSACTION_COMPLETE事务,然后陷入休眠,等待服务端返回的reply。
此时从上文我们知道
binder_transaction返回到binder_thread_write,然后再返回到2.3.10 的binder_ioctl函数。我们便从这里开始继续分析。
2.4.1 binder_ioctl
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret;
struct binder_proc *proc = filp->private_data;//取出media服务进程对应的porc对象
struct binder_thread *thread;//media服务进程的binder线程
unsigned int size = _IOC_SIZE(cmd);
void __user *ubuf = (void __user *)arg;//__user表示用户空间的指针
trace_binder_ioctl(cmd, arg);
ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);//条件成立,立即返回0,不休眠
if (ret)
goto err_unlocked;
binder_lock(__func__);
thread = binder_get_thread(proc);//获取binder_thread
if (thread == NULL) {
ret = -ENOMEM;
goto err;
}
switch (cmd) {
case BINDER_WRITE_READ: {//如果命令是BINDER_WRITE_READ
struct binder_write_read bwr;
if (size != sizeof(struct binder_write_read)) {//判断大小
ret = -EINVAL;
goto err;
}
if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {//从用户空间拷贝数据到内核空间
ret = -EFAULT;
goto err;
}
if (bwr.write_size > 0) {//此时写大于0
ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed);
trace_binder_write_done(ret);
if (ret < 0) {
bwr.read_consumed = 0;
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
goto err;
}
}
if (bwr.read_size > 0) {//此时读的大小大于0,代表我们需要从驱动中读取消息
ret = binder_thread_read(proc, thread, (void __user *)bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK);
//此函数下面会有大量展开参数分析:
//proc,meidaservice服务的proc
//bwr.read_buffer,read_buffer的地址
//read_size>0
//read_consumed,代表已消费的字节数0
//最后一个参数是0
trace_binder_read_done(ret);
/**if (!list_empty(&proc->todo))
wake_up_interruptible(&proc->wait);
if (ret < 0) {
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
goto err;
}*/
}
binder_debug(BINDER_DEBUG_READ_WRITE,
"binder: %d:%d wrote %ld of %ld, read return %ld of %ld\n",
proc->pid, thread->pid, bwr.write_consumed, bwr.write_size,
bwr.read_consumed, bwr.read_size);
if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
ret = -EFAULT;
goto err;
}
break;
}
}
ret = 0;
err:
if (thread)
thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;
binder_unlock(__func__);
wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
if (ret && ret != -ERESTARTSYS)
printk(KERN_INFO "binder: %d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret);
err_unlocked:
trace_binder_ioctl_done(ret);
return ret;
}
2.4.2 binder_thread_read
1.第一次循环,首先会往read_buffer中塞入BR_NOOP,然后从todo队列中取出BINDER_WORK_TRANSACTION_COMPLETE事务,转化为BR_TRANSACTION_COMPLETE,并放入read_buffer中。
2.第二次循环,检查todo队列中是否还存在事务。此时不存在,则返回read_buffer,返回
2.4.1 binder_ioctl函数,此函数会拷贝数据到用户空间。
第一次循环:
static int binder_thread_read(struct binder_proc *proc,
struct binder_thread *thread,
void __user *buffer, int size,
signed long *consumed, int non_block)
//参数分析:
//proc,meidaservice服务的proc
//buffer=bwr.read_buffer,read_buffer的地址
//size=read_size>0
//read_consumed,代表已消费的字节数0
//non_block是0,代表阻塞
{
void __user *ptr = buffer + *consumed;//指向首地址
void __user *end = buffer + size;//指向尾端地址
int ret = 0;
int wait_for_proc_work;
if (*consumed == 0) {
if (put_user(BR_NOOP, (uint32_t __user *)ptr))//往用户指向的空间里面放一个BR_NOOP
return -EFAULT;
ptr += sizeof(uint32_t);
}
retry:
wait_for_proc_work = thread->transaction_stack == NULL &&
list_empty(&thread->todo);//此时线程的todo队列中有一个未完成的事务
/**
if (thread->return_error != BR_OK && ptr < end) {
if (thread->return_error2 != BR_OK) {
if (put_user(thread->return_error2, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
binder_stat_br(proc, thread, thread->return_error2);
if (ptr == end)
goto done;
thread->return_error2 = BR_OK;
}
if (put_user(thread->return_error, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
binder_stat_br(proc, thread, thread->return_error);
thread->return_error = BR_OK;
goto done;
}
*/
thread->looper |= BINDER_LOOPER_STATE_WAITING;
/**
if (wait_for_proc_work)//此时不为真,因为队列中有数据
proc->ready_threads++;
binder_unlock(__func__);
trace_binder_wait_for_work(wait_for_proc_work,
!!thread->transaction_stack,
!list_empty(&thread->todo));
if (wait_for_proc_work) {
if (!(thread->looper & (BINDER_LOOPER_STATE_REGISTERED |
BINDER_LOOPER_STATE_ENTERED))) {
binder_user_error("binder: %d:%d ERROR: Thread waiting "
"for process work before calling BC_REGISTER_"
"LOOPER or BC_ENTER_LOOPER (state %x)\n",
proc->pid, thread->pid, thread->looper);
wait_event_interruptible(binder_user_error_wait,
binder_stop_on_user_error < 2);
}
binder_set_nice(proc->default_priority);
if (non_block) {
if (!binder_has_proc_work(proc, thread))
ret = -EAGAIN;
} else
ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread));
}*/
else {
if (non_block) {//如果非阻塞
if (!binder_has_thread_work(thread))
ret = -EAGAIN;
} else
ret = wait_event_freezable(thread->wait, binder_has_thread_work(thread));//此时thread中有消息是不会阻塞的
}
binder_lock(__func__);
/**
if (wait_for_proc_work)
proc->ready_threads--;
*/
thread->looper &= ~BINDER_LOOPER_STATE_WAITING;//取消当前线程正在等待的标志
/**if (ret)
return ret;*/
while (1) {
uint32_t cmd;
struct binder_transaction_data tr;
struct binder_work *w;
struct binder_transaction *t = NULL;
if (!list_empty(&thread->todo))
w = list_first_entry(&thread->todo, struct binder_work, entry);//取出BINDER_WORK_TRANSACTION_COMPLETE事务
/**
else if (!list_empty(&proc->todo) && wait_for_proc_work)
w = list_first_entry(&proc->todo, struct binder_work, entry);
else {
if (ptr - buffer == 4 && !(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN)) /* no data added
goto retry;
break;
}*/
/**
if (end - ptr < sizeof(tr) + 4)
break;
*/
switch (w->type) {
/**
case BINDER_WORK_TRANSACTION: {
t = container_of(w, struct binder_transaction, work);
} break;
*/
case BINDER_WORK_TRANSACTION_COMPLETE: {//此时走这里。
cmd = BR_TRANSACTION_COMPLETE;//生成BR_TRANSACTION_COMPLETE
if (put_user(cmd, (uint32_t __user *)ptr))//将此命令放入用户空间中,此时有两个命令BR_TRANSACTION_COMPLETE和BR_NOOP
return -EFAULT;
ptr += sizeof(uint32_t);
binder_stat_br(proc, thread, cmd);
binder_debug(BINDER_DEBUG_TRANSACTION_COMPLETE,
"binder: %d:%d BR_TRANSACTION_COMPLETE\n",
proc->pid, thread->pid);
list_del(&w->entry);//删除w代表的BINDER_WORK_TRANSACTION_COMPLETE事务,因为此时已经用完了
kfree(w);//释放w的空间
binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE);
} break;
}
if (!t)
continue;//开启下一次循环
.....
}
第二次循环:
static int binder_thread_read(struct binder_proc *proc,
struct binder_thread *thread,
void __user *buffer, int size,
signed long *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))
w = list_first_entry(&thread->todo, struct binder_work, entry);
else if (!list_empty(&proc->todo) && wait_for_proc_work)
w = list_first_entry(&proc->todo, struct binder_work, entry);
*/
else {//此时走这里
/**不执行
if (ptr - buffer == 4 && !(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN)) /* no data added
goto retry;
break;
*/
}
if (end - ptr < sizeof(tr) + 4)//根据书上的流程,此时应该走这里,退出循环,因为此时end是readbuffer的尾地址
//而ptr是第8个字节的位置,里面有两个命令分别是BR_TRANSACTION_COMPLETE和BR_NOOP
break;
}
done:
*consumed = ptr - buffer;//值是8,里面是两个命令BR_NOOP和BR_TRANSACTION_COMPLETE和
return 0;
}
2.4.3 IPCThreadState::talkWithDriver
此时我们流程回到了2.3.9中的talkWithDriver函数。前面部分一样,我们主要分析bwr.write_consumed>0,这一块。然后会继续返回到2.3.8的IPCThreadState::waitForResponse函数。
截取部分为:
if (err >= NO_ERROR) {//代表读取成功
if (bwr.write_consumed > 0) {
if (bwr.write_consumed < mOut.dataSize())//如果驱动消费的数据大小小于mout的大小,则说明驱动没有消费mout数据
LOG_ALWAYS_FATAL("Driver did not consume write buffer. "
"err: %s consumed: %zu of %zu",
statusToString(err).c_str(),
(size_t)bwr.write_consumed,
mOut.dataSize());
else {//代表mout被正确消费
mOut.setDataSize(0);//重置数据大小为0
processPostWriteDerefs();//主要是将写的引用计数减少1,释放
}
}
//此时bwr中有两个数据,一个BR_NOOP和BR_TRANSACTION_COMPLETE
if (bwr.read_consumed > 0) {//如果驱动读的数据大小大于0
mIn.setDataSize(bwr.read_consumed);//设置mIn的大小
mIn.setDataPosition(0);//设置min数据起始位置
}
return NO_ERROR;
}
源部分为:
status_t IPCThreadState::talkWithDriver(bool doReceive)//doReceive默认是true
{
/**
if (mProcess->mDriverFD < 0) {
return -EBADF;
}
*/
binder_write_read bwr;
//struct binder_write_read {
//binder_size_t write_size;//要写入的字节数,write_buffer的总字节数
//binder_size_t write_consumed;//驱动程序占用的字节数,write_buffer已消费的字节数
//binder_uintptr_t write_buffer;//写缓冲数据的指针
//binder_size_t read_size;//要读的字节数,read_buffer的总字节数
//binder_size_t read_consumed;//驱动程序占用的字节数,read_buffer已消费的字节数
//binder_uintptr_t read_buffer;//读缓存数据的指针
//};
// Is the read buffer empty?
const bool needRead = mIn.dataPosition() >= mIn.dataSize();//此时needRead是ture
//因为mIn.dataPosition返回值和mIn.dataSize相等,很奇怪
//当我们正在从min中读取数据,或者调用方打算读取下一条数据(doReceive为true时),我们不会写入任何内容。
//此时doReceive是false,且无数据可读,所以我们是会写入数据的
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
bwr.write_size = outAvail;//write_size是mOut.dataSize()
bwr.write_buffer = (uintptr_t)mOut.data();
if (doReceive && needRead) {//当我们正在读的时候。
bwr.read_size = mIn.dataCapacity();
bwr.read_buffer = (uintptr_t)mIn.data();
}
/* else {//当不读的时候,设置读的大小和buffer为0
bwr.read_size = 0;
bwr.read_buffer = 0;
}*/
// 如果读缓冲区和写缓冲区都为0,代表无事可做,立即返回,此时write_size中有数据。
/**
if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
*/
bwr.write_consumed = 0;
bwr.read_consumed = 0;
status_t err;
do {
#if defined(__ANDROID__)
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)//向binder驱动区写,因为此时是add服务,所以mout有数据
err = NO_ERROR;
else
err = -errno;
#else
err = INVALID_OPERATION;
#endif
/**
if (mProcess->mDriverFD < 0) {
err = -EBADF;
}
*/
} while (err == -EINTR);
if (err >= NO_ERROR) {//代表读取成功
if (bwr.write_consumed > 0) {
if (bwr.write_consumed < mOut.dataSize())//如果驱动消费的数据大小小于mout的大小,则说明驱动没有消费mout数据
LOG_ALWAYS_FATAL("Driver did not consume write buffer. "
"err: %s consumed: %zu of %zu",
statusToString(err).c_str(),
(size_t)bwr.write_consumed,
mOut.dataSize());
else {//代表mout被正确消费
mOut.setDataSize(0);//重置数据大小为0
processPostWriteDerefs();//主要是将写的引用计数减少1,释放
}
}
//此时bwr中有两个数据,一个BR_NOOP和BR_TRANSACTION_COMPLETE
if (bwr.read_consumed > 0) {//如果驱动读的数据大小大于0
mIn.setDataSize(bwr.read_consumed);//设置mIn的大小
mIn.setDataPosition(0);//设置min数据起始位置
}
return NO_ERROR;
}
///return err;
}
2.4.4 IPCThreadState::waitForResponse
1.第一次循环会取出BR_NOOP,此命令啥都没做。
2.第二次循环会取出BR_TRANSACTION_COMPLETE,如果此时消息是异步的消息,则此次通信
结束,miedaplayservice陷入休眠等待来自驱动的回复消息,如果是同步的消息,则会进入第三次循环,此次循环,miedaplayservice会休眠,等待来自驱动的消息和唤醒。
第一次循环:
//第一次循环取出BR_NOOP
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)//acquireResult默认是nullptr
{
uint32_t cmd;
int32_t err;
while (1) {
if ((err=talkWithDriver()) < NO_ERROR) break;//第一次循环时,向驱动发送请求add消息,mout中有值
err = mIn.errorCheck();//检查数据是否错误
if (err < NO_ERROR) break;
//if (mIn.dataAvail() == 0) continue;此时min中有数据,故不会执行
cmd = (uint32_t)mIn.readInt32();//取出第一个cmd,此时是BR_NOOP
IF_LOG_COMMANDS() {
alog << "Processing waitForResponse Command: "
<< getReturnString(cmd) << endl;
}
switch (cmd) {//此时是BR_NOOP,没找到,所以执行executeCommand
default:
err = executeCommand(cmd);//查看第47行
if (err != NO_ERROR) goto finish;
break;
}
}
finish:
if (err != NO_ERROR) {
if (acquireResult) *acquireResult = err;
if (reply) reply->setError(err);
mLastError = err;
}
return err;
}
status_t IPCThreadState::executeCommand(int32_t cmd)//此时cmd是BR_NOOP,此命令没做处理
{
BBinder* obj;
RefBase::weakref_type* refs;
status_t result = NO_ERROR;
switch ((uint32_t)cmd) {
case BR_NOOP:
break;
}
if (result != NO_ERROR) {
mLastError = result;
}
return result;
}
第二次循环:
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)//acquireResult默认是nullptr
{
uint32_t cmd;
int32_t err;
while (1) {
if ((err=talkWithDriver()) < NO_ERROR) break;//第二次循环
err = mIn.errorCheck();//检查数据是否错误
if (err < NO_ERROR) break;
if (mIn.dataAvail() == 0) continue;//此时min中有数据,故不会执行
cmd = (uint32_t)mIn.readInt32();//取出第二个cmd,此时是BR_TRANSACTION_COMPLETE
switch (cmd) {
case BR_TRANSACTION_COMPLETE:
if (!reply && !acquireResult) goto finish;//如果是异步,则走到finish中,如果是同步,则进入下一次while循环
break;
}
finish:
if (err != NO_ERROR) {
if (acquireResult) *acquireResult = err;
if (reply) reply->setError(err);
mLastError = err;
}
return err;
}
2.4.5 talkWithDriver第三次循环(同步消息才会有):
1.此时meidalservice服务陷入休眠。
status_t IPCThreadState::talkWithDriver(bool doReceive)//默认doReceive是true
{
if (mProcess->mDriverFD <= 0) {
return -EBADF;
}
binder_write_read bwr;
const bool needRead = mIn.dataPosition() >= mIn.dataSize();//此时needRead是true
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;//此时outAvail是0
bwr.write_size = outAvail;//write_size是0
bwr.write_buffer = (uintptr_t)mOut.data();
// This is what we'll read.
if (doReceive && needRead) {//需要读取数据
bwr.read_size = mIn.dataCapacity();//设置需要读取的大小。
bwr.read_buffer = (uintptr_t)mIn.data();
}
/*else {//不执行
bwr.read_size = 0;
bwr.read_buffer = 0;
}*/
// 不会执行
//if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
bwr.write_consumed = 0;
bwr.read_consumed = 0;
status_t err;
do {
#if defined(__ANDROID__)
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)//从驱动中读取消息,在这里面
//会线程休眠,//查看【3.3.2】binder_ioctl
err = NO_ERROR;
else
err = -errno;
/*
#else
err = INVALID_OPERATION;
#endif
if (mProcess->mDriverFD <= 0) {
err = -EBADF;
}
IF_LOG_COMMANDS() {
alog << "Finished read/write, write size = " << mOut.dataSize() << endl;
}
} while (err == -EINTR);
IF_LOG_COMMANDS() {
alog << "Our err: " << (void*)(intptr_t)err << ", write consumed: "
<< bwr.write_consumed << " (of " << mOut.dataSize()
<< "), read consumed: " << bwr.read_consumed << endl;
}
if (err >= NO_ERROR) {
if (bwr.write_consumed > 0) {
if (bwr.write_consumed < mOut.dataSize())
mOut.remove(0, bwr.write_consumed);
else {
mOut.setDataSize(0);
processPostWriteDerefs();
}
}
if (bwr.read_consumed > 0) {
mIn.setDataSize(bwr.read_consumed);
mIn.setDataPosition(0);
}
IF_LOG_COMMANDS() {
TextOutput::Bundle _b(alog);
alog << "Remaining data size: " << mOut.dataSize() << endl;
alog << "Received commands from driver: " << indent;
const void* cmds = mIn.data();
const void* end = mIn.data() + mIn.dataSize();
alog << HexDump(cmds, mIn.dataSize()) << endl;
while (cmds < end) cmds = printReturnCommand(alog, cmds);
alog << dedent;
}
return NO_ERROR;
}
return err;
*/
}
2.4.6 binder_ioctl
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret;
struct binder_proc *proc = filp->private_data;//取出meidaservice进程对应的porc对象
struct binder_thread *thread;//meidaservice进进程的binder线程
unsigned int size = _IOC_SIZE(cmd);
void __user *ubuf = (void __user *)arg;//__user表示用户空间的指针
trace_binder_ioctl(cmd, arg);
ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);//条件成立,立即返回,不休眠
if (ret)
goto err_unlocked;
binder_lock(__func__);
thread = binder_get_thread(proc);//获取binder_thread
if (thread == NULL) {
ret = -ENOMEM;
goto err;
}
switch (cmd) {
case BINDER_WRITE_READ: {
struct binder_write_read bwr;
if (size != sizeof(struct binder_write_read)) {//计算数据是否和规范
ret = -EINVAL;
goto err;
}
if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {//拷贝数据到内核空间
ret = -EFAULT;
goto err;
}
/*if (bwr.write_size > 0) {//此时write_siz=0,不执行
ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed);
trace_binder_write_done(ret);
if (ret < 0) {
bwr.read_consumed = 0;
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
goto err;
}
}
*/
if (bwr.read_size > 0) {//此时read_size>0
ret = binder_thread_read(proc, thread, (void __user *)bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK);
//此时meidaservice的binder线程会阻塞在这里。后面暂不执行,等待唤醒时,才会执行
/*
if (!list_empty(&proc->todo))
wake_up_interruptible(&proc->wait);
if (ret < 0) {
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
goto err;
}
}
binder_debug(BINDER_DEBUG_READ_WRITE,
"binder: %d:%d wrote %ld of %ld, read return %ld of %ld\n",
proc->pid, thread->pid, bwr.write_consumed, bwr.write_size,
bwr.read_consumed, bwr.read_size);
if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
ret = -EFAULT;
goto err;
}
break;
}
}
ret = 0;
err:
if (thread)
thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;
binder_unlock(__func__);
wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
if (ret && ret != -ERESTARTSYS)
printk(KERN_INFO "binder: %d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret);
err_unlocked:
trace_binder_ioctl_done(ret);
return ret;
*/
}
2.4.7 binder_thread_read
static int binder_thread_read(struct binder_proc *proc,
struct binder_thread *thread,
void __user *buffer, int size,
signed long *consumed, int non_block)
//参数分析:
//proc是media是mediaservice服务的proc
//thread是meidaservice服务的线程
//buffer指向read_buffer,读的首地址
//read_size>0
//read_consumed是0
//non_block是0,表示是阻塞的
{
void __user *ptr = buffer + *consumed;//指向buffer首地址
void __user *end = buffer + size;//指向尾地址
int ret = 0;
int wait_for_proc_work;
if (*consumed == 0) {
if (put_user(BR_NOOP, (uint32_t __user *)ptr))//向里面放一个BR_NOOP命令
return -EFAULT;
ptr += sizeof(uint32_t);
}
retry:
wait_for_proc_work = thread->transaction_stack == NULL &&
list_empty(&thread->todo);//此时当前线程的运输事务不空,即transaction_stack不为空
thread->looper |= BINDER_LOOPER_STATE_WAITING;//设置等待的flag
/*if (wait_for_proc_work)//不执行
proc->ready_threads++;*/
binder_unlock(__func__);
/*if (wait_for_proc_work) {//wait_for_proc_work是false,不执行
if (!(thread->looper & (BINDER_LOOPER_STATE_REGISTERED |
BINDER_LOOPER_STATE_ENTERED))) {
wait_event_interruptible(binder_user_error_wait,
binder_stop_on_user_error < 2);
}
binder_set_nice(proc->default_priority);
if (non_block) {
if (!binder_has_proc_work(proc, thread))
ret = -EAGAIN;
} else
ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread));
} */
else {//走这里
/*if (non_block) {不执行
if (!binder_has_thread_work(thread))
ret = -EAGAIN;
} */
else
ret = wait_event_freezable(thread->wait, binder_has_thread_work(thread));//meidaservice线程陷入休眠
}
//后面都不执行,故省略.....
}
2.5 ServiceManager被唤醒
在2.3.13 binder_transaction的最后,我们知道mediaplayservice服务往servicemanager服务的todo队列中,插入了add消息,并且唤醒了servicemanager服务。
在启动篇,我们知道servicemanager没有消息的时候,会阻塞休眠。我们回到servicemanager启动分析线程阻塞处。如有疑问,可先看启动篇。
我们先回顾一下servicemanager的休眠时的函数调用栈。
binder_loop->binder_ioctl->binder_thread_read->然后休眠阻塞。
2.5.1 binder_thread_read
1.当servicemanager被唤醒后,则会从tod队列中取出获取binder_transaction_data消息。并写入
BR_TRANSACTION。
2.将binder_transaction_data数据拷贝到用户空间,注意此处只是执行了拷贝命令,但没有拷贝数据,binder只有一次数据拷贝。
//此时在serviceManager端。
static int binder_thread_read(struct binder_proc *proc,
struct binder_thread *thread,
void __user *buffer, int size,
signed long *consumed, int non_block)
//参数分析:
//sm对应的proc对象
//binder线程对象
//读buffer的首地址,
//size是32字节
//consumed是0,代表驱动写入readbuffer的大小
//non_block是0,代表阻塞
{
void __user *ptr = buffer + *consumed;//还是数据首地址
void __user *end = buffer + size;//数据尾地址
int ret = 0;
int wait_for_proc_work;
if (*consumed == 0) {//当消费数量为空时,将BR_NOOP放入ptr,即放入了read buffer,那么就是覆盖了BC_ENTER_LOOPER
if (put_user(BR_NOOP, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);//readbuffer往后移动跳过命令的位置。
}
retry:
wait_for_proc_work = thread->transaction_stack == NULL &&
list_empty(&thread->todo);//此时todo为空,并且transaction_stack也为空,即wait_for_proc_work为true
//如果一个线程的的事务堆栈 transaction_stack 不等于 NULL, 表示它正在等待其他线程完成另外一个事务.
//如果一个线程的 todo 队列不等于 NULL, 表示该线程有未处理的工作项.
//一个线程只有在其事务堆栈 transaction_stack 为 NULL, 并且 todo 队列为 NULL 时, 才可以去处理其所属进程todo 队列中的待处理工作项.
//否则就要处理其事务堆栈 transaction_stack 中的事物或者 todo 队列中的待处理工作项.
/**
if (thread->return_error != BR_OK && ptr < end) {//如果当前线程的状态是错误,并且readbuffer有空间,则写入错误信息。
if (thread->return_error2 != BR_OK) {
if (put_user(thread->return_error2, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
binder_stat_br(proc, thread, thread->return_error2);
if (ptr == end)
goto done;
thread->return_error2 = BR_OK;
}
if (put_user(thread->return_error, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
binder_stat_br(proc, thread, thread->return_error);
thread->return_error = BR_OK;
goto done;
}
*/
thread->looper |= BINDER_LOOPER_STATE_WAITING;//BINDER_LOOPER_STATE_WAITING 表示该线程正处于空闲状态
if (wait_for_proc_work)//无任何任务处理
proc->ready_threads++;//进程中空闲binder线程加1
binder_unlock(__func__);
trace_binder_wait_for_work(wait_for_proc_work,
!!thread->transaction_stack,
!list_empty(&thread->todo));
if (wait_for_proc_work) {//当进程todo队列没有数据,则进入休眠等待状态
/**
if (!(thread->looper & (BINDER_LOOPER_STATE_REGISTERED |
BINDER_LOOPER_STATE_ENTERED))) {//如果当前线程还没有注册过,即还未发送BC_ENTER_LOOPER指令,而我们挂起了该线程,即为出错。
binder_user_error("binder: %d:%d ERROR: Thread waiting "
"for process work before calling BC_REGISTER_"
"LOOPER or BC_ENTER_LOOPER (state %x)\n",
proc->pid, thread->pid, thread->looper);
wait_event_interruptible(binder_user_error_wait,
binder_stop_on_user_error < 2);//不休眠
}
*/
binder_set_nice(proc->default_priority);
/**
if (non_block) {//如果是非阻塞的。但是binder通信一般是阻塞的
if (!binder_has_proc_work(proc, thread))
ret = -EAGAIN;
}
*/
else
ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread));//当进程todo队列没有数据,则进入休眠等待状态,
//待直到其所属的进程有新的未处理工作项为止.
}
//此时被唤醒后,执行后半段。
binder_lock(__func__);
if (wait_for_proc_work)
proc->ready_threads--;//空闲线程减1
thread->looper &= ~BINDER_LOOPER_STATE_WAITING;//取消等待的标志
if (ret)
return ret;
while (1) {
uint32_t cmd;
struct binder_transaction_data tr;//运输事务的数据
struct binder_work *w;
struct binder_transaction *t = NULL;//运输事务
/**先从线程todo队列获取事务数据
if (!list_empty(&thread->todo))
w = list_first_entry(&thread->todo, struct binder_work, entry);
*/
else if (!list_empty(&proc->todo) && wait_for_proc_work)
//线程todo队列没有数据, 则从进程todo对获取事务数据
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;
}
*/
if (end - ptr < sizeof(tr) + 4)//如果数据不规范,则break
break;
switch (w->type) {
case BINDER_WORK_TRANSACTION: {//获取transaction数据
t = container_of(w, struct binder_transaction, work);
} break;
}
/**if (!t)//如果数据错误
continue;
*/
BUG_ON(t->buffer == NULL);
if (t->buffer->target_node) {
struct binder_node *target_node = t->buffer->target_node;//取出目标binder实体此时是SM的binder实体
tr.target.ptr = target_node->ptr;//SM的binder实体BBinder对应的bpBiner引用
tr.cookie = target_node->cookie;//SM的binder实体本地地址
t->saved_priority = task_nice(current);//保存之前的优先级
if (t->priority < target_node->min_priority &&
!(t->flags & TF_ONE_WAY))
binder_set_nice(t->priority);//设置较大的优先级
else if (!(t->flags & TF_ONE_WAY) ||
t->saved_priority > target_node->min_priority)
binder_set_nice(target_node->min_priority);
cmd = BR_TRANSACTION;//设置cmd是BR_TRANSACTION
}
/**
else {
tr.target.ptr = NULL;
tr.cookie = NULL;
cmd = BR_REPLY;
}
*/
tr.code = t->code;//code是ADD_SERVICE_TRANSACTION,3
tr.flags = t->flags;//允许使用文件描述符进行答复,值是0X10
tr.sender_euid = t->sender_euid;//mediaservice的进程的uid
if (t->from) {
struct task_struct *sender = t->from->proc->tsk;
tr.sender_pid = task_tgid_nr_ns(sender,//mediaservice的进程的pid
current->nsproxy->pid_ns);
} else {
tr.sender_pid = 0;
}
tr.data_size = t->buffer->data_size;//buffer大小
tr.offsets_size = t->buffer->offsets_size;
tr.data.ptr.buffer = (void *)t->buffer->data +
proc->user_buffer_offset;//buffer
tr.data.ptr.offsets = tr.data.ptr.buffer +
ALIGN(t->buffer->data_size,
sizeof(void *));//offsets大小
if (put_user(cmd, (uint32_t __user *)ptr))//将cmd命令写回用户空间,此时是命令是BR_NOOP和BR_TRANSACTION
return -EFAULT;
ptr += sizeof(uint32_t);//跳过cmd
if (copy_to_user(ptr, &tr, sizeof(tr)))//拷贝内核数据到用户空间
return -EFAULT;
ptr += sizeof(tr);
trace_binder_transaction_received(t);
binder_stat_br(proc, thread, cmd);
list_del(&t->work.entry);
t->buffer->allow_user_free = 1;
if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) {
t->to_parent = thread->transaction_stack;
t->to_thread = thread;
thread->transaction_stack = t;//设置当前SMbinder线程的运输事务是t
}
/*else {
t->buffer->transaction = NULL;
kfree(t);
binder_stats_deleted(BINDER_STAT_TRANSACTION);
}
*/
break;
}
done:
*consumed = ptr - buffer;//消费的大小
if (proc->requested_threads + proc->ready_threads == 0 &&
proc->requested_threads_started < proc->max_threads &&
(thread->looper & (BINDER_LOOPER_STATE_REGISTERED |
BINDER_LOOPER_STATE_ENTERED)) /* the user-space code fails to */
/*spawn a new thread if we leave this out */) {
proc->requested_threads++;
binder_debug(BINDER_DEBUG_THREADS,
"binder: %d:%d BR_SPAWN_LOOPER\n",
proc->pid, thread->pid);
if (put_user(BR_SPAWN_LOOPER, (uint32_t __user *)buffer))
return -EFAULT;
binder_stat_br(proc, thread, BR_SPAWN_LOOPER);
}
return 0;
}
static int binder_has_proc_work(struct binder_proc *proc,
struct binder_thread *thread)
{
return !list_empty(&proc->todo) ||
(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN);//此时todo不为空,故返回false,故不再阻塞。
}
2.5.2 binder_ioctl
此时根据调用流程,我们再回到了binder_loop->binder_ioctl。
1.再次拷贝数据到用户空间,注意此处只是执行了拷贝命令,但没有拷贝数据,binder只有一次数据拷贝。
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret;
struct binder_proc *proc = filp->private_data;
struct binder_thread *thread;//binder线程
unsigned int size = _IOC_SIZE(cmd);
void __user *ubuf = (void __user *)arg;
trace_binder_ioctl(cmd, arg);
ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);//不休眠
if (ret)
goto err_unlocked;
binder_lock(__func__);
thread = binder_get_thread(proc);//获取binder_thread
if (thread == NULL) {
ret = -ENOMEM;
goto err;
}
switch (cmd) {
case BINDER_WRITE_READ: {
struct binder_write_read bwr;
if (size != sizeof(struct binder_write_read)) {//检查大小是否正常
ret = -EINVAL;
goto err;
}
if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {//拷贝用户空间数据到内核空间
ret = -EFAULT;
goto err;
}
/**
if (bwr.write_size > 0) {//此时为0,不执行
ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed);
trace_binder_write_done(ret);
if (ret < 0) {
bwr.read_consumed = 0;
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
goto err;
}
}
*/
if (bwr.read_size > 0) {
ret = binder_thread_read(proc, thread, (void __user *)bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK);
//此时会阻塞,等待消息的到来。
trace_binder_read_done(ret);
if (!list_empty(&proc->todo))//如果list队列不为空,则唤醒线程
wake_up_interruptible(&proc->wait);
/**
if (ret < 0) {
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
goto err;
}
*/
}
if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {//复制内核空间数据到用户空间,注意此处只是执行了拷贝命令,但没有拷贝数据,binder只有一次数据拷贝。
ret = -EFAULT;
goto err;
}
break;
}
}
ret = 0;
err:
if (thread)
thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;
binder_unlock(__func__);
wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
if (ret && ret != -ERESTARTSYS)
printk(KERN_INFO "binder: %d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret);
err_unlocked:
trace_binder_ioctl_done(ret);
return ret;
}
2.5.3 binder_loop
再次返回到此binder_loop函数中。
1.当SM拿到数据后,会调用binder_parse对数据进行解析。
//此时回到ServiceManager此函数,
void binder_loop(struct binder_state *bs, binder_handler func)
//参数分析:bs是存储了binder的三个信息。func是回调函数svcmgr_handler
{
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驱动发送命令协议BC_ENTER_LOOPER,告诉binder驱动"本线程要进入循环状态了"
binder_write(bs, readbuf, sizeof(uint32_t));//下文有展开。只写入,即BC_ENTER_LOOPER
for (;;) {//死循环,从驱动中读取消息
bwr.read_size = sizeof(readbuf);//此时是BC_ENTER_LOOPER的大小,32字节
bwr.read_consumed = 0;//
bwr.read_buffer = (uintptr_t) readbuf;//数据是BC_ENTER_LOOPER
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);//无消息时,会阻塞在此处,等待有消息,然后调用binder_parse去解析消息。
//此时readbuffer有数据了。
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);
//参数分析:
//bs结构体
//readbuf,readbuf首地址
//readbuf的消息大小
//func是回调函数svcmgr_handler
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;
}
}
}
2.5.4 binder_parse
此时数据中有两个指令。
1.BR_NOOP指令。此命令没做什么。
2.BR_TRANSACTION指令。首先会取出这个命令后面携带数据的binder_transaction_data消息,
然后调用回调函数去处理,如果是异步的,则会释放掉数据,如果是同步的,则会向驱动发送回复的消息。
第一次循环会先处理BR_NOOP指令。
//第一次循环解析数据BR_NOOP
int binder_parse(struct binder_state *bs, struct binder_io *bio,
uintptr_t ptr, size_t size, binder_handler func)
//参数分析:
//bs结构体
//bio是0
//readbuf,readbuf首地址
//readbuf的消息大小
//func是回调函数svcmgr_handler
{
int r = 1;
uintptr_t end = ptr + (uintptr_t) size;//计算数据尾地址
while (ptr < end) {//死循环取数据
uint32_t cmd = *(uint32_t *) ptr;//从buffer取出cmd,此时第一个是BR_NOOP,第二个是BR_TRANSACTION
ptr += sizeof(uint32_t);//指针位置后移
#if TRACE
fprintf(stderr,"%s:\n", cmd_name(cmd));
#endif
switch(cmd) {
case BR_NOOP:
break;
}
}
/**return r;此时并没有返回,要处理第二个数据*/
}
第二次循环会处理BR_TRANSACTION指令。
//第二次循环解析数据BR_TRANSACTION
int binder_parse(struct binder_state *bs, struct binder_io *bio,
uintptr_t ptr, size_t size, binder_handler func)
//参数分析:
//bs结构体
//bio是0
//readbuf,readbuf首地址
//readbuf的消息大小
//func是回调函数svcmgr_handler
{
int r = 1;
uintptr_t end = ptr + (uintptr_t) size;//计算数据尾地址
while (ptr < end) {//死循环取数据
uint32_t cmd = *(uint32_t *) ptr;//从buffer取出cmd,此时第二个是BR_TRANSACTION
ptr += sizeof(uint32_t);//指针位置后移
#if TRACE
fprintf(stderr,"%s:\n", cmd_name(cmd));
#endif
switch(cmd) {
case BR_TRANSACTION_SEC_CTX:
case BR_TRANSACTION: {
struct binder_transaction_data_secctx txn;
/**
if (cmd == BR_TRANSACTION_SEC_CTX) {//不执行
if ((end - ptr) < sizeof(struct binder_transaction_data_secctx)) {
ALOGE("parse: txn too small (binder_transaction_data_secctx)!\n");
return -1;
}
memcpy(&txn, (void*) ptr, sizeof(struct binder_transaction_data_secctx));
ptr += sizeof(struct binder_transaction_data_secctx);
}
*/else /* BR_TRANSACTION */ {//BR_TRANSACTION
if ((end - ptr) < sizeof(struct binder_transaction_data)) {//检查数据大小是否正确
ALOGE("parse: txn too small (binder_transaction_data)!\n");
return -1;
}
memcpy(&txn.transaction_data, (void*) ptr, sizeof(struct binder_transaction_data));//将binder_transaction_data拷贝到transaction_data中
ptr += sizeof(struct binder_transaction_data);//位置移动
txn.secctx = 0;
}
binder_dump_txn(&txn.transaction_data);
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.transaction_data);//从txn.transaction_data 解析出binder_io的信息,存入msg
res = func(bs, &txn, &msg, &reply);//调用回调函数去处理
if (txn.transaction_data.flags & TF_ONE_WAY) {//如果是TF_ONE_WAY处理,则释放txn->data的数据
binder_free_buffer(bs, txn.transaction_data.data.ptr.buffer);
} else {//如果不是TF_ONE_WAY处理,给binder驱动回复数据
binder_send_reply(bs, &reply, txn.transaction_data.data.ptr.buffer, res);//参数分析:
//bs是sm进程的信息
//reply中有一个0
//txn.transaction_data.data.ptr.buffer,发送方数据的首地址
//res=0
}
}
break;
}
}
}
return r;
}
2.5.5 bio_init
1.用于初始化空的回复消息。
void bio_init(struct binder_io *bio, void *data,
size_t maxdata, size_t maxoffs)
//参数&reply, rdata, sizeof(rdata), 4
//bio是reply
//data是rdata[256/4]
//maxdata是大小是256
//maxoffs是4
{
size_t n = maxoffs * sizeof(size_t);
if (n > maxdata) {
bio->flags = BIO_F_OVERFLOW;
bio->data_avail = 0;
bio->offs_avail = 0;
return;
}
bio->data = bio->data0 = (char *) data + n;//指向了数据的第32位
bio->offs = bio->offs0 = data;//指向了数据的首段
bio->data_avail = maxdata - n;//可用数据是256-32
bio->offs_avail = maxoffs;//偏移是4
bio->flags = 0;
}
2.5.6 bio_init_from_txn
1.用于从txn.transaction_data 解析出binder_io的信息。
void bio_init_from_txn(struct binder_io *bio, struct binder_transaction_data *txn)
{
bio->data = bio->data0 = (char *)(intptr_t)txn->data.ptr.buffer;//指向buffer数据的首地址
bio->offs = bio->offs0 = (binder_size_t *)(intptr_t)txn->data.ptr.offsets;//偏移量
bio->data_avail = txn->data_size;//可用数据为buffer数据的大小
bio->offs_avail = txn->offsets_size / sizeof(size_t);//偏移的大小
bio->flags = BIO_F_SHARED;
}
2.5.7 svcmgr_handler
此处便是处理消息的回调函数。
1.首先便是根据传入的数据,按字节取出对应的数据。
2.发现其是add服务的请求后,则取出meidaplay服务对应的string值和其mediaservice的binder的句柄值。
3.然后会将meidaservice服务的hanle和服务名称保存到svclist,完成注册。
//data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());//写入RPC头信息"android.os.IServiceManager"
//data.writeString16(name);//写入"media.player"
//data.writeStrongBinder(service);//把一个binder实体“打扁”并写入parcel, 服务的实体对象:new MediaPlayerService
//data.writeInt32(allowIsolated ? 1 : 0);//写入0
//data.writeInt32(dumpsysPriority);//写入8
int svcmgr_handler(struct binder_state *bs,
struct binder_transaction_data_secctx *txn_secctx,
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;
uint32_t dumpsys_priority;
struct binder_transaction_data *txn = &txn_secctx->transaction_data;
//ALOGI("target=%p code=%d pid=%d uid=%d\n",
// (void*) txn->target.ptr, txn->code, txn->sender_pid, txn->sender_euid);
if (txn->target.ptr != BINDER_SERVICE_MANAGER)//BINDER_SERVICE_MANAGER是0,txn->target.ptr是SM的句柄,判断目标的句柄是不是sm服务
return -1;
if (txn->code == PING_TRANSACTION)//如果code是之前的伪事务,用于确认sm是否已经注册好
return 0;
//从 msg的 binder_io.data的起始地址读取4个字节的内容,存入strict_policy,strict_policy现在不需要使用,可以直接忽略
//然后msg->data 往后偏移4个字节,即忽略了开头的strict_policy;"android.os.IServiceManager"。msg->data_avail 缓冲区的剩余可用字节数减去4个字节。
//msg->data0一直不变,指向数据缓冲区的起始地址
strict_policy = bio_get_uint32(msg);
bio_get_uint32(msg); //继续偏移4个字节,忽略了header("android.os.IServiceManager"),然后msg->data 往后偏移4个字节,即忽略了开头的strict_policy;
//msg->data_avail 缓冲区的剩余可用字节数减去4个字节。
s = bio_get_string16(msg, &len);
if (s == NULL) {
return -1;
}
if ((len != (sizeof(svcmgr_id) / 2)) ||
memcmp(svcmgr_id, s, sizeof(svcmgr_id))) {
fprintf(stderr,"invalid id %s\n", str8(s, len));
return -1;
}
/**seliux相关
if (sehandle && selinux_status_updated() > 0) {
#ifdef VENDORSERVICEMANAGER
struct selabel_handle *tmp_sehandle = selinux_android_vendor_service_context_handle();
#else
struct selabel_handle *tmp_sehandle = selinux_android_service_context_handle();
#endif
if (tmp_sehandle) {
selabel_close(sehandle);
sehandle = tmp_sehandle;
}
}*/
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 = do_find_service(s, len, txn->sender_euid, txn->sender_pid,
(const char*) txn_secctx->secctx);
if (!handle)
break;
bio_put_ref(reply, handle);
return 0;
*/
case SVC_MGR_ADD_SERVICE: //添加服务
s = bio_get_string16(msg, &len); //读取服务的string名字和长度,保存在s和len中,此时是media.player
if (s == NULL) {
return -1;
}
handle = bio_get_ref(msg);//获取mediaservice的binder的句柄
allow_isolated = bio_get_uint32(msg) ? 1 : 0;//allow_isolated是0
dumpsys_priority = bio_get_uint32(msg);//dumpsys_priority是8
//注册服务
if (do_add_service(bs, s, len, handle, txn->sender_euid, allow_isolated, dumpsys_priority,
txn->sender_pid, (const char*) txn_secctx->secctx))
//参数分析:
//bs是serviceManager的信息
//s是字符串media.player
//len是media.player的长度
//handle是mediaservice的句柄,是会每次加1,此时如果只有两个服务则,是1
//sender_euid,发送者id,即meidaservice的uid
//allow_isolated是0
//dumpsys_priority是8
//sender_pid,发送者的pid,即meidaservice的pid
//secctx安全上下文
return -1;
break;
}
bio_put_uint32(reply, 0);
return 0;
}
2.5.8 bio_get_ref
//此函数作用:
//1.返回服务对应的句柄值。此时是meidaservice的对应的句柄
uint32_t bio_get_ref(struct binder_io *bio)
{
struct flat_binder_object *obj;//binder扁平对象
obj = _bio_get_obj(bio);
if (!obj)
return 0;
if (obj->hdr.type == BINDER_TYPE_HANDLE)
return obj->handle;//返回meidaservice的对应的句柄
return 0;
}
2.5.9 do_add_service
1.查询此服务是否已经注册过,如果没有注册过,则将meidaservice服务的hanle和服务名称保存到svclist,完成注册。
2.向驱动发送消息请求为meidaservice服务的binder引用注册死亡通知。
//此函数作用:
//1.将meidaservice服务的hanle和服务名称保存到svclist,完成注册。
//2.向驱动发送消息请求为meidaservice服务的binder引用注册死亡通知
int do_add_service(struct binder_state *bs, const uint16_t *s, size_t len, uint32_t handle,
uid_t uid, int allow_isolated, uint32_t dumpsys_priority, pid_t spid, const char* sid) {
//参数分析:
//bs是serviceManager的信息
//s是字符串media.player
//len是media.player的长度
//handle是mediaservice的句柄,是会每次加1,此时如果只有两个服务则,是1
//sender_euid,发送者id,即meidaservice的uid
//allow_isolated是0
//dumpsys_priority是8
//sender_pid,发送者的pid,即meidaservice的pid
//secctx安全上下文
struct svcinfo *si;
//service的name长度不能大于127
if (!handle || (len == 0) || (len > 127))
return -1;
if (!svc_can_register(s, len, spid, sid, uid)) {//最终调用selinux_check_access() 进行selinux的权限检查,检查服务是否有进行服务注册
ALOGE("add_service('%s',%x) uid=%d - PERMISSION DENIED\n",
str8(s, len), handle, uid);
return -1;
}
si = find_svc(s, len);//查询是否包含该media.player的svcinfo
/**
if (si) {//如果已经注册过,则覆盖之前的
if (si->handle) {
ALOGE("add_service('%s',%x) uid=%d - ALREADY REGISTERED, OVERRIDE\n",
str8(s, len), handle, uid);
svcinfo_death(bs, si);//服务已注册时,释放相应的服务
}
si->handle = handle;
}
*/
else {//如果没注册过
si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));//给svcinfo分配大小,因为里面保存名字的数组长度是0,
//故需要(len + 1) * sizeof(uint16_t)分配string的长度,+1是因为字符串需要\0
if (!si) {
ALOGE("add_service('%s',%x) uid=%d - OUT OF MEMORY\n",
str8(s, len), handle, uid);
return -1;
}
si->handle = handle;//保存meidaservice的句柄
si->len = len;//名字的长度
memcpy(si->name, s, (len + 1) * sizeof(uint16_t));//拷贝名字
si->name[len] = '\0';//赋值\0
si->death.func = (void*) svcinfo_death;//binder死亡时,执行的函数
si->death.ptr = si;
si->allow_isolated = allow_isolated;//0
si->dumpsys_priority = dumpsys_priority;//8
si->next = svclist;//指向下一个服务的svcinfo,svclist保存所有已注册的服务
svclist = si;//更新下一个服务为meidaservice的svcinfo,用链表保存
}
binder_acquire(bs, handle);//以BC_ACQUIRE命令,handle为目标的信息,通过ioctl发送给binder驱动
binder_link_to_death(bs, handle, &si->death);//以BC_REQUEST_DEATH_NOTIFICATION命令的信息,
//通过ioctl发送给binder驱动,主要用于清理内存等收尾工作。BC_REQUEST_DEATH_NOTIFICATION作用是注册死亡通知。
return 0;
}
2.5.10 find_svc
1.查询svclist中是否有包含当前mediaservice的svcinfo结构体,svclist存储的是已经向Sm注册过的的服务,包含了名称和handle值。
struct svcinfo *find_svc(const uint16_t *s16, size_t len)
{
struct svcinfo *si;
for (si = svclist; si; si = si->next) {//查询svclist中是否有包含当前mediaservice的svcinfo结构体
if ((len == si->len) &&
!memcmp(s16, si->name, len * sizeof(uint16_t))) {
return si;
}
}
return NULL;
}
2.5.11 binder_acquire
1.此时是分析meidaservice服务的handle对应驱动中的binder_ref的强引用计数+1
//此时是分析meidaservice服务的handle对应驱动中的binder_ref的强引用计数+1
void binder_acquire(struct binder_state *bs, uint32_t target)
{
uint32_t cmd[2];
cmd[0] = BC_ACQUIRE;//让binder_ref的强引用计数+1
cmd[1] = target;//此时target是meidaservice服务的handle
binder_write(bs, cmd, sizeof(cmd));
}
2.5.12 binder_write
//此时是分析meidaservice服务的handle对应驱动中的binder_ref的强引用计数+1
int binder_write(struct binder_state *bs, void *data, size_t len)
//此时参数:data=cmd数组,cmd[0] = BC_ACQUIRE;cmd[1] = meidaservice服务的handle
{
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;
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);//和binder驱动通信
if (res < 0) {
fprintf(stderr,"binder_write: ioctl failed (%s)\n",
strerror(errno));
}
return res;
}
2.5.13 binder_ioctl
//此时是分析meidaservice服务的handle对应驱动中的binder_ref的强引用计数+1
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret;
struct binder_proc *proc = filp->private_data;//取出SM进程对应的porc对象
struct binder_thread *thread;//SM进程的binder线程
unsigned int size = _IOC_SIZE(cmd);
void __user *ubuf = (void __user *)arg;//__user表示用户空间的指针
trace_binder_ioctl(cmd, arg);
ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);//条件成立,立即返回,不休眠
if (ret)
goto err_unlocked;
binder_lock(__func__);
thread = binder_get_thread(proc);//获取binder_thread
if (thread == NULL) {
ret = -ENOMEM;
goto err;
}
switch (cmd) {
case BINDER_WRITE_READ: {
struct binder_write_read bwr;
if (size != sizeof(struct binder_write_read)) {
ret = -EINVAL;
goto err;
}
if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
ret = -EFAULT;
goto err;
}
binder_debug(BINDER_DEBUG_READ_WRITE,
"binder: %d:%d write %ld at %08lx, read %ld at %08lx\n",
proc->pid, thread->pid, bwr.write_size, bwr.write_buffer,
bwr.read_size, bwr.read_buffer);
if (bwr.write_size > 0) {
ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed);
trace_binder_write_done(ret);
/**
if (ret < 0) {
bwr.read_consumed = 0;
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
goto err;
}
*/
}
/**
if (bwr.read_size > 0) {
ret = binder_thread_read(proc, thread, (void __user *)bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK);
trace_binder_read_done(ret);
if (!list_empty(&proc->todo))
wake_up_interruptible(&proc->wait);
if (ret < 0) {
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
goto err;
}
}
*/
if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {//此处复制到用户空间,只是更新了一下consumed大小
ret = -EFAULT;
goto err;
}
break;
}
}
ret = 0;
err:
if (thread)
thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;
binder_unlock(__func__);
wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
if (ret && ret != -ERESTARTSYS)
printk(KERN_INFO "binder: %d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret);
err_unlocked:
trace_binder_ioctl_done(ret);
return ret;
}
2.5.14 binder_thread_write
1.此时是分析meidaservice服务的handle对应驱动中的binder_ref的强引用计数+1
//此时是分析meidaservice服务的handle对应驱动中的binder_ref的强引用计数+1
int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,
void __user *buffer, int size, signed long *consumed)
{
uint32_t cmd;
void __user *ptr = buffer + *consumed;
void __user *end = buffer + size;
while (ptr < end && thread->return_error == BR_OK) {
if (get_user(cmd, (uint32_t __user *)ptr))//取出cmd,此时是BC_ACQUIRE
return -EFAULT;
ptr += sizeof(uint32_t);
trace_binder_command(cmd);
if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.bc)) {
binder_stats.bc[_IOC_NR(cmd)]++;
proc->stats.bc[_IOC_NR(cmd)]++;
thread->stats.bc[_IOC_NR(cmd)]++;
}
switch (cmd) {
case BC_INCREFS:
case BC_ACQUIRE:
case BC_RELEASE:
case BC_DECREFS: {
uint32_t target;
struct binder_ref *ref;
const char *debug_string;
if (get_user(target, (uint32_t __user *)ptr))//取出句柄此时是meidaservice的句柄
return -EFAULT;
ptr += sizeof(uint32_t);
/**
if (target == 0 && binder_context_mgr_node &&
(cmd == BC_INCREFS || cmd == BC_ACQUIRE)) {
ref = binder_get_ref_for_node(proc,
binder_context_mgr_node);
if (ref->desc != target) {
binder_user_error("binder: %d:"
"%d tried to acquire "
"reference to desc 0, "
"got %d instead\n",
proc->pid, thread->pid,
ref->desc);
}
}
*/
else
ref = binder_get_ref(proc, target);//proc是SM进程的信息,target是meidaservice的句柄,
//在sm的进程的binder引用的红黑树中,根据句柄,找到binder_ref
if (ref == NULL) {
binder_user_error("binder: %d:%d refcou"
"nt change on invalid ref %d\n",
proc->pid, thread->pid, target);
break;
}
switch (cmd) {
case BC_INCREFS:
debug_string = "IncRefs";
binder_inc_ref(ref, 0, NULL);
break;
case BC_ACQUIRE:
debug_string = "Acquire";
binder_inc_ref(ref, 1, NULL);//binder_ref对象引用计数+1
break;
}
binder_debug(BINDER_DEBUG_USER_REFS,
"binder: %d:%d %s ref %d desc %d s %d w %d for node %d\n",
proc->pid, thread->pid, debug_string, ref->debug_id,
ref->desc, ref->strong, ref->weak, ref->node->debug_id);
break;
}
}
*consumed = ptr - buffer;
}
return 0;
}
tatic struct binder_ref *binder_get_ref(struct binder_proc *proc,
uint32_t desc)
{
struct rb_node *n = proc->refs_by_desc.rb_node;
struct binder_ref *ref;
while (n) {
ref = rb_entry(n, struct binder_ref, rb_node_desc);
if (desc < ref->desc)
n = n->rb_left;
else if (desc > ref->desc)
n = n->rb_right;
else
return ref;
}
return NULL;
}
2.5.15 binder_link_to_death
1.为meidaservice服务向驱动注册死亡通知,传入一个回调函数
//为meidaservice服务向驱动注册死亡通知,传入一个回调函数
void binder_link_to_death(struct binder_state *bs, uint32_t target, struct binder_death *death)
//参数分析:
//target是meidaservice的句柄
//death是一个结构体,保存了死亡时的回调函数地址
{
struct {
uint32_t cmd;
struct binder_handle_cookie payload;
} __attribute__((packed)) data;
data.cmd = BC_REQUEST_DEATH_NOTIFICATION;//请求注册死亡通知
data.payload.handle = target;//medaservice服务的句柄
data.payload.cookie = (uintptr_t) death;//包含死亡的回调函数
binder_write(bs, &data, sizeof(data));
}
死亡通知的回调函数如下:
1.向驱动发送释放的指令,驱动从红黑数中删除。
2.清空svclist列表中对应的handle值。
void svcinfo_death(struct binder_state *bs, void *ptr)
{
struct svcinfo *si = (struct svcinfo* ) ptr;
ALOGI("service '%s' died\n", str8(si->name, si->len));
if (si->handle) {
binder_release(bs, si->handle);
si->handle = 0;
}
}
void binder_release(struct binder_state *bs, uint32_t target)
{
uint32_t cmd[2];
cmd[0] = BC_RELEASE;
cmd[1] = target;
binder_write(bs, cmd, sizeof(cmd));
}
2.5.16 binder_write
1.此时是分析向驱动注册死亡通知
//此时是分析向驱动注册死亡通知
int binder_write(struct binder_state *bs, void *data, size_t len)
//此时参数:请查看上面data.cmd = BC_REQUEST_DEATH_NOTIFICATION;
{
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;
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);//和binder驱动通信
if (res < 0) {
fprintf(stderr,"binder_write: ioctl failed (%s)\n",
strerror(errno));
}
return res;
}
2.5.17 binder_ioctl
1.此时是分析meidaservice服务的handle对应驱动中的binder_ref的强引用计数+1
//此时是分析meidaservice服务的handle对应驱动中的binder_ref的强引用计数+1
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret;
struct binder_proc *proc = filp->private_data;//取出SM进程对应的porc对象
struct binder_thread *thread;//SM进程的binder线程
unsigned int size = _IOC_SIZE(cmd);
void __user *ubuf = (void __user *)arg;//__user表示用户空间的指针
trace_binder_ioctl(cmd, arg);
ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);//条件成立,立即返回,不休眠
if (ret)
goto err_unlocked;
binder_lock(__func__);
thread = binder_get_thread(proc);//获取binder_thread
if (thread == NULL) {
ret = -ENOMEM;
goto err;
}
switch (cmd) {
case BINDER_WRITE_READ: {
struct binder_write_read bwr;
if (size != sizeof(struct binder_write_read)) {
ret = -EINVAL;
goto err;
}
if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
ret = -EFAULT;
goto err;
}
binder_debug(BINDER_DEBUG_READ_WRITE,
"binder: %d:%d write %ld at %08lx, read %ld at %08lx\n",
proc->pid, thread->pid, bwr.write_size, bwr.write_buffer,
bwr.read_size, bwr.read_buffer);
if (bwr.write_size > 0) {
ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed);
trace_binder_write_done(ret);
/**
if (ret < 0) {
bwr.read_consumed = 0;
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
goto err;
}
*/
}
/**
if (bwr.read_size > 0) {
ret = binder_thread_read(proc, thread, (void __user *)bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK);
trace_binder_read_done(ret);
if (!list_empty(&proc->todo))
wake_up_interruptible(&proc->wait);
if (ret < 0) {
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
goto err;
}
}
*/
if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {//此处复制到用户空间,只是更新了一下consumed大小
ret = -EFAULT;
goto err;
}
break;
}
}
ret = 0;
err:
if (thread)
thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;
binder_unlock(__func__);
wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
if (ret && ret != -ERESTARTSYS)
printk(KERN_INFO "binder: %d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret);
err_unlocked:
trace_binder_ioctl_done(ret);
return ret;
}
2.5.18 binder_thread_write
1.此时分析的是注册死亡通知
int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,
void __user *buffer, int size, signed long *consumed)
//proc是SM进程的信息
//write_buffer包含的是请求注册死亡通知的信息,有回调函数等
//write_size大小
//write_consumed=0
{
uint32_t cmd;
void __user *ptr = buffer + *consumed;
void __user *end = buffer + size;
while (ptr < end && thread->return_error == BR_OK) {
if (get_user(cmd, (uint32_t __user *)ptr))//cmd是BC_REQUEST_DEATH_NOTIFICATION,代表请求注册死亡通知
return -EFAULT;
ptr += sizeof(uint32_t);
trace_binder_command(cmd);
if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.bc)) {
binder_stats.bc[_IOC_NR(cmd)]++;
proc->stats.bc[_IOC_NR(cmd)]++;
thread->stats.bc[_IOC_NR(cmd)]++;
}
switch (cmd) {
case BC_REQUEST_DEATH_NOTIFICATION:
case BC_CLEAR_DEATH_NOTIFICATION: {
uint32_t target;
void __user *cookie;
struct binder_ref *ref;
struct binder_ref_death *death;
if (get_user(target, (uint32_t __user *)ptr))//获取medaservice服务的句柄
return -EFAULT;
ptr += sizeof(uint32_t);
if (get_user(cookie, (void __user * __user *)ptr))//获取一个结构体,此结构体包含死亡的回调函数
return -EFAULT;
ptr += sizeof(void *);
ref = binder_get_ref(proc, target);//获取medaservice服务对应的binder_ref引用对象
if (ref == NULL) {
binder_user_error("binder: %d:%d %s "
"invalid ref %d\n",
proc->pid, thread->pid,
cmd == BC_REQUEST_DEATH_NOTIFICATION ?
"BC_REQUEST_DEATH_NOTIFICATION" :
"BC_CLEAR_DEATH_NOTIFICATION",
target);
break;
}
binder_debug(BINDER_DEBUG_DEATH_NOTIFICATION,
"binder: %d:%d %s %p ref %d desc %d s %d w %d for node %d\n",
proc->pid, thread->pid,
cmd == BC_REQUEST_DEATH_NOTIFICATION ?
"BC_REQUEST_DEATH_NOTIFICATION" :
"BC_CLEAR_DEATH_NOTIFICATION",
cookie, ref->debug_id, ref->desc,
ref->strong, ref->weak, ref->node->debug_id);
if (cmd == BC_REQUEST_DEATH_NOTIFICATION) {
if (ref->death) {//此binder引用的死亡通知已经注册
binder_user_error("binder: %d:%"
"d BC_REQUEST_DEATH_NOTI"
"FICATION death notific"
"ation already set\n",
proc->pid, thread->pid);
break;
}
death = kzalloc(sizeof(*death), GFP_KERNEL);//分配binder_ref_death内核空间
if (death == NULL) {
thread->return_error = BR_ERROR;
binder_debug(BINDER_DEBUG_FAILED_TRANSACTION,
"binder: %d:%d "
"BC_REQUEST_DEATH_NOTIFICATION failed\n",
proc->pid, thread->pid);
break;
}
binder_stats_created(BINDER_STAT_DEATH);
INIT_LIST_HEAD(&death->work.entry);
death->cookie = cookie;//cookie中包含死亡的回调函数
ref->death = death;//将此binder_ref_death保存到meidaservice的binder引用中
/**
if (ref->node->proc == NULL) {//如果meidaservice的proc为空,代表service组件死亡。Binder会立即发送通知给Client进程。
ref->death->work.type = BINDER_WORK_DEAD_BINDER;
if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) {
list_add_tail(&ref->death->work.entry, &thread->todo);
} else {
list_add_tail(&ref->death->work.entry, &proc->todo);
wake_up_interruptible(&proc->wait);
}
}
*/
}/**
else {
if (ref->death == NULL) {
binder_user_error("binder: %d:%"
"d BC_CLEAR_DEATH_NOTIFI"
"CATION death notificat"
"ion not active\n",
proc->pid, thread->pid);
break;
}
death = ref->death;
if (death->cookie != cookie) {
binder_user_error("binder: %d:%"
"d BC_CLEAR_DEATH_NOTIFI"
"CATION death notificat"
"ion cookie mismatch "
"%p != %p\n",
proc->pid, thread->pid,
death->cookie, cookie);
break;
}
ref->death = NULL;
if (list_empty(&death->work.entry)) {
death->work.type = BINDER_WORK_CLEAR_DEATH_NOTIFICATION;
if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) {
list_add_tail(&death->work.entry, &thread->todo);
} else {
list_add_tail(&death->work.entry, &proc->todo);
wake_up_interruptible(&proc->wait);
}
} else {
BUG_ON(death->work.type != BINDER_WORK_DEAD_BINDER);
death->work.type = BINDER_WORK_DEAD_BINDER_AND_CLEAR;
}
}
*/
} break;
}
*consumed = ptr - buffer;
}
return 0;
}
2.6 Servicemanager服务发送reply消息给meidaservice
我们先看一下目前处于的函数调用栈。
binder_parse
svcmgr_handler
bio_put_uint32
binder_send_reply
svcmgr_handler->bio_put_uint32
2.6.1 bio_put_uint32
1.然后sm会向驱动sm写入reply回复消息,然后唤醒并发送给meidaplay服务。
//此时分析的是sm向驱动写入reply回复消息
void bio_put_uint32(struct binder_io *bio, uint32_t n)
//参数是reply
//n是0
{
uint32_t *ptr = bio_alloc(bio, sizeof(n));
if (ptr)
*ptr = n;//reply赋值为0,代表是sm服务的回复。
}
2.6.2 bio_alloc
//此时分析的是sm向驱动写入reply回复消息
static void *bio_alloc(struct binder_io *bio, size_t size)
{
size = (size + 3) & (~3);//是4
if (size > bio->data_avail) {
bio->flags |= BIO_F_OVERFLOW;
return NULL;
} else {
void *ptr = bio->data;//指向reply的第32位字节
bio->data += size;//size是4,往后移动四个字节,即第36位字节
bio->data_avail -= size;// //256-8-4
return ptr;
}
}
2.6.3 binder_send_reply
1.此时servicemanager会向驱动写入reply回复消息。
//此时分析的是sm向驱动写入reply回复消息
void binder_send_reply(struct binder_state *bs,
struct binder_io *reply,
binder_uintptr_t buffer_to_free,
int status)
//bs是sm进程的信息
//reply的消息中有一个数据0,代表SM服务
//txn.transaction_data.data.ptr.buffer,发送方数据的首地址
//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;//请求释放来自发送方的buffer数据
data.buffer = buffer_to_free;//指向要释放的buffer的首地址
data.cmd_reply = BC_REPLY;//设置回复
data.txn.target.ptr = 0;
data.txn.cookie = 0;
data.txn.code = 0;
/**
if (status) {
data.txn.flags = TF_STATUS_CODE;
data.txn.data_size = sizeof(int);
data.txn.offsets_size = 0;
data.txn.data.ptr.buffer = (uintptr_t)&status;
data.txn.data.ptr.offsets = 0;
}
*/
else {
data.txn.flags = 0;
data.txn.data_size = reply->data - reply->data0;//reply->data指向的是第36位,reply->data0指向的是第32位,故大小是4字节,也就是int 0的大小
data.txn.offsets_size = ((char*) reply->offs) - ((char*) reply->offs0);//是0,
data.txn.data.ptr.buffer = (uintptr_t)reply->data0;//buffer的数据首地址指向了第32位
data.txn.data.ptr.offsets = (uintptr_t)reply->offs0;//数据第0位
}
binder_write(bs, &data, sizeof(data));
}
2.6.4 binder_write
此时分析的是sm向驱动写入reply回复消息
1.写入BC_FREE_BUFFER;请求释放来自发送方的buffer数据。
int binder_write(struct binder_state *bs, void *data, size_t len)
//此时参数:请查看上面
//bs是sm的信息
//data数值如下
//len是data的大小
//data.cmd_free = BC_FREE_BUFFER;//请求释放来自发送方的buffer数据
//data.buffer = buffer_to_free;//指向要释放的发送方buffer的首地址
//data.cmd_reply = BC_REPLY;//设置回复
//data.txn.target.ptr = 0;
//data.txn.cookie = 0;
//data.txn.code = 0;
//data.txn.flags = 0;
//data.txn.data_size = reply->data - reply->data0;//reply->data指向的是第36位,reply->data0指向的是第32位,故大小是4字节,也就是int 0的大小
//data.txn.offsets_size = ((char*) reply->offs) - ((char*) reply->offs0);//是0,
//data.txn.data.ptr.buffer = (uintptr_t)reply->data0;//buffer的数据首地址指向了第32位,这里面存储了一个0
//data.txn.data.ptr.offsets = (uintptr_t)reply->offs0;//数据第0位
{
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;
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);//和binder驱动通信
if (res < 0) {
fprintf(stderr,"binder_write: ioctl failed (%s)\n",
strerror(errno));
}
return res;
}
2.6.5 binder_ioctl
//此时分析的是sm向驱动写入reply回复消息
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret;
struct binder_proc *proc = filp->private_data;//取出SM进程对应的porc对象
struct binder_thread *thread;//SM进程的binder线程
unsigned int size = _IOC_SIZE(cmd);
void __user *ubuf = (void __user *)arg;//__user表示用户空间的指针
trace_binder_ioctl(cmd, arg);
ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);//条件成立,立即返回,不休眠
if (ret)
goto err_unlocked;
binder_lock(__func__);
thread = binder_get_thread(proc);//获取binder_thread
if (thread == NULL) {
ret = -ENOMEM;
goto err;
}
switch (cmd) {
case BINDER_WRITE_READ: {
struct binder_write_read bwr;
if (size != sizeof(struct binder_write_read)) {
ret = -EINVAL;
goto err;
}
if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
ret = -EFAULT;
goto err;
}
if (bwr.write_size > 0) {
ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed);
trace_binder_write_done(ret);
if (ret < 0) {
bwr.read_consumed = 0;
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
goto err;
}
}
if (bwr.read_size > 0) {
ret = binder_thread_read(proc, thread, (void __user *)bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK);
trace_binder_read_done(ret);
if (!list_empty(&proc->todo))
wake_up_interruptible(&proc->wait);
if (ret < 0) {
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
goto err;
}
}
binder_debug(BINDER_DEBUG_READ_WRITE,
"binder: %d:%d wrote %ld of %ld, read return %ld of %ld\n",
proc->pid, thread->pid, bwr.write_consumed, bwr.write_size,
bwr.read_consumed, bwr.read_size);
if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
ret = -EFAULT;
goto err;
}
break;
}
}
ret = 0;
err:
if (thread)
thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;
binder_unlock(__func__);
wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
if (ret && ret != -ERESTARTSYS)
printk(KERN_INFO "binder: %d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret);
err_unlocked:
trace_binder_ioctl_done(ret);
return ret;
}
2.6.6 binder_thread_write
此时分析的是sm向驱动写入reply回复消息
1.此时第一次while循环取出第一个命令BC_FREE_BUFFER,用于释放释放meidaservice发送给sm服务的add消息的buffer
2.此时第二次while循环取出第二个命令BC_REPLY,用于回复消息给meidaservice
第一次循环:
//此时第一次while循环取出第一个命令BC_FREE_BUFFER,用于释放释放meidaservice发送给sm服务的add消息的buffer
int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,
void __user *buffer, int size, signed long *consumed)
//此时参数:请查看上面
//bs是sm的信息
//data数值如下
//len是data的大小
//data.cmd_free = BC_FREE_BUFFER;//请求释放来自发送方的buffer数据
//data.buffer = buffer_to_free;//指向要释放的发送方buffer的首地址
//data.cmd_reply = BC_REPLY;//设置回复
//data.txn.target.ptr = 0;
//data.txn.cookie = 0;
//data.txn.code = 0;
//data.txn.flags = 0;
//data.txn.data_size = reply->data - reply->data0;//reply->data指向的是第36位,reply->data0指向的是第32位,故大小是4字节,也就是int 0的大小
//data.txn.offsets_size = ((char*) reply->offs) - ((char*) reply->offs0);//是0,
//data.txn.data.ptr.buffer = (uintptr_t)reply->data0;//buffer的数据首地址指向了第32位,这里面存储了一个0
//data.txn.data.ptr.offsets = (uintptr_t)reply->offs0;//数据第0位
{
uint32_t cmd;
void __user *ptr = buffer + *consumed;
void __user *end = buffer + size;
while (ptr < end && thread->return_error == BR_OK) {//死循环读取数据,取出第一个命令
if (get_user(cmd, (uint32_t __user *)ptr))//此时cmd是BC_FREE_BUFFER,请求释放发送方的缓冲buffer区
return -EFAULT;
ptr += sizeof(uint32_t);//指针后移
trace_binder_command(cmd);
if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.bc)) {
binder_stats.bc[_IOC_NR(cmd)]++;
proc->stats.bc[_IOC_NR(cmd)]++;
thread->stats.bc[_IOC_NR(cmd)]++;
}
switch (cmd) {
case BC_FREE_BUFFER: {//请求释放meidaservice发送给sm服务的add消息的buffer
void __user *data_ptr;
struct binder_buffer *buffer;
if (get_user(data_ptr, (void * __user *)ptr))//获取要释放的buffer地址
return -EFAULT;
ptr += sizeof(void *);
buffer = binder_buffer_lookup(proc, data_ptr);//查询此数据的buffer是否存在
if (buffer == NULL) {
binder_user_error("binder: %d:%d "
"BC_FREE_BUFFER u%p no match\n",
proc->pid, thread->pid, data_ptr);
break;
}
if (!buffer->allow_user_free) {//表示允许用户释放
binder_user_error("binder: %d:%d "
"BC_FREE_BUFFER u%p matched "
"unreturned buffer\n",
proc->pid, thread->pid, data_ptr);
break;
}
binder_debug(BINDER_DEBUG_FREE_BUFFER,
"binder: %d:%d BC_FREE_BUFFER u%p found buffer %d for %s transaction\n",
proc->pid, thread->pid, data_ptr, buffer->debug_id,
buffer->transaction ? "active" : "finished");
if (buffer->transaction) {//清空该缓冲区的事务
buffer->transaction->buffer = NULL;
buffer->transaction = NULL;
}
/**
if (buffer->async_transaction && buffer->target_node) {//如果是异步的
BUG_ON(!buffer->target_node->has_async_transaction);
if (list_empty(&buffer->target_node->async_todo))
buffer->target_node->has_async_transaction = 0;
else
list_move_tail(buffer->target_node->async_todo.next, &thread->todo);
}
*/
trace_binder_transaction_buffer_release(buffer);
binder_transaction_buffer_release(proc, buffer, NULL);//释放buffer空间
binder_free_buf(proc, buffer);//释放buffer空间
break;
}
}
*consumed = ptr - buffer;
}
return 0;
}
第二次循环第二个命令BC_REPLY,用于回复消息给meidaservice:
//此时第二次while循环取出第二个命令BC_REPLY,用于回复消息给客户端
int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,
void __user *buffer, int size, signed long *consumed)
//此时参数:请查看上面
//bs是sm的信息
//data数值如下
//len是data的大小
//data.cmd_free = BC_FREE_BUFFER;//请求释放来自发送方的buffer数据
//data.buffer = buffer_to_free;//指向要释放的发送方buffer的首地址
//data.cmd_reply = BC_REPLY;//设置回复
//data.txn.target.ptr = 0;
//data.txn.cookie = 0;
//data.txn.code = 0;
//data.txn.flags = 0;
//data.txn.data_size = reply->data - reply->data0;//reply->data指向的是第36位,reply->data0指向的是第32位,故大小是4字节,也就是int 0的大小
//data.txn.offsets_size = ((char*) reply->offs) - ((char*) reply->offs0);//是0,
//data.txn.data.ptr.buffer = (uintptr_t)reply->data0;//buffer的数据首地址指向了第32位,这里面存储了一个0
//data.txn.data.ptr.offsets = (uintptr_t)reply->offs0;//数据第0位
{
uint32_t cmd;
void __user *ptr = buffer + *consumed;
void __user *end = buffer + size;
while (ptr < end && thread->return_error == BR_OK) {
if (get_user(cmd, (uint32_t __user *)ptr))//取出命令BC_REPLY
return -EFAULT;
ptr += sizeof(uint32_t);
trace_binder_command(cmd);
if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.bc)) {
binder_stats.bc[_IOC_NR(cmd)]++;
proc->stats.bc[_IOC_NR(cmd)]++;
thread->stats.bc[_IOC_NR(cmd)]++;
}
switch (cmd) {
case BC_TRANSACTION:
case BC_REPLY: {
struct binder_transaction_data tr;
if (copy_from_user(&tr, ptr, sizeof(tr)))//拷贝的数据
return -EFAULT;
ptr += sizeof(tr);
binder_transaction(proc, thread, &tr, cmd == BC_REPLY);//此时参数为
//proc是SM进程的proc
//thread是sm进程的binder线程
//tr是binder_transaction_data对象
//cmd是1
break;
}
}
*consumed = ptr - buffer;
}
return 0;
}
2.6.7 binder_transaction
1.首先会找到目标的进程(meidaplaysercice)的proc对象和目标进程的线程。
2.从目标进程(meidaplayservice服务)target_proc中分配一块内核buffer空间,此buffer是映射了的地址空间。
3.拷贝回复消息到此内核空间,即此时就到了meidaplayservice的用户空间了。
然后就分两个流程:
第一个流程是由于往SM的todo队列中插入了未完成事务。故sm服务端要处理此事务。
第一个流程是唤醒meidaservice服务,meidiaservice服务处理reply消息
//此时分析的是sm向驱动写入reply回复消息
static void binder_transaction(struct binder_proc *proc,
struct binder_thread *thread,
struct binder_transaction_data *tr, int reply)
//proc是SM进程的proc
//thread是sm进程的binder线程
//tr是binder_transaction_data对象,数据内容如下:
//data.txn.target.ptr = 0;
//data.txn.cookie = 0;
//data.txn.code = 0;
//data.txn.flags = 0;
//data.txn.data_size = reply->data - reply->data0;//reply->data指向的是第36位,reply->data0指向的是第32位,故大小是4字节,也就是int 0的大小
//data.txn.offsets_size = ((char*) reply->offs) - ((char*) reply->offs0);//是0,
//data.txn.data.ptr.buffer = (uintptr_t)reply->data0;//buffer的数据首地址指向了第32位,这里面存储了一个0
//data.txn.data.ptr.offsets = (uintptr_t)reply->offs0;//数据第0位
//reply是1
{
struct binder_transaction *t;
struct binder_work *tcomplete;
size_t *offp, *off_end;
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;
struct binder_transaction *in_reply_to = NULL;
struct binder_transaction_log_entry *e;
uint32_t return_error;
/**log事务
e = binder_transaction_log_add(&binder_transaction_log);
e->call_type = reply ? 2 : !!(tr->flags & TF_ONE_WAY);
e->from_proc = proc->pid;
e->from_thread = thread->pid;
e->target_handle = tr->target.handle;
e->data_size = tr->data_size;
e->offsets_size = tr->offsets_size;
*/
if (reply) {//代表是BC_REPLY消息回复
in_reply_to = thread->transaction_stack;//此事务是meidaservice发送请求sm的add服务的事务。
//描述Binder进程中通信过程,这个过程称为一个transaction(事务),
//用以中转请求和返回结果
binder_set_nice(in_reply_to->saved_priority);//是8
if (in_reply_to->to_thread != thread) {//此事务是meidaservice发送请求sm的add服务的事务。故此事务发送时的目标线程就是SM的线程
binder_user_error("binder: %d:%d got reply transaction "
"with bad transaction stack,"
" transaction %d has target %d:%d\n",
proc->pid, thread->pid, in_reply_to->debug_id,
in_reply_to->to_proc ?
in_reply_to->to_proc->pid : 0,
in_reply_to->to_thread ?
in_reply_to->to_thread->pid : 0);
return_error = BR_FAILED_REPLY;
in_reply_to = NULL;
goto err_bad_call_stack;
}
thread->transaction_stack = in_reply_to->to_parent;//当前SM的binder线程的事务就是此事务。
target_thread = in_reply_to->from;//即当前reply的目标线程,就是请求方当时消息的源线程,即meidaservice服务的binder线程。
if (target_thread->transaction_stack != in_reply_to) {//检查是否是同一个事务
binder_user_error("binder: %d:%d got reply transaction "
"with bad target transaction stack %d, "
"expected %d\n",
proc->pid, thread->pid,
target_thread->transaction_stack ?
target_thread->transaction_stack->debug_id : 0,
in_reply_to->debug_id);
return_error = BR_FAILED_REPLY;
in_reply_to = NULL;
target_thread = NULL;
goto err_dead_binder;
}
target_proc = target_thread->proc;//reply的目标进程是目标线程的proc,即mediaservice服务的proc对象
}
if (target_thread) {//如果目标线程不为空,此时是不为空的
/**e->to_thread = target_thread->pid;*/ //log事务
target_list = &target_thread->todo;//目标list是meidaservice服务的线程的todo队列
target_wait = &target_thread->wait;//目标是meidaservice服务的线程的wait队列
}/**
else {
target_list = &target_proc->todo;
target_wait = &target_proc->wait;
}*/
e->to_proc = target_proc->pid;//log
/* TODO: reuse incoming transaction for reply */
t = kzalloc(sizeof(*t), GFP_KERNEL);//分配一个新的事务binder_transaction
if (t == NULL) {
return_error = BR_FAILED_REPLY;
goto err_alloc_t_failed;
}
binder_stats_created(BINDER_STAT_TRANSACTION);
tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL);//分配创建binder_work,用来描述处理的工作事项
if (tcomplete == NULL) {
return_error = BR_FAILED_REPLY;
goto err_alloc_tcomplete_failed;
}
binder_stats_created(BINDER_STAT_TRANSACTION_COMPLETE);
t->debug_id = ++binder_last_id;
e->debug_id = t->debug_id;
if (reply)
binder_debug(BINDER_DEBUG_TRANSACTION,
"binder: %d:%d BC_REPLY %d -> %d:%d, "
"data %p-%p size %zd-%zd\n",
proc->pid, thread->pid, t->debug_id,
target_proc->pid, target_thread->pid,
tr->data.ptr.buffer, tr->data.ptr.offsets,
tr->data_size, tr->offsets_size);
else
binder_debug(BINDER_DEBUG_TRANSACTION,
"binder: %d:%d BC_TRANSACTION %d -> "
"%d - node %d, data %p-%p size %zd-%zd\n",
proc->pid, thread->pid, t->debug_id,
target_proc->pid, target_node->debug_id,
tr->data.ptr.buffer, tr->data.ptr.offsets,
tr->data_size, tr->offsets_size);
if (!reply && !(tr->flags & TF_ONE_WAY))//此时reply是1不执行
t->from = thread;
else
t->from = NULL;//设置from线程为null
t->sender_euid = proc->tsk->cred->euid;//发送方uid,此时是sm的uid
t->to_proc = target_proc;//目标的proc是mediaservice服务的proc对象
t->to_thread = target_thread;//目标线程是mediaservice服务的线程
t->code = tr->code;//code值是0
t->flags = tr->flags;//flag是0
t->priority = task_nice(current);//线程优先级是8
trace_binder_transaction(reply, t, target_node);
t->buffer = binder_alloc_buf(target_proc, tr->data_size,
tr->offsets_size, !reply && (t->flags & TF_ONE_WAY));//从目标进程(meidaservice服务)target_proc中分配一块内核buffer空间,此buffer是映射了的地址空间。
if (t->buffer == NULL) {
return_error = BR_FAILED_REPLY;
goto err_binder_alloc_buf_failed;
}
t->buffer->allow_user_free = 0;//不允许用户释放
t->buffer->debug_id = t->debug_id;
t->buffer->transaction = t;//buffer的运输事务为当前事务
t->buffer->target_node = target_node;//此时是null
trace_binder_transaction_alloc_buf(t->buffer);
if (target_node)
binder_inc_node(target_node, 1, 0, NULL);
offp = (size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *)));
if (copy_from_user(t->buffer->data, tr->data.ptr.buffer, tr->data_size)) {//将buffer拷贝到内核空间,里面的数据只有一个0
binder_user_error("binder: %d:%d got transaction with invalid "
"data ptr\n", proc->pid, thread->pid);
return_error = BR_FAILED_REPLY;
goto err_copy_data_failed;
}
if (copy_from_user(offp, tr->data.ptr.offsets, tr->offsets_size)) {//拷贝偏移量的起始地址
binder_user_error("binder: %d:%d got transaction with invalid "
"offsets ptr\n", proc->pid, thread->pid);
return_error = BR_FAILED_REPLY;
goto err_copy_data_failed;
}
if (!IS_ALIGNED(tr->offsets_size, sizeof(size_t))) {//检查偏移大小是否合法
binder_user_error("binder: %d:%d got transaction with "
"invalid offsets size, %zd\n",
proc->pid, thread->pid, tr->offsets_size);
return_error = BR_FAILED_REPLY;
goto err_bad_offset;
}
off_end = (void *)offp + tr->offsets_size;//计算偏移的尾端,其实还是首地址,因为回复消息中没有flat_binder_object对象,所以offsets_size是0
if (reply) {//reply是1
BUG_ON(t->buffer->async_transaction != 0);
binder_pop_transaction(target_thread, in_reply_to);//将meidaservice服务的发送的add服务的事务从meidaservice线程中删除。
binder_pop_transaction(target_thread, in_reply_to);
}
/**
else if (!(t->flags & TF_ONE_WAY)) {
BUG_ON(t->buffer->async_transaction != 0);
t->need_reply = 1;
t->from_parent = thread->transaction_stack;
thread->transaction_stack = t;
} else {
BUG_ON(target_node == NULL);
BUG_ON(t->buffer->async_transaction != 1);
if (target_node->has_async_transaction) {
target_list = &target_node->async_todo;
target_wait = NULL;
} else
target_node->has_async_transaction = 1;
}*/
t->work.type = BINDER_WORK_TRANSACTION;//业务类型
list_add_tail(&t->work.entry, target_list);//添加到目标进程(meidaservice服务)的todo队列中
tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;//
list_add_tail(&tcomplete->entry, &thread->todo);//添加一个未完成业务,到sm进程的todo列表中
if (target_wait)
wake_up_interruptible(target_wait);//唤醒meidaservice服务的线程
return;
}
2.7 servicemanager处理未完成事务,并再次陷休眠
2.7.1 binder_loop
我们先看看之前的调用栈
binder_loop
binder_parse
binder_send_reply
binder_write
binder_ioctl
binder_thread_write
binder_transaction
故当binder_transaction发送完回复消息后,我们会返回到binder_loop函数的binder_parse一行。
//此时回到ServiceManager此函数,
void binder_loop(struct binder_state *bs, binder_handler func)
//参数分析:bs是存储了binder的三个信息。func是回调函数svcmgr_handler
{
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驱动发送命令协议BC_ENTER_LOOPER,告诉binder驱动"本线程要进入循环状态了"
binder_write(bs, readbuf, sizeof(uint32_t));//下文有展开。只写入,即BC_ENTER_LOOPER
for (;;) {//死循环,从驱动中读取消息
bwr.read_size = sizeof(readbuf);//此时是32字节
bwr.read_consumed = 0;//
bwr.read_buffer = (uintptr_t) readbuf;//数据是空
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);//无消息时,会阻塞在此处,等待有消息,然后调用binder_parse去解析消息。
//此时readbuffer有数据了。
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);//这里
//参数分析:
//bs结构体
//readbuf,readbuf首地址
//readbuf的消息大小
//func是回调函数svcmgr_handler
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;
}
}
}
然后开启下一次循环。由于其todo队列中存在todo队列有一条未完成事务。故此次循环会先处理此未完成的事务。
2.7.2 binder_ioctl
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret;
struct binder_proc *proc = filp->private_data;//取出sm服务进程对应的porc对象
struct binder_thread *thread;//sm服务进程的binder线程
unsigned int size = _IOC_SIZE(cmd);
void __user *ubuf = (void __user *)arg;//__user表示用户空间的指针
trace_binder_ioctl(cmd, arg);
ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);//条件成立,立即返回0,不休眠
if (ret)
goto err_unlocked;
binder_lock(__func__);
thread = binder_get_thread(proc);//获取binder_thread
if (thread == NULL) {
ret = -ENOMEM;
goto err;
}
switch (cmd) {
case BINDER_WRITE_READ: {//如果命令是BINDER_WRITE_READ
struct binder_write_read bwr;
if (size != sizeof(struct binder_write_read)) {//判断大小
ret = -EINVAL;
goto err;
}
if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {//从用户空间拷贝数据到内核空间
ret = -EFAULT;
goto err;
}
if (bwr.write_size > 0) {//此时写大于0
ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed);
trace_binder_write_done(ret);
if (ret < 0) {
bwr.read_consumed = 0;
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
goto err;
}
}
if (bwr.read_size > 0) {//此时读的大小大于0,代表我们需要从驱动中读取消息
ret = binder_thread_read(proc, thread, (void __user *)bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK);
//此函数下面会有大量展开参数分析:
//proc,meidaservice服务的proc
//bwr.read_buffer,read_buffer的地址
//read_size>0
//read_consumed,代表已消费的字节数0
//最后一个参数是0
trace_binder_read_done(ret);
/**if (!list_empty(&proc->todo))
wake_up_interruptible(&proc->wait);
if (ret < 0) {
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
goto err;
}*/
}
binder_debug(BINDER_DEBUG_READ_WRITE,
"binder: %d:%d wrote %ld of %ld, read return %ld of %ld\n",
proc->pid, thread->pid, bwr.write_consumed, bwr.write_size,
bwr.read_consumed, bwr.read_size);
if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
ret = -EFAULT;
goto err;
}
break;
}
}
ret = 0;
err:
if (thread)
thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;
binder_unlock(__func__);
wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
if (ret && ret != -ERESTARTSYS)
printk(KERN_INFO "binder: %d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret);
err_unlocked:
trace_binder_ioctl_done(ret);
return ret;
}
2.7.3 binder_thread_read
1.第一次循环,首先会往read_buffer中塞入BR_NOOP,然后从todo队列中取出BINDER_WORK_TRANSACTION_COMPLETE事务,转化为BR_TRANSACTION_COMPLETE,并放入read_buffer中。
2.第二次循环,检查todo队列中是否还存在事务。此时不存在,则返回read_buffer,返回
binder_ioctl函数,此函数会拷贝数据到用户空间。
第一次循环:
static int binder_thread_read(struct binder_proc *proc,
struct binder_thread *thread,
void __user *buffer, int size,
signed long *consumed, int non_block)
//参数分析:
//proc,sm服务的proc
//buffer=bwr.read_buffer,read_buffer的地址
//size=read_size>0
//read_consumed,代表已消费的字节数0
//non_block是0,代表阻塞
{
void __user *ptr = buffer + *consumed;//指向首地址
void __user *end = buffer + size;//指向尾端地址
int ret = 0;
int wait_for_proc_work;
if (*consumed == 0) {
if (put_user(BR_NOOP, (uint32_t __user *)ptr))//往用户指向的空间里面放一个BR_NOOP
return -EFAULT;
ptr += sizeof(uint32_t);
}
retry:
wait_for_proc_work = thread->transaction_stack == NULL &&
list_empty(&thread->todo);//此时sm线程的todo队列中有一个未完成的事务
/**
if (thread->return_error != BR_OK && ptr < end) {
if (thread->return_error2 != BR_OK) {
if (put_user(thread->return_error2, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
binder_stat_br(proc, thread, thread->return_error2);
if (ptr == end)
goto done;
thread->return_error2 = BR_OK;
}
if (put_user(thread->return_error, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
binder_stat_br(proc, thread, thread->return_error);
thread->return_error = BR_OK;
goto done;
}
*/
thread->looper |= BINDER_LOOPER_STATE_WAITING;
/**
if (wait_for_proc_work)//此时不为真,因为队列中有数据
proc->ready_threads++;
binder_unlock(__func__);
trace_binder_wait_for_work(wait_for_proc_work,
!!thread->transaction_stack,
!list_empty(&thread->todo));
if (wait_for_proc_work) {
if (!(thread->looper & (BINDER_LOOPER_STATE_REGISTERED |
BINDER_LOOPER_STATE_ENTERED))) {
binder_user_error("binder: %d:%d ERROR: Thread waiting "
"for process work before calling BC_REGISTER_"
"LOOPER or BC_ENTER_LOOPER (state %x)\n",
proc->pid, thread->pid, thread->looper);
wait_event_interruptible(binder_user_error_wait,
binder_stop_on_user_error < 2);
}
binder_set_nice(proc->default_priority);
if (non_block) {
if (!binder_has_proc_work(proc, thread))
ret = -EAGAIN;
} else
ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread));
}*/
else {
if (non_block) {//如果非阻塞
if (!binder_has_thread_work(thread))
ret = -EAGAIN;
} else
ret = wait_event_freezable(thread->wait, binder_has_thread_work(thread));//此时thread中有消息是不会阻塞的
}
binder_lock(__func__);
/**
if (wait_for_proc_work)
proc->ready_threads--;
*/
thread->looper &= ~BINDER_LOOPER_STATE_WAITING;//取消当前线程正在等待的标志
/**if (ret)
return ret;*/
while (1) {
uint32_t cmd;
struct binder_transaction_data tr;
struct binder_work *w;
struct binder_transaction *t = NULL;
if (!list_empty(&thread->todo))
w = list_first_entry(&thread->todo, struct binder_work, entry);//取出BINDER_WORK_TRANSACTION_COMPLETE事务
/**
else if (!list_empty(&proc->todo) && wait_for_proc_work)
w = list_first_entry(&proc->todo, struct binder_work, entry);
else {
if (ptr - buffer == 4 && !(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN)) /* no data added
goto retry;
break;
}*/
/**
if (end - ptr < sizeof(tr) + 4)
break;
*/
switch (w->type) {
/**
case BINDER_WORK_TRANSACTION: {
t = container_of(w, struct binder_transaction, work);
} break;
*/
case BINDER_WORK_TRANSACTION_COMPLETE: {//此时走这里。
cmd = BR_TRANSACTION_COMPLETE;//生成BR_TRANSACTION_COMPLETE
if (put_user(cmd, (uint32_t __user *)ptr))//将此命令放入用户空间中,此时有两个命令BR_TRANSACTION_COMPLETE和BR_NOOP
return -EFAULT;
ptr += sizeof(uint32_t);
binder_stat_br(proc, thread, cmd);
binder_debug(BINDER_DEBUG_TRANSACTION_COMPLETE,
"binder: %d:%d BR_TRANSACTION_COMPLETE\n",
proc->pid, thread->pid);
list_del(&w->entry);//删除w代表的BINDER_WORK_TRANSACTION_COMPLETE事务,因为此时已经用完了
kfree(w);//释放w的空间
binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE);
} break;
}
if (!t)
continue;//开启下一次循环
.....
}
第二次循环:
static int binder_thread_read(struct binder_proc *proc,
struct binder_thread *thread,
void __user *buffer, int size,
signed long *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))
w = list_first_entry(&thread->todo, struct binder_work, entry);
else if (!list_empty(&proc->todo) && wait_for_proc_work)
w = list_first_entry(&proc->todo, struct binder_work, entry);
*/
else {//此时走这里
/**不执行
if (ptr - buffer == 4 && !(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN)) /* no data added
goto retry;
break;
*/
}
if (end - ptr < sizeof(tr) + 4)//根据书上的流程,此时应该走这里,退出循环,因为此时end是readbuffer的尾地址
//而ptr是第8个字节的位置,里面有两个命令分别是BR_TRANSACTION_COMPLETE和BR_NOOP
break;
}
done:
*consumed = ptr - buffer;//值是8,里面是两个命令BR_NOOP和BR_TRANSACTION_COMPLETE和
return 0;
}
2.7.4 binder_parse
1.第一次循环解析数据BR_NOOP
2.第二次循环解析数据BR_TRANSACTION_COMPLETE
第一次循环:
//第一次循环解析数据BR_NOOP
int binder_parse(struct binder_state *bs, struct binder_io *bio,
uintptr_t ptr, size_t size, binder_handler func)
//参数分析:
//bs结构体
//bio是0
//readbuf,readbuf首地址
//readbuf的消息大小
//func是回调函数svcmgr_handler
{
int r = 1;
uintptr_t end = ptr + (uintptr_t) size;//计算数据尾地址
while (ptr < end) {//死循环取数据
uint32_t cmd = *(uint32_t *) ptr;//从buffer取出cmd,此时第一个是BR_NOOP,第二个是BR_TRANSACTION
ptr += sizeof(uint32_t);//指针位置后移
#if TRACE
fprintf(stderr,"%s:\n", cmd_name(cmd));
#endif
switch(cmd) {
case BR_NOOP:
break;
}
}
/**return r;此时并没有返回,要处理第二个数据*/
}
第二次循环解析数据BR_TRANSACTION_COMPLETE
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) {//第二次死循环取数据BR_TRANSACTION_COMPLETE
uint32_t cmd = *(uint32_t *) ptr;
ptr += sizeof(uint32_t);
#if TRACE
fprintf(stderr,"%s:\n", cmd_name(cmd));
#endif
switch(cmd) {
case BR_TRANSACTION_COMPLETE:
break;
}
}
return r;
}
然后返回到 binder_loop函数,此时无消息,servicemanager便会继续阻塞休眠,等待来自驱动的消息。
2.7.5 sm主线程再次休眠,等待来自驱动的消息
//此时回到ServiceManager此函数,
void binder_loop(struct binder_state *bs, binder_handler func)
//参数分析:bs是存储了binder的三个信息。func是回调函数svcmgr_handler
{
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驱动发送命令协议BC_ENTER_LOOPER,告诉binder驱动"本线程要进入循环状态了"
binder_write(bs, readbuf, sizeof(uint32_t));//下文有展开。只写入,即BC_ENTER_LOOPER
for (;;) {//第三次死循环,从驱动中读取消息
bwr.read_size = sizeof(readbuf);//此时是32字节
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;
}
}
*/
}
2.8 唤醒meidaservice服务,meida服务处理reply消息
在2.6.7 binder_transaction的最后,我们知道servicemanager服务往mediaplayservice服务的todo队列中,插入了回复消息,并且唤醒了mediaplayservice服务。此时我们需要回到meidaservice阻塞的地方2.4.7 binder_thread_read。
我们先回顾一下阻塞前的调用栈
MediaPlayerService::instantiate
IServiceManager::addService
BpBinder::transact
IPCThreadState::transact
waitForResponse
talkWithDriver
binder_ioctl
binder_thread_read
2.8.1 binder_thread_read
主要作用为:
1.当mediaplayservice被唤醒后,则会从tod队列中取出获取binder_transaction_data消息。并写入
BR_REPLY。
2.将binder_transaction_data数据拷贝到用户空间。注意此处只是执行了拷贝命令,但没有拷贝数据,binder只有一次数据拷贝。
3.删除发送给sm进程的add服务的事务,避免内存泄露。
//mediaservice处理回复消息
static int binder_thread_read(struct binder_proc *proc,
struct binder_thread *thread,
void __user *buffer, int size,
signed long *consumed, int non_block)
//参数分析:
//proc是media是mediaservice服务的proc
//thread是meidaservice服务的线程
//buffer指向read_buffer,读的首地址
//read_size>0
//read_consumed是0
//non_block是0,表示是阻塞的
{
void __user *ptr = buffer + *consumed;//指向buffer首地址
void __user *end = buffer + size;//指向尾地址
int ret = 0;
int wait_for_proc_work;
if (*consumed == 0) {
if (put_user(BR_NOOP, (uint32_t __user *)ptr))//向里面放一个BR_NOOP命令
return -EFAULT;
ptr += sizeof(uint32_t);
}
retry:
wait_for_proc_work = thread->transaction_stack == NULL &&
list_empty(&thread->todo);//此时当前线程的运输事务不空,即transaction_stack不为空
/*
if (thread->return_error != BR_OK && ptr < end) {
if (thread->return_error2 != BR_OK) {
if (put_user(thread->return_error2, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
binder_stat_br(proc, thread, thread->return_error2);
if (ptr == end)
goto done;
thread->return_error2 = BR_OK;
}
if (put_user(thread->return_error, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
binder_stat_br(proc, thread, thread->return_error);
thread->return_error = BR_OK;
goto done;
}
*/
thread->looper |= BINDER_LOOPER_STATE_WAITING;//设置等待的flag
/*if (wait_for_proc_work)//不执行
proc->ready_threads++;*/
binder_unlock(__func__);
/*if (wait_for_proc_work) {//wait_for_proc_work是false,不执行
if (!(thread->looper & (BINDER_LOOPER_STATE_REGISTERED |
BINDER_LOOPER_STATE_ENTERED))) {
wait_event_interruptible(binder_user_error_wait,
binder_stop_on_user_error < 2);
}
binder_set_nice(proc->default_priority);
if (non_block) {
if (!binder_has_proc_work(proc, thread))
ret = -EAGAIN;
} else
ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread));
} */
else {//走这里
/*if (non_block) {不执行
if (!binder_has_thread_work(thread))
ret = -EAGAIN;
} */
else
ret = wait_event_freezable(thread->wait, binder_has_thread_work(thread));//此时不再阻塞
}
binder_lock(__func__);
/*if (wait_for_proc_work)
proc->ready_threads--;*/
thread->looper &= ~BINDER_LOOPER_STATE_WAITING;
/*if (ret)
return ret;*/
while (1) {
uint32_t cmd;
struct binder_transaction_data tr;
struct binder_work *w;
struct binder_transaction *t = NULL;
if (!list_empty(&thread->todo))
w = list_first_entry(&thread->todo, struct binder_work, entry);//从队列中取出回复的消息事务
/*
else if (!list_empty(&proc->todo) && wait_for_proc_work)
w = list_first_entry(&proc->todo, struct binder_work, entry);
else {
if (ptr - buffer == 4 && !(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN))
goto retry;
break;
}*/
/*if (end - ptr < sizeof(tr) + 4)
break;*/
switch (w->type) {
case BINDER_WORK_TRANSACTION: {
t = container_of(w, struct binder_transaction, work);
} break;
}
/*if (!t)
continue;*/
BUG_ON(t->buffer == NULL);
/*
if (t->buffer->target_node) {
struct binder_node *target_node = t->buffer->target_node;//此时target_node是null
tr.target.ptr = target_node->ptr;//为空
tr.cookie = target_node->cookie;//为空
t->saved_priority = task_nice(current);//8
if (t->priority < target_node->min_priority &&
!(t->flags & TF_ONE_WAY))
binder_set_nice(t->priority);
else if (!(t->flags & TF_ONE_WAY) ||
t->saved_priority > target_node->min_priority)
binder_set_nice(target_node->min_priority);
cmd = BR_TRANSACTION;
}*/
else {
tr.target.ptr = NULL;
tr.cookie = NULL;
cmd = BR_REPLY;//设置cmd是BR_REPLY
}
tr.code = t->code;//code值是0
tr.flags = t->flags;//flag值也是0
tr.sender_euid = t->sender_euid;//是sm的uid
if (t->from) {//是sm
struct task_struct *sender = t->from->proc->tsk;//sm服务的pid
tr.sender_pid = task_tgid_nr_ns(sender,
current->nsproxy->pid_ns);
} else {
tr.sender_pid = 0;
}
tr.data_size = t->buffer->data_size;//buffer数据区大小
tr.offsets_size = t->buffer->offsets_size;//offset数据区大小
tr.data.ptr.buffer = (void *)t->buffer->data +
proc->user_buffer_offset;//内核空间+用户空间偏移量就是用户空间buffer地址
tr.data.ptr.offsets = tr.data.ptr.buffer +
ALIGN(t->buffer->data_size,
sizeof(void *));
if (put_user(cmd, (uint32_t __user *)ptr))//放入cmd是BR_REPLY
return -EFAULT;
ptr += sizeof(uint32_t);
if (copy_to_user(ptr, &tr, sizeof(tr)))//拷贝数据到用户空间
return -EFAULT;
ptr += sizeof(tr);
trace_binder_transaction_received(t);
binder_stat_br(proc, thread, cmd);
list_del(&t->work.entry);//删除事务
t->buffer->allow_user_free = 1;
/*
if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) {
t->to_parent = thread->transaction_stack;
t->to_thread = thread;
thread->transaction_stack = t;
} */
else {
t->buffer->transaction = NULL;//运输事务变成空
kfree(t);//释放事务
binder_stats_deleted(BINDER_STAT_TRANSACTION);
}
break;
}
done:
*consumed = ptr - buffer;//reply的大小
/*
if (proc->requested_threads + proc->ready_threads == 0 &&
proc->requested_threads_started < proc->max_threads &&
(thread->looper & (BINDER_LOOPER_STATE_REGISTERED |
BINDER_LOOPER_STATE_ENTERED))) {
proc->requested_threads++;
binder_debug(BINDER_DEBUG_THREADS,
"binder: %d:%d BR_SPAWN_LOOPER\n",
proc->pid, thread->pid);
if (put_user(BR_SPAWN_LOOPER, (uint32_t __user *)buffer))
return -EFAULT;
binder_stat_br(proc, thread, BR_SPAWN_LOOPER);
}
*/
return 0;
}
2.8.2 binder_ioctl
根据调用栈,我们返回binder_ioctl。
1.再次拷贝数据到用户空间,注意此处只是执行了拷贝命令,但没有拷贝数据,binder只有一次数据拷贝。
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret;
struct binder_proc *proc = filp->private_data;//取出meidaservice进程对应的porc对象
struct binder_thread *thread;//meidaservice进程的binder线程
unsigned int size = _IOC_SIZE(cmd);
void __user *ubuf = (void __user *)arg;//__user表示用户空间的指针
trace_binder_ioctl(cmd, arg);
ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);//条件成立,立即返回,不休眠
if (ret)
goto err_unlocked;
binder_lock(__func__);
thread = binder_get_thread(proc);//获取binder_thread
if (thread == NULL) {
ret = -ENOMEM;
goto err;
}
switch (cmd) {
case BINDER_WRITE_READ: {
struct binder_write_read bwr;
if (size != sizeof(struct binder_write_read)) {//计算数据是否和规范
ret = -EINVAL;
goto err;
}
if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {//拷贝数据到内核空间
ret = -EFAULT;
goto err;
}
/*if (bwr.write_size > 0) {//此时write_siz=0,不执行
ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed);
trace_binder_write_done(ret);
if (ret < 0) {
bwr.read_consumed = 0;
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
goto err;
}
}
*/
if (bwr.read_size > 0) {//此时read_size>0
ret = binder_thread_read(proc, thread, (void __user *)bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK);
//此时meidaservice的binder线程收到reply后,继续执行
/*
if (!list_empty(&proc->todo))
wake_up_interruptible(&proc->wait);
if (ret < 0) {
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
goto err;
}
*/
}
if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {//拷贝reply消息到用户空间
ret = -EFAULT;
goto err;
}
break;
}
}
ret = 0;
err:
if (thread)
thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;
binder_unlock(__func__);
wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
if (ret && ret != -ERESTARTSYS)
printk(KERN_INFO "binder: %d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret);
err_unlocked:
trace_binder_ioctl_done(ret);
return ret;
}
2.8.3 talkWithDriver
然后我们需要再次返回talkWithDriver。
1.从驱动中读取到消息后,设置read的位置。
status_t IPCThreadState::talkWithDriver(bool doReceive)//默认doReceive是true
{
if (mProcess->mDriverFD <= 0) {
return -EBADF;
}
binder_write_read bwr;
// Is the read buffer empty?
const bool needRead = mIn.dataPosition() >= mIn.dataSize();//needRead是true
// We don't want to write anything if we are still reading
// from data left in the input buffer and the caller
// has requested to read the next data.
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
bwr.write_size = outAvail;//write_size是0
bwr.write_buffer = (uintptr_t)mOut.data();
// This is what we'll read.
if (doReceive && needRead) {//需要读取数据
bwr.read_size = mIn.dataCapacity();//设置需要读取的大小。
bwr.read_buffer = (uintptr_t)mIn.data();
}
/*else {//不执行
bwr.read_size = 0;
bwr.read_buffer = 0;
}*/
// 不会执行
//if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
bwr.write_consumed = 0;
bwr.read_consumed = 0;
status_t err;
do {
#if defined(__ANDROID__)
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)//从驱动中读取消息,在这里面
//收到reply消息
err = NO_ERROR;
else
err = -errno;
#else
err = INVALID_OPERATION;
#endif
if (mProcess->mDriverFD <= 0) {
err = -EBADF;
}
} while (err == -EINTR);
if (err >= NO_ERROR) {
/* if (bwr.write_consumed > 0) {
if (bwr.write_consumed < mOut.dataSize())
mOut.remove(0, bwr.write_consumed);
else {
mOut.setDataSize(0);
processPostWriteDerefs();
}
}*/
if (bwr.read_consumed > 0) {//此时read区中有数据
mIn.setDataSize(bwr.read_consumed);
mIn.setDataPosition(0);//设置起始位置
}
return NO_ERROR;
}
return err;
}
2.8.4 waitForResponse
此时我们再次返回waitForResponse函数。
此时有两个命令,分别是BR_NOOP命令和BR_REPLY
1.第一次循环取出BR_NOOP命令,啥也没干,就不在叙述。
2.第二次循环取出BR_REPLY命令
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
uint32_t cmd;
int32_t err;
while (1) {
if ((err=talkWithDriver()) < NO_ERROR) break;
err = mIn.errorCheck();
if (err < NO_ERROR) break;
if (mIn.dataAvail() == 0) continue;//有数据不执行
cmd = (uint32_t)mIn.readInt32();//取出BR_REPLY
switch (cmd) {
case BR_REPLY:
{
binder_transaction_data tr;
err = mIn.read(&tr, sizeof(tr));
ALOG_ASSERT(err == NO_ERROR, "Not enough command data for brREPLY");
if (err != NO_ERROR) goto finish;
if (reply) {//走这里
if ((tr.flags & TF_STATUS_CODE) == 0) {//flags是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);
freeBuffer(nullptr,
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(binder_size_t), this);
}*/
}
/*else {
freeBuffer(nullptr,
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(binder_size_t), this);
continue;
}*/
}
goto finish;
}
}
finish:
if (err != NO_ERROR) {
if (acquireResult) *acquireResult = err;
if (reply) reply->setError(err);
mLastError = err;
}
return err;
}
2.8.5 Parcel::ipcSetDataReference
1.此时接收的是reply(0),主要作用是将数据填充到reply中。
然后此函数返回到IPCThreadState::transact ,再返回到BpBinder::transact ,再返回到SM的注册服务IServiceManager::addService,再返回到MediaPlayerService::instantiate()。都没有对此reply做任何处理。原因是因为meidaservice服务端不需要此来自sm注册服务的reply,一般reply是meida的客户端请求meidaservice服务端,需要接收一个handle,所以才需要处理。
void Parcel::ipcSetDataReference(const uint8_t* data, size_t dataSize,
const binder_size_t* objects, size_t objectsCount, release_func relFunc, void* relCookie)
//参数分析
//data指向的buffer就只有一个数据0
//dataSize四字节
//objects为空
//objectsCount为0
//relFunc是freeBuffer函数
//this
{
binder_size_t minOffset = 0;
freeDataNoInit();
mError = NO_ERROR;
mData = const_cast<uint8_t*>(data);//存储的是0
mDataSize = mDataCapacity = dataSize;
//ALOGI("setDataReference Setting data size of %p to %lu (pid=%d)", this, mDataSize, getpid());
mDataPos = 0;
ALOGV("setDataReference Setting data pos of %p to %zu", this, mDataPos);
mObjects = const_cast<binder_size_t*>(objects);//为空
mObjectsSize = mObjectsCapacity = objectsCount;//0
mNextObjectHint = 0;
mObjectsSorted = false;
mOwner = relFunc;
mOwnerCookie = relCookie;
/*
for (size_t i = 0; i < mObjectsSize; i++) {
binder_size_t offset = mObjects[i];
if (offset < minOffset) {
ALOGE("%s: bad object offset %" PRIu64 " < %" PRIu64 "\n",
__func__, (uint64_t)offset, (uint64_t)minOffset);
mObjectsSize = 0;
break;
}
*/
minOffset = offset + sizeof(flat_binder_object);//0
}
scanForFds();
}
2.9 ProcessState::startThreadPool
主要作用为:
1.创建一个新的线程,然后向驱动消息此线程进入循环。同时此线程死循环的去接受来自驱动的消息。
void ProcessState::startThreadPool()
{
AutoMutex _l(mLock);
if (!mThreadPoolStarted) {//默认是false
mThreadPoolStarted = true;//设置true,表示线程池已经启动了,不要再重复启动
spawnPooledThread(true);//开启线程池
}
2.9.1 ProcessState::spawnPooledThread
1.创建了一个PoolThread对象,本质上创建了一个新的线程,线程调用run方法后,会调用threadLoop方法,当其返回true并且没有调用requsetexit函数时,会一直循环的调用threadLoop函数
此处涉及线程机制篇,本人会另写一篇。
void ProcessState::spawnPooledThread(bool isMain)
//isMain是true
{
if (mThreadPoolStarted) {
String8 name = makeBinderThreadName();//根据pid获取binder线程池的名字
ALOGV("Spawning new pooled thread, name=%s\n", name.string());
sp<Thread> t = new PoolThread(isMain);//main传入的是true
t->run(name.string());
}
}
String8 ProcessState::makeBinderThreadName() {
int32_t s = android_atomic_add(1, &mThreadPoolSeq);//原子操作+1,此时mThreadPoolSeq=2,返回s=1
pid_t pid = getpid();//获取进程pid
String8 name;
name.appendFormat("Binder:%d_%X", pid, s);//根据pid获取名称
return name;
}
class PoolThread : public Thread//继承自Thread类,此类请查看本人另外分析的线程篇
{
public:
explicit PoolThread(bool isMain)
: mIsMain(isMain)
{
}
protected:
virtual bool threadLoop()
{
IPCThreadState::self()->joinThreadPool(mIsMain);
return false;
}
const bool mIsMain;
};
2.9.2 threadLoop
//此处请查看本人写的安卓Thread篇。需要知道的是会执行threadLoop函数。
//线程调用run方法后,会调用threadLoop方法,当其返回true并且没有调用requsetexit函数时,会一直循环的调用threadLoop函数
virtual bool threadLoop()
{
IPCThreadState::self()->joinThreadPool(mIsMain);
return false;
}
2.9.3 IPCThreadState::joinThreadPool
1.向驱动发送BC_ENTER_LOOPER指令。
2.死循环中,不断的接受来自其他客户端对meidaservice服务的请求。
void IPCThreadState::joinThreadPool(bool isMain)//isMain是true
{
mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);//向mOut中写入BC_ENTER_LOOPER指令
//对于isMain=true的情况下, command为BC_ENTER_LOOPER,代表的是Binder主线程,不会退出的线程;
//对于isMain=false的情况下,command为BC_REGISTER_LOOPER,表示是由binder驱动创建的线程。
status_t result;
do {
processPendingDerefs();//处理一些引用计数
result = getAndExecuteCommand();//等待来自其他客户端对meidaservice服务的请求。
if (result < NO_ERROR && result != TIMED_OUT && result != -ECONNREFUSED && result != -EBADF) {
ALOGE("getAndExecuteCommand(fd=%d) returned unexpected error %d, aborting",
mProcess->mDriverFD, result);
abort();
}
if(result == TIMED_OUT && !isMain) {//如果超时并且不是主线程,则退出循环
break;
}
} while (result != -ECONNREFUSED && result != -EBADF);//死循环一直等待获取消息
LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%d\n",
(void*)pthread_self(), getpid(), result);
mOut.writeInt32(BC_EXIT_LOOPER);//如果退出了循环,则告诉驱动要退出循环。
talkWithDriver(false);
}
void IPCThreadState::processPendingDerefs()
{
if (mIn.dataPosition() >= mIn.dataSize()) {//如果min中无数据
while (mPendingWeakDerefs.size() > 0 || mPendingStrongDerefs.size() > 0) {//mPendingWeakDerefs
//存储的是要销毁的弱引用,所以必须保证min中无数据,才能销毁。
//mPendingStrongDerefs存储的是BBbinder实体
while (mPendingWeakDerefs.size() > 0) {
RefBase::weakref_type* refs = mPendingWeakDerefs[0];
mPendingWeakDerefs.removeAt(0);
refs->decWeak(mProcess.get());//handle弱引用减1
}
if (mPendingStrongDerefs.size() > 0) {
BBinder* obj = mPendingStrongDerefs[0];//BBbinder实体引用减少1,一般是同进程才会有实体的存储。
mPendingStrongDerefs.removeAt(0);
obj->decStrong(mProcess.get());
}
}
}
}
2.9.4 IPCThreadState::getAndExecuteCommand
1.此时作用为,用于向驱动发送BC_ENTER_LOOPER消息
status_t IPCThreadState::getAndExecuteCommand()
{
status_t result;
int32_t cmd;
result = talkWithDriver();//先将驱动发送BC_ENTER_LOOPER,将自己注册到Binder线程池中
//然后会阻塞在read中,等待消息的读取
if (result >= NO_ERROR) {
size_t IN = mIn.dataAvail();//如果有消息
if (IN < sizeof(int32_t)) return result;
cmd = mIn.readInt32();//读取cmd
pthread_mutex_lock(&mProcess->mThreadCountLock);
mProcess->mExecutingThreadsCount++;//正在执行的线程数+1
if (mProcess->mExecutingThreadsCount >= mProcess->mMaxThreads &&
mProcess->mStarvationStartTimeMs == 0) {//不能超出线程池上限
mProcess->mStarvationStartTimeMs = uptimeMillis();
}
pthread_mutex_unlock(&mProcess->mThreadCountLock);
result = executeCommand(cmd);//执行获取来的命令
pthread_mutex_lock(&mProcess->mThreadCountLock);
mProcess->mExecutingThreadsCount--;//正在执行的线程数-1
if (mProcess->mExecutingThreadsCount < mProcess->mMaxThreads &&
mProcess->mStarvationStartTimeMs != 0) {
int64_t starvationTimeMs = uptimeMillis() - mProcess->mStarvationStartTimeMs;
if (starvationTimeMs > 100) {
ALOGE("binder thread pool (%zu threads) starved for %" PRId64 " ms",
mProcess->mMaxThreads, starvationTimeMs);
}
mProcess->mStarvationStartTimeMs = 0;
}
pthread_cond_broadcast(&mProcess->mThreadCountDecrement);
pthread_mutex_unlock(&mProcess->mThreadCountLock);
}
return result;
}
2.9.5 IPCThreadState::talkWithDriver
status_t IPCThreadState::talkWithDriver(bool doReceive)//doReceive默认是true
{
/**
if (mProcess->mDriverFD < 0) {
return -EBADF;
}
*/
binder_write_read bwr;
//struct binder_write_read {
//binder_size_t write_size;//要写入的字节数,write_buffer的总字节数
//binder_size_t write_consumed;//驱动程序占用的字节数,write_buffer已消费的字节数
//binder_uintptr_t write_buffer;//写缓冲数据的指针
//binder_size_t read_size;//要读的字节数,read_buffer的总字节数
//binder_size_t read_consumed;//驱动程序占用的字节数,read_buffer已消费的字节数
//binder_uintptr_t read_buffer;//读缓存数据的指针
//};
// Is the read buffer empty?
const bool needRead = mIn.dataPosition() >= mIn.dataSize();//此时needRead是ture
//因为mIn.dataPosition返回值和mIn.dataSize相等
//当我们正在从min中读取数据,或者调用方打算读取下一条数据(doReceive为true时),我们不会写入任何内容。
//此时outAvail值等于mOut.dataSize()
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
bwr.write_size = outAvail;//write_size是mOut.dataSize()
bwr.write_buffer = (uintptr_t)mOut.data();
if (doReceive && needRead) {//当我们需要从驱动中读的时候。
bwr.read_size = mIn.dataCapacity();//设置大小为256字节
bwr.read_buffer = (uintptr_t)mIn.data();
}
/*
else {//当不读的时候,设置读的大小和buffer为0
bwr.read_size = 0;
bwr.read_buffer = 0;
}*/
// 如果读缓冲区和写缓冲区都为0,代表无事可做,立即返回,此时write_size中有数据。
/**
if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
*/
bwr.write_consumed = 0;
bwr.read_consumed = 0;
status_t err;
do {
#if defined(__ANDROID__)
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)//向binder驱动区写,因为此时是注册当前线程成为binder主looper线程,所以mout有数据
err = NO_ERROR;
else
err = -errno;
#else
err = INVALID_OPERATION;
#endif
/**
if (mProcess->mDriverFD < 0) {
err = -EBADF;
}
*/
} while (err == -EINTR);
if (err >= NO_ERROR) {//代表驱动收到了消息
if (bwr.write_consumed > 0) {
if (bwr.write_consumed < mOut.dataSize())//如果驱动消费的数据大小小于mout的大小,则说明驱动没有消费mout数据
LOG_ALWAYS_FATAL("Driver did not consume write buffer. "
"err: %s consumed: %zu of %zu",
statusToString(err).c_str(),
(size_t)bwr.write_consumed,
mOut.dataSize());
else {//代表mout被正确消费
mOut.setDataSize(0);//重置数据大小为0
processPostWriteDerefs();//主要是将写的引用计数减少1,释放
}
}
/**
if (bwr.read_consumed > 0) {//如果驱动读的数据大小大于0
mIn.setDataSize(bwr.read_consumed);//设置mIn的大小
mIn.setDataPosition(0);//设置min数据起始位置
}
*/
return NO_ERROR;
}
///return err;
}
2.9.6 binder_ioctl
//此时数据是BC_ENTER_LOOPER,cmd是BINDER_WRITE_READ
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret;
struct binder_proc *proc = filp->private_data;//取出此fd的proc对象
struct binder_thread *thread;//此sm进程对应的binder线程
unsigned int size = _IOC_SIZE(cmd);
void __user *ubuf = (void __user *)arg;//是bwr
trace_binder_ioctl(cmd, arg);
ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);//不休眠
if (ret)
goto err_unlocked;
binder_lock(__func__);
thread = binder_get_thread(proc);//获取此proc的binder_thread
if (thread == NULL) {
ret = -ENOMEM;
goto err;
}
switch (cmd) {
case BINDER_WRITE_READ: {
struct binder_write_read bwr;
if (size != sizeof(struct binder_write_read)) {//查看大小是否正确
ret = -EINVAL;
goto err;
}
if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {//从用户空间复制数据到内核空间
//第一个参数to是内核空间的数据目标地址指针,
//第二个参数from是用户空间的数据源地址指针,
//第三个参数n是数据的长度。
ret = -EFAULT;
goto err;
}
if (bwr.write_size > 0) {//当写缓存有数据的时候,执行写操作
ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed);
//参数分析:
//proc代表sm对象的proc
//thread为此sm进程的binder线程
//bwr.write_buffer,内核数据的起始地址
//write_size,数据大小
//write_consumed,驱动程序已消费的数据大小
trace_binder_write_done(ret);
/**
if (ret < 0) {//如果写失败,再将bwr的值写回给ubuf
bwr.read_consumed = 0;
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
//第一个参数是用户空间的指针,
//第二个参数是内核空间指针,
//n表示从内核空间向用户空间拷贝数据的字节数
ret = -EFAULT;
goto err;
}
*/
}
/**
if (bwr.read_size > 0) {//当读缓存有数据的时候,执行读操作,此时读缓存无数据
ret = binder_thread_read(proc, thread, (void __user *)bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK);
trace_binder_read_done(ret);
if (!list_empty(&proc->todo))
wake_up_interruptible(&proc->wait);
if (ret < 0) {
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
goto err;
}
}
*/
if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {//将此内核空间数据,拷贝到ubuf中,此时是写的消费的大小write_consumed从变成了4字节。
ret = -EFAULT;
goto err;
}
break;
}
ret = 0;
err:
if (thread)
thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;
binder_unlock(__func__);
wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);//不休眠
if (ret && ret != -ERESTARTSYS)
printk(KERN_INFO "binder: %d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret);
err_unlocked:
trace_binder_ioctl_done(ret);
return ret;
}
2.9.7 binder_thread_write
1.驱动侧为当前线程设置已经looper,表示已经准备好循环接受驱动消息。
int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,
void __user *buffer, int size, signed long *consumed)
//参数分析:
//proc代表sm对象的proc
//thread为此sm进程的binder线程
//bwr.write_buffer,内核数据的起始地址,数据是BC_ENTER_LOOPER
//write_size,4字节,数据大小
//consumed=0,驱动程序已消费的数据大小
{
uint32_t cmd;
void __user *ptr = buffer + *consumed;//首地址+0,还是写buffer首地址。
void __user *end = buffer + size;//buffer的尾地址。
while (ptr < end && thread->return_error == BR_OK) {
if (get_user(cmd, (uint32_t __user *)ptr))//从写buffer中获取命令给cmd,即此时是BC_ENTER_LOOPER
return -EFAULT;
ptr += sizeof(uint32_t);//让buffer的地址跳过BC_ENTER_LOOPER,因为buffer中可能还有其他数据。此时是没数据了
trace_binder_command(cmd);
if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.bc)) {//记录信息
binder_stats.bc[_IOC_NR(cmd)]++;
proc->stats.bc[_IOC_NR(cmd)]++;
thread->stats.bc[_IOC_NR(cmd)]++;
}
switch (cmd) {
case BC_ENTER_LOOPER:
/**
if (thread->looper & BINDER_LOOPER_STATE_REGISTERED) {//如果此looper已经注册过,则错误
thread->looper |= BINDER_LOOPER_STATE_INVALID;
binder_user_error("binder: %d:%d ERROR:"
" BC_ENTER_LOOPER called after "
"BC_REGISTER_LOOPER\n",
proc->pid, thread->pid);
}
*/
thread->looper |= BINDER_LOOPER_STATE_ENTERED;//设置为此binder线程已经注册过了。
break;
}
*consumed = ptr - buffer;//已消费的字节大小,此时为4字节
}
return 0;
}
2.9.8 死循环用于获取来自驱动的消息
1.当向驱动发送完BC_ENTER_LOOPER的消息后,会再走到IPCThreadState::joinThreadPool函数的死循环处。
2.getAndExecuteCommand会执行talkWithDriver函数,此函数上文已多次出现,然后会阻塞,等待消息的来临
void IPCThreadState::joinThreadPool(bool isMain)//isMain是true
{
do {
processPendingDerefs();//处理一些引用计数
result = getAndExecuteCommand();//等待来自其他客户端对meidaservice服务的请求。
if (result < NO_ERROR && result != TIMED_OUT && result != -ECONNREFUSED && result != -EBADF) {
ALOGE("getAndExecuteCommand(fd=%d) returned unexpected error %d, aborting",
mProcess->mDriverFD, result);
abort();
}
if(result == TIMED_OUT && !isMain) {//如果超时并且不是主线程,则退出循环
break;
}
} while (result != -ECONNREFUSED && result != -EBADF);//死循环一直等待获取消息
}
2.9.9 getAndExecuteCommand
status_t IPCThreadState::getAndExecuteCommand()
{
status_t result;
int32_t cmd;
result = talkWithDriver();//此时会阻塞在read中,等待消息的读取
if (result >= NO_ERROR) {
size_t IN = mIn.dataAvail();//如果有消息
if (IN < sizeof(int32_t)) return result;
cmd = mIn.readInt32();//读取cmd
pthread_mutex_lock(&mProcess->mThreadCountLock);
mProcess->mExecutingThreadsCount++;//正在执行的线程数+1
if (mProcess->mExecutingThreadsCount >= mProcess->mMaxThreads &&
mProcess->mStarvationStartTimeMs == 0) {//不能超出线程池上限
mProcess->mStarvationStartTimeMs = uptimeMillis();
}
pthread_mutex_unlock(&mProcess->mThreadCountLock);
result = executeCommand(cmd);//执行获取来的命令
pthread_mutex_lock(&mProcess->mThreadCountLock);
mProcess->mExecutingThreadsCount--;//正在执行的线程数-1
if (mProcess->mExecutingThreadsCount < mProcess->mMaxThreads &&
mProcess->mStarvationStartTimeMs != 0) {
int64_t starvationTimeMs = uptimeMillis() - mProcess->mStarvationStartTimeMs;
if (starvationTimeMs > 100) {
ALOGE("binder thread pool (%zu threads) starved for %" PRId64 " ms",
mProcess->mMaxThreads, starvationTimeMs);
}
mProcess->mStarvationStartTimeMs = 0;
}
pthread_cond_broadcast(&mProcess->mThreadCountDecrement);
pthread_mutex_unlock(&mProcess->mThreadCountLock);
}
return result;
}
2.9.10 talkWithDriver
1.此时当前专门用于ipc通信的线程会阻塞,等待来自驱动的消息。
status_t IPCThreadState::talkWithDriver(bool doReceive)//默认doReceive是true
{
if (mProcess->mDriverFD <= 0) {
return -EBADF;
}
binder_write_read bwr;
const bool needRead = mIn.dataPosition() >= mIn.dataSize();//此时needRead是true
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;//此时outAvail是0
bwr.write_size = outAvail;//write_size是0
bwr.write_buffer = (uintptr_t)mOut.data();
// This is what we'll read.
if (doReceive && needRead) {//需要读取数据
bwr.read_size = mIn.dataCapacity();//设置需要读取的大小。
bwr.read_buffer = (uintptr_t)mIn.data();
}
/*else {//不执行
bwr.read_size = 0;
bwr.read_buffer = 0;
}*/
// 不会执行
//if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
bwr.write_consumed = 0;
bwr.read_consumed = 0;
status_t err;
do {
#if defined(__ANDROID__)
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)//从驱动中读取消息,在这里面
//会线程休眠
err = NO_ERROR;
else
err = -errno;
/*
#else
err = INVALID_OPERATION;
#endif
if (mProcess->mDriverFD <= 0) {
err = -EBADF;
}
IF_LOG_COMMANDS() {
alog << "Finished read/write, write size = " << mOut.dataSize() << endl;
}
} while (err == -EINTR);
IF_LOG_COMMANDS() {
alog << "Our err: " << (void*)(intptr_t)err << ", write consumed: "
<< bwr.write_consumed << " (of " << mOut.dataSize()
<< "), read consumed: " << bwr.read_consumed << endl;
}
if (err >= NO_ERROR) {
if (bwr.write_consumed > 0) {
if (bwr.write_consumed < mOut.dataSize())
mOut.remove(0, bwr.write_consumed);
else {
mOut.setDataSize(0);
processPostWriteDerefs();
}
}
if (bwr.read_consumed > 0) {
mIn.setDataSize(bwr.read_consumed);
mIn.setDataPosition(0);
}
IF_LOG_COMMANDS() {
TextOutput::Bundle _b(alog);
alog << "Remaining data size: " << mOut.dataSize() << endl;
alog << "Received commands from driver: " << indent;
const void* cmds = mIn.data();
const void* end = mIn.data() + mIn.dataSize();
alog << HexDump(cmds, mIn.dataSize()) << endl;
while (cmds < end) cmds = printReturnCommand(alog, cmds);
alog << dedent;
}
return NO_ERROR;
}
return err;
*/
}
2.9.11 binder_ioctl
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret;
struct binder_proc *proc = filp->private_data;//取出meidaservice进程对应的porc对象
struct binder_thread *thread;//meidaservice进进程的binder线程
unsigned int size = _IOC_SIZE(cmd);
void __user *ubuf = (void __user *)arg;//__user表示用户空间的指针
trace_binder_ioctl(cmd, arg);
ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);//条件成立,立即返回,不休眠
if (ret)
goto err_unlocked;
binder_lock(__func__);
thread = binder_get_thread(proc);//获取binder_thread
if (thread == NULL) {
ret = -ENOMEM;
goto err;
}
switch (cmd) {
case BINDER_WRITE_READ: {
struct binder_write_read bwr;
if (size != sizeof(struct binder_write_read)) {//计算数据是否和规范
ret = -EINVAL;
goto err;
}
if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {//拷贝数据到内核空间
ret = -EFAULT;
goto err;
}
/*if (bwr.write_size > 0) {//此时write_siz=0,不执行
ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed);
trace_binder_write_done(ret);
if (ret < 0) {
bwr.read_consumed = 0;
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
goto err;
}
}
*/
if (bwr.read_size > 0) {//此时read_size>0
ret = binder_thread_read(proc, thread, (void __user *)bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK);
//此时meidaservice的binder线程会阻塞在这里。后面暂不执行,等待唤醒时,才会执行
/*
if (!list_empty(&proc->todo))
wake_up_interruptible(&proc->wait);
if (ret < 0) {
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
goto err;
}
}
binder_debug(BINDER_DEBUG_READ_WRITE,
"binder: %d:%d wrote %ld of %ld, read return %ld of %ld\n",
proc->pid, thread->pid, bwr.write_consumed, bwr.write_size,
bwr.read_consumed, bwr.read_size);
if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
ret = -EFAULT;
goto err;
}
break;
}
}
ret = 0;
err:
if (thread)
thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;
binder_unlock(__func__);
wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
if (ret && ret != -ERESTARTSYS)
printk(KERN_INFO "binder: %d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret);
err_unlocked:
trace_binder_ioctl_done(ret);
return ret;
*/
}
2.9.12 binder_thread_read
static int binder_thread_read(struct binder_proc *proc,
struct binder_thread *thread,
void __user *buffer, int size,
signed long *consumed, int non_block)
//参数分析:
//proc是media是mediaservice服务的proc
//thread是meidaservice服务的线程
//buffer指向read_buffer,读的首地址
//read_size>0
//read_consumed是0
//non_block是0,表示是阻塞的
{
void __user *ptr = buffer + *consumed;//指向buffer首地址
void __user *end = buffer + size;//指向尾地址
int ret = 0;
int wait_for_proc_work;
if (*consumed == 0) {
if (put_user(BR_NOOP, (uint32_t __user *)ptr))//向里面放一个BR_NOOP命令
return -EFAULT;
ptr += sizeof(uint32_t);
}
retry:
wait_for_proc_work = thread->transaction_stack == NULL &&
list_empty(&thread->todo);//此时当前线程的运输事务不空,即transaction_stack不为空
thread->looper |= BINDER_LOOPER_STATE_WAITING;//设置等待的flag
/*if (wait_for_proc_work)//不执行
proc->ready_threads++;*/
binder_unlock(__func__);
/*if (wait_for_proc_work) {//wait_for_proc_work是false,不执行
if (!(thread->looper & (BINDER_LOOPER_STATE_REGISTERED |
BINDER_LOOPER_STATE_ENTERED))) {
wait_event_interruptible(binder_user_error_wait,
binder_stop_on_user_error < 2);
}
binder_set_nice(proc->default_priority);
if (non_block) {
if (!binder_has_proc_work(proc, thread))
ret = -EAGAIN;
} else
ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread));
} */
else {//走这里
/*if (non_block) {不执行
if (!binder_has_thread_work(thread))
ret = -EAGAIN;
} */
else
ret = wait_event_freezable(thread->wait, binder_has_thread_work(thread));//meidaservice线程陷入休眠
}
//后面都不执行,故省略.....
}
2.10 joinThreadPool
此处全流程和2.9.3到2.9.12是一模一样的。
那么为什么执行此步呢?
答:因为开启线程池startThreadPool函数是创建了另一个线程,是异步的,而当前的meidaplayservice是主线程,1如果main函数所在的主线程会退出,而导致所有的子线程退出。
所以meidaplayservice主线程不能推出,需要将主线程也阻塞,加入到binder线程池中,因此此处便存在两个binder线程,都用于处于来自驱动的消息。提高binder的效率。main也不会结束。
2.10.1 IPCThreadState::joinThreadPool
1.向驱动发送BC_ENTER_LOOPER指令。
2.死循环中,不断的接受来自其他客户端对meidaservice服务的请求。
void IPCThreadState::joinThreadPool(bool isMain)//isMain是true
{
mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);//向mOut中写入BC_ENTER_LOOPER指令
//对于isMain=true的情况下, command为BC_ENTER_LOOPER,代表的是Binder主线程,不会退出的线程;
//对于isMain=false的情况下,command为BC_REGISTER_LOOPER,表示是由binder驱动创建的线程。
status_t result;
do {
processPendingDerefs();//处理一些引用计数
result = getAndExecuteCommand();//等待来自其他客户端对meidaservice服务的请求。
if (result < NO_ERROR && result != TIMED_OUT && result != -ECONNREFUSED && result != -EBADF) {
ALOGE("getAndExecuteCommand(fd=%d) returned unexpected error %d, aborting",
mProcess->mDriverFD, result);
abort();
}
if(result == TIMED_OUT && !isMain) {//如果超时并且不是主线程,则退出循环
break;
}
} while (result != -ECONNREFUSED && result != -EBADF);//死循环一直等待获取消息
LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%d\n",
(void*)pthread_self(), getpid(), result);
mOut.writeInt32(BC_EXIT_LOOPER);//如果退出了循环,则告诉驱动要退出循环。
talkWithDriver(false);
}
void IPCThreadState::processPendingDerefs()
{
if (mIn.dataPosition() >= mIn.dataSize()) {//如果min中无数据
while (mPendingWeakDerefs.size() > 0 || mPendingStrongDerefs.size() > 0) {//mPendingWeakDerefs
//存储的是要销毁的弱引用,所以必须保证min中无数据,才能销毁。
//mPendingStrongDerefs存储的是BBbinder实体
while (mPendingWeakDerefs.size() > 0) {
RefBase::weakref_type* refs = mPendingWeakDerefs[0];
mPendingWeakDerefs.removeAt(0);
refs->decWeak(mProcess.get());//handle弱引用减1
}
if (mPendingStrongDerefs.size() > 0) {
BBinder* obj = mPendingStrongDerefs[0];//BBbinder实体引用减少1,一般是同进程才会有实体的存储。
mPendingStrongDerefs.removeAt(0);
obj->decStrong(mProcess.get());
}
}
}
}
2.10.2 IPCThreadState::getAndExecuteCommand
1.此时作用为,用于向驱动发送BC_ENTER_LOOPER消息
status_t IPCThreadState::getAndExecuteCommand()
{
status_t result;
int32_t cmd;
result = talkWithDriver();//先将驱动发送BC_ENTER_LOOPER,将自己注册到Binder线程池中
//然后会阻塞在read中,等待消息的读取
if (result >= NO_ERROR) {
size_t IN = mIn.dataAvail();//如果有消息
if (IN < sizeof(int32_t)) return result;
cmd = mIn.readInt32();//读取cmd
pthread_mutex_lock(&mProcess->mThreadCountLock);
mProcess->mExecutingThreadsCount++;//正在执行的线程数+1
if (mProcess->mExecutingThreadsCount >= mProcess->mMaxThreads &&
mProcess->mStarvationStartTimeMs == 0) {//不能超出线程池上限
mProcess->mStarvationStartTimeMs = uptimeMillis();
}
pthread_mutex_unlock(&mProcess->mThreadCountLock);
result = executeCommand(cmd);//执行获取来的命令
pthread_mutex_lock(&mProcess->mThreadCountLock);
mProcess->mExecutingThreadsCount--;//正在执行的线程数-1
if (mProcess->mExecutingThreadsCount < mProcess->mMaxThreads &&
mProcess->mStarvationStartTimeMs != 0) {
int64_t starvationTimeMs = uptimeMillis() - mProcess->mStarvationStartTimeMs;
if (starvationTimeMs > 100) {
ALOGE("binder thread pool (%zu threads) starved for %" PRId64 " ms",
mProcess->mMaxThreads, starvationTimeMs);
}
mProcess->mStarvationStartTimeMs = 0;
}
pthread_cond_broadcast(&mProcess->mThreadCountDecrement);
pthread_mutex_unlock(&mProcess->mThreadCountLock);
}
return result;
}
2.10.3 IPCThreadState::talkWithDriver
status_t IPCThreadState::talkWithDriver(bool doReceive)//doReceive默认是true
{
/**
if (mProcess->mDriverFD < 0) {
return -EBADF;
}
*/
binder_write_read bwr;
//struct binder_write_read {
//binder_size_t write_size;//要写入的字节数,write_buffer的总字节数
//binder_size_t write_consumed;//驱动程序占用的字节数,write_buffer已消费的字节数
//binder_uintptr_t write_buffer;//写缓冲数据的指针
//binder_size_t read_size;//要读的字节数,read_buffer的总字节数
//binder_size_t read_consumed;//驱动程序占用的字节数,read_buffer已消费的字节数
//binder_uintptr_t read_buffer;//读缓存数据的指针
//};
// Is the read buffer empty?
const bool needRead = mIn.dataPosition() >= mIn.dataSize();//此时needRead是ture
//因为mIn.dataPosition返回值和mIn.dataSize相等
//当我们正在从min中读取数据,或者调用方打算读取下一条数据(doReceive为true时),我们不会写入任何内容。
//此时outAvail值等于mOut.dataSize()
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
bwr.write_size = outAvail;//write_size是mOut.dataSize()
bwr.write_buffer = (uintptr_t)mOut.data();
if (doReceive && needRead) {//当我们需要从驱动中读的时候。
bwr.read_size = mIn.dataCapacity();//设置大小为256字节
bwr.read_buffer = (uintptr_t)mIn.data();
}
/*
else {//当不读的时候,设置读的大小和buffer为0
bwr.read_size = 0;
bwr.read_buffer = 0;
}*/
// 如果读缓冲区和写缓冲区都为0,代表无事可做,立即返回,此时write_size中有数据。
/**
if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
*/
bwr.write_consumed = 0;
bwr.read_consumed = 0;
status_t err;
do {
#if defined(__ANDROID__)
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)//向binder驱动区写,因为此时是注册当前线程成为binder主looper线程,所以mout有数据
err = NO_ERROR;
else
err = -errno;
#else
err = INVALID_OPERATION;
#endif
/**
if (mProcess->mDriverFD < 0) {
err = -EBADF;
}
*/
} while (err == -EINTR);
if (err >= NO_ERROR) {//代表驱动收到了消息
if (bwr.write_consumed > 0) {
if (bwr.write_consumed < mOut.dataSize())//如果驱动消费的数据大小小于mout的大小,则说明驱动没有消费mout数据
LOG_ALWAYS_FATAL("Driver did not consume write buffer. "
"err: %s consumed: %zu of %zu",
statusToString(err).c_str(),
(size_t)bwr.write_consumed,
mOut.dataSize());
else {//代表mout被正确消费
mOut.setDataSize(0);//重置数据大小为0
processPostWriteDerefs();//主要是将写的引用计数减少1,释放
}
}
/**
if (bwr.read_consumed > 0) {//如果驱动读的数据大小大于0
mIn.setDataSize(bwr.read_consumed);//设置mIn的大小
mIn.setDataPosition(0);//设置min数据起始位置
}
*/
return NO_ERROR;
}
///return err;
}
2.10.4 binder_ioctl
//此时数据是BC_ENTER_LOOPER,cmd是BINDER_WRITE_READ
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret;
struct binder_proc *proc = filp->private_data;//取出此fd的proc对象
struct binder_thread *thread;//此sm进程对应的binder线程
unsigned int size = _IOC_SIZE(cmd);
void __user *ubuf = (void __user *)arg;//是bwr
trace_binder_ioctl(cmd, arg);
ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);//不休眠
if (ret)
goto err_unlocked;
binder_lock(__func__);
thread = binder_get_thread(proc);//获取此proc的binder_thread
if (thread == NULL) {
ret = -ENOMEM;
goto err;
}
switch (cmd) {
case BINDER_WRITE_READ: {
struct binder_write_read bwr;
if (size != sizeof(struct binder_write_read)) {//查看大小是否正确
ret = -EINVAL;
goto err;
}
if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {//从用户空间复制数据到内核空间
//第一个参数to是内核空间的数据目标地址指针,
//第二个参数from是用户空间的数据源地址指针,
//第三个参数n是数据的长度。
ret = -EFAULT;
goto err;
}
if (bwr.write_size > 0) {//当写缓存有数据的时候,执行写操作
ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed);
//参数分析:
//proc代表sm对象的proc
//thread为此sm进程的binder线程
//bwr.write_buffer,内核数据的起始地址
//write_size,数据大小
//write_consumed,驱动程序已消费的数据大小
trace_binder_write_done(ret);
/**
if (ret < 0) {//如果写失败,再将bwr的值写回给ubuf
bwr.read_consumed = 0;
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
//第一个参数是用户空间的指针,
//第二个参数是内核空间指针,
//n表示从内核空间向用户空间拷贝数据的字节数
ret = -EFAULT;
goto err;
}
*/
}
/**
if (bwr.read_size > 0) {//当读缓存有数据的时候,执行读操作,此时读缓存无数据
ret = binder_thread_read(proc, thread, (void __user *)bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK);
trace_binder_read_done(ret);
if (!list_empty(&proc->todo))
wake_up_interruptible(&proc->wait);
if (ret < 0) {
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
goto err;
}
}
*/
if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {//将此内核空间数据,拷贝到ubuf中,此时是写的消费的大小write_consumed从变成了4字节。
ret = -EFAULT;
goto err;
}
break;
}
ret = 0;
err:
if (thread)
thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;
binder_unlock(__func__);
wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);//不休眠
if (ret && ret != -ERESTARTSYS)
printk(KERN_INFO "binder: %d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret);
err_unlocked:
trace_binder_ioctl_done(ret);
return ret;
}
2.10.5 binder_thread_write
1.驱动侧为当前线程设置已经looper,表示已经准备好循环接受驱动消息。
int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,
void __user *buffer, int size, signed long *consumed)
//参数分析:
//proc代表sm对象的proc
//thread为此sm进程的binder线程
//bwr.write_buffer,内核数据的起始地址,数据是BC_ENTER_LOOPER
//write_size,4字节,数据大小
//consumed=0,驱动程序已消费的数据大小
{
uint32_t cmd;
void __user *ptr = buffer + *consumed;//首地址+0,还是写buffer首地址。
void __user *end = buffer + size;//buffer的尾地址。
while (ptr < end && thread->return_error == BR_OK) {
if (get_user(cmd, (uint32_t __user *)ptr))//从写buffer中获取命令给cmd,即此时是BC_ENTER_LOOPER
return -EFAULT;
ptr += sizeof(uint32_t);//让buffer的地址跳过BC_ENTER_LOOPER,因为buffer中可能还有其他数据。此时是没数据了
trace_binder_command(cmd);
if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.bc)) {//记录信息
binder_stats.bc[_IOC_NR(cmd)]++;
proc->stats.bc[_IOC_NR(cmd)]++;
thread->stats.bc[_IOC_NR(cmd)]++;
}
switch (cmd) {
case BC_ENTER_LOOPER:
/**
if (thread->looper & BINDER_LOOPER_STATE_REGISTERED) {//如果此looper已经注册过,则错误
thread->looper |= BINDER_LOOPER_STATE_INVALID;
binder_user_error("binder: %d:%d ERROR:"
" BC_ENTER_LOOPER called after "
"BC_REGISTER_LOOPER\n",
proc->pid, thread->pid);
}
*/
thread->looper |= BINDER_LOOPER_STATE_ENTERED;//设置为此binder线程已经注册过了。
break;
}
*consumed = ptr - buffer;//已消费的字节大小,此时为4字节
}
return 0;
}
2.10.6 死循环用于获取来自驱动的消息
1.当向驱动发送完BC_ENTER_LOOPER的消息后,会再走到IPCThreadState::joinThreadPool函数的死循环处。
2.getAndExecuteCommand会执行talkWithDriver函数,此函数上文已多次出现,然后会阻塞,等待消息的来临
void IPCThreadState::joinThreadPool(bool isMain)//isMain是true
{
do {
processPendingDerefs();//处理一些引用计数
result = getAndExecuteCommand();//等待来自其他客户端对meidaservice服务的请求。
if (result < NO_ERROR && result != TIMED_OUT && result != -ECONNREFUSED && result != -EBADF) {
ALOGE("getAndExecuteCommand(fd=%d) returned unexpected error %d, aborting",
mProcess->mDriverFD, result);
abort();
}
if(result == TIMED_OUT && !isMain) {//如果超时并且不是主线程,则退出循环
break;
}
} while (result != -ECONNREFUSED && result != -EBADF);//死循环一直等待获取消息
}
2.10.7 getAndExecuteCommand
status_t IPCThreadState::getAndExecuteCommand()
{
status_t result;
int32_t cmd;
result = talkWithDriver();//此时会阻塞在read中,等待消息的读取
if (result >= NO_ERROR) {
size_t IN = mIn.dataAvail();//如果有消息
if (IN < sizeof(int32_t)) return result;
cmd = mIn.readInt32();//读取cmd
pthread_mutex_lock(&mProcess->mThreadCountLock);
mProcess->mExecutingThreadsCount++;//正在执行的线程数+1
if (mProcess->mExecutingThreadsCount >= mProcess->mMaxThreads &&
mProcess->mStarvationStartTimeMs == 0) {//不能超出线程池上限
mProcess->mStarvationStartTimeMs = uptimeMillis();
}
pthread_mutex_unlock(&mProcess->mThreadCountLock);
result = executeCommand(cmd);//执行获取来的命令
pthread_mutex_lock(&mProcess->mThreadCountLock);
mProcess->mExecutingThreadsCount--;//正在执行的线程数-1
if (mProcess->mExecutingThreadsCount < mProcess->mMaxThreads &&
mProcess->mStarvationStartTimeMs != 0) {
int64_t starvationTimeMs = uptimeMillis() - mProcess->mStarvationStartTimeMs;
if (starvationTimeMs > 100) {
ALOGE("binder thread pool (%zu threads) starved for %" PRId64 " ms",
mProcess->mMaxThreads, starvationTimeMs);
}
mProcess->mStarvationStartTimeMs = 0;
}
pthread_cond_broadcast(&mProcess->mThreadCountDecrement);
pthread_mutex_unlock(&mProcess->mThreadCountLock);
}
return result;
}
2.10.8 talkWithDriver
1.此时当前专门用于ipc通信的线程会阻塞,等待来自驱动的消息。
status_t IPCThreadState::talkWithDriver(bool doReceive)//默认doReceive是true
{
if (mProcess->mDriverFD <= 0) {
return -EBADF;
}
binder_write_read bwr;
const bool needRead = mIn.dataPosition() >= mIn.dataSize();//此时needRead是true
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;//此时outAvail是0
bwr.write_size = outAvail;//write_size是0
bwr.write_buffer = (uintptr_t)mOut.data();
// This is what we'll read.
if (doReceive && needRead) {//需要读取数据
bwr.read_size = mIn.dataCapacity();//设置需要读取的大小。
bwr.read_buffer = (uintptr_t)mIn.data();
}
/*else {//不执行
bwr.read_size = 0;
bwr.read_buffer = 0;
}*/
// 不会执行
//if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
bwr.write_consumed = 0;
bwr.read_consumed = 0;
status_t err;
do {
#if defined(__ANDROID__)
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)//从驱动中读取消息,在这里面
//会线程休眠
err = NO_ERROR;
else
err = -errno;
/*
#else
err = INVALID_OPERATION;
#endif
if (mProcess->mDriverFD <= 0) {
err = -EBADF;
}
IF_LOG_COMMANDS() {
alog << "Finished read/write, write size = " << mOut.dataSize() << endl;
}
} while (err == -EINTR);
IF_LOG_COMMANDS() {
alog << "Our err: " << (void*)(intptr_t)err << ", write consumed: "
<< bwr.write_consumed << " (of " << mOut.dataSize()
<< "), read consumed: " << bwr.read_consumed << endl;
}
if (err >= NO_ERROR) {
if (bwr.write_consumed > 0) {
if (bwr.write_consumed < mOut.dataSize())
mOut.remove(0, bwr.write_consumed);
else {
mOut.setDataSize(0);
processPostWriteDerefs();
}
}
if (bwr.read_consumed > 0) {
mIn.setDataSize(bwr.read_consumed);
mIn.setDataPosition(0);
}
IF_LOG_COMMANDS() {
TextOutput::Bundle _b(alog);
alog << "Remaining data size: " << mOut.dataSize() << endl;
alog << "Received commands from driver: " << indent;
const void* cmds = mIn.data();
const void* end = mIn.data() + mIn.dataSize();
alog << HexDump(cmds, mIn.dataSize()) << endl;
while (cmds < end) cmds = printReturnCommand(alog, cmds);
alog << dedent;
}
return NO_ERROR;
}
return err;
*/
}
2.10.9 binder_ioctl
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret;
struct binder_proc *proc = filp->private_data;//取出meidaservice进程对应的porc对象
struct binder_thread *thread;//meidaservice进进程的binder线程
unsigned int size = _IOC_SIZE(cmd);
void __user *ubuf = (void __user *)arg;//__user表示用户空间的指针
trace_binder_ioctl(cmd, arg);
ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);//条件成立,立即返回,不休眠
if (ret)
goto err_unlocked;
binder_lock(__func__);
thread = binder_get_thread(proc);//获取binder_thread
if (thread == NULL) {
ret = -ENOMEM;
goto err;
}
switch (cmd) {
case BINDER_WRITE_READ: {
struct binder_write_read bwr;
if (size != sizeof(struct binder_write_read)) {//计算数据是否和规范
ret = -EINVAL;
goto err;
}
if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {//拷贝数据到内核空间
ret = -EFAULT;
goto err;
}
/*if (bwr.write_size > 0) {//此时write_siz=0,不执行
ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed);
trace_binder_write_done(ret);
if (ret < 0) {
bwr.read_consumed = 0;
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
goto err;
}
}
*/
if (bwr.read_size > 0) {//此时read_size>0
ret = binder_thread_read(proc, thread, (void __user *)bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK);
//此时meidaservice的binder线程会阻塞在这里。后面暂不执行,等待唤醒时,才会执行
/*
if (!list_empty(&proc->todo))
wake_up_interruptible(&proc->wait);
if (ret < 0) {
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
goto err;
}
}
binder_debug(BINDER_DEBUG_READ_WRITE,
"binder: %d:%d wrote %ld of %ld, read return %ld of %ld\n",
proc->pid, thread->pid, bwr.write_consumed, bwr.write_size,
bwr.read_consumed, bwr.read_size);
if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
ret = -EFAULT;
goto err;
}
break;
}
}
ret = 0;
err:
if (thread)
thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;
binder_unlock(__func__);
wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
if (ret && ret != -ERESTARTSYS)
printk(KERN_INFO "binder: %d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret);
err_unlocked:
trace_binder_ioctl_done(ret);
return ret;
*/
}
2.10.10 binder_thread_read
static int binder_thread_read(struct binder_proc *proc,
struct binder_thread *thread,
void __user *buffer, int size,
signed long *consumed, int non_block)
//参数分析:
//proc是media是mediaservice服务的proc
//thread是meidaservice服务的线程
//buffer指向read_buffer,读的首地址
//read_size>0
//read_consumed是0
//non_block是0,表示是阻塞的
{
void __user *ptr = buffer + *consumed;//指向buffer首地址
void __user *end = buffer + size;//指向尾地址
int ret = 0;
int wait_for_proc_work;
if (*consumed == 0) {
if (put_user(BR_NOOP, (uint32_t __user *)ptr))//向里面放一个BR_NOOP命令
return -EFAULT;
ptr += sizeof(uint32_t);
}
retry:
wait_for_proc_work = thread->transaction_stack == NULL &&
list_empty(&thread->todo);//此时当前线程的运输事务不空,即transaction_stack不为空
thread->looper |= BINDER_LOOPER_STATE_WAITING;//设置等待的flag
/*if (wait_for_proc_work)//不执行
proc->ready_threads++;*/
binder_unlock(__func__);
/*if (wait_for_proc_work) {//wait_for_proc_work是false,不执行
if (!(thread->looper & (BINDER_LOOPER_STATE_REGISTERED |
BINDER_LOOPER_STATE_ENTERED))) {
wait_event_interruptible(binder_user_error_wait,
binder_stop_on_user_error < 2);
}
binder_set_nice(proc->default_priority);
if (non_block) {
if (!binder_has_proc_work(proc, thread))
ret = -EAGAIN;
} else
ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread));
} */
else {//走这里
/*if (non_block) {不执行
if (!binder_has_thread_work(thread))
ret = -EAGAIN;
} */
else
ret = wait_event_freezable(thread->wait, binder_has_thread_work(thread));//meidaservice线程陷入休眠
}
//后面都不执行,故省略.....
}
至此所有流程分析完毕。