在 Android 系统中,Binder 是用于进程间通信(IPC)的主要机制,而 ServiceManager 则是 Binder 框架中的核心组件之一。ServiceManager 负责管理系统中的各个 binder 服务,并提供服务注册和查找功能
ServiceManager 本身也是 Binder 对象 ,跑在 servicemanager 进程里面
上篇 android binderfs 介绍 里提到 binderfs 文件系统的挂载 ,并在 /dev/ 目录下生成了三个链接文件 。
这篇文章我将把介绍 servicemanager 进程如何与 binder 设备文件通信,并把 ServiceManager 设置成为 binder 上下文管理者的 ,会结合 binder 内核代码一起讲 。
servicemanager 进程的启动
servicemanager进程 是通过 Android init 进程 解析 init.rc 文件启动的
servicemanager.rc 文件
sh
# 定义一个名为 servicemanager 的服务。/system/bin/servicemanager 是服务的可执行文件路径。
service servicemanager /system/bin/servicemanager
# 将这个服务归类为 core 类, core 类的服务通常在系统启动的早期阶段启动,
# animation 为附加属性,可以用来标记这个服务,可能与启动动画有关
class core animation
# 指定该服务以 system 用户身份运行
user system
# 指定该服务属于 system 组,并且具有 readproc 组的权限。
group system readproc
# 将这个服务标记为关键服务。如果该服务崩溃或停止,设备将重新启动。
critical
# 赋予该服务对 /dev/kmsg 文件的写权限,用于内核消息日志。
file /dev/kmsg w
# 指令指定在服务重新启动时应该执行的动作
onrestart setprop servicemanager.ready false
onrestart restart --only-if-running apexd
onrestart restart audioserver
onrestart restart gatekeeperd
onrestart class_restart --only-enabled main
onrestart class_restart --only-enabled hal
onrestart class_restart --only-enabled early_hal
# 将 ServiceCapacityLow 任务配置文件应用于该服务,与资源限制或管理策略有关。
task_profiles ServiceCapacityLow
# 标记该服务为关键服务,即使在关机过程中也应确保其正确处理。
shutdown critical
servicemanager main 函数
c
int main(int argc, char** argv) {
//初始化日志系统,使用内核日志记录器
android::base::InitLogging(argv, android::base::KernelLogger);
// 根据 servicemanager.rc 文件 servicemanager 没有附加命令行参数
if (argc > 2) {
LOG(FATAL) << "usage: " << argv[0] << " [binder driver]";
}
// argc 不为 2 ,driver 为 /dev/binder
const char* driver = argc == 2 ? argv[1] : "/dev/binder";
LOG(INFO) << "Starting sm instance on " << driver;
// 调用 ProcessState::initWithDriver 函数
sp<ProcessState> ps = ProcessState::initWithDriver(driver);
// 设置binder线程最大线程数为 0
ps->setThreadPoolMaxThreadCount(0);
ps->setCallRestriction(ProcessState::CallRestriction::FATAL_IF_NOT_ONEWAY);
// 创建 ServiceManager 对象 ,并且创建了一个Access 对象作为构造函数的参数
// Access 对象是用来 SELinux 审核权限用的,用来限制普通 app 随便添加 binder对象到 ServiceManager
sp<ServiceManager> manager = sp<ServiceManager>::make(std::make_unique<Access>());
// 把自己添加到 ServiceManager 里面
if (!manager->addService("manager", manager, false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()) {
LOG(ERROR) << "Could not self register servicemanager";
}
// 把 ServiceManager 保存到 IPCThreadState
IPCThreadState::self()->setTheContextObject(manager);
// 设置成为 binder上下文管理者
ps->becomeContextManager();
// 创建 Looper对象
sp<Looper> looper = Looper::prepare(false /*allowNonCallbacks*/);
// 设置 Looper 回调监听
BinderCallback::setupTo(looper);
ClientCallbackCallback::setupTo(looper, manager);
// 循环等待客户端请求
while(true) {
looper->pollAll(-1);
}
// should not be reached
return EXIT_FAILURE;
}
启动过程可以分成三部分
- 打开 /dev/binder 设备文件 ,构建与 binder内核通信渠道
- 把自己添加到系统服务中 ,本身是个 binder 服务,自己添加到自身,并通过 ioctl 调用 把自己设置为 binder上下文管理者
- 开启 Looper 循环,等待客户端请求。
打开 /dev/binder 设备文件
c
sp<ProcessState> ProcessState::initWithDriver(const char* driver)
{
return init(driver, true /*requireDefault*/);
}
// ProcessState 对象是个单例,只会创建一次
sp<ProcessState> ProcessState::init(const char *driver, bool requireDefault)
{
// driver 不为空
if (driver == nullptr) {
std::lock_guard<std::mutex> l(gProcessMutex);
if (gProcess) {
verifyNotForked(gProcess->mForked);
}
return gProcess;
}
// 声明一个 std::once_flag 对象
[[clang::no_destroy]] static std::once_flag gProcessOnce;
// 只会调用一次
std::call_once(gProcessOnce, [&](){
// 判断 driver 路径是否存在
if (access(driver, R_OK) == -1) {
ALOGE("Binder driver %s is unavailable. Using /dev/binder instead.", driver);
driver = "/dev/binder";
}
// 在调用 fork 之前和之后注册特定的回调函数,这些回调函数可以确保在创建新进程时正确处理锁和其他资源,从而避免多线程程序中的潜在问题
int ret = pthread_atfork(ProcessState::onFork, ProcessState::parentPostFork,
ProcessState::childPostFork);
LOG_ALWAYS_FATAL_IF(ret != 0, "pthread_atfork error %s", strerror(ret));
// 加锁
std::lock_guard<std::mutex> l(gProcessMutex);
// 新建 ProcessState 对象
gProcess = sp<ProcessState>::make(driver);
});
return gProcess;
}
c
// ProcessState 构造函数 ,初始化一些默认参数
ProcessState::ProcessState(const char* driver)
: mDriverName(String8(driver)),
mDriverFD(-1),
mVMStart(MAP_FAILED),
mThreadCountLock(PTHREAD_MUTEX_INITIALIZER),
mThreadCountDecrement(PTHREAD_COND_INITIALIZER),
mExecutingThreadsCount(0),
mWaitingForThreads(0),
mMaxThreads(DEFAULT_MAX_BINDER_THREADS),
mCurrentThreads(0),
mKernelStartedThreads(0),
mStarvationStartTimeMs(0),
mForked(false),
mThreadPoolStarted(false),
mThreadPoolSeq(1),
mCallRestriction(CallRestriction::NONE) {
// 打开文件
base::Result<int> opened = open_driver(driver);
// 打开文件成功
if (opened.ok()) {
// mmap binder, 提供一块虚拟地址空间来接收事务。
mVMStart = mmap(nullptr, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE,
opened.value(), 0);
if (mVMStart == MAP_FAILED) {
close(opened.value());
opened = base::Error()
<< "Using " << driver << " failed: unable to mmap transaction memory.";
mDriverName.clear();
}
}
if (opened.ok()) {
mDriverFD = opened.value();
}
}
// 打开设备文件
static base::Result<int> open_driver(const char* driver) {
// open 系统调用,打开文件成功返回文件描述符
int fd = open(driver, O_RDWR | O_CLOEXEC);
if (fd < 0) {
return base::ErrnoError() << "Opening '" << driver << "' failed";
}
int vers = 0;
// ioctl 系统调用 ,获取到版本号
status_t result = ioctl(fd, BINDER_VERSION, &vers);
if (result == -1) {
close(fd);
return base::ErrnoError() << "Binder ioctl to obtain version failed";
}
if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
close(fd);
return base::Error() << "Binder driver protocol(" << vers
<< ") does not match user space protocol("
<< BINDER_CURRENT_PROTOCOL_VERSION
<< ")! ioctl() return value: " << result;
}
// ioctl 系统调用 ,设置binder 最大线程数 ,默认为 15
size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
if (result == -1) {
ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
}
// ioctl 系统调用 开启检测和防止 "oneway" 方法调用的滥用 ,默认开启
uint32_t enable = DEFAULT_ENABLE_ONEWAY_SPAM_DETECTION;
result = ioctl(fd, BINDER_ENABLE_ONEWAY_SPAM_DETECTION, &enable);
if (result == -1) {
ALOGE_IF(ProcessState::isDriverFeatureEnabled(
ProcessState::DriverFeature::ONEWAY_SPAM_DETECTION),
"Binder ioctl to enable oneway spam detection failed: %s", strerror(errno));
}
return fd;
}
请注意在之前的文章中提到 android binderfs 介绍 在 binderfs 的 binderfs_binder_device_create
函数中创建binder文件的 inode 绑定文件操作函数
c
inode->i_fop = &binder_fops;
const struct file_operations binder_fops = {
.owner = THIS_MODULE,
.poll = binder_poll,
.unlocked_ioctl = binder_ioctl,
.compat_ioctl = compat_ptr_ioctl,
.mmap = binder_mmap,
.open = binder_open,
.flush = binder_flush,
.release = binder_release,
};
open 系统调用
open 系统调用后会调用 binder_open ,binder_open 会创建 binder_proc 对象 是描述 一个和 binder 内核通信的进程,一个使用 binder的进程只有一个 binder_proc对象 ,会存储在 binder 内核全局 binder_procs 链表中
把 binder_proc 结构体对象存储到 file 文件对象的 private_data 域中 ,并返回文件描述符,返回的文件描述符内核已经把它和 file 对象建立了绑定关系 ,当后面使用该文件描述符进行其他的系统调用时,file 对象的 private_data 域中可以获取 binder_proc 对象
关于进程 ID ,线程ID ,对于linux 内核是不区分进程和线程的 都是由 task_struct 描述的 ,进程和线程的区别在于,进程是有独立的的地址空间和系统资源,线程是共享进程的地址空间和系统资源。
current 是一个宏获取当前线程的 task_struct 结构体 。 current->group_leader 相当于主线程 current->pid 相当于当前线程的 ID
C
// 打开文件打开
static int binder_open(struct inode *nodp, struct file *filp)
{
struct binder_proc *proc, *itr;
struct binder_device *binder_dev;
struct binderfs_info *info;
struct dentry *binder_binderfs_dir_entry_proc = NULL;
bool existing_pid = false;
// 打印日志
binder_debug(BINDER_DEBUG_OPEN_CLOSE, "%s: %d:%d\n", __func__,
current->group_leader->pid, current->pid);
// 创建 binder_proc 对象
proc = kzalloc(sizeof(*proc), GFP_KERNEL);
if (proc == NULL)
return -ENOMEM;
// 初始化 inner_lock 自旋锁
spin_lock_init(&proc->inner_lock);
// 初始化 outer_lock 自旋锁
spin_lock_init(&proc->outer_lock);
// 获取主线程引用+1
get_task_struct(current->group_leader);
// 初始化 binder_proc 对象 ,记录进程
proc->tsk = current->group_leader;
// 记录文件的凭据
proc->cred = get_cred(filp->f_cred);
// 初始化链表
INIT_LIST_HEAD(&proc->todo);
// 初始化等待队列
init_waitqueue_head(&proc->freeze_wait);
// 记录进程调度策略和优先级
if (binder_supported_policy(current->policy)) {
proc->default_priority.sched_policy = current->policy;
proc->default_priority.prio = current->normal_prio;
} else {
proc->default_priority.sched_policy = SCHED_NORMAL;
proc->default_priority.prio = NICE_TO_PRIO(0);
}
/* 获取 binderfs 文件系统的信息 */
if (is_binderfs_device(nodp)) {
binder_dev = nodp->i_private;
info = nodp->i_sb->s_fs_info;
binder_binderfs_dir_entry_proc = info->proc_log_dir;
} else {
binder_dev = container_of(filp->private_data,
struct binder_device, miscdev);
}
// binder_dev 引用加 1
refcount_inc(&binder_dev->ref);
// 记录 binder_dev 上下文
proc->context = &binder_dev->context;
// 初始化 binder_alloc 对象
binder_alloc_init(&proc->alloc);
// binder_stats.obj_created 加 1
binder_stats_created(BINDER_STAT_PROC);
// 记录主线程 pid
proc->pid = current->group_leader->pid;
// 初始化 delivered_death 链表
INIT_LIST_HEAD(&proc->delivered_death);
// 初始化 waiting_threads 链表
INIT_LIST_HEAD(&proc->waiting_threads);
// binder_proc 结构体对象存储到 private_data
filp->private_data = proc;
// 互斥锁 lock
mutex_lock(&binder_procs_lock);
// 遍历 binder_procs 链表查找链表当中是否存在同一个进程组 pid 的 binder_proc 对象
hlist_for_each_entry(itr, &binder_procs, proc_node) {
if (itr->pid == proc->pid) {
existing_pid = true;
break;
}
}
// 把当前 binder_proc 对象 添加到 binder_procs 链表
hlist_add_head(&proc->proc_node, &binder_procs);
// 互斥锁 解锁
mutex_unlock(&binder_procs_lock);
trace_android_vh_binder_preset(&binder_procs, &binder_procs_lock);
// 在/sys/kernel/debug 创建文件
if (binder_debugfs_dir_entry_proc && !existing_pid) {
char strbuf[11];
snprintf(strbuf, sizeof(strbuf), "%u", proc->pid);
proc->debugfs_entry = debugfs_create_file(strbuf, 0444,
binder_debugfs_dir_entry_proc,
(void *)(unsigned long)proc->pid,
&proc_fops);
}
// 在 /dev/binderfs/binder_logs/proc 创建文件
if (binder_binderfs_dir_entry_proc && !existing_pid) {
char strbuf[11];
struct dentry *binderfs_entry;
snprintf(strbuf, sizeof(strbuf), "%u", proc->pid);
binderfs_entry = binderfs_create_file(binder_binderfs_dir_entry_proc,
strbuf, &proc_fops, (void *)(unsigned long)proc->pid);
if (!IS_ERR(binderfs_entry)) {
proc->binderfs_entry = binderfs_entry;
} else {
int error;
error = PTR_ERR(binderfs_entry);
pr_warn("Unable to create file %s in binderfs (error %d)\n",
strbuf, error);
}
}
return 0;
}
// 初始化 binder_alloc 对象
void binder_alloc_init(struct binder_alloc *alloc)
{
// 记录 pid
alloc->pid = current->group_leader->pid;
// 记录 获取管理进程地址空间的核心数据结构
alloc->vma_vm_mm = current->mm;
// count 加 1
mmgrab(alloc->vma_vm_mm);
// 初始化 互斥锁
mutex_init(&alloc->mutex);
// 初始化链表
INIT_LIST_HEAD(&alloc->buffers);
}
ioctl 系统调用
ioctl 系统调用后会调用 binder_fops 的 函数指针 unlocked_ioctl ,即 binder_ioctl 函数 ,
-
BINDER_VERSION 获取 binder 版本号
-
BINDER_SET_MAX_THREADS 设置 binder 最大线程数
-
BINDER_SET_CONTEXT_MGR_EXT 注册成为 binder 上下文管理者
-
BINDER_ENABLE_ONEWAY_SPAM_DETECTION 开启检测和防止 "oneway" 方法调用的滥用
c
/*
struct file *:一个指向打开的文件对象的指针,代表了打开的文件。struct file 结构体包含了文件的相关信息和操作方法。
cmd:一个表示具体 ioctl 操作命令的数值。每个 ioctl 操作都有一个唯一的命令编号,用于区分不同的操作。
arg :用户空间传递给内核的参数,可以是各种数据类型,通常是一个指针,用于传递或接收数据。
*/
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret;
// 从文件私有数据中拿到 binder_proc 对象
struct binder_proc *proc = filp->private_data;
struct binder_thread *thread;
unsigned int size = _IOC_SIZE(cmd);
void __user *ubuf = (void __user *)arg;
/*pr_info("binder_ioctl: %d:%d %x %lx\n",
proc->pid, current->pid, cmd, arg);*/
binder_selftest_alloc(&proc->alloc);
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_thread 对象
thread = binder_get_thread(proc);
if (thread == NULL) {
ret = -ENOMEM;
goto err;
}
switch (cmd) {
// 用户空间给内核发读写数据
case BINDER_WRITE_READ:
ret = binder_ioctl_write_read(filp, cmd, arg, thread);
if (ret)
goto err;
break;
// 设置 binder 最大线程数
case BINDER_SET_MAX_THREADS: {
int max_threads;
// 把设置的最大数值从用户空间拷贝到内核空间
if (copy_from_user(&max_threads, ubuf,
sizeof(max_threads))) {
ret = -EINVAL;
goto err;
}
//加锁
binder_inner_proc_lock(proc);
// 把最大线程数记录在 binder_proc.max_threads
proc->max_threads = max_threads;
// 解锁
binder_inner_proc_unlock(proc);
break;
}
// 注册成为 binder 上下文管理者
case BINDER_SET_CONTEXT_MGR_EXT: {
struct flat_binder_object fbo;
// 从用户空间拷贝flat_binder_object对象到内核空间
if (copy_from_user(&fbo, ubuf, sizeof(fbo))) {
ret = -EINVAL;
goto err;
}
// 设置成为 binder 上下文管理者
ret = binder_ioctl_set_ctx_mgr(filp, &fbo);
if (ret)
goto err;
break;
}
// .... 省略其他分支
// 获取 binder 版本号
case BINDER_VERSION: {
// 用户空间用开接收版本号的指针
struct binder_version __user *ver = ubuf;
// 校验数据大小
if (size != sizeof(struct binder_version)) {
ret = -EINVAL;
goto err;
}
// 把版本数据从内核空间拷贝到用户空间 ,#define BINDER_CURRENT_PROTOCOL_VERSION 8
if (put_user(BINDER_CURRENT_PROTOCOL_VERSION,
&ver->protocol_version)) {
ret = -EINVAL;
goto err;
}
break;
}
// .... 省略其他分支
default:
ret = -EINVAL;
goto err;
}
ret = 0;
err:
if (thread)
thread->looper_need_return = false;
wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
if (ret && ret != -EINTR)
pr_info("%d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret);
err_unlocked:
trace_binder_ioctl_done(ret);
return ret;
}
binder_thread 描述调用了 binder 线程的对象 ,把使用了 binder 的线程记录在 binder_proc.threads 红黑树当中
c
static struct binder_thread *binder_get_thread(struct binder_proc *proc)
{
struct binder_thread *thread;
struct binder_thread *new_thread;
binder_inner_proc_lock(proc);
// 调用 binder_get_thread_ilocked 方法 new_thread 传 NULL
thread = binder_get_thread_ilocked(proc, NULL);
binder_inner_proc_unlock(proc);
if (!thread) { // 若返回为 NULL
// 创建 binder_thread 对象
new_thread = kzalloc(sizeof(*thread), GFP_KERNEL);
if (new_thread == NULL)
return NULL;
binder_inner_proc_lock(proc);
// 再次调用 binder_get_thread_ilocked 方法 ,传入 new_thread
thread = binder_get_thread_ilocked(proc, new_thread);
binder_inner_proc_unlock(proc);
if (thread != new_thread)
kfree(new_thread);
}
return thread;
}
static struct binder_thread *binder_get_thread_ilocked(
struct binder_proc *proc, struct binder_thread *new_thread)
{
struct binder_thread *thread = NULL;
struct rb_node *parent = NULL;
// binder_proc binder_thread 对象红黑树
struct rb_node **p = &proc->threads.rb_node;
// 遍历红黑树获取 binder_thread 对象
while (*p) {
parent = *p;
thread = rb_entry(parent, struct binder_thread, rb_node);
if (current->pid < thread->pid)
p = &(*p)->rb_left;
else if (current->pid > thread->pid)
p = &(*p)->rb_right;
else
return thread;
}
// 红黑树中未获取到当前线程的的 binder_thread 对象
// new_thread 为 NULL ,返回 NULL
if (!new_thread)
return NULL;
// new_thread 不为 NULL
thread = new_thread;
// 记录 BINDER_STAT_THREAD 状态
binder_stats_created(BINDER_STAT_THREAD);
// 初始化 binder_thread 对象
thread->proc = proc;
// 记录当前线程 id
thread->pid = current->pid;
// 当前线程引用 +1
get_task_struct(current);
// 记录当前线程 task_struct 结构体
thread->task = current;
atomic_set(&thread->tmp_ref, 0);
// 初始化等待队列
init_waitqueue_head(&thread->wait);
// 初始化 todo 链表
INIT_LIST_HEAD(&thread->todo);
// 把当前线程的 binder_thread对象 插入到 proc->threads.rb_node 红黑树
rb_link_node(&thread->rb_node, parent, p);
rb_insert_color(&thread->rb_node, &proc->threads);
thread->looper_need_return = true;
thread->return_error.work.type = BINDER_WORK_RETURN_ERROR;
thread->return_error.cmd = BR_OK;
thread->reply_error.work.type = BINDER_WORK_RETURN_ERROR;
thread->reply_error.cmd = BR_OK;
// 初始化锁
spin_lock_init(&thread->prio_lock);
// 设置 prio_state 状态
thread->prio_state = BINDER_PRIO_SET;
// 初始化链表
INIT_LIST_HEAD(&new_thread->waiting_thread_node);
return thread;
}
mmap 系统调用
调用 mmap 函数后 ,会调用 binder_fops.mmap 函数指针,既 binder_mmap函数
c
/*
filp :一个指向打开的文件对象的指针,代表了正在被内存映射的文件或设备。
struct file 结构体包含了文件的相关信息和操作方法。
vma :一个指向虚拟内存区域结构体的指针,描述了将要创建的内存映射区域。
struct vm_area_struct 结构体包含了虚拟地址空间中一个连续区域的信息,如起始地址、长度、保护属性等。
*/
static int binder_mmap(struct file *filp, struct vm_area_struct *vma)
{
// 获取文件 private_data 数据
struct binder_proc *proc = filp->private_data;
// 校验进程
if (proc->tsk != current->group_leader)
return -EINVAL;
binder_debug(BINDER_DEBUG_OPEN_CLOSE,
"%s: %d %lx-%lx (%ld K) vma %lx pagep %lx\n",
__func__, proc->pid, vma->vm_start, vma->vm_end,
(vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags,
(unsigned long)pgprot_val(vma->vm_page_prot));
// vma 代表进程的虚拟进程地址
// vm_flags 这块内存区域如果可写的直接报错返回
if (vma->vm_flags & FORBIDDEN_MMAP_FLAGS) {
pr_err("%s: %d %lx-%lx %s failed %d\n", __func__,
proc->pid, vma->vm_start, vma->vm_end, "bad vm_flags", -EPERM);
return -EPERM;
}
// 设置 vm_flags 在fork()时不复制, 可包含 "struct page" 和纯 PFN 页面的混合映射
vma->vm_flags |= VM_DONTCOPY | VM_MIXEDMAP;
//设置 vm_flags 该块内存区域不可通过 mprotect 系统调用 更改为可写
vma->vm_flags &= ~VM_MAYWRITE;
// 设置 vm_ops
vma->vm_ops = &binder_vm_ops;
// vma 私有数据设置为 proc
vma->vm_private_data = proc;
return binder_alloc_mmap_handler(&proc->alloc, vma);
}
static const struct vm_operations_struct binder_vm_ops = {
.open = binder_vma_open,
.close = binder_vma_close,
.fault = binder_vm_fault,
};
static int binder_mmap(struct file *filp, struct vm_area_struct *vma)
{
// 获取文件 private_data 数据
struct binder_proc *proc = filp->private_data;
// 校验进程
if (proc->tsk != current->group_leader)
return -EINVAL;
binder_debug(BINDER_DEBUG_OPEN_CLOSE,
"%s: %d %lx-%lx (%ld K) vma %lx pagep %lx\n",
__func__, proc->pid, vma->vm_start, vma->vm_end,
(vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags,
(unsigned long)pgprot_val(vma->vm_page_prot));
// vma 代表进程的虚拟进程地址
// vm_flags 这块内存区域如果可写的直接报错返回
if (vma->vm_flags & FORBIDDEN_MMAP_FLAGS) {
pr_err("%s: %d %lx-%lx %s failed %d\n", __func__,
proc->pid, vma->vm_start, vma->vm_end, "bad vm_flags", -EPERM);
return -EPERM;
}
// 设置 vm_flags 在fork()时不复制, 可包含 "struct page" 和纯 PFN 页面的混合映射
vma->vm_flags |= VM_DONTCOPY | VM_MIXEDMAP;
//设置 vm_flags 该块内存区域不可通过 mprotect 系统调用 更改为可写
vma->vm_flags &= ~VM_MAYWRITE;
// 设置 vm_ops
vma->vm_ops = &binder_vm_ops;
// vma 私有数据设置为 proc
vma->vm_private_data = proc;
return binder_alloc_mmap_handler(&proc->alloc, vma);
}
int binder_alloc_mmap_handler(struct binder_alloc *alloc,
struct vm_area_struct *vma)
{
int ret;
const char *failure_string;
struct binder_buffer *buffer;
// 校验 mm_struct 对象
if (unlikely(vma->vm_mm != alloc->vma_vm_mm)) {
ret = -EINVAL;
failure_string = "invalid vma->vm_mm";
goto err_invalid_mm;
}
// 加锁
mutex_lock(&binder_alloc_mmap_lock);
// 如果 alloc->buffer_size 已经被赋值过了,说明该进程已经 mmap 过
if (alloc->buffer_size) {
ret = -EBUSY;
failure_string = "already mapped";
goto err_already_mapped;
}
//取 mmap 内存大小 与 4M 的最小值
alloc->buffer_size = min_t(unsigned long, vma->vm_end - vma->vm_start,
SZ_4M);
mutex_unlock(&binder_alloc_mmap_lock);
// 存储进程虚拟内存地址
alloc->buffer = (void __user *)vma->vm_start;
// 创建映射虚拟内存对应物理页面个数的 binder_lru_page 对象
alloc->pages = kcalloc(alloc->buffer_size / PAGE_SIZE,
sizeof(alloc->pages[0]),
GFP_KERNEL);
//校验是否创建成功
if (alloc->pages == NULL) {
ret = -ENOMEM;
failure_string = "alloc page array";
goto err_alloc_pages_failed;
}
// 创建 binder_buffer 对象
buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
//校验是否创建成功
if (!buffer) {
ret = -ENOMEM;
failure_string = "alloc buffer struct";
goto err_alloc_buf_struct_failed;
}
// binder_buffer 进程虚拟内存地址
buffer->user_data = alloc->buffer;
// binder_buffer 对象添加到 binder_alloc 对象的链表里面
list_add(&buffer->entry, &alloc->buffers);
// 标记 binder_buffer 为空闲
buffer->free = 1;
// 把 buffer 插入到alloc. free_buffers 红黑树里面
binder_insert_free_buffer(alloc, buffer);
alloc->free_async_space = alloc->buffer_size / 2;
/* Signal binder_alloc is fully initialized */
// vma 赋值给 allc.vma 字段
binder_alloc_set_vma(alloc, vma);
return 0;
err_alloc_buf_struct_failed:
kfree(alloc->pages);
alloc->pages = NULL;
err_alloc_pages_failed:
alloc->buffer = NULL;
mutex_lock(&binder_alloc_mmap_lock);
alloc->buffer_size = 0;
err_already_mapped:
mutex_unlock(&binder_alloc_mmap_lock);
err_invalid_mm:
binder_alloc_debug(BINDER_DEBUG_USER_ERROR,
"%s: %d %lx-%lx %s failed %d\n", __func__,
alloc->pid, vma->vm_start, vma->vm_end,
failure_string, ret);
return ret;
}
ps->setThreadPoolMaxThreadCount(0);
很多人会好奇为啥会设置 binder 线程最大线程数为 0 ,首先我们要先想清楚什么是 binder 线程 ,binder 线程是用户空间开启的与 binder 内核通信,等待接收 binder 内核发出来的命令的子线程 。servicemanager 进程只有一个功能 管理 binder 服务 ,比较简单,只用主线程就够用,不用动态开启子线程去处理 binder 请求,主线程使用 Looper 机制等待内核发出的数据。
c
status_t ProcessState::setThreadPoolMaxThreadCount(size_t maxThreads) {
LOG_ALWAYS_FATAL_IF(mThreadPoolStarted && maxThreads < mMaxThreads,
"Binder threadpool cannot be shrunk after starting");
status_t result = NO_ERROR;
// ioctl 调用 设置binder最大线程数
if (ioctl(mDriverFD, BINDER_SET_MAX_THREADS, &maxThreads) != -1) {
mMaxThreads = maxThreads;
} else {
result = -errno;
ALOGE("Binder ioctl to set max threads failed: %s", strerror(-result));
}
return result;
}
向 binder 内核设置自己为 binder 上下文管理者
Access 构造函数
c
Access::Access() {
#ifdef __ANDROID__
union selinux_callback cb;
// 设置审计回调
cb.func_audit = auditCallback;
selinux_set_callback(SELINUX_CB_AUDIT, cb);
// 设置日志回调
cb.func_log = kIsVendor ? selinux_vendor_log_callback : selinux_log_callback;
selinux_set_callback(SELINUX_CB_LOG, cb);
// 初始化和打开 SELinux 状态描述符
CHECK(selinux_status_open(true /*fallback*/) >= 0);
// 获取当前进程的安全上下文并存储在 mThisProcessContext 变量中。
CHECK(getcon(&mThisProcessContext) == 0);
#endif
}
Access::CallingContext Access::getCallingContext() {
#ifdef __ANDROID__
IPCThreadState* ipc = IPCThreadState::self();
// 获取调用者 SELinux 安全标识符(SID)
const char* callingSid = ipc->getCallingSid();
// 获取调用者 进程pid
pid_t callingPid = ipc->getCallingPid();
return CallingContext {
.debugPid = callingPid,
.uid = ipc->getCallingUid(), // 获取调用者 uid
.sid = callingSid ? std::string(callingSid) : getPidcon(callingPid),
};
#else
return CallingContext();
#endif
}
把自己添加到 ServiceManager 服务里面
c
Status ServiceManager::addService(const std::string& name, const sp<IBinder>& binder, bool allowIsolated, int32_t dumpPriority) {
// 获取调用者 安全上下文
auto ctx = mAccess->getCallingContext();
/*
Android 系统支持多用户模式,每个用户都有自己的一组应用和数据。Android 使用了复合 UID,
其中高8位部分表示用户 ID,低位部分表示应用程序 ID。
*/
// 应用 uid 大于等于 10000 ,binder 不能添加 ServiceManager
if (multiuser_get_app_id(ctx.uid) >= AID_APP) {
return Status::fromExceptionCode(Status::EX_SECURITY, "App UIDs cannot add services.");
}
// SELinux 安全上下文判断 能否添加 ServiceManager
if (!mAccess->canAdd(ctx, name)) {
return Status::fromExceptionCode(Status::EX_SECURITY, "SELinux denied.");
}
// 判断 binder 对象是否为空
if (binder == nullptr) {
return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, "Null binder.");
}
// 校验 binder 服务的名字
if (!isValidServiceName(name)) {
ALOGE("Invalid service name: %s", name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, "Invalid service name.");
}
// 检查给定名称是否在 VINTF 中声明
/*
VINTF(Vendor Interface)声明是 Android 系统中的一种机制,用于描述硬件抽象层(Hardware Abstraction Layer,HAL)和其他系统组件的要求和依赖关系。
它是 Android Vendor Test Suite(VTS)的一部分,旨在确保 Android 设备的兼容性和稳定性
*/
#ifndef VENDORSERVICEMANAGER
if (!meetsDeclarationRequirements(binder, name)) {
// already logged
return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, "VINTF declaration error.");
}
#endif // !VENDORSERVICEMANAGER
// 若没有设置 dump 优先级 ,打印警告
if ((dumpPriority & DUMP_FLAG_PRIORITY_ALL) == 0) {
ALOGW("Dump flag priority is not set when adding %s", name.c_str());
}
// ServiceManager 是一个 BBinder 所以 remoteBinder() 为 空
// 如果是一个 BpBinder ,添加 linkToDeath 不成功返回失败
if (binder->remoteBinder() != nullptr &&
binder->linkToDeath(sp<ServiceManager>::fromExisting(this)) != OK) {
ALOGE("Could not linkToDeath when adding %s", name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, "Couldn't linkToDeath.");
}
// mNameToService 是一个 Map,类型为 std::map<std::string, Service>;
// 遍历 Map 查找名字为 name 对于的 Service
auto it = mNameToService.find(name);
// 如果找到了,说明重复添加了,打印一些警告日志
if (it != mNameToService.end()) {
const Service& existing = it->second;
// We could do better than this because if the other service dies, it
// may not have an entry here. However, this case is unlikely. We are
// only trying to detect when two different services are accidentally installed.
if (existing.ctx.uid != ctx.uid) {
ALOGW("Service '%s' originally registered from UID %u but it is now being registered "
"from UID %u. Multiple instances installed?",
name.c_str(), existing.ctx.uid, ctx.uid);
}
if (existing.ctx.sid != ctx.sid) {
ALOGW("Service '%s' originally registered from SID %s but it is now being registered "
"from SID %s. Multiple instances installed?",
name.c_str(), existing.ctx.sid.c_str(), ctx.sid.c_str());
}
ALOGI("Service '%s' originally registered from PID %d but it is being registered again "
"from PID %d. Bad state? Late death notification? Multiple instances installed?",
name.c_str(), existing.ctx.debugPid, ctx.debugPid);
}
// 如果存在,直接覆盖,存储最新的
mNameToService[name] = Service{
.binder = binder,
.allowIsolated = allowIsolated,
.dumpPriority = dumpPriority,
.ctx = ctx,
};
// mNameToRegistrationCallback 也是一个Map,类型为 std::map<std::string, std::vector<sp<IServiceCallback>>>;
// 查找name 对应的 std::vector<sp<IServiceCallback> 列表
if (auto it = mNameToRegistrationCallback.find(name); it != mNameToRegistrationCallback.end()) {
// See also getService - handles case where client never gets the service,
// we want the service to quit.
mNameToService[name].guaranteeClient = true;
// 通知已注册的服务状态发生变化监听器
CHECK(handleServiceClientCallback(2 /* sm + transaction */, name, false));
mNameToService[name].guaranteeClient = true;
// 依次通知这些监听器,name 对应该的 binder已添加注册
for (const sp<IServiceCallback>& cb : it->second) {
// permission checked in registerForNotifications
cb->onRegistration(name, binder);
}
}
return Status::ok();
}
// 服务的名字 大于 0 小于 127 个字符 ,只能 0-9,a-z,A-Z ,_-./
bool isValidServiceName(const std::string& name) {
if (name.size() == 0) return false;
if (name.size() > 127) return false;
for (char c : name) {
if (c == '_' || c == '-' || c == '.' || c == '/') continue;
if (c >= 'a' && c <= 'z') continue;
if (c >= 'A' && c <= 'Z') continue;
if (c >= '0' && c <= '9') continue;
return false;
}
return true;
}
struct Service {
sp<IBinder> binder; // not null
bool allowIsolated;
int32_t dumpPriority;
bool hasClients = false; // notifications sent on true -> false.
bool guaranteeClient = false; // forces the client check to true
Access::CallingContext ctx; // process that originally registers this
// the number of clients of the service, including servicemanager itself
ssize_t getNodeStrongRefCount();
~Service();
};
向 binder 内核注册成为 binder 上下文管理者
c
bool ProcessState::becomeContextManager()
{
AutoMutex _l(mLock);
// 创建 flat_binder_object 对象
flat_binder_object obj {
.flags = FLAT_BINDER_FLAG_TXN_SECURITY_CTX,
};
// ioctl 系统调用
int result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR_EXT, &obj);
// fallback to original method
if (result != 0) {
android_errorWriteLog(0x534e4554, "121035042");
int unused = 0;
result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR, &unused);
}
if (result == -1) {
ALOGE("Binder ioctl to become context manager failed: %s\n", strerror(errno));
}
return result == 0;
}
ioctl 系统调用后 binder 内核会调用 binder_ioctl_set_ctx_mgr 方法
设置 binder 上下文管理者 最主要就是创建 binder_node 对象 node->ptr 值为 0 。
c
static int binder_ioctl_set_ctx_mgr(struct file *filp,
struct flat_binder_object *fbo)
{
int ret = 0;
// 获取 binder_proc 对象
struct binder_proc *proc = filp->private_data;
// 获取 binder_context 对象
struct binder_context *context = proc->context;
struct binder_node *new_node;
// 获取有效 uid
kuid_t curr_euid = current_euid();
mutex_lock(&context->context_mgr_node_lock);
// 如果之前已经设置过 binder_context_mgr_node 之后就报错
if (context->binder_context_mgr_node) {
pr_err("BINDER_SET_CONTEXT_MGR already set\n");
ret = -EBUSY;
goto out;
}
// SELinux 安全校验
ret = security_binder_set_context_mgr(proc->cred);
if (ret < 0)
goto out;
// binderfs 文件系统初始化的时候 已设置为 INVALID_UID 。uid_valid() 为false
if (uid_valid(context->binder_context_mgr_uid)) {
if (!uid_eq(context->binder_context_mgr_uid, curr_euid)) {
pr_err("BINDER_SET_CONTEXT_MGR bad uid %d != %d\n",
from_kuid(&init_user_ns, curr_euid),
from_kuid(&init_user_ns,
context->binder_context_mgr_uid));
ret = -EPERM;
goto out;
}
} else {
// 赋值为 euid
context->binder_context_mgr_uid = curr_euid;
}
// 创建一个 binder_node 节点
new_node = binder_new_node(proc, fbo);
if (!new_node) {
ret = -ENOMEM;
goto out;
}
binder_node_lock(new_node);
new_node->local_weak_refs++;
new_node->local_strong_refs++;
new_node->has_strong_ref = 1;
new_node->has_weak_ref = 1;
// 把 new_node 节点存储到 context->binder_context_mgr_node
// 这个节点就是就是代表 用户空间的 ServiceManager
context->binder_context_mgr_node = new_node;
binder_node_unlock(new_node);
binder_put_node(new_node);
out:
mutex_unlock(&context->context_mgr_node_lock);
return ret;
}
static struct binder_node *binder_new_node(struct binder_proc *proc,
struct flat_binder_object *fp)
{
struct binder_node *node;
// 创建了 binder_node 对象
struct binder_node *new_node = kzalloc(sizeof(*node), GFP_KERNEL);
if (!new_node)
return NULL;
binder_inner_proc_lock(proc);
// 初始化 binder_node 节点
node = binder_init_node_ilocked(proc, new_node, fp);
binder_inner_proc_unlock(proc);
if (node != new_node)
/*
* The node was already added by another thread
*/
kfree(new_node);
return node;
}
static struct binder_node *binder_init_node_ilocked(
struct binder_proc *proc,
struct binder_node *new_node,
struct flat_binder_object *fp)
{
// binder_proc 存储 binder_node 节点的红黑树
struct rb_node **p = &proc->nodes.rb_node;
struct rb_node *parent = NULL;
struct binder_node *node;
// becomeContextManager() 函数设置的 flat_binder_object 对象
// 只设置了 flags ,所以 fp->binder 默认值为 0
binder_uintptr_t ptr = fp ? fp->binder : 0;
binder_uintptr_t cookie = fp ? fp->cookie : 0;
__u32 flags = fp ? fp->flags : 0;
s8 priority;
assert_spin_locked(&proc->inner_lock);
while (*p) {
parent = *p;
node = rb_entry(parent, struct binder_node, rb_node);
// 根据 binder 指针排序
if (ptr < node->ptr)
p = &(*p)->rb_left;
else if (ptr > node->ptr)
p = &(*p)->rb_right;
else {
// 如果红黑树中,指针匹配上,说明已经添加过了 ,放弃初始化,并返回 node
binder_inc_node_tmpref_ilocked(node); // node->tmp_refs++;
return node;
}
}
node = new_node;
// BINDER_STAT_NODE 状态 +1
binder_stats_created(BINDER_STAT_NODE);
node->tmp_refs++;
// new_node 插入 proc->nodes 红黑树
rb_link_node(&node->rb_node, parent, p);
rb_insert_color(&node->rb_node, &proc->nodes);
// 记录 debug_id
node->debug_id = atomic_inc_return(&binder_last_id);
node->proc = proc;
// 存储 ptr
node->ptr = ptr;
node->cookie = cookie;
// 设置 work.type
node->work.type = BINDER_WORK_NODE;
// 优先级
priority = flags & FLAT_BINDER_FLAG_PRIORITY_MASK;
node->sched_policy = (flags & FLAT_BINDER_FLAG_SCHED_POLICY_MASK) >>
FLAT_BINDER_FLAG_SCHED_POLICY_SHIFT;
node->min_priority = to_kernel_prio(node->sched_policy, priority);
node->accept_fds = !!(flags & FLAT_BINDER_FLAG_ACCEPTS_FDS);
node->inherit_rt = !!(flags & FLAT_BINDER_FLAG_INHERIT_RT);
node->txn_security_ctx = !!(flags & FLAT_BINDER_FLAG_TXN_SECURITY_CTX);
// 初始化 node->lock 自旋锁
spin_lock_init(&node->lock);
// 初始化 node->work.entry 链表
INIT_LIST_HEAD(&node->work.entry);
// 初始化 node->async_todo 链表
INIT_LIST_HEAD(&node->async_todo);
binder_debug(BINDER_DEBUG_INTERNAL_REFS,
"%d:%d node %d u%016llx c%016llx created\n",
proc->pid, current->pid, node->debug_id,
(u64)node->ptr, (u64)node->cookie);
return node;
}
static void binder_put_node(struct binder_node *node)
{
binder_dec_node_tmpref(node);
}
// binder_node 删除临时索引节点
static void binder_dec_node_tmpref(struct binder_node *node)
{
bool free_node;
binder_node_inner_lock(node);
if (!node->proc)
spin_lock(&binder_dead_nodes_lock);
else
__acquire(&binder_dead_nodes_lock);
// node->tmp_refs 索引减 1
node->tmp_refs--;
BUG_ON(node->tmp_refs < 0);
if (!node->proc)
spin_unlock(&binder_dead_nodes_lock);
else
__release(&binder_dead_nodes_lock);
/*
调用 binder_dec_node() 以检查是否所有引用计数均为 0 并且需要清理。
使用 strong=0 和 internal=1 进行调用会导致 binder_dec_node() 中没有释放实际引用
*/
free_node = binder_dec_node_nilocked(node, 0, 1);
binder_node_inner_unlock(node);
// 返回 false 不释放
if (free_node)
binder_free_node(node);
}
static bool binder_dec_node_nilocked(struct binder_node *node,
int strong, int internal)
{
struct binder_proc *proc = node->proc;
assert_spin_locked(&node->lock);
if (proc)
assert_spin_locked(&proc->inner_lock);
// strong = 0
if (strong) {
if (internal)
node->internal_strong_refs--;
else
node->local_strong_refs--;
if (node->local_strong_refs || node->internal_strong_refs)
return false;
} else {
if (!internal)
node->local_weak_refs--;
// internal = 1 ,node->local_weak_refs 不为 0 ,返回 false
if (node->local_weak_refs || node->tmp_refs ||
!hlist_empty(&node->refs))
return false;
}
if (proc && (node->has_strong_ref || node->has_weak_ref)) {
if (list_empty(&node->work.entry)) {
binder_enqueue_work_ilocked(&node->work, &proc->todo);
binder_wakeup_proc_ilocked(proc);
}
} else {
if (hlist_empty(&node->refs) && !node->local_strong_refs &&
!node->local_weak_refs && !node->tmp_refs) {
if (proc) {
binder_dequeue_work_ilocked(&node->work);
rb_erase(&node->rb_node, &proc->nodes);
binder_debug(BINDER_DEBUG_INTERNAL_REFS,
"refless node %d deleted\n",
node->debug_id);
} else {
BUG_ON(!list_empty(&node->work.entry));
spin_lock(&binder_dead_nodes_lock);
/*
* tmp_refs could have changed so
* check it again
*/
if (node->tmp_refs) {
spin_unlock(&binder_dead_nodes_lock);
return false;
}
hlist_del(&node->dead_node);
spin_unlock(&binder_dead_nodes_lock);
binder_debug(BINDER_DEBUG_INTERNAL_REFS,
"dead node %d deleted\n",
node->debug_id);
}
return true;
}
}
return false;
}
开启 Looper 循环
关于 Looper 机制请查看 Android Handler 线程消息机制
c
class BinderCallback : public LooperCallback {
public:
static sp<BinderCallback> setupTo(const sp<Looper>& looper) {
// 创建 BinderCallback 对象
sp<BinderCallback> cb = sp<BinderCallback>::make();
int binder_fd = -1;
IPCThreadState::self()->setupPolling(&binder_fd);
LOG_ALWAYS_FATAL_IF(binder_fd < 0, "Failed to setupPolling: %d", binder_fd);
// 添加文件描述符监听 可读事件
int ret = looper->addFd(binder_fd,
Looper::POLL_CALLBACK,
Looper::EVENT_INPUT,
cb,
nullptr /*data*/);
LOG_ALWAYS_FATAL_IF(ret != 1, "Failed to add binder FD to Looper");
return cb;
}
// 当 /dev/binder 文件有可读事件时会回调
int handleEvent(int /* fd */, int /* events */, void* /* data */) override {
IPCThreadState::self()->handlePolledCommands();
return 1; // Continue receiving callbacks.
}
};
status_t IPCThreadState::setupPolling(int* fd)
{
// initWithDriver 已打开设备文件, 文件描述符不会小于 0
if (mProcess->mDriverFD < 0) {
return -EBADF;
}
//Parcel 对象mOut 写入一个 int32 数据 BC_ENTER_LOOPER
mOut.writeInt32(BC_ENTER_LOOPER);
// 把数据写入 binder 内核
flushCommands();
// 把 fd 赋值为 binder 设备文件描述符
*fd = mProcess->mDriverFD;
pthread_mutex_lock(&mProcess->mThreadCountLock);
// 当前 binder 线程数 mCurrentThreads +1
mProcess->mCurrentThreads++;
pthread_mutex_unlock(&mProcess->mThreadCountLock);
return 0;
}
void IPCThreadState::flushCommands()
{
if (mProcess->mDriverFD < 0)
return;
// 向 binder 内核写入数据 ,不需要接收 binder 内核返回数据 binder
talkWithDriver(false);
// The flush could have caused post-write refcount decrements to have
// been executed, which in turn could result in BC_RELEASE/BC_DECREFS
// being queued in mOut. So flush again, if we need to.
// 如果数据没有写入完成,再次写入
if (mOut.dataSize() > 0) {
talkWithDriver(false);
}
// 如果数据还是没有写入 ,打印警告日志
if (mOut.dataSize() > 0) {
ALOGW("mOut.dataSize() > 0 after flushCommands()");
}
}
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
if (mProcess->mDriverFD < 0) {
return -EBADF;
}
// 声明 binder_write_read 对象
binder_write_read bwr;
//Parcel对象 mIn 没有数据,所以 needRead 为false
const bool needRead = mIn.dataPosition() >= mIn.dataSize();
// doReceive 为false ,所以 outAvail 为 32
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
// 初始化 binder_write_read 对象
bwr.write_size = outAvail;
bwr.write_buffer = (uintptr_t)mOut.data();
// This is what we'll read.
if (doReceive && needRead) {
bwr.read_size = mIn.dataCapacity();
bwr.read_buffer = (uintptr_t)mIn.data();
} else {
// 不需要读取内核返回的数据,所以设置为 0
bwr.read_size = 0;
bwr.read_buffer = 0;
}
// 打印日志
IF_LOG_COMMANDS() {
std::ostringstream logStream;
if (outAvail != 0) {
logStream << "Sending commands to driver: ";
const void* cmds = (const void*)bwr.write_buffer;
const void* end = ((const uint8_t*)cmds) + bwr.write_size;
logStream << "\t" << HexDump(cmds, bwr.write_size) << "\n";
while (cmds < end) cmds = printCommand(logStream, cmds);
}
logStream << "Size of receive buffer: " << bwr.read_size << ", needRead: " << needRead
<< ", doReceive: " << doReceive << "\n";
std::string message = logStream.str();
ALOGI("%s", message.c_str());
}
// 校验一下 binder_write_read 对象 ,如果写入数据,读取数据都为 0 ,没必要和binder 内核通信 ,直接返回 。
if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
// 已写入和已读取数据初始化为 0
bwr.write_consumed = 0;
bwr.read_consumed = 0;
status_t err;
do {
// 打印日志
IF_LOG_COMMANDS() {
std::ostringstream logStream;
logStream << "About to read/write, write size = " << mOut.dataSize() << "\n";
std::string message = logStream.str();
ALOGI("%s", message.c_str());
}
#if defined(__ANDROID__)
// iotcl 系统调用 把 binder_write_read 对象 传递到 binder 内核层
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() {
std::ostringstream logStream;
logStream << "Finished read/write, write size = " << mOut.dataSize() << "\n";
std::string message = logStream.str();
ALOGI("%s", message.c_str());
}
} while (err == -EINTR); // 如果系统调用被中断 就再次调用 ,没有中断会跳出循环
// 打印日志
IF_LOG_COMMANDS() {
std::ostringstream logStream;
logStream << "Our err: " << (void*)(intptr_t)err
<< ", write consumed: " << bwr.write_consumed << " (of " << mOut.dataSize()
<< "), read consumed: " << bwr.read_consumed << "\n";
std::string message = logStream.str();
ALOGI("%s", message.c_str());
}
// 如果 ioctl 系统调用成功
if (err >= NO_ERROR) {
// 已写入的数据大于 0
if (bwr.write_consumed > 0) {
// 如果没有写入完全,打印日志
if (bwr.write_consumed < mOut.dataSize())
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 数据设置为 0
mOut.setDataSize(0);
processPostWriteDerefs();
}
}
if (bwr.read_consumed > 0) {
mIn.setDataSize(bwr.read_consumed);
mIn.setDataPosition(0);
}
// 打印日志
IF_LOG_COMMANDS() {
std::ostringstream logStream;
logStream << "Remaining data size: " << mOut.dataSize() << "\n";
logStream << "Received commands from driver: ";
const void* cmds = mIn.data();
const void* end = mIn.data() + mIn.dataSize();
logStream << "\t" << HexDump(cmds, mIn.dataSize()) << "\n";
while (cmds < end) cmds = printReturnCommand(logStream, cmds);
std::string message = logStream.str();
ALOGI("%s", message.c_str());
}
return NO_ERROR;
}
// 打印日志
ALOGE_IF(mProcess->mDriverFD >= 0,
"Driver returned error (%s). This is a bug in either libbinder or the driver. This "
"thread's connection to %s will no longer work.",
statusToString(err).c_str(), mProcess->mDriverName.c_str());
return err;
}
调用到内核空间
c
// iotcl 系统调用 BINDER_WRITE_READ
static int binder_ioctl_write_read(struct file *filp,
unsigned int cmd, unsigned long arg,
struct binder_thread *thread)
{
int ret = 0;
struct binder_proc *proc = filp->private_data;
unsigned int size = _IOC_SIZE(cmd);
void __user *ubuf = (void __user *)arg;
struct binder_write_read bwr;
// 校验 binder_write_read 大小
if (size != sizeof(struct binder_write_read)) {
ret = -EINVAL;
goto out;
}
// 从用户空间拷贝到内核空间
if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
ret = -EFAULT;
goto out;
}
binder_debug(BINDER_DEBUG_READ_WRITE,
"%d:%d write %lld at %016llx, read %lld at %016llx\n",
proc->pid, thread->pid,
(u64)bwr.write_size, (u64)bwr.write_buffer,
(u64)bwr.read_size, (u64)bwr.read_buffer);
// bwr.write_size 为 32 只写入了 BC_ENTER_LOOPER
if (bwr.write_size > 0) {
ret = binder_thread_write(proc, thread,
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 out;
}
}
// bwr.read_size =0
if (bwr.read_size > 0) {
ret = binder_thread_read(proc, thread, bwr.read_buffer,
bwr.read_size,
&bwr.read_consumed,
filp->f_flags & O_NONBLOCK);
trace_binder_read_done(ret);
binder_inner_proc_lock(proc);
if (!binder_worklist_empty_ilocked(&proc->todo))
binder_wakeup_proc_ilocked(proc);
binder_inner_proc_unlock(proc);
trace_android_vh_binder_read_done(proc, thread);
if (ret < 0) {
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
goto out;
}
}
binder_debug(BINDER_DEBUG_READ_WRITE,
"%d:%d wrote %lld of %lld, read return %lld of %lld\n",
proc->pid, thread->pid,
(u64)bwr.write_consumed, (u64)bwr.write_size,
(u64)bwr.read_consumed, (u64)bwr.read_size);
// bwr 数据拷贝到用户空间
if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
ret = -EFAULT;
goto out;
}
out:
return ret;
}
// 处理用户空间写入的数据 ,只写入了 BC_ENTER_LOOPER
static int binder_thread_write(struct binder_proc *proc,
struct binder_thread *thread,
binder_uintptr_t binder_buffer, size_t size,
binder_size_t *consumed)
{
uint32_t cmd;
struct binder_context *context = proc->context;
void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
void __user *ptr = buffer + *consumed;
void __user *end = buffer + size;
// while 循环 ,读取写入的数据
while (ptr < end && thread->return_error.cmd == BR_OK) {
int ret;
// 获取写入的数据 cmd
if (get_user(cmd, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
trace_binder_command(cmd);
if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.bc)) {
atomic_inc(&binder_stats.bc[_IOC_NR(cmd)]);
atomic_inc(&proc->stats.bc[_IOC_NR(cmd)]);
atomic_inc(&thread->stats.bc[_IOC_NR(cmd)]);
}
// cmd 为 BC_ENTER_LOOPER
switch (cmd) {
// .... 省略其他分支
case BC_ENTER_LOOPER:
binder_debug(BINDER_DEBUG_THREADS,
"%d:%d BC_ENTER_LOOPER\n",
proc->pid, thread->pid);
if (thread->looper & BINDER_LOOPER_STATE_REGISTERED) {
thread->looper |= BINDER_LOOPER_STATE_INVALID;
binder_user_error("%d:%d ERROR: BC_ENTER_LOOPER called after BC_REGISTER_LOOPER\n",
proc->pid, thread->pid);
}
// 把当前线程 looper 设置为 BINDER_LOOPER_STATE_ENTERED
thread->looper |= BINDER_LOOPER_STATE_ENTERED;
break;
// .... 省略其他分支
default:
pr_err("%d:%d unknown command %d\n",
proc->pid, thread->pid, cmd);
return -EINVAL;
}
// 更新已写入完成的数据的大小
*consumed = ptr - buffer;
}
return 0;
}
- Looper 监听文件描述符 ,Looper 用到 epoll 机制进行 ,使用 epoll 的文件描述符,需要实现 file_operations 对象的 poll 函数指针 。当
looper->pollAll(-1);
会调用 epoll_wait () 系统调用,最后会调用到 file_operations 对象的 poll 函数指针 ,进行等待 binder 设备文件有可读事件
请注意我们普通的文件描述符是无法使用的 ,为此我们的 binder 设备文件特此实现了 poll 函数指针 函数如下
c
static __poll_t binder_poll(struct file *filp,
struct poll_table_struct *wait)
{
struct binder_proc *proc = filp->private_data;
struct binder_thread *thread = NULL;
bool wait_for_proc_work;
// 获取当前线程的 binder_thread 对象
thread = binder_get_thread(proc);
if (!thread)
return EPOLLERR;
binder_inner_proc_lock(thread->proc);
// binder_thread 对象looper 设置为 BINDER_LOOPER_STATE_POLL 状态
thread->looper |= BINDER_LOOPER_STATE_POLL;
// binder_available_for_proc_work_ilocked() 返回 true
wait_for_proc_work = binder_available_for_proc_work_ilocked(thread);
binder_inner_proc_unlock(thread->proc);
// 将当前线程添加到 thread->wait 队列中。这样,当 thread 有工作可做时,内核会唤醒等待的线程。
poll_wait(filp, &thread->wait, wait);
// 如果有工作可做,会返回 epoll 可读事件
if (binder_has_work(thread, wait_for_proc_work))
return EPOLLIN;
return 0;
}
static bool binder_available_for_proc_work_ilocked(struct binder_thread *thread)
{ // servicemanager 还没有其他进程发送请求,所以 thread->transaction_stack 为空 ,thread->todo 也为 空
// 调用 IPCThreadState::setupPolling()函数时,已把 thread->looper 设置为 BINDER_LOOPER_STATE_ENTERED
return !thread->transaction_stack &&
binder_worklist_empty_ilocked(&thread->todo) &&
(thread->looper & (BINDER_LOOPER_STATE_ENTERED |
BINDER_LOOPER_STATE_REGISTERED));
}
当 binder 设备文件有可读事件时内核会向 servicemanager 发出通知调用 handleEvent() 方法,handleEvent() 方法调用 IPCThreadState::handlePolledCommands 处理内核可读数据 ,后面我会写文章详细讲解的 。
c
// 处理内核发出来的消息
status_t IPCThreadState::handlePolledCommands()
{
status_t result;
do {
result = getAndExecuteCommand();
} while (mIn.dataPosition() < mIn.dataSize());
processPendingDerefs();
flushCommands();
return result;
}
servicemanager 还注册了一个定时器 ,定时向已注册的客户端监听器发送通知
c
// LooperCallback for IClientCallback
class ClientCallbackCallback : public LooperCallback {
public:
static sp<ClientCallbackCallback> setupTo(const sp<Looper>& looper, const sp<ServiceManager>& manager) {
// 创建 ClientCallbackCallback 对象
sp<ClientCallbackCallback> cb = sp<ClientCallbackCallback>::make(manager);
// 创建时间文件描述符
int fdTimer = timerfd_create(CLOCK_MONOTONIC, 0 /*flags*/);
LOG_ALWAYS_FATAL_IF(fdTimer < 0, "Failed to timerfd_create: fd: %d err: %d", fdTimer, errno);
// 设置定时器:初始到期时间为5秒,之后每5秒触发一次
itimerspec timespec {
.it_interval = {
.tv_sec = 5,
.tv_nsec = 0,
},
.it_value = {
.tv_sec = 5,
.tv_nsec = 0,
},
};
// 设置时间描述符 定时器
int timeRes = timerfd_settime(fdTimer, 0 /*flags*/, ×pec, nullptr);
LOG_ALWAYS_FATAL_IF(timeRes < 0, "Failed to timerfd_settime: res: %d err: %d", timeRes, errno);
// looper 添加时间文件描述符可读事件
int addRes = looper->addFd(fdTimer,
Looper::POLL_CALLBACK,
Looper::EVENT_INPUT,
cb,
nullptr);
LOG_ALWAYS_FATAL_IF(addRes != 1, "Failed to add client callback FD to Looper");
return cb;
}
// 每隔 5 秒都会 调用 handleEvent 方法
int handleEvent(int fd, int /*events*/, void* /*data*/) override {
uint64_t expirations;
// 读取时间文件描述符的数据 ,expirations 自上次读取以来定时器到期的次数
int ret = read(fd, &expirations, sizeof(expirations));
if (ret != sizeof(expirations)) {
ALOGE("Read failed to callback FD: ret: %d err: %d", ret, errno);
}
// 给监听器发送通知
mManager->handleClientCallbacks();
return 1; // Continue receiving callbacks.
}
private:
friend sp<ClientCallbackCallback>;
ClientCallbackCallback(const sp<ServiceManager>& manager) : mManager(manager) {}
sp<ServiceManager> mManager;
};