• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 #define LOG_TAG "BackupHandler"
17 
18 #include "backup_handler.h"
19 #include <directory_ex.h>
20 #include <fcntl.h>
21 #include <unistd.h>
22 #include <nlohmann/json.hpp>
23 #include "account_delegate.h"
24 #include "battery_info.h"
25 #include "battery_srv_client.h"
26 #include "constant.h"
27 #include "kv_store_delegate_manager.h"
28 #include "kv_scheduler.h"
29 #include "kvstore_data_service.h"
30 #include "log_print.h"
31 #include "kvstore_meta_manager.h"
32 #include "power_mgr_client.h"
33 #include "time_utils.h"
34 #include "utils/crypto.h"
35 
36 namespace OHOS::DistributedKv {
37 using json = nlohmann::json;
38 
BackupHandler(IKvStoreDataService * kvStoreDataService)39 BackupHandler::BackupHandler(IKvStoreDataService *kvStoreDataService)
40 {
41 }
42 
BackupHandler()43 BackupHandler::BackupHandler()
44 {
45 }
~BackupHandler()46 BackupHandler::~BackupHandler()
47 {
48 }
BackSchedule()49 void BackupHandler::BackSchedule()
50 {
51     std::chrono::duration<int> delay(1800); // delay 30 minutes
52     std::chrono::duration<int> internal(1800); // duration is 30 minutes
53     ZLOGI("BackupHandler Schedule start.");
54     scheduler_.Every(delay, internal, [&]() {
55         if (!CheckNeedBackup()) {
56             ZLOGE("it is not meet the condition of backup.");
57             return;
58         }
59         std::map<std::string, MetaData> results;
60         ZLOGI("BackupHandler Schedule Every start.");
61         if (!KvStoreMetaManager::GetInstance().GetFullMetaData(results)) {
62             ZLOGE("GetFullMetaData failed.");
63             return;
64         }
65 
66         for (auto const &entry : results) {
67             if (!entry.second.kvStoreMetaData.isBackup || entry.second.kvStoreMetaData.isDirty) {
68                 continue;
69             }
70 
71             KvStoreType type = entry.second.kvStoreMetaData.kvStoreType;
72             if (type == KvStoreType::MULTI_VERSION) {
73                 MultiKvStoreBackup(entry.second);
74             } else if (type == KvStoreType::SINGLE_VERSION) {
75                 SingleKvStoreBackup(entry.second);
76             }
77         }
78         backupSuccessTime_ = TimeUtils::CurrentTimeMicros();
79     });
80 }
81 
SingleKvStoreBackup(const MetaData & metaData)82 void BackupHandler::SingleKvStoreBackup(const MetaData &metaData)
83 {
84     ZLOGI("SingleKvStoreBackup start.");
85     BackupPara backupPara;
86     auto initPara = InitBackupPara(metaData, backupPara);
87     if (!initPara) {
88         return;
89     }
90 
91     DistributedDB::KvStoreNbDelegate::Option dbOption;
92     dbOption.createIfNecessary = false;
93     dbOption.isEncryptedDb = backupPara.password.GetSize() > 0;
94     dbOption.passwd = backupPara.password;
95     dbOption.createDirByStoreIdOnly = true;
96     dbOption.secOption = KvStoreAppManager::ConvertSecurity(metaData.kvStoreMetaData.securityLevel);
97 
98     auto *delegateMgr = new DistributedDB::KvStoreDelegateManager(metaData.kvStoreMetaData.appId,
99         AccountDelegate::GetInstance()->GetCurrentAccountId(metaData.kvStoreMetaData.bundleName));
100 
101     std::string appDataStoragePath = KvStoreAppManager::GetDataStoragePath(metaData.kvStoreMetaData.deviceAccountId,
102         metaData.kvStoreMetaData.bundleName, backupPara.pathType);
103     DistributedDB::KvStoreConfig kvStoreConfig = {appDataStoragePath};
104     delegateMgr->SetKvStoreConfig(kvStoreConfig);
105     std::function<void(DistributedDB::DBStatus, DistributedDB::KvStoreNbDelegate *)> fun =
106         [&](DistributedDB::DBStatus status, DistributedDB::KvStoreNbDelegate *delegate) {
107             auto del = std::shared_ptr<DistributedDB::KvStoreDelegateManager>(delegateMgr);
108             if (delegate == nullptr) {
109                 ZLOGE("SingleKvStoreBackup delegate is null");
110                 return;
111             }
112             if (metaData.kvStoreMetaData.isAutoSync) {
113                 bool autoSync = true;
114                 DistributedDB::PragmaData data = static_cast<DistributedDB::PragmaData>(&autoSync);
115                 auto pragmaStatus = delegate->Pragma(DistributedDB::PragmaCmd::AUTO_SYNC, data);
116                 if (pragmaStatus != DistributedDB::DBStatus::OK) {
117                     ZLOGE("pragmaStatus: %d", static_cast<int>(pragmaStatus));
118                 }
119             }
120             ZLOGW("SingleKvStoreBackup export");
121             if (status == DistributedDB::DBStatus::OK) {
122                 auto backupFullName = backupPara.backupFullName;
123                 auto backupBackFullName = backupPara.backupBackFullName;
124                 RenameFile(backupFullName, backupBackFullName);
125                 status = delegate->Export(backupFullName, dbOption.passwd);
126                 if (status == DistributedDB::DBStatus::OK) {
127                     ZLOGD("SingleKvStoreBackup export success.");
128                     RemoveFile(backupBackFullName);
129                 } else {
130                     ZLOGE("SingleKvStoreBackup export failed, status is %d.", status);
131                     RenameFile(backupBackFullName, backupFullName);
132                 }
133             }
134             del->CloseKvStore(delegate);
135         };
136     delegateMgr->GetKvStore(metaData.kvStoreMetaData.storeId, dbOption, fun);
137 }
138 
MultiKvStoreBackup(const MetaData & metaData)139 void BackupHandler::MultiKvStoreBackup(const MetaData &metaData)
140 {
141     ZLOGI("MultiKvStoreBackup start.");
142     BackupPara backupPara;
143     auto initPara = InitBackupPara(metaData, backupPara);
144     if (!initPara) {
145         return;
146     }
147 
148     DistributedDB::KvStoreDelegate::Option option;
149     option.createIfNecessary = false;
150     option.isEncryptedDb = backupPara.password.GetSize() > 0;
151     option.passwd = backupPara.password;
152     option.createDirByStoreIdOnly = true;
153 
154     auto *delegateMgr = new DistributedDB::KvStoreDelegateManager(metaData.kvStoreMetaData.appId,
155         AccountDelegate::GetInstance()->GetCurrentAccountId(metaData.kvStoreMetaData.bundleName));
156     std::string appDataStoragePath = KvStoreAppManager::GetDataStoragePath(metaData.kvStoreMetaData.deviceAccountId,
157         metaData.kvStoreMetaData.bundleName, backupPara.pathType);
158     DistributedDB::KvStoreConfig kvStoreConfig;
159     kvStoreConfig.dataDir = appDataStoragePath;
160     delegateMgr->SetKvStoreConfig(kvStoreConfig);
161     std::function<void(DistributedDB::DBStatus, DistributedDB::KvStoreDelegate *)> fun =
162         [&](DistributedDB::DBStatus status, DistributedDB::KvStoreDelegate *delegate) {
163             auto del = std::shared_ptr<DistributedDB::KvStoreDelegateManager>(delegateMgr);
164             if (delegate == nullptr) {
165                 ZLOGE("MultiKvStoreBackup delegate is null");
166                 return;
167             }
168             ZLOGW("MultiKvStoreBackup export");
169             if (status == DistributedDB::DBStatus::OK) {
170                 auto backupFullName = backupPara.backupFullName;
171                 auto backupBackFullName = backupPara.backupBackFullName;
172 
173                 RenameFile(backupFullName, backupBackFullName);
174                 status = delegate->Export(backupFullName, option.passwd);
175                 if (status == DistributedDB::DBStatus::OK) {
176                     ZLOGD("MultiKvStoreBackup export success.");
177                     RemoveFile(backupBackFullName);
178                     ZLOGD("MultiKvStoreBackup export success.");
179                 } else {
180                     ZLOGE("MultiKvStoreBackup export failed.");
181                     RenameFile(backupBackFullName, backupFullName);
182                 }
183             }
184             del->CloseKvStore(delegate);
185         };
186     delegateMgr->GetKvStore(metaData.kvStoreMetaData.storeId, option, fun);
187 }
188 
InitBackupPara(const MetaData & metaData,BackupPara & backupPara)189 bool BackupHandler::InitBackupPara(const MetaData &metaData, BackupPara &backupPara)
190 {
191     BackupPara backupParameter;
192     auto pathType = KvStoreAppManager::ConvertPathType(
193         metaData.kvStoreMetaData.uid, metaData.kvStoreMetaData.bundleName, metaData.kvStoreMetaData.securityLevel);
194     if (!ForceCreateDirectory(BackupHandler::GetBackupPath(metaData.kvStoreMetaData.deviceAccountId, pathType))) {
195         ZLOGE("MultiKvStoreBackup backup create directory failed.");
196         return false;
197     }
198 
199     DistributedDB::CipherPassword password;
200     const std::vector<uint8_t> &secretKey = metaData.secretKeyMetaData.secretKey;
201     if (password.SetValue(secretKey.data(), secretKey.size()) != DistributedDB::CipherPassword::OK) {
202         ZLOGE("Set secret key value failed. len is (%d)", int32_t(secretKey.size()));
203         return false;
204     }
205 
206     std::initializer_list<std::string> backList = {metaData.kvStoreMetaData.userId, "_",
207         metaData.kvStoreMetaData.appId, "_", metaData.kvStoreMetaData.storeId};
208     std::string backupName = Constant::Concatenate(backList);
209     std::initializer_list<std::string> backFullList = {
210         BackupHandler::GetBackupPath(metaData.kvStoreMetaData.deviceAccountId, pathType), "/",
211         GetHashedBackupName(backupName)};
212     auto backupFullName = Constant::Concatenate(backFullList);
213     std::initializer_list<std::string> backNameList = {backupFullName, ".", "backup"};
214     auto backupBackFullName = Constant::Concatenate(backNameList);
215 
216     backupParameter.pathType = pathType;
217     backupParameter.password = password;
218     backupParameter.backupFullName = backupFullName;
219     backupParameter.backupBackFullName = backupBackFullName;
220     backupPara = backupParameter;
221 
222     return true;
223 }
224 
SingleKvStoreRecover(MetaData & metaData,DistributedDB::KvStoreNbDelegate * delegate)225 bool BackupHandler::SingleKvStoreRecover(MetaData &metaData, DistributedDB::KvStoreNbDelegate *delegate)
226 {
227     ZLOGI("start.");
228     if (delegate == nullptr) {
229         ZLOGE("SingleKvStoreRecover failed, delegate is null.");
230         return false;
231     }
232     auto pathType = KvStoreAppManager::ConvertPathType(
233         metaData.kvStoreMetaData.uid, metaData.kvStoreMetaData.bundleName, metaData.kvStoreMetaData.securityLevel);
234     if (!BackupHandler::FileExists(BackupHandler::GetBackupPath(metaData.kvStoreMetaData.deviceAccountId, pathType))) {
235         ZLOGE("SingleKvStoreRecover failed, backupDir_ file is not exist.");
236         return false;
237     }
238 
239     DistributedDB::CipherPassword password;
240     const std::vector<uint8_t> &secretKey = metaData.secretKeyMetaData.secretKey;
241     if (password.SetValue(secretKey.data(), secretKey.size()) != DistributedDB::CipherPassword::OK) {
242         ZLOGE("Set secret key failed.");
243         return false;
244     }
245 
246     std::string backupName = Constant::Concatenate(
247         {metaData.kvStoreMetaData.userId, "_", metaData.kvStoreMetaData.appId, "_",
248          metaData.kvStoreMetaData.storeId});
249     auto backupFullName = Constant::Concatenate({
250         BackupHandler::GetBackupPath(metaData.kvStoreMetaData.deviceAccountId, pathType), "/",
251         GetHashedBackupName(backupName)
252     });
253     DistributedDB::DBStatus dbStatus = delegate->Import(backupFullName, password);
254     if (dbStatus == DistributedDB::DBStatus::OK) {
255         ZLOGI("SingleKvStoreRecover success.");
256         return true;
257     }
258     ZLOGI("SingleKvStoreRecover failed.");
259     return false;
260 }
261 
MultiKvStoreRecover(MetaData & metaData,DistributedDB::KvStoreDelegate * delegate)262 bool BackupHandler::MultiKvStoreRecover(MetaData &metaData,
263                                         DistributedDB::KvStoreDelegate *delegate)
264 {
265     ZLOGI("start.");
266     if (delegate == nullptr) {
267         ZLOGE("MultiKvStoreRecover failed, delegate is null.");
268         return false;
269     }
270     auto pathType = KvStoreAppManager::ConvertPathType(
271         metaData.kvStoreMetaData.uid, metaData.kvStoreMetaData.bundleName, metaData.kvStoreMetaData.securityLevel);
272     if (!BackupHandler::FileExists(BackupHandler::GetBackupPath(metaData.kvStoreMetaData.deviceAccountId, pathType))) {
273         ZLOGE("MultiKvStoreRecover failed, backupDir_ file is not exist.");
274         return false;
275     }
276 
277     ZLOGI("MultiKvStoreRecover start.");
278     DistributedDB::CipherPassword password;
279     const std::vector<uint8_t> &secretKey = metaData.secretKeyMetaData.secretKey;
280     if (password.SetValue(secretKey.data(), secretKey.size()) != DistributedDB::CipherPassword::OK) {
281         ZLOGE("Set secret key failed.");
282         return false;
283     }
284 
285     std::string backupName = Constant::Concatenate(
286         {metaData.kvStoreMetaData.userId, "_", metaData.kvStoreMetaData.appId, "_",
287          metaData.kvStoreMetaData.storeId});
288     auto backupFullName = Constant::Concatenate({
289         BackupHandler::GetBackupPath(metaData.kvStoreMetaData.deviceAccountId, pathType), "/",
290         GetHashedBackupName(backupName)
291     });
292     DistributedDB::DBStatus dbStatus = delegate->Import(backupFullName, password);
293     if (dbStatus == DistributedDB::DBStatus::OK) {
294         ZLOGI("MultiKvStoreRecover success.");
295         return true;
296     }
297     ZLOGI("MultiKvStoreRecover failed.");
298     return false;
299 }
300 
301 std::string BackupHandler::backupDirCe_;
302 std::string BackupHandler::backupDirDe_;
GetBackupPath(const std::string & deviceAccountId,int pathType)303 const std::string &BackupHandler::GetBackupPath(const std::string &deviceAccountId, int pathType)
304 {
305     if (pathType == KvStoreAppManager::PATH_DE) {
306         if (backupDirDe_.empty()) {
307             backupDirDe_ = Constant::Concatenate({ Constant::ROOT_PATH_DE, "/", Constant::SERVICE_NAME, "/",
308                                                    deviceAccountId, "/", Constant::GetDefaultHarmonyAccountName(),
309                                                    "/", "backup" });
310         }
311         return backupDirDe_;
312     } else {
313         if (backupDirCe_.empty()) {
314             backupDirCe_ = Constant::Concatenate({ Constant::ROOT_PATH_CE, "/", Constant::SERVICE_NAME, "/",
315                                                    deviceAccountId, "/", Constant::GetDefaultHarmonyAccountName(),
316                                                    "/", "backup" });
317         }
318         return backupDirCe_;
319     }
320 }
321 
RenameFile(const std::string & oldPath,const std::string & newPath)322 bool BackupHandler::RenameFile(const std::string &oldPath, const std::string &newPath)
323 {
324     if (oldPath.empty() || newPath.empty()) {
325         ZLOGE("RenameFile failed: path is empty");
326         return false;
327     }
328     if (!RemoveFile(newPath)) {
329         ZLOGE("RenameFile failed: newPath file is already exist");
330         return false;
331     }
332     if (rename(oldPath.c_str(), newPath.c_str()) != 0) {
333         ZLOGE("RenameFile: rename error, errno[%d].", errno);
334         return false;
335     }
336     return true;
337 }
338 
RemoveFile(const std::string & path)339 bool BackupHandler::RemoveFile(const std::string &path)
340 {
341     if (path.empty()) {
342         ZLOGI("RemoveFile: path is empty");
343         return true;
344     }
345 
346     if (unlink(path.c_str()) != 0 && (errno != ENOENT)) {
347         ZLOGE("RemoveFile: failed to RemoveFile, errno[%d].", errno);
348         return false;
349     }
350     return true;
351 }
352 
FileExists(const std::string & path)353 bool BackupHandler::FileExists(const std::string &path)
354 {
355     if (path.empty()) {
356         ZLOGI("FileExists: path is empty");
357         return false;
358     }
359 
360     if (access(path.c_str(), F_OK) != 0) {
361         ZLOGI("FileExists: file is not exist");
362         return false;
363     }
364     return true;
365 }
366 
CheckNeedBackup()367 bool BackupHandler::CheckNeedBackup()
368 {
369     auto &batterySrvClient = PowerMgr::BatterySrvClient::GetInstance();
370     auto chargingStatus = batterySrvClient.GetChargingStatus();
371     if (chargingStatus != PowerMgr::BatteryChargeState::CHARGE_STATE_ENABLE) {
372         if (chargingStatus != PowerMgr::BatteryChargeState::CHARGE_STATE_FULL) {
373             ZLOGE("the device is not in charge state, chargingStatus=%{public}d.", chargingStatus);
374             return false;
375         }
376         auto batteryPluggedType = batterySrvClient.GetPluggedType();
377         if (batteryPluggedType != PowerMgr::BatteryPluggedType::PLUGGED_TYPE_AC &&
378             batteryPluggedType != PowerMgr::BatteryPluggedType::PLUGGED_TYPE_USB &&
379             batteryPluggedType != PowerMgr::BatteryPluggedType::PLUGGED_TYPE_WIRELESS) {
380             ZLOGE("the device is not in charge full statue, the batteryPluggedType is %{public}d.", batteryPluggedType);
381             return false;
382         }
383     }
384     auto &powerMgrClient = PowerMgr::PowerMgrClient::GetInstance();
385     if (powerMgrClient.IsScreenOn()) {
386         ZLOGE("the device screen is on.");
387         return false;
388     }
389     int64_t currentTime = TimeUtils::CurrentTimeMicros();
390     if (currentTime - backupSuccessTime_ < 36000000 && backupSuccessTime_ > 0) { // 36000000 is 10 hours
391         ZLOGE("no more than 10 hours since the last backup success.");
392         return false;
393     }
394     return true;
395 }
396 
GetHashedBackupName(const std::string & bundleName)397 std::string BackupHandler::GetHashedBackupName(const std::string &bundleName)
398 {
399     if (bundleName.empty()) {
400         return bundleName;
401     }
402     return DistributedData::Crypto::Sha256(bundleName);
403 }
404 } // namespace OHOS::DistributedKv
405