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 
16 #include "mission/dsched_sync_e2e.h"
17 
18 #include <parameter.h>
19 
20 namespace OHOS {
21 namespace DistributedSchedule {
22 namespace {
23 const std::string TAG = "DmsKvSyncE2E";
24 const std::string BMS_KV_BASE_DIR = "/data/service/el1/public/database/DistributedSchedule";
25 const int32_t SLEEP_INTERVAL = 100 * 1000;  // 100ms
26 const int32_t EL1 = 1;
27 const int32_t MAX_TIMES = 600;              // 1min
28 const char DETERMINE_DEVICE_TYPE_KEY[] = "persist.distributed_scene.sys_settings_data_sync";
29 }  // namespace
30 
31 std::shared_ptr<DmsKvSyncE2E> DmsKvSyncE2E::instance_ = nullptr;
32 std::mutex DmsKvSyncE2E::mutex_;
33 
DmsKvSyncE2E()34 DmsKvSyncE2E::DmsKvSyncE2E()
35 {
36     HILOGD("called.");
37     TryTwice([this] { return GetKvStore(); });
38     HILOGD("end.");
39 }
40 
~DmsKvSyncE2E()41 DmsKvSyncE2E::~DmsKvSyncE2E()
42 {
43     HILOGD("called.");
44     dataManager_.CloseKvStore(appId_, storeId_);
45     HILOGD("end.");
46 }
47 
GetInstance()48 std::shared_ptr<DmsKvSyncE2E> DmsKvSyncE2E::GetInstance()
49 {
50     HILOGD("called.");
51     std::lock_guard<std::mutex> lock(mutex_);
52     if (instance_ == nullptr) {
53         instance_ = std::make_shared<DmsKvSyncE2E>();
54     }
55     HILOGD("end.");
56     return instance_;
57 }
58 
SetDeviceCfg()59 void DmsKvSyncE2E::SetDeviceCfg()
60 {
61     HILOGI("called.");
62     const char *syncType = "1";
63     const int bufferLen = 10;
64     char paramOutBuf[bufferLen] = {0};
65     int ret = GetParameter(DETERMINE_DEVICE_TYPE_KEY, "", paramOutBuf, bufferLen);
66     HILOGI("paramOutBuf: %{public}s, ret: %{public}d", paramOutBuf, ret);
67     if (ret > 0 && strncmp(paramOutBuf, syncType, strlen(syncType)) == 0) {
68         HILOGI("Determining the e2e device succeeded.");
69         isCfgDevices_ = true;
70     }
71 }
72 
CheckDeviceCfg()73 bool DmsKvSyncE2E::CheckDeviceCfg()
74 {
75     HILOGI("called.");
76     return isCfgDevices_;
77 }
78 
PushAndPullData()79 bool DmsKvSyncE2E::PushAndPullData()
80 {
81     HILOGI("called.");
82     std::vector<std::string> networkIdList = DtbschedmgrDeviceInfoStorage::GetInstance().GetNetworkIdList();
83     if (networkIdList.empty()) {
84         HILOGE("GetNetworkIdList failed");
85         return false;
86     }
87     if (!CheckKvStore()) {
88         HILOGE("kvStore is nullptr");
89         return false;
90     }
91     DistributedKv::DataQuery dataQuery;
92     std::shared_ptr<DmsKvSyncCB> syncCallback = std::make_shared<DmsKvSyncCB>();
93     Status status = kvStorePtr_->Sync(networkIdList, DistributedKv::SyncMode::PUSH_PULL, dataQuery, syncCallback);
94     if (status != Status::SUCCESS) {
95         HILOGE("sync error: %{public}d", status);
96         return false;
97     }
98     HILOGI("Synchronizing");
99     return true;
100 }
101 
PushAndPullData(const std::string & networkId)102 bool DmsKvSyncE2E::PushAndPullData(const std::string &networkId)
103 {
104     HILOGI("called.");
105     if (!CheckDeviceCfg() && IsSynchronized(networkId)) {
106         HILOGW("The normal device been synchronized : %{public}s", GetAnonymStr(networkId).c_str());
107         return false;
108     }
109     std::vector<std::string> networkIdList = {networkId};
110     if (!CheckKvStore()) {
111         HILOGE("kvStore is nullptr");
112         return false;
113     }
114 
115     SetSyncRecord(networkId);
116     DistributedKv::DataQuery dataQuery;
117     std::shared_ptr<DmsKvSyncCB> syncCallback = std::make_shared<DmsKvSyncCB>();
118     Status status = kvStorePtr_->Sync(networkIdList, DistributedKv::SyncMode::PUSH_PULL, dataQuery, syncCallback);
119     if (status != Status::SUCCESS) {
120         HILOGE("sync error: %{public}d", status);
121         return false;
122     }
123     HILOGI("Synchronizing");
124     return true;
125 }
126 
SetSyncRecord(const std::string & networkId)127 void DmsKvSyncE2E::SetSyncRecord(const std::string &networkId)
128 {
129     std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
130     deviceSyncRecord_.insert(std::make_pair(networkId, true));
131 }
132 
ClearSyncRecord(const std::string & networkId)133 void DmsKvSyncE2E::ClearSyncRecord(const std::string &networkId)
134 {
135     std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
136     auto it = deviceSyncRecord_.find(networkId);
137     if (it != deviceSyncRecord_.end()) {
138         deviceSyncRecord_.erase(it);
139         HILOGI("Successfully cleared synchronization records for: %{public}s", GetAnonymStr(networkId).c_str());
140     } else {
141         HILOGI("No need to clean up for: %{public}s", GetAnonymStr(networkId).c_str());
142     }
143 }
144 
IsSynchronized(const std::string & networkId)145 bool DmsKvSyncE2E::IsSynchronized(const std::string &networkId)
146 {
147     std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
148     if (deviceSyncRecord_.find(networkId) != deviceSyncRecord_.end() && deviceSyncRecord_[networkId]) {
149         return true;
150     }
151     return false;
152 }
153 
CheckKvStore()154 bool DmsKvSyncE2E::CheckKvStore()
155 {
156     HILOGD("called.");
157     std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
158     if (kvStorePtr_ != nullptr) {
159         return true;
160     }
161     int32_t tryTimes = MAX_TIMES;
162     while (tryTimes > 0) {
163         Status status = GetKvStore();
164         if (status == Status::SUCCESS && kvStorePtr_ != nullptr) {
165             return true;
166         }
167         HILOGW("CheckKvStore, Times: %{public}d", tryTimes);
168         usleep(SLEEP_INTERVAL);
169         tryTimes--;
170     }
171     HILOGD("end.");
172     return kvStorePtr_ != nullptr;
173 }
174 
GetKvStore()175 Status DmsKvSyncE2E::GetKvStore()
176 {
177     HILOGI("called.");
178     Options options = {
179         .createIfMissing = true,
180         .encrypt = false,
181         .autoSync = false,
182         .isPublic = true,
183         .securityLevel = SecurityLevel::S1,
184         .area = EL1,
185         .kvStoreType = KvStoreType::SINGLE_VERSION,
186         .baseDir = BMS_KV_BASE_DIR,
187         .dataType = DataType::TYPE_DYNAMICAL,
188         .cloudConfig = {
189             .enableCloud = true,
190             .autoSync = true
191         },
192     };
193     Status status = dataManager_.GetSingleKvStore(options, appId_, storeId_, kvStorePtr_);
194     if (status == Status::SUCCESS) {
195         HILOGI("get kvStore success");
196     } else if (status == DistributedKv::Status::STORE_META_CHANGED) {
197         HILOGE("This db meta changed, remove and rebuild it");
198         dataManager_.DeleteKvStore(appId_, storeId_, BMS_KV_BASE_DIR + appId_.appId);
199     }
200     HILOGI("end.");
201     return status;
202 }
203 
TryTwice(const std::function<Status ()> & func) const204 void DmsKvSyncE2E::TryTwice(const std::function<Status()> &func) const
205 {
206     HILOGD("called.");
207     Status status = func();
208     if (status != Status::SUCCESS) {
209         status = func();
210         HILOGW("error and try to call again, result = %{public}d", status);
211     }
212     HILOGD("end.");
213 }
214 
DmsKvSyncCB()215 DmsKvSyncCB::DmsKvSyncCB()
216 {
217     HILOGD("create");
218 }
219 
~DmsKvSyncCB()220 DmsKvSyncCB::~DmsKvSyncCB()
221 {
222     HILOGD("destroy");
223 }
224 
SyncCompleted(const std::map<std::string,DistributedKv::Status> & result)225 void DmsKvSyncCB::SyncCompleted(const std::map<std::string, DistributedKv::Status> &result)
226 {
227     HILOGI("kvstore sync completed.");
228     for (auto ele : result) {
229         HILOGI("uuid: %{public}s , result: %{public}d", GetAnonymStr(ele.first).c_str(), ele.second);
230     }
231 }
232 }  // namespace DistributedSchedule
233 }  // namespace OHOS
234