当前位置: 首页 > news >正文

Android Binder 驱动 - Media 服务启动流程

到现在为止我对Binder 的了解只是知道它很难和它是 Android 系统中最核心的跨进程通信机制,仅此而已,所以接下来几篇文章都是学习的Android Binder 驱动的。

以安卓 12 源码为基础分析

相关文件:

frameworks/av/media/mediaserver/mediaserver.rc

frameworks/av/media/mediaserver/main_mediaserver.cpp

frameworks/native/libs/binder/ProcessState.cpp

frameworks/native/libs/binder/IServiceManager.cpp

frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp

frameworks/native/libs/binder/BpBinder.cpp

frameworks/native/libs/binder/ndk/service_manager.cpp

frameworks/native/libs/binder/IPCThreadState.cpp

我们关注的是:一个系统级 Native 服务(mediaserver)如何被创建,并通过 Binder 机制向系统注册其提供的服务

主线:

1. 内核启动 → 加载 Binder 驱动↓
2. init 进程启动 → 解析 .rc 文件↓
3. 启动 mediaserver 进程(fork + exec)↓
4. mediaserver 初始化 ProcessState 和 IPCThreadState↓
5. 实例化并注册媒体服务(如 MediaPlayerService)↓
6. 服务通过 Binder 被 servicemanager 管理↓
7. 其他进程可通过 Binder 获取服务代理

在开始之前我们要先简单了解下什么是Binder,首先我们都知道它可以用来跨进程通信,那么对跨进程该怎么理解呢:

每个 Android 应用通常运行在自己独立的进程中,拥有自己独立的内存空间。一个进程不能直接访问另一个进程的内存。当应用需要与其他应用或系统服务交互时,就必须通过 IPC 机制。

这个很简单,但是Binder 是如何实现跨进程通信的呢?

Binder 的架构基于客户端-服务器(Client-Server)模型。它的核心思想是:虽然不能直接访问对方的内存,但可以通过内核空间(一个所有进程都能共享的区域)来间接地完成数据交换和方法调用。

这个也很好理解,Binder 就相当于做了各个进程之间的中转工作,和路由器的原理有点像,对客户端来说,你只需要调用一个简单的方法,Binder 就可以帮你完成跨进程的通信任务,我们对Binder 的理解先到这,先不去深究其实现。

另外 Binder 只需要一次数据拷贝(从用户空间到内核空间),相较于其他 IPC 机制性能更高,这也是安卓选它跨进程通信的原因之一!


Binder 驱动初始化(内核层)

  • 内核启动时加载 binder 模块。
  • 创建设备节点 /dev/binder
  • 提供 openmmapioctl 系统调用接口。

所有使用 Binder 的进程都必须先 open("/dev/binder")

mmap 映射一块内存用于 Binder 数据传输(减少拷贝)。

驱动已就绪!

init 解析 mediaserver.rc

frameworks/av/media/mediaserver/mediaserver.rc

on property:init.svc.media=*setprop init.svc.mediadrm ${init.svc.media}service media /system/bin/mediaserverclass mainuser mediagroup audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrmioprio rt 4task_profiles ProcessCapacityHigh HighPerformance

init 进程在解析 init.rc 时会启动一个名为 mediaserver 的守护进程。

/system/bin/mediaserver 入口

frameworks/av/media/mediaserver/main_mediaserver.cpp

int main(int argc __unused, char **argv __unused)
{signal(SIGPIPE, SIG_IGN);// 获取 ProcessState 单例(打开 /dev/binder,mmap)sp<ProcessState> proc(ProcessState::self());// 获取 ServiceManager 代理sp<IServiceManager> sm(defaultServiceManager());ALOGI("ServiceManager: %p", sm.get());// 实例化核心媒体服务MediaPlayerService::instantiate();// 媒体资源管理ResourceManagerService::instantiate();// 注册可选的媒体扩展服务(厂商定制或第三方插件)registerExtensions();::android::hardware::configureRpcThreadpool(16, false);// 启动 Binder 线程池ProcessState::self()->startThreadPool();// 当前线程加入线程池,等待 Binder 请求IPCThreadState::self()->joinThreadPool();::android::hardware::joinRpcThreadpool();
}

sp<...> 是 Android 的强引用智能指针(StrongPointer),用于自动管理 Binder 对象生命周期。

sp<ProcessState> proc(ProcessState::self());

执行 sp<ProcessState> proc(ProcessState::self());来到ProcessState.cpp 中:

frameworks/native/libs/binder/ProcessState.cpp

执行代码:

sp<ProcessState> ProcessState::self() {return init(kDefaultDriver, false /*requireDefault*/);
}sp<ProcessState> ProcessState::init(const char *driver, bool requireDefault) {static sp<ProcessState> gProcess;static std::mutex gProcessMutex;static std::once_flag gProcessOnce;if (driver == nullptr) {std::lock_guard<std::mutex> l(gProcessMutex);return gProcess;}std::call_once(gProcessOnce, [&](){if (access(driver, R_OK) == -1) {ALOGE("Binder driver %s is unavailable. Using /dev/binder instead.", driver);// 如果传入的 driver 设备文件不可访问,则退回 /dev/binder。driver = "/dev/binder";}std::lock_guard<std::mutex> l(gProcessMutex);// make 就是执行构造函数,等价于:new ProcessState("/dev/binder");// make 属于sp 作用域,具体可以看 system/core/libutils/include/utils/StrongPointer.hgProcess = sp<ProcessState>::make(driver);});if (requireDefault) {LOG_ALWAYS_FATAL_IF(gProcess->getDriverName() != driver,"ProcessState was already initialized with %s, can't initialize with %s.",gProcess->getDriverName().c_str(), driver);}return gProcess;
}

构造函数 ProcessState::ProcessState(const char* driver)

ProcessState::ProcessState(const char *driver): mDriverName(String8(driver)) // 保存驱动路径到 mDriverName, mDriverFD(open_driver(driver)) // 打开驱动 → 调用 open_driver(driver) 返回 mDriverFD, mVMStart(MAP_FAILED), mMaxThreads(DEFAULT_MAX_BINDER_THREADS), mThreadPoolStarted(false), mThreadPoolSeq(1), mCallRestriction(CallRestriction::NONE)
{if (mDriverFD >= 0) {// 内存映射 (mmap) → 分配一块虚拟内存空间给 Binder 事务缓冲区mVMStart = mmap(nullptr, BINDER_VM_SIZE, PROT_READ,MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);if (mVMStart == MAP_FAILED) {ALOGE("Using %s failed: unable to mmap transaction memory.\n",mDriverName.c_str());// 没有足够空间分配给 /dev/binder, 则关闭驱动close(mDriverFD);mDriverFD = -1;mDriverName.clear();}}LOG_ALWAYS_FATAL_IF(mDriverFD < 0,"Binder driver '%s' could not be opened.  Terminating.", driver);
}

mmap:

  • 作用:给 Binder 驱动分配一块进程虚拟内存,专门用来存放事务数据(Parcel 数据 buffer)。
  • Binder 驱动通过 copy_from_user/copy_to_user 在内核和用户空间之间交换数据。

打开驱动:

static int open_driver(const char *driver)
{// 打开驱动,得到一个文件描述符 → Binder 驱动的通信入口int fd = open(driver, O_RDWR | O_CLOEXEC);if (fd >= 0) {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;}size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;// 告诉内核这个进程最多可以有多少个 Binder 线程(默认 15)result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);if (result == -1) {ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));}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));}} else {ALOGW("Opening '%s' failed: %s\n", driver, strerror(errno));}return fd;
}

open 是打开驱动、mmap 是映射驱动、ioctl 是操作驱动、close 是关闭驱动,分别对应以下函数:

  • binder_open():打开 Binder 设备(每个进程调用一次)
  • binder_mmap():映射内核缓冲区到用户空间(用于高效数据传输)
  • binder_ioctl():处理 Binder 通信命令(如 BC_TRANSACTION)
  • binder_colse:关闭驱动

sp<IServiceManager> sm(defaultServiceManager())

获取系统的 ServiceManager(服务的大管家),用来向 Binder 驱动注册/查询服务。

sp<IServiceManager> defaultServiceManager()
{// call_once:确保里面的 lambda 函数 只执行一次,即使多线程调用 defaultServiceManager()// 这是 C++ 中实现单例的经典模式std::call_once(gSmOnce, []() {sp<AidlServiceManager> sm = nullptr;while (sm == nullptr) {// 获取 Binder 驱动为每个进程自动提供的 “上下文管理者”(context manager) 的 Binder 引用。// 这个“上下文管理者”其实就是 /dev/vndbinder 或 /dev/binder 上的 servicemanager 进程 的代理。// 将原始的 IBinder 接口(BpBinder(0))转换为 AidlServiceManager 接口sm = interface_cast<AidlServiceManager>(ProcessState::self()->getContextObject(nullptr));if (sm == nullptr) {ALOGE("Waiting 1s on context object on %s.", ProcessState::self()->getDriverName().c_str());// 因为 servicemanager 进程可能 还没有启动完成,等待一秒sleep(1);}}// 兼容层(Shim Layer)// 在 Android 10 及之前:servicemanager 使用 HIDL 定义// Android 11+ 开始:Google 将 servicemanager 重构为使用 AIDLgDefaultServiceManager = sp<ServiceManagerShim>::make(sm);});return gDefaultServiceManager;
}

getContextObject(nullptr):

sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{// 传入 handle = 0,这是整个 Binder 架构中唯一硬编码的句柄// handle=0 固定代表 ServiceManager// 所有进程都知道:要找 ServiceManager,就去拿 handle=0 的代理。sp<IBinder> context = getStrongProxyForHandle(0);if (context) {// The root object is special since we get it directly from the driver, it is never// written by Parcell::writeStrongBinder.internal::Stability::markCompilationUnit(context.get());} else {ALOGW("Not able to get context object on %s.", mDriverName.c_str());}return context;
}
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{sp<IBinder> result;// mLock 是 ProcessState 的互斥锁AutoMutex _l(mLock);// struct handle_entry {// IBinder* binder;        // 对应的代理对象(BpBinder)// weakref_type* refs;     // 弱引用计数器// };//lookupHandleLocked 维护一个数组:mHandleToObject(Vector<handle_entry>)// 所有 handle 的映射都集中管理,避免重复创建代理。handle_entry* e = lookupHandleLocked(handle);if (e != nullptr) {IBinder* b = e->binder;if (b == nullptr || !e->refs->attemptIncWeak(this)) {// 代理不存在 或 弱引用已失效 → 需要重建if (handle == 0) {IPCThreadState* ipc = IPCThreadState::self();CallRestriction originalCallRestriction = ipc->getCallRestriction();ipc->setCallRestriction(CallRestriction::NONE);Parcel data;// 即使 handle=0 存在,也不能保证 servicemanager 进程还活着// 发送一个 PING_TRANSACTION 事务,如果返回 DEAD_OBJECT:说明 servicemanager 死了,不能返回代理status_t status = ipc->transact(0, IBinder::PING_TRANSACTION, data, nullptr, 0);ipc->setCallRestriction(originalCallRestriction);if (status == DEAD_OBJECT)return nullptr;}// 创建一个 BpBinder 对象,封装 handle// BpBinder 是 Binder 代理的基类// 所有跨进程调用最终都通过 BpBinder::transact() 发送到内核sp<BpBinder> b = BpBinder::create(handle);e->binder = b.get();if (b) e->refs = b->getWeakRefs();result = b;} else {// 代理存在且有效 → 直接返回强引用result.force_set(b);e->refs->decWeak(this);}}return result;
}

流程图:

getStrongProxyForHandle(handle)↓
加锁 mLock↓
lookupHandleLocked(handle) → 获取 handle_entry↓
是否有有效代理?├─ 是 → attemptIncWeak → 成功? → 返回强引用└─ 否 → handle == 0? → 是 → 发送 PING_TRANSACTION 检查存活→ 失败? → 返回 nullptr创建 BpBinder(handle)保存到 handle_entry返回 sp<BpBinder>

这样就拿到了 ServiceManager 的 Binder 代理对象。


MediaPlayerService::instantiate();

启动并向 ServiceManager 注册 MediaPlayerService

frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp

void MediaPlayerService::instantiate() {defaultServiceManager()->addService(String16("media.player"), new MediaPlayerService());
}

因为 defaultServiceManager() 返回的是sp<IServiceManager> 对象, 所以可以在IServiceManager 中找到下面方法:

using AidlServiceManager = android::os::IServiceManager;
//...
class ServiceManagerShim : public IServiceManager//...status_t ServiceManagerShim::addService(const String16& name, const sp<IBinder>& service,bool allowIsolated, int dumpsysPriority)
{Status status = mTheRealServiceManager->addService(String8(name).c_str(), service, allowIsolated, dumpsysPriority);return status.exceptionCode();
}

mTheRealServiceManager 是一个 AIDL 接口的客户端代理,指向真正的 AIDL 版 servicemanager 服务。

此处的 addService 就对应了 frameworks/base/core/java/android/os/ServiceManager.java 中的 addService 方法,代表着 Java 和 Native 都可以独立地向 servicemanager 注册服务:

    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)public static void addService(String name, IBinder service, boolean allowIsolated,int dumpPriority) {try {getIServiceManager().addService(name, service, allowIsolated, dumpPriority);} catch (RemoteException e) {Log.e(TAG, "error in addService", e);}}

ResourceManagerService::instantiate();

启动并注册 ResourceManagerService,用于统一管理多媒体硬件资源(解码器、音视频硬件编解码能力)

void ResourceManagerService::instantiate() {// 创建 ResourceManagerService 实例(使用 NDK AIDL 模式)std::shared_ptr<ResourceManagerService> service =::ndk::SharedRefBase::make<ResourceManagerService>();// 将服务注册到 servicemanagerbinder_status_t status =AServiceManager_addService(service->asBinder().get(), getServiceName());// 如果失败就直接返回,不继续初始化if (status != STATUS_OK) {return;}// 创建并设置观察者服务std::shared_ptr<ResourceObserverService> observerService =ResourceObserverService::instantiate();// 使用观察者模式解耦资源管理和状态通知。if (observerService != nullptr) {service->setObserverService(observerService);}// TODO: mediaserver main() is already starting the thread pool,// move this to mediaserver main() when other services in mediaserver// are converted to ndk-platform aidl.//ABinderProcess_startThreadPool();
}

这段代码的作用是: 使用现代 NDK AIDL 架构,创建并注册 ResourceManagerService 服务到 servicemanager,同时设置其依赖的观察者服务,为 mediaserver 提供资源管理能力。

其中AServiceManager_addService 代码实现在 service_manager.cpp :

frameworks/native/libs/binder/ndk/service_manager.cpp

binder_exception_t AServiceManager_addService(AIBinder* binder, const char* instance) {if (binder == nullptr || instance == nullptr) {return EX_ILLEGAL_ARGUMENT;}sp<IServiceManager> sm = defaultServiceManager();status_t exception = sm->addService(String16(instance), binder->getBinder());return PruneException(exception);
}

IPCThreadState::self()->joinThreadPool();

将当前线程变成一个可处理传入和传出 Binder 请求的“Binder 线程”,并进入一个无限循环,等待并执行来自其他进程的 Binder 调用。

关键源码:

void IPCThreadState::joinThreadPool(bool isMain)
{status_t result;mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);do {processPendingDerefs();// 等待并处理来自 Binder 驱动的消息result = getAndExecuteCommand();} while (result != -ECONNREFUSED && result != -EBADF);mOut.writeInt32(BC_EXIT_LOOPER);talkWithDriver(false);
}

与驱动进行通信:

status_t IPCThreadState::talkWithDriver(bool doReceive)
{if (mProcess->mDriverFD < 0) {return -EBADF;}binder_write_read bwr;const bool needRead = mIn.dataPosition() >= mIn.dataSize();const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;bwr.write_size = outAvail;bwr.write_buffer = (uintptr_t)mOut.data();// This is what we'll read.if (doReceive && needRead) {// 接收数据缓冲区信息的填充。如果以后收到数据,就直接填在mIn中了。bwr.read_size = mIn.dataCapacity();bwr.read_buffer = (uintptr_t)mIn.data();} 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;}// Return immediately if there is nothing to do.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__)// 通过ioctl不停的读写操作,跟Binder Driver进行通信if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)err = NO_ERROR;elseerr = -errno;
#elseerr = INVALID_OPERATION;
#endifif (mProcess->mDriverFD < 0) {err = -EBADF;}IF_LOG_COMMANDS() {alog << "Finished read/write, write size = " << mOut.dataSize() << endl;}} while (err == -EINTR);//...return err;
}

这里提一下 binder_write_read 可以把它理解为一个 双向信封

  • 一边装着 我要告诉驱动什么(write)
  • 一边留着 驱动要告诉我什么(read)
write_size/buffer用户 → 内核发送命令(BC_TRANSACTION等)
read_size/buffer内核 → 用户接收事件(BR_TRANSACTION等)
write/read_consumed内核 → 用户告知处理进度

上面我们说过 所有跨进程调用最终都通过 BpBinder::transact() 发送到内核

sp<BpBinder> b = BpBinder::create(handle);

BpBinder 在 sp ProcessState::getStrongProxyForHandle 中被创建

status_t IPCThreadState::transact(int32_t handle,uint32_t code, const Parcel& data,Parcel* reply, uint32_t flags)
{LOG_ALWAYS_FATAL_IF(data.isForRpc(), "Parcel constructed for RPC, but being used with binder.");status_t err;// ...waitForResponse(nullptr, nullptr);//...return err;
}

waitForResponse:

status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{uint32_t cmd;int32_t err;while (1) {// 调用 talkWithDriver if ((err=talkWithDriver()) < NO_ERROR) break;err = mIn.errorCheck();if (err < NO_ERROR) break;if (mIn.dataAvail() == 0) continue;cmd = (uint32_t)mIn.readInt32();IF_LOG_COMMANDS() {alog << "Processing waitForResponse Command: "<< getReturnString(cmd) << endl;}switch (cmd) {case BR_ONEWAY_SPAM_SUSPECT://..case BR_TRANSACTION_COMPLETE://..case BR_DEAD_REPLY://..case BR_FAILED_REPLY:err = FAILED_TRANSACTION;goto finish;case BR_FROZEN_REPLY:err = FAILED_TRANSACTION;goto finish;case BR_ACQUIRE_RESULT://..case BR_REPLY://..default:err = executeCommand(cmd);if (err != NO_ERROR) goto finish;break;}}finish:if (err != NO_ERROR) {if (acquireResult) *acquireResult = err;if (reply) reply->setError(err);mLastError = err;}return err;
}

客户端通过 transact 发送消息, 调用 talkWithDriver 监听返回消息,至此形成闭环。


最后

本人能力有限,关于具体函数的介绍只能停留在表面上,分析不到之处还请不吝赐教,啊,头皮发麻…

http://www.xdnf.cn/news/1429849.html

相关文章:

  • 三格电子CAN总线通信原理及在消防领域中的应用
  • 第三章:生活重构:当程序员不再只是“码农“
  • 威科夫与强化学习状态
  • @Apache Hive 介绍部署与使用详细指南
  • 跨越产业技术障碍、创新制造模式的智慧工业开源了
  • HiMarket:开源AI中台革命——企业智能化的新基建
  • 从全球视角到K8s落地的Apache IoTDB实战
  • 2025年渗透测试面试题总结-47(题目+回答)
  • C++入门自学Day17-- 模版进阶知识
  • [re_1] const|cap|zookper|snowflake
  • maven私有仓库配置
  • 【linux】firewall防火墙
  • 急招 MySQL / PG DBA,欢迎自荐或推荐朋友!推荐有奖!
  • Delphi 5 操作Word表格选区问题解析
  • 玩转Docker | 使用Docker部署Haptic笔记管理应用
  • Resemble Enhance:AI语音增强技术的革新之作
  • Rsync + Rsyncd 从入门到项目实战:自动化备份全攻略
  • 阅读Linux 4.0内核RMAP机制的代码,画出父子进程之间VMA、AVC、anon_vma和page等数据结构之间的关系图。
  • innovus: postRoute如何加shielding
  • ARM - GPIO 标准库开发
  • 【Python3教程】Python3高级篇之XML解析
  • 3dmax烘培插件3dmax法线贴图烘焙教程glb和gltf元宇宙灯光效果图烘焙烘焙光影贴图支持VR渲染器
  • 10 51单片机之DS1302实时时钟
  • Java集合源码解析之ArrayList
  • 网络共享协议
  • 【Vue2 ✨】 Vue2 入门之旅(五):组件化开发
  • 车载刷写架构 --- ECU软件更新怎么保证数据的正确性?
  • MATLAB矩阵及其运算(三)矩阵的创建
  • 应用层:HTTP/HTTPS协议
  • 【Python数据可视化:Matplotlib高级技巧】