=============================================================================================
Android中的通信很多都是通过Binder机制来完成的,对于MediaPlayer和MediaPlayerService也不例外。
我们来看看下面的C/S Binder通信图:
从图中可以总结出下面几点:
-
MediaPlayer是客户端也就是 C/S中的 Client层
-
MediaPlayerService和MediaPlayerService::Client是服务端,也就是我们说的 C/S模型中的S层
-
MediaPlayerService实现 IMediaPlayerService 定义的业务逻辑
-
MediaPlayerService::Client 实现 IMediaPlayer定义的业务逻辑
-
通过
Transact()
可以向远端的IBinder对象发出调用,通过onTransact()
可以使你自己的远程对象能够响应接收到的调用。
==========================================================================
我们知道Binder通信时,需要通过 IBinder接口转化具体的实体对象,那么中间会有很多其它类,下面看看类关系图:
细品IPC通信图,可以得出下面的结论:
- BnXXX 和 BpXXX都派生自两个类
class BpXXX : public IMediaPlayerService, public BpRefBase
class BnXXX : public IMediaPlayerService, public BBinder
- BpXXX和BnXXX都派生自 IMediaPlayerService,我们之前说过,IMediaPlayerService使用来定义一些功能的接口的,而派生出两个类,所以它们虽然使用了相同的接口,但是他们有不同的实现方式。
BpXXX中:把对应的binder_transaction_data 打包之后,通过BpRefBase中的 mRemote(BpBinder)发送出去,并等待结果
BnXXX中:实现对应的业务逻辑,通过调用 BnXXX 派生类中的方法来实现,如 MediaPlayerService::Client
- IBinder用于进程间通信
BpRefBase中有一个remote()
用来与Binder驱动交互
Binder是用来从Binder驱动中接收相关请求并进行相关处理的
BpBinder和BinderDriver进行互通
===========================================================================================
我们从入口看,入口在 /frameworks/av/media/mediaserver/main_mediaserver.cpp:
int main(int argc __unused, char **argv __unused)
{
//信号
signal(SIGPIPE, SIG_IGN);
//进程赋值处理
sp proc(ProcessState::self());
sp sm(defaultServiceManager());
ALOGI(“ServiceManager: %p”, sm.get());
InitializeIcuOrDie();
MediaPlayerService::instantiate();
ResourceManagerService::instantiate();
registerExtensions();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
从第一个有意义的函数 defaultServiceManager()
,它在/frameworks/native/libs/binder/IServiceManager.cpp:
p defaultServiceManager()
{
//如果存在一个 BpServiceManager就返回它
if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
//单例模式
{
AutoMutex _l(gDefaultServiceManagerLock);
while (gDefaultServiceManager == NULL) {
gDefaultServiceManager = interface_cast(
ProcessState::self()->getContextObject(NULL));
if (gDefaultServiceManager == NULL)
sleep(1);
}
}
return gDefaultServiceManager;
}
这种构建模式其实是我们熟悉的 单例模式。每个进程都只需要构建出一个 BpServiceManager代理,
ProcessState::self() -> getContextObject(NULL)
,接下来看看 getContextObject(),它在 /frameworks/native/libs/binder/ProcessState.cpp中:
sp ProcessState::getContextObject(const sp& /caller/)
{
return getStrongProxyForHandle(0);
}
sp ProcessState::getStrongProxyForHandle(int32_t handle)
{
sp result;
AutoMutex _l(mLock);
//在数组 mHandleToObject里面根据handle索引查找handle_entry结构体
handle_entry* e = lookupHandleLocked(handle);
if (e != NULL) {
//指向结构体中的binder地址
IBinder* b = e->binder;
if (b == NULL || !e->refs->attemptIncWeak(this)) {
if (handle == 0) {
Parcel data;
status_t status = IPCThreadState::self()->transact(
0, IBinder::PING_TRANSACTION, data, NULL, 0);
if (status == DEAD_OBJECT)
return NULL;
}
//BpBinder新建一个IBinder BpBinder.create(0)
b = BpBinder::create(handle);
e->binder = b;
if (b) e->refs = b->getWeakRefs();
result = b;
} else {
result.force_set(b);
e->refs->decWeak(this);
}
}
return result;
}
struct handle_entry{
IBinder* binder;
RefBase::weakref_type* refs;
}
总结代码:
传入的句柄handler的值为0,表示ServiceManager,构建一个BpBinder,所以现在相当于 gDefaultServiceManager = interface_cast(BpBinder.create(0))
接下来看看 interface_cast()
是什么:
inline sp interface_cast(const sp& obj)
{
return IServiceManager::asInterface(obj);
}
…
asInteface(){
…
//这里构建了一个新的BoServiceManager对象
intr = new BpServiceManager(obj)
}
其asInterface最终还是创建出一个 BpServiceManager对象。
所以defaultServiceManager()
就是 句柄handle(0)创建一个 BpBinder(0),跟举这个BpBinder创建出一个 BpServiceManager代理。
下面来分析一下BpServiceManager
这个类是什么成分,代码如下:
class BpServiceManager : public BpInterface
{
public:
-
explicit BpServiceManager(const sp& impl)
- BpInterface(impl) {}
};
这里的 它继承了 BpInterface
,它是一个模板类,这里相当于它同时 继承了 BpInterface
和 IServiceManager
而 BpInterface
在用到它的构造函数时,就会 去添加服务内部。
在 MediaPlayerSrvice.cpp中有一个 instantiate()
,通过ServiceManager来添加MediaPlayerService服务:
void MediaPlayerService::instantiate() {
defaultServiceManager()->addService(
String16(“media.player”), new MediaPlayerService());
}
defaultServiceManager()
返回的是刚创建的BpServiceManager,并调用它的 addService()
BpMediaPlayerService作为服务端代理,那么BnMediaPlayerService一定是实现端
MediaPlayerService继承自 BnMediaPlayerService,实现了真正的的业务函数。
============================================================================
下面分析一下 BpServiceManager的 addService()
virtual status_t addService(const String16& name, const sp& service,
bool allowIsolated, int dumpsysPriority) {
Parcel data, reply;
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
data.writeString16(name);
//也就是MediaPlayerService
data.writeStrongBinder(service);
data.writeInt32(allowIsolated ? 1 : 0);
data.writeInt32(dumpsysPriority);
status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
return err == NO_ERROR ? reply.readExceptionCode() : err;
}
这里的 remote函数返回的就是 前面创建的 BpBinder(0)对象:
status_t BpBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
// Once a binder has died, it will never come back to life.
if (mAlive) {
status_t status = IPCThreadState::self()->transact(
mHandle, code, data, reply, flags);
if (status == DEAD_OBJECT) mAlive = 0;
return status;
}
return DEAD_OBJECT;
}
status_t IPCThreadState::transact(int32_t handle,
uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags)
{
…
//发送addTransactionData
err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
…
} else {
//等待响应
err = waitForResponse(NULL, NULL);
}
return err;
}
status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
{
//cmd BC_TRANSACTION 应用程序向Binder发送的命令
binder_transaction_data tr;
tr.target.handle = handle;
tr.code = code;
tr.flags = binderFlags;
…
//把命令和数据一起发送到 Parcel mOut中
mOut.writeInt32(cmd);
mOut.write(&tr, sizeof(tr));
return NO_ERROR;
}
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
uint32_t cmd;
while (1) {
//和Driver进行沟通后获得结果
if ((err=talkWithDriver()) < NO_ERROR) break;
cmd = (uint32_t)mIn.readInt32();
switch (cmd) {
case BR_TRANSACTION_COMPLETE:
…
break;
}
}
return err;
}
status_t IPCThreadState::talkWithDriver(bool doReceive) {
binder_write_read bwr;
bwr.write_size = outAvail;
//写入 mOut的数据
bwr.write_buffer = (uintptr_t) mOut.data();
bwr.read_size = mIn.dataCapacity();
bwr.read_buffer = (uintptr_t) mIn.data();
…
//把mOut写到Binder中,并读取mIn的数据
if (ioctl(mProcess -> mDriverFD, BINDER_WRITE_READ, & bwr) >=0)
err = NO_ERROR;
…
return err;
}
joinThreadPool、startThreadPool 进入线程循环
talkWithDriver等待客户端Client请求,从Binder读取命令请求进行处理。
到现在为止,MediaPlayerService的服务端已经向总管 ServiceManager注册了。
5. 通过BinderDriver和MediaPlayer通信的过程
====================================================================================================
下面看看客户端是如何获得服务的代理并和服务端通信的。
我们以 MediaPlayer的业务函数解码解析播放一个 网络视频的URL为例。
首先在 MediaPlayer decode(url)
时,首先调用了 getMediaPlayerService()
我们来看看这个函数:
IMediaDeathNotifier::
getMediaPlayerService() {
//生成一个BpServiceManager代理对象
sp sm = defaultServiceManager();
sp binder;
do {
//获取String16(“media.player”)的服务对象
binder = sm -> getService(String16(“media.player”));
if (binder != 0) {
break;
}
usleep(500000); // 0.5 s
} while (true);
…
sMediaPlayerService = interface_cast < IMediaPlayerService > (binder);
return sMediaPlayerService;
}
Client端的MediaPlayer先获取一个 BpServiceManager的代理,然后调用其 getService()
向服务总管 ServiceManager查询名叫 String16(“media.player”)的服务,这个getService的方法处于 /frameworks/native/libs/binder/ 的 IServiceManager.cpp:
class BpServiceManager :public BpInterface
{
public:
virtual sp getService(const String16 & name) const
{
int n = 0;
while (uptimeMillis() < timeout) {
n++;
//调用checkService函数
sp svc = checkService(name);
if (svc != NULL) return svc;
}
return NULL;
}
virtual sp checkService( const String16 & name) const
{
Parcel data, reply;
//首先调用writeInterfaceToken,然后写入 android.os.IServiceManager
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor ());
//写入media.player
data.writeString16(name);
//然后通过Binder把data及reply的数据通知出去,在onTransact函数中进行回调
remote()->transact(CHECK_SERVICE_TRANSACTION, data, & reply);
return reply.readStrongBinder();
}
}
这里首先将请求打包成Parcel格式,然后调用 remote->transact
函数,前面我们分析过 BpServiceManager::remote返回的就是 newBpBinder(0)
,对应的句柄为 ServiceManager。继续在BpBinder中寻找实现代码:
status_t BpBinder::transact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){
IPCThreadState::self()->transact(mHandle, code, data, reply, flags);
}
最后调用 IPCThreadState
的transact函数,在Android中 ProcessState是哭护短和服务端的公共部分,作为Binder通信的基础,ProcessState是一个singleton类, 每个进程只有一个对象,这个对象负责打开Binder驱动,建立线程池,让其进程里面的所有线程都能通过Binder通信。
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
![](https://i-blog.csdnimg.cn/blog_migrate/38ac256e51bf5a7a60775f267cde46de.jpeg)
文末
那么对于想坚持程序员这行的真的就一点希望都没有吗?
其实不然,在互联网的大浪淘沙之下,留下的永远是最优秀的,我们考虑的不是哪个行业差哪个行业难,就逃避掉这些,无论哪个行业,都会有他的问题,但是无论哪个行业都会有站在最顶端的那群人。我们要做的就是努力提升自己,让自己站在最顶端,学历不够那就去读,知识不够那就去学。人之所以为人,不就是有解决问题的能力吗?挡住自己的由于只有自己。
Android希望=技能+面试
- 技能
- 面试技巧+面试题
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
图片转存中…(img-oAcnO0eW-1712447942072)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
![](https://i-blog.csdnimg.cn/blog_migrate/38ac256e51bf5a7a60775f267cde46de.jpeg)
文末
那么对于想坚持程序员这行的真的就一点希望都没有吗?
其实不然,在互联网的大浪淘沙之下,留下的永远是最优秀的,我们考虑的不是哪个行业差哪个行业难,就逃避掉这些,无论哪个行业,都会有他的问题,但是无论哪个行业都会有站在最顶端的那群人。我们要做的就是努力提升自己,让自己站在最顶端,学历不够那就去读,知识不够那就去学。人之所以为人,不就是有解决问题的能力吗?挡住自己的由于只有自己。
Android希望=技能+面试
- 技能
[外链图片转存中…(img-bFCSM7vU-1712447942072)] - 面试技巧+面试题
[外链图片转存中…(img-2vQLj3T3-1712447942073)]
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!