Android Binder 驱动 - 启动 ServiceManager 进程

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

一、ServiceManager 启动

解析 servicemanager.rc

servicemanager 是 Android 系统中最早启动的核心守护进程之一。它的生命周期由 init 进程直接管理。 当 Android 内核启动完毕后,会启动用户空间的第一个进程 initinit 进程会去解析一系列的 .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 进程拉起后,直接进入 servicemanagermain 函数。

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

通过 ioctlBINDER_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;
}

其中 mInmOut 定义在下面文件中它们是 类中的成员变量,类型为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 方法中进行 addServicecheckService 等逻辑。

发送回复并还原身份

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

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,本质上是去执行"把数据从驱动拷贝到用户空间"的操作。由于数据已经就绪,这个动作会瞬间完成。
相关推荐
农村小镇哥1 小时前
ThinkPHP-MVC什么是框架
android
换元不配限2 小时前
Jetpack Compose 状态管理指南
android·状态管理·compose·状态·单向数据流·jetpack compose·状态容器
爱笑鱼4 小时前
JNI(二):Java 里的一个 long,为什么能找到 C++ 对象?
android
爱笑鱼5 小时前
JNI(一):nativePollOnce() 到底去了哪里?
android
hqk7 小时前
玩Android×AI Coding:从产品到代码,完整跑通一套 AI 软件研发工作流
android·ai编程·vibecoding
安卓修改大师8 小时前
安卓修改大师实战:深入解析Android主题Theme修改与沉浸式界面实现
android
齊家治國平天下9 小时前
CarService 深度解析 —— 基于 Android 14
android·车载系统·aaos·carservice·电源管理·android 14·vhal
stevenzqzq10 小时前
app性能日志工具
android
DB哥讲数据库10 小时前
【最新】MySQL9.7安装教程:图文详解(附MySQL安装包)
android·mysql·adb