1/*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15#include "async_obtain_data.h"
16#define LOG_TAG "AsyncObtainData"
17#include <cstdint>
18#include <algorithm>
19#include "unified_types.h"
20#include "logger.h"
21#include "udmf_service_client.h"
22#include "securec.h"
23
24namespace OHOS {
25namespace UDMF {
26static constexpr size_t MAX_THREADS = 2;
27static constexpr size_t MIN_THREADS = 0;
28static constexpr uint32_t MAX_PROGRESS = 100;
29static constexpr double MAX_PROGRESS_DOUBLE = 100.0;
30static constexpr double SYNC_COEFF = 0.5;
31static constexpr double PERM_COEFF = 0.4;
32
33AsyncObtainData::AsyncObtainData() : executor_(MAX_THREADS, MIN_THREADS) {}
34
35Status AsyncObtainData::InitTask(const QueryOption &query, ObtainDataCallback callback)
36{
37    if (callback == nullptr) {
38        LOG_ERROR(UDMF_CLIENT, "callback invalid");
39        taskStatus_ = ASYNC_FAILURE;
40        return E_INVALID_PARAMETERS;
41    }
42
43    serviceClient_ = UdmfServiceClient::GetInstance();
44    if (serviceClient_ == nullptr) {
45        LOG_ERROR(UDMF_CLIENT, "Service unavailable");
46        taskStatus_ = ASYNC_FAILURE;
47        return E_IPC;
48    }
49
50    initialized_ = true;
51    query_ = query;
52    callback_ = callback;
53    taskStatus_ = ASYNC_RUNNING;
54    processInfo_.syncStatus = ASYNC_RUNNING;
55    return E_OK;
56}
57
58Status AsyncObtainData::RunTask()
59{
60    LOG_DEBUG(UDMF_CLIENT, "Enter");
61    if (serviceClient_ == nullptr) {
62        LOG_ERROR(UDMF_CLIENT, "failed! service client is nullptr");
63        return E_IPC;
64    }
65    if (!initialized_) {
66        LOG_ERROR(UDMF_CLIENT, "failed! not init");
67        return E_ERROR;
68    }
69    obtainDataTaskId_ = executor_.Execute(std::bind(&AsyncObtainData::ObtainDataTask, this));
70    progressTaskId_ = executor_.Execute(std::bind(&AsyncObtainData::ProgressTask, this));
71
72    return E_OK;
73}
74
75void AsyncObtainData::ObtainDataTask()
76{
77    LOG_DEBUG(UDMF_CLIENT, "Enter");
78    if ((taskStatus_ == ASYNC_RUNNING) && (processInfo_.syncStatus == ASYNC_RUNNING)) {
79        Executor::Duration delay = std::chrono::milliseconds(500);
80        obtainDataTaskId_ = executor_.Schedule(delay, std::bind(&AsyncObtainData::ObtainDataTask, this));
81        return;
82    }
83
84    UnifiedData unifiedData;
85    if (taskStatus_ != ASYNC_FAILURE) {
86        if (serviceClient_ == nullptr) {
87            LOG_ERROR(UDMF_CLIENT, "failed! serviceClient_ is nullptr");
88            return;
89        }
90        int32_t ret = serviceClient_->GetData(query_, unifiedData);
91        if (ret != E_OK) {
92            LOG_ERROR(UDMF_CLIENT, "failed! ret = %{public}d", ret);
93            taskStatus_ = ASYNC_FAILURE;
94        } else {
95            taskStatus_ = ASYNC_SUCCESS;
96        }
97    }
98    InvokeCallback(unifiedData);
99    ClearTask();
100}
101
102void AsyncObtainData::ProgressTask()
103{
104    LOG_DEBUG(UDMF_CLIENT, "Enter");
105    if (serviceClient_ == nullptr) {
106        LOG_ERROR(UDMF_CLIENT, "failed! serviceClient_ is nullptr");
107        return;
108    }
109    AsyncProcessInfo processInfo;
110    int32_t ret = serviceClient_->ObtainAsynProcess(processInfo);
111    if (ret != E_OK) {
112        LOG_ERROR(UDMF_CLIENT, "failed! ret = %{public}d", ret);
113        taskStatus_ = ASYNC_FAILURE;
114        return;
115    }
116
117    UpdateProcessInfo(processInfo);
118
119    UnifiedData unifiedData;
120    InvokeCallback(unifiedData);
121
122    if ((taskStatus_ == ASYNC_RUNNING) &&
123        ((processInfo.syncStatus == ASYNC_RUNNING) || (processInfo.permStatus == ASYNC_RUNNING))) {
124        Executor::Duration delay = std::chrono::milliseconds(500);
125        progressTaskId_ = executor_.Schedule(delay, std::bind(&AsyncObtainData::ProgressTask, this));
126    }
127}
128
129void AsyncObtainData::InvokeCallback(UnifiedData &data)
130{
131    ProgressInfo progress{ "", ASYNC_IDLE, 0 };
132    progress.status = taskStatus_;
133    progress.srcDevName = processInfo_.srcDevName;
134
135    progress.progress = CalProgress();
136    if (progress.progress <= lastProgress_) {
137        progress.progress = lastProgress_;
138    } else {
139        lastProgress_ = progress.progress;
140    }
141    if (callback_ == nullptr) {
142        LOG_ERROR(UDMF_CLIENT, "failed! callback_ is nullptr");
143        return;
144    }
145    callback_(progress, data);
146}
147
148void AsyncObtainData::UpdateProcessInfo(AsyncProcessInfo &info)
149{
150    processInfo_.syncStatus = info.syncStatus;
151    processInfo_.permStatus = info.permStatus;
152    processInfo_.srcDevName = (info.syncStatus == ASYNC_IDLE ? "Local" : info.srcDevName);
153    processInfo_.syncFinished = info.syncFinished;
154    processInfo_.syncTotal = info.syncTotal;
155    processInfo_.syncId = info.syncId;
156    processInfo_.permFnished = info.permFnished;
157    processInfo_.permTotal = info.permTotal;
158
159    if (processInfo_.syncStatus == ASYNC_FAILURE || processInfo_.permStatus == ASYNC_FAILURE) {
160        taskStatus_ = ASYNC_FAILURE;
161    }
162}
163
164void AsyncObtainData::ClearTask()
165{
166    initialized_ = false;
167    taskStatus_ = ASYNC_IDLE;
168    lastProgress_ = 0;
169    progressTaskId_ = ExecutorPool::INVALID_TASK_ID;
170    obtainDataTaskId_ = ExecutorPool::INVALID_TASK_ID;
171    (void)memset_s(&processInfo_, sizeof(processInfo_), 0, sizeof(processInfo_));
172
173    serviceClient_ = UdmfServiceClient::GetInstance();
174    if (serviceClient_ == nullptr) {
175        return;
176    }
177    auto ret = serviceClient_->ClearAsynProcess();
178    if (ret != E_OK) {
179        LOG_ERROR(UDMF_CLIENT, "failed! ret = %{public}d", ret);
180    }
181    serviceClient_ = nullptr;
182}
183
184uint32_t AsyncObtainData::CalProgress()
185{
186    if (taskStatus_ == ASYNC_SUCCESS) {
187        return MAX_PROGRESS;
188    }
189    if ((taskStatus_ == ASYNC_FAILURE) || (processInfo_.syncStatus == ASYNC_FAILURE) ||
190        processInfo_.permStatus == ASYNC_FAILURE) {
191        return lastProgress_;
192    }
193
194    uint32_t syncProgress = CalSyncProgress();
195    uint32_t permProgress = CalPermProgress();
196    double totalProgress = syncProgress * SYNC_COEFF + permProgress * PERM_COEFF;
197    return static_cast<uint32_t>(totalProgress);
198}
199
200uint32_t AsyncObtainData::CalSyncProgress()
201{
202    if (processInfo_.syncStatus == ASYNC_SUCCESS || processInfo_.syncStatus == ASYNC_IDLE) {
203        return MAX_PROGRESS;
204    }
205    if (processInfo_.syncTotal == 0) {
206        return 0;
207    }
208    return std::min(MAX_PROGRESS,
209        static_cast<uint32_t>(processInfo_.syncFinished * MAX_PROGRESS_DOUBLE / processInfo_.syncTotal));
210}
211
212uint32_t AsyncObtainData::CalPermProgress()
213{
214    if (processInfo_.permStatus == ASYNC_SUCCESS) {
215        return MAX_PROGRESS;
216    }
217    if (processInfo_.permTotal == 0) {
218        return 0;
219    }
220    return std::min(MAX_PROGRESS,
221        static_cast<uint32_t>(processInfo_.permFnished * MAX_PROGRESS_DOUBLE / processInfo_.permTotal));
222}
223} // namespace UDMF
224} // namespace OHOS