android ServiceManager 介绍

在 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;
}

启动过程可以分成三部分

  1. 打开 /dev/binder 设备文件 ,构建与 binder内核通信渠道
  2. 把自己添加到系统服务中 ,本身是个 binder 服务,自己添加到自身,并通过 ioctl 调用 把自己设置为 binder上下文管理者
  3. 开启 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*/, &timespec, 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;
};
相关推荐
姑苏风2 小时前
《Kotlin实战》-附录
android·开发语言·kotlin
数据猎手小k5 小时前
AndroidLab:一个系统化的Android代理框架,包含操作环境和可复现的基准测试,支持大型语言模型和多模态模型。
android·人工智能·机器学习·语言模型
你的小106 小时前
JavaWeb项目-----博客系统
android
风和先行6 小时前
adb 命令查看设备存储占用情况
android·adb
AaVictory.7 小时前
Android 开发 Java中 list实现 按照时间格式 yyyy-MM-dd HH:mm 顺序
android·java·list
似霰8 小时前
安卓智能指针sp、wp、RefBase浅析
android·c++·binder
大风起兮云飞扬丶8 小时前
Android——网络请求
android
干一行,爱一行8 小时前
android camera data -> surface 显示
android
断墨先生8 小时前
uniapp—android原生插件开发(3Android真机调试)
android·uni-app
无极程序员10 小时前
PHP常量
android·ide·android studio