Files
openharmony_ci 817f9f7817 !3388 merge master into master
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
2026-08-22 15:58:04 +08:00

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_);
}
}
}