* 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 "utils/oe_extension_utils.h"
#include "ability_manager_errors.h"
#include "ability_record.h"
#include "app_scheduler.h"
#include "ffrt.h"
#include "hilog_tag_wrapper.h"
#include "startup_util.h"
namespace OHOS {
namespace AAFwk {
namespace {
constexpr int32_t OESA_UID = 7061;
}
OEExtensionUtils &OEExtensionUtils::GetInstance()
{
static OEExtensionUtils instance;
return instance;
}
int32_t OEExtensionUtils::ValidateCaller(
int32_t callingUid,
const Want &want,
const sptr<IRemoteObject> &callerToken,
int32_t hostPid,
std::string &hostBundleName,
int32_t &userId)
{
if (callingUid != OESA_UID) {
TAG_LOGE(AAFwkTag::ABILITYMGR, "invalid calling uid: %{public}d, expected: %{public}d", callingUid, OESA_UID);
return CHECK_PERMISSION_FAILED;
}
auto abilityRecord = Token::GetAbilityRecordByToken(callerToken);
if (abilityRecord == nullptr) {
TAG_LOGE(AAFwkTag::ABILITYMGR, "invalid caller token");
return ERR_INVALID_CALLER;
}
const auto &abilityInfo = abilityRecord->GetAbilityInfo();
if (abilityInfo.type != AppExecFwk::AbilityType::EXTENSION ||
abilityInfo.extensionAbilityType != AppExecFwk::ExtensionAbilityType::CONTENT_EMBED) {
TAG_LOGE(AAFwkTag::ABILITYMGR, "caller is not oe extension");
return ERR_INVALID_CALLER;
}
if (want.GetBundleNameRef() != abilityInfo.bundleName) {
TAG_LOGE(AAFwkTag::ABILITYMGR, "want bundleName %{public}s does not match caller bundleName %{public}s",
want.GetBundleNameRef().c_str(), abilityInfo.bundleName.c_str());
return INVALID_PARAMETERS_ERR;
}
if (want.GetAbilityNameRef().empty()) {
TAG_LOGE(AAFwkTag::ABILITYMGR, "want abilityName is empty");
return INVALID_PARAMETERS_ERR;
}
AppExecFwk::RunningProcessInfo processInfo;
DelayedSingleton<AppScheduler>::GetInstance()->GetRunningProcessInfoByPid(hostPid, processInfo);
if (processInfo.state_ != AppExecFwk::AppProcessState::APP_STATE_FOREGROUND) {
TAG_LOGE(AAFwkTag::ABILITYMGR, "hostPid=%{public}d not foreground: %{public}d", hostPid, processInfo.state_);
return NOT_TOP_ABILITY;
}
int32_t appIndex = 0;
if (!AbilityRuntime::StartupUtil::GetAppIndex(want, appIndex) ||
(appIndex != 0 && appIndex != abilityRecord->GetAppIndex())) {
return ERR_APP_CLONE_INDEX_INVALID;
}
const_cast<Want &>(want).SetParam(Want::PARAM_APP_CLONE_INDEX_KEY, appIndex);
hostBundleName = processInfo.bundleNames.empty() ? "" : processInfo.bundleNames[0];
userId = abilityRecord->GetOwnerMissionUserId();
return ERR_OK;
}
void OEExtensionUtils::AddOEExtRequest(int32_t requestId)
{
ScheduleDelayedCleanup(requestId);
std::lock_guard<std::mutex> lock(oeExtRequestsMutex_);
oeExtRequests_.insert(requestId);
TAG_LOGI(AAFwkTag::ABILITYMGR, "Add OE extension request, requestId=%{public}d", requestId);
}
bool OEExtensionUtils::RemoveOEExtRequest(int32_t requestId)
{
std::lock_guard<std::mutex> lock(oeExtRequestsMutex_);
return oeExtRequests_.erase(requestId) > 0;
}
void OEExtensionUtils::ScheduleDelayedCleanup(int32_t requestId)
{
auto cleanupTask = [requestId]() {
if (OEExtensionUtils::GetInstance().RemoveOEExtRequest(requestId)) {
TAG_LOGI(AAFwkTag::ABILITYMGR, "Remove OE extension request, requestId=%{public}d", requestId);
}
};
constexpr int32_t cleanupDelay = 10 * 1000 * 1000;
ffrt::submit(std::move(cleanupTask), ffrt::task_attr().delay(cleanupDelay).name("OERequestCleanup"));
}
}
}