mirror of
https://github.com/openharmony/multimedia_av_session.git
synced 2026-08-24 18:26:13 -04:00
817f9f7817
lanqu2
Created-by: xuhy2
Commit-by: xuhy2;xuhy
Merged-by: openharmony_ci
Description: ### 一、内容说明(相关的Issue)
### 二、建议测试周期和提测地址
建议测试完成时间:xxxx.xx.xx
投产上线时间:xxxx.xx.xx
提测地址:CI环境/压测环境
测试账号:
### 三、变更内容
* 3.1 关联PR列表
* 3.2 数据库和部署说明
1. 常规更新
2. 重启unicorn
3. 重启sidekiq
4. 迁移任务:是否有迁移任务,没有写 "无"
5. rake脚本:`bundle exec xxx RAILS_ENV = production`;没有写 "无"
* 3.4 其他技术优化内容(做了什么,变更了什么)
- 重构了 xxxx 代码
- xxxx 算法优化
* 3.5 废弃通知(什么字段、方法弃用?)
* 3.6 后向不兼容变更(是否有无法向后兼容的变更?)
### 四、研发自测点(自测哪些?冒烟用例全部自测?)
自测测试结论:
### 五、测试关注点(需要提醒QA重点关注的、可能会忽略的地方)
检查点:
| 需求名称 | 是否影响xx公共模块 | 是否需要xx功能 | 需求升级是否依赖其他子产品 |
|------|------------|----------|---------------|
| xxx | 否 | 需要 | 不需要 |
| | | | |
接口测试:
性能测试:
并发测试:
其他:
See merge request: openharmony/multimedia_av_session!3388
366 lines
14 KiB
C++
366 lines
14 KiB
C++
/*
|
|
* Copyright (c) 2023 Huawei Device Co., Ltd.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "bundle_status_adapter.h"
|
|
|
|
#include "avsession_log.h"
|
|
#include "iservice_registry.h"
|
|
#include "system_ability_definition.h"
|
|
#include "cJSON.h"
|
|
#include "want.h"
|
|
#include "want_params_wrapper.h"
|
|
#include "string_wrapper.h"
|
|
#include "array_wrapper.h"
|
|
#include "avsession_sysevent.h"
|
|
|
|
namespace OHOS::AVSession {
|
|
std::shared_ptr<BundleStatusAdapter> BundleStatusAdapter::instance_;
|
|
std::recursive_mutex BundleStatusAdapter::instanceLock_;
|
|
std::recursive_mutex BundleStatusAdapter::listenerLock_;
|
|
|
|
BundleStatusAdapter::BundleStatusAdapter()
|
|
{
|
|
SLOGI("construct");
|
|
}
|
|
|
|
BundleStatusAdapter::~BundleStatusAdapter()
|
|
{
|
|
SLOGI("destroy");
|
|
}
|
|
|
|
BundleStatusAdapter& BundleStatusAdapter::GetInstance()
|
|
{
|
|
std::lock_guard lockGuard(instanceLock_);
|
|
if (instance_ != nullptr) {
|
|
return *instance_;
|
|
}
|
|
SLOGI("GetInstance in");
|
|
instance_ = std::make_shared<BundleStatusAdapter>();
|
|
return *instance_;
|
|
}
|
|
|
|
void BundleStatusAdapter::ReleaseInstance()
|
|
{
|
|
std::lock_guard lockGuard(instanceLock_);
|
|
SLOGI("ReleaseInstance in");
|
|
instance_ = nullptr;
|
|
}
|
|
|
|
void BundleStatusAdapter::Init()
|
|
{
|
|
std::lock_guard bundleMgrProxyLockGuard(bundleMgrProxyLock_);
|
|
auto systemAbilityManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
|
|
if (!systemAbilityManager) {
|
|
SLOGI("fail to get system ability mgr");
|
|
return;
|
|
}
|
|
|
|
auto remoteObject = systemAbilityManager->GetSystemAbility(BUNDLE_MGR_SERVICE_SYS_ABILITY_ID);
|
|
if (!remoteObject) {
|
|
SLOGI("fail to get bundle manager proxy");
|
|
return;
|
|
}
|
|
|
|
SLOGI("get bundle manager proxy success.");
|
|
bundleMgrProxy = iface_cast<AppExecFwk::IBundleMgr>(remoteObject);
|
|
CHECK_AND_RETURN_LOG(bundleMgrProxy != nullptr, "iface_cast bundleMgrProxy failed");
|
|
bundleResourceProxy = bundleMgrProxy->GetBundleResourceProxy();
|
|
CHECK_AND_RETURN_LOG(bundleResourceProxy != nullptr, "GetBundleResourceProxy failed");
|
|
{
|
|
std::lock_guard LockGuard(listenerLock_);
|
|
bundleStatusListeners_.clear();
|
|
SLOGI("clear bundleStatusListeners done");
|
|
}
|
|
}
|
|
|
|
bool BundleStatusAdapter::GetBundleIcon(const std::string bundleName, const std::string abilityName, std::string& icon)
|
|
{
|
|
std::lock_guard bundleMgrProxyLockGuard(bundleMgrProxyLock_);
|
|
SLOGI("GetBundleIcon with bundleName:%{public}s", bundleName.c_str());
|
|
|
|
if (bundleMgrProxy == nullptr || bundleResourceProxy == nullptr) {
|
|
SLOGE("GetBundleIcon with bundleMgrProxy:%{public}d, bundleResourceProxy:%{public}d",
|
|
static_cast<int>(bundleMgrProxy != nullptr), static_cast<int>(bundleResourceProxy != nullptr));
|
|
return false;
|
|
}
|
|
AppExecFwk::BundleInfo bundleInfo;
|
|
if (!bundleMgrProxy->GetBundleInfo(bundleName, getBundleInfoWithHapModule, bundleInfo, startUserId)) {
|
|
SLOGE("GetBundleInfo of bundleName:%{public}s fail!", bundleName.c_str());
|
|
return false;
|
|
}
|
|
std::vector<AppExecFwk::LauncherAbilityResourceInfo> LauncherAbilityResourceInfoList;
|
|
ErrCode ret = bundleResourceProxy->GetLauncherAbilityResourceInfo(bundleName, 0, LauncherAbilityResourceInfoList);
|
|
if (ret != ERR_OK) {
|
|
SLOGE("GetLauncherAbilityResourceInfo of bundleName:%{public}s fail for errCode:%{public}d",
|
|
bundleName.c_str(), ret);
|
|
return false;
|
|
}
|
|
for (const auto& resourceInfo : LauncherAbilityResourceInfoList) {
|
|
if (abilityName == resourceInfo.abilityName) {
|
|
icon = resourceInfo.icon;
|
|
break;
|
|
}
|
|
}
|
|
if (icon.empty() && LauncherAbilityResourceInfoList.size() > 0) {
|
|
icon = LauncherAbilityResourceInfoList[LauncherAbilityResourceInfoList.size() - 1].icon;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool BundleStatusAdapter::SubscribeBundleStatusEvent(const std::string bundleName,
|
|
const std::function<void(const std::string, const int32_t userId)>& callback, int32_t userId)
|
|
{
|
|
SLOGI("Bundle status adapter subscribe bundle status event, bundleName=%{public}s, userId=%{public}d.",
|
|
bundleName.c_str(), userId);
|
|
{
|
|
std::lock_guard LockGuard(listenerLock_);
|
|
auto bundleStatusListener = bundleStatusListeners_.find(std::make_pair(bundleName, userId));
|
|
CHECK_AND_RETURN_RET_LOG(bundleStatusListener == bundleStatusListeners_.end(), false,
|
|
"bundle status has already register");
|
|
}
|
|
auto bundleStatusCallback = [this](std::string bundleName, int32_t userId) {
|
|
NotifyBundleRemoved(bundleName, userId);
|
|
};
|
|
sptr<BundleStatusCallbackImpl> bundleStatusCallbackImpl =
|
|
new(std::nothrow) BundleStatusCallbackImpl(bundleStatusCallback, userId);
|
|
if (bundleStatusCallbackImpl == nullptr) {
|
|
SLOGE("no memory");
|
|
return false;
|
|
}
|
|
std::lock_guard bundleMgrProxyLockGuard(bundleMgrProxyLock_);
|
|
bool isProxyNull = false;
|
|
isProxyNull = (bundleMgrProxy == nullptr);
|
|
if (isProxyNull) {
|
|
SLOGE("SubscribeBundleStatusEvent with proxy null!");
|
|
Init();
|
|
if (bundleMgrProxy == nullptr) {
|
|
SLOGE("SubscribeBundleStatusEvent with proxy null after init!");
|
|
return false;
|
|
}
|
|
}
|
|
bundleStatusCallbackImpl->SetBundleName(bundleName);
|
|
bundleStatusCallbackImpl->SetUserId(userId);
|
|
if (bundleMgrProxy->RegisterBundleStatusCallback(bundleStatusCallbackImpl)) {
|
|
std::lock_guard LockGuard(listenerLock_);
|
|
bundleStatusListeners_.insert(std::make_pair(std::make_pair(bundleName, userId), callback));
|
|
return true;
|
|
} else {
|
|
SLOGE("Register bundle status callback failed, bundleName=%{public}s", bundleName.c_str());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool BundleStatusAdapter::IsAudioPlayback(const std::string& bundleName, const std::string& abilityName)
|
|
{
|
|
std::lock_guard bundleMgrProxyLockGuard(bundleMgrProxyLock_);
|
|
|
|
SLOGI("Estimate bundle audio playback status, bundleName=%{public}s", bundleName.c_str());
|
|
CHECK_AND_RETURN_RET_LOG(bundleMgrProxy != nullptr, false, "bundleMgrProxy is nullptr");
|
|
AppExecFwk::AbilityInfo abilityInfo;
|
|
bool flag = false;
|
|
if (bundleMgrProxy->GetAbilityInfo(bundleName, abilityName, abilityInfo)) {
|
|
flag = static_cast<int32_t>(abilityInfo.backgroundModes) == backgroundModeDemand ? true : false;
|
|
}
|
|
return flag;
|
|
}
|
|
|
|
void BundleStatusAdapter::NotifyBundleRemoved(const std::string bundleName, const int32_t userId)
|
|
{
|
|
std::lock_guard LockGuard(listenerLock_);
|
|
auto bundleStatusListener = bundleStatusListeners_.find(std::make_pair(bundleName, userId));
|
|
if (bundleStatusListener == bundleStatusListeners_.end()) {
|
|
return;
|
|
}
|
|
bundleStatusListener->second(bundleName, userId);
|
|
// BMS will keep callbackImpl for the bundleName & userId until avsession do ClearBundleStatusCallback
|
|
SLOGI("notify bundle status callback without erase, bundleName=%{public}s, userId=%{public}d",
|
|
bundleName.c_str(), userId);
|
|
}
|
|
|
|
std::string BundleStatusAdapter::GetBundleNameFromUid(const int32_t uid)
|
|
{
|
|
std::lock_guard bundleMgrProxyLockGuard(bundleMgrProxyLock_);
|
|
|
|
std::string bundleName {""};
|
|
if (bundleMgrProxy != nullptr) {
|
|
bundleMgrProxy->GetNameForUid(uid, bundleName);
|
|
}
|
|
return bundleName;
|
|
}
|
|
|
|
std::string BundleStatusAdapter::GetDefaultAbilityName(const std::string& bundleName, int32_t userId)
|
|
{
|
|
std::lock_guard bundleMgrProxyLockGuard(bundleMgrProxyLock_);
|
|
CHECK_AND_RETURN_RET_LOG(bundleMgrProxy != nullptr, "", "bundleMgrProxy is null");
|
|
AAFwk::Want launchWant;
|
|
auto ret = bundleMgrProxy->GetLaunchWantForBundle(bundleName, launchWant, userId);
|
|
CHECK_AND_RETURN_RET_LOG(ret == ERR_OK && !launchWant.GetElement().GetAbilityName().empty(), "",
|
|
"GetLaunchWantForBundle fail:%{public}d", ret);
|
|
return launchWant.GetElement().GetAbilityName();
|
|
}
|
|
|
|
int32_t BundleStatusAdapter::GetUidFromBundleName(const std::string bundleName, const int32_t userId)
|
|
{
|
|
AppExecFwk::BundleInfo bundleInfo;
|
|
{
|
|
std::lock_guard bundleMgrProxyLockGuard(bundleMgrProxyLock_);
|
|
CHECK_AND_RETURN_RET_LOG(bundleMgrProxy != nullptr, -1, "bundleMgrProxy is null");
|
|
auto ret = bundleMgrProxy->GetBundleInfo(bundleName,
|
|
static_cast<int32_t>(AppExecFwk::GetBundleInfoFlag::GET_BUNDLE_INFO_DEFAULT),
|
|
bundleInfo, userId);
|
|
CHECK_AND_RETURN_RET_LOG(ret, -1, "getbundleinfo fail");
|
|
}
|
|
return bundleInfo.uid;
|
|
}
|
|
|
|
std::string BundleStatusAdapter::GetAppVersion(const std::string& bundleName)
|
|
{
|
|
std::string appVersion = "default";
|
|
std::lock_guard bundleMgrProxyLockGuard(bundleMgrProxyLock_);
|
|
if (bundleMgrProxy != nullptr && !bundleName.empty()) {
|
|
AppExecFwk::BundleInfo bundleInfo;
|
|
if (bundleMgrProxy->GetBundleInfo(bundleName, getBundleInfoWithHapModule, bundleInfo, startUserId)) {
|
|
std::string tmpVersion = bundleInfo.versionName;
|
|
if (!tmpVersion.empty()) {
|
|
appVersion = tmpVersion;
|
|
}
|
|
}
|
|
}
|
|
return appVersion;
|
|
}
|
|
|
|
bool BundleStatusAdapter::CheckExecuteModeItem(cJSON* executeModeArray, const std::string& bundleName,
|
|
const char* insightName)
|
|
{
|
|
cJSON* modeItem = nullptr;
|
|
cJSON_ArrayForEach(modeItem, executeModeArray) {
|
|
if (cJSON_IsString(modeItem) && modeItem->valuestring != nullptr &&
|
|
strcmp(modeItem->valuestring, "background") == 0) {
|
|
#ifdef ENABLE_AVSESSION_SYSEVENT_CONTROL
|
|
if (insightName != nullptr) {
|
|
AVSessionSysEvent::GetInstance().UpdateSupportIntent(bundleName, std::string(insightName));
|
|
}
|
|
#endif
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool BundleStatusAdapter::CheckBundleSupport(const std::string& bundleName, std::string& profile)
|
|
{
|
|
// check bundle support background mode & playmusiclist intent
|
|
cJSON* profileValues = cJSON_Parse(profile.c_str());
|
|
CHECK_AND_RETURN_RET_LOG(profileValues != nullptr, false, "parse profile fail");
|
|
if (cJSON_IsInvalid(profileValues)) {
|
|
SLOGE("CheckBundleSupport parse profile not valid json");
|
|
cJSON_Delete(profileValues);
|
|
return false;
|
|
}
|
|
cJSON* insightIntentsArray = cJSON_GetObjectItem(profileValues, "insightIntents");
|
|
if (insightIntentsArray == nullptr || !cJSON_IsArray(insightIntentsArray)) {
|
|
SLOGE("CheckBundleSupport json do not contain insightIntentsArray");
|
|
cJSON_Delete(profileValues);
|
|
return false;
|
|
}
|
|
cJSON* insightIntentsItem = nullptr;
|
|
cJSON_ArrayForEach(insightIntentsItem, insightIntentsArray) {
|
|
cJSON* intentNameItem = cJSON_GetObjectItem(insightIntentsItem, "intentName");
|
|
if (intentNameItem == nullptr || !cJSON_IsString(intentNameItem)) {
|
|
SLOGE("CheckBundleSupport json do not contain intentName");
|
|
continue;
|
|
}
|
|
const char* insightName = intentNameItem->valuestring;
|
|
if (insightName != nullptr &&
|
|
strcmp(insightName, PLAY_MUSICLIST.c_str()) != 0 && strcmp(insightName, PLAY_AUDIO.c_str()) != 0) {
|
|
continue;
|
|
}
|
|
|
|
cJSON* uiAbilityItem = cJSON_GetObjectItem(insightIntentsItem, "uiAbility");
|
|
if (uiAbilityItem == nullptr) {
|
|
SLOGE("CheckBundleSupport json do not contain uiAbility");
|
|
cJSON_Delete(profileValues);
|
|
return false;
|
|
}
|
|
cJSON* executeModeArray = cJSON_GetObjectItem(uiAbilityItem, "executeMode");
|
|
if (executeModeArray == nullptr || !cJSON_IsArray(executeModeArray)) {
|
|
SLOGE("CheckBundleSupport json do not contain executeMode");
|
|
cJSON_Delete(profileValues);
|
|
return false;
|
|
}
|
|
if (CheckExecuteModeItem(executeModeArray, bundleName, insightName)) {
|
|
cJSON_Delete(profileValues);
|
|
return true;
|
|
}
|
|
}
|
|
cJSON_Delete(profileValues);
|
|
return false;
|
|
}
|
|
|
|
__attribute__((no_sanitize("cfi"))) bool BundleStatusAdapter::IsSupportPlayIntent(const std::string& bundleName,
|
|
std::string& supportModule, std::string& profile)
|
|
{
|
|
std::lock_guard bundleMgrProxyLockGuard(bundleMgrProxyLock_);
|
|
|
|
if (bundleMgrProxy == nullptr) {
|
|
return false;
|
|
}
|
|
AppExecFwk::BundleInfo bundleInfo;
|
|
if (!bundleMgrProxy->GetBundleInfo(bundleName,
|
|
getBundleInfoWithHapModule | getBundleInfoExcludeExt, bundleInfo, startUserId)) {
|
|
SLOGE("GetBundleInfo=%{public}s fail", bundleName.c_str());
|
|
return false;
|
|
}
|
|
bool isSupportIntent = false;
|
|
for (std::string module : bundleInfo.moduleNames) {
|
|
auto ret = bundleMgrProxy->GetJsonProfile(AppExecFwk::ProfileType::INTENT_PROFILE, bundleName, module,
|
|
profile, startUserId);
|
|
if (ret == 0) {
|
|
SLOGD("GetJsonProfile success, profile=%{public}s", profile.c_str());
|
|
isSupportIntent = true;
|
|
supportModule = module;
|
|
break;
|
|
}
|
|
}
|
|
if (!isSupportIntent) {
|
|
SLOGE("Bundle=%{public}s does not support insight", bundleName.c_str());
|
|
return false;
|
|
}
|
|
return CheckBundleSupport(bundleName, profile);
|
|
}
|
|
|
|
BundleStatusCallbackImpl::BundleStatusCallbackImpl(
|
|
const std::function<void(const std::string, const int32_t userId)>& callback, int32_t userId)
|
|
{
|
|
SLOGI("Create bundle status instance with userId %{public}d", userId);
|
|
callback_ = callback;
|
|
userId_ = userId;
|
|
}
|
|
|
|
BundleStatusCallbackImpl::~BundleStatusCallbackImpl()
|
|
{
|
|
SLOGI("Destroy bundle status instance");
|
|
}
|
|
|
|
void BundleStatusCallbackImpl::OnBundleStateChanged(const uint8_t installType, const int32_t resultCode,
|
|
const std::string &resultMsg, const std::string &bundleName)
|
|
{
|
|
if (installType == static_cast<uint8_t>(AppExecFwk::InstallType::UNINSTALL_CALLBACK)) {
|
|
callback_(bundleName, userId_);
|
|
}
|
|
}
|
|
}
|