从0到1学Binder-ServiceManager详解(1)

646 阅读15分钟

1 前言

思君如满月,夜夜减清辉。

欢迎关注微信公众号“ZZH的Android”,一起探索Android系统源码,还能加入微信交流群与众多大佬相互切磋。

1.1 环境

1.2 内容概要

之前我们讲Binder驱动初始化的时候看到会初始化三个binder驱动设备dev/binder,dev/hwbinder,dev/vnbinder,

/dev/binder是system分区的进程间通过binder通信的binder设备;

/dev/hwbinder是system分区进程和vendor分区进程间通过binder通信的binder设备;

/dev/vnbinder是vendor分区的进程间通过binder通信的binder设备;

其中每个binder设备都有一个servicemanager进程与之对应,如下:

今天我们主要开始讲与/dev/binder驱动对应的servicemanager进程。本章主要包含如下图中绿色部分内容:

2 servicemanager进程启动

servicemanager进程由init进程启动,在init.rc文件里进行配置启动参数。如下:

// android-14.0.0_r17/frameworks/native/cmds/servicemanager/servicemanager.rc
service servicemanager /system/bin/servicemanager
    class core animation
    user system
    group system readproc
    critical
    file /dev/kmsg w
    onrestart setprop servicemanager.ready false
    // 当servicemanager重启时,如下服务都重启
    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
    task_profiles ServiceCapacityLow
    // 关机时确保其最后退出
    shutdown critical

可以看到其可执行文件为/system/bin/servicemanager,Android.bp配置如下:

// android-14.0.0_r17/frameworks/native/cmds/servicemanager/Android.bp
cc_binary {
    name: "servicemanager",
    defaults: ["servicemanager_defaults"],
    init_rc: ["servicemanager.rc"],
    srcs: ["main.cpp"],
    bootstrap: true,
}

可以看到其入口函数为main.cpp

// android-14.0.0_r17/frameworks/native/cmds/servicemanager/main.cpp
int main(int argc, char** argv) {
    android::base::InitLogging(argv, android::base::KernelLogger);

    if (argc > 2) {
        LOG(FATAL) << "usage: " << argv[0] << " [binder driver]";
    }

    // 可以看到会检查输入参数,如果参数为空,则driver为"/dev/binder",
    // 这个地方vndservicemanagwer会用到,vndservicemanager
    // 启动时会传入参数 “/dev/vndbinder”
    const char* driver = argc == 2 ? argv[1] : "/dev/binder";

    LOG(INFO) << "Starting sm instance on " << driver;

    // 下面详细介绍ProcessState,每个进程只会有一个ProcessState对象。
    sp<ProcessState> ps = ProcessState::initWithDriver(driver);
    ps->setThreadPoolMaxThreadCount(0);
    ps->setCallRestriction(ProcessState::CallRestriction::FATAL_IF_NOT_ONEWAY);

    IPCThreadState::self()->disableBackgroundScheduling(true);

    sp<ServiceManager> manager = sp<ServiceManager>::make(std::make_unique<Access>());
    if (!manager->addService("manager", manager, false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()) {
        LOG(ERROR) << "Could not self register servicemanager";
    }

    IPCThreadState::self()->setTheContextObject(manager);
    ps->becomeContextManager();

    sp<Looper> looper = Looper::prepare(false /*allowNonCallbacks*/);

    BinderCallback::setupTo(looper);
    ClientCallbackCallback::setupTo(looper, manager);

#ifndef VENDORSERVICEMANAGER
    if (!SetProperty("servicemanager.ready""true")) {
        LOG(ERROR) << "Failed to set servicemanager ready property";
    }
#endif

    while(true) {
        looper->pollAll(-1);
    }

    // should not be reached
    return EXIT_FAILURE;
}

接下来我们详细解析main.cpp的实现。

2.1 ProcessState

aosp源码里有两个ProcessState类,一个给使用/dev/binder和/dev/vndbinder的进程使用,另一个给使用/dev/hwbinder的进程使用。这里先知道这个,后面将/dev/hwbinder时再详叙述。

ProcessState::initWithDriver

// android-14.0.0_r17/frameworks/native/libs/binder/ProcessState.cpp
sp<ProcessState> ProcessState::initWithDriver(const char* driver)
{
    return init(driver, true /*requireDefault*/);
}

// 主要看init函数,这里参数 driver=/dev/binder, requireDefault=true
sp<ProcessState> ProcessState::init(const char *driver, bool requireDefault)
{
    ...
    // 对于servicemanager来说,driver肯定不为空
    // 如果driver为空的话其实就是获取当前实例。如果当前实例没有初始化过则返回空。
    if (driver == nullptr) {
        std::lock_guard<std::mutex> l(gProcessMutex);
        if (gProcess) {
            verifyNotForked(gProcess->mForked);
        }
        return gProcess;
    }

    // 这里使用C++ 11新特性,std::once_flag和std::call_once使得
    // 在多线程环境下如下函数只会执行一次。这样就确保了一个进程当中只有
    // 一个ProcessState对象,所有线程共享一个ProcessState对象。
    [[clang::no_destroy]] static std::once_flag gProcessOnce;
    std::call_once(gProcessOnce, [&](){
        // 如下匿名函数只会执行一次
        // 检查driver文件是否可读,如果不可读则重新赋值为/dev/binder
        if (access(driver, R_OK) == -1) {
            ALOGE("Binder driver %s is unavailable. Using /dev/binder instead.", driver);
            driver = "/dev/binder";
        }

        // 如果是/dev/vndbinder文件且isVndservicemanagerEnabled返回false的情况
        // isVndservicemanagerEnabled的实现为
        // return access("/vendor/bin/vndservicemanager", R_OK) == 0;
        if (0 == strcmp(driver, "/dev/vndbinder") && !isVndservicemanagerEnabled()) {
            ALOGE("vndservicemanager is not started on this device, you can save resources/threads "
                  "by not initializing ProcessState with /dev/vndbinder.");
        }

        // 这里定义了fork进程的三个回调函数,目的是确保gProcess对象在父进程和子进程中状态
        // 的一致性。我们下面会详细解释。
        // we must install these before instantiating the gProcess object,
        // otherwise this would race with creating it, and there could be the
        // possibility of an invalid gProcess object forked by another thread
        // before these are installed
        int ret = pthread_atfork(ProcessState::onFork, ProcessState::parentPostFork,
                                 ProcessState::childPostFork);
        LOG_ALWAYS_FATAL_IF(ret != 0"pthread_atfork error %s"strerror(ret));

        // 创建gProcess对象,这里执行的是ProcessState的构造函数。
        std::lock_guard<std::mutex> l(gProcessMutex);
        gProcess = sp<ProcessState>::make(driver);
    });

    if (requireDefault) {
        // Detect if we are trying to initialize with a different driver, and
        // consider that an error. ProcessState will only be initialized once above.
        // 检查gProcess的driverName跟传入的是否一致。
        LOG_ALWAYS_FATAL_IF(gProcess->getDriverName() != driver,
                            "ProcessState was already initialized with %s,"
                            " can't initialize with %s.",
                            gProcess->getDriverName().c_str(), driver);
    }
    
    /* 凡是有这句代码的表示在子进程中执行到这里时程序会终止。
     * 在子进程fork后,子进程的gProcess->mForked会标记为true。
     *下面会详细介绍。
     */
    verifyNotForked(gProcess->mForked);
    return gProcess;
}

在ProcessState对象gProcess对象创建之前,先定义了fork相关的回调函数。

int ret = pthread_atfork(ProcessState::onFork, ProcessState::parentPostFork,
                         ProcessState::childPostFork);
LOG_ALWAYS_FATAL_IF(ret != 0, "pthread_atfork error %s", strerror(ret));

这三个回调函数定义如下:

onFork

在进程执行fork操作前调用。其作用是确保在fork操作进行时,没有其他线程在访问或修改全局的进程状态对象gProcess。只有执行fork操作的线程可以访问或修改gProcess,这样可以确保fork后子程序的状态跟当前执行fork操作的线程状态一致。

void ProcessState::onFork() {
    // make sure another thread isn't currently retrieving ProcessState
    gProcessMutex.lock();
}

parentPostFork

在fork操作后由父进程调用。其作用是解锁全局互斥量gProcessMutex,使其他线程可以继续访问或修改全局进程状态对象。

void ProcessState::parentPostFork() {
    gProcessMutex.unlock();
}

childPostFork

函数在fork操作后由子进程调用。其作用是处理子进程特有的状态,包括关闭子进程中继承的文件描述符和标记进程状态。要注意这里的gProcess是子进程的,是拷贝的父进程的,同时与父进程的gProcess是分离的,所以这里只是修改了子进程的状态,父进程不受影响。这里以标志gProcess->mForked来表明是否是fork出的子进程。

void ProcessState::childPostFork() {
    // another thread might call fork before gProcess is instantiated, but after
    // the thread handler is installed
    if (gProcess) {
        gProcess->mForked = true;

        // "O_CLOFORK"
        close(gProcess->mDriverFD);
        gProcess->mDriverFD = -1;
    }
    gProcessMutex.unlock();
}

还记得这个函数吗?forked为true,表明在子进程中,所以凡是有如下检查的地方,在fork出的子进程中遇到都会终止程序。LOG_ALWAYS_FATAL_IF在条件为true时会调用abort函数。

static void verifyNotForked(bool forked) {
    LOG_ALWAYS_FATAL_IF(forked, "libbinder ProcessState can not be used after fork");
}

我们目前遇到的执行verifyNotForked的地方有两处,都在ProcessState::init函数中。说明fork的子进程中不能再调用该函数。

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) {
    // 打开/dev/binder文件,得到文件描述符,并且执行一些设置操作。
    base::Result<int> opened = open_driver(driver);

    if (opened.ok()) {
        // mmap 的作用是将 /dev/binder 设备文件的一部分内存映射到调用进程的虚拟地址空间。
        // 具体来说,它将从 /dev/binder 开始的 BINDER_VM_SIZE 大小的内存区域映射到进程
        // 地址空间中的 mVMStart 地址。这种映射使得进程能够直接访问 Binder 驱动的数据区域,
        // 从而高效地进行进程间通信(IPC)。
        // mmap the binder, providing a chunk of virtual address space to receive transactions.
        mVMStart = mmap(nullptr, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE,
                        opened.value(), 0);
        if (mVMStart == MAP_FAILED) {
            close(opened.value());
            // *sigh*
            opened = base::Error()
                    << "Using " << driver << " failed: unable to mmap transaction memory.";
            mDriverName.clear();
        }
    }

#ifdef __ANDROID__
    LOG_ALWAYS_FATAL_IF(!opened.ok(), "Binder driver '%s' could not be opened. Terminating: %s",
                        driver, opened.error().message().c_str());
#endif

    if (opened.ok()) {
        mDriverFD = opened.value();
    }
}

下面看具体实现

open_driver

static base::Result<int> open_driver(const char* driver) {
    // 打开binder驱动设备,得到文件描述符fd,内核里对应函数为binder_open
    int fd = open(driver, O_RDWR | O_CLOEXEC);
    if (fd < 0) {
        return base::ErrnoError() << "Opening '" << driver << "' failed";
    }
    // 下面的ioctl函数,在内核里对应的是binder_ioctl
    // 获取 Binder 驱动的版本号
    int vers = 0;
    status_t result = ioctl(fd, BINDER_VERSION, &vers);
    if (result == -1) {
        close(fd);
        return base::ErrnoError() << "Binder ioctl to obtain version failed";
    }
    
    // 如果 ioctl 调用返回值不为 0 或获取的版本号 vers 不等于
    // 用户空间协议版本 BINDER_CURRENT_PROTOCOL_VERSION,
    // 表示版本不匹配,关闭文件描述符并返回错误。
    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;
    }
    // 设置 Binder 驱动的最大线程数,可以控制系统中用于处理 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));
    }
    // 启用 Binder 驱动的单向(oneway)垃圾检测功能,以防止 Binder 通信中可能的滥用行为。
    /* 
    单向消息(Oneway Message)
        定义:单向消息是一种特殊类型的 IPC(进程间通信)调用。与普通的同步 IPC 调用不同,
              单向消息是异步的,即调用者发出请求后立即返回,而不等待被调用者处理完成。
        使用场景:单向消息通常用于不需要立即返回结果的操作。例如,发送通知或更新状态等。
    单向垃圾(Oneway Spam)
        单向垃圾:单向垃圾指的是大量的、不受控制的单向消息。这些消息可能会被滥用,
                导致系统资源耗尽或性能下降。
        滥用行为:滥用单向消息可能会导致:
            资源耗尽:频繁发送单向消息可能会占用大量的系统资源(如内存、CPU),影响系统的稳定性。
            性能下降:过多的单向消息处理可能会导致系统响应变慢,影响用户体验。
    单向垃圾检测(Oneway Spam Detection)
        单向垃圾检测功能用于监控和限制单向消息的发送,以防止滥用行为。
        通过启用单向垃圾检测,可以确保系统不会因为过多的单向消息而受到影响
    */
    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;
}

我们知道,应用层的open和ioctl操作,在Kernel里是有对应的实现的,所以接下来我们需要看下上面涉及到的几个调用的kernel实现。

binder_open

应用层调用open函数时,kernel会执行binder_open函数。

其主要作用是初始化与该进程相关的 Binder 资源和数据结构,并将其加入到全局管理列表中。

// struct inode 是 Linux 内核中用于表示文件系统中节点(node)的数据结构。
// 每个文件或目录在文件系统中都有一个对应的 inode,它存储了文件的元数据,
// 例如文件大小、所有者、权限和时间戳等信息。struct inode *nodp 是一个
// 指向这种 inode 结构体的指针,表示文件系统中的某个节点。

// struct file 通常指的是一个指向 struct file 结构体的指针。
// 在 Linux 内核中,struct file 结构体用于表示一个打开的文件。
// 每当一个进程打开一个文件时,内核会为这个打开的文件创建一个 struct file 实例,
// 并返回一个文件描述符给用户空间。
static int binder_open(struct inode *nodp, struct file *filp)
{
    // binder_proc_wrap包含一个binder_proc成员和一个自旋锁成员
    // 其意义在于通过添加额外的锁来保护 binder_proc 结构体中的数据,
    // 确保在多线程或多进程环境中对 binder_proc 的访问是线程安全的。
 struct binder_proc_wrap *proc_wrap;
    // binder_proc是 Android Binder 驱动程序中用于记录进程信息的重要数据结构。
    // 它包含了与进程相关的各种信息,包括线程、节点、引用、事务等。
 struct binder_proc *proc, *itr;
    // 该结构体包含了与 Binder 设备节点相关的各种信息
 struct binder_device *binder_dev;
    // 用于描述与 Binder 文件系统(binderfs)挂载点相关的信息
 struct binderfs_info *info;
    // 用于表示 binderfs 文件系统中用于进程特定日志的目录项(dentry)。
    // dentry 是 Linux 内核中的一个基本数据结构,用于表示文件系统中的目录项。
 struct dentry *binder_binderfs_dir_entry_proc = NULL;
 bool existing_pid = false;

    // 输出调试信息,包输出当前进程组组长的PID和当前进程的PID。
    // current是一个函数,返回task_struct结构体
 binder_debug(BINDER_DEBUG_OPEN_CLOSE, "%s: %d:%d\n", __func__,
       current->group_leader->pid, current->pid);

    // 分配 binder_proc_wrap 结构体,并检查分配是否成功。
    // 将 proc 指向分配的 binder_proc 结构体。
 proc_wrap = kzalloc(sizeof(*proc_wrap), GFP_KERNEL);
 if (proc_wrap == NULL)
  return -ENOMEM;
 proc = &proc_wrap->proc;

    // 初始化proc的两个自旋锁。
 spin_lock_init(&proc->inner_lock);
 spin_lock_init(&proc->outer_lock);
    
    // 增加current->group_leader的引用计数,防止其在使用期间被释放
 get_task_struct(current->group_leader);
 proc->tsk = current->group_leader;
    // cred表示与这个打开的文件相关联的凭据(credentials)。
    // 凭据包含了执行文件操作的进程的身份信息,如用户ID(UID)和组ID(GID)。
    // get_cred 会增加 cred 结构体的引用计数,并返回指向该 cred 结构体的指针。
    // 通过增加引用计数,可以确保在使用期间这个 cred 结构体不会被释放。
 proc->cred = get_cred(filp->f_cred);
    // INIT_LIST_HEAD 是一个宏,用于初始化链表头,使其成为一个有效的链表。
    // proc->todo 将用于存储该进程的待处理事务。
 INIT_LIST_HEAD(&proc->todo);
    // init_waitqueue_head 函数用于初始化等待队列头,使其成为一个有效的等待队列。
    // proc->freeze_wait 将用于处理冻结进程的等待事件, 是一个列表结构。
 init_waitqueue_head(&proc->freeze_wait);
    // 对 binder_proc 结构体中的 default_priority 成员进行初始化。
    // 它检查当前进程的调度策略是否受支持,并相应地设置 default_priority 的调度策略和优先级。
 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 stashes devices in i_private */
    // 从文件系统节点或文件指针中获取 Binder 设备信息,并根据设备类型执行不同的初始化操作
 if (is_binderfs_device(nodp)) {
        // 如果使用了binderfs文件系统
  binder_dev = nodp->i_private;
  info = nodp->i_sb->s_fs_info;
        // 这个在创建binder进程调试信息文件时会用到。
  binder_binderfs_dir_entry_proc = info->proc_log_dir;
 } else {
  binder_dev = container_of(filp->private_data,
       struct binder_device, miscdev);
 }
    // 增加引用计数
 refcount_inc(&binder_dev->ref);
 proc->context = &binder_dev->context;
 binder_alloc_init(&proc->alloc);

    // 设置进程 PID 并初始化相关链表
 binder_stats_created(BINDER_STAT_PROC);
 proc->pid = current->group_leader->pid;
 INIT_LIST_HEAD(&proc->delivered_death);
 INIT_LIST_HEAD(&proc->waiting_threads);
    // 记住这个private_data是binder_proc
 filp->private_data = proc;

    // 检查是否已有相同 PID 的进程,这里理解应该为是否之前存在过pid相同的进程。
 mutex_lock(&binder_procs_lock);
 hlist_for_each_entry(itr, &binder_procs, proc_node) {
  if (itr->pid == proc->pid) {
   existing_pid = true;
   break;
  }
 }
    // 将新的proc->proc_node添加到binder_procs列表头
 hlist_add_head(&proc->proc_node, &binder_procs);
 mutex_unlock(&binder_procs_lock);
    // 看到trace,应该是记录 binder_procs 和 binder_procs_lock 的状态
    // 用于调试和性能分析
 trace_android_vh_binder_preset(&binder_procs, &binder_procs_lock);
    // 还记得这个binder_binderfs_dir_entry_proc吗,上一篇讲过。
    // 表示/sys/kernel/debug/binder/proc目录创建成功。
    // 并且之前没有存在过相同Pid的进程,就会创建一个文件。
 if (binder_debugfs_dir_entry_proc && !existing_pid) {
  char strbuf[11];
        // strbuf表示文件名,为proc->pid,也就是以进程号命名。
  snprintf(strbuf, sizeof(strbuf), "%u", proc->pid);
  /*
   * proc debug entries are shared between contexts.
   * Only create for the first PID to avoid debugfs log spamming
   * The printing code will anyway print all contexts for a given
   * PID so this is not a problem.
   */
         //创建文件pid
         // 权限为0444,只读
         // 父目录为/sys/kernel/debug/binder/proc/
         // 文件的数据指针为进程的 PID(通过类型转换)
         // 文件操作结构体为 proc_fops
  proc->debugfs_entry = debugfs_create_file(strbuf, 0444,
   binder_debugfs_dir_entry_proc,
   (void *)(unsigned long)proc->pid,
   &proc_fops);
 }

    // 如果binder使用了binderfs文件系统
 if (binder_binderfs_dir_entry_proc && !existing_pid) {
  char strbuf[11];
  struct dentry *binderfs_entry;

        
  snprintf(strbuf, sizeof(strbuf), "%u", proc->pid);
  /*
   * Similar to debugfs, the process specific log file is shared
   * between contexts. Only create for the first PID.
   * This is ok since same as debugfs, the log file will contain
   * information on all contexts of a given PID.
   */
         // 与前面类似,只是父目录为binder_binderfs_dir_entry_proc
  binderfs_entry = binderfs_create_file(binder_binderfs_dir_entry_proc,
   strbuf, &proc_fops, (void *)(unsigned long)proc->pid);
  if (!IS_ERR(binderfs_entry)) {
            // 记录到proc中
   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_ioctl

用户空间的ioctl调用对应kernel里的binder_ioctl函数。

// *struct file filp:打开/dev/binder的文件指针
// unsigned int cmd:ioctl操作命令。
// unsigned long arg:命令参数
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
    int ret;
    // 这个private_data上面提到过,binder_open时赋值的
    struct binder_proc *proc = filp->private_data;
    struct binder_thread *thread;
    unsigned int size = _IOC_SIZE(cmd);
    // 参数保存到ubuf里
    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信息
    trace_binder_ioctl(cmd, arg);

    ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
    if (ret)
        goto err_unlocked;

    thread = binder_get_thread(proc);
    if (thread == NULL) {
        ret = -ENOMEM;
        goto err;
    }

    ...
}

BINDER_VERSION

case BINDER_VERSION: {
    struct binder_version __user *ver = ubuf;

    if (size != sizeof(struct binder_version)) {
        ret = -EINVAL;
        goto err;
    }
    // 将binder version放到传进来的参数中,
    // 这样用户空间就能获取到了。
    // put_user 是一个内核函数,用于将数据从内核空间复制到用户空间。
    if (put_user(BINDER_CURRENT_PROTOCOL_VERSION,
             &ver->protocol_version)) {
        ret = -EINVAL;
        goto err;
    }
    break;
}

BINDER_SET_MAX_THREADS

case BINDER_SET_MAX_THREADS: {
    int max_threads;
    // 将用户空间的参数复制到max_threads
    // copy_from_user 是一个内核函数,用于将数据从用户空间复制到内核空间。
    if (copy_from_user(&max_threads, ubuf,
               sizeof(max_threads))) {
        ret = -EINVAL;
        goto err;
    }
    
    binder_inner_proc_lock(proc);
    // 赋值给proc->max_threads
    proc->max_threads = max_threads;
    binder_inner_proc_unlock(proc);
    break;
}

BINDER_ENABLE_ONEWAY_SPAM_DETECTION

 case BINDER_ENABLE_ONEWAY_SPAM_DETECTION: {
  uint32_t enable;
  if (copy_from_user(&enable, ubuf, sizeof(enable))) {
   ret = -EFAULT;
   goto err;
  }
  binder_inner_proc_lock(proc);
        // 赋值proc的oneway_spam_detection_enabled
  proc->oneway_spam_detection_enabled = (bool)enable;
  binder_inner_proc_unlock(proc);
  break;
 }

下节内容

下一章将详细讲解binder_mmap函数的实现。