OpenHarmony 5.0 audio服务初始化失败分析
问题现象
在开机时没有开机铃声,音乐应用无法播放,systemui或者使用了getVolumeGroupManager接口的应用有如下日志报错甚至闪退等现象

分析过程
从日志中由上到下可以看到,加载默认设备超时->获取不到有效的音频组->获取音频组管理器失败,类似一个故障堆栈,那么调用顺序就应该是获取音频组管理器->获取音频组信息->加载默认设备,根据日志信息跟踪到对应代码
// foundation/multimedia/audio_framework/frameworks/js/napi/audiomanager/napi_audio_volume_group_manager.cpp
napi_value NapiAudioVolumeGroupManager::CreateAudioVolumeGroupManagerWrapper(napi_env env, int32_t groupId)
{
// Check whether the group id is valid.
auto groupManager = AudioSystemManager::GetInstance()->GetGroupManager(groupId);
if (groupManager == nullptr) {
AUDIO_ERR_LOG("Failed to get group manager!"); // GetGroupManager失败报错
NapiAudioVolumeGroupManager::isConstructSuccess_ = NAPI_ERR_INVALID_PARAM;
return NapiParamUtils::GetUndefinedValue(env);
}
...
}
// foundation/multimedia/audio_framework/services/audio_service/client/src/audio_group_manager.cpp
int32_t AudioGroupManager::Init()
{
// init networkId_
std::string netWorkId;
int32_t ret = AudioPolicyManager::GetInstance().GetNetworkIdByGroupId(groupId_, netWorkId);
if (ret == SUCCESS) {
netWorkId_ = netWorkId;
connectType_ = netWorkId_ == LOCAL_NETWORK_ID ? CONNECT_TYPE_LOCAL : CONNECT_TYPE_DISTRIBUTED;
AUDIO_INFO_LOG("AudioGroupManager::init set networkId %{public}s.", netWorkId_.c_str());
} else {
AUDIO_ERR_LOG("AudioGroupManager::init failed, has no valid group"); // GetNetworkIdByGroupId失败报错
return ERROR;
}
...
}
// foundation/multimedia/audio_framework/services/audio_policy/server/src/audio_policy_server.cpp
int32_t AudioPolicyServer::GetNetworkIdByGroupId(int32_t groupId, std::string &networkId)
{
auto volumeGroupInfos = audioPolicyService_.GetVolumeGroupInfos();
...
if (volumeGroupInfos.size() > 0) {
networkId = volumeGroupInfos[0]->networkId_;
AUDIO_INFO_LOG("GetNetworkIdByGroupId: get networkId %{public}s.", networkId.c_str());
} else {
AUDIO_ERR_LOG("GetNetworkIdByGroupId: has no valid group"); // 音频组信息size为0
return ERROR;
}
return SUCCESS;
}
// foundation/multimedia/audio_framework/services/audio_policy/server/src/service/audio_policy_service.cpp
std::vector<sptr<VolumeGroupInfo>> AudioPolicyService::GetVolumeGroupInfos()
{
if (!isPrimaryMicModuleInfoLoaded_.load()) {
std::unique_lock<std::mutex> lock(defaultDeviceLoadMutex_);
bool loadWaiting = loadDefaultDeviceCV_.wait_for(lock,
std::chrono::milliseconds(WAIT_LOAD_DEFAULT_DEVICE_TIME_MS), // 等待默认设备加载
[this] { return isPrimaryMicModuleInfoLoaded_.load(); }
);
if (!loadWaiting) {
AUDIO_ERR_LOG("load default device time out"); // 超时
}
}
std::vector<sptr<VolumeGroupInfo>> volumeGroupInfos = {};
std::shared_lock deviceLock(deviceStatusUpdateSharedMutex_);
for (auto& v : volumeGroups_) {
sptr<VolumeGroupInfo> info = new(std::nothrow) VolumeGroupInfo(v->volumeGroupId_, v->mappingId_, v->groupName_,
v->networkId_, v->connectType_);
volumeGroupInfos.push_back(info);
}
return volumeGroupInfos; // 返回空数组
}
通过添加日志打印可以得知最后返回了空数组,那么为什么最后返回的是空数组?
从for循环中,volumeGroupInfos的信息来自全局变量volumeGroups_,而volumeGroups_的更新处理通过调用如下函数
// foundation/multimedia/audio_framework/services/audio_policy/server/src/service/audio_policy_service.cpp
void AudioPolicyService::UpdateGroupInfo(GroupType type, std::string groupName, int32_t& groupId, std::string networkId,
bool connected, int32_t mappingId)
{
...
if (type == GroupType::VOLUME_TYPE) {
...
if (iter != volumeGroups_.end()) {
groupId = (*iter)->volumeGroupId_;
// if status is disconnected, remove the group that has none audio device
std::vector<sptr<AudioDeviceDescriptor>> devsInGroup = GetDevicesForGroup(type, groupId);
if (!connected && devsInGroup.size() == 0) {
volumeGroups_.erase(iter);
}
return;
}
if (groupName != GROUP_NAME_NONE && connected) {
groupId = AudioGroupHandle::GetInstance().GetNextId(type);
sptr<VolumeGroupInfo> volumeGroupInfo = new(std::nothrow) VolumeGroupInfo(groupId,
mappingId, groupName, networkId, connectType);
volumeGroups_.push_back(volumeGroupInfo);
}
} else {
...
}
}
往上跟踪代码,整个调用栈为AddAudioServiceOnStart->ConnectServiceAdapter->OnServiceConnected->OpenPortAndAddDeviceOnServiceConnected->AddAudioDevice->UpdateGroupInfo
而监听到3001服务起来后会执行AddAudioServiceOnStart
// foundation/multimedia/audio_framework/services/audio_policy/server/src/audio_policy_server.cpp
void AudioPolicyServer::OnAddSystemAbility(int32_t systemAbilityId, const std::string& deviceId)
{
AUDIO_INFO_LOG("SA Id is :%{public}d", systemAbilityId);
int64_t stamp = ClockTime::GetCurNano();
switch (systemAbilityId) {
...
case AUDIO_DISTRIBUTED_SERVICE_ID: // AUDIO_DISTRIBUTED_SERVICE_ID = 3001,
AUDIO_INFO_LOG("OnAddSystemAbility audio service start");
AddAudioServiceOnStart();
break;
...
}
// eg. done systemAbilityId: [3001] cost 780ms
AUDIO_INFO_LOG("done systemAbilityId: [%{public}d] cost %{public}" PRId64 " ms", systemAbilityId,
(ClockTime::GetCurNano() - stamp) / AUDIO_US_PER_SECOND);
}
但是日志中并无该打印(后面验证应该是日志太多或者hilog还没起来导致没打印,实际服务起来了)

多次重启后发现偶尔是有打印的

此时日志显示加载配置文件失败

// foundation/multimedia/audio_framework/services/audio_policy/server/src/service/audio_policy_service.cpp
bool AudioPolicyService::Init(void)
{
AUDIO_INFO_LOG("Audio policy service init enter");
...
bool ret = audioPolicyConfigParser_.LoadConfiguration();
...
CHECK_AND_RETURN_RET_LOG(ret, false, "Audio Policy Config Load Configuration failed"); // 报错后return
...
}
// foundation/multimedia/audio_framework/services/audio_policy/server/src/service/config/audio_policy_parser.cpp
bool AudioPolicyParser::LoadConfiguration()
{
AUDIO_INFO_LOG("Enter");
doc_ = xmlReadFile(CHIP_PROD_CONFIG_FILE, nullptr, 0); // 优先解析/chip_prod/etc/audio/audio_policy_config.xml
if (doc_ == nullptr) {
doc_ = xmlReadFile(CONFIG_FILE, nullptr, 0); // 如果找不到,再解析vendor/etc/audio/audio_policy_config.xml
if (doc_ == nullptr) {
AUDIO_ERR_LOG("xmlReadFile Failed");
return false;
}
}
AUDIO_INFO_LOG("Done");
return true;
}
但其实vendor/etc/audio/audio_policy_config.xml是存在对应文件的
手动cp vendor/etc/audio/audio_policy_config.xml 到 /chip_prod/etc/audio/audio_policy_config.xml发现可以成功解析了(暂时不清楚是什么原因导致vendor/etc/audio/audio_policy_config.xml读取失败)
但OH5.0 audio_policy_config.xml文件格式变更,导致解析出错

// foundation/multimedia/audio_framework/services/audio_policy/server/src/service/config/audio_policy_parser.cpp
XmlNodeType AudioPolicyParser::GetXmlNodeTypeAsInt(xmlNode &node)
{
if (!xmlStrcmp(node.name, reinterpret_cast<const xmlChar*>("adapters"))) {
return XmlNodeType::ADAPTERS;
} else if (!xmlStrcmp(node.name, reinterpret_cast<const xmlChar*>("volumeGroups"))) {
return XmlNodeType::VOLUME_GROUPS;
} else if (!xmlStrcmp(node.name, reinterpret_cast<const xmlChar*>("interruptGroups"))) {
return XmlNodeType::INTERRUPT_GROUPS;
} else if (!xmlStrcmp(node.name, reinterpret_cast<const xmlChar*>("globalConfigs"))) {
return XmlNodeType::GLOBAL_CONFIGS;
} else {
return XmlNodeType::XML_UNKNOWN;
}
}
更多推荐
所有评论(0)