Android多媒体研究之mediaservice

本文探讨了Android多媒体服务中的Mediaserver,从init进程开始,详细解析了如何启动Mediaserver及其与网络的交互。重点在于Mediaserver如何通过binder IPC工作,分析了ProcessState、ServiceManager以及MediaPlayerService的角色和交互过程,阐述了binder线程的创建和工作原理,为理解Android多媒体服务的内部运作提供了清晰的思路。

多媒体和网络在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。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值