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 
24 namespace OHOS {
25 namespace UDMF {
26 static constexpr size_t MAX_THREADS = 2;
27 static constexpr size_t MIN_THREADS = 0;
28 static constexpr uint32_t MAX_PROGRESS = 100;
29 static constexpr double MAX_PROGRESS_DOUBLE = 100.0;
30 static constexpr double SYNC_COEFF = 0.5;
31 static constexpr double PERM_COEFF = 0.4;
32 
AsyncObtainData()33 AsyncObtainData::AsyncObtainData() : executor_(MAX_THREADS, MIN_THREADS) {}
34 
InitTask(const QueryOption &query, ObtainDataCallback callback)35 Status 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 
RunTask()58 Status 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 
ObtainDataTask()75 void 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 
ProgressTask()102 void 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 
InvokeCallback(UnifiedData &data)129 void 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 
UpdateProcessInfo(AsyncProcessInfo &info)148 void 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 
ClearTask()164 void 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 
CalProgress()184 uint32_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 
CalSyncProgress()200 uint32_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 
CalPermProgress()212 uint32_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