0. 前言
最近计划在写这个关于Android音视频框架的专栏,一是回顾和整理之前工作时碰到过的一些Android底层知识,二是想更了解以下Android上的音视频架构。今天先介绍下Android中多媒体系统服务MediaServer。
1 SystemServices 系统服务
在Android系统架构中,SystemServices是一类模块化、功能集中的系统功能提供者。它们往往以native进程的形式运行在系统中,App可以通过Android Framework API调用,通过Binder来对他们进行访问,以获得操作底层硬件的能力。常见的系统服务进程包括:
- SurfaceFlinger:Android的显示管理器,负责合成和渲染不同应用窗口的内容。
- system_server:包含各类的管理服务,如进行窗口相关的操作会用到窗口管理服务WindowManager,进行电源相关的操作会用到电源管理服务PowerManager,如通知管理服务NotifacationManager、振动管理服务Vibrator、电池管理服务BatteryManager等等。
- CameraServer:Android的相机服务,为上层提供访问相机的能力,可以通过Camera2 API访问。
- MediaServer:专用于处理多媒体,提供播放,编解码能力,App可以通过MediaPlayer,MediaCodec系列API进行访问。
- ServiceManager:义如其名,Services的管理者,是Binder通信的基础,为Binder通信提供对象(名字)查找的功能。
p.s. 这里谈论到的SystemServices要和两个概念相区分:
(1)Service,Android的应用层四大组件之一,它是一个后台运行的组件,执行长时间运行且不需要用户交互的任务,由应用层定义和使用。
(2)system_server,上面也提及到了,system_server包含很多系统的管理服务,但它并不和框架层级上的SystemServices划等号,只是Android中其中的一个系统服务提供者,仍然有其他的系统设备服务独立于它,与之平级。
2. MediaServer
Android中的多媒体服务的覆盖范围很广,主要包括为App提供音视频格式解析、播放显示功能、编解码、音频混音、相机拍摄和录制等。
在Android 7.0以前,整体的多媒体服务均由单一的进程MediaServer提供,该进程包含众多的权限(相机访问权限、音频访问权限、视频驱动程序访问权限、文件访问权限、网络访问权限等)。在7.0之后,MediaServer被拆分成多个进程,所需要的权限也因此被划分到各个进程。现如今MediaServer是其中主要负责多媒体资源管理,硬件和软件编解码功能的一个系统服务。
3 MediaServer的启动
在Android系统中,MediaServer进程由init进程创建。在Linux系统中,init进程是内核启动的第一个用户空间进程,它的进程号总是1。当bootloader启动后,系统会启动kernel,kernel启动完后,会在用户空间启动init进程。init创建后,会挂载文件系统,挂载对应的分区,启动selinux安全策略,最后会通过配置的.rc文件,启动一系列系统服务。
这里借用《Android MultiMedia框架完全解析 - 从开机到MediaServer的注册过程》中的一张图来说明。init进程会启动一系列的系统服务,比如Zygote,它是Android系统的第一个Java进程,也是所有的Java进程的父进程。Zygote会孵化出System_Server,上文中有提及过该进程会包含系统各方面的管理服务。init进程还会孵化出ServiceManager,该线程用于Binder通信,为它们提供Binder对象(名字)查找的功能。 MediaServer在图中属于Native Services一类,它会向ServiceManager注册自己,等待后续App的调用。
4. 具体的构建和调用过程
MediaServer的代码在Android源码的frameworks/av/media/mediaserver/
目录下,可以通过谷歌的Android Code Search访问到对应的代码。我们可以重点看下Android.bp了解其构建过程。
我们截取了Android.bp文件下的一部分来说明,这里会编译一个C++的二进制文件mediaserver
,其最后的产物会放在/system/bin/mediaserver
,mediaserver的编译控制中有一个条件编译选项TARGET_DYNAMIC_64_32_MEDIASERVER
, 但是一般也没有打开,换言之用的默认选项只设置类init_rc
属性。而init_rc
属性,会在编译后将会把本目录下的mediaserver.rc
放入到系统的目录system/etc/init
下。
swift
// 编译产物是二进制的可执行文件mediaserver
mediaserver_cc_binary {
name: "mediaserver",
defaults: ["libcodec2_hal_selection"],
// 输入的source只有同目录下的main_mediaserver.cpp
srcs: ["main_mediaserver.cpp"],
// mediaserver的一些更细致的任务,都单独编译进了具体的lib之中
shared_libs: [
"[email protected]",
"libicu",
"libfmq",
"libbinder",
"libbinder_ndk",
"libhidlbase",
"liblog",
"libmediaplayerservice",
"libresourcemanagerservice",
"libutils",
],
static_libs: [
"libregistermsext",
],
// By default mediaserver runs in 32-bit to save memory, except
// on 64-bit-only lunch targets.
// ****************************************************************
// TO ENABLE 64-BIT MEDIASERVER ON MIXED 32/64-BIT DEVICES, COMMENT
// OUT THE FOLLOWING LINE:
// ****************************************************************
compile_multilib: "prefer32",
cflags: [
"-Werror",
"-Wall",
],
vintf_fragment_modules: ["manifest_media_c2_software.xml"],
soong_config_variables: {
// 一个条件编译选项,但是默认情况是没有打开
TARGET_DYNAMIC_64_32_MEDIASERVER: {
compile_multilib: "both",
multilib: {
lib32: {
suffix: "32",
},
lib64: {
suffix: "64",
},
},
required: [
"mediaserver.zygote64_32.rc",
"mediaserver.zygote64.rc",
],
init_rc: ["mediaserver_dynamic.rc"],
// 默认情况下,只设置了init_rc
conditions_default: {
init_rc: ["mediaserver.rc"],
},
},
},
}
所以,我们能在Android的system/bin/
下看到mediaserver
,这个就是服务的可执行文件。 配套的,我们能在
system/etc/init/
下找到对应的配置文件mediaserver.rc
。
当init进程启动后,就会解析/system/etc/init/
目录下的.rc配置文件。以下是init进程源码中,查找启动script的方法。
c++
static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list) {
Parser parser = CreateParser(action_manager, service_list);
std::string bootscript = GetProperty("ro.boot.init_rc", "");
if (bootscript.empty()) {
parser.ParseConfig("/system/etc/init/hw/init.rc");
if (!parser.ParseConfig("/system/etc/init")) { // 这里就会解析和调用/system/ect/init下的配置文件,启动MediaServer服务。
late_import_paths.emplace_back("/system/etc/init");
}
// late_import is available only in Q and earlier release. As we don't
// have system_ext in those versions, skip late_import for system_ext.
parser.ParseConfig("/system_ext/etc/init");
if (!parser.ParseConfig("/vendor/etc/init")) {
late_import_paths.emplace_back("/vendor/etc/init");
}
if (!parser.ParseConfig("/odm/etc/init")) {
late_import_paths.emplace_back("/odm/etc/init");
}
if (!parser.ParseConfig("/product/etc/init")) {
late_import_paths.emplace_back("/product/etc/init");
}
} else {
parser.ParseConfig(bootscript);
}
}
此后,MediaServer
正常启动,我们可以通过ps在手机中查到对应的进程,可以看见其父进程的pid就是1,正是刚刚上文中提到的init
进程。
5. MediaServer的主逻辑
我们简单看一下MediaServer
的主要逻辑。MediaServer
进程的入口在frameworks/av/media/mediaserver/main_mediaserver.cpp
中。可以看见,它在main函数中主要进行
c++
int main(int argc __unused, char **argv __unused)
{
signal(SIGPIPE, SIG_IGN);
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm(defaultServiceManager()); // 这里拿到全局的serviceManager
ALOGI("ServiceManager: %p", sm.get());
MediaPlayerService::instantiate(); // 实例化MediaPlayerService服务
ResourceManagerService::instantiate(); // 实例化ResourceManagerService服务
registerExtensions();
bool aidl = ::android::IsCodec2AidlHalSelected();
if (!aidl) {
::android::hardware::configureRpcThreadpool(kCodecThreadPoolCount, false);
} else {
ABinderProcess_setThreadPoolMaxThreadCount(
kCodecThreadPoolCount + kDefaultBinderThreadPoolCount);
}
ProcessState::self()->startThreadPool(); // 进入循环,监听Binder事件。
IPCThreadState::self()->joinThreadPool();
}
MediaPlayerService::instantiate()
方法,便是创建一个MediaPlayerService
服务,并向ServiceManager
进行注册。
C++
void MediaPlayerService::instantiate() {
defaultServiceManager()->addService(
String16("media.player"), new MediaPlayerService());
}
// MediaPlayerService是继承自BnMediaPlayerService,是具体实现了IMediaPlayerService的Binder服务端
// class MediaPlayerService : public BnMediaPlayerService
而ResourceManagerSerResourceManagerService::instantiate()
方法,也是类似的
C++
void ResourceManagerService::instantiate() {
// ResourceManagerService继承自BnResourceManagerService,也是Binder对象
std::shared_ptr<ResourceManagerService> service = Create();
binder_status_t status =
AServiceManager_addServiceWithFlags(
service->asBinder().get(), getServiceName(),
AServiceManager_AddServiceFlag::ADD_SERVICE_ALLOW_ISOLATED);
if (status != STATUS_OK) {
return;
}
// ResourceObserverService继承自BnResourceObserverService的Binder对象,与ResourceManagerService一起使用
std::shared_ptr<ResourceObserverService> observerService =
ResourceObserverService::instantiate();
if (observerService != nullptr) {
service->setObserverService(observerService);
}
// TODO: mediaserver main() is already starting the thread pool,
// move this to mediaserver main() when other services in mediaserver
// are converted to ndk-platform aidl.
//ABinderProcess_startThreadPool();
}
我们可以看到,MediaServer
的主逻辑其实就是创建了MediaPlayerService
和ResourceManagerService
这两个Service,其后续的工作也因此分担至两个具体的Service之中。后续我们将从App的使用,具体来分析他们的作用。