多媒体和网络在Android中占有举足轻重的地位,网络的重要性不必说,后有文分析。这里主要是面向消费者的多媒体,包括音频、视频、图片、动画等。可谓是传媒和各种算法的宠儿,同时在流媒体中还涉及到网络,因此多媒体与网络的交互将是研究的重点。
还是利用源头分析法,从init进程开始,init.rc中启动mediaserver
service media /system/bin/mediaserver
class main
user media
group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm
ioprio rt 4
其源码在framework/av/media/mediaserver/main_mediaserver.cpp
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
ALOGI("ServiceManager: %p", sm.get());
AudioFlinger::instantiate();
MediaPlayerService::instantiate();
CameraService::instantiate();
AudioPolicyService::instantiate();
registerExtensions();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
这是一个native层的服务,利用的binder IPC,与netd、vold等unix socket IPC大有不同,值得分析。
sp<ProcessState> ProcessState::self()
{
Mutex::Autolock _l(gProcessMutex);
if (gProcess != NULL) {
return gProcess;
}
gProcess = new ProcessState;
return gProcess;
}
首先获得一个进程的ProcessState实例,根据代码这个实例具有单例的特征。继续其构造函数:
ProcessState::ProcessState()
: mDriverFD(open_driver())
, mVMStart(MAP_FAILED)
, mManagesContexts(false)
, mBinderContextCheckFunc(NULL)
, mBinderContextUserData(NULL)
, mThreadPoolStarted(false)
, mThreadPoolSeq(1)
{
if (mDriverFD >= 0) {
mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
}
这里大有学问,即在构造ProcessState实例时,首先会open_driver,然后mmap。这里driver正是binder驱动,int fd = open("/dev/binder", O_RDWR);。
看来一个ProcessState关联了一个binder驱动,以此进行IPC通信。
继续看defaultServiceManager:
sp<IServiceManager> defaultServiceManager()
{
if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
{
AutoMutex _l(gDefaultServiceManagerLock);
while (gDefaultServiceManager == NULL) {
gDefaultServiceManager = interface_cast<IServiceManager>(
ProcessState::self()->getContextObject(NULL));
if (gDefaultServiceManager == NULL)
sleep(1);
}
}
return gDefaultServiceManager;
}
仍然是一个单例模式,这个gDefaultServiceManager就是ServiceManager的一个IServiceManager,其实质是一个BpBinder(即native层的Binder代理),BpBinder将通过IPCThreadState与Binder驱动通信。
继续看MediaPlayerService::instantiate();
void MediaPlayerService::instantiate() {
defaultServiceManager()->addService(
String16("media.player"), new MediaPlayerService());
}
这里如同java层一样,用addService将media.player服务加入到ServiceManager中进行管理。需要注意的是其中的代理关系:
./av/media/libmedia/IMediaPlayerService.cpp
class BpMediaPlayerService: public BpInterface<IMediaPlayerService>
./av/include/media/IMediaPlayerService.h
class IMediaPlayerService: public IInterface
class BnMediaPlayerService: public BnInterface<IMediaPlayerService>
class MediaPlayerService : public BnMediaPlayerService
从类的继承关系来看,服务端为BnMediaPlayerService;客户端(代理端)为BpMediaPlayerService;而我们从ServiceManager中getService得到的是代理端,这和java层的一样。所以真正实现功能的是MediaPlayerService。
把这个关系理清楚了,整个binder IPC思路将会清楚很多。再补充一句,在native层代理工作的代码是手动写的,而java层可以用AIDL工具生成。
media.player注册之后,作为服务端肯定要进入一个死循环,进行重复工作:事件侦听-处理-事件侦听。
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
void ProcessState::startThreadPool()
{
pawnPooledThread(true);
}
void ProcessState::spawnPooledThread(bool isMain)
{
sp<Thread> t = new PoolThread(isMain);
String8 name = makeBinderThreadName();
t->run(name.string());
}
String8 ProcessState::makeBinderThreadName() {
int32_t s = android_atomic_add(1, &mThreadPoolSeq);
String8 name;
name.appendFormat("Binder_%X", s);
return name;
}
class PoolThread : public Thread
这里的Thread来自./system/core/include/utils/threads.h
新创建一个PoolThread后,这就是所谓的binder线程。在进程全局且唯一的ProcessState对象中,有一个已经创建的binder线程的计数器mThreadPoolSeq,每创建一个新的线程,这个计数器就会加1。在ProcessState::makeBinderThreadName()函数中,会根据当前的binder线程计数器的值来构造新创建的binder线程的线程名”Binder_%X”,从而可以根据线程名来识别各个不同的binder线程。其中最多能创建15个的binder线程。
接下来调用run:
status_t Thread::run(const char* name, int32_t priority, size_t stack)
{
Mutex::Autolock _l(mLock);
res = androidCreateRawThreadEtc(_threadLoop,
this, name, priority, stack, &mThread);
最后调用IPCThreadState::joinThreadPool
void IPCThreadState::joinThreadPool(bool isMain) {
do {
result = getAndExecuteCommand();
if (result < NO_ERROR && result != TIMED_OUT && result != -ECONNREFUSED && result != -EBADF) {
abort();
}
// Let this thread exit the thread pool if it is no longer
// needed and it is not the main process thread.
if(result == TIMED_OUT && !isMain) {
break;
}
} while (result != -ECONNREFUSED && result != -EBADF);
talkWithDriver(false);
}
status_t IPCThreadState::getAndExecuteCommand()
{
status_t result;
int32_t cmd;
result = talkWithDriver();
if (result >= NO_ERROR) {
size_t IN = mIn.dataAvail();
if (IN < sizeof(int32_t)) return result;
cmd = mIn.readInt32();
IF_LOG_COMMANDS() {
alog << "Processing top-level Command: "
<< getReturnString(cmd) << endl;
}
result = executeCommand(cmd);
set_sched_policy(mMyThreadId, SP_FOREGROUND);
}
return result;
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr);
}
joinThreadPool主要以轮循的方式获取binder驱动数据,数据分为读、写数据,然后进行处理。
至此,mediaservice以media.player服务为例分析结束,主要理清了native层的服务的IPC通路,和服务“动”起来的原理。
下一节将分析多媒体一个重要的服务:MediaPlayerService。
本文探讨了Android多媒体服务中的Mediaserver,从init进程开始,详细解析了如何启动Mediaserver及其与网络的交互。重点在于Mediaserver如何通过binder IPC工作,分析了ProcessState、ServiceManager以及MediaPlayerService的角色和交互过程,阐述了binder线程的创建和工作原理,为理解Android多媒体服务的内部运作提供了清晰的思路。
5188

被折叠的 条评论
为什么被折叠?



