mediaserver的启动

Android  源码分析  2023年8月8日 am8:08发布1年前 (2023)更新 91es.com站长
90 0 0

前言

之前介绍MediaPlayer的使用,上次写过《MediaPlayer JNI层介绍》,发现很多方法都是都是

# //BpMediaPlayer.prepareAsync()
mPlayer->start()

调用,而且BpMediaPlayer也只是代理而已,真正调用的还是另有其人。

通过百度或谷歌,知道媒体相关的内部跟mediaserver有关系,因此提前介绍一下mediaserver的启动。

正文

涉及文件

system\core\init\init.cpp
frameworks\av\media\mediaserver\mediaserver.rc
frameworks\av\media\mediaserver\main_mediaserver.cpp

frameworks\native\libs\binder\IServiceManager.cpp

frameworks\av\media\libmediaplayerservice\MediaPlayerService.cpp
frameworks\av\media\libmediaplayerservice\MediaPlayerService.h
frameworks\av\media\libmediaplayerservice\MediaPlayerFactory.cpp

mediaserver启动

我们知道,大部分服务都是在init中启动,mediaserver也不例外。Android7之后,mediaserver的启动是放在mediaserver.rc中

# mediaserver.rc
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
    writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks

或许你会好奇那啥时候解析mediaserver.rc文件呢?

在Android中,init的启动后会遍历设备中的/system/etc/init目录,而且这个目录中有很多.rc文件

# 部分(随机删除过)
hwservicemanager.rc
mediaserver.rc
servicemanager.rc
statsd.rc
storaged.rc
surfaceflinger.rc
tombstoned.rc
wait_for_keymaster.rc
wifi-events.rc
wificond.rc
# init.cpp
static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list) {
    Parser parser = CreateParser(action_manager, service_list);
    std::string bootscript = GetProperty("ro.boot.init_rc", "");
    //看是否有值,如果有就解析bootscript
    if (bootscript.empty()) {
        parser.ParseConfig("/init.rc");
        //解析/system/etc/init目录中的rc
        if (!parser.ParseConfig("/system/etc/init")) {
            late_import_paths.emplace_back("/system/etc/init");
        }
        //定制rc文件启动
        if (!parser.ParseConfig("/product/etc/init")) {
            late_import_paths.emplace_back("/product/etc/init");
        }
    } else {
        parser.ParseConfig(bootscript);
    }
}

所以mediaserver在上面中启动的,对应的代码是main_mediaserver.cpp

main_mediaserver.cpp

代码很少

int main(int argc , char **argv )
{
    //ProcessState初始化
    sp<ProcessState> proc(ProcessState::self());
    //BpServiceManager初始化,其实就是跟ServiceManager搭上关系,用于通信
    sp<IServiceManager> sm(defaultServiceManager());
    InitializeIcuOrDie();
    //MediaPlayerService初始化[重点,本文只关心这块]
    MediaPlayerService::instantiate();
    //ResourceManagerService初始化
    ResourceManagerService::instantiate();
    registerExtensions();
    //启动线程池
    ProcessState::self()->startThreadPool();
    //加入线程池
    IPCThreadState::self()->joinThreadPool();
}

这里不关注服务的添加和其他的哈,只关注MediaPlayerService的启动,后面其他地方需要分析。

进入MediaPlayerService

 MediaPlayerService::instantiate();

MediaPlayerService.cpp

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

至于defaultServiceManager(),这里稍微提一下,哈哈 很多地方都有这个,单例模式,

IServiceManager::defaultServiceManager()
//BpServiceManager,在interface_cast中进行转换的
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;
}

也是单例模式,通过之前文章(《interface_cast简介》)对interface_cast有一定的了解,那就可以得出 defaultServiceManager()放回的就是BpServiceManager,也就是ServiceManager的代理。

addService

addService()等分析MediaPlayerService时在介绍哈,

意思是MediaPlayerService注册ServiceManager进行统一管理,其他地方可通过getService()获取MediaPlayerService。

我们关注MediaPlayerService对象的创建。

new MediaPlayerService();
MediaPlayerService构造函数

进入MediaPlayerService构造函数

MediaPlayerService::MediaPlayerService(){
    mNextConnId = 1;
    MediaPlayerFactory::registerBuiltinFactories();
}

继续看registerBuiltinFactories()

void MediaPlayerFactory::registerBuiltinFactories() {
    Mutex::Autolock lock_(&sLock);
    //第一次为sInitComplete= 0,下面会赋值,也就是后面不会再次进入了。
    if (sInitComplete)
        return;
    //初始化NuPlayerFactory
    IFactory* factory = new NuPlayerFactory();
    //如果注册失败就delete
    if (registerFactory_l(factory, NU_PLAYER) != OK)
        delete factory;
    //下面是TestPlayerFactory
    factory = new TestPlayerFactory();
    if (registerFactory_l(factory, TEST_PLAYER) != OK)
        delete factory;
    sInitComplete = true;
}

重点是NuPlayerFactory对象,然后注册registerFactory_l()

registerFactory_l()
registerFactory_l(factory, NU_PLAYER)

第一个参数是NuPlayerFactory对象,第二个是NU_PLAYER类型(枚举类型)。

enum player_type {
    STAGEFRIGHT_PLAYER = 3,
    NU_PLAYER = 4,
    TEST_PLAYER = 5,
};

进入registerFactory_l()

status_t MediaPlayerFactory::registerFactory_l(IFactory* factory,player_type type) {
    if (NULL == factory) {
        return BAD_VALUE;
    }
	//判断当前类型的factory是否存在
    if (sFactoryMap.indexOfKey(type) >= 0) {
        return ALREADY_EXISTS;
    }
    //通过类型索引添加factory
    if (sFactoryMap.add(type, factory) < 0) {
        return UNKNOWN_ERROR;
    }
    return OK;
}

sFactoryMap集合通过类型进行存储对应的IFactory,因为上面只初始化一次,后面需要直接通过类型获取。

至此,MediaPlayerService的启动和初始化都启动了。

这里顺带说一下NuPlayerFactory哈。

NuPlayerFactory

在MediaPlayerFactory.cpp中定义。

class NuPlayerFactory : public MediaPlayerFactory::IFactory {
  public:
	//略
    virtual sp<MediaPlayerBase> createPlayer(pid_t pid) {
		//重点
        return new NuPlayerDriver(pid);
    }
};

部分省略,重点就是createPlayer(),返回的是NuPlayerDriver对象。

小结

  1. init解析mediaserver.rc启动mediaserver

  2. 获取ServiceManager的代理把mediaserver添加到服务列表,以供其他需要的获取

  3. 注册NuPlayerFactory到sFactoryMap,以便需要的获取

参考文章

  1. mediaserver创建

  2. Android P (9.0) 之Init进程源码分析

  3. Android 7.0 init.rc mediaserver

  4. Android MultiMedia框架——mediaserver启动

  5. Binder系列5—注册服务(addService)

 历史上的今天

  1. 2022: [摘]CMakeLists.txt常用语法之常用命令(0条评论)
  2. 2020: [摘]WindowManager.LayoutParams的各种flag含义(0条评论)
版权声明 1、 本站名称: 91易搜
2、 本站网址: 91es.com3xcn.com
3、 本站内容: 部分来源于网络,仅供学习和参考,若侵权请留言
3、 本站申明: 个人流水账日记,内容并不保证有效

暂无评论

暂无评论...

随机推荐

《MySQL基础教程》笔记4

前言本文主要是select语句的使用学习一下MySQL,一直没有系统的学习一下。最近有空,看了《MySQL基础教程-西泽梦路》,简单的做一下笔记。记录于此,方便自己回忆。MySQL中对大小写没有区分,我这里习惯性用小些。正文我这以Window版的phpstudy软件验证。需要进入...

Application多次初始化

前言如果一个apk中在设置多进程,也就是在AndroidManifest.xml中,通过android:process属性配置。<activity   android:name=".OneActivity"   android:exported="true"   androi...

Android Jetpack - Navigation的简单使用

前言Android Jetpack的Navigation确实好用,这里就简单记录一下,方便自己查阅。这个出来了很久了,但也就偶尔用用,用完就忘了,正应了微信之父张小龙的名言[用完即走]。PS: 好记性不如烂笔头。正文Jetpack的导航组件——Navigation,就可以很方便的管理各f...

Android子线程是否可以更新UI么

前言本文内容主要摘抄[Android子线程是否可以刷新UI],这里只做简单的总结,具体还是看参考文章,谢谢。记录于此,只是方便自己查阅。小结Android子线程(非UI线程)可以刷新UI,前提条件是有自己的ViewRoot。Activity的onCreate()周期时可以在子线程...

张小娴:有女人爱的男人

从来没有光顾过这么“雅致”的的士。三十来岁的司机衣着整齐,精神爽利,与证件上的照片一样,不像大部分的的士司机,相片比真人至少年轻十多岁。车上的椅套光洁如新,车尾玻璃窗下面,放着一件叠好的风衣,数盒柠檬茶、菊花茶,几瓶矿泉水,还有香口珠,我差点以为是拿来卖给乘客的。“是我太太放在这里的。夏天嘛,乘客...

莎士比亚:你的长夏永远不会凋谢

我怎能够把你来比拟作夏天?你不独比他可爱也比他温婉;狂风把五月宠爱的嫩蕊作践夏天出赁的期限又未免太短;天上的眼睛有时照得太酷烈,他那炳耀的金颜又常遭掩蔽;给机缘或无偿的天道所摧残,没有芳颜不终于凋残或销毁。但你的长夏将永远不会凋落,也不会损失你这皎洁...