* Copyright (c) 2026 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 "obs_permission_verifier.h"
#include "bundle_mgr_helper.h"
#include "dataobs_mgr_errors.h"
#include "data_share_permission.h"
#include "ipc_skeleton.h"
#include "hilog_tag_wrapper.h"
namespace OHOS {
namespace AAFwk {
using namespace Security::AccessToken;
using namespace AppExecFwk;
ObsPermissionVerifier& ObsPermissionVerifier::GetInstance()
{
static ObsPermissionVerifier instance;
return instance;
}
bool ObsPermissionVerifier::VerifyPermission(uint32_t listenerTokenId, int32_t userId,
const Uri &uri, uint32_t tokenId)
{
if (listenerTokenId == tokenId) {
return true;
}
auto [isSA, listenerCallingName] = GetCallingInfo(listenerTokenId);
if (isSA) {
return true;
}
Uri uriTemp = uri;
std::vector<std::string> listenerGroupIds = GetGroupInfosFromCache(listenerCallingName, userId);
for (auto &groupId : listenerGroupIds) {
if (uriTemp.GetAuthority() == groupId) {
return true;
}
}
std::string scheme = uriTemp.GetScheme();
std::string errMsg = listenerCallingName + ":" + scheme +
" checkfailed:" + std::string(listenerGroupIds.empty() ? "empty" : "notEmpty");
auto errCode = (scheme == RELATIONAL_STORE) ? DATAOBS_RDB_INVALID_URI : DATAOBS_PREFERENCE_INVALID_URI;
TAG_LOGE(AAFwkTag::DBOBSMGR, "verify failed listenerCallingName:%{public}s, errCode:%{public}d",
listenerCallingName.c_str(), errCode);
std::string msg = __FUNCTION__;
DataShare::DataSharePermission::ReportExtensionFault(errCode, listenerTokenId, errMsg, msg);
return false;
}
std::pair<bool, std::string> ObsPermissionVerifier::GetCallingInfo(uint32_t callingTokenId)
{
std::string callingName;
bool isSA = false;
auto tokenType = Security::AccessToken::AccessTokenKit::GetTokenTypeFlag(callingTokenId);
if (tokenType == Security::AccessToken::TOKEN_HAP) {
Security::AccessToken::HapTokenInfo tokenInfo;
int result = Security::AccessToken::AccessTokenKit::GetHapTokenInfo(callingTokenId, tokenInfo);
if (result == Security::AccessToken::RET_SUCCESS) {
callingName = std::move(tokenInfo.bundleName);
}
} else if (tokenType == Security::AccessToken::TOKEN_NATIVE || tokenType == Security::AccessToken::TOKEN_SHELL) {
isSA = true;
} else {
TAG_LOGE(AAFwkTag::DBOBSMGR, "tokenType is invalid, tokenType:%{public}d", tokenType);
}
return {isSA, callingName};
}
std::vector<std::string> ObsPermissionVerifier::GetGroupInfosFromCache(const std::string &bundleName, int32_t userId)
{
std::string key = bundleName + ":" + std::to_string(userId);
{
std::shared_lock<std::shared_mutex> readLock(groupsIdMutex_);
auto it = std::find_if(groupsIdCache_.begin(), groupsIdCache_.end(),
[&key](const auto& pair) { return pair.first == key; });
if (it != groupsIdCache_.end()) {
return it->second;
}
}
std::vector<DataGroupInfo> infos;
auto bmsHelper = DelayedSingleton<BundleMgrHelper>::GetInstance();
if (bmsHelper == nullptr) {
TAG_LOGE(AAFwkTag::DBOBSMGR, "bmsHelper is nullptr");
return {};
}
bool res = bmsHelper->QueryDataGroupInfos(bundleName, userId, infos);
if (!res) {
TAG_LOGE(AAFwkTag::DBOBSMGR, "query group failed:%{public}s, user:%{public}d", bundleName.c_str(), userId);
return {};
}
std::vector<std::string> groupIds;
for (auto &it : infos) {
groupIds.push_back(std::move(it.dataGroupId));
}
std::unique_lock<std::shared_mutex> writeLock(groupsIdMutex_);
auto it = std::find_if(groupsIdCache_.begin(), groupsIdCache_.end(),
[&key](const auto& pair) { return pair.first == key; });
if (it != groupsIdCache_.end()) {
return it->second;
}
while (groupsIdCache_.size() >= CACHE_SIZE_THRESHOLD) {
groupsIdCache_.pop_front();
}
groupsIdCache_.emplace_back(key, groupIds);
return groupIds;
}
}
}