mediaserver的启动

Android  源码分析  2023年8月8日 am8:08发布1年前 (2023)更新 城堡大人
117 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、 本站名称: 笔友城堡
2、 本站网址: https://www.biumall.com/
3、 本站部分文章来源于网络,仅供学习与参考,如有侵权,请留言

暂无评论

暂无评论...

随机推荐

XmlPullParser简单使用

前言本文记录一下Android中XmlPullParser 对xml的解析记录。记录于此,方便自己查阅。正文xml介绍XML: Extentsible Markup Language(可扩展标记语言)的缩写,它的格式与HTML文件的格式类似,xml是使用自定义标记来定义对象和每个对象中的数...

Unable to make field

前言升级新版本Android Studio后倒入部分工程出现如下问题:Unable to make field private final java.lang.String java.io.File.path accessible: module java.base does not "ope...

Android添加保护广播protected-broadcast

前言monkey测试时,在Android原生设置点击多用户,也就是新创建了用户,导致system进程发送的无法接受到。03-30 09:35:31.829 3827 4459 E ActivityManager: Sending non-protected broadcast droi...

Exoplayer简单实用

前言记录一下ExoPlayer的简单使用,记录于此,方便自己查阅。正文ExoPlayer 是 Media3 中此接口的默认实现。与 Android 的 MediaPlayer API 相比,它增加了额外的便利性,例如支持多种流式传输协议、默认音频和视频渲染程序以及处理媒体缓冲的组件。Exo...

Android截图命令总结

前言简单记录一下Android设备多个屏幕或单个屏幕的截图方式。记录一下,方便自己查阅。正文查看displayId查看有屏幕的displayIdadb shell dumpsys window displays | grep displayIdubuntu$ adb shell d...

Android创建Widget

前言简单的记录一下Android小部件Widget的创建,Widget也就是Launcher界面上的小部件,很实用的一个功能。主要实现:创建小部件和参数介绍添加小部件View的点击事件等记录一下,方便自己查阅。正文个人流水,不一定适合您隐藏内容!付费阅读后才能...