mediaserver的启动

Android  源码分析  2023年8月8日 am8:08发布1年前 (2023)更新 91es.com站长
75 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、 本站申明: 个人流水账日记,内容并不保证有效

暂无评论

暂无评论...

随机推荐

许立志:我咽下一枚铁做的月亮

我咽下一枚铁做的月亮他们把它叫做螺丝 我咽下这工业的废水,失业的订单那些低于机台的青春早早夭亡 我咽下奔波,咽下流离失所咽下人行天桥,咽下长满水锈的生活 我再咽不下了所有我曾经咽下的现在都从喉咙汹涌而出在祖国的领土上铺成一首耻辱的诗 ​

Cygwin安装教程简介

前言cygwin是一个在windows平台上运行的unix模拟环境,是cygnus solutions公司开发的自由软件。Cygwin就是一个windows软件,该软件就是在windows上仿真linux操作系统。正文Cygwin 下载链接: Cygwin官方网站点击下: Install...

[摘]Android源码之init.rc文件规则和init.c解析

前言本文主要讲解Android源码之init.rc文件规则和init.c解析。本文摘抄网上大牛的文章(链接文末),方便自己查阅。多谢分享。正文init.c与init.rc在源码中的位置:init.c : /system/core/initinit.rc : /system/core...

新建工程,导入旧的module,出现Android Studio duplicate entry xx.class

前言这个是导入SystemUI时出现的,记录一下,方便自己查阅。好记性不如烂笔头正文导入旧的module后出现:Cause: duplicate entry: androidx/core/R$attr.class更多日志Execution failed for task ':Sys...

CountDownTimer音量值淡入淡出

前言有时候播放开始播放和暂停时,需要做一个淡入淡出的效果,要不然急速暂停或播放,容易出现尖锐的杂音。正文显示对MediaPlayer播放和暂停时音量淡入和淡出代码片段。隐藏内容!付费阅读后才能查看!¥1 ¥3多个隐藏块只需支付一次付费阅读

《MySQL基础教程》笔记6

前言主要是记录一下update和delete命令的使用。根据《MySQL基础教程-西泽梦路》学习,简单的做一下笔记。记录于此,方便自己回忆。正文我这以Window版的phpstudy软件验证。需要进入这个目录,才可以使用mysql命令D:\phpstudy_pro\Extensions...