mediaserver的启动

Android  源码分析  2023年8月8日 am8:08发布1年前 (2023)更新 91es.com站长
110 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.com
3、 本站内容: 部分来源于网络,仅供学习和参考,若侵权请留言
3、 本站申明: 个人流水账日记,内容并不保证有效

暂无评论

暂无评论...

随机推荐

触发了v2ex.com某些机制,被禁止访问

前言尴尬,触发了v2ex.com某些机制,被禁止访问。Google Chrome提示访问 v2ex.com 的请求遭到拒绝您未获授权,无法查看此网页。HTTP ERROR 403微软 Edge提示访问 v2ex.com 被拒绝你没有查看此页面的用户权限。HTTP ERROR 403...

佚名 :可是你没有

我记得那天我借用你的新车,我弄坏了它我以为你一定会杀了我可是你没有 我记得那天我拖你去海滩,而它真如你所说的下雨了我以为你会说“我告诉过你 '可是你没有 我记得那天我和所有男人调情好让你嫉妒,而你真的嫉妒了我以为你一定会离开我可是你没有 ...

Android中判断Service是否启动了

前言偶然需要使用,记录于此。好记性不如烂笔头正文使用getRunningServices获取运行的服务有时候需要盘服务是否启动,如果没有启动就需要拉起来PS:SERVICE_PACKAGENAME和SERVICE_NAME分别是定义的包名和服务包名,这里省略。 /** ...

余光中:等你 在雨中

等你 在雨中 在造虹的雨中蝉声沉落 蛙声升起一池的红莲如红焰 在雨中 你来不来都一样 竟感觉每朵莲都像你尤其隔著黄昏 隔著这样的细雨 永恒 刹那 刹那 永恒等你 在时间之外在时间之内 等你 在刹那 在永恒 如果你的手在我的手里 此刻如果你的清芬...

PhoneStatusBar初始化分析

接上一篇《SystemUI源码分析之PhoneStatusBar启动流程简单分析》,我们简单的了解了是怎么启动PhoneStatusBar的,同时也知道在PhoneStatusBar的start()方法中主要执行了如下几个步骤:一、createAndAddWindows()二、addN...

梁实秋:快乐

天下最快乐的事大概莫过于做皇帝。“首出庶物,万国咸宁”。至不济可以生杀予夺,为所欲为。至于后宫粉黛三千,御膳八珍罗列,更是不在话下。清乾隆皇帝,“称八旬之觞,镌十全之宝”,三下江南,附庸风雅。那副志得意满的神情,真是不能不令人兴起“大丈夫当如是也”的感喟。在穷措大眼里,九五之尊,乐不可支。但是试起...