Android Binder 驱动 - 启动 ServiceManager 进程

先来一张图熟悉下各进程之间的关系

一、ServiceManager 启动

解析 servicemanager.rc

servicemanager 是 Android 系统中最早启动的核心守护进程之一。它的生命周期由 init 进程直接管理。 当 Android 内核启动完毕后,会启动用户空间的第一个进程 init。init 进程会去解析一系列的 .rc 配置文件,就包括 servicemanager.rc。

frameworks/native/cmds/servicemanager/servicemanager.rc

c 复制代码
service servicemanager /system/bin/servicemanager
    class core animation
    user system
    group system readproc
    critical
    onrestart restart apexd
    onrestart restart audioserver
    onrestart restart gatekeeperd
    onrestart class_restart main
    onrestart class_restart hal
    onrestart class_restart early_hal
    writepid /dev/cpuset/system-background/tasks
    shutdown critical

当 init 解析到这里时,会将 servicemanager 归类为 core 级的服务。 在 init 阶段的后期,会通过 class_start core 命令通过 fork + execve 正式拉起 /system/bin/servicemanager 进程。

启动 servicemanager

打开Binder驱动 、 成为Context Manager 进程拉起后,直接进入 servicemanager 的 main 函数。

frameworks/native/cmds/servicemanager/main.cpp

c 复制代码
int main(int argc, char** argv) {
    if (argc > 2) {
        LOG(FATAL) << "usage: " << argv[0] << " [binder driver]";
    }

    const char* driver = argc == 2 ? argv[1] : "/dev/binder";
    // 打开 Binder 驱动,并将自己映射到内存空间
    sp<ProcessState> ps = ProcessState::initWithDriver(driver);
    // 因为 servicemanager 采用了 Looper 的事件循环机制,不需要 Binder 线程池
    // 这里设置为单线程
    ps->setThreadPoolMaxThreadCount(0);
    ps->setCallRestriction(ProcessState::CallRestriction::FATAL_IF_NOT_ONEWAY);

    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);
    // 核心!通过 ioctl(BINDER_SET_CONTEXT_MGR) 告诉驱动我是老大(Handle为0)
    ps->becomeContextManager();

    sp<Looper> looper = Looper::prepare(false /*allowNonCallbacks*/);
    // 将 Binder 驱动的 file descriptor 加入 epoll 监听
    BinderCallback::setupTo(looper);
    ClientCallbackCallback::setupTo(looper, manager);

    while(true) {
        // 阻塞等待客户端(如 system_server)发来请求
        looper->pollAll(-1);
    }

    // should not be reached
    return EXIT_FAILURE;
}

至此,servicemanager 启动完毕,静静等待其他进程(如注册服务、查询服务)的打扰。

二、打开 binder 驱动

frameworks/native/libs/binder/ProcessState.cpp

ProcessState 是用户空间进程与 Binder 驱动沟通的桥梁。它是一个 进程单例,主要负责打开 Binder 驱动、进行内存映射(mmap)以及管理该进程的全局 Binder 状态。

c 复制代码
#define BINDER_VM_SIZE ((1 * 1024 * 1024) - sysconf(_SC_PAGE_SIZE) * 2)
...
// 构造函数
ProcessState::ProcessState(const char* driver)
    : mDriverFD(open_driver(driver)) // 1. 打开驱动
    , mVMStart(MAP_FAILED)           // 2. 内存映射的起始地址
    , ... 
{
    if (mDriverFD >= 0) {
        // 3. 执行 mmap,将驱动的虚拟内存映射到当前进程的空间
        // BINDER_VM_SIZE 在普通进程中通常是 (1MB - 2个页面),servicemanager 为 128KB
        mVMStart = mmap(nullptr, BINDER_VM_SIZE, PROT_READ, 
                        MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
        if (mVMStart == MAP_FAILED) {
            close(mDriverFD);
            mDriverFD = -1;
        }
    }
}

2.1 open_driver()

c 复制代码
int fd = open(driver, O_RDWR | O_CLOEXEC);

这里以读写模式(O_RDWR)打开 /dev/binder 设备文件。O_CLOEXEC 确保该进程如果 fork 出子进程并执行 exec 时,该文件描述符会自动关闭,防止安全泄漏。

2.2 校验版本

c 复制代码
        int vers = 0;
        status_t result = ioctl(fd, BINDER_VERSION, &vers);
        // 版本不匹配则报错关闭
        if (result == -1) {
            ALOGE("Binder ioctl to obtain version failed: %s", strerror(errno));
            close(fd);
            fd = -1;
        }
        if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
          ALOGE("Binder driver protocol(%d) does not match user space protocol(%d)! ioctl() return value: %d",
                vers, BINDER_CURRENT_PROTOCOL_VERSION, result);
            close(fd);
            fd = -1;
        }

通过 ioctl 的 BINDER_VERSION 命令读取内核驱动的 Binder 版本,确保用户空间的 libbinder 和内核驱动的协议版本完全一致。

2.3 设置最大线程数

c 复制代码
#define DEFAULT_MAX_BINDER_THREADS 15
...
size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);

通过 BINDER_SET_MAX_THREADS 告知内核驱动,该进程的 Binder 线程池最多可以自动创建多少个线程来处理并发请求。

2.4 开启泛洪攻击检测

c 复制代码
uint32_t enable = DEFAULT_ENABLE_ONEWAY_SPAM_DETECTION;
result = ioctl(fd, BINDER_ENABLE_ONEWAY_SPAM_DETECTION, &enable);
if (result == -1) {
     ALOGD("Binder ioctl to enable oneway spam detection failed: %s", strerror(errno));
}

这是 Android 为防止 Binder 异步调用被滥用而设置的一道内核级安全阀门。

完整流程如下所示:

c 复制代码
open_driver()

│
├── open("/dev/binder")
│       │
│       └── 打开Binder设备
│
├── ioctl(BINDER_VERSION)
│       │
│       └── 检查驱动版本是否匹配
│
├── ioctl(BINDER_SET_MAX_THREADS)
│       │
│       └── 设置Binder线程池最大线程数
│
└── ioctl(BINDER_ENABLE_ONEWAY_SPAM_DETECTION)
        │
        └── 开启oneway事务洪泛检测

三、成为上下文管理者 becomeContextManager

只有 servicemanager 进程有资格成为上下文管理者。在 ProcessState.cpp 中,该功能的实现极其简洁,但分量极重:

c 复制代码
bool ProcessState::becomeContextManager()
{
    AutoMutex _l(mLock);
    
    // 构造一个 flat_binder_object 结构体
    flat_binder_object obj;
    memset(&obj, 0, sizeof(obj));
    obj.flags = FLAT_BINDER_FLAG_TXN_SECURITY_CTX; // 开启安全上下文传输检查

    // Android 12 核心系统调用
    int result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR_EXT, &obj);

    // 如果内核不支持带扩展参数的命令,则回退到传统命令
    if (result != 0) {
        android_errorWriteLog(0x534e4554, "121035042");
        int dummy = 0;
        result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR, &dummy);
    }

    return result == 0;
}

当 BINDER_SET_CONTEXT_MGR_EXT 被调用时,内核会:

  • 验证调用者是否具有 binder:set_context_mgr SELinux 权限
  • 将该进程的 binder_proc 标记为 context manager
  • 此后所有 BINDER_TYPE_HANDLE 的服务注册/查找请求都路由到该进程

创建 0 号句柄:内核会为当前进程(即 servicemanager)专门创建一个特殊的内核 Binder 实体节点。所有其他进程在尝试获取"Handle = 0"的 Binder 引用时,驱动都会自动将请求路由到这个节点。

四、 进入循环等待消息到来

在打开驱动、做好映射、确立身份后,进程必须进入一个无限循环,等待并处理来自驱动的 IPC 事务。 对于普通的系统服务或 App 进程,它们使用的是 IPCThreadState 机制;而对 servicemanager 而言,Android 12 使用了更为现代的 Looper (基于 Linux epoll)。但无论哪种,它们底层的核心逻辑都是一致的:阻塞在驱动的读操作上。

c 复制代码
sp<Looper> looper = Looper::prepare(false);

// ① Binder 事务(服务注册/查询)
BinderCallback::setupTo(looper);

// ② 客户端死亡通知 + 超时检测等非Binder事件
ClientCallbackCallback::setupTo(looper, manager);

while(true) {
    looper->pollAll(-1);  // 统一等待两类事件
}

BinderCallback 在 frameworks/native/cmds/servicemanager/main.cpp 中

c 复制代码
class BinderCallback : public LooperCallback {
public:
    static sp<BinderCallback> setupTo(const sp<Looper>& looper) {
        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);

        // 【核心】将 binder fd 添加到 Looper 的 epoll 监听列表
        // EVENT_INPUT = EPOLLIN,即监听"有数据可读"
        int ret = looper->addFd(binder_fd, // 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;
    }

    int handleEvent(int /* fd */, int /* events */, void* /* data */) override {
        // 处理单次任务
        IPCThreadState::self()->handlePolledCommands();
        return 1;  // Continue receiving callbacks.
    }
};
c 复制代码
status_t IPCThreadState::setupPolling(int* fd)
{
    if (mProcess->mDriverFD < 0) {
        return -EBADF;
    }
    // 向内核声明当前线程进入 Looper 模式
    mOut.writeInt32(BC_ENTER_LOOPER);
    // 立即将 BC_ENTER_LOOPER 写入内核
    flushCommands();
    // 通过出参返回 binder fd,供 Looper::addFd 使用
    *fd = mProcess->mDriverFD;
    return 0;
}

status_t IPCThreadState::handlePolledCommands()
{
    status_t result;

    do {
        // 批量消费所有已到达的命令
        result = getAndExecuteCommand();

        // 循环条件:只要 mIn 中还有未解析的数据就继续
    } while (mIn.dataPosition() < mIn.dataSize());

    // 处理延迟的引用计数操作
    processPendingDerefs();
    // 发送本批次产生的所有出站命令
    flushCommands();
    return result;
}

其中 mIn和 mOut 定义在下面文件中它们是 类中的成员变量,类型为Parcel

frameworks/native/libs/binder/include/binder/IPCThreadState.h

c 复制代码
class IPCThreadState {
    // ...
private:
    Parcel              mIn;      // 入站缓冲区:存放从内核读取的 BR_* 命令及负载
    Parcel              mOut;     // 出站缓冲区:存放待发送给内核的 BC_* 命令及负载
    // ...
};

后面的talkWithDriver(false)就是将 mOut 的内容通过 ioctl 写入内核,同时将内核返回的数据填充到 mIn 中,并重置 mIn 的读游标到起始位置。


无论是添加服务还是查询服务,本质上都是一次 Binder Transaction (事务)。 数据的流动方向

  • 发送端 (Client): 调用 IPCThreadState::transact() -> writeTransactionData() -> 将请求打包成 BC_TRANSACTION 写入 mOut -> talkWithDriver() 将数据发送给内核。
  • 接收端 (Server / ServiceManager): 阻塞在 talkWithDriver() -> 收到数据,读取到 BR_TRANSACTION -> executeCommand() 进行处理。

看一张图,加深一下印象:

4.1 getAndExecuteCommand

c 复制代码
status_t IPCThreadState::getAndExecuteCommand()
{
    status_t result;
    int32_t cmd;

    result = talkWithDriver(); // 1. 阻塞等待驱动的数据
    if (result >= NO_ERROR) {
        size_t IN = mIn.dataAvail();
        if (IN < sizeof(int32_t)) return result;
        cmd = mIn.readInt32(); // 2. 读取命令字 (例如 BR_TRANSACTION)
        
        // ... 省略线程池管理代码 ...

        result = executeCommand(cmd); // 3. 执行具体的命令逻辑
        // ...
    }
    return result;
}

4.2 talkWithDriver

talkWithDriver(bool doReceive) 的核心职责是构建 binder_write_read 结构体,并通过 ioctl 系统调用与 Binder 驱动进行双向数据交换。

c 复制代码
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
    ...
        
    binder_write_read bwr;

    // 检查输入缓冲区 mIn 是否已经读空
    const bool needRead = mIn.dataPosition() >= mIn.dataSize();

    // 确定写出大小:如果不需要接收新数据(doReceive为false),或者需要接收新数据且输入缓冲区已空,才把 mOut 的数据发出去
    const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;

    bwr.write_size = outAvail;
    // 发送缓冲区的数据指针,里面存放着 BC_ 协议指令
    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(); // 指定驱动把数据写到 mIn 的这段内存中
    } else {
        bwr.read_size = 0;
        bwr.read_buffer = 0;
    }

    IF_LOG_COMMANDS() {
        TextOutput::Bundle _b(alog);
        if (outAvail != 0) {
            alog << "Sending commands to driver: " << indent;
            const void* cmds = (const void*)bwr.write_buffer;
            const void* end = ((const uint8_t*)cmds)+bwr.write_size;
            alog << HexDump(cmds, bwr.write_size) << endl;
            while (cmds < end) cmds = printCommand(alog, cmds);
            alog << dedent;
        }
        alog << "Size of receive buffer: " << bwr.read_size
            << ", needRead: " << needRead << ", doReceive: " << doReceive << endl;
    }

    // 如果读写 size 都为 0,直接返回
    if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;

    bwr.write_consumed = 0;
    bwr.read_consumed = 0;
    status_t err;
    do {
        IF_LOG_COMMANDS() {
            alog << "About to read/write, write size = " << mOut.dataSize() << endl;
        }
#if defined(__ANDROID__)
        // 核心阻塞点:执行 BINDER_WRITE_READ。线程在此陷入内核空间。
        if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
            err = NO_ERROR;
        else
            err = -errno;
#else
        err = INVALID_OPERATION;
#endif
        if (mProcess->mDriverFD < 0) {
            err = -EBADF;
        }
        IF_LOG_COMMANDS() {
            alog << "Finished read/write, write size = " << mOut.dataSize() << endl;
        }
    } while (err == -EINTR);// 被信号中断则重试
    // 对于 ServiceManager 来说,如果没有客户端发起请求,ioctl 就会在驱动层将当前线程挂起阻塞。
    // 当 ioctl 返回时,说明驱动已经处理了 mOut 中的数据,或者向 mIn 中写入了新的数据。

    ...

    if (err >= NO_ERROR) {
        // 如果驱动读取了用户空间的数据
        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.setDataSize(0);
                processPostWriteDerefs();
            }
        }
        // 如果驱动向用户空间写入了数据
        if (bwr.read_consumed > 0) {
            mIn.setDataSize(bwr.read_consumed);// 更新 mIn 的有效数据大小
            mIn.setDataPosition(0);// 重置读指针到头部,准备解析
        }

        ...
        return NO_ERROR;
    }

    return err;
}

执行到这里,talkWithDriver 结束,mIn 缓冲区中已经装满了来自驱动的 BR_ 命令。

4.3 executeCommand

回到 getAndExecuteCommand 函数中,它会从 mIn 中读取一个 32 位的命令字(cmd),然后传递给 executeCommand(int32_t cmd) 函数进行解析。 对于 ServiceManager(以及所有服务端),最核心的指令是 BR_TRANSACTION:

解析事务数据与零拷贝

c 复制代码
case BR_TRANSACTION_SEC_CTX:
case BR_TRANSACTION:
        {
            binder_transaction_data_secctx tr_secctx;
            binder_transaction_data& tr = tr_secctx.transaction_data;

            // 1. 读取事务元数据(包含发送方 PID/UID,调用方法 code,目标对象 target,以及数据内存地址)
            if (cmd == (int) BR_TRANSACTION_SEC_CTX) {
                result = mIn.read(&tr_secctx, sizeof(tr_secctx));
            } else {
                result = mIn.read(&tr, sizeof(tr));
                tr_secctx.secctx = 0;
            }

            Parcel buffer;
            // 2. 【核心】直接利用驱动映射好的内存地址(tr.data.ptr.buffer),无需二次拷贝,直接关联给 Parcel 对象
            buffer.ipcSetDataReference(
                reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
                tr.data_size,
                reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
                tr.offsets_size/sizeof(binder_size_t), freeBuffer);

保存并切换调用者身份

为了让业务层(比如 ServiceManager 的 SELinux 检查)知道是哪个进程发起的调用,IPCThreadState 必须将当前线程的调用者身份替换为发送方的身份:

c 复制代码
// 备份当前的身份信息(压栈保存)
            const pid_t origPid = mCallingPid;
            const char* origSid = mCallingSid;
            const uid_t origUid = mCallingUid;
            // ... 省略部分备份代码 ...

            // 替换为来自驱动解析出的发送方 PID 和 UID (无法伪造)
            mCallingPid = tr.sender_pid;
            mCallingSid = reinterpret_cast<const char*>(tr_secctx.secctx);
            mCallingUid = tr.sender_euid;
            mLastTransactionBinderFlags = tr.flags;

路由并执行业务逻辑

这是 ServiceManager 接收消息的最关键分支:

c 复制代码
            Parcel reply;
            status_t error;

            if (tr.target.ptr) {
                // 普通 Binder 服务处理分支
                // 如果 target.ptr 有值,说明目标是一个具体的 Binder 实体节点 (BBinder)
                if (reinterpret_cast<RefBase::weakref_type*>(tr.target.ptr)->attemptIncStrong(this)) {
                    error = reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code, buffer, &reply, tr.flags);
                    reinterpret_cast<BBinder*>(tr.cookie)->decStrong(this);
                } else {
                    error = UNKNOWN_TRANSACTION;
                }
            } else {
                // ServiceManager 处理分支
                // 驱动发往 Handle 0 的请求,tr.target.ptr 恒为空(0)
                error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
            }

针对 ServiceManager: 因为它向驱动注册为 Context Manager(句柄为0),驱动在向其分发事务时,tr.target.ptr 为空。 因此,代码必定走入 else 分支。 the_context_object 是一个全局静态 sp<BBinder> 变量,它在 ServiceManager 进程启动时,通过 IPCThreadState::setTheContextObject() 函数被赋值为 ServiceManager 的本地实例。 于是,消息通过 the_context_object->transact(...) 完美跳转到了业务层的 ServiceManager::onTransact 方法中进行 addService 或 checkService 等逻辑。

发送回复并还原身份

业务处理完毕后,将结果发回给客户端,并还原线程身份:

c 复制代码
if ((tr.flags & TF_ONE_WAY) == 0) {
                // 如果不是 ONEWAY(异步)调用,则需要将 reply 中的数据返回给客户端
                if (error < NO_ERROR) reply.setError(error);
                constexpr uint32_t kForwardReplyFlags = TF_CLEAR_BUF;
                
                // 将答复数据写入 mOut,并最终通过 talkWithDriver 传给驱动
                sendReply(reply, (tr.flags & kForwardReplyFlags));
            } else {
                // ONEWAY 调用,无需发送 reply
            }

            // 出栈:恢复原始的线程身份上下文
            mCallingPid = origPid;
            mCallingSid = origSid;
            mCallingUid = origUid;
            // ...
        }
        break;

小结

talkWithDriver 是物理通讯层:严格通过 binder_write_read 结构,将 mOut 刷入驱动,将驱动指令拉入 mIn,通过 ioctl(BINDER_WRITE_READ) 实现线程的阻塞与唤醒。 executeCommand 是协议解析层:从 mIn 读取指令,对于核心的 BR_TRANSACTION,它进行零拷贝 Parcel 组装,备份并切换 PID/UID。由于是 ServiceManager,它通过 tr.target.ptr == NULL 的判定,将事务精准路由到了静态绑定的 the_context_object,最后通过 sendReply 完成闭环。


4.4 添加服务/查询服务

由上面分析可知:

c 复制代码
// 驱动发往 Handle 0 的请求,tr.target.ptr 恒为空(0)
error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);

由于 the_context_object 本质是一个指向 ServiceManager 实例的指针,它继承自 BBinder。因此,这里的 transact 调用会直接跳转到 BBinder 的成员函数中。 最终会经过:Binder.cpp->BnServiceManager::onTransact分发到 ServiceManager.cpp

c 复制代码
// 1. 添加服务的终极执行点!
Status ServiceManager::addService(const std::string& name, const sp<IBinder>& binder,
                                  bool allowIsolated, int32_t dumpPriority) {
    // 执行 SELinux 权限校验
    if (!mAccess->canAdd(ctx, name)) return Status::fromExceptionCode(Status::EX_SECURITY);

    // 【真正写入内存】把服务名和服务的引用装入 Service 结构,写进本地的 std::map 存储中!
    mNameToService[name] = Service {
        .binder = binder,
        .allowIsolated = allowIsolated,
        .dumpPriority = dumpPriority,
    };

    return Status::ok();
}

// 2. 查询服务的终极执行点!
Status ServiceManager::checkService(const std::string& name, sp<IBinder>* outBinder) {
    *outBinder = nullptr;

    // 执行 SELinux 权限校验
    if (!mAccess->canFind(ctx, name)) return Status::ok();

    // 【真正读取内存】在 std::map 中通过 name 键值查找对应的服务
    auto it = mNameToService.find(name);
    if (it != mNameToService.end()) {
        // 找到后,把底层服务的 Binder 引用赋值给传出参数 outBinder
        *outBinder = it->second.binder;
    }

    return Status::ok();
}

在 Android 12 中,addService 中的 service 它在 C++ 代码层表现为 sp<IBinder>,在物理内存中表现为 BpBinder,在最底层的 Binder 协议层表现为一个 整型句柄值(Handle)。 在安卓 10 及之前版本 serviceManager 是用 service_manager.c C 语言写的,当时其他进程传进来的只是handle 裸数据:

c 复制代码
// 旧版 C 语言 service_manager.c
struct svcinfo {
    struct svcinfo *next;
    uint32_t handle; // 【注意:这里直接存的就是一个 uint32_t 的数字!】
    struct binder_death death;
    size_t len;
    uint16_t name[0];
};

五、疑惑点解析

5.1 线程单例 IPCThreadState

IPCThreadState是基于线程的一个单例,即每个线程都有一个独立的IPCThreadState,用户和 binder 驱动进行通信。 Thread-Local 绑定:不管是 system_server 的 Binder 线程、App 的主线程,还是 servicemanager 的主线程,只要它需要与 Binder 驱动交互,其线程内部就会通过 TLS 拥有一个独一无二的 IPCThreadState 实例。 对于内核驱动而言,它不在乎你是客户端还是服务端,它只在乎"当前这个线程是否要写数据(mOut)"以及"是否要读数据(mIn)"。

5.2 IPCThreadState::transact 和 BBinder::transact

IPCThreadState::transact(...)(客户端发送出口): 作用是把数据打包成 BC_TRANSACTION 写入 mOut 并通过 talkWithDriver 发给内核驱动。 BBinder::transact(...)(服务端本地入口): 因为 the_context_object 是一个 BBinder(在 servicemanager 进程中,它指向 ServiceManager 实例)。 所以,这里的 transact 是一次本地 C++ 对象的方法调用,绝对不涉及驱动。

5.3 BC_xxx 指令和 BR_xxx 指令有什么区别?

六、最后

通常我们认为 ioctl 会阻塞,那是因为在标准 Binder 线程池模式中,线程必须等到驱动有数据才能返回。 而在 ServiceManager 的 Looper 模式中:

  • 驱动先通知:通过 epoll 告知 FD 有数据。
  • 我们再去拿:talkWithDriver 此时调用 ioctl,本质上是去执行"把数据从驱动拷贝到用户空间"的操作。由于数据已经就绪,这个动作会瞬间完成。
相关推荐
martindelophy1 小时前
用自然语言剪视频:我们在 Timeline Studio 中实现了 ChatCut 对话剪辑
android·音视频
ao-weilai2 小时前
MySQL数据库:复合查询
android·数据库·mysql
三少爷的鞋14 小时前
AI 时代,我们都将成为通才型开发者:只懂 Android,已经不够了
android
Dovis(誓平步青云)18 小时前
家里设备越来越多,如何用一张空间地图控制灯光和温度![
android·java·前端·javascript·人工智能·电脑
晚风叙码20 小时前
MySQL 数据类型详解:从数值到字符串,一篇讲透
android·mysql·adb
传奇开心果编程20 小时前
【Compose Multiplatform 跨端开发学与练】第3课 布局与组件
android·windows·学习·ui·ios·kotlin·composer
传奇开心果编程1 天前
【Compose Multiplatform 跨端开发学与练】第8课 资源管理与主题
android·windows·学习·ios·kotlin·web·composer
传奇开心果编程1 天前
【Compose Multiplatform 跨端开发学与练】第9课 测试与调试
android·学习·macos·ios·kotlin·web·composer
传奇开心果编程1 天前
【Compose Multiplatform 跨端开发学与练】第4课 导航与路由
android·windows·学习·ui·ios·kotlin·composer
传奇开心果编程1 天前
【Compose Multiplatform 跨端开发学与练】第6课 状态管理与架构
android·学习·ui·ios·架构·kotlin·composer