AudioServer是被init拉起来的一个deamon程序,其rc文件如下:
bash
//frameworks/av/media/audioserver/audioserver.rc
service audioserver /system/bin/audioserver
class core
user audioserver
# media gid needed for /dev/fm (radio) and for /data/misc/media (tee)
group audio camera drmrpc media mediadrm net_bt net_bt_admin net_bw_acct wakelock
capabilities BLOCK_SUSPEND
# match rtprio cur / max with sensor service as we handle AR/VR HID sensor data.
rlimit rtprio 10 10
ioprio rt 4
task_profiles ProcessCapacityHigh HighPerformance
onrestart restart vendor.audio-hal
onrestart restart vendor.audio-hal-aidl
onrestart restart vendor.audio-effect-hal-aidl
onrestart restart vendor.audio-hal-4-0-msd
onrestart restart audio_proxy_service
audioserver 是 Android 系统中一个至关重要的原生守护进程(native daemon)。它的核心任务是初始化并托管 Android 系统中最关键的几个音频服务,包括:
AudioFlinger: 负责所有音频数据的混音、处理和最终输出到硬件。它是音频系统的核心。AudioPolicyService: 负责音频策略管理,如决定音频路由(声音从扬声器、耳机还是蓝牙播放)、音量控制、设备选择等。AAudioService: 提供现代化的低延迟音频 API(AAudio)的后端服务。
main函数的职责就是按照正确的顺序创建、初始化这些服务,并将它们注册到系统的 ServiceManager 中,以便其他应用和系统服务可以访问它们。
cpp
// frameworks/av/media/audioserver/main_audioserver.cpp
int main(int argc __unused, char **argv __unused)
{
SLOGI("%s: starting", __func__);
// 获取当前系统时间并保存,用于在函数末尾计算整个初始化过程耗费了多长时间
const auto startTime = std::chrono::steady_clock::now();
// 限制当前进程(audioserver)的最大内存使用量,使用 setrlimit(RLIMIT_AS) 限制进程可以
// 分配的内存量。要使用的值将从指定的系统属性中读取;如果该属性不存在,
// 则将使用指定的字节数或总内存的指定百分比,以较小者为准。
// 参数1 "audio.maxmem" : 对应的ro.audio.maxmem系统属性名
// 参数2 : 绝对上限值(512MB)
// 参数3 : 相对物理内存的百分比上限(20%)
// 这可以防止音频服务出现内存泄漏时耗尽整个系统的内存
limitProcessMemory(
"audio.maxmem", /* "ro.audio.maxmem", property that defines limit */
(size_t)512 * (1 << 20), /* SIZE_MAX, upper limit in bytes */
20 /* upper limit as percentage of physical RAM */);
// 忽略 SIGPIPE 信号。在进行 Socket 或管道通信时,如果对端已经关闭,
// 本端继续写入会导致程序收到 SIGPIPE 信号并默认崩溃。忽略此信号可让程序改为接收一个
// 错误码而不是直接崩溃
signal(SIGPIPE, SIG_IGN);
// 配置 HIDL/AIDL 的硬件抽象层(HAL)RPC 通信线程池,最大线程数为 4。
// false 表示当前调用者稍后不会主动加入该线程池
android::hardware::configureRpcThreadpool(4, false /*callerWillJoin*/);
// 启动 Binder 线程池。这是为了让 audioserver
// 能够处理来自其他进程的 Binder 回调和跨进程调用
ProcessState::self()->startThreadPool();
// 为了避免 AudioFlinger 提前暴露给外部导致在 AudioPolicy 初始化完成前
// 被错误调用从而引发崩溃或超时,代码选择在本地同一个进程内先创建好这两个服务,
// 相互绑定后,再统一注册到 ServiceManager。
const auto af = sp<AudioFlinger>::make();
const auto afAdapter = sp<AudioFlingerServerAdapter>::make(af);
// 其af设置为当前进程的本地实例-保存到AudioSystem
AudioSystem::setLocalAudioFlinger(af);
const auto aps = sp<AudioPolicyService>::make();
// 将刚刚创建的音频策略服务实例传递给 AudioFlinger,完成它们在内部的相互绑定
af->initAudioPolicyLocal(aps);
// 其aps设置为当前进程的本地实例
AudioSystem::setLocalAudioPolicyService(aps);
// Start initialization of internally managed audio objects such as Device Effects.
// 通知 AudioPolicyService 整个音频系统内部对象已经准备就绪,可以开始初始化底层音频设备
//(如加载 Device Effects 等)
aps->onAudioSystemReady();
// Add AudioFlinger and AudioPolicy to ServiceManager.
sp<IServiceManager> sm = defaultServiceManager();
// 将afAdapter注册为media.audio_flinger服务
sm->addService(String16(IAudioFlinger::DEFAULT_SERVICE_NAME), afAdapter,
false /* allowIsolated */, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT);
// 将aps注册为media.audio_policy服务
sm->addService(String16(AudioPolicyService::getServiceName()), aps,
false /* allowIsolated */, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT);
// 准备查询系统是否支持 MMAP(内存映射)模式的音频传输。MMAP 是实现
// AAudio(Android 低延迟音频 API)的关键机制
std::vector<AudioMMapPolicyInfo> policyInfos;
// 向底层查询当前的 MMAP 策略信息并存入 policyInfos 列表中。
status_t status = AudioSystem::getMmapPolicyInfos(
AudioMMapPolicyType::DEFAULT, &policyInfos);
// policyInfos 中任意一个(std::any_of)策略是 AUTO 或 ALWAYS
//(即系统支持并允许 MMAP 机制)
if (status == NO_ERROR &&
std::any_of(policyInfos.begin(), policyInfos.end(), [](const auto& info) {
return info.mmapPolicy == AudioMMapPolicy::AUTO ||
info.mmapPolicy == AudioMMapPolicy::ALWAYS;
})) {
// 实例化并启动 AAudioService 服务
AAudioService::instantiate();
} else {
// ......
}
// 获取初始化完成时的当前时间
const auto endTime = std::chrono::steady_clock::now();
// 通知 AudioFlinger 初始化流程彻底完成
af->startupFinished();
using FloatMillis = std::chrono::duration<float, std::milli>;
const float timeTaken = std::chrono::duration_cast<FloatMillis>(
endTime - startTime).count();
// 显示整个音频服务启动初始化所消耗的时间
SLOGI("%s: initialization done in %.3f ms, joining thread pool", __func__, timeTaken);
// 调用这一行后,主线程将无限期地阻塞在这里,专门负责监听和处理来自其他进程的
// Binder 请求(也就是客户端发来的音频请求)。直到系统关机或 audioserver 进程被杀死,
// 程序才可能退出
IPCThreadState::self()->joinThreadPool();
}
limitProcessMemory
限制当前进程(audioserver)的最大内存使用量,以防止内存泄漏导致耗尽整个系统的内存。使用 setrlimit(RLIMIT_AS) 限制进程可以分配的内存量。要使用的值将从指定的系统属性中读取;如果该属性不存在,则将使用指定的字节数或总内存的指定百分比,以较小者为准。
- 如果系统使用了 Scudo 内存分配器(Android 11 及以后的默认分配器),代码调用了
__scudo_set_rss_limit,它严格限制的是进程的 RSS(常驻内存集,即实际占用的物理内存)。 - 如果走到了底部的
android_mallopt(M_SET_ALLOCATION_LIMIT_BYTES, ...),它限制的是 malloc 堆分配的总字节数上限。虽然 malloc 申请的是虚拟内存,但这种限制间接也限制了物理内存的增长。
参数说明 :
property:系统属性名称(例如上文传进来的 "audio.maxmem"),允许通过修改系统属性来强制覆盖内存限制。numberOfBytes:硬性限制的字节数上限(例如传入的 512MB)。percentageOfTotalMem:相对于设备总物理内存的百分比上限(例如传入的 20%)。
cpp
// frameworks/av/media/utils/LimitProcessMemory.cpp
void limitProcessMemory(const char *property, size_t numberOfBytes,
size_t percentageOfTotalMem) {
// 获取系统每一页内存的大小(通常是 4KB)
long pageSize = sysconf(_SC_PAGESIZE);
// 获取系统总的物理内存页数
long numPages = sysconf(_SC_PHYS_PAGES);
// 默认初始化为无限制 (SIZE_MAX)
size_t maxMem = SIZE_MAX;
if (pageSize > 0 && numPages > 0) {
if (size_t(numPages) < SIZE_MAX / size_t(pageSize)) {
// / 设备总物理内存(字节)
maxMem = size_t(numPages) * size_t(pageSize);
}
// 限制百分比不能超过 100%
if (percentageOfTotalMem > 100) {
percentageOfTotalMem = 100;
}
// 计算出百分比对应的物理内存大小
maxMem = maxMem / 100 * percentageOfTotalMem;
// 取"百分比计算值"和"传入的硬性上限值"中较小的那一个作为最终限制
if (numberOfBytes < maxMem) {
maxMem = numberOfBytes;
}
ALOGV("requested limit: %zu", maxMem);
} else {
ALOGW("couldn't determine total RAM");
}
// 尝试读取指定的系统属性(如 ro.audio.maxmem)
// 如果开发者或厂商配置了这个属性,那么使用属性值直接覆盖刚刚计算出来的 maxMem。
// 这为调试和不同硬件平台的定制留下了后门。
int64_t propVal = property_get_int64(property, maxMem);
if (propVal > 0 && uint64_t(propVal) <= SIZE_MAX) {
maxMem = propVal;
}
// If Scudo is in use, enforce the hard RSS limit (in MB).
// 检查当前系统是否链接了 Scudo 内存分配器(Android 默认的现代安全内存分配器)
if (maxMem != SIZE_MAX && &__scudo_set_rss_limit != 0) {
// 将字节数向右位移 20 位(相当于除以 1024 * 1024),将单位从 Bytes
// 转换为 Megabytes (MB)
// RSS 指常驻集大小(物理内存)。第二个参数 1 表示硬性上限,超限会被 Scudo 直接 OOM 终止,然后 return。
__scudo_set_rss_limit(maxMem >> 20, 1);
ALOGV("Scudo hard RSS limit set to %zu MB", maxMem >> 20);
return;
}
// M_SET_ALLOCATION_LIMIT_BYTES 用于限制堆内存分配总量;超过 maxMem 后,
// 后续 malloc/new 失败(返回 nullptr 或抛异常)。
if (!android_mallopt(M_SET_ALLOCATION_LIMIT_BYTES, &maxMem,
sizeof(maxMem))) {
ALOGW("couldn't set allocation limit");
}
}
总结
- 首先限制了当前进程可以申请的最大物理内存
- 创建了
AudioFlinger,AudioPolicyService,并将这两个实例保存在AudioSystem中.之后再将这两个实例分别注册为名为media.audio_flinger和media.audio_policy服务. - 根据是否支持
mmap,有条件的创建AAudioService