• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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