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 <filesystem>
19 #include <fstream>
20 #include <iostream>
21 #include <parameter.h>
22
23 #include "config_policy_utils.h"
24 #include "parameters.h"
25 #include "securec.h"
26
27 namespace OHOS {
28 namespace DistributedSchedule {
29 namespace {
30 const std::string TAG = "DmsKvSyncE2E";
31 const std::string BMS_KV_BASE_DIR = "/data/service/el1/public/database/DistributedSchedule";
32 const int32_t SLEEP_INTERVAL = 100 * 1000; // 100ms
33 const int32_t EL1 = 1;
34 const int32_t MAX_TIMES = 600; // 1min
35 const char DETERMINE_DEVICE_TYPE_KEY[] = "persist.distributed_scene.sys_settings_data_sync";
36 static const int32_t FORBID_SEND_FORBID_RECV = 0;
37 static const int32_t ALLOW_SEND_ALLOW_RECV = 1;
38 const std::string PARAM_DISTRIBUTED_DATAFILES_TRANS_CTRL = "persist.distributed_scene.datafiles_trans_ctrl";
39 const std::string CONTINUE_CONFIG_RELATIVE_PATH = "etc/distributedhardware/dms/continue_config.json";
40 const std::string ALLOW_APP_LIST_KEY = "allow_applist";
41 constexpr int32_t MAX_CONFIG_PATH_LEN = 1024;
42 } // namespace
43
44 std::shared_ptr<DmsKvSyncE2E> DmsKvSyncE2E::instance_ = nullptr;
45 std::mutex DmsKvSyncE2E::mutex_;
46
DmsKvSyncE2E()47 DmsKvSyncE2E::DmsKvSyncE2E()
48 {
49 HILOGD("called.");
50 TryTwice([this] { return GetKvStore(); });
51 HILOGD("end.");
52 }
53
~DmsKvSyncE2E()54 DmsKvSyncE2E::~DmsKvSyncE2E()
55 {
56 HILOGD("called.");
57 dataManager_.CloseKvStore(appId_, storeId_);
58 HILOGD("end.");
59 }
60
GetInstance()61 std::shared_ptr<DmsKvSyncE2E> DmsKvSyncE2E::GetInstance()
62 {
63 HILOGD("called.");
64 std::lock_guard<std::mutex> lock(mutex_);
65 if (instance_ == nullptr) {
66 instance_ = std::make_shared<DmsKvSyncE2E>();
67 }
68 HILOGD("end.");
69 return instance_;
70 }
71
SetDeviceCfg()72 void DmsKvSyncE2E::SetDeviceCfg()
73 {
74 HILOGD("called.");
75 const char *syncType = "1";
76 const int bufferLen = 10;
77 char paramOutBuf[bufferLen] = {0};
78 int ret = GetParameter(DETERMINE_DEVICE_TYPE_KEY, "", paramOutBuf, bufferLen);
79 HILOGD("paramOutBuf: %{public}s, ret: %{public}d", paramOutBuf, ret);
80 if (ret > 0 && strncmp(paramOutBuf, syncType, strlen(syncType)) == 0) {
81 HILOGI("Determining the e2e device succeeded.");
82 isCfgDevices_ = true;
83 }
84
85 auto contralType = OHOS::system::GetIntParameter(PARAM_DISTRIBUTED_DATAFILES_TRANS_CTRL,
86 ALLOW_SEND_ALLOW_RECV);
87 HILOGI("contralType=%{public}d", contralType);
88 if (contralType == FORBID_SEND_FORBID_RECV) {
89 isForbidSendAndRecv_ = true;
90 }
91
92 int32_t result = LoadContinueConfig();
93 if (result != ERR_OK) {
94 HILOGE("Load continue config fail, result %{public}d.", result);
95 }
96 }
97
CheckDeviceCfg()98 bool DmsKvSyncE2E::CheckDeviceCfg()
99 {
100 HILOGD("called.");
101 return isCfgDevices_;
102 }
103
CheckCtrlRule()104 bool DmsKvSyncE2E::CheckCtrlRule()
105 {
106 HILOGD("called.");
107 if (isCfgDevices_ && isForbidSendAndRecv_) {
108 HILOGE("The device is a special device and checkCtrlRule fail");
109 return false;
110 }
111 return true;
112 }
113
IsValidPath(const std::string & inFilePath,std::string & realFilePath)114 bool DmsKvSyncE2E::IsValidPath(const std::string &inFilePath, std::string &realFilePath)
115 {
116 char path[PATH_MAX + 1] = { 0 };
117 if (inFilePath.empty() || inFilePath.length() > PATH_MAX || inFilePath.length() + 1 > MAX_CONFIG_PATH_LEN ||
118 realpath(inFilePath.c_str(), path) == nullptr) {
119 HILOGE("Get continue config file real path fail, inFilePath %{public}s.", GetAnonymStr(inFilePath).c_str());
120 return false;
121 }
122
123 realFilePath = std::string(path);
124 if (realFilePath.empty()) {
125 HILOGE("Real file path is empty.");
126 return false;
127 }
128 if (!std::filesystem::exists(realFilePath)) {
129 HILOGE("The real file path %{public}s does not exist in the file system.", GetAnonymStr(realFilePath).c_str());
130 realFilePath = "";
131 return false;
132 }
133 HILOGD("The real file path %{public}s exist in the file system.", GetAnonymStr(realFilePath).c_str());
134 return true;
135 }
136
UpdateWhiteList(const std::string & cfgJsonStr)137 bool DmsKvSyncE2E::UpdateWhiteList(const std::string &cfgJsonStr)
138 {
139 cJSON *inJson = nullptr;
140 cJSON *allowList = nullptr;
141 bool isSuccess = false;
142 do {
143 inJson = cJSON_Parse(cfgJsonStr.c_str());
144 if (inJson == nullptr) {
145 HILOGE("parse continue config json file stream to json fail.");
146 break;
147 }
148
149 allowList = cJSON_GetObjectItem(inJson, ALLOW_APP_LIST_KEY.c_str());
150 if (allowList == nullptr || !cJSON_IsArray(allowList)) {
151 HILOGE("allow app list array is not in continue config json file.");
152 break;
153 }
154
155 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
156 for (int32_t i = 0; i < cJSON_GetArraySize(allowList); i++) {
157 cJSON *iAllowAppJson = cJSON_GetArrayItem(allowList, i);
158 if (!cJSON_IsString(iAllowAppJson)) {
159 HILOGE("allow app list [%{public}d] is not string.", i);
160 continue;
161 }
162
163 std::string iAllowAppStr = std::string(cJSON_GetStringValue(iAllowAppJson));
164 HILOGI("allow app list show [%{public}d] : [%{public}s].", i, iAllowAppStr.c_str());
165 whiteList_.push_back(iAllowAppStr);
166 }
167 isSuccess = true;
168 } while (false);
169
170 if (inJson != nullptr) {
171 cJSON_Delete(inJson);
172 inJson = nullptr;
173 }
174 return isSuccess;
175 }
176
LoadContinueConfig()177 int32_t DmsKvSyncE2E::LoadContinueConfig()
178 {
179 HILOGD("Load continue config, continueCfgFullPath %{public}s.", GetAnonymStr(continueCfgFullPath_).c_str());
180 std::string tempPath = continueCfgFullPath_;
181 if ((continueCfgFullPath_.empty() || !IsValidPath(tempPath, continueCfgFullPath_))) {
182 char cfgPathBuf[MAX_CONFIG_PATH_LEN] = { 0 };
183 char *filePath = GetOneCfgFile(CONTINUE_CONFIG_RELATIVE_PATH.c_str(), cfgPathBuf, MAX_CONFIG_PATH_LEN);
184 if (filePath == nullptr || filePath != cfgPathBuf) {
185 HILOGE("Not find continue config file, relative path %{public}s.",
186 GetAnonymStr(CONTINUE_CONFIG_RELATIVE_PATH).c_str());
187 continueCfgFullPath_ = "";
188 return ERR_OK;
189 }
190 continueCfgFullPath_ = std::string(filePath);
191 HILOGD("Get Continue config file full path success, cfgFullPath %{public}s.",
192 GetAnonymStr(continueCfgFullPath_).c_str());
193 }
194
195 tempPath = continueCfgFullPath_;
196 if (!IsValidPath(tempPath, continueCfgFullPath_)) {
197 HILOGE("Continue config full path is invalid, cfgFullPath %{public}s.",
198 GetAnonymStr(continueCfgFullPath_).c_str());
199 return DMS_PERMISSION_DENIED;
200 }
201 std::ifstream in;
202 in.open(continueCfgFullPath_.c_str(), std::ios::binary | std::ios::in);
203 if (!in.is_open()) {
204 HILOGE("Open continue config json file fail, cfgFullPath %{public}s.",
205 GetAnonymStr(continueCfgFullPath_).c_str());
206 return DMS_PERMISSION_DENIED;
207 }
208
209 std::string cfgFileContent;
210 in.seekg(0, std::ios::end);
211 cfgFileContent.resize(in.tellg());
212 in.seekg(0, std::ios::beg);
213 in.rdbuf()->sgetn(&cfgFileContent[0], cfgFileContent.size());
214 in.close();
215
216 if (!UpdateWhiteList(cfgFileContent)) {
217 HILOGE("Update allow app list fail, cfgFullPath %{public}s.",
218 GetAnonymStr(continueCfgFullPath_).c_str());
219 return DMS_PERMISSION_DENIED;
220 }
221 HILOGD("Load continue config success, cfgFullPath %{public}s.", GetAnonymStr(continueCfgFullPath_).c_str());
222 return ERR_OK;
223 }
224
CheckBundleContinueConfig(const std::string & bundleName)225 bool DmsKvSyncE2E::CheckBundleContinueConfig(const std::string &bundleName)
226 {
227 if (!isCfgDevices_) {
228 HILOGD("The device is a normal device");
229 return true;
230 }
231
232 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
233 auto it = std::find(whiteList_.begin(), whiteList_.end(), bundleName);
234 if (it == whiteList_.end()) {
235 HILOGE("Current app is not allow to continue in config file, bundleName %{public}s, cfgPath %{public}s.",
236 bundleName.c_str(), GetAnonymStr(continueCfgFullPath_).c_str());
237 return false;
238 }
239
240 HILOGD("Current app is allow to continue in config file, bundleName %{public}s, cfgPath %{public}s.",
241 bundleName.c_str(), GetAnonymStr(continueCfgFullPath_).c_str());
242 return true;
243 }
244
PushAndPullData()245 bool DmsKvSyncE2E::PushAndPullData()
246 {
247 HILOGI("called.");
248 std::vector<std::string> networkIdList = DtbschedmgrDeviceInfoStorage::GetInstance().GetNetworkIdList();
249 if (networkIdList.empty()) {
250 HILOGE("GetNetworkIdList failed");
251 return false;
252 }
253 if (!CheckKvStore()) {
254 HILOGE("kvStore is nullptr");
255 return false;
256 }
257 DistributedKv::DataQuery dataQuery;
258 std::shared_ptr<DmsKvSyncCB> syncCallback = std::make_shared<DmsKvSyncCB>();
259 Status status = kvStorePtr_->Sync(networkIdList, DistributedKv::SyncMode::PUSH_PULL, dataQuery, syncCallback);
260 if (status != Status::SUCCESS) {
261 HILOGE("sync error: %{public}d", status);
262 return false;
263 }
264 HILOGI("Synchronizing");
265 return true;
266 }
267
PushAndPullData(const std::string & networkId)268 bool DmsKvSyncE2E::PushAndPullData(const std::string &networkId)
269 {
270 HILOGI("called.");
271 std::vector<std::string> networkIdList = {networkId};
272 if (!CheckKvStore()) {
273 HILOGE("kvStore is nullptr");
274 return false;
275 }
276
277 DistributedKv::DataQuery dataQuery;
278 std::shared_ptr<DmsKvSyncCB> syncCallback = std::make_shared<DmsKvSyncCB>();
279 Status status = kvStorePtr_->Sync(networkIdList, DistributedKv::SyncMode::PUSH_PULL, dataQuery, syncCallback);
280 if (status != Status::SUCCESS) {
281 HILOGE("sync error: %{public}d", status);
282 return false;
283 }
284 HILOGI("Synchronizing");
285 return true;
286 }
287
CheckKvStore()288 bool DmsKvSyncE2E::CheckKvStore()
289 {
290 HILOGD("called.");
291 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
292 if (kvStorePtr_ != nullptr) {
293 return true;
294 }
295 int32_t tryTimes = MAX_TIMES;
296 while (tryTimes > 0) {
297 Status status = GetKvStore();
298 if (status == Status::SUCCESS && kvStorePtr_ != nullptr) {
299 return true;
300 }
301 HILOGW("CheckKvStore, Times: %{public}d", tryTimes);
302 usleep(SLEEP_INTERVAL);
303 tryTimes--;
304 }
305 HILOGD("end.");
306 return kvStorePtr_ != nullptr;
307 }
308
GetKvStore()309 Status DmsKvSyncE2E::GetKvStore()
310 {
311 HILOGD("called.");
312 Options options = {
313 .createIfMissing = true,
314 .encrypt = false,
315 .autoSync = false,
316 .isPublic = true,
317 .securityLevel = SecurityLevel::S1,
318 .area = EL1,
319 .kvStoreType = KvStoreType::SINGLE_VERSION,
320 .baseDir = BMS_KV_BASE_DIR,
321 .dataType = DataType::TYPE_DYNAMICAL,
322 .cloudConfig = {
323 .enableCloud = true,
324 .autoSync = true
325 },
326 };
327 Status status = dataManager_.GetSingleKvStore(options, appId_, storeId_, kvStorePtr_);
328 if (status == Status::SUCCESS) {
329 HILOGD("get kvStore success");
330 } else if (status == DistributedKv::Status::STORE_META_CHANGED) {
331 HILOGE("This db meta changed, remove and rebuild it");
332 dataManager_.DeleteKvStore(appId_, storeId_, BMS_KV_BASE_DIR + appId_.appId);
333 }
334 HILOGD("end.");
335 return status;
336 }
337
TryTwice(const std::function<Status ()> & func) const338 void DmsKvSyncE2E::TryTwice(const std::function<Status()> &func) const
339 {
340 HILOGD("called.");
341 Status status = func();
342 if (status != Status::SUCCESS) {
343 status = func();
344 HILOGW("error and try to call again, result = %{public}d", status);
345 }
346 HILOGD("end.");
347 }
348
DmsKvSyncCB()349 DmsKvSyncCB::DmsKvSyncCB()
350 {
351 HILOGD("create");
352 }
353
~DmsKvSyncCB()354 DmsKvSyncCB::~DmsKvSyncCB()
355 {
356 HILOGD("destroy");
357 }
358
SyncCompleted(const std::map<std::string,DistributedKv::Status> & result)359 void DmsKvSyncCB::SyncCompleted(const std::map<std::string, DistributedKv::Status> &result)
360 {
361 HILOGI("kvstore sync completed.");
362 for (auto ele : result) {
363 HILOGI("uuid: %{public}s , result: %{public}d", GetAnonymStr(ele.first).c_str(), ele.second);
364 }
365 }
366 } // namespace DistributedSchedule
367 } // namespace OHOS
368