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