* Copyright (c) 2025 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 "request_manager_impl.h"
#include <algorithm>
#include <cinttypes>
#include <vector>
#include "iam_check.h"
#include "iam_logger.h"
#include "iam_para2str.h"
#include "iam_safe_arithmetic.h"
#include "singleton_manager.h"
#include "task_runner_manager.h"
#define LOG_TAG "CDA_SA"
#define LOG_FILE_ID LOG_FILE_REQUEST_MANAGER_IMPL
namespace OHOS {
namespace UserIam {
namespace CompanionDeviceAuth {
RequestManagerImpl::RequestManagerImpl()
{
}
std::shared_ptr<RequestManagerImpl> RequestManagerImpl::Create()
{
auto manager = std::shared_ptr<RequestManagerImpl>(new (std::nothrow) RequestManagerImpl());
ENSURE_OR_RETURN_VAL(manager != nullptr, nullptr);
return manager;
}
bool RequestManagerImpl::Start(const std::shared_ptr<IRequest> &request)
{
ENSURE_OR_RETURN_VAL(request != nullptr, false);
constexpr size_t maxTotalRequests = 200;
auto totalRequests = SafeAdd(waitingRequests_.size(), runningRequests_.size());
ENSURE_OR_RETURN_VAL(totalRequests.has_value(), false);
if (totalRequests.value() >= maxTotalRequests) {
IAM_LOGE("total requests limit reached (%{public}zu), reject requestId:0x%{public}08X", totalRequests.value(),
request->GetRequestId());
return false;
}
RequestId requestId = request->GetRequestId();
if (Get(requestId) != nullptr) {
IAM_LOGE("request already exists, requestId:0x%{public}08X", requestId);
return false;
}
std::vector<std::shared_ptr<IRequest>> requestToCancel;
auto processRequests = [&request, &requestToCancel](const auto &container) {
for (auto it = container.rbegin(); it != container.rend(); ++it) {
const auto &existingRequest = *it;
ENSURE_OR_CONTINUE(existingRequest != nullptr);
if (existingRequest->ShouldCancelOnNewRequest(*request, 0)) {
requestToCancel.push_back(existingRequest);
continue;
}
}
};
processRequests(waitingRequests_);
processRequests(runningRequests_);
TaskRunnerManager::GetInstance().PostTaskOnResident([requestToCancel]() {
for (auto &request : requestToCancel) {
ENSURE_OR_CONTINUE(request != nullptr);
request->Cancel(ResultCode::CANCELED);
}
});
std::vector<std::shared_ptr<IRequest>> prevRequests;
prevRequests.insert(prevRequests.end(), runningRequests_.begin(), runningRequests_.end());
prevRequests.insert(prevRequests.end(), waitingRequests_.begin(), waitingRequests_.end());
if (!request->CanStart(prevRequests)) {
IAM_LOGI("request cannot start, enqueued requestId:0x%{public}08X", requestId);
waitingRequests_.push_back(request);
return true;
}
runningRequests_.push_back(request);
TaskRunnerManager::GetInstance().PostTaskOnResident([request]() {
ENSURE_OR_RETURN(request != nullptr);
request->Start();
});
return true;
}
bool RequestManagerImpl::Cancel(RequestId requestId)
{
auto request = Get(requestId);
if (request != nullptr) {
return request->Cancel(ResultCode::CANCELED);
}
IAM_LOGE("request not found, requestId:0x%{public}08X", requestId);
return false;
}
bool RequestManagerImpl::CancelRequestByScheduleId(ScheduleId scheduleId)
{
ENSURE_OR_RETURN_VAL(scheduleId != 0, false);
for (const auto &request : runningRequests_) {
ENSURE_OR_CONTINUE(request != nullptr);
if (request->GetScheduleId() == scheduleId) {
return request->Cancel(ResultCode::CANCELED);
}
}
for (const auto &request : waitingRequests_) {
ENSURE_OR_CONTINUE(request != nullptr);
if (request->GetScheduleId() == scheduleId) {
return request->Cancel(ResultCode::CANCELED);
}
}
IAM_LOGE("request not found, scheduleId:0x%{public}016" PRIX64, scheduleId);
return false;
}
void RequestManagerImpl::CancelAll()
{
for (const auto &request : runningRequests_) {
ENSURE_OR_CONTINUE(request != nullptr);
RequestId requestId = request->GetRequestId();
if (!request->Cancel(ResultCode::CANCELED)) {
IAM_LOGE("cancel request 0x%{public}08X failed", requestId);
}
}
for (const auto &request : waitingRequests_) {
ENSURE_OR_CONTINUE(request != nullptr);
RequestId requestId = request->GetRequestId();
if (!request->Cancel(ResultCode::CANCELED)) {
IAM_LOGE("cancel request 0x%{public}08X failed", requestId);
}
}
}
void RequestManagerImpl::Remove(RequestId requestId)
{
auto runningIt = std::find_if(runningRequests_.begin(), runningRequests_.end(),
[requestId](const auto &request) { return request != nullptr && request->GetRequestId() == requestId; });
bool wasRunning = (runningIt != runningRequests_.end());
if (wasRunning) {
runningRequests_.erase(runningIt);
}
auto waitingIt = std::find_if(waitingRequests_.begin(), waitingRequests_.end(),
[requestId](const auto &request) { return request != nullptr && request->GetRequestId() == requestId; });
if (waitingIt != waitingRequests_.end()) {
waitingRequests_.erase(waitingIt);
}
if (!wasRunning) {
return;
}
std::vector<std::shared_ptr<IRequest>> prevRequests(runningRequests_.begin(), runningRequests_.end());
std::vector<std::shared_ptr<IRequest>> toStart;
for (auto it = waitingRequests_.begin(); it != waitingRequests_.end();) {
const auto &waitingRequest = *it;
if (waitingRequest == nullptr) {
it = waitingRequests_.erase(it);
continue;
}
bool canStart = waitingRequest->CanStart(prevRequests);
prevRequests.push_back(waitingRequest);
if (canStart) {
toStart.push_back(waitingRequest);
runningRequests_.push_back(waitingRequest);
it = waitingRequests_.erase(it);
} else {
++it;
}
}
for (const auto &req : toStart) {
TaskRunnerManager::GetInstance().PostTaskOnResident([req]() {
ENSURE_OR_RETURN(req != nullptr);
req->Start();
});
}
}
std::shared_ptr<IRequest> RequestManagerImpl::Get(RequestId requestId) const
{
for (const auto &request : runningRequests_) {
ENSURE_OR_CONTINUE(request != nullptr);
if (request->GetRequestId() == requestId) {
return request;
}
}
for (const auto &request : waitingRequests_) {
ENSURE_OR_CONTINUE(request != nullptr);
if (request->GetRequestId() == requestId) {
return request;
}
}
return nullptr;
}
}
}
}